Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate sub created events only if recursive=True #454

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/watchdog/observers/read_directory_changes.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def queue_events(self, timeout):
isdir = os.path.isdir(src_path)
cls = DirCreatedEvent if isdir else FileCreatedEvent
self.queue_event(cls(src_path))
if isdir:
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
Expand Down
6 changes: 3 additions & 3 deletions tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
import unittest

try:
from Queue import Queue # Python 2
from Queue import Queue, Empty # Python 2
except ImportError:
from queue import Queue # Python 3
from queue import Queue, Empty # Python 3

__all__ = ["unittest", "Queue"]
__all__ = ["unittest", "Queue", "Empty"]
146 changes: 111 additions & 35 deletions tests/test_emitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import time
import pytest
import logging
from tests import Queue
from tests import Queue, Empty
from functools import partial
from .shell import mkdir, touch, mv, rm, mkdtemp
from watchdog.utils import platform
Expand All @@ -43,8 +43,12 @@
elif platform.is_darwin():
pytestmark = pytest.mark.skip("FIXME: It is a matter of bad comparisons between bytes and str.")
from watchdog.observers.fsevents2 import FSEventsEmitter as Emitter
elif platform.is_windows():
from watchdog.observers.read_directory_changes import (
WindowsApiEmitter as Emitter
)
else:
pytestmark = pytest.mark.skip("GNU/Linux and macOS only.")
pytestmark = pytest.mark.skip("GNU/Linux, macOS and Windows only.")

logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
Expand All @@ -57,16 +61,16 @@ def setup_function(function):
event_queue = Queue()


def start_watching(path=None, use_full_emitter=False):
def start_watching(path=None, use_full_emitter=False, recursive=True):
path = p('') if path is None else path
global emitter
if platform.is_linux() and use_full_emitter:
emitter = InotifyFullEmitter(event_queue, ObservedWatch(path, recursive=True))
emitter = InotifyFullEmitter(event_queue, ObservedWatch(path, recursive=recursive))
else:
emitter = Emitter(event_queue, ObservedWatch(path, recursive=True))
emitter = Emitter(event_queue, ObservedWatch(path, recursive=recursive))

if platform.is_darwin():
# FSEvents will report old evens (like create for mkdtemp in test
# FSEvents will report old events (like create for mkdtemp in test
# setup. Waiting for a considerable time seems to 'flush' the events.
time.sleep(10)
emitter.start()
Expand All @@ -87,9 +91,10 @@ def test_create():
assert event.src_path == p('a')
assert isinstance(event, FileCreatedEvent)

event = event_queue.get(timeout=5)[0]
assert os.path.normpath(event.src_path) == os.path.normpath(p(''))
assert isinstance(event, DirModifiedEvent)
if not platform.is_windows():
event = event_queue.get(timeout=5)[0]
assert os.path.normpath(event.src_path) == os.path.normpath(p(''))
assert isinstance(event, DirModifiedEvent)


def test_delete():
Expand All @@ -101,9 +106,10 @@ def test_delete():
assert event.src_path == p('a')
assert isinstance(event, FileDeletedEvent)

event = event_queue.get(timeout=5)[0]
assert os.path.normpath(event.src_path) == os.path.normpath(p(''))
assert isinstance(event, DirModifiedEvent)
if not platform.is_windows():
event = event_queue.get(timeout=5)[0]
assert os.path.normpath(event.src_path) == os.path.normpath(p(''))
assert isinstance(event, DirModifiedEvent)


def test_modify():
Expand All @@ -121,98 +127,137 @@ def test_move():
mkdir(p('dir2'))
touch(p('dir1', 'a'))
start_watching()

mv(p('dir1', 'a'), p('dir2', 'b'))

event = event_queue.get(timeout=5)[0]
assert event.src_path == p('dir1', 'a')
assert event.dest_path == p('dir2', 'b')
assert isinstance(event, FileMovedEvent)
if not platform.is_windows():
event = event_queue.get(timeout=5)[0]
assert event.src_path == p('dir1', 'a')
assert event.dest_path == p('dir2', 'b')
assert isinstance(event, FileMovedEvent)
else:
event = event_queue.get(timeout=5)[0]
assert event.src_path == p('dir1', 'a')
assert isinstance(event, FileDeletedEvent)
event = event_queue.get(timeout=5)[0]
assert event.src_path == p('dir2', 'b')
assert isinstance(event, FileCreatedEvent)

event = event_queue.get(timeout=5)[0]
assert event.src_path == p('dir1')
assert event.src_path in [p('dir1'), p('dir2')]
assert isinstance(event, DirModifiedEvent)

event = event_queue.get(timeout=5)[0]
assert event.src_path == p('dir2')
assert isinstance(event, DirModifiedEvent)
if not platform.is_windows():
event = event_queue.get(timeout=5)[0]
assert event.src_path in [p('dir1'), p('dir2')]
assert isinstance(event, DirModifiedEvent)


def test_move_to():
mkdir(p('dir1'))
mkdir(p('dir2'))
touch(p('dir1', 'a'))
start_watching(p('dir2'))

mv(p('dir1', 'a'), p('dir2', 'b'))

event = event_queue.get(timeout=5)[0]
assert isinstance(event, FileCreatedEvent)
assert event.src_path == p('dir2', 'b')
assert isinstance(event, FileCreatedEvent)

if not platform.is_windows():
event = event_queue.get(timeout=5)[0]
assert event.src_path == p('dir2')
assert isinstance(event, DirModifiedEvent)


@pytest.mark.skipif(platform.is_windows(), reason="InotifyFullEmitter not supported by Windows")
def test_move_to_full():
mkdir(p('dir1'))
mkdir(p('dir2'))
touch(p('dir1', 'a'))
start_watching(p('dir2'), use_full_emitter=True)
mv(p('dir1', 'a'), p('dir2', 'b'))

event = event_queue.get(timeout=5)[0]
assert isinstance(event, FileMovedEvent)
assert event.dest_path == p('dir2', 'b')
assert event.src_path == None #Should equal none since the path was not watched
assert event.src_path is None # Should equal None since the path was not watched


def test_move_from():
mkdir(p('dir1'))
mkdir(p('dir2'))
touch(p('dir1', 'a'))
start_watching(p('dir1'))

mv(p('dir1', 'a'), p('dir2', 'b'))

event = event_queue.get(timeout=5)[0]
assert isinstance(event, FileDeletedEvent)
assert event.src_path == p('dir1', 'a')


if not platform.is_windows():
event = event_queue.get(timeout=5)[0]
assert event.src_path == p('dir1')
assert isinstance(event, DirModifiedEvent)


@pytest.mark.skipif(platform.is_windows(), reason="InotifyFullEmitter not supported by Windows")
def test_move_from_full():
mkdir(p('dir1'))
mkdir(p('dir2'))
touch(p('dir1', 'a'))
start_watching(p('dir1'), use_full_emitter=True)
mv(p('dir1', 'a'), p('dir2', 'b'))

event = event_queue.get(timeout=5)[0]
assert isinstance(event, FileMovedEvent)
assert event.src_path == p('dir1', 'a')
assert event.dest_path == None #Should equal None since path not watched
assert event.dest_path == None # Should equal None since path not watched


def test_separate_consecutive_moves():
mkdir(p('dir1'))
touch(p('dir1', 'a'))
touch(p('b'))

start_watching(p('dir1'))

mv(p('dir1', 'a'), p('c'))
mv(p('b'), p('dir1', 'd'))

event = event_queue.get(timeout=5)[0]
assert isinstance(event, FileDeletedEvent)
assert event.src_path == p('dir1', 'a')
assert isinstance(event, FileDeletedEvent)

assert isinstance(event_queue.get(timeout=5)[0], DirModifiedEvent)
if not platform.is_windows():
event = event_queue.get(timeout=5)[0]
assert event.src_path == p('dir1')
assert isinstance(event, DirModifiedEvent)

event = event_queue.get(timeout=5)[0]
assert isinstance(event, FileCreatedEvent)
assert event.src_path == p('dir1', 'd')
assert isinstance(event, FileCreatedEvent)

assert isinstance(event_queue.get(timeout=5)[0], DirModifiedEvent)
if not platform.is_windows():
event = event_queue.get(timeout=5)[0]
assert event.src_path == p('dir1')
assert isinstance(event, DirModifiedEvent)


@pytest.mark.skipif(platform.is_linux(), reason="bug. inotify will deadlock")
@pytest.mark.skipif(platform.is_windows(), reason="""
WindowsError: [Error 5]
access denied when trying delete directory dir1, because them opened by test
via start_watching.""")
def test_delete_self():
mkdir(p('dir1'))
start_watching(p('dir1'))
rm(p('dir1'), True)
event_queue.get(timeout=5)[0]

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


@pytest.mark.skipif(platform.is_windows(),
reason="Windows create another set of events for this test")
def test_fast_subdirectory_creation_deletion():
root_dir = p('dir1')
sub_dir = p('dir1', 'subdir1')
Expand Down Expand Up @@ -248,8 +293,39 @@ def test_passing_unicode_should_give_unicode():
assert isinstance(event.src_path, str_cls)


@pytest.mark.skipif(platform.is_windows(),
reason="Windows ReadDirectoryChangesW supports only"
" unicode for paths.")
def test_passing_bytes_should_give_bytes():
start_watching(p('').encode())
touch(p('a'))
event = event_queue.get(timeout=5)[0]
assert isinstance(event.src_path, bytes)
assert isinstance(event.src_path, bytes)


def test_recursive_on():
mkdir(p('dir1', 'dir2', 'dir3'), True)
start_watching()
touch(p('dir1', 'dir2', 'dir3', 'a'))

event = event_queue.get(timeout=5)[0]
assert event.src_path == p('dir1', 'dir2', 'dir3', 'a')
assert isinstance(event, FileCreatedEvent)

if not platform.is_windows():
event = event_queue.get(timeout=5)[0]
assert event.src_path == p('dir1', 'dir2', 'dir3')
assert isinstance(event, DirModifiedEvent)

event = event_queue.get(timeout=5)[0]
assert event.src_path == p('dir1', 'dir2', 'dir3', 'a')
assert isinstance(event, FileModifiedEvent)


def test_recursive_off():
mkdir(p('dir1'))
start_watching(recursive=False)
touch(p('dir1', 'a'))

with pytest.raises(Empty):
event_queue.get(timeout=5)