diff --git a/docs/providers/configuration.rst b/docs/providers/configuration.rst index 0ce046e6..496cb69d 100644 --- a/docs/providers/configuration.rst +++ b/docs/providers/configuration.rst @@ -16,8 +16,8 @@ Configuration provider .. literalinclude:: ../../examples/providers/configuration/configuration.py :language: python - :emphasize-lines: 4,9-10 - :lines: 4-14 + :emphasize-lines: 7,12-13 + :lines: 3- It implements the principle "use first, define later". @@ -29,8 +29,8 @@ Loading from an INI file .. literalinclude:: ../../examples/providers/configuration/configuration_ini.py :language: python - :lines: 3-5,6- - :emphasize-lines: 6 + :lines: 3- + :emphasize-lines: 12 where ``examples/providers/configuration/config.ini`` is: @@ -49,8 +49,8 @@ Loading from a YAML file .. literalinclude:: ../../examples/providers/configuration/configuration_yaml.py :language: python - :lines: 3-5,6- - :emphasize-lines: 6 + :lines: 3- + :emphasize-lines: 12 where ``examples/providers/configuration/config.yml`` is: @@ -83,8 +83,8 @@ Loading from a dictionary .. literalinclude:: ../../examples/providers/configuration/configuration_dict.py :language: python - :lines: 3-5,6- - :emphasize-lines: 6-13 + :lines: 3- + :emphasize-lines: 12-19 Loading from an environment variable ------------------------------------ @@ -94,8 +94,8 @@ Loading from an environment variable .. literalinclude:: ../../examples/providers/configuration/configuration_env.py :language: python - :lines: 5-7,13-21 - :emphasize-lines: 6-8 + :lines: 3- + :emphasize-lines: 18-20 Loading from the multiple sources --------------------------------- @@ -105,8 +105,8 @@ configuration is merged recursively over the existing configuration. .. literalinclude:: ../../examples/providers/configuration/configuration_multiple.py :language: python - :lines: 3-5,6-14 - :emphasize-lines: 6-7 + :lines: 3- + :emphasize-lines: 12-13 where ``examples/providers/configuration/config.local.yml`` is: @@ -124,7 +124,7 @@ convert it into an ``int`` or a ``float``. .. literalinclude:: ../../examples/providers/configuration/configuration_type.py :language: python :lines: 3- - :emphasize-lines: 17 + :emphasize-lines: 19 ``Configuration`` provider has next helper methods: @@ -137,10 +137,27 @@ The last method ``.as_(callback, *args, **kwargs)`` helps to implement other con .. literalinclude:: ../../examples/providers/configuration/configuration_type_custom.py :language: python :lines: 3- - :emphasize-lines: 16 + :emphasize-lines: 18 With the ``.as_(callback, *args, **kwargs)`` you can specify a function that will be called before the injection. The value from the config will be passed as a first argument. The returned value will be injected. Parameters ``*args`` and ``**kwargs`` are handled as any other injections. +Injecting invariants +-------------------- + +You can inject invariant configuration options based on the value of the other configuration +option. + +To use that you should provide the switch-value as an item of the configuration option that +contains sections ``config.options[config.switch]``: + +- When the value of the ``config.switch`` is ``A``, the ``config.options.A`` is injected +- When the value of the ``config.switch`` is ``B``, the ``config.options.B`` is injected + +.. literalinclude:: ../../examples/providers/configuration/configuration_itemselector.py + :language: python + :lines: 3- + :emphasize-lines: 15,30-31,38 + .. disqus:: diff --git a/examples/providers/configuration/configuration.py b/examples/providers/configuration/configuration.py index a1ea0f44..7a11cbfc 100644 --- a/examples/providers/configuration/configuration.py +++ b/examples/providers/configuration/configuration.py @@ -1,21 +1,24 @@ """`Configuration` provider example.""" import boto3 -from dependency_injector import providers +from dependency_injector import containers, providers -config = providers.Configuration() +class Container(containers.DeclarativeContainer): -s3_client_factory = providers.Factory( - boto3.client, - 's3', - aws_access_key_id=config.aws.access_key_id, - aws_secret_access_key=config.aws.secret_access_key, -) + config = providers.Configuration() + + s3_client_factory = providers.Factory( + boto3.client, + 's3', + aws_access_key_id=config.aws.access_key_id, + aws_secret_access_key=config.aws.secret_access_key, + ) if __name__ == '__main__': - config.from_dict( + container = Container() + container.config.from_dict( { 'aws': { 'access_key_id': 'KEY', @@ -23,4 +26,4 @@ if __name__ == '__main__': }, }, ) - s3_client = s3_client_factory() + s3_client = container.s3_client_factory() diff --git a/examples/providers/configuration/configuration_dict.py b/examples/providers/configuration/configuration_dict.py index 275c2b12..d5669ccc 100644 --- a/examples/providers/configuration/configuration_dict.py +++ b/examples/providers/configuration/configuration_dict.py @@ -1,20 +1,34 @@ """`Configuration` provider values loading example.""" -from dependency_injector import providers +from dependency_injector import containers, providers -config = providers.Configuration() +class Container(containers.DeclarativeContainer): -config.from_dict( - { + config = providers.Configuration() + + +if __name__ == '__main__': + container = Container() + + container.config.from_dict( + { + 'aws': { + 'access_key_id': 'KEY', + 'secret_access_key': 'SECRET', + }, + }, + ) + + assert container.config() == { 'aws': { - 'access_key_id': 'KEY', - 'secret_access_key': 'SECRET', - }, - }, -) - -assert config() == {'aws': {'access_key_id': 'KEY', 'secret_access_key': 'SECRET'}} -assert config.aws() == {'access_key_id': 'KEY', 'secret_access_key': 'SECRET'} -assert config.aws.access_key_id() == 'KEY' -assert config.aws.secret_access_key() == 'SECRET' + 'access_key_id': 'KEY', + 'secret_access_key': 'SECRET', + }, + } + assert container.config.aws() == { + 'access_key_id': 'KEY', + 'secret_access_key': 'SECRET', + } + assert container.config.aws.access_key_id() == 'KEY' + assert container.config.aws.secret_access_key() == 'SECRET' diff --git a/examples/providers/configuration/configuration_env.py b/examples/providers/configuration/configuration_env.py index 52c3e0ca..b9d491bc 100644 --- a/examples/providers/configuration/configuration_env.py +++ b/examples/providers/configuration/configuration_env.py @@ -2,20 +2,25 @@ import os -from dependency_injector import providers +from dependency_injector import containers, providers -# Emulate environment variables -os.environ['AWS_ACCESS_KEY_ID'] = 'KEY' -os.environ['AWS_SECRET_ACCESS_KEY'] = 'SECRET' +class Container(containers.DeclarativeContainer): + + config = providers.Configuration() -config = providers.Configuration() +if __name__ == '__main__': + container = Container() -config.aws.access_key_id.from_env('AWS_ACCESS_KEY_ID') -config.aws.secret_access_key.from_env('AWS_SECRET_ACCESS_KEY') -config.optional.from_env('UNDEFINED', 'default_value') + # Emulate environment variables + os.environ['AWS_ACCESS_KEY_ID'] = 'KEY' + os.environ['AWS_SECRET_ACCESS_KEY'] = 'SECRET' -assert config.aws.access_key_id() == 'KEY' -assert config.aws.secret_access_key() == 'SECRET' -assert config.optional() == 'default_value' + container.config.aws.access_key_id.from_env('AWS_ACCESS_KEY_ID') + container.config.aws.secret_access_key.from_env('AWS_SECRET_ACCESS_KEY') + container.config.optional.from_env('UNDEFINED', 'default_value') + + assert container.config.aws.access_key_id() == 'KEY' + assert container.config.aws.secret_access_key() == 'SECRET' + assert container.config.optional() == 'default_value' diff --git a/examples/providers/configuration/configuration_ini.py b/examples/providers/configuration/configuration_ini.py index 0533a8ae..98783bd0 100644 --- a/examples/providers/configuration/configuration_ini.py +++ b/examples/providers/configuration/configuration_ini.py @@ -1,13 +1,27 @@ """`Configuration` provider values loading example.""" -from dependency_injector import providers +from dependency_injector import containers, providers -config = providers.Configuration() +class Container(containers.DeclarativeContainer): -config.from_ini('examples/providers/configuration/config.ini') + config = providers.Configuration() -assert config() == {'aws': {'access_key_id': 'KEY', 'secret_access_key': 'SECRET'}} -assert config.aws() == {'access_key_id': 'KEY', 'secret_access_key': 'SECRET'} -assert config.aws.access_key_id() == 'KEY' -assert config.aws.secret_access_key() == 'SECRET' + +if __name__ == '__main__': + container = Container() + + container.config.from_ini('examples/providers/configuration/config.ini') + + assert container.config() == { + 'aws': { + 'access_key_id': 'KEY', + 'secret_access_key': 'SECRET', + }, + } + assert container.config.aws() == { + 'access_key_id': 'KEY', + 'secret_access_key': 'SECRET', + } + assert container.config.aws.access_key_id() == 'KEY' + assert container.config.aws.secret_access_key() == 'SECRET' diff --git a/examples/providers/configuration/configuration_itemselector.py b/examples/providers/configuration/configuration_itemselector.py index fd60a616..eb257843 100644 --- a/examples/providers/configuration/configuration_itemselector.py +++ b/examples/providers/configuration/configuration_itemselector.py @@ -1,11 +1,8 @@ -"""`Configuration` provider dynamic item selector. - -Details: https://github.com/ets-labs/python-dependency-injector/issues/274 -""" +"""`Configuration` provider dynamic item selector.""" import dataclasses -from dependency_injector import providers +from dependency_injector import containers, providers @dataclasses.dataclass @@ -14,34 +11,37 @@ class Foo: option2: object -config = providers.Configuration(default={ - 'target': 'A', - 'items': { - 'A': { - 'option1': 60, - 'option2': 80, - }, - 'B': { - 'option1': 10, - 'option2': 20, - }, - }, -}) +class Container(containers.DeclarativeContainer): -foo = providers.Factory( - Foo, - option1=config.items[config.target].option1, - option2=config.items[config.target].option2, -) + config = providers.Configuration(default={ + 'target': 'A', + 'items': { + 'A': { + 'option1': 60, + 'option2': 80, + }, + 'B': { + 'option1': 10, + 'option2': 20, + }, + }, + }) + + foo_factory = providers.Factory( + Foo, + option1=config.items[config.target].option1, + option2=config.items[config.target].option2, + ) if __name__ == '__main__': - config.target.from_env('TARGET') - f = foo() - print(f.option1, f.option2) + container = Container() + container.config.target.from_env('TARGET') + foo = container.foo_factory() + print(foo.option1, foo.option2) -# $ TARGET=A python configuration_itemselector.py -# 60 80 -# $ TARGET=B python configuration_itemselector.py -# 10 20 + # $ TARGET=A python configuration_itemselector.py + # 60 80 + # $ TARGET=B python configuration_itemselector.py + # 10 20 diff --git a/examples/providers/configuration/configuration_multiple.py b/examples/providers/configuration/configuration_multiple.py index 4b85c87b..ac95b3e2 100644 --- a/examples/providers/configuration/configuration_multiple.py +++ b/examples/providers/configuration/configuration_multiple.py @@ -1,14 +1,28 @@ """`Configuration` provider values loading example.""" -from dependency_injector import providers +from dependency_injector import containers, providers -config = providers.Configuration() +class Container(containers.DeclarativeContainer): -config.from_yaml('examples/providers/configuration/config.yml') -config.from_yaml('examples/providers/configuration/config.local.yml') + config = providers.Configuration() -assert config() == {'aws': {'access_key_id': 'LOCAL-KEY', 'secret_access_key': 'LOCAL-SECRET'}} -assert config.aws() == {'access_key_id': 'LOCAL-KEY', 'secret_access_key': 'LOCAL-SECRET'} -assert config.aws.access_key_id() == 'LOCAL-KEY' -assert config.aws.secret_access_key() == 'LOCAL-SECRET' + +if __name__ == '__main__': + container = Container() + + container.config.from_yaml('examples/providers/configuration/config.yml') + container.config.from_yaml('examples/providers/configuration/config.local.yml') + + assert container.config() == { + 'aws': { + 'access_key_id': 'LOCAL-KEY', + 'secret_access_key': 'LOCAL-SECRET', + }, + } + assert container.config.aws() == { + 'access_key_id': 'LOCAL-KEY', + 'secret_access_key': 'LOCAL-SECRET', + } + assert container.config.aws.access_key_id() == 'LOCAL-KEY' + assert container.config.aws.secret_access_key() == 'LOCAL-SECRET' diff --git a/examples/providers/configuration/configuration_type.py b/examples/providers/configuration/configuration_type.py index 213f9f79..8c8e044d 100644 --- a/examples/providers/configuration/configuration_type.py +++ b/examples/providers/configuration/configuration_type.py @@ -2,7 +2,7 @@ import os -from dependency_injector import providers +from dependency_injector import containers, providers class ApiClient: @@ -11,24 +11,28 @@ class ApiClient: self.timeout = timeout -config = providers.Configuration() +class Container(containers.DeclarativeContainer): -api_client_factory = providers.Factory( - ApiClient, - api_key=config.api.key, - timeout=config.api.timeout.as_int(), -) + config = providers.Configuration() + + api_client_factory = providers.Factory( + ApiClient, + api_key=config.api.key, + timeout=config.api.timeout.as_int(), + ) if __name__ == '__main__': + container = Container() + # Emulate environment variables os.environ['API_KEY'] = 'secret' os.environ['API_TIMEOUT'] = '5' - config.api.key.from_env('API_KEY') - config.api.timeout.from_env('API_TIMEOUT') + container.config.api.key.from_env('API_KEY') + container.config.api.timeout.from_env('API_TIMEOUT') - api_client = api_client_factory() + api_client = container.api_client_factory() assert api_client.api_key == 'secret' assert api_client.timeout == 5 diff --git a/examples/providers/configuration/configuration_type_custom.py b/examples/providers/configuration/configuration_type_custom.py index 9b53dafe..6782ab52 100644 --- a/examples/providers/configuration/configuration_type_custom.py +++ b/examples/providers/configuration/configuration_type_custom.py @@ -3,7 +3,7 @@ import os import decimal -from dependency_injector import providers +from dependency_injector import containers, providers class Calculator: @@ -11,20 +11,24 @@ class Calculator: self.pi = pi -config = providers.Configuration() +class Container(containers.DeclarativeContainer): -calculator_factory = providers.Factory( - Calculator, - pi=config.pi.as_(decimal.Decimal), -) + config = providers.Configuration() + + calculator_factory = providers.Factory( + Calculator, + pi=config.pi.as_(decimal.Decimal), + ) if __name__ == '__main__': + container = Container() + # Emulate environment variables os.environ['PI'] = '3.1415926535897932384626433832' - config.pi.from_env('PI') + container.config.pi.from_env('PI') - calculator = calculator_factory() + calculator = container.calculator_factory() assert calculator.pi == decimal.Decimal('3.1415926535897932384626433832') diff --git a/examples/providers/configuration/configuration_yaml.py b/examples/providers/configuration/configuration_yaml.py index 842b4ae8..d281aaf0 100644 --- a/examples/providers/configuration/configuration_yaml.py +++ b/examples/providers/configuration/configuration_yaml.py @@ -1,13 +1,27 @@ """`Configuration` provider values loading example.""" -from dependency_injector import providers +from dependency_injector import containers, providers -config = providers.Configuration() +class Container(containers.DeclarativeContainer): -config.from_yaml('examples/providers/configuration/config.yml') + config = providers.Configuration() -assert config() == {'aws': {'access_key_id': 'KEY', 'secret_access_key': 'SECRET'}} -assert config.aws() == {'access_key_id': 'KEY', 'secret_access_key': 'SECRET'} -assert config.aws.access_key_id() == 'KEY' -assert config.aws.secret_access_key() == 'SECRET' + +if __name__ == '__main__': + container = Container() + + container.config.from_yaml('examples/providers/configuration/config.yml') + + assert container.config() == { + 'aws': { + 'access_key_id': 'KEY', + 'secret_access_key': 'SECRET', + }, + } + assert container.config.aws() == { + 'access_key_id': 'KEY', + 'secret_access_key': 'SECRET', + } + assert container.config.aws.access_key_id() == 'KEY' + assert container.config.aws.secret_access_key() == 'SECRET'