Skip to content

Commit 753e863

Browse files
authored
Add Configuration.from_json() method (#602)
* Add implementation and tests * Refactor naming in configuration fixtures * Add typing for .from_json() * Move get/set_ini_files() methods upper * Add init implementation and tests * Refactor typing tests * Add examples * Add docs * Update docs index and readme * Update changelog
1 parent 14b5dda commit 753e863

22 files changed

+13440
-10635
lines changed

README.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ Key features of the ``Dependency Injector``:
5959
- **Overriding**. Can override any provider by another provider on the fly. This helps in testing
6060
and configuring dev/stage environment to replace API clients with stubs etc. See
6161
`Provider overriding <https://python-dependency-injector.ets-labs.org/providers/overriding.html>`_.
62-
- **Configuration**. Reads configuration from ``yaml`` & ``ini`` files, ``pydantic`` settings,
62+
- **Configuration**. Reads configuration from ``yaml``, ``ini``, and ``json`` files, ``pydantic`` settings,
6363
environment variables, and dictionaries.
6464
See `Configuration provider <https://python-dependency-injector.ets-labs.org/providers/configuration.html>`_.
6565
- **Resources**. Helps with initialization and configuring of logging, event loop, thread

docs/index.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ Key features of the ``Dependency Injector``:
7070
- **Overriding**. Can override any provider by another provider on the fly. This helps in testing
7171
and configuring dev/stage environment to replace API clients with stubs etc. See
7272
:ref:`provider-overriding`.
73-
- **Configuration**. Reads configuration from ``yaml`` & ``ini`` files, ``pydantic`` settings,
73+
- **Configuration**. Reads configuration from ``yaml``, ``ini``, and ``json`` files, ``pydantic`` settings,
7474
environment variables, and dictionaries. See :ref:`configuration-provider`.
7575
- **Resources**. Helps with initialization and configuring of logging, event loop, thread
7676
or process pool, etc. Can be used for per-function execution scope in tandem with wiring.

docs/introduction/key_features.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Key features of the ``Dependency Injector``:
1616
- **Overriding**. Can override any provider by another provider on the fly. This helps in testing
1717
and configuring dev/stage environment to replace API clients with stubs etc. See
1818
:ref:`provider-overriding`.
19-
- **Configuration**. Reads configuration from ``yaml`` & ``ini`` files, ``pydantic`` settings,
19+
- **Configuration**. Reads configuration from ``yaml``, ``ini``, and ``json`` files, ``pydantic`` settings,
2020
environment variables, and dictionaries. See :ref:`configuration-provider`.
2121
- **Resources**. Helps with initialization and configuring of logging, event loop, thread
2222
or process pool, etc. Can be used for per-function execution scope in tandem with wiring.

docs/main/changelog.rst

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ follows `Semantic versioning`_
1010

1111
Development
1212
-----------
13+
- Add ``Configuration.from_json()`` method to load configuration from a json file.
1314
- Improve wording on the "Dependency injection and inversion of control in Python" docs page.
1415
- Update typing in the main example and cohesion/coupling correlation definition in
1516
"Dependency injection and inversion of control in Python".

docs/providers/configuration.rst

+44
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,50 @@ To use another loader use ``loader`` argument:
136136

137137
*Don't forget to mirror the changes in the requirements file.*
138138

139+
Loading from a JSON file
140+
------------------------
141+
142+
``Configuration`` provider can load configuration from a ``json`` file using the
143+
:py:meth:`Configuration.from_json` method:
144+
145+
.. literalinclude:: ../../examples/providers/configuration/configuration_json.py
146+
:language: python
147+
:lines: 3-
148+
:emphasize-lines: 12
149+
150+
where ``examples/providers/configuration/config.json`` is:
151+
152+
.. literalinclude:: ../../examples/providers/configuration/config.json
153+
:language: json
154+
155+
Alternatively, you can provide a path to a json file over the configuration provider argument. In that case,
156+
the container will call ``config.from_json()`` automatically:
157+
158+
.. code-block:: python
159+
:emphasize-lines: 3
160+
161+
class Container(containers.DeclarativeContainer):
162+
163+
config = providers.Configuration(json_files=["./config.json"])
164+
165+
166+
if __name__ == "__main__":
167+
container = Container() # Config is loaded from ./config.json
168+
169+
:py:meth:`Configuration.from_json` method supports environment variables interpolation.
170+
171+
.. code-block:: json
172+
173+
{
174+
"section": {
175+
"option1": "${ENV_VAR}",
176+
"option2": "${ENV_VAR}/path",
177+
"option3": "${ENV_VAR:default}"
178+
}
179+
}
180+
181+
See also: :ref:`configuration-envs-interpolation`.
182+
139183
Loading from a Pydantic settings
140184
--------------------------------
141185

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"aws": {
3+
"access_key_id": "KEY",
4+
"secret_access_key": "SECRET"
5+
}
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"""`Configuration` provider values loading example."""
2+
3+
from dependency_injector import containers, providers
4+
5+
6+
class Container(containers.DeclarativeContainer):
7+
8+
config = providers.Configuration()
9+
10+
11+
if __name__ == "__main__":
12+
container = Container()
13+
14+
container.config.from_json("./config.json")
15+
16+
assert container.config() == {
17+
"aws": {
18+
"access_key_id": "KEY",
19+
"secret_access_key": "SECRET",
20+
},
21+
}
22+
assert container.config.aws() == {
23+
"access_key_id": "KEY",
24+
"secret_access_key": "SECRET",
25+
}
26+
assert container.config.aws.access_key_id() == "KEY"
27+
assert container.config.aws.secret_access_key() == "SECRET"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"""`Configuration` provider values loading example."""
2+
3+
from dependency_injector import containers, providers
4+
5+
6+
class Container(containers.DeclarativeContainer):
7+
8+
config = providers.Configuration(json_files=["./config.json"])
9+
10+
11+
if __name__ == "__main__":
12+
container = Container()
13+
14+
assert container.config() == {
15+
"aws": {
16+
"access_key_id": "KEY",
17+
"secret_access_key": "SECRET",
18+
},
19+
}
20+
assert container.config.aws() == {
21+
"access_key_id": "KEY",
22+
"secret_access_key": "SECRET",
23+
}
24+
assert container.config.aws.access_key_id() == "KEY"
25+
assert container.config.aws.secret_access_key() == "SECRET"

0 commit comments

Comments
 (0)