## File: docs/source/api.rst .. include:: global.rst.inc .. _api_reference: ============= API Reference ============= .. toctree:: :maxdepth: 2 api/events api/observers_api api/observers api/observers_polling api/utils api/utils_dirsnapshot api/tricks --- ## File: docs/source/hacking.rst .. include:: global.rst.inc .. _hacking: Contributing ============ πŸ‘‹ **Welcome hacker!** So you have got something you would like to see in |project_name|? Whee! This document will help you get started. Important URLs -------------- * πŸ™ **Code Repository**: `code repository`_ (GitHub) * πŸ› **Issue Tracker**: `issue tracker`_ (GitHub Issues) * πŸ“– **Documentation**: `Official Documentation `_ Before you start ---------------- Ensure your system has the following programs and libraries installed before beginning to hack: 1. Python_ 2. git_ 3. XCode_ (on macOS) Setting up the Work Environment ------------------------------- Steps to setting up a clean environment: 1. Fork the `code repository`_ into your github_ account. 2. Clone fork and create virtual environment: .. code:: bash $ git clone https://github.com/gorakhargosh/watchdog.git $ cd watchdog $ python -m venv venv 3. Activate the virtual environment and install the package in editable mode: *macOS & Linux* .. code:: bash $ . venv/bin/activate (venv)$ python -m pip install -e '.[watchmedo]' *Windows* .. code:: batch > venv\Scripts\activate (venv)> python -m pip install -e '.[watchmedo]' That's it with the setup. Now you're ready to hack on |project_name|. Running Tests and Checks ------------------------ Before submitting a Pull Request, please verify your changes pass the test suite and style checks. If you are adding a new feature or fixing a bug, please include new test cases covering the changes. Make sure your virtual environment is active, then install the testing and development dependencies: .. code:: bash (venv)$ python -m pip install -r requirements-tests.txt To run style and formatting checks: .. code:: bash # Run Ruff to check and format code (venv)$ python -m ruff format src tests docs/source/examples (venv)$ python -m ruff check --fix src tests docs/source/examples To run type checking: .. code:: bash (venv)$ python -m mypy src docs/source/examples To run the test suite: .. code:: bash # Run pytest (venv)$ python -m pytest # Or run the entire suite using tox (if installed in your venv) (venv)$ tox # Or run using uv without installing tox locally (venv)$ uvx tox To build the documentation locally: .. code:: bash # Build using sphinx-build directly (venv)$ sphinx-build -b html docs/source docs/build/html # Or build using tox via uv without installing tox locally (venv)$ uvx tox -e docs .. note:: If you are using `uv` to manage your environment, you can use `uv pip install -r requirements-tests.txt` instead of standard `pip` to avoid externally-managed environment errors. Additionally, `tox` is not included in `requirements-tests.txt` to keep the testing dependency lightweight; running via `uvx tox` is the recommended way if `tox` is not installed globally. πŸš€ **Happy hacking!** We are excited to see what you build. --- ## File: docs/source/index.rst .. watchdog documentation master file, created by sphinx-quickstart on Tue Nov 30 00:43:58 2010. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. .. include:: global.rst.inc Watchdog ======== Python API library and shell utilities to monitor file system events. Works on 3.9+. Directory monitoring made easy with ----------------------------------- * A cross-platform API. * A shell tool to run commands in response to directory changes. Get started quickly with a simple example in :ref:`quickstart`. Easy installation ----------------- You can use pip_ to install |project_name| quickly and easily:: $ python -m pip install -U watchdog Need more help with installing? See :ref:`installation`. User's Guide ============ .. toctree:: :maxdepth: 2 installation quickstart examples api hacking Command-Line Tool ================= .. toctree:: :maxdepth: 2 watchmedo_cli tricks .. toctree:: :maxdepth: 1 changelog .. toctree:: :maxdepth: 2 third_party_licenses authors Contribute ========== Found a bug in or want a feature added to |project_name|? You can fork the official `code repository`_ or file an issue ticket at the `issue tracker`_. You may also want to refer to :ref:`hacking` for information about contributing code or documentation to |project_name|. Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` --- ## File: docs/source/installation.rst .. include:: global.rst.inc .. _installation: Installation ============ |project_name| requires 3.9+ to work. See a list of :ref:`installation-dependencies`. Installing from PyPI using pip ------------------------------ .. parsed-literal:: $ python -m pip install -U |project_name| # or to install the watchmedo utility: $ python -m pip install -U '|project_name|\[watchmedo]' Installing from source tarballs ------------------------------- .. parsed-literal:: $ wget -c https://pypi.python.org/packages/source/w/watchdog/watchdog-|project_version|.tar.gz $ tar zxvf |project_name|-|project_version|.tar.gz $ cd |project_name|-|project_version| $ python -m pip install -e . # or to install the watchmedo utility: $ python -m pip install -e '.[watchmedo]' Installing from the code repository ----------------------------------- :: $ git clone --recursive git://github.com/gorakhargosh/watchdog.git $ cd watchdog $ python -m pip install -e . # or to install the watchmedo utility: $ python -m pip install -e '.[watchmedo]' .. _installation-dependencies: Dependencies ------------ |project_name| depends on many libraries to do its job. The following is a list of dependencies you need based on the operating system you are using. +---------------------+-------------+-------------+--------+-------------+ | Operating system | Windows | Linux 2.6 | macOS | BSD | | Dependency (row) | | | Darwin | | +=====================+=============+=============+========+=============+ | XCode_ | | | Yes | | +---------------------+-------------+-------------+--------+-------------+ The following is a list of dependencies you need based on the operating system you are using the ``watchmedo`` utility. +---------------------+-------------+-------------+--------+-------------+ | Operating system | Windows | Linux 2.6 | macOS | BSD | | Dependency (row) | | | Darwin | | +=====================+=============+=============+========+=============+ | PyYAML_ | Yes | Yes | Yes | Yes | +---------------------+-------------+-------------+--------+-------------+ Supported Platforms (and Caveats) --------------------------------- |project_name| uses native APIs as much as possible falling back to polling the disk periodically to compare directory snapshots only when it cannot use an API natively-provided by the underlying operating system. The following operating systems are currently supported: .. WARNING:: Differences between behaviors of these native API are noted below. Linux 2.6+ Linux kernel version 2.6 and later come with an API called inotify_ that programs can use to monitor file system events. .. NOTE:: On most systems the maximum number of watches that can be created per user is limited to ``8192``. |project_name| needs one per directory to monitor. To change this limit, edit ``/etc/sysctl.conf`` and add:: fs.inotify.max_user_watches=16384 macOS The Darwin kernel/OS X API maintains two ways to monitor directories for file system events: * kqueue_ * FSEvents_ |project_name| can use whichever one is available, preferring FSEvents over ``kqueue(2)``. ``kqueue(2)`` uses open file descriptors for monitoring and the current implementation uses `macOS File System Monitoring Performance Guidelines`_ to open these file descriptors only to monitor events, thus allowing OS X to unmount volumes that are being watched without locking them. .. NOTE:: More information about how |project_name| uses ``kqueue(2)`` is noted in `BSD Unix variants`_. Much of this information applies to macOS as well. _`BSD Unix variants` BSD variants come with kqueue_ which programs can use to monitor changes to open file descriptors. Because of the way ``kqueue(2)`` works, |project_name| needs to open these files and directories in read-only non-blocking mode and keep books about them. |project_name| will automatically open file descriptors for all new files/directories created and close those for which are deleted. .. NOTE:: The maximum number of open file descriptor per process limit on your operating system can hinder |project_name|'s ability to monitor files. You should ensure this limit is set to at least **1024** (or a value suitable to your usage). The following command appended to your ``~/.profile`` configuration file does this for you:: ulimit -n 1024 Windows Vista and later The Windows API provides the ReadDirectoryChangesW_. |project_name| currently contains implementation for a synchronous approach requiring additional API functionality only available in Windows Vista and later. .. NOTE:: Since renaming is not the same operation as movement on Windows, |project_name| tries hard to convert renames to movement events. Also, because the ReadDirectoryChangesW_ API function returns rename/movement events for directories even before the underlying I/O is complete, |project_name| may not be able to completely scan the moved directory in order to successfully queue movement events for files and directories within it. .. NOTE:: Since the Windows API does not provide information about whether an object is a file or a directory, delete events for directories may be reported as a file deleted event. OS Independent Polling |project_name| also includes a fallback-implementation that polls watched directories for changes by periodically comparing snapshots of the directory tree. --- ## File: docs/source/quickstart.rst .. include:: global.rst.inc .. _quickstart: Quickstart ========== Below we present a simple example that monitors the current directory recursively (which means, it will traverse any sub-directories) to detect changes. Here is what we will do with the API: 1. Create an instance of the :class:`watchdog.observers.Observer` thread class. 2. Implement a subclass of :class:`watchdog.events.FileSystemEventHandler`. 3. Schedule monitoring a few paths with the observer instance attaching the event handler. 4. Start the observer thread and wait for it generate events without blocking our main thread. By default, an :class:`watchdog.observers.Observer` instance will not monitor sub-directories. By passing ``recursive=True`` in the call to :meth:`watchdog.observers.Observer.schedule` monitoring entire directory trees is ensured. A Simple Example ---------------- The following example program will monitor the current directory recursively for file system changes and simply print them to the console: .. literalinclude:: examples/simple.py :language: python :linenos: To stop the program, press Control-C. Alternatively, you can use the observer as a context manager for cleaner code: .. code-block:: python :linenos: import time from watchdog.events import FileSystemEvent, FileSystemEventHandler from watchdog.observers import Observer class MyEventHandler(FileSystemEventHandler): def on_any_event(self, event: FileSystemEvent) -> None: print(event) event_handler = MyEventHandler() observer = Observer() observer.schedule(event_handler, ".", recursive=True) with observer: while True: time.sleep(1) The context manager automatically handles starting and stopping the observer, ensuring proper cleanup even if an exception occurs. Typing ------ If you are using type annotations it is important to note that :class:`watchdog.observers.Observer` is not actually a class; it is a variable that hold the "best" observer class available on your platform. In order to correctly type your own code your should use :class:`watchdog.observers.api.BaseObserver`. For example: .. code-block:: python :linenos: from watchdog.observers import Observer from watchdog.observers.api import BaseObserver def my_func(obs: BaseObserver) -> None: # Do something with obs pass observer: BaseObserver = Observer() my_func(observer) --- ## File: README.rst Watchdog ======== |PyPI Version| |PyPI Status| |PyPI Python Versions| |GitHub Build Status| |GitHub License| .. tip:: Become **my boss** to help me work on this awesome software, and make the world better: |Patreon| Python API and shell utilities to monitor file system events. Works on 3.9+. Example API Usage ----------------- A simple program that uses watchdog to monitor directories specified as command-line arguments and logs events generated: .. code-block:: python import time from watchdog.events import FileSystemEvent, FileSystemEventHandler from watchdog.observers import Observer class MyEventHandler(FileSystemEventHandler): def on_any_event(self, event: FileSystemEvent) -> None: print(event) event_handler = MyEventHandler() observer = Observer() observer.schedule(event_handler, ".", recursive=True) observer.start() try: while True: time.sleep(1) finally: observer.stop() observer.join() Alternatively, you can use the observer as a context manager for cleaner code: .. code-block:: python import time from watchdog.events import FileSystemEvent, FileSystemEventHandler from watchdog.observers import Observer class MyEventHandler(FileSystemEventHandler): def on_any_event(self, event: FileSystemEvent) -> None: print(event) event_handler = MyEventHandler() observer = Observer() observer.schedule(event_handler, ".", recursive=True) with observer: while True: time.sleep(1) Shell Utilities --------------- Watchdog comes with an *optional* utility script called ``watchmedo``. Please type ``watchmedo --help`` at the shell prompt to know more about this tool. Here is how you can log the current directory recursively for events related only to ``*.py`` and ``*.txt`` files while ignoring all directory events: .. code-block:: bash watchmedo log \ --patterns='**/*.py;**/*.txt' \ --ignore-directories \ --recursive \ --verbose \ . You can use the ``shell-command`` subcommand to execute shell commands in response to events: .. code-block:: bash watchmedo shell-command \ --patterns='**/*.py;**/*.txt' \ --recursive \ --command='echo "${watch_src_path}"' \ . Please see the help information for these commands by typing: .. code-block:: bash watchmedo [command] --help About ``watchmedo`` Tricks ~~~~~~~~~~~~~~~~~~~~~~~~~~ ``watchmedo`` can read ``tricks.yaml`` files and execute tricks within them in response to file system events. Tricks are actually event handlers that subclass ``watchdog.tricks.Trick`` and are written by plugin authors. Trick classes are augmented with a few additional features that regular event handlers don't need. An example ``tricks.yaml`` file: .. code-block:: yaml tricks: - watchdog.tricks.LoggerTrick: patterns: ["**/*.py", "**/*.js"] - watchmedo_webtricks.GoogleClosureTrick: patterns: ['**/*.js'] hash_names: true mappings_format: json # json|yaml|python mappings_module: app/javascript_mappings suffix: .min.js compilation_level: advanced # simple|advanced source_directory: app/static/js/ destination_directory: app/public/js/ files: index-page: - app/static/js/vendor/jquery*.js - app/static/js/base.js - app/static/js/index-page.js about-page: - app/static/js/vendor/jquery*.js - app/static/js/base.js - app/static/js/about-page/**/*.js The directory containing the ``tricks.yaml`` file will be monitored. Each trick class is initialized with its corresponding keys in the ``tricks.yaml`` file as arguments and events are fed to an instance of this class as they arrive. Installation ------------ Install from PyPI using ``pip``: .. code-block:: bash $ python -m pip install -U watchdog # or to install the watchmedo utility: $ python -m pip install -U 'watchdog[watchmedo]' Install from source: .. code-block:: bash $ python -m pip install -e . # or to install the watchmedo utility: $ python -m pip install -e '.[watchmedo]' Documentation ------------- You can browse the latest release documentation_ online. Contribute ---------- Fork the `repository`_ on GitHub and send a pull request, or file an issue ticket at the `issue tracker`_. For general help and questions use `stackoverflow`_ with tag `python-watchdog`. Create and activate your virtual environment, then:: python -m pip install tox python -m tox [-q] [-e ENV] If you are making a substantial change, add an entry to the "Unreleased" section of the `changelog`_. Supported Platforms ------------------- * Linux 2.6 (inotify) * macOS (FSEvents, kqueue) * FreeBSD/BSD (kqueue) * Windows (ReadDirectoryChangesW with I/O completion ports; ReadDirectoryChangesW worker threads) * OS-independent (polling the disk for directory snapshots and comparing them periodically; slow and not recommended) Note that when using watchdog with kqueue, you need the number of file descriptors allowed to be opened by programs running on your system to be increased to more than the number of files that you will be monitoring. The easiest way to do that is to edit your ``~/.profile`` file and add a line similar to:: ulimit -n 1024 or:: ulimit -n unlimited This is an inherent problem with kqueue because it uses file descriptors to monitor files. That plus the enormous amount of bookkeeping that watchdog needs to do in order to monitor file descriptors just makes this a painful way to monitor files and directories. In essence, kqueue is not a very scalable way to monitor a deeply nested directory of files and directories with a large number of files. Free threaded support --------------------- `watchdog` has support for being built and run under free-threaded CPython. However, a full thread safety audit has not been completed, in particular this affects the `macOS FSEvents` interface. About using watchdog with editors like Vim ------------------------------------------ Vim does not modify files unless directed to do so. It creates backup files and then swaps them in to replace the files you are editing on the disk. This means that if you use Vim to edit your files, the on-modified events for those files will not be triggered by watchdog. You may need to configure Vim appropriately to disable this feature. About using watchdog with CIFS ------------------------------ When you want to watch changes in CIFS, you need to explicitly tell watchdog to use ``PollingObserver``, that is, instead of letting watchdog decide an appropriate observer like in the example above, do:: from watchdog.observers.polling import PollingObserver as Observer Dependencies ------------ 1. Python 3.9 or above. 2. XCode_ (only on macOS when installing from sources) 3. PyYAML_ (only for ``watchmedo``) Applications Using Watchdog ---------------------------- * `Watchdog.app`_ β€” A macOS application for monitoring file changes in selected directories. Built with the OMC engine, it provides a graphical interface for observing directories. The Apple-notarized app is read to use and does not require additional installations. Licensing --------- Watchdog is licensed under the terms of the `Apache License, version 2.0`_. - Copyright 2018-2025 MickaΓ«l Schoentgen & contributors - Copyright 2014-2018 Thomas Amland & contributors - Copyright 2012-2014 Google, Inc. - Copyright 2011-2012 Yesudeep Mangalapilly Project `source code`_ is available at Github. Please report bugs and file enhancement requests at the `issue tracker`_. Why Watchdog? ------------- Too many people tried to do the same thing and none did what I needed Python to do: * pnotify_ * `unison fsmonitor`_ * fsmonitor_ * guard_ * pyinotify_ * `inotify-tools`_ * jnotify_ * treewatcher_ * `file.monitor`_ * pyfilesystem_ .. links: .. _Yesudeep Mangalapilly: yesudeep@gmail.com .. _source code: https://github.com/gorakhargosh/watchdog .. _issue tracker: https://github.com/gorakhargosh/watchdog/issues .. _Apache License, version 2.0: https://www.apache.org/licenses/LICENSE-2.0 .. _documentation: https://python-watchdog.readthedocs.io/ .. _stackoverflow: https://stackoverflow.com/questions/tagged/python-watchdog .. _repository: https://github.com/gorakhargosh/watchdog .. _issue tracker: https://github.com/gorakhargosh/watchdog/issues .. _changelog: https://github.com/gorakhargosh/watchdog/blob/master/changelog.rst .. _PyYAML: https://www.pyyaml.org/ .. _XCode: https://developer.apple.com/technologies/tools/xcode.html .. _Watchdog.app: https://github.com/abra-code/WatchdogApp .. _pnotify: http://mark.heily.com/pnotify .. _unison fsmonitor: https://webdav.seas.upenn.edu/viewvc/unison/trunk/src/fsmonitor.py?view=markup&pathrev=471 .. _fsmonitor: https://github.com/shaurz/fsmonitor .. _guard: https://github.com/guard/guard .. _pyinotify: https://github.com/seb-m/pyinotify .. _inotify-tools: https://github.com/rvoicilas/inotify-tools .. _jnotify: http://jnotify.sourceforge.net/ .. _treewatcher: https://github.com/jbd/treewatcher .. _file.monitor: https://github.com/pke/file.monitor .. _pyfilesystem: https://github.com/PyFilesystem/pyfilesystem .. |PyPI Version| image:: https://img.shields.io/pypi/v/watchdog.svg :target: https://pypi.python.org/pypi/watchdog/ .. |PyPI Status| image:: https://img.shields.io/pypi/status/watchdog.svg :target: https://pypi.python.org/pypi/watchdog/ .. |PyPI Python Versions| image:: https://img.shields.io/pypi/pyversions/watchdog.svg :target: https://pypi.python.org/pypi/watchdog/ .. |Github Build Status| image:: https://github.com/gorakhargosh/watchdog/workflows/Tests/badge.svg :target: https://github.com/gorakhargosh/watchdog/actions?query=workflow%3ATests .. |GitHub License| image:: https://img.shields.io/github/license/gorakhargosh/watchdog.svg :target: https://github.com/gorakhargosh/watchdog/blob/master/LICENSE .. |Patreon| image:: https://img.shields.io/badge/Patreon-F96854?style=for-the-badge&logo=patreon&logoColor=white :target: https://www.patreon.com/mschoentgen