Remove catalog bundles

This commit is contained in:
Roman Mogilatov 2016-05-22 16:49:08 +03:00
parent 5bc6ad0165
commit 918335e0e4
14 changed files with 2 additions and 514 deletions

View File

@ -1,6 +1,5 @@
"""Dependency injector catalogs package.""" """Dependency injector catalogs package."""
from dependency_injector.catalogs.bundle import CatalogBundle
from dependency_injector.catalogs.dynamic import DynamicCatalog from dependency_injector.catalogs.dynamic import DynamicCatalog
from dependency_injector.catalogs.declarative import ( from dependency_injector.catalogs.declarative import (
DeclarativeCatalogMetaClass, DeclarativeCatalogMetaClass,
@ -13,7 +12,6 @@ from dependency_injector.catalogs.utils import (
__all__ = ( __all__ = (
'CatalogBundle',
'DynamicCatalog', 'DynamicCatalog',
'DeclarativeCatalogMetaClass', 'DeclarativeCatalogMetaClass',
'DeclarativeCatalog', 'DeclarativeCatalog',

View File

@ -1,118 +0,0 @@
"""Dependency injector catalogs bundle module."""
import six
from dependency_injector.errors import (
Error,
UndefinedProviderError,
)
@six.python_2_unicode_compatible
class CatalogBundle(object):
"""Bundle of catalog providers.
:py:class:`CatalogBundle` is a frozen, limited collection of catalog
providers. While catalog could be used as a centralized place for
particular providers group, such bundles of catalog providers can be used
for creating several frozen, limited scopes that could be passed to
different subsystems.
:py:class:`CatalogBundle` has API's parity with catalogs
(:py:class:`DeclarativeCatalog` or :py:class:`DynamicCatalog`) in terms of
retrieving the providers, but it is "frozen" in terms of modification
provider's list.
:py:class:`CatalogBundle` is considered to be dependable on catalogs
(:py:class:`DeclarativeCatalog` or :py:class:`DynamicCatalog`) entity by
its design.
.. py:attribute:: catalog
Bundle's catalog.
:type: :py:class:`DeclarativeCatalog` | :py:class:`DynamicCatalog`
.. py:attribute:: providers
Dictionary of all providers.
:type: dict[str, :py:class:`dependency_injector.providers.Provider`]
"""
catalog = None
__IS_CATALOG_BUNDLE__ = True
__slots__ = ('providers', '__dict__')
@classmethod
def sub_cls_factory(cls, catalog):
"""Create bundle subclass for catalog.
:return: Subclass of :py:class:`CatalogBundle`.
:rtype: :py:class:`CatalogBundle`
"""
return type('BundleSubclass', (cls,), dict(catalog=catalog))
def __init__(self, *providers):
"""Initializer.
:param providers: Tuple of catalog's bundle providers.
:type providers: tuple[
:py:class:`dependency_injector.providers.Provider`]
"""
self.providers = dict((self.catalog.get_provider_bind_name(provider),
provider)
for provider in providers)
self.__dict__.update(self.providers)
super(CatalogBundle, self).__init__()
def get_provider(self, name):
"""Return provider with specified name or raise an error.
:param name: Provider's name.
:type name: str
:raise: :py:exc:`dependency_injector.errors.UndefinedProviderError`
:return: Provider with specified name.
:rtype: :py:class:`dependency_injector.providers.Provider`
"""
try:
return self.providers[name]
except KeyError:
raise Error('Provider "{0}" is not a part of {1}'.format(name,
self))
def has_provider(self, name):
"""Check if there is provider with certain name.
:param name: Provider's name.
:type name: str
:rtype: bool
"""
return name in self.providers
def __getattr__(self, item):
"""Return provider with specified name or raise en error.
:param name: Attribute's name.
:type name: str
:raise: :py:exc:`dependency_injector.errors.UndefinedProviderError`
"""
if item.startswith('__') and item.endswith('__'):
return super(CatalogBundle, self).__getattr__(item)
raise UndefinedProviderError('Provider "{0}" is not a part '
'of {1}'.format(item, self))
def __repr__(self):
"""Return string representation of catalog's bundle.
:rtype: str
"""
return '<{0}.Bundle({1})>'.format(
self.catalog.name, ', '.join(six.iterkeys(self.providers)))
__str__ = __repr__

View File

@ -3,7 +3,6 @@
import six import six
from dependency_injector.catalogs.dynamic import DynamicCatalog from dependency_injector.catalogs.dynamic import DynamicCatalog
from dependency_injector.catalogs.bundle import CatalogBundle
from dependency_injector.utils import ( from dependency_injector.utils import (
is_provider, is_provider,
is_catalog, is_catalog,
@ -47,8 +46,6 @@ class DeclarativeCatalogMetaClass(type):
cls._cls_providers = dict(cls_providers) cls._cls_providers = dict(cls_providers)
cls._inherited_providers = dict(inherited_providers) cls._inherited_providers = dict(inherited_providers)
cls.Bundle = cls._catalog.Bundle
return cls return cls
@property @property
@ -187,12 +184,6 @@ class DeclarativeCatalog(object):
users_service = Services.users() users_service = Services.users()
.. py:attribute:: Bundle
Catalog's bundle class.
:type: :py:class:`CatalogBundle`
.. py:attribute:: provider_type .. py:attribute:: provider_type
If provider type is defined, :py:class:`DeclarativeCatalog` checks that If provider type is defined, :py:class:`DeclarativeCatalog` checks that
@ -202,8 +193,6 @@ class DeclarativeCatalog(object):
:type: type | None :type: type | None
""" """
Bundle = CatalogBundle
provider_type = None provider_type = None
_catalog = DynamicCatalog _catalog = DynamicCatalog
@ -273,17 +262,6 @@ class DeclarativeCatalog(object):
""" """
return self.__class__.last_overriding return self.__class__.last_overriding
@classmethod
def is_bundle_owner(cls, bundle):
"""Check if catalog is bundle owner.
:param bundle: Catalog's bundle instance.
:type bundle: :py:class:`CatalogBundle`
:rtype: bool
"""
return cls._catalog.is_bundle_owner(bundle)
@classmethod @classmethod
def get_provider_bind_name(cls, provider): def get_provider_bind_name(cls, provider):
"""Return provider's name in catalog. """Return provider's name in catalog.

View File

@ -2,11 +2,9 @@
import six import six
from dependency_injector.catalogs.bundle import CatalogBundle
from dependency_injector.utils import ( from dependency_injector.utils import (
is_provider, is_provider,
ensure_is_provider, ensure_is_provider,
ensure_is_catalog_bundle,
) )
from dependency_injector.errors import ( from dependency_injector.errors import (
Error, Error,
@ -32,12 +30,6 @@ class DynamicCatalog(object):
users_service = services.users() users_service = services.users()
.. py:attribute:: Bundle
Catalog's bundle class.
:type: :py:class:`CatalogBundle`
.. py:attribute:: name .. py:attribute:: name
Catalog's name. Catalog's name.
@ -71,8 +63,7 @@ class DynamicCatalog(object):
provider_type = None provider_type = None
__IS_CATALOG__ = True __IS_CATALOG__ = True
__slots__ = ('name', 'providers', 'provider_names', 'overridden_by', __slots__ = ('name', 'providers', 'provider_names', 'overridden_by')
'Bundle')
def __init__(self, **providers): def __init__(self, **providers):
"""Initializer. """Initializer.
@ -81,7 +72,6 @@ class DynamicCatalog(object):
:type providers: :type providers:
dict[str, :py:class:`dependency_injector.providers.Provider`] dict[str, :py:class:`dependency_injector.providers.Provider`]
""" """
self.Bundle = CatalogBundle.sub_cls_factory(self)
self.name = '.'.join((self.__class__.__module__, self.name = '.'.join((self.__class__.__module__,
self.__class__.__name__)) self.__class__.__name__))
self.providers = dict() self.providers = dict()
@ -90,16 +80,6 @@ class DynamicCatalog(object):
self.bind_providers(providers) self.bind_providers(providers)
super(DynamicCatalog, self).__init__() super(DynamicCatalog, self).__init__()
def is_bundle_owner(self, bundle):
"""Check if catalog is bundle owner.
:param bundle: Catalog's bundle instance.
:type bundle: :py:class:`CatalogBundle`
:rtype: bool
"""
return ensure_is_catalog_bundle(bundle) and bundle.catalog is self
def get_provider_bind_name(self, provider): def get_provider_bind_name(self, provider):
"""Return provider's name in catalog. """Return provider's name in catalog.

View File

@ -175,36 +175,6 @@ def is_declarative_catalog(instance):
return (isinstance(instance, six.class_types) and is_catalog(instance)) return (isinstance(instance, six.class_types) and is_catalog(instance))
def is_catalog_bundle(instance):
"""Check if instance is catalog bundle instance.
:param instance: Instance to be checked.
:type instance: object
:rtype: bool
"""
return (not isinstance(instance, six.class_types) and
hasattr(instance, '__IS_CATALOG_BUNDLE__') and
getattr(instance, '__IS_CATALOG_BUNDLE__', False) is True)
def ensure_is_catalog_bundle(instance):
"""Check if instance is catalog bundle instance and return it.
:param instance: Instance to be checked.
:type instance: object
:raise: :py:exc:`dependency_injector.errors.Error` if provided instance
is not catalog bundle.
:rtype: :py:class:`dependency_injector.catalogs.CatalogBundle`
"""
if not is_catalog_bundle(instance):
raise Error('Expected catalog bundle instance, '
'got {0}'.format(str(instance)))
return instance
def represent_provider(provider, provides): def represent_provider(provider, provides):
"""Return string representation of provider. """Return string representation of provider.

View File

@ -1,63 +0,0 @@
Catalog provider bundles
------------------------
.. currentmodule:: dependency_injector.catalogs
:py:class:`CatalogBundle` is a frozen, limited collection of catalog
providers. While catalog could be used as a centralized place for
particular providers group, such bundles of catalog providers can be used
for creating several frozen, limited scopes that could be passed to different
subsystems.
:py:class:`CatalogBundle` has API's parity with catalogs
(:py:class:`DeclarativeCatalog` or :py:class:`DynamicCatalog`) in terms of
retrieving the providers, but it is "frozen" in terms of modification
provider's list.
:py:class:`CatalogBundle` is considered to be dependable on catalogs
(:py:class:`DeclarativeCatalog` or :py:class:`DynamicCatalog`) entity by
its design.
Each catalog (:py:class:`DeclarativeCatalog` or :py:class:`DynamicCatalog`)
has a reference to its bundle class - :py:attr:`DeclarativeCatalog.Bundle`
(or :py:attr:`DynamicCatalog.Bundle` consequently). For example, subclass of
:py:class:`CatalogBundle` for some concrete declarative catalog
``SomeCatalog`` could be reached as ``SomeCatalog.Bundle``.
:py:class:`CatalogBundle` expects to get the list of its catalog providers
as positional arguments and will limit the scope of created bundle to this
list.
.. note::
Some notes about :py:class:`CatalogBundle` design.
Design and syntax of :py:class:`CatalogBundle` was developed with the idea
of keeping full functionalities of type-hinting and introspection of
modern IDE's. This design came from some practical experience of using
:py:class:`CatalogBundle` and considered to be the most comfortable for
developer.
Example:
.. image:: /images/catalogs/bundles.png
:width: 100%
:align: center
Listing of `services.py`:
.. literalinclude:: ../../examples/catalogs/bundles/services.py
:language: python
:linenos:
Listing of `views.py`:
.. literalinclude:: ../../examples/catalogs/bundles/views.py
:language: python
:linenos:
Listing of `catalogs.py`:
.. literalinclude:: ../../examples/catalogs/bundles/catalogs.py
:language: python
:linenos:

View File

@ -23,6 +23,5 @@ Catalogs module API docs - :py:mod:`dependency_injector.catalogs`.
declarative declarative
dynamic dynamic
bundles
specialization specialization
overriding overriding

View File

@ -23,6 +23,7 @@ Development version
- ``Class`` - ``Class``
- ``Config`` - ``Config``
- Drop ``Method`` injections. - Drop ``Method`` injections.
- Drop catalog bundles.
- Drop backward compatibilities of 1.x. - Drop backward compatibilities of 1.x.
1.17.0 1.17.0

View File

@ -1,59 +0,0 @@
"""Catalog bundles example."""
from dependency_injector import catalogs
from dependency_injector import providers
from dependency_injector import errors
import services
import views
# Declaring services catalog:
class Services(catalogs.DeclarativeCatalog):
"""Example catalog of service providers."""
users = providers.Factory(services.Users)
auth = providers.Factory(services.Auth)
photos = providers.Factory(services.Photos)
# Declaring views catalog:
class Views(catalogs.DeclarativeCatalog):
"""Example catalog of web views."""
auth = providers.Factory(views.Auth,
services=Services.Bundle(Services.users,
Services.auth))
photos = providers.Factory(views.Photos,
services=Services.Bundle(Services.users,
Services.photos))
# Creating example views:
auth_view = Views.auth()
photos_view = Views.photos()
print auth_view.services # prints: <__main__.Services.Bundle(users, auth)>
print photos_view.services # prints <__main__.Services.Bundle(photos, users)>
# 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 errors.Error:
# `photos` service provider is not in scope of `auth_view` services bundle,
# 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 errors.Error as exception:
# `auth` service provider is not in scope of `photo_processing_view`
# services bundle, so `di.Error` will be raised.
pass

View File

@ -1,17 +0,0 @@
"""Example services."""
class BaseService(object):
"""Example base class of service."""
class Users(BaseService):
"""Example users service."""
class Auth(BaseService):
"""Example auth service."""
class Photos(BaseService):
"""Example photo service."""

View File

@ -1,21 +0,0 @@
"""Example web views."""
class BaseWebView(object):
"""Example base class of web view."""
def __init__(self, services):
"""Initializer.
:param services: Bundle of service providers
:type services: catalogs.Services
"""
self.services = services
class Auth(BaseWebView):
"""Example auth web view."""
class Photos(BaseWebView):
"""Example photo processing web view."""

View File

@ -1,101 +0,0 @@
"""Dependency injector catalog bundles unittests."""
import unittest2 as unittest
from dependency_injector import (
catalogs,
providers,
errors,
)
class CatalogA(catalogs.DeclarativeCatalog):
"""Test catalog A."""
p11 = providers.Provider()
p12 = providers.Provider()
class CatalogB(CatalogA):
"""Test catalog B."""
p21 = providers.Provider()
p22 = providers.Provider()
class CatalogBundleTests(unittest.TestCase):
"""Catalog bundle test cases."""
def setUp(self):
"""Set test environment up."""
self.bundle = CatalogB.Bundle(CatalogB.p11,
CatalogB.p12)
def test_get_attr_from_bundle(self):
"""Test get providers (attribute) from catalog bundle."""
self.assertIs(self.bundle.p11, CatalogA.p11)
self.assertIs(self.bundle.p12, CatalogA.p12)
def test_get_attr_not_from_bundle(self):
"""Test get providers (attribute) that are not in bundle."""
self.assertRaises(errors.Error, getattr, self.bundle, 'p21')
self.assertRaises(errors.Error, getattr, self.bundle, 'p22')
def test_get_method_from_bundle(self):
"""Test get providers (get() method) from bundle."""
self.assertIs(self.bundle.get_provider('p11'), CatalogB.p11)
self.assertIs(self.bundle.get_provider('p12'), CatalogB.p12)
def test_get_method_not_from_bundle(self):
"""Test get providers (get() method) that are not in bundle."""
self.assertRaises(errors.Error, self.bundle.get_provider, 'p21')
self.assertRaises(errors.Error, self.bundle.get_provider, 'p22')
def test_has(self):
"""Test checks of providers availability in bundle."""
self.assertTrue(self.bundle.has_provider('p11'))
self.assertTrue(self.bundle.has_provider('p12'))
self.assertFalse(self.bundle.has_provider('p21'))
self.assertFalse(self.bundle.has_provider('p22'))
def test_hasattr(self):
"""Test checks of providers availability in bundle."""
self.assertTrue(hasattr(self.bundle, 'p11'))
self.assertTrue(hasattr(self.bundle, 'p12'))
self.assertFalse(hasattr(self.bundle, 'p21'))
self.assertFalse(hasattr(self.bundle, 'p22'))
def test_create_bundle_with_unbound_provider(self):
"""Test that bundle is not created with unbound provider."""
self.assertRaises(errors.Error, CatalogB.Bundle, providers.Provider())
def test_create_bundle_with_another_catalog_provider(self):
"""Test that bundle can not contain another catalog's provider."""
class TestCatalog(catalogs.DeclarativeCatalog):
"""Test catalog."""
provider = providers.Provider()
self.assertRaises(errors.Error,
CatalogB.Bundle, CatalogB.p21, TestCatalog.provider)
def test_create_bundle_with_another_catalog_provider_with_same_name(self):
"""Test that bundle can not contain another catalog's provider."""
class TestCatalog(catalogs.DeclarativeCatalog):
"""Test catalog."""
p21 = providers.Provider()
self.assertRaises(errors.Error,
CatalogB.Bundle, CatalogB.p21, TestCatalog.p21)
def test_is_bundle_owner(self):
"""Test that catalog bundle is owned by catalog."""
self.assertTrue(CatalogB.is_bundle_owner(self.bundle))
self.assertFalse(CatalogA.is_bundle_owner(self.bundle))
def test_is_bundle_owner_with_not_bundle_instance(self):
"""Test that check of bundle ownership raises error with not bundle."""
self.assertRaises(errors.Error, CatalogB.is_bundle_owner, object())

View File

@ -3,7 +3,6 @@
import unittest2 as unittest import unittest2 as unittest
from dependency_injector import injections from dependency_injector import injections
from dependency_injector import catalogs
from dependency_injector import providers from dependency_injector import providers
from dependency_injector import errors from dependency_injector import errors
@ -26,17 +25,6 @@ class InjectionTests(unittest.TestCase):
injection = injections.Injection(providers.Factory(object)) injection = injections.Injection(providers.Factory(object))
self.assertIsInstance(injection.get_value(), object) self.assertIsInstance(injection.get_value(), object)
def test_value_with_catalog_bundle_injectable(self):
"""Test Injection value property with catalog bundle."""
class TestCatalog(catalogs.DeclarativeCatalog):
"""Test catalog."""
provider = providers.Provider()
injection = injections.Injection(
TestCatalog.Bundle(TestCatalog.provider))
self.assertIsInstance(injection.get_value(), TestCatalog.Bundle)
def test_repr(self): def test_repr(self):
"""Test Injection representation.""" """Test Injection representation."""
provider = providers.Factory(object) provider = providers.Factory(object)

View File

@ -252,50 +252,3 @@ class IsDeclarativeCatalogTests(unittest.TestCase):
"""Test with dynamic catalog.""" """Test with dynamic catalog."""
self.assertFalse(utils.is_declarative_catalog( self.assertFalse(utils.is_declarative_catalog(
catalogs.DynamicCatalog())) catalogs.DynamicCatalog()))
class IsCatalogBundleTests(unittest.TestCase):
"""`is_catalog_bundle()` test cases."""
def test_with_instance(self):
"""Test with instance."""
self.assertTrue(utils.is_catalog_bundle(catalogs.CatalogBundle()))
def test_with_cls(self):
"""Test with class."""
self.assertFalse(utils.is_catalog_bundle(catalogs.CatalogBundle))
def test_with_string(self):
"""Test with string."""
self.assertFalse(utils.is_catalog_bundle('some_string'))
def test_with_object(self):
"""Test with object."""
self.assertFalse(utils.is_catalog_bundle(object()))
class EnsureIsCatalogBundleTests(unittest.TestCase):
"""`ensure_is_catalog_bundle` test cases."""
def test_with_instance(self):
"""Test with instance."""
bundle = catalogs.CatalogBundle()
self.assertIs(utils.ensure_is_catalog_bundle(bundle), bundle)
def test_with_class(self):
"""Test with class."""
self.assertRaises(errors.Error,
utils.ensure_is_catalog_bundle,
catalogs.CatalogBundle)
def test_with_string(self):
"""Test with string."""
self.assertRaises(errors.Error,
utils.ensure_is_catalog_bundle,
'some_string')
def test_with_object(self):
"""Test with object."""
self.assertRaises(errors.Error,
utils.ensure_is_catalog_bundle,
object())