dynamic-config-loader 2.5.0__tar.gz → 2.7.0__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.
- {dynamic_config_loader-2.5.0/src/dynamic_config_loader.egg-info → dynamic_config_loader-2.7.0}/PKG-INFO +110 -53
- dynamic_config_loader-2.7.0/README.md +153 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/pyproject.toml +1 -1
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/environment.py +11 -4
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/strategies/env/parser.py +3 -18
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0/src/dynamic_config_loader.egg-info}/PKG-INFO +110 -53
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/tests/test_env_injection.py +32 -5
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/tests/test_env_strategy.py +28 -8
- dynamic_config_loader-2.5.0/README.md +0 -96
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/AUTHORS +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/LICENSE +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/NOTICE +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/setup.cfg +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/__init__.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/loader.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/strategies/__init__.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/strategies/base_strategy.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/strategies/env/__init__.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/strategies/env/merger.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/strategies/ini/__init__.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/strategies/ini/merger.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/strategies/ini/parser.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/strategies/json/__init__.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/strategies/json/merger.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/strategies/json/parser.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/strategies/properties/__init__.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/strategies/properties/merger.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/strategies/properties/parser.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/strategies/toml/__init__.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/strategies/toml/merger.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/strategies/toml/parser.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/strategies/xml/__init__.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/strategies/xml/merger.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/strategies/xml/parser.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/strategies/yaml/__init__.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/strategies/yaml/merger.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/strategies/yaml/parser.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader.egg-info/SOURCES.txt +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader.egg-info/dependency_links.txt +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader.egg-info/requires.txt +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader.egg-info/top_level.txt +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/tests/test_deep_merge.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/tests/test_factory.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/tests/test_ini_strategy.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/tests/test_json_strategy.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/tests/test_loader.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/tests/test_logging_safety.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/tests/test_properties_strategy.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/tests/test_toml_strategy.py +0 -0
- {dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/tests/test_xml_strategy.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dynamic-config-loader
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.7.0
|
|
4
4
|
Summary: An enterprise-grade configuration orchestration engine designed to ingest, cascade, and deeply merge multiple configuration file layers.
|
|
5
5
|
Author-email: Avinash Kumar <halfhiddencode@gmail.com>
|
|
6
6
|
License:
|
|
@@ -237,51 +237,79 @@ Dynamic: license-file
|
|
|
237
237
|
|
|
238
238
|
# Dynamic Configuration Loader
|
|
239
239
|
|
|
240
|
-
A lightweight, production-grade, strategy-driven configuration orchestration engine designed to dynamically discover,
|
|
240
|
+
A lightweight, production-grade, strategy-driven configuration orchestration engine designed to dynamically discover, cascade, and deep-merge multi-layered configuration files.
|
|
241
241
|
|
|
242
|
-
|
|
242
|
+
---
|
|
243
243
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
*
|
|
250
|
-
* **
|
|
251
|
-
* **
|
|
244
|
+
> [!TIP]
|
|
245
|
+
> ### 👋 NEW TO DYNAMIC CONFIG LOADER? START HERE!
|
|
246
|
+
>
|
|
247
|
+
> Choose your role to find the fastest path to get up and running:
|
|
248
|
+
>
|
|
249
|
+
> * **🆕 Application Developer (First Time User):** Start with the **[3-Line Quick Start Tutorial](docs/tutorials/getting_started.md)**.
|
|
250
|
+
> * **🚀 DevOps / SRE Engineer:** Check the **[Configuration Lifecycle Matrix](docs/guides/user_usage.md#1-minimal-to-advanced-configuration-lifecycle-guide)** & **[K8s Deployment Scenarios](docs/guides/user_usage.md#7-production-deployment-scenarios)**.
|
|
251
|
+
> * **🛠️ Open-Source Contributor:** See the **[Track A vs Track B Contributor Guide](docs/guides/contributor_guide.md#1-contributing-features-vs-format-strategies)**.
|
|
252
|
+
> * **📦 Maintainer / DevOps Release:** Read the **[Release & OIDC Deployment Guide](docs/guides/release_guide.md)**.
|
|
252
253
|
|
|
253
254
|
---
|
|
254
255
|
|
|
255
|
-
|
|
256
|
-
Copyright (C) 2026 Avinash Kumar <halfhiddencode AT gmail DOT com>
|
|
256
|
+
## 📌 Quick Navigation Index
|
|
257
257
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
258
|
+
- [⚡ Minimal Quick Start](#-quick-start-minimal-3-lines)
|
|
259
|
+
- [📦 Installation](#-installation)
|
|
260
|
+
- [⚙️ Supported Configuration Formats](#%EF%B8%8F-supported-configuration-formats)
|
|
261
|
+
- [🔀 Multi-Layer Overrides & Environment Injection](#-multi-layer-overrides--environment-injection)
|
|
262
|
+
- [📖 Documentation Index](#-documentation-index)
|
|
263
|
+
- [🎨 System Architecture Visualizer](#-system-architecture)
|
|
261
264
|
|
|
262
|
-
|
|
265
|
+
---
|
|
263
266
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
267
|
+
### 🚀 Configuration Lifecycle Matrix: Minimal to Advanced
|
|
268
|
+
|
|
269
|
+
| Lifecycle Phase | Component Requirement | How It Works in Code / Environment | Primary Purpose |
|
|
270
|
+
| :--- | :--- | :--- | :--- |
|
|
271
|
+
| **1. Local Dev (Coding Time)** | `[OPTIONAL FALLBACK]` | `loader = DynamicConfigLoader("config.yaml")` | Local fallback file for offline developer workstations. |
|
|
272
|
+
| **2. Image Build (CI/CD Build Time)** | `[REQUIRED IN CODE]` | `loader = DynamicConfigLoader()` | **Image Immutability!** Zero hardcoded secrets in Docker image. |
|
|
273
|
+
| **3. Deployment (K8s Runtime Time)** | `[OPTIONAL AT DEPLOYMENT]` | `export PYTHON_ADDITIONAL_CONFIG="/etc/config/prod.yaml"` | Mounts K8s ConfigMaps & Vault secrets into container at runtime. |
|
|
274
|
+
| **4. Live Ops Overrides (Runtime)** | `[OPTIONAL AT RUNTIME]` | `export DCL_ENV_LOADER=true` <br> `export DCL_PORT=8080` | Overrides specific keys in memory dynamically without rebuilding image. |
|
|
270
275
|
|
|
271
276
|
---
|
|
272
277
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
278
|
+
### Minimal Execution Code Snippets
|
|
279
|
+
|
|
280
|
+
#### Mode 1: Container / Kubernetes Mode (`[RECOMMENDED FOR PROD]`)
|
|
281
|
+
|
|
282
|
+
> [!NOTE]
|
|
283
|
+
> **[OPTIONAL FILE PATH - CAN SKIP!]**
|
|
284
|
+
> If you don't have a local config file, **YOU CAN SKIP IT!** In production container deployments, you do NOT need any hardcoded file paths in your code. The engine will handle configuration loading automatically at deployment time via environment variables (`PYTHON_ADDITIONAL_CONFIG` or `DCL_`).
|
|
285
|
+
|
|
286
|
+
```python
|
|
287
|
+
from dynamic_config_loader import DynamicConfigLoader
|
|
288
|
+
|
|
289
|
+
# Zero hardcoded file paths! Fully handled at deployment time
|
|
290
|
+
loader = DynamicConfigLoader()
|
|
291
|
+
config = loader.load()
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
#### Mode 2: Local Development Mode (`[OPTIONAL FALLBACK]`)
|
|
295
|
+
|
|
296
|
+
> [!NOTE]
|
|
297
|
+
> **[LOCAL FALLBACK ONLY]**
|
|
298
|
+
> Useful for local developer laptops so you can run `python app.py` offline without configuring environment variables.
|
|
299
|
+
|
|
300
|
+
```python
|
|
301
|
+
from dynamic_config_loader import DynamicConfigLoader
|
|
302
|
+
|
|
303
|
+
# Optional local fallback file
|
|
304
|
+
loader = DynamicConfigLoader("config.yaml")
|
|
305
|
+
config = loader.load()
|
|
306
|
+
```
|
|
279
307
|
|
|
280
308
|
---
|
|
281
309
|
|
|
282
|
-
## Installation
|
|
310
|
+
## 📦 Installation
|
|
283
311
|
|
|
284
|
-
Install
|
|
312
|
+
Install from PyPI via `pip`:
|
|
285
313
|
|
|
286
314
|
```bash
|
|
287
315
|
pip install dynamic-config-loader
|
|
@@ -295,39 +323,68 @@ pip install -e .
|
|
|
295
323
|
|
|
296
324
|
---
|
|
297
325
|
|
|
298
|
-
##
|
|
326
|
+
## ⚙️ Supported Configuration Formats
|
|
299
327
|
|
|
300
|
-
|
|
301
|
-
import os
|
|
302
|
-
from dynamic_config_loader import DynamicConfigLoader
|
|
328
|
+
The orchestration engine natively ingests, parses, and cascades **7 configuration formats**:
|
|
303
329
|
|
|
304
|
-
|
|
305
|
-
|
|
330
|
+
| Format | Extensions | Key Behavior & Conversion | Guide Link |
|
|
331
|
+
| :--- | :--- | :--- | :--- |
|
|
332
|
+
| **YAML** | `.yaml`, `.yml` | Native YAML indentation & deep dictionary parsing | [View Details](docs/guides/user_usage.md#71-yaml-strategy-yamlstrategy) |
|
|
333
|
+
| **JSON** | `.json` | Strict JSON objects & typed arrays | [View Details](docs/guides/user_usage.md#72-json-strategy-jsonstrategy) |
|
|
334
|
+
| **Dotenv** | `.env` | **100% Flat Keys** (`SERVICE_GATEWAY_NAME` $\rightarrow$ `config["service_gateway_name"]`) | [View Details](docs/guides/user_usage.md#87-dotenv-strategy-envstrategy) |
|
|
335
|
+
| **TOML** | `.toml` | Section headers (`[table]`), inline tables, & datetimes | [View Details](docs/guides/user_usage.md#74-toml-strategy-tomlstrategy) |
|
|
336
|
+
| **INI / Conf** | `.ini`, `.conf` | Section headers (`[section]`) & automatic primitive type casting | [View Details](docs/guides/user_usage.md#75-ini--conf-strategy-inistrategy) |
|
|
337
|
+
| **Java Properties**| `.properties` | Dot notation (`app.database.port=5432` $\rightarrow$ `app.database.port`) | [View Details](docs/guides/user_usage.md#76-java-properties-strategy-propertiesstrategy) |
|
|
338
|
+
| **XML** | `.xml` | Tag element hierarchies auto-converted into Python dicts | [View Details](docs/guides/user_usage.md#73-xml-strategy-xmlstrategy) |
|
|
306
339
|
|
|
307
|
-
|
|
308
|
-
loader = DynamicConfigLoader(default_config_path="/app/configs/base_defaults.yaml")
|
|
340
|
+
---
|
|
309
341
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
342
|
+
## 🔀 Multi-Layer Overrides & Environment Injection
|
|
343
|
+
|
|
344
|
+
<details>
|
|
345
|
+
<summary><b>Click to expand Advanced Environment Overrides & Logging Options</b></summary>
|
|
346
|
+
|
|
347
|
+
### 1. External File/Directory Overrides (`PYTHON_ADDITIONAL_CONFIG`)
|
|
348
|
+
Specify an external file or directory of override files via system environment variables:
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
export PYTHON_ADDITIONAL_CONFIG="/etc/app/production_overrides.yaml"
|
|
313
352
|
```
|
|
314
353
|
|
|
354
|
+
### 2. Environment Variable Injection (`DCL_ENV_LOADER=true`)
|
|
355
|
+
Inject or override specific keys dynamically at runtime using environment variables:
|
|
356
|
+
|
|
357
|
+
```bash
|
|
358
|
+
export DCL_ENV_LOADER=true
|
|
359
|
+
export DCL_PORT=9000
|
|
360
|
+
export DCL_LOG_LEVEL=info
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### 3. Log Redaction Controls (`ENABLE_UNSAFE_LOGGING`)
|
|
364
|
+
* **Default (Safe Mode):** Sensitive passwords and tokens are redacted (`[REDACTED]`) in logs.
|
|
365
|
+
* **Unsafe Mode (`ENABLE_UNSAFE_LOGGING=true`):** Exposes raw values during local debug sessions.
|
|
366
|
+
|
|
367
|
+
</details>
|
|
368
|
+
|
|
315
369
|
---
|
|
316
370
|
|
|
317
|
-
##
|
|
371
|
+
## 🎨 System Architecture
|
|
372
|
+
|
|
373
|
+

|
|
374
|
+
|
|
375
|
+
---
|
|
318
376
|
|
|
319
|
-
|
|
377
|
+
## 📖 Documentation Index
|
|
320
378
|
|
|
321
|
-
| Track |
|
|
379
|
+
| Guide Track | Link | Description |
|
|
322
380
|
| :--- | :--- | :--- |
|
|
323
|
-
|
|
|
324
|
-
|
|
|
325
|
-
|
|
|
326
|
-
|
|
|
381
|
+
| **🚀 Getting Started Tutorial** | [getting_started.md](docs/tutorials/getting_started.md) | Step-by-step onboarding & minimal execution tracks. |
|
|
382
|
+
| **📖 Operations & Usage Guide** | [user_usage.md](docs/guides/user_usage.md) | Complete format matrix, K8s/DevOps deployment scenarios, & path edge cases. |
|
|
383
|
+
| **🛠️ Contributor Guide** | [contributor_guide.md](docs/guides/contributor_guide.md) | Adding custom format strategies & factory registry hooks. |
|
|
384
|
+
| **🚀 Release & OIDC Guide** | [release_guide.md](docs/guides/release_guide.md) | OIDC Trusted Publishing, version bump rules, & PyPI deployment protocols. |
|
|
385
|
+
| **🏗️ Architecture Reference** | [architecture.md](docs/reference/architecture.md) | System design, UML diagrams, & deep merge algorithms. |
|
|
327
386
|
|
|
328
387
|
---
|
|
329
388
|
|
|
330
|
-
##
|
|
331
|
-
|
|
332
|
-
* Security Policy: [SECURITY.md](https://gitlab.com/halfhiddencode/python-dynamic-config-loader/-/blob/main/SECURITY.md)
|
|
333
|
-
* Contribution Protocols: [CONTRIBUTING.md](https://gitlab.com/halfhiddencode/python-dynamic-config-loader/-/blob/main/CONTRIBUTING.md)
|
|
389
|
+
## 📜 License
|
|
390
|
+
Licensed under the [Apache License, Version 2.0](LICENSE).
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Dynamic Configuration Loader
|
|
2
|
+
|
|
3
|
+
A lightweight, production-grade, strategy-driven configuration orchestration engine designed to dynamically discover, cascade, and deep-merge multi-layered configuration files.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
> [!TIP]
|
|
8
|
+
> ### 👋 NEW TO DYNAMIC CONFIG LOADER? START HERE!
|
|
9
|
+
>
|
|
10
|
+
> Choose your role to find the fastest path to get up and running:
|
|
11
|
+
>
|
|
12
|
+
> * **🆕 Application Developer (First Time User):** Start with the **[3-Line Quick Start Tutorial](docs/tutorials/getting_started.md)**.
|
|
13
|
+
> * **🚀 DevOps / SRE Engineer:** Check the **[Configuration Lifecycle Matrix](docs/guides/user_usage.md#1-minimal-to-advanced-configuration-lifecycle-guide)** & **[K8s Deployment Scenarios](docs/guides/user_usage.md#7-production-deployment-scenarios)**.
|
|
14
|
+
> * **🛠️ Open-Source Contributor:** See the **[Track A vs Track B Contributor Guide](docs/guides/contributor_guide.md#1-contributing-features-vs-format-strategies)**.
|
|
15
|
+
> * **📦 Maintainer / DevOps Release:** Read the **[Release & OIDC Deployment Guide](docs/guides/release_guide.md)**.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 📌 Quick Navigation Index
|
|
20
|
+
|
|
21
|
+
- [⚡ Minimal Quick Start](#-quick-start-minimal-3-lines)
|
|
22
|
+
- [📦 Installation](#-installation)
|
|
23
|
+
- [⚙️ Supported Configuration Formats](#%EF%B8%8F-supported-configuration-formats)
|
|
24
|
+
- [🔀 Multi-Layer Overrides & Environment Injection](#-multi-layer-overrides--environment-injection)
|
|
25
|
+
- [📖 Documentation Index](#-documentation-index)
|
|
26
|
+
- [🎨 System Architecture Visualizer](#-system-architecture)
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
### 🚀 Configuration Lifecycle Matrix: Minimal to Advanced
|
|
31
|
+
|
|
32
|
+
| Lifecycle Phase | Component Requirement | How It Works in Code / Environment | Primary Purpose |
|
|
33
|
+
| :--- | :--- | :--- | :--- |
|
|
34
|
+
| **1. Local Dev (Coding Time)** | `[OPTIONAL FALLBACK]` | `loader = DynamicConfigLoader("config.yaml")` | Local fallback file for offline developer workstations. |
|
|
35
|
+
| **2. Image Build (CI/CD Build Time)** | `[REQUIRED IN CODE]` | `loader = DynamicConfigLoader()` | **Image Immutability!** Zero hardcoded secrets in Docker image. |
|
|
36
|
+
| **3. Deployment (K8s Runtime Time)** | `[OPTIONAL AT DEPLOYMENT]` | `export PYTHON_ADDITIONAL_CONFIG="/etc/config/prod.yaml"` | Mounts K8s ConfigMaps & Vault secrets into container at runtime. |
|
|
37
|
+
| **4. Live Ops Overrides (Runtime)** | `[OPTIONAL AT RUNTIME]` | `export DCL_ENV_LOADER=true` <br> `export DCL_PORT=8080` | Overrides specific keys in memory dynamically without rebuilding image. |
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
### Minimal Execution Code Snippets
|
|
42
|
+
|
|
43
|
+
#### Mode 1: Container / Kubernetes Mode (`[RECOMMENDED FOR PROD]`)
|
|
44
|
+
|
|
45
|
+
> [!NOTE]
|
|
46
|
+
> **[OPTIONAL FILE PATH - CAN SKIP!]**
|
|
47
|
+
> If you don't have a local config file, **YOU CAN SKIP IT!** In production container deployments, you do NOT need any hardcoded file paths in your code. The engine will handle configuration loading automatically at deployment time via environment variables (`PYTHON_ADDITIONAL_CONFIG` or `DCL_`).
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from dynamic_config_loader import DynamicConfigLoader
|
|
51
|
+
|
|
52
|
+
# Zero hardcoded file paths! Fully handled at deployment time
|
|
53
|
+
loader = DynamicConfigLoader()
|
|
54
|
+
config = loader.load()
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
#### Mode 2: Local Development Mode (`[OPTIONAL FALLBACK]`)
|
|
58
|
+
|
|
59
|
+
> [!NOTE]
|
|
60
|
+
> **[LOCAL FALLBACK ONLY]**
|
|
61
|
+
> Useful for local developer laptops so you can run `python app.py` offline without configuring environment variables.
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from dynamic_config_loader import DynamicConfigLoader
|
|
65
|
+
|
|
66
|
+
# Optional local fallback file
|
|
67
|
+
loader = DynamicConfigLoader("config.yaml")
|
|
68
|
+
config = loader.load()
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 📦 Installation
|
|
74
|
+
|
|
75
|
+
Install from PyPI via `pip`:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
pip install dynamic-config-loader
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Or install in editable mode for local development:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
pip install -e .
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## ⚙️ Supported Configuration Formats
|
|
90
|
+
|
|
91
|
+
The orchestration engine natively ingests, parses, and cascades **7 configuration formats**:
|
|
92
|
+
|
|
93
|
+
| Format | Extensions | Key Behavior & Conversion | Guide Link |
|
|
94
|
+
| :--- | :--- | :--- | :--- |
|
|
95
|
+
| **YAML** | `.yaml`, `.yml` | Native YAML indentation & deep dictionary parsing | [View Details](docs/guides/user_usage.md#71-yaml-strategy-yamlstrategy) |
|
|
96
|
+
| **JSON** | `.json` | Strict JSON objects & typed arrays | [View Details](docs/guides/user_usage.md#72-json-strategy-jsonstrategy) |
|
|
97
|
+
| **Dotenv** | `.env` | **100% Flat Keys** (`SERVICE_GATEWAY_NAME` $\rightarrow$ `config["service_gateway_name"]`) | [View Details](docs/guides/user_usage.md#87-dotenv-strategy-envstrategy) |
|
|
98
|
+
| **TOML** | `.toml` | Section headers (`[table]`), inline tables, & datetimes | [View Details](docs/guides/user_usage.md#74-toml-strategy-tomlstrategy) |
|
|
99
|
+
| **INI / Conf** | `.ini`, `.conf` | Section headers (`[section]`) & automatic primitive type casting | [View Details](docs/guides/user_usage.md#75-ini--conf-strategy-inistrategy) |
|
|
100
|
+
| **Java Properties**| `.properties` | Dot notation (`app.database.port=5432` $\rightarrow$ `app.database.port`) | [View Details](docs/guides/user_usage.md#76-java-properties-strategy-propertiesstrategy) |
|
|
101
|
+
| **XML** | `.xml` | Tag element hierarchies auto-converted into Python dicts | [View Details](docs/guides/user_usage.md#73-xml-strategy-xmlstrategy) |
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 🔀 Multi-Layer Overrides & Environment Injection
|
|
106
|
+
|
|
107
|
+
<details>
|
|
108
|
+
<summary><b>Click to expand Advanced Environment Overrides & Logging Options</b></summary>
|
|
109
|
+
|
|
110
|
+
### 1. External File/Directory Overrides (`PYTHON_ADDITIONAL_CONFIG`)
|
|
111
|
+
Specify an external file or directory of override files via system environment variables:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
export PYTHON_ADDITIONAL_CONFIG="/etc/app/production_overrides.yaml"
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### 2. Environment Variable Injection (`DCL_ENV_LOADER=true`)
|
|
118
|
+
Inject or override specific keys dynamically at runtime using environment variables:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
export DCL_ENV_LOADER=true
|
|
122
|
+
export DCL_PORT=9000
|
|
123
|
+
export DCL_LOG_LEVEL=info
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### 3. Log Redaction Controls (`ENABLE_UNSAFE_LOGGING`)
|
|
127
|
+
* **Default (Safe Mode):** Sensitive passwords and tokens are redacted (`[REDACTED]`) in logs.
|
|
128
|
+
* **Unsafe Mode (`ENABLE_UNSAFE_LOGGING=true`):** Exposes raw values during local debug sessions.
|
|
129
|
+
|
|
130
|
+
</details>
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## 🎨 System Architecture
|
|
135
|
+
|
|
136
|
+

|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## 📖 Documentation Index
|
|
141
|
+
|
|
142
|
+
| Guide Track | Link | Description |
|
|
143
|
+
| :--- | :--- | :--- |
|
|
144
|
+
| **🚀 Getting Started Tutorial** | [getting_started.md](docs/tutorials/getting_started.md) | Step-by-step onboarding & minimal execution tracks. |
|
|
145
|
+
| **📖 Operations & Usage Guide** | [user_usage.md](docs/guides/user_usage.md) | Complete format matrix, K8s/DevOps deployment scenarios, & path edge cases. |
|
|
146
|
+
| **🛠️ Contributor Guide** | [contributor_guide.md](docs/guides/contributor_guide.md) | Adding custom format strategies & factory registry hooks. |
|
|
147
|
+
| **🚀 Release & OIDC Guide** | [release_guide.md](docs/guides/release_guide.md) | OIDC Trusted Publishing, version bump rules, & PyPI deployment protocols. |
|
|
148
|
+
| **🏗️ Architecture Reference** | [architecture.md](docs/reference/architecture.md) | System design, UML diagrams, & deep merge algorithms. |
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## 📜 License
|
|
153
|
+
Licensed under the [Apache License, Version 2.0](LICENSE).
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "dynamic-config-loader"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.7.0"
|
|
8
8
|
description = "An enterprise-grade configuration orchestration engine designed to ingest, cascade, and deeply merge multiple configuration file layers."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
{dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/environment.py
RENAMED
|
@@ -56,11 +56,18 @@ def inject_environment_variables(
|
|
|
56
56
|
if env_key.startswith(prefix):
|
|
57
57
|
# Strip prefix
|
|
58
58
|
sliced_key = env_key[len(prefix):]
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
parsed_val = _parse_env_value(env_val)
|
|
60
|
+
|
|
61
|
+
# Resolution order:
|
|
62
|
+
# 1. Explicit double-underscore '__': Splits into nested objects (e.g. DCL_AUTH__TENANT_ID -> config_data["auth"]["tenant_id"])
|
|
63
|
+
# 2. Default: Preserves as 100% FLAT key (e.g. DCL_SERVICE_GATEWAY_NAME -> config_data["service_gateway_name"])
|
|
64
|
+
flat_key = sliced_key.strip().lower()
|
|
65
|
+
|
|
66
|
+
if "__" in sliced_key:
|
|
67
|
+
parts = [p.lower() for p in sliced_key.split("__") if p]
|
|
68
|
+
else:
|
|
69
|
+
parts = [flat_key]
|
|
61
70
|
|
|
62
|
-
# Case Normalization and tokenizing
|
|
63
|
-
parts = [p.lower() for p in sliced_key.split("_") if p]
|
|
64
71
|
if not parts:
|
|
65
72
|
continue
|
|
66
73
|
|
|
@@ -46,15 +46,11 @@ def parse_env_file(file_path: Path) -> Dict[str, Any]:
|
|
|
46
46
|
with open(file_path, "r", encoding="utf-8") as f:
|
|
47
47
|
for line in f:
|
|
48
48
|
line = line.strip()
|
|
49
|
-
|
|
50
|
-
if not line or line.startswith("#"):
|
|
51
|
-
continue
|
|
52
|
-
|
|
53
|
-
if "=" not in line:
|
|
49
|
+
if not line or line.startswith("#") or line.startswith("!") or "=" not in line:
|
|
54
50
|
continue
|
|
55
51
|
|
|
56
52
|
key, val = line.split("=", 1)
|
|
57
|
-
key = key.strip()
|
|
53
|
+
key = key.strip().lower()
|
|
58
54
|
val = val.strip()
|
|
59
55
|
|
|
60
56
|
if not key:
|
|
@@ -67,18 +63,7 @@ def parse_env_file(file_path: Path) -> Dict[str, Any]:
|
|
|
67
63
|
val = val[1:-1]
|
|
68
64
|
|
|
69
65
|
parsed_val = _parse_env_file_value(val)
|
|
70
|
-
|
|
71
|
-
# Tokenize key by single underscore delimiter to align with env injection track
|
|
72
|
-
parts = [p.lower() for p in key.split("_") if p]
|
|
73
|
-
if not parts:
|
|
74
|
-
continue
|
|
75
|
-
|
|
76
|
-
curr = data
|
|
77
|
-
for part in parts[:-1]:
|
|
78
|
-
if part not in curr or not isinstance(curr[part], dict):
|
|
79
|
-
curr[part] = {}
|
|
80
|
-
curr = curr[part]
|
|
81
|
-
curr[parts[-1]] = parsed_val
|
|
66
|
+
data[key] = parsed_val
|
|
82
67
|
|
|
83
68
|
except (IOError, PermissionError) as e:
|
|
84
69
|
logger.exception(f"Failed to read or parse dotenv file: {file_path.name}", exc_info=e)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dynamic-config-loader
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.7.0
|
|
4
4
|
Summary: An enterprise-grade configuration orchestration engine designed to ingest, cascade, and deeply merge multiple configuration file layers.
|
|
5
5
|
Author-email: Avinash Kumar <halfhiddencode@gmail.com>
|
|
6
6
|
License:
|
|
@@ -237,51 +237,79 @@ Dynamic: license-file
|
|
|
237
237
|
|
|
238
238
|
# Dynamic Configuration Loader
|
|
239
239
|
|
|
240
|
-
A lightweight, production-grade, strategy-driven configuration orchestration engine designed to dynamically discover,
|
|
240
|
+
A lightweight, production-grade, strategy-driven configuration orchestration engine designed to dynamically discover, cascade, and deep-merge multi-layered configuration files.
|
|
241
241
|
|
|
242
|
-
|
|
242
|
+
---
|
|
243
243
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
*
|
|
250
|
-
* **
|
|
251
|
-
* **
|
|
244
|
+
> [!TIP]
|
|
245
|
+
> ### 👋 NEW TO DYNAMIC CONFIG LOADER? START HERE!
|
|
246
|
+
>
|
|
247
|
+
> Choose your role to find the fastest path to get up and running:
|
|
248
|
+
>
|
|
249
|
+
> * **🆕 Application Developer (First Time User):** Start with the **[3-Line Quick Start Tutorial](docs/tutorials/getting_started.md)**.
|
|
250
|
+
> * **🚀 DevOps / SRE Engineer:** Check the **[Configuration Lifecycle Matrix](docs/guides/user_usage.md#1-minimal-to-advanced-configuration-lifecycle-guide)** & **[K8s Deployment Scenarios](docs/guides/user_usage.md#7-production-deployment-scenarios)**.
|
|
251
|
+
> * **🛠️ Open-Source Contributor:** See the **[Track A vs Track B Contributor Guide](docs/guides/contributor_guide.md#1-contributing-features-vs-format-strategies)**.
|
|
252
|
+
> * **📦 Maintainer / DevOps Release:** Read the **[Release & OIDC Deployment Guide](docs/guides/release_guide.md)**.
|
|
252
253
|
|
|
253
254
|
---
|
|
254
255
|
|
|
255
|
-
|
|
256
|
-
Copyright (C) 2026 Avinash Kumar <halfhiddencode AT gmail DOT com>
|
|
256
|
+
## 📌 Quick Navigation Index
|
|
257
257
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
258
|
+
- [⚡ Minimal Quick Start](#-quick-start-minimal-3-lines)
|
|
259
|
+
- [📦 Installation](#-installation)
|
|
260
|
+
- [⚙️ Supported Configuration Formats](#%EF%B8%8F-supported-configuration-formats)
|
|
261
|
+
- [🔀 Multi-Layer Overrides & Environment Injection](#-multi-layer-overrides--environment-injection)
|
|
262
|
+
- [📖 Documentation Index](#-documentation-index)
|
|
263
|
+
- [🎨 System Architecture Visualizer](#-system-architecture)
|
|
261
264
|
|
|
262
|
-
|
|
265
|
+
---
|
|
263
266
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
267
|
+
### 🚀 Configuration Lifecycle Matrix: Minimal to Advanced
|
|
268
|
+
|
|
269
|
+
| Lifecycle Phase | Component Requirement | How It Works in Code / Environment | Primary Purpose |
|
|
270
|
+
| :--- | :--- | :--- | :--- |
|
|
271
|
+
| **1. Local Dev (Coding Time)** | `[OPTIONAL FALLBACK]` | `loader = DynamicConfigLoader("config.yaml")` | Local fallback file for offline developer workstations. |
|
|
272
|
+
| **2. Image Build (CI/CD Build Time)** | `[REQUIRED IN CODE]` | `loader = DynamicConfigLoader()` | **Image Immutability!** Zero hardcoded secrets in Docker image. |
|
|
273
|
+
| **3. Deployment (K8s Runtime Time)** | `[OPTIONAL AT DEPLOYMENT]` | `export PYTHON_ADDITIONAL_CONFIG="/etc/config/prod.yaml"` | Mounts K8s ConfigMaps & Vault secrets into container at runtime. |
|
|
274
|
+
| **4. Live Ops Overrides (Runtime)** | `[OPTIONAL AT RUNTIME]` | `export DCL_ENV_LOADER=true` <br> `export DCL_PORT=8080` | Overrides specific keys in memory dynamically without rebuilding image. |
|
|
270
275
|
|
|
271
276
|
---
|
|
272
277
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
278
|
+
### Minimal Execution Code Snippets
|
|
279
|
+
|
|
280
|
+
#### Mode 1: Container / Kubernetes Mode (`[RECOMMENDED FOR PROD]`)
|
|
281
|
+
|
|
282
|
+
> [!NOTE]
|
|
283
|
+
> **[OPTIONAL FILE PATH - CAN SKIP!]**
|
|
284
|
+
> If you don't have a local config file, **YOU CAN SKIP IT!** In production container deployments, you do NOT need any hardcoded file paths in your code. The engine will handle configuration loading automatically at deployment time via environment variables (`PYTHON_ADDITIONAL_CONFIG` or `DCL_`).
|
|
285
|
+
|
|
286
|
+
```python
|
|
287
|
+
from dynamic_config_loader import DynamicConfigLoader
|
|
288
|
+
|
|
289
|
+
# Zero hardcoded file paths! Fully handled at deployment time
|
|
290
|
+
loader = DynamicConfigLoader()
|
|
291
|
+
config = loader.load()
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
#### Mode 2: Local Development Mode (`[OPTIONAL FALLBACK]`)
|
|
295
|
+
|
|
296
|
+
> [!NOTE]
|
|
297
|
+
> **[LOCAL FALLBACK ONLY]**
|
|
298
|
+
> Useful for local developer laptops so you can run `python app.py` offline without configuring environment variables.
|
|
299
|
+
|
|
300
|
+
```python
|
|
301
|
+
from dynamic_config_loader import DynamicConfigLoader
|
|
302
|
+
|
|
303
|
+
# Optional local fallback file
|
|
304
|
+
loader = DynamicConfigLoader("config.yaml")
|
|
305
|
+
config = loader.load()
|
|
306
|
+
```
|
|
279
307
|
|
|
280
308
|
---
|
|
281
309
|
|
|
282
|
-
## Installation
|
|
310
|
+
## 📦 Installation
|
|
283
311
|
|
|
284
|
-
Install
|
|
312
|
+
Install from PyPI via `pip`:
|
|
285
313
|
|
|
286
314
|
```bash
|
|
287
315
|
pip install dynamic-config-loader
|
|
@@ -295,39 +323,68 @@ pip install -e .
|
|
|
295
323
|
|
|
296
324
|
---
|
|
297
325
|
|
|
298
|
-
##
|
|
326
|
+
## ⚙️ Supported Configuration Formats
|
|
299
327
|
|
|
300
|
-
|
|
301
|
-
import os
|
|
302
|
-
from dynamic_config_loader import DynamicConfigLoader
|
|
328
|
+
The orchestration engine natively ingests, parses, and cascades **7 configuration formats**:
|
|
303
329
|
|
|
304
|
-
|
|
305
|
-
|
|
330
|
+
| Format | Extensions | Key Behavior & Conversion | Guide Link |
|
|
331
|
+
| :--- | :--- | :--- | :--- |
|
|
332
|
+
| **YAML** | `.yaml`, `.yml` | Native YAML indentation & deep dictionary parsing | [View Details](docs/guides/user_usage.md#71-yaml-strategy-yamlstrategy) |
|
|
333
|
+
| **JSON** | `.json` | Strict JSON objects & typed arrays | [View Details](docs/guides/user_usage.md#72-json-strategy-jsonstrategy) |
|
|
334
|
+
| **Dotenv** | `.env` | **100% Flat Keys** (`SERVICE_GATEWAY_NAME` $\rightarrow$ `config["service_gateway_name"]`) | [View Details](docs/guides/user_usage.md#87-dotenv-strategy-envstrategy) |
|
|
335
|
+
| **TOML** | `.toml` | Section headers (`[table]`), inline tables, & datetimes | [View Details](docs/guides/user_usage.md#74-toml-strategy-tomlstrategy) |
|
|
336
|
+
| **INI / Conf** | `.ini`, `.conf` | Section headers (`[section]`) & automatic primitive type casting | [View Details](docs/guides/user_usage.md#75-ini--conf-strategy-inistrategy) |
|
|
337
|
+
| **Java Properties**| `.properties` | Dot notation (`app.database.port=5432` $\rightarrow$ `app.database.port`) | [View Details](docs/guides/user_usage.md#76-java-properties-strategy-propertiesstrategy) |
|
|
338
|
+
| **XML** | `.xml` | Tag element hierarchies auto-converted into Python dicts | [View Details](docs/guides/user_usage.md#73-xml-strategy-xmlstrategy) |
|
|
306
339
|
|
|
307
|
-
|
|
308
|
-
loader = DynamicConfigLoader(default_config_path="/app/configs/base_defaults.yaml")
|
|
340
|
+
---
|
|
309
341
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
342
|
+
## 🔀 Multi-Layer Overrides & Environment Injection
|
|
343
|
+
|
|
344
|
+
<details>
|
|
345
|
+
<summary><b>Click to expand Advanced Environment Overrides & Logging Options</b></summary>
|
|
346
|
+
|
|
347
|
+
### 1. External File/Directory Overrides (`PYTHON_ADDITIONAL_CONFIG`)
|
|
348
|
+
Specify an external file or directory of override files via system environment variables:
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
export PYTHON_ADDITIONAL_CONFIG="/etc/app/production_overrides.yaml"
|
|
313
352
|
```
|
|
314
353
|
|
|
354
|
+
### 2. Environment Variable Injection (`DCL_ENV_LOADER=true`)
|
|
355
|
+
Inject or override specific keys dynamically at runtime using environment variables:
|
|
356
|
+
|
|
357
|
+
```bash
|
|
358
|
+
export DCL_ENV_LOADER=true
|
|
359
|
+
export DCL_PORT=9000
|
|
360
|
+
export DCL_LOG_LEVEL=info
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### 3. Log Redaction Controls (`ENABLE_UNSAFE_LOGGING`)
|
|
364
|
+
* **Default (Safe Mode):** Sensitive passwords and tokens are redacted (`[REDACTED]`) in logs.
|
|
365
|
+
* **Unsafe Mode (`ENABLE_UNSAFE_LOGGING=true`):** Exposes raw values during local debug sessions.
|
|
366
|
+
|
|
367
|
+
</details>
|
|
368
|
+
|
|
315
369
|
---
|
|
316
370
|
|
|
317
|
-
##
|
|
371
|
+
## 🎨 System Architecture
|
|
372
|
+
|
|
373
|
+

|
|
374
|
+
|
|
375
|
+
---
|
|
318
376
|
|
|
319
|
-
|
|
377
|
+
## 📖 Documentation Index
|
|
320
378
|
|
|
321
|
-
| Track |
|
|
379
|
+
| Guide Track | Link | Description |
|
|
322
380
|
| :--- | :--- | :--- |
|
|
323
|
-
|
|
|
324
|
-
|
|
|
325
|
-
|
|
|
326
|
-
|
|
|
381
|
+
| **🚀 Getting Started Tutorial** | [getting_started.md](docs/tutorials/getting_started.md) | Step-by-step onboarding & minimal execution tracks. |
|
|
382
|
+
| **📖 Operations & Usage Guide** | [user_usage.md](docs/guides/user_usage.md) | Complete format matrix, K8s/DevOps deployment scenarios, & path edge cases. |
|
|
383
|
+
| **🛠️ Contributor Guide** | [contributor_guide.md](docs/guides/contributor_guide.md) | Adding custom format strategies & factory registry hooks. |
|
|
384
|
+
| **🚀 Release & OIDC Guide** | [release_guide.md](docs/guides/release_guide.md) | OIDC Trusted Publishing, version bump rules, & PyPI deployment protocols. |
|
|
385
|
+
| **🏗️ Architecture Reference** | [architecture.md](docs/reference/architecture.md) | System design, UML diagrams, & deep merge algorithms. |
|
|
327
386
|
|
|
328
387
|
---
|
|
329
388
|
|
|
330
|
-
##
|
|
331
|
-
|
|
332
|
-
* Security Policy: [SECURITY.md](https://gitlab.com/halfhiddencode/python-dynamic-config-loader/-/blob/main/SECURITY.md)
|
|
333
|
-
* Contribution Protocols: [CONTRIBUTING.md](https://gitlab.com/halfhiddencode/python-dynamic-config-loader/-/blob/main/CONTRIBUTING.md)
|
|
389
|
+
## 📜 License
|
|
390
|
+
Licensed under the [Apache License, Version 2.0](LICENSE).
|
|
@@ -39,9 +39,9 @@ class TestEnvInjection(unittest.TestCase):
|
|
|
39
39
|
Verifies that configuration parameters are injected correctly with the default prefix.
|
|
40
40
|
"""
|
|
41
41
|
os.environ["DCL_ENV_LOADER"] = "true"
|
|
42
|
-
os.environ["
|
|
43
|
-
os.environ["
|
|
44
|
-
os.environ["
|
|
42
|
+
os.environ["DCL_DATABASE__PORT"] = "9000"
|
|
43
|
+
os.environ["DCL_DATABASE__USER"] = "postgres_env"
|
|
44
|
+
os.environ["DCL_SERVICE_GATEWAY_NAME"] = "payment_gateway"
|
|
45
45
|
|
|
46
46
|
loader = DynamicConfigLoader(default_config_path=str(self.base_file))
|
|
47
47
|
result = loader.load()
|
|
@@ -49,14 +49,41 @@ class TestEnvInjection(unittest.TestCase):
|
|
|
49
49
|
# Check nested structures are created or overridden
|
|
50
50
|
self.assertEqual(result["database"]["port"], 9000) # String "9000" is parsed to int 9000
|
|
51
51
|
self.assertEqual(result["database"]["user"], "postgres_env")
|
|
52
|
-
self.
|
|
52
|
+
self.assertEqual(result["service_gateway_name"], "payment_gateway") # Single _ is 100% flat!
|
|
53
|
+
|
|
54
|
+
def test_injection_double_underscore_delimiter(self):
|
|
55
|
+
"""
|
|
56
|
+
Verifies that double-underscore '__' preserves single underscores in injected key names.
|
|
57
|
+
"""
|
|
58
|
+
os.environ["DCL_ENV_LOADER"] = "true"
|
|
59
|
+
os.environ["DCL_AUTH__TENANT_ID"] = "5fa1dea3-2af8-4cd5"
|
|
60
|
+
os.environ["DCL_AWS_S3__BUCKET_NAME"] = "my-bucket-prod"
|
|
61
|
+
|
|
62
|
+
loader = DynamicConfigLoader(default_config_path=str(self.base_file))
|
|
63
|
+
result = loader.load()
|
|
64
|
+
|
|
65
|
+
self.assertEqual(result["auth"]["tenant_id"], "5fa1dea3-2af8-4cd5")
|
|
66
|
+
self.assertEqual(result["aws_s3"]["bucket_name"], "my-bucket-prod")
|
|
67
|
+
|
|
68
|
+
def test_injection_flat_key_override(self):
|
|
69
|
+
"""
|
|
70
|
+
Verifies that DCL_APP_NAME cleanly overrides a flat key 'app_name' from baseline.
|
|
71
|
+
"""
|
|
72
|
+
os.environ["DCL_ENV_LOADER"] = "true"
|
|
73
|
+
os.environ["DCL_APP_NAME"] = "Overridden Gateway App"
|
|
74
|
+
|
|
75
|
+
env_file = self.TEST_DIR / "test_configs" / "base_config.env"
|
|
76
|
+
loader = DynamicConfigLoader(default_config_path=str(env_file))
|
|
77
|
+
result = loader.load()
|
|
78
|
+
|
|
79
|
+
self.assertEqual(result["app_name"], "Overridden Gateway App")
|
|
53
80
|
|
|
54
81
|
def test_injection_custom_prefix(self):
|
|
55
82
|
"""
|
|
56
83
|
Verifies that configuration parameters are injected correctly using a custom prefix.
|
|
57
84
|
"""
|
|
58
85
|
os.environ["DCL_ENV_LOADER"] = "true"
|
|
59
|
-
os.environ["
|
|
86
|
+
os.environ["MYAPP_DB__HOST"] = "remote.db"
|
|
60
87
|
|
|
61
88
|
# Pass custom prefix to constructor
|
|
62
89
|
loader = DynamicConfigLoader(default_config_path=str(self.base_file), prefix="MYAPP_")
|
|
@@ -36,10 +36,30 @@ class TestEnvStrategy(unittest.TestCase):
|
|
|
36
36
|
Verifies that parse_env_file correctly parses env variables and translates primitive types.
|
|
37
37
|
"""
|
|
38
38
|
data = parse_env_file(self.base_file)
|
|
39
|
-
self.assertEqual(data["
|
|
40
|
-
self.assertFalse(data["
|
|
41
|
-
self.assertEqual(data["
|
|
42
|
-
self.assertEqual(data["
|
|
39
|
+
self.assertEqual(data["app_name"], "Test Env Gateway")
|
|
40
|
+
self.assertFalse(data["debug_mode"])
|
|
41
|
+
self.assertEqual(data["database_port"], 5432)
|
|
42
|
+
self.assertEqual(data["database_host"], "127.0.0.1")
|
|
43
|
+
|
|
44
|
+
def test_flat_env_key_parsing(self):
|
|
45
|
+
"""
|
|
46
|
+
Verifies that dotenv files return 100% flat dictionary mappings without creating nested sub-dictionaries.
|
|
47
|
+
"""
|
|
48
|
+
import tempfile
|
|
49
|
+
with tempfile.NamedTemporaryFile("w+", suffix=".env", delete=False) as f:
|
|
50
|
+
f.write("AUTH__TENANT_ID=5fa1dea3\n")
|
|
51
|
+
f.write("AWS_S3__BUCKET_NAME=my-bucket\n")
|
|
52
|
+
f.write("SERVICE_GATEWAY_NAME=my_app\n")
|
|
53
|
+
temp_path = Path(f.name)
|
|
54
|
+
|
|
55
|
+
try:
|
|
56
|
+
data = parse_env_file(temp_path)
|
|
57
|
+
self.assertEqual(data["auth__tenant_id"], "5fa1dea3")
|
|
58
|
+
self.assertEqual(data["aws_s3__bucket_name"], "my-bucket")
|
|
59
|
+
self.assertEqual(data["service_gateway_name"], "my_app")
|
|
60
|
+
finally:
|
|
61
|
+
if temp_path.exists():
|
|
62
|
+
temp_path.unlink()
|
|
43
63
|
|
|
44
64
|
def test_env_deep_merging(self):
|
|
45
65
|
"""
|
|
@@ -80,10 +100,10 @@ class TestEnvStrategy(unittest.TestCase):
|
|
|
80
100
|
loader = DynamicConfigLoader(default_config_path=str(self.base_file))
|
|
81
101
|
result = loader.load()
|
|
82
102
|
|
|
83
|
-
self.assertEqual(result["
|
|
84
|
-
self.assertTrue(result["
|
|
85
|
-
self.assertEqual(result["
|
|
86
|
-
self.assertEqual(result["
|
|
103
|
+
self.assertEqual(result["app_name"], "Test Env Gateway")
|
|
104
|
+
self.assertTrue(result["debug_mode"])
|
|
105
|
+
self.assertEqual(result["database_host"], "env-dev-cluster.local")
|
|
106
|
+
self.assertEqual(result["database_port"], 5432)
|
|
87
107
|
|
|
88
108
|
def test_env_log_masking(self):
|
|
89
109
|
"""
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
# Dynamic Configuration Loader
|
|
2
|
-
|
|
3
|
-
A lightweight, production-grade, strategy-driven configuration orchestration engine designed to dynamically discover, alphabetically sort, and recursively deep-merge multi-layered configuration files.
|
|
4
|
-
|
|
5
|
-
## Supported Formats
|
|
6
|
-
|
|
7
|
-
The orchestration engine natively parses and cascades the following configuration formats:
|
|
8
|
-
* **YAML** (`.yaml`, `.yml`)
|
|
9
|
-
* **JSON** (`.json`)
|
|
10
|
-
* **XML** (`.xml`)
|
|
11
|
-
* **TOML** (`.toml`)
|
|
12
|
-
* **INI / Conf** (`.ini`, `.conf`)
|
|
13
|
-
* **Java Properties** (`.properties`)
|
|
14
|
-
* **Dotenv** (`.env`)
|
|
15
|
-
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
```text
|
|
19
|
-
Copyright (C) 2026 Avinash Kumar <halfhiddencode AT gmail DOT com>
|
|
20
|
-
|
|
21
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
22
|
-
you may not use this file except in compliance with the License.
|
|
23
|
-
You may obtain a copy of the License at
|
|
24
|
-
|
|
25
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
26
|
-
|
|
27
|
-
Unless required by applicable law or agreed to in writing, software
|
|
28
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
29
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
30
|
-
See the License for the specific language governing permissions and
|
|
31
|
-
limitations under the License.
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
---
|
|
35
|
-
|
|
36
|
-
## Project Metadata
|
|
37
|
-
* **Maintainer:** Avinash Kumar
|
|
38
|
-
* **Target Ecosystem:** Python 3.8+ / GitLab Source Hosting and PyPI Package Registry
|
|
39
|
-
* **Official Repository:** [python-dynamic-config-loader](https://gitlab.com/halfhiddencode/python-dynamic-config-loader)
|
|
40
|
-
* **Licensing:** Apache License, Version 2.0
|
|
41
|
-
* **Core Design Patterns:** Strategy Pattern, Registry Factory
|
|
42
|
-
|
|
43
|
-
---
|
|
44
|
-
|
|
45
|
-
## Installation
|
|
46
|
-
|
|
47
|
-
Install the package directly from PyPI:
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
pip install dynamic-config-loader
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
Or install in editable mode for local development:
|
|
54
|
-
|
|
55
|
-
```bash
|
|
56
|
-
pip install -e .
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
---
|
|
60
|
-
|
|
61
|
-
## Quick Start
|
|
62
|
-
|
|
63
|
-
```python
|
|
64
|
-
import os
|
|
65
|
-
from dynamic_config_loader import DynamicConfigLoader
|
|
66
|
-
|
|
67
|
-
# 1. (Optional) Provide path override layers via system environment
|
|
68
|
-
os.environ["PYTHON_ADDITIONAL_CONFIG"] = "/app/configs/overrides_directory"
|
|
69
|
-
|
|
70
|
-
# 2. Instantiate with a local base configuration file
|
|
71
|
-
loader = DynamicConfigLoader(default_config_path="/app/configs/base_defaults.yaml")
|
|
72
|
-
|
|
73
|
-
# 3. Load and compile configurations
|
|
74
|
-
config = loader.load()
|
|
75
|
-
print(config["database"]["host"])
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
---
|
|
79
|
-
|
|
80
|
-
## Documentation Index
|
|
81
|
-
|
|
82
|
-
The complete enterprise documentation is organized under the Diátaxis framework layout rules within the `docs/` directory. No emojis are used in the index or guidelines.
|
|
83
|
-
|
|
84
|
-
| Track | Target Document | Description |
|
|
85
|
-
| :--- | :--- | :--- |
|
|
86
|
-
| **Getting Started** | [Getting Started Tutorial](https://gitlab.com/halfhiddencode/python-dynamic-config-loader/-/blob/main/docs/tutorials/getting_started.md) | Onboarding sequence, repeatable format tracks, and installation via GitLab Package Registry. |
|
|
87
|
-
| **Operations Guide** | [Advanced Ingestion and Path Traversal Guide](https://gitlab.com/halfhiddencode/python-dynamic-config-loader/-/blob/main/docs/guides/user_usage.md) | Path parsing matrix, edge-case refusals, Central Config Manager pattern, and log masking safety details. |
|
|
88
|
-
| **Contributor Guide** | [Format Strategy Contribution Guide](https://gitlab.com/halfhiddencode/python-dynamic-config-loader/-/blob/main/docs/guides/contributor_guide.md) | Abstract base strategy class signatures, factory registration hooks, and copy-pasteable JSON blueprints. |
|
|
89
|
-
| **Technical Reference** | [Core Architecture Reference](https://gitlab.com/halfhiddencode/python-dynamic-config-loader/-/blob/main/docs/reference/architecture.md) | System design architecture, UML mapping, execution pipelines, and logging safety compliance matrices. |
|
|
90
|
-
|
|
91
|
-
---
|
|
92
|
-
|
|
93
|
-
## Repository Ledgers
|
|
94
|
-
* Version History: [CHANGELOG.md](https://gitlab.com/halfhiddencode/python-dynamic-config-loader/-/blob/main/CHANGELOG.md)
|
|
95
|
-
* Security Policy: [SECURITY.md](https://gitlab.com/halfhiddencode/python-dynamic-config-loader/-/blob/main/SECURITY.md)
|
|
96
|
-
* Contribution Protocols: [CONTRIBUTING.md](https://gitlab.com/halfhiddencode/python-dynamic-config-loader/-/blob/main/CONTRIBUTING.md)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/__init__.py
RENAMED
|
File without changes
|
{dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/src/dynamic_config_loader/loader.py
RENAMED
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dynamic_config_loader-2.5.0 → dynamic_config_loader-2.7.0}/tests/test_properties_strategy.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|