diff --git a/dependency_injector/__init__.py b/dependency_injector/__init__.py index 8420bd47..d0cd6304 100644 --- a/dependency_injector/__init__.py +++ b/dependency_injector/__init__.py @@ -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', diff --git a/dependency_injector/catalog.py b/dependency_injector/catalog.py index 5d995317..544cb8c2 100644 --- a/dependency_injector/catalog.py +++ b/dependency_injector/catalog.py @@ -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 '' + @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 ''.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.""" diff --git a/dependency_injector/utils.py b/dependency_injector/utils.py index 42a18202..426584cd 100644 --- a/dependency_injector/utils.py +++ b/dependency_injector/utils.py @@ -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) diff --git a/docs/catalogs/index.rst b/docs/catalogs/index.rst index a1a36705..3106ae5b 100644 --- a/docs/catalogs/index.rst +++ b/docs/catalogs/index.rst @@ -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 diff --git a/docs/catalogs/operating.rst b/docs/catalogs/operating.rst new file mode 100644 index 00000000..4b344b4e --- /dev/null +++ b/docs/catalogs/operating.rst @@ -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 diff --git a/docs/catalogs/overriding.rst b/docs/catalogs/overriding.rst new file mode 100644 index 00000000..4cd3a949 --- /dev/null +++ b/docs/catalogs/overriding.rst @@ -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 + diff --git a/docs/catalogs/subsets.rst b/docs/catalogs/subsets.rst new file mode 100644 index 00000000..be27061a --- /dev/null +++ b/docs/catalogs/subsets.rst @@ -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 diff --git a/docs/catalogs/writing.rst b/docs/catalogs/writing.rst new file mode 100644 index 00000000..054dc094 --- /dev/null +++ b/docs/catalogs/writing.rst @@ -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 diff --git a/docs/images/catalogs/operating_with_providers.png b/docs/images/catalogs/operating_with_providers.png new file mode 100644 index 00000000..7c1a9ac7 Binary files /dev/null and b/docs/images/catalogs/operating_with_providers.png differ diff --git a/docs/images/catalogs/simple.png b/docs/images/catalogs/simple.png deleted file mode 100644 index ae675ca6..00000000 Binary files a/docs/images/catalogs/simple.png and /dev/null differ diff --git a/docs/images/catalogs/subsets.png b/docs/images/catalogs/subsets.png new file mode 100644 index 00000000..f09c0c0d Binary files /dev/null and b/docs/images/catalogs/subsets.png differ diff --git a/docs/images/catalogs/writing_catalogs.png b/docs/images/catalogs/writing_catalogs.png new file mode 100644 index 00000000..a2bc6791 Binary files /dev/null and b/docs/images/catalogs/writing_catalogs.png differ diff --git a/docs/main/changelog.rst b/docs/main/changelog.rst index 7b09e3db..51108acf 100644 --- a/docs/main/changelog.rst +++ b/docs/main/changelog.rst @@ -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 diff --git a/examples/catalogs/simple.py b/examples/catalogs/simple.py deleted file mode 100644 index 1d63eafa..00000000 --- a/examples/catalogs/simple.py +++ /dev/null @@ -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 diff --git a/examples/catalogs/subsets.py b/examples/catalogs/subsets.py new file mode 100644 index 00000000..814af380 --- /dev/null +++ b/examples/catalogs/subsets.py @@ -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 diff --git a/examples/catalogs/writing_catalogs.py b/examples/catalogs/writing_catalogs.py new file mode 100644 index 00000000..bc49bac2 --- /dev/null +++ b/examples/catalogs/writing_catalogs.py @@ -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) diff --git a/tests/test_catalog.py b/tests/test_catalog.py index fd3946f1..26f1ec9b 100644 --- a/tests/test_catalog.py +++ b/tests/test_catalog.py @@ -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): diff --git a/tests/test_utils.py b/tests/test_utils.py index 2943aa3d..3d86b04d 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -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()))