File
provide.foundation.file
¶
TODO: Add module docstring.
Classes¶
DetectorConfig
¶
Configuration for operation detection.
FileEvent
¶
FileEventMetadata
¶
Rich metadata for a file event.
FileLock
¶
FileLock(
path: Path | str,
timeout: float = DEFAULT_FILE_LOCK_TIMEOUT,
check_interval: float = 0.1,
)
File-based lock for concurrent access control.
Uses exclusive file creation as the locking mechanism. The lock file contains the PID of the process holding the lock.
Thread-safe: Multiple threads can safely use the same FileLock instance. The internal thread lock protects instance state while the file lock provides inter-process synchronization.
Example
with FileLock("/tmp/myapp.lock"): # Exclusive access to resource do_something()
Initialize file lock.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path | str
|
Lock file path |
required |
timeout
|
float
|
Max seconds to wait for lock |
DEFAULT_FILE_LOCK_TIMEOUT
|
check_interval
|
float
|
Seconds between lock checks |
0.1
|
Source code in provide/foundation/file/lock.py
Functions¶
__enter__
¶
__exit__
¶
acquire
¶
Acquire the lock.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
blocking
|
bool
|
If True, wait for lock. If False, return immediately. |
True
|
Returns:
| Type | Description |
|---|---|
bool
|
True if lock acquired, False if not (non-blocking mode only) |
Raises:
| Type | Description |
|---|---|
LockError
|
If timeout exceeded (blocking mode) |
Source code in provide/foundation/file/lock.py
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | |
release
¶
Release the lock.
Only removes the lock file if we own it.
Source code in provide/foundation/file/lock.py
FileOperation
¶
LockError
¶
LockError(
message: str,
*,
lock_path: str | None = None,
timeout: float | None = None,
**kwargs: Any
)
Bases: FoundationError
Raised when file lock operations fail.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
str
|
Error message describing the lock issue. |
required |
lock_path
|
str | None
|
Optional path to the lock file. |
None
|
timeout
|
float | None
|
Optional timeout that was exceeded. |
None
|
**kwargs
|
Any
|
Additional context passed to FoundationError. |
{}
|
Examples:
>>> raise LockError("Failed to acquire lock")
>>> raise LockError("Lock timeout", lock_path="/tmp/app.lock", timeout=30)
Source code in provide/foundation/errors/resources.py
OperationDetector
¶
OperationDetector(
config: DetectorConfig | None = None,
on_operation_complete: Any = None,
registry: Registry | None = None,
)
Detects and classifies file operations from events.
Initialize with optional configuration and callback.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
DetectorConfig | None
|
Detector configuration |
None
|
on_operation_complete
|
Any
|
Callback function(operation: FileOperation) called when an operation is detected. Used for streaming mode. |
None
|
registry
|
Registry | None
|
Optional registry for detectors (defaults to global) |
None
|
Source code in provide/foundation/file/operations/detectors/orchestrator.py
Functions¶
add_event
¶
Add event with auto-flush and callback support.
This is the recommended method for streaming detection with automatic temp file hiding and callback-based operation reporting.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event
|
FileEvent
|
File event to process |
required |
Behavior
- Hides temp files automatically (no callback until operation completes)
- Schedules auto-flush timer for pending operations
- Calls on_operation_complete(operation) when pattern detected
- Emits non-temp files immediately if no operation pattern found
Source code in provide/foundation/file/operations/detectors/orchestrator.py
detect
¶
Detect all operations from a list of events.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
events
|
list[FileEvent]
|
List of file events to analyze |
required |
Returns:
| Type | Description |
|---|---|
list[FileOperation]
|
List of detected operations, ordered by start time |
Source code in provide/foundation/file/operations/detectors/orchestrator.py
detect_streaming
¶
Process events in streaming fashion.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event
|
FileEvent
|
Single file event |
required |
Returns:
| Type | Description |
|---|---|
FileOperation | None
|
Completed operation if detected, None otherwise |
Source code in provide/foundation/file/operations/detectors/orchestrator.py
flush
¶
Get any pending operations and clear buffer.
Source code in provide/foundation/file/operations/detectors/orchestrator.py
Functions¶
align_offset
¶
Align offset to specified boundary.
Aligns an offset up to the next boundary. The alignment must be a power of 2.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
offset
|
int
|
The offset to align (in bytes) |
required |
alignment
|
int
|
Alignment boundary in bytes (must be power of 2) |
DEFAULT_ALIGNMENT
|
Returns:
| Type | Description |
|---|---|
int
|
Aligned offset (>= input offset) |
Raises:
| Type | Description |
|---|---|
ValueError
|
If alignment is not a power of 2 or is <= 0 |
Examples:
>>> align_offset(10, 16)
16
>>> align_offset(16, 16)
16
>>> align_offset(17, 16)
32
>>> align_offset(0, 16)
0
Notes
Uses bit manipulation for efficiency: aligned = (offset + alignment - 1) & ~(alignment - 1)
Source code in provide/foundation/file/alignment.py
align_to_page
¶
Align offset to page boundary for optimal mmap performance.
Page alignment is required for memory-mapped file operations on most systems. Common page sizes: - 4KB (4096 bytes): Most x86_64 systems, Linux, Windows - 16KB (16384 bytes): Apple Silicon (M1/M2/M3), some ARM64 systems
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
offset
|
int
|
The offset to align (in bytes) |
required |
page_size
|
int
|
Page size in bytes (default: 4096) |
PAGE_SIZE_4K
|
Returns:
| Type | Description |
|---|---|
int
|
Page-aligned offset (>= input offset) |
Raises:
| Type | Description |
|---|---|
ValueError
|
If page_size is not a power of 2 |
Examples:
>>> align_to_page(100)
4096
>>> align_to_page(4096)
4096
>>> align_to_page(4097)
8192
>>> align_to_page(100, page_size=16384)
16384
See Also
get_system_page_size() for detecting the system's page size
Source code in provide/foundation/file/alignment.py
atomic_replace
¶
Replace existing file atomically, preserving permissions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path | str
|
Target file path (must exist) |
required |
data
|
bytes
|
Binary data to write |
required |
preserve_mode
|
bool
|
Whether to preserve file permissions |
True
|
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If file doesn't exist |
OSError
|
If file operation fails |
Source code in provide/foundation/file/atomic.py
atomic_write
¶
atomic_write(
path: Path | str,
data: bytes,
mode: int | None = None,
backup: bool = False,
preserve_mode: bool = True,
) -> None
Write file atomically using temp file + rename.
This ensures that the file is either fully written or not written at all, preventing partial writes or corruption.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path | str
|
Target file path |
required |
data
|
bytes
|
Binary data to write |
required |
mode
|
int | None
|
Optional file permissions (e.g., 0o644) |
None
|
backup
|
bool
|
Create .bak file before overwrite |
False
|
preserve_mode
|
bool
|
Whether to preserve existing file permissions when mode is None |
True
|
Raises:
| Type | Description |
|---|---|
OSError
|
If file operation fails |
Source code in provide/foundation/file/atomic.py
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | |
atomic_write_text
¶
atomic_write_text(
path: Path | str,
text: str,
encoding: str = "utf-8",
mode: int | None = None,
backup: bool = False,
preserve_mode: bool = True,
) -> None
Write text file atomically.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path | str
|
Target file path |
required |
text
|
str
|
Text content to write |
required |
encoding
|
str
|
Text encoding (default: utf-8) |
'utf-8'
|
mode
|
int | None
|
Optional file permissions |
None
|
backup
|
bool
|
Create .bak file before overwrite |
False
|
preserve_mode
|
bool
|
Whether to preserve existing file permissions when mode is None |
True
|
Raises:
| Type | Description |
|---|---|
OSError
|
If file operation fails |
UnicodeEncodeError
|
If text cannot be encoded |
Source code in provide/foundation/file/atomic.py
backup_file
¶
Create backup copy of file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path | str
|
File to backup |
required |
suffix
|
str
|
Backup suffix |
'.bak'
|
timestamp
|
bool
|
If True, add timestamp to backup name |
False
|
Returns:
| Type | Description |
|---|---|
Path | None
|
Path to backup file, or None if source doesn't exist |
Source code in provide/foundation/file/utils.py
calculate_padding
¶
Calculate padding bytes needed to align to boundary.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
current_offset
|
int
|
Current offset position (in bytes) |
required |
alignment
|
int
|
Desired alignment boundary (in bytes) |
DEFAULT_ALIGNMENT
|
Returns:
| Type | Description |
|---|---|
int
|
Number of padding bytes needed (0 if already aligned) |
Raises:
| Type | Description |
|---|---|
ValueError
|
If alignment is not a power of 2 or is <= 0 |
Examples:
>>> calculate_padding(10, 16)
6
>>> calculate_padding(16, 16)
0
>>> calculate_padding(17, 16)
15
>>> calculate_padding(100, 64)
28
Notes
This is useful when writing binary formats where you need to insert padding bytes to maintain alignment.
Source code in provide/foundation/file/alignment.py
check_disk_space
¶
Check if sufficient disk space is available.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path
|
Directory path to check (or parent if it doesn't exist) |
required |
required_bytes
|
int
|
Number of bytes required |
required |
raise_on_insufficient
|
bool
|
Raise OSError if insufficient space (default: True) |
True
|
Returns:
| Type | Description |
|---|---|
bool
|
True if sufficient space available, False otherwise |
Raises:
| Type | Description |
|---|---|
OSError
|
If insufficient space and raise_on_insufficient=True |
Examples:
>>> from pathlib import Path
>>> # Check if 1GB is available
>>> check_disk_space(Path.home(), 1024**3, raise_on_insufficient=False)
True
>>> # Will raise if insufficient (default behavior)
>>> check_disk_space(Path.home(), 10**15)
Traceback (most recent call last):
...
OSError: Insufficient disk space...
Notes
On systems where disk space cannot be determined (e.g., Windows without proper permissions), this function logs a warning but does not fail, returning True to allow the operation to proceed.
Source code in provide/foundation/file/disk.py
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | |
detect_atomic_save
¶
Detect if events represent an atomic save operation.
Source code in provide/foundation/file/operations/utils.py
ensure_dir
¶
Ensure directory exists with proper permissions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path | str
|
Directory path |
required |
mode
|
int
|
Directory permissions |
493
|
parents
|
bool
|
Create parent directories if needed |
True
|
Returns:
| Type | Description |
|---|---|
Path
|
Path object for the directory |
Source code in provide/foundation/file/directory.py
ensure_parent_dir
¶
Ensure parent directory of file exists.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file_path
|
Path | str
|
File path whose parent to ensure |
required |
mode
|
int
|
Directory permissions |
493
|
Returns:
| Type | Description |
|---|---|
Path
|
Path object for the parent directory |
Source code in provide/foundation/file/directory.py
ensure_secure_permissions
¶
ensure_secure_permissions(
path: Path,
is_executable: bool = False,
file_mode: int = DEFAULT_FILE_PERMS,
dir_mode: int = DEFAULT_DIR_PERMS,
executable_mode: int = DEFAULT_EXECUTABLE_PERMS,
) -> None
Apply secure default permissions to a file or directory.
Automatically determines the appropriate permission mode based on whether the path is a file, directory, or executable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path
|
Path to file or directory |
required |
is_executable
|
bool
|
Whether file should be executable (ignored for directories) |
False
|
file_mode
|
int
|
Permission mode for regular files |
DEFAULT_FILE_PERMS
|
dir_mode
|
int
|
Permission mode for directories |
DEFAULT_DIR_PERMS
|
executable_mode
|
int
|
Permission mode for executable files |
DEFAULT_EXECUTABLE_PERMS
|
Examples:
>>> from pathlib import Path
>>> # Regular file gets 0o644
>>> p = Path("/tmp/file.txt")
>>> p.touch()
>>> ensure_secure_permissions(p)
>>> # Executable gets 0o755
>>> p2 = Path("/tmp/script.sh")
>>> p2.touch()
>>> ensure_secure_permissions(p2, is_executable=True)
>>> # Directory gets 0o755
>>> d = Path("/tmp/mydir")
>>> d.mkdir(exist_ok=True)
>>> ensure_secure_permissions(d)
Source code in provide/foundation/file/permissions.py
extract_original_path
¶
Extract the original filename from a temp file path.
Source code in provide/foundation/file/operations/utils.py
find_files
¶
Find files matching pattern.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pattern
|
str
|
Glob pattern (e.g., ".py", "**/.json") |
required |
root
|
Path | str
|
Root directory to search from |
'.'
|
recursive
|
bool
|
If True, search recursively |
True
|
Returns:
| Type | Description |
|---|---|
list[Path]
|
List of matching file paths |
Source code in provide/foundation/file/utils.py
format_bytes
¶
Format bytes as human-readable string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_bytes
|
int
|
Number of bytes |
required |
Returns:
| Type | Description |
|---|---|
str
|
Formatted string (e.g., "1.50 GB", "256.00 MB") |
Examples:
>>> format_bytes(1024)
'1.00 KB'
>>> format_bytes(1024**2)
'1.00 MB'
>>> format_bytes(1536 * 1024**2)
'1.50 GB'
>>> format_bytes(500)
'500 B'
Source code in provide/foundation/file/disk.py
format_permissions
¶
Format permission bits as octal string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mode
|
int
|
Permission bits (can include file type bits) |
required |
Returns:
| Type | Description |
|---|---|
str
|
Formatted string like "0755" (last 3 octal digits only) |
Examples:
>>> format_permissions(0o755)
'0755'
>>> format_permissions(0o644)
'0644'
>>> format_permissions(493) # 0o755 in decimal
'0755'
Source code in provide/foundation/file/permissions.py
get_available_space
¶
Get available disk space in bytes for a path.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path
|
Directory path to check (uses parent if path doesn't exist) |
required |
Returns:
| Type | Description |
|---|---|
int | None
|
Available bytes or None if unable to determine |
Examples:
>>> from pathlib import Path
>>> space = get_available_space(Path.home())
>>> space is not None and space > 0
True
Notes
Uses os.statvfs on Unix-like systems (Linux, macOS, BSD). Returns None on Windows or if statvfs is unavailable.
Source code in provide/foundation/file/disk.py
get_disk_usage
¶
Get total, used, and free disk space for a path.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path
|
Directory path to check |
required |
Returns:
| Type | Description |
|---|---|
tuple[int, int, int] | None
|
Tuple of (total, used, free) in bytes, or None if unable to determine |
Examples:
>>> from pathlib import Path
>>> usage = get_disk_usage(Path.home())
>>> if usage:
... total, used, free = usage
... assert total > 0 and used >= 0 and free > 0
... assert total >= used + free # May have reserved space
Notes
Uses os.statvfs on Unix-like systems. Returns None on Windows or if unavailable.
Source code in provide/foundation/file/disk.py
get_mtime
¶
Get modification time, None if not exists.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path | str
|
File path |
required |
Returns:
| Type | Description |
|---|---|
float | None
|
Modification time as timestamp, or None if doesn't exist |
Source code in provide/foundation/file/utils.py
get_permissions
¶
Get current file permissions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path
|
File or directory path |
required |
Returns:
| Type | Description |
|---|---|
int
|
Permission bits as integer (0 if file doesn't exist or error) |
Examples:
>>> from pathlib import Path
>>> p = Path("/tmp/test.txt")
>>> p.touch()
>>> p.chmod(0o644)
>>> get_permissions(p)
420
>>> format_permissions(get_permissions(p))
'0644'
Source code in provide/foundation/file/permissions.py
get_size
¶
Get file size in bytes, 0 if not exists.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path | str
|
File path |
required |
Returns:
| Type | Description |
|---|---|
int
|
Size in bytes, or 0 if file doesn't exist |
Source code in provide/foundation/file/utils.py
get_system_page_size
¶
Get the system's page size.
Returns:
| Type | Description |
|---|---|
int
|
Page size in bytes (typically 4096 or 16384) |
Examples:
Notes
Uses os.sysconf('SC_PAGE_SIZE') on Unix-like systems. Falls back to PAGE_SIZE_4K if detection fails.
Source code in provide/foundation/file/alignment.py
group_related_events
¶
Group events that occur within a time window.
Source code in provide/foundation/file/operations/utils.py
is_aligned
¶
Check if offset is aligned to boundary.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
offset
|
int
|
The offset to check (in bytes) |
required |
alignment
|
int
|
Alignment boundary in bytes |
DEFAULT_ALIGNMENT
|
Returns:
| Type | Description |
|---|---|
bool
|
True if offset is aligned to the boundary |
Raises:
| Type | Description |
|---|---|
ValueError
|
If alignment is not a power of 2 or is <= 0 |
Examples:
>>> is_aligned(16, 16)
True
>>> is_aligned(17, 16)
False
>>> is_aligned(0, 16)
True
>>> is_aligned(4096, 4096)
True
Notes
Uses bit manipulation for efficiency: is_aligned = (offset & (alignment - 1)) == 0
Source code in provide/foundation/file/alignment.py
is_power_of_two
¶
Check if a value is a power of 2.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
int
|
Value to check |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if value is a power of 2 |
Examples:
>>> is_power_of_two(16)
True
>>> is_power_of_two(17)
False
>>> is_power_of_two(4096)
True
>>> is_power_of_two(0)
False
Notes
Uses bit manipulation: (value & (value - 1)) == 0
Source code in provide/foundation/file/alignment.py
is_temp_file
¶
Check if a path represents a temporary file.
parse_permissions
¶
Parse permission string to octal integer.
Accepts various permission string formats: - Octal with prefix: "0o755", "0755" - Octal without prefix: "755" - Integer strings: "493" (decimal for 0o755)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
perms_str
|
str | None
|
Permission string (e.g., "0755", "755", "0o755") |
required |
default
|
int
|
Default permissions if parsing fails |
DEFAULT_FILE_PERMS
|
Returns:
| Type | Description |
|---|---|
int
|
Permission as integer (e.g., 0o755 = 493) |
Examples:
>>> parse_permissions("0755")
493
>>> parse_permissions("0o755")
493
>>> parse_permissions("755")
493
>>> parse_permissions(None)
420
>>> parse_permissions("invalid")
420
Source code in provide/foundation/file/permissions.py
read_json
¶
Read JSON file with error handling.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path | str
|
JSON file path |
required |
default
|
Any
|
Default value if file doesn't exist or is invalid |
None
|
encoding
|
str
|
Text encoding |
'utf-8'
|
Returns:
| Type | Description |
|---|---|
Any
|
Parsed JSON data or default value |
Source code in provide/foundation/file/formats.py
read_toml
¶
Read TOML file with error handling.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path | str
|
TOML file path |
required |
default
|
Any
|
Default value if file doesn't exist or is invalid |
None
|
encoding
|
str
|
Text encoding |
'utf-8'
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
Parsed TOML data or default value |
Source code in provide/foundation/file/formats.py
read_yaml
¶
Read YAML file with error handling.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path | str
|
YAML file path |
required |
default
|
Any
|
Default value if file doesn't exist or is invalid |
None
|
encoding
|
str
|
Text encoding |
'utf-8'
|
Returns:
| Type | Description |
|---|---|
Any
|
Parsed YAML data or default value |
Source code in provide/foundation/file/formats.py
safe_copy
¶
safe_copy(
src: Path | str,
dst: Path | str,
overwrite: bool = False,
preserve_mode: bool = True,
) -> None
Copy file safely with metadata preservation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
src
|
Path | str
|
Source file path |
required |
dst
|
Path | str
|
Destination file path |
required |
overwrite
|
bool
|
Whether to overwrite existing destination |
False
|
preserve_mode
|
bool
|
Whether to preserve file permissions |
True
|
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If source doesn't exist |
FileExistsError
|
If destination exists and overwrite=False |
OSError
|
If copy operation fails |
Source code in provide/foundation/file/safe.py
safe_delete
¶
Delete file safely.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path | str
|
File to delete |
required |
missing_ok
|
bool
|
If True, don't raise error if file doesn't exist |
True
|
Returns:
| Type | Description |
|---|---|
bool
|
True if deleted, False if didn't exist |
Raises:
| Type | Description |
|---|---|
OSError
|
If deletion fails and file exists |
Source code in provide/foundation/file/safe.py
safe_move
¶
Move file safely with optional overwrite.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
src
|
Path | str
|
Source file path |
required |
dst
|
Path | str
|
Destination file path |
required |
overwrite
|
bool
|
Whether to overwrite existing destination |
False
|
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If source doesn't exist |
FileExistsError
|
If destination exists and overwrite=False |
OSError
|
If move operation fails |
Source code in provide/foundation/file/safe.py
safe_read
¶
safe_read(
path: Path | str,
default: bytes | None = None,
encoding: str | None = None,
) -> bytes | str | None
Read file safely, returning default if not found.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path | str
|
File to read |
required |
default
|
bytes | None
|
Value to return if file doesn't exist |
None
|
encoding
|
str | None
|
If provided, decode bytes to str |
None
|
Returns:
| Type | Description |
|---|---|
bytes | str | None
|
File contents or default value |
Source code in provide/foundation/file/safe.py
safe_read_text
¶
Read text file safely with default.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path | str
|
File to read |
required |
default
|
str
|
Default text if file doesn't exist |
''
|
encoding
|
str
|
Text encoding |
'utf-8'
|
Returns:
| Type | Description |
|---|---|
str
|
File contents or default text |
Source code in provide/foundation/file/safe.py
safe_rmtree
¶
Remove directory tree safely.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path | str
|
Directory to remove |
required |
missing_ok
|
bool
|
If True, don't raise error if doesn't exist |
True
|
Returns:
| Type | Description |
|---|---|
bool
|
True if removed, False if didn't exist |
Raises:
| Type | Description |
|---|---|
OSError
|
If removal fails and directory exists |
Source code in provide/foundation/file/directory.py
secure_temp_file
¶
secure_temp_file(
suffix: str = DEFAULT_TEMP_SUFFIX,
prefix: str = DEFAULT_TEMP_PREFIX,
dir: Path | str | None = None,
) -> tuple[int, Path]
Create a secure temporary file with restricted permissions.
This is similar to tempfile.mkstemp but uses Foundation's defaults. The file is created with permissions 0o600 (owner read/write only).
Use this when you need: - Direct file descriptor access (for os.fdopen, os.fsync, etc.) - Atomic file operations - Maximum security (restricted permissions)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
suffix
|
str
|
File suffix |
DEFAULT_TEMP_SUFFIX
|
prefix
|
str
|
File name prefix |
DEFAULT_TEMP_PREFIX
|
dir
|
Path | str | None
|
Directory for the temp file (None = system temp) |
None
|
Returns:
| Type | Description |
|---|---|
tuple[int, Path]
|
Tuple of (file_descriptor, Path) - caller must close the fd |
Example
fd, path = secure_temp_file(suffix='.tmp') try: ... with os.fdopen(fd, 'wb') as f: ... f.write(b'data') ... os.fsync(f.fileno()) ... finally: ... path.unlink(missing_ok=True)
Source code in provide/foundation/file/temp.py
set_file_permissions
¶
Set file permissions safely with error handling.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path
|
File or directory path |
required |
mode
|
int
|
Unix permission mode (e.g., 0o755) |
required |
Raises:
| Type | Description |
|---|---|
OSError
|
If setting permissions fails on the underlying filesystem |
Examples:
>>> from pathlib import Path
>>> p = Path("/tmp/test.txt")
>>> p.touch()
>>> set_file_permissions(p, 0o644)
Source code in provide/foundation/file/permissions.py
system_temp_dir
¶
Get the operating system's temporary directory.
Returns:
| Type | Description |
|---|---|
Path
|
Path to the OS temp directory |
Example
temp_path = system_temp_dir() print(temp_path) # e.g., /tmp or C:\Users...\Temp
Source code in provide/foundation/file/temp.py
temp_dir
¶
temp_dir(
prefix: str = DEFAULT_TEMP_PREFIX,
cleanup: bool = DEFAULT_TEMP_CLEANUP,
) -> Generator[Path, None, None]
Create temporary directory with automatic cleanup.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prefix
|
str
|
Directory name prefix |
DEFAULT_TEMP_PREFIX
|
cleanup
|
bool
|
Whether to remove directory on exit |
DEFAULT_TEMP_CLEANUP
|
Yields:
| Type | Description |
|---|---|
Path
|
Path object for the temporary directory |
Example
with temp_dir() as tmpdir: ... (tmpdir / 'data.txt').write_text('content') ... process_directory(tmpdir)
Source code in provide/foundation/file/temp.py
temp_file
¶
temp_file(
suffix: str = DEFAULT_TEMP_SUFFIX,
prefix: str = DEFAULT_TEMP_PREFIX,
dir: Path | str | None = None,
text: bool = DEFAULT_TEMP_TEXT_MODE,
cleanup: bool = DEFAULT_TEMP_CLEANUP,
) -> Generator[Path, None, None]
Create a temporary file with automatic cleanup.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
suffix
|
str
|
File suffix (e.g., '.txt', '.json') |
DEFAULT_TEMP_SUFFIX
|
prefix
|
str
|
File name prefix |
DEFAULT_TEMP_PREFIX
|
dir
|
Path | str | None
|
Directory for the temp file (None = system temp) |
None
|
text
|
bool
|
Whether to open in text mode |
DEFAULT_TEMP_TEXT_MODE
|
cleanup
|
bool
|
Whether to remove file on exit |
DEFAULT_TEMP_CLEANUP
|
Yields:
| Type | Description |
|---|---|
Path
|
Path object for the temporary file |
Example
with temp_file(suffix='.json') as tmp: ... tmp.write_text('{"key": "value"}') ... process_file(tmp)
Source code in provide/foundation/file/temp.py
touch
¶
Create empty file or update timestamp.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path | str
|
File path |
required |
mode
|
int
|
File permissions for new files |
420
|
exist_ok
|
bool
|
If False, raise error if file exists |
True
|
Raises:
| Type | Description |
|---|---|
FileExistsError
|
If exist_ok=False and file exists |
Source code in provide/foundation/file/utils.py
write_json
¶
write_json(
path: Path | str,
data: Any,
indent: int = 2,
sort_keys: bool = False,
atomic: bool = True,
encoding: str = "utf-8",
) -> None
Write JSON file, optionally atomic.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path | str
|
JSON file path |
required |
data
|
Any
|
Data to serialize |
required |
indent
|
int
|
Indentation level (None for compact) |
2
|
sort_keys
|
bool
|
Whether to sort dictionary keys |
False
|
atomic
|
bool
|
Use atomic write |
True
|
encoding
|
str
|
Text encoding |
'utf-8'
|
Source code in provide/foundation/file/formats.py
write_toml
¶
write_toml(
path: Path | str,
data: dict[str, Any],
atomic: bool = True,
encoding: str = "utf-8",
) -> None
Write TOML file, optionally atomic.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path | str
|
TOML file path |
required |
data
|
dict[str, Any]
|
Data to serialize (must be a dictionary) |
required |
atomic
|
bool
|
Use atomic write |
True
|
encoding
|
str
|
Text encoding |
'utf-8'
|
Source code in provide/foundation/file/formats.py
write_yaml
¶
write_yaml(
path: Path | str,
data: Any,
atomic: bool = True,
encoding: str = "utf-8",
default_flow_style: bool = False,
) -> None
Write YAML file, optionally atomic.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path | str
|
YAML file path |
required |
data
|
Any
|
Data to serialize |
required |
atomic
|
bool
|
Use atomic write |
True
|
encoding
|
str
|
Text encoding |
'utf-8'
|
default_flow_style
|
bool
|
Use flow style (JSON-like) instead of block style |
False
|