diff --git a/README.md b/README.md index 7e604ec1..78fb8a21 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,7 @@ class ObjectA(object): self.db = db +# Mock of example class. class ObjectAMock(ObjectA): pass @@ -357,3 +358,74 @@ assert arg1 == 1 assert arg2 == 2 assert arg3 == 3 ``` + +Example of objects catalog with config provider: + +```python +""" +Config provider examples. +""" + +from objects import AbstractCatalog +from objects.providers import Config, NewInstance +from objects.injections import InitArg + + +# Some example class. +class ObjectA(object): + def __init__(self, setting_one, setting_two, setting_three): + self.setting_one = setting_one + self.setting_two = setting_two + self.setting_three = setting_three + + +# Catalog of objects providers. +class Catalog(AbstractCatalog): + """ + Objects catalog. + """ + + config = Config() + """ :type: (objects.Config) """ + + object_a = NewInstance(ObjectA, + InitArg('setting_one', config.SETTING_ONE), + InitArg('setting_two', config.SETTING_TWO), + InitArg('setting_three', config.GLOBAL.SETTING_THREE)) + """ :type: (objects.Provider) -> ObjectA """ + + +# Setting config value and making some tests. +Catalog.config.update_from({ + 'SETTING_ONE': 1, + 'SETTING_TWO': 2, + 'GLOBAL': { + 'SETTING_THREE': 3 + } +}) + +object_a1 = Catalog.object_a() + +assert object_a1.setting_one == 1 +assert object_a1.setting_two == 2 +assert object_a1.setting_three == 3 + +# Changing config value one more time and making some tests. +Catalog.config.update_from({ + 'SETTING_ONE': 11, + 'SETTING_TWO': 22, + 'GLOBAL': { + 'SETTING_THREE': 33 + } +}) + +object_a2 = Catalog.object_a() + +assert object_a2.setting_one == 11 +assert object_a2.setting_two == 22 +assert object_a2.setting_three == 33 + +assert object_a1.setting_one == 1 +assert object_a1.setting_two == 2 +assert object_a1.setting_three == 3 +``` diff --git a/examples/config_provider.py b/examples/config_provider.py new file mode 100644 index 00000000..599293b6 --- /dev/null +++ b/examples/config_provider.py @@ -0,0 +1,66 @@ +""" +Config provider examples. +""" + +from objects import AbstractCatalog +from objects.providers import Config, NewInstance +from objects.injections import InitArg + + +# Some example class. +class ObjectA(object): + def __init__(self, setting_one, setting_two, setting_three): + self.setting_one = setting_one + self.setting_two = setting_two + self.setting_three = setting_three + + +# Catalog of objects providers. +class Catalog(AbstractCatalog): + """ + Objects catalog. + """ + + config = Config() + """ :type: (objects.Config) """ + + object_a = NewInstance(ObjectA, + InitArg('setting_one', config.SETTING_ONE), + InitArg('setting_two', config.SETTING_TWO), + InitArg('setting_three', config.GLOBAL.SETTING_THREE)) + """ :type: (objects.Provider) -> ObjectA """ + + +# Setting config value and making some tests. +Catalog.config.update_from({ + 'SETTING_ONE': 1, + 'SETTING_TWO': 2, + 'GLOBAL': { + 'SETTING_THREE': 3 + } +}) + +object_a1 = Catalog.object_a() + +assert object_a1.setting_one == 1 +assert object_a1.setting_two == 2 +assert object_a1.setting_three == 3 + +# Changing config value one more time and making some tests. +Catalog.config.update_from({ + 'SETTING_ONE': 11, + 'SETTING_TWO': 22, + 'GLOBAL': { + 'SETTING_THREE': 33 + } +}) + +object_a2 = Catalog.object_a() + +assert object_a2.setting_one == 11 +assert object_a2.setting_two == 22 +assert object_a2.setting_three == 33 + +assert object_a1.setting_one == 1 +assert object_a1.setting_two == 2 +assert object_a1.setting_three == 3 diff --git a/examples/overrides.py b/examples/overrides.py index 242ec45a..4b4dc4db 100644 --- a/examples/overrides.py +++ b/examples/overrides.py @@ -16,6 +16,7 @@ class ObjectA(object): self.db = db +# Mock of example class. class ObjectAMock(ObjectA): pass diff --git a/objects/providers.py b/objects/providers.py index 9b0a63dc..c94361e3 100644 --- a/objects/providers.py +++ b/objects/providers.py @@ -251,7 +251,7 @@ class Value(_StaticProvider): class Callable(Provider): """ - Callable providers will provides callable calls with some predefined + Callable provider will provide callable calls with some predefined dependencies injections. """ @@ -275,3 +275,68 @@ class Callable(Provider): injections.update(kwargs) return self.calls(*args, **injections) + + +class _DeferredConfig(Provider): + """ + Deferred config providers provide an value from the root config object. + """ + def __init__(self, paths, root_config): + """ + Initializer. + """ + self.paths = paths + self.root_config = root_config + super(_DeferredConfig, self).__init__() + + def __getattr__(self, item): + """ + Returns instance of deferred config. + """ + return _DeferredConfig(paths=self.paths + (item,), + root_config=self.root_config) + + def __call__(self, *args, **kwargs): + """ + Returns provided instance. + """ + return self.root_config(self.paths) + + +class Config(Provider): + """ + Config provider provides dict values. Also config provider creates + deferred config objects for all undefined attribute calls. + """ + + def __init__(self, value=None): + """ + Initializer. + """ + if not value: + value = dict() + self.value = value + super(Config, self).__init__() + + def update_from(self, value): + """ + Updates current value from another one. + """ + self.value.update(value) + + def __getattr__(self, item): + """ + Returns instance of deferred config. + """ + return _DeferredConfig(paths=(item,), + root_config=self) + + def __call__(self, paths=None): + """ + Returns provided instance. + """ + value = self.value + if paths: + for path in paths: + value = value[path] + return value