Implement lazy initialization and improve copying for Dependency provider

This commit is contained in:
Roman Mogylatov 2021-03-09 07:58:01 -05:00
parent f7fcb22139
commit 17ecd6c8c0
4 changed files with 7335 additions and 7179 deletions

File diff suppressed because it is too large Load Diff

View File

@ -102,10 +102,15 @@ class Delegate(Provider[Provider]):
class Dependency(Provider[T]):
def __init__(self, instance_of: Type[T] = object, default: Optional[Union[Provider, Any]] = None) -> None: ...
def __getattr__(self, name: str) -> Any: ...
@property
def instance_of(self) -> Type[T]: ...
def set_instance_of(self, instance_of: Type[T]) -> Dependency[T]: ...
@property
def default(self) -> Provider[T]: ...
def set_default(self, default: Optional[Union[Provider, Any]]) -> Dependency[T]: ...
@property
def is_defined(self) -> bool: ...
def provided_by(self, provider: Provider) -> OverridingContext[P]: ...

View File

@ -619,20 +619,13 @@ cdef class Dependency(Provider):
:type: type
"""
def __init__(self, object instance_of=object, default=UNDEFINED):
"""Initializer."""
if not isinstance(instance_of, CLASS_TYPES):
raise TypeError(
'Argument \'instance_of\' has incorrect type (expected {0}, got {1}))'.format(
CLASS_TYPES,
instance_of,
)
)
self.__instance_of = instance_of
def __init__(self, object instance_of=object, default=None):
"""Initialize provider."""
self.__instance_of = None
self.set_instance_of(instance_of)
if default is not UNDEFINED and not isinstance(default, Provider):
default = Object(default)
self.__default = default
self.__default = None
self.set_default(default)
self.__parent = None
@ -644,14 +637,9 @@ cdef class Dependency(Provider):
if copied is not None:
return copied
copied_default = (
deepcopy(self.__default, memo)
if self.__default is not UNDEFINED
else UNDEFINED
)
copied = self.__class__(self.__instance_of, copied_default)
memo[id(self)] = copied
copied = _memorized_duplicate(self, memo)
copied.set_instance_of(self.instance_of)
copied.set_default(deepcopy(self.default, memo))
self._copy_parent(copied, memo)
self._copy_overridings(copied, memo)
@ -667,7 +655,7 @@ cdef class Dependency(Provider):
"""
if self.__last_overriding:
result = self.__last_overriding(*args, **kwargs)
elif not self.__last_overriding and self.__default is not UNDEFINED:
elif self.__default:
result = self.__default(*args, **kwargs)
else:
self._raise_undefined_error()
@ -700,7 +688,7 @@ cdef class Dependency(Provider):
def __getattr__(self, name):
if self.__last_overriding:
return getattr(self.__last_overriding, name)
elif self.__default is not UNDEFINED:
elif self.__default:
return getattr(self.__default, name)
raise AttributeError(f'Provider "{self.__class__.__name__}" has no attribute "{name}"')
@ -725,18 +713,37 @@ cdef class Dependency(Provider):
@property
def instance_of(self):
"""Return class of required dependency."""
"""Return type."""
return self.__instance_of
def set_instance_of(self, instance_of):
"""Set type."""
if not isinstance(instance_of, CLASS_TYPES):
raise TypeError(
'"instance_of" has incorrect type (expected {0}, got {1}))'.format(
CLASS_TYPES,
instance_of,
),
)
self.__instance_of = instance_of
return self
@property
def default(self):
"""Return default provider."""
return self.__default
def set_default(self, default):
"""Set type."""
if default and not isinstance(default, Provider):
default = Object(default)
self.__default = default
return self
@property
def is_defined(self):
"""Return True if dependency is defined."""
return self.__last_overriding or self.__default is not UNDEFINED
return self.__last_overriding or self.__default
def provided_by(self, provider):
"""Set external dependency provider.
@ -751,7 +758,7 @@ cdef class Dependency(Provider):
@property
def related(self):
"""Return related providers generator."""
if self.__default is not UNDEFINED:
if self.__default:
yield self.__default
yield from super().related

View File

@ -335,6 +335,24 @@ class DependencyTests(unittest.TestCase):
def setUp(self):
self.provider = providers.Dependency(instance_of=list)
def test_init_optional(self):
list_provider = providers.List(1, 2, 3)
provider = providers.Dependency()
provider.set_instance_of(list)
provider.set_default(list_provider)
self.assertIs(provider.instance_of, list)
self.assertIs(provider.default, list_provider)
self.assertEqual(provider(), [1, 2, 3])
def test_set_instance_of_returns_self(self):
provider = providers.Dependency()
self.assertIs(provider.set_instance_of(list), provider)
def test_set_default_returns_self(self):
provider = providers.Dependency()
self.assertIs(provider.set_default(providers.Provider()), provider)
def test_init_with_not_class(self):
self.assertRaises(TypeError, providers.Dependency, object())