Skip to content

Commit

Permalink
[mac] Fix relative path handling for non-recursive watch in FSEventsO…
Browse files Browse the repository at this point in the history
…bserver (#799)

* Add test for issue #797

This works for me locally, let's see what the CI machine says.

* Use absolute watch path in recursive check

A watch path may be relative, while an event path is always absolute. Since the check for recursive events simply compared the watch path with the event path then that would fail in case the watch was set to a relative folder. This resolves the issue.

Fixes #797

* Add support for ~ in watch path

Same problem as relative paths.

* Update changelog.rst

Co-authored-by: Mickaël Schoentgen <contact@tiger-222.fr>
  • Loading branch information
CCP-Aporia and BoboTiG committed May 19, 2021
1 parent 50af6eb commit 8fb9409
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 5 deletions.
3 changes: 2 additions & 1 deletion changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ Changelog

2021-xx-xx • `full history <https://github.com/gorakhargosh/watchdog/compare/v2.1.2...master>`__

- [mac] Fix relative path handling for non-recursive watch. (`#797 <https://github.com/gorakhargosh/watchdog/pull/797>`_)
- [windows] On PyPy, events happening right after ``start()`` were missed. Add a workaround for that. (`#796 <https://github.com/gorakhargosh/watchdog/pull/796>`_)
- Thanks to our beloved contributors: @oprypin
- Thanks to our beloved contributors: @oprypin, @CCP-Aporia

2.1.1
~~~~~
Expand Down
5 changes: 3 additions & 2 deletions src/watchdog/observers/fsevents.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ def __init__(self, event_queue, watch, timeout=DEFAULT_EMITTER_TIMEOUT, suppress
self._start_time = 0.0
self._starting_state = None
self._lock = threading.Lock()
self._absolute_watch_path = os.path.abspath(os.path.expanduser(self.watch.path))

def on_thread_stop(self):
_fsevents.remove_watch(self.watch)
Expand All @@ -104,14 +105,14 @@ def queue_event(self, event):

def _is_recursive_event(self, event):
src_path = event.src_path if event.is_directory else os.path.dirname(event.src_path)
if src_path == self._watch.path:
if src_path == self._absolute_watch_path:
return False

if isinstance(event, (FileMovedEvent, DirMovedEvent)):
# when moving something into the watch path we must always take the dirname,
# otherwise we miss out on `DirMovedEvent`s
dest_path = os.path.dirname(event.dest_path)
if dest_path == self._watch.path:
if dest_path == self._absolute_watch_path:
return False

return True
Expand Down
56 changes: 54 additions & 2 deletions tests/test_fsevents.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ def teardown_function(function):
rm(p(""), recursive=True)


def start_watching(path=None, use_full_emitter=False):
def start_watching(path=None, recursive=True, use_full_emitter=False):
global emitter
path = p("") if path is None else path
emitter = FSEventsEmitter(event_queue, ObservedWatch(path, recursive=True), suppress_history=True)
emitter = FSEventsEmitter(event_queue, ObservedWatch(path, recursive=recursive), suppress_history=True)
emitter.start()


Expand Down Expand Up @@ -247,6 +247,58 @@ def test_converting_cfstring_to_pyunicode():
emitter.stop()


def test_recursive_check_accepts_relative_paths():
"""See https://github.com/gorakhargosh/watchdog/issues/797
The test code provided in the defect observes the current working directory
using ".". Since the watch path wasn't normalized then that failed.
This test emulates the scenario.
"""
from watchdog.events import (
PatternMatchingEventHandler,
FileCreatedEvent,
FileModifiedEvent
)

class TestEventHandler(PatternMatchingEventHandler):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# the TestEventHandler instance is set to ignore_directories,
# as such we won't get a DirModifiedEvent(p()) here.
self.expected_events = [
FileCreatedEvent(p('foo.json')),
FileModifiedEvent(p('foo.json'))
]
self.observed_events = set()

def on_any_event(self, event):
self.expected_events.remove(event)
self.observed_events.add(event)

def done(self):
return not self.expected_events

cwd = os.getcwd()
os.chdir(p())
event_handler = TestEventHandler(patterns=["*.json"], ignore_patterns=[], ignore_directories=True)
observer = Observer()
observer.schedule(event_handler, ".")
observer.start()
time.sleep(0.1)

try:
touch(p('foo.json'))
timeout_at = time.time() + 5
while not event_handler.done() and time.time() < timeout_at:
time.sleep(0.1)

assert event_handler.done()
finally:
os.chdir(cwd)
observer.stop()
observer.join()


def test_watchdog_recursive():
""" See https://github.com/gorakhargosh/watchdog/issues/706
"""
Expand Down

0 comments on commit 8fb9409

Please sign in to comment.