Source code for confii.config_builder

"""Configuration builder pattern for Confii.

This module provides a fluent builder interface for creating Config instances,
making it easier to configure complex setup scenarios with better readability.
"""

from typing import TYPE_CHECKING, Any, List, Optional

if TYPE_CHECKING:
    from confii.config import Config
    from confii.loaders.loader import Loader
    from confii.secret_stores.resolver import SecretResolver


[docs] class ConfigBuilder: """Fluent builder for creating Config instances. This class provides a builder pattern for constructing Config instances with better readability and easier configuration management. Example: >>> builder = ConfigBuilder() >>> config = builder \ ... .with_env("production") \ ... .add_loader(YamlLoader("base.yaml")) \ ... .add_loader(YamlLoader("production.yaml")) \ ... .with_secrets(secret_resolver) \ ... .enable_debug() \ ... .enable_dynamic_reloading() \ ... .build() """
[docs] def __init__(self) -> None: """Initialize a new ConfigBuilder with default values.""" self._env: Optional[str] = None self._loaders: List[Loader] = [] self._dynamic_reloading: Optional[bool] = None self._use_env_expander: bool = True self._use_type_casting: bool = True self._enable_ide_support: bool = True self._ide_stub_path: Optional[str] = None self._debug_mode: bool = False self._deep_merge: bool = True self._secret_resolver: Optional[SecretResolver] = None self._schema: Optional[Any] = None self._validate_on_load: bool = False self._strict_validation: bool = False
[docs] def with_env(self, env: str) -> "ConfigBuilder": """Set the environment name. Args: env: Environment name (e.g., 'development', 'production', 'staging') Returns: Self for method chaining Example: >>> builder.with_env("production") """ self._env = env return self
[docs] def add_loader(self, loader: "Loader") -> "ConfigBuilder": """Add a configuration loader. Args: loader: Configuration loader instance to add (e.g., YamlLoader, JsonLoader) Returns: Self for method chaining Example: >>> builder.add_loader(YamlLoader("config.yaml")) """ self._loaders.append(loader) return self
[docs] def add_loaders(self, loaders: List["Loader"]) -> "ConfigBuilder": """Add multiple configuration loaders at once. Args: loaders: List of Loader instances to add Returns: Self for method chaining Example: >>> builder.add_loaders( ... [ ... YamlLoader("base.yaml"), ... JsonLoader("overrides.json"), ... ] ... ) """ self._loaders.extend(loaders) return self
[docs] def with_secrets(self, secret_resolver: "SecretResolver") -> "ConfigBuilder": """Configure secret resolver for secret store integration. Args: secret_resolver: SecretResolver instance for resolving secrets Returns: Self for method chaining Example: >>> from confii.secret_stores import AWSSecretsManager, SecretResolver >>> store = AWSSecretsManager(region_name="us-east-1") >>> builder.with_secrets(SecretResolver(store)) """ self._secret_resolver = secret_resolver return self
[docs] def enable_dynamic_reloading(self) -> "ConfigBuilder": """Enable dynamic configuration reloading (file watching). Returns: Self for method chaining Example: >>> builder.enable_dynamic_reloading() """ self._dynamic_reloading = True return self
[docs] def disable_dynamic_reloading(self) -> "ConfigBuilder": """Disable dynamic configuration reloading. Returns: Self for method chaining Example: >>> builder.disable_dynamic_reloading() """ self._dynamic_reloading = False return self
[docs] def enable_env_expander(self) -> "ConfigBuilder": """Enable environment variable expansion in config values. Returns: Self for method chaining Example: >>> builder.enable_env_expander() """ self._use_env_expander = True return self
[docs] def disable_env_expander(self) -> "ConfigBuilder": """Disable environment variable expansion. Returns: Self for method chaining Example: >>> builder.disable_env_expander() """ self._use_env_expander = False return self
[docs] def enable_type_casting(self) -> "ConfigBuilder": """Enable automatic type casting of config values. Returns: Self for method chaining Example: >>> builder.enable_type_casting() """ self._use_type_casting = True return self
[docs] def disable_type_casting(self) -> "ConfigBuilder": """Disable automatic type casting. Returns: Self for method chaining Example: >>> builder.disable_type_casting() """ self._use_type_casting = False return self
[docs] def enable_ide_support(self, stub_path: Optional[str] = None) -> "ConfigBuilder": """Enable IDE support (type stub generation). Args: stub_path: Optional custom path for IDE stub file Returns: Self for method chaining Example: >>> builder.enable_ide_support(".confii/stubs.pyi") """ self._enable_ide_support = True self._ide_stub_path = stub_path return self
[docs] def disable_ide_support(self) -> "ConfigBuilder": """Disable IDE support generation. Returns: Self for method chaining Example: >>> builder.disable_ide_support() """ self._enable_ide_support = False return self
[docs] def enable_debug(self) -> "ConfigBuilder": """Enable debug mode (detailed source tracking). Returns: Self for method chaining Example: >>> builder.enable_debug() """ self._debug_mode = True return self
[docs] def disable_debug(self) -> "ConfigBuilder": """Disable debug mode. Returns: Self for method chaining Example: >>> builder.disable_debug() """ self._debug_mode = False return self
[docs] def enable_deep_merge(self) -> "ConfigBuilder": """Enable deep merging of nested configurations. Returns: Self for method chaining Example: >>> builder.enable_deep_merge() """ self._deep_merge = True return self
[docs] def disable_deep_merge(self) -> "ConfigBuilder": """Disable deep merging (use shallow merge instead). Returns: Self for method chaining Example: >>> builder.disable_deep_merge() """ self._deep_merge = False return self
[docs] def with_schema( self, schema: Any, validate_on_load: bool = True, strict: bool = False ) -> "ConfigBuilder": """Configure schema validation for configuration. Args: schema: Pydantic model class or JSON Schema dictionary validate_on_load: If True, validate immediately after loading (default: True) strict: If True, raise ConfigValidationError on failure (default: False) Returns: Self for method chaining Example: >>> from pydantic import BaseModel >>> class AppConfig(BaseModel): ... database_url: str >>> builder.with_schema(AppConfig, validate_on_load=True) """ self._schema = schema self._validate_on_load = validate_on_load self._strict_validation = strict return self
[docs] def enable_validation(self, strict: bool = False) -> "ConfigBuilder": """Enable validation using the configured schema. Args: strict: If True, raise ConfigValidationError on failure (default: False) Returns: Self for method chaining Example: >>> builder.enable_validation(strict=True) """ self._validate_on_load = True self._strict_validation = strict return self
[docs] def disable_validation(self) -> "ConfigBuilder": """Disable validation on load. Returns: Self for method chaining Example: >>> builder.disable_validation() """ self._validate_on_load = False return self
[docs] def build(self) -> "Config": """Build and return the Config instance. Returns: Configured Config instance Raises: ConfiiError: If configuration is invalid Example: >>> config = builder.build() """ # Use None for loaders if empty (allows default loading) loaders = self._loaders if self._loaders else None from confii.config import Config # Import here to avoid circular import return Config( env=self._env, loaders=loaders, dynamic_reloading=self._dynamic_reloading, use_env_expander=self._use_env_expander, use_type_casting=self._use_type_casting, enable_ide_support=self._enable_ide_support, ide_stub_path=self._ide_stub_path, debug_mode=self._debug_mode, deep_merge=self._deep_merge, secret_resolver=self._secret_resolver, schema=self._schema, validate_on_load=self._validate_on_load, strict_validation=self._strict_validation, )
[docs] @classmethod def create(cls) -> "ConfigBuilder": """Create a new ConfigBuilder instance. This is a convenience method for creating a builder. You can also use `ConfigBuilder()` directly. Returns: New ConfigBuilder instance Example: >>> builder = ConfigBuilder.create() """ return cls()
# Convenience function for creating builders
[docs] def builder() -> ConfigBuilder: """Create a new ConfigBuilder instance. This is a convenience function for creating a builder with a shorter syntax: `builder().with_env("prod").build()` Returns: New ConfigBuilder instance Example: >>> from confii.config_builder import builder >>> config = builder().with_env("prod").build() """ return ConfigBuilder()