mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-22 09:36:48 +03:00
Add catalog subsets
This commit is contained in:
parent
b1cb5b2d56
commit
3e8232e9db
|
@ -1,6 +1,7 @@
|
|||
"""Dependency injector."""
|
||||
|
||||
from .catalog import AbstractCatalog
|
||||
from .catalog import CatalogSubset
|
||||
from .catalog import override
|
||||
|
||||
from .providers import Provider
|
||||
|
@ -30,6 +31,7 @@ from .utils import is_kwarg_injection
|
|||
from .utils import is_attribute_injection
|
||||
from .utils import is_method_injection
|
||||
from .utils import is_catalog
|
||||
from .utils import is_catalog_subset
|
||||
|
||||
from .errors import Error
|
||||
|
||||
|
@ -37,6 +39,7 @@ from .errors import Error
|
|||
__all__ = (
|
||||
# Catalogs
|
||||
'AbstractCatalog',
|
||||
'CatalogSubset',
|
||||
'override',
|
||||
|
||||
# Providers
|
||||
|
@ -69,6 +72,7 @@ __all__ = (
|
|||
'is_attribute_injection',
|
||||
'is_method_injection',
|
||||
'is_catalog',
|
||||
'is_catalog_subset',
|
||||
|
||||
# Errors
|
||||
'Error',
|
||||
|
|
|
@ -31,6 +31,10 @@ class CatalogMetaClass(type):
|
|||
attributes['providers'] = providers
|
||||
return type.__new__(mcs, class_name, bases, attributes)
|
||||
|
||||
def __repr__(cls):
|
||||
"""Return string representation of the catalog class."""
|
||||
return '<Catalog "' + '.'.join((cls.__module__, cls.__name__)) + '">'
|
||||
|
||||
|
||||
@six.add_metaclass(CatalogMetaClass)
|
||||
class AbstractCatalog(object):
|
||||
|
@ -53,22 +57,20 @@ class AbstractCatalog(object):
|
|||
inherited_providers = dict()
|
||||
|
||||
__IS_CATALOG__ = True
|
||||
__slots__ = ('used_providers',)
|
||||
|
||||
def __init__(self, *used_providers):
|
||||
"""Initializer."""
|
||||
self.used_providers = set(used_providers)
|
||||
def __new__(cls, *providers):
|
||||
"""Catalog constructor.
|
||||
|
||||
def __getattribute__(self, item):
|
||||
"""Return providers."""
|
||||
attribute = super(AbstractCatalog, self).__getattribute__(item)
|
||||
if item in ('providers', 'used_providers', '__class__'):
|
||||
return attribute
|
||||
Catalogs are declaratives entities that could not be instantiated.
|
||||
Catalog constructor is designed to produce subsets of catalog
|
||||
providers.
|
||||
"""
|
||||
return CatalogSubset(catalog=cls, providers=providers)
|
||||
|
||||
if attribute not in self.used_providers:
|
||||
raise Error('Provider \'{0}\' '.format(item) +
|
||||
'is not listed in dependencies')
|
||||
return attribute
|
||||
@classmethod
|
||||
def is_subset_owner(cls, subset):
|
||||
"""Check if catalog is subset owner."""
|
||||
return subset.catalog is cls
|
||||
|
||||
@classmethod
|
||||
def filter(cls, provider_type):
|
||||
|
@ -86,6 +88,68 @@ class AbstractCatalog(object):
|
|||
for name, provider in six.iteritems(overriding.cls_providers):
|
||||
cls.providers[name].override(provider)
|
||||
|
||||
@classmethod
|
||||
def get(cls, name):
|
||||
"""Return provider with specified name or raises error."""
|
||||
try:
|
||||
return cls.providers[name]
|
||||
except KeyError:
|
||||
raise Error('{0} has no provider with such name - {1}'.format(
|
||||
cls, name))
|
||||
|
||||
@classmethod
|
||||
def has(cls, name):
|
||||
"""Check if there is provider with certain name."""
|
||||
return name in cls.providers
|
||||
|
||||
|
||||
class CatalogSubset(object):
|
||||
"""Subset of catalog providers."""
|
||||
|
||||
__IS_SUBSET__ = True
|
||||
__slots__ = ('catalog', 'available_providers', 'providers', '__dict__')
|
||||
|
||||
def __init__(self, catalog, providers):
|
||||
"""Initializer."""
|
||||
self.catalog = catalog
|
||||
self.available_providers = set(providers)
|
||||
self.providers = dict()
|
||||
for provider_name in self.available_providers:
|
||||
try:
|
||||
provider = self.catalog.providers[provider_name]
|
||||
except KeyError:
|
||||
raise Error('Subset could not add "{0}" provider in scope, '
|
||||
'because {1} has no provider with '
|
||||
'such name'.format(provider_name, self.catalog))
|
||||
else:
|
||||
self.providers[provider_name] = provider
|
||||
self.__dict__.update(self.providers)
|
||||
super(CatalogSubset, self).__init__()
|
||||
|
||||
def get(self, name):
|
||||
"""Return provider with specified name or raises error."""
|
||||
try:
|
||||
return self.providers[name]
|
||||
except KeyError:
|
||||
self._raise_undefined_provider_error(name)
|
||||
|
||||
def has(self, name):
|
||||
"""Check if there is provider with certain name."""
|
||||
return name in self.providers
|
||||
|
||||
def __getattr__(self, item):
|
||||
"""Raise an error on every attempt to get undefined provider."""
|
||||
self._raise_undefined_provider_error(item)
|
||||
|
||||
def __repr__(self):
|
||||
"""Return string representation of subset."""
|
||||
return '<Subset ({0}), {1}>'.format(
|
||||
', '.join(self.available_providers), self.catalog)
|
||||
|
||||
def _raise_undefined_provider_error(self, name):
|
||||
"""Raise error for cases when there is no such provider in subset."""
|
||||
raise Error('Provider "{0}" is not a part of {1}'.format(name, self))
|
||||
|
||||
|
||||
def override(catalog):
|
||||
"""Catalog overriding decorator."""
|
||||
|
|
|
@ -62,6 +62,12 @@ def is_catalog(instance):
|
|||
getattr(instance, '__IS_CATALOG__', False) is True)
|
||||
|
||||
|
||||
def is_catalog_subset(instance):
|
||||
"""Check if instance is catalog subset instance."""
|
||||
return (not isinstance(instance, six.class_types) and
|
||||
getattr(instance, '__IS_SUBSET__', False) is True)
|
||||
|
||||
|
||||
def get_injectable_kwargs(kwargs, injections):
|
||||
"""Return dictionary of kwargs, patched with injections."""
|
||||
init_kwargs = dict(((injection.name, injection.value)
|
||||
|
|
|
@ -16,76 +16,10 @@ Also, for both of these and some other cases, it might be useful to attach
|
|||
some init / shutdown functionality or something else, that deals with group
|
||||
of providers.
|
||||
|
||||
Writing catalogs
|
||||
----------------
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
Catalogs have to extend base catalog class ``di.AbstractCatalog``.
|
||||
|
||||
Providers have to be defined like catalog's attributes. Every provider in
|
||||
catalog has name. This name should follow ``some_provider`` convention,
|
||||
that is standard naming convention for attribute names in Python.
|
||||
|
||||
.. note::
|
||||
|
||||
It might be useful to add such ``""":type: (di.Provider) -> Object1"""``
|
||||
documentation blocks one line after provider definition for every provider.
|
||||
It will help code analyzing tools and IDE's to understand that variable
|
||||
above contains some callable object, that returns particular instance
|
||||
in a result of call.
|
||||
|
||||
Example:
|
||||
|
||||
.. image:: /images/catalogs/simple.png
|
||||
:width: 100%
|
||||
:align: center
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/simple.py
|
||||
:language: python
|
||||
|
||||
Operating with catalog providers
|
||||
--------------------------------
|
||||
|
||||
``di.AbstractCatalog`` has several features that could be useful for some kind
|
||||
of operations on catalog's providers:
|
||||
|
||||
- ``di.AbstractCatalog.providers`` is read-only attribute that contains
|
||||
``dict`` of all catalog providers, including providers that are inherited
|
||||
from parent catalogs, where key is the name of provider and value is
|
||||
provider itself.
|
||||
- ``di.AbstractCatalog.cls_providers`` is read-only attribute contains ``dict``
|
||||
of current catalog providers, where key is the name of provider and value is
|
||||
provider itself.
|
||||
- ``di.AbstractCatalog.inherited_providers`` is read-only attribute contains
|
||||
``dict`` of all providers that are inherited from parent catalogs, where key
|
||||
is the name of provider and value is provider itself.
|
||||
- ``di.AbstractCatalog.filter(provider_type=di.Provider)`` is a class method
|
||||
that could be used for filtering catalog providers by provider types
|
||||
(for example, for getting all ``di.Factory`` providers).
|
||||
``di.AbstractCatalog.filter()`` method use ``di.AbstractCatalog.providers``.
|
||||
|
||||
Example:
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/operating_with_providers.py
|
||||
:language: python
|
||||
|
||||
Overriding of catalogs
|
||||
----------------------
|
||||
|
||||
Catalogs can be overridden by other catalogs. This, actually, means that
|
||||
all of the providers from overriding catalog will override providers with the
|
||||
same names in overridden catalog.
|
||||
|
||||
There are two ways to override catalog by another catalog:
|
||||
|
||||
- Use ``di.AbstractCatalog.override(AnotherCatalog)`` method.
|
||||
- Use ``@di.override(AnotherCatalog)`` class decorator.
|
||||
|
||||
Example of overriding catalog using ``di.AbstractCatalog.override()`` method:
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/override.py
|
||||
:language: python
|
||||
|
||||
Example of overriding catalog using ``@di.override()`` decorator:
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/override_decorator.py
|
||||
:language: python
|
||||
writing
|
||||
operating
|
||||
subsets
|
||||
overriding
|
||||
|
|
29
docs/catalogs/operating.rst
Normal file
29
docs/catalogs/operating.rst
Normal file
|
@ -0,0 +1,29 @@
|
|||
Operating with catalogs
|
||||
-----------------------
|
||||
|
||||
``di.AbstractCatalog`` has several features that could be useful for some kind
|
||||
of operations on catalog's providers:
|
||||
|
||||
- ``di.AbstractCatalog.providers`` is read-only attribute that contains
|
||||
``dict`` of all catalog providers, including providers that are inherited
|
||||
from parent catalogs, where key is the name of provider and value is
|
||||
provider itself.
|
||||
- ``di.AbstractCatalog.cls_providers`` is read-only attribute contains ``dict``
|
||||
of current catalog providers, where key is the name of provider and value is
|
||||
provider itself.
|
||||
- ``di.AbstractCatalog.inherited_providers`` is read-only attribute contains
|
||||
``dict`` of all providers that are inherited from parent catalogs, where key
|
||||
is the name of provider and value is provider itself.
|
||||
- ``di.AbstractCatalog.filter(provider_type=di.Provider)`` is a class method
|
||||
that could be used for filtering catalog providers by provider types
|
||||
(for example, for getting all ``di.Factory`` providers).
|
||||
``di.AbstractCatalog.filter()`` method use ``di.AbstractCatalog.providers``.
|
||||
|
||||
Example:
|
||||
|
||||
.. image:: /images/catalogs/operating_with_providers.png
|
||||
:width: 100%
|
||||
:align: center
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/operating_with_providers.py
|
||||
:language: python
|
22
docs/catalogs/overriding.rst
Normal file
22
docs/catalogs/overriding.rst
Normal file
|
@ -0,0 +1,22 @@
|
|||
Overriding of catalogs
|
||||
----------------------
|
||||
|
||||
Catalogs can be overridden by other catalogs. This, actually, means that
|
||||
all of the providers from overriding catalog will override providers with the
|
||||
same names in overridden catalog.
|
||||
|
||||
There are two ways to override catalog by another catalog:
|
||||
|
||||
- Use ``di.AbstractCatalog.override(AnotherCatalog)`` method.
|
||||
- Use ``@di.override(AnotherCatalog)`` class decorator.
|
||||
|
||||
Example of overriding catalog using ``di.AbstractCatalog.override()`` method:
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/override.py
|
||||
:language: python
|
||||
|
||||
Example of overriding catalog using ``@di.override()`` decorator:
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/override_decorator.py
|
||||
:language: python
|
||||
|
19
docs/catalogs/subsets.rst
Normal file
19
docs/catalogs/subsets.rst
Normal file
|
@ -0,0 +1,19 @@
|
|||
Creating catalog subsets
|
||||
------------------------
|
||||
|
||||
``di.AbstractCatalog`` subset is a limited collection of catalog providers.
|
||||
While catalog could be used as a centralized place for particular providers
|
||||
group, such subsets of catalog providers can be used for creating several
|
||||
limited scopes that could be passed to different subsystems.
|
||||
|
||||
``di.AbstractCatalog`` subsets could be created by instantiating of particular
|
||||
catalog with passing provider names to the constructor.
|
||||
|
||||
Example:
|
||||
|
||||
.. image:: /images/catalogs/subsets.png
|
||||
:width: 100%
|
||||
:align: center
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/subsets.py
|
||||
:language: python
|
25
docs/catalogs/writing.rst
Normal file
25
docs/catalogs/writing.rst
Normal file
|
@ -0,0 +1,25 @@
|
|||
Writing catalogs
|
||||
----------------
|
||||
|
||||
Catalogs have to extend base catalog class ``di.AbstractCatalog``.
|
||||
|
||||
Providers have to be defined like catalog's attributes. Every provider in
|
||||
catalog has name. This name should follow ``some_provider`` convention,
|
||||
that is standard naming convention for attribute names in Python.
|
||||
|
||||
.. note::
|
||||
|
||||
It might be useful to add such ``""":type: (di.Provider) -> Object1"""``
|
||||
docstrings just on the next line after provider's definition. It will
|
||||
help code analyzing tools and IDE's to understand that variable above
|
||||
contains some callable object, that returns particular instance as a
|
||||
result of its call.
|
||||
|
||||
Here is an simple example of catalog with several factories:
|
||||
|
||||
.. image:: /images/catalogs/writing_catalogs.png
|
||||
:width: 85%
|
||||
:align: center
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/writing_catalogs.py
|
||||
:language: python
|
BIN
docs/images/catalogs/operating_with_providers.png
Normal file
BIN
docs/images/catalogs/operating_with_providers.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 51 KiB |
Binary file not shown.
Before Width: | Height: | Size: 31 KiB |
BIN
docs/images/catalogs/subsets.png
Normal file
BIN
docs/images/catalogs/subsets.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 96 KiB |
BIN
docs/images/catalogs/writing_catalogs.png
Normal file
BIN
docs/images/catalogs/writing_catalogs.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
|
@ -12,7 +12,10 @@ Development version
|
|||
-------------------
|
||||
|
||||
- Add functionality for decorating classes with ``@di.inject``.
|
||||
- Add functionality for creating ``di.AbstractCatalog`` subsets.
|
||||
- Add enhancement for ``di.AbstractCatalog`` inheritance.
|
||||
- Add images for catalog "Writing catalogs" and "Operating with catalogs"
|
||||
examples.
|
||||
- Add minor refactorings and code style fixes.
|
||||
|
||||
0.9.5
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
"""Catalog example."""
|
||||
|
||||
import collections
|
||||
import dependency_injector as di
|
||||
|
||||
|
||||
# Creating some example classes:
|
||||
Object1 = collections.namedtuple('Object1', ['arg1', 'arg2'])
|
||||
Object2 = collections.namedtuple('Object2', ['object1'])
|
||||
|
||||
|
||||
class Catalog(di.AbstractCatalog):
|
||||
"""Providers catalog."""
|
||||
|
||||
object1_factory = di.Factory(Object1,
|
||||
arg1=1,
|
||||
arg2=2)
|
||||
""":type: (di.Provider) -> Object1"""
|
||||
|
||||
object2_factory = di.Factory(Object2,
|
||||
object1=object1_factory)
|
||||
""":type: (di.Provider) -> Object2"""
|
||||
|
||||
# Creating some objects:
|
||||
object2_1 = Catalog.object2_factory()
|
||||
object2_2 = Catalog.object2_factory()
|
||||
|
||||
# Making some asserts:
|
||||
assert object2_1 is not object2_2
|
||||
|
||||
assert isinstance(object2_1, Object2)
|
||||
assert object2_1.object1.arg1 == 1
|
||||
assert object2_1.object1.arg2 == 2
|
||||
|
||||
assert isinstance(object2_2, Object2)
|
||||
assert object2_2.object1.arg1 == 1
|
||||
assert object2_2.object1.arg2 == 2
|
59
examples/catalogs/subsets.py
Normal file
59
examples/catalogs/subsets.py
Normal file
|
@ -0,0 +1,59 @@
|
|||
"""Catalog subsets example."""
|
||||
|
||||
import dependency_injector as di
|
||||
|
||||
|
||||
# Declaring example services catalog:
|
||||
class Services(di.AbstractCatalog):
|
||||
"""Example catalog of service providers."""
|
||||
|
||||
users = di.Provider()
|
||||
|
||||
auth = di.Provider()
|
||||
|
||||
photos = di.Provider()
|
||||
|
||||
|
||||
# Declaring example base class for some web views:
|
||||
class BaseWebView(object):
|
||||
"""Example base class of web view."""
|
||||
|
||||
def __init__(self, services):
|
||||
"""Initializer.
|
||||
|
||||
:type services: Services
|
||||
:param services: Subset of service providers
|
||||
"""
|
||||
self.services = services
|
||||
|
||||
|
||||
# Declaring several example web views:
|
||||
class AuthView(BaseWebView):
|
||||
"""Example auth web view."""
|
||||
|
||||
|
||||
class PhotosView(BaseWebView):
|
||||
"""Example photo processing web view."""
|
||||
|
||||
# Creating example views with appropriate service provider subsets:
|
||||
auth_view = AuthView(Services('users', 'auth'))
|
||||
photos_view = PhotosView(Services('users', 'photos'))
|
||||
|
||||
# Making some asserts:
|
||||
assert auth_view.services.users is Services.users
|
||||
assert auth_view.services.auth is Services.auth
|
||||
try:
|
||||
auth_view.services.photos
|
||||
except di.Error:
|
||||
# `photos` service provider is not in scope of `auth_view` services subset,
|
||||
# so `di.Error` will be raised.
|
||||
pass
|
||||
|
||||
assert photos_view.services.users is Services.users
|
||||
assert photos_view.services.photos is Services.photos
|
||||
try:
|
||||
photos_view.services.auth
|
||||
except di.Error as exception:
|
||||
# `auth` service provider is not in scope of `photo_processing_view`
|
||||
# services subset, so `di.Error` will be raised.
|
||||
pass
|
22
examples/catalogs/writing_catalogs.py
Normal file
22
examples/catalogs/writing_catalogs.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
"""Catalog example."""
|
||||
|
||||
import dependency_injector as di
|
||||
|
||||
|
||||
class Catalog(di.AbstractCatalog):
|
||||
"""Providers catalog."""
|
||||
|
||||
factory1 = di.Factory(object)
|
||||
""":type: (di.Provider) -> object"""
|
||||
|
||||
factory2 = di.Factory(object)
|
||||
""":type: (di.Provider) -> object"""
|
||||
|
||||
# Creating some objects:
|
||||
object1 = Catalog.factory1()
|
||||
object2 = Catalog.factory2()
|
||||
|
||||
# Making some asserts:
|
||||
assert object1 is not object2
|
||||
assert isinstance(object1, object)
|
||||
assert isinstance(object2, object)
|
|
@ -4,93 +4,159 @@ import unittest2 as unittest
|
|||
import dependency_injector as di
|
||||
|
||||
|
||||
class CatalogA(di.AbstractCatalog):
|
||||
"""Test catalog A."""
|
||||
|
||||
p11 = di.Provider()
|
||||
p12 = di.Provider()
|
||||
|
||||
|
||||
class CatalogB(CatalogA):
|
||||
"""Test catalog B."""
|
||||
|
||||
p21 = di.Provider()
|
||||
p22 = di.Provider()
|
||||
|
||||
|
||||
class CatalogC(CatalogB):
|
||||
"""Test catalog C."""
|
||||
|
||||
p31 = di.Provider()
|
||||
p32 = di.Provider()
|
||||
|
||||
|
||||
class CatalogsInheritanceTests(unittest.TestCase):
|
||||
"""Catalogs inheritance tests."""
|
||||
|
||||
class CatalogA(di.AbstractCatalog):
|
||||
"""Test catalog A."""
|
||||
|
||||
p11 = di.Provider()
|
||||
p12 = di.Provider()
|
||||
|
||||
class CatalogB(CatalogA):
|
||||
"""Test catalog B."""
|
||||
|
||||
p21 = di.Provider()
|
||||
p22 = di.Provider()
|
||||
|
||||
class CatalogC(CatalogB):
|
||||
"""Test catalog C."""
|
||||
|
||||
p31 = di.Provider()
|
||||
p32 = di.Provider()
|
||||
|
||||
def test_cls_providers(self):
|
||||
"""Test `di.AbstractCatalog.cls_providers` contents."""
|
||||
self.assertDictEqual(self.CatalogA.cls_providers,
|
||||
dict(p11=self.CatalogA.p11,
|
||||
p12=self.CatalogA.p12))
|
||||
self.assertDictEqual(self.CatalogB.cls_providers,
|
||||
dict(p21=self.CatalogB.p21,
|
||||
p22=self.CatalogB.p22))
|
||||
self.assertDictEqual(self.CatalogC.cls_providers,
|
||||
dict(p31=self.CatalogC.p31,
|
||||
p32=self.CatalogC.p32))
|
||||
self.assertDictEqual(CatalogA.cls_providers,
|
||||
dict(p11=CatalogA.p11,
|
||||
p12=CatalogA.p12))
|
||||
self.assertDictEqual(CatalogB.cls_providers,
|
||||
dict(p21=CatalogB.p21,
|
||||
p22=CatalogB.p22))
|
||||
self.assertDictEqual(CatalogC.cls_providers,
|
||||
dict(p31=CatalogC.p31,
|
||||
p32=CatalogC.p32))
|
||||
|
||||
def test_inherited_providers(self):
|
||||
"""Test `di.AbstractCatalog.inherited_providers` contents."""
|
||||
self.assertDictEqual(self.CatalogA.inherited_providers, dict())
|
||||
self.assertDictEqual(self.CatalogB.inherited_providers,
|
||||
dict(p11=self.CatalogA.p11,
|
||||
p12=self.CatalogA.p12))
|
||||
self.assertDictEqual(self.CatalogC.inherited_providers,
|
||||
dict(p11=self.CatalogA.p11,
|
||||
p12=self.CatalogA.p12,
|
||||
p21=self.CatalogB.p21,
|
||||
p22=self.CatalogB.p22))
|
||||
self.assertDictEqual(CatalogA.inherited_providers, dict())
|
||||
self.assertDictEqual(CatalogB.inherited_providers,
|
||||
dict(p11=CatalogA.p11,
|
||||
p12=CatalogA.p12))
|
||||
self.assertDictEqual(CatalogC.inherited_providers,
|
||||
dict(p11=CatalogA.p11,
|
||||
p12=CatalogA.p12,
|
||||
p21=CatalogB.p21,
|
||||
p22=CatalogB.p22))
|
||||
|
||||
def test_providers(self):
|
||||
"""Test `di.AbstractCatalog.inherited_providers` contents."""
|
||||
self.assertDictEqual(self.CatalogA.providers,
|
||||
dict(p11=self.CatalogA.p11,
|
||||
p12=self.CatalogA.p12))
|
||||
self.assertDictEqual(self.CatalogB.providers,
|
||||
dict(p11=self.CatalogA.p11,
|
||||
p12=self.CatalogA.p12,
|
||||
p21=self.CatalogB.p21,
|
||||
p22=self.CatalogB.p22))
|
||||
self.assertDictEqual(self.CatalogC.providers,
|
||||
dict(p11=self.CatalogA.p11,
|
||||
p12=self.CatalogA.p12,
|
||||
p21=self.CatalogB.p21,
|
||||
p22=self.CatalogB.p22,
|
||||
p31=self.CatalogC.p31,
|
||||
p32=self.CatalogC.p32))
|
||||
self.assertDictEqual(CatalogA.providers,
|
||||
dict(p11=CatalogA.p11,
|
||||
p12=CatalogA.p12))
|
||||
self.assertDictEqual(CatalogB.providers,
|
||||
dict(p11=CatalogA.p11,
|
||||
p12=CatalogA.p12,
|
||||
p21=CatalogB.p21,
|
||||
p22=CatalogB.p22))
|
||||
self.assertDictEqual(CatalogC.providers,
|
||||
dict(p11=CatalogA.p11,
|
||||
p12=CatalogA.p12,
|
||||
p21=CatalogB.p21,
|
||||
p22=CatalogB.p22,
|
||||
p31=CatalogC.p31,
|
||||
p32=CatalogC.p32))
|
||||
|
||||
|
||||
class CatalogSubsetTests(unittest.TestCase):
|
||||
"""Catalog subset test cases."""
|
||||
|
||||
catalog = None
|
||||
|
||||
def setUp(self):
|
||||
"""Set test environment up."""
|
||||
self.subset = CatalogC('p11', 'p12')
|
||||
|
||||
def test_get_attr_from_subset(self):
|
||||
"""Test get providers (attribute) from subset."""
|
||||
self.assertIs(self.subset.p11, CatalogC.p11)
|
||||
self.assertIs(self.subset.p12, CatalogC.p12)
|
||||
|
||||
def test_get_attr_not_from_subset(self):
|
||||
"""Test get providers (attribute) that are not in subset."""
|
||||
self.assertRaises(di.Error, getattr, self.subset, 'p21')
|
||||
self.assertRaises(di.Error, getattr, self.subset, 'p22')
|
||||
self.assertRaises(di.Error, getattr, self.subset, 'p31')
|
||||
self.assertRaises(di.Error, getattr, self.subset, 'p32')
|
||||
|
||||
def test_get_method_from_subset(self):
|
||||
"""Test get providers (get() method) from subset."""
|
||||
self.assertIs(self.subset.get('p11'), CatalogC.p11)
|
||||
self.assertIs(self.subset.get('p12'), CatalogC.p12)
|
||||
|
||||
def test_get_method_not_from_subset(self):
|
||||
"""Test get providers (get() method) that are not in subset."""
|
||||
self.assertRaises(di.Error, self.subset.get, 'p21')
|
||||
self.assertRaises(di.Error, self.subset.get, 'p22')
|
||||
self.assertRaises(di.Error, self.subset.get, 'p31')
|
||||
self.assertRaises(di.Error, self.subset.get, 'p32')
|
||||
|
||||
def test_has(self):
|
||||
"""Test checks of providers availability in subsets."""
|
||||
self.assertTrue(self.subset.has('p11'))
|
||||
self.assertTrue(self.subset.has('p12'))
|
||||
|
||||
self.assertFalse(self.subset.has('p21'))
|
||||
self.assertFalse(self.subset.has('p22'))
|
||||
self.assertFalse(self.subset.has('p31'))
|
||||
self.assertFalse(self.subset.has('p32'))
|
||||
|
||||
def test_creating_with_undefined_provider(self):
|
||||
"""Test subset creation with provider that is not in catalog."""
|
||||
self.assertRaises(di.Error, CatalogC, 'undefined_provider')
|
||||
|
||||
|
||||
class CatalogTests(unittest.TestCase):
|
||||
"""Catalog test cases."""
|
||||
|
||||
class Catalog(di.AbstractCatalog):
|
||||
"""Test catalog."""
|
||||
def test_get(self):
|
||||
"""Test getting of providers using get() method."""
|
||||
self.assertIs(CatalogC.get('p11'), CatalogC.p11)
|
||||
self.assertIs(CatalogC.get('p12'), CatalogC.p12)
|
||||
self.assertIs(CatalogC.get('p22'), CatalogC.p22)
|
||||
self.assertIs(CatalogC.get('p22'), CatalogC.p22)
|
||||
self.assertIs(CatalogC.get('p32'), CatalogC.p32)
|
||||
self.assertIs(CatalogC.get('p32'), CatalogC.p32)
|
||||
|
||||
obj = di.Object(object())
|
||||
another_obj = di.Object(object())
|
||||
def test_get_undefined(self):
|
||||
"""Test getting of undefined providers using get() method."""
|
||||
self.assertRaises(di.Error, CatalogC.get, 'undefined')
|
||||
|
||||
def test_get_used(self):
|
||||
"""Test retrieving used provider."""
|
||||
catalog = self.Catalog(self.Catalog.obj)
|
||||
self.assertIsInstance(catalog.obj(), object)
|
||||
def test_has(self):
|
||||
"""Test checks of providers availability in subsets."""
|
||||
self.assertTrue(CatalogC.has('p11'))
|
||||
self.assertTrue(CatalogC.has('p12'))
|
||||
self.assertTrue(CatalogC.has('p21'))
|
||||
self.assertTrue(CatalogC.has('p22'))
|
||||
self.assertTrue(CatalogC.has('p31'))
|
||||
self.assertTrue(CatalogC.has('p32'))
|
||||
self.assertFalse(CatalogC.has('undefined'))
|
||||
|
||||
def test_get_unused(self):
|
||||
"""Test retrieving unused provider."""
|
||||
catalog = self.Catalog()
|
||||
self.assertRaises(di.Error, getattr, catalog, 'obj')
|
||||
def test_is_subset_owner(self):
|
||||
"""Test that catalog is subset owner."""
|
||||
subset = CatalogA()
|
||||
|
||||
def test_all_providers_by_type(self):
|
||||
self.assertTrue(CatalogA.is_subset_owner(subset))
|
||||
self.assertFalse(CatalogB.is_subset_owner(subset))
|
||||
self.assertFalse(CatalogC.is_subset_owner(subset))
|
||||
|
||||
def test_filter_all_providers_by_type(self):
|
||||
"""Test getting of all catalog providers of specific type."""
|
||||
self.assertTrue(len(self.Catalog.filter(di.Object)) == 2)
|
||||
self.assertTrue(len(self.Catalog.filter(di.Value)) == 0)
|
||||
self.assertTrue(len(CatalogC.filter(di.Provider)) == 6)
|
||||
self.assertTrue(len(CatalogC.filter(di.Value)) == 0)
|
||||
|
||||
|
||||
class OverrideTests(unittest.TestCase):
|
||||
|
|
|
@ -5,7 +5,6 @@ import dependency_injector as di
|
|||
|
||||
|
||||
class IsProviderTests(unittest.TestCase):
|
||||
|
||||
"""`is_provider()` test cases."""
|
||||
|
||||
def test_with_instance(self):
|
||||
|
@ -27,7 +26,6 @@ class IsProviderTests(unittest.TestCase):
|
|||
def test_with_subclass_instance(self):
|
||||
"""Test with subclass of provider instance."""
|
||||
class SomeProvider(di.Provider):
|
||||
|
||||
"""Some provider for test."""
|
||||
|
||||
self.assertTrue(di.is_provider(SomeProvider()))
|
||||
|
@ -35,7 +33,6 @@ class IsProviderTests(unittest.TestCase):
|
|||
def test_with_class_with_getattr(self):
|
||||
"""Test with class that has __getattr__() method implementation."""
|
||||
class SomeClass(object):
|
||||
|
||||
"""Some test class with __getattr__() method implementation."""
|
||||
|
||||
def __getattr__(self, _):
|
||||
|
@ -46,7 +43,6 @@ class IsProviderTests(unittest.TestCase):
|
|||
|
||||
|
||||
class EnsureIsProviderTests(unittest.TestCase):
|
||||
|
||||
"""`ensure_is_provider` test cases."""
|
||||
|
||||
def test_with_instance(self):
|
||||
|
@ -68,7 +64,6 @@ class EnsureIsProviderTests(unittest.TestCase):
|
|||
|
||||
|
||||
class IsInjectionTests(unittest.TestCase):
|
||||
|
||||
"""`is_injection()` test cases."""
|
||||
|
||||
def test_with_instance(self):
|
||||
|
@ -95,7 +90,6 @@ class IsInjectionTests(unittest.TestCase):
|
|||
|
||||
|
||||
class EnsureIsInjectionTests(unittest.TestCase):
|
||||
|
||||
"""`ensure_is_injection` test cases."""
|
||||
|
||||
def test_with_instance(self):
|
||||
|
@ -117,7 +111,6 @@ class EnsureIsInjectionTests(unittest.TestCase):
|
|||
|
||||
|
||||
class IsKwArgInjectionTests(unittest.TestCase):
|
||||
|
||||
"""`is_kwarg_injection()` test cases."""
|
||||
|
||||
def test_with_instance(self):
|
||||
|
@ -142,7 +135,6 @@ class IsKwArgInjectionTests(unittest.TestCase):
|
|||
|
||||
|
||||
class IsAttributeInjectionTests(unittest.TestCase):
|
||||
|
||||
"""`is_attribute_injection()` test cases."""
|
||||
|
||||
def test_with_instance(self):
|
||||
|
@ -168,7 +160,6 @@ class IsAttributeInjectionTests(unittest.TestCase):
|
|||
|
||||
|
||||
class IsMethodInjectionTests(unittest.TestCase):
|
||||
|
||||
"""`is_method_injection()` test cases."""
|
||||
|
||||
def test_with_instance(self):
|
||||
|
@ -193,7 +184,6 @@ class IsMethodInjectionTests(unittest.TestCase):
|
|||
|
||||
|
||||
class IsCatalogTests(unittest.TestCase):
|
||||
|
||||
"""`is_catalog()` test cases."""
|
||||
|
||||
def test_with_cls(self):
|
||||
|
@ -207,7 +197,6 @@ class IsCatalogTests(unittest.TestCase):
|
|||
def test_with_child_class(self):
|
||||
"""Test with parent class."""
|
||||
class Catalog(di.AbstractCatalog):
|
||||
|
||||
"""Example catalog child class."""
|
||||
|
||||
self.assertTrue(di.is_catalog(Catalog))
|
||||
|
@ -219,3 +208,24 @@ class IsCatalogTests(unittest.TestCase):
|
|||
def test_with_object(self):
|
||||
"""Test with object."""
|
||||
self.assertFalse(di.is_catalog(object()))
|
||||
|
||||
|
||||
class IsCatalogSubsetTests(unittest.TestCase):
|
||||
"""`is_catalog_subset()` test cases."""
|
||||
|
||||
def test_with_cls(self):
|
||||
"""Test with class."""
|
||||
self.assertFalse(di.is_catalog_subset(di.CatalogSubset))
|
||||
|
||||
def test_with_instance(self):
|
||||
"""Test with class."""
|
||||
self.assertTrue(di.is_catalog_subset(
|
||||
di.CatalogSubset(catalog=di.AbstractCatalog, providers=tuple())))
|
||||
|
||||
def test_with_string(self):
|
||||
"""Test with string."""
|
||||
self.assertFalse(di.is_catalog_subset('some_string'))
|
||||
|
||||
def test_with_object(self):
|
||||
"""Test with object."""
|
||||
self.assertFalse(di.is_catalog_subset(object()))
|
||||
|
|
Loading…
Reference in New Issue
Block a user