You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CHANGELOG.md
+28-23Lines changed: 28 additions & 23 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -9,61 +9,66 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
10
10
No unreleased changes.
11
11
12
-
## [0.3.1] — 2026-06-05
12
+
## [0.4.0] — 2026-06-05
13
13
14
14
### Fixed
15
15
16
-
- SQLite cache files are now correctly excluded when the scan root is accessed through a symbolic link. Path comparison now uses `resolve(strict=False)` on both sides so symlinked and real paths map to the same canonical key.
17
-
-`-wal`, `-shm`, and `-journal` SQLite auxiliary files are excluded alongside the main cache database.
16
+
- Root symbolic links are rejected when symbolic link traversal is disabled (`follow_symlinks=False`), including directory and file symlinks used as the scan root.
17
+
- SQLite cache database and all auxiliary files (`-wal`, `-shm`, `-journal`) are excluded from scans.
18
+
- Cache exclusion works correctly when the scan root is accessed through a symbolic link, using `resolve(strict=False)` on both sides of the comparison.
19
+
- Internal path comparison during cache exclusion no longer raises `OSError` or `RuntimeError` on symlink loops or broken symlinks.
18
20
- PyPI publishing workflow (`publish.yml`) rewritten as valid YAML — the previous file contained Markdown code fences that made it unparseable by GitHub Actions.
21
+
- Public type annotations in `ScanOptions`, `ScanEvent`, and `ScanProgress` now resolve correctly on all supported Python versions via `get_type_hints()`.
19
22
20
23
### Changed
21
24
25
+
- Cancelled CLI scans return exit status `3`. Exit code `3` takes priority over `--fail-on-duplicates`.
22
26
- Minimum supported Python version raised from 3.9 to 3.10. The codebase uses `X | Y` union syntax broadly; requiring 3.10 makes this consistent and allows `get_type_hints()` to resolve annotations correctly at runtime.
23
-
-`ProgressPhase` values corrected to `"discovery"`, `"hashing"`, and `"done"` — the `"grouping"` phase mentioned in the previous changelog was never emitted.
27
+
-`ProgressPhase` values restricted to the phases actually emitted: `"discovery"`, `"hashing"`, and `"done"`.
28
+
29
+
### Removed
30
+
31
+
-`ScanEvent.from_cache` and `ScanEvent.bytes_read` fields removed. These fields were added in 0.3.0 but were never populated — they always remained at their default values (`False` and `0`). Removing them eliminates misleading API surface.
24
32
25
33
### Tooling
26
34
27
-
- CI restructured into three jobs: `quality` (Ruff lint + format check + Pyright), `tests` (matrix across Ubuntu/Windows/macOS and Python 3.10–3.13), and `package` (build, Twine check, `py.typed` verification, wheel smoke test).
35
+
- CI restructured into three jobs: `quality` (Ruff lint + format check + Pyright on Ubuntu), `tests` (matrix across Ubuntu, Windows, and macOS with Python 3.10–3.13), and `package` (build, Twine check, `py.typed` verification, wheel smoke test).
36
+
- Publishing workflow (`publish.yml`) now runs Ruff, Pyright, and full quality checks before building, so manual releases cannot skip linting.
28
37
-`pyyaml` added to development dependencies to enable workflow YAML validation in tests.
29
-
-New regression tests: symlink policy (directory and file roots, broken symlinks), cache exclusion through symlinked roots, WAL/SHM/journal exclusion, typing contract, cancellation exit codes, version consistency, `py.typed` marker, workflow YAML validation.
-`DupeFinder` class — integration-ready scan engine with typed events, cancellation, and optional hash cache.
36
45
-`ScanEvent` frozen dataclass — typed events emitted during each scan phase (`scan_started`, `file_discovered`, `file_hashed`, `duplicate_group_found`, `issue`, `scan_completed`, `scan_cancelled`).
37
-
-`ScanProgress` frozen dataclass — simplified progress snapshots delivered to the new `on_progress` callback. Fields: `root`, `phase` (`"discovery"`, `"hashing"`, `"done"`), `scanned_files`, `hashed_files`, `total_candidates`, `duplicate_groups`, `elapsed_seconds`, `cancelled`.
46
+
-`ScanEvent.from_cache` and `ScanEvent.bytes_read` fields (reserved; removed in 0.4.0).
47
+
-`ScanProgress` frozen dataclass — simplified progress snapshots delivered to the new `on_progress` callback. Fields: `root`, `phase`, `scanned_files`, `hashed_files`, `total_candidates`, `duplicate_groups`, `elapsed_seconds`, `cancelled`.
38
48
-`DupeFinder.on_progress` parameter — optional callback that receives a `ScanProgress` snapshot after each file discovered or hashed, and once more at the end with `phase="done"`.
39
49
-`ScanOptions.max_files` — stop file discovery after N files.
0 commit comments