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

emit a FileClosedEvent when a file is closed (inotify-only feature) #245

Closed
wants to merge 1 commit into from
Closed
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
49 changes: 30 additions & 19 deletions src/watchdog/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
EVENT_TYPE_DELETED = 'deleted'
EVENT_TYPE_CREATED = 'created'
EVENT_TYPE_MODIFIED = 'modified'
EVENT_TYPE_CLOSED = 'closed'


class FileSystemEvent(object):
Expand Down Expand Up @@ -216,7 +217,19 @@ class FileModifiedEvent(FileSystemEvent):
def __init__(self, src_path):
super(FileModifiedEvent, self).__init__(event_type=EVENT_TYPE_MODIFIED,
src_path=src_path)
def __repr__(self):
return ("<%(class_name)s: src_path=%(src_path)s>"
) % (dict(class_name=self.__class__.__name__,
src_path=self.src_path))


class FileClosedEvent(FileSystemEvent):

"""File system event representing file deletion on the file system."""

def __init__(self, src_path):
super(FileClosedEvent, self).__init__(event_type=EVENT_TYPE_CLOSED,
src_path=src_path)
def __repr__(self):
return ("<%(class_name)s: src_path=%(src_path)s>"
) % (dict(class_name=self.__class__.__name__,
Expand All @@ -230,7 +243,6 @@ class FileCreatedEvent(FileSystemEvent):
def __init__(self, src_path):
super(FileCreatedEvent, self).__init__(event_type=EVENT_TYPE_CREATED,
src_path=src_path)

def __repr__(self):
return ("<%(class_name)s: src_path=%(src_path)s>"
) % (dict(class_name=self.__class__.__name__,
Expand Down Expand Up @@ -353,6 +365,7 @@ def dispatch(self, event):
self.on_any_event(event)
_method_map = {
EVENT_TYPE_MODIFIED: self.on_modified,
EVENT_TYPE_CLOSED: self.on_closed,
EVENT_TYPE_MOVED: self.on_moved,
EVENT_TYPE_CREATED: self.on_created,
EVENT_TYPE_DELETED: self.on_deleted,
Expand Down Expand Up @@ -405,6 +418,15 @@ def on_modified(self, event):
:class:`DirModifiedEvent` or :class:`FileModifiedEvent`
"""

def on_closed(self, event):
"""Called when a file is closed (inotify only).

:param event:
Event representing file modification.
:type event:
:class:`FileClosedEvent`
"""


class PatternMatchingEventHandler(FileSystemEventHandler):

Expand Down Expand Up @@ -475,15 +497,7 @@ def dispatch(self, event):
included_patterns=self.patterns,
excluded_patterns=self.ignore_patterns,
case_sensitive=self.case_sensitive):
self.on_any_event(event)
_method_map = {
EVENT_TYPE_MODIFIED: self.on_modified,
EVENT_TYPE_MOVED: self.on_moved,
EVENT_TYPE_CREATED: self.on_created,
EVENT_TYPE_DELETED: self.on_deleted,
}
event_type = event.event_type
_method_map[event_type](event)
super(PatternMatchingEventHandler, self).dispatch(event)


class RegexMatchingEventHandler(FileSystemEventHandler):
Expand Down Expand Up @@ -559,15 +573,7 @@ def dispatch(self, event):
return

if any(r.match(p) for r in self.regexes for p in paths):
self.on_any_event(event)
_method_map = {
EVENT_TYPE_MODIFIED: self.on_modified,
EVENT_TYPE_MOVED: self.on_moved,
EVENT_TYPE_CREATED: self.on_created,
EVENT_TYPE_DELETED: self.on_deleted,
}
event_type = event.event_type
_method_map[event_type](event)
super(RegexMatchingEventHandler, self).dispatch(event)


class LoggingEventHandler(FileSystemEventHandler):
Expand Down Expand Up @@ -599,6 +605,11 @@ def on_modified(self, event):
what = 'directory' if event.is_directory else 'file'
logging.info("Modified %s: %s", what, event.src_path)

def on_closed(self, event):
super(LoggingEventHandler, self).on_closed(event)

logging.info("Closed file: %s", event.src_path)


class LoggingFileSystemEventHandler(LoggingEventHandler):

Expand Down
4 changes: 4 additions & 0 deletions src/watchdog/observers/inotify.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
DirCreatedEvent,
FileDeletedEvent,
FileModifiedEvent,
FileClosedEvent,
FileMovedEvent,
FileCreatedEvent
)
Expand Down Expand Up @@ -139,6 +140,9 @@ def queue_events(self, timeout):
elif event.is_modify:
cls = DirModifiedEvent if event.is_directory else FileModifiedEvent
self.queue_event(cls(event.src_path))
elif event.is_close and not event.is_directory:
cls = FileClosedEvent
self.queue_event(cls(event.src_path))
elif event.is_delete_self:
cls = DirDeletedEvent if event.is_directory else FileDeletedEvent
self.queue_event(cls(event.src_path))
Expand Down
7 changes: 5 additions & 2 deletions src/watchdog/observers/inotify_c.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ class InotifyConstants(object):
IN_MOVE_SELF = 0x00000800 # Self was moved.

# Helper user-space events.
IN_CLOSE = IN_CLOSE_WRITE | IN_CLOSE_NOWRITE # Close.
IN_MOVE = IN_MOVED_FROM | IN_MOVED_TO # Moves.

# Events sent by the kernel to a watch.
Expand Down Expand Up @@ -495,6 +494,10 @@ def name(self):
def is_modify(self):
return self._mask & InotifyConstants.IN_MODIFY > 0

@property
def is_close(self):
return self.is_close_write or self.is_close_nowrite

@property
def is_close_write(self):
return self._mask & InotifyConstants.IN_CLOSE_WRITE > 0
Expand Down Expand Up @@ -574,7 +577,7 @@ def __hash__(self):
def _get_mask_string(self, mask):
masks = []
for c in dir(InotifyConstants):
if c.startswith('IN_') and c not in ['IN_ALL_EVENTS', 'IN_CLOSE', 'IN_MOVE']:
if c.startswith('IN_') and c not in ['IN_ALL_EVENTS', 'IN_MOVE']:
c_val = getattr(InotifyConstants, c)
if mask & c_val:
masks.append(c)
Expand Down