Coverage for src/pytribeam/GUI/common/config_manager.py: 0%
52 statements
« prev ^ index » next coverage.py v7.6.1, created at 2026-06-16 18:30 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2026-06-16 18:30 +0000
1"""Application configuration management.
3This module provides centralized management of application-wide settings
4and ensures necessary directories exist.
5"""
7import os
8from dataclasses import dataclass, field
9from pathlib import Path
10from typing import Optional, List
13@dataclass
14class AppConfig:
15 """Application-wide configuration settings.
17 This dataclass holds all application-level configuration that persists
18 across sessions and is not specific to individual experiments.
20 Attributes:
21 data_dir: Directory for application data
22 log_dir: Directory for log files
23 default_theme: Default UI theme ('dark' or 'light')
24 auto_save_interval: Seconds between auto-saves (0 to disable)
25 recent_configs: List of recently opened config files
26 max_recent_files: Maximum number of recent files to track
27 """
29 data_dir: Path
30 log_dir: Path
31 default_theme: str = "dark"
32 auto_save_interval: int = 300 # seconds
33 recent_configs: List[str] = field(default_factory=list)
34 max_recent_files: int = 10
36 @classmethod
37 def from_env(cls, app_name: str = "pytribeam") -> "AppConfig":
38 """Create configuration from environment variables.
40 Uses LOCALAPPDATA on Windows or ~/.local/share on Unix-like systems.
42 Args:
43 app_name: Application name for directory structure
45 Returns:
46 AppConfig instance with paths set from environment
47 """
48 if os.name == "nt":
49 # Windows
50 base_dir = Path(os.getenv("LOCALAPPDATA", os.path.expanduser("~")))
51 else:
52 # Unix-like
53 base_dir = Path(
54 os.getenv("XDG_DATA_HOME", os.path.expanduser("~/.local/share"))
55 )
57 app_dir = base_dir / app_name
59 return cls(
60 data_dir=app_dir / "data",
61 log_dir=app_dir / "logs",
62 )
64 @classmethod
65 def from_file(cls, config_file: Path) -> "AppConfig":
66 """Load configuration from JSON file.
68 Args:
69 config_file: Path to configuration JSON file
71 Returns:
72 AppConfig instance loaded from file
74 Raises:
75 FileNotFoundError: If config file doesn't exist
76 ValueError: If config file is invalid
77 """
78 import json
80 if not config_file.exists():
81 raise FileNotFoundError(f"Config file not found: {config_file}")
83 with open(config_file, "r") as f:
84 data = json.load(f)
86 return cls(
87 data_dir=Path(data["data_dir"]),
88 log_dir=Path(data["log_dir"]),
89 default_theme=data.get("default_theme", "dark"),
90 auto_save_interval=data.get("auto_save_interval", 300),
91 recent_configs=data.get("recent_configs", []),
92 max_recent_files=data.get("max_recent_files", 10),
93 )
95 def save_to_file(self, config_file: Path):
96 """Save configuration to JSON file.
98 Args:
99 config_file: Path where config should be saved
100 """
101 import json
103 config_file.parent.mkdir(parents=True, exist_ok=True)
105 data = {
106 "data_dir": str(self.data_dir),
107 "log_dir": str(self.log_dir),
108 "default_theme": self.default_theme,
109 "auto_save_interval": self.auto_save_interval,
110 "recent_configs": self.recent_configs,
111 "max_recent_files": self.max_recent_files,
112 }
114 with open(config_file, "w") as f:
115 json.dump(data, f, indent=2)
117 def ensure_directories(self):
118 """Create necessary directories if they don't exist.
120 This should be called during application startup to ensure
121 all required directories are present.
122 """
123 self.data_dir.mkdir(parents=True, exist_ok=True)
124 self.log_dir.mkdir(parents=True, exist_ok=True)
126 def add_recent_config(self, config_path: Path):
127 """Add configuration file to recent files list.
129 Args:
130 config_path: Path to configuration file to add
131 """
132 config_str = str(config_path.absolute())
134 # Remove if already in list
135 if config_str in self.recent_configs:
136 self.recent_configs.remove(config_str)
138 # Add to front of list
139 self.recent_configs.insert(0, config_str)
141 # Trim to max length
142 self.recent_configs = self.recent_configs[: self.max_recent_files]
144 def get_recent_configs(self) -> List[Path]:
145 """Get list of recent configuration files that still exist.
147 Returns:
148 List of Path objects for existing recent configs
149 """
150 return [Path(p) for p in self.recent_configs if Path(p).exists()]
152 def get_terminal_log_path(self) -> Path:
153 """Get path for new terminal log file.
155 Returns:
156 Path for terminal log file with timestamp
157 """
158 import time
160 timestamp = time.strftime("%Y%m%d-%H%M%S")
161 return self.log_dir / f"{timestamp}_terminal.txt"
163 def get_error_log_path(self) -> Path:
164 """Get path for new error traceback file.
166 Returns:
167 Path for error log file with timestamp
168 """
169 import time
171 timestamp = time.strftime("%Y%m%d-%H%M%S")
172 return self.log_dir / f"{timestamp}_error_traceback.txt"