Source code for axe_usd.core.filesystem

"""File system helpers with validation and consistent error wrapping."""

import json
from contextlib import contextmanager
from pathlib import Path
from typing import Any, Dict, Optional

from .exceptions import FileSystemError, ValidationError


[docs] class DefaultFileSystem: """Default file system implementation with validation.""" @staticmethod @contextmanager def _fs_error(msg, **details): """Wrap file system exceptions into FileSystemError.""" try: yield except (OSError, ValueError, json.JSONDecodeError, TypeError) as exc: raise FileSystemError( msg, details={**details, "error": str(exc), "type": type(exc).__name__}, ) from exc
[docs] def ensure_directory(self, path: Path) -> Path: """Create directory if it doesn't exist.""" with self._fs_error(f"Failed to create directory: {path}", path=str(path)): path.mkdir(parents=True, exist_ok=True) return path
[docs] def validate_path(self, path: Path, base_dir: Optional[Path] = None) -> Path: """Validate and resolve a path.""" try: resolved = path.resolve() except (OSError, RuntimeError) as exc: raise ValidationError( f"Cannot resolve path: {path}", details={"path": str(path), "error": str(exc)}, ) from exc # Check for path traversal if base_dir provided if base_dir: try: base_resolved = base_dir.resolve() resolved.relative_to(base_resolved) except ValueError as exc: raise ValidationError( f"Path escapes base directory: {path}", details={ "path": str(path), "base_dir": str(base_dir), "resolved": str(resolved), "base_resolved": str(base_resolved), }, ) from exc return resolved
[docs] def path_exists(self, path: Path) -> bool: """Check if path exists.""" return path.exists()
[docs] def read_json(self, path: Path) -> Dict[str, Any]: """Read JSON file.""" with self._fs_error(f"Failed to read JSON from {path}", path=str(path)): with path.open("r", encoding="utf-8") as f: return json.load(f)
[docs] def write_json(self, path: Path, data: Dict[str, Any]) -> None: """Write JSON file.""" with self._fs_error(f"Failed to write JSON to {path}", path=str(path)): # Ensure parent directory exists self.ensure_directory(path.parent) with path.open("w", encoding="utf-8") as f: json.dump(data, f, indent=2)
__all__ = ["DefaultFileSystem"]