Simple, modern file watching and code reload in python.
Reason this release was yanked:
moving to new package name.
Project description
watchgod
Simple, modern and high performance file watching and code reload in python.
NOTE! New Unstable Version
The docs here refer to watchgod version v0.10a1
which is a significant rewrite from v0.8
,
the docs for v0.8
are available here.
Please try v0.10a1
(installed via pip install watchgod==v0.10a1
) and give feedback,
here.
Underlying file system notifications are now handled by the Notify rust library.
(watchgod is inspired by watchdog, hence the name, but tries to fix some of the frustrations I found with watchdog, namely: separate approaches for each OS, an inelegant approach to concurrency using threading, challenges around debouncing changes and bugs which weren't being fixed)
Installation
watchgod requires Python 3.7 - 3.10.
pip install watchgod==v0.10a1
Binaries are available for:
- Linux:
manylinux-x86_64
,musllinux-x86_64
&manylinux-i686
- MacOS:
x86_64
&arm64
(except python 3.7) - Windows:
amd64
&win32
Otherwise, you can install from source which requires Rust stable to be installed.
Usage
Synchronous Methods
To watch for changes in a directory:
from watchgod import watch
for changes in watch('./path/to/dir'):
print(changes)
watch
(and all other methods described below) can take multiple paths as arguments to watch.
To run a function and restart it when code changes:
from watchgod import run_process
def foobar(a, b, c):
...
run_process('./path/to/dir', target=foobar, args=(1, 2, 3))
run_process
uses PythonFilter
by default so only changes to python files will prompt a reload,
see custom event filtering below.
If you need notifications about change events as well as to restart a process you can
use the callback
argument to pass a function which will be called on every file change
with one argument: the set of file changes.
File changes are also available via the WATCHGOD_CHANGES
environment variable which contains JSON encoded
details of changes, see the CLI example below.
Asynchronous Methods
watchgod comes with an asynchronous equivalents of watch
: awatch
.
import asyncio
from watchgod import awatch
async def main():
async for changes in awatch('/path/to/dir'):
print(changes)
asyncio.run(main())
There's also an asynchronous equivalents of run_process
: arun_process
which in turn
uses awatch
:
import asyncio
from watchgod import arun_process
def foobar(a, b, c):
...
async def main():
await arun_process('./path/to/dir', target=foobar, args=(1, 2, 3))
asyncio.run(main())
The signature of arun_process
is almost identical to run_process
except that
the optional callback
argument may be a coroutine.
Custom Filters
The watch_filter
argument to the above methods allows you to specify which file system events watchgod should
react to (either yield or reload code). watch_filter
should just be a callable which takes a change
(either "added", "modified" or "deleted") and a path (as a string) and should return whether or not that change
should be registered.
watchgod comes with the following classes, instances of which can be with watch_filter
:
DefaultFilter
The watcher used by default bywatch
andawatch
, commonly ignored files like*.swp
,*.pyc
and*~
are ignored along with directories like.git
.PythonFilter
Specific to python files, only*.py
,*.pyx
and*.pyd
files are watched.BaseFilter
, used byDefaultFilter
andPythonFilter
, useful for defining your own filters which leverage the same logic
Here's an example of a custom filter which extends DefaultFilter
to only notice changes to common web files:
from watchgod import Change, DefaultFilter, watch
class WebFilter(DefaultFilter):
allowed_extensions = '.html', '.css', '.js'
def __call__(self, change: Change, path: str) -> bool:
return super().__call__(change, path) and path.endswith(self.allowed_extensions)
for changes in watch('my/web/project', watch_filter=WebFilter()):
print (changes)
Here's an example of a customer filter which is a simple callable that ignores changes unless they represent a new file being created:
from watchgod import Change, watch
def only_added(change: Change, path: str) -> bool:
return change == Change.added
for changes in watch('my/project', watch_filter=only_added):
print (changes)
For more details, checkout
filters.py
,
it's pretty simple.
CLI
watchgod also comes with a CLI for running and reloading python code.
Let's say you have foobar.py
(this is a very simple web server using
aiohttp) which gets details about recent file changes from the
WATCHGOD_CHANGES
environment variable and returns them as JSON.
import os, json
from aiohttp import web
async def handle(request):
# get the most recent file changes and return them
changes = os.getenv('WATCHGOD_CHANGES', '[]')
changes = json.loads(changes)
return web.json_response(dict(changes=changes))
app = web.Application()
app.router.add_get('/', handle)
def main():
web.run_app(app, port=8000)
You could run this and reload it when any file in the current directory changes with:
watchgod foobar.main
Run watchgod --help
for more options.
The CLI can also be used via python -m watchgod ...
.
How Watchgod Works
watchgod after version v0.10
is based on the Notify rust library.
All the hard work of integrating with the OS's file system events notifications and falling back to polling is palmed off on the rust library.
"Debouncing" changes - e.g. grouping changes into batches rather than firing a yield/reload for each file changed is managed in rust.
The rust code takes care of creating a new thread to watch for file changes so in the case of the synchronous methods
(watch
and run_process
) no threading logic is required in python. When using the asynchronous methods (awatch
and
arun_process
) `anyio.to_thread.run_sync
is used to wait for changes in rust within a thread.
Prior to v0.10
the library used filesystem polling to watch for changes,
see the README for v0.8.1 for more details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Hashes for watchgod-0.10a1-cp310-cp310-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 022be41807932081dceb3463cbecf1105be3230e15d1ac0582d5b97fcbc7fcf2 |
|
MD5 | 87d4b880dfe3fe1e036de9fe7fc4b637 |
|
BLAKE2b-256 | 97205b13364a88b08ca7091a29d9e9f8e5c9e5a3ebfe6ba3b60b437be78f18f9 |
Hashes for watchgod-0.10a1-cp310-cp310-win32.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 98f38128baacb7f222c20a09c8ecbd118aac6ecbcc60e947a796649ea282c5c5 |
|
MD5 | dfb434dcc40f084cf3c76f7ec30860d9 |
|
BLAKE2b-256 | 7badb231a302a8ca181ae964fdcd2ea0431c06b86c4ed64c873272223d295eab |
Hashes for watchgod-0.10a1-cp310-cp310-manylinux_2_24_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 9056f0c49bec833e774d301def96c8dcd0453ad8d41cbca7cdd44fbe4788401f |
|
MD5 | 87c0759a09ce42c978aba706245781f6 |
|
BLAKE2b-256 | 5d530aeabeb602eaad900f66bfa9e02d7943d2bd703a153785b9a37dd01c2831 |
Hashes for watchgod-0.10a1-cp310-cp310-manylinux_2_24_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | e487bb91cd3f3f18632f1904975a417d3d1d17aa7df8fc8184b6052bc0f17ae5 |
|
MD5 | 883011929e4283a2ac1a65568dcf5821 |
|
BLAKE2b-256 | 0471c012dd80adb662f756f2778880132aa08c63b15672f19c35caa69ba03aad |
Hashes for watchgod-0.10a1-cp310-cp310-macosx_11_0_arm64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | f7413e6785d9adc6dbbb641a7eab3466b08f1a1ba330bd6c2f6daa78a8bed8fa |
|
MD5 | 5bebe151712fd19adf7dad8d563c33e8 |
|
BLAKE2b-256 | 09223b683669f471eb04deebfe5692e05542284dae3938a4e0958cdd9cab1481 |
Hashes for watchgod-0.10a1-cp310-cp310-macosx_10_9_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 349f777620eaed37400e23ad44beb18f0659ae5526c5c076c9eb064a9b9bd0c0 |
|
MD5 | ef52e74e1c7dd5583ff178cc903ae65b |
|
BLAKE2b-256 | b7b722920f59a35125881c55b1dc7c7429ab0b687a03fd2f551c46cabbfb714e |
Hashes for watchgod-0.10a1-cp39-cp39-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 272449049340631e69ca1b31a27e255d20e6df1f6b2e22edbb9a22faf3d987fb |
|
MD5 | 5fbb33585d5a6832b724e2dae6505a6a |
|
BLAKE2b-256 | 3367f086245cb98aa9be7d4fbea938b9157c4b6020fc04b26bf3673480f5eef8 |
Hashes for watchgod-0.10a1-cp39-cp39-win32.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | dd74e102e17a10669621a5b5988fa51baba4427769d8e4da9d2409bd293719ec |
|
MD5 | 1c77b9c5c9a8c1935c5f052e6b0e40d4 |
|
BLAKE2b-256 | 36b005140b56168b64c6ad3a9a666dd8357ad78d61eaaad3cf6a70e2ee4e16ca |
Hashes for watchgod-0.10a1-cp39-cp39-manylinux_2_24_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 7a5fc4e65cf12a24a75304d13710a69db08a818fd4e9f413f8c8d79cd70dcd20 |
|
MD5 | 48f5ee7be62217a0a30ea6c26578b4f0 |
|
BLAKE2b-256 | 1e49d1a3eca9d4bed29b031e77ce2f3b7ba11fff2ee791dc1ea4d325ac2e725b |
Hashes for watchgod-0.10a1-cp39-cp39-manylinux_2_24_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 0fd3a9ba95c07117599796023fbda733112c0f51cd2fa36e92df63d3812c83f2 |
|
MD5 | 8622848134d587a1285bf8056d3fa908 |
|
BLAKE2b-256 | b3de43508845feb8d85cc31991048e75e61ffdd69988720d3dbddb895e392940 |
Hashes for watchgod-0.10a1-cp39-cp39-macosx_11_0_arm64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | b5200e88b9665f43ba86b619af1542763636f7f12b341395aae66d747a57afd9 |
|
MD5 | 2dbb63a1c6ec8673ace17f40399c6521 |
|
BLAKE2b-256 | 0e7cbd42fd509ad0d2b1e77331c1d581b577a740c5bfb2455e2830c776813459 |
Hashes for watchgod-0.10a1-cp39-cp39-macosx_10_9_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 808a19f3c4428a9c271219bdd018ad63e837c0f738353fa92c684c64ec8f091f |
|
MD5 | fbd511763d8bf314881e68ce2d741ce7 |
|
BLAKE2b-256 | 2b632c78161d0cf3112b8366ce1395f2a22cf015a26d9d2556f683ddd251594c |
Hashes for watchgod-0.10a1-cp38-cp38-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | bd64688d16e8037f298a7495c13036ada6b4cdc99a38d7b7d192724c14e712e0 |
|
MD5 | 692141f4b86c61215972d73893c7e31e |
|
BLAKE2b-256 | d8c88386421af835fa937c33c00e56d52760bc75c851856cb81e4a8b49cb9e3b |
Hashes for watchgod-0.10a1-cp38-cp38-win32.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 247184c7a4558c03a8ddedbe300a4cac832a490437f56a76855ab8b3e5bc9ad1 |
|
MD5 | 97d34521728fb01024540c7eb4470086 |
|
BLAKE2b-256 | a3634a78a2261c87b6f18bca7c4968cd094aaa62b7e01609f4ed14e19e0956ff |
Hashes for watchgod-0.10a1-cp38-cp38-manylinux_2_24_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 392c0f71434c946b3bf256adf9e8a53546b7026195d17fb8dfb57de345b68eb0 |
|
MD5 | 553973a1f1df40e67d3f3bc8404daa92 |
|
BLAKE2b-256 | 5888022dc7b687f419ca7cbb0f11b3061cbfbefcf6c68a9f98fcff217cc109ea |
Hashes for watchgod-0.10a1-cp38-cp38-manylinux_2_24_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | fa37b98240aa56dcefea68ab991a2b269b09fb26d155f5f0453a5b9e548215f4 |
|
MD5 | 24a304effd844ef074fc08ede798907a |
|
BLAKE2b-256 | e5549e225f375aaa40edca520f56fe4f51e56ae1630eefb8b90c7bd89ed2e393 |
Hashes for watchgod-0.10a1-cp38-cp38-macosx_11_0_arm64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 753054f15bc4578a59434ebfebbefdfcdac521006f8e590e8f0ed12ef8b2e74b |
|
MD5 | 96fbb97e5d787b95bd8b2c1fb162bed4 |
|
BLAKE2b-256 | 758443e1db501ab507af2b34a34d3853ba99d066afc8ba4d709ba7cead74a553 |
Hashes for watchgod-0.10a1-cp38-cp38-macosx_10_9_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | d0f382a7e06ff646c1d272908391309e809cf162635d51bb9c7ea4ac58ce2d74 |
|
MD5 | 6c0cdd67bbe42dcf193d0e927070eb09 |
|
BLAKE2b-256 | a89da9c169f1e57545278dafa5d12da9c2bb288175e37a1283eb10d22db8ee6e |
Hashes for watchgod-0.10a1-cp37-cp37m-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 5f47c9dda2251f15d4a878ae66de67e563cc430835e3c05fae5f9fe2fbcfd6c6 |
|
MD5 | aeb5a7d2300f3e354a81291b46c817b8 |
|
BLAKE2b-256 | 2687b82e521510a608ccd5b71c88eadc12b8e3ea8075449f7310f034632404de |
Hashes for watchgod-0.10a1-cp37-cp37m-win32.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | dfeef243848e337b66c2b951720e56f13012cfd1a4f704f4be7f2cf10df39ee3 |
|
MD5 | 7dc509b7781992484cde473c5c2b9434 |
|
BLAKE2b-256 | e841508bb42eaab40ca4d8dd6a428a69f43099a713168e74118c33d87417c6e7 |
Hashes for watchgod-0.10a1-cp37-cp37m-manylinux_2_24_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 75902197196443dd7776aa24461a030644011a61c7433f0c90dcbf68d2c138e7 |
|
MD5 | 4ac930b65ddee38669d4459b843e5947 |
|
BLAKE2b-256 | d6e85d71c436fb392c8705233d355ffdaa0c659c3ce2db47a6e9aadd9702f83f |
Hashes for watchgod-0.10a1-cp37-cp37m-manylinux_2_24_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 84ca3e5941490821cc0bc20ef5b4a4944cdd087688b8657bed2d3ba5f5919757 |
|
MD5 | 5c4996b5904dc4d334f82387894aeaa9 |
|
BLAKE2b-256 | 9764b8da227625c970d2b7d0000807dff809835666ad01cde53924b26bb2b89b |
Hashes for watchgod-0.10a1-cp37-cp37m-macosx_10_9_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | c81daf004aa2310eed783f003ab6b5ddb31f548c3562badf88de9f1a3e5a81cb |
|
MD5 | f2c3ab2210fb3a419b6b31132dc8cc70 |
|
BLAKE2b-256 | 675fd646a2fa83df72c695c81cdce3f8e4de8ded228e912d0165fd3fe2a61aa3 |