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."""
|
"""Dependency injector."""
|
||||||
|
|
||||||
from .catalog import AbstractCatalog
|
from .catalog import AbstractCatalog
|
||||||
|
from .catalog import CatalogSubset
|
||||||
from .catalog import override
|
from .catalog import override
|
||||||
|
|
||||||
from .providers import Provider
|
from .providers import Provider
|
||||||
|
@ -30,6 +31,7 @@ from .utils import is_kwarg_injection
|
||||||
from .utils import is_attribute_injection
|
from .utils import is_attribute_injection
|
||||||
from .utils import is_method_injection
|
from .utils import is_method_injection
|
||||||
from .utils import is_catalog
|
from .utils import is_catalog
|
||||||
|
from .utils import is_catalog_subset
|
||||||
|
|
||||||
from .errors import Error
|
from .errors import Error
|
||||||
|
|
||||||
|
@ -37,6 +39,7 @@ from .errors import Error
|
||||||
__all__ = (
|
__all__ = (
|
||||||
# Catalogs
|
# Catalogs
|
||||||
'AbstractCatalog',
|
'AbstractCatalog',
|
||||||
|
'CatalogSubset',
|
||||||
'override',
|
'override',
|
||||||
|
|
||||||
# Providers
|
# Providers
|
||||||
|
@ -69,6 +72,7 @@ __all__ = (
|
||||||
'is_attribute_injection',
|
'is_attribute_injection',
|
||||||
'is_method_injection',
|
'is_method_injection',
|
||||||
'is_catalog',
|
'is_catalog',
|
||||||
|
'is_catalog_subset',
|
||||||
|
|
||||||
# Errors
|
# Errors
|
||||||
'Error',
|
'Error',
|
||||||
|
|
|
@ -31,6 +31,10 @@ class CatalogMetaClass(type):
|
||||||
attributes['providers'] = providers
|
attributes['providers'] = providers
|
||||||
return type.__new__(mcs, class_name, bases, attributes)
|
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)
|
@six.add_metaclass(CatalogMetaClass)
|
||||||
class AbstractCatalog(object):
|
class AbstractCatalog(object):
|
||||||
|
@ -53,22 +57,20 @@ class AbstractCatalog(object):
|
||||||
inherited_providers = dict()
|
inherited_providers = dict()
|
||||||
|
|
||||||
__IS_CATALOG__ = True
|
__IS_CATALOG__ = True
|
||||||
__slots__ = ('used_providers',)
|
|
||||||
|
|
||||||
def __init__(self, *used_providers):
|
def __new__(cls, *providers):
|
||||||
"""Initializer."""
|
"""Catalog constructor.
|
||||||
self.used_providers = set(used_providers)
|
|
||||||
|
|
||||||
def __getattribute__(self, item):
|
Catalogs are declaratives entities that could not be instantiated.
|
||||||
"""Return providers."""
|
Catalog constructor is designed to produce subsets of catalog
|
||||||
attribute = super(AbstractCatalog, self).__getattribute__(item)
|
providers.
|
||||||
if item in ('providers', 'used_providers', '__class__'):
|
"""
|
||||||
return attribute
|
return CatalogSubset(catalog=cls, providers=providers)
|
||||||
|
|
||||||
if attribute not in self.used_providers:
|
@classmethod
|
||||||
raise Error('Provider \'{0}\' '.format(item) +
|
def is_subset_owner(cls, subset):
|
||||||
'is not listed in dependencies')
|
"""Check if catalog is subset owner."""
|
||||||
return attribute
|
return subset.catalog is cls
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def filter(cls, provider_type):
|
def filter(cls, provider_type):
|
||||||
|
@ -86,6 +88,68 @@ class AbstractCatalog(object):
|
||||||
for name, provider in six.iteritems(overriding.cls_providers):
|
for name, provider in six.iteritems(overriding.cls_providers):
|
||||||
cls.providers[name].override(provider)
|
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):
|
def override(catalog):
|
||||||
"""Catalog overriding decorator."""
|
"""Catalog overriding decorator."""
|
||||||
|
|
|
@ -62,6 +62,12 @@ def is_catalog(instance):
|
||||||
getattr(instance, '__IS_CATALOG__', False) is True)
|
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):
|
def get_injectable_kwargs(kwargs, injections):
|
||||||
"""Return dictionary of kwargs, patched with injections."""
|
"""Return dictionary of kwargs, patched with injections."""
|
||||||
init_kwargs = dict(((injection.name, injection.value)
|
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
|
some init / shutdown functionality or something else, that deals with group
|
||||||
of providers.
|
of providers.
|
||||||
|
|
||||||
Writing catalogs
|
.. toctree::
|
||||||
----------------
|
:maxdepth: 2
|
||||||
|
|
||||||
Catalogs have to extend base catalog class ``di.AbstractCatalog``.
|
writing
|
||||||
|
operating
|
||||||
Providers have to be defined like catalog's attributes. Every provider in
|
subsets
|
||||||
catalog has name. This name should follow ``some_provider`` convention,
|
overriding
|
||||||
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
|
|
||||||
|
|
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 decorating classes with ``@di.inject``.
|
||||||
|
- Add functionality for creating ``di.AbstractCatalog`` subsets.
|
||||||
- Add enhancement for ``di.AbstractCatalog`` inheritance.
|
- Add enhancement for ``di.AbstractCatalog`` inheritance.
|
||||||
|
- Add images for catalog "Writing catalogs" and "Operating with catalogs"
|
||||||
|
examples.
|
||||||
- Add minor refactorings and code style fixes.
|
- Add minor refactorings and code style fixes.
|
||||||
|
|
||||||
0.9.5
|
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
|
import dependency_injector as di
|
||||||
|
|
||||||
|
|
||||||
class CatalogsInheritanceTests(unittest.TestCase):
|
|
||||||
"""Catalogs inheritance tests."""
|
|
||||||
|
|
||||||
class CatalogA(di.AbstractCatalog):
|
class CatalogA(di.AbstractCatalog):
|
||||||
"""Test catalog A."""
|
"""Test catalog A."""
|
||||||
|
|
||||||
p11 = di.Provider()
|
p11 = di.Provider()
|
||||||
p12 = di.Provider()
|
p12 = di.Provider()
|
||||||
|
|
||||||
|
|
||||||
class CatalogB(CatalogA):
|
class CatalogB(CatalogA):
|
||||||
"""Test catalog B."""
|
"""Test catalog B."""
|
||||||
|
|
||||||
p21 = di.Provider()
|
p21 = di.Provider()
|
||||||
p22 = di.Provider()
|
p22 = di.Provider()
|
||||||
|
|
||||||
|
|
||||||
class CatalogC(CatalogB):
|
class CatalogC(CatalogB):
|
||||||
"""Test catalog C."""
|
"""Test catalog C."""
|
||||||
|
|
||||||
p31 = di.Provider()
|
p31 = di.Provider()
|
||||||
p32 = di.Provider()
|
p32 = di.Provider()
|
||||||
|
|
||||||
|
|
||||||
|
class CatalogsInheritanceTests(unittest.TestCase):
|
||||||
|
"""Catalogs inheritance tests."""
|
||||||
|
|
||||||
def test_cls_providers(self):
|
def test_cls_providers(self):
|
||||||
"""Test `di.AbstractCatalog.cls_providers` contents."""
|
"""Test `di.AbstractCatalog.cls_providers` contents."""
|
||||||
self.assertDictEqual(self.CatalogA.cls_providers,
|
self.assertDictEqual(CatalogA.cls_providers,
|
||||||
dict(p11=self.CatalogA.p11,
|
dict(p11=CatalogA.p11,
|
||||||
p12=self.CatalogA.p12))
|
p12=CatalogA.p12))
|
||||||
self.assertDictEqual(self.CatalogB.cls_providers,
|
self.assertDictEqual(CatalogB.cls_providers,
|
||||||
dict(p21=self.CatalogB.p21,
|
dict(p21=CatalogB.p21,
|
||||||
p22=self.CatalogB.p22))
|
p22=CatalogB.p22))
|
||||||
self.assertDictEqual(self.CatalogC.cls_providers,
|
self.assertDictEqual(CatalogC.cls_providers,
|
||||||
dict(p31=self.CatalogC.p31,
|
dict(p31=CatalogC.p31,
|
||||||
p32=self.CatalogC.p32))
|
p32=CatalogC.p32))
|
||||||
|
|
||||||
def test_inherited_providers(self):
|
def test_inherited_providers(self):
|
||||||
"""Test `di.AbstractCatalog.inherited_providers` contents."""
|
"""Test `di.AbstractCatalog.inherited_providers` contents."""
|
||||||
self.assertDictEqual(self.CatalogA.inherited_providers, dict())
|
self.assertDictEqual(CatalogA.inherited_providers, dict())
|
||||||
self.assertDictEqual(self.CatalogB.inherited_providers,
|
self.assertDictEqual(CatalogB.inherited_providers,
|
||||||
dict(p11=self.CatalogA.p11,
|
dict(p11=CatalogA.p11,
|
||||||
p12=self.CatalogA.p12))
|
p12=CatalogA.p12))
|
||||||
self.assertDictEqual(self.CatalogC.inherited_providers,
|
self.assertDictEqual(CatalogC.inherited_providers,
|
||||||
dict(p11=self.CatalogA.p11,
|
dict(p11=CatalogA.p11,
|
||||||
p12=self.CatalogA.p12,
|
p12=CatalogA.p12,
|
||||||
p21=self.CatalogB.p21,
|
p21=CatalogB.p21,
|
||||||
p22=self.CatalogB.p22))
|
p22=CatalogB.p22))
|
||||||
|
|
||||||
def test_providers(self):
|
def test_providers(self):
|
||||||
"""Test `di.AbstractCatalog.inherited_providers` contents."""
|
"""Test `di.AbstractCatalog.inherited_providers` contents."""
|
||||||
self.assertDictEqual(self.CatalogA.providers,
|
self.assertDictEqual(CatalogA.providers,
|
||||||
dict(p11=self.CatalogA.p11,
|
dict(p11=CatalogA.p11,
|
||||||
p12=self.CatalogA.p12))
|
p12=CatalogA.p12))
|
||||||
self.assertDictEqual(self.CatalogB.providers,
|
self.assertDictEqual(CatalogB.providers,
|
||||||
dict(p11=self.CatalogA.p11,
|
dict(p11=CatalogA.p11,
|
||||||
p12=self.CatalogA.p12,
|
p12=CatalogA.p12,
|
||||||
p21=self.CatalogB.p21,
|
p21=CatalogB.p21,
|
||||||
p22=self.CatalogB.p22))
|
p22=CatalogB.p22))
|
||||||
self.assertDictEqual(self.CatalogC.providers,
|
self.assertDictEqual(CatalogC.providers,
|
||||||
dict(p11=self.CatalogA.p11,
|
dict(p11=CatalogA.p11,
|
||||||
p12=self.CatalogA.p12,
|
p12=CatalogA.p12,
|
||||||
p21=self.CatalogB.p21,
|
p21=CatalogB.p21,
|
||||||
p22=self.CatalogB.p22,
|
p22=CatalogB.p22,
|
||||||
p31=self.CatalogC.p31,
|
p31=CatalogC.p31,
|
||||||
p32=self.CatalogC.p32))
|
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):
|
class CatalogTests(unittest.TestCase):
|
||||||
"""Catalog test cases."""
|
"""Catalog test cases."""
|
||||||
|
|
||||||
class Catalog(di.AbstractCatalog):
|
def test_get(self):
|
||||||
"""Test catalog."""
|
"""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())
|
def test_get_undefined(self):
|
||||||
another_obj = di.Object(object())
|
"""Test getting of undefined providers using get() method."""
|
||||||
|
self.assertRaises(di.Error, CatalogC.get, 'undefined')
|
||||||
|
|
||||||
def test_get_used(self):
|
def test_has(self):
|
||||||
"""Test retrieving used provider."""
|
"""Test checks of providers availability in subsets."""
|
||||||
catalog = self.Catalog(self.Catalog.obj)
|
self.assertTrue(CatalogC.has('p11'))
|
||||||
self.assertIsInstance(catalog.obj(), object)
|
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):
|
def test_is_subset_owner(self):
|
||||||
"""Test retrieving unused provider."""
|
"""Test that catalog is subset owner."""
|
||||||
catalog = self.Catalog()
|
subset = CatalogA()
|
||||||
self.assertRaises(di.Error, getattr, catalog, 'obj')
|
|
||||||
|
|
||||||
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."""
|
"""Test getting of all catalog providers of specific type."""
|
||||||
self.assertTrue(len(self.Catalog.filter(di.Object)) == 2)
|
self.assertTrue(len(CatalogC.filter(di.Provider)) == 6)
|
||||||
self.assertTrue(len(self.Catalog.filter(di.Value)) == 0)
|
self.assertTrue(len(CatalogC.filter(di.Value)) == 0)
|
||||||
|
|
||||||
|
|
||||||
class OverrideTests(unittest.TestCase):
|
class OverrideTests(unittest.TestCase):
|
||||||
|
|
|
@ -5,7 +5,6 @@ import dependency_injector as di
|
||||||
|
|
||||||
|
|
||||||
class IsProviderTests(unittest.TestCase):
|
class IsProviderTests(unittest.TestCase):
|
||||||
|
|
||||||
"""`is_provider()` test cases."""
|
"""`is_provider()` test cases."""
|
||||||
|
|
||||||
def test_with_instance(self):
|
def test_with_instance(self):
|
||||||
|
@ -27,7 +26,6 @@ class IsProviderTests(unittest.TestCase):
|
||||||
def test_with_subclass_instance(self):
|
def test_with_subclass_instance(self):
|
||||||
"""Test with subclass of provider instance."""
|
"""Test with subclass of provider instance."""
|
||||||
class SomeProvider(di.Provider):
|
class SomeProvider(di.Provider):
|
||||||
|
|
||||||
"""Some provider for test."""
|
"""Some provider for test."""
|
||||||
|
|
||||||
self.assertTrue(di.is_provider(SomeProvider()))
|
self.assertTrue(di.is_provider(SomeProvider()))
|
||||||
|
@ -35,7 +33,6 @@ class IsProviderTests(unittest.TestCase):
|
||||||
def test_with_class_with_getattr(self):
|
def test_with_class_with_getattr(self):
|
||||||
"""Test with class that has __getattr__() method implementation."""
|
"""Test with class that has __getattr__() method implementation."""
|
||||||
class SomeClass(object):
|
class SomeClass(object):
|
||||||
|
|
||||||
"""Some test class with __getattr__() method implementation."""
|
"""Some test class with __getattr__() method implementation."""
|
||||||
|
|
||||||
def __getattr__(self, _):
|
def __getattr__(self, _):
|
||||||
|
@ -46,7 +43,6 @@ class IsProviderTests(unittest.TestCase):
|
||||||
|
|
||||||
|
|
||||||
class EnsureIsProviderTests(unittest.TestCase):
|
class EnsureIsProviderTests(unittest.TestCase):
|
||||||
|
|
||||||
"""`ensure_is_provider` test cases."""
|
"""`ensure_is_provider` test cases."""
|
||||||
|
|
||||||
def test_with_instance(self):
|
def test_with_instance(self):
|
||||||
|
@ -68,7 +64,6 @@ class EnsureIsProviderTests(unittest.TestCase):
|
||||||
|
|
||||||
|
|
||||||
class IsInjectionTests(unittest.TestCase):
|
class IsInjectionTests(unittest.TestCase):
|
||||||
|
|
||||||
"""`is_injection()` test cases."""
|
"""`is_injection()` test cases."""
|
||||||
|
|
||||||
def test_with_instance(self):
|
def test_with_instance(self):
|
||||||
|
@ -95,7 +90,6 @@ class IsInjectionTests(unittest.TestCase):
|
||||||
|
|
||||||
|
|
||||||
class EnsureIsInjectionTests(unittest.TestCase):
|
class EnsureIsInjectionTests(unittest.TestCase):
|
||||||
|
|
||||||
"""`ensure_is_injection` test cases."""
|
"""`ensure_is_injection` test cases."""
|
||||||
|
|
||||||
def test_with_instance(self):
|
def test_with_instance(self):
|
||||||
|
@ -117,7 +111,6 @@ class EnsureIsInjectionTests(unittest.TestCase):
|
||||||
|
|
||||||
|
|
||||||
class IsKwArgInjectionTests(unittest.TestCase):
|
class IsKwArgInjectionTests(unittest.TestCase):
|
||||||
|
|
||||||
"""`is_kwarg_injection()` test cases."""
|
"""`is_kwarg_injection()` test cases."""
|
||||||
|
|
||||||
def test_with_instance(self):
|
def test_with_instance(self):
|
||||||
|
@ -142,7 +135,6 @@ class IsKwArgInjectionTests(unittest.TestCase):
|
||||||
|
|
||||||
|
|
||||||
class IsAttributeInjectionTests(unittest.TestCase):
|
class IsAttributeInjectionTests(unittest.TestCase):
|
||||||
|
|
||||||
"""`is_attribute_injection()` test cases."""
|
"""`is_attribute_injection()` test cases."""
|
||||||
|
|
||||||
def test_with_instance(self):
|
def test_with_instance(self):
|
||||||
|
@ -168,7 +160,6 @@ class IsAttributeInjectionTests(unittest.TestCase):
|
||||||
|
|
||||||
|
|
||||||
class IsMethodInjectionTests(unittest.TestCase):
|
class IsMethodInjectionTests(unittest.TestCase):
|
||||||
|
|
||||||
"""`is_method_injection()` test cases."""
|
"""`is_method_injection()` test cases."""
|
||||||
|
|
||||||
def test_with_instance(self):
|
def test_with_instance(self):
|
||||||
|
@ -193,7 +184,6 @@ class IsMethodInjectionTests(unittest.TestCase):
|
||||||
|
|
||||||
|
|
||||||
class IsCatalogTests(unittest.TestCase):
|
class IsCatalogTests(unittest.TestCase):
|
||||||
|
|
||||||
"""`is_catalog()` test cases."""
|
"""`is_catalog()` test cases."""
|
||||||
|
|
||||||
def test_with_cls(self):
|
def test_with_cls(self):
|
||||||
|
@ -207,7 +197,6 @@ class IsCatalogTests(unittest.TestCase):
|
||||||
def test_with_child_class(self):
|
def test_with_child_class(self):
|
||||||
"""Test with parent class."""
|
"""Test with parent class."""
|
||||||
class Catalog(di.AbstractCatalog):
|
class Catalog(di.AbstractCatalog):
|
||||||
|
|
||||||
"""Example catalog child class."""
|
"""Example catalog child class."""
|
||||||
|
|
||||||
self.assertTrue(di.is_catalog(Catalog))
|
self.assertTrue(di.is_catalog(Catalog))
|
||||||
|
@ -219,3 +208,24 @@ class IsCatalogTests(unittest.TestCase):
|
||||||
def test_with_object(self):
|
def test_with_object(self):
|
||||||
"""Test with object."""
|
"""Test with object."""
|
||||||
self.assertFalse(di.is_catalog(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