Source code for wxyz.dvcs.widget_watch

""" widgets for watching files
"""
import time

# pylint: disable=keyword-arg-before-vararg
from asyncio import Event
from pathlib import Path

import ipywidgets as W
import traitlets as T
from tornado.ioloop import IOLoop
from watchgod import DefaultDirWatcher, awatch


class _JupyterWatcher(DefaultDirWatcher):
    """a notebook-aware watcher

    TODO: this will need to be revisited... we might in fact want to watch
    more things
    """

    def should_watch_dir(self, entry):
        if not super().should_watch_dir(entry):
            return False
        return ".ipynb_checkpoints" not in str(entry)


[docs]class Watcher(W.Widget): """A lightweight watcher TODO: expose more bits """ path = T.Instance(Path, help="the root path to watch") watching = T.Bool(default_value=False, help="whether to be watching") changes = T.Tuple(help="the last changes that were detected", allow_none=True) _stop = T.Instance(Event, allow_none=True, help="the event to use for stopping") _watcher_cls = T.Any(default_value=_JupyterWatcher) def __init__(self, path=None, *args, **kwargs): kwargs["path"] = kwargs.get("path", Path(path)) super().__init__(*args, **kwargs) @T.default("changes") def _default_changes(self): return tuple() @T.observe("watching", "path") def _on_watching(self, change): """handle starting/stopping the watcher""" if self._stop is not None: self._stop.set() self.changes = None self._stop = None if change.new: IOLoop.current().add_callback(self._watch) def _changes(self, changes): """publish the changes. schedule to run in the loop""" self.changes = [ { "change": k.name, "path": str(Path(v).relative_to(self.path)), "time": time.time(), } for k, v in sorted(changes) ] async def _watch(self): """the actual watcher. schedule to run in the loop""" self._stop = Event() async for changes in awatch( self.path, watcher_cls=self._watcher_cls, stop_event=self._stop ): IOLoop.current().add_callback(self._changes, changes)