dynamic-config-loader 2.4.0__tar.gz → 2.6.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.
Files changed (50) hide show
  1. {dynamic_config_loader-2.4.0/src/dynamic_config_loader.egg-info → dynamic_config_loader-2.6.0}/PKG-INFO +98 -52
  2. dynamic_config_loader-2.6.0/README.md +140 -0
  3. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/pyproject.toml +3 -1
  4. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/src/dynamic_config_loader/environment.py +14 -4
  5. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/src/dynamic_config_loader/strategies/__init__.py +4 -0
  6. dynamic_config_loader-2.6.0/src/dynamic_config_loader/strategies/env/__init__.py +36 -0
  7. dynamic_config_loader-2.6.0/src/dynamic_config_loader/strategies/env/merger.py +73 -0
  8. dynamic_config_loader-2.6.0/src/dynamic_config_loader/strategies/env/parser.py +71 -0
  9. dynamic_config_loader-2.6.0/src/dynamic_config_loader/strategies/properties/__init__.py +36 -0
  10. dynamic_config_loader-2.6.0/src/dynamic_config_loader/strategies/properties/merger.py +73 -0
  11. dynamic_config_loader-2.6.0/src/dynamic_config_loader/strategies/properties/parser.py +86 -0
  12. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0/src/dynamic_config_loader.egg-info}/PKG-INFO +98 -52
  13. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/src/dynamic_config_loader.egg-info/SOURCES.txt +8 -0
  14. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/tests/test_env_injection.py +27 -0
  15. dynamic_config_loader-2.6.0/tests/test_env_strategy.py +140 -0
  16. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/tests/test_factory.py +10 -0
  17. dynamic_config_loader-2.6.0/tests/test_properties_strategy.py +120 -0
  18. dynamic_config_loader-2.4.0/README.md +0 -94
  19. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/AUTHORS +0 -0
  20. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/LICENSE +0 -0
  21. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/NOTICE +0 -0
  22. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/setup.cfg +0 -0
  23. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/src/dynamic_config_loader/__init__.py +0 -0
  24. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/src/dynamic_config_loader/loader.py +0 -0
  25. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/src/dynamic_config_loader/strategies/base_strategy.py +0 -0
  26. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/src/dynamic_config_loader/strategies/ini/__init__.py +0 -0
  27. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/src/dynamic_config_loader/strategies/ini/merger.py +0 -0
  28. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/src/dynamic_config_loader/strategies/ini/parser.py +0 -0
  29. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/src/dynamic_config_loader/strategies/json/__init__.py +0 -0
  30. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/src/dynamic_config_loader/strategies/json/merger.py +0 -0
  31. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/src/dynamic_config_loader/strategies/json/parser.py +0 -0
  32. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/src/dynamic_config_loader/strategies/toml/__init__.py +0 -0
  33. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/src/dynamic_config_loader/strategies/toml/merger.py +0 -0
  34. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/src/dynamic_config_loader/strategies/toml/parser.py +0 -0
  35. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/src/dynamic_config_loader/strategies/xml/__init__.py +0 -0
  36. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/src/dynamic_config_loader/strategies/xml/merger.py +0 -0
  37. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/src/dynamic_config_loader/strategies/xml/parser.py +0 -0
  38. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/src/dynamic_config_loader/strategies/yaml/__init__.py +0 -0
  39. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/src/dynamic_config_loader/strategies/yaml/merger.py +0 -0
  40. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/src/dynamic_config_loader/strategies/yaml/parser.py +0 -0
  41. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/src/dynamic_config_loader.egg-info/dependency_links.txt +0 -0
  42. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/src/dynamic_config_loader.egg-info/requires.txt +0 -0
  43. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/src/dynamic_config_loader.egg-info/top_level.txt +0 -0
  44. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/tests/test_deep_merge.py +0 -0
  45. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/tests/test_ini_strategy.py +0 -0
  46. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/tests/test_json_strategy.py +0 -0
  47. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/tests/test_loader.py +0 -0
  48. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/tests/test_logging_safety.py +0 -0
  49. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.0}/tests/test_toml_strategy.py +0 -0
  50. {dynamic_config_loader-2.4.0 → dynamic_config_loader-2.6.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.4.0
3
+ Version: 2.6.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:
@@ -210,7 +210,7 @@ Project-URL: Repository, https://gitlab.com/halfhiddencode/python-dynamic-config
210
210
  Project-URL: Issues, https://gitlab.com/halfhiddencode/python-dynamic-config-loader/-/issues
211
211
  Project-URL: Documentation, https://gitlab.com/halfhiddencode/python-dynamic-config-loader/-/tree/main/docs
212
212
  Project-URL: Changelog, https://gitlab.com/halfhiddencode/python-dynamic-config-loader/-/blob/main/CHANGELOG.md
213
- Keywords: config,configuration,dynamic-loader,cascading-config,deep-merge,strategy-pattern,yaml,json,xml,toml,ini,conf,devops
213
+ Keywords: config,configuration,dynamic-loader,cascading-config,deep-merge,strategy-pattern,yaml,json,xml,toml,ini,conf,properties,dotenv,devops
214
214
  Classifier: Development Status :: 5 - Production/Stable
215
215
  Classifier: Intended Audience :: Developers
216
216
  Classifier: Intended Audience :: System Administrators
@@ -237,49 +237,67 @@ 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, alphabetically sort, and recursively deep-merge multi-layered configuration files.
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
- ## Supported Formats
242
+ ---
243
+
244
+ ## 📌 Quick Navigation Index
243
245
 
244
- The orchestration engine natively parses and cascades the following configuration formats:
245
- * **YAML** (`.yaml`, `.yml`)
246
- * **JSON** (`.json`)
247
- * **XML** (`.xml`)
248
- * **TOML** (`.toml`)
249
- * **INI / Conf** (`.ini`, `.conf`)
246
+ - [⚡ Minimal Quick Start](#-quick-start-minimal-3-lines)
247
+ - [📦 Installation](#-installation)
248
+ - [⚙️ Supported Configuration Formats](#%EF%B8%8F-supported-configuration-formats)
249
+ - [🔀 Multi-Layer Overrides & Environment Injection](#-multi-layer-overrides--environment-injection)
250
+ - [📖 Documentation Index](#-documentation-index)
251
+ - [🎨 System Architecture Visualizer](#-system-architecture)
250
252
 
251
253
  ---
252
254
 
253
- ```text
254
- Copyright (C) 2026 Avinash Kumar <halfhiddencode AT gmail DOT com>
255
+ ### 🚀 Configuration Lifecycle Matrix: Minimal to Advanced
256
+
257
+ | Lifecycle Phase | Component Requirement | How It Works in Code / Environment | Primary Purpose |
258
+ | :--- | :--- | :--- | :--- |
259
+ | **1. Local Dev (Coding Time)** | `[OPTIONAL FALLBACK]` | `loader = DynamicConfigLoader("config.yaml")` | Local fallback file for offline developer workstations. |
260
+ | **2. Image Build (CI/CD Build Time)** | `[REQUIRED IN CODE]` | `loader = DynamicConfigLoader()` | **Image Immutability!** Zero hardcoded secrets in Docker image. |
261
+ | **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. |
262
+ | **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. |
263
+
264
+ ---
255
265
 
256
- Licensed under the Apache License, Version 2.0 (the "License");
257
- you may not use this file except in compliance with the License.
258
- You may obtain a copy of the License at
266
+ ### Minimal Execution Code Snippets
259
267
 
260
- http://www.apache.org/licenses/LICENSE-2.0
268
+ #### Mode 1: Container / Kubernetes Mode (`[RECOMMENDED FOR PROD]`)
269
+
270
+ > [!NOTE]
271
+ > **[OPTIONAL FILE PATH - CAN SKIP!]**
272
+ > 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_`).
273
+
274
+ ```python
275
+ from dynamic_config_loader import DynamicConfigLoader
261
276
 
262
- Unless required by applicable law or agreed to in writing, software
263
- distributed under the License is distributed on an "AS IS" BASIS,
264
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
265
- See the License for the specific language governing permissions and
266
- limitations under the License.
277
+ # Zero hardcoded file paths! Fully handled at deployment time
278
+ loader = DynamicConfigLoader()
279
+ config = loader.load()
267
280
  ```
268
281
 
269
- ---
282
+ #### Mode 2: Local Development Mode (`[OPTIONAL FALLBACK]`)
283
+
284
+ > [!NOTE]
285
+ > **[LOCAL FALLBACK ONLY]**
286
+ > Useful for local developer laptops so you can run `python app.py` offline without configuring environment variables.
287
+
288
+ ```python
289
+ from dynamic_config_loader import DynamicConfigLoader
270
290
 
271
- ## Project Metadata
272
- * **Maintainer:** Avinash Kumar
273
- * **Target Ecosystem:** Python 3.8+ / GitLab Source Hosting and PyPI Package Registry
274
- * **Official Repository:** [python-dynamic-config-loader](https://gitlab.com/halfhiddencode/python-dynamic-config-loader)
275
- * **Licensing:** Apache License, Version 2.0
276
- * **Core Design Patterns:** Strategy Pattern, Registry Factory
291
+ # Optional local fallback file
292
+ loader = DynamicConfigLoader("config.yaml")
293
+ config = loader.load()
294
+ ```
277
295
 
278
296
  ---
279
297
 
280
- ## Installation
298
+ ## 📦 Installation
281
299
 
282
- Install the package directly from PyPI:
300
+ Install from PyPI via `pip`:
283
301
 
284
302
  ```bash
285
303
  pip install dynamic-config-loader
@@ -293,39 +311,67 @@ pip install -e .
293
311
 
294
312
  ---
295
313
 
296
- ## Quick Start
314
+ ## ⚙️ Supported Configuration Formats
297
315
 
298
- ```python
299
- import os
300
- from dynamic_config_loader import DynamicConfigLoader
316
+ The orchestration engine natively ingests, parses, and cascades **7 configuration formats**:
301
317
 
302
- # 1. (Optional) Provide path override layers via system environment
303
- os.environ["PYTHON_ADDITIONAL_CONFIG"] = "/app/configs/overrides_directory"
318
+ | Format | Extensions | Key Behavior & Conversion | Guide Link |
319
+ | :--- | :--- | :--- | :--- |
320
+ | **YAML** | `.yaml`, `.yml` | Native YAML indentation & deep dictionary parsing | [View Details](docs/guides/user_usage.md#71-yaml-strategy-yamlstrategy) |
321
+ | **JSON** | `.json` | Strict JSON objects & typed arrays | [View Details](docs/guides/user_usage.md#72-json-strategy-jsonstrategy) |
322
+ | **Dotenv** | `.env` | **100% Flat Keys** (`SERVICE_GATEWAY_NAME` $\rightarrow$ `config["service_gateway_name"]`) | [View Details](docs/guides/user_usage.md#87-dotenv-strategy-envstrategy) |
323
+ | **TOML** | `.toml` | Section headers (`[table]`), inline tables, & datetimes | [View Details](docs/guides/user_usage.md#74-toml-strategy-tomlstrategy) |
324
+ | **INI / Conf** | `.ini`, `.conf` | Section headers (`[section]`) & automatic primitive type casting | [View Details](docs/guides/user_usage.md#75-ini--conf-strategy-inistrategy) |
325
+ | **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) |
326
+ | **XML** | `.xml` | Tag element hierarchies auto-converted into Python dicts | [View Details](docs/guides/user_usage.md#73-xml-strategy-xmlstrategy) |
304
327
 
305
- # 2. Instantiate with a local base configuration file
306
- loader = DynamicConfigLoader(default_config_path="/app/configs/base_defaults.yaml")
328
+ ---
307
329
 
308
- # 3. Load and compile configurations
309
- config = loader.load()
310
- print(config["database"]["host"])
330
+ ## 🔀 Multi-Layer Overrides & Environment Injection
331
+
332
+ <details>
333
+ <summary><b>Click to expand Advanced Environment Overrides & Logging Options</b></summary>
334
+
335
+ ### 1. External File/Directory Overrides (`PYTHON_ADDITIONAL_CONFIG`)
336
+ Specify an external file or directory of override files via system environment variables:
337
+
338
+ ```bash
339
+ export PYTHON_ADDITIONAL_CONFIG="/etc/app/production_overrides.yaml"
311
340
  ```
312
341
 
342
+ ### 2. Environment Variable Injection (`DCL_ENV_LOADER=true`)
343
+ Inject or override specific keys dynamically at runtime using environment variables:
344
+
345
+ ```bash
346
+ export DCL_ENV_LOADER=true
347
+ export DCL_PORT=9000
348
+ export DCL_LOG_LEVEL=info
349
+ ```
350
+
351
+ ### 3. Log Redaction Controls (`ENABLE_UNSAFE_LOGGING`)
352
+ * **Default (Safe Mode):** Sensitive passwords and tokens are redacted (`[REDACTED]`) in logs.
353
+ * **Unsafe Mode (`ENABLE_UNSAFE_LOGGING=true`):** Exposes raw values during local debug sessions.
354
+
355
+ </details>
356
+
313
357
  ---
314
358
 
315
- ## Documentation Index
359
+ ## 🎨 System Architecture
360
+
361
+ ![Master Architecture Pipeline & Deep Merge Visualizer](docs/images/master_architecture_deep_merge.svg)
362
+
363
+ ---
316
364
 
317
- 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.
365
+ ## 📖 Documentation Index
318
366
 
319
- | Track | Target Document | Description |
367
+ | Guide Track | Link | Description |
320
368
  | :--- | :--- | :--- |
321
- | **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. |
322
- | **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. |
323
- | **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. |
324
- | **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. |
369
+ | **🚀 Getting Started Tutorial** | [getting_started.md](docs/tutorials/getting_started.md) | Step-by-step onboarding & minimal execution tracks. |
370
+ | **📖 Operations & Usage Guide** | [user_usage.md](docs/guides/user_usage.md) | Complete format matrix, K8s/DevOps deployment scenarios, & path edge cases. |
371
+ | **🛠️ Contributor Guide** | [contributor_guide.md](docs/guides/contributor_guide.md) | Adding custom format strategies & factory registry hooks. |
372
+ | **🏗️ Architecture Reference** | [architecture.md](docs/reference/architecture.md) | System design, UML diagrams, & deep merge algorithms. |
325
373
 
326
374
  ---
327
375
 
328
- ## Repository Ledgers
329
- * Version History: [CHANGELOG.md](https://gitlab.com/halfhiddencode/python-dynamic-config-loader/-/blob/main/CHANGELOG.md)
330
- * Security Policy: [SECURITY.md](https://gitlab.com/halfhiddencode/python-dynamic-config-loader/-/blob/main/SECURITY.md)
331
- * Contribution Protocols: [CONTRIBUTING.md](https://gitlab.com/halfhiddencode/python-dynamic-config-loader/-/blob/main/CONTRIBUTING.md)
376
+ ## 📜 License
377
+ Licensed under the [Apache License, Version 2.0](LICENSE).
@@ -0,0 +1,140 @@
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
+ ## 📌 Quick Navigation Index
8
+
9
+ - [⚡ Minimal Quick Start](#-quick-start-minimal-3-lines)
10
+ - [📦 Installation](#-installation)
11
+ - [⚙️ Supported Configuration Formats](#%EF%B8%8F-supported-configuration-formats)
12
+ - [🔀 Multi-Layer Overrides & Environment Injection](#-multi-layer-overrides--environment-injection)
13
+ - [📖 Documentation Index](#-documentation-index)
14
+ - [🎨 System Architecture Visualizer](#-system-architecture)
15
+
16
+ ---
17
+
18
+ ### 🚀 Configuration Lifecycle Matrix: Minimal to Advanced
19
+
20
+ | Lifecycle Phase | Component Requirement | How It Works in Code / Environment | Primary Purpose |
21
+ | :--- | :--- | :--- | :--- |
22
+ | **1. Local Dev (Coding Time)** | `[OPTIONAL FALLBACK]` | `loader = DynamicConfigLoader("config.yaml")` | Local fallback file for offline developer workstations. |
23
+ | **2. Image Build (CI/CD Build Time)** | `[REQUIRED IN CODE]` | `loader = DynamicConfigLoader()` | **Image Immutability!** Zero hardcoded secrets in Docker image. |
24
+ | **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. |
25
+ | **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. |
26
+
27
+ ---
28
+
29
+ ### Minimal Execution Code Snippets
30
+
31
+ #### Mode 1: Container / Kubernetes Mode (`[RECOMMENDED FOR PROD]`)
32
+
33
+ > [!NOTE]
34
+ > **[OPTIONAL FILE PATH - CAN SKIP!]**
35
+ > 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_`).
36
+
37
+ ```python
38
+ from dynamic_config_loader import DynamicConfigLoader
39
+
40
+ # Zero hardcoded file paths! Fully handled at deployment time
41
+ loader = DynamicConfigLoader()
42
+ config = loader.load()
43
+ ```
44
+
45
+ #### Mode 2: Local Development Mode (`[OPTIONAL FALLBACK]`)
46
+
47
+ > [!NOTE]
48
+ > **[LOCAL FALLBACK ONLY]**
49
+ > Useful for local developer laptops so you can run `python app.py` offline without configuring environment variables.
50
+
51
+ ```python
52
+ from dynamic_config_loader import DynamicConfigLoader
53
+
54
+ # Optional local fallback file
55
+ loader = DynamicConfigLoader("config.yaml")
56
+ config = loader.load()
57
+ ```
58
+
59
+ ---
60
+
61
+ ## 📦 Installation
62
+
63
+ Install from PyPI via `pip`:
64
+
65
+ ```bash
66
+ pip install dynamic-config-loader
67
+ ```
68
+
69
+ Or install in editable mode for local development:
70
+
71
+ ```bash
72
+ pip install -e .
73
+ ```
74
+
75
+ ---
76
+
77
+ ## ⚙️ Supported Configuration Formats
78
+
79
+ The orchestration engine natively ingests, parses, and cascades **7 configuration formats**:
80
+
81
+ | Format | Extensions | Key Behavior & Conversion | Guide Link |
82
+ | :--- | :--- | :--- | :--- |
83
+ | **YAML** | `.yaml`, `.yml` | Native YAML indentation & deep dictionary parsing | [View Details](docs/guides/user_usage.md#71-yaml-strategy-yamlstrategy) |
84
+ | **JSON** | `.json` | Strict JSON objects & typed arrays | [View Details](docs/guides/user_usage.md#72-json-strategy-jsonstrategy) |
85
+ | **Dotenv** | `.env` | **100% Flat Keys** (`SERVICE_GATEWAY_NAME` $\rightarrow$ `config["service_gateway_name"]`) | [View Details](docs/guides/user_usage.md#87-dotenv-strategy-envstrategy) |
86
+ | **TOML** | `.toml` | Section headers (`[table]`), inline tables, & datetimes | [View Details](docs/guides/user_usage.md#74-toml-strategy-tomlstrategy) |
87
+ | **INI / Conf** | `.ini`, `.conf` | Section headers (`[section]`) & automatic primitive type casting | [View Details](docs/guides/user_usage.md#75-ini--conf-strategy-inistrategy) |
88
+ | **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) |
89
+ | **XML** | `.xml` | Tag element hierarchies auto-converted into Python dicts | [View Details](docs/guides/user_usage.md#73-xml-strategy-xmlstrategy) |
90
+
91
+ ---
92
+
93
+ ## 🔀 Multi-Layer Overrides & Environment Injection
94
+
95
+ <details>
96
+ <summary><b>Click to expand Advanced Environment Overrides & Logging Options</b></summary>
97
+
98
+ ### 1. External File/Directory Overrides (`PYTHON_ADDITIONAL_CONFIG`)
99
+ Specify an external file or directory of override files via system environment variables:
100
+
101
+ ```bash
102
+ export PYTHON_ADDITIONAL_CONFIG="/etc/app/production_overrides.yaml"
103
+ ```
104
+
105
+ ### 2. Environment Variable Injection (`DCL_ENV_LOADER=true`)
106
+ Inject or override specific keys dynamically at runtime using environment variables:
107
+
108
+ ```bash
109
+ export DCL_ENV_LOADER=true
110
+ export DCL_PORT=9000
111
+ export DCL_LOG_LEVEL=info
112
+ ```
113
+
114
+ ### 3. Log Redaction Controls (`ENABLE_UNSAFE_LOGGING`)
115
+ * **Default (Safe Mode):** Sensitive passwords and tokens are redacted (`[REDACTED]`) in logs.
116
+ * **Unsafe Mode (`ENABLE_UNSAFE_LOGGING=true`):** Exposes raw values during local debug sessions.
117
+
118
+ </details>
119
+
120
+ ---
121
+
122
+ ## 🎨 System Architecture
123
+
124
+ ![Master Architecture Pipeline & Deep Merge Visualizer](docs/images/master_architecture_deep_merge.svg)
125
+
126
+ ---
127
+
128
+ ## 📖 Documentation Index
129
+
130
+ | Guide Track | Link | Description |
131
+ | :--- | :--- | :--- |
132
+ | **🚀 Getting Started Tutorial** | [getting_started.md](docs/tutorials/getting_started.md) | Step-by-step onboarding & minimal execution tracks. |
133
+ | **📖 Operations & Usage Guide** | [user_usage.md](docs/guides/user_usage.md) | Complete format matrix, K8s/DevOps deployment scenarios, & path edge cases. |
134
+ | **🛠️ Contributor Guide** | [contributor_guide.md](docs/guides/contributor_guide.md) | Adding custom format strategies & factory registry hooks. |
135
+ | **🏗️ Architecture Reference** | [architecture.md](docs/reference/architecture.md) | System design, UML diagrams, & deep merge algorithms. |
136
+
137
+ ---
138
+
139
+ ## 📜 License
140
+ 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.4.0"
7
+ version = "2.6.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"
@@ -27,6 +27,8 @@ keywords = [
27
27
  "toml",
28
28
  "ini",
29
29
  "conf",
30
+ "properties",
31
+ "dotenv",
30
32
  "devops"
31
33
  ]
32
34
 
@@ -56,11 +56,21 @@ def inject_environment_variables(
56
56
  if env_key.startswith(prefix):
57
57
  # Strip prefix
58
58
  sliced_key = env_key[len(prefix):]
59
- if not sliced_key:
60
- continue
59
+ parsed_val = _parse_env_value(env_val)
60
+
61
+ flat_key = sliced_key.strip().lower()
62
+
63
+ # Resolution order:
64
+ # 1. Direct flat key match in config_data (e.g. DCL_TEST_NAME -> config_data["test_name"])
65
+ # 2. Double-underscore '__' explicit namespace splitting (e.g. DCL_AUTH__TENANT_ID -> config_data["auth"]["tenant_id"])
66
+ # 3. Single-underscore '_' nested path splitting (e.g. DCL_DATABASE_PORT -> config_data["database"]["port"])
67
+ if flat_key in config_data:
68
+ parts = [flat_key]
69
+ elif "__" in sliced_key:
70
+ parts = [p.lower() for p in sliced_key.split("__") if p]
71
+ else:
72
+ parts = [p.lower() for p in sliced_key.split("_") if p]
61
73
 
62
- # Case Normalization and tokenizing
63
- parts = [p.lower() for p in sliced_key.split("_") if p]
64
74
  if not parts:
65
75
  continue
66
76
 
@@ -19,6 +19,8 @@ from dynamic_config_loader.strategies.json import JsonStrategy
19
19
  from dynamic_config_loader.strategies.xml import XmlStrategy
20
20
  from dynamic_config_loader.strategies.ini import IniStrategy
21
21
  from dynamic_config_loader.strategies.toml import TomlStrategy
22
+ from dynamic_config_loader.strategies.env import EnvStrategy
23
+ from dynamic_config_loader.strategies.properties import PropertiesStrategy
22
24
 
23
25
 
24
26
  class StrategyFactory:
@@ -39,6 +41,8 @@ class StrategyFactory:
39
41
  ".ini": IniStrategy(),
40
42
  ".conf": IniStrategy(),
41
43
  ".toml": TomlStrategy(),
44
+ ".env": EnvStrategy(),
45
+ ".properties": PropertiesStrategy(),
42
46
  }
43
47
 
44
48
  def get_strategy(self, extension: str) -> Optional[BaseStrategy]:
@@ -0,0 +1,36 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # SPDX-License-Identifier: Apache-2.0
4
+ # Copyright (C) 2026 Avinash Kumar
5
+
6
+ """
7
+ Env Strategy Entrypoint.
8
+
9
+ Exposes the EnvStrategy wrapper subclassing BaseStrategy.
10
+ """
11
+
12
+ from pathlib import Path
13
+ from typing import Any, Dict
14
+ from dynamic_config_loader.strategies.base_strategy import BaseStrategy
15
+ from dynamic_config_loader.strategies.env.parser import parse_env_file
16
+ from dynamic_config_loader.strategies.env.merger import execute_env_deep_merge
17
+
18
+
19
+ class EnvStrategy(BaseStrategy):
20
+ """
21
+ Strategy implementation managing the parsing and deep-merging of dotenv (.env) assets.
22
+ """
23
+
24
+ def parse(self, file_path: Path) -> Dict[str, Any]:
25
+ return parse_env_file(file_path)
26
+
27
+ def merge(
28
+ self,
29
+ base_dict: Dict[str, Any],
30
+ update_dict: Dict[str, Any],
31
+ path: str = "",
32
+ mask_secrets: bool = True,
33
+ ) -> None:
34
+ execute_env_deep_merge(
35
+ base_dict, update_dict, path=path, mask_secrets=mask_secrets
36
+ )
@@ -0,0 +1,73 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # SPDX-License-Identifier: Apache-2.0
4
+ # Copyright (C) 2026 Avinash Kumar
5
+
6
+ """
7
+ Env Merging Strategy Module.
8
+
9
+ Provides recursive tree-merging algorithms engineered to blend cascading dotenv layers.
10
+ """
11
+
12
+ import logging
13
+ from typing import Any, Dict
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ def execute_env_deep_merge(
19
+ base_dict: Dict[str, Any],
20
+ update_dict: Dict[str, Any],
21
+ path: str = "",
22
+ mask_secrets: bool = True,
23
+ ) -> None:
24
+ """
25
+ Recursively deep-merges update_dict into base_dict in-place.
26
+ """
27
+ for key, value in update_dict.items():
28
+ current_path = f"{path}.{key}" if path else key
29
+
30
+ # Case A: Both values are dictionaries -> recurse
31
+ if key in base_dict and isinstance(base_dict[key], dict) and isinstance(value, dict):
32
+ logger.debug(f"Deep merging nested env structure at path: {current_path}")
33
+ execute_env_deep_merge(
34
+ base_dict[key], value, path=current_path, mask_secrets=mask_secrets
35
+ )
36
+
37
+ # Case B: Structural conflict or key exists
38
+ elif key in base_dict:
39
+ if isinstance(base_dict[key], dict) or isinstance(value, dict):
40
+ logger.warning(
41
+ f"Type mismatch conflict detected at path '{current_path}'. "
42
+ f"Overwriting base env structural type ({type(base_dict[key]).__name__}) "
43
+ f"with incoming type ({type(value).__name__})."
44
+ )
45
+ base_dict[key] = value
46
+ else:
47
+ if base_dict[key] != value:
48
+ if logger.isEnabledFor(logging.DEBUG):
49
+ if not mask_secrets:
50
+ logger.debug(
51
+ f"Updating env path '{current_path}': {repr(base_dict[key])} -> {repr(value)}"
52
+ )
53
+ else:
54
+ logger.debug(
55
+ f"Updating env path '{current_path}': [REDACTED] -> [REDACTED]"
56
+ )
57
+ else:
58
+ logger.info(
59
+ f"Updating configuration attribute path: {current_path} [Value Redacted]"
60
+ )
61
+ base_dict[key] = value
62
+ # Case C: New key
63
+ else:
64
+ if logger.isEnabledFor(logging.DEBUG):
65
+ if not mask_secrets:
66
+ logger.debug(f"Adding new env key at path '{current_path}': {repr(value)}")
67
+ else:
68
+ logger.debug(f"Adding new env key at path '{current_path}': [REDACTED]")
69
+ else:
70
+ logger.info(
71
+ f"Adding new configuration attribute path: {current_path} [Value Redacted]"
72
+ )
73
+ base_dict[key] = value
@@ -0,0 +1,71 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # SPDX-License-Identifier: Apache-2.0
4
+ # Copyright (C) 2026 Avinash Kumar
5
+
6
+ """
7
+ Env Parsing Strategy Module.
8
+
9
+ Provides isolated, low-level file stream ingestion utilities optimized
10
+ for handling standard dotenv configuration assets.
11
+ """
12
+
13
+ import logging
14
+ from pathlib import Path
15
+ from typing import Any, Dict
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ def _parse_env_file_value(val: str) -> Any:
21
+ """
22
+ Parses env string values into standard primitives (bool, int, float, str).
23
+ """
24
+ val_lower = val.strip().lower()
25
+ if val_lower == "true":
26
+ return True
27
+ if val_lower == "false":
28
+ return False
29
+ try:
30
+ return int(val)
31
+ except ValueError:
32
+ pass
33
+ try:
34
+ return float(val)
35
+ except ValueError:
36
+ pass
37
+ return val.strip()
38
+
39
+
40
+ def parse_env_file(file_path: Path) -> Dict[str, Any]:
41
+ """
42
+ Reads a dotenv configuration file asset from disk and returns a dictionary mapping.
43
+ """
44
+ data: Dict[str, Any] = {}
45
+ try:
46
+ with open(file_path, "r", encoding="utf-8") as f:
47
+ for line in f:
48
+ line = line.strip()
49
+ if not line or line.startswith("#") or line.startswith("!") or "=" not in line:
50
+ continue
51
+
52
+ key, val = line.split("=", 1)
53
+ key = key.strip().lower()
54
+ val = val.strip()
55
+
56
+ if not key:
57
+ continue
58
+
59
+ # Strip surrounding double or single quotes
60
+ if len(val) >= 2 and (
61
+ (val[0] == '"' and val[-1] == '"') or (val[0] == "'" and val[-1] == "'")
62
+ ):
63
+ val = val[1:-1]
64
+
65
+ parsed_val = _parse_env_file_value(val)
66
+ data[key] = parsed_val
67
+
68
+ except (IOError, PermissionError) as e:
69
+ logger.exception(f"Failed to read or parse dotenv file: {file_path.name}", exc_info=e)
70
+
71
+ return data
@@ -0,0 +1,36 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # SPDX-License-Identifier: Apache-2.0
4
+ # Copyright (C) 2026 Avinash Kumar
5
+
6
+ """
7
+ Java Properties Strategy Entrypoint.
8
+
9
+ Exposes the PropertiesStrategy wrapper subclassing BaseStrategy.
10
+ """
11
+
12
+ from pathlib import Path
13
+ from typing import Any, Dict
14
+ from dynamic_config_loader.strategies.base_strategy import BaseStrategy
15
+ from dynamic_config_loader.strategies.properties.parser import parse_properties_file
16
+ from dynamic_config_loader.strategies.properties.merger import execute_properties_deep_merge
17
+
18
+
19
+ class PropertiesStrategy(BaseStrategy):
20
+ """
21
+ Strategy implementation managing the parsing and deep-merging of Java properties assets.
22
+ """
23
+
24
+ def parse(self, file_path: Path) -> Dict[str, Any]:
25
+ return parse_properties_file(file_path)
26
+
27
+ def merge(
28
+ self,
29
+ base_dict: Dict[str, Any],
30
+ update_dict: Dict[str, Any],
31
+ path: str = "",
32
+ mask_secrets: bool = True,
33
+ ) -> None:
34
+ execute_properties_deep_merge(
35
+ base_dict, update_dict, path=path, mask_secrets=mask_secrets
36
+ )