Improve resource subclasses typing and make shutdown definition optional (#492)

* Improve resource subclasses typing and make shutdown definition optional

* Update mypy tests
This commit is contained in:
Roman Mogylatov 2021-08-23 20:54:17 -04:00 committed by GitHub
parent 83c2af0e7e
commit 36bfd2ed58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 18 additions and 29 deletions

View File

@ -1,7 +1,7 @@
"""Resources module.""" """Resources module."""
import abc import abc
from typing import TypeVar, Generic from typing import TypeVar, Generic, Optional
T = TypeVar('T') T = TypeVar('T')
@ -10,20 +10,18 @@ T = TypeVar('T')
class Resource(Generic[T], metaclass=abc.ABCMeta): class Resource(Generic[T], metaclass=abc.ABCMeta):
@abc.abstractmethod @abc.abstractmethod
def init(self, *args, **kwargs) -> T: def init(self, *args, **kwargs) -> Optional[T]:
... ...
@abc.abstractmethod def shutdown(self, resource: Optional[T]) -> None:
def shutdown(self, resource: T) -> None:
... ...
class AsyncResource(Generic[T], metaclass=abc.ABCMeta): class AsyncResource(Generic[T], metaclass=abc.ABCMeta):
@abc.abstractmethod @abc.abstractmethod
async def init(self, *args, **kwargs) -> T: async def init(self, *args, **kwargs) -> Optional[T]:
... ...
@abc.abstractmethod async def shutdown(self, resource: Optional[T]) -> None:
async def shutdown(self, resource: T) -> None:
... ...

View File

@ -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 from dependency_injector import providers, resources
@ -35,7 +35,7 @@ class MyResource4(resources.Resource[List[int]]):
def init(self, *args, **kwargs) -> List[int]: def init(self, *args, **kwargs) -> List[int]:
return [] 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]: async def init(self, *args, **kwargs) -> List[int]:
return [] return []
async def shutdown(self, resource: List[int]) -> None: async def shutdown(self, resource: Optional[List[int]]) -> None:
... ...

View File

@ -1,6 +1,7 @@
"""Dependency injector resource provider unit tests.""" """Dependency injector resource provider unit tests."""
import asyncio import asyncio
import inspect
import unittest import unittest
from typing import Any from typing import Any
@ -158,7 +159,7 @@ class ResourceTests(unittest.TestCase):
self.assertTrue(issubclass(TestResource, resources.Resource)) 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): class TestResource(resources.Resource):
... ...
@ -166,19 +167,13 @@ class ResourceTests(unittest.TestCase):
TestResource() TestResource()
self.assertIn("Can't instantiate abstract class TestResource", str(context.exception)) 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_not_required(self):
def test_init_class_abc_shutdown_definition_is_required(self):
class TestResource(resources.Resource): class TestResource(resources.Resource):
def init(self): def init(self):
... ...
self.assertTrue(hasattr(TestResource(), 'shutdown'))
with self.assertRaises(TypeError) as context:
TestResource()
self.assertIn("Can't instantiate abstract class TestResource", str(context.exception))
self.assertIn("shutdown", str(context.exception))
def test_init_not_callable(self): def test_init_not_callable(self):
provider = providers.Resource(1) provider = providers.Resource(1)
@ -497,7 +492,7 @@ class AsyncResourceTest(AsyncTestCase):
self.assertTrue(issubclass(TestAsyncResource, resources.AsyncResource)) 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): class TestAsyncResource(resources.AsyncResource):
... ...
@ -505,18 +500,14 @@ class AsyncResourceTest(AsyncTestCase):
TestAsyncResource() TestAsyncResource()
self.assertIn("Can't instantiate abstract class TestAsyncResource", str(context.exception)) 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): class TestAsyncResource(resources.AsyncResource):
async def init(self): async def init(self):
... ...
self.assertTrue(hasattr(TestAsyncResource(), 'shutdown'))
with self.assertRaises(TypeError) as context: self.assertTrue(inspect.iscoroutinefunction(TestAsyncResource.shutdown))
TestAsyncResource()
self.assertIn("Can't instantiate abstract class TestAsyncResource", str(context.exception))
self.assertIn("shutdown", str(context.exception))
def test_init_with_error(self): def test_init_with_error(self):
async def _init(): async def _init():