# trixy_core.config Konfigurationssystem mit Validierung, Environment-Substitution, Vererbung und Migration. ## Übersicht ```python from trixy_core.config import ( # Core ConfigManager, ServerConfig, ClientConfig, StandaloneConfig, TrainerConfig, # Environment EnvironmentSubstitutor, substitute_env, # Validation ConfigSchema, ConfigFieldSpec, validate_config, # Inheritance ConfigInheritance, deep_merge, # CLI CLIConfigMerger, CLIOption, # Secrets SecretsProvider, EncryptedSecretsProvider, EnvironmentSecretsProvider, FileSecretsProvider, # Migration ConfigMigration, ConfigMigrator, ) ``` --- ## ConfigManager Lädt und verwaltet Konfigurationen. ```python from trixy_core.config import ConfigManager # Manager erstellen manager = ConfigManager() # Konfiguration laden config = manager.load("config/server_config.json") # Mit Validierung config = manager.load( "config/server_config.json", schema=ServerConfigSchema, validate=True, ) # Als Dataclass server_config: ServerConfig = manager.load_as( "config/server_config.json", ServerConfig, ) # Werte abrufen port = config.get("server.port", default=2101) debug = config.get("debug", default=False) # Dateiüberwachung manager.watch("config/server_config.json", callback=on_config_changed) # Konfiguration speichern manager.save("config/server_config.json", config) ``` ### Auto-Reload ```python from trixy_core.config import ConfigManager manager = ConfigManager(auto_reload=True) @manager.on_change("config/server_config.json") def handle_config_change(old_config, new_config): print("Konfiguration geändert") apply_new_config(new_config) ``` --- ## Konfigurationsklassen ### ServerConfig ```python from trixy_core.config import ServerConfig @dataclass class ServerConfig: host: str = "0.0.0.0" port: int = 2101 debug: bool = False # Netzwerk command_port: int = 2101 audio_in_port: int = 2102 audio_out_port: int = 2103 music_port: int = 2104 # Sicherheit encryption_key: str = "" require_registration: bool = True registration_timeout: int = 60 # Audio sample_rate: int = 16000 channels: int = 1 chunk_size: int = 1024 # Plugins plugin_directory: str = "plugins" enabled_plugins: list[str] = field(default_factory=list) ``` ### ClientConfig ```python from trixy_core.config import ClientConfig @dataclass class ClientConfig: server_host: str = "" server_port: int = 2101 room_id: str = "" alias: str = "" # Wakeword wakeword_model: str = "default" wakeword_sensitivity: float = 0.5 # Audio audio_device: str = "default" sample_rate: int = 16000 ``` --- ## Environment-Substitution Ersetzt Umgebungsvariablen in Konfigurationen. ```python from trixy_core.config import EnvironmentSubstitutor, substitute_env # JSON-Konfiguration config = { "database": { "host": "${DB_HOST}", "port": "${DB_PORT:-5432}", "password": "${DB_PASSWORD}", }, "api_key": "${API_KEY:-default_key}", } # Substitution durchführen substitutor = EnvironmentSubstitutor() result = substitutor.substitute(config) # Oder einfach result = substitute_env(config) # Ergebnis (mit DB_HOST=localhost, DB_PASSWORD=secret) # { # "database": { # "host": "localhost", # "port": "5432", # Default verwendet # "password": "secret", # }, # "api_key": "default_key", # Default verwendet # } ``` ### Syntax | Pattern | Beschreibung | |---------|--------------| | `${VAR}` | Pflicht-Variable | | `${VAR:-default}` | Mit Default-Wert | | `${VAR:?error}` | Fehler wenn nicht gesetzt | --- ## Validierung Schema-basierte Konfigurationsvalidierung. ```python from trixy_core.config import ( ConfigSchema, ConfigFieldSpec, ConfigValueType, validate_config, ConfigValidationError, ) # Schema definieren schema = ConfigSchema( fields={ "host": ConfigFieldSpec( type=ConfigValueType.STRING, required=True, pattern=r"^[\w.-]+$", ), "port": ConfigFieldSpec( type=ConfigValueType.INTEGER, required=True, min_value=1, max_value=65535, ), "debug": ConfigFieldSpec( type=ConfigValueType.BOOLEAN, default=False, ), "plugins": ConfigFieldSpec( type=ConfigValueType.LIST, item_type=ConfigValueType.STRING, ), } ) # Validieren try: validated = validate_config(config, schema) except ConfigValidationError as e: for error in e.errors: print(f"{error.field}: {error.message}") ``` ### Schema aus Dataclass ```python from trixy_core.config import schema_from_dataclass @dataclass class MyConfig: name: str count: int = 10 enabled: bool = True schema = schema_from_dataclass(MyConfig) validated = validate_config(config, schema) ``` --- ## Konfigurationsvererbung Mehrschichtige Konfiguration mit Overrides. ```python from trixy_core.config import ConfigInheritance, deep_merge inheritance = ConfigInheritance() # Basis-Konfiguration inheritance.add_layer("base", { "logging": {"level": "INFO"}, "server": {"host": "localhost", "port": 8080}, }) # Environment-Override inheritance.add_layer("production", { "logging": {"level": "WARNING"}, "server": {"host": "0.0.0.0"}, }) # Lokale Overrides inheritance.add_layer("local", { "debug": True, }) # Zusammenführen config = inheritance.merge() # Ergebnis: # { # "logging": {"level": "WARNING"}, # "server": {"host": "0.0.0.0", "port": 8080}, # "debug": True, # } ``` ### Dateibasiert ```python from trixy_core.config import ConfigInheritance inheritance = ConfigInheritance() # Dateien in Reihenfolge laden inheritance.load_file("config/base.json") inheritance.load_file("config/production.json") inheritance.load_file("config/local.json", optional=True) config = inheritance.merge() ``` --- ## CLI-Integration Konfiguration aus Kommandozeilen-Argumenten. ```python from trixy_core.config import CLIConfigMerger, CLIOption merger = CLIConfigMerger() # Optionen definieren merger.add_option(CLIOption( name="--host", config_path="server.host", type=str, )) merger.add_option(CLIOption( name="--port", config_path="server.port", type=int, )) merger.add_option(CLIOption( name="--debug", config_path="debug", type=bool, flag=True, )) # Mit Datei-Konfiguration zusammenführen import argparse parser = argparse.ArgumentParser() args = parser.parse_args() config = merger.merge(file_config, args) ``` --- ## Secrets-Management Sichere Speicherung sensibler Daten. ### EncryptedSecretsProvider ```python from trixy_core.config.secrets import EncryptedSecretsProvider provider = EncryptedSecretsProvider( key_file="secrets.key", secrets_file="secrets.enc", ) # Secret setzen provider.set("database_password", "super_secret") provider.set("api_key", "key_12345") # Secret abrufen password = provider.get("database_password") # Als SecretValue (schützt vor versehentlichem Logging) secret = provider.get_secure("api_key") print(secret) # Gibt "***" aus print(secret.reveal()) # Gibt echten Wert aus ``` ### EnvironmentSecretsProvider ```python from trixy_core.config.secrets import EnvironmentSecretsProvider provider = EnvironmentSecretsProvider(prefix="TRIXY_") # Liest TRIXY_DATABASE_PASSWORD aus Umgebung password = provider.get("database_password") ``` ### FileSecretsProvider ```python from trixy_core.config.secrets import FileSecretsProvider provider = FileSecretsProvider( directory=Path("/run/secrets"), encoding="utf-8", ) # Liest /run/secrets/database_password password = provider.get("database_password") ``` --- ## Konfigurationsmigration Versionierte Migrationen zwischen Config-Versionen. ```python from trixy_core.config.versioning import ( ConfigMigration, ConfigMigrator, MigrationResult, ) # Migrationen definieren class MigrateV1ToV2(ConfigMigration): from_version = "1.0.0" to_version = "2.0.0" def migrate(self, config: dict) -> dict: # Port-Feld umbenannt if "port" in config: config["server_port"] = config.pop("port") # Neues Pflichtfeld config.setdefault("encryption_enabled", True) return config class MigrateV2ToV3(ConfigMigration): from_version = "2.0.0" to_version = "3.0.0" def migrate(self, config: dict) -> dict: # Strukturänderung config["server"] = { "port": config.pop("server_port"), "host": config.pop("host", "localhost"), } return config # Migrator erstellen migrator = ConfigMigrator() migrator.register(MigrateV1ToV2()) migrator.register(MigrateV2ToV3()) # Migration durchführen old_config = {"version": "1.0.0", "port": 8080} result = migrator.migrate(old_config, target_version="3.0.0") print(f"Migriert von {result.from_version} zu {result.to_version}") print(f"Neue Konfiguration: {result.config}") ``` ### Config-Diff ```python from trixy_core.config.versioning import diff_configs, DiffType old = {"a": 1, "b": {"c": 2}} new = {"a": 1, "b": {"c": 3, "d": 4}} diff = diff_configs(old, new) for entry in diff.entries: print(f"{entry.type.name}: {entry.path} = {entry.new_value}") # MODIFIED: b.c = 3 # ADDED: b.d = 4 ```