22[ ![ pypi] ( https://img.shields.io/pypi/v/essentials-configuration.svg )] ( https://pypi.python.org/pypi/essentials-configuration )
33[ ![ versions] ( https://img.shields.io/pypi/pyversions/essentials-configuration.svg )] ( https://github.com/Neoteroi/essentials-configuration )
44[ ![ codecov] ( https://codecov.io/gh/Neoteroi/essentials-configuration/branch/main/graph/badge.svg?token=VzAnusWIZt )] ( https://codecov.io/gh/Neoteroi/essentials-configuration )
5- [ ![ license] ( https://img.shields.io/github/license/Neoteroi/essentials-configuration.svg )] ( https://github.com/Neoteroi/essentials-configuration/blob/master /LICENSE )
5+ [ ![ license] ( https://img.shields.io/github/license/Neoteroi/essentials-configuration.svg )] ( https://github.com/Neoteroi/essentials-configuration/blob/main /LICENSE )
66
77# Python configuration utilities
88Implementation of key-value pair based configuration for Python applications.
@@ -18,26 +18,42 @@ This library is freely inspired by .NET Core `Microsoft.Extensions.Configuration
1818The main class is influenced by Luciano Ramalho`s example of
1919JSON structure explorer using attribute notation, in his book [ Fluent Python] ( http://shop.oreilly.com/product/0636920032519.do ) .
2020
21+ ## Overview
22+
23+ ` essentials-configuration ` provides a way to handle configuration roots
24+ composed of different layers, such as configuration files and environmental
25+ variables. Layers are applied in order and can override each others' values,
26+ enabling different scenarios like configuration by environment and system
27+ instance.
28+
2129## Supported sources:
2230* ** yaml** files
2331* ** json** files
2432* ** ini** files
2533* environmental variables
2634* dictionaries
2735* keys and values
36+ * [ Azure Key Vault] ( https://docs.microsoft.com/en-us/azure/key-vault/general/basic-concepts ) , using [ essentials-configuration-keyvault] ( https://github.com/Neoteroi/essentials-configuration )
37+ * custom sources, implementing the ` ConfigurationSource ` interface
2838
2939## Installation
3040
3141``` bash
3242pip install essentials-configuration
3343```
3444
35- Alternatively, to install it with support for ` YAML ` configuration files:
45+ To install with support for ` YAML ` configuration files:
3646
3747```
3848pip install essentials-configuration[yaml]
3949```
4050
51+ ## Extensions
52+
53+ * Azure Key Vault secrets configuration source:
54+ [ essentials-configuration-keyvault] ( https://github.com/Neoteroi/essentials-configuration-keyvault )
55+
56+
4157# Examples
4258
4359### JSON file and environmental variables
@@ -48,14 +64,14 @@ Settings are applied in order, so environmental variables with matching name
4864override values from the ` json ` file.
4965
5066``` python
51- from configuration import ConfigurationBuilder
67+ from configuration.common import ConfigurationBuilder
5268from configuration.json import JSONFile
53- from configuration.env import EnvironmentalVariables
54-
55- builder = ConfigurationBuilder()
69+ from configuration.env import EnvironmentVariables
5670
57- builder.add_source(JSONFile(" settings.json" ))
58- builder.add_source(EnvironmentalVariables(prefix = " APP_" ))
71+ builder = ConfigurationBuilder(
72+ JSONFile(" settings.json" ),
73+ EnvironmentVariables(prefix = " APP_" )
74+ )
5975
6076config = builder.build()
6177```
@@ -76,7 +92,7 @@ And the environment has a variable named `APP_foo=AAA`:
7692
7793``` python
7894>> > config
79- < Configuration {' logging' : { ' level ' : ' INFO ' } , ' example' : ' Hello World ' , ' foo' : ' AAA ' }>
95+ < Configuration {' logging' : ' ... ' , ' example' : ' ... ' , ' foo' : ' ... ' }>
8096>> > config.foo
8197' AAA'
8298>> > config.logging.level
@@ -91,14 +107,14 @@ environmental variables with matching name override values from the `yaml` file
91107
92108
93109``` python
94- from configuration import ConfigurationBuilder
95- from configuration.env import EnvironmentalVariables
110+ from configuration.common import ConfigurationBuilder
111+ from configuration.env import EnvironmentVariables
96112from configuration.yaml import YAMLFile
97113
98114builder = ConfigurationBuilder()
99115
100116builder.add_source(YAMLFile(" settings.yaml" ))
101- builder.add_source(EnvironmentalVariables ())
117+ builder.add_source(EnvironmentVariables ())
102118
103119config = builder.build()
104120```
@@ -111,8 +127,8 @@ present, it is read to override values configured in `settings.yaml` file.
111127``` python
112128import os
113129
114- from configuration import ConfigurationBuilder
115- from configuration.env import EnvironmentalVariables
130+ from configuration.common import ConfigurationBuilder
131+ from configuration.env import EnvironmentVariables
116132from configuration.yaml import YAMLFile
117133
118134environment_name = os.environ[" APP_ENVIRONMENT" ]
@@ -123,15 +139,15 @@ builder.add_source(YAMLFile("settings.yaml"))
123139
124140builder.add_source(YAMLFile(f " settings. { environment_name} .yaml " , optional = True ))
125141
126- builder.add_source(EnvironmentalVariables (prefix = " APP_" ))
142+ builder.add_source(EnvironmentVariables (prefix = " APP_" ))
127143
128144config = builder.build()
129145```
130146
131147### Filtering environmental variables by prefix
132148
133149``` python
134- from configuration import Configuration
150+ from configuration.common import Configuration
135151
136152config = Configuration()
137153
@@ -147,7 +163,7 @@ INI files are parsed using the built-in `configparser` module, therefore
147163support ` [DEFAULT] ` section; all values are kept as strings.
148164
149165``` python
150- from configuration import ConfigurationBuilder
166+ from configuration.common import ConfigurationBuilder
151167from configuration.ini import INIFile
152168
153169builder = ConfigurationBuilder()
@@ -160,7 +176,7 @@ config = builder.build()
160176### Dictionaries
161177
162178``` python
163- from configuration import ConfigurationBuilder
179+ from configuration.common import ConfigurationBuilder
164180
165181builder = ConfigurationBuilder()
166182
@@ -180,7 +196,7 @@ assert config.example[1].id == 2
180196### Keys and values
181197
182198``` python
183- from configuration import ConfigurationBuilder
199+ from configuration.common import ConfigurationBuilder
184200
185201builder = ConfigurationBuilder()
186202
@@ -203,24 +219,22 @@ dictionary keys using the following notation for sub properties:
203219* keys separated by "__ ", such as ` a__d__e `
204220
205221``` python
206- from configuration import ConfigurationBuilder, MapSource
222+ from configuration.common import ConfigurationBuilder, MapSource
207223
208224
209225builder = ConfigurationBuilder(
210- [
211- MapSource(
212- {
213- " a" : {
214- " b" : 1 ,
215- " c" : 2 ,
216- " d" : {
217- " e" : 3 ,
218- " f" : 4 ,
219- },
220- }
226+ MapSource(
227+ {
228+ " a" : {
229+ " b" : 1 ,
230+ " c" : 2 ,
231+ " d" : {
232+ " e" : 3 ,
233+ " f" : 4 ,
234+ },
221235 }
222- )
223- ]
236+ }
237+ )
224238)
225239
226240config = builder.build()
@@ -243,20 +257,18 @@ assert config.a.d.f == 4
243257import os
244258
245259builder = ConfigurationBuilder(
246- [
247- MapSource(
248- {
249- " a" : {
250- " b" : 1 ,
251- " c" : 2 ,
252- " d" : {
253- " e" : 3 ,
254- " f" : 4 ,
255- },
256- }
260+ MapSource(
261+ {
262+ " a" : {
263+ " b" : 1 ,
264+ " c" : 2 ,
265+ " d" : {
266+ " e" : 3 ,
267+ " f" : 4 ,
268+ },
257269 }
258- )
259- ]
270+ }
271+ )
260272)
261273
262274config = builder.build()
@@ -274,7 +286,7 @@ assert config.a.d.f == 4
274286
275287os.environ[" a__d__e" ] = " 5"
276288
277- builder.sources.append(EnvironmentalVariables ())
289+ builder.sources.append(EnvironmentVariables ())
278290
279291config = builder.build()
280292
@@ -285,17 +297,15 @@ assert config.a.d.e == "5"
285297
286298``` python
287299builder = ConfigurationBuilder(
288- [
289- MapSource(
290- {
291- " b2c" : [
292- {" tenant" : " 1" },
293- {" tenant" : " 2" },
294- {" tenant" : " 3" },
295- ]
296- }
297- )
298- ]
300+ MapSource(
301+ {
302+ " b2c" : [
303+ {" tenant" : " 1" },
304+ {" tenant" : " 2" },
305+ {" tenant" : " 3" },
306+ ]
307+ }
308+ )
299309)
300310
301311builder.add_value(" b2c:1:tenant" , " 4" )
@@ -307,3 +317,14 @@ assert config.b2c[1].tenant == "4"
307317assert config.b2c[2 ].tenant == " 3"
308318
309319```
320+
321+ ### Goal and non-goals
322+ The goal of this package is to provide a way to handle configuration roots,
323+ fetching and composing settings from different sources, usually happening
324+ once at application's start.
325+
326+ The library implements only a synchronous API and fetching of application
327+ settings atomically (it doesn't support generators), like application settings
328+ fetched from INI, JSON, or YAML files that are read once in memory entirely.
329+ An asynchronous API is currently out of the scope of this library, since its
330+ primary use case is to fetch configuration values once at application's start.
0 commit comments