diff --git a/docs/providers/configuration.rst b/docs/providers/configuration.rst index e4c65633..bbe90216 100644 --- a/docs/providers/configuration.rst +++ b/docs/providers/configuration.rst @@ -5,10 +5,11 @@ Configuration provider .. meta:: :keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Configuration,Injection, - Option,Ini,Json,Yaml,Dict,Environment Variable,Load,Read,Get + Option,Ini,Json,Yaml,Pydantic,Dict,Environment Variable,Load,Read,Get :description: Configuration provides configuration options to the other providers. This page demonstrates how to use Configuration provider to inject the dependencies, load - a configuration from an ini or yaml file, dictionary or an environment variable. + a configuration from an ini or yaml file, a dictionary, an environment variable, + or a pydantic settings object. .. currentmodule:: dependency_injector.providers @@ -89,6 +90,38 @@ You can also specify a YAML loader as an argument: *Don't forget to mirror the changes in the requirements file.* +Loading from a Pydantic settings +-------------------------------- + +``Configuration`` provider can load configuration from a ``pydantic`` settings object using the +:py:meth:`Configuration.from_pydantic` method: + +.. literalinclude:: ../../examples/providers/configuration/configuration_pydantic.py + :language: python + :lines: 3- + :emphasize-lines: 31 + +To get the data from pydantic settings ``Configuration`` provider calls ``Settings.dict()`` method. +If you need to pass an argument to this call, use ``.from_pydantic()`` keyword arguments. + +.. code-block:: python + + container.config.from_pydantic(Settings(), exclude={'optional'}) + +.. note:: + + ``Dependency Injector`` doesn't install ``pydantic`` by default. + + You can install the ``Dependency Injector`` with an extra dependency:: + + pip install dependency-injector[pydantic] + + or install ``pydantic`` directly:: + + pip install pydantic + + *Don't forget to mirror the changes in the requirements file.* + Loading from a dictionary ------------------------- @@ -211,7 +244,7 @@ Methods ``.from_*()`` in strict mode raise an exception if configuration file do configuration data is undefined: .. code-block:: python - :emphasize-lines: 10,15,20,25 + :emphasize-lines: 10,15,20,25,30 class Container(containers.DeclarativeContainer): @@ -231,6 +264,11 @@ configuration data is undefined: except FileNotFoundError: ... + try: + container.config.from_pydantic(EmptySettings()) # raise exception + except ValueError: + ... + try: container.config.from_env('UNDEFINED_ENV_VAR') # raise exception except ValueError: diff --git a/examples/providers/configuration/configuration_pydantic.py b/examples/providers/configuration/configuration_pydantic.py new file mode 100644 index 00000000..7dd20460 --- /dev/null +++ b/examples/providers/configuration/configuration_pydantic.py @@ -0,0 +1,37 @@ +"""`Configuration` provider values loading example.""" + +import os + +from dependency_injector import containers, providers +from pydantic import BaseSettings, Field + +# Emulate environment variables +os.environ['AWS_ACCESS_KEY_ID'] = 'KEY' +os.environ['AWS_SECRET_ACCESS_KEY'] = 'SECRET' + + +class AwsSettings(BaseSettings): + + access_key_id: str = Field(env='aws_access_key_id') + secret_access_key: str = Field(env='aws_secret_access_key') + + +class Settings(BaseSettings): + + aws: AwsSettings = AwsSettings() + optional: str = Field(default='default_value') + + +class Container(containers.DeclarativeContainer): + + config = providers.Configuration() + + +if __name__ == '__main__': + container = Container() + + container.config.from_pydantic(Settings()) + + assert container.config.aws.access_key_id() == 'KEY' + assert container.config.aws.secret_access_key() == 'SECRET' + assert container.config.optional() == 'default_value'