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