Source code for src.config.settings

"""
Configuration settings for the Wordle solver application.
"""

import os
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Dict, Optional

import yaml

from ..modules.backend.solver.constants import (
    DEFAULT_BACKUP_COUNT,
    DEFAULT_ENCODING,
    DEFAULT_MAX_ATTEMPTS,
    DEFAULT_SUGGESTIONS_COUNT,
    DEFAULT_WORD_LENGTH,
)

# Environment variable name
WORDLE_ENV_VAR = "WORDLE_ENVIRONMENT"


[docs] @dataclass class GameSettings: """Settings for the Wordle game.""" max_attempts: int = DEFAULT_MAX_ATTEMPTS word_length: int = DEFAULT_WORD_LENGTH
[docs] @dataclass class LoggingSettings: """Settings for logging configuration.""" level: str = "INFO" format: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" file_handler: bool = True console_handler: bool = True backup_count: int = DEFAULT_BACKUP_COUNT
[docs] @dataclass class SolverSettings: """Settings for the solver strategies.""" default_strategy: str = "entropy" suggestions_count: int = DEFAULT_SUGGESTIONS_COUNT enable_memory_optimization: bool = True enable_performance_profiling: bool = False
[docs] @dataclass class AppSettings: """Main application settings.""" game: GameSettings logging: LoggingSettings solver: SolverSettings
[docs] def __init__( self, game: Optional[GameSettings] = None, logging: Optional[LoggingSettings] = None, solver: Optional[SolverSettings] = None, ): self.game = game or GameSettings() self.logging = logging or LoggingSettings() self.solver = solver or SolverSettings()
[docs] @classmethod def load_from_file(cls, config_path: Path) -> "AppSettings": """Load settings from a YAML configuration file.""" try: with open(config_path, encoding=DEFAULT_ENCODING) as f: data = yaml.safe_load(f) # Create settings instances from loaded data game_data = data.get("game", {}) logging_data = data.get("logging", {}) solver_data = data.get("solver", {}) game_settings = GameSettings(**game_data) logging_settings = LoggingSettings(**logging_data) solver_settings = SolverSettings(**solver_data) return cls( game=game_settings, logging=logging_settings, solver=solver_settings ) except FileNotFoundError: # Return default settings if file doesn't exist return cls() except (yaml.YAMLError, TypeError) as e: # Log error and return default settings print(f"Error loading configuration: {e}") return cls()
[docs] def to_dict(self) -> Dict[str, Any]: """Convert settings to dictionary format.""" return { "game": { "max_attempts": self.game.max_attempts, "word_length": self.game.word_length, }, "logging": { "level": self.logging.level, "format": self.logging.format, "file_handler": self.logging.file_handler, "console_handler": self.logging.console_handler, "backup_count": self.logging.backup_count, }, "solver": { "default_strategy": self.solver.default_strategy, "suggestions_count": self.solver.suggestions_count, "enable_memory_optimization": self.solver.enable_memory_optimization, "enable_performance_profiling": self.solver.enable_performance_profiling, }, }
[docs] def get_environment() -> str: """ Get the current environment setting from the WORDLE_ENVIRONMENT variable. If not set or empty, defaults to 'PROD'. Valid values are 'DEV' and 'PROD'. Returns: str: The current environment ('DEV' or 'PROD') """ env = os.environ.get(WORDLE_ENV_VAR, "") if not env or env not in ["DEV", "PROD"]: return "PROD" return env
# Global settings instance _app_settings: Optional[AppSettings] = None
[docs] def get_settings() -> AppSettings: """Get the global application settings instance.""" global _app_settings if _app_settings is None: # Try to load from config file in the project root config_path = Path(__file__).parent.parent.parent / "config.yaml" _app_settings = AppSettings.load_from_file(config_path) return _app_settings
[docs] def initialize_config(config_path: Optional[str] = None) -> AppSettings: """Initialize configuration from file or use defaults. Args: config_path: Optional path to configuration file Returns: AppSettings instance """ # Check environment variable for configuration environment = get_environment() # Allow different config paths based on environment if not config_path: # Use default config path default_config_path = Path(__file__).parent.parent.parent / "config.yaml" # Check for environment-specific config file env_config_path = ( Path(__file__).parent.parent.parent / f"config.{environment.lower()}.yaml" ) if env_config_path.exists(): default_config_path = env_config_path return AppSettings.load_from_file(default_config_path) else: return AppSettings.load_from_file(Path(config_path))
[docs] def reset_settings() -> None: """Reset the global settings instance (useful for testing).""" global _app_settings _app_settings = None