diff --git a/objects/__init__.py b/objects/__init__.py index 4b9e34d3..b8b9a289 100644 --- a/objects/__init__.py +++ b/objects/__init__.py @@ -4,6 +4,7 @@ Dependency management tool for Python projects. """ from .catalog import AbstractCatalog +from .catalog import override from .providers import Provider from .providers import Delegate @@ -20,9 +21,7 @@ from .providers import Config from .injections import KwArg from .injections import Attribute from .injections import Method - -from .decorators import override -from .decorators import inject +from .injections import inject from .errors import Error diff --git a/objects/catalog.py b/objects/catalog.py index 4630a76a..033e60fc 100644 --- a/objects/catalog.py +++ b/objects/catalog.py @@ -65,3 +65,12 @@ class AbstractCatalog(object): """ for name, provider in iteritems(overriding.providers): cls.providers[name].override(provider) + + +def override(catalog): + """Catalog overriding decorator.""" + def decorator(overriding_catalog): + """Overriding decorator.""" + catalog.override(overriding_catalog) + return overriding_catalog + return decorator diff --git a/objects/decorators.py b/objects/decorators.py deleted file mode 100644 index 3884b86c..00000000 --- a/objects/decorators.py +++ /dev/null @@ -1,42 +0,0 @@ -"""Decorators module.""" - -from six import wraps - -from .utils import ensure_is_injection -from .utils import get_injectable_kwargs - - -def override(catalog): - """Catalog overriding decorator.""" - def decorator(overriding_catalog): - """Overriding decorator.""" - catalog.override(overriding_catalog) - return overriding_catalog - return decorator - - -def inject(injection): - """Dependency injection decorator. - - :type injection: Injection - :return: (callable) -> (callable) - """ - injection = ensure_is_injection(injection) - - def decorator(callback): - """Dependency injection decorator.""" - if hasattr(callback, '_injections'): - callback._injections += (injection,) - - @wraps(callback) - def decorated(*args, **kwargs): - """Decorated with dependency injection callback.""" - return callback(*args, - **get_injectable_kwargs(kwargs, - getattr(decorated, - '_injections'))) - - setattr(decorated, '_injections', (injection,)) - - return decorated - return decorator diff --git a/objects/injections.py b/objects/injections.py index 3bb70df7..546fdeb9 100644 --- a/objects/injections.py +++ b/objects/injections.py @@ -1,6 +1,10 @@ """Injections module.""" +from six import wraps + from .utils import is_provider +from .utils import ensure_is_injection +from .utils import get_injectable_kwargs class Injection(object): @@ -42,3 +46,30 @@ class Method(Injection): """Method injection.""" __IS_METHOD_INJECTION__ = True + + +def inject(injection): + """Dependency injection decorator. + + :type injection: Injection + :return: (callable) -> (callable) + """ + injection = ensure_is_injection(injection) + + def decorator(callback): + """Dependency injection decorator.""" + if hasattr(callback, '_injections'): + callback._injections += (injection,) + + @wraps(callback) + def decorated(*args, **kwargs): + """Decorated with dependency injection callback.""" + return callback(*args, + **get_injectable_kwargs(kwargs, + getattr(decorated, + '_injections'))) + + setattr(decorated, '_injections', (injection,)) + + return decorated + return decorator diff --git a/tests/test_catalog.py b/tests/test_catalog.py index 16bedf1c..cc17a499 100644 --- a/tests/test_catalog.py +++ b/tests/test_catalog.py @@ -3,6 +3,7 @@ import unittest2 as unittest from objects.catalog import AbstractCatalog +from objects.catalog import override from objects.providers import Object from objects.providers import Value @@ -68,3 +69,29 @@ class CatalogTests(unittest.TestCase): self.assertIs(Catalog2.provider, Catalog2.providers['provider']) self.assertIsNot(Catalog1.provider, Catalog2.provider) + + +class OverrideTests(unittest.TestCase): + + """Override decorator test cases.""" + + class Catalog(AbstractCatalog): + + """Test catalog.""" + + obj = Object(object()) + another_obj = Object(object()) + + def test_overriding(self): + """Test catalog overriding with another catalog.""" + @override(self.Catalog) + class OverridingCatalog(self.Catalog): + + """Overriding catalog.""" + + obj = Value(1) + another_obj = Value(2) + + self.assertEqual(self.Catalog.obj(), 1) + self.assertEqual(self.Catalog.another_obj(), 2) + diff --git a/tests/test_decorators.py b/tests/test_decorators.py deleted file mode 100644 index 1f3dbbb8..00000000 --- a/tests/test_decorators.py +++ /dev/null @@ -1,115 +0,0 @@ -"""Objects decorators unittests.""" - -import unittest2 as unittest - -from objects.decorators import override -from objects.decorators import inject - -from objects.catalog import AbstractCatalog - -from objects.providers import Factory -from objects.providers import Object -from objects.providers import Value - -from objects.injections import KwArg - -from objects.errors import Error - - -class OverrideTests(unittest.TestCase): - - """Override decorator test cases.""" - - class Catalog(AbstractCatalog): - - """Test catalog.""" - - obj = Object(object()) - another_obj = Object(object()) - - def test_overriding(self): - """Test catalog overriding with another catalog.""" - @override(self.Catalog) - class OverridingCatalog(self.Catalog): - - """Overriding catalog.""" - - obj = Value(1) - another_obj = Value(2) - - self.assertEqual(self.Catalog.obj(), 1) - self.assertEqual(self.Catalog.another_obj(), 2) - - -class InjectTests(unittest.TestCase): - - """Inject decorator test cases.""" - - def test_decorated(self): - """Test `inject()` decorated callback.""" - provider1 = Factory(object) - provider2 = Factory(list) - - @inject(KwArg('a', provider1)) - @inject(KwArg('b', provider2)) - def test(a, b): - return a, b - - a1, b1 = test() - a2, b2 = test() - - self.assertIsInstance(a1, object) - self.assertIsInstance(a2, object) - self.assertIsNot(a1, a2) - - self.assertIsInstance(b1, list) - self.assertIsInstance(b2, list) - self.assertIsNot(b1, b2) - - def test_decorated_kwargs_priority(self): - """Test `inject()` decorated callback kwargs priority.""" - provider1 = Factory(object) - provider2 = Factory(list) - object_a = object() - - @inject(KwArg('a', provider1)) - @inject(KwArg('b', provider2)) - def test(a, b): - return a, b - - a1, b1 = test(a=object_a) - a2, b2 = test(a=object_a) - - self.assertIsInstance(a1, object) - self.assertIsInstance(a2, object) - self.assertIs(a1, object_a) - self.assertIs(a2, object_a) - - self.assertIsInstance(b1, list) - self.assertIsInstance(b2, list) - self.assertIsNot(b1, b2) - - def test_decorated_with_args(self): - """Test `inject()` decorated callback with args.""" - provider = Factory(list) - object_a = object() - - @inject(KwArg('b', provider)) - def test(a, b): - return a, b - - a1, b1 = test(object_a) - a2, b2 = test(object_a) - - self.assertIsInstance(a1, object) - self.assertIsInstance(a2, object) - self.assertIs(a1, object_a) - self.assertIs(a2, object_a) - - self.assertIsInstance(b1, list) - self.assertIsInstance(b2, list) - self.assertIsNot(b1, b2) - - def test_decorate_with_not_injection(self): - """Test `inject()` decorator with not an injection instance.""" - self.assertRaises(Error, inject, object) diff --git a/tests/test_injections.py b/tests/test_injections.py index aa682ecd..84d66cf3 100644 --- a/tests/test_injections.py +++ b/tests/test_injections.py @@ -6,9 +6,12 @@ from objects.injections import Injection from objects.injections import KwArg from objects.injections import Attribute from objects.injections import Method +from objects.injections import inject from objects.providers import Factory +from objects.errors import Error + class InjectionTests(unittest.TestCase): @@ -62,3 +65,77 @@ class MethodTests(unittest.TestCase): injection = Method('some_arg_name', 'some_value') self.assertEqual(injection.name, 'some_arg_name') self.assertEqual(injection.injectable, 'some_value') + + +class InjectTests(unittest.TestCase): + + """Inject decorator test cases.""" + + def test_decorated(self): + """Test `inject()` decorated callback.""" + provider1 = Factory(object) + provider2 = Factory(list) + + @inject(KwArg('a', provider1)) + @inject(KwArg('b', provider2)) + def test(a, b): + return a, b + + a1, b1 = test() + a2, b2 = test() + + self.assertIsInstance(a1, object) + self.assertIsInstance(a2, object) + self.assertIsNot(a1, a2) + + self.assertIsInstance(b1, list) + self.assertIsInstance(b2, list) + self.assertIsNot(b1, b2) + + def test_decorated_kwargs_priority(self): + """Test `inject()` decorated callback kwargs priority.""" + provider1 = Factory(object) + provider2 = Factory(list) + object_a = object() + + @inject(KwArg('a', provider1)) + @inject(KwArg('b', provider2)) + def test(a, b): + return a, b + + a1, b1 = test(a=object_a) + a2, b2 = test(a=object_a) + + self.assertIsInstance(a1, object) + self.assertIsInstance(a2, object) + self.assertIs(a1, object_a) + self.assertIs(a2, object_a) + + self.assertIsInstance(b1, list) + self.assertIsInstance(b2, list) + self.assertIsNot(b1, b2) + + def test_decorated_with_args(self): + """Test `inject()` decorated callback with args.""" + provider = Factory(list) + object_a = object() + + @inject(KwArg('b', provider)) + def test(a, b): + return a, b + + a1, b1 = test(object_a) + a2, b2 = test(object_a) + + self.assertIsInstance(a1, object) + self.assertIsInstance(a2, object) + self.assertIs(a1, object_a) + self.assertIs(a2, object_a) + + self.assertIsInstance(b1, list) + self.assertIsInstance(b2, list) + self.assertIsNot(b1, b2) + + def test_decorate_with_not_injection(self): + """Test `inject()` decorator with not an injection instance.""" + self.assertRaises(Error, inject, object)