diff --git a/changelog.rst b/changelog.rst index ded4e9e6d..52aef8267 100644 --- a/changelog.rst +++ b/changelog.rst @@ -10,7 +10,8 @@ Changelog - Add logger parameter for the LoggingEventHandler (`#676 `_) - Replace mutable default arguments with ``if None`` implementation (`#677 `_) -- Thanks to our beloved contributors: @Sraw +- [inotify] Add events for IN_WRITE_CLOSE and IN_NOWRITE_CLOSE (`#690 `) +- Thanks to our beloved contributors: @Sraw, @lukassup 0.10.3 diff --git a/src/watchdog/events.py b/src/watchdog/events.py index 766cca050..db2c92ac9 100755 --- a/src/watchdog/events.py +++ b/src/watchdog/events.py @@ -52,6 +52,10 @@ :members: :show-inheritance: +.. autoclass:: FileClosedEvent + :members: + :show-inheritance: + .. autoclass:: DirCreatedEvent :members: :show-inheritance: @@ -97,6 +101,7 @@ EVENT_TYPE_DELETED = 'deleted' EVENT_TYPE_CREATED = 'created' EVENT_TYPE_MODIFIED = 'modified' +EVENT_TYPE_CLOSED = 'closed' class FileSystemEvent(object): @@ -248,6 +253,19 @@ def __repr__(self): dest_path=self.dest_path)) +class FileClosedEvent(FileSystemEvent): + """File system event representing file close on the file system.""" + + event_type = EVENT_TYPE_CLOSED + + def __init__(self, src_path): + super(FileClosedEvent, self).__init__(src_path) + + def __repr__(self): + return ("<%(class_name)s: src_path=%(src_path)r>" + ) % (dict(class_name=self.__class__.__name__, + src_path=self.src_path)) + # Directory events. diff --git a/src/watchdog/observers/inotify.py b/src/watchdog/observers/inotify.py index 68ffa66ea..f710d79c0 100644 --- a/src/watchdog/observers/inotify.py +++ b/src/watchdog/observers/inotify.py @@ -89,6 +89,7 @@ FileModifiedEvent, FileMovedEvent, FileCreatedEvent, + FileClosedEvent, generate_sub_moved_events, generate_sub_created_events, ) @@ -174,6 +175,13 @@ 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_close_write and not event.is_directory: + cls = FileClosedEvent + self.queue_event(cls(src_path)) + self.queue_event(DirModifiedEvent(os.path.dirname(src_path))) + elif event.is_close_nowrite and not event.is_directory: + cls = FileClosedEvent + self.queue_event(cls(src_path)) def _decode_path(self, path): """ Decode path only if unicode string was passed to this emitter. """ diff --git a/tests/test_events.py b/tests/test_events.py index fe02f3e46..b9ba8cb86 100644 --- a/tests/test_events.py +++ b/tests/test_events.py @@ -20,6 +20,7 @@ FileDeletedEvent, FileModifiedEvent, FileCreatedEvent, + FileClosedEvent, DirDeletedEvent, DirModifiedEvent, DirCreatedEvent, @@ -30,6 +31,7 @@ EVENT_TYPE_CREATED, EVENT_TYPE_DELETED, EVENT_TYPE_MOVED, + EVENT_TYPE_CLOSED, ) path_1 = '/path/xyz' @@ -82,6 +84,12 @@ def test_file_moved_event(): assert not event.is_directory assert not event.is_synthetic +def test_file_closed_event(): + event = FileClosedEvent(path_1) + assert path_1 == event.src_path + assert EVENT_TYPE_CLOSED == event.event_type + assert not event.is_directory + assert not event.is_synthetic def test_dir_deleted_event(): event = DirDeletedEvent(path_1) @@ -112,6 +120,7 @@ def test_file_system_event_handler_dispatch(): file_del_event = FileDeletedEvent('/path/blah.txt') dir_cre_event = DirCreatedEvent('/path/blah.py') file_cre_event = FileCreatedEvent('/path/blah.txt') + file_cls_event = FileClosedEvent('/path/blah.txt') dir_mod_event = DirModifiedEvent('/path/blah.py') file_mod_event = FileModifiedEvent('/path/blah.txt') dir_mov_event = DirMovedEvent('/path/blah.py', '/path/blah') @@ -126,6 +135,7 @@ def test_file_system_event_handler_dispatch(): file_del_event, file_cre_event, file_mov_event, + file_cls_event, ] class TestableEventHandler(FileSystemEventHandler): @@ -145,6 +155,9 @@ def on_moved(self, event): def on_created(self, event): assert event.event_type == EVENT_TYPE_CREATED + def on_closed(self, event): + assert event.event_type == EVENT_TYPE_CLOSED + handler = TestableEventHandler() for event in all_events: