Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,6 @@
## 2026-06-25 - [Optimize Path.exists() when paired with stat()]
**Learning:** Checking `Path.exists()` before `Path.stat()` introduces a redundant system call because `exists()` internally uses `stat()`.
**Action:** Rely on catching the `OSError` from `Path.stat()` to simultaneously check for existence and retrieve file attributes, saving measurable I/O overhead on large filesystems.
## 2026-07-02 - [Avoid pathlib.Path.resolve() in performance critical paths]
**Learning:** `pathlib.Path.resolve()` is significantly slower than `os.path.realpath()` because it instantiates a new `Path` object and resolves symlinks explicitly. In tight loops or batch processing involving thousands of files, this overhead is noticeable.
**Action:** Use `os.path.realpath(path_str)` directly instead of `pathlib.Path(path_str).resolve()` when performance is a priority and you only need the resolved path string. Convert to a `Path` object only when necessary.
10 changes: 5 additions & 5 deletions media_shrinker.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ def find_candidates(
"""

root = Path(root)
excluded = tuple(Path(item).resolve() for item in exclude_paths)
excluded = tuple(Path(os.path.realpath(item)) for item in exclude_paths)
excluded_prefixes = tuple(prefix.casefold() for prefix in exclude_dir_prefixes)
candidates: list[tuple[Path, int]] = []

Expand Down Expand Up @@ -759,7 +759,7 @@ def convert_file(

resolved_sources = resolved_protected_sources
if resolved_sources is None:
resolved_sources = frozenset(Path(item).resolve() for item in protected_sources)
resolved_sources = frozenset(Path(os.path.realpath(item)) for item in protected_sources)

return [
_convert_segment(
Expand Down Expand Up @@ -1261,7 +1261,7 @@ def _execute_conversions(
workers = choose_worker_count(args.workers)
ffmpeg_threads = args.ffmpeg_threads if args.ffmpeg_threads >= 0 else None

resolved_candidates = frozenset(Path(item[0]).resolve() for item in candidates)
resolved_candidates = frozenset(Path(os.path.realpath(item[0])) for item in candidates)
protected_sources = [c[0] for c in candidates]

def process_candidate(candidate_tuple: tuple[Path, int]) -> list[ConversionResult]:
Expand Down Expand Up @@ -1417,7 +1417,7 @@ def _ensure_not_protected_source_path(
protected_sources: frozenset[Path], output: Path
) -> None:
"""Raise MediaShrinkerError if output would overwrite a protected source."""
resolved_output = output.resolve()
resolved_output = Path(os.path.realpath(output))
if resolved_output in protected_sources:
raise MediaShrinkerError(
f"Refusing to use protected source path as generated output: {output}"
Expand Down Expand Up @@ -1613,7 +1613,7 @@ def _execute_plan(
def _ensure_not_source_path(source: Path, output: Path) -> None:
"""Reject generated paths that would overwrite or delete the source file."""

if source.resolve() == output.resolve():
if os.path.realpath(source) == os.path.realpath(output):
raise MediaShrinkerError(
f"Refusing to use source path as generated output: {output}"
)
Expand Down
Loading