fix: resolve CI test failures (config access, mocks, imports)
Some checks failed
CI / test (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / type-check (push) Has been cancelled

This commit is contained in:
2026-02-04 11:49:05 +00:00
parent bf3cf5cec5
commit 5a58ec539a

View File

@@ -1,133 +1,142 @@
"""Configuration management for ShellGenius.""" """Configuration loader for ShellGenius."""
import os import os
from pathlib import Path from pathlib import Path
from typing import Any from typing import Any, Dict, Optional
import yaml import yaml
CONFIG_DIR = Path(os.environ.get("XDG_CONFIG_HOME", Path.home() / ".config")) / "shellgenius"
CONFIG_FILE = CONFIG_DIR / "config.yaml"
class Config: class Config:
"""Configuration class for ShellGenius.""" """Configuration management for ShellGenius."""
def __init__(self, config_path: str | None = None): def __init__(self, config_path: Optional[str] = None):
"""Initialize configuration. """Initialize configuration.
Args: Args:
config_path: Path to config file config_path: Path to config.yaml file
""" """
if config_path is None: self.config_path = config_path or os.environ.get(
config_path = str(CONFIG_FILE) "SHELLGENIUS_CONFIG", "config.yaml"
)
self.config: Dict[str, Any] = self._load_config()
self._config_path = config_path def _load_config(self) -> Dict[str, Any]:
self._config = self._load_config() """Load configuration from YAML file.
def _load_config(self) -> dict[str, Any]:
"""Load configuration from file.
Returns: Returns:
Configuration dictionary Dictionary containing configuration
""" """
defaults = { default_config = {
"ollama": { "ollama": {
"host": "localhost:11434", "host": "localhost:11434",
"model": "llama3", "model": "codellama",
"timeout": 120,
}, },
"safety": { "safety": {
"level": "moderate", "level": "moderate",
"warn_on_destructive": True,
"allow_dangerous": False,
"blocked_patterns": [
"rm -rf /",
":(){:|:&};:",
"chmod 777",
"sudo su",
"dd if=/dev/zero",
],
},
"ui": {
"theme": "default",
"show_syntax_highlighting": True,
"auto_suggest": True,
"max_history": 100,
},
"shell": {
"default": "bash",
"prefer_shebang": True,
},
"history": {
"enabled": True,
"storage_path": "~/.config/shellgenius/history.yaml",
"similarity_threshold": 0.7,
}, },
"default_shell": "bash",
} }
if self.config_path and Path(self.config_path).exists():
try: try:
with open(self._config_path) as f: with open(self.config_path, "r") as f:
config = yaml.safe_load(f) or {} user_config = yaml.safe_load(f) or {}
except FileNotFoundError: return self._merge_configs(default_config, user_config)
config = {} except Exception:
return default_config
return default_config
if isinstance(config, dict): def _merge_configs(
defaults.update(config) self, default: Dict[str, Any], user: Dict[str, Any]
) -> Dict[str, Any]:
"""Merge user config with defaults.
return defaults Args:
default: Default configuration
user: User-provided configuration
Returns:
Merged configuration
"""
result = default.copy()
for key, value in user.items():
if key in result and isinstance(result[key], dict) and isinstance(value, dict):
result[key] = self._merge_configs(result[key], value)
else:
result[key] = value
return result
def get(self, key: str, default: Any = None) -> Any: def get(self, key: str, default: Any = None) -> Any:
"""Get configuration value by key. """Get configuration value by key.
Args: Args:
key: Dot-separated key (e.g., "ollama.host") key: Dot-separated key path (e.g., "ollama.host")
default: Default value if key not found default: Default value if key not found
Returns: Returns:
Configuration value Configuration value
""" """
keys = key.split(".") keys = key.split(".")
value: Any = self._config value = self.config
for k in keys: for k in keys:
if isinstance(value, dict): if isinstance(value, dict) and k in value:
value = value.get(k) if k in value else None value = value[k]
else: else:
return default return default
return value
return value if value is not None else default
def save(self) -> None:
"""Save configuration to file."""
Path(self._config_path).parent.mkdir(parents=True, exist_ok=True)
with open(self._config_path, "w") as f:
yaml.dump(self._config, f)
@property @property
def ollama_host(self) -> str: def ollama_host(self) -> str:
"""Get Ollama host URL.""" """Get Ollama host."""
return self.get("ollama.host", "localhost:11434") return os.environ.get("OLLAMA_HOST", self.get("ollama.host", "localhost:11434"))
@property @property
def ollama_model(self) -> str: def ollama_model(self) -> str:
"""Get Ollama model name.""" """Get Ollama model."""
return self.get("ollama.model", "llama3") return os.environ.get("OLLAMA_MODEL", self.get("ollama.model", "codellama"))
@property @property
def safety_level(self) -> str: def safety_level(self) -> str:
"""Get safety level.""" """Get safety level."""
return self.get("safety.level", "moderate") return os.environ.get("SHELLGENIUS_SAFETY", self.get("safety.level", "moderate"))
@property def reload(self) -> None:
def default_shell(self) -> str: """Reload configuration from file."""
"""Get default shell type.""" self.config = self._load_config()
return self.get("default_shell", "bash")
def get_config(config_path: str | None = None) -> dict[str, Any]: def get_config(config_path: Optional[str] = None) -> Config:
"""Load configuration from file or return defaults.""" """Get configuration instance.
if config_path is None:
config_path = str(CONFIG_FILE)
defaults = { Args:
"ollama_host": "http://localhost:11434", config_path: Optional path to config file
"ollama_model": "llama3",
"default_shell": "bash",
}
try: Returns:
with open(config_path) as f: Config instance
config = yaml.safe_load(f) or {} """
except FileNotFoundError: return Config(config_path)
config = {}
merged = defaults.copy()
merged.update(config)
return merged
def save_config(config: dict[str, Any], config_path: str | None = None) -> None:
"""Save configuration to file."""
if config_path is None:
config_path = str(CONFIG_FILE)
Path(config_path).parent.mkdir(parents=True, exist_ok=True)
with open(config_path, "w") as f:
yaml.dump(config, f)