Skip to content

Commit

Permalink
Uniformize event for deletion of watched dir (#727)
Browse files Browse the repository at this point in the history
* monitor our own root

* properly handle root change event

* test on all platforms that root deleted event is emitted ...

... and that emitter is stopped

* basic test for root moved

* winapi: emit DirDeletedEvent of removed root

* removed leftover commented-out code

* expect KeyError when unscheduling removed watch

* propagate root deleted event in inotify

* remove `test_move_self`

* catch OSError when stopping watch in fixture

* adapt test_inotify_c to stopped emitter after delete_self

* don't emit root deleted for child watches
  • Loading branch information
SamSchott committed Dec 16, 2020
1 parent 1d7cb5d commit 2758815
Show file tree
Hide file tree
Showing 7 changed files with 38 additions and 8 deletions.
13 changes: 13 additions & 0 deletions src/watchdog/observers/fsevents.py
Expand Up @@ -123,6 +123,19 @@ def queue_events(self, timeout):
cls = DirDeletedEvent if event.is_directory else FileDeletedEvent
self.queue_event(cls(src_path))
self.queue_event(DirModifiedEvent(os.path.dirname(src_path)))

if src_path == self.watch.path:
# this should not really occur, instead we expect
# is_root_changed to be set
self.stop()

elif event.is_root_changed:
# This will be set if root or any if its parents is renamed or
# deleted.
# TODO: find out new path and generate DirMovedEvent?
self.queue_event(DirDeletedEvent(self.watch.path))
self.stop()

i += 1

def run(self):
Expand Down
3 changes: 3 additions & 0 deletions src/watchdog/observers/inotify.py
Expand Up @@ -170,6 +170,9 @@ def queue_events(self, timeout, full_events=False):
cls = DirCreatedEvent if event.is_directory else FileCreatedEvent
self.queue_event(cls(src_path))
self.queue_event(DirModifiedEvent(os.path.dirname(src_path)))
elif event.is_delete_self and src_path == self.watch.path:
self.queue_event(DirDeletedEvent(src_path))
self.stop()

def _decode_path(self, path):
"""Decode path only if unicode string was passed to this emitter. """
Expand Down
2 changes: 2 additions & 0 deletions src/watchdog/observers/read_directory_changes.py
Expand Up @@ -22,6 +22,7 @@

from watchdog.events import (
DirCreatedEvent,
DirDeletedEvent,
DirMovedEvent,
DirModifiedEvent,
FileCreatedEvent,
Expand Down Expand Up @@ -121,6 +122,7 @@ def queue_events(self, timeout):
elif winapi_event.is_removed:
self.queue_event(FileDeletedEvent(src_path))
elif winapi_event.is_removed_self:
self.queue_event(DirDeletedEvent(self.watch.path))
self.stop()


Expand Down
2 changes: 1 addition & 1 deletion src/watchdog_fsevents.c
Expand Up @@ -493,7 +493,7 @@ watchdog_FSEventStreamCreate(StreamCallbackInfo *stream_callback_info_ref,
paths,
kFSEventStreamEventIdSinceNow,
stream_latency,
kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents);
kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents | kFSEventStreamCreateFlagWatchRoot);
CFRelease(paths);
return stream_ref;
}
Expand Down
16 changes: 11 additions & 5 deletions tests/test_emitter.py
Expand Up @@ -64,7 +64,11 @@ def setup_teardown(tmpdir):

yield

emitter.stop()
try:
emitter.stop()
except OSError:
# watch was already stopped, e.g., in `test_delete_self`
pass
emitter.join(5)
assert not emitter.is_alive()

Expand Down Expand Up @@ -283,10 +287,12 @@ def test_delete_self():
start_watching(p('dir1'))
rm(p('dir1'), True)

if platform.is_darwin():
event = event_queue.get(timeout=5)[0]
assert event.src_path == p('dir1')
assert isinstance(event, FileDeletedEvent)
event = event_queue.get(timeout=5)[0]
assert event.src_path == p('dir1')
assert isinstance(event, DirDeletedEvent)

emitter.join(timeout=1)
assert not emitter.is_alive()


@pytest.mark.skipif(platform.is_windows() or platform.is_bsd(),
Expand Down
4 changes: 3 additions & 1 deletion tests/test_fsevents.py
Expand Up @@ -100,7 +100,9 @@ def on_thread_stop(self):
w = observer.schedule(FileSystemEventHandler(), a, recursive=False)
rmdir(a)
time.sleep(0.1)
observer.unschedule(w)
with pytest.raises(KeyError):
# watch no longer exists!
observer.unschedule(w)


def test_watchdog_recursive():
Expand Down
6 changes: 5 additions & 1 deletion tests/test_inotify_c.py
Expand Up @@ -40,7 +40,11 @@ def watching(path=None, use_full_emitter=False):
emitter = Emitter(event_queue, ObservedWatch(path, recursive=True))
emitter.start()
yield
emitter.stop()
try:
emitter.stop()
except OSError:
# watch was already stopped, e.g., because root was deleted
pass
emitter.join(5)


Expand Down

0 comments on commit 2758815

Please sign in to comment.