punimtag/path_utils.py
tanyar09 36aaadca1d Add folder browsing and path validation features to Dashboard GUI and photo management
This commit introduces a folder browsing button in the Dashboard GUI, allowing users to select a folder for photo scanning. It also implements path normalization and validation using new utility functions from the path_utils module, ensuring that folder paths are absolute and accessible before scanning. Additionally, the PhotoManager class has been updated to utilize these path utilities, enhancing the robustness of folder scanning operations. This improves user experience by preventing errors related to invalid paths and streamlining folder management across the application.
2025-10-09 12:43:28 -04:00

175 lines
4.4 KiB
Python

#!/usr/bin/env python3
"""
Path utility functions for PunimTag
Ensures all paths are stored as absolute paths for consistency
"""
import os
from pathlib import Path
from typing import Union
def normalize_path(path: Union[str, Path]) -> str:
"""
Convert any path to an absolute path.
Args:
path: Path to normalize (can be relative or absolute)
Returns:
Absolute path as string
Examples:
normalize_path("demo_photos") -> "/home/user/punimtag/demo_photos"
normalize_path("./photos") -> "/home/user/punimtag/photos"
normalize_path("/absolute/path") -> "/absolute/path"
"""
if not path:
raise ValueError("Path cannot be empty or None")
# Convert to string if Path object
path_str = str(path)
# Use pathlib for robust path resolution
normalized = Path(path_str).resolve()
return str(normalized)
def is_absolute_path(path: Union[str, Path]) -> bool:
"""
Check if a path is absolute.
Args:
path: Path to check
Returns:
True if path is absolute, False if relative
"""
return Path(path).is_absolute()
def is_relative_path(path: Union[str, Path]) -> bool:
"""
Check if a path is relative.
Args:
path: Path to check
Returns:
True if path is relative, False if absolute
"""
return not Path(path).is_absolute()
def validate_path_exists(path: Union[str, Path]) -> bool:
"""
Check if a path exists and is accessible.
Args:
path: Path to validate
Returns:
True if path exists and is accessible, False otherwise
"""
try:
normalized = normalize_path(path)
return os.path.exists(normalized) and os.access(normalized, os.R_OK)
except (ValueError, OSError):
return False
def get_path_info(path: Union[str, Path]) -> dict:
"""
Get detailed information about a path.
Args:
path: Path to analyze
Returns:
Dictionary with path information
"""
try:
normalized = normalize_path(path)
path_obj = Path(normalized)
return {
'original': str(path),
'normalized': normalized,
'is_absolute': path_obj.is_absolute(),
'is_relative': not path_obj.is_absolute(),
'exists': path_obj.exists(),
'is_file': path_obj.is_file(),
'is_dir': path_obj.is_dir(),
'parent': str(path_obj.parent),
'name': path_obj.name,
'stem': path_obj.stem,
'suffix': path_obj.suffix
}
except Exception as e:
return {
'original': str(path),
'error': str(e)
}
def ensure_directory_exists(path: Union[str, Path]) -> str:
"""
Ensure a directory exists, creating it if necessary.
Args:
path: Directory path to ensure exists
Returns:
Absolute path to the directory
"""
normalized = normalize_path(path)
Path(normalized).mkdir(parents=True, exist_ok=True)
return normalized
def get_relative_path_from_base(absolute_path: Union[str, Path], base_path: Union[str, Path]) -> str:
"""
Get relative path from a base directory.
Args:
absolute_path: Absolute path to convert
base_path: Base directory to make relative to
Returns:
Relative path from base directory
"""
abs_path = normalize_path(absolute_path)
base = normalize_path(base_path)
try:
return str(Path(abs_path).relative_to(base))
except ValueError:
# If paths don't share a common base, return the absolute path
return abs_path
# Test the utility functions
if __name__ == "__main__":
print("=== Path Utility Functions Test ===")
test_paths = [
"demo_photos",
"./demo_photos",
"../demo_photos",
"/home/ladmin/Code/punimtag/demo_photos",
"C:/Users/Test/Photos",
"/tmp/test"
]
for path in test_paths:
print(f"\nTesting: {path}")
try:
normalized = normalize_path(path)
info = get_path_info(path)
print(f" Normalized: {normalized}")
print(f" Exists: {info['exists']}")
print(f" Is directory: {info['is_dir']}")
except Exception as e:
print(f" Error: {e}")