Skip to content

Commit 6e80e97

Browse files
v0.0.2 🌵
1 parent 7058ffb commit 6e80e97

20 files changed

Lines changed: 158 additions & 111 deletions

File tree

.github/workflows/build.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,18 +72,18 @@ jobs:
7272
7373
- name: Install distribution dependencies
7474
run: pip install --upgrade twine setuptools wheel
75-
if: matrix.python-version == 3.8 || matrix.python-version == 3.9
75+
if: matrix.python-version == 3.9
7676

7777
- name: Create distribution package
7878
run: python setup.py sdist bdist_wheel
79-
if: matrix.python-version == 3.8 || matrix.python-version == 3.9
79+
if: matrix.python-version == 3.9
8080

8181
- name: Upload distribution package
8282
uses: actions/upload-artifact@master
8383
with:
8484
name: dist-package-${{ matrix.python-version }}
8585
path: dist
86-
if: matrix.python-version == 3.8 || matrix.python-version == 3.9
86+
if: matrix.python-version == 3.9
8787

8888
publish:
8989
runs-on: ubuntu-18.04

.gitignore

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,7 @@ celerybeat-schedule
8484
# Environments
8585
.env
8686
.venv
87-
env/
8887
venv/
89-
ENV/
90-
env.bak/
9188
venv.bak/
9289

9390
# Spyder project settings
@@ -107,4 +104,4 @@ venv.bak/
107104

108105
test-cov.xml
109106
test-output.xml
110-
*.py,cover
107+
*.py,cover

CHANGELOG.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8-
## [1.0.0] - 2021-08-09 :cactus:
9-
- Forks new project from [roconfiguration](https://github.com/Neoteroi/roconfiguration), with name `essentials-configuration`
10-
- New code API to support extensions
8+
## [0.0.2] - 2021-08-11 :cactus:
9+
- Forks a new project from
10+
[roconfiguration](https://github.com/Neoteroi/roconfiguration), with name
11+
`essentials-configuration`
12+
- Implements a new code API that better supports extensions
13+
- Makes `PyYAML` an optional dependency, necessary only if the user desires to
14+
use YAML files
1115
- Applies `isort` and enforces `isort` and `black` checks in CI pipeline

MANIFEST.in

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
include README.md
2-
include LICENSE
2+
include LICENSE
3+
recursive-include configuration py.typed

Makefile

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,20 @@ artifacts: test
55
python setup.py sdist bdist_wheel
66

77

8-
release: test
9-
python setup.py sdist upload
8+
clean:
9+
rm -rf dist/
10+
11+
12+
prepforbuild:
13+
pip install --upgrade twine setuptools wheel
14+
15+
16+
testrelease:
17+
twine upload --repository-url https://test.pypi.org/legacy/ dist/*
18+
19+
20+
release: clean artifacts
21+
twine upload --repository-url https://upload.pypi.org/legacy/ dist/*
1022

1123

1224
test:

README.md

Lines changed: 79 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
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
88
Implementation of key-value pair based configuration for Python applications.
@@ -18,26 +18,42 @@ This library is freely inspired by .NET Core `Microsoft.Extensions.Configuration
1818
The main class is influenced by Luciano Ramalho`s example of
1919
JSON 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
3242
pip 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
```
3848
pip 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
4864
override values from the `json` file.
4965

5066
```python
51-
from configuration import ConfigurationBuilder
67+
from configuration.common import ConfigurationBuilder
5268
from 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

6076
config = 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
96112
from configuration.yaml import YAMLFile
97113

98114
builder = ConfigurationBuilder()
99115

100116
builder.add_source(YAMLFile("settings.yaml"))
101-
builder.add_source(EnvironmentalVariables())
117+
builder.add_source(EnvironmentVariables())
102118

103119
config = builder.build()
104120
```
@@ -111,8 +127,8 @@ present, it is read to override values configured in `settings.yaml` file.
111127
```python
112128
import 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
116132
from configuration.yaml import YAMLFile
117133

118134
environment_name = os.environ["APP_ENVIRONMENT"]
@@ -123,15 +139,15 @@ builder.add_source(YAMLFile("settings.yaml"))
123139

124140
builder.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

128144
config = 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

136152
config = Configuration()
137153

@@ -147,7 +163,7 @@ INI files are parsed using the built-in `configparser` module, therefore
147163
support `[DEFAULT]` section; all values are kept as strings.
148164

149165
```python
150-
from configuration import ConfigurationBuilder
166+
from configuration.common import ConfigurationBuilder
151167
from configuration.ini import INIFile
152168

153169
builder = 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

165181
builder = 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

185201
builder = 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

209225
builder = 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

226240
config = builder.build()
@@ -243,20 +257,18 @@ assert config.a.d.f == 4
243257
import os
244258

245259
builder = 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

262274
config = builder.build()
@@ -274,7 +286,7 @@ assert config.a.d.f == 4
274286

275287
os.environ["a__d__e"] = "5"
276288

277-
builder.sources.append(EnvironmentalVariables())
289+
builder.sources.append(EnvironmentVariables())
278290

279291
config = builder.build()
280292

@@ -285,17 +297,15 @@ assert config.a.d.e == "5"
285297

286298
```python
287299
builder = 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

301311
builder.add_value("b2c:1:tenant", "4")
@@ -307,3 +317,14 @@ assert config.b2c[1].tenant == "4"
307317
assert 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

Comments
 (0)