Source code for hupper.watchdog

# check ``hupper.utils.is_watchdog_supported`` before using this module
from __future__ import absolute_import
import os.path
import threading
from watchdog.events import FileSystemEventHandler
from watchdog.observers import Observer

from .interfaces import IFileMonitor


[docs] class WatchdogFileMonitor(FileSystemEventHandler, Observer, IFileMonitor): """ An :class:`hupper.interfaces.IFileMonitor` that uses ``watchdog`` to watch for file changes uses inotify. ``callback`` is a callable that accepts a path to a changed file. ``logger`` is an :class:`hupper.interfaces.ILogger` instance. """ def __init__(self, callback, logger, **kw): super(WatchdogFileMonitor, self).__init__() self.callback = callback self.logger = logger self.paths = set() self.dirpaths = set() self.lock = threading.Lock() def add_path(self, path): with self.lock: dirpath = os.path.dirname(path) if dirpath not in self.dirpaths: try: self.schedule(self, dirpath) except OSError as ex: # pragma: no cover # watchdog raises exceptions if folders are missing # or if the ulimit is passed self.logger.error('watchdog error: ' + str(ex)) else: self.dirpaths.add(dirpath) if path not in self.paths: self.paths.add(path) def _check(self, path): with self.lock: if path in self.paths: self.callback(path) def on_created(self, event): self._check(event.src_path) def on_modified(self, event): self._check(event.src_path) def on_moved(self, event): self._check(event.src_path) self._check(event.dest_path) self.add_path(event.dest_path) def on_deleted(self, event): self._check(event.src_path)