pyw-config 0.0.0.post1__py3-none-any.whl → 0.0.0.post2__py3-none-any.whl

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,411 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyw-config
3
+ Version: 0.0.0.post2
4
+ Summary: Reserved placeholder for pyw-config (configuration utilities for pythonWoods suite)
5
+ Project-URL: Homepage, https://github.com/pythonWoods/pyw-config
6
+ Project-URL: Documentation, https://pythonwoods.dev/docs/pyw-config/latest/
7
+ Project-URL: Issues, https://github.com/pythonWoods/pyw-config/issues
8
+ Project-URL: Changelog, https://github.com/pythonWoods/pyw-config/releases
9
+ Author-email: pythonWoods <you@example.com>
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Classifier: Development Status :: 2 - Pre-Alpha
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3 :: Only
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Typing :: Typed
17
+ Requires-Python: >=3.9
18
+ Requires-Dist: pyw-core>=0.0.0
19
+ Description-Content-Type: text/markdown
20
+
21
+ # pyw-config ⚙️
22
+ [![PyPI](https://img.shields.io/pypi/v/pyw-config.svg)](https://pypi.org/project/pyw-config/)
23
+ [![CI](https://github.com/pythonWoods/pyw-config/actions/workflows/ci.yml/badge.svg)](https://github.com/pythonWoods/pyw-config/actions/workflows/ci.yml)
24
+ [![License](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
25
+
26
+ > Configuration management utilities for the **pythonWoods** ecosystem.
27
+
28
+ ## Overview
29
+
30
+ **pyw-config** fornisce un sistema di gestione configurazioni type-safe e flessibile, con supporto per multipli backend (file, environment variables, remote sources) e validazione automatica tramite Pydantic.
31
+
32
+ ## Philosophy
33
+
34
+ * **Type-safe configs** – Pydantic models per zero errori di configurazione
35
+ * **Multiple sources** – YAML, JSON, TOML, .env, environment variables
36
+ * **Hierarchical merging** – override intelligente di configurazioni
37
+ * **Environment-aware** – profili per dev/staging/prod
38
+ * **Validation-first** – errori chiari e actionable per configurazioni invalide
39
+
40
+ ## Installation
41
+
42
+ ```bash
43
+ pip install pyw-config
44
+ ```
45
+
46
+ Per backend aggiuntivi:
47
+
48
+ ```bash
49
+ pip install pyw-config[yaml] # + PyYAML per file YAML
50
+ pip install pyw-config[toml] # + tomli/tomllib per TOML
51
+ pip install pyw-config[vault] # + hvac per HashiCorp Vault
52
+ pip install pyw-config[remote] # + requests per config remote
53
+ pip install pyw-config[full] # tutti i backend
54
+ ```
55
+
56
+ ## Quick Start
57
+
58
+ ### Basic Configuration
59
+
60
+ ```python
61
+ from pyw.config import BaseConfig, Field
62
+ from pyw.config.sources import from_file, from_env
63
+
64
+ class DatabaseConfig(BaseConfig):
65
+ host: str = Field(default="localhost")
66
+ port: int = Field(default=5432, ge=1, le=65535)
67
+ username: str
68
+ password: str = Field(..., min_length=8)
69
+ database: str
70
+ ssl_enabled: bool = Field(default=True)
71
+
72
+ class AppConfig(BaseConfig):
73
+ debug: bool = Field(default=False)
74
+ secret_key: str = Field(..., min_length=32)
75
+ db: DatabaseConfig
76
+ api_timeout: float = Field(default=30.0, gt=0)
77
+
78
+ # Carica da file + environment
79
+ config = AppConfig.from_sources(
80
+ from_file("config.yaml"),
81
+ from_env(prefix="MYAPP_")
82
+ )
83
+
84
+ print(f"Connecting to {config.db.host}:{config.db.port}")
85
+ ```
86
+
87
+ ### Configuration Files
88
+
89
+ **config.yaml:**
90
+ ```yaml
91
+ debug: false
92
+ secret_key: "your-super-secret-key-here-min-32-chars"
93
+ db:
94
+ host: "prod-db.example.com"
95
+ username: "myapp"
96
+ database: "production"
97
+ ssl_enabled: true
98
+ api_timeout: 60.0
99
+ ```
100
+
101
+ **Environment Variables:**
102
+ ```bash
103
+ export MYAPP_DEBUG=true
104
+ export MYAPP_DB_PASSWORD=secure_password_123
105
+ export MYAPP_DB_PORT=5433
106
+ ```
107
+
108
+ ## Features
109
+
110
+ ### 🔄 Multiple Configuration Sources
111
+
112
+ ```python
113
+ from pyw.config.sources import (
114
+ from_file, from_env, from_dict,
115
+ from_vault, from_url
116
+ )
117
+
118
+ config = AppConfig.from_sources(
119
+ # 1. File di base
120
+ from_file("config.yaml"),
121
+
122
+ # 2. Override per environment
123
+ from_file(f"config.{env}.yaml", optional=True),
124
+
125
+ # 3. Secrets da Vault
126
+ from_vault("secret/myapp", optional=True),
127
+
128
+ # 4. Environment variables (priorità massima)
129
+ from_env(prefix="MYAPP_"),
130
+
131
+ # 5. Config remota
132
+ from_url("https://config.myapp.com/api/config", optional=True)
133
+ )
134
+ ```
135
+
136
+ ### 🌍 Environment Profiles
137
+
138
+ ```python
139
+ from pyw.config import ConfigProfile
140
+
141
+ class AppConfig(BaseConfig):
142
+ class Meta:
143
+ profiles = {
144
+ "development": {
145
+ "debug": True,
146
+ "db.host": "localhost",
147
+ "api_timeout": 5.0
148
+ },
149
+ "production": {
150
+ "debug": False,
151
+ "db.ssl_enabled": True,
152
+ "api_timeout": 30.0
153
+ }
154
+ }
155
+
156
+ # Carica profilo automaticamente da ENV
157
+ config = AppConfig.load_profile() # Legge ENVIRONMENT=production
158
+
159
+ # Oppure esplicitamente
160
+ config = AppConfig.load_profile("development")
161
+ ```
162
+
163
+ ### 🔒 Secrets Management
164
+
165
+ ```python
166
+ from pyw.config import SecretStr, SecretBytes
167
+ from pyw.config.secrets import from_keyring, from_1password
168
+
169
+ class Config(BaseConfig):
170
+ # Secrets non loggati/serializzati
171
+ api_key: SecretStr
172
+ private_key: SecretBytes
173
+
174
+ # Caricamento da secret manager
175
+ class Meta:
176
+ secret_sources = [
177
+ from_keyring("myapp"),
178
+ from_1password("myapp-vault")
179
+ ]
180
+
181
+ # I secrets sono automaticamente mascherati
182
+ print(config.api_key) # → SecretStr('**********')
183
+ print(config.api_key.get_secret_value()) # → valore reale
184
+ ```
185
+
186
+ ### 🔄 Dynamic Configuration
187
+
188
+ ```python
189
+ from pyw.config import WatchableConfig
190
+ import asyncio
191
+
192
+ class AppConfig(WatchableConfig):
193
+ feature_flags: dict[str, bool] = Field(default_factory=dict)
194
+ rate_limit: int = 100
195
+
196
+ # Reload automatico su cambio file
197
+ config = AppConfig.from_file("config.yaml", watch=True)
198
+
199
+ @config.on_change
200
+ async def config_changed(old_config, new_config):
201
+ if old_config.rate_limit != new_config.rate_limit:
202
+ await update_rate_limiter(new_config.rate_limit)
203
+
204
+ # Avvia watching
205
+ await config.start_watching()
206
+ ```
207
+
208
+ ### 📊 Configuration Validation
209
+
210
+ ```python
211
+ from pyw.config import validator, root_validator
212
+ from typing import Optional
213
+
214
+ class DatabaseConfig(BaseConfig):
215
+ host: str
216
+ port: int = Field(ge=1, le=65535)
217
+ replica_hosts: Optional[list[str]] = None
218
+
219
+ @validator('host')
220
+ def validate_host(cls, v):
221
+ if not v or v == 'localhost':
222
+ return v
223
+ # Valida formato hostname/IP
224
+ import socket
225
+ try:
226
+ socket.gethostbyname(v)
227
+ return v
228
+ except socket.gaierror:
229
+ raise ValueError(f"Invalid hostname: {v}")
230
+
231
+ @root_validator
232
+ def validate_replicas(cls, values):
233
+ if values.get('replica_hosts'):
234
+ main_host = values.get('host')
235
+ if main_host in values['replica_hosts']:
236
+ raise ValueError("Main host cannot be in replica list")
237
+ return values
238
+ ```
239
+
240
+ ### 🧪 Testing Support
241
+
242
+ ```python
243
+ from pyw.config.testing import temporary_config, mock_env
244
+
245
+ class TestApp:
246
+ def test_with_temp_config(self):
247
+ with temporary_config(AppConfig, {"debug": True}):
248
+ config = AppConfig.load()
249
+ assert config.debug is True
250
+
251
+ def test_with_mock_env(self):
252
+ with mock_env(MYAPP_DEBUG="false"):
253
+ config = AppConfig.from_env(prefix="MYAPP_")
254
+ assert config.debug is False
255
+ ```
256
+
257
+ ## Advanced Usage
258
+
259
+ ### Custom Configuration Sources
260
+
261
+ ```python
262
+ from pyw.config.sources import ConfigSource
263
+ import redis
264
+
265
+ class RedisConfigSource(ConfigSource):
266
+ def __init__(self, redis_client, key_prefix="config:"):
267
+ self.redis = redis_client
268
+ self.prefix = key_prefix
269
+
270
+ def load(self) -> dict:
271
+ keys = self.redis.keys(f"{self.prefix}*")
272
+ config = {}
273
+ for key in keys:
274
+ config_key = key.decode().replace(self.prefix, "")
275
+ config[config_key] = self.redis.get(key).decode()
276
+ return config
277
+
278
+ # Utilizzo
279
+ redis_client = redis.Redis()
280
+ config = AppConfig.from_sources(
281
+ RedisConfigSource(redis_client),
282
+ from_env(prefix="MYAPP_")
283
+ )
284
+ ```
285
+
286
+ ### Configuration Schemas
287
+
288
+ ```python
289
+ from pyw.config import ConfigSchema, generate_schema
290
+
291
+ # Genera JSON Schema
292
+ schema = generate_schema(AppConfig)
293
+ print(schema)
294
+
295
+ # Genera esempio di configurazione
296
+ example = AppConfig.generate_example()
297
+ with open("config.example.yaml", "w") as f:
298
+ yaml.dump(example, f)
299
+
300
+ # Validazione esterna
301
+ from pyw.config.validation import validate_file
302
+
303
+ errors = validate_file("config.yaml", AppConfig)
304
+ if errors:
305
+ for error in errors:
306
+ print(f"❌ {error.location}: {error.message}")
307
+ ```
308
+
309
+ ### Configuration Migrations
310
+
311
+ ```python
312
+ from pyw.config.migrations import ConfigMigration
313
+
314
+ class Migration001(ConfigMigration):
315
+ """Rename db_host to database.host"""
316
+ version = "0.0.1"
317
+
318
+ def migrate(self, config: dict) -> dict:
319
+ if "db_host" in config:
320
+ config.setdefault("database", {})
321
+ config["database"]["host"] = config.pop("db_host")
322
+ return config
323
+
324
+ # Auto-apply migrations
325
+ config = AppConfig.from_file("old-config.yaml",
326
+ migrations=[Migration001()])
327
+ ```
328
+
329
+ ## Integration Examples
330
+
331
+ ### FastAPI Integration
332
+
333
+ ```python
334
+ from fastapi import FastAPI, Depends
335
+ from pyw.config import inject_config
336
+
337
+ app = FastAPI()
338
+
339
+ @app.get("/status")
340
+ def get_status(config: AppConfig = Depends(inject_config(AppConfig))):
341
+ return {
342
+ "debug": config.debug,
343
+ "database_host": config.db.host
344
+ }
345
+ ```
346
+
347
+ ### Django Integration
348
+
349
+ ```python
350
+ # settings.py
351
+ from pyw.config import django_settings
352
+
353
+ class DjangoConfig(BaseConfig):
354
+ SECRET_KEY: str
355
+ DEBUG: bool = False
356
+ DATABASES: dict
357
+ ALLOWED_HOSTS: list[str] = Field(default_factory=list)
358
+
359
+ # Auto-populate Django settings
360
+ config = DjangoConfig.from_sources(
361
+ from_file("django.yaml"),
362
+ from_env(prefix="DJANGO_")
363
+ )
364
+
365
+ globals().update(django_settings(config))
366
+ ```
367
+
368
+ ## CLI Integration
369
+
370
+ ```bash
371
+ # Valida configurazione
372
+ pyw-config validate config.yaml --schema=myapp.config:AppConfig
373
+
374
+ # Genera esempio
375
+ pyw-config generate-example myapp.config:AppConfig > config.example.yaml
376
+
377
+ # Merge configurazioni
378
+ pyw-config merge base.yaml override.yaml > final.yaml
379
+
380
+ # Mostra configurazione risolta (con secrets mascherati)
381
+ pyw-config show --env=production
382
+ ```
383
+
384
+ ## Roadmap
385
+
386
+ - 🔐 **Enhanced secrets**: Integrazione con AWS Secrets Manager, Azure Key Vault
387
+ - 🌐 **Remote configs**: Etcd, Consul, Kubernetes ConfigMaps
388
+ - 📝 **Configuration UI**: Web interface per editing configurazioni
389
+ - 🔄 **Hot reload**: Reload automatico in runtime senza restart
390
+ - 📊 **Config analytics**: Metriche di utilizzo e drift detection
391
+ - 🧩 **Plugin system**: Custom validators e sources
392
+
393
+ ## Contributing
394
+
395
+ 1. Fork il repo: `git clone https://github.com/pythonWoods/pyw-config.git`
396
+ 2. Crea virtual-env: `poetry install && poetry shell`
397
+ 3. Lancia tests: `pytest`
398
+ 4. Lancia linter: `ruff check . && mypy`
399
+ 5. Apri la PR: CI esegue tutti i check
400
+
401
+ Felice configurazione nella foresta di **pythonWoods**! 🌲⚙️
402
+
403
+ ## Links utili
404
+
405
+ Documentazione dev (work-in-progress) → https://pythonwoods.dev/docs/pyw-config/latest/
406
+
407
+ Issue tracker → https://github.com/pythonWoods/pyw-config/issues
408
+
409
+ Changelog → https://github.com/pythonWoods/pyw-config/releases
410
+
411
+ © pythonWoods — MIT License
@@ -0,0 +1,6 @@
1
+ pyw/__init__.py,sha256=yHu7XfvDr1YKArhukYnKx9Eb5EGNv_P-89S4fJn2F1g,87
2
+ pyw/config/__init__.py,sha256=nZ8syR0SThxKmV0Mmd-mf9p_qYtrmrlywY5sNt0959I,14
3
+ pyw_config-0.0.0.post2.dist-info/METADATA,sha256=05bjL2Ls3duT-22EWAlWVtAHERMj508uj4r9HytWoAo,11086
4
+ pyw_config-0.0.0.post2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
5
+ pyw_config-0.0.0.post2.dist-info/licenses/LICENSE,sha256=Jn96Lhnfqd-Zr3dFIJhaDlIZJSk-pbfnZ6sGlp0Gv5E,12
6
+ pyw_config-0.0.0.post2.dist-info/RECORD,,
@@ -1,34 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: pyw-config
3
- Version: 0.0.0.post1
4
- Summary: Reserved placeholder for pyw-config (configuration utilities for pythonWoods suite)
5
- Project-URL: Homepage, https://github.com/pythonWoods/pyw-config
6
- Project-URL: Documentation, https://pythonwoods.dev/docs/pyw-config/latest/
7
- Project-URL: Issues, https://github.com/pythonWoods/pyw-config/issues
8
- Project-URL: Changelog, https://github.com/pythonWoods/pyw-config/releases
9
- Author-email: pythonWoods <you@example.com>
10
- License: MIT
11
- License-File: LICENSE
12
- Classifier: Development Status :: 2 - Pre-Alpha
13
- Classifier: License :: OSI Approved :: MIT License
14
- Classifier: Programming Language :: Python :: 3 :: Only
15
- Classifier: Programming Language :: Python :: 3.11
16
- Classifier: Typing :: Typed
17
- Requires-Python: >=3.9
18
- Requires-Dist: pyw-core>=0.0.0
19
- Description-Content-Type: text/markdown
20
-
21
- # pyw-config
22
- [![PyPI](https://img.shields.io/pypi/v/pyw-config.svg)](https://pypi.org/project/pyw-config/)
23
- [![CI](https://github.com/pythonWoods/pyw-config/actions/workflows/ci.yml/badge.svg)](https://github.com/pythonWoods/pyw-config/actions/workflows/ci.yml)
24
- [![License](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
25
-
26
-
27
- ## Links utili
28
- Documentazione dev (work-in-progress) → https://pythonwoods.dev/docs/pyw-config/latest/
29
-
30
- Issue tracker → https://github.com/pythonWoods/pyw-config/issues
31
-
32
- Changelog → https://github.com/pythonWoods/pyw-config/releases
33
-
34
- © pythonWoods — MIT License
@@ -1,6 +0,0 @@
1
- pyw/__init__.py,sha256=yHu7XfvDr1YKArhukYnKx9Eb5EGNv_P-89S4fJn2F1g,87
2
- pyw/config/__init__.py,sha256=nZ8syR0SThxKmV0Mmd-mf9p_qYtrmrlywY5sNt0959I,14
3
- pyw_config-0.0.0.post1.dist-info/METADATA,sha256=zxehOjS_vDryKZ8TANMs6oAi9HHYnKTjetPT6iv7eng,1455
4
- pyw_config-0.0.0.post1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
5
- pyw_config-0.0.0.post1.dist-info/licenses/LICENSE,sha256=Jn96Lhnfqd-Zr3dFIJhaDlIZJSk-pbfnZ6sGlp0Gv5E,12
6
- pyw_config-0.0.0.post1.dist-info/RECORD,,