diff --git a/dependency_injector/injections.py b/dependency_injector/injections.py index 27f6cfc6..02b1400e 100644 --- a/dependency_injector/injections.py +++ b/dependency_injector/injections.py @@ -1,13 +1,15 @@ """Injections module.""" +import itertools + import six from dependency_injector.utils import ( is_provider, - is_delegated_provider, is_injection, is_arg_injection, is_kwarg_injection, + is_delegated_provider, fetch_cls_init, ) @@ -246,18 +248,20 @@ def inject(*args, **kwargs): def _parse_args_injections(args): - """Parse positional argument injections according to current syntax.""" return tuple(Arg(arg) if not is_injection(arg) else arg for arg in args if not is_injection(arg) or is_arg_injection(arg)) def _parse_kwargs_injections(args, kwargs): - """Parse keyword argument injections according to current syntax.""" kwarg_injections = tuple(injection for injection in args if is_kwarg_injection(injection)) if kwargs: - kwarg_injections += tuple(KwArg(name, value) - for name, value in six.iteritems(kwargs)) + kwarg_injections += tuple(itertools.starmap(KwArg, + six.iteritems(kwargs))) return kwarg_injections + + +def _parse_attribute_injections(attributes): + return tuple(itertools.starmap(Attribute, six.iteritems(attributes))) diff --git a/dependency_injector/providers/callable.py b/dependency_injector/providers/callable.py index a69f70eb..3093927b 100644 --- a/dependency_injector/providers/callable.py +++ b/dependency_injector/providers/callable.py @@ -13,27 +13,18 @@ from dependency_injector.errors import Error @six.python_2_unicode_compatible class Callable(Provider): - """:py:class:`Callable` provider calls wrapped callable on every call. + r""":py:class:`Callable` provider calls wrapped callable on every call. :py:class:`Callable` provider provides callable that is called on every provider call with some predefined dependency injections. - :py:class:`Callable` syntax of passing injections is the same like - :py:class:`Factory` one: + :py:class:`Callable` supports positional and keyword argument injections: .. code-block:: python - # simplified syntax for passing positional and keyword argument - # injections: - some_function = Callable(some_function, 'arg1', 'arg2', arg3=3, arg4=4) - - # extended (full) syntax for passing positional and keyword argument - # injections: - some_function = Callable(some_function, - injections.Arg(1), - injections.Arg(2), - injections.KwArg('some_arg', 3), - injections.KwArg('other_arg', 4)) + some_function = Callable(some_function) \ + .args('arg1', 'arg2') \ + .kwargs(arg3=3, arg4=4) .. py:attribute:: provides @@ -41,32 +32,26 @@ class Callable(Provider): :type: callable - .. py:attribute:: args + .. py:attribute:: _args Tuple of positional argument injections. :type: tuple[:py:class:`dependency_injector.injections.Arg`] - .. py:attribute:: kwargs + .. py:attribute:: _kwargs Tuple of keyword argument injections. :type: tuple[:py:class:`dependency_injector.injections.KwArg`] """ - __slots__ = ('provides', 'args', 'kwargs') + __slots__ = ('provides', '_args', '_kwargs') - def __init__(self, provides, *args, **kwargs): + def __init__(self, provides): """Initializer. :param provides: Wrapped callable. :type provides: callable - - :param args: Tuple of injections. - :type args: tuple - - :param kwargs: Dictionary of injections. - :type kwargs: dict """ if not callable(provides): raise Error('Provider {0} expected to get callable, ' @@ -76,10 +61,8 @@ class Callable(Provider): self.provides = provides - self.args = tuple() - self.kwargs = tuple() - - self.add_injections(*args, **kwargs) + self._args = tuple() + self._kwargs = tuple() super(Callable, self).__init__() @@ -89,19 +72,29 @@ class Callable(Provider): :rtype: tuple[:py:class:`dependency_injector.injections.Injection`] """ - return self.args + self.kwargs + return self._args + self._kwargs - def add_injections(self, *args, **kwargs): - """Add provider injections. + def args(self, *args): + """Add postional argument injections. :param args: Tuple of injections. :type args: tuple + :return: Reference ``self`` + """ + self._args += _parse_args_injections(args) + return self + + def kwargs(self, **kwargs): + """Add keyword argument injections. + :param kwargs: Dictionary of injections. :type kwargs: dict + + :return: Reference ``self`` """ - self.args += _parse_args_injections(args) - self.kwargs += _parse_kwargs_injections(args, kwargs) + self._kwargs += _parse_kwargs_injections(tuple(), kwargs) + return self def _provide(self, *args, **kwargs): """Return provided instance. @@ -114,10 +107,10 @@ class Callable(Provider): :rtype: object """ - if self.args: - args = tuple(arg.value for arg in self.args) + args + if self._args: + args = tuple(arg.value for arg in self._args) + args - for kwarg in self.kwargs: + for kwarg in self._kwargs: if kwarg.name not in kwargs: kwargs[kwarg.name] = kwarg.value diff --git a/dependency_injector/providers/creational.py b/dependency_injector/providers/creational.py index cfd2dea3..3069a872 100644 --- a/dependency_injector/providers/creational.py +++ b/dependency_injector/providers/creational.py @@ -1,10 +1,8 @@ """Dependency injector creational providers.""" from dependency_injector.providers.callable import Callable -from dependency_injector.utils import ( - is_attribute_injection, - GLOBAL_LOCK, -) +from dependency_injector.injections import _parse_attribute_injections +from dependency_injector.utils import GLOBAL_LOCK from dependency_injector.errors import Error @@ -79,7 +77,7 @@ class Factory(Callable): provided_type = None - __slots__ = ('cls', 'attributes') + __slots__ = ('cls', '_attributes') def __init__(self, provides, *args, **kwargs): """Initializer. @@ -99,7 +97,7 @@ class Factory(Callable): raise Error('{0} can provide only {1} instances'.format( self.__class__, self.__class__.provided_type)) - self.attributes = tuple() + self._attributes = tuple() super(Factory, self).__init__(provides, *args, **kwargs) @@ -111,22 +109,17 @@ class Factory(Callable): :rtype: tuple[:py:class:`dependency_injector.injections.Injection`] """ - return self.args + self.kwargs + self.attributes + return self._args + self._kwargs + self._attributes - def add_injections(self, *args, **kwargs): - """Add provider injections. - - :param args: Tuple of injections. - :type args: tuple + def attributes(self, **kwargs): + """Add attribute injections. :param kwargs: Dictionary of injections. :type kwargs: dict - """ - self.attributes += tuple(injection - for injection in args - if is_attribute_injection(injection)) - super(Factory, self).add_injections(*args, **kwargs) + :return: Reference ``self`` + """ + self._attributes += _parse_attribute_injections(kwargs) return self def _provide(self, *args, **kwargs): @@ -140,16 +133,16 @@ class Factory(Callable): :rtype: object """ - if self.args: - args = tuple(arg.value for arg in self.args) + args + if self._args: + args = tuple(arg.value for arg in self._args) + args - for kwarg in self.kwargs: + for kwarg in self._kwargs: if kwarg.name not in kwargs: kwargs[kwarg.name] = kwarg.value instance = self.provides(*args, **kwargs) - for attribute in self.attributes: + for attribute in self._attributes: setattr(instance, attribute.name, attribute.value) return instance diff --git a/tests/catalogs/test_declarative.py b/tests/catalogs/test_declarative.py index e3279c2c..0bf2a86d 100644 --- a/tests/catalogs/test_declarative.py +++ b/tests/catalogs/test_declarative.py @@ -382,7 +382,8 @@ class CopyingTests(unittest.TestCase): """Test catalog providers copying.""" class CatalogA(catalogs.DeclarativeCatalog): p11 = providers.Object(0) - p12 = providers.Factory(dict, p11=p11) + p12 = providers.Factory(dict) \ + .kwargs(p11=p11) @catalogs.copy(CatalogA) class CatalogA1(CatalogA): diff --git a/tests/providers/test_callable.py b/tests/providers/test_callable.py index cfaf83df..681599fd 100644 --- a/tests/providers/test_callable.py +++ b/tests/providers/test_callable.py @@ -4,7 +4,6 @@ import unittest2 as unittest from dependency_injector import ( providers, - injections, utils, errors, ) @@ -35,7 +34,9 @@ class CallableTests(unittest.TestCase): New simplified syntax. """ - provider = providers.Callable(self.example, 1, 2, 3, 4) + provider = providers.Callable(self.example) \ + .args(1, 2, 3, 4) + self.assertTupleEqual(provider(), (1, 2, 3, 4)) def test_call_with_keyword_args(self): @@ -43,11 +44,9 @@ class CallableTests(unittest.TestCase): New simplified syntax. """ - provider = providers.Callable(self.example, - arg1=1, - arg2=2, - arg3=3, - arg4=4) + provider = providers.Callable(self.example) \ + .kwargs(arg1=1, arg2=2, arg3=3, arg4=4) + self.assertTupleEqual(provider(), (1, 2, 3, 4)) def test_call_with_positional_and_keyword_args(self): @@ -55,40 +54,37 @@ class CallableTests(unittest.TestCase): Simplified syntax of positional and keyword arg injections. """ - provider = providers.Callable(self.example, 1, 2, arg3=3, arg4=4) - self.assertTupleEqual(provider(), (1, 2, 3, 4)) + provider = providers.Callable(self.example) \ + .args(1, 2) \ + .kwargs(arg3=3, arg4=4) - def test_call_with_positional_and_keyword_args_extended_syntax(self): - """Test call with positional and keyword args. - - Extended syntax of positional and keyword arg injections. - """ - provider = providers.Callable(self.example, - injections.Arg(1), - injections.Arg(2), - injections.KwArg('arg3', 3), - injections.KwArg('arg4', 4)) self.assertTupleEqual(provider(), (1, 2, 3, 4)) def test_call_with_context_args(self): """Test call with context args.""" - provider = providers.Callable(self.example, 1, 2) + provider = providers.Callable(self.example) \ + .args(1, 2) + self.assertTupleEqual(provider(3, 4), (1, 2, 3, 4)) def test_call_with_context_kwargs(self): """Test call with context kwargs.""" - provider = providers.Callable(self.example, - injections.KwArg('arg1', 1)) + provider = providers.Callable(self.example) \ + .kwargs(arg1=1) + self.assertTupleEqual(provider(arg2=2, arg3=3, arg4=4), (1, 2, 3, 4)) def test_call_with_context_args_and_kwargs(self): """Test call with context args and kwargs.""" - provider = providers.Callable(self.example, 1) + provider = providers.Callable(self.example) \ + .args(1) + self.assertTupleEqual(provider(2, arg3=3, arg4=4), (1, 2, 3, 4)) def test_call_overridden(self): """Test creation of new instances on overridden provider.""" provider = providers.Callable(self.example) + provider.override(providers.Object((4, 3, 2, 1))) provider.override(providers.Object((1, 2, 3, 4))) @@ -96,24 +92,20 @@ class CallableTests(unittest.TestCase): def test_injections(self): """Test getting a full list of injections using injections property.""" - provider = providers.Callable(self.example, 1, 2, arg3=3, arg4=4) + provider = providers.Callable(self.example) \ + .args(1, 2) \ + .kwargs(arg3=3, arg4=4) + self.assertEquals(len(provider.injections), 4) def test_repr(self): """Test representation of provider.""" - provider = providers.Callable(self.example, - injections.KwArg( - 'arg1', - providers.Factory(dict)), - injections.KwArg( - 'arg2', - providers.Factory(list)), - injections.KwArg( - 'arg3', - providers.Factory(set)), - injections.KwArg( - 'arg4', - providers.Factory(tuple))) + provider = providers.Callable(self.example) \ + .kwargs(arg1=providers.Factory(dict), + arg2=providers.Factory(list), + arg3=providers.Factory(set), + arg4=providers.Factory(tuple)) + self.assertEqual(repr(provider), ''.format( diff --git a/tests/providers/test_creational.py b/tests/providers/test_creational.py index 5c5f9b19..e29f13be 100644 --- a/tests/providers/test_creational.py +++ b/tests/providers/test_creational.py @@ -47,7 +47,8 @@ class FactoryTests(unittest.TestCase): provided_type = Example - example_provider = ExampleProvider(Example, 1, 2) + example_provider = ExampleProvider(Example) \ + .args(1, 2) self.assertIsInstance(example_provider(), Example) @@ -61,7 +62,8 @@ class FactoryTests(unittest.TestCase): class NewExampe(Example): """Example class subclass.""" - example_provider = ExampleProvider(NewExampe, 1, 2) + example_provider = ExampleProvider(NewExampe) \ + .args(1, 2) self.assertIsInstance(example_provider(), NewExampe) @@ -90,7 +92,8 @@ class FactoryTests(unittest.TestCase): New simplified syntax. """ - provider = providers.Factory(Example, 'i1', 'i2') + provider = providers.Factory(Example) \ + .args('i1', 'i2') instance1 = provider() instance2 = provider() @@ -110,7 +113,8 @@ class FactoryTests(unittest.TestCase): New simplified syntax. """ - provider = providers.Factory(Example, init_arg1='i1', init_arg2='i2') + provider = providers.Factory(Example) \ + .kwargs(init_arg1='i1', init_arg2='i2') instance1 = provider() instance2 = provider() @@ -130,7 +134,9 @@ class FactoryTests(unittest.TestCase): Simplified syntax of positional and keyword arg injections. """ - provider = providers.Factory(Example, 'i1', init_arg2='i2') + provider = providers.Factory(Example) \ + .args('i1') \ + .kwargs(init_arg2='i2') instance1 = provider() instance2 = provider() @@ -150,9 +156,9 @@ class FactoryTests(unittest.TestCase): Extended syntax of positional and keyword arg injections. """ - provider = providers.Factory(Example, - injections.Arg('i1'), - injections.KwArg('init_arg2', 'i2')) + provider = providers.Factory(Example) \ + .args('i1') \ + .kwargs(init_arg2='i2') instance1 = provider() instance2 = provider() @@ -169,9 +175,8 @@ class FactoryTests(unittest.TestCase): def test_call_with_attributes(self): """Test creation of new instances with attribute injections.""" - provider = providers.Factory(Example, - injections.Attribute('attribute1', 'a1'), - injections.Attribute('attribute2', 'a2')) + provider = providers.Factory(Example) \ + .attributes(attribute1='a1', attribute2='a2') instance1 = provider() instance2 = provider() @@ -188,7 +193,8 @@ class FactoryTests(unittest.TestCase): def test_call_with_context_args(self): """Test creation of new instances with context args.""" - provider = providers.Factory(Example, 11, 22) + provider = providers.Factory(Example) \ + .args(11, 22) instance = provider(33, 44) self.assertEqual(instance.init_arg1, 11) @@ -198,8 +204,8 @@ class FactoryTests(unittest.TestCase): def test_call_with_context_kwargs(self): """Test creation of new instances with context kwargs.""" - provider = providers.Factory(Example, - injections.KwArg('init_arg1', 1)) + provider = providers.Factory(Example) \ + .kwargs(init_arg1=1) instance1 = provider(init_arg2=22) self.assertEqual(instance1.init_arg1, 1) @@ -211,7 +217,8 @@ class FactoryTests(unittest.TestCase): def test_call_with_context_args_and_kwargs(self): """Test creation of new instances with context args and kwargs.""" - provider = providers.Factory(Example, 11) + provider = providers.Factory(Example) \ + .args(11) instance = provider(22, init_arg3=33, init_arg4=44) self.assertEqual(instance.init_arg1, 11) @@ -237,20 +244,19 @@ class FactoryTests(unittest.TestCase): def test_injections(self): """Test getting a full list of injections using injections property.""" - provider = providers.Factory(Example, - injections.Arg(1), - injections.KwArg('init_arg2', 2), - injections.Attribute('attribute1', 3), - injections.Attribute('attribute2', 4)) + provider = providers.Factory(Example) \ + .args(1) \ + .kwargs(init_arg2=2) \ + .attributes(attribute1=3, attribute2=4) + self.assertEquals(len(provider.injections), 4) def test_repr(self): """Test representation of provider.""" - provider = providers.Factory(Example, - injections.KwArg('init_arg1', - providers.Factory(dict)), - injections.KwArg('init_arg2', - providers.Factory(list))) + provider = providers.Factory(Example) \ + .kwargs(init_arg1=providers.Factory(dict), + init_arg2=providers.Factory(list)) + self.assertEqual(repr(provider), ''.format( @@ -300,7 +306,8 @@ class SingletonTests(unittest.TestCase): provided_type = Example - example_provider = ExampleProvider(Example, 1, 2) + example_provider = ExampleProvider(Example) \ + .args(1, 2) self.assertIsInstance(example_provider(), Example) @@ -314,7 +321,8 @@ class SingletonTests(unittest.TestCase): class NewExampe(Example): """Example class subclass.""" - example_provider = ExampleProvider(NewExampe, 1, 2) + example_provider = ExampleProvider(NewExampe) \ + .args(1, 2) self.assertIsInstance(example_provider(), NewExampe) @@ -343,7 +351,8 @@ class SingletonTests(unittest.TestCase): New simplified syntax. """ - provider = providers.Singleton(Example, 'i1', 'i2') + provider = providers.Singleton(Example) \ + .args('i1', 'i2') instance1 = provider() instance2 = provider() @@ -363,7 +372,8 @@ class SingletonTests(unittest.TestCase): New simplified syntax. """ - provider = providers.Singleton(Example, init_arg1='i1', init_arg2='i2') + provider = providers.Singleton(Example) \ + .kwargs(init_arg1='i1', init_arg2='i2') instance1 = provider() instance2 = provider() @@ -383,7 +393,9 @@ class SingletonTests(unittest.TestCase): Simplified syntax of positional and keyword arg injections. """ - provider = providers.Singleton(Example, 'i1', init_arg2='i2') + provider = providers.Singleton(Example) \ + .args('i1') \ + .kwargs(init_arg2='i2') instance1 = provider() instance2 = provider() @@ -403,9 +415,9 @@ class SingletonTests(unittest.TestCase): Extended syntax of positional and keyword arg injections. """ - provider = providers.Singleton(Example, - injections.Arg('i1'), - injections.KwArg('init_arg2', 'i2')) + provider = providers.Singleton(Example) \ + .args('i1') \ + .kwargs(init_arg2='i2') instance1 = provider() instance2 = provider() @@ -422,11 +434,8 @@ class SingletonTests(unittest.TestCase): def test_call_with_attributes(self): """Test getting of instances with attribute injections.""" - provider = providers.Singleton(Example, - injections.Attribute('attribute1', - 'a1'), - injections.Attribute('attribute2', - 'a2')) + provider = providers.Singleton(Example) \ + .attributes(attribute1='a1', attribute2='a2') instance1 = provider() instance2 = provider() @@ -451,8 +460,8 @@ class SingletonTests(unittest.TestCase): def test_call_with_context_kwargs(self): """Test getting of instances with context kwargs.""" - provider = providers.Singleton(Example, - injections.KwArg('init_arg1', 1)) + provider = providers.Singleton(Example) \ + .kwargs(init_arg1=1) instance1 = provider(init_arg2=22) self.assertEqual(instance1.init_arg1, 1) @@ -465,7 +474,8 @@ class SingletonTests(unittest.TestCase): def test_call_with_context_args_and_kwargs(self): """Test getting of instances with context args and kwargs.""" - provider = providers.Singleton(Example, 11) + provider = providers.Singleton(Example) \ + .args(11) instance = provider(22, init_arg3=33, init_arg4=44) self.assertEqual(instance.init_arg1, 11) @@ -496,28 +506,32 @@ class SingletonTests(unittest.TestCase): def test_args_attr(self): """Test args attribute.""" - provider = providers.Singleton(Example, 1, 2) - self.assertEquals(len(provider.args), 2) + provider = providers.Singleton(Example) \ + .args(1, 2) + + self.assertEquals(len(provider._args), 2) def test_kwargs_attr(self): """Test kwargs attribute.""" - provider = providers.Singleton(Example, init_arg1=1, init_arg2=2) - self.assertEquals(len(provider.kwargs), 2) + provider = providers.Singleton(Example) \ + .kwargs(init_arg1=1, init_arg2=2) + + self.assertEquals(len(provider._kwargs), 2) def test_attributes_attr(self): """Test attributes attribute.""" - provider = providers.Singleton(Example, - injections.Attribute('attribute1', 1), - injections.Attribute('attribute2', 2)) - self.assertEquals(len(provider.attributes), 2) + provider = providers.Singleton(Example) \ + .attributes(attribute1=1, attribute2=2) + + self.assertEquals(len(provider._attributes), 2) def test_injections(self): """Test getting a full list of injections using injections property.""" - provider = providers.Singleton(Example, - injections.Arg(1), - injections.KwArg('init_arg2', 2), - injections.Attribute('attribute1', 3), - injections.Attribute('attribute2', 4)) + provider = providers.Singleton(Example) \ + .args(1) \ + .kwargs(init_arg2=2) \ + .attributes(attribute1=3, attribute2=4) + self.assertEquals(len(provider.injections), 4) def test_reset(self): @@ -536,13 +550,10 @@ class SingletonTests(unittest.TestCase): def test_repr(self): """Test representation of provider.""" - provider = providers.Singleton(Example, - injections.KwArg( - 'init_arg1', - providers.Factory(dict)), - injections.KwArg( - 'init_arg2', - providers.Factory(list))) + provider = providers.Singleton(Example) \ + .kwargs(init_arg1=providers.Factory(dict), + init_arg2=providers.Factory(list)) + self.assertEqual(repr(provider), ''.format(