From 614d52736e827872ba56a4eb98527f0187bd4fa8 Mon Sep 17 00:00:00 2001 From: Chris Angelico Date: Tue, 10 Oct 2023 05:38:20 +1100 Subject: [PATCH 1/4] Force FSEvents to use recursive mode to ensure that events are delivered --- src/watchdog/observers/fsevents.py | 6 ++++-- tests/test_fsevents.py | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/watchdog/observers/fsevents.py b/src/watchdog/observers/fsevents.py index 40dce1ad..5c5d30d7 100644 --- a/src/watchdog/observers/fsevents.py +++ b/src/watchdog/observers/fsevents.py @@ -337,9 +337,11 @@ class FSEventsObserver(BaseObserver): def __init__(self, timeout=DEFAULT_OBSERVER_TIMEOUT): super().__init__(emitter_class=FSEventsEmitter, timeout=timeout) - def schedule(self, event_handler, path, recursive=False): + def schedule(self, event_handler, path, recursive=True): # Fix for issue #26: Trace/BPT error when given a unicode path # string. https://github.com/gorakhargosh/watchdog/issues#issue/26 if isinstance(path, str): path = unicodedata.normalize("NFC", path) - return BaseObserver.schedule(self, event_handler, path, recursive) + if not recursive: + warnings.warn("FSEvents requires and assumes recursive=True") + return BaseObserver.schedule(self, event_handler, path, recursive=True) diff --git a/tests/test_fsevents.py b/tests/test_fsevents.py index e2ddefeb..081ef533 100644 --- a/tests/test_fsevents.py +++ b/tests/test_fsevents.py @@ -327,3 +327,9 @@ def on_any_event(self, event): observer.unschedule(watch) observer.stop() observer.join(1) + +def test_watchdog_assumes_recursive(p: P) -> None: + """See https://github.com/gorakhargosh/watchdog/issues/918""" + observer = Observer() + w = observer.schedule(FileSystemEventHandler(), ".") + assert w.is_recursive, "FSEvents should assume recursive mode" From 04f687c298ad973c91de4b4ee303b70ac651d1ec Mon Sep 17 00:00:00 2001 From: Chris Angelico Date: Tue, 10 Oct 2023 07:26:45 +1100 Subject: [PATCH 2/4] Import warnings (duh) --- src/watchdog/observers/fsevents.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/watchdog/observers/fsevents.py b/src/watchdog/observers/fsevents.py index 5c5d30d7..b3b434b0 100644 --- a/src/watchdog/observers/fsevents.py +++ b/src/watchdog/observers/fsevents.py @@ -343,5 +343,6 @@ def schedule(self, event_handler, path, recursive=True): if isinstance(path, str): path = unicodedata.normalize("NFC", path) if not recursive: + import warnings warnings.warn("FSEvents requires and assumes recursive=True") return BaseObserver.schedule(self, event_handler, path, recursive=True) From fba678fd18136bf1694f87c1726294920ea7ad5f Mon Sep 17 00:00:00 2001 From: Chris Angelico Date: Tue, 10 Oct 2023 09:09:22 +1100 Subject: [PATCH 3/4] Allow all tests to be run with recursive=True --- tests/test_fsevents.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_fsevents.py b/tests/test_fsevents.py index 081ef533..355799f2 100644 --- a/tests/test_fsevents.py +++ b/tests/test_fsevents.py @@ -78,7 +78,7 @@ def test_add_watch_twice(observer: BaseObserver, p: P) -> None: a = p("a") mkdir(a) h = FileSystemEventHandler() - w = ObservedWatch(a, recursive=False) + w = ObservedWatch(a) def callback(path, inodes, flags, ids): pass @@ -219,7 +219,7 @@ def on_thread_stop(self): """ a = p("a") mkdir(a) - w = observer.schedule(FileSystemEventHandler(), a, recursive=False) + w = observer.schedule(FileSystemEventHandler(), a) rmdir(a) time.sleep(0.1) observer.unschedule(w) From b59d7b4c7019f81e1ab86d539734e51164c70b87 Mon Sep 17 00:00:00 2001 From: Chris Angelico Date: Thu, 12 Oct 2023 19:32:42 +1100 Subject: [PATCH 4/4] Provide the parameter, since it's mandatory there --- tests/test_fsevents.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_fsevents.py b/tests/test_fsevents.py index 355799f2..4814ba86 100644 --- a/tests/test_fsevents.py +++ b/tests/test_fsevents.py @@ -78,7 +78,7 @@ def test_add_watch_twice(observer: BaseObserver, p: P) -> None: a = p("a") mkdir(a) h = FileSystemEventHandler() - w = ObservedWatch(a) + w = ObservedWatch(a, recursive=True) def callback(path, inodes, flags, ids): pass