From 36bfd2ed58c6bf9d95366ac397402b01eb346669 Mon Sep 17 00:00:00 2001 From: Roman Mogylatov Date: Mon, 23 Aug 2021 20:54:17 -0400 Subject: [PATCH] Improve resource subclasses typing and make shutdown definition optional (#492) * Improve resource subclasses typing and make shutdown definition optional * Update mypy tests --- src/dependency_injector/resources.py | 12 ++++----- tests/typing/resource.py | 6 ++--- tests/unit/providers/test_resource_py35.py | 29 ++++++++-------------- 3 files changed, 18 insertions(+), 29 deletions(-) diff --git a/src/dependency_injector/resources.py b/src/dependency_injector/resources.py index efa6b15e..2468fd7a 100644 --- a/src/dependency_injector/resources.py +++ b/src/dependency_injector/resources.py @@ -1,7 +1,7 @@ """Resources module.""" import abc -from typing import TypeVar, Generic +from typing import TypeVar, Generic, Optional T = TypeVar('T') @@ -10,20 +10,18 @@ T = TypeVar('T') class Resource(Generic[T], metaclass=abc.ABCMeta): @abc.abstractmethod - def init(self, *args, **kwargs) -> T: + def init(self, *args, **kwargs) -> Optional[T]: ... - @abc.abstractmethod - def shutdown(self, resource: T) -> None: + def shutdown(self, resource: Optional[T]) -> None: ... class AsyncResource(Generic[T], metaclass=abc.ABCMeta): @abc.abstractmethod - async def init(self, *args, **kwargs) -> T: + async def init(self, *args, **kwargs) -> Optional[T]: ... - @abc.abstractmethod - async def shutdown(self, resource: T) -> None: + async def shutdown(self, resource: Optional[T]) -> None: ... diff --git a/tests/typing/resource.py b/tests/typing/resource.py index b5687451..b468df42 100644 --- a/tests/typing/resource.py +++ b/tests/typing/resource.py @@ -1,4 +1,4 @@ -from typing import List, Iterator, Generator, AsyncIterator, AsyncGenerator +from typing import List, Iterator, Generator, AsyncIterator, AsyncGenerator, Optional from dependency_injector import providers, resources @@ -35,7 +35,7 @@ class MyResource4(resources.Resource[List[int]]): def init(self, *args, **kwargs) -> List[int]: return [] - def shutdown(self, resource: List[int]) -> None: + def shutdown(self, resource: Optional[List[int]]) -> None: ... @@ -87,7 +87,7 @@ class MyResource8(resources.AsyncResource[List[int]]): async def init(self, *args, **kwargs) -> List[int]: return [] - async def shutdown(self, resource: List[int]) -> None: + async def shutdown(self, resource: Optional[List[int]]) -> None: ... diff --git a/tests/unit/providers/test_resource_py35.py b/tests/unit/providers/test_resource_py35.py index 2a38881e..ae8074b3 100644 --- a/tests/unit/providers/test_resource_py35.py +++ b/tests/unit/providers/test_resource_py35.py @@ -1,6 +1,7 @@ """Dependency injector resource provider unit tests.""" import asyncio +import inspect import unittest from typing import Any @@ -158,7 +159,7 @@ class ResourceTests(unittest.TestCase): self.assertTrue(issubclass(TestResource, resources.Resource)) - def test_init_class_abc_definition_is_required(self): + def test_init_class_abc_init_definition_is_required(self): class TestResource(resources.Resource): ... @@ -166,19 +167,13 @@ class ResourceTests(unittest.TestCase): TestResource() self.assertIn("Can't instantiate abstract class TestResource", str(context.exception)) - self.assertIn("init, shutdown", str(context.exception)) + self.assertIn("init", str(context.exception)) - - def test_init_class_abc_shutdown_definition_is_required(self): + def test_init_class_abc_shutdown_definition_is_not_required(self): class TestResource(resources.Resource): def init(self): ... - - with self.assertRaises(TypeError) as context: - TestResource() - - self.assertIn("Can't instantiate abstract class TestResource", str(context.exception)) - self.assertIn("shutdown", str(context.exception)) + self.assertTrue(hasattr(TestResource(), 'shutdown')) def test_init_not_callable(self): provider = providers.Resource(1) @@ -497,7 +492,7 @@ class AsyncResourceTest(AsyncTestCase): self.assertTrue(issubclass(TestAsyncResource, resources.AsyncResource)) - def test_init_async_class_abc_definition_is_required(self): + def test_init_async_class_abc_init_definition_is_required(self): class TestAsyncResource(resources.AsyncResource): ... @@ -505,18 +500,14 @@ class AsyncResourceTest(AsyncTestCase): TestAsyncResource() self.assertIn("Can't instantiate abstract class TestAsyncResource", str(context.exception)) - self.assertIn("init, shutdown", str(context.exception)) + self.assertIn("init", str(context.exception)) - def test_init_async_class_abc_shutdown_definition_is_required(self): + def test_init_async_class_abc_shutdown_definition_is_not_required(self): class TestAsyncResource(resources.AsyncResource): async def init(self): ... - - with self.assertRaises(TypeError) as context: - TestAsyncResource() - - self.assertIn("Can't instantiate abstract class TestAsyncResource", str(context.exception)) - self.assertIn("shutdown", str(context.exception)) + self.assertTrue(hasattr(TestAsyncResource(), 'shutdown')) + self.assertTrue(inspect.iscoroutinefunction(TestAsyncResource.shutdown)) def test_init_with_error(self): async def _init():