FileHandler class provides thread-safe, atomic file operations for markdown files using POSIX file locks (via portalocker). It implements shared locks for reads and exclusive locks for writes with atomic file replacement.
Class Definition
Constructor
Absolute or relative path to the markdown file. The path will be expanded and resolved automatically.
Example
Properties
filepath
Exposes the resolved markdown file path served by this handler.The resolved absolute path to the markdown file for read and write operations.
Example
Methods
read()
Read markdown content from disk using a shared lock (LOCK_SH). Multiple readers can hold shared locks simultaneously.UTF-8 decoded markdown content currently stored on disk.
This method acquires a shared lock, allowing multiple concurrent reads but blocking if an exclusive write lock is held.
FileReadError- If the file does not exist, is not valid UTF-8, or cannot be read
Example
write()
Persist markdown content atomically using an exclusive lock (LOCK_EX). Writes to a temporary file, syncs to disk, then atomically replaces the original.Full markdown document content to save. This will replace the entire file contents.
Always returns
True when content is written and moved into place successfully.FileWriteError- If the temporary file cannot be created, written to, or replaced
- Acquires exclusive lock (blocks other readers and writers)
- Writes content to temporary file in same directory:
.{filename}.tmp - Calls
fsync()to ensure data is on disk - Atomically replaces original file with
os.replace() - Releases lock
Example
get_metadata()
Return current file metadata used by API responses.File metadata dictionary containing:
path(str): Absolute file path as stringsize_bytes(int): File size in bytesmodified_at(float): Last modification timestamp (Unix time)created_at(float): Creation timestamp (Unix time, platform-dependent)
FileReadError- If the file does not exist or cannot be inspected
Example
cleanup()
Remove the lock file created by this handler instance. Safe to call multiple times.This method has best-effort semantics and never raises exceptions. It’s recommended to call this when done with a handler, typically in server shutdown hooks.
{filename}.md.lock in the same directory as the markdown file.
Example
Exceptions
FileReadError
Raised when reading markdown content fails.RuntimeError. Common scenarios:
- File does not exist
- File is not valid UTF-8 text
- File cannot be read due to permissions or I/O errors
FileWriteError
Raised when writing markdown content fails.RuntimeError. Common scenarios:
- Failed to acquire exclusive lock
- Failed to create or write temporary file
- Failed to replace original file atomically
Complete Usage Example
Lock Behavior
TheFileHandler uses POSIX file locks via the portalocker library:
| Operation | Lock Type | Behavior |
|---|---|---|
read() | Shared (LOCK_SH) | Multiple readers allowed, blocks if exclusive lock held |
write() | Exclusive (LOCK_EX) | Blocks all other readers and writers |
{filename}.md.lock in the same directory as the target file.
Thread Safety
TheFileHandler is thread-safe for concurrent reads and writes:
- Multiple threads can read simultaneously (shared locks)
- Write operations are serialized (exclusive locks)
- Atomic writes prevent partial file corruption
Source Reference
See the complete implementation inmarkdown_os/file_handler.py.