Skip to content

Commit 36bfd2e

Browse files
authored
Improve resource subclasses typing and make shutdown definition optional (ets-labs#492)
* Improve resource subclasses typing and make shutdown definition optional * Update mypy tests
1 parent 83c2af0 commit 36bfd2e

File tree

3 files changed

+18
-29
lines changed

3 files changed

+18
-29
lines changed

src/dependency_injector/resources.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""Resources module."""
22

33
import abc
4-
from typing import TypeVar, Generic
4+
from typing import TypeVar, Generic, Optional
55

66

77
T = TypeVar('T')
@@ -10,20 +10,18 @@
1010
class Resource(Generic[T], metaclass=abc.ABCMeta):
1111

1212
@abc.abstractmethod
13-
def init(self, *args, **kwargs) -> T:
13+
def init(self, *args, **kwargs) -> Optional[T]:
1414
...
1515

16-
@abc.abstractmethod
17-
def shutdown(self, resource: T) -> None:
16+
def shutdown(self, resource: Optional[T]) -> None:
1817
...
1918

2019

2120
class AsyncResource(Generic[T], metaclass=abc.ABCMeta):
2221

2322
@abc.abstractmethod
24-
async def init(self, *args, **kwargs) -> T:
23+
async def init(self, *args, **kwargs) -> Optional[T]:
2524
...
2625

27-
@abc.abstractmethod
28-
async def shutdown(self, resource: T) -> None:
26+
async def shutdown(self, resource: Optional[T]) -> None:
2927
...

tests/typing/resource.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import List, Iterator, Generator, AsyncIterator, AsyncGenerator
1+
from typing import List, Iterator, Generator, AsyncIterator, AsyncGenerator, Optional
22

33
from dependency_injector import providers, resources
44

@@ -35,7 +35,7 @@ class MyResource4(resources.Resource[List[int]]):
3535
def init(self, *args, **kwargs) -> List[int]:
3636
return []
3737

38-
def shutdown(self, resource: List[int]) -> None:
38+
def shutdown(self, resource: Optional[List[int]]) -> None:
3939
...
4040

4141

@@ -87,7 +87,7 @@ class MyResource8(resources.AsyncResource[List[int]]):
8787
async def init(self, *args, **kwargs) -> List[int]:
8888
return []
8989

90-
async def shutdown(self, resource: List[int]) -> None:
90+
async def shutdown(self, resource: Optional[List[int]]) -> None:
9191
...
9292

9393

tests/unit/providers/test_resource_py35.py

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Dependency injector resource provider unit tests."""
22

33
import asyncio
4+
import inspect
45
import unittest
56
from typing import Any
67

@@ -158,27 +159,21 @@ def shutdown(self, resource: TestDependency) -> None: ...
158159

159160
self.assertTrue(issubclass(TestResource, resources.Resource))
160161

161-
def test_init_class_abc_definition_is_required(self):
162+
def test_init_class_abc_init_definition_is_required(self):
162163
class TestResource(resources.Resource):
163164
...
164165

165166
with self.assertRaises(TypeError) as context:
166167
TestResource()
167168

168169
self.assertIn("Can't instantiate abstract class TestResource", str(context.exception))
169-
self.assertIn("init, shutdown", str(context.exception))
170+
self.assertIn("init", str(context.exception))
170171

171-
172-
def test_init_class_abc_shutdown_definition_is_required(self):
172+
def test_init_class_abc_shutdown_definition_is_not_required(self):
173173
class TestResource(resources.Resource):
174174
def init(self):
175175
...
176-
177-
with self.assertRaises(TypeError) as context:
178-
TestResource()
179-
180-
self.assertIn("Can't instantiate abstract class TestResource", str(context.exception))
181-
self.assertIn("shutdown", str(context.exception))
176+
self.assertTrue(hasattr(TestResource(), 'shutdown'))
182177

183178
def test_init_not_callable(self):
184179
provider = providers.Resource(1)
@@ -497,26 +492,22 @@ async def shutdown(self, resource: TestDependency) -> None: ...
497492

498493
self.assertTrue(issubclass(TestAsyncResource, resources.AsyncResource))
499494

500-
def test_init_async_class_abc_definition_is_required(self):
495+
def test_init_async_class_abc_init_definition_is_required(self):
501496
class TestAsyncResource(resources.AsyncResource):
502497
...
503498

504499
with self.assertRaises(TypeError) as context:
505500
TestAsyncResource()
506501

507502
self.assertIn("Can't instantiate abstract class TestAsyncResource", str(context.exception))
508-
self.assertIn("init, shutdown", str(context.exception))
503+
self.assertIn("init", str(context.exception))
509504

510-
def test_init_async_class_abc_shutdown_definition_is_required(self):
505+
def test_init_async_class_abc_shutdown_definition_is_not_required(self):
511506
class TestAsyncResource(resources.AsyncResource):
512507
async def init(self):
513508
...
514-
515-
with self.assertRaises(TypeError) as context:
516-
TestAsyncResource()
517-
518-
self.assertIn("Can't instantiate abstract class TestAsyncResource", str(context.exception))
519-
self.assertIn("shutdown", str(context.exception))
509+
self.assertTrue(hasattr(TestAsyncResource(), 'shutdown'))
510+
self.assertTrue(inspect.iscoroutinefunction(TestAsyncResource.shutdown))
520511

521512
def test_init_with_error(self):
522513
async def _init():

0 commit comments

Comments
 (0)