Fixed #1110 -- Do not report symlink create/delete as a move in DirectorySnapshotDiff#1176
Open
apoorvdarshan wants to merge 1 commit into
Open
Conversation
…ove in DirectorySnapshotDiff A new symlink shares its target's inode because the default stat function follows symlinks. The move-detection heuristic matched that shared inode and reported the creation of a symlink (or the removal of one whose target remains) as a move of the target file, so PollingObserver emitted a spurious FileMovedEvent instead of the create/delete event the native observers emit. Only treat an inode match as a move when the counterpart path is genuinely new (destination) or gone (source), leaving the move-replace behaviour intact. Added regression tests for both the create and delete symlink cases.
35f6744 to
a0fcba1
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #1110.
PollingObserverreported the creation of a new symlink as aFileMovedEventinstead of aFileCreatedEvent, diverging from the native (fsevents/inotify/winapi) observers.Root cause
DirectorySnapshotbuilds its inode index with the defaultstat=os.stat, which follows symlinks. A new symlink therefore reports the same(st_ino, st_dev)as its target.DirectorySnapshotDiff's move detection matches paths by inode, so whendata.trigger -> datais created, the created symlink's inode maps back to the still-presentdata, and the change is emitted as a movedata -> data.trigger(with an emptyfiles_created). The symmetric case — removing a symlink whose target remains — was reported as a move onto the target.Fix
Treat an inode match as a move only when the counterpart path is genuinely new (for the destination) or genuinely gone (for the source):
This leaves real moves — including the move-replace case where the destination pre-existed with a different inode (
test_move_replace) — unchanged, while symlinks/hard links that merely share a target's inode degrade to create/delete events, matching the native observers and the module's own "represent movement as created/deleted when inode logic breaks" note.Verification
test_create_symlink_to_existing_fileandtest_delete_symlink_to_existing_file(skipped on Windows, where symlinks need privileges). Both fail onmasterand pass with this change.tests/test_snapshot_diff.py: 15 passed (including the pre-existingtest_move_replace/test_move_internal).tests/test_observers_polling.pyandtests/test_observers_api.py: 9 passed.ruff checkandruff format --checkclean on the changed files.Disclosure: this change was prepared with AI assistance; I have reviewed and verified it locally against the test suite.