Skip to content

Commit 54de3a9

Browse files
committed
Merge branch 'release/4.34.0' into master
2 parents 9abf34c + 6ffb98a commit 54de3a9

File tree

10 files changed

+10717
-10388
lines changed

10 files changed

+10717
-10388
lines changed

docs/main/changelog.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,19 @@ that were made in every particular version.
77
From version 0.7.6 *Dependency Injector* framework strictly
88
follows `Semantic versioning`_
99

10+
4.34.0
11+
------
12+
- Add option ``envs_required`` for configuration provider ``.from_yaml()`` and ``.from_ini()``
13+
methods. With ``envs_required=True`` methods ``.from_yaml()`` and ``.from_ini()`` raise
14+
an exception when encounter an undefined environment variable in the configuration file.
15+
By default this option is set to false for preserving previous behavior ``envs_required=False``.
16+
- Add raising of an exception in configuration provider strict mode when provider encounters
17+
an undefined environment variable in the configuration file.
18+
- Update configuration provider environment variables interpolation to replace
19+
undefined environment variables with an empty value.
20+
- Update configuration provider to perform environment variables interpolation before passing
21+
configuration file content to the parser.
22+
1023
4.33.0
1124
------
1225
- Add support of default value for environment variable in INI and YAML

docs/providers/configuration.rst

Lines changed: 93 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@ Configuration provider
55

66
.. meta::
77
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Configuration,Injection,
8-
Option,Ini,Json,Yaml,Pydantic,Dict,Environment Variable,Default,Load,Read,Get
8+
Option,Ini,Json,Yaml,Pydantic,Dict,Environment Variable Interpolation,
9+
Environment Variable Substitution,Environment Variable in Config,
10+
Environment Variable in YAML file,Environment Variable in INI file,Default,Load,Read
911
:description: Configuration provides configuration options to the other providers. This page
1012
demonstrates how to use Configuration provider to inject the dependencies, load
1113
a configuration from an ini or yaml file, a dictionary, an environment variable,
12-
or a pydantic settings object.
14+
or a pydantic settings object. This page also describes how to substitute (interpolate)
15+
environment variables in YAML and INI configuration files.
1316

1417
.. currentmodule:: dependency_injector.providers
1518

@@ -42,12 +45,7 @@ where ``examples/providers/configuration/config.ini`` is:
4245
.. literalinclude:: ../../examples/providers/configuration/config.ini
4346
:language: ini
4447

45-
:py:meth:`Configuration.from_ini` method supports environment variables interpolation. Use
46-
``${ENV_NAME}`` format in the configuration file to substitute value from ``ENV_NAME`` environment
47-
variable.
48-
49-
You can also specify a default value using ``${ENV_NAME:default}`` format. If environment
50-
variable ``ENV_NAME`` is undefined, configuration provider will substitute value ``default``.
48+
:py:meth:`Configuration.from_ini` method supports environment variables interpolation.
5149

5250
.. code-block:: ini
5351
@@ -56,6 +54,8 @@ variable ``ENV_NAME`` is undefined, configuration provider will substitute value
5654
option2 = {$ENV_VAR}/path
5755
option3 = {$ENV_VAR:default}
5856
57+
See also: :ref:`configuration-envs-interpolation`.
58+
5959
Loading from a YAML file
6060
------------------------
6161

@@ -72,12 +72,7 @@ where ``examples/providers/configuration/config.yml`` is:
7272
.. literalinclude:: ../../examples/providers/configuration/config.yml
7373
:language: ini
7474

75-
:py:meth:`Configuration.from_yaml` method supports environment variables interpolation. Use
76-
``${ENV_NAME}`` format in the configuration file to substitute value from ``ENV_NAME`` environment
77-
variable.
78-
79-
You can also specify a default value using ``${ENV_NAME:default}`` format. If environment
80-
variable ``ENV_NAME`` is undefined, configuration provider will substitute value ``default``.
75+
:py:meth:`Configuration.from_yaml` method supports environment variables interpolation.
8176

8277
.. code-block:: ini
8378
@@ -86,6 +81,8 @@ variable ``ENV_NAME`` is undefined, configuration provider will substitute value
8681
option2: {$ENV_VAR}/path
8782
option3: {$ENV_VAR:default}
8883
84+
See also: :ref:`configuration-envs-interpolation`.
85+
8986
:py:meth:`Configuration.from_yaml` method uses custom version of ``yaml.SafeLoader``.
9087
To use another loader use ``loader`` argument:
9188

@@ -191,6 +188,73 @@ where ``examples/providers/configuration/config.local.yml`` is:
191188
.. literalinclude:: ../../examples/providers/configuration/config.local.yml
192189
:language: ini
193190

191+
.. _configuration-envs-interpolation:
192+
193+
Using environment variables in configuration files
194+
--------------------------------------------------
195+
196+
``Configuration`` provider supports environment variables interpolation in configuration files.
197+
Use ``${ENV_NAME}`` in the configuration file to substitute value from environment
198+
variable ``ENV_NAME``.
199+
200+
.. code-block:: ini
201+
202+
section:
203+
option: ${ENV_NAME}
204+
205+
You can also specify a default value using ``${ENV_NAME:default}`` format. If environment
206+
variable ``ENV_NAME`` is undefined, configuration provider will substitute value ``default``.
207+
208+
.. code-block:: ini
209+
210+
[section]
211+
option = {$ENV_NAME:default}
212+
213+
If you'd like to specify a default value for environment variable inside of the application you can use
214+
``os.environ.setdefault()``.
215+
216+
.. literalinclude:: ../../examples/providers/configuration/configuration_env_interpolation_os_default.py
217+
:language: python
218+
:lines: 3-
219+
:emphasize-lines: 12
220+
221+
If environment variable is undefined and doesn't have a default, ``Configuration`` provider
222+
will replace it with an empty value. This is a default behavior. To raise an error on
223+
undefined environment variable that doesn't have a default value, pass argument
224+
``envs_required=True`` to a configuration reading method:
225+
226+
.. code-block:: python
227+
228+
container.config.from_yaml('config.yml', envs_required=True)
229+
230+
See also: :ref:`configuration-strict-mode`.
231+
232+
.. note::
233+
``Configuration`` provider makes environment variables interpolation before parsing. This preserves
234+
original parser behavior. For instance, undefined environment variable in YAML configuration file
235+
will be replaced with an empty value and then YAML parser will load the file.
236+
237+
Original configuration file:
238+
239+
.. code-block:: ini
240+
241+
section:
242+
option: ${ENV_NAME}
243+
244+
Configuration file after interpolation where ``ENV_NAME`` is undefined:
245+
246+
.. code-block:: ini
247+
248+
section:
249+
option:
250+
251+
Configuration provider after parsing interpolated YAML file contains ``None`` in
252+
option ``section.option``:
253+
254+
.. code-block:: python
255+
256+
assert container.config.section.option() is None
257+
194258
Mandatory and optional sources
195259
------------------------------
196260

@@ -310,6 +374,21 @@ configuration data is undefined:
310374
except ValueError:
311375
...
312376
377+
Environment variables interpolation in strict mode raises an exception when encounters
378+
an undefined environment variable without a default value.
379+
380+
.. code-block:: ini
381+
382+
section:
383+
option: {$UNDEFINED}
384+
385+
.. code-block:: python
386+
387+
try:
388+
container.config.from_yaml('undefined_env.yml') # raise exception
389+
except ValueError:
390+
...
391+
313392
You can override ``.from_*()`` methods behaviour in strict mode using ``required`` argument:
314393

315394
.. code-block:: python
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
section:
2+
option: ${ENV_VAR}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
"""`Configuration` provider values loading example."""
2+
3+
import os
4+
5+
from dependency_injector import containers, providers
6+
7+
8+
class Container(containers.DeclarativeContainer):
9+
10+
config = providers.Configuration()
11+
12+
13+
if __name__ == '__main__':
14+
os.environ.setdefault('ENV_VAR', 'default value')
15+
16+
container = Container()
17+
container.config.from_yaml('config-with-env-var.yml')
18+
19+
assert container.config.section.option() == 'default value'

src/dependency_injector/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Top-level package."""
22

3-
__version__ = '4.33.0'
3+
__version__ = '4.34.0'
44
"""Version number.
55
66
:type: str

0 commit comments

Comments
 (0)