zpp_config 2.2.0__tar.gz → 2.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {zpp_config-2.2.0/zpp_config.egg-info → zpp_config-2.2.2}/PKG-INFO +56 -56
- zpp_config-2.2.2/zpp_config/backend/toml.py +28 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/zpp_config/config.py +25 -3
- {zpp_config-2.2.0 → zpp_config-2.2.2/zpp_config.egg-info}/PKG-INFO +56 -56
- zpp_config-2.2.0/zpp_config/backend/toml.py +0 -13
- {zpp_config-2.2.0 → zpp_config-2.2.2}/LICENSE +0 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/README.md +0 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/setup.cfg +0 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/tests/test_access.py +0 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/tests/test_backends.py +0 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/tests/test_merge_update_delete.py +0 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/tests/test_validation.py +0 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/zpp_config/__init__.py +0 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/zpp_config/backend/__init__.py +0 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/zpp_config/backend/cfg.py +0 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/zpp_config/backend/global_backend.py +0 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/zpp_config/backend/ini.py +0 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/zpp_config/backend/json.py +0 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/zpp_config/backend/yaml.py +0 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/zpp_config/cli.py +0 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/zpp_config/core/__init__.py +0 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/zpp_config/core/autoreload.py +0 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/zpp_config/core/logs.py +0 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/zpp_config/core/vault.py +0 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/zpp_config/core/vault_encryption.py +0 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/zpp_config.egg-info/SOURCES.txt +0 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/zpp_config.egg-info/dependency_links.txt +0 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/zpp_config.egg-info/entry_points.txt +0 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/zpp_config.egg-info/requires.txt +0 -0
- {zpp_config-2.2.0 → zpp_config-2.2.2}/zpp_config.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: zpp_config
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.2
|
|
4
4
|
Summary: Module pour le chargement et la modification de fichier de configuration
|
|
5
5
|
Home-page: https://github.com/ZephyrOff/zpp_config
|
|
6
6
|
Author:
|
|
@@ -37,18 +37,18 @@ Dynamic: project-url
|
|
|
37
37
|
Dynamic: requires-dist
|
|
38
38
|
Dynamic: summary
|
|
39
39
|
|
|
40
|
-
#
|
|
40
|
+
# Présentation
|
|
41
41
|
|
|
42
|
-
Ce module fournit un
|
|
42
|
+
Ce module fournit un système complet de **gestion de fichiers de configuration** permettant :
|
|
43
43
|
|
|
44
44
|
- YAML / JSON / TOML
|
|
45
45
|
- Templates Jinja2 (avec variables, `env()`, `vault()`, `vault_encryption()`)
|
|
46
46
|
- Chargement lazy - Auto-save - Export
|
|
47
|
-
- Validation via
|
|
48
|
-
-
|
|
49
|
-
- Merge / Update sans
|
|
47
|
+
- Validation via schéma hiérarchique et règles globales
|
|
48
|
+
- Accès dynamique par attributs _ou_ indexés (`cfg.db.host`)
|
|
49
|
+
- Merge / Update sans écrasement
|
|
50
50
|
- Auto-reload du fichier via **watchdog**
|
|
51
|
-
-
|
|
51
|
+
- Compatibilité Vault (clé protégée et décryptage)
|
|
52
52
|
|
|
53
53
|
# Installation
|
|
54
54
|
|
|
@@ -66,11 +66,11 @@ from zpp_config import Config
|
|
|
66
66
|
config = Config("config.yaml")
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
Le backend est automatiquement choisi selon l
|
|
69
|
+
Le backend est automatiquement choisi selon l’extension du fichier, mais il est possible de définir le type de configuration avec l'attribut **filetype** (yaml, json ou toml).
|
|
70
70
|
|
|
71
|
-
Lors de l'initialisation, il est
|
|
71
|
+
Lors de l'initialisation, il est également possible de définir plusieurs paramètres qui seront utile pour le render Jinja.
|
|
72
72
|
|
|
73
|
-
**context**:
|
|
73
|
+
**context**: défini un dictionnaire contenant les variables Jinja
|
|
74
74
|
**vault_file**: emplacement du fichier vault
|
|
75
75
|
**vault_keyfile**: emplacement du fichier contenant le mot de passe du vault
|
|
76
76
|
**vault_password**: mot de passe du vault
|
|
@@ -90,7 +90,7 @@ config = Config(
|
|
|
90
90
|
|
|
91
91
|
#### set_context()
|
|
92
92
|
|
|
93
|
-
Il est possible de
|
|
93
|
+
Il est possible de redéfinir le context après chargement grâce à:
|
|
94
94
|
|
|
95
95
|
```python
|
|
96
96
|
config.set_context({"env": "staging", "debug": True})
|
|
@@ -99,38 +99,38 @@ config.reload() # re-rend le template avec le nouveau contexte
|
|
|
99
99
|
|
|
100
100
|
### Chargement du fichier
|
|
101
101
|
|
|
102
|
-
Il est possible de forcer le chargement du fichier avec la
|
|
102
|
+
Il est possible de forcer le chargement du fichier avec la méthode **load**
|
|
103
103
|
|
|
104
104
|
```python
|
|
105
105
|
config.load()
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
-
Toutefois, la configuration sera
|
|
108
|
+
Toutefois, la configuration sera chargé automatiquement lors du premier appel de la configuration.
|
|
109
109
|
|
|
110
110
|
#### Auto-reload
|
|
111
111
|
|
|
112
|
-
Il est possible d'activer l'auto-reload pour permet de recharger la configuration dans le cas
|
|
112
|
+
Il est possible d'activer l'auto-reload pour permet de recharger la configuration dans le cas où le fichier de configuration change
|
|
113
113
|
|
|
114
114
|
```python
|
|
115
115
|
config.autoreload(True)
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
-
Il est possible de
|
|
118
|
+
Il est possible de définir un callback a déclenché lorsque la configuration est rechargé
|
|
119
119
|
|
|
120
120
|
```python
|
|
121
121
|
def on_reload(cfg):
|
|
122
|
-
print("Configuration
|
|
122
|
+
print("Configuration rechargée !")
|
|
123
123
|
|
|
124
124
|
config._on_reload = on_reload
|
|
125
125
|
config.autoreload(True)
|
|
126
126
|
```
|
|
127
127
|
|
|
128
|
-
On est
|
|
128
|
+
On est également désactiver l'auto-reload avec:
|
|
129
129
|
```python
|
|
130
130
|
config.stop_autoreload()
|
|
131
131
|
```
|
|
132
132
|
|
|
133
|
-
###
|
|
133
|
+
### Accès aux valeurs
|
|
134
134
|
|
|
135
135
|
#### Par attributs
|
|
136
136
|
```python
|
|
@@ -144,13 +144,13 @@ db_host = config["db.host"]
|
|
|
144
144
|
```python
|
|
145
145
|
db_host = config.get("db.host", default="127.0.0.1")
|
|
146
146
|
```
|
|
147
|
-
####
|
|
147
|
+
#### Itération
|
|
148
148
|
```python
|
|
149
149
|
for key, sub in config.db.items():
|
|
150
150
|
print(key, sub.to_dict())
|
|
151
151
|
```
|
|
152
152
|
|
|
153
|
-
####
|
|
153
|
+
#### Vérifier l’existence d’un chemin
|
|
154
154
|
```python
|
|
155
155
|
"db.host" in config # True / False
|
|
156
156
|
```
|
|
@@ -164,7 +164,7 @@ config.set("feature.enable", True)
|
|
|
164
164
|
config.delete("db.password")
|
|
165
165
|
```
|
|
166
166
|
|
|
167
|
-
Toutes les modifications sont
|
|
167
|
+
Toutes les modifications sont gardées en mémoire tant qu’on ne sauvegarde pas.
|
|
168
168
|
|
|
169
169
|
### Suppression des valeurs
|
|
170
170
|
|
|
@@ -178,13 +178,13 @@ del config.db.password
|
|
|
178
178
|
|
|
179
179
|
#### Sauvegarde manuelle
|
|
180
180
|
|
|
181
|
-
Pour sauvegarder la configuration, on utilise la
|
|
181
|
+
Pour sauvegarder la configuration, on utilise la méthode **save**
|
|
182
182
|
|
|
183
183
|
```python
|
|
184
184
|
config.save()
|
|
185
185
|
```
|
|
186
186
|
|
|
187
|
-
L'argument **filepath** permettra de
|
|
187
|
+
L'argument **filepath** permettra de définir le fichier de sortie.
|
|
188
188
|
|
|
189
189
|
|
|
190
190
|
#### Sauvegarde automatique
|
|
@@ -204,39 +204,39 @@ config.merge({"db": {"port": 3307}}, overload=True)
|
|
|
204
204
|
```
|
|
205
205
|
|
|
206
206
|
|
|
207
|
-
Met
|
|
207
|
+
Met à jour **une partie** :
|
|
208
208
|
```python
|
|
209
209
|
config.update("db", {"user": "root"})
|
|
210
210
|
```
|
|
211
211
|
|
|
212
|
-
- `overload=False`
|
|
213
|
-
- `overload=True`
|
|
212
|
+
- `overload=False` → ne remplace pas les valeurs existantes
|
|
213
|
+
- `overload=True` → écrase celles existantes
|
|
214
214
|
|
|
215
|
-
### Vault et
|
|
215
|
+
### Vault et données chiffrées
|
|
216
216
|
|
|
217
|
-
Le render Jinja fournis 2
|
|
217
|
+
Le render Jinja fournis 2 méthodes pour récupérer des données chiffrées depuis un fichier vault ou un string vault_encryption
|
|
218
218
|
|
|
219
|
-
La
|
|
219
|
+
La méthode **vault** permet de récupérer des clés depuis un vault
|
|
220
220
|
|
|
221
221
|
```python
|
|
222
222
|
password: "{{ vault('db_password') }}"
|
|
223
223
|
```
|
|
224
224
|
|
|
225
|
-
Lors de l'initialisation de la config, il faudra
|
|
225
|
+
Lors de l'initialisation de la config, il faudra forcément **vault_file** et **vault_password** ou **vault_keyfile**
|
|
226
226
|
|
|
227
|
-
La
|
|
227
|
+
La méthode **vault_encryption** permet de déchiffrer des clés vault_encryption
|
|
228
228
|
|
|
229
229
|
```python
|
|
230
230
|
api_key: "{{ vault_encryption('encrypted_api_key') }}"
|
|
231
231
|
```
|
|
232
232
|
|
|
233
|
-
Lors de l'initialisation de la config, il faudra
|
|
233
|
+
Lors de l'initialisation de la config, il faudra forcément **vault_encryption_keyfile** ou **vault_encryption_password**
|
|
234
234
|
|
|
235
|
-
###
|
|
235
|
+
### Méthode complémentaire Jinja
|
|
236
236
|
|
|
237
|
-
####
|
|
237
|
+
#### Méthode env
|
|
238
238
|
|
|
239
|
-
La
|
|
239
|
+
La méthode **env** permet de récupérer des variables d'environnements
|
|
240
240
|
|
|
241
241
|
```python
|
|
242
242
|
debug: "{{ env('DEBUG', False) }}"
|
|
@@ -245,7 +245,7 @@ url: "https://{{ env('DOMAIN') }}/api"
|
|
|
245
245
|
|
|
246
246
|
## Enregistrement Jinja (filtres / tests / globals)
|
|
247
247
|
|
|
248
|
-
Tu peux enrichir l'environnement Jinja
|
|
248
|
+
Tu peux enrichir l'environnement Jinja utilisé pour rendre le fichier de config.
|
|
249
249
|
#### register_filter(name: str, func)
|
|
250
250
|
|
|
251
251
|
Enregistre un **filtre** Jinja utilisable dans le template.
|
|
@@ -306,10 +306,10 @@ generated_at: "{{ now() }}"
|
|
|
306
306
|
|
|
307
307
|
### Validation de la configuration
|
|
308
308
|
|
|
309
|
-
#### Validation via
|
|
309
|
+
#### Validation via schéma hiérarchique
|
|
310
310
|
|
|
311
|
-
Il est possible de
|
|
312
|
-
Le
|
|
311
|
+
Il est possible de vérifier une configuration à partir d'un schéma.
|
|
312
|
+
Le schéma va décrire l'architecture et les prérequis des clés définis.
|
|
313
313
|
|
|
314
314
|
```python
|
|
315
315
|
schema = {
|
|
@@ -322,10 +322,10 @@ schema = {
|
|
|
322
322
|
errors = config.validate(schema=schema)
|
|
323
323
|
```
|
|
324
324
|
|
|
325
|
-
#### Validation via des
|
|
325
|
+
#### Validation via des règles
|
|
326
326
|
|
|
327
|
-
Il est possible de
|
|
328
|
-
Le
|
|
327
|
+
Il est possible de vérifier une configuration à partir d'un schéma.
|
|
328
|
+
Le schéma va décrire l'architecture et les prérequis des clés définis.
|
|
329
329
|
|
|
330
330
|
```python
|
|
331
331
|
rules = {
|
|
@@ -335,16 +335,16 @@ rules = {
|
|
|
335
335
|
errors = config.validate(rules=rules, strict=False)
|
|
336
336
|
```
|
|
337
337
|
|
|
338
|
-
####
|
|
338
|
+
#### Définition possible
|
|
339
339
|
|
|
340
|
-
|
|
|
340
|
+
|Règle|Pour|Description|
|
|
341
341
|
|---|---|---|
|
|
342
|
-
|`_required`|Tout|
|
|
342
|
+
|`_required`|Tout|Clé obligatoire|
|
|
343
343
|
|`_type`|Tout|Type Python attendu|
|
|
344
|
-
|`_min`, `_max`|
|
|
345
|
-
|`_len`, `_min_len`, `_max_len`|
|
|
346
|
-
|`_regex`|
|
|
347
|
-
|`_enum`|Tout|Liste de valeurs
|
|
344
|
+
|`_min`, `_max`|Numérique|Limites|
|
|
345
|
+
|`_len`, `_min_len`, `_max_len`|Chaînes|Taille|
|
|
346
|
+
|`_regex`|Chaînes|Validation Regex|
|
|
347
|
+
|`_enum`|Tout|Liste de valeurs autorisées|
|
|
348
348
|
|`_not`|Tout|Valeur interdite|
|
|
349
349
|
|
|
350
350
|
### Export
|
|
@@ -357,37 +357,37 @@ config.export("output.toml", type="toml")
|
|
|
357
357
|
|
|
358
358
|
### Conversion
|
|
359
359
|
|
|
360
|
-
Ces
|
|
360
|
+
Ces méthodes permettent d'obtenir des formats de sortie facilement utilisables.
|
|
361
361
|
|
|
362
362
|
### to_dict()
|
|
363
363
|
|
|
364
|
-
Retourne le contenu du
|
|
364
|
+
Retourne le contenu du nœud courant (ou racine) sous forme de `dict` Python standard.
|
|
365
365
|
|
|
366
366
|
Exemple :
|
|
367
367
|
```python
|
|
368
368
|
data = config.to_dict()
|
|
369
|
-
# data est un dict
|
|
369
|
+
# data est un dict prêt à être sérialisé
|
|
370
370
|
```
|
|
371
371
|
|
|
372
372
|
### to_json(indent: int = 4)
|
|
373
373
|
|
|
374
|
-
Retourne une
|
|
374
|
+
Retourne une chaîne JSON formatée du nœud courant :
|
|
375
375
|
```python
|
|
376
376
|
json_str = config.to_json()
|
|
377
377
|
```
|
|
378
378
|
|
|
379
379
|
### to_yaml(sort_keys: bool = True)
|
|
380
380
|
|
|
381
|
-
Retourne YAML
|
|
381
|
+
Retourne YAML sérialisé :
|
|
382
382
|
```python
|
|
383
383
|
yaml_str = config.to_yaml()
|
|
384
384
|
```
|
|
385
385
|
|
|
386
386
|
### to_toml()
|
|
387
387
|
|
|
388
|
-
Retourne TOML
|
|
388
|
+
Retourne TOML sérialisé (si toml est disponible) :
|
|
389
389
|
```python
|
|
390
390
|
toml_str = config.to_toml()
|
|
391
391
|
```
|
|
392
392
|
|
|
393
|
-
Ces
|
|
393
|
+
Ces méthodes n’écrivent pas sur le disque — elles renvoient des chaînes. Pour écrire un fichier, utilise `export(filepath, type=...)` ou `save()`.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from tomlkit import parse, dumps
|
|
2
|
+
from tomlkit.items import Table, Array
|
|
3
|
+
from tomlkit.toml_document import TOMLDocument
|
|
4
|
+
from .global_backend import ConfigBackend
|
|
5
|
+
|
|
6
|
+
#Convertisseur pour transformer les objets TOML en dictionnaire
|
|
7
|
+
def tomlkit_to_dict(obj):
|
|
8
|
+
if isinstance(obj, (TOMLDocument, Table)):
|
|
9
|
+
return {k: tomlkit_to_dict(v) for k, v in obj.items()}
|
|
10
|
+
elif isinstance(obj, Array):
|
|
11
|
+
return [tomlkit_to_dict(v) for v in obj]
|
|
12
|
+
else:
|
|
13
|
+
return obj
|
|
14
|
+
|
|
15
|
+
class TomlBackend(ConfigBackend):
|
|
16
|
+
"""NOUVEAU: Backend pour les fichiers TOML."""
|
|
17
|
+
def load(self, filename):
|
|
18
|
+
doc = parse(filename.read_text())
|
|
19
|
+
return tomlkit_to_dict(doc)
|
|
20
|
+
|
|
21
|
+
def load_data(self, rendered):
|
|
22
|
+
if not rendered.strip():
|
|
23
|
+
return {}
|
|
24
|
+
doc = parse(rendered)
|
|
25
|
+
return tomlkit_to_dict(doc)
|
|
26
|
+
|
|
27
|
+
def save(self, filename, data):
|
|
28
|
+
filename.write_text(dumps(data))
|
|
@@ -1,10 +1,32 @@
|
|
|
1
1
|
import impmagic
|
|
2
|
-
|
|
2
|
+
from jinja2 import FileSystemLoader
|
|
3
|
+
from pathlib import Path
|
|
3
4
|
|
|
4
5
|
class ValidationError(Exception):
|
|
5
6
|
pass
|
|
6
7
|
|
|
7
8
|
|
|
9
|
+
class SafeFileSystemLoader(FileSystemLoader):
|
|
10
|
+
def get_source(self, environment, template):
|
|
11
|
+
try:
|
|
12
|
+
return super().get_source(environment, template)
|
|
13
|
+
|
|
14
|
+
except UnicodeDecodeError:
|
|
15
|
+
# Reconstruction du chemin réel
|
|
16
|
+
for searchpath in self.searchpath:
|
|
17
|
+
filename = Path(searchpath) / template
|
|
18
|
+
if filename.exists():
|
|
19
|
+
break
|
|
20
|
+
else:
|
|
21
|
+
raise
|
|
22
|
+
|
|
23
|
+
# Fallback Windows
|
|
24
|
+
with open(filename, "r", encoding="cp1252") as f:
|
|
25
|
+
source = f.read()
|
|
26
|
+
|
|
27
|
+
return source, str(filename), lambda: False
|
|
28
|
+
|
|
29
|
+
|
|
8
30
|
## Méthode Jinja2
|
|
9
31
|
@impmagic.loader(
|
|
10
32
|
{'module':'os'},
|
|
@@ -338,7 +360,7 @@ class Config(ConfigNode):
|
|
|
338
360
|
{'module':'zpp_config.backend.ini', 'submodule': ['IniBackend']},
|
|
339
361
|
{'module':'zpp_config.backend.cfg', 'submodule': ['CfgBackend']},
|
|
340
362
|
{'module':'pathlib', 'submodule': ['Path']},
|
|
341
|
-
{'module':'jinja2', 'submodule': ['Environment'
|
|
363
|
+
{'module':'jinja2', 'submodule': ['Environment']},
|
|
342
364
|
{'module':'zpp_config.core.vault_encryption', 'submodule': ['vault_decrypt']},
|
|
343
365
|
)
|
|
344
366
|
def __init__(self, filename, filetype=None, context=None, vault_file=None, vault_keyfile=None, vault_password=None, vault_encryption_keyfile=None, vault_encryption_password=None):
|
|
@@ -358,7 +380,7 @@ class Config(ConfigNode):
|
|
|
358
380
|
|
|
359
381
|
# Environment Jinja2 personnalisable
|
|
360
382
|
self._env = Environment(
|
|
361
|
-
loader=
|
|
383
|
+
loader=SafeFileSystemLoader(self._filename.parent),
|
|
362
384
|
autoescape=False
|
|
363
385
|
)
|
|
364
386
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: zpp_config
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.2
|
|
4
4
|
Summary: Module pour le chargement et la modification de fichier de configuration
|
|
5
5
|
Home-page: https://github.com/ZephyrOff/zpp_config
|
|
6
6
|
Author:
|
|
@@ -37,18 +37,18 @@ Dynamic: project-url
|
|
|
37
37
|
Dynamic: requires-dist
|
|
38
38
|
Dynamic: summary
|
|
39
39
|
|
|
40
|
-
#
|
|
40
|
+
# Présentation
|
|
41
41
|
|
|
42
|
-
Ce module fournit un
|
|
42
|
+
Ce module fournit un système complet de **gestion de fichiers de configuration** permettant :
|
|
43
43
|
|
|
44
44
|
- YAML / JSON / TOML
|
|
45
45
|
- Templates Jinja2 (avec variables, `env()`, `vault()`, `vault_encryption()`)
|
|
46
46
|
- Chargement lazy - Auto-save - Export
|
|
47
|
-
- Validation via
|
|
48
|
-
-
|
|
49
|
-
- Merge / Update sans
|
|
47
|
+
- Validation via schéma hiérarchique et règles globales
|
|
48
|
+
- Accès dynamique par attributs _ou_ indexés (`cfg.db.host`)
|
|
49
|
+
- Merge / Update sans écrasement
|
|
50
50
|
- Auto-reload du fichier via **watchdog**
|
|
51
|
-
-
|
|
51
|
+
- Compatibilité Vault (clé protégée et décryptage)
|
|
52
52
|
|
|
53
53
|
# Installation
|
|
54
54
|
|
|
@@ -66,11 +66,11 @@ from zpp_config import Config
|
|
|
66
66
|
config = Config("config.yaml")
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
Le backend est automatiquement choisi selon l
|
|
69
|
+
Le backend est automatiquement choisi selon l’extension du fichier, mais il est possible de définir le type de configuration avec l'attribut **filetype** (yaml, json ou toml).
|
|
70
70
|
|
|
71
|
-
Lors de l'initialisation, il est
|
|
71
|
+
Lors de l'initialisation, il est également possible de définir plusieurs paramètres qui seront utile pour le render Jinja.
|
|
72
72
|
|
|
73
|
-
**context**:
|
|
73
|
+
**context**: défini un dictionnaire contenant les variables Jinja
|
|
74
74
|
**vault_file**: emplacement du fichier vault
|
|
75
75
|
**vault_keyfile**: emplacement du fichier contenant le mot de passe du vault
|
|
76
76
|
**vault_password**: mot de passe du vault
|
|
@@ -90,7 +90,7 @@ config = Config(
|
|
|
90
90
|
|
|
91
91
|
#### set_context()
|
|
92
92
|
|
|
93
|
-
Il est possible de
|
|
93
|
+
Il est possible de redéfinir le context après chargement grâce à:
|
|
94
94
|
|
|
95
95
|
```python
|
|
96
96
|
config.set_context({"env": "staging", "debug": True})
|
|
@@ -99,38 +99,38 @@ config.reload() # re-rend le template avec le nouveau contexte
|
|
|
99
99
|
|
|
100
100
|
### Chargement du fichier
|
|
101
101
|
|
|
102
|
-
Il est possible de forcer le chargement du fichier avec la
|
|
102
|
+
Il est possible de forcer le chargement du fichier avec la méthode **load**
|
|
103
103
|
|
|
104
104
|
```python
|
|
105
105
|
config.load()
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
-
Toutefois, la configuration sera
|
|
108
|
+
Toutefois, la configuration sera chargé automatiquement lors du premier appel de la configuration.
|
|
109
109
|
|
|
110
110
|
#### Auto-reload
|
|
111
111
|
|
|
112
|
-
Il est possible d'activer l'auto-reload pour permet de recharger la configuration dans le cas
|
|
112
|
+
Il est possible d'activer l'auto-reload pour permet de recharger la configuration dans le cas où le fichier de configuration change
|
|
113
113
|
|
|
114
114
|
```python
|
|
115
115
|
config.autoreload(True)
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
-
Il est possible de
|
|
118
|
+
Il est possible de définir un callback a déclenché lorsque la configuration est rechargé
|
|
119
119
|
|
|
120
120
|
```python
|
|
121
121
|
def on_reload(cfg):
|
|
122
|
-
print("Configuration
|
|
122
|
+
print("Configuration rechargée !")
|
|
123
123
|
|
|
124
124
|
config._on_reload = on_reload
|
|
125
125
|
config.autoreload(True)
|
|
126
126
|
```
|
|
127
127
|
|
|
128
|
-
On est
|
|
128
|
+
On est également désactiver l'auto-reload avec:
|
|
129
129
|
```python
|
|
130
130
|
config.stop_autoreload()
|
|
131
131
|
```
|
|
132
132
|
|
|
133
|
-
###
|
|
133
|
+
### Accès aux valeurs
|
|
134
134
|
|
|
135
135
|
#### Par attributs
|
|
136
136
|
```python
|
|
@@ -144,13 +144,13 @@ db_host = config["db.host"]
|
|
|
144
144
|
```python
|
|
145
145
|
db_host = config.get("db.host", default="127.0.0.1")
|
|
146
146
|
```
|
|
147
|
-
####
|
|
147
|
+
#### Itération
|
|
148
148
|
```python
|
|
149
149
|
for key, sub in config.db.items():
|
|
150
150
|
print(key, sub.to_dict())
|
|
151
151
|
```
|
|
152
152
|
|
|
153
|
-
####
|
|
153
|
+
#### Vérifier l’existence d’un chemin
|
|
154
154
|
```python
|
|
155
155
|
"db.host" in config # True / False
|
|
156
156
|
```
|
|
@@ -164,7 +164,7 @@ config.set("feature.enable", True)
|
|
|
164
164
|
config.delete("db.password")
|
|
165
165
|
```
|
|
166
166
|
|
|
167
|
-
Toutes les modifications sont
|
|
167
|
+
Toutes les modifications sont gardées en mémoire tant qu’on ne sauvegarde pas.
|
|
168
168
|
|
|
169
169
|
### Suppression des valeurs
|
|
170
170
|
|
|
@@ -178,13 +178,13 @@ del config.db.password
|
|
|
178
178
|
|
|
179
179
|
#### Sauvegarde manuelle
|
|
180
180
|
|
|
181
|
-
Pour sauvegarder la configuration, on utilise la
|
|
181
|
+
Pour sauvegarder la configuration, on utilise la méthode **save**
|
|
182
182
|
|
|
183
183
|
```python
|
|
184
184
|
config.save()
|
|
185
185
|
```
|
|
186
186
|
|
|
187
|
-
L'argument **filepath** permettra de
|
|
187
|
+
L'argument **filepath** permettra de définir le fichier de sortie.
|
|
188
188
|
|
|
189
189
|
|
|
190
190
|
#### Sauvegarde automatique
|
|
@@ -204,39 +204,39 @@ config.merge({"db": {"port": 3307}}, overload=True)
|
|
|
204
204
|
```
|
|
205
205
|
|
|
206
206
|
|
|
207
|
-
Met
|
|
207
|
+
Met à jour **une partie** :
|
|
208
208
|
```python
|
|
209
209
|
config.update("db", {"user": "root"})
|
|
210
210
|
```
|
|
211
211
|
|
|
212
|
-
- `overload=False`
|
|
213
|
-
- `overload=True`
|
|
212
|
+
- `overload=False` → ne remplace pas les valeurs existantes
|
|
213
|
+
- `overload=True` → écrase celles existantes
|
|
214
214
|
|
|
215
|
-
### Vault et
|
|
215
|
+
### Vault et données chiffrées
|
|
216
216
|
|
|
217
|
-
Le render Jinja fournis 2
|
|
217
|
+
Le render Jinja fournis 2 méthodes pour récupérer des données chiffrées depuis un fichier vault ou un string vault_encryption
|
|
218
218
|
|
|
219
|
-
La
|
|
219
|
+
La méthode **vault** permet de récupérer des clés depuis un vault
|
|
220
220
|
|
|
221
221
|
```python
|
|
222
222
|
password: "{{ vault('db_password') }}"
|
|
223
223
|
```
|
|
224
224
|
|
|
225
|
-
Lors de l'initialisation de la config, il faudra
|
|
225
|
+
Lors de l'initialisation de la config, il faudra forcément **vault_file** et **vault_password** ou **vault_keyfile**
|
|
226
226
|
|
|
227
|
-
La
|
|
227
|
+
La méthode **vault_encryption** permet de déchiffrer des clés vault_encryption
|
|
228
228
|
|
|
229
229
|
```python
|
|
230
230
|
api_key: "{{ vault_encryption('encrypted_api_key') }}"
|
|
231
231
|
```
|
|
232
232
|
|
|
233
|
-
Lors de l'initialisation de la config, il faudra
|
|
233
|
+
Lors de l'initialisation de la config, il faudra forcément **vault_encryption_keyfile** ou **vault_encryption_password**
|
|
234
234
|
|
|
235
|
-
###
|
|
235
|
+
### Méthode complémentaire Jinja
|
|
236
236
|
|
|
237
|
-
####
|
|
237
|
+
#### Méthode env
|
|
238
238
|
|
|
239
|
-
La
|
|
239
|
+
La méthode **env** permet de récupérer des variables d'environnements
|
|
240
240
|
|
|
241
241
|
```python
|
|
242
242
|
debug: "{{ env('DEBUG', False) }}"
|
|
@@ -245,7 +245,7 @@ url: "https://{{ env('DOMAIN') }}/api"
|
|
|
245
245
|
|
|
246
246
|
## Enregistrement Jinja (filtres / tests / globals)
|
|
247
247
|
|
|
248
|
-
Tu peux enrichir l'environnement Jinja
|
|
248
|
+
Tu peux enrichir l'environnement Jinja utilisé pour rendre le fichier de config.
|
|
249
249
|
#### register_filter(name: str, func)
|
|
250
250
|
|
|
251
251
|
Enregistre un **filtre** Jinja utilisable dans le template.
|
|
@@ -306,10 +306,10 @@ generated_at: "{{ now() }}"
|
|
|
306
306
|
|
|
307
307
|
### Validation de la configuration
|
|
308
308
|
|
|
309
|
-
#### Validation via
|
|
309
|
+
#### Validation via schéma hiérarchique
|
|
310
310
|
|
|
311
|
-
Il est possible de
|
|
312
|
-
Le
|
|
311
|
+
Il est possible de vérifier une configuration à partir d'un schéma.
|
|
312
|
+
Le schéma va décrire l'architecture et les prérequis des clés définis.
|
|
313
313
|
|
|
314
314
|
```python
|
|
315
315
|
schema = {
|
|
@@ -322,10 +322,10 @@ schema = {
|
|
|
322
322
|
errors = config.validate(schema=schema)
|
|
323
323
|
```
|
|
324
324
|
|
|
325
|
-
#### Validation via des
|
|
325
|
+
#### Validation via des règles
|
|
326
326
|
|
|
327
|
-
Il est possible de
|
|
328
|
-
Le
|
|
327
|
+
Il est possible de vérifier une configuration à partir d'un schéma.
|
|
328
|
+
Le schéma va décrire l'architecture et les prérequis des clés définis.
|
|
329
329
|
|
|
330
330
|
```python
|
|
331
331
|
rules = {
|
|
@@ -335,16 +335,16 @@ rules = {
|
|
|
335
335
|
errors = config.validate(rules=rules, strict=False)
|
|
336
336
|
```
|
|
337
337
|
|
|
338
|
-
####
|
|
338
|
+
#### Définition possible
|
|
339
339
|
|
|
340
|
-
|
|
|
340
|
+
|Règle|Pour|Description|
|
|
341
341
|
|---|---|---|
|
|
342
|
-
|`_required`|Tout|
|
|
342
|
+
|`_required`|Tout|Clé obligatoire|
|
|
343
343
|
|`_type`|Tout|Type Python attendu|
|
|
344
|
-
|`_min`, `_max`|
|
|
345
|
-
|`_len`, `_min_len`, `_max_len`|
|
|
346
|
-
|`_regex`|
|
|
347
|
-
|`_enum`|Tout|Liste de valeurs
|
|
344
|
+
|`_min`, `_max`|Numérique|Limites|
|
|
345
|
+
|`_len`, `_min_len`, `_max_len`|Chaînes|Taille|
|
|
346
|
+
|`_regex`|Chaînes|Validation Regex|
|
|
347
|
+
|`_enum`|Tout|Liste de valeurs autorisées|
|
|
348
348
|
|`_not`|Tout|Valeur interdite|
|
|
349
349
|
|
|
350
350
|
### Export
|
|
@@ -357,37 +357,37 @@ config.export("output.toml", type="toml")
|
|
|
357
357
|
|
|
358
358
|
### Conversion
|
|
359
359
|
|
|
360
|
-
Ces
|
|
360
|
+
Ces méthodes permettent d'obtenir des formats de sortie facilement utilisables.
|
|
361
361
|
|
|
362
362
|
### to_dict()
|
|
363
363
|
|
|
364
|
-
Retourne le contenu du
|
|
364
|
+
Retourne le contenu du nœud courant (ou racine) sous forme de `dict` Python standard.
|
|
365
365
|
|
|
366
366
|
Exemple :
|
|
367
367
|
```python
|
|
368
368
|
data = config.to_dict()
|
|
369
|
-
# data est un dict
|
|
369
|
+
# data est un dict prêt à être sérialisé
|
|
370
370
|
```
|
|
371
371
|
|
|
372
372
|
### to_json(indent: int = 4)
|
|
373
373
|
|
|
374
|
-
Retourne une
|
|
374
|
+
Retourne une chaîne JSON formatée du nœud courant :
|
|
375
375
|
```python
|
|
376
376
|
json_str = config.to_json()
|
|
377
377
|
```
|
|
378
378
|
|
|
379
379
|
### to_yaml(sort_keys: bool = True)
|
|
380
380
|
|
|
381
|
-
Retourne YAML
|
|
381
|
+
Retourne YAML sérialisé :
|
|
382
382
|
```python
|
|
383
383
|
yaml_str = config.to_yaml()
|
|
384
384
|
```
|
|
385
385
|
|
|
386
386
|
### to_toml()
|
|
387
387
|
|
|
388
|
-
Retourne TOML
|
|
388
|
+
Retourne TOML sérialisé (si toml est disponible) :
|
|
389
389
|
```python
|
|
390
390
|
toml_str = config.to_toml()
|
|
391
391
|
```
|
|
392
392
|
|
|
393
|
-
Ces
|
|
393
|
+
Ces méthodes n’écrivent pas sur le disque — elles renvoient des chaînes. Pour écrire un fichier, utilise `export(filepath, type=...)` ou `save()`.
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import toml
|
|
2
|
-
from .global_backend import ConfigBackend
|
|
3
|
-
|
|
4
|
-
class TomlBackend(ConfigBackend):
|
|
5
|
-
"""NOUVEAU: Backend pour les fichiers TOML."""
|
|
6
|
-
def load(self, filename):
|
|
7
|
-
return toml.loads(filename.read_text())
|
|
8
|
-
|
|
9
|
-
def load_data(self, rendered):
|
|
10
|
-
return toml.loads(rendered) if rendered.strip() else {}
|
|
11
|
-
|
|
12
|
-
def save(self, filename, data):
|
|
13
|
-
filename.write_text(toml.dumps(data))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|