mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-25 11:04:01 +03:00
Merge remote-tracking branch 'origin/factory_and_singleton_positional_args'
This commit is contained in:
commit
402539ed7f
|
@ -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',
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
34
examples/providers/factory_init_args.py
Normal file
34
examples/providers/factory_init_args.py
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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())
|
|
@ -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."""
|
||||
|
||||
|
|
|
@ -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."""
|
||||
|
|
|
@ -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."""
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user