diff --git a/.coveragerc b/.coveragerc index 46a0a2ee..8c762b2a 100644 --- a/.coveragerc +++ b/.coveragerc @@ -3,5 +3,8 @@ source = src/dependency_injector omit = tests/unit plugins = Cython.Coverage +[report] +show_missing = true + [html] directory=reports/unittests/ diff --git a/docs/main/changelog.rst b/docs/main/changelog.rst index 5f416ea3..dc045074 100644 --- a/docs/main/changelog.rst +++ b/docs/main/changelog.rst @@ -13,6 +13,10 @@ follows `Semantic versioning`_ See issue `#477 `_. Thanks to `Andrey Torsunov @gtors `_ for reporting the issue. - Fix typing stub for ``container.override_providers()`` to accept other types besides ``Provider``. +- Fix runtime issue with generic typing in resource initializer classes ``resources.Resource`` + and ``resources.AsyncResource``. + See issue `#488 `_. + Thanks to `@EdwardBlair `_ for reporting the issue. 4.35.2 ------ diff --git a/src/dependency_injector/resources.py b/src/dependency_injector/resources.py index 50eeb3d2..da74ff02 100644 --- a/src/dependency_injector/resources.py +++ b/src/dependency_injector/resources.py @@ -1,26 +1,13 @@ """Resources module.""" import abc -import sys from typing import TypeVar, Generic -if sys.version_info < (3, 7): - from typing import GenericMeta -else: - class GenericMeta(type): - ... - T = TypeVar('T') -class ResourceMeta(GenericMeta, abc.ABCMeta): - def __getitem__(cls, item): - # Spike for Python 3.6 - return cls(item) - - -class Resource(Generic[T], metaclass=ResourceMeta): +class Resource(Generic[T]): @abc.abstractmethod def init(self, *args, **kwargs) -> T: @@ -31,7 +18,7 @@ class Resource(Generic[T], metaclass=ResourceMeta): ... -class AsyncResource(Generic[T], metaclass=ResourceMeta): +class AsyncResource(Generic[T]): @abc.abstractmethod async def init(self, *args, **kwargs) -> T: diff --git a/tests/unit/providers/test_resource_py35.py b/tests/unit/providers/test_resource_py35.py index 3a912307..e2a3f26f 100644 --- a/tests/unit/providers/test_resource_py35.py +++ b/tests/unit/providers/test_resource_py35.py @@ -1,8 +1,8 @@ """Dependency injector resource provider unit tests.""" import asyncio - import unittest +from typing import Any from dependency_injector import containers, providers, resources, errors @@ -603,3 +603,31 @@ class AsyncResourceTest(AsyncTestCase): self.assertIs(result2, resource) self.assertEqual(_init.counter, 1) + + +class ResourceTypingTest(unittest.TestCase): + # See issue: https://github.com/ets-labs/python-dependency-injector/issues/488 + + def test_sync_generic_type(self): + class MyDependency: + ... + + class MyResource(resources.Resource[MyDependency]): + def init(self, *args: Any, **kwargs: Any) -> MyDependency: + return MyDependency() + + def shutdown(self, resource: MyDependency) -> None: ... + + self.assertTrue(issubclass(MyResource, resources.Resource)) + + def test_async_generic_type(self): + class MyDependency: + ... + + class MyAsyncResource(resources.AsyncResource[MyDependency]): + async def init(self, *args: Any, **kwargs: Any) -> MyDependency: + return MyDependency() + + async def shutdown(self, resource: MyDependency) -> None: ... + + self.assertTrue(issubclass(MyAsyncResource, resources.AsyncResource))