Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@ source = src/dependency_injector
omit = tests/unit
plugins = Cython.Coverage

[report]
show_missing = true

[html]
directory=reports/unittests/
4 changes: 4 additions & 0 deletions docs/main/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ follows `Semantic versioning`_
See issue `#477 <https://github.com/ets-labs/python-dependency-injector/issues/477>`_.
Thanks to `Andrey Torsunov @gtors <https://github.com/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 <https://github.com/ets-labs/python-dependency-injector/issues/488>`_.
Thanks to `@EdwardBlair <https://github.com/EdwardBlair>`_ for reporting the issue.

4.35.2
------
Expand Down
17 changes: 2 additions & 15 deletions src/dependency_injector/resources.py
Original file line number Diff line number Diff line change
@@ -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]):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this still not need to inherit from abc.ABC?


@abc.abstractmethod
def init(self, *args, **kwargs) -> T:
Expand All @@ -31,7 +18,7 @@ def shutdown(self, resource: T) -> None:
...


class AsyncResource(Generic[T], metaclass=ResourceMeta):
class AsyncResource(Generic[T]):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this still not need to inherit from abc.ABC?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm... It probably needs to. I didn't have a test for unimplemented abc methods. I'll revise this later today. Thanks!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returned abc.ABCMeta inheritance and added tests in 1163ac5. I should be more watchful. Thanks for pointing out the issue.


@abc.abstractmethod
async def init(self, *args, **kwargs) -> T:
Expand Down
30 changes: 29 additions & 1 deletion tests/unit/providers/test_resource_py35.py
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -603,3 +603,31 @@ async def _init():

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))