configplusplus 0.1.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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Florian BARRE
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,418 @@
1
+ Metadata-Version: 2.4
2
+ Name: configplusplus
3
+ Version: 0.1.0
4
+ Summary: A powerful configuration management library with beautiful display, environment variables and YAML support
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Keywords: config,configuration,environment,yaml,settings
8
+ Author: Florian BARRE
9
+ Requires-Python: >=3.10,<4.0
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Requires-Dist: loggerplusplus (>=1.0.5)
21
+ Requires-Dist: python-dotenv (>=1.0.0,<2.0.0)
22
+ Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
23
+ Project-URL: Documentation, https://github.com/Florian-BARRE/ConfigPlusPlus#readme
24
+ Project-URL: Homepage, https://github.com/Florian-BARRE/ConfigPlusPlus
25
+ Project-URL: Repository, https://github.com/Florian-BARRE/ConfigPlusPlus
26
+ Description-Content-Type: text/markdown
27
+
28
+ # ConfigPlusPlus
29
+
30
+ > Beautiful configuration management for Python with environment variables and YAML support
31
+
32
+ [![PyPI version](https://badge.fury.io/py/configplusplus.svg)](https://pypi.org/project/configplusplus/)
33
+ [![Python](https://img.shields.io/pypi/pyversions/configplusplus.svg)](https://pypi.org/project/configplusplus/)
34
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
35
+
36
+ ## Features
37
+
38
+ ✨ **Beautiful Display** - Pretty formatted configuration output with automatic grouping and secret masking
39
+
40
+ 🔐 **Secret Masking** - Automatically hides sensitive values (API keys, passwords, tokens)
41
+
42
+ 🌍 **Environment Variables** - Load configuration from environment variables with type casting
43
+
44
+ 📄 **YAML Support** - Load configuration from YAML files with custom parsing
45
+
46
+ 🎯 **Type Casting** - Automatic type conversion (str, int, float, bool, Path)
47
+
48
+ 🏷️ **Static & Instance** - Support for both static class-based and instance-based configs
49
+
50
+ ## Installation
51
+
52
+ ```bash
53
+ pip install configplusplus
54
+ ```
55
+
56
+ Or with Poetry:
57
+
58
+ ```bash
59
+ poetry add configplusplus
60
+ ```
61
+
62
+ ## Quick Start
63
+
64
+ ### Environment-Based Configuration
65
+
66
+ ```python
67
+ from configplusplus import EnvConfigLoader, env
68
+ import pathlib
69
+
70
+ class AppConfig(EnvConfigLoader):
71
+ # Required variables
72
+ DATABASE_HOST = env("DATABASE_HOST")
73
+ DATABASE_PORT = env("DATABASE_PORT", cast=int)
74
+
75
+ # Optional with defaults
76
+ DEBUG_MODE = env("DEBUG_MODE", cast=bool, default=False)
77
+
78
+ # Paths
79
+ DATA_DIR = env("DATA_DIR", cast=pathlib.Path)
80
+
81
+ # Secrets (automatically masked in output)
82
+ SECRET_API_KEY = env("SECRET_API_KEY")
83
+
84
+ # Use as static class
85
+ print(AppConfig.DATABASE_HOST)
86
+ print(AppConfig) # Beautiful formatted output
87
+ ```
88
+
89
+ **Output:**
90
+ ```
91
+ ╔════════════════════════════════════════════╗
92
+ ║ APPCONFIG ║
93
+ ╚════════════════════════════════════════════╝
94
+
95
+ ▶ DATABASE
96
+ DATABASE_HOST = 'localhost'
97
+ DATABASE_PORT = 5432
98
+
99
+ ▶ DEBUG
100
+ DEBUG_MODE = False
101
+
102
+ ▶ DATA
103
+ DATA_DIR = '/var/data/myapp'
104
+
105
+ ▶ SECRET
106
+ SECRET_API_KEY = 'sec...et (hidden)'
107
+ ```
108
+
109
+ ### YAML-Based Configuration
110
+
111
+ ```python
112
+ from configplusplus import YamlConfigLoader
113
+
114
+ class UiConfig(YamlConfigLoader):
115
+ def __post_init__(self) -> None:
116
+ # Parse the loaded YAML data
117
+ self.app_name = self._raw_config["application"]["name"]
118
+ self.theme = self._raw_config["display"]["theme"]
119
+
120
+ # Parse nested structures
121
+ self.filters = [
122
+ FilterConfig(**f)
123
+ for f in self._raw_config["filters"]
124
+ ]
125
+
126
+ # Instantiate with path
127
+ config = UiConfig("config.yaml")
128
+ print(config.app_name)
129
+ print(config) # Beautiful formatted output
130
+ ```
131
+
132
+ ## Environment Variables
133
+
134
+ ### Basic Usage
135
+
136
+ ```python
137
+ from configplusplus import env
138
+
139
+ # String (default)
140
+ DATABASE_HOST = env("DATABASE_HOST")
141
+
142
+ # Integer
143
+ DATABASE_PORT = env("DATABASE_PORT", cast=int)
144
+
145
+ # Boolean
146
+ DEBUG_MODE = env("DEBUG_MODE", cast=bool)
147
+
148
+ # Float
149
+ TEMPERATURE = env("TEMPERATURE", cast=float)
150
+
151
+ # Path
152
+ DATA_DIR = env("DATA_DIR", cast=pathlib.Path)
153
+
154
+ # With default value
155
+ TIMEOUT = env("TIMEOUT", cast=int, default=30)
156
+
157
+ # Optional (won't raise if missing)
158
+ OPTIONAL = env("OPTIONAL", required=False, default=None)
159
+ ```
160
+
161
+ ### Boolean Casting
162
+
163
+ When `cast=bool`, these strings are considered `False`:
164
+ - `"false"`, `"False"`, `"FALSE"`
165
+ - `"0"`
166
+ - `"no"`, `"No"`, `"NO"`
167
+ - `""` (empty string)
168
+
169
+ All other values are considered `True`.
170
+
171
+ ### Loading .env Files
172
+
173
+ ```python
174
+ from configplusplus import safe_load_envs
175
+
176
+ # Load .env file with logging
177
+ safe_load_envs() # Loads from ".env"
178
+
179
+ # Load from custom path
180
+ safe_load_envs("config/.env")
181
+
182
+ # Silent loading
183
+ safe_load_envs(verbose=False)
184
+ ```
185
+
186
+ ## YAML Configuration
187
+
188
+ ### Basic Usage
189
+
190
+ ```python
191
+ from configplusplus import YamlConfigLoader
192
+
193
+ class MyConfig(YamlConfigLoader):
194
+ def __post_init__(self) -> None:
195
+ # Access raw YAML data
196
+ self.database_host = self._raw_config["database"]["host"]
197
+ self.database_port = self._raw_config["database"]["port"]
198
+ ```
199
+
200
+ ### Helper Methods
201
+
202
+ ```python
203
+ config = MyConfig("config.yaml")
204
+
205
+ # Get values with dot notation
206
+ host = config.get("database.host")
207
+ port = config.get("database.port")
208
+
209
+ # Get with default
210
+ timeout = config.get("api.timeout", default=30)
211
+
212
+ # Check if key exists
213
+ if config.has("database.host"):
214
+ print("Database configured")
215
+
216
+ # Convert to dictionary
217
+ config_dict = config.to_dict()
218
+ ```
219
+
220
+ ## Advanced Features
221
+
222
+ ### Custom Validation
223
+
224
+ ```python
225
+ class ValidatedConfig(EnvConfigLoader):
226
+ DATABASE_PORT = env("DATABASE_PORT", cast=int)
227
+
228
+ @classmethod
229
+ def validate(cls) -> None:
230
+ super().validate()
231
+ if cls.DATABASE_PORT < 1024:
232
+ raise RuntimeError("DATABASE_PORT must be >= 1024")
233
+
234
+ # Validate configuration
235
+ ValidatedConfig.validate()
236
+ ```
237
+
238
+ ### Structured Data from YAML
239
+
240
+ ```python
241
+ from dataclasses import dataclass
242
+ from typing import List
243
+
244
+ @dataclass
245
+ class FilterConfig:
246
+ name: str
247
+ type: str
248
+ enabled: bool = True
249
+
250
+ class UiConfig(YamlConfigLoader):
251
+ def __post_init__(self) -> None:
252
+ # Parse list of structured objects
253
+ self.filters: List[FilterConfig] = [
254
+ FilterConfig(**f)
255
+ for f in self._raw_config["filters"]
256
+ ]
257
+ ```
258
+
259
+ ### Multiple Configuration Sources
260
+
261
+ ```python
262
+ # Combine environment and YAML configs
263
+ class AppConfig(EnvConfigLoader):
264
+ # From environment
265
+ SECRET_API_KEY = env("SECRET_API_KEY")
266
+ DATABASE_HOST = env("DATABASE_HOST")
267
+
268
+ # Load YAML for features
269
+ @classmethod
270
+ def load_features(cls) -> None:
271
+ yaml_config = YamlConfigLoader("features.yaml")
272
+ cls.FEATURES = yaml_config.get("features")
273
+
274
+ AppConfig.load_features()
275
+ ```
276
+
277
+ ## Secret Masking
278
+
279
+ Variables containing these keywords are automatically masked in output:
280
+ - `SECRET`
281
+ - `API_KEY`
282
+ - `PASSWORD`
283
+ - `TOKEN`
284
+ - `CREDENTIAL`
285
+
286
+ Example:
287
+ ```python
288
+ SECRET_API_KEY = "sk_live_abc123xyz789"
289
+ # Output: "sk_...89 (hidden)"
290
+
291
+ PASSWORD = "short"
292
+ # Output: "***hidden***"
293
+ ```
294
+
295
+ ## Configuration Grouping
296
+
297
+ Configuration values are automatically grouped by prefix:
298
+
299
+ ```python
300
+ class AppConfig(EnvConfigLoader):
301
+ DATABASE_HOST = env("DATABASE_HOST")
302
+ DATABASE_PORT = env("DATABASE_PORT", cast=int)
303
+ API_ENDPOINT = env("API_ENDPOINT")
304
+ API_KEY = env("API_KEY")
305
+ ```
306
+
307
+ **Output shows grouped display:**
308
+ ```
309
+ ▶ DATABASE
310
+ DATABASE_HOST = 'localhost'
311
+ DATABASE_PORT = 5432
312
+
313
+ ▶ API
314
+ API_ENDPOINT = 'https://api.example.com'
315
+ API_KEY = 'key...23 (hidden)'
316
+ ```
317
+
318
+ ## Real-World Examples
319
+
320
+ ### FastAPI Application Config
321
+
322
+ ```python
323
+ from configplusplus import EnvConfigLoader, env, safe_load_envs
324
+ import pathlib
325
+
326
+ safe_load_envs()
327
+
328
+ class APIConfig(EnvConfigLoader):
329
+ # Server
330
+ HOST = env("HOST", default="0.0.0.0")
331
+ PORT = env("PORT", cast=int, default=8000)
332
+
333
+ # Database
334
+ DATABASE_URL = env("DATABASE_URL")
335
+ DATABASE_POOL_SIZE = env("DATABASE_POOL_SIZE", cast=int, default=10)
336
+
337
+ # Redis
338
+ REDIS_HOST = env("REDIS_HOST", default="localhost")
339
+ REDIS_PORT = env("REDIS_PORT", cast=int, default=6379)
340
+
341
+ # Security
342
+ SECRET_JWT_KEY = env("SECRET_JWT_KEY")
343
+ TOKEN_EXPIRE_MINUTES = env("TOKEN_EXPIRE_MINUTES", cast=int, default=60)
344
+
345
+ # Features
346
+ ENABLE_CORS = env("ENABLE_CORS", cast=bool, default=True)
347
+ ENABLE_DOCS = env("ENABLE_DOCS", cast=bool, default=False)
348
+
349
+ @classmethod
350
+ def validate(cls) -> None:
351
+ if cls.PORT < 1024 or cls.PORT > 65535:
352
+ raise RuntimeError("Invalid PORT")
353
+
354
+ # Use in FastAPI
355
+ from fastapi import FastAPI
356
+
357
+ app = FastAPI(
358
+ title="My API",
359
+ docs_url="/docs" if APIConfig.ENABLE_DOCS else None,
360
+ )
361
+ ```
362
+
363
+ ### Document Processing Pipeline Config
364
+
365
+ ```python
366
+ from configplusplus import YamlConfigLoader
367
+ from typing import List
368
+ from dataclasses import dataclass
369
+
370
+ @dataclass
371
+ class ProcessorConfig:
372
+ name: str
373
+ enabled: bool
374
+ priority: int
375
+
376
+ class PipelineConfig(YamlConfigLoader):
377
+ def __post_init__(self) -> None:
378
+ # Parse processors
379
+ self.processors: List[ProcessorConfig] = [
380
+ ProcessorConfig(**p)
381
+ for p in self._raw_config["processors"]
382
+ ]
383
+
384
+ # Parse paths
385
+ self.input_dir = pathlib.Path(self._raw_config["paths"]["input"])
386
+ self.output_dir = pathlib.Path(self._raw_config["paths"]["output"])
387
+
388
+ # Parse settings
389
+ self.batch_size = self._raw_config["settings"]["batch_size"]
390
+ self.max_workers = self._raw_config["settings"]["max_workers"]
391
+
392
+ # Load configuration
393
+ config = PipelineConfig("pipeline.yaml")
394
+
395
+ # Use in pipeline
396
+ for processor in sorted(config.processors, key=lambda x: x.priority):
397
+ if processor.enabled:
398
+ print(f"Running {processor.name}")
399
+ ```
400
+
401
+ ## Documentation
402
+
403
+ - **Quick Reference**: See [REFERENCE.md](REFERENCE.md) for a cheat sheet
404
+ - **Detailed Guide**: See [USAGE.md](USAGE.md) for comprehensive documentation
405
+ - **Examples**: Check the `examples/` directory for working code samples
406
+
407
+ ## Links
408
+
409
+ - **PyPI**: https://pypi.org/project/configplusplus/
410
+ - **GitHub**: https://github.com/Florian-BARRE/ConfigPlusPlus
411
+ - **Issues**: https://github.com/Florian-BARRE/ConfigPlusPlus/issues
412
+
413
+ ## License
414
+
415
+ MIT License - See [LICENSE](LICENSE) file for details.
416
+
417
+ **Author**: Florian BARRE
418
+