watchgod


Namewatchgod JSON
Version 0.8.2 PyPI version JSON
download
home_pagehttps://github.com/samuelcolvin/watchfiles
SummarySimple, modern file watching and code reload in python.
upload_time2022-04-01 12:18:05
maintainer
docs_urlNone
authorSamuel Colvin
requires_python>=3.7
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # watchgod

[![CI](https://github.com/samuelcolvin/watchgod/workflows/ci/badge.svg?event=push)](https://github.com/samuelcolvin/watchgod/actions?query=event%3Apush+branch%3Amaster+workflow%3Aci)
[![Coverage](https://codecov.io/gh/samuelcolvin/watchgod/branch/master/graph/badge.svg)](https://codecov.io/gh/samuelcolvin/watchgod)
[![pypi](https://img.shields.io/pypi/v/watchgod.svg)](https://pypi.python.org/pypi/watchgod)
[![license](https://img.shields.io/github/license/samuelcolvin/watchgod.svg)](https://github.com/samuelcolvin/watchgod/blob/master/LICENSE)

Simple, modern file watching and code reload in python.

---

## NOTICE - Package Renamed to `watchfiles`

**Please note:** This package (watchgod) has been renamed to [watchfiles](https://pypi.org/project/watchfiles/). 
Please replace `watchgod` with `watchfiles`, see [the migration guide](https://watchfiles.helpmanual.io/migrating/)
for help and instructions on switching.

As well as a better name, `watchfiles` has a whole new backend based on rust-notify which makes watching
for filesystem events much more efficient.

**The package under the name `watchgod` will not be further developed and will only receive critical security fixes.**

---

## Usage

To watch for changes in a directory:

```python
from watchgod import watch

for changes in watch('./path/to/dir'):
    print(changes)
```

To run a function and restart it when code changes:

```python
from watchgod import run_process

def foobar(a, b, c):
    ...

run_process('./path/to/dir', foobar, args=(1, 2, 3))
```

`run_process` uses `PythonWatcher` so only changes to python files will prompt a
reload, see **custom watchers** 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.

## Installation

```bash
pip install watchgod
```

## Asynchronous Methods

*watchgod* comes with an asynchronous equivalents of `watch`: `awatch` which uses
a `ThreadPoolExecutor` to iterate over files.

```python
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`:

```python
import asyncio
from watchgod import arun_process

def foobar(a, b, c):
    ...

async def main():
    await arun_process('./path/to/dir', foobar, args=(1, 2, 3))

asyncio.run(main())
```

`arun_process` uses `PythonWatcher` so only changes to python files will prompt a
reload, see **custom watchers** below.

The signature of `arun_process` is almost identical to `run_process` except that
the optional `callback` argument must be a coroutine, not a function.

## Custom Watchers


*watchgod* comes with the following watcher classes which can be used via the `watcher_cls`
keyword argument to any of the methods above.

For example:

```python
for changes in watch(directoryin, watcher_cls=RegExpWatcher, watcher_kwargs=dict(re_files=r'^.*(\.mp3)$')):
   print (changes)
```

For more details, checkout
[`watcher.py`](https://github.com/samuelcolvin/watchgod/blob/master/watchgod/watcher.py),
it's pretty simple.

* **AllWatcher** The base watcher, all files are checked for changes.

* **DefaultWatcher** The watcher used by default by `watch` and `awatch`, commonly ignored files
  like `*.swp`, `*.pyc` and `*~` are ignored along with directories like
  `.git`.

* **PythonWatcher** Specific to python files, only `*.py`, `*.pyx` and `*.pyd` files are watched.

* **DefaultDirWatcher** Is the base for `DefaultWatcher` and `DefaultDirWatcher`. 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 override `should_watch_dir` and `should_watch_file`. Unless you're
doing something very odd, you'll want to inherit from `DefaultDirWatcher`.

Note that events related to *directories* are not reported (e.g. creation of a
directory), but new files in new directories will be reported.

## CLI

*watchgod* also comes with a CLI for running and reloading python code.

Lets say you have `foobar.py`:

```python
from aiohttp import web

async def handle(request):
    return web.Response(text='testing')

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

In case you need to ignore certain files or directories, you can use the argument
 `--ignore-paths`.

Run `watchgod --help` for more options. *watchgod* is also available as a python executable module
via `python -m watchgod ...`.

## Why no inotify / kqueue / fsevent / winapi support

*watchgod* (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:

1. Polling is "fast enough", particularly since PEP 471 introduced fast `scandir`.
  For reasonably large projects like the TutorCruncher code base with 850 files and 300k lines
  of code, *watchgod* can scan the entire tree in ~24ms. With a scan interval of 400ms that is roughly
  5% of one CPU - perfectly acceptable load during development.
2. 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.
3. 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](https://github.com/samuelcolvin/watchgod/issues/25).



            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/samuelcolvin/watchfiles",
    "name": "watchgod",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": "",
    "keywords": "",
    "author": "Samuel Colvin",
    "author_email": "s@muelcolvin.com",
    "download_url": "https://files.pythonhosted.org/packages/e8/6e/3904af0715e03fc5b2636cb8cf8b0eabc45b1f2cf6e4cf8453ddb6d23042/watchgod-0.8.2.tar.gz",
    "platform": null,
    "description": "# watchgod\n\n[![CI](https://github.com/samuelcolvin/watchgod/workflows/ci/badge.svg?event=push)](https://github.com/samuelcolvin/watchgod/actions?query=event%3Apush+branch%3Amaster+workflow%3Aci)\n[![Coverage](https://codecov.io/gh/samuelcolvin/watchgod/branch/master/graph/badge.svg)](https://codecov.io/gh/samuelcolvin/watchgod)\n[![pypi](https://img.shields.io/pypi/v/watchgod.svg)](https://pypi.python.org/pypi/watchgod)\n[![license](https://img.shields.io/github/license/samuelcolvin/watchgod.svg)](https://github.com/samuelcolvin/watchgod/blob/master/LICENSE)\n\nSimple, modern file watching and code reload in python.\n\n---\n\n## NOTICE - Package Renamed to `watchfiles`\n\n**Please note:** This package (watchgod) has been renamed to [watchfiles](https://pypi.org/project/watchfiles/). \nPlease replace `watchgod` with `watchfiles`, see [the migration guide](https://watchfiles.helpmanual.io/migrating/)\nfor help and instructions on switching.\n\nAs well as a better name, `watchfiles` has a whole new backend based on rust-notify which makes watching\nfor filesystem events much more efficient.\n\n**The package under the name `watchgod` will not be further developed and will only receive critical security fixes.**\n\n---\n\n## Usage\n\nTo watch for changes in a directory:\n\n```python\nfrom watchgod import watch\n\nfor changes in watch('./path/to/dir'):\n    print(changes)\n```\n\nTo run a function and restart it when code changes:\n\n```python\nfrom watchgod import run_process\n\ndef foobar(a, b, c):\n    ...\n\nrun_process('./path/to/dir', foobar, args=(1, 2, 3))\n```\n\n`run_process` uses `PythonWatcher` so only changes to python files will prompt a\nreload, see **custom watchers** below.\n\nIf you need notifications about change events as well as to restart a process you can\nuse the `callback` argument to pass a function which will be called on every file change\nwith one argument: the set of file changes.\n\n## Installation\n\n```bash\npip install watchgod\n```\n\n## Asynchronous Methods\n\n*watchgod* comes with an asynchronous equivalents of `watch`: `awatch` which uses\na `ThreadPoolExecutor` to iterate over files.\n\n```python\nimport asyncio\nfrom watchgod import awatch\n\nasync def main():\n    async for changes in awatch('/path/to/dir'):\n        print(changes)\n\nasyncio.run(main())\n```\n\nThere's also an asynchronous equivalents of `run_process`: `arun_process` which in turn\nuses `awatch`:\n\n```python\nimport asyncio\nfrom watchgod import arun_process\n\ndef foobar(a, b, c):\n    ...\n\nasync def main():\n    await arun_process('./path/to/dir', foobar, args=(1, 2, 3))\n\nasyncio.run(main())\n```\n\n`arun_process` uses `PythonWatcher` so only changes to python files will prompt a\nreload, see **custom watchers** below.\n\nThe signature of `arun_process` is almost identical to `run_process` except that\nthe optional `callback` argument must be a coroutine, not a function.\n\n## Custom Watchers\n\n\n*watchgod* comes with the following watcher classes which can be used via the `watcher_cls`\nkeyword argument to any of the methods above.\n\nFor example:\n\n```python\nfor changes in watch(directoryin, watcher_cls=RegExpWatcher, watcher_kwargs=dict(re_files=r'^.*(\\.mp3)$')):\n   print (changes)\n```\n\nFor more details, checkout\n[`watcher.py`](https://github.com/samuelcolvin/watchgod/blob/master/watchgod/watcher.py),\nit's pretty simple.\n\n* **AllWatcher** The base watcher, all files are checked for changes.\n\n* **DefaultWatcher** The watcher used by default by `watch` and `awatch`, commonly ignored files\n  like `*.swp`, `*.pyc` and `*~` are ignored along with directories like\n  `.git`.\n\n* **PythonWatcher** Specific to python files, only `*.py`, `*.pyx` and `*.pyd` files are watched.\n\n* **DefaultDirWatcher** Is the base for `DefaultWatcher` and `DefaultDirWatcher`. It takes care of ignoring\n  some regular directories.\n\n\nIf these classes aren't sufficient you can define your own watcher, in particular\nyou will want to override `should_watch_dir` and `should_watch_file`. Unless you're\ndoing something very odd, you'll want to inherit from `DefaultDirWatcher`.\n\nNote that events related to *directories* are not reported (e.g. creation of a\ndirectory), but new files in new directories will be reported.\n\n## CLI\n\n*watchgod* also comes with a CLI for running and reloading python code.\n\nLets say you have `foobar.py`:\n\n```python\nfrom aiohttp import web\n\nasync def handle(request):\n    return web.Response(text='testing')\n\napp = web.Application()\napp.router.add_get('/', handle)\n\ndef main():\n    web.run_app(app, port=8000)\n```\n\nYou could run this and reload it when any file in the current directory changes with::\n\n    watchgod foobar.main\n\nIn case you need to ignore certain files or directories, you can use the argument\n `--ignore-paths`.\n\nRun `watchgod --help` for more options. *watchgod* is also available as a python executable module\nvia `python -m watchgod ...`.\n\n## Why no inotify / kqueue / fsevent / winapi support\n\n*watchgod* (for now) uses file polling rather than the OS's built in file change notifications.\n\nThis is not an oversight, it's a decision with the following rationale:\n\n1. Polling is \"fast enough\", particularly since PEP 471 introduced fast `scandir`.\n  For reasonably large projects like the TutorCruncher code base with 850 files and 300k lines\n  of code, *watchgod* can scan the entire tree in ~24ms. With a scan interval of 400ms that is roughly\n  5% of one CPU - perfectly acceptable load during development.\n2. The clue is in the title, there are at least 4 different file notification systems to integrate\n  with, most of them not trivial. That is all before we get to changes between different OS versions.\n3. Polling works well when you want to group or \"debounce\" changes.\n  Let's say you're running a dev server and you change branch in git, 100 files change.\n  Do you want to reload the dev server 100 times or once? Right.\n  Polling periodically will likely group these changes into one event. If you're receiving a\n  stream of events you need to delay execution of the reload when you receive the first event\n  to see if it's part of a group of file changes. This is not trivial.\n\nAll that said, I might still use rust's \"notify\" crate to do the heavy lifting of file watching,\nsee[#25](https://github.com/samuelcolvin/watchgod/issues/25).\n\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Simple, modern file watching and code reload in python.",
    "version": "0.8.2",
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "9f60cfd9150167cb8ec0ac07642fe1383d27300729e0b2b877ff89cb0862bbeb",
                "md5": "2fea32e30b6eee1cb094dd591a6f2fa3",
                "sha256": "2f3e8137d98f493ff58af54ea00f4d1433a6afe2ed08ab331a657df468c6bfce"
            },
            "downloads": -1,
            "filename": "watchgod-0.8.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "2fea32e30b6eee1cb094dd591a6f2fa3",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 12255,
            "upload_time": "2022-04-01T12:18:03",
            "upload_time_iso_8601": "2022-04-01T12:18:03.879295Z",
            "url": "https://files.pythonhosted.org/packages/9f/60/cfd9150167cb8ec0ac07642fe1383d27300729e0b2b877ff89cb0862bbeb/watchgod-0.8.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "e86e3904af0715e03fc5b2636cb8cf8b0eabc45b1f2cf6e4cf8453ddb6d23042",
                "md5": "14907e53496e743e93d78c4d72f1e759",
                "sha256": "cb11ff66657befba94d828e3b622d5fb76f22fbda1376f355f3e6e51e97d9450"
            },
            "downloads": -1,
            "filename": "watchgod-0.8.2.tar.gz",
            "has_sig": false,
            "md5_digest": "14907e53496e743e93d78c4d72f1e759",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 13865,
            "upload_time": "2022-04-01T12:18:05",
            "upload_time_iso_8601": "2022-04-01T12:18:05.163154Z",
            "url": "https://files.pythonhosted.org/packages/e8/6e/3904af0715e03fc5b2636cb8cf8b0eabc45b1f2cf6e4cf8453ddb6d23042/watchgod-0.8.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2022-04-01 12:18:05",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "github_user": "samuelcolvin",
    "github_project": "watchfiles",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "watchgod"
}
        
Elapsed time: 0.04384s