File Operations
The file operations module provides utilities for file manipulation, copying, moving, and general file system operations.
Module Overview
Modern file operations for siege_utilities. Provides clean, type-safe file manipulation utilities.
- siege_utilities.files.operations.sanitize_filename(name)[source]
Convert an arbitrary string into a safe filename component.
Unsafe characters (path separators, control characters, punctuation other than
.and-) are replaced with underscores, runs of underscores are collapsed, and leading/trailing dots and underscores are trimmed. The result is always a non-empty string and the operation is idempotent (sanitize_filename(sanitize_filename(x)) == sanitize_filename(x)).
- siege_utilities.files.operations.atomic_write_path(target)[source]
Context manager that yields a temporary path for writing, then atomically replaces the target on successful exit.
Usage:
with atomic_write_path("/data/output.csv") as tmp: df.to_csv(tmp, index=False) # target is now atomically updated
If the block raises, the temp file is cleaned up and the target is left unchanged.
- siege_utilities.files.operations.atomic_write_shapefile(gdf, target, **kwargs)[source]
Write a GeoDataFrame as a Shapefile atomically.
Shapefiles produce sidecar files (.shx, .dbf, .prj, .cpg). This writes to a temp stem then renames all produced files to the final stem.
- siege_utilities.files.operations.remove_tree(path)[source]
Remove a file or directory tree safely.
SECURITY: Validates paths to prevent removing sensitive system files.
- Parameters:
- Raises:
FileNotFoundError – If path does not exist
PathSecurityError – If path fails security validation
OSError – If removal fails
- Return type:
None
Example
>>> remove_tree("temp_directory") >>> remove_tree(Path("old_files"))
- siege_utilities.files.operations.file_exists(path)[source]
Check if a file exists at the specified path.
SECURITY: This function validates paths to prevent path traversal attacks and access to sensitive system files.
- Parameters:
- Returns:
True if file exists, False otherwise
- Raises:
PathSecurityError – If path fails security validation
- Return type:
Example
>>> if file_exists("config.yaml"): ... print("Config file found") >>> file_exists("../../../etc/passwd")
- Security Changes:
Now validates paths to block path traversal
Blocks access to sensitive system files
- siege_utilities.files.operations.touch_file(path, create_parents=True)[source]
Create an empty file, creating parent directories if needed.
SECURITY: Validates paths to prevent path traversal attacks.
- Parameters:
- Raises:
PathSecurityError – If path fails security validation
OSError – If file creation fails
- Return type:
None
Example
>>> touch_file("logs/app.log") >>> touch_file(Path("data/output.txt"))
- siege_utilities.files.operations.count_lines(file_path, encoding='utf-8')[source]
Count the total number of lines in a text file.
SECURITY: This function validates paths to prevent path traversal attacks and access to sensitive system files.
- Parameters:
- Returns:
Number of lines
- Raises:
FileNotFoundError – If file does not exist or is not a file
PathSecurityError – If path fails security validation
OSError – If file cannot be read
UnicodeDecodeError – If file cannot be decoded with given encoding
- Return type:
Example
>>> line_count = count_lines("data.csv") >>> print(f"File has {line_count} lines")
- siege_utilities.files.operations.copy_file(source, destination, overwrite=False)[source]
Copy a file from source to destination.
SECURITY: Validates both source and destination paths.
- Parameters:
- Raises:
FileNotFoundError – If source does not exist or is not a file
FileExistsError – If destination exists and overwrite=False
PathSecurityError – If paths fail security validation
OSError – If copy fails
- Return type:
None
Example
>>> copy_file("source.txt", "backup/source.txt") >>> copy_file(Path("config.yaml"), Path("config.yaml.bak"))
- siege_utilities.files.operations.move_file(source, destination, overwrite=False)[source]
Move a file from source to destination.
SECURITY: Validates both source and destination paths.
- Parameters:
- Raises:
FileNotFoundError – If source does not exist or is not a file
FileExistsError – If destination exists and overwrite=False
PathSecurityError – If paths fail security validation
OSError – If move fails
- Return type:
None
Example
>>> move_file("temp.txt", "archive/temp.txt") >>> move_file(Path("old.log"), Path("logs/old.log"))
- siege_utilities.files.operations.get_file_size(file_path)[source]
Get the size of a file in bytes.
SECURITY: This function validates paths to prevent path traversal attacks and access to sensitive system files.
- Parameters:
- Returns:
File size in bytes
- Raises:
FileNotFoundError – If file does not exist or is not a file
PathSecurityError – If path fails security validation
OSError – If file size cannot be determined
- Return type:
Example
>>> size = get_file_size("large_file.zip") >>> print(f"File size: {size} bytes")
- siege_utilities.files.operations.list_directory(path, pattern='*', include_dirs=True, include_files=True)[source]
List contents of a directory with optional filtering.
SECURITY: Validates directory path to prevent traversal attacks.
- Parameters:
- Returns:
List of Path objects
- Raises:
FileNotFoundError – If directory does not exist or is not a directory
PathSecurityError – If path fails security validation
OSError – If directory cannot be read
- Return type:
Example
>>> files = list_directory("data", "*.csv") >>> dirs = list_directory("logs", include_files=False)
- siege_utilities.files.operations.run_command(command, cwd=None, timeout=30, capture_output=True, allow_list=None, unsafe=False)[source]
Run a shell command with security validation and proper error handling.
SECURITY: This function now validates commands by default. Only whitelisted commands are allowed unless unsafe=True is explicitly set.
- Parameters:
timeout (int | None) – Timeout in seconds (default: 30)
capture_output (bool) – Whether to capture command output
allow_list (set | None) – Optional custom whitelist of allowed commands
unsafe (bool) – If True, bypass the allow-list check. The command is still executed via argv (shell=False) — string commands are shlex-split and run without shell expansion. Use this when you legitimately need a binary that isn’t in the allow-list, not when you need shell features.
- Returns:
CompletedProcess object on success or non-zero exit.
- Raises:
SecurityError – If command fails security validation (when unsafe=False).
subprocess.TimeoutExpired – If the command exceeds timeout.
OSError – If the command binary cannot be found or executed.
- Return type:
Example
>>> result = run_command("ls -la") >>> if result and result.returncode == 0: ... print("Command succeeded") >>> result = run_command("rm -rf /") >>> result = run_command("git status", allow_list={'git', 'ls'}) >>> result = run_command("custom_cmd", unsafe=True)
- Security Changes:
Previously used shell=True with no validation (CRITICAL VULNERABILITY)
Now validates all commands against whitelist by default
Blocks command injection, path traversal, sensitive file access
Use unsafe=True ONLY with trusted input in trusted environments
- siege_utilities.files.operations.ensure_directory_exists(directory)[source]
Ensure a directory exists, creating it if necessary.
- Parameters:
- Returns:
Path object for the directory
- Raises:
PathSecurityError – If path fails security validation.
- Return type:
- siege_utilities.files.operations.safe_file_write(file_path, content, encoding='utf-8', create_dirs=True)[source]
Safely write content to a file, optionally creating parent directories.
- Parameters:
- Returns:
True if successful, False otherwise
- Raises:
PathSecurityError – If path fails security validation.
- Return type:
- siege_utilities.files.operations.safe_file_read(file_path, encoding='utf-8', default=None)[source]
Safely read content from a file.
- Parameters:
- Returns:
File content or default value
- Raises:
PathSecurityError – If path fails security validation.
- Return type:
str | None
- siege_utilities.files.operations.safe_json_write(file_path, data, indent=2, create_dirs=True)[source]
Safely write data to a JSON file.
- Parameters:
- Returns:
True if successful, False otherwise
- Raises:
PathSecurityError – If path fails security validation.
- Return type:
- siege_utilities.files.operations.safe_json_read(file_path, default=None)[source]
Safely read data from a JSON file.
- Parameters:
- Returns:
Parsed JSON data or default value
- Raises:
PathSecurityError – If path fails security validation.
- Return type:
Any | None
- siege_utilities.files.operations.get_file_size_mb(file_path)[source]
Get file size in megabytes.
- Parameters:
- Returns:
File size in MB.
- Raises:
FileNotFoundError – If the file does not exist.
PathSecurityError – If path fails security validation.
OSError – If the file size cannot be determined.
- Return type:
- siege_utilities.files.operations.list_files_recursive(directory, pattern='*', exclude_dirs=True)[source]
List all files in a directory recursively.
- Parameters:
- Returns:
List of Path objects
- Raises:
FileNotFoundError – If the directory does not exist.
PathSecurityError – If path fails security validation.
OSError – If the directory cannot be read.
- Return type:
- siege_utilities.files.operations.rmtree(path)
Remove a file or directory tree safely.
SECURITY: Validates paths to prevent removing sensitive system files.
- Parameters:
- Raises:
FileNotFoundError – If path does not exist
PathSecurityError – If path fails security validation
OSError – If removal fails
- Return type:
None
Example
>>> remove_tree("temp_directory") >>> remove_tree(Path("old_files"))
- siege_utilities.files.operations.check_if_file_exists_at_path(path)[source]
Check if a file exists at the specified path.
Deprecated since version 3.19.0: Use
file_exists()instead. Will be removed in v4.0.0.
- siege_utilities.files.operations.delete_existing_file_and_replace_it_with_an_empty_file(file_path, create_parents=True)[source]
Backward compatibility function that deletes existing file and replaces it with empty file.
Deprecated since version 3.19.0: Use
touch_file()for creating empty files. Note thattouch_filedoes not delete the existing file first; if you need delete-then-create semantics, callPath.unlink()beforetouch_file(). Will be removed in v4.0.0.SECURITY: Validates paths to prevent path traversal attacks.
- Parameters:
- Raises:
PathSecurityError – If path fails security validation
OSError – If file creation fails
- Return type:
None
- siege_utilities.files.operations.count_total_rows_in_file_pythonically(file_path, encoding='utf-8')
Count the total number of lines in a text file.
SECURITY: This function validates paths to prevent path traversal attacks and access to sensitive system files.
- Parameters:
- Returns:
Number of lines
- Raises:
FileNotFoundError – If file does not exist or is not a file
PathSecurityError – If path fails security validation
OSError – If file cannot be read
UnicodeDecodeError – If file cannot be decoded with given encoding
- Return type:
Example
>>> line_count = count_lines("data.csv") >>> print(f"File has {line_count} lines")
Functions
- siege_utilities.files.operations.copy_file(source, destination, overwrite=False)[source]
Copy a file from source to destination.
SECURITY: Validates both source and destination paths.
- Parameters:
- Raises:
FileNotFoundError – If source does not exist or is not a file
FileExistsError – If destination exists and overwrite=False
PathSecurityError – If paths fail security validation
OSError – If copy fails
- Return type:
None
Example
>>> copy_file("source.txt", "backup/source.txt") >>> copy_file(Path("config.yaml"), Path("config.yaml.bak"))
- siege_utilities.files.operations.move_file(source, destination, overwrite=False)[source]
Move a file from source to destination.
SECURITY: Validates both source and destination paths.
- Parameters:
- Raises:
FileNotFoundError – If source does not exist or is not a file
FileExistsError – If destination exists and overwrite=False
PathSecurityError – If paths fail security validation
OSError – If move fails
- Return type:
None
Example
>>> move_file("temp.txt", "archive/temp.txt") >>> move_file(Path("old.log"), Path("logs/old.log"))
Usage Examples
Basic file operations:
import siege_utilities
# Copy a file
siege_utilities.copy_file('source.txt', 'destination.txt')
# Move a file
siege_utilities.move_file('old_name.txt', 'new_name.txt')
# Delete a file
siege_utilities.delete_file('unwanted_file.txt')
# Create directory
siege_utilities.create_directory('new_folder')
# List files in directory
files = siege_utilities.list_files('data_folder')
print(f"Found {len(files)} files")
Batch file processing:
import os
# Process multiple files
source_dir = 'input_files'
output_dir = 'processed_files'
# Create output directory
siege_utilities.create_directory(output_dir)
# Process all files
for filename in siege_utilities.list_files(source_dir):
if filename.endswith('.txt'):
source_path = os.path.join(source_dir, filename)
dest_path = os.path.join(output_dir, f"processed_{filename}")
siege_utilities.copy_file(source_path, dest_path)
Unit Tests
The file operations module has comprehensive test coverage:
✅ test_file_operations.py - All file operation tests pass
Test Coverage:
- File copying with various scenarios
- File moving and renaming
- File deletion with safety checks
- Directory creation and management
- File listing and discovery
- Error handling for missing files
- Permission handling
Test Results: All file operation tests pass successfully with comprehensive coverage.