mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-05 01:50:27 +08:00
fix(config): add specific exception handling for path operations
Replaces generic Exception handling with specific PermissionError and OSError handling in __post_init__ and ensure_runtime_dirs(). Provides clear diagnostic messages to distinguish permission issues from other filesystem errors. Solution-ID: SOL-1735385400008 Issue-ID: ISS-1766921318981-8 Task-ID: T1
This commit is contained in:
@@ -122,8 +122,21 @@ class Config:
|
||||
self.data_dir = self.data_dir.expanduser().resolve()
|
||||
self.venv_path = self.venv_path.expanduser().resolve()
|
||||
self.data_dir.mkdir(parents=True, exist_ok=True)
|
||||
except PermissionError as exc:
|
||||
raise ConfigError(
|
||||
f"Permission denied initializing paths (data_dir={self.data_dir}, venv_path={self.venv_path}) "
|
||||
f"[{type(exc).__name__}]: {exc}"
|
||||
) from exc
|
||||
except OSError as exc:
|
||||
raise ConfigError(
|
||||
f"Filesystem error initializing paths (data_dir={self.data_dir}, venv_path={self.venv_path}) "
|
||||
f"[{type(exc).__name__}]: {exc}"
|
||||
) from exc
|
||||
except Exception as exc:
|
||||
raise ConfigError(f"Failed to initialize data_dir at {self.data_dir}: {exc}") from exc
|
||||
raise ConfigError(
|
||||
f"Unexpected error initializing paths (data_dir={self.data_dir}, venv_path={self.venv_path}) "
|
||||
f"[{type(exc).__name__}]: {exc}"
|
||||
) from exc
|
||||
|
||||
@cached_property
|
||||
def cache_dir(self) -> Path:
|
||||
@@ -145,8 +158,18 @@ class Config:
|
||||
for directory in (self.cache_dir, self.index_dir):
|
||||
try:
|
||||
directory.mkdir(parents=True, exist_ok=True)
|
||||
except PermissionError as exc:
|
||||
raise ConfigError(
|
||||
f"Permission denied creating directory {directory} [{type(exc).__name__}]: {exc}"
|
||||
) from exc
|
||||
except OSError as exc:
|
||||
raise ConfigError(
|
||||
f"Filesystem error creating directory {directory} [{type(exc).__name__}]: {exc}"
|
||||
) from exc
|
||||
except Exception as exc:
|
||||
raise ConfigError(f"Failed to create directory {directory}: {exc}") from exc
|
||||
raise ConfigError(
|
||||
f"Unexpected error creating directory {directory} [{type(exc).__name__}]: {exc}"
|
||||
) from exc
|
||||
|
||||
def language_for_path(self, path: str | Path) -> str | None:
|
||||
"""Infer a supported language ID from a file path."""
|
||||
|
||||
@@ -118,6 +118,57 @@ class TestConfig:
|
||||
config = Config(data_dir=data_dir)
|
||||
assert data_dir.exists()
|
||||
|
||||
def test_post_init_permission_error_includes_path_and_cause(self, monkeypatch):
|
||||
"""PermissionError during __post_init__ should raise ConfigError with context."""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
data_dir = Path(tmpdir) / "blocked"
|
||||
venv_path = Path(tmpdir) / "venv"
|
||||
expected_data_dir = data_dir.expanduser().resolve()
|
||||
|
||||
real_mkdir = Path.mkdir
|
||||
|
||||
def guarded_mkdir(self, *args, **kwargs):
|
||||
if self == expected_data_dir:
|
||||
raise PermissionError("Permission denied")
|
||||
return real_mkdir(self, *args, **kwargs)
|
||||
|
||||
monkeypatch.setattr(Path, "mkdir", guarded_mkdir)
|
||||
|
||||
with pytest.raises(ConfigError) as excinfo:
|
||||
Config(data_dir=data_dir, venv_path=venv_path)
|
||||
|
||||
message = str(excinfo.value)
|
||||
assert str(expected_data_dir) in message
|
||||
assert "permission" in message.lower()
|
||||
assert "PermissionError" in message
|
||||
assert isinstance(excinfo.value.__cause__, PermissionError)
|
||||
|
||||
def test_post_init_os_error_includes_path_and_cause(self, monkeypatch):
|
||||
"""OSError during __post_init__ should raise ConfigError with context."""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
data_dir = Path(tmpdir) / "invalid"
|
||||
venv_path = Path(tmpdir) / "venv"
|
||||
expected_data_dir = data_dir.expanduser().resolve()
|
||||
|
||||
real_mkdir = Path.mkdir
|
||||
|
||||
def guarded_mkdir(self, *args, **kwargs):
|
||||
if self == expected_data_dir:
|
||||
raise OSError("Invalid path")
|
||||
return real_mkdir(self, *args, **kwargs)
|
||||
|
||||
monkeypatch.setattr(Path, "mkdir", guarded_mkdir)
|
||||
|
||||
with pytest.raises(ConfigError) as excinfo:
|
||||
Config(data_dir=data_dir, venv_path=venv_path)
|
||||
|
||||
message = str(excinfo.value)
|
||||
assert str(expected_data_dir) in message
|
||||
assert "permission" not in message.lower()
|
||||
assert "filesystem" in message.lower()
|
||||
assert "OSError" in message
|
||||
assert isinstance(excinfo.value.__cause__, OSError)
|
||||
|
||||
def test_supported_languages(self):
|
||||
"""Test default supported languages."""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
@@ -158,6 +209,55 @@ class TestConfig:
|
||||
assert config.cache_dir.exists()
|
||||
assert config.index_dir.exists()
|
||||
|
||||
def test_ensure_runtime_dirs_permission_error_includes_path_and_cause(self, monkeypatch):
|
||||
"""PermissionError during ensure_runtime_dirs should raise ConfigError with context."""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
config = Config(data_dir=Path(tmpdir))
|
||||
target_dir = config.cache_dir
|
||||
|
||||
real_mkdir = Path.mkdir
|
||||
|
||||
def guarded_mkdir(self, *args, **kwargs):
|
||||
if self == target_dir:
|
||||
raise PermissionError("Permission denied")
|
||||
return real_mkdir(self, *args, **kwargs)
|
||||
|
||||
monkeypatch.setattr(Path, "mkdir", guarded_mkdir)
|
||||
|
||||
with pytest.raises(ConfigError) as excinfo:
|
||||
config.ensure_runtime_dirs()
|
||||
|
||||
message = str(excinfo.value)
|
||||
assert str(target_dir) in message
|
||||
assert "permission" in message.lower()
|
||||
assert "PermissionError" in message
|
||||
assert isinstance(excinfo.value.__cause__, PermissionError)
|
||||
|
||||
def test_ensure_runtime_dirs_os_error_includes_path_and_cause(self, monkeypatch):
|
||||
"""OSError during ensure_runtime_dirs should raise ConfigError with context."""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
config = Config(data_dir=Path(tmpdir))
|
||||
target_dir = config.cache_dir
|
||||
|
||||
real_mkdir = Path.mkdir
|
||||
|
||||
def guarded_mkdir(self, *args, **kwargs):
|
||||
if self == target_dir:
|
||||
raise OSError("Invalid path")
|
||||
return real_mkdir(self, *args, **kwargs)
|
||||
|
||||
monkeypatch.setattr(Path, "mkdir", guarded_mkdir)
|
||||
|
||||
with pytest.raises(ConfigError) as excinfo:
|
||||
config.ensure_runtime_dirs()
|
||||
|
||||
message = str(excinfo.value)
|
||||
assert str(target_dir) in message
|
||||
assert "permission" not in message.lower()
|
||||
assert "filesystem" in message.lower()
|
||||
assert "OSError" in message
|
||||
assert isinstance(excinfo.value.__cause__, OSError)
|
||||
|
||||
def test_language_for_path_python(self):
|
||||
"""Test language detection for Python files."""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
|
||||
Reference in New Issue
Block a user