/
devsec
/
anothertap
Обзор
Документация
Войти
/
devsec
/
anothertap
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/services/config_manager.py
289 строк
11 KB
devsec
init project
23 авг 2025, 21:01
23 авг 2025, 21:01
5b0e5af
Код
Авторство
О чём код?
""" Application Configuration and Settings Management """ import json import os import logging from pathlib import Path from typing import Dict, Any, Optional from dataclasses import dataclass, field @dataclass class AppConfig: """Application configuration class""" # UI Settings window_geometry: Dict[str, int] = field(default_factory=lambda: { "x": 100, "y": 100, "width": 1400, "height": 900 }) window_maximized: bool = False splitter_sizes: Dict[str, list] = field(default_factory=dict) # Application Settings auto_save_interval: int = 300 # seconds max_log_lines: int = 1000 default_timeout: float = 5.0 default_data_directory: str = "data" # Device Settings auto_connect_devices: bool = False device_discovery_timeout: float = 10.0 visa_library_path: str = "" # Test Plan Settings stop_on_first_failure: bool = True auto_save_test_plans: bool = True default_step_timeout: float = 5.0 # Logging Settings log_level: str = "INFO" log_to_file: bool = True log_directory: str = "logs" # Recent Files recent_test_plans: list = field(default_factory=list) recent_device_configs: list = field(default_factory=list) max_recent_files: int = 10 class ConfigManager: """Manager for application configuration and settings""" def __init__(self, config_file: str = "config.json"): self.logger = logging.getLogger(__name__) self.config_file = Path(config_file) self.config = AppConfig() # Load existing configuration self.load_config() def load_config(self) -> bool: """Load configuration from file""" try: if self.config_file.exists(): with open(self.config_file, 'r', encoding='utf-8') as f: data = json.load(f) # Update config object with loaded data for key, value in data.items(): if hasattr(self.config, key): setattr(self.config, key, value) self.logger.info(f"Configuration loaded from {self.config_file}") return True else: self.logger.info("No configuration file found, using defaults") return False except Exception as e: self.logger.error(f"Failed to load configuration: {e}") return False def save_config(self) -> bool: """Save configuration to file""" try: config_dict = { "window_geometry": self.config.window_geometry, "window_maximized": self.config.window_maximized, "splitter_sizes": self.config.splitter_sizes, "auto_save_interval": self.config.auto_save_interval, "max_log_lines": self.config.max_log_lines, "default_timeout": self.config.default_timeout, "default_data_directory": self.config.default_data_directory, "auto_connect_devices": self.config.auto_connect_devices, "device_discovery_timeout": self.config.device_discovery_timeout, "visa_library_path": self.config.visa_library_path, "stop_on_first_failure": self.config.stop_on_first_failure, "auto_save_test_plans": self.config.auto_save_test_plans, "default_step_timeout": self.config.default_step_timeout, "log_level": self.config.log_level, "log_to_file": self.config.log_to_file, "log_directory": self.config.log_directory, "recent_test_plans": self.config.recent_test_plans, "recent_device_configs": self.config.recent_device_configs, "max_recent_files": self.config.max_recent_files } with open(self.config_file, 'w', encoding='utf-8') as f: json.dump(config_dict, f, indent=2, ensure_ascii=False) self.logger.debug(f"Configuration saved to {self.config_file}") return True except Exception as e: self.logger.error(f"Failed to save configuration: {e}") return False def get_setting(self, key: str, default: Any = None) -> Any: """Get a configuration setting""" return getattr(self.config, key, default) def set_setting(self, key: str, value: Any) -> bool: """Set a configuration setting""" try: if hasattr(self.config, key): setattr(self.config, key, value) return True else: self.logger.warning(f"Unknown configuration key: {key}") return False except Exception as e: self.logger.error(f"Failed to set configuration: {e}") return False def add_recent_file(self, file_path: str, file_type: str = "test_plan") -> None: """Add a file to recent files list""" if file_type == "test_plan": recent_list = self.config.recent_test_plans elif file_type == "device_config": recent_list = self.config.recent_device_configs else: self.logger.warning(f"Unknown file type: {file_type}") return # Remove if already exists if file_path in recent_list: recent_list.remove(file_path) # Add to beginning recent_list.insert(0, file_path) # Limit list size if len(recent_list) > self.config.max_recent_files: recent_list[:] = recent_list[:self.config.max_recent_files] def get_recent_files(self, file_type: str = "test_plan") -> list: """Get list of recent files""" if file_type == "test_plan": return self.config.recent_test_plans.copy() elif file_type == "device_config": return self.config.recent_device_configs.copy() else: return [] def clear_recent_files(self, file_type: str = "test_plan") -> None: """Clear recent files list""" if file_type == "test_plan": self.config.recent_test_plans.clear() elif file_type == "device_config": self.config.recent_device_configs.clear() def reset_to_defaults(self) -> None: """Reset configuration to default values""" self.config = AppConfig() self.logger.info("Configuration reset to defaults") def apply_environment_overrides(self) -> None: """Apply configuration overrides from environment variables""" # Log level override log_level = os.environ.get("LOG_LEVEL") if log_level: self.config.log_level = log_level.upper() # VISA library override visa_library = os.environ.get("VISA_LIBRARY") if visa_library: self.config.visa_library_path = visa_library # Data directory override data_dir = os.environ.get("TAP_DATA_DIR") if data_dir: self.config.default_data_directory = data_dir self.logger.debug("Applied environment variable overrides") def ensure_directories(self) -> None: """Ensure required directories exist""" directories = [ self.config.default_data_directory, self.config.log_directory ] for directory in directories: Path(directory).mkdir(exist_ok=True) self.logger.debug(f"Ensured directory exists: {directory}") def get_window_settings(self) -> Dict[str, Any]: """Get window-related settings""" return { "geometry": self.config.window_geometry, "maximized": self.config.window_maximized, "splitter_sizes": self.config.splitter_sizes } def save_window_settings(self, geometry: Dict[str, int], maximized: bool, splitter_sizes: Dict[str, list] = None) -> None: """Save window settings""" self.config.window_geometry = geometry self.config.window_maximized = maximized if splitter_sizes: self.config.splitter_sizes.update(splitter_sizes) self.save_config() def get_device_settings(self) -> Dict[str, Any]: """Get device-related settings""" return { "auto_connect": self.config.auto_connect_devices, "discovery_timeout": self.config.device_discovery_timeout, "visa_library_path": self.config.visa_library_path, "default_timeout": self.config.default_timeout } def get_test_plan_settings(self) -> Dict[str, Any]: """Get test plan-related settings""" return { "stop_on_first_failure": self.config.stop_on_first_failure, "auto_save": self.config.auto_save_test_plans, "default_step_timeout": self.config.default_step_timeout } def export_config(self, file_path: str) -> bool: """Export configuration to a file""" try: config_dict = { "window_geometry": self.config.window_geometry, "window_maximized": self.config.window_maximized, "auto_save_interval": self.config.auto_save_interval, "max_log_lines": self.config.max_log_lines, "default_timeout": self.config.default_timeout, "auto_connect_devices": self.config.auto_connect_devices, "device_discovery_timeout": self.config.device_discovery_timeout, "stop_on_first_failure": self.config.stop_on_first_failure, "auto_save_test_plans": self.config.auto_save_test_plans, "default_step_timeout": self.config.default_step_timeout, "log_level": self.config.log_level, "log_to_file": self.config.log_to_file } with open(file_path, 'w', encoding='utf-8') as f: json.dump(config_dict, f, indent=2, ensure_ascii=False) self.logger.info(f"Configuration exported to {file_path}") return True except Exception as e: self.logger.error(f"Failed to export configuration: {e}") return False def import_config(self, file_path: str) -> bool: """Import configuration from a file""" try: with open(file_path, 'r', encoding='utf-8') as f: data = json.load(f) # Update config object with imported data for key, value in data.items(): if hasattr(self.config, key): setattr(self.config, key, value) self.save_config() self.logger.info(f"Configuration imported from {file_path}") return True except Exception as e: self.logger.error(f"Failed to import configuration: {e}") return False