Skip to content

Commit

Permalink
[windows] Remove the WATCHDOG_TRAVERSE_MOVED_DIR_DELAY hack (#986)
Browse files Browse the repository at this point in the history
The `observers.read_directory_changes.WATCHDOG_TRAVERSE_MOVED_DIR_DELAY` hack was removed.
The constant will be kept to prevent breaking other softwares.
  • Loading branch information
BoboTiG committed Apr 22, 2023
1 parent 41fca1e commit 363fe62
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 103 deletions.
1 change: 1 addition & 0 deletions changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Changelog
- [events] Log ``FileOpenedEvent``, and ``FileClosedEvent``, events in ``LoggingEventHandler``
- [tests] Improve ``FileSystemEvent`` coverage
- [watchmedo] Log all events in ``LoggerTrick``
- [windows] The ``observers.read_directory_changes.WATCHDOG_TRAVERSE_MOVED_DIR_DELAY`` hack was removed. The constant will be kept to prevent breaking other softwares.
- Thanks to our beloved contributors: @BoboTiG

3.0.0
Expand Down
29 changes: 6 additions & 23 deletions src/watchdog/observers/read_directory_changes.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import platform
import sys
import threading
import time

from watchdog.events import (
DirCreatedEvent,
Expand All @@ -40,7 +39,7 @@

from watchdog.observers.winapi import close_directory_handle, get_directory_handle, read_events # noqa: E402

# HACK:
# Obsolete constant, it's no more used since v4.0.0.
WATCHDOG_TRAVERSE_MOVED_DIR_DELAY = 1 # seconds


Expand All @@ -62,8 +61,10 @@ def on_thread_start(self):

def start(self):
"""PyPy needs some time before receiving events, see #792."""
from time import sleep

super().start()
time.sleep(0.01)
sleep(0.01)

def on_thread_stop(self):
if self._handle:
Expand All @@ -85,23 +86,10 @@ def queue_events(self, timeout):
dest_path = src_path
src_path = last_renamed_src_path
if os.path.isdir(dest_path):
event = DirMovedEvent(src_path, dest_path)
self.queue_event(DirMovedEvent(src_path, dest_path))
if self.watch.is_recursive:
# HACK: We introduce a forced delay before
# traversing the moved directory. This will read
# only file movement that finishes within this
# delay time.
time.sleep(WATCHDOG_TRAVERSE_MOVED_DIR_DELAY)
# The following block of code may not
# obtain moved events for the entire tree if
# the I/O is not completed within the above
# delay time. So, it's not guaranteed to work.
# TODO: Come up with a better solution, possibly
# a way to wait for I/O to complete before
# queuing events.
for sub_moved_event in generate_sub_moved_events(src_path, dest_path):
self.queue_event(sub_moved_event)
self.queue_event(event)
else:
self.queue_event(FileMovedEvent(src_path, dest_path))
elif winapi_event.is_modified:
Expand All @@ -112,12 +100,7 @@ def queue_events(self, timeout):
cls = DirCreatedEvent if isdir else FileCreatedEvent
self.queue_event(cls(src_path))
if isdir and self.watch.is_recursive:
# If a directory is moved from outside the watched folder to inside it
# we only get a created directory event out of it, not any events for its children
# so use the same hack as for file moves to get the child events
time.sleep(WATCHDOG_TRAVERSE_MOVED_DIR_DELAY)
sub_events = generate_sub_created_events(src_path)
for sub_created_event in sub_events:
for sub_created_event in generate_sub_created_events(src_path):
self.queue_event(sub_created_event)
elif winapi_event.is_removed:
self.queue_event(FileDeletedEvent(src_path))
Expand Down
89 changes: 9 additions & 80 deletions tests/test_emitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,7 @@

def rerun_filter(exc, *args):
time.sleep(5)
if issubclass(exc[0], Empty) and platform.is_windows():
return True

return False
return bool(issubclass(exc[0], Empty) and platform.is_windows())


@pytest.mark.flaky(max_runs=5, min_passes=1, rerun_filter=rerun_filter)
Expand Down Expand Up @@ -449,7 +446,7 @@ def test_recursive_off(
expect_event(DirModifiedEvent(p()))


@pytest.mark.skipif(platform.is_windows(), reason="Windows create another set of events for this test")
@pytest.mark.flaky(max_runs=5, min_passes=1, rerun_filter=rerun_filter)
def test_renaming_top_level_directory(
p: P,
event_queue: TestEventQueue,
Expand All @@ -460,17 +457,18 @@ def test_renaming_top_level_directory(

mkdir(p("a"))
expect_event(DirCreatedEvent(p("a")))
expect_event(DirModifiedEvent(p()))
if not platform.is_windows():
expect_event(DirModifiedEvent(p()))

mkdir(p("a", "b"))
expect_event(DirCreatedEvent(p("a", "b")))
expect_event(DirModifiedEvent(p("a")))

mv(p("a"), p("a2"))
expect_event(DirMovedEvent(p("a"), p("a2")))
expect_event(DirModifiedEvent(p()))
expect_event(DirModifiedEvent(p()))

if not platform.is_windows():
expect_event(DirModifiedEvent(p()))
expect_event(DirModifiedEvent(p()))
expect_event(DirMovedEvent(p("a", "b"), p("a2", "b"), is_synthetic=True))

if platform.is_bsd():
Expand All @@ -486,19 +484,8 @@ def test_renaming_top_level_directory(
break

assert all(
[
isinstance(
e,
(
FileCreatedEvent,
FileMovedEvent,
FileOpenedEvent,
DirModifiedEvent,
FileClosedEvent,
),
)
for e in events
]
isinstance(e, (FileCreatedEvent, FileMovedEvent, FileOpenedEvent, DirModifiedEvent, FileClosedEvent))
for e in events
)

for event in events:
Expand All @@ -511,64 +498,6 @@ def test_renaming_top_level_directory(
assert event.src_path == p("a2", "b")


@pytest.mark.flaky(max_runs=5, min_passes=1, rerun_filter=rerun_filter)
@pytest.mark.skipif(
not platform.is_windows(),
reason="Non-Windows create another set of events for this test",
)
def test_renaming_top_level_directory_on_windows(
p: P,
event_queue: TestEventQueue,
start_watching: StartWatching,
) -> None:
start_watching()

mkdir(p("a"))
event = event_queue.get(timeout=5)[0]
assert isinstance(event, DirCreatedEvent)
assert event.src_path == p("a")

mkdir(p("a", "b"))
event = event_queue.get(timeout=5)[0]
assert isinstance(event, DirCreatedEvent)
assert event.src_path == p("a", "b")

event = event_queue.get(timeout=5)[0]
assert isinstance(event, DirCreatedEvent)
assert event.src_path == p("a", "b")

event = event_queue.get(timeout=5)[0]
assert isinstance(event, DirModifiedEvent)
assert event.src_path == p("a")

mv(p("a"), p("a2"))
event = event_queue.get(timeout=5)[0]
assert isinstance(event, DirMovedEvent)
assert event.src_path == p("a", "b")

open(p("a2", "b", "c"), "a").close()

events = []
while True:
events.append(event_queue.get(timeout=5)[0])
if event_queue.empty():
break

assert all(isinstance(e, (FileCreatedEvent, FileMovedEvent, DirMovedEvent, DirModifiedEvent)) for e in events)

for event in events:
if isinstance(event, FileCreatedEvent):
assert event.src_path == p("a2", "b", "c")
elif isinstance(event, FileMovedEvent):
assert event.dest_path == p("a2", "b", "c")
assert event.src_path == p("a", "b", "c")
elif isinstance(event, DirMovedEvent):
assert event.dest_path == p("a2")
assert event.src_path == p("a")
elif isinstance(event, DirModifiedEvent):
assert event.src_path == p("a2", "b")


@pytest.mark.skipif(platform.is_windows(), reason="Windows create another set of events for this test")
def test_move_nested_subdirectories(
p: P,
Expand Down

0 comments on commit 363fe62

Please sign in to comment.