Package: watchgod
watchgodSimple, modern file watching and code reload in python.NOTICE - Package Renamed towatchfilesPlease note:This package (watchgod) has been renamed towatchfiles.
Please replacewatchgodwithwatchfiles, seethe migration guidefor help and instructions on switching.As well as a better name,watchfileshas a whole new backend based on rust-notify which makes watching
for filesystem events much more efficient.The package under the namewatchgodwill not be further developed and will only receive critical security fixes.UsageTo watch for changes in a directory:fromwatchgodimportwatchforchangesinwatch('./path/to/dir'):print(changes)To run a function and restart it when code changes:fromwatchgodimportrun_processdeffoobar(a,b,c):...run_process('./path/to/dir',foobar,args=(1,2,3))run_processusesPythonWatcherso only changes to python files will prompt a
reload, seecustom watchersbelow.If you need notifications about change events as well as to restart a process you can
use thecallbackargument to pass a function which will be called on every file change
with one argument: the set of file changes.InstallationpipinstallwatchgodAsynchronous Methodswatchgodcomes with an asynchronous equivalents ofwatch:awatchwhich uses
aThreadPoolExecutorto iterate over files.importasynciofromwatchgodimportawatchasyncdefmain():asyncforchangesinawatch('/path/to/dir'):print(changes)asyncio.run(main())There's also an asynchronous equivalents ofrun_process:arun_processwhich in turn
usesawatch:importasynciofromwatchgodimportarun_processdeffoobar(a,b,c):...asyncdefmain():awaitarun_process('./path/to/dir',foobar,args=(1,2,3))asyncio.run(main())arun_processusesPythonWatcherso only changes to python files will prompt a
reload, seecustom watchersbelow.The signature ofarun_processis almost identical torun_processexcept that
the optionalcallbackargument must be a coroutine, not a function.Custom Watcherswatchgodcomes with the following watcher classes which can be used via thewatcher_clskeyword argument to any of the methods above.For example:forchangesinwatch(directoryin,watcher_cls=RegExpWatcher,watcher_kwargs=dict(re_files=r'^.*(\.mp3)$')):print(changes)For more details, checkoutwatcher.py,
it's pretty simple.AllWatcherThe base watcher, all files are checked for changes.DefaultWatcherThe watcher used by default bywatchandawatch, commonly ignored files
like*.swp,*.pycand*~are ignored along with directories like.git.PythonWatcherSpecific to python files, only*.py,*.pyxand*.pydfiles are watched.DefaultDirWatcherIs the base forDefaultWatcherandDefaultDirWatcher. It takes care of ignoring
some regular directories.If these classes aren't sufficient you can define your own watcher, in particular
you will want to overrideshould_watch_dirandshould_watch_file. Unless you're
doing something very odd, you'll want to inherit fromDefaultDirWatcher.Note that events related todirectoriesare not reported (e.g. creation of a
directory), but new files in new directories will be reported.CLIwatchgodalso comes with a CLI for running and reloading python code.Lets say you havefoobar.py:fromaiohttpimportwebasyncdefhandle(request):returnweb.Response(text='testing')app=web.Application()app.router.add_get('/',handle)defmain():web.run_app(app,port=8000)You could run this and reload it when any file in the current directory changes with::watchgod foobar.mainIn case you need to ignore certain files or directories, you can use the argument--ignore-paths.Runwatchgod --helpfor more options.watchgodis also available as a python executable module
viapython -m watchgod ....Why no inotify / kqueue / fsevent / winapi supportwatchgod(for now) uses file polling rather than the OS's built in file change notifications.This is not an oversight, it's a decision with the following rationale:Polling is "fast enough", particularly since PEP 471 introduced fastscandir.
For reasonably large projects like the TutorCruncher code base with 850 files and 300k lines
of code,watchgodcan scan the entire tree in ~24ms. With a scan interval of 400ms that is roughly
5% of one CPU - perfectly acceptable load during development.The clue is in the title, there are at least 4 different file notification systems to integrate
with, most of them not trivial. That is all before we get to changes between different OS versions.Polling works well when you want to group or "debounce" changes.
Let's say you're running a dev server and you change branch in git, 100 files change.
Do you want to reload the dev server 100 times or once? Right.
Polling periodically will likely group these changes into one event. If you're receiving a
stream of events you need to delay execution of the reload when you receive the first event
to see if it's part of a group of file changes. This is not trivial.All that said, I might still use rust's "notify" crate to do the heavy lifting of file watching,
see#25.