Merge remote-tracking branch 'origin/factory_and_singleton_positional_args'

This commit is contained in:
Roman Mogilatov 2015-10-19 17:31:42 +03:00
commit 402539ed7f
12 changed files with 472 additions and 122 deletions

View File

@ -18,6 +18,7 @@ from .providers import Callable
from .providers import Config
from .injections import Injection
from .injections import Arg
from .injections import KwArg
from .injections import Attribute
from .injections import Method
@ -27,6 +28,7 @@ from .utils import is_provider
from .utils import ensure_is_provider
from .utils import is_injection
from .utils import ensure_is_injection
from .utils import is_arg_injection
from .utils import is_kwarg_injection
from .utils import is_attribute_injection
from .utils import is_method_injection
@ -59,6 +61,7 @@ __all__ = (
# Injections
'Injection',
'Arg',
'KwArg',
'Attribute',
'Method',
@ -69,6 +72,7 @@ __all__ = (
'ensure_is_provider',
'is_injection',
'ensure_is_injection',
'is_arg_injection',
'is_kwarg_injection',
'is_attribute_injection',
'is_method_injection',

View File

@ -21,11 +21,10 @@ class Injection(object):
"""Base injection class."""
__IS_INJECTION__ = True
__slots__ = ('name', 'injectable', 'is_provider')
__slots__ = ('injectable', 'is_provider')
def __init__(self, name, injectable):
def __init__(self, injectable):
"""Initializer."""
self.name = name
self.injectable = injectable
self.is_provider = is_provider(injectable)
@ -37,19 +36,36 @@ class Injection(object):
return self.injectable
class KwArg(Injection):
class NamedInjection(Injection):
"""Base class of named injections."""
__slots__ = ('name',)
def __init__(self, name, injectable):
"""Initializer."""
self.name = name
super(NamedInjection, self).__init__(injectable)
class Arg(Injection):
"""Positional argument injection."""
__IS_ARG_INJECTION__ = True
class KwArg(NamedInjection):
"""Keyword argument injection."""
__IS_KWARG_INJECTION__ = True
class Attribute(Injection):
class Attribute(NamedInjection):
"""Attribute injection."""
__IS_ATTRIBUTE_INJECTION__ = True
class Method(Injection):
class Method(NamedInjection):
"""Method injection."""
__IS_METHOD_INJECTION__ = True

View File

@ -2,12 +2,16 @@
import six
from .injections import Arg
from .injections import KwArg
from .utils import ensure_is_provider
from .utils import is_injection
from .utils import is_arg_injection
from .utils import is_kwarg_injection
from .utils import is_attribute_injection
from .utils import is_method_injection
from .utils import get_injectable_args
from .utils import get_injectable_kwargs
from .utils import GLOBAL_LOCK
@ -104,33 +108,35 @@ class Factory(Provider):
Factory provider creates new instance of specified class on every call.
"""
__slots__ = ('provides', 'kwargs', 'attributes', 'methods')
__slots__ = ('provides', 'args', 'kwargs', 'attributes', 'methods')
def __init__(self, provides, *injections, **kwargs):
def __init__(self, provides, *args, **kwargs):
"""Initializer."""
if not callable(provides):
raise Error('Factory provider expects to get callable, ' +
'got {0} instead'.format(str(provides)))
self.provides = provides
self.args = tuple(Arg(arg) if not is_injection(arg) else arg
for arg in args
if not is_injection(arg) or is_arg_injection(arg))
self.kwargs = tuple(injection
for injection in injections
for injection in args
if is_kwarg_injection(injection))
if kwargs:
self.kwargs += tuple(KwArg(name, value)
for name, value in six.iteritems(kwargs))
self.attributes = tuple(injection
for injection in injections
for injection in args
if is_attribute_injection(injection))
self.methods = tuple(injection
for injection in injections
for injection in args
if is_method_injection(injection))
super(Factory, self).__init__()
def _provide(self, *args, **kwargs):
"""Return provided instance."""
instance = self.provides(*args,
**get_injectable_kwargs(kwargs,
self.kwargs))
instance = self.provides(*get_injectable_args(args, self.args),
**get_injectable_kwargs(kwargs, self.kwargs))
for attribute in self.attributes:
setattr(instance, attribute.name, attribute.value)
for method in self.methods:
@ -141,7 +147,7 @@ class Factory(Provider):
@property
def injections(self):
"""Return tuple of all injections."""
return self.kwargs + self.attributes + self.methods
return self.args + self.kwargs + self.attributes + self.methods
class Singleton(Provider):
@ -152,10 +158,10 @@ class Singleton(Provider):
__slots__ = ('instance', 'factory')
def __init__(self, provides, *injections, **kwargs):
def __init__(self, provides, *args, **kwargs):
"""Initializer."""
self.instance = None
self.factory = Factory(provides, *injections, **kwargs)
self.factory = Factory(provides, *args, **kwargs)
super(Singleton, self).__init__()
def _provide(self, *args, **kwargs):
@ -169,6 +175,11 @@ class Singleton(Provider):
"""Reset instance."""
self.instance = None
@property
def injections(self):
"""Return tuple of all injections."""
return self.factory.injections
class ExternalDependency(Provider):
"""External dependency provider.

View File

@ -1,6 +1,7 @@
"""Utils module."""
import threading
import itertools
import six
@ -41,6 +42,12 @@ def ensure_is_injection(instance):
return instance
def is_arg_injection(instance):
"""Check if instance is positional argument injection instance."""
return (not isinstance(instance, six.class_types) and
getattr(instance, '__IS_ARG_INJECTION__', False) is True)
def is_kwarg_injection(instance):
"""Check if instance is keyword argument injection instance."""
return (not isinstance(instance, six.class_types) and
@ -82,9 +89,14 @@ def ensure_is_catalog_bundle(instance):
return instance
def get_injectable_kwargs(kwargs, injections):
"""Return dictionary of kwargs, patched with injections."""
init_kwargs = dict(((injection.name, injection.value)
for injection in injections))
init_kwargs.update(kwargs)
return init_kwargs
def get_injectable_args(context_args, arg_injections):
"""Return tuple of positional args, patched with injections."""
return itertools.chain((arg.value for arg in arg_injections), context_args)
def get_injectable_kwargs(context_kwargs, kwarg_injections):
"""Return dictionary of keyword args, patched with injections."""
kwargs = dict((kwarg.name, kwarg.value)
for kwarg in kwarg_injections)
kwargs.update(context_kwargs)
return kwargs

View File

@ -11,15 +11,17 @@ follows `Semantic versioning`_
Development version
-------------------
- Add functionality for decorating classes with ``@di.inject``.
- Add functionality for creating ``di.AbstractCatalog`` provider bundles.
- Add enhancement for ``di.AbstractCatalog`` inheritance.
- Enhance ``di.AbstractCatalog`` inheritance.
- Add images for catalog "Writing catalogs" and "Operating with catalogs"
examples.
- Add support of Python 3.5.
- Add support of six 1.10.0.
- Add functionality for using positional argument injections with
``di.Factory`` and ``di.Singleton`` providers.
- Add optimization for ``di.Injection.value`` property that will compute
type of injection once, instead of doing this on every call.
- Add functionality for decorating classes with ``@di.inject``.
- Add support of Python 3.5.
- Add support of six 1.10.0.
- Add minor refactorings and code style fixes.
0.9.5

View File

@ -15,46 +15,57 @@ Nothing could be better than brief example:
Factory providers and __init__ injections
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``di.Factory`` takes a various number of keyword arguments that are
transformed into keyword argument injections. Every time, when ``di.Factory``
creates new one instance, keyword argument injections would be passed as an
instance's keyword arguments.
``di.Factory`` takes a various number of positional and keyword arguments that
are used as ``__init__()`` injections. Every time, when ``di.Factory``
creates new one instance, positional and keyword argument injections would be
passed as an instance's arguments.
All injectable values are provided *"as is"*, except of providers (subclasses
of ``di.Provider``). Providers will be called every time, when injection needs
to be done. For example, if injectable value of keyword argument injection is a
``di.Factory``, it will provide new one instance (as a result of its call) as
an injectable value every time, when injection needs to be done.
Such behaviour is very similar to the standard Python ``functools.partial``
object, except of one thing: all injectable values are provided
*"as is"*, except of providers (subclasses of ``di.Provider``). Providers
will be called every time, when injection needs to be done. For example,
if injectable value of injection is a ``di.Factory``, it will provide new one
instance (as a result of its call) every time, when injection needs to be done.
Example below is a little bit more complicated. It shows how to create
``di.Factory`` of particular class with ``__init__`` keyword argument
injections which injectable values are also provided by another factories:
``di.Factory`` of particular class with ``__init__()`` argument injections
which injectable values are also provided by another factories:
.. note::
Current keyword argument injections syntax (in an example below) is a
**simplified one**. Full syntax and other types of injections could be
found in sections below.
Current positional and keyword argument injections syntax (in the examples
below) is a **simplified one** version of full syntax. Examples of full
syntax and other types of injections could be found in sections below.
While keyword argument injections may be the best way of passing
injections, current simplified syntax might be the preferable one and
could be widely used.
While positional / keyword argument injections may be the best way of
passing injections, current simplified syntax might be the preferable one
and could be widely used.
.. image:: /images/providers/factory_init_injections.png
:width: 90%
:align: center
.. literalinclude:: ../../examples/providers/factory_init_injections.py
Example of usage positional argument injections:
.. literalinclude:: ../../examples/providers/factory_init_args.py
:language: python
Example of usage keyword argument injections:
.. literalinclude:: ../../examples/providers/factory_init_kwargs.py
:language: python
Factory providers and __init__ injections priority
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Next example shows how ``di.Factory`` provider deals with positional and
keyword ``__init__`` context arguments. In few words, ``di.Factory``
provider fully passes positional context arguments to class's ``__init__``
method, but keyword context arguments have priority on predefined keyword
argument injections.
keyword ``__init__()`` context arguments. In few words, ``di.Factory``
behaviour here is very like a standard Python ``functools.partial``:
- Positional context arguments will be appended after ``di.Factory``
positional injections.
- Keyword context arguments have priority on ``di.Factory`` keyword injections
and will be merged over them.
So, please, follow the example below:
@ -67,7 +78,7 @@ So, please, follow the example below:
Factory providers and other types of injections
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Objects can take dependencies in different forms(some objects take init
Objects can take dependencies in different forms (some objects take init
arguments, other use attributes setting or method calls). It affects how
such objects are created and initialized.
@ -78,8 +89,11 @@ All of those instructions are defined in ``di.injections`` module and are
subclasses of ``di.injections.Injection`` (shortcut ``di.Injection``). There
are several types of injections that are used by ``di.Factory`` provider:
+ ``di.Arg`` - injection is done by passing injectable value in object's
``__init__()`` method in time of object's creation as positional argument.
Takes injectable value only.
+ ``di.KwArg`` - injection is done by passing injectable value in object's
``__init__()`` method in time of object's creation via keyword argument.
``__init__()`` method in time of object's creation as keyword argument.
Takes keyword name of ``__init__()`` argument and injectable value.
+ ``di.Attribute`` - injection is done by setting specified attribute with
injectable value right after object's creation. Takes attribute's name

View File

@ -0,0 +1,34 @@
"""`di.Factory` providers with init positional injections example."""
import dependency_injector as di
class User(object):
"""Example class User."""
def __init__(self, main_photo):
"""Initializer."""
self.main_photo = main_photo
super(User, self).__init__()
class Photo(object):
"""Example class Photo."""
# User and Photo factories:
photos_factory = di.Factory(Photo)
users_factory = di.Factory(User, photos_factory)
# Creating several User objects:
user1 = users_factory() # Same as: user1 = User(Photo())
user2 = users_factory() # Same as: user2 = User(Photo())
# Making some asserts:
assert isinstance(user1, User)
assert isinstance(user1.main_photo, Photo)
assert isinstance(user2, User)
assert isinstance(user2.main_photo, Photo)
assert user1 is not user2
assert user1.main_photo is not user2.main_photo

View File

@ -62,7 +62,8 @@ assert user1.credit_card is not user2.credit_card
main_photo_mock = Photo()
credit_card_mock = CreditCard()
user3 = users_factory(3, main_photo=main_photo_mock,
user3 = users_factory(3,
main_photo=main_photo_mock,
credit_card=credit_card_mock)
assert user3.id == 3

View File

@ -1,4 +1,4 @@
"""`di.Factory` providers with init injections example."""
"""`di.Factory` providers with init keyword injections example."""
import dependency_injector as di
@ -17,8 +17,7 @@ class Photo(object):
# User and Photo factories:
photos_factory = di.Factory(Photo)
users_factory = di.Factory(User,
main_photo=photos_factory)
users_factory = di.Factory(User, main_photo=photos_factory)
# Creating several User objects:
user1 = users_factory() # Same as: user1 = User(main_photo=Photo())

View File

@ -9,18 +9,17 @@ class InjectionTests(unittest.TestCase):
def test_init(self):
"""Test Injection creation and initialization."""
injection = di.Injection('some_arg_name', 'some_value')
self.assertEqual(injection.name, 'some_arg_name')
injection = di.Injection('some_value')
self.assertEqual(injection.injectable, 'some_value')
def test_value_with_scalar_injectable(self):
"""Test Injection value property with scalar value."""
injection = di.Injection('some_arg_name', 'some_value')
injection = di.Injection('some_value')
self.assertEqual(injection.value, 'some_value')
def test_value_with_provider_injectable(self):
"""Test Injection value property with provider."""
injection = di.Injection('some_arg_name', di.Factory(object))
injection = di.Injection(di.Factory(object))
self.assertIsInstance(injection.value, object)
def test_value_with_catalog_bundle_injectable(self):
@ -29,12 +28,20 @@ class InjectionTests(unittest.TestCase):
"""Test catalog."""
provider = di.Provider()
injection = di.Injection('some_arg_name',
TestCatalog.Bundle(TestCatalog.provider))
injection = di.Injection(TestCatalog.Bundle(TestCatalog.provider))
self.assertIsInstance(injection.value, TestCatalog.Bundle)
class ArgTests(unittest.TestCase):
"""Positional arg injection test cases."""
def test_init(self):
"""Test Arg creation and initialization."""
injection = di.Arg('some_value')
self.assertEqual(injection.injectable, 'some_value')
class KwArgTests(unittest.TestCase):
"""Keyword arg injection test cases."""

View File

@ -4,6 +4,34 @@ import unittest2 as unittest
import dependency_injector as di
class Example(object):
"""Example class for Factory provider tests."""
def __init__(self, init_arg1=None, init_arg2=None):
"""Initializer.
:param init_arg1:
:param init_arg2:
:return:
"""
self.init_arg1 = init_arg1
self.init_arg2 = init_arg2
self.attribute1 = None
self.attribute2 = None
self.method1_value = None
self.method2_value = None
def method1(self, value):
"""Setter method 1."""
self.method1_value = value
def method2(self, value):
"""Setter method 2."""
self.method2_value = value
class ProviderTests(unittest.TestCase):
"""Provider test cases."""
@ -132,36 +160,9 @@ class DelegateTests(unittest.TestCase):
class FactoryTests(unittest.TestCase):
"""Factory test cases."""
class Example(object):
"""Example class for Factory provider tests."""
def __init__(self, init_arg1=None, init_arg2=None):
"""Initializer.
:param init_arg1:
:param init_arg2:
:return:
"""
self.init_arg1 = init_arg1
self.init_arg2 = init_arg2
self.attribute1 = None
self.attribute2 = None
self.method1_value = None
self.method2_value = None
def method1(self, value):
"""Setter method 1."""
self.method1_value = value
def method2(self, value):
"""Setter method 2."""
self.method2_value = value
def test_is_provider(self):
"""Test `is_provider` check."""
self.assertTrue(di.is_provider(di.Factory(self.Example)))
self.assertTrue(di.is_provider(di.Factory(Example)))
def test_init_with_callable(self):
"""Test creation of provider with a callable."""
@ -173,22 +174,20 @@ class FactoryTests(unittest.TestCase):
def test_call(self):
"""Test creation of new instances."""
provider = di.Factory(self.Example)
provider = di.Factory(Example)
instance1 = provider()
instance2 = provider()
self.assertIsNot(instance1, instance2)
self.assertIsInstance(instance1, self.Example)
self.assertIsInstance(instance2, self.Example)
self.assertIsInstance(instance1, Example)
self.assertIsInstance(instance2, Example)
def test_call_with_init_args_simplified_syntax(self):
"""Test creation of new instances with init args injections.
def test_call_with_init_positional_args(self):
"""Test creation of new instances with init positional args.
New simplified syntax.
"""
provider = di.Factory(self.Example,
init_arg1='i1',
init_arg2='i2')
provider = di.Factory(Example, 'i1', 'i2')
instance1 = provider()
instance2 = provider()
@ -200,13 +199,56 @@ class FactoryTests(unittest.TestCase):
self.assertEqual(instance2.init_arg2, 'i2')
self.assertIsNot(instance1, instance2)
self.assertIsInstance(instance1, self.Example)
self.assertIsInstance(instance2, self.Example)
self.assertIsInstance(instance1, Example)
self.assertIsInstance(instance2, Example)
def test_call_with_init_args_old_syntax(self):
"""Test creation of new instances with init args injections."""
provider = di.Factory(self.Example,
di.KwArg('init_arg1', 'i1'),
def test_call_with_init_keyword_args(self):
"""Test creation of new instances with init keyword args.
New simplified syntax.
"""
provider = di.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):
"""Test creation of new instances with init positional and keyword args.
Simplified syntax of positional and keyword arg injections.
"""
provider = di.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_init_positional_and_keyword_args_extended_syntax(self):
"""Test creation of new instances with init positional and keyword args.
Extended syntax of positional and keyword arg injections.
"""
provider = di.Factory(Example,
di.Arg('i1'),
di.KwArg('init_arg2', 'i2'))
instance1 = provider()
@ -219,12 +261,12 @@ class FactoryTests(unittest.TestCase):
self.assertEqual(instance2.init_arg2, 'i2')
self.assertIsNot(instance1, instance2)
self.assertIsInstance(instance1, self.Example)
self.assertIsInstance(instance2, self.Example)
self.assertIsInstance(instance1, Example)
self.assertIsInstance(instance2, Example)
def test_call_with_attributes(self):
"""Test creation of new instances with attribute injections."""
provider = di.Factory(self.Example,
provider = di.Factory(Example,
di.Attribute('attribute1', 'a1'),
di.Attribute('attribute2', 'a2'))
@ -238,12 +280,12 @@ class FactoryTests(unittest.TestCase):
self.assertEqual(instance2.attribute2, 'a2')
self.assertIsNot(instance1, instance2)
self.assertIsInstance(instance1, self.Example)
self.assertIsInstance(instance2, self.Example)
self.assertIsInstance(instance1, Example)
self.assertIsInstance(instance2, Example)
def test_call_with_methods(self):
"""Test creation of new instances with method injections."""
provider = di.Factory(self.Example,
provider = di.Factory(Example,
di.Method('method1', 'm1'),
di.Method('method2', 'm2'))
@ -257,12 +299,12 @@ class FactoryTests(unittest.TestCase):
self.assertEqual(instance2.method2_value, 'm2')
self.assertIsNot(instance1, instance2)
self.assertIsInstance(instance1, self.Example)
self.assertIsInstance(instance2, self.Example)
self.assertIsInstance(instance1, Example)
self.assertIsInstance(instance2, Example)
def test_call_with_context_args(self):
"""Test creation of new instances with context args."""
provider = di.Factory(self.Example)
provider = di.Factory(Example)
instance = provider(11, 22)
self.assertEqual(instance.init_arg1, 11)
@ -270,7 +312,7 @@ class FactoryTests(unittest.TestCase):
def test_call_with_context_kwargs(self):
"""Test creation of new instances with context kwargs."""
provider = di.Factory(self.Example,
provider = di.Factory(Example,
di.KwArg('init_arg1', 1))
instance1 = provider(init_arg2=22)
@ -283,7 +325,7 @@ class FactoryTests(unittest.TestCase):
def test_call_overridden(self):
"""Test creation of new instances on overridden provider."""
provider = di.Factory(self.Example)
provider = di.Factory(Example)
overriding_provider1 = di.Factory(dict)
overriding_provider2 = di.Factory(list)
@ -298,9 +340,9 @@ class FactoryTests(unittest.TestCase):
self.assertIsInstance(instance2, list)
def test_injections(self):
"""Test getting a full list of injections using Factory.injections."""
provider = di.Factory(self.Example,
di.KwArg('init_arg1', 1),
"""Test getting a full list of injections using injections property."""
provider = di.Factory(Example,
di.Arg(1),
di.KwArg('init_arg2', 2),
di.Attribute('attribute1', 3),
di.Attribute('attribute2', 4),
@ -315,16 +357,199 @@ class FactoryTests(unittest.TestCase):
class SingletonTests(unittest.TestCase):
"""Singleton test cases."""
def test_is_provider(self):
"""Test `is_provider` check."""
self.assertTrue(di.is_provider(di.Singleton(Example)))
def test_init_with_callable(self):
"""Test creation of provider with a callable."""
self.assertTrue(di.Singleton(credits))
def test_init_with_not_callable(self):
"""Test creation of provider with not a callable."""
self.assertRaises(di.Error, di.Singleton, 123)
def test_call(self):
"""Test creation and returning of single object."""
provider = di.Singleton(object)
"""Test getting of instances."""
provider = di.Singleton(Example)
instance1 = provider()
instance2 = provider()
self.assertIs(instance1, instance2)
self.assertIsInstance(instance1, Example)
self.assertIsInstance(instance2, Example)
def test_call_with_init_positional_args(self):
"""Test getting of instances with init positional args.
New simplified syntax.
"""
provider = di.Singleton(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.assertIs(instance1, instance2)
self.assertIsInstance(instance1, Example)
self.assertIsInstance(instance2, Example)
def test_call_with_init_keyword_args(self):
"""Test getting of instances with init keyword args.
New simplified syntax.
"""
provider = di.Singleton(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.assertIs(instance1, instance2)
self.assertIsInstance(instance1, Example)
self.assertIsInstance(instance2, Example)
def test_call_with_init_positional_and_keyword_args(self):
"""Test getting of instances with init positional and keyword args.
Simplified syntax of positional and keyword arg injections.
"""
provider = di.Singleton(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.assertIs(instance1, instance2)
self.assertIsInstance(instance1, Example)
self.assertIsInstance(instance2, Example)
def test_call_with_init_positional_and_keyword_args_extended_syntax(self):
"""Test getting of instances with init positional and keyword args.
Extended syntax of positional and keyword arg injections.
"""
provider = di.Singleton(Example,
di.Arg('i1'),
di.KwArg('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.assertIs(instance1, instance2)
self.assertIsInstance(instance1, Example)
self.assertIsInstance(instance2, Example)
def test_call_with_attributes(self):
"""Test getting of instances with attribute injections."""
provider = di.Singleton(Example,
di.Attribute('attribute1', 'a1'),
di.Attribute('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.assertIs(instance1, instance2)
self.assertIsInstance(instance1, Example)
self.assertIsInstance(instance2, Example)
def test_call_with_methods(self):
"""Test getting of instances with method injections."""
provider = di.Singleton(Example,
di.Method('method1', 'm1'),
di.Method('method2', 'm2'))
instance1 = provider()
instance2 = provider()
self.assertEqual(instance1.method1_value, 'm1')
self.assertEqual(instance1.method2_value, 'm2')
self.assertEqual(instance2.method1_value, 'm1')
self.assertEqual(instance2.method2_value, 'm2')
self.assertIs(instance1, instance2)
self.assertIsInstance(instance1, Example)
self.assertIsInstance(instance2, Example)
def test_call_with_context_args(self):
"""Test getting of instances with context args."""
provider = di.Singleton(Example)
instance = provider(11, 22)
self.assertEqual(instance.init_arg1, 11)
self.assertEqual(instance.init_arg2, 22)
def test_call_with_context_kwargs(self):
"""Test getting of instances with context kwargs."""
provider = di.Singleton(Example,
di.KwArg('init_arg1', 1))
instance1 = provider(init_arg2=22)
self.assertEqual(instance1.init_arg1, 1)
self.assertEqual(instance1.init_arg2, 22)
# Instance is created earlier
instance1 = provider(init_arg1=11, init_arg2=22)
self.assertEqual(instance1.init_arg1, 1)
self.assertEqual(instance1.init_arg2, 22)
def test_call_overridden(self):
"""Test getting of instances on overridden provider."""
provider = di.Singleton(Example)
overriding_provider1 = di.Singleton(dict)
overriding_provider2 = di.Singleton(object)
provider.override(overriding_provider1)
provider.override(overriding_provider2)
instance1 = provider()
instance2 = provider()
self.assertIs(instance1, instance2)
self.assertIsInstance(instance1, object)
self.assertIsInstance(instance2, object)
self.assertIs(instance1, instance2)
def test_injections(self):
"""Test getting a full list of injections using injections property."""
provider = di.Singleton(Example,
di.Arg(1),
di.KwArg('init_arg2', 2),
di.Attribute('attribute1', 3),
di.Attribute('attribute2', 4),
di.Method('method1', 5),
di.Method('method2', 6))
injections = provider.injections
self.assertEquals(len(injections), 6)
def test_reset(self):
"""Test creation and reset of single object."""

View File

@ -68,10 +68,11 @@ class IsInjectionTests(unittest.TestCase):
def test_with_instance(self):
"""Test with instance."""
self.assertTrue(di.is_injection(di.Injection('name', 'value')))
self.assertTrue(di.is_injection(di.Injection('value')))
def test_with_subclass_instances(self):
"""Test with subclass instances."""
self.assertTrue(di.is_injection(di.Arg('value')))
self.assertTrue(di.is_injection(di.KwArg('name', 'value')))
self.assertTrue(di.is_injection(di.Attribute('name', 'value')))
self.assertTrue(di.is_injection(di.Method('name', 'value')))
@ -94,7 +95,7 @@ class EnsureIsInjectionTests(unittest.TestCase):
def test_with_instance(self):
"""Test with instance."""
injection = di.Injection('name', 'value')
injection = di.Injection('value')
self.assertIs(di.ensure_is_injection(injection), injection)
def test_with_class(self):
@ -110,6 +111,30 @@ class EnsureIsInjectionTests(unittest.TestCase):
self.assertRaises(di.Error, di.ensure_is_injection, object())
class IsArgInjectionTests(unittest.TestCase):
"""`is_arg_injection()` test cases."""
def test_with_instance(self):
"""Test with instance."""
self.assertTrue(di.is_arg_injection(di.Arg('value')))
def test_with_class(self):
"""Test with class."""
self.assertFalse(di.is_arg_injection(di.Arg))
def test_with_parent_class(self):
"""Test with parent class."""
self.assertFalse(di.is_arg_injection(di.Injection))
def test_with_string(self):
"""Test with string."""
self.assertFalse(di.is_arg_injection('some_string'))
def test_with_object(self):
"""Test with object."""
self.assertFalse(di.is_arg_injection(object()))
class IsKwArgInjectionTests(unittest.TestCase):
"""`is_kwarg_injection()` test cases."""