From b2f6a2cd1af80f9e8a249f93dff4e3d38a4263f8 Mon Sep 17 00:00:00 2001 From: Roman Mogilatov Date: Fri, 4 Nov 2016 20:45:26 +0200 Subject: [PATCH] Commit onging work results --- src/dependency_injector/providers/base.pyx | 15 +- .../providers/callables.pxd | 15 +- .../providers/callables.pyx | 190 ++++++++++++- .../providers/factories.pxd | 7 +- .../providers/factories.pyx | 257 +++++++++++++++++- .../providers/injections.pxd | 46 +++- src/dependency_injector/providers/static.pyx | 5 + .../{test_callable.py => test_callables.py} | 2 +- tests/unit/providers/test_factories.py | 219 +++++++++++++++ ...{test_creational.py => test_singletons.py} | 217 +-------------- tests/unit/providers/test_static.py | 4 +- 11 files changed, 737 insertions(+), 240 deletions(-) rename tests/unit/providers/{test_callable.py => test_callables.py} (99%) create mode 100644 tests/unit/providers/test_factories.py rename tests/unit/providers/{test_creational.py => test_singletons.py} (67%) diff --git a/src/dependency_injector/providers/base.pyx b/src/dependency_injector/providers/base.pyx index 1c9aac95..05049f20 100644 --- a/src/dependency_injector/providers/base.pyx +++ b/src/dependency_injector/providers/base.pyx @@ -72,6 +72,7 @@ cdef class Provider(object): """Initializer.""" self.__overridden = tuple() self.__overridden_len = 0 + super(Provider, self).__init__() def __call__(self, *args, **kwargs): """Return provided object. @@ -96,7 +97,12 @@ cdef class Provider(object): """ return self.__str__() - def override(self, Provider provider): + @property + def overridden(self): + """Return tuple of overriding providers.""" + return self.__overridden + + def override(self, provider): """Override provider with another provider. :param provider: Overriding provider. @@ -114,7 +120,8 @@ cdef class Provider(object): if not is_provider(provider): provider = Object(provider) - self.__overridden += tuple(ensure_is_provider(provider),) + print(self.__overridden, provider) + self.__overridden += (provider,) self.__overridden_len += 1 return OverridingContext(self, provider) @@ -132,7 +139,7 @@ cdef class Provider(object): if self.__overridden_len == 0: raise Error('Provider {0} is not overridden'.format(str(self))) - self.__overridden = self.overridden[:self.__overridden_len - 1] + self.__overridden = self.__overridden[:self.__overridden_len - 1] self.__overridden_len -= 1 def reset_override(self): @@ -141,7 +148,7 @@ cdef class Provider(object): :rtype: None """ self.__overridden = tuple() - self.__overridden_len += 0 + self.__overridden_len = 0 def delegate(self): """Return provider's delegate. diff --git a/src/dependency_injector/providers/callables.pxd b/src/dependency_injector/providers/callables.pxd index caea77a0..357a038e 100644 --- a/src/dependency_injector/providers/callables.pxd +++ b/src/dependency_injector/providers/callables.pxd @@ -4,10 +4,23 @@ Powered by Cython. """ from .base cimport Provider +from .injections cimport ( + PositionalInjection, + NamedInjection, +) + cdef class Callable(Provider): - pass + cdef object __provides + + cdef tuple __args + cdef int __args_len + + cdef tuple __kwargs + cdef int __kwargs_len + + cpdef object _provide(self, tuple args, dict kwargs) cdef class DelegatedCallable(Callable): diff --git a/src/dependency_injector/providers/callables.pyx b/src/dependency_injector/providers/callables.pyx index ecdfe8f3..2ca4d897 100644 --- a/src/dependency_injector/providers/callables.pyx +++ b/src/dependency_injector/providers/callables.pyx @@ -3,12 +3,200 @@ Powered by Cython. """ +from dependency_injector.errors import Error + from .base cimport Provider +from .injections cimport ( + PositionalInjection, + NamedInjection, + parse_positional_injections, + parse_named_injections, + __provide_positional_args, + __provide_keyword_args, +) +from .utils import represent_provider cdef class Callable(Provider): - pass + r"""Callable provider calls wrapped callable on every call. + + Callable supports positional and keyword argument injections: + + .. code-block:: python + + some_function = Callable(some_function, + 'positional_arg1', 'positional_arg2', + keyword_argument1=3, keyword_argument=4) + + # or + + some_function = Callable(some_function) \ + .add_args('positional_arg1', 'positional_arg2') \ + .add_kwargs(keyword_argument1=3, keyword_argument=4) + + # or + + some_function = Callable(some_function) + some_function.add_args('positional_arg1', 'positional_arg2') + some_function.add_kwargs(keyword_argument1=3, keyword_argument=4) + """ + + def __init__(self, provides, *args, **kwargs): + """Initializer. + + :param provides: Wrapped callable. + :type provides: callable + + :param args: Tuple of positional argument injections. + :type args: tuple[object] + + :param kwargs: Dictionary of context keyword argument injections. + :type kwargs: dict[str, object] + """ + if not callable(provides): + raise Error('Provider {0} expected to get callable, ' + 'got {0}'.format('.'.join((self.__class__.__module__, + self.__class__.__name__)), + provides)) + self.__provides = provides + + self.__args = tuple() + self.__args_len = 0 + self.set_args(*args) + + self.__kwargs = tuple() + self.__kwargs_len = 0 + self.set_kwargs(**kwargs) + + super(Callable, self).__init__() + + def __str__(self): + """Return string representation of provider. + + :rtype: str + """ + return represent_provider(provider=self, provides=self.__provides) + + @property + def provides(self): + """Return wrapped callable.""" + return self.__provides + + @property + def args(self): + """Return positional argument injections.""" + cdef int index + cdef PositionalInjection arg + cdef list args + + args = list() + for index in range(self.__args_len): + arg = self.__args[index] + args.append(arg.__value) + return tuple(args) + + def add_args(self, *args): + """Add postional argument injections. + + :param args: Tuple of injections. + :type args: tuple + + :return: Reference ``self`` + """ + self.__args += parse_positional_injections(args) + self.__args_len = len(self.__args) + return self + + def set_args(self, *args): + """Set postional argument injections. + + Existing positional argument injections are dropped. + + :param args: Tuple of injections. + :type args: tuple + + :return: Reference ``self`` + """ + self.__args = parse_positional_injections(args) + self.__args_len = len(self.__args) + return self + + def clear_args(self): + """Drop postional argument injections. + + :return: Reference ``self`` + """ + self.__args = tuple() + self.__args_len = len(self.__args) + return self + + @property + def kwargs(self): + """Return keyword argument injections.""" + cdef int index + cdef NamedInjection arg + cdef dict kwargs + + kwargs = dict() + for index in range(self.__args_len): + arg = self.__args[index] + kwargs[arg.__name] = arg.__value + return kwargs + + def add_kwargs(self, **kwargs): + """Add keyword argument injections. + + :param kwargs: Dictionary of injections. + :type kwargs: dict + + :return: Reference ``self`` + """ + self.__kwargs += parse_named_injections(kwargs) + self.__kwargs_len = len(self.__kwargs) + return self + + def set_kwargs(self, **kwargs): + """Set keyword argument injections. + + Existing keyword argument injections are dropped. + + :param kwargs: Dictionary of injections. + :type kwargs: dict + + :return: Reference ``self`` + """ + self.__kwargs = parse_named_injections(kwargs) + self.__kwargs_len = len(self.__kwargs) + return self + + def clear_kwargs(self): + """Drop keyword argument injections. + + :return: Reference ``self`` + """ + self.__kwargs = tuple() + self.__kwargs_len = len(self.__kwargs) + return self + + cpdef object _provide(self, tuple args, dict kwargs): + """Return result of provided callable's call.""" + cdef tuple positional_args + cdef dict keyword_args + + positional_args = __provide_positional_args(args, + self.__args, + self.__args_len) + keyword_args = __provide_keyword_args(kwargs, + self.__kwargs, + self.__kwargs_len) + + return self.__provides(*positional_args, **keyword_args) cdef class DelegatedCallable(Callable): + """Callable that is injected "as is". + + DelegatedCallable is a :py:class:`Callable`, that is injected "as is". + """ + __IS_DELEGATED__ = True diff --git a/src/dependency_injector/providers/factories.pxd b/src/dependency_injector/providers/factories.pxd index 44e730c2..28e3d354 100644 --- a/src/dependency_injector/providers/factories.pxd +++ b/src/dependency_injector/providers/factories.pxd @@ -7,7 +7,12 @@ from .base cimport Provider cdef class Factory(Provider): - pass + cdef object __instantiator + + cdef tuple __attributes + cdef int __attributes_len + + cpdef object _provide(self, tuple args, dict kwargs) cdef class DelegatedFactory(Factory): diff --git a/src/dependency_injector/providers/factories.pyx b/src/dependency_injector/providers/factories.pyx index ba9b5187..607f9319 100644 --- a/src/dependency_injector/providers/factories.pyx +++ b/src/dependency_injector/providers/factories.pyx @@ -3,12 +3,267 @@ Powered by Cython. """ +from dependency_injector.errors import Error + from .base cimport Provider +from .callables cimport Callable +from .injections cimport ( + PositionalInjection, + NamedInjection, + parse_positional_injections, + parse_named_injections, + __provide_positional_args, + __provide_keyword_args, + __inject_attributes, +) +from .utils import represent_provider cdef class Factory(Provider): - pass + r"""Factory provider creates new instance on every call. + + :py:class:`Factory` supports positional & keyword argument injections, + as well as attribute injections. + + Positional and keyword argument injections could be defined like this: + + .. code-block:: python + + factory = Factory(SomeClass, + 'positional_arg1', 'positional_arg2', + keyword_argument1=3, keyword_argument=4) + + # or + + factory = Factory(SomeClass) \ + .add_args('positional_arg1', 'positional_arg2') \ + .add_kwargs(keyword_argument1=3, keyword_argument=4) + + # or + + factory = Factory(SomeClass) + factory.add_args('positional_arg1', 'positional_arg2') + factory.add_kwargs(keyword_argument1=3, keyword_argument=4) + + + Attribute injections are defined by using :py:meth:`Factory.attributes`: + + .. code-block:: python + + factory = Factory(SomeClass) \ + .add_attributes(attribute1=1, attribute2=2) + + Retrieving of provided instance can be performed via calling + :py:class:`Factory` object: + + .. code-block:: python + + factory = Factory(SomeClass) + some_object = factory() + + .. py:attribute:: provided_type + + If provided type is defined, provider checks that providing class is + its subclass. + + :type: type | None + """ + + provided_type = None + + def __init__(self, provides, *args, **kwargs): + """Initializer. + + :param provides: Provided type. + :type provides: type + + :param args: Tuple of positional argument injections. + :type args: tuple[object] + + :param kwargs: Dictionary of context keyword argument injections. + :type kwargs: dict[str, object] + """ + if (self.__class__.provided_type and + not issubclass(provides, self.__class__.provided_type)): + raise Error('{0} can provide only {1} instances'.format( + self.__class__, self.__class__.provided_type)) + + self.__instantiator = Callable(provides) + + self.__attributes = tuple() + self.__attributes_len = 0 + + self.set_args(*args) + self.set_kwargs(**kwargs) + + super(Factory, self).__init__() + + + def __str__(self): + """Return string representation of provider. + + :rtype: str + """ + return represent_provider(provider=self, + provides=self.__instantiator.provides) + + @property + def cls(self): + """Return provided type.""" + return self.__instantiator.provides + + @property + def args(self): + """Return positional argument injections.""" + return self.__instantiator.args + + def add_args(self, *args): + """Add __init__ postional argument injections. + + :param args: Tuple of injections. + :type args: tuple + + :return: Reference ``self`` + """ + self.__instantiator.add_args(*args) + return self + + def set_args(self, *args): + """Set __init__ postional argument injections. + + Existing __init__ positional argument injections are dropped. + + :param args: Tuple of injections. + :type args: tuple + + :return: Reference ``self`` + """ + self.__instantiator.set_args(*args) + return self + + def clear_args(self): + """Drop __init__ postional argument injections. + + :return: Reference ``self`` + """ + self.__instantiator.clear_args() + return self + + @property + def kwargs(self): + """Return keyword argument injections.""" + return self.__instantiator.kwargs + + def add_kwargs(self, **kwargs): + """Add __init__ keyword argument injections. + + :param kwargs: Dictionary of injections. + :type kwargs: dict + + :return: Reference ``self`` + """ + self.__instantiator.add_kwargs(**kwargs) + return self + + def set_kwargs(self, **kwargs): + """Set __init__ keyword argument injections. + + Existing __init__ keyword argument injections are dropped. + + :param kwargs: Dictionary of injections. + :type kwargs: dict + + :return: Reference ``self`` + """ + self.__instantiator.set_kwargs(**kwargs) + return self + + def clear_kwargs(self): + """Drop __init__ keyword argument injections. + + :return: Reference ``self`` + """ + self.__instantiator.clear_kwargs() + return self + + @property + def attributes(self): + """Return attribute injections.""" + cdef int index + cdef NamedInjection attribute + cdef dict attributes + + attributes = dict() + for index in range(self.__args_len): + attribute = self.__args[index] + attributes[attribute.__name] = attribute.__value + return attributes + + def add_attributes(self, **kwargs): + """Add attribute injections. + + :param args: Tuple of injections. + :type args: tuple + + :return: Reference ``self`` + """ + self.__attributes += parse_named_injections(kwargs) + self.__attributes_len = len(self.__attributes) + return self + + def set_attributes(self, **kwargs): + """Set attribute injections. + + Existing attribute injections are dropped. + + :param args: Tuple of injections. + :type args: tuple + + :return: Reference ``self`` + """ + self.__attributes = parse_named_injections(kwargs) + self.__attributes_len = len(self.__attributes) + return self + + def clear_attributes(self): + """Drop attribute injections. + + :return: Reference ``self`` + """ + self.__attributes = tuple() + self.__attributes_len = len(self.__attributes) + return self + + cpdef object _provide(self, tuple args, dict kwargs): + """Return new instance.""" + cdef object instance + + instance = self.__instantiator._provide(args, kwargs) + + if self.__attributes_len > 0: + __inject_attributes(instance, + self.__attributes, + self.__attributes_len) + + return instance cdef class DelegatedFactory(Factory): + """Factory that is injected "as is". + + .. py:attribute:: provided_type + + If provided type is defined, provider checks that providing class is + its subclass. + + :type: type | None + + .. py:attribute:: cls + + Class that provides object. + Alias for :py:attr:`provides`. + + :type: type + """ + __IS_DELEGATED__ = True diff --git a/src/dependency_injector/providers/injections.pxd b/src/dependency_injector/providers/injections.pxd index 38682403..66a9ed2b 100644 --- a/src/dependency_injector/providers/injections.pxd +++ b/src/dependency_injector/providers/injections.pxd @@ -40,9 +40,9 @@ cdef class NamedInjection(Injection): @cython.boundscheck(False) @cython.wraparound(False) -cdef inline tuple __provide_positional_args(tuple inj_args, - int inj_args_len, - tuple args): +cdef inline tuple __provide_positional_args(tuple args, + tuple inj_args, + int inj_args_len): cdef int index cdef list positional_args cdef PositionalInjection injection @@ -56,26 +56,46 @@ cdef inline tuple __provide_positional_args(tuple inj_args, positional_args.append(injection.get_value()) positional_args.extend(args) - return positional_args + return tuple(positional_args) @cython.boundscheck(False) @cython.wraparound(False) -cdef inline dict __provide_keyword_args(tuple inj_kwargs, - int inj_kwargs_len, - dict kwargs): +cdef inline dict __provide_keyword_args(dict kwargs, + tuple inj_kwargs, + int inj_kwargs_len): cdef int index + cdef object name + cdef int kwargs_len cdef NamedInjection kw_injection - if inj_kwargs_len == 0: - return kwargs - - for index in range(inj_kwargs_len): - kw_injection = inj_kwargs[index] - kwargs[kw_injection.get_name()] = kw_injection.get_value() + kwargs_len = len(kwargs) + if kwargs_len == 0: + for index in range(inj_kwargs_len): + kw_injection = inj_kwargs[index] + kwargs[kw_injection.get_name()] = kw_injection.get_value() + else: + for index in range(inj_kwargs_len): + kw_injection = inj_kwargs[index] + name = kw_injection.get_name() + if name not in kwargs: + kwargs[name] = kw_injection.get_value() return kwargs +@cython.boundscheck(False) +@cython.wraparound(False) +cdef inline object __inject_attributes(object instance, + tuple attributes, + int attributes_len): + cdef NamedInjection attr_injection + for index in range(attributes_len): + attr_injection = attributes[index] + setattr(instance, + attr_injection.get_name(), + attr_injection.get_value()) + + cpdef tuple parse_positional_injections(tuple args) cpdef tuple parse_named_injections(dict kwargs) diff --git a/src/dependency_injector/providers/static.pyx b/src/dependency_injector/providers/static.pyx index cd4f4b1a..aed1b69a 100644 --- a/src/dependency_injector/providers/static.pyx +++ b/src/dependency_injector/providers/static.pyx @@ -149,6 +149,11 @@ cdef class ExternalDependency(Provider): """ return self.__str__() + @property + def instance_of(self): + """Return class of required dependency.""" + return self.__instance_of + def provided_by(self, provider): """Set external dependency provider. diff --git a/tests/unit/providers/test_callable.py b/tests/unit/providers/test_callables.py similarity index 99% rename from tests/unit/providers/test_callable.py rename to tests/unit/providers/test_callables.py index a9a8ec48..e1d8ecad 100644 --- a/tests/unit/providers/test_callable.py +++ b/tests/unit/providers/test_callables.py @@ -70,7 +70,7 @@ class CallableTests(unittest.TestCase): provider = providers.Callable(self.example) self.assertEqual(repr(provider), - ''.format( repr(self.example), hex(id(provider)))) diff --git a/tests/unit/providers/test_factories.py b/tests/unit/providers/test_factories.py new file mode 100644 index 00000000..3461fd35 --- /dev/null +++ b/tests/unit/providers/test_factories.py @@ -0,0 +1,219 @@ +"""Dependency injector factory providers unit tests.""" + +import unittest2 as unittest + +from dependency_injector import ( + providers, + errors, +) + + +class Example(object): + + def __init__(self, init_arg1=None, init_arg2=None, init_arg3=None, + init_arg4=None): + self.init_arg1 = init_arg1 + self.init_arg2 = init_arg2 + self.init_arg3 = init_arg3 + self.init_arg4 = init_arg4 + + self.attribute1 = None + self.attribute2 = None + + +class FactoryTests(unittest.TestCase): + + def test_is_provider(self): + self.assertTrue(providers.is_provider(providers.Factory(Example))) + + def test_init_with_callable(self): + self.assertTrue(providers.Factory(credits)) + + def test_init_with_not_callable(self): + self.assertRaises(errors.Error, providers.Factory, 123) + + def test_init_with_valid_provided_type(self): + class ExampleProvider(providers.Factory): + provided_type = Example + + example_provider = ExampleProvider(Example, 1, 2) + + self.assertIsInstance(example_provider(), Example) + + def test_init_with_valid_provided_subtype(self): + class ExampleProvider(providers.Factory): + provided_type = Example + + class NewExampe(Example): + pass + + example_provider = ExampleProvider(NewExampe, 1, 2) + + self.assertIsInstance(example_provider(), NewExampe) + + def test_init_with_invalid_provided_type(self): + class ExampleProvider(providers.Factory): + provided_type = Example + + with self.assertRaises(errors.Error): + ExampleProvider(list) + + def test_call(self): + provider = providers.Factory(Example) + + instance1 = provider() + instance2 = provider() + + self.assertIsNot(instance1, instance2) + self.assertIsInstance(instance1, Example) + self.assertIsInstance(instance2, Example) + + def test_call_with_init_positional_args(self): + provider = providers.Factory(Example, 'i1', 'i2') + + instance1 = provider() + instance2 = provider() + + self.assertEqual(instance1.init_arg1, 'i1') + self.assertEqual(instance1.init_arg2, 'i2') + + self.assertEqual(instance2.init_arg1, 'i1') + self.assertEqual(instance2.init_arg2, 'i2') + + self.assertIsNot(instance1, instance2) + self.assertIsInstance(instance1, Example) + self.assertIsInstance(instance2, Example) + + def test_call_with_init_keyword_args(self): + provider = providers.Factory(Example, init_arg1='i1', init_arg2='i2') + + instance1 = provider() + instance2 = provider() + + self.assertEqual(instance1.init_arg1, 'i1') + self.assertEqual(instance1.init_arg2, 'i2') + + self.assertEqual(instance2.init_arg1, 'i1') + self.assertEqual(instance2.init_arg2, 'i2') + + self.assertIsNot(instance1, instance2) + self.assertIsInstance(instance1, Example) + self.assertIsInstance(instance2, Example) + + def test_call_with_init_positional_and_keyword_args(self): + provider = providers.Factory(Example, 'i1', init_arg2='i2') + + instance1 = provider() + instance2 = provider() + + self.assertEqual(instance1.init_arg1, 'i1') + self.assertEqual(instance1.init_arg2, 'i2') + + self.assertEqual(instance2.init_arg1, 'i1') + self.assertEqual(instance2.init_arg2, 'i2') + + self.assertIsNot(instance1, instance2) + self.assertIsInstance(instance1, Example) + self.assertIsInstance(instance2, Example) + + def test_call_with_attributes(self): + provider = providers.Factory(Example) + provider.add_attributes(attribute1='a1', attribute2='a2') + + instance1 = provider() + instance2 = provider() + + self.assertEqual(instance1.attribute1, 'a1') + self.assertEqual(instance1.attribute2, 'a2') + + self.assertEqual(instance2.attribute1, 'a1') + self.assertEqual(instance2.attribute2, 'a2') + + self.assertIsNot(instance1, instance2) + self.assertIsInstance(instance1, Example) + self.assertIsInstance(instance2, Example) + + def test_call_with_context_args(self): + provider = providers.Factory(Example, 11, 22) + + instance = provider(33, 44) + + self.assertEqual(instance.init_arg1, 11) + self.assertEqual(instance.init_arg2, 22) + self.assertEqual(instance.init_arg3, 33) + self.assertEqual(instance.init_arg4, 44) + + def test_call_with_context_kwargs(self): + provider = providers.Factory(Example, init_arg1=1) + + instance1 = provider(init_arg2=22) + self.assertEqual(instance1.init_arg1, 1) + self.assertEqual(instance1.init_arg2, 22) + + instance2 = provider(init_arg1=11, init_arg2=22) + self.assertEqual(instance2.init_arg1, 11) + self.assertEqual(instance2.init_arg2, 22) + + def test_call_with_context_args_and_kwargs(self): + provider = providers.Factory(Example, 11) + + instance = provider(22, init_arg3=33, init_arg4=44) + + self.assertEqual(instance.init_arg1, 11) + self.assertEqual(instance.init_arg2, 22) + self.assertEqual(instance.init_arg3, 33) + self.assertEqual(instance.init_arg4, 44) + + def test_fluent_interface(self): + provider = providers.Factory(Example) \ + .add_args(1, 2) \ + .add_kwargs(init_arg3=3, init_arg4=4) \ + .add_attributes(attribute1=5, attribute2=6) + + instance = provider() + + self.assertEqual(instance.init_arg1, 1) + self.assertEqual(instance.init_arg2, 2) + self.assertEqual(instance.init_arg3, 3) + self.assertEqual(instance.init_arg4, 4) + self.assertEqual(instance.attribute1, 5) + self.assertEqual(instance.attribute2, 6) + + def test_call_overridden(self): + provider = providers.Factory(Example) + overriding_provider1 = providers.Factory(dict) + overriding_provider2 = providers.Factory(list) + + provider.override(overriding_provider1) + provider.override(overriding_provider2) + + instance1 = provider() + instance2 = provider() + + self.assertIsNot(instance1, instance2) + self.assertIsInstance(instance1, list) + self.assertIsInstance(instance2, list) + + def test_repr(self): + provider = providers.Factory(Example) + + self.assertEqual(repr(provider), + ''.format( + repr(Example), + hex(id(provider)))) + + +class DelegatedFactoryTests(unittest.TestCase): + + def test_inheritance(self): + self.assertIsInstance(providers.DelegatedFactory(object), + providers.Factory) + + def test_is_provider(self): + self.assertTrue( + providers.is_provider(providers.DelegatedFactory(object))) + + def test_is_delegated_provider(self): + self.assertTrue( + providers.is_delegated(providers.DelegatedFactory(object))) diff --git a/tests/unit/providers/test_creational.py b/tests/unit/providers/test_singletons.py similarity index 67% rename from tests/unit/providers/test_creational.py rename to tests/unit/providers/test_singletons.py index ed13215e..f6050dd5 100644 --- a/tests/unit/providers/test_creational.py +++ b/tests/unit/providers/test_singletons.py @@ -1,4 +1,4 @@ -"""Dependency injector creational providers unit tests.""" +"""Dependency injector singleton providers unit tests.""" import unittest2 as unittest @@ -21,204 +21,6 @@ class Example(object): self.attribute2 = None -class FactoryTests(unittest.TestCase): - - def test_is_provider(self): - self.assertTrue(providers.is_provider(providers.Factory(Example))) - - def test_init_with_callable(self): - self.assertTrue(providers.Factory(credits)) - - def test_init_with_not_callable(self): - self.assertRaises(errors.Error, providers.Factory, 123) - - def test_init_with_valid_provided_type(self): - class ExampleProvider(providers.Factory): - provided_type = Example - - example_provider = ExampleProvider(Example, 1, 2) - - self.assertIsInstance(example_provider(), Example) - - def test_init_with_valid_provided_subtype(self): - class ExampleProvider(providers.Factory): - provided_type = Example - - class NewExampe(Example): - pass - - example_provider = ExampleProvider(NewExampe, 1, 2) - - self.assertIsInstance(example_provider(), NewExampe) - - def test_init_with_invalid_provided_type(self): - class ExampleProvider(providers.Factory): - provided_type = Example - - with self.assertRaises(errors.Error): - ExampleProvider(list) - - def test_call(self): - provider = providers.Factory(Example) - - instance1 = provider() - instance2 = provider() - - self.assertIsNot(instance1, instance2) - self.assertIsInstance(instance1, Example) - self.assertIsInstance(instance2, Example) - - def test_call_with_init_positional_args(self): - provider = providers.Factory(Example, 'i1', 'i2') - - instance1 = provider() - instance2 = provider() - - self.assertEqual(instance1.init_arg1, 'i1') - self.assertEqual(instance1.init_arg2, 'i2') - - self.assertEqual(instance2.init_arg1, 'i1') - self.assertEqual(instance2.init_arg2, 'i2') - - self.assertIsNot(instance1, instance2) - self.assertIsInstance(instance1, Example) - self.assertIsInstance(instance2, Example) - - def test_call_with_init_keyword_args(self): - provider = providers.Factory(Example, init_arg1='i1', init_arg2='i2') - - instance1 = provider() - instance2 = provider() - - self.assertEqual(instance1.init_arg1, 'i1') - self.assertEqual(instance1.init_arg2, 'i2') - - self.assertEqual(instance2.init_arg1, 'i1') - self.assertEqual(instance2.init_arg2, 'i2') - - self.assertIsNot(instance1, instance2) - self.assertIsInstance(instance1, Example) - self.assertIsInstance(instance2, Example) - - def test_call_with_init_positional_and_keyword_args(self): - provider = providers.Factory(Example, 'i1', init_arg2='i2') - - instance1 = provider() - instance2 = provider() - - self.assertEqual(instance1.init_arg1, 'i1') - self.assertEqual(instance1.init_arg2, 'i2') - - self.assertEqual(instance2.init_arg1, 'i1') - self.assertEqual(instance2.init_arg2, 'i2') - - self.assertIsNot(instance1, instance2) - self.assertIsInstance(instance1, Example) - self.assertIsInstance(instance2, Example) - - def test_call_with_attributes(self): - provider = providers.Factory(Example) - provider.add_attributes(attribute1='a1', attribute2='a2') - - instance1 = provider() - instance2 = provider() - - self.assertEqual(instance1.attribute1, 'a1') - self.assertEqual(instance1.attribute2, 'a2') - - self.assertEqual(instance2.attribute1, 'a1') - self.assertEqual(instance2.attribute2, 'a2') - - self.assertIsNot(instance1, instance2) - self.assertIsInstance(instance1, Example) - self.assertIsInstance(instance2, Example) - - def test_call_with_context_args(self): - provider = providers.Factory(Example, 11, 22) - - instance = provider(33, 44) - - self.assertEqual(instance.init_arg1, 11) - self.assertEqual(instance.init_arg2, 22) - self.assertEqual(instance.init_arg3, 33) - self.assertEqual(instance.init_arg4, 44) - - def test_call_with_context_kwargs(self): - provider = providers.Factory(Example, init_arg1=1) - - instance1 = provider(init_arg2=22) - self.assertEqual(instance1.init_arg1, 1) - self.assertEqual(instance1.init_arg2, 22) - - instance2 = provider(init_arg1=11, init_arg2=22) - self.assertEqual(instance2.init_arg1, 11) - self.assertEqual(instance2.init_arg2, 22) - - def test_call_with_context_args_and_kwargs(self): - provider = providers.Factory(Example, 11) - - instance = provider(22, init_arg3=33, init_arg4=44) - - self.assertEqual(instance.init_arg1, 11) - self.assertEqual(instance.init_arg2, 22) - self.assertEqual(instance.init_arg3, 33) - self.assertEqual(instance.init_arg4, 44) - - def test_fluent_interface(self): - provider = providers.Factory(Example) \ - .add_args(1, 2) \ - .add_kwargs(init_arg3=3, init_arg4=4) \ - .add_attributes(attribute1=5, attribute2=6) - - instance = provider() - - self.assertEqual(instance.init_arg1, 1) - self.assertEqual(instance.init_arg2, 2) - self.assertEqual(instance.init_arg3, 3) - self.assertEqual(instance.init_arg4, 4) - self.assertEqual(instance.attribute1, 5) - self.assertEqual(instance.attribute2, 6) - - def test_call_overridden(self): - provider = providers.Factory(Example) - overriding_provider1 = providers.Factory(dict) - overriding_provider2 = providers.Factory(list) - - provider.override(overriding_provider1) - provider.override(overriding_provider2) - - instance1 = provider() - instance2 = provider() - - self.assertIsNot(instance1, instance2) - self.assertIsInstance(instance1, list) - self.assertIsInstance(instance2, list) - - def test_repr(self): - provider = providers.Factory(Example) - - self.assertEqual(repr(provider), - ''.format( - repr(Example), - hex(id(provider)))) - - -class DelegatedFactoryTests(unittest.TestCase): - - def test_inheritance(self): - self.assertIsInstance(providers.DelegatedFactory(object), - providers.Factory) - - def test_is_provider(self): - self.assertTrue( - providers.is_provider(providers.DelegatedFactory(object))) - - def test_is_delegated_provider(self): - provider = providers.DelegatedFactory(object) - self.assertIs(provider.provide_injection(), provider) - - class SingletonTests(unittest.TestCase): def test_is_provider(self): @@ -643,20 +445,3 @@ class DelegatedThreadLocalSingletonTests(unittest.TestCase): def test_is_delegated_provider(self): provider = providers.DelegatedThreadLocalSingleton(object) self.assertIs(provider.provide_injection(), provider) - - -class FactoryAsDecoratorTests(unittest.TestCase): - - def test_decoration_and_overriding(self): - @providers.Factory - class AuthService(object): - pass - - @providers.override(AuthService) - @providers.Factory - class ExtAuthService(AuthService.cls): - pass - - auth_service = AuthService() - - self.assertIsInstance(auth_service, ExtAuthService.cls) diff --git a/tests/unit/providers/test_static.py b/tests/unit/providers/test_static.py index 7395ba9e..47e568b0 100644 --- a/tests/unit/providers/test_static.py +++ b/tests/unit/providers/test_static.py @@ -38,13 +38,13 @@ class DelegateTests(unittest.TestCase): def setUp(self): self.delegated = providers.Provider() - self.delegate = providers.Delegate(delegated=self.delegated) + self.delegate = providers.Delegate(self.delegated) def test_is_provider(self): self.assertTrue(providers.is_provider(self.delegate)) def test_init_with_not_provider(self): - self.assertRaises(errors.Error, providers.Delegate, delegated=object()) + self.assertRaises(errors.Error, providers.Delegate, object()) def test_call(self): delegated1 = self.delegate()