diff --git a/README.rst b/README.rst index bb9f09c4..67d83a09 100644 --- a/README.rst +++ b/README.rst @@ -134,26 +134,26 @@ IoC containers from previous example could look like these: """Catalog of platform service providers.""" database = providers.Singleton(sqlite3.connect) \ - .args(':memory:') + .add_args(':memory:') s3 = providers.Singleton(boto.s3.connection.S3Connection) \ - .kwargs(aws_access_key_id='KEY', - aws_secret_access_key='SECRET') + .add_kwargs(aws_access_key_id='KEY', + aws_secret_access_key='SECRET') class Services(catalogs.DeclarativeCatalog): """Catalog of business service providers.""" users = providers.Factory(example.services.Users) \ - .kwargs(db=Platform.database) + .add_kwargs(db=Platform.database) photos = providers.Factory(example.services.Photos) \ - .kwargs(db=Platform.database, - s3=Platform.s3) + .add_kwargs(db=Platform.database, + s3=Platform.s3) auth = providers.Factory(example.services.Auth) \ - .kwargs(db=Platform.database, - token_ttl=3600) + .add_kwargs(db=Platform.database, + token_ttl=3600) or like this these: @@ -163,26 +163,26 @@ or like this these: """Catalog of platform service providers.""" database = providers.Singleton(sqlite3.connect) - database.args(':memory:') + database.add_args(':memory:') s3 = providers.Singleton(boto.s3.connection.S3Connection) - s3.kwargs(aws_access_key_id='KEY', - aws_secret_access_key='SECRET') + s3.add_kwargs(aws_access_key_id='KEY', + aws_secret_access_key='SECRET') class Services(catalogs.DeclarativeCatalog): """Catalog of business service providers.""" users = providers.Factory(example.services.Users) - users.kwargs(db=Platform.database) + users.add_kwargs(db=Platform.database) photos = providers.Factory(example.services.Photos) - photos.kwargs(db=Platform.database, - s3=Platform.s3) + photos.add_kwargs(db=Platform.database, + s3=Platform.s3) auth = providers.Factory(example.services.Auth) - auth.kwargs(db=Platform.database, - token_ttl=3600) + auth.add_kwargs(db=Platform.database, + token_ttl=3600) You can get more *Dependency Injector* examples in ``/examples`` directory on GitHub: diff --git a/dependency_injector/injections.py b/dependency_injector/injections.py index 2387c63c..b5c1e0b5 100644 --- a/dependency_injector/injections.py +++ b/dependency_injector/injections.py @@ -1,148 +1,13 @@ """Injections module.""" -import itertools - import six -from dependency_injector.utils import ( - is_provider, - is_injection, - is_arg_injection, - is_kwarg_injection, - is_delegated_provider, - fetch_cls_init, +from dependency_injector.providers.base import ( + _parse_positional_injections, + _parse_keyword_injections, ) - -from dependency_injector.errors import Error - - -@six.python_2_unicode_compatible -class Injection(object): - """Base injection class. - - All injections extend this class. - - .. py:attribute:: injectable - - Injectable value, could be provider or any other object. - - :type: object | :py:class:`dependency_injector.providers.Provider` - - .. py:attribute:: call_injectable - - Flag that is set to ``True`` if it is needed to call injectable. - - Injectable needs to be called if it is not delegated provider. - - :type: bool - """ - - __IS_INJECTION__ = True - __slots__ = ('injectable', 'get_value') - - def __init__(self, injectable): - """Initializer. - - :param injectable: Injectable value, could be provider or any - other object. - :type injectable: object | - :py:class:`dependency_injector.providers.Provider` - """ - self.injectable = injectable - - if not is_provider(injectable) or is_delegated_provider(injectable): - def injectable(): - return self.injectable - self.get_value = injectable - - super(Injection, self).__init__() - - def __str__(self): - """Return string representation of provider. - - :rtype: str - """ - return '<{injection}({injectable}) at {address}>'.format( - injection='.'.join((self.__class__.__module__, - self.__class__.__name__)), - injectable=repr(self.injectable), - address=hex(id(self))) - - __repr__ = __str__ - - -class Arg(Injection): - """Positional argument injection.""" - - __IS_ARG_INJECTION__ = True - - -@six.python_2_unicode_compatible -class _NamedInjection(Injection): - """Base class of named injections. - - .. py:attribute:: name - - Injection target's name (keyword argument, attribute). - - :type: str - """ - - __slots__ = ('name',) - - def __init__(self, name, injectable): - """Initializer. - - :param name: Injection target's name. - :type name: str - - :param injectable: Injectable value, could be provider or any - other object. - :type injectable: object | - :py:class:`dependency_injector.providers.Provider` - """ - self.name = name - super(_NamedInjection, self).__init__(injectable) - - def __str__(self): - """Return string representation of provider. - - :rtype: str - """ - return '<{injection}({name}, {injectable}) at {address}>'.format( - name=repr(self.name), - injection='.'.join((self.__class__.__module__, - self.__class__.__name__)), - injectable=repr(self.injectable), - address=hex(id(self))) - - __repr__ = __str__ - - -class KwArg(_NamedInjection): - """Keyword argument injection. - - .. py:attribute:: name - - Keyword argument's name. - - :type: str - """ - - __IS_KWARG_INJECTION__ = True - - -class Attribute(_NamedInjection): - """Attribute injection. - - .. py:attribute:: name - - Attribute's name. - - :type: str - """ - - __IS_ATTRIBUTE_INJECTION__ = True +from dependency_injector import utils +from dependency_injector import errors def inject(*args, **kwargs): @@ -157,24 +22,18 @@ def inject(*args, **kwargs): .. code-block:: python - # Positional arguments injections (simplified syntax): + # Positional arguments injections: @inject(1, 2) def some_function(arg1, arg2): pass - # Keyword arguments injections (simplified syntax): + # Keyword arguments injections: @inject(arg1=1) @inject(arg2=2) def some_function(arg1, arg2): pass - # Keyword arguments injections (extended (full) syntax): - @inject(KwArg('arg1', 1)) - @inject(KwArg('arg2', 2)) - def some_function(arg1, arg2): - pass - - # Keyword arguments injections into class init (simplified syntax): + # Keyword arguments injections into class init: @inject(arg1=1) @inject(arg2=2) class SomeClass(object): @@ -191,16 +50,16 @@ def inject(*args, **kwargs): :return: Class / callable decorator :rtype: (callable) -> (type | callable) """ - arg_injections = _parse_args_injections(args) - kwarg_injections = _parse_kwargs_injections(args, kwargs) + arg_injections = _parse_positional_injections(args) + kwarg_injections = _parse_keyword_injections(kwargs) def decorator(callback_or_cls): """Dependency injection decorator.""" if isinstance(callback_or_cls, six.class_types): cls = callback_or_cls - cls_init = fetch_cls_init(cls) + cls_init = utils.fetch_cls_init(cls) if not cls_init: - raise Error( + raise errors.Error( 'Class {0}.{1} has no __init__() '.format(cls.__module__, cls.__name__) + 'method and could not be decorated with @inject decorator') @@ -211,19 +70,18 @@ def inject(*args, **kwargs): if hasattr(callback, '__INJECT_DECORATED__'): callback.args += arg_injections - callback.kwargs += kwarg_injections - callback.injections += arg_injections + kwarg_injections + callback.kwargs.update(kwarg_injections) return callback @six.wraps(callback) def decorated(*args, **kwargs): """Decorated with dependency injection callback.""" if decorated.args: - args = tuple(arg.get_value() for arg in decorated.args) + args + args = tuple(arg.inject() for arg in decorated.args) + args - for kwarg in decorated.kwargs: - if kwarg.name not in kwargs: - kwargs[kwarg.name] = kwarg.get_value() + for name, arg in six.iteritems(decorated.kwargs): + if name not in kwargs: + kwargs[name] = arg.inject() return callback(*args, **kwargs) @@ -231,23 +89,6 @@ def inject(*args, **kwargs): decorated.origin = callback decorated.args = arg_injections decorated.kwargs = kwarg_injections - decorated.injections = arg_injections + kwarg_injections return decorated return decorator - - -def _parse_args_injections(args): - 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): - kwarg_injections = tuple(injection - for injection in args - if is_kwarg_injection(injection)) - if kwargs: - kwarg_injections += tuple(itertools.starmap(KwArg, - six.iteritems(kwargs))) - return kwarg_injections diff --git a/dependency_injector/providers/__init__.py b/dependency_injector/providers/__init__.py index 1b61f62e..3ed291c2 100644 --- a/dependency_injector/providers/__init__.py +++ b/dependency_injector/providers/__init__.py @@ -5,6 +5,8 @@ from dependency_injector.providers.base import ( Delegate, Object, ExternalDependency, + OverridingContext, + override, ) from dependency_injector.providers.callable import ( Callable, @@ -16,10 +18,6 @@ from dependency_injector.providers.creational import ( Singleton, DelegatedSingleton, ) -from dependency_injector.providers.utils import ( - OverridingContext, - override, -) __all__ = ( @@ -28,6 +26,9 @@ __all__ = ( 'Object', 'ExternalDependency', + 'OverridingContext', + 'override', + 'Callable', 'DelegatedCallable', @@ -35,7 +36,4 @@ __all__ = ( 'DelegatedFactory', 'Singleton', 'DelegatedSingleton', - - 'OverridingContext', - 'override', ) diff --git a/dependency_injector/providers/base.py b/dependency_injector/providers/base.py index 1a7ad116..36b9a6e9 100644 --- a/dependency_injector/providers/base.py +++ b/dependency_injector/providers/base.py @@ -2,7 +2,6 @@ import six -from dependency_injector.providers.utils import OverridingContext from dependency_injector.errors import Error from dependency_injector.utils import ( is_provider, @@ -84,6 +83,13 @@ class Provider(object): """Call last overriding provider and return result.""" return self.last_overriding(*args, **kwargs) + def inject(self): + """Injection strategy implementation. + + :rtype: object + """ + return self.provide() + @property def is_overridden(self): """Read-only property that is set to ``True`` if provider is overridden. @@ -349,3 +355,77 @@ class ExternalDependency(Provider): return represent_provider(provider=self, provides=self.instance_of) __repr__ = __str__ + + +class OverridingContext(object): + """Provider overriding context. + + :py:class:`OverridingContext` is used by :py:meth:`Provider.override` for + implemeting ``with`` contexts. When :py:class:`OverridingContext` is + closed, overriding that was created in this context is dropped also. + + .. code-block:: python + + with provider.override(another_provider): + assert provider.is_overridden + assert not provider.is_overridden + """ + + def __init__(self, overridden, overriding): + """Initializer. + + :param overridden: Overridden provider. + :type overridden: :py:class:`Provider` + + :param overriding: Overriding provider. + :type overriding: :py:class:`Provider` + """ + self.overridden = overridden + self.overriding = overriding + + def __enter__(self): + """Do nothing.""" + return self.overriding + + def __exit__(self, *_): + """Exit overriding context.""" + self.overridden.reset_last_overriding() + + +def override(overridden): + """Decorator for overriding providers. + + This decorator overrides ``overridden`` provider by decorated one. + + .. code-block:: python + + @Factory + class SomeClass(object): + pass + + + @override(SomeClass) + @Factory + class ExtendedSomeClass(SomeClass.cls): + pass + + :param overridden: Provider that should be overridden. + :type overridden: :py:class:`Provider` + + :return: Overriding provider. + :rtype: :py:class:`Provider` + """ + def decorator(overriding): + overridden.override(overriding) + return overriding + return decorator + + +def _parse_positional_injections(args): + return tuple(arg if is_provider(arg) else Object(arg) + for arg in args) + + +def _parse_keyword_injections(kwargs): + return dict((name, arg if is_provider(arg) else Object(arg)) + for name, arg in six.iteritems(kwargs)) diff --git a/dependency_injector/providers/callable.py b/dependency_injector/providers/callable.py index f2714b3c..578d5e0d 100644 --- a/dependency_injector/providers/callable.py +++ b/dependency_injector/providers/callable.py @@ -2,8 +2,11 @@ import six -from dependency_injector.providers.base import Provider -from dependency_injector.injections import Arg, KwArg +from dependency_injector.providers.base import ( + Provider, + _parse_positional_injections, + _parse_keyword_injections, +) from dependency_injector.utils import represent_provider from dependency_injector.errors import Error @@ -26,17 +29,17 @@ class Callable(Provider): # or some_function = Callable(some_function) \ - .args('positional_arg1', 'positional_arg2') \ - .kwargs(keyword_argument1=3, keyword_argument=4) + .add_args('positional_arg1', 'positional_arg2') \ + .add_kwargs(keyword_argument1=3, keyword_argument=4) # or some_function = Callable(some_function) - some_function.args('positional_arg1', 'positional_arg2') - some_function.kwargs(keyword_argument1=3, keyword_argument=4) + some_function.add_args('positional_arg1', 'positional_arg2') + some_function.add_kwargs(keyword_argument1=3, keyword_argument=4) """ - __slots__ = ('_provides', '_args', '_kwargs') + __slots__ = ('provides', 'args', 'kwargs') def __init__(self, provides, *args, **kwargs): """Initializer. @@ -50,24 +53,17 @@ class Callable(Provider): self.__class__.__name__)), provides)) - self._provides = provides - self._args = tuple() - self._kwargs = tuple() + self.provides = provides - self.args(*args) - self.kwargs(**kwargs) + self.args = tuple() + self.kwargs = dict() + + self.add_args(*args) + self.add_kwargs(**kwargs) super(Callable, self).__init__() - @property - def injections(self): - """Read-only tuple of all injections. - - :rtype: tuple[:py:class:`dependency_injector.injections.Injection`] - """ - return self._args + self._kwargs - - def args(self, *args): + def add_args(self, *args): """Add postional argument injections. :param args: Tuple of injections. @@ -75,10 +71,10 @@ class Callable(Provider): :return: Reference ``self`` """ - self._args += tuple(Arg(value) for value in args) + self.args += _parse_positional_injections(args) return self - def kwargs(self, **kwargs): + def add_kwargs(self, **kwargs): """Add keyword argument injections. :param kwargs: Dictionary of injections. @@ -86,8 +82,7 @@ class Callable(Provider): :return: Reference ``self`` """ - self._kwargs += tuple(KwArg(name, value) - for name, value in six.iteritems(kwargs)) + self.kwargs.update(_parse_keyword_injections(kwargs)) return self def _provide(self, *args, **kwargs): @@ -101,21 +96,21 @@ class Callable(Provider): :rtype: object """ - if self._args: - args = tuple(arg.get_value() for arg in self._args) + args + if self.args: + args = tuple(arg.inject() for arg in self.args) + args - for kwarg in self._kwargs: - if kwarg.name not in kwargs: - kwargs[kwarg.name] = kwarg.get_value() + for name, arg in six.iteritems(self.kwargs): + if name not in kwargs: + kwargs[name] = arg.inject() - return self._provides(*args, **kwargs) + return self.provides(*args, **kwargs) def __str__(self): """Return string representation of provider. :rtype: str """ - return represent_provider(provider=self, provides=self._provides) + return represent_provider(provider=self, provides=self.provides) __repr__ = __str__ @@ -127,4 +122,9 @@ class DelegatedCallable(Callable): "as is". """ - __IS_DELEGATED__ = True + def inject(self): + """Injection strategy implementation. + + :rtype: object + """ + return self diff --git a/dependency_injector/providers/creational.py b/dependency_injector/providers/creational.py index 4a307ed1..712f40ce 100644 --- a/dependency_injector/providers/creational.py +++ b/dependency_injector/providers/creational.py @@ -3,7 +3,7 @@ import six from dependency_injector.providers.callable import Callable -from dependency_injector.injections import Attribute +from dependency_injector.providers.base import _parse_keyword_injections from dependency_injector.utils import GLOBAL_LOCK from dependency_injector.errors import Error @@ -25,14 +25,14 @@ class Factory(Callable): # or factory = Factory(SomeClass) \ - .args('positional_arg1', 'positional_arg2') \ - .kwargs(keyword_argument1=3, keyword_argument=4) + .add_args('positional_arg1', 'positional_arg2') \ + .add_kwargs(keyword_argument1=3, keyword_argument=4) # or factory = Factory(SomeClass) - factory.args('positional_arg1', 'positional_arg2') - factory.kwargs(keyword_argument1=3, keyword_argument=4) + 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`: @@ -40,7 +40,7 @@ class Factory(Callable): .. code-block:: python factory = Factory(SomeClass) \ - .attributes(attribute1=1, attribute2=2) + .add_attributes(attribute1=1, attribute2=2) Retrieving of provided instance can be performed via calling :py:class:`Factory` object: @@ -68,7 +68,7 @@ class Factory(Callable): provided_type = None - __slots__ = ('cls', '_attributes') + __slots__ = ('cls', 'attributes') def __init__(self, provides, *args, **kwargs): """Initializer. @@ -82,21 +82,13 @@ class Factory(Callable): raise Error('{0} can provide only {1} instances'.format( self.__class__, self.__class__.provided_type)) - self._attributes = tuple() + self.attributes = dict() super(Factory, self).__init__(provides, *args, **kwargs) - self.cls = self._provides + self.cls = self.provides - @property - def injections(self): - """Read-only tuple of all injections. - - :rtype: tuple[:py:class:`dependency_injector.injections.Injection`] - """ - return super(Factory, self).injections + self._attributes - - def attributes(self, **kwargs): + def add_attributes(self, **kwargs): """Add attribute injections. :param kwargs: Dictionary of injections. @@ -104,8 +96,7 @@ class Factory(Callable): :return: Reference ``self`` """ - self._attributes += tuple(Attribute(name, value) - for name, value in six.iteritems(kwargs)) + self.attributes.update(_parse_keyword_injections(kwargs)) return self def _provide(self, *args, **kwargs): @@ -119,17 +110,10 @@ class Factory(Callable): :rtype: object """ - if self._args: - args = tuple(arg.get_value() for arg in self._args) + args + instance = super(Factory, self)._provide(*args, **kwargs) - for kwarg in self._kwargs: - if kwarg.name not in kwargs: - kwargs[kwarg.name] = kwarg.get_value() - - instance = self._provides(*args, **kwargs) - - for attribute in self._attributes: - setattr(instance, attribute.name, attribute.get_value()) + for name, arg in six.iteritems(self.attributes): + setattr(instance, name, arg.inject()) return instance @@ -156,7 +140,12 @@ class DelegatedFactory(Factory): :type: type """ - __IS_DELEGATED__ = True + def inject(self): + """Injection strategy implementation. + + :rtype: object + """ + return self class Singleton(Factory): @@ -193,7 +182,7 @@ class Singleton(Factory): :type: type """ - __slots__ = ('_instance',) + __slots__ = ('instance',) def __init__(self, provides, *args, **kwargs): """Initializer. @@ -202,7 +191,7 @@ class Singleton(Factory): for creation. :type provides: type | callable """ - self._instance = None + self.instance = None super(Singleton, self).__init__(provides, *args, **kwargs) def reset(self): @@ -210,7 +199,7 @@ class Singleton(Factory): :rtype: None """ - self._instance = None + self.instance = None def _provide(self, *args, **kwargs): """Return provided instance. @@ -223,13 +212,13 @@ class Singleton(Factory): :rtype: object """ - if self._instance: - return self._instance + if self.instance: + return self.instance with GLOBAL_LOCK: - self._instance = super(Singleton, self)._provide(*args, **kwargs) + self.instance = super(Singleton, self)._provide(*args, **kwargs) - return self._instance + return self.instance class DelegatedSingleton(Singleton): @@ -254,4 +243,9 @@ class DelegatedSingleton(Singleton): :type: type """ - __IS_DELEGATED__ = True + def inject(self): + """Injection strategy implementation. + + :rtype: object + """ + return self diff --git a/dependency_injector/providers/utils.py b/dependency_injector/providers/utils.py deleted file mode 100644 index 40b9278e..00000000 --- a/dependency_injector/providers/utils.py +++ /dev/null @@ -1,65 +0,0 @@ -"""Dependency injector provider utils.""" - - -class OverridingContext(object): - """Provider overriding context. - - :py:class:`OverridingContext` is used by :py:meth:`Provider.override` for - implemeting ``with`` contexts. When :py:class:`OverridingContext` is - closed, overriding that was created in this context is dropped also. - - .. code-block:: python - - with provider.override(another_provider): - assert provider.is_overridden - assert not provider.is_overridden - """ - - def __init__(self, overridden, overriding): - """Initializer. - - :param overridden: Overridden provider. - :type overridden: :py:class:`Provider` - - :param overriding: Overriding provider. - :type overriding: :py:class:`Provider` - """ - self.overridden = overridden - self.overriding = overriding - - def __enter__(self): - """Do nothing.""" - return self.overriding - - def __exit__(self, *_): - """Exit overriding context.""" - self.overridden.reset_last_overriding() - - -def override(overridden): - """Decorator for overriding providers. - - This decorator overrides ``overridden`` provider by decorated one. - - .. code-block:: python - - @Factory - class SomeClass(object): - pass - - - @override(SomeClass) - @Factory - class ExtendedSomeClass(SomeClass.cls): - pass - - :param overridden: Provider that should be overridden. - :type overridden: :py:class:`Provider` - - :return: Overriding provider. - :rtype: :py:class:`Provider` - """ - def decorator(overriding): - overridden.override(overriding) - return overriding - return decorator diff --git a/dependency_injector/utils.py b/dependency_injector/utils.py index fb6bedeb..f65dfcea 100644 --- a/dependency_injector/utils.py +++ b/dependency_injector/utils.py @@ -7,7 +7,7 @@ import threading import six -from dependency_injector.errors import Error +from dependency_injector import errors GLOBAL_LOCK = threading.RLock() @@ -54,93 +54,11 @@ def ensure_is_provider(instance): :rtype: :py:class:`dependency_injector.providers.Provider` """ if not is_provider(instance): - raise Error('Expected provider instance, ' - 'got {0}'.format(str(instance))) + raise errors.Error('Expected provider instance, ' + 'got {0}'.format(str(instance))) return instance -def is_delegated_provider(instance): - """Check if instance is delegated provider instance. - - :param instance: Instance to be checked. - :type instance: object - - :rtype: bool - """ - return (is_provider(instance) and - hasattr(instance, '__IS_DELEGATED__') and - getattr(instance, '__IS_DELEGATED__') is True) - - -def is_injection(instance): - """Check if instance is injection instance. - - :param instance: Instance to be checked. - :type instance: object - - :rtype: bool - """ - return (not isinstance(instance, six.class_types) and - hasattr(instance, '__IS_INJECTION__') and - getattr(instance, '__IS_INJECTION__') is True) - - -def ensure_is_injection(instance): - """Check if instance is injection instance and return it. - - :param instance: Instance to be checked. - :type instance: object - - :raise: :py:exc:`dependency_injector.errors.Error` if provided instance is - not injection. - - :rtype: :py:class:`dependency_injector.injections.Injection` - """ - if not is_injection(instance): - raise Error('Expected injection instance, ' - 'got {0}'.format(str(instance))) - return instance - - -def is_arg_injection(instance): - """Check if instance is positional argument injection instance. - - :param instance: Instance to be checked. - :type instance: object - - :rtype: bool - """ - return (not isinstance(instance, six.class_types) and - hasattr(instance, '__IS_ARG_INJECTION__') and - getattr(instance, '__IS_ARG_INJECTION__', False) is True) - - -def is_kwarg_injection(instance): - """Check if instance is keyword argument injection instance. - - :param instance: Instance to be checked. - :type instance: object - - :rtype: bool - """ - return (not isinstance(instance, six.class_types) and - hasattr(instance, '__IS_KWARG_INJECTION__') and - getattr(instance, '__IS_KWARG_INJECTION__', False) is True) - - -def is_attribute_injection(instance): - """Check if instance is attribute injection instance. - - :param instance: Instance to be checked. - :type instance: object - - :rtype: bool - """ - return (not isinstance(instance, six.class_types) and - hasattr(instance, '__IS_ATTRIBUTE_INJECTION__') and - getattr(instance, '__IS_ATTRIBUTE_INJECTION__', False) is True) - - def is_catalog(instance): """Check if instance is catalog instance. diff --git a/examples/miniapps/services/catalogs_alt_syntax_1.py b/examples/miniapps/services/catalogs_alt_syntax_1.py index 8cc97603..7f2c615f 100644 --- a/examples/miniapps/services/catalogs_alt_syntax_1.py +++ b/examples/miniapps/services/catalogs_alt_syntax_1.py @@ -15,23 +15,23 @@ class Platform(catalogs.DeclarativeCatalog): """Catalog of platform service providers.""" database = providers.Singleton(sqlite3.connect) \ - .args(':memory:') + .add_args(':memory:') s3 = providers.Singleton(boto.s3.connection.S3Connection) \ - .kwargs(aws_access_key_id='KEY', - aws_secret_access_key='SECRET') + .add_kwargs(aws_access_key_id='KEY', + aws_secret_access_key='SECRET') class Services(catalogs.DeclarativeCatalog): """Catalog of business service providers.""" users = providers.Factory(example.services.Users) \ - .kwargs(db=Platform.database) + .add_kwargs(db=Platform.database) photos = providers.Factory(example.services.Photos) \ - .kwargs(db=Platform.database, - s3=Platform.s3) + .add_kwargs(db=Platform.database, + s3=Platform.s3) auth = providers.Factory(example.services.Auth) \ - .kwargs(db=Platform.database, - token_ttl=3600) + .add_kwargs(db=Platform.database, + token_ttl=3600) diff --git a/examples/miniapps/services/catalogs_alt_syntax_2.py b/examples/miniapps/services/catalogs_alt_syntax_2.py index 1d5746b9..0f3c245d 100644 --- a/examples/miniapps/services/catalogs_alt_syntax_2.py +++ b/examples/miniapps/services/catalogs_alt_syntax_2.py @@ -15,23 +15,23 @@ class Platform(catalogs.DeclarativeCatalog): """Catalog of platform service providers.""" database = providers.Singleton(sqlite3.connect) - database.args(':memory:') + database.add_args(':memory:') s3 = providers.Singleton(boto.s3.connection.S3Connection) - s3.kwargs(aws_access_key_id='KEY', - aws_secret_access_key='SECRET') + s3.add_kwargs(aws_access_key_id='KEY', + aws_secret_access_key='SECRET') class Services(catalogs.DeclarativeCatalog): """Catalog of business service providers.""" users = providers.Factory(example.services.Users) - users.kwargs(db=Platform.database) + users.add_kwargs(db=Platform.database) photos = providers.Factory(example.services.Photos) - photos.kwargs(db=Platform.database, - s3=Platform.s3) + photos.add_kwargs(db=Platform.database, + s3=Platform.s3) auth = providers.Factory(example.services.Auth) - auth.kwargs(db=Platform.database, - token_ttl=3600) + auth.add_kwargs(db=Platform.database, + token_ttl=3600) diff --git a/tests/catalogs/test_declarative.py b/tests/catalogs/test_declarative.py index 37108a87..a35b9bc5 100644 --- a/tests/catalogs/test_declarative.py +++ b/tests/catalogs/test_declarative.py @@ -383,7 +383,7 @@ class CopyingTests(unittest.TestCase): class CatalogA(catalogs.DeclarativeCatalog): p11 = providers.Object(0) p12 = providers.Factory(dict) \ - .kwargs(p11=p11) + .add_kwargs(p11=p11) @catalogs.copy(CatalogA) class CatalogA1(CatalogA): @@ -404,9 +404,9 @@ class CopyingTests(unittest.TestCase): self.assertIsNot(CatalogA1.p11, CatalogA2.p11) self.assertIsNot(CatalogA1.p12, CatalogA2.p12) - self.assertIs(CatalogA.p12.injections[0].injectable, CatalogA.p11) - self.assertIs(CatalogA1.p12.injections[0].injectable, CatalogA1.p11) - self.assertIs(CatalogA2.p12.injections[0].injectable, CatalogA2.p11) + self.assertIs(CatalogA.p12.kwargs['p11'], CatalogA.p11) + self.assertIs(CatalogA1.p12.kwargs['p11'], CatalogA1.p11) + self.assertIs(CatalogA2.p12.kwargs['p11'], CatalogA2.p11) self.assertEqual(CatalogA.p12(), dict(p11=0)) self.assertEqual(CatalogA1.p12(), dict(p11=1)) diff --git a/tests/providers/test_callable.py b/tests/providers/test_callable.py index 2f526470..f6a8f3da 100644 --- a/tests/providers/test_callable.py +++ b/tests/providers/test_callable.py @@ -30,47 +30,52 @@ class CallableTests(unittest.TestCase): New simplified syntax. """ - provider = providers.Callable(self.example) \ - .args(1, 2, 3, 4) + provider = providers.Callable(self.example, + 1, 2, 3, 4) self.assertTupleEqual(provider(), (1, 2, 3, 4)) def test_call_with_keyword_args(self): """Test call with keyword args.""" - provider = providers.Callable(self.example) \ - .kwargs(arg1=1, arg2=2, arg3=3, arg4=4) + provider = providers.Callable(self.example, + arg1=1, arg2=2, arg3=3, arg4=4) self.assertTupleEqual(provider(), (1, 2, 3, 4)) def test_call_with_positional_and_keyword_args(self): """Test call with positional and keyword args.""" - provider = providers.Callable(self.example) \ - .args(1, 2) \ - .kwargs(arg3=3, arg4=4) + provider = providers.Callable(self.example, + 1, 2, + arg3=3, 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) \ - .args(1, 2) + provider = providers.Callable(self.example, 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) \ - .kwargs(arg1=1) + provider = providers.Callable(self.example, 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) \ - .args(1) + provider = providers.Callable(self.example, 1) self.assertTupleEqual(provider(2, arg3=3, arg4=4), (1, 2, 3, 4)) + def test_fluent_interface(self): + """Test injections definition with fluent interface.""" + provider = providers.Singleton(self.example) \ + .add_args(1, 2) \ + .add_kwargs(arg3=3, arg4=4) \ + + self.assertTupleEqual(provider(), (1, 2, 3, 4)) + def test_call_overridden(self): """Test creation of new instances on overridden provider.""" provider = providers.Callable(self.example) @@ -80,21 +85,9 @@ class CallableTests(unittest.TestCase): self.assertTupleEqual(provider(), (1, 2, 3, 4)) - def test_injections(self): - """Test getting a full list of injections using injections property.""" - 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) \ - .kwargs(arg1=providers.Factory(dict), - arg2=providers.Factory(list), - arg3=providers.Factory(set), - arg4=providers.Factory(tuple)) + provider = providers.Callable(self.example) self.assertEqual(repr(provider), ''.format( - repr(provider), - hex(id(injection)))) - - -class ArgTests(unittest.TestCase): - """Positional arg injection test cases.""" - - def test_init(self): - """Test Arg creation and initialization.""" - injection = injections.Arg('some_value') - self.assertEqual(injection.injectable, 'some_value') - - def test_repr(self): - """Test Arg representation.""" - provider = providers.Factory(object) - injection = injections.Arg(provider) - self.assertEqual( - repr(injection), - ''.format( - repr(provider), - hex(id(injection)))) - - -class KwArgTests(unittest.TestCase): - """Keyword arg injection test cases.""" - - def test_init(self): - """Test KwArg creation and initialization.""" - injection = injections.KwArg('some_arg_name', 'some_value') - self.assertEqual(injection.name, 'some_arg_name') - self.assertEqual(injection.injectable, 'some_value') - - def test_repr(self): - """Test KwArg representation.""" - provider = providers.Factory(object) - injection = injections.KwArg('name', provider) - self.assertEqual( - repr(injection), - ''.format( - repr('name'), - repr(provider), - hex(id(injection)))) - - -class AttributeTests(unittest.TestCase): - """Attribute injection test cases.""" - - def test_init(self): - """Test Attribute creation and initialization.""" - injection = injections.Attribute('some_arg_name', 'some_value') - self.assertEqual(injection.name, 'some_arg_name') - self.assertEqual(injection.injectable, 'some_value') - - def test_repr(self): - """Test Attribute representation.""" - provider = providers.Factory(object) - injection = injections.Attribute('name', provider) - self.assertEqual( - repr(injection), - ''.format( - repr('name'), - repr(provider), - hex(id(injection)))) - - class InjectTests(unittest.TestCase): """Inject decorator test cases.""" @@ -121,27 +30,6 @@ class InjectTests(unittest.TestCase): self.assertIsInstance(b2, list) self.assertIsNot(b1, b2) - def test_decorated_args_extended_syntax(self): - """Test `inject()` decoration with args.""" - provider1 = providers.Factory(object) - provider2 = providers.Factory(list) - - @injections.inject(injections.Arg(provider1), - injections.Arg(provider2)) - def test(a, b): - return a, b - - a1, b1 = test() - a2, b2 = test() - - self.assertIsInstance(a1, object) - self.assertIsInstance(a2, object) - self.assertIsNot(a1, a2) - - self.assertIsInstance(b1, list) - self.assertIsInstance(b2, list) - self.assertIsNot(b1, b2) - def test_decorated_args_several_times(self): """Test `inject()` decoration with args several times.""" provider1 = providers.Factory(object) @@ -248,27 +136,6 @@ class InjectTests(unittest.TestCase): self.assertIsInstance(b2, list) self.assertIsNot(b1, b2) - def test_injection_kwarg_syntax(self): - """Test `inject()` decorated callback with "old" style using KwArg.""" - provider = providers.Factory(list) - object_a = object() - - @injections.inject(injections.KwArg('b', provider)) - def test(a, b): - return a, b - - a1, b1 = test(object_a) - a2, b2 = test(object_a) - - self.assertIsInstance(a1, object) - self.assertIsInstance(a2, object) - self.assertIs(a1, object_a) - self.assertIs(a2, object_a) - - self.assertIsInstance(b1, list) - self.assertIsInstance(b2, list) - self.assertIsNot(b1, b2) - def test_decorate_class_method(self): """Test `inject()` decorator with class method.""" class Test(object): diff --git a/tests/test_utils.py b/tests/test_utils.py index 353f5b12..95b3a826 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -4,7 +4,6 @@ import unittest2 as unittest from dependency_injector import utils from dependency_injector import providers -from dependency_injector import injections from dependency_injector import catalogs from dependency_injector import errors @@ -72,135 +71,6 @@ class EnsureIsProviderTests(unittest.TestCase): self.assertRaises(errors.Error, utils.ensure_is_provider, object()) -class IsInjectionTests(unittest.TestCase): - """`is_injection()` test cases.""" - - def test_with_instance(self): - """Test with instance.""" - self.assertTrue(utils.is_injection(injections.Injection('value'))) - - def test_with_subclass_instances(self): - """Test with subclass instances.""" - self.assertTrue(utils.is_injection(injections.Arg('value'))) - self.assertTrue(utils.is_injection(injections.KwArg('name', - 'value'))) - self.assertTrue(utils.is_injection(injections.Attribute('name', - 'value'))) - - def test_with_class(self): - """Test with class.""" - self.assertFalse(utils.is_injection(injections.Injection)) - - def test_with_string(self): - """Test with string.""" - self.assertFalse(utils.is_injection('some_string')) - - def test_with_object(self): - """Test with object.""" - self.assertFalse(utils.is_injection(object())) - - -class EnsureIsInjectionTests(unittest.TestCase): - """`ensure_is_injection` test cases.""" - - def test_with_instance(self): - """Test with instance.""" - injection = injections.Injection('value') - self.assertIs(utils.ensure_is_injection(injection), injection) - - def test_with_class(self): - """Test with class.""" - self.assertRaises(errors.Error, - utils.ensure_is_injection, - injections.Injection) - - def test_with_string(self): - """Test with string.""" - self.assertRaises(errors.Error, - utils.ensure_is_injection, - 'some_string') - - def test_with_object(self): - """Test with object.""" - self.assertRaises(errors.Error, - utils.ensure_is_injection, - object()) - - -class IsArgInjectionTests(unittest.TestCase): - """`is_arg_injection()` test cases.""" - - def test_with_instance(self): - """Test with instance.""" - self.assertTrue(utils.is_arg_injection(injections.Arg('value'))) - - def test_with_class(self): - """Test with class.""" - self.assertFalse(utils.is_arg_injection(injections.Arg)) - - def test_with_parent_class(self): - """Test with parent class.""" - self.assertFalse(utils.is_arg_injection(injections.Injection)) - - def test_with_string(self): - """Test with string.""" - self.assertFalse(utils.is_arg_injection('some_string')) - - def test_with_object(self): - """Test with object.""" - self.assertFalse(utils.is_arg_injection(object())) - - -class IsKwArgInjectionTests(unittest.TestCase): - """`is_kwarg_injection()` test cases.""" - - def test_with_instance(self): - """Test with instance.""" - self.assertTrue(utils.is_kwarg_injection(injections.KwArg('name', - 'value'))) - - def test_with_class(self): - """Test with class.""" - self.assertFalse(utils.is_kwarg_injection(injections.KwArg)) - - def test_with_parent_class(self): - """Test with parent class.""" - self.assertFalse(utils.is_kwarg_injection(injections.Injection)) - - def test_with_string(self): - """Test with string.""" - self.assertFalse(utils.is_kwarg_injection('some_string')) - - def test_with_object(self): - """Test with object.""" - self.assertFalse(utils.is_kwarg_injection(object())) - - -class IsAttributeInjectionTests(unittest.TestCase): - """`is_attribute_injection()` test cases.""" - - def test_with_instance(self): - """Test with instance.""" - self.assertTrue(utils.is_attribute_injection( - injections.Attribute('name', 'value'))) - - def test_with_class(self): - """Test with class.""" - self.assertFalse(utils.is_attribute_injection(injections.Attribute)) - - def test_with_parent_class(self): - """Test with parent class.""" - self.assertFalse(utils.is_attribute_injection(injections.Injection)) - - def test_with_string(self): - """Test with string.""" - self.assertFalse(utils.is_attribute_injection('some_string')) - - def test_with_object(self): - """Test with object.""" - self.assertFalse(utils.is_attribute_injection(object())) - - class IsCatalogTests(unittest.TestCase): """`is_catalog()` test cases."""