Last active
February 5, 2026 05:15
-
-
Save ernstki/759383313185aae343bc87b989c44241 to your computer and use it in GitHub Desktop.
Very, very simple watchdog-based Python interpreter launcher; watches your script for changes and re-runs it
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| ## | |
| ## watchme.py - monitor *.py files or a given path and re-run 'python <path>' | |
| ## | |
| ## Author: Kevin Ernst | |
| ## Date: 4 February 2026 | |
| ## License: Apache License Version 2.0 | |
| ## (https://github.com/gorakhargosh/watchdog/blob/master/LICENSE) | |
| ## Homepage: https://gist.github.com/ernstki/759383313185aae343bc87b989c44241 | |
| ## | |
| ## sources: | |
| ## - https://github.com/gorakhargosh/watchdog#example-api-usage | |
| ## - https://github.com/yejianye/watchdog-tricks/blob/master/watchdog_tricks/compiler.py#L32 | |
| ## | |
| import os, sys, glob, time, subprocess | |
| from functools import wraps | |
| from watchdog.events import FileSystemEvent, FileSystemEventHandler | |
| from watchdog.observers import Observer | |
| def trace_event(func): | |
| """ | |
| source: https://github.com/yejianye/watchdog-tricks/blob/master/watchdog_tricks/utils.py | |
| license: see https://github.com/yejianye/watchdog-tricks/pull/1#issuecomment-3850884907 | |
| """ | |
| @wraps(func) | |
| def _traced_func(self, event): | |
| if hasattr(event, 'dest_path'): | |
| print('%s: %s -> %s' % (event.event_type, event.src_path, | |
| event.dest_path), file=sys.stderr) | |
| else: | |
| print('%s %s' % (event.event_type, event.src_path), | |
| file=sys.stderr) | |
| return func(self, event) | |
| return _traced_func | |
| class SavedFileHandler(FileSystemEventHandler): | |
| def __init__(self, *args, **kwargs): | |
| self.watchpats = [] | |
| self.watched = [] | |
| if 'watchpats' in kwargs: | |
| for watch in kwargs.get('watchpats'): | |
| self.watchpats.append(watch) | |
| del kwargs['watchpats'] | |
| if not self.watchpats: | |
| self.watchpats = ["*.py"] | |
| print("Watching for changes to: {}".format(", ".join(self.watchpats)), | |
| file=sys.stderr) | |
| for pat in self.watchpats: # expand all globs now | |
| self.watched += glob.glob(pat) | |
| # and make all paths absolute, but ignore this script itself | |
| self.watched = set([ | |
| os.path.abspath(p) for p in self.watched | |
| if os.path.abspath(p) != os.path.abspath(__file__) | |
| ]) | |
| super().__init__(*args, **kwargs) | |
| @trace_event | |
| def on_moved(self, e): # many/most? editors save with delete, then move | |
| if os.path.dirname(e.src_path) == os.path.dirname(e.dest_path) \ | |
| and os.path.abspath(e.dest_path) in self.watched: | |
| subprocess.run("python " + e.dest_path) | |
| save_handler = SavedFileHandler(watchpats=sys.argv[1:]) | |
| observer = Observer() | |
| observer.schedule(save_handler, ".", recursive=True) | |
| with observer: | |
| try: | |
| while True: | |
| time.sleep(20) | |
| except KeyboardInterrupt: | |
| print("Received interrupt, quitting...", file=sys.stderr) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment