MCPcopy Create free account
hub / github.com/VectifyAI/OpenKB / DebouncedHandler

Class DebouncedHandler

openkb/watcher.py:17–77  ·  view source on GitHub ↗

Debounced file-system event handler. Collects file creation/modification events and waits *debounce_seconds* after the last event before calling *callback* with all pending paths. Directories and dotfiles (hidden files) are ignored. Args: callback: Called with a sorted list

Source from the content-addressed store, hash-verified

15
16
17class DebouncedHandler(FileSystemEventHandler):
18 """Debounced file-system event handler.
19
20 Collects file creation/modification events and waits *debounce_seconds*
21 after the last event before calling *callback* with all pending paths.
22 Directories and dotfiles (hidden files) are ignored.
23
24 Args:
25 callback: Called with a sorted list of path strings when the debounce
26 timer fires.
27 debounce_seconds: How long to wait after the last event before
28 flushing. Defaults to 2.0 seconds.
29 """
30
31 def __init__(
32 self, callback: Callable[[list[str]], None], debounce_seconds: float = 2.0
33 ) -> None:
34 super().__init__()
35 self._callback = callback
36 self._debounce_seconds = debounce_seconds
37 self._pending: set[str] = set()
38 self._timer: threading.Timer | None = None
39 self._lock = threading.Lock()
40
41 def _schedule_flush(self) -> None:
42 """Cancel any existing timer and start a fresh debounce timer."""
43 with self._lock:
44 if self._timer is not None:
45 self._timer.cancel()
46 self._timer = threading.Timer(self._debounce_seconds, self._flush)
47 self._timer.daemon = True
48 self._timer.start()
49
50 def _flush(self) -> None:
51 """Call the callback with all collected pending paths, then clear."""
52 with self._lock:
53 paths = sorted(self._pending)
54 self._pending.clear()
55 self._timer = None
56 if paths:
57 self._callback(paths)
58
59 def _handle_event(self, event) -> None:
60 """Add the event's source path to pending if it's a supported file."""
61 if event.is_directory:
62 return
63 path = Path(event.src_path)
64 # Ignore hidden/dotfiles
65 if path.name.startswith("."):
66 return
67 with self._lock:
68 self._pending.add(str(path))
69 self._schedule_flush()
70
71 def on_created(self, event) -> None:
72 """Handle file creation events."""
73 self._handle_event(event)
74

Calls

no outgoing calls