Full Code of gorakhargosh/watchdog for AI

master 88ba3b22df20 cached
92 files
576.3 KB
146.0k tokens
811 symbols
1 requests
Download .txt
Showing preview only (605K chars total). Download the full file or copy to clipboard to get everything.
Repository: gorakhargosh/watchdog
Branch: master
Commit: 88ba3b22df20
Files: 92
Total size: 576.3 KB

Directory structure:
gitextract_aij9dq2r/

├── .cirrus.yml
├── .gitattributes
├── .github/
│   ├── FUNDING.yml
│   ├── dependabot.yml
│   └── workflows/
│       ├── build-and-publish.yml
│       └── tests.yml
├── .gitignore
├── .well-known/
│   └── funding-manifest-urls
├── AUTHORS
├── COPYING
├── LICENSE
├── MANIFEST.in
├── README.rst
├── THIRD_PARTY_LICENSES.md
├── changelog.rst
├── docs/
│   ├── Makefile
│   ├── eclipse_cdt_style.xml
│   ├── make.bat
│   └── source/
│       ├── api.rst
│       ├── conf.py
│       ├── examples/
│       │   ├── __init__.py
│       │   ├── logger.py
│       │   ├── patterns.py
│       │   ├── simple.py
│       │   ├── tricks.json
│       │   └── tricks.yaml
│       ├── global.rst.inc
│       ├── hacking.rst
│       ├── index.rst
│       ├── installation.rst
│       └── quickstart.rst
├── pyproject.toml
├── requirements-tests.txt
├── setup.cfg
├── setup.py
├── src/
│   ├── pythoncapi_compat.h
│   ├── watchdog/
│   │   ├── __init__.py
│   │   ├── events.py
│   │   ├── observers/
│   │   │   ├── __init__.py
│   │   │   ├── api.py
│   │   │   ├── fsevents.py
│   │   │   ├── fsevents2.py
│   │   │   ├── inotify.py
│   │   │   ├── inotify_c.py
│   │   │   ├── inotify_move_event_grouper.py
│   │   │   ├── kqueue.py
│   │   │   ├── polling.py
│   │   │   ├── read_directory_changes.py
│   │   │   └── winapi.py
│   │   ├── py.typed
│   │   ├── tricks/
│   │   │   └── __init__.py
│   │   ├── utils/
│   │   │   ├── __init__.py
│   │   │   ├── backwards_compat.py
│   │   │   ├── bricks.py
│   │   │   ├── delayed_queue.py
│   │   │   ├── dirsnapshot.py
│   │   │   ├── echo.py
│   │   │   ├── event_debouncer.py
│   │   │   ├── patterns.py
│   │   │   ├── platform.py
│   │   │   └── process_watcher.py
│   │   ├── version.py
│   │   └── watchmedo.py
│   └── watchdog_fsevents.c
├── tests/
│   ├── __init__.py
│   ├── conftest.py
│   ├── isolated/
│   │   ├── __init__.py
│   │   ├── eventlet_observer_stops.py
│   │   └── eventlet_skip_repeat_queue.py
│   ├── shell.py
│   ├── test_0_watchmedo.py
│   ├── test_delayed_queue.py
│   ├── test_echo.py
│   ├── test_emitter.py
│   ├── test_events.py
│   ├── test_fsevents.py
│   ├── test_inotify_c.py
│   ├── test_inotify_watch_group.py
│   ├── test_isolated.py
│   ├── test_logging_event_handler.py
│   ├── test_observer.py
│   ├── test_observers_api.py
│   ├── test_observers_polling.py
│   ├── test_observers_winapi.py
│   ├── test_pattern_matching_event_handler.py
│   ├── test_patterns.py
│   ├── test_regex_matching_event_handler.py
│   ├── test_skip_repeats_queue.py
│   ├── test_snapshot_diff.py
│   └── utils.py
├── tools/
│   └── watchmedo.bat
└── tox.ini

================================================
FILE CONTENTS
================================================

================================================
FILE: .cirrus.yml
================================================
task:
  matrix:
    freebsd_instance:
      image_family: freebsd-13-0
    freebsd_instance:
      image_family: freebsd-12-2
      
  install_script:
    - pkg install -y python39 py39-sqlite3
    # Print the Python version, only to be sure we are running the version we want
    - python3.9 -c 'import platform; print("Python", platform.python_version())'
    # Check SQLite3 is installed
    - python3.9 -c 'import sqlite3; print("SQLite3", sqlite3.version)'
  setup_script:
    - python3.9 -m ensurepip
    - python3.9 -m pip install -U pip
    - python3.9 -m pip install -r requirements-tests.txt
  lint_script:
    - python3.9 -m ruff src
  tests_script:
    - python3.9 -bb -m pytest tests


================================================
FILE: .gitattributes
================================================
# Language aware diff headers
# https://tekin.co.uk/2020/10/better-git-diff-output-for-ruby-python-elixir-and-more
# https://gist.github.com/tekin/12500956bd56784728e490d8cef9cb81
# https://github.com/git/git/blob/master/userdiff.c
*.c diff=cpp
*.py diff=python


================================================
FILE: .github/FUNDING.yml
================================================
github: [BoboTiG]
polar: tiger-222


================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
  # GitHub Actions
  - package-ecosystem: github-actions
    directory: /
    schedule:
      interval: daily


================================================
FILE: .github/workflows/build-and-publish.yml
================================================
# Because this library provides extension modules for macOS, but not for other
# platforms, we want to provide built distributions for each macOS platform, but we
# explicitly DON'T want to provide a cross-platform pure-Python wheel to fall back on.
#
# This is because in the event that a new Python version is released or a new
# macOS platform is released, macOS users won't be able to install the built
# distributions we've provided and should fall back to the source distribution,
# but pip's behavior is to prefer a pure-Python wheel first, which will be
# missing the extension modules.
#
# However, to provide built distributions for Linux and Windows (which don't
# have extension modules) we can just build a pure-Python wheel on that
# platform and override the platform name manually via wheel's --plat-name
# feature, to provide a platform-specific wheel for all platforms.

name: Build & Publish

on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - "**"

  workflow_dispatch:
    inputs:
      branch:
        description: "The branch, tag or SHA to release from"
        required: true
        default: "master"

concurrency:
  group: ${{ github.ref }}-${{ github.workflow }}-${{ github.event_name }}-${{ github.event_name != 'pull_request' && github.sha || '' }}
  cancel-in-progress: true

jobs:
  macos-built-distributions:
    name: Build macOS wheels
    runs-on: macos-latest
    timeout-minutes: 20
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          ref: ${{ github.event.inputs.branch }}
      - name: Install Python
        uses: actions/setup-python@v6
        with:
          python-version: "3.11"
      - name: Install build dependencies
        run: python -m pip install cibuildwheel
      - name: Build wheels
        run: python -m cibuildwheel
        env:
          CIBW_ARCHS_MACOS: "x86_64 universal2 arm64"
      - name: Artifacts list
        run: ls -l wheelhouse
      - uses: actions/upload-artifact@v7
        with:
          name: python-package-distributions-macos
          path: ./wheelhouse/*.whl

  pure-built-distributions:
    name: Build pure wheels
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          ref: ${{ github.event.inputs.branch }}
      - name: Install Python
        uses: actions/setup-python@v6
        with:
          python-version: "3.11"
      - name: Install build dependencies
        run: python -m pip install -U setuptools wheel
      - name: Build wheels
        run: |
          for platform in 'manylinux_2_17_x86_64' 'manylinux_2_17_aarch64' 'manylinux_2_17_i686' 'manylinux_2_17_ppc64le' 'manylinux_2_17_s390x' 'manylinux_2_17_armv7l' 'manylinux_2_17_ppc64' 'manylinux2014_x86_64' 'manylinux2014_i686' 'manylinux2014_aarch64' 'manylinux2014_armv7l' 'manylinux2014_ppc64' 'manylinux2014_ppc64le' 'manylinux2014_s390x' 'win32' 'win_amd64' 'win_ia64'
          do
            python setup.py bdist_wheel --plat-name $platform
          done
      - name: Artifacts list
        run: ls -l dist
      - uses: actions/upload-artifact@v7
        with:
          name: python-package-distributions-pure-wheels
          path: ./dist/*.whl

  source-distribution:
    name: Build source distribution
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          ref: ${{ github.event.inputs.branch }}
      - name: Install Python
        uses: actions/setup-python@v6
        with:
          python-version: "3.11"
      - name: Build source distribution
        run: python setup.py sdist
      - name: Artifacts list
        run: ls -l dist
      - name: Store the source distribution
        uses: actions/upload-artifact@v7
        with:
          name: python-package-distributions-source
          path: dist/*.tar.gz

  publish:
    needs:
      - macos-built-distributions
      - pure-built-distributions
      - source-distribution
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - name: Download all the dists
        uses: actions/download-artifact@v8
        with:
          pattern: python-package-distributions-*
          merge-multiple: true
          path: dist/
      - name: What will we publish?
        run: ls -l dist
      - name: Publish
        if: github.event.inputs.branch != ''
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          user: __token__
          password: ${{ secrets.PYPI_API_TOKEN }}
          skip-existing: true


================================================
FILE: .github/workflows/tests.yml
================================================
name: Tests

on:
  push:
    branches:
      - master
  pull_request:
  workflow_dispatch:

concurrency:
  group: ${{ github.ref }}-${{ github.workflow }}-${{ github.event_name }}-${{ github.event_name != 'pull_request' && github.sha || '' }}
  cancel-in-progress: true

jobs:
  quality:
    name: 🧑‍🏭 Quality & Docs
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Set up Python
        uses: actions/setup-python@v6
        with:
          python-version: "3.13"
          cache: pip

      - name: Install dependencies
        run: python -m pip install tox

      - name: Run linters
        run: python -m tox -q -e types,lint

      - name: Build the documentation
        run: python -m tox -q -e docs

  tox:
    name: ${{ matrix.tox.name }} ${{ matrix.os.emoji }} ${{ matrix.os.name }} ${{ matrix.python }}
    runs-on: ${{ matrix.os.runs-on }}
    timeout-minutes: 15
    strategy:
      fail-fast: false
      matrix:
        os:
          - name: Linux
            matrix: linux
            emoji: 🐧
            runs-on: [ubuntu-latest]
          - name: macOS
            matrix: macos
            emoji: 🍎
            runs-on: [macos-latest]
          - name: Windows
            matrix: windows
            emoji: 🪟
            runs-on: [windows-latest]
        python:
          - "3.9"
          - "3.10"
          - "3.11"
          - "3.12"
          - "3.13"
          - "3.13t"
          - "3.14"
          - "3.14t"
          - "pypy-3.9"
        exclude:
          - os:
              matrix: macos
            python: "pypy-3.9"
          - os:
              matrix: windows
            python: "pypy-3.9"

    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Set up Python ${{ matrix.python }}
        uses: actions/setup-python@v6
        with:
          python-version: ${{ matrix.python }}
          allow-prereleases: true
          cache: pip

      - name: Install dependencies
        run: python -m pip install tox

      - name: Run tests
        run: python -m tox -q -e py


================================================
FILE: .gitignore
================================================
# Ignore temporary files.
*.bak
*.bkp
*.log
*.py[co]
*.swp
*~
.DS_Store
.\#*
._*
*.o
*.so
Desktop.ini
Thumbs.db
\#*\#
__MACOSX__

# Ignore generated files and directories.
*.egg-info/
*.egg
.installed.cfg
build/
develop-eggs/
dist/
eggs/
parts/
__pycache__/
MANIFEST

# Project files for VS Code, idea, eclipse, and netbeans
nbproject/
.idea/
.settings/
.vscode/

# Generated by tests.
.coverage
.coverage.*
htmlcov/
.tox/
.cache/
.pytest_cache/

# From virtualenv.
include/
lib/
/bootstrap.py
venv/
.venv/


================================================
FILE: .well-known/funding-manifest-urls
================================================
https://www.tiger-222.fr/funding.json


================================================
FILE: AUTHORS
================================================
Original Project Lead:
----------------------
Yesudeep Mangalapilly <yesudeep@google.com>

Current Project Lead:
---------------------
Mickaël Schoentgen <contact@tiger-222.fr>

Contributors in alphabetical order:
-----------------------------------
Adrian Tejn Kern <tejnkern@gmail.com>
Andrew Schaaf <andrew@andrewschaaf.com>
Danilo de Jesus da Silva Bellini <danilo.bellini@gmail.com>
David LaPalomento <dlapalomento@gmail.com>
dvogel <dvogel@wlscapi.uwsc.wisc.edu>
Filip Noetzel <filip@j03.de>
Gary van der Merwe <garyvdm@garyvdm.localdomain>
gfxmonk <tim3d.junk@gmail.com>
Gora Khargosh <gora.khargosh@gmail.com>
Hannu Valtonen <hannu.valtonen@ohmu.fi>
Jesse Printz <jesse@jonypawks.net>
Kurt McKee <contactme@kurtmckee.org>
Léa Klein <lklein@nuxeo.com>
Luke McCarthy <luke@iogopro.co.uk>
Lukáš Lalinský <lalinsky@gmail.com>
Malthe Borch <mborch@gmail.com>
Martin Kreichgauer <kreichgauer@gmail.com>
Martin Kreichgauer <martin@kreichgauer.com>
Mike Lundy <mike@fluffypenguin.org>
Nicholas Hairs <info+watchdog@nicholashairs.com>
Raymond Hettinger <python@rcn.com>
Roman Ovchinnikov <coolthecold@gmail.com>
Rotem Yaari <vmalloc@gmail.com>
Ryan Kelly <ryan@rfk.id.au>
Senko Rasic <senko.rasic@dobarkod.hr>
Senko Rašić <senko@senko.net>
Shane Hathaway <shane@hathawaymix.org>
Simon Pantzare <simon@pewpewlabs.com>
Simon Pantzare <simpa395@student.liu.se>
Steven Samuel Cole <steven.samuel.cole@gmail.com>
Stéphane Klein <stephane@harobed.org>
Thomas Guest <tag@wordaligned.org>
Thomas Heller <theller@ctypes.org>
Tim Cuthbertson <tim+github@gfxmonk.net>
Todd Whiteman <toddw@activestate.com>
Will McGugan <will@willmcgugan.com>
Yesudeep Mangalapilly <gora.khargosh@gmail.com>
Yesudeep Mangalapilly <yesudeep@google.com>

We would like to thank these individuals for ideas:
---------------------------------------------------
Tim Golden               <mail@timgolden.me.uk>
Sebastien Martini        <seb@dbzteam.org>

Initially we used the flask theme for the documentation which was written by
----------------------------------------------------------------------------
Armin Ronacher           <armin.ronacher@active-4.com>


Watchdog also includes open source libraries or adapted code
from the following projects:

- MacFSEvents - https://github.com/malthe/macfsevents
- watch_directory.py - http://timgolden.me.uk/python/downloads/watch_directory.py
- pyinotify - https://github.com/seb-m/pyinotify
- fsmonitor - https://github.com/shaurz/fsmonitor
- echo - http://wordaligned.org/articles/echo
- Lukáš Lalinský's ordered set queue implementation:
  https://stackoverflow.com/questions/1581895/how-check-if-a-task-is-already-in-python-queue
- Armin Ronacher's flask-sphinx-themes for the documentation:
  https://github.com/mitsuhiko/flask-sphinx-themes
- pyfilesystem - https://github.com/PyFilesystem/pyfilesystem
- get_FILE_NOTIFY_INFORMATION - http://blog.gmane.org/gmane.comp.python.ctypes/month=20070901


================================================
FILE: COPYING
================================================
Copyright 2018-2025 Mickaël Schoentgen & contributors
Copyright 2014-2018 Thomas Amland & contributors
Copyright 2012-2014 Google, Inc.
Copyright 2011-2012 Yesudeep Mangalapilly

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.


================================================
FILE: LICENSE
================================================

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: MANIFEST.in
================================================
include README.rst
include changelog.rst
include LICENSE
include COPYING
include AUTHORS
recursive-include src *.py *.h *.c
include src/watchdog/py.typed
include tox.ini
include docs/*.txt
include docs/*.xml
include docs/Makefile
include docs/make.bat
include requirements-tests.txt
recursive-include docs/source *
recursive-include tests *.py
#global-exclude .DS_Store
#global-exclude Thumbs.db
#global-exclude Desktop.ini
#global-exclude *.swp
#global-exclude *~
#global-exclude *.bak


================================================
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``)

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

.. _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


================================================
FILE: THIRD_PARTY_LICENSES.md
================================================
# Third Party Licenses

## Python C-API compatibility header

This project includes the `pythoncapi_compat.h` header provided by the
`pythoncapi-compat` project. It is located in the `src` directory.

This header is included to allow writing code using C API constructs only
available in newer Python versions.

**License**: Zero Clause BSD
**Copyright**: Contributors to the pythoncapi_compat project.
**Source**: https://github.com/python/pythoncapi_compat

## Python Standard Library Compatibility Code

This project includes the following unmodified functions from the Python 3.13 standard library:

- `glob.translate` (from `Lib/glob.py`)
- `fnmatch._translate` (from `Lib/fnmatch.py`)

These are included in `backwards_compat.py` to provide backwards compatibility with older Python versions.

**License**: Python Software Foundation License Version 2
**Copyright**: © 2001–2024 Python Software Foundation; All Rights Reserved
**Source**: https://github.com/python/cpython

---

### Zero Clause BSD License

BSD Zero Clause License

Copyright Contributors to the pythoncapi_compat project.

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.

### Python Software Foundation License Version 2

1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and the Individual or Organization ("Licensee") accessing and otherwise using this software ("Python") in source or binary form and its associated documentation.

2. Subject to the terms and conditions of this License Agreement, PSF hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of copyright, i.e., "Copyright (c) 2001 Python Software Foundation; All Rights Reserved" are retained in Python alone or in any derivative version prepared by Licensee.

3. In the event Licensee prepares a derivative work that is based on or incorporates Python or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python.

4. PSF is making Python available to Licensee on an "AS IS" basis.  PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.

5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.

6. This License Agreement will automatically terminate upon a material breach of its terms and conditions.

7. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between PSF and Licensee.  This License Agreement does not grant permission to use PSF trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party.

8. By copying, installing or otherwise using Python, Licensee agrees to be bound by the terms and conditions of this License Agreement.



================================================
FILE: changelog.rst
================================================
.. :changelog:

Changelog
---------

7.0.0-dev
~~~~~~~~~

202x-xx-xx • `full history <https://github.com/gorakhargosh/watchdog/compare/v6.0.0...HEAD>`__

**Breaking Changes**

- [core] Changed pattern matching mechanism from using ``path.match()`` to ``path.full_match()``. Users must update patterns to glob-like syntax: e.g., `*.py` to `**/*.py`. (`#1101 <https://github.com/gorakhargosh/watchdog/pull/1101>`__)

**Other Changes**

- [core] Add context manager support to ``Observer`` class. The observer can now be used with a ``with`` statement for automatic start/stop management. (`#1090 <https://github.com/gorakhargosh/watchdog/pull/1149>`__)
- [freebsd] Supports ``inotify`` on FreeBSD 15+. (`#1147 <https://github.com/gorakhargosh/watchdog/pull/1147>`__)
- [core] Adjust ``Observer.schedule()`` ``path`` type annotation to reflect the ``pathlib.Path`` support. (`#1096 <https://github.com/gorakhargosh/watchdog/pull/1096>`__)
- [core] Add support for the ``follow_symlink`` keyword argument to ``ObservedWatch``. (`#1086 <https://github.com/gorakhargosh/watchdog/pull/1086>`__)
- [fsevents] Add support for the ``follow_symlink`` keyword argument. (`#1086 <https://github.com/gorakhargosh/watchdog/pull/1086>`__)
- [inotify] Reduce number of created inotify instance. (`#1099 <https://github.com/gorakhargosh/watchdog/pull/1099>`__)
- [inotify] Add support for the ``follow_symlink`` keyword argument. (`#1086 <https://github.com/gorakhargosh/watchdog/pull/1086>`__)
- [utils] Fixed ``repr(EmptyDirectorySnapshot)``, before that it was throwing an ``AttributeError: 'EmptyDirectorySnapshot' object has no attribute '_stat_info'``.
- [utils] Implemented ``len(DirectorySnapshotDiff)`` to return the total number of changes.
- [core] Fixed ``generate_sub_moved_events()`` corrupting paths when the directory name appears multiple times in the path. (`#1158 <https://github.com/gorakhargosh/watchdog/pull/1158>`__)
- Thanks to our beloved contributors: @BoboTiG, @tybug, @Corentin-pro, @kirkhansen, @JoachimCoenen, @blitztide
- [core] Call ``task_done()`` for the stop sentinel in ``dispatch_events()`` to prevent ``join()`` from hanging. (`#1159 <https://github.com/gorakhargosh/watchdog/pull/1159>`__)

6.0.0
~~~~~

2024-11-01 • `full history <https://github.com/gorakhargosh/watchdog/compare/v5.0.3...v6.0.0>`__

- Pin test dependencies.
- [docs] Add typing info to quick start. (`#1082 <https://github.com/gorakhargosh/watchdog/pull/1082>`__)
- [inotify] Use of ``select.poll()`` instead of deprecated ``select.select()``, if available. (`#1078 <https://github.com/gorakhargosh/watchdog/pull/1078>`__)
- [inotify] Fix reading inotify file descriptor after closing it. (`#1081 <https://github.com/gorakhargosh/watchdog/pull/1081>`__)
- [utils] The ``stop_signal`` keyword-argument type of the ``AutoRestartTrick`` class can now be either a ``signal.Signals`` or an ``int``.
- [utils] Added the ``__repr__()`` method to the ``Trick`` class.
- [utils] Removed the unused ``echo_class()`` function from the ``echo`` module.
- [utils] Removed the unused ``echo_instancemethod()`` function from the ``echo`` module.
- [utils] Removed the unused ``echo_module()`` function from the ``echo`` module.
- [utils] Removed the unused ``is_class_private_name()`` function from the ``echo`` module.
- [utils] Removed the unused ``is_classmethod()`` function from the ``echo`` module.
- [utils] Removed the unused ``ic_method(met()`` function from the ``echo`` module.
- [utils] Removed the unused ``method_name()`` function from the ``echo`` module.
- [utils] Removed the unused ``name()`` function from the ``echo`` module.
- [watchmedo] Fixed Mypy issues.
- [watchmedo] Added the ``__repr__()`` method to the ``HelpFormatter`` class.
- [watchmedo] Removed the ``--trace`` CLI argument from the ``watchmedo log`` command, useless since events are logged by default at the ``LoggerTrick`` class level.
- [windows] Fixed Mypy issues.
- Thanks to our beloved contributors: @BoboTiG, @g-pichler, @ethan-vanderheijden, @nhairs

5.0.3
~~~~~

2024-09-27 • `full history <https://github.com/gorakhargosh/watchdog/compare/v5.0.2...v5.0.3>`__

- [inotify] Improve cleaning up ``Inotify`` threads, and add ``eventlet`` test cases (`#1070 <https://github.com/gorakhargosh/watchdog/pull/1070>`__)
- Thanks to our beloved contributors: @BoboTiG, @ethan-vanderheijden

5.0.2
~~~~~

2024-09-03 • `full history <https://github.com/gorakhargosh/watchdog/compare/v5.0.1...v5.0.2>`__

- Enable OS specific Mypy checks (`#1064 <https://github.com/gorakhargosh/watchdog/pull/1064>`__)
- [watchmedo] Fix ``tricks`` argument type of ``schedule_tricks()`` (`#1063 <https://github.com/gorakhargosh/watchdog/pull/1063>`__)
- Thanks to our beloved contributors: @gnought, @BoboTiG

5.0.1
~~~~~

2024-09-02 • `full history <https://github.com/gorakhargosh/watchdog/compare/v5.0.0...v5.0.1>`__

- [kqueue] Fix ``TypeError: kqueue.control() only accepts positional parameters``  (`#1062 <https://github.com/gorakhargosh/watchdog/pull/1062>`__)
- Thanks to our beloved contributors: @apoirier, @BoboTiG

5.0.0
~~~~~

2024-08-26 • `full history <https://github.com/gorakhargosh/watchdog/compare/v4.0.2...v5.0.0>`__

**Breaking Changes**

- Drop support for Python 3.8 (`#1055 <https://github.com/gorakhargosh/watchdog/pull/1055>`__)
- [core] Enforced usage of proper keyword-arguments (`#1057 <https://github.com/gorakhargosh/watchdog/pull/1057>`__)
- [core] Renamed the ``BaseObserverSubclassCallable`` class to ``ObserverType`` (`#1055 <https://github.com/gorakhargosh/watchdog/pull/1055>`__)
- [inotify] Renamed the ``inotify_event_struct`` class to ``InotifyEventStruct`` (`#1055 <https://github.com/gorakhargosh/watchdog/pull/1055>`__)
- [inotify] Renamed the ``UnsupportedLibc`` exception to ``UnsupportedLibcError`` (`#1057 <https://github.com/gorakhargosh/watchdog/pull/1057>`__)
- [inotify] Removed the ``InotifyConstants.IN_CLOSE`` constant (`#1046 <https://github.com/gorakhargosh/watchdog/pull/1046>`__)
- [watchmedo] Renamed the ``LogLevelException`` exception to ``LogLevelError`` (`#1057 <https://github.com/gorakhargosh/watchdog/pull/1057>`__)
- [watchmedo] Renamed the ``WatchdogShutdown`` exception to ``WatchdogShutdownError`` (`#1057 <https://github.com/gorakhargosh/watchdog/pull/1057>`__)
- [windows] Renamed the ``FILE_NOTIFY_INFORMATION`` class to ``FileNotifyInformation`` (`#1055 <https://github.com/gorakhargosh/watchdog/pull/1055>`__)
- [windows] Removed the unused ``WATCHDOG_TRAVERSE_MOVED_DIR_DELAY`` constant (`#1057 <https://github.com/gorakhargosh/watchdog/pull/1057>`__)

**Other Changes**

- [core] Enable ``disallow_untyped_calls`` Mypy rule (`#1055 <https://github.com/gorakhargosh/watchdog/pull/1055>`__)
- [core] Enable ``disallow_untyped_defs`` Mypy rule (`#1060 <https://github.com/gorakhargosh/watchdog/pull/1060>`__)
- [core] Improve typing references for events (`#1040 <https://github.com/gorakhargosh/watchdog/issues/1040>`__)
- [inotify] Add support for ``IN_CLOSE_NOWRITE`` events. A ``FileClosedNoWriteEvent`` event will be fired, and its ``on_closed_no_write()`` dispatcher has been introduced (`#1046 <https://github.com/gorakhargosh/watchdog/pull/1046>`__)
- Thanks to our beloved contributors: @BoboTiG

4.0.2
~~~~~

2024-08-11 • `full history <https://github.com/gorakhargosh/watchdog/compare/v4.0.1...v4.0.2>`__

- Add support for Python 3.13 (`#1052 <https://github.com/gorakhargosh/watchdog/pull/1052>`__)
- [core] Run ``ruff``, apply several fixes (`#1033 <https://github.com/gorakhargosh/watchdog/pull/1033>`__)
- [core] Remove execution rights from ``events.py``
- [documentation] Update ``PatternMatchingEventHandler`` docstrings (`#1048 <https://github.com/gorakhargosh/watchdog/pull/1048>`__)
- [documentation] Simplify the quickstart example (`#1047 <https://github.com/gorakhargosh/watchdog/pull/1047>`__)
- [fsevents] Add missing ``event_filter`` keyword-argument to ``FSEventsObserver.schedule()`` (`#1049 <https://github.com/gorakhargosh/watchdog/pull/1049>`__)
- [utils] Fix a possible race condition in ``AutoRestartTrick`` (`#1002 <https://github.com/gorakhargosh/watchdog/pull/1002>`__)
- [watchmedo] Remove execution rights from ``watchmedo.py``
- Thanks to our beloved contributors: @BoboTiG, @nbelakovski, @ivg

4.0.1
~~~~~

2024-05-23 • `full history <https://github.com/gorakhargosh/watchdog/compare/v4.0.0...v4.0.1>`__

- [inotify] Fix missing ``event_filter`` for the full emitter (`#1032 <https://github.com/gorakhargosh/watchdog/pull/1032>`__)
- Thanks to our beloved contributors: @mraspaud, @BoboTiG

4.0.0
~~~~~

2024-02-06 • `full history <https://github.com/gorakhargosh/watchdog/compare/v3.0.0...v4.0.0>`__

- Drop support for Python 3.7.
- Add support for Python 3.12.
- [snapshot] Add typing to ``dirsnapshot`` (`#1012 <https://github.com/gorakhargosh/watchdog/pull/1012>`__)
- [snapshot] Added ``DirectorySnapshotDiff.ContextManager`` (`#1011 <https://github.com/gorakhargosh/watchdog/pull/1011>`__)
- [events] ``FileSystemEvent``, and subclasses, are now ``dataclass``es, and their ``repr()`` has changed
- [windows] ``WinAPINativeEvent`` is now a ``dataclass``, and its ``repr()`` has changed
- [events] Log ``FileOpenedEvent``, and ``FileClosedEvent``, events in ``LoggingEventHandler``
- [tests] Improve ``FileSystemEvent`` coverage
- [watchmedo] Log all events in ``LoggerTrick``
- [windows] The ``observers.read_directory_changes.WATCHDOG_TRAVERSE_MOVED_DIR_DELAY`` hack was removed. The constant will be kept to prevent breaking other software.
- Thanks to our beloved contributors: @BoboTiG, @msabramo

3.0.0
~~~~~

2023-03-20 • `full history <https://github.com/gorakhargosh/watchdog/compare/v2.3.1...v3.0.0>`__

- Drop support for Python 3.6.
- ``watchdog`` is now PEP 561 compatible, and tested with ``mypy``
- Fix missing ``>`` in ``FileSystemEvent.__repr__()``  (`#980 <https://github.com/gorakhargosh/watchdog/pull/980>`__)
- [ci] Lots of improvements
- [inotify] Return from ``InotifyEmitter.queue_events()`` if not launched when thread is inactive (`#963 <https://github.com/gorakhargosh/watchdog/pull/963>`__)
- [tests] Stability improvements
- [utils] Remove handling of ``threading.Event.isSet`` spelling (`#962 <https://github.com/gorakhargosh/watchdog/pull/962>`__)
- [watchmedo] Fixed tricks YAML generation (`#965 <https://github.com/gorakhargosh/watchdog/pull/965>`__)
- Thanks to our beloved contributors: @kurtmckee, @altendky, @agroszer, @BoboTiG

2.3.1
~~~~~

2023-02-28 • `full history <https://github.com/gorakhargosh/watchdog/compare/v2.3.0...v2.3.1>`__

- Run ``black`` on the entire source code
- Bundle the ``requirements-tests.txt`` file in the source distribution (`#939 <https://github.com/gorakhargosh/watchdog/pull/939>`__)
- [watchmedo] Exclude ``FileOpenedEvent`` events from ``AutoRestartTrick``, and ``ShellCommandTrick``, to restore watchdog < 2.3.0 behavior. A better solution should be found in the future. (`#949 <https://github.com/gorakhargosh/watchdog/pull/949>`__)
- [watchmedo] Log ``FileOpenedEvent``, and ``FileClosedEvent``, events in ``LoggerTrick``
- Thanks to our beloved contributors: @BoboTiG

2.3.0
~~~~~

2023-02-23 • `full history <https://github.com/gorakhargosh/watchdog/compare/v2.2.1...v2.3.0>`__

- [inotify] Add support for ``IN_OPEN`` events: a ``FileOpenedEvent`` event will be fired (`#941 <https://github.com/gorakhargosh/watchdog/pull/941>`__)
- [watchmedo] Add optional event debouncing for ``auto-restart``, only restarting once if many events happen in quick succession (``--debounce-interval``) (`#940 <https://github.com/gorakhargosh/watchdog/pull/940>`__)
- [watchmedo] Exit gracefully on ``KeyboardInterrupt`` exception (Ctrl+C) (`#945 <https://github.com/gorakhargosh/watchdog/pull/945>`__)
- [watchmedo] Add option to not auto-restart the command after it exits (``--no-restart-on-command-exit``) (`#946 <https://github.com/gorakhargosh/watchdog/pull/946>`__)
- Thanks to our beloved contributors: @BoboTiG, @dstaple, @taleinat, @cernekj

2.2.1
~~~~~

2023-01-01 • `full history <https://github.com/gorakhargosh/watchdog/compare/v2.2.0...v2.2.1>`__

- Enable ``mypy`` to discover type hints as specified in PEP 561 (`#933 <https://github.com/gorakhargosh/watchdog/pull/933>`__)
- [ci] Set the expected Python version when building release files
- [ci] Update actions versions in use
- [watchmedo] [regression] Fix usage of missing ``signal.SIGHUP`` attribute on non-Unix OSes (`#935 <https://github.com/gorakhargosh/watchdog/pull/935>`__)
- Thanks to our beloved contributors: @BoboTiG, @simon04, @piotrpdev

2.2.0
~~~~~

2022-12-05 • `full history <https://github.com/gorakhargosh/watchdog/compare/v2.1.9...v2.2.0>`__

- [build] Wheels are now available for Python 3.11 (`#932 <https://github.com/gorakhargosh/watchdog/pull/932>`__)
- [documentation] HTML documentation builds are now tested for errors (`#902 <https://github.com/gorakhargosh/watchdog/pull/902>`__)
- [documentation] Fix typos here, and there (`#910 <https://github.com/gorakhargosh/watchdog/pull/910>`__)
- [fsevents2] The ``fsevents2`` observer is now deprecated (`#909 <https://github.com/gorakhargosh/watchdog/pull/909>`__)
- [tests] The error message returned by musl libc for error code ``-1`` is now allowed (`#923 <https://github.com/gorakhargosh/watchdog/pull/923>`__)
- [utils] Remove unnecessary code in ``dirsnapshot.py`` (`#930 <https://github.com/gorakhargosh/watchdog/pull/930>`__)
- [watchmedo] Handle shutdown events from ``SIGHUP`` (`#912 <https://github.com/gorakhargosh/watchdog/pull/912>`__)
- Thanks to our beloved contributors: @kurtmckee, @babymastodon, @QuantumEnergyE, @timgates42, @BoboTiG

2.1.9
~~~~~

2022-06-10 • `full history <https://github.com/gorakhargosh/watchdog/compare/v2.1.8...v2.1.9>`__

- [fsevents] Fix flakey test to assert that there are no errors when stopping the emitter.
- [inotify] Suppress occasional ``OSError: [Errno 9] Bad file descriptor`` at shutdown. (`#805 <https://github.com/gorakhargosh/watchdog/issues/805>`__)
- [watchmedo] Make ``auto-restart`` restart the sub-process if it terminates. (`#896 <https://github.com/gorakhargosh/watchdog/pull/896>`__)
- [watchmedo] Avoid zombie sub-processes when running ``shell-command`` without ``--wait``. (`#405 <https://github.com/gorakhargosh/watchdog/issues/405>`__)
- Thanks to our beloved contributors: @samschott, @taleinat, @altendky, @BoboTiG

2.1.8
~~~~~

2022-05-15 • `full history <https://github.com/gorakhargosh/watchdog/compare/v2.1.7...v2.1.8>`__

- Fix adding failed emitters on observer schedule. (`#872 <https://github.com/gorakhargosh/watchdog/issues/872>`__)
- [inotify] Fix hang when unscheduling watch on a path in an unmounted filesystem. (`#869 <https://github.com/gorakhargosh/watchdog/pull/869>`__)
- [watchmedo] Fix broken parsing of ``--kill-after`` argument for the ``auto-restart`` command. (`#870 <https://github.com/gorakhargosh/watchdog/issues/870>`__)
- [watchmedo] Fix broken parsing of boolean arguments. (`#887 <https://github.com/gorakhargosh/watchdog/issues/887>`__)
- [watchmedo] Fix broken parsing of commands from ``auto-restart``, and ``shell-command``. (`#888 <https://github.com/gorakhargosh/watchdog/issues/888>`__)
- [watchmedo] Support setting verbosity level via ``-q/--quiet`` and ``-v/--verbose`` arguments. (`#889 <https://github.com/gorakhargosh/watchdog/pull/889>`__)
- Thanks to our beloved contributors: @taleinat, @kianmeng, @palfrey, @IlayRosenberg, @BoboTiG

2.1.7
~~~~~

2022-03-25 • `full history <https://github.com/gorakhargosh/watchdog/compare/v2.1.6...v2.1.7>`__

- Eliminate timeout in waiting on event queue. (`#861 <https://github.com/gorakhargosh/watchdog/pull/861>`__)
- [inotify] Fix ``not`` equality implementation for ``InotifyEvent``. (`#848 <https://github.com/gorakhargosh/watchdog/pull/848>`__)
- [watchmedo] Fix calling commands from within a Python script. (`#879 <https://github.com/gorakhargosh/watchdog/pull/879>`__)
- [watchmedo] ``PyYAML`` is loaded only when strictly necessary. Simple usages of ``watchmedo`` are possible without the module being installed. (`#847 <https://github.com/gorakhargosh/watchdog/pull/847>`__)
- Thanks to our beloved contributors: @sattlerc, @JanzenLiu, @BoboTiG

2.1.6
~~~~~

2021-10-01 • `full history <https://github.com/gorakhargosh/watchdog/compare/v2.1.5...v2.1.6>`__

- [bsd] Fixed returned paths in ``kqueue.py`` and restored the overall results of the test suite. (`#842 <https://github.com/gorakhargosh/watchdog/pull/842>`__)
- [bsd] Updated FreeBSD CI support .(`#841 <https://github.com/gorakhargosh/watchdog/pull/841>`__)
- [watchmedo] Removed the ``argh`` dependency in favor of the builtin ``argparse`` module. (`#836 <https://github.com/gorakhargosh/watchdog/pull/836>`__)
- [watchmedo] Removed unexistant ``WindowsApiAsyncObserver`` references and ``--debug-force-winapi-async`` arguments.
- [watchmedo] Improved the help output.
- Thanks to our beloved contributors: @knobix, @AndreaRe9, @BoboTiG

2.1.5
~~~~~

2021-08-23 • `full history <https://github.com/gorakhargosh/watchdog/compare/v2.1.4...v2.1.5>`__

- Fix regression introduced in 2.1.4 (reverted "Allow overriding or adding custom event handlers to event dispatch map. (`#814 <https://github.com/gorakhargosh/watchdog/pull/814>`__)"). (`#830 <https://github.com/gorakhargosh/watchdog/pull/830>`__)
- Convert regexes of type ``str`` to ``list``. (`831 <https://github.com/gorakhargosh/watchdog/pull/831>`__)
- Thanks to our beloved contributors: @unique1o1, @BoboTiG

2.1.4
~~~~~

2021-08-19 • `full history <https://github.com/gorakhargosh/watchdog/compare/v2.1.3...v2.1.4>`__

- [watchmedo] Fix usage of ``os.setsid()`` and ``os.killpg()`` Unix-only functions. (`#809 <https://github.com/gorakhargosh/watchdog/pull/809>`__)
- [mac] Fix missing ``FileModifiedEvent`` on permission or ownership changes of a file. (`#815 <https://github.com/gorakhargosh/watchdog/pull/815>`__)
- [mac] Convert absolute watch path in ``FSEeventsEmitter`` with ``os.path.realpath()``. (`#822 <https://github.com/gorakhargosh/watchdog/pull/822>`__)
- Fix a possible ``AttributeError`` in ``SkipRepeatsQueue._put()``. (`#818 <https://github.com/gorakhargosh/watchdog/pull/818>`__)
- Allow overriding or adding custom event handlers to event dispatch map. (`#814 <https://github.com/gorakhargosh/watchdog/pull/814>`__)
- Fix tests on big endian platforms. (`#828 <https://github.com/gorakhargosh/watchdog/pull/828>`__)
- Thanks to our beloved contributors: @replabrobin, @BoboTiG, @SamSchott, @AndreiB97, @NiklasRosenstein, @ikokollari, @mgorny

2.1.3
~~~~~

2021-06-26 • `full history <https://github.com/gorakhargosh/watchdog/compare/v2.1.2...v2.1.3>`__

- Publish macOS ``arm64`` and ``universal2`` wheels. (`#740 <https://github.com/gorakhargosh/watchdog/pull/740>`__)
- Thanks to our beloved contributors: @kainjow, @BoboTiG

2.1.2
~~~~~

2021-05-19 • `full history <https://github.com/gorakhargosh/watchdog/compare/v2.1.1...v2.1.2>`__

- [mac] Fix relative path handling for non-recursive watch. (`#797 <https://github.com/gorakhargosh/watchdog/pull/797>`__)
- [windows] On PyPy, events happening right after ``start()`` were missed. Add a workaround for that. (`#796 <https://github.com/gorakhargosh/watchdog/pull/796>`__)
- Thanks to our beloved contributors: @oprypin, @CCP-Aporia, @BoboTiG

2.1.1
~~~~~

2021-05-10 • `full history <https://github.com/gorakhargosh/watchdog/compare/v2.1.0...v2.1.1>`__

- [mac] Fix callback exceptions when the watcher is deleted but still receiving events (`#786 <https://github.com/gorakhargosh/watchdog/pull/786>`__)
- Thanks to our beloved contributors: @rom1win, @BoboTiG, @CCP-Aporia


2.1.0
~~~~~

2021-05-04 • `full history <https://github.com/gorakhargosh/watchdog/compare/v2.0.3...v2.1.0>`__

- [inotify] Simplify ``libc`` loading (`#776 <https://github.com/gorakhargosh/watchdog/pull/776>`__)
- [mac] Add support for non-recursive watches in ``FSEventsEmitter`` (`#779 <https://github.com/gorakhargosh/watchdog/pull/779>`__)
- [watchmedo] Add support for ``--debug-force-*`` arguments to ``tricks`` (`#781 <https://github.com/gorakhargosh/watchdog/pull/781>`__)
- Thanks to our beloved contributors: @CCP-Aporia, @aodj, @UnitedMarsupials, @BoboTiG


2.0.3
~~~~~

2021-04-22 • `full history <https://github.com/gorakhargosh/watchdog/compare/v2.0.2...v2.0.3>`__

- [mac] Use ``logger.debug()`` instead of ``logger.info()`` (`#774 <https://github.com/gorakhargosh/watchdog/pull/774>`__)
- Updated documentation links (`#777 <https://github.com/gorakhargosh/watchdog/pull/777>`__)
- Thanks to our beloved contributors: @globau, @imba-tjd, @BoboTiG


2.0.2
~~~~~

2021-02-22 • `full history <https://github.com/gorakhargosh/watchdog/compare/v2.0.1...v2.0.2>`__

- [mac] Add missing exception objects (`#766 <https://github.com/gorakhargosh/watchdog/pull/766>`__)
- Thanks to our beloved contributors: @CCP-Aporia, @BoboTiG


2.0.1
~~~~~

2021-02-17 • `full history <https://github.com/gorakhargosh/watchdog/compare/v2.0.0...v2.0.1>`__

- [mac] Fix a segmentation fault when dealing with unicode paths (`#763 <https://github.com/gorakhargosh/watchdog/pull/763>`__)
- Moved the CI from Travis-CI to GitHub Actions (`#764 <https://github.com/gorakhargosh/watchdog/pull/764>`__)
- Thanks to our beloved contributors: @SamSchott, @BoboTiG


2.0.0
~~~~~

2021-02-11 • `full history <https://github.com/gorakhargosh/watchdog/compare/v1.0.2...v2.0.0>`__

- Avoid deprecated ``PyEval_InitThreads`` on Python 3.7+ (`#746 <https://github.com/gorakhargosh/watchdog/pull/746>`__)
- [inotify] Add support for ``IN_CLOSE_WRITE`` events. A ``FileCloseEvent`` event will be fired. Note that ``IN_CLOSE_NOWRITE`` events are not handled to prevent much noise. (`#184 <https://github.com/gorakhargosh/watchdog/pull/184>`__, `#245 <https://github.com/gorakhargosh/watchdog/pull/245>`__, `#280 <https://github.com/gorakhargosh/watchdog/pull/280>`__, `#313 <https://github.com/gorakhargosh/watchdog/pull/313>`__, `#690 <https://github.com/gorakhargosh/watchdog/pull/690>`__)
- [inotify] Allow to stop the emitter multiple times (`#760 <https://github.com/gorakhargosh/watchdog/pull/760>`__)
- [mac] Support coalesced filesystem events (`#734 <https://github.com/gorakhargosh/watchdog/pull/734>`__)
- [mac] Drop support for macOS 10.12 and earlier (`#750 <https://github.com/gorakhargosh/watchdog/pull/750>`__)
- [mac] Fix an issue when renaming an item changes only the casing (`#750 <https://github.com/gorakhargosh/watchdog/pull/750>`__)
- Thanks to our beloved contributors: @bstaletic, @lukassup, @ysard, @SamSchott, @CCP-Aporia, @BoboTiG


1.0.2
~~~~~

2020-12-18 • `full history <https://github.com/gorakhargosh/watchdog/compare/v1.0.1...v1.0.2>`__

- Wheels are published for GNU/Linux, macOS and Windows (`#739 <https://github.com/gorakhargosh/watchdog/pull/739>`__)
- [mac] Fix missing ``event_id`` attribute in ``fsevents`` (`#721 <https://github.com/gorakhargosh/watchdog/pull/721>`__)
- [mac] Return byte paths if a byte path was given in ``fsevents`` (`#726 <https://github.com/gorakhargosh/watchdog/pull/726>`__)
- [mac] Add compatibility with old macOS versions (`#733 <https://github.com/gorakhargosh/watchdog/pull/733>`__)
- Uniformize event for deletion of watched dir (`#727 <https://github.com/gorakhargosh/watchdog/pull/727>`__)
- Thanks to our beloved contributors: @SamSchott, @CCP-Aporia, @di, @BoboTiG


1.0.1
~~~~~

2020-12-10 • Fix version with good metadatas.


1.0.0
~~~~~

2020-12-10 • `full history <https://github.com/gorakhargosh/watchdog/compare/v0.10.4...v1.0.0>`__

- Versioning is now following the `semver <https://semver.org/>`__
- Drop support for Python 2.7, 3.4 and 3.5
- [mac] Regression fixes for native ``fsevents`` (`#717 <https://github.com/gorakhargosh/watchdog/pull/717>`__)
- [windows] ``winapi.BUFFER_SIZE`` now defaults to ``64000`` (instead of ``2048``) (`#700 <https://github.com/gorakhargosh/watchdog/pull/700>`__)
- [windows] Introduced ``winapi.PATH_BUFFER_SIZE`` (defaults to ``2048``) to keep the old behavior with path-realted functions (`#700 <https://github.com/gorakhargosh/watchdog/pull/700>`__)
- Use ``pathlib`` from the standard library, instead of pathtools (`#556 <https://github.com/gorakhargosh/watchdog/pull/556>`__)
- Allow file paths on Unix that don't follow the file system encoding (`#703 <https://github.com/gorakhargosh/watchdog/pull/703>`__)
- Removed the long-time deprecated ``events.LoggingFileSystemEventHandler`` class, use ``LoggingEventHandler`` instead
- Thanks to our beloved contributors: @SamSchott, @bstaletic, @BoboTiG, @CCP-Aporia


0.10.4
~~~~~~

2020-11-21 • `full history <https://github.com/gorakhargosh/watchdog/compare/v0.10.3...v0.10.4>`__

- Add ``logger`` parameter for the ``LoggingEventHandler`` (`#676 <https://github.com/gorakhargosh/watchdog/pull/676>`__)
- Replace mutable default arguments with ``if None`` implementation (`#677 <https://github.com/gorakhargosh/watchdog/pull/677>`__)
- Expand tests to Python 2.7 and 3.5-3.10 for GNU/Linux, macOS and Windows
- [mac] Performance improvements for the ``fsevents`` module (`#680 <https://github.com/gorakhargosh/watchdog/pull/680>`__)
- [mac] Prevent compilation of ``watchdog_fsevents.c`` on non-macOS machines (`#687 <https://github.com/gorakhargosh/watchdog/pull/687>`__)
- [watchmedo] Handle shutdown events from ``SIGTERM`` and ``SIGINT`` more reliably (`#693 <https://github.com/gorakhargosh/watchdog/pull/693>`__)
- Thanks to our beloved contributors: @Sraw, @CCP-Aporia, @BoboTiG, @maybe-sybr


0.10.3
~~~~~~

2020-06-25 • `full history <https://github.com/gorakhargosh/watchdog/compare/v0.10.2...v0.10.3>`__

- Ensure ``ObservedWatch.path`` is a string (`#651 <https://github.com/gorakhargosh/watchdog/pull/651>`__)
- [inotify] Allow to monitor single file (`#655 <https://github.com/gorakhargosh/watchdog/pull/655>`__)
- [inotify] Prevent raising an exception when a file in a monitored folder has no permissions (`#669 <https://github.com/gorakhargosh/watchdog/pull/669>`__, `#670 <https://github.com/gorakhargosh/watchdog/pull/670>`__)
- Thanks to our beloved contributors: @brant-ruan, @rec, @andfoy, @BoboTiG


0.10.2
~~~~~~

2020-02-08 • `full history <https://github.com/gorakhargosh/watchdog/compare/v0.10.1...v0.10.2>`__

- Fixed the ``build_ext`` command on macOS Catalina (`#628 <https://github.com/gorakhargosh/watchdog/pull/628>`__)
- Fixed the installation of macOS requirements on non-macOS OSes (`#635 <https://github.com/gorakhargosh/watchdog/pull/635>`__)
- Refactored ``dispatch()`` method of ``FileSystemEventHandler``,
  ``PatternMatchingEventHandler`` and ``RegexMatchingEventHandler``
- [bsd] Improved tests support on non Windows/Linux platforms (`#633 <https://github.com/gorakhargosh/watchdog/pull/633>`__, `#639 <https://github.com/gorakhargosh/watchdog/pull/639>`__)
- [bsd] Added FreeBSD CI support (`#532 <https://github.com/gorakhargosh/watchdog/pull/532>`__)
- [bsd] Restored full support (`#638 <https://github.com/gorakhargosh/watchdog/pull/638>`__, `#641 <https://github.com/gorakhargosh/watchdog/pull/641>`__)
- Thanks to our beloved contributors: @BoboTiG, @evilham, @danilobellini


0.10.1
~~~~~~

2020-01-30 • `full history <https://github.com/gorakhargosh/watchdog/compare/v0.10.0...v0.10.1>`__

- Fixed Python 2.7 to 3.6 installation when the OS locale is set to POSIX (`#615 <https://github.com/gorakhargosh/watchdog/pull/615>`__)
- Fixed the ``build_ext`` command on macOS  (`#618 <https://github.com/gorakhargosh/watchdog/pull/618>`__, `#620 <https://github.com/gorakhargosh/watchdog/pull/620>`__)
- Moved requirements to ``setup.cfg``  (`#617 <https://github.com/gorakhargosh/watchdog/pull/617>`__)
- [mac] Removed old C code for Python 2.5 in the `fsevents` C implementation
- [snapshot] Added ``EmptyDirectorySnapshot`` (`#613 <https://github.com/gorakhargosh/watchdog/pull/613>`__)
- Thanks to our beloved contributors: @Ajordat, @tehkirill, @BoboTiG


0.10.0
~~~~~~

2020-01-26 • `full history <https://github.com/gorakhargosh/watchdog/compare/v0.9.0...v0.10.0>`__

**Breaking Changes**

- Dropped support for Python 2.6, 3.2 and 3.3
- Emitters that failed to start are now removed
- [snapshot] Removed the deprecated ``walker_callback`` argument,
  use ``stat`` instead
- [watchmedo] The utility is no more installed by default but via the extra
  ``watchdog[watchmedo]``

**Other Changes**

- Fixed several Python 3 warnings
- Identify synthesized events with ``is_synthetic`` attribute (`#369 <https://github.com/gorakhargosh/watchdog/pull/369>`__)
- Use ``os.scandir()`` to improve memory usage (`#503 <https://github.com/gorakhargosh/watchdog/pull/503>`__)
- [bsd] Fixed flavors of FreeBSD detection (`#529 <https://github.com/gorakhargosh/watchdog/pull/529>`__)
- [bsd] Skip unprocessable socket files (`#509 <https://github.com/gorakhargosh/watchdog/issue/509>`__)
- [inotify] Fixed events containing non-ASCII characters (`#516 <https://github.com/gorakhargosh/watchdog/issues/516>`__)
- [inotify] Fixed the way ``OSError`` are re-raised (`#377 <https://github.com/gorakhargosh/watchdog/issues/377>`__)
- [inotify] Fixed wrong source path after renaming a top level folder (`#515 <https://github.com/gorakhargosh/watchdog/pull/515>`__)
- [inotify] Removed  delay from non-move events (`#477 <https://github.com/gorakhargosh/watchdog/pull/477>`__)
- [mac] Fixed a bug when calling ``FSEventsEmitter.stop()`` twice (`#466 <https://github.com/gorakhargosh/watchdog/pull/466>`__)
- [mac] Support for unscheduling deleted watch (`#541 <https://github.com/gorakhargosh/watchdog/issue/541>`__)
- [mac] Fixed missing field initializers and unused parameters in
  ``watchdog_fsevents.c``
- [snapshot] Don't walk directories without read permissions (`#408 <https://github.com/gorakhargosh/watchdog/pull/408>`__)
- [snapshot] Fixed a race condition crash when a directory is swapped for a file (`#513 <https://github.com/gorakhargosh/watchdog/pull/513>`__)
- [snasphot] Fixed an ``AttributeError`` about forgotten ``path_for_inode`` attr (`#436 <https://github.com/gorakhargosh/watchdog/issues/436>`__)
- [snasphot] Added the ``ignore_device=False`` parameter to the ctor (`597 <https://github.com/gorakhargosh/watchdog/pull/597>`__)
- [watchmedo] Fixed the path separator used (`#478 <https://github.com/gorakhargosh/watchdog/pull/478>`__)
- [watchmedo] Fixed the use of ``yaml.load()`` for ``yaml.safe_load()`` (`#453 <https://github.com/gorakhargosh/watchdog/issues/453>`__)
- [watchmedo] Handle all available signals (`#549 <https://github.com/gorakhargosh/watchdog/issue/549>`__)
- [watchmedo] Added the ``--debug-force-polling`` argument (`#404 <https://github.com/gorakhargosh/watchdog/pull/404>`__)
- [windows] Fixed issues when the observed directory is deleted (`#570 <https://github.com/gorakhargosh/watchdog/issues/570>`__ and `#601 <https://github.com/gorakhargosh/watchdog/pull/601>`__)
- [windows] ``WindowsApiEmitter`` made easier to subclass (`#344 <https://github.com/gorakhargosh/watchdog/pull/344>`__)
- [windows] Use separate ctypes DLL instances
- [windows] Generate sub created events only if ``recursive=True`` (`#454 <https://github.com/gorakhargosh/watchdog/pull/454>`__)
- Thanks to our beloved contributors: @BoboTiG, @LKleinNux, @rrzaripov,
  @wildmichael, @TauPan, @segevfiner, @petrblahos, @QuantumEnergyE,
  @jeffwidman, @kapsh, @nickoala, @petrblahos, @julianolf, @tonybaloney,
  @mbakiev, @pR0Ps, javaguirre, @skurfer, @exarkun, @joshuaskelly,
  @danilobellini, @Ajordat


0.9.0
~~~~~

2018-08-28 • `full history <https://github.com/gorakhargosh/watchdog/compare/v0.8.3...v0.9.0>`__

- Deleting the observed directory now emits a ``DirDeletedEvent`` event
- [bsd] Improved the platform detection (`#378 <https://github.com/gorakhargosh/watchdog/pull/378>`__)
- [inotify] Fixed a crash when the root directory being watched by was deleted (`#374 <https://github.com/gorakhargosh/watchdog/pull/374>`__)
- [inotify] Handle systems providing uClibc
- [linux] Fixed a possible ``DirDeletedEvent`` duplication when
  deleting a directory
- [mac] Fixed unicode path handling ``fsevents2.py`` (`#298 <https://github.com/gorakhargosh/watchdog/pull/298>`__)
- [watchmedo] Added the ``--debug-force-polling`` argument (`#336 <https://github.com/gorakhargosh/watchdog/pull/336>`__)
- [windows] Fixed the ``FILE_LIST_DIRECTORY`` constant (`#376 <https://github.com/gorakhargosh/watchdog/pull/376>`__)
- Thanks to our beloved contributors: @vulpeszerda, @hpk42, @tamland, @senden9,
  @gorakhargosh, @nolsto, @mafrosis, @DonyorM, @anthrotype, @danilobellini,
  @pierregr, @ShinNoNoir, @adrpar, @gforcada, @pR0Ps, @yegorich, @dhke


0.8.3
~~~~~

2015-02-11 • `full history <https://github.com/gorakhargosh/watchdog/compare/v0.8.2...v0.8.3>`__

- Fixed the use of the root logger (`#274 <https://github.com/gorakhargosh/watchdog/issues/274>`__)
- [inotify] Refactored libc loading and improved error handling in
  ``inotify_c.py``
- [inotify] Fixed a possible unbound local error in ``inotify_c.py``
- Thanks to our beloved contributors: @mmorearty, @tamland, @tony,
  @gorakhargosh


0.8.2
~~~~~

2014-10-29 • `full history <https://github.com/gorakhargosh/watchdog/compare/v0.8.1...v0.8.2>`__

- Event emitters are no longer started on schedule if ``Observer`` is not
  already running
- [mac] Fixed unused arguments to pass clang compilation (`#265 <https://github.com/gorakhargosh/watchdog/pull/265>`__)
- [snapshot] Fixed a possible race condition crash on directory deletion (`#281 <https://github.com/gorakhargosh/watchdog/pull/281>`__)
- [windows] Fixed an error when watching the same folder again (`#270 <https://github.com/gorakhargosh/watchdog/pull/270>`__)
- Thanks to our beloved contributors: @tamland, @apetrone, @Falldog,
  @theospears


0.8.1
~~~~~

2014-07-28 • `full history <https://github.com/gorakhargosh/watchdog/compare/v0.8.0...v0.8.1>`__

- Fixed ``anon_inode`` descriptors leakage  (`#249 <https://github.com/gorakhargosh/watchdog/pull/249>`__)
- [inotify] Fixed thread stop dead lock (`#250 <https://github.com/gorakhargosh/watchdog/issues/250>`__)
- Thanks to our beloved contributors: @Witos, @adiroiban, @tamland


0.8.0
~~~~~

2014-07-02 • `full history <https://github.com/gorakhargosh/watchdog/compare/v0.7.1...v0.8.0>`__

- Fixed ``argh`` deprecation warnings (`#242 <https://github.com/gorakhargosh/watchdog/pull/242>`__)
- [snapshot] Methods returning internal stats info were replaced by
  ``mtime()``, ``inode()`` and ``path()`` methods
- [snapshot] Deprecated the ``walker_callback`` argument
- [watchmedo] Fixed ``auto-restart`` to terminate all children processes (`#225 <https://github.com/gorakhargosh/watchdog/pull/225>`__)
- [watchmedo] Added the ``--no-parallel`` argument (`#227 <https://github.com/gorakhargosh/watchdog/issues/227>`__)
- [windows] Fixed the value of ``INVALID_HANDLE_VALUE`` (`#123 <https://github.com/gorakhargosh/watchdog/issues/123>`__)
- [windows] Fixed octal usages to work with Python 3 as well (`#223 <https://github.com/gorakhargosh/watchdog/issues/223>`__)
- Thanks to our beloved contributors: @tamland, @Ormod, @berdario, @cro,
  @BernieSumption, @pypingou, @gotcha, @tommorris, @frewsxcv


================================================
FILE: docs/Makefile
================================================
# Makefile for Sphinx documentation
#

# You can set these variables from the command line.
SPHINXOPTS    =
SPHINXBUILD   = sphinx-build
PAPER         =
BUILDDIR      = build

# Internal variables.
PAPEROPT_a4     = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source

.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest

help:
	@echo "Please use \`make <target>' where <target> is one of"
	@echo "  html       to make standalone HTML files"
	@echo "  dirhtml    to make HTML files named index.html in directories"
	@echo "  singlehtml to make a single large HTML file"
	@echo "  pickle     to make pickle files"
	@echo "  json       to make JSON files"
	@echo "  htmlhelp   to make HTML files and a HTML help project"
	@echo "  qthelp     to make HTML files and a qthelp project"
	@echo "  devhelp    to make HTML files and a Devhelp project"
	@echo "  epub       to make an epub"
	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
	@echo "  text       to make text files"
	@echo "  man        to make manual pages"
	@echo "  changes    to make an overview of all changed/added/deprecated items"
	@echo "  linkcheck  to check all external links for integrity"
	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"

clean:
	-rm -rf $(BUILDDIR)/*

html:
	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
	@echo
	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."

dirhtml:
	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
	@echo
	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."

singlehtml:
	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
	@echo
	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."

pickle:
	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
	@echo
	@echo "Build finished; now you can process the pickle files."

json:
	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
	@echo
	@echo "Build finished; now you can process the JSON files."

htmlhelp:
	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
	@echo
	@echo "Build finished; now you can run HTML Help Workshop with the" \
	      ".hhp project file in $(BUILDDIR)/htmlhelp."

qthelp:
	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
	@echo
	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/watchdog.qhcp"
	@echo "To view the help file:"
	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/watchdog.qhc"

devhelp:
	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
	@echo
	@echo "Build finished."
	@echo "To view the help file:"
	@echo "# mkdir -p $$HOME/.local/share/devhelp/watchdog"
	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/watchdog"
	@echo "# devhelp"

epub:
	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
	@echo
	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."

latex:
	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
	@echo
	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
	@echo "Run \`make' in that directory to run these through (pdf)latex" \
	      "(use \`make latexpdf' here to do that automatically)."

latexpdf:
	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
	@echo "Running LaTeX files through pdflatex..."
	make -C $(BUILDDIR)/latex all-pdf
	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."

text:
	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
	@echo
	@echo "Build finished. The text files are in $(BUILDDIR)/text."

man:
	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
	@echo
	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."

changes:
	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
	@echo
	@echo "The overview file is in $(BUILDDIR)/changes."

linkcheck:
	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
	@echo
	@echo "Link check complete; look for any errors in the above output " \
	      "or in $(BUILDDIR)/linkcheck/output.txt."

doctest:
	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
	@echo "Testing of doctests in the sources finished, look at the " \
	      "results in $(BUILDDIR)/doctest/output.txt."


================================================
FILE: docs/eclipse_cdt_style.xml
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="1">
<profile kind="CodeFormatterProfile" name="Yesudeep Mangalapilly" version="1">
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.lineSplit" value="100"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_base_types" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
<setting id="org.eclipse.cdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_exception_specification" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_base_types" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.indent_body_declarations_compare_to_access_specifier" value="true"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_exception_specification" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_template_arguments" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_declarator_list" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_bracket" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.tabulation.size" value="4"/>
<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_else_in_if_statement" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.alignment_for_enumerator_list" value="48"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.alignment_for_declarator_list" value="16"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.indent_empty_lines" value="false"/>
<setting id="org.eclipse.cdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
<setting id="org.eclipse.cdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.brace_position_for_method_declaration" value="next_line"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_closing_angle_bracket_in_template_arguments" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_base_clause" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_declarator_list" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.alignment_for_arguments_in_method_invocation" value="82"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_brackets" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_bracket" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.alignment_for_parameters_in_method_declaration" value="83"/>
<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.brace_position_for_block" value="next_line_shifted"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.brace_position_for_type_declaration" value="next_line"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_angle_bracket_in_template_arguments" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_expression_list" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_angle_bracket_in_template_parameters" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.continuation_indentation" value="2"/>
<setting id="org.eclipse.cdt.core.formatter.alignment_for_expression_list" value="0"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_template_parameters" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.alignment_for_conditional_expression" value="80"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.indent_access_specifier_compare_to_type_header" value="false"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.indent_body_declarations_compare_to_namespace_header" value="true"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.alignment_for_compact_if" value="0"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_template_parameters" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_expression_list" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_exception_specification" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_identifier_in_function_declaration" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.alignment_for_base_clause_in_type_declaration" value="80"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_exception_specification" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.indent_declaration_compare_to_template_header" value="true"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.indent_statements_compare_to_body" value="true"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.indent_statements_compare_to_block" value="true"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_template_arguments" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="82"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_angle_bracket_in_template_parameters" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.tabulation.char" value="space"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_angle_bracket_in_template_parameters" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.brace_position_for_block_in_case" value="next_line_shifted"/>
<setting id="org.eclipse.cdt.core.formatter.compact_else_if" value="true"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_colon_in_base_clause" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_new_line_after_template_declaration" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
<setting id="org.eclipse.cdt.core.formatter.brace_position_for_switch" value="next_line_shifted"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
<setting id="org.eclipse.cdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.indentation.size" value="8"/>
<setting id="org.eclipse.cdt.core.formatter.brace_position_for_namespace_declaration" value="next_line"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_angle_bracket_in_template_arguments" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.brace_position_for_array_initializer" value="next_line_shifted"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_namespace_declaration" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_bracket" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_while_in_do_statement" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_closing_angle_bracket_in_template_parameters" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_angle_bracket_in_template_arguments" value="do not insert"/>
</profile>
</profiles>


================================================
FILE: docs/make.bat
================================================
@ECHO OFF

REM Command file for Sphinx documentation

if "%SPHINXBUILD%" == "" (
	set SPHINXBUILD=sphinx-build
)
set BUILDDIR=build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source
if NOT "%PAPER%" == "" (
	set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
)

if "%1" == "" goto help

if "%1" == "help" (
	:help
	echo.Please use `make ^<target^>` where ^<target^> is one of
	echo.  html       to make standalone HTML files
	echo.  dirhtml    to make HTML files named index.html in directories
	echo.  singlehtml to make a single large HTML file
	echo.  pickle     to make pickle files
	echo.  json       to make JSON files
	echo.  htmlhelp   to make HTML files and a HTML help project
	echo.  qthelp     to make HTML files and a qthelp project
	echo.  devhelp    to make HTML files and a Devhelp project
	echo.  epub       to make an epub
	echo.  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter
	echo.  text       to make text files
	echo.  man        to make manual pages
	echo.  changes    to make an overview over all changed/added/deprecated items
	echo.  linkcheck  to check all external links for integrity
	echo.  doctest    to run all doctests embedded in the documentation if enabled
	goto end
)

if "%1" == "clean" (
	for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
	del /q /s %BUILDDIR%\*
	goto end
)

if "%1" == "html" (
	%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished. The HTML pages are in %BUILDDIR%/html.
	goto end
)

if "%1" == "dirhtml" (
	%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
	goto end
)

if "%1" == "singlehtml" (
	%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
	goto end
)

if "%1" == "pickle" (
	%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished; now you can process the pickle files.
	goto end
)

if "%1" == "json" (
	%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished; now you can process the JSON files.
	goto end
)

if "%1" == "htmlhelp" (
	%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
	goto end
)

if "%1" == "qthelp" (
	%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
	echo.^> qcollectiongenerator %BUILDDIR%\qthelp\watchdog.qhcp
	echo.To view the help file:
	echo.^> assistant -collectionFile %BUILDDIR%\qthelp\watchdog.ghc
	goto end
)

if "%1" == "devhelp" (
	%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished.
	goto end
)

if "%1" == "epub" (
	%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished. The epub file is in %BUILDDIR%/epub.
	goto end
)

if "%1" == "latex" (
	%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
	goto end
)

if "%1" == "text" (
	%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished. The text files are in %BUILDDIR%/text.
	goto end
)

if "%1" == "man" (
	%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished. The manual pages are in %BUILDDIR%/man.
	goto end
)

if "%1" == "changes" (
	%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
	if errorlevel 1 exit /b 1
	echo.
	echo.The overview file is in %BUILDDIR%/changes.
	goto end
)

if "%1" == "linkcheck" (
	%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
	if errorlevel 1 exit /b 1
	echo.
	echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
	goto end
)

if "%1" == "doctest" (
	%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
	if errorlevel 1 exit /b 1
	echo.
	echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
	goto end
)

:end


================================================
FILE: docs/source/api.rst
================================================
.. include:: global.rst.inc

.. api_reference:

=============
API Reference
=============

`watchdog.events`
=================

.. automodule:: watchdog.events


`watchdog.observers.api`
========================

.. automodule:: watchdog.observers.api
    :synopsis: Classes useful to observer implementers.

    Immutables
    ----------
    .. autoclass:: ObservedWatch
       :members:
       :show-inheritance:


    Collections
    -----------
    .. autoclass:: EventQueue
       :members:
       :show-inheritance:

    Classes
    -------
    .. autoclass:: EventEmitter
       :members:
       :show-inheritance:

    .. autoclass:: EventDispatcher
       :members:
       :show-inheritance:

    .. autoclass:: BaseObserver
       :members:
       :show-inheritance:



`watchdog.observers`
====================

.. automodule:: watchdog.observers


`watchdog.observers.polling`
============================

.. automodule:: watchdog.observers.polling


`watchdog.utils`
================

.. automodule:: watchdog.utils


`watchdog.utils.dirsnapshot`
============================

.. automodule:: watchdog.utils.dirsnapshot

`watchdog.tricks`
=================

.. automodule:: watchdog.tricks


.. toctree::
   :maxdepth: 2


================================================
FILE: docs/source/conf.py
================================================
# watchdog documentation build configuration file, created by
# sphinx-quickstart on Tue Nov 30 00:43:58 2010.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys
import os.path

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
TOP_DIR_PATH = os.path.abspath("../../")
SRC_DIR_PATH = os.path.join(TOP_DIR_PATH, "src")
sys.path.insert(0, SRC_DIR_PATH)

import watchdog.version  # noqa: E402

PROJECT_NAME = "watchdog"
AUTHOR_NAME = "Mickaël Schoentgen & contributors"
COPYRIGHT = f"2010-2025, {AUTHOR_NAME}"


# -- General configuration -----------------------------------------------------

# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
    "sphinx.ext.autodoc",
    "sphinx.ext.todo",
    "sphinx.ext.coverage",
    "sphinx.ext.ifconfig",
    "sphinx.ext.viewcode",
]

# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]

# The suffix of source filenames.
source_suffix = ".rst"

# The master toctree document.
master_doc = "index"

# General information about the project.
project = PROJECT_NAME
copyright = COPYRIGHT

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = watchdog.version.VERSION_STRING
# The full version, including alpha/beta/rc tags.
release = version

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = []

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = "sphinx"


# -- Options for HTML output ---------------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
html_theme = "pyramid"

# Output file base name for HTML help builder.
htmlhelp_basename = "%sdoc" % PROJECT_NAME


# -- Options for LaTeX output --------------------------------------------------

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
    (
        "index",
        "%s.tex" % PROJECT_NAME,
        "%s Documentation" % PROJECT_NAME,
        AUTHOR_NAME,
        "manual",
    ),
]

# -- Options for manual page output --------------------------------------------

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
    ("index", PROJECT_NAME, "%s Documentation" % PROJECT_NAME, [AUTHOR_NAME], 1)
]


# -- Options for Epub output ---------------------------------------------------

# Bibliographic Dublin Core info.
epub_title = PROJECT_NAME
epub_author = AUTHOR_NAME
epub_publisher = AUTHOR_NAME
epub_copyright = COPYRIGHT


================================================
FILE: docs/source/examples/__init__.py
================================================


================================================
FILE: docs/source/examples/logger.py
================================================
import sys
import time

from watchdog.observers import Observer
from watchdog.tricks import LoggerTrick

event_handler = LoggerTrick()
observer = Observer()
observer.schedule(event_handler, sys.argv[1], recursive=True)
observer.start()
try:
    while True:
        time.sleep(1)
finally:
    observer.stop()
    observer.join()


================================================
FILE: docs/source/examples/patterns.py
================================================
import logging
import sys
import time

from watchdog.events import FileSystemEvent, PatternMatchingEventHandler
from watchdog.observers import Observer

logging.basicConfig(level=logging.DEBUG)


class MyEventHandler(PatternMatchingEventHandler):
    def on_any_event(self, event: FileSystemEvent) -> None:
        logging.debug(event)


event_handler = MyEventHandler(
    patterns=["**/*.py", "**/*.pyc"], ignore_patterns=["version.py"], ignore_directories=True
)
observer = Observer()
observer.schedule(event_handler, sys.argv[1], recursive=True)
observer.start()
try:
    while True:
        time.sleep(1)
finally:
    observer.stop()
    observer.join()


================================================
FILE: docs/source/examples/simple.py
================================================
from __future__ import annotations

import logging
import sys
import time

from watchdog import events
from watchdog.observers import Observer

logging.basicConfig(level=logging.DEBUG)


class MyEventHandler(events.FileSystemEventHandler):
    def catch_all_handler(self, event: events.FileSystemEvent) -> None:
        logging.debug(event)

    def on_moved(self, event: events.DirMovedEvent | events.FileMovedEvent) -> None:
        self.catch_all_handler(event)

    def on_created(self, event: events.DirCreatedEvent | events.FileCreatedEvent) -> None:
        self.catch_all_handler(event)

    def on_deleted(self, event: events.DirDeletedEvent | events.FileDeletedEvent) -> None:
        self.catch_all_handler(event)

    def on_modified(self, event: events.DirModifiedEvent | events.FileModifiedEvent) -> None:
        self.catch_all_handler(event)

    def on_closed(self, event: events.FileClosedEvent) -> None:
        self.catch_all_handler(event)

    def on_closed_no_write(self, event: events.FileClosedNoWriteEvent) -> None:
        self.catch_all_handler(event)

    def on_opened(self, event: events.FileOpenedEvent) -> None:
        self.catch_all_handler(event)


path = sys.argv[1]

event_handler = MyEventHandler()
observer = Observer()
observer.schedule(event_handler, path, recursive=True)
observer.start()
try:
    while True:
        time.sleep(1)
finally:
    observer.stop()
    observer.join()


================================================
FILE: docs/source/examples/tricks.json
================================================
[
    {
        "watchdog.tricks.LoggerTrick": {
            "patterns": [
                "**/*.py",
                "**/*.js"
            ]
        }
    },
    {
        "watchmedo_webtricks.GoogleClosureTrick": {
            "scripts": {
                "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"]
            },
            "suffix": ".min.js",
            "source_directory": "app/static/js/",
            "hash_names": true,
            "patterns": ["**/*.js"],
            "destination_directory": "app/public/js/",
            "compilation_level": "advanced",
            "mappings_module": "app/javascript_mappings.json"
        }
    }
]


================================================
FILE: docs/source/examples/tricks.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


================================================
FILE: docs/source/global.rst.inc
================================================
.. Global includes, substitutions, and common links.

.. |author_name| replace:: Mickaël Schoentgen
.. |author_email| replace:: contact@tiger-222.fr
.. |copyright| replace:: Copyright 2010-2025 Mickaël Schoentgen & contributors.
.. |project_name| replace:: ``watchdog``
.. |project_version| replace:: 7.0.0

.. _issue tracker: https://github.com/gorakhargosh/watchdog/issues
.. _code repository: https://github.com/gorakhargosh/watchdog

.. _kqueue: https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2
.. _FSEvents: https://developer.apple.com/library/mac/#documentation/Darwin/Conceptual/FSEvents_ProgGuide/Introduction/Introduction.html
.. _inotify: https://linux.die.net/man/7/inotify
.. _macOS File System Monitoring Performance Guidelines: https://developer.apple.com/library/ios/#documentation/Performance/Conceptual/FileSystem/Articles/TrackingChanges.html
.. _ReadDirectoryChangesW: https://docs.microsoft.com/windows/win32/api/winbase/nf-winbase-readdirectorychangesw

.. _file.monitor: https://github.com/pke/file.monitor
.. _fsmonitor: https://github.com/shaurz/fsmonitor
.. _git: https://git-scm.org/
.. _github: https://github.com/
.. _guard: https://github.com/guard/guard
.. _inotify-tools: https://github.com/rvoicilas/inotify-tools
.. _jnotify: http://jnotify.sourceforge.net/
.. _pip: https://pypi.python.org/pypi/pip
.. _pnotify: http://mark.heily.com/pnotify
.. _pyfilesystem: https://github.com/PyFilesystem/pyfilesystem
.. _pyinotify: https://github.com/seb-m/pyinotify
.. _Python: https://python.org
.. _PyYAML: https://www.pyyaml.org/
.. _treewatcher: https://github.com/jbd/treewatcher
.. _unison fsmonitor: https://webdav.seas.upenn.edu/viewvc/unison/trunk/src/fsmonitor.py?view=markup&pathrev=471
.. _XCode: https://developer.apple.com/technologies/tools/xcode.html


================================================
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
--------------
|project_name| uses git_ to track code history and hosts its `code repository`_
at github_. The `issue tracker`_ is where you can file bug reports and request
features or enhancements to |project_name|.

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. Linux

.. code:: bash

    $ . venv/bin/activate
    (venv)$ python -m pip install -e '.'

4. Windows

.. code:: batch

    > venv\Scripts\activate
    (venv)> python -m pip install -e '.'

That's it with the setup. Now you're ready to hack on |project_name|.

Happy hacking!


================================================
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
   api
   hacking

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

    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()

To stop the program, press Control-C.

Alternatively, you can use the observer as a context manager for cleaner code::

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

    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: pyproject.toml
================================================
[build-system]
requires = [
    # Pin to an older setuptools version for PyPy only, due to pypa/distutils#283
    "setuptools; platform_python_implementation != 'PyPy'",
    "setuptools<72.2; platform_python_implementation == 'PyPy'",
]
build-backend = "setuptools.build_meta"

[tool.cibuildwheel]
enable = ["cpython-freethreading"]
skip = "*t*_i686"

[tool.coverage.report]
exclude_also = [
    "if TYPE_CHECKING:",
    "if __name__ == __main__:",
]

[tool.mypy]
# Ensure we know what we do
warn_redundant_casts = true
warn_unused_ignores = true
warn_unused_configs = true

# Imports management
ignore_missing_imports = true
follow_imports = "skip"

# Ensure full coverage
disallow_untyped_defs = true
disallow_incomplete_defs = true
disallow_untyped_calls = true

# Restrict dynamic typing (a little)
# e.g. `x: List[Any]` or x: List`
# disallow_any_generics = true

strict_equality = true

[tool.pytest.ini_options]
pythonpath = "src"
addopts = """
    --showlocals
    -vvv
    --cov=watchdog
    --cov-report=term-missing:skip-covered
"""

[tool.ruff]
line-length = 120
indent-width = 4
target-version = "py39"

[tool.ruff.lint]
extend-select = ["ALL"]
ignore = [
    "ARG",
    "ANN",  # TODO
    "B023",  # TODO
    "BLE001",
    "C90",
    "COM812",
    "D",
    "EM101",
    "EM102",
    "FIX",
    "ISC001",
    "PERF203",
    "PL",
    "PTH",  # TODO?
    "S",
    "TD",
]
fixable = ["ALL"]

[tool.ruff.format]
quote-style = "double"
indent-style = "space"
skip-magic-trailing-comma = false
line-ending = "auto"
docstring-code-format = true


================================================
FILE: requirements-tests.txt
================================================
eventlet==0.37.0; python_version < "3.13"
flaky==3.8.1
pytest==8.3.3
pytest-cov==6.0.0
pytest-timeout==2.3.1
ruff==0.7.1
sphinx==7.4.7; python_version <= "3.9"
sphinx==8.1.3; python_version > "3.9"
mypy==1.13.0
types-PyYAML==6.0.12.20240917


================================================
FILE: setup.cfg
================================================
[metadata]
project_urls =
    Documentation=https://python-watchdog.readthedocs.io/en/stable/
    Source=https://github.com/gorakhargosh/watchdog/
    Issues=https://github.com/gorakhargosh/watchdog/issues
    Changelog=https://github.com/gorakhargosh/watchdog/blob/master/changelog.rst

[build_sphinx]
source-dir = docs/source
build-dir  = docs/build
all_files  = 1

[upload_sphinx]
# Requires sphinx-pypi-upload to work.
upload-dir = docs/build/html


================================================
FILE: setup.py
================================================
import importlib.util
import sys
import os
import os.path
from platform import machine
from setuptools import setup, find_packages
from setuptools.extension import Extension
from setuptools.command.build_ext import build_ext

SRC_DIR = "src"
WATCHDOG_PKG_DIR = os.path.join(SRC_DIR, "watchdog")

# Load the module version
spec = importlib.util.spec_from_file_location(
    "version", os.path.join(WATCHDOG_PKG_DIR, "version.py")
)
version = importlib.util.module_from_spec(spec)
spec.loader.exec_module(version)

# Ignored Apple devices on which compiling watchdog_fsevents.c would fail.
# The FORCE_MACOS_MACHINE envar, when set to 1, will force the compilation.
_apple_devices = ("appletv", "iphone", "ipod", "ipad", "watch")
is_macos = sys.platform == "darwin" and not machine().lower().startswith(_apple_devices)

ext_modules = []
if is_macos or os.getenv("FORCE_MACOS_MACHINE", "0") == "1":
    ext_modules = [
        Extension(
            name="_watchdog_fsevents",
            sources=[
                "src/watchdog_fsevents.c",
            ],
            libraries=["m"],
            define_macros=[
                ("WATCHDOG_VERSION_STRING", '"' + version.VERSION_STRING + '"'),
                ("WATCHDOG_VERSION_MAJOR", version.VERSION_MAJOR),
                ("WATCHDOG_VERSION_MINOR", version.VERSION_MINOR),
                ("WATCHDOG_VERSION_BUILD", version.VERSION_BUILD),
            ],
            extra_link_args=[
                "-framework",
                "CoreFoundation",
                "-framework",
                "CoreServices",
            ],
            extra_compile_args=[
                "-std=c99",
                "-pedantic",
                "-Wall",
                "-Wextra",
                "-fPIC",
                # Issue #620
                "-Wno-nullability-completeness",
                # Issue #628
                "-Wno-nullability-extension",
                "-Wno-newline-eof",
                # required w/Xcode 5.1+ and above because of '-mno-fused-madd'
                "-Wno-error=unused-command-line-argument",
            ],
        ),
    ]

extras_require = {
    "watchmedo": ["PyYAML>=3.10"],
}

with open("README.rst", encoding="utf-8") as f:
    readme = f.read()

with open("changelog.rst", encoding="utf-8") as f:
    changelog = f.read()

setup(
    name="watchdog",
    version=version.VERSION_STRING,
    description="Filesystem events monitoring",
    long_description=readme + "\n\n" + changelog,
    long_description_content_type="text/x-rst",
    author="Mickaël Schoentgen",
    author_email="contact@tiger-222.fr",
    license="Apache-2.0",
    url="https://github.com/gorakhargosh/watchdog",
    keywords=" ".join(
        [
            "python",
            "filesystem",
            "monitoring",
            "monitor",
            "FSEvents",
            "kqueue",
            "inotify",
            "ReadDirectoryChangesW",
            "polling",
            "DirectorySnapshot",
        ]
    ),
    classifiers=[
        "Development Status :: 5 - Production/Stable",
        "Environment :: Console",
        "Intended Audience :: Developers",
        "Intended Audience :: System Administrators",
        "License :: OSI Approved :: Apache Software License",
        "Natural Language :: English",
        "Operating System :: POSIX :: Linux",
        "Operating System :: MacOS :: MacOS X",
        "Operating System :: POSIX :: BSD",
        "Operating System :: Microsoft :: Windows :: Windows Vista",
        "Operating System :: Microsoft :: Windows :: Windows 7",
        "Operating System :: Microsoft :: Windows :: Windows 8",
        "Operating System :: Microsoft :: Windows :: Windows 8.1",
        "Operating System :: Microsoft :: Windows :: Windows 10",
        "Operating System :: Microsoft :: Windows :: Windows 11",
        "Operating System :: OS Independent",
        "Programming Language :: Python",
        "Programming Language :: Python :: 3",
        "Programming Language :: Python :: 3 :: Only",
        "Programming Language :: Python :: 3.9",
        "Programming Language :: Python :: 3.10",
        "Programming Language :: Python :: 3.11",
        "Programming Language :: Python :: 3.12",
        "Programming Language :: Python :: 3.13",
        "Programming Language :: Python :: Implementation :: CPython",
        "Programming Language :: Python :: Implementation :: PyPy",
        "Programming Language :: C",
        "Topic :: Software Development :: Libraries",
        "Topic :: System :: Monitoring",
        "Topic :: System :: Filesystems",
        "Topic :: Utilities",
    ],
    package_dir={"": SRC_DIR},
    packages=find_packages(SRC_DIR),
    include_package_data=True,
    extras_require=extras_require,
    cmdclass={
        "build_ext": build_ext,
    },
    ext_modules=ext_modules,
    entry_points={
        "console_scripts": [
            "watchmedo = watchdog.watchmedo:main [watchmedo]",
        ]
    },
    python_requires=">=3.9",
    zip_safe=False,
)


================================================
FILE: src/pythoncapi_compat.h
================================================
// Header file providing new C API functions to old Python versions.
//
// File distributed under the Zero Clause BSD (0BSD) license.
// Copyright Contributors to the pythoncapi_compat project.
//
// Homepage:
// https://github.com/python/pythoncapi_compat
//
// Latest version:
// https://raw.githubusercontent.com/python/pythoncapi-compat/main/pythoncapi_compat.h
//
// SPDX-License-Identifier: 0BSD

#ifndef PYTHONCAPI_COMPAT
#define PYTHONCAPI_COMPAT

#ifdef __cplusplus
extern "C" {
#endif

#include <Python.h>
#include <stddef.h>               // offsetof()

// Python 3.11.0b4 added PyFrame_Back() to Python.h
#if PY_VERSION_HEX < 0x030b00B4 && !defined(PYPY_VERSION)
#  include "frameobject.h"        // PyFrameObject, PyFrame_GetBack()
#endif
#if PY_VERSION_HEX < 0x030C00A3
#  include <structmember.h>       // T_SHORT, READONLY
#endif


#ifndef _Py_CAST
#  define _Py_CAST(type, expr) ((type)(expr))
#endif

// Static inline functions should use _Py_NULL rather than using directly NULL
// to prevent C++ compiler warnings. On C23 and newer and on C++11 and newer,
// _Py_NULL is defined as nullptr.
#ifndef _Py_NULL
#  if (defined (__STDC_VERSION__) && __STDC_VERSION__ > 201710L) \
          || (defined(__cplusplus) && __cplusplus >= 201103)
#    define _Py_NULL nullptr
#  else
#    define _Py_NULL NULL
#  endif
#endif

// Cast argument to PyObject* type.
#ifndef _PyObject_CAST
#  define _PyObject_CAST(op) _Py_CAST(PyObject*, op)
#endif

#ifndef Py_BUILD_ASSERT
#  define Py_BUILD_ASSERT(cond) \
        do { \
            (void)sizeof(char [1 - 2 * !(cond)]); \
        } while(0)
#endif


// bpo-42262 added Py_NewRef() to Python 3.10.0a3
#if PY_VERSION_HEX < 0x030A00A3 && !defined(Py_NewRef)
static inline PyObject* _Py_NewRef(PyObject *obj)
{
    Py_INCREF(obj);
    return obj;
}
#define Py_NewRef(obj) _Py_NewRef(_PyObject_CAST(obj))
#endif


// bpo-42262 added Py_XNewRef() to Python 3.10.0a3
#if PY_VERSION_HEX < 0x030A00A3 && !defined(Py_XNewRef)
static inline PyObject* _Py_XNewRef(PyObject *obj)
{
    Py_XINCREF(obj);
    return obj;
}
#define Py_XNewRef(obj) _Py_XNewRef(_PyObject_CAST(obj))
#endif


// bpo-39573 added Py_SET_REFCNT() to Python 3.9.0a4
#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_REFCNT)
static inline void _Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt)
{
    ob->ob_refcnt = refcnt;
}
#define Py_SET_REFCNT(ob, refcnt) _Py_SET_REFCNT(_PyObject_CAST(ob), refcnt)
#endif


// Py_SETREF() and Py_XSETREF() were added to Python 3.5.2.
// It is excluded from the limited C API.
#if (PY_VERSION_HEX < 0x03050200 && !defined(Py_SETREF)) && !defined(Py_LIMITED_API)
#define Py_SETREF(dst, src)                                     \
    do {                                                        \
        PyObject **_tmp_dst_ptr = _Py_CAST(PyObject**, &(dst)); \
        PyObject *_tmp_dst = (*_tmp_dst_ptr);                   \
        *_tmp_dst_ptr = _PyObject_CAST(src);                    \
        Py_DECREF(_tmp_dst);                                    \
    } while (0)

#define Py_XSETREF(dst, src)                                    \
    do {                                                        \
        PyObject **_tmp_dst_ptr = _Py_CAST(PyObject**, &(dst)); \
        PyObject *_tmp_dst = (*_tmp_dst_ptr);                   \
        *_tmp_dst_ptr = _PyObject_CAST(src);                    \
        Py_XDECREF(_tmp_dst);                                   \
    } while (0)
#endif


// bpo-43753 added Py_Is(), Py_IsNone(), Py_IsTrue() and Py_IsFalse()
// to Python 3.10.0b1.
#if PY_VERSION_HEX < 0x030A00B1 && !defined(Py_Is)
#  define Py_Is(x, y) ((x) == (y))
#endif
#if PY_VERSION_HEX < 0x030A00B1 && !defined(Py_IsNone)
#  define Py_IsNone(x) Py_Is(x, Py_None)
#endif
#if (PY_VERSION_HEX < 0x030A00B1 || defined(PYPY_VERSION)) && !defined(Py_IsTrue)
#  define Py_IsTrue(x) Py_Is(x, Py_True)
#endif
#if (PY_VERSION_HEX < 0x030A00B1 || defined(PYPY_VERSION)) && !defined(Py_IsFalse)
#  define Py_IsFalse(x) Py_Is(x, Py_False)
#endif


// bpo-39573 added Py_SET_TYPE() to Python 3.9.0a4
#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_TYPE)
static inline void _Py_SET_TYPE(PyObject *ob, PyTypeObject *type)
{
    ob->ob_type = type;
}
#define Py_SET_TYPE(ob, type) _Py_SET_TYPE(_PyObject_CAST(ob), type)
#endif


// bpo-39573 added Py_SET_SIZE() to Python 3.9.0a4
#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_SIZE)
static inline void _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size)
{
    ob->ob_size = size;
}
#define Py_SET_SIZE(ob, size) _Py_SET_SIZE((PyVarObject*)(ob), size)
#endif


// bpo-40421 added PyFrame_GetCode() to Python 3.9.0b1
#if PY_VERSION_HEX < 0x030900B1 || defined(PYPY_VERSION)
static inline PyCodeObject* PyFrame_GetCode(PyFrameObject *frame)
{
    assert(frame != _Py_NULL);
    assert(frame->f_code != _Py_NULL);
    return _Py_CAST(PyCodeObject*, Py_NewRef(frame->f_code));
}
#endif

static inline PyCodeObject* _PyFrame_GetCodeBorrow(PyFrameObject *frame)
{
    PyCodeObject *code = PyFrame_GetCode(frame);
    Py_DECREF(code);
    return code;
}


// bpo-40421 added PyFrame_GetBack() to Python 3.9.0b1
#if PY_VERSION_HEX < 0x030900B1 && !defined(PYPY_VERSION)
static inline PyFrameObject* PyFrame_GetBack(PyFrameObject *frame)
{
    assert(frame != _Py_NULL);
    return _Py_CAST(PyFrameObject*, Py_XNewRef(frame->f_back));
}
#endif

#if !defined(PYPY_VERSION)
static inline PyFrameObject* _PyFrame_GetBackBorrow(PyFrameObject *frame)
{
    PyFrameObject *back = PyFrame_GetBack(frame);
    Py_XDECREF(back);
    return back;
}
#endif


// bpo-40421 added PyFrame_GetLocals() to Python 3.11.0a7
#if PY_VERSION_HEX < 0x030B00A7 && !defined(PYPY_VERSION)
static inline PyObject* PyFrame_GetLocals(PyFrameObject *frame)
{
#if PY_VERSION_HEX >= 0x030400B1
    if (PyFrame_FastToLocalsWithError(frame) < 0) {
        return NULL;
    }
#else
    PyFrame_FastToLocals(frame);
#endif
    return Py_NewRef(frame->f_locals);
}
#endif


// bpo-40421 added PyFrame_GetGlobals() to Python 3.11.0a7
#if PY_VERSION_HEX < 0x030B00A7 && !defined(PYPY_VERSION)
static inline PyObject* PyFrame_GetGlobals(PyFrameObject *frame)
{
    return Py_NewRef(frame->f_globals);
}
#endif


// bpo-40421 added PyFrame_GetBuiltins() to Python 3.11.0a7
#if PY_VERSION_HEX < 0x030B00A7 && !defined(PYPY_VERSION)
static inline PyObject* PyFrame_GetBuiltins(PyFrameObject *frame)
{
    return Py_NewRef(frame->f_builtins);
}
#endif


// bpo-40421 added PyFrame_GetLasti() to Python 3.11.0b1
#if PY_VERSION_HEX < 0x030B00B1 && !defined(PYPY_VERSION)
static inline int PyFrame_GetLasti(PyFrameObject *frame)
{
#if PY_VERSION_HEX >= 0x030A00A7
    // bpo-27129: Since Python 3.10.0a7, f_lasti is an instruction offset,
    // not a bytes offset anymore. Python uses 16-bit "wordcode" (2 bytes)
    // instructions.
    if (frame->f_lasti < 0) {
        return -1;
    }
    return frame->f_lasti * 2;
#else
    return frame->f_lasti;
#endif
}
#endif


// gh-91248 added PyFrame_GetVar() to Python 3.12.0a2
#if PY_VERSION_HEX < 0x030C00A2 && !defined(PYPY_VERSION)
static inline PyObject* PyFrame_GetVar(PyFrameObject *frame, PyObject *name)
{
    PyObject *locals, *value;

    locals = PyFrame_GetLocals(frame);
    if (locals == NULL) {
        return NULL;
    }
#if PY_VERSION_HEX >= 0x03000000
    value = PyDict_GetItemWithError(locals, name);
#else
    value = _PyDict_GetItemWithError(locals, name);
#endif
    Py_DECREF(locals);

    if (value == NULL) {
        if (PyErr_Occurred()) {
            return NULL;
        }
#if PY_VERSION_HEX >= 0x03000000
        PyErr_Format(PyExc_NameError, "variable %R does not exist", name);
#else
        PyErr_SetString(PyExc_NameError, "variable does not exist");
#endif
        return NULL;
    }
    return Py_NewRef(value);
}
#endif


// gh-91248 added PyFrame_GetVarString() to Python 3.12.0a2
#if PY_VERSION_HEX < 0x030C00A2 && !defined(PYPY_VERSION)
static inline PyObject*
PyFrame_GetVarString(PyFrameObject *frame, const char *name)
{
    PyObject *name_obj, *value;
#if PY_VERSION_HEX >= 0x03000000
    name_obj = PyUnicode_FromString(name);
#else
    name_obj = PyString_FromString(name);
#endif
    if (name_obj == NULL) {
        return NULL;
    }
    value = PyFrame_GetVar(frame, name_obj);
    Py_DECREF(name_obj);
    return value;
}
#endif


// bpo-39947 added PyThreadState_GetInterpreter() to Python 3.9.0a5
#if PY_VERSION_HEX < 0x030900A5 || (defined(PYPY_VERSION) && PY_VERSION_HEX < 0x030B0000)
static inline PyInterpreterState *
PyThreadState_GetInterpreter(PyThreadState *tstate)
{
    assert(tstate != _Py_NULL);
    return tstate->interp;
}
#endif


// bpo-40429 added PyThreadState_GetFrame() to Python 3.9.0b1
#if PY_VERSION_HEX < 0x030900B1 && !defined(PYPY_VERSION)
static inline PyFrameObject* PyThreadState_GetFrame(PyThreadState *tstate)
{
    assert(tstate != _Py_NULL);
    return _Py_CAST(PyFrameObject *, Py_XNewRef(tstate->frame));
}
#endif

#if !defined(PYPY_VERSION)
static inline PyFrameObject*
_PyThreadState_GetFrameBorrow(PyThreadState *tstate)
{
    PyFrameObject *frame = PyThreadState_GetFrame(tstate);
    Py_XDECREF(frame);
    return frame;
}
#endif


// bpo-39947 added PyInterpreterState_Get() to Python 3.9.0a5
#if PY_VERSION_HEX < 0x030900A5 || defined(PYPY_VERSION)
static inline PyInterpreterState* PyInterpreterState_Get(void)
{
    PyThreadState *tstate;
    PyInterpreterState *interp;

    tstate = PyThreadState_GET();
    if (tstate == _Py_NULL) {
        Py_FatalError("GIL released (tstate is NULL)");
    }
    interp = tstate->interp;
    if (interp == _Py_NULL) {
        Py_FatalError("no current interpreter");
    }
    return interp;
}
#endif


// bpo-39947 added PyInterpreterState_Get() to Python 3.9.0a6
#if 0x030700A1 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030900A6 && !defined(PYPY_VERSION)
static inline uint64_t PyThreadState_GetID(PyThreadState *tstate)
{
    assert(tstate != _Py_NULL);
    return tstate->id;
}
#endif

// bpo-43760 added PyThreadState_EnterTracing() to Python 3.11.0a2
#if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION)
static inline void PyThreadState_EnterTracing(PyThreadState *tstate)
{
    tstate->tracing++;
#if PY_VERSION_HEX >= 0x030A00A1
    tstate->cframe->use_tracing = 0;
#else
    tstate->use_tracing = 0;
#endif
}
#endif

// bpo-43760 added PyThreadState_LeaveTracing() to Python 3.11.0a2
#if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION)
static inline void PyThreadState_LeaveTracing(PyThreadState *tstate)
{
    int use_tracing = (tstate->c_tracefunc != _Py_NULL
                       || tstate->c_profilefunc != _Py_NULL);
    tstate->tracing--;
#if PY_VERSION_HEX >= 0x030A00A1
    tstate->cframe->use_tracing = use_tracing;
#else
    tstate->use_tracing = use_tracing;
#endif
}
#endif


// bpo-37194 added PyObject_CallNoArgs() to Python 3.9.0a1
// PyObject_CallNoArgs() added to PyPy 3.9.16-v7.3.11
#if !defined(PyObject_CallNoArgs) && PY_VERSION_HEX < 0x030900A1
static inline PyObject* PyObject_CallNoArgs(PyObject *func)
{
    return PyObject_CallFunctionObjArgs(func, NULL);
}
#endif


// bpo-39245 made PyObject_CallOneArg() public (previously called
// _PyObject_CallOneArg) in Python 3.9.0a4
// PyObject_CallOneArg() added to PyPy 3.9.16-v7.3.11
#if !defined(PyObject_CallOneArg) && PY_VERSION_HEX < 0x030900A4
static inline PyObject* PyObject_CallOneArg(PyObject *func, PyObject *arg)
{
    return PyObject_CallFunctionObjArgs(func, arg, NULL);
}
#endif


// bpo-1635741 added PyModule_AddObjectRef() to Python 3.10.0a3
#if PY_VERSION_HEX < 0x030A00A3
static inline int
PyModule_AddObjectRef(PyObject *module, const char *name, PyObject *value)
{
    int res;

    if (!value && !PyErr_Occurred()) {
        // PyModule_AddObject() raises TypeError in this case
        PyErr_SetString(PyExc_SystemError,
                        "PyModule_AddObjectRef() must be called "
                        "with an exception raised if value is NULL");
        return -1;
    }

    Py_XINCREF(value);
    res = PyModule_AddObject(module, name, value);
    if (res < 0) {
        Py_XDECREF(value);
    }
    return res;
}
#endif


// bpo-40024 added PyModule_AddType() to Python 3.9.0a5
#if PY_VERSION_HEX < 0x030900A5
static inline int PyModule_AddType(PyObject *module, PyTypeObject *type)
{
    const char *name, *dot;

    if (PyType_Ready(type) < 0) {
        return -1;
    }

    // inline _PyType_Name()
    name = type->tp_name;
    assert(name != _Py_NULL);
    dot = strrchr(name, '.');
    if (dot != _Py_NULL) {
        name = dot + 1;
    }

    return PyModule_AddObjectRef(module, name, _PyObject_CAST(type));
}
#endif


// bpo-40241 added PyObject_GC_IsTracked() to Python 3.9.0a6.
// bpo-4688 added _PyObject_GC_IS_TRACKED() to Python 2.7.0a2.
#if PY_VERSION_HEX < 0x030900A6 && !defined(PYPY_VERSION)
static inline int PyObject_GC_IsTracked(PyObject* obj)
{
    return (PyObject_IS_GC(obj) && _PyObject_GC_IS_TRACKED(obj));
}
#endif

// bpo-40241 added PyObject_GC_IsFinalized() to Python 3.9.0a6.
// bpo-18112 added _PyGCHead_FINALIZED() to Python 3.4.0 final.
#if PY_VERSION_HEX < 0x030900A6 && PY_VERSION_HEX >= 0x030400F0 && !defined(PYPY_VERSION)
static inline int PyObject_GC_IsFinalized(PyObject *obj)
{
    PyGC_Head *gc = _Py_CAST(PyGC_Head*, obj) - 1;
    return (PyObject_IS_GC(obj) && _PyGCHead_FINALIZED(gc));
}
#endif


// bpo-39573 added Py_IS_TYPE() to Python 3.9.0a4
#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_IS_TYPE)
static inline int _Py_IS_TYPE(PyObject *ob, PyTypeObject *type) {
    return Py_TYPE(ob) == type;
}
#define Py_IS_TYPE(ob, type) _Py_IS_TYPE(_PyObject_CAST(ob), type)
#endif


// bpo-46906 added PyFloat_Pack2() and PyFloat_Unpack2() to Python 3.11a7.
// bpo-11734 added _PyFloat_Pack2() and _PyFloat_Unpack2() to Python 3.6.0b1.
// Python 3.11a2 moved _PyFloat_Pack2() and _PyFloat_Unpack2() to the internal
// C API: Python 3.11a2-3.11a6 versions are not supported.
#if 0x030600B1 <= PY_VERSION_HEX && PY_VERSION_HEX <= 0x030B00A1 && !defined(PYPY_VERSION)
static inline int PyFloat_Pack2(double x, char *p, int le)
{ return _PyFloat_Pack2(x, (unsigned char*)p, le); }

static inline double PyFloat_Unpack2(const char *p, int le)
{ return _PyFloat_Unpack2((const unsigned char *)p, le); }
#endif


// bpo-46906 added PyFloat_Pack4(), PyFloat_Pack8(), PyFloat_Unpack4() and
// PyFloat_Unpack8() to Python 3.11a7.
// Python 3.11a2 moved _PyFloat_Pack4(), _PyFloat_Pack8(), _PyFloat_Unpack4()
// and _PyFloat_Unpack8() to the internal C API: Python 3.11a2-3.11a6 versions
// are not supported.
#if PY_VERSION_HEX <= 0x030B00A1 && !defined(PYPY_VERSION)
static inline int PyFloat_Pack4(double x, char *p, int le)
{ return _PyFloat_Pack4(x, (unsigned char*)p, le); }

static inline int PyFloat_Pack8(double x, char *p, int le)
{ return _PyFloat_Pack8(x, (unsigned char*)p, le); }

static inline double PyFloat_Unpack4(const char *p, int le)
{ return _PyFloat_Unpack4((const unsigned char *)p, le); }

static inline double PyFloat_Unpack8(const char *p, int le)
{ return _PyFloat_Unpack8((const unsigned char *)p, le); }
#endif


// gh-92154 added PyCode_GetCode() to Python 3.11.0b1
#if PY_VERSION_HEX < 0x030B00B1 && !defined(PYPY_VERSION)
static inline PyObject* PyCode_GetCode(PyCodeObject *code)
{
    return Py_NewRef(code->co_code);
}
#endif


// gh-95008 added PyCode_GetVarnames() to Python 3.11.0rc1
#if PY_VERSION_HEX < 0x030B00C1 && !defined(PYPY_VERSION)
static inline PyObject* PyCode_GetVarnames(PyCodeObject *code)
{
    return Py_NewRef(code->co_varnames);
}
#endif

// gh-95008 added PyCode_GetFreevars() to Python 3.11.0rc1
#if PY_VERSION_HEX < 0x030B00C1 && !defined(PYPY_VERSION)
static inline PyObject* PyCode_GetFreevars(PyCodeObject *code)
{
    return Py_NewRef(code->co_freevars);
}
#endif

// gh-95008 added PyCode_GetCellvars() to Python 3.11.0rc1
#if PY_VERSION_HEX < 0x030B00C1 && !defined(PYPY_VERSION)
static inline PyObject* PyCode_GetCellvars(PyCodeObject *code)
{
    return Py_NewRef(code->co_cellvars);
}
#endif


// Py_UNUSED() was added to Python 3.4.0b2.
#if PY_VERSION_HEX < 0x030400B2 && !defined(Py_UNUSED)
#  if defined(__GNUC__) || defined(__clang__)
#    define Py_UNUSED(name) _unused_ ## name __attribute__((unused))
#  else
#    define Py_UNUSED(name) _unused_ ## name
#  endif
#endif


// gh-105922 added PyImport_AddModuleRef() to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D00A0
static inline PyObject* PyImport_AddModuleRef(const char *name)
{
    return Py_XNewRef(PyImport_AddModule(name));
}
#endif


// gh-105927 added PyWeakref_GetRef() to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D0000
static inline int PyWeakref_GetRef(PyObject *ref, PyObject **pobj)
{
    PyObject *obj;
    if (ref != NULL && !PyWeakref_Check(ref)) {
        *pobj = NULL;
        PyErr_SetString(PyExc_TypeError, "expected a weakref");
        return -1;
    }
    obj = PyWeakref_GetObject(ref);
    if (obj == NULL) {
        // SystemError if ref is NULL
        *pobj = NULL;
        return -1;
    }
    if (obj == Py_None) {
        *pobj = NULL;
        return 0;
    }
    *pobj = Py_NewRef(obj);
    return 1;
}
#endif


// bpo-36974 added PY_VECTORCALL_ARGUMENTS_OFFSET to Python 3.8b1
#ifndef PY_VECTORCALL_ARGUMENTS_OFFSET
#  define PY_VECTORCALL_ARGUMENTS_OFFSET (_Py_CAST(size_t, 1) << (8 * sizeof(size_t) - 1))
#endif

// bpo-36974 added PyVectorcall_NARGS() to Python 3.8b1
#if PY_VERSION_HEX < 0x030800B1
static inline Py_ssize_t PyVectorcall_NARGS(size_t n)
{
    return n & ~PY_VECTORCALL_ARGUMENTS_OFFSET;
}
#endif


// gh-105922 added PyObject_Vectorcall() to Python 3.9.0a4
#if PY_VERSION_HEX < 0x030900A4
static inline PyObject*
PyObject_Vectorcall(PyObject *callable, PyObject *const *args,
                     size_t nargsf, PyObject *kwnames)
{
#if PY_VERSION_HEX >= 0x030800B1 && !defined(PYPY_VERSION)
    // bpo-36974 added _PyObject_Vectorcall() to Python 3.8.0b1
    return _PyObject_Vectorcall(callable, args, nargsf, kwnames);
#else
    PyObject *posargs = NULL, *kwargs = NULL;
    PyObject *res;
    Py_ssize_t nposargs, nkwargs, i;

    if (nargsf != 0 && args == NULL) {
        PyErr_BadInternalCall();
        goto error;
    }
    if (kwnames != NULL && !PyTuple_Check(kwnames)) {
        PyErr_BadInternalCall();
        goto error;
    }

    nposargs = (Py_ssize_t)PyVectorcall_NARGS(nargsf);
    if (kwnames) {
        nkwargs = PyTuple_GET_SIZE(kwnames);
    }
    else {
        nkwargs = 0;
    }

    posargs = PyTuple_New(nposargs);
    if (posargs == NULL) {
        goto error;
    }
    if (nposargs) {
        for (i=0; i < nposargs; i++) {
            PyTuple_SET_ITEM(posargs, i, Py_NewRef(*args));
            args++;
        }
    }

    if (nkwargs) {
        kwargs = PyDict_New();
        if (kwargs == NULL) {
            goto error;
        }

        for (i = 0; i < nkwargs; i++) {
            PyObject *key = PyTuple_GET_ITEM(kwnames, i);
            PyObject *value = *args;
            args++;
            if (PyDict_SetItem(kwargs, key, value) < 0) {
                goto error;
            }
        }
    }
    else {
        kwargs = NULL;
    }

    res = PyObject_Call(callable, posargs, kwargs);
    Py_DECREF(posargs);
    Py_XDECREF(kwargs);
    return res;

error:
    Py_DECREF(posargs);
    Py_XDECREF(kwargs);
    return NULL;
#endif
}
#endif


// gh-106521 added PyObject_GetOptionalAttr() and
// PyObject_GetOptionalAttrString() to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D00A1
static inline int
PyObject_GetOptionalAttr(PyObject *obj, PyObject *attr_name, PyObject **result)
{
    // bpo-32571 added _PyObject_LookupAttr() to Python 3.7.0b1
#if PY_VERSION_HEX >= 0x030700B1 && !defined(PYPY_VERSION)
    return _PyObject_LookupAttr(obj, attr_name, result);
#else
    *result = PyObject_GetAttr(obj, attr_name);
    if (*result != NULL) {
        return 1;
    }
    if (!PyErr_Occurred()) {
        return 0;
    }
    if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
        PyErr_Clear();
        return 0;
    }
    return -1;
#endif
}

static inline int
PyObject_GetOptionalAttrString(PyObject *obj, const char *attr_name, PyObject **result)
{
    PyObject *name_obj;
    int rc;
#if PY_VERSION_HEX >= 0x03000000
    name_obj = PyUnicode_FromString(attr_name);
#else
    name_obj = PyString_FromString(attr_name);
#endif
    if (name_obj == NULL) {
        *result = NULL;
        return -1;
    }
    rc = PyObject_GetOptionalAttr(obj, name_obj, result);
    Py_DECREF(name_obj);
    return rc;
}
#endif


// gh-106307 added PyObject_GetOptionalAttr() and
// PyMapping_GetOptionalItemString() to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D00A1
static inline int
PyMapping_GetOptionalItem(PyObject *obj, PyObject *key, PyObject **result)
{
    *result = PyObject_GetItem(obj, key);
    if (*result) {
        return 1;
    }
    if (!PyErr_ExceptionMatches(PyExc_KeyError)) {
        return -1;
    }
    PyErr_Clear();
    return 0;
}

static inline int
PyMapping_GetOptionalItemString(PyObject *obj, const char *key, PyObject **result)
{
    PyObject *key_obj;
    int rc;
#if PY_VERSION_HEX >= 0x03000000
    key_obj = PyUnicode_FromString(key);
#else
    key_obj = PyString_FromString(key);
#endif
    if (key_obj == NULL) {
        *result = NULL;
        return -1;
    }
    rc = PyMapping_GetOptionalItem(obj, key_obj, result);
    Py_DECREF(key_obj);
    return rc;
}
#endif

// gh-108511 added PyMapping_HasKeyWithError() and
// PyMapping_HasKeyStringWithError() to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D00A1
static inline int
PyMapping_HasKeyWithError(PyObject *obj, PyObject *key)
{
    PyObject *res;
    int rc = PyMapping_GetOptionalItem(obj, key, &res);
    Py_XDECREF(res);
    return rc;
}

static inline int
PyMapping_HasKeyStringWithError(PyObject *obj, const char *key)
{
    PyObject *res;
    int rc = PyMapping_GetOptionalItemString(obj, key, &res);
    Py_XDECREF(res);
    return rc;
}
#endif


// gh-108511 added PyObject_HasAttrWithError() and
// PyObject_HasAttrStringWithError() to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D00A1
static inline int
PyObject_HasAttrWithError(PyObject *obj, PyObject *attr)
{
    PyObject *res;
    int rc = PyObject_GetOptionalAttr(obj, attr, &res);
    Py_XDECREF(res);
    return rc;
}

static inline int
PyObject_HasAttrStringWithError(PyObject *obj, const char *attr)
{
    PyObject *res;
    int rc = PyObject_GetOptionalAttrString(obj, attr, &res);
    Py_XDECREF(res);
    return rc;
}
#endif


// gh-106004 added PyDict_GetItemRef() and PyDict_GetItemStringRef()
// to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D00A1
static inline int
PyDict_GetItemRef(PyObject *mp, PyObject *key, PyObject **result)
{
#if PY_VERSION_HEX >= 0x03000000
    PyObject *item = PyDict_GetItemWithError(mp, key);
#else
    PyObject *item = _PyDict_GetItemWithError(mp, key);
#endif
    if (item != NULL) {
        *result = Py_NewRef(item);
        return 1;  // found
    }
    if (!PyErr_Occurred()) {
        *result = NULL;
        return 0;  // not found
    }
    *result = NULL;
    return -1;
}

static inline int
PyDict_GetItemStringRef(PyObject *mp, const char *key, PyObject **result)
{
    int res;
#if PY_VERSION_HEX >= 0x03000000
    PyObject *key_obj = PyUnicode_FromString(key);
#else
    PyObject *key_obj = PyString_FromString(key);
#endif
    if (key_obj == NULL) {
        *result = NULL;
        return -1;
    }
    res = PyDict_GetItemRef(mp, key_obj, result);
    Py_DECREF(key_obj);
    return res;
}
#endif


// gh-106307 added PyModule_Add() to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D00A1
static inline int
PyModule_Add(PyObject *mod, const char *name, PyObject *value)
{
    int res = PyModule_AddObjectRef(mod, name, value);
    Py_XDECREF(value);
    return res;
}
#endif


// gh-108014 added Py_IsFinalizing() to Python 3.13.0a1
// bpo-1856 added _Py_Finalizing to Python 3.2.1b1.
// _Py_IsFinalizing() was added to PyPy 7.3.0.
#if (0x030201B1 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030D00A1) \
        && (!defined(PYPY_VERSION_NUM) || PYPY_VERSION_NUM >= 0x7030000)
static inline int Py_IsFinalizing(void)
{
#if PY_VERSION_HEX >= 0x030700A1
    // _Py_IsFinalizing() was added to Python 3.7.0a1.
    return _Py_IsFinalizing();
#else
    return (_Py_Finalizing != NULL);
#endif
}
#endif


// gh-108323 added PyDict_ContainsString() to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D00A1
static inline int PyDict_ContainsString(PyObject *op, const char *key)
{
    PyObject *key_obj = PyUnicode_FromString(key);
    if (key_obj == NULL) {
        return -1;
    }
    int res = PyDict_Contains(op, key_obj);
    Py_DECREF(key_obj);
    return res;
}
#endif


// gh-108445 added PyLong_AsInt() to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D00A1
static inline int PyLong_AsInt(PyObject *obj)
{
#ifdef PYPY_VERSION
    long value = PyLong_AsLong(obj);
    if (value == -1 && PyErr_Occurred()) {
        return -1;
    }
    if (value < (long)INT_MIN || (long)INT_MAX < value) {
        PyErr_SetString(PyExc_OverflowError,
                        "Python int too large to convert to C int");
        return -1;
    }
    return (int)value;
#else
    return _PyLong_AsInt(obj);
#endif
}
#endif


// gh-107073 added PyObject_VisitManagedDict() to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D00A1
static inline int
PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
{
    PyObject **dict = _PyObject_GetDictPtr(obj);
    if (dict == NULL || *dict == NULL) {
        return -1;
    }
    Py_VISIT(*dict);
    return 0;
}

static inline void
PyObject_ClearManagedDict(PyObject *obj)
{
    PyObject **dict = _PyObject_GetDictPtr(obj);
    if (dict == NULL || *dict == NULL) {
        return;
    }
    Py_CLEAR(*dict);
}
#endif

// gh-108867 added PyThreadState_GetUnchecked() to Python 3.13.0a1
// Python 3.5.2 added _PyThreadState_UncheckedGet().
#if PY_VERSION_HEX >= 0x03050200 && PY_VERSION_HEX < 0x030D00A1
static inline PyThreadState*
PyThreadState_GetUnchecked(void)
{
    return _PyThreadState_UncheckedGet();
}
#endif

// gh-110289 added PyUnicode_EqualToUTF8() and PyUnicode_EqualToUTF8AndSize()
// to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D00A1
static inline int
PyUnicode_EqualToUTF8AndSize(PyObject *unicode, const char *str, Py_ssize_t str_len)
{
    Py_ssize_t len;
    const void *utf8;
    PyObject *exc_type, *exc_value, *exc_tb;
    int res;

    // API cannot report errors so save/restore the exception
    PyErr_Fetch(&exc_type, &exc_value, &exc_tb);

    // Python 3.3.0a1 added PyUnicode_AsUTF8AndSize()
#if PY_VERSION_HEX >= 0x030300A1
    if (PyUnicode_IS_ASCII(unicode)) {
        utf8 = PyUnicode_DATA(unicode);
        len = PyUnicode_GET_LENGTH(unicode);
    }
    else {
        utf8 = PyUnicode_AsUTF8AndSize(unicode, &len);
        if (utf8 == NULL) {
            // Memory allocation failure. The API cannot report error,
            // so ignore the exception and return 0.
            res = 0;
            goto done;
        }
    }

    if (len != str_len) {
        res = 0;
        goto done;
    }
    res = (memcmp(utf8, str, (size_t)len) == 0);
#else
    PyObject *bytes = PyUnicode_AsUTF8String(unicode);
    if (bytes == NULL) {
        // Memory allocation failure. The API cannot report error,
        // so ignore the exception and return 0.
        res = 0;
        goto done;
    }

#if PY_VERSION_HEX >= 0x03000000
    len = PyBytes_GET_SIZE(bytes);
    utf8 = PyBytes_AS_STRING(bytes);
#else
    len = PyString_GET_SIZE(bytes);
    utf8 = PyString_AS_STRING(bytes);
#endif
    if (len != str_len) {
        Py_DECREF(bytes);
        res = 0;
        goto done;
    }

    res = (memcmp(utf8, str, (size_t)len) == 0);
    Py_DECREF(bytes);
#endif

done:
    PyErr_Restore(exc_type, exc_value, exc_tb);
    return res;
}

static inline int
PyUnicode_EqualToUTF8(PyObject *unicode, const char *str)
{
    return PyUnicode_EqualToUTF8AndSize(unicode, str, (Py_ssize_t)strlen(str));
}
#endif


// gh-111138 added PyList_Extend() and PyList_Clear() to Python 3.13.0a2
#if PY_VERSION_HEX < 0x030D00A2
static inline int
PyList_Extend(PyObject *list, PyObject *iterable)
{
    return PyList_SetSlice(list, PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, iterable);
}

static inline int
PyList_Clear(PyObject *list)
{
    return PyList_SetSlice(list, 0, PY_SSIZE_T_MAX, NULL);
}
#endif

// gh-111262 added PyDict_Pop() and PyDict_PopString() to Python 3.13.0a2
#if PY_VERSION_HEX < 0x030D00A2
static inline int
PyDict_Pop(PyObject *dict, PyObject *key, PyObject **result)
{
    PyObject *value;

    if (!PyDict_Check(dict)) {
        PyErr_BadInternalCall();
        if (result) {
            *result = NULL;
        }
        return -1;
    }

    // bpo-16991 added _PyDict_Pop() to Python 3.5.0b2.
    // Python 3.6.0b3 changed _PyDict_Pop() first argument type to PyObject*.
    // Python 3.13.0a1 removed _PyDict_Pop().
#if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x030500b2 || PY_VERSION_HEX >= 0x030D0000
    value = PyObject_CallMethod(dict, "pop", "O", key);
#elif PY_VERSION_HEX < 0x030600b3
    value = _PyDict_Pop(_Py_CAST(PyDictObject*, dict), key, NULL);
#else
    value = _PyDict_Pop(dict, key, NULL);
#endif
    if (value == NULL) {
        if (result) {
            *result = NULL;
        }
        if (PyErr_Occurred() && !PyErr_ExceptionMatches(PyExc_KeyError)) {
            return -1;
        }
        PyErr_Clear();
        return 0;
    }
    if (result) {
        *result = value;
    }
    else {
        Py_DECREF(value);
    }
    return 1;
}

static inline int
PyDict_PopString(PyObject *dict, const char *key, PyObject **result)
{
    PyObject *key_obj = PyUnicode_FromString(key);
    if (key_obj == NULL) {
        if (result != NULL) {
            *result = NULL;
        }
        return -1;
    }

    int res = PyDict_Pop(dict, key_obj, result);
    Py_DECREF(key_obj);
    return res;
}
#endif


#if PY_VERSION_HEX < 0x030200A4
// Python 3.2.0a4 added Py_hash_t type
typedef Py_ssize_t Py_hash_t;
#endif


// gh-111545 added Py_HashPointer() to Python 3.13.0a3
#if PY_VERSION_HEX < 0x030D00A3
static inline Py_hash_t Py_HashPointer(const void *ptr)
{
#if PY_VERSION_HEX >= 0x030900A4 && !defined(PYPY_VERSION)
    return _Py_HashPointer(ptr);
#else
    return _Py_HashPointer(_Py_CAST(void*, ptr));
#endif
}
#endif


// Python 3.13a4 added a PyTime API.
// Use the private API added to Python 3.5.
#if PY_VERSION_HEX < 0x030D00A4 && PY_VERSION_HEX  >= 0x03050000
typedef _PyTime_t PyTime_t;
#define PyTime_MIN _PyTime_MIN
#define PyTime_MAX _PyTime_MAX

static inline double PyTime_AsSecondsDouble(PyTime_t t)
{ return _PyTime_AsSecondsDouble(t); }

static inline int PyTime_Monotonic(PyTime_t *result)
{ return _PyTime_GetMonotonicClockWithInfo(result, NULL); }

static inline int PyTime_Time(PyTime_t *result)
{ return _PyTime_GetSystemClockWithInfo(result, NULL); }

static inline int PyTime_PerfCounter(PyTime_t *result)
{
#if PY_VERSION_HEX >= 0x03070000 && !defined(PYPY_VERSION)
    return _PyTime_GetPerfCounterWithInfo(result, NULL);
#elif PY_VERSION_HEX >= 0x03070000
    // Call time.perf_counter_ns() and convert Python int object to PyTime_t.
    // Cache time.perf_counter_ns() function for best performance.
    static PyObject *func = NULL;
    if (func == NULL) {
        PyObject *mod = PyImport_ImportModule("time");
        if (mod == NULL) {
            return -1;
        }

        func = PyObject_GetAttrString(mod, "perf_counter_ns");
        Py_DECREF(mod);
        if (func == NULL) {
            return -1;
        }
    }

    PyObject *res = PyObject_CallNoArgs(func);
    if (res == NULL) {
        return -1;
    }
    long long value = PyLong_AsLongLong(res);
    Py_DECREF(res);

    if (value == -1 && PyErr_Occurred()) {
        return -1;
    }

    Py_BUILD_ASSERT(sizeof(value) >= sizeof(PyTime_t));
    *result = (PyTime_t)value;
    return 0;
#else
    // Call time.perf_counter() and convert C double to PyTime_t.
    // Cache time.perf_counter() function for best performance.
    static PyObject *func = NULL;
    if (func == NULL) {
        PyObject *mod = PyImport_ImportModule("time");
        if (mod == NULL) {
            return -1;
        }

        func = PyObject_GetAttrString(mod, "perf_counter");
        Py_DECREF(mod);
        if (func == NULL) {
            return -1;
        }
    }

    PyObject *res = PyObject_CallNoArgs(func);
    if (res == NULL) {
        return -1;
    }
    double d = PyFloat_AsDouble(res);
    Py_DECREF(res);

    if (d == -1.0 && PyErr_Occurred()) {
        return -1;
    }

    // Avoid floor() to avoid having to link to libm
    *result = (PyTime_t)(d * 1e9);
    return 0;
#endif
}

#endif

// gh-111389 added hash constants to Python 3.13.0a5. These constants were
// added first as private macros to Python 3.4.0b1 and PyPy 7.3.8.
#if (!defined(PyHASH_BITS) \
     && ((!defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x030400B1) \
         || (defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x03070000 \
             && PYPY_VERSION_NUM >= 0x07030800)))
#  define PyHASH_BITS _PyHASH_BITS
#  define PyHASH_MODULUS _PyHASH_MODULUS
#  define PyHASH_INF _PyHASH_INF
#  define PyHASH_IMAG _PyHASH_IMAG
#endif


// gh-111545 added Py_GetConstant() and Py_GetConstantBorrowed()
// to Python 3.13.0a6
#if PY_VERSION_HEX < 0x030D00A6 && !defined(Py_CONSTANT_NONE)

#define Py_CONSTANT_NONE 0
#define Py_CONSTANT_FALSE 1
#define Py_CONSTANT_TRUE 2
#define Py_CONSTANT_ELLIPSIS 3
#define Py_CONSTANT_NOT_IMPLEMENTED 4
#define Py_CONSTANT_ZERO 5
#define Py_CONSTANT_ONE 6
#define Py_CONSTANT_EMPTY_STR 7
#define Py_CONSTANT_EMPTY_BYTES 8
#define Py_CONSTANT_EMPTY_TUPLE 9

static inline PyObject* Py_GetConstant(unsigned int constant_id)
{
    static PyObject* constants[Py_CONSTANT_EMPTY_TUPLE + 1] = {NULL};

    if (constants[Py_CONSTANT_NONE] == NULL) {
        constants[Py_CONSTANT_NONE] = Py_None;
        constants[Py_CONSTANT_FALSE] = Py_False;
        constants[Py_CONSTANT_TRUE] = Py_True;
        constants[Py_CONSTANT_ELLIPSIS] = Py_Ellipsis;
        constants[Py_CONSTANT_NOT_IMPLEMENTED] = Py_NotImplemented;

        constants[Py_CONSTANT_ZERO] = PyLong_FromLong(0);
        if (constants[Py_CONSTANT_ZERO] == NULL) {
            goto fatal_error;
        }

        constants[Py_CONSTANT_ONE] = PyLong_FromLong(1);
        if (constants[Py_CONSTANT_ONE] == NULL) {
            goto fatal_error;
        }

        constants[Py_CONSTANT_EMPTY_STR] = PyUnicode_FromStringAndSize("", 0);
        if (constants[Py_CONSTANT_EMPTY_STR] == NULL) {
            goto fatal_error;
        }

        constants[Py_CONSTANT_EMPTY_BYTES] = PyBytes_FromStringAndSize("", 0);
        if (constants[Py_CONSTANT_EMPTY_BYTES] == NULL) {
            goto fatal_error;
        }

        constants[Py_CONSTANT_EMPTY_TUPLE] = PyTuple_New(0);
        if (constants[Py_CONSTANT_EMPTY_TUPLE] == NULL) {
            goto fatal_error;
        }
        // goto dance to avoid compiler warnings about Py_FatalError()
        goto init_done;

fatal_error:
        // This case should never happen
        Py_FatalError("Py_GetConstant() failed to get constants");
    }

init_done:
    if (constant_id <= Py_CONSTANT_EMPTY_TUPLE) {
        return Py_NewRef(constants[constant_id]);
    }
    else {
        PyErr_BadInternalCall();
        return NULL;
    }
}

static inline PyObject* Py_GetConstantBorrowed(unsigned int constant_id)
{
    PyObject *obj = Py_GetConstant(constant_id);
    Py_XDECREF(obj);
    return obj;
}
#endif


// gh-114329 added PyList_GetItemRef() to Python 3.13.0a4
#if PY_VERSION_HEX < 0x030D00A4
static inline PyObject *
PyList_GetItemRef(PyObject *op, Py_ssize_t index)
{
    PyObject *item = PyList_GetItem(op, index);
    Py_XINCREF(item);
    return item;
}
#endif


// gh-114329 added PyList_GetItemRef() to Python 3.13.0a4
#if PY_VERSION_HEX < 0x030D00A4
static inline int
PyDict_SetDefaultRef(PyObject *d, PyObject *key, PyObject *default_value,
                     PyObject **result)
{
    PyObject *value;
    if (PyDict_GetItemRef(d, key, &value) < 0) {
        // get error
        if (result) {
            *result = NULL;
        }
        return -1;
    }
    if (value != NULL) {
        // present
        if (result) {
            *result = value;
        }
        else {
            Py_DECREF(value);
        }
        return 1;
    }

    // missing: set the item
    if (PyDict_SetItem(d, key, default_value) < 0) {
        // set error
        if (result) {
            *result = NULL;
        }
        return -1;
    }
    if (result) {
        *result = Py_NewRef(default_value);
    }
    return 0;
}
#endif

#if PY_VERSION_HEX < 0x030D00B3
#  define Py_BEGIN_CRITICAL_SECTION(op) {
#  define Py_END_CRITICAL_SECTION() }
#  define Py_BEGIN_CRITICAL_SECTION2(a, b) {
#  define Py_END_CRITICAL_SECTION2() }
#endif

#if PY_VERSION_HEX < 0x030E0000 && PY_VERSION_HEX >= 0x03060000 && !defined(PYPY_VERSION)
typedef struct PyUnicodeWriter PyUnicodeWriter;

static inline void PyUnicodeWriter_Discard(PyUnicodeWriter *writer)
{
    _PyUnicodeWriter_Dealloc((_PyUnicodeWriter*)writer);
    PyMem_Free(writer);
}

static inline PyUnicodeWriter* PyUnicodeWriter_Create(Py_ssize_t length)
{
    if (length < 0) {
        PyErr_SetString(PyExc_ValueError,
                        "length must be positive");
        return NULL;
    }

    const size_t size = sizeof(_PyUnicodeWriter);
    PyUnicodeWriter *pub_writer = (PyUnicodeWriter *)PyMem_Malloc(size);
    if (pub_writer == _Py_NULL) {
        PyErr_NoMemory();
        return _Py_NULL;
    }
    _PyUnicodeWriter *writer = (_PyUnicodeWriter *)pub_writer;

    _PyUnicodeWriter_Init(writer);
    if (_PyUnicodeWriter_Prepare(writer, length, 127) < 0) {
        PyUnicodeWriter_Discard(pub_writer);
        return NULL;
    }
    writer->overallocate = 1;
    return pub_writer;
}

static inline PyObject* PyUnicodeWriter_Finish(PyUnicodeWriter *writer)
{
    PyObject *str = _PyUnicodeWriter_Finish((_PyUnicodeWriter*)writer);
    assert(((_PyUnicodeWriter*)writer)->buffer == NULL);
    PyMem_Free(writer);
    return str;
}

static inline int
PyUnicodeWriter_WriteChar(PyUnicodeWriter *writer, Py_UCS4 ch)
{
    if (ch > 0x10ffff) {
        PyErr_SetString(PyExc_ValueError,
                        "character must be in range(0x110000)");
        return -1;
    }

    return _PyUnicodeWriter_WriteChar((_PyUnicodeWriter*)writer, ch);
}

static inline int
PyUnicodeWriter_WriteStr(PyUnicodeWriter *writer, PyObject *obj)
{
    PyObject *str = PyObject_Str(obj);
    if (str == NULL) {
        return -1;
    }

    int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str);
    Py_DECREF(str);
    return res;
}

static inline int
PyUnicodeWriter_WriteRepr(PyUnicodeWriter *writer, PyObject *obj)
{
    PyObject *str = PyObject_Repr(obj);
    if (str == NULL) {
        return -1;
    }

    int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str);
    Py_DECREF(str);
    return res;
}

static inline int
PyUnicodeWriter_WriteUTF8(PyUnicodeWriter *writer,
                          const char *str, Py_ssize_t size)
{
    if (size < 0) {
        size = (Py_ssize_t)strlen(str);
    }

    PyObject *str_obj = PyUnicode_FromStringAndSize(str, size);
    if (str_obj == _Py_NULL) {
        return -1;
    }

    int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str_obj);
    Py_DECREF(str_obj);
    return res;
}

static inline int
PyUnicodeWriter_WriteASCII(PyUnicodeWriter *writer,
                           const char *str, Py_ssize_t size)
{
    if (size < 0) {
        size = (Py_ssize_t)strlen(str);
    }

    return _PyUnicodeWriter_WriteASCIIString((_PyUnicodeWriter*)writer,
                                             str, size);
}

static inline int
PyUnicodeWriter_WriteWideChar(PyUnicodeWriter *writer,
                              const wchar_t *str, Py_ssize_t size)
{
    if (size < 0) {
        size = (Py_ssize_t)wcslen(str);
    }

    PyObject *str_obj = PyUnicode_FromWideChar(str, size);
    if (str_obj == _Py_NULL) {
        return -1;
    }

    int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str_obj);
    Py_DECREF(str_obj);
    return res;
}

static inline int
PyUnicodeWriter_WriteSubstring(PyUnicodeWriter *writer, PyObject *str,
                               Py_ssize_t start, Py_ssize_t end)
{
    if (!PyUnicode_Check(str)) {
        PyErr_Format(PyExc_TypeError, "expect str, not %s",
                     Py_TYPE(str)->tp_name);
        return -1;
    }
    if (start < 0 || start > end) {
        PyErr_Format(PyExc_ValueError, "invalid start argument");
        return -1;
    }
    if (end > PyUnicode_GET_LENGTH(str)) {
        PyErr_Format(PyExc_ValueError, "invalid end argument");
        return -1;
    }

    return _PyUnicodeWriter_WriteSubstring((_PyUnicodeWriter*)writer, str,
                                           start, end);
}

static inline int
PyUnicodeWriter_Format(PyUnicodeWriter *writer, const char *format, ...)
{
    va_list vargs;
    va_start(vargs, format);
    PyObject *str = PyUnicode_FromFormatV(format, vargs);
    va_end(vargs);
    if (str == _Py_NULL) {
        return -1;
    }

    int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str);
    Py_DECREF(str);
    return res;
}
#endif  // PY_VERSION_HEX < 0x030E0000

// gh-116560 added PyLong_GetSign() to Python 3.14.0a0
#if PY_VERSION_HEX < 0x030E00A0
static inline int PyLong_GetSign(PyObject *obj, int *sign)
{
    if (!PyLong_Check(obj)) {
        PyErr_Format(PyExc_TypeError, "expect int, got %s", Py_TYPE(obj)->tp_name);
        return -1;
    }

    *sign = _PyLong_Sign(obj);
    return 0;
}
#endif

// gh-126061 added PyLong_IsPositive/Negative/Zero() to Python in 3.14.0a2
#if PY_VERSION_HEX < 0x030E00A2
static inline int PyLong_IsPositive(PyObject *obj)
{
    if (!PyLong_Check(obj)) {
        PyErr_Format(PyExc_TypeError, "expected int, got %s", Py_TYPE(obj)->tp_name);
        return -1;
    }
    return _PyLong_Sign(obj) == 1;
}

static inline int PyLong_IsNegative(PyObject *obj)
{
    if (!PyLong_Check(obj)) {
        PyErr_Format(PyExc_TypeError, "expected int, got %s", Py_TYPE(obj)->tp_name);
        return -1;
    }
    return _PyLong_Sign(obj) == -1;
}

static inline int PyLong_IsZero(PyObject *obj)
{
    if (!PyLong_Check(obj)) {
        PyErr_Format(PyExc_TypeError, "expected int, got %s", Py_TYPE(obj)->tp_name);
        return -1;
    }
    return _PyLong_Sign(obj) == 0;
}
#endif


// gh-124502 added PyUnicode_Equal() to Python 3.14.0a0
#if PY_VERSION_HEX < 0x030E00A0
static inline int PyUnicode_Equal(PyObject *str1, PyObject *str2)
{
    if (!PyUnicode_Check(str1)) {
        PyErr_Format(PyExc_TypeError, "first argument must be str, not %s",
                     Py_TYPE(str1)->tp_name);
        return -1;
    }
    if (!PyUnicode_Check(str2)) {
        PyErr_Format(PyExc_TypeError, "second argument must be str, not %s",
                     Py_TYPE(str2)->tp_name);
        return -1;
    }

#if PY_VERSION_HEX >= 0x030d0000 && !defined(PYPY_VERSION)
    PyAPI_FUNC(int) _PyUnicode_Equal(PyObject *str1, PyObject *str2);

    return _PyUnicode_Equal(str1, str2);
#elif PY_VERSION_HEX >= 0x03060000 && !defined(PYPY_VERSION)
    return _PyUnicode_EQ(str1, str2);
#elif PY_VERSION_HEX >= 0x03090000 && defined(PYPY_VERSION)
    return _PyUnicode_EQ(str1, str2);
#else
    return (PyUnicode_Compare(str1, str2) == 0);
#endif
}
#endif


// gh-121645 added PyBytes_Join() to Python 3.14.0a0
#if PY_VERSION_HEX < 0x030E00A0
static inline PyObject* PyBytes_Join(PyObject *sep, PyObject *iterable)
{
    return _PyBytes_Join(sep, iterable);
}
#endif


#if PY_VERSION_HEX < 0x030E00A0
static inline Py_hash_t Py_HashBuffer(const void *ptr, Py_ssize_t len)
{
#if PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION)
    PyAPI_FUNC(Py_hash_t) _Py_HashBytes(const void *src, Py_ssize_t len);

    return _Py_HashBytes(ptr, len);
#else
    Py_hash_t hash;
    PyObject *bytes = PyBytes_FromStringAndSize((const char*)ptr, len);
    if (bytes == NULL) {
        return -1;
    }
    hash = PyObject_Hash(bytes);
    Py_DECREF(bytes);
    return hash;
#endif
}
#endif


#if PY_VERSION_HEX < 0x030E00A0
static inline int PyIter_NextItem(PyObject *iter, PyObject **item)
{
    iternextfunc tp_iternext;

    assert(iter != NULL);
    assert(item != NULL);

    tp_iternext = Py_TYPE(iter)->tp_iternext;
    if (tp_iternext == NULL) {
        *item = NULL;
        PyErr_Format(PyExc_TypeError, "expected an iterator, got '%s'",
                     Py_TYPE(iter)->tp_name);
        return -1;
    }

    if ((*item = tp_iternext(iter))) {
        return 1;
    }
    if (!PyErr_Occurred()) {
        return 0;
    }
    if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
        PyErr_Clear();
        return 0;
    }
    return -1;
}
#endif


#if PY_VERSION_HEX < 0x030E00A0
static inline PyObject* PyLong_FromInt32(int32_t value)
{
    Py_BUILD_ASSERT(sizeof(long) >= 4);
    return PyLong_FromLong(value);
}

static inline PyObject* PyLong_FromInt64(int64_t value)
{
    Py_BUILD_ASSERT(sizeof(long long) >= 8);
    return PyLong_FromLongLong(value);
}

static inline PyObject* PyLong_FromUInt32(uint32_t value)
{
    Py_BUILD_ASSERT(sizeof(unsigned long) >= 4);
    return PyLong_FromUnsignedLong(value);
}

static inline PyObject* PyLong_FromUInt64(uint64_t value)
{
    Py_BUILD_ASSERT(sizeof(unsigned long long) >= 8);
    return PyLong_FromUnsignedLongLong(value);
}

static inline int PyLong_AsInt32(PyObject *obj, int32_t *pvalue)
{
    Py_BUILD_ASSERT(sizeof(int) == 4);
    int value = PyLong_AsInt(obj);
    if (value == -1 && PyErr_Occurred()) {
        return -1;
    }
    *pvalue = (int32_t)value;
    return 0;
}

static inline int PyLong_AsInt64(PyObject *obj, int64_t *pvalue)
{
    Py_BUILD_ASSERT(sizeof(long long) == 8);
    long long value = PyLong_AsLongLong(obj);
    if (value == -1 && PyErr_Occurred()) {
        return -1;
    }
    *pvalue = (int64_t)value;
    return 0;
}

static inline int PyLong_AsUInt32(PyObject *obj, uint32_t *pvalue)
{
    Py_BUILD_ASSERT(sizeof(long) >= 4);
    unsigned long value = PyLong_AsUnsignedLong(obj);
    if (value == (unsigned long)-1 && PyErr_Occurred()) {
        return -1;
    }
#if SIZEOF_LONG > 4
    if ((unsigned long)UINT32_MAX < value) {
        PyErr_SetString(PyExc_OverflowError,
                        "Python int too large to convert to C uint32_t");
        return -1;
    }
#endif
    *pvalue = (uint32_t)value;
    return 0;
}

static inline int PyLong_AsUInt64(PyObject *obj, uint64_t *pvalue)
{
    Py_BUILD_ASSERT(sizeof(long long) == 8);
    unsigned long long value = PyLong_AsUnsignedLongLong(obj);
    if (value == (unsigned long long)-1 && PyErr_Occurred()) {
        return -1;
    }
    *pvalue = (uint64_t)value;
    return 0;
}
#endif


// gh-102471 added import and export API for integers to 3.14.0a2.
#if PY_VERSION_HEX < 0x030E00A2 && PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION)
// Helpers to access PyLongObject internals.
static inline void
_PyLong_SetSignAndDigitCount(PyLongObject *op, int sign, Py_ssize_t size)
{
#if PY_VERSION_HEX >= 0x030C0000
    op->long_value.lv_tag = (uintptr_t)(1 - sign) | ((uintptr_t)(size) << 3);
#elif PY_VERSION_HEX >= 0x030900A4
    Py_SET_SIZE(op, sign * size);
#else
    Py_SIZE(op) = sign * size;
#endif
}

static inline Py_ssize_t
_PyLong_DigitCount(const PyLongObject *op)
{
#if PY_VERSION_HEX >= 0x030C0000
    return (Py_ssize_t)(op->long_value.lv_tag >> 3);
#else
    return _PyLong_Sign((PyObject*)op) < 0 ? -Py_SIZE(op) : Py_SIZE(op);
#endif
}

static inline digit*
_PyLong_GetDigits(const PyLongObject *op)
{
#if PY_VERSION_HEX >= 0x030C0000
    return (digit*)(op->long_value.ob_digit);
#else
    return (digit*)(op->ob_digit);
#endif
}

typedef struct PyLongLayout {
    uint8_t bits_per_digit;
    uint8_t digit_size;
    int8_t digits_order;
    int8_t digit_endianness;
} PyLongLayout;

typedef struct PyLongExport {
    int64_t value;
    uint8_t negative;
    Py_ssize_t ndigits;
    const void *digits;
    Py_uintptr_t _reserved;
} PyLongExport;

typedef struct PyLongWriter PyLongWriter;

static inline const PyLongLayout*
PyLong_GetNativeLayout(void)
{
    static const PyLongLayout PyLong_LAYOUT = {
        PyLong_SHIFT,
        sizeof(digit),
        -1,  // least significant first
        PY_LITTLE_ENDIAN ? -1 : 1,
    };

    return &PyLong_LAYOUT;
}

static inline int
PyLong_Export(PyObject *obj, PyLongExport *export_long)
{
    if (!PyLong_Check(obj)) {
        memset(export_long, 0, sizeof(*export_long));
        PyErr_Format(PyExc_TypeError, "expected int, got %s",
                     Py_TYPE(obj)->tp_name);
        return -1;
    }

    // Fast-path: try to convert to a int64_t
    PyLongObject *self = (PyLongObject*)obj;
    int overflow;
#if SIZEOF_LONG == 8
    long value = PyLong_AsLongAndOverflow(obj, &overflow);
#else
    // Windows has 32-bit long, so use 64-bit long long instead
    long long value = PyLong_AsLongLongAndOverflow(obj, &overflow);
#endif
    Py_BUILD_ASSERT(sizeof(value) == sizeof(int64_t));
    // the function cannot fail since obj is a PyLongObject
    assert(!(value == -1 && PyErr_Occurred()));

    if (!overflow) {
        export_long->value = value;
        export_long->negative = 0;
        export_long->ndigits = 0;
        export_long->digits = 0;
        export_long->_reserved = 0;
    }
    else {
        export_long->value = 0;
        export_long->negative = _PyLong_Sign(obj) < 0;
        export_long->ndigits = _PyLong_DigitCount(self);
        if (export_long->ndigits == 0) {
            export_long->ndigits = 1;
        }
        export_long->digits = _PyLong_GetDigits(self);
        export_long->_reserved = (Py_uintptr_t)Py_NewRef(obj);
    }
    return 0;
}

static inline void
PyLong_FreeExport(PyLongExport *export_long)
{
    PyObject *obj = (PyObject*)export_long->_reserved;

    if (obj) {
        export_long->_reserved = 0;
        Py_DECREF(obj);
    }
}

static inline PyLongWriter*
PyLongWriter_Create(int negative, Py_ssize_t ndigits, void **digits)
{
    if (ndigits <= 0) {
        PyErr_SetString(PyExc_ValueError, "ndigits must be positive");
        return NULL;
    }
    assert(digits != NULL);

    PyLongObject *obj = _PyLong_New(ndigits);
    if (obj == NULL) {
        return NULL;
    }
    _PyLong_SetSignAndDigitCount(obj, negative?-1:1, ndigits);

    *digits = _PyLong_GetDigits(obj);
    return (PyLongWriter*)obj;
}

static inline void
PyLongWriter_Discard(PyLongWriter *writer)
{
    PyLongObject *obj = (PyLongObject *)writer;

    assert(Py_REFCNT(obj) == 1);
    Py_DECREF(obj);
}

static inline PyObject*
PyLongWriter_Finish(PyLongWriter *writer)
{
    PyObject *obj = (PyObject *)writer;
    PyLongObject *self = (PyLongObject*)obj;
    Py_ssize_t j = _PyLong_DigitCount(self);
    Py_ssize_t i = j;
    int sign = _PyLong_Sign(obj);

    assert(Py_REFCNT(obj) == 1);

    // Normalize and get singleton if possible
    while (i > 0 && _PyLong_GetDigits(self)[i-1] == 0) {
        --i;
    }
    if (i != j) {
        if (i == 0) {
            sign = 0;
        }
        _PyLong_SetSignAndDigitCount(self, sign, i);
    }
    if (i <= 1) {
        long val = sign * (long)(_PyLong_GetDigits(self)[0]);
        Py_DECREF(obj);
        return PyLong_FromLong(val);
    }

    return obj;
}
#endif


#if PY_VERSION_HEX < 0x030C00A3
#  define Py_T_SHORT      T_SHORT
#  define Py_T_INT        T_INT
#  define Py_T_LONG       T_LONG
#  define Py_T_FLOAT      T_FLOAT
#  define Py_T_DOUBLE     T_DOUBLE
#  define Py_T_STRING     T_STRING
#  define _Py_T_OBJECT    T_OBJECT
#  define Py_T_CHAR       T_CHAR
#  define Py_T_BYTE       T_BYTE
#  define Py_T_UBYTE      T_UBYTE
#  define Py_T_USHORT     T_USHORT
#  define Py_T_UINT       T_UINT
#  define Py_T_ULONG      T_ULONG
#  define Py_T_STRING_INPLACE  T_STRING_INPLACE
#  define Py_T_BOOL       T_BOOL
#  define Py_T_OBJECT_EX  T_OBJECT_EX
#  define Py_T_LONGLONG   T_LONGLONG
#  define Py_T_ULONGLONG  T_ULONGLONG
#  define Py_T_PYSSIZET   T_PYSSIZET

#  if PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION)
#    define _Py_T_NONE      T_NONE
#  endif

#  define Py_READONLY            READONLY
#  define Py_AUDIT_READ          READ_RESTRICTED
#  define _Py_WRITE_RESTRICTED   PY_WRITE_RESTRICTED
#endif


// gh-127350 added Py_fopen() and Py_fclose() to Python 3.14a4
#if PY_VERSION_HEX < 0x030E00A4
static inline FILE* Py_fopen(PyObject *path, const char *mode)
{
#if 0x030400A2 <= PY_VERSION_HEX && !defined(PYPY_VERSION)
    PyAPI_FUNC(FILE*) _Py_fopen_obj(PyObject *path, const char *mode);

    return _Py_fopen_obj(path, mode);
#else
    FILE *f;
    PyObject *bytes;
#if PY_VERSION_HEX >= 0x03000000
    if (!PyUnicode_FSConverter(path, &bytes)) {
        return NULL;
    }
#else
    if (!PyString_Check(path)) {
        PyErr_SetString(PyExc_TypeError, "except str");
        return NULL;
    }
    bytes = Py_NewRef(path);
#endif
    const char *path_bytes = PyBytes_AS_STRING(bytes);

    f = fopen(path_bytes, mode);
    Py_DECREF(bytes);

    if (f == NULL) {
        PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path);
        return NULL;
    }
    return f;
#endif
}

static inline int Py_fclose(FILE *file)
{
    return fclose(file);
}
#endif


#if 0x03090000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030E0000 && !defined(PYPY_VERSION)
static inline PyObject*
PyConfig_Get(const char *name)
{
    typedef enum {
        _PyConfig_MEMBER_INT,
        _PyConfig_MEMBER_UINT,
        _PyConfig_MEMBER_ULONG,
        _PyConfig_MEMBER_BOOL,
        _PyConfig_MEMBER_WSTR,
        _PyConfig_MEMBER_WSTR_OPT,
        _PyConfig_MEMBER_WSTR_LIST,
    } PyConfigMemberType;

    typedef struct {
        const char *name;
        size_t offset;
        PyConfigMemberType type;
        const char *sys_attr;
    } PyConfigSpec;

#define PYTHONCAPI_COMPAT_SPEC(MEMBER, TYPE, sys_attr) \
    {#MEMBER, offsetof(PyConfig, MEMBER), \
     _PyConfig_MEMBER_##TYPE, sys_attr}

    static const PyConfigSpec config_spec[] = {
        PYTHONCAPI_COMPAT_SPEC(argv, WSTR_LIST, "argv"),
        PYTHONCAPI_COMPAT_SPEC(base_exec_prefix, WSTR_OPT, "base_exec_prefix"),
        PYTHONCAPI_COMPAT_SPEC(base_executable, WSTR_OPT, "_base_executable"),
        PYTHONCAPI_COMPAT_SPEC(base_prefix, WSTR_OPT, "base_prefix"),
        PYTHONCAPI_COMPAT_SPEC(bytes_warning, UINT, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(exec_prefix, WSTR_OPT, "exec_prefix"),
        PYTHONCAPI_COMPAT_SPEC(executable, WSTR_OPT, "executable"),
        PYTHONCAPI_COMPAT_SPEC(inspect, BOOL, _Py_NULL),
#if 0x030C0000 <= PY_VERSION_HEX
        PYTHONCAPI_COMPAT_SPEC(int_max_str_digits, UINT, _Py_NULL),
#endif
        PYTHONCAPI_COMPAT_SPEC(interactive, BOOL, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(module_search_paths, WSTR_LIST, "path"),
        PYTHONCAPI_COMPAT_SPEC(optimization_level, UINT, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(parser_debug, BOOL, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(platlibdir, WSTR, "platlibdir"),
        PYTHONCAPI_COMPAT_SPEC(prefix, WSTR_OPT, "prefix"),
        PYTHONCAPI_COMPAT_SPEC(pycache_prefix, WSTR_OPT, "pycache_prefix"),
        PYTHONCAPI_COMPAT_SPEC(quiet, BOOL, _Py_NULL),
#if 0x030B0000 <= PY_VERSION_HEX
        PYTHONCAPI_COMPAT_SPEC(stdlib_dir, WSTR_OPT, "_stdlib_dir"),
#endif
        PYTHONCAPI_COMPAT_SPEC(use_environment, BOOL, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(verbose, UINT, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(warnoptions, WSTR_LIST, "warnoptions"),
        PYTHONCAPI_COMPAT_SPEC(write_bytecode, BOOL, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(xoptions, WSTR_LIST, "_xoptions"),
        PYTHONCAPI_COMPAT_SPEC(buffered_stdio, BOOL, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(check_hash_pycs_mode, WSTR, _Py_NULL),
#if 0x030B0000 <= PY_VERSION_HEX
        PYTHONCAPI_COMPAT_SPEC(code_debug_ranges, BOOL, _Py_NULL),
#endif
        PYTHONCAPI_COMPAT_SPEC(configure_c_stdio, BOOL, _Py_NULL),
#if 0x030D0000 <= PY_VERSION_HEX
        PYTHONCAPI_COMPAT_SPEC(cpu_count, INT, _Py_NULL),
#endif
        PYTHONCAPI_COMPAT_SPEC(dev_mode, BOOL, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(dump_refs, BOOL, _Py_NULL),
#if 0x030B0000 <= PY_VERSION_HEX
        PYTHONCAPI_COMPAT_SPEC(dump_refs_file, WSTR_OPT, _Py_NULL),
#endif
#ifdef Py_GIL_DISABLED
        PYTHONCAPI_COMPAT_SPEC(enable_gil, INT, _Py_NULL),
#endif
        PYTHONCAPI_COMPAT_SPEC(faulthandler, BOOL, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(filesystem_encoding, WSTR, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(filesystem_errors, WSTR, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(hash_seed, ULONG, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(home, WSTR_OPT, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(import_time, BOOL, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(install_signal_handlers, BOOL, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(isolated, BOOL, _Py_NULL),
#ifdef MS_WINDOWS
        PYTHONCAPI_COMPAT_SPEC(legacy_windows_stdio, BOOL, _Py_NULL),
#endif
        PYTHONCAPI_COMPAT_SPEC(malloc_stats, BOOL, _Py_NULL),
#if 0x030A0000 <= PY_VERSION_HEX
        PYTHONCAPI_COMPAT_SPEC(orig_argv, WSTR_LIST, "orig_argv"),
#endif
        PYTHONCAPI_COMPAT_SPEC(parse_argv, BOOL, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(pathconfig_warnings, BOOL, _Py_NULL),
#if 0x030C0000 <= PY_VERSION_HEX
        PYTHONCAPI_COMPAT_SPEC(perf_profiling, UINT, _Py_NULL),
#endif
        PYTHONCAPI_COMPAT_SPEC(program_name, WSTR, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(run_command, WSTR_OPT, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(run_filename, WSTR_OPT, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(run_module, WSTR_OPT, _Py_NULL),
#if 0x030B0000 <= PY_VERSION_HEX
        PYTHONCAPI_COMPAT_SPEC(safe_path, BOOL, _Py_NULL),
#endif
        PYTHONCAPI_COMPAT_SPEC(show_ref_count, BOOL, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(site_import, BOOL, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(skip_source_first_line, BOOL, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(stdio_encoding, WSTR, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(stdio_errors, WSTR, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(tracemalloc, UINT, _Py_NULL),
#if 0x030B0000 <= PY_VERSION_HEX
        PYTHONCAPI_COMPAT_SPEC(use_frozen_modules, BOOL, _Py_NULL),
#endif
        PYTHONCAPI_COMPAT_SPEC(use_hash_seed, BOOL, _Py_NULL),
        PYTHONCAPI_COMPAT_SPEC(user_site_directory, BOOL, _Py_NULL),
#if 0x030A0000 <= PY_VERSION_HEX
        PYTHONCAPI_COMPAT_SPEC(warn_default_encoding, BOOL, _Py_NULL),
#endif
    };

#undef PYTHONCAPI_COMPAT_SPEC

    const PyConfigSpec *spec;
    int found = 0;
    for (size_t i=0; i < sizeof(config_spec) / sizeof(config_spec[0]); i++) {
        spec = &config_spec[i];
        if (strcmp(spec->name, name) == 0) {
            found = 1;
            break;
        }
    }
    if (found) {
        if (spec->sys_attr != NULL) {
            PyObject *value = PySys_GetObject(spec->sys_attr);
            if (value == NULL) {
                PyErr_Format(PyExc_RuntimeError, "lost sys.%s", spec->sys_attr);
                return NULL;
            }
            return Py_NewRef(value);
        }

        PyAPI_FUNC(const PyConfig*) _Py_GetConfig(void);

        const PyConfig *config = _Py_GetConfig();
        void *member = (char *)config + spec->offset;
        switch (spec->type) {
        case _PyConfig_MEMBER_INT:
        case _PyConfig_MEMBER_UINT:
        {
            int value = *(int *)member;
            return PyLong_FromLong(value);
        }
        case _PyConfig_MEMBER_BOOL:
        {
            int value = *(int *)member;
            return PyBool_FromLong(value != 0);
        }
        case _PyConfig_MEMBER_ULONG:
        {
            unsigned long value = *(unsigned long *)member;
            return PyLong_FromUnsignedLong(value);
        }
        case _PyConfig_MEMBER_WSTR:
        case _PyConfig_MEMBER_WSTR_OPT:
        {
            wchar_t *wstr = *(wchar_t **)member;
            if (wstr != NULL) {
                return PyUnicode_FromWideChar(wstr, -1);
            }
            else {
                return Py_NewRef(Py_None);
            }
        }
        case _PyConfig_MEMBER_WSTR_LIST:
        {
            const PyWideStringList *list = (const PyWideStringList *)member;
            PyObject *tuple = PyTuple_New(list->length);
            if (tuple == NULL) {
                return NULL;
            }

            for (Py_ssize_t i = 0; i < list->length; i++) {
                PyObject *item = PyUnicode_FromWideChar(list->items[i], -1);
                if (item == NULL) {
                    Py_DECREF(tuple);
                    return NULL;
                }
                PyTuple_SET_ITEM(tuple, i, item);
            }
            return tuple;
        }
        default:
            Py_UNREACHABLE();
        }
    }

    PyErr_Format(PyExc_ValueError, "unknown config option name: %s", name);
    return NULL;
}

static inline int
PyConfig_GetInt(const char *name, int *value)
{
    PyObject *obj = PyConfig_Get(name);
    if (obj == NULL) {
        return -1;
    }

    if (!PyLong_Check(obj)) {
        Py_DECREF(obj);
        PyErr_Format(PyExc_TypeError, "config option %s is not an int", name);
        return -1;
    }

    int as_int = PyLong_AsInt(obj);
    Py_DECREF(obj);
    if (as_int == -1 && PyErr_Occurred()) {
        PyErr_Format(PyExc_OverflowError,
                     "config option %s value does not fit into a C int", name);
        return -1;
    }

    *value = as_int;
    return 0;
}
#endif  // PY_VERSION_HEX > 0x03090000 && !defined(PYPY_VERSION)

// gh-133144 added PyUnstable_Object_IsUniquelyReferenced() to Python 3.14.0b1.
// Adapted from  _PyObject_IsUniquelyReferenced() implementation.
#if PY_VERSION_HEX < 0x030E00B0
static inline int PyUnstable_Object_IsUniquelyReferenced(PyObject *obj)
{
#if !defined(Py_GIL_DISABLED)
    return Py_REFCNT(obj) == 1;
#else
    // NOTE: the entire ob_ref_shared field must be zero, including flags, to
    // ensure that other threads cannot concurrently create new references to
    // this object.
    return (_Py_IsOwnedByCurrentThread(obj) &&
            _Py_atomic_load_uint32_relaxed(&obj->ob_ref_local) == 1 &&
            _Py_atomic_load_ssize_relaxed(&obj->ob_ref_shared) == 0);
#endif
}
#endif


#if PY_VERSION_HEX < 0x030F0000
static inline PyObject*
PySys_GetAttrString(const char *name)
{
#if PY_VERSION_HEX >= 0x03000000
    PyObject *value = Py_XNewRef(PySys_GetObject(name));
#else
    PyObject *value = Py_XNewRef(PySys_GetObject((char*)name));
#endif
    if (value != NULL) {
        return value;
    }
    if (!PyErr_Occurred()) {
        PyErr_Format(PyExc_RuntimeError, "lost sys.%s", name);
    }
    return NULL;
}

static inline PyObject*
PySys_GetAttr(PyObject *name)
{
#if PY_VERSION_HEX >= 0x03000000
    const char *name_str = PyUnicode_AsUTF8(name);
#else
    const char *name_str = PyString_AsString(name);
#endif
    if (name_str == NULL) {
        return NULL;
    }

    return PySys_GetAttrString(name_str);
}

static inline int
PySys_GetOptionalAttrString(const char *name, PyObject **value)
{
#if PY_VERSION_HEX >= 0x03000000
    *value = Py_XNewRef(PySys_GetObject(name));
#else
    *value = Py_XNewRef(PySys_GetObject((char*)name));
#endif
    if (*value != NULL) {
        return 1;
    }
    return 0;
}

static inline int
PySys_GetOptionalAttr(PyObject *name, PyObject **value)
{
#if PY_VERSION_HEX >= 0x03000000
    const char *name_str = PyUnicode_AsUTF8(name);
#else
    const char *name_str = PyString_AsString(name);
#endif
    if (name_str == NULL) {
        *value = NULL;
        return -1;
    }

    return PySys_GetOptionalAttrString(name_str, value);
}
#endif  // PY_VERSION_HEX < 0x030F00A1


#ifdef __cplusplus
}
#endif
#endif  // PYTHONCAPI_COMPAT


================================================
FILE: src/watchdog/__init__.py
================================================


================================================
FILE: src/watchdog/events.py
================================================
""":module: watchdog.events
:synopsis: File system events and event handlers.
:author: yesudeep@google.com (Yesudeep Mangalapilly)
:author: Mickaël Schoentgen <contact@tiger-222.fr>

Event Classes
-------------
.. autoclass:: FileSystemEvent
   :members:
   :show-inheritance:
   :inherited-members:

.. autoclass:: FileSystemMovedEvent
   :members:
   :show-inheritance:

.. autoclass:: FileMovedEvent
   :members:
   :show-inheritance:

.. autoclass:: DirMovedEvent
   :members:
   :show-inheritance:

.. autoclass:: FileModifiedEvent
   :members:
   :show-inheritance:

.. autoclass:: DirModifiedEvent
   :members:
   :show-inheritance:

.. autoclass:: FileCreatedEvent
   :members:
   :show-inheritance:

.. autoclass:: FileClosedEvent
   :members:
   :show-inheritance:

.. autoclass:: FileClosedNoWriteEvent
   :members:
   :show-inheritance:

.. autoclass:: FileOpenedEvent
   :members:
   :show-inheritance:

.. autoclass:: DirCreatedEvent
   :members:
   :show-inheritance:

.. autoclass:: FileDeletedEvent
   :members:
   :show-inheritance:

.. autoclass:: DirDeletedEvent
   :members:
   :show-inheritance:


Event Handler Classes
---------------------
.. autoclass:: FileSystemEventHandler
   :members:
   :show-inheritance:

.. autoclass:: PatternMatchingEventHandler
   :members:
   :show-inheritance:

.. autoclass:: RegexMatchingEventHandler
   :members:
   :show-inheritance:

.. autoclass:: LoggingEventHandler
   :members:
   :show-inheritance:

"""

from __future__ import annotations

import logging
import os.path
import re
from dataclasses import dataclass, field
from typing import TYPE_CHECKING

from watchdog.utils.patterns import match_any_paths

if TYPE_CHECKING:
    from collections.abc import Generator

EVENT_TYPE_MOVED = "moved"
EVENT_TYPE_DELETED = "deleted"
EVENT_TYPE_CREATED = "created"
EVENT_TYPE_MODIFIED = "modified"
EVENT_TYPE_CLOSED = "closed"
EVENT_TYPE_CLOSED_NO_WRITE = "closed_no_write"
EVENT_TYPE_OPENED = "opened"


@dataclass(unsafe_hash=True)
class FileSystemEvent:
    """Immutable type that represents a file system event that is triggered
    when a change occurs on the monitored file system.

    All FileSystemEvent objects are required to be immutable and hence
    can be used as keys in dictionaries or be added to sets.
    """

    src_path: bytes | str
    dest_path: bytes | str = ""
    event_type: str = field(default="", init=False)
    is_directory: bool = field(default=False, init=False)

    """
    True if event was synthesized; False otherwise.
    These are events that weren't actually broadcast by the OS, but
    are presumed to have happened based on other, actual events.
    """
    is_synthetic: bool = field(default=False)


class FileSystemMovedEvent(FileSystemEvent):
    """File system event representing any kind of file system movement."""

    event_type = EVENT_TYPE_MOVED


# File events.


class FileDeletedEvent(FileSystemEvent):
    """File system event representing file deletion on the file system."""

    event_type = EVENT_TYPE_DELETED


class FileModifiedEvent(FileSystemEvent):
    """File system event representing file modification on the file system."""

    event_type = EVENT_TYPE_MODIFIED


class FileCreatedEvent(FileSystemEvent):
    """File system event representing file creation on the file system."""

    event_type = EVENT_TYPE_CREATED


class FileMovedEvent(FileSystemMovedEvent):
    """File system event representing file movement on the file system."""


class FileClosedEvent(FileSystemEvent):
    """File system event representing file close on the file system."""

    event_type = EVENT_TYPE_CLOSED


class FileClosedNoWriteEvent(FileSystemEvent):
    """File system event representing an unmodified file close on the file system."""

    event_type = EVENT_TYPE_CLOSED_NO_WRITE


class FileOpenedEvent(FileSystemEvent):
    """File system event representing file close on the file system."""

    event_type = EVENT_TYP
Download .txt
gitextract_aij9dq2r/

├── .cirrus.yml
├── .gitattributes
├── .github/
│   ├── FUNDING.yml
│   ├── dependabot.yml
│   └── workflows/
│       ├── build-and-publish.yml
│       └── tests.yml
├── .gitignore
├── .well-known/
│   └── funding-manifest-urls
├── AUTHORS
├── COPYING
├── LICENSE
├── MANIFEST.in
├── README.rst
├── THIRD_PARTY_LICENSES.md
├── changelog.rst
├── docs/
│   ├── Makefile
│   ├── eclipse_cdt_style.xml
│   ├── make.bat
│   └── source/
│       ├── api.rst
│       ├── conf.py
│       ├── examples/
│       │   ├── __init__.py
│       │   ├── logger.py
│       │   ├── patterns.py
│       │   ├── simple.py
│       │   ├── tricks.json
│       │   └── tricks.yaml
│       ├── global.rst.inc
│       ├── hacking.rst
│       ├── index.rst
│       ├── installation.rst
│       └── quickstart.rst
├── pyproject.toml
├── requirements-tests.txt
├── setup.cfg
├── setup.py
├── src/
│   ├── pythoncapi_compat.h
│   ├── watchdog/
│   │   ├── __init__.py
│   │   ├── events.py
│   │   ├── observers/
│   │   │   ├── __init__.py
│   │   │   ├── api.py
│   │   │   ├── fsevents.py
│   │   │   ├── fsevents2.py
│   │   │   ├── inotify.py
│   │   │   ├── inotify_c.py
│   │   │   ├── inotify_move_event_grouper.py
│   │   │   ├── kqueue.py
│   │   │   ├── polling.py
│   │   │   ├── read_directory_changes.py
│   │   │   └── winapi.py
│   │   ├── py.typed
│   │   ├── tricks/
│   │   │   └── __init__.py
│   │   ├── utils/
│   │   │   ├── __init__.py
│   │   │   ├── backwards_compat.py
│   │   │   ├── bricks.py
│   │   │   ├── delayed_queue.py
│   │   │   ├── dirsnapshot.py
│   │   │   ├── echo.py
│   │   │   ├── event_debouncer.py
│   │   │   ├── patterns.py
│   │   │   ├── platform.py
│   │   │   └── process_watcher.py
│   │   ├── version.py
│   │   └── watchmedo.py
│   └── watchdog_fsevents.c
├── tests/
│   ├── __init__.py
│   ├── conftest.py
│   ├── isolated/
│   │   ├── __init__.py
│   │   ├── eventlet_observer_stops.py
│   │   └── eventlet_skip_repeat_queue.py
│   ├── shell.py
│   ├── test_0_watchmedo.py
│   ├── test_delayed_queue.py
│   ├── test_echo.py
│   ├── test_emitter.py
│   ├── test_events.py
│   ├── test_fsevents.py
│   ├── test_inotify_c.py
│   ├── test_inotify_watch_group.py
│   ├── test_isolated.py
│   ├── test_logging_event_handler.py
│   ├── test_observer.py
│   ├── test_observers_api.py
│   ├── test_observers_polling.py
│   ├── test_observers_winapi.py
│   ├── test_pattern_matching_event_handler.py
│   ├── test_patterns.py
│   ├── test_regex_matching_event_handler.py
│   ├── test_skip_repeats_queue.py
│   ├── test_snapshot_diff.py
│   └── utils.py
├── tools/
│   └── watchmedo.bat
└── tox.ini
Download .txt
SYMBOL INDEX (811 symbols across 51 files)

FILE: docs/source/examples/patterns.py
  class MyEventHandler (line 11) | class MyEventHandler(PatternMatchingEventHandler):
    method on_any_event (line 12) | def on_any_event(self, event: FileSystemEvent) -> None:

FILE: docs/source/examples/simple.py
  class MyEventHandler (line 13) | class MyEventHandler(events.FileSystemEventHandler):
    method catch_all_handler (line 14) | def catch_all_handler(self, event: events.FileSystemEvent) -> None:
    method on_moved (line 17) | def on_moved(self, event: events.DirMovedEvent | events.FileMovedEvent...
    method on_created (line 20) | def on_created(self, event: events.DirCreatedEvent | events.FileCreate...
    method on_deleted (line 23) | def on_deleted(self, event: events.DirDeletedEvent | events.FileDelete...
    method on_modified (line 26) | def on_modified(self, event: events.DirModifiedEvent | events.FileModi...
    method on_closed (line 29) | def on_closed(self, event: events.FileClosedEvent) -> None:
    method on_closed_no_write (line 32) | def on_closed_no_write(self, event: events.FileClosedNoWriteEvent) -> ...
    method on_opened (line 35) | def on_opened(self, event: events.FileOpenedEvent) -> None:

FILE: src/pythoncapi_compat.h
  function PyObject (line 64) | static inline PyObject* _Py_NewRef(PyObject *obj)
  function PyObject (line 75) | static inline PyObject* _Py_XNewRef(PyObject *obj)
  function _Py_SET_REFCNT (line 86) | static inline void _Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt)
  function _Py_SET_TYPE (line 133) | static inline void _Py_SET_TYPE(PyObject *ob, PyTypeObject *type)
  function _Py_SET_SIZE (line 143) | static inline void _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size)
  function PyCodeObject (line 153) | static inline PyCodeObject* PyFrame_GetCode(PyFrameObject *frame)
  function PyCodeObject (line 161) | static inline PyCodeObject* _PyFrame_GetCodeBorrow(PyFrameObject *frame)
  function PyFrameObject (line 171) | static inline PyFrameObject* PyFrame_GetBack(PyFrameObject *frame)
  function PyFrameObject (line 179) | static inline PyFrameObject* _PyFrame_GetBackBorrow(PyFrameObject *frame)
  function PyObject (line 190) | static inline PyObject* PyFrame_GetLocals(PyFrameObject *frame)
  function PyObject (line 206) | static inline PyObject* PyFrame_GetGlobals(PyFrameObject *frame)
  function PyObject (line 215) | static inline PyObject* PyFrame_GetBuiltins(PyFrameObject *frame)
  function PyFrame_GetLasti (line 224) | static inline int PyFrame_GetLasti(PyFrameObject *frame)
  function PyObject (line 243) | static inline PyObject* PyFrame_GetVar(PyFrameObject *frame, PyObject *n...
  function PyObject (line 276) | static inline PyObject*
  function PyInterpreterState (line 297) | static inline PyInterpreterState *
  function PyFrameObject (line 308) | static inline PyFrameObject* PyThreadState_GetFrame(PyThreadState *tstate)
  function PyFrameObject (line 316) | static inline PyFrameObject*
  function PyInterpreterState (line 328) | static inline PyInterpreterState* PyInterpreterState_Get(void)
  function PyThreadState_GetID (line 348) | static inline uint64_t PyThreadState_GetID(PyThreadState *tstate)
  function PyThreadState_EnterTracing (line 357) | static inline void PyThreadState_EnterTracing(PyThreadState *tstate)
  function PyThreadState_LeaveTracing (line 370) | static inline void PyThreadState_LeaveTracing(PyThreadState *tstate)
  function PyObject (line 387) | static inline PyObject* PyObject_CallNoArgs(PyObject *func)
  function PyObject (line 398) | static inline PyObject* PyObject_CallOneArg(PyObject *func, PyObject *arg)
  function PyModule_AddObjectRef (line 407) | static inline int
  function PyModule_AddType (line 432) | static inline int PyModule_AddType(PyObject *module, PyTypeObject *type)
  function PyObject_GC_IsTracked (line 456) | static inline int PyObject_GC_IsTracked(PyObject* obj)
  function PyObject_GC_IsFinalized (line 465) | static inline int PyObject_GC_IsFinalized(PyObject *obj)
  function _Py_IS_TYPE (line 475) | static inline int _Py_IS_TYPE(PyObject *ob, PyTypeObject *type) {
  function PyFloat_Pack2 (line 487) | static inline int PyFloat_Pack2(double x, char *p, int le)
  function PyFloat_Unpack2 (line 490) | static inline double PyFloat_Unpack2(const char *p, int le)
  function PyFloat_Pack4 (line 501) | static inline int PyFloat_Pack4(double x, char *p, int le)
  function PyFloat_Pack8 (line 504) | static inline int PyFloat_Pack8(double x, char *p, int le)
  function PyFloat_Unpack4 (line 507) | static inline double PyFloat_Unpack4(const char *p, int le)
  function PyFloat_Unpack8 (line 510) | static inline double PyFloat_Unpack8(const char *p, int le)
  function PyObject (line 517) | static inline PyObject* PyCode_GetCode(PyCodeObject *code)
  function PyObject (line 526) | static inline PyObject* PyCode_GetVarnames(PyCodeObject *code)
  function PyObject (line 534) | static inline PyObject* PyCode_GetFreevars(PyCodeObject *code)
  function PyObject (line 542) | static inline PyObject* PyCode_GetCellvars(PyCodeObject *code)
  function PyObject (line 561) | static inline PyObject* PyImport_AddModuleRef(const char *name)
  function PyWeakref_GetRef (line 570) | static inline int PyWeakref_GetRef(PyObject *ref, PyObject **pobj)
  function Py_ssize_t (line 601) | static inline Py_ssize_t PyVectorcall_NARGS(size_t n)
  function PyObject (line 610) | static inline PyObject*
  function PyObject_GetOptionalAttr (line 686) | static inline int
  function PyObject_GetOptionalAttrString (line 708) | static inline int
  function PyMapping_GetOptionalItem (line 732) | static inline int
  function PyMapping_GetOptionalItemString (line 746) | static inline int
  function PyMapping_HasKeyWithError (line 769) | static inline int
  function PyMapping_HasKeyStringWithError (line 778) | static inline int
  function PyObject_HasAttrWithError (line 792) | static inline int
  function PyObject_HasAttrStringWithError (line 801) | static inline int
  function PyDict_GetItemRef (line 815) | static inline int
  function PyDict_GetItemStringRef (line 835) | static inline int
  function PyModule_Add (line 857) | static inline int
  function Py_IsFinalizing (line 872) | static inline int Py_IsFinalizing(void)
  function PyDict_ContainsString (line 886) | static inline int PyDict_ContainsString(PyObject *op, const char *key)
  function PyLong_AsInt (line 901) | static inline int PyLong_AsInt(PyObject *obj)
  function PyObject_VisitManagedDict (line 923) | static inline int
  function PyObject_ClearManagedDict (line 934) | static inline void
  function PyThreadState (line 948) | static inline PyThreadState*
  function PyUnicode_EqualToUTF8AndSize (line 958) | static inline int
  function PyUnicode_EqualToUTF8 (line 1021) | static inline int
  function PyList_Extend (line 1031) | static inline int
  function PyList_Clear (line 1037) | static inline int
  function PyDict_Pop (line 1046) | static inline int
  function PyDict_PopString (line 1088) | static inline int
  type Py_ssize_t (line 1108) | typedef Py_ssize_t Py_hash_t;
  function Py_hash_t (line 1114) | static inline Py_hash_t Py_HashPointer(const void *ptr)
  type _PyTime_t (line 1128) | typedef _PyTime_t PyTime_t;
  function PyTime_AsSecondsDouble (line 1132) | static inline double PyTime_AsSecondsDouble(PyTime_t t)
  function PyTime_Monotonic (line 1135) | static inline int PyTime_Monotonic(PyTime_t *result)
  function PyTime_Time (line 1138) | static inline int PyTime_Time(PyTime_t *result)
  function PyTime_PerfCounter (line 1141) | static inline int PyTime_PerfCounter(PyTime_t *result)
  function PyObject (line 1240) | static inline PyObject* Py_GetConstant(unsigned int constant_id)
  function PyObject (line 1293) | static inline PyObject* Py_GetConstantBorrowed(unsigned int constant_id)
  function PyObject (line 1304) | static inline PyObject *
  function PyDict_SetDefaultRef (line 1316) | static inline int
  type PyUnicodeWriter (line 1362) | typedef struct PyUnicodeWriter PyUnicodeWriter;
  function PyUnicodeWriter_Discard (line 1364) | static inline void PyUnicodeWriter_Discard(PyUnicodeWriter *writer)
  function PyUnicodeWriter (line 1370) | static inline PyUnicodeWriter* PyUnicodeWriter_Create(Py_ssize_t length)
  function PyObject (line 1395) | static inline PyObject* PyUnicodeWriter_Finish(PyUnicodeWriter *writer)
  function PyUnicodeWriter_WriteChar (line 1403) | static inline int
  function PyUnicodeWriter_WriteStr (line 1415) | static inline int
  function PyUnicodeWriter_WriteRepr (line 1428) | static inline int
  function PyUnicodeWriter_WriteUTF8 (line 1441) | static inline int
  function PyUnicodeWriter_WriteASCII (line 1459) | static inline int
  function PyUnicodeWriter_WriteWideChar (line 1471) | static inline int
  function PyUnicodeWriter_WriteSubstring (line 1489) | static inline int
  function PyUnicodeWriter_Format (line 1511) | static inline int
  function PyLong_GetSign (line 1530) | static inline int PyLong_GetSign(PyObject *obj, int *sign)
  function PyLong_IsPositive (line 1544) | static inline int PyLong_IsPositive(PyObject *obj)
  function PyLong_IsNegative (line 1553) | static inline int PyLong_IsNegative(PyObject *obj)
  function PyLong_IsZero (line 1562) | static inline int PyLong_IsZero(PyObject *obj)
  function PyUnicode_Equal (line 1575) | static inline int PyUnicode_Equal(PyObject *str1, PyObject *str2)
  function PyObject (line 1605) | static inline PyObject* PyBytes_Join(PyObject *sep, PyObject *iterable)
  function Py_hash_t (line 1613) | static inline Py_hash_t Py_HashBuffer(const void *ptr, Py_ssize_t len)
  function PyIter_NextItem (line 1634) | static inline int PyIter_NextItem(PyObject *iter, PyObject **item)
  function PyObject (line 1665) | static inline PyObject* PyLong_FromInt32(int32_t value)
  function PyObject (line 1671) | static inline PyObject* PyLong_FromInt64(int64_t value)
  function PyObject (line 1677) | static inline PyObject* PyLong_FromUInt32(uint32_t value)
  function PyObject (line 1683) | static inline PyObject* PyLong_FromUInt64(uint64_t value)
  function PyLong_AsInt32 (line 1689) | static inline int PyLong_AsInt32(PyObject *obj, int32_t *pvalue)
  function PyLong_AsInt64 (line 1700) | static inline int PyLong_AsInt64(PyObject *obj, int64_t *pvalue)
  function PyLong_AsUInt32 (line 1711) | static inline int PyLong_AsUInt32(PyObject *obj, uint32_t *pvalue)
  function PyLong_AsUInt64 (line 1729) | static inline int PyLong_AsUInt64(PyObject *obj, uint64_t *pvalue)
  function _PyLong_SetSignAndDigitCount (line 1745) | static inline void
  function Py_ssize_t (line 1757) | static inline Py_ssize_t
  function digit (line 1767) | static inline digit*
  type PyLongLayout (line 1777) | typedef struct PyLongLayout {
  type PyLongExport (line 1784) | typedef struct PyLongExport {
  type PyLongWriter (line 1792) | typedef struct PyLongWriter PyLongWriter;
  function PyLongLayout (line 1794) | static inline const PyLongLayout*
  function PyLong_Export (line 1807) | static inline int
  function PyLong_FreeExport (line 1850) | static inline void
  function PyLongWriter (line 1861) | static inline PyLongWriter*
  function PyLongWriter_Discard (line 1880) | static inline void
  function PyObject (line 1889) | static inline PyObject*
  function FILE (line 1954) | static inline FILE* Py_fopen(PyObject *path, const char *mode)
  function Py_fclose (line 1987) | static inline int Py_fclose(FILE *file)
  function PyObject (line 1995) | static inline PyObject*
  function PyConfig_GetInt (line 2187) | static inline int
  function PyUnstable_Object_IsUniquelyReferenced (line 2217) | static inline int PyUnstable_Object_IsUniquelyReferenced(PyObject *obj)
  function PyObject (line 2234) | static inline PyObject*
  function PyObject (line 2251) | static inline PyObject*
  function PySys_GetOptionalAttrString (line 2266) | static inline int
  function PySys_GetOptionalAttr (line 2280) | static inline int

FILE: src/watchdog/events.py
  class FileSystemEvent (line 105) | class FileSystemEvent:
  class FileSystemMovedEvent (line 126) | class FileSystemMovedEvent(FileSystemEvent):
  class FileDeletedEvent (line 135) | class FileDeletedEvent(FileSystemEvent):
  class FileModifiedEvent (line 141) | class FileModifiedEvent(FileSystemEvent):
  class FileCreatedEvent (line 147) | class FileCreatedEvent(FileSystemEvent):
  class FileMovedEvent (line 153) | class FileMovedEvent(FileSystemMovedEvent):
  class FileClosedEvent (line 157) | class FileClosedEvent(FileSystemEvent):
  class FileClosedNoWriteEvent (line 163) | class FileClosedNoWriteEvent(FileSystemEvent):
  class FileOpenedEvent (line 169) | class FileOpenedEvent(FileSystemEvent):
  class DirDeletedEvent (line 178) | class DirDeletedEvent(FileSystemEvent):
  class DirModifiedEvent (line 185) | class DirModifiedEvent(FileSystemEvent):
  class DirCreatedEvent (line 192) | class DirCreatedEvent(FileSystemEvent):
  class DirMovedEvent (line 199) | class DirMovedEvent(FileSystemMovedEvent):
  class FileSystemEventHandler (line 205) | class FileSystemEventHandler:
    method dispatch (line 208) | def dispatch(self, event: FileSystemEvent) -> None:
    method on_any_event (line 219) | def on_any_event(self, event: FileSystemEvent) -> None:
    method on_moved (line 228) | def on_moved(self, event: DirMovedEvent | FileMovedEvent) -> None:
    method on_created (line 237) | def on_created(self, event: DirCreatedEvent | FileCreatedEvent) -> None:
    method on_deleted (line 246) | def on_deleted(self, event: DirDeletedEvent | FileDeletedEvent) -> None:
    method on_modified (line 255) | def on_modified(self, event: DirModifiedEvent | FileModifiedEvent) -> ...
    method on_closed (line 264) | def on_closed(self, event: FileClosedEvent) -> None:
    method on_closed_no_write (line 273) | def on_closed_no_write(self, event: FileClosedNoWriteEvent) -> None:
    method on_opened (line 282) | def on_opened(self, event: FileOpenedEvent) -> None:
  class PatternMatchingEventHandler (line 292) | class PatternMatchingEventHandler(FileSystemEventHandler):
    method __init__ (line 298) | def __init__(
    method patterns (line 314) | def patterns(self) -> list[str] | None:
    method ignore_patterns (line 321) | def ignore_patterns(self) -> list[str] | None:
    method ignore_directories (line 328) | def ignore_directories(self) -> bool:
    method case_sensitive (line 335) | def case_sensitive(self) -> bool:
    method dispatch (line 342) | def dispatch(self, event: FileSystemEvent) -> None:
  class RegexMatchingEventHandler (line 368) | class RegexMatchingEventHandler(FileSystemEventHandler):
    method __init__ (line 373) | def __init__(
    method regexes (line 399) | def regexes(self) -> list[re.Pattern[str]]:
    method ignore_regexes (line 406) | def ignore_regexes(self) -> list[re.Pattern[str]]:
    method ignore_directories (line 413) | def ignore_directories(self) -> bool:
    method case_sensitive (line 420) | def case_sensitive(self) -> bool:
    method dispatch (line 427) | def dispatch(self, event: FileSystemEvent) -> None:
  class LoggingEventHandler (line 451) | class LoggingEventHandler(FileSystemEventHandler):
    method __init__ (line 454) | def __init__(self, *, logger: logging.Logger | None = None) -> None:
    method on_moved (line 458) | def on_moved(self, event: DirMovedEvent | FileMovedEvent) -> None:
    method on_created (line 464) | def on_created(self, event: DirCreatedEvent | FileCreatedEvent) -> None:
    method on_deleted (line 470) | def on_deleted(self, event: DirDeletedEvent | FileDeletedEvent) -> None:
    method on_modified (line 476) | def on_modified(self, event: DirModifiedEvent | FileModifiedEvent) -> ...
    method on_closed (line 482) | def on_closed(self, event: FileClosedEvent) -> None:
    method on_closed_no_write (line 487) | def on_closed_no_write(self, event: FileClosedNoWriteEvent) -> None:
    method on_opened (line 492) | def on_opened(self, event: FileOpenedEvent) -> None:
  function generate_sub_moved_events (line 498) | def generate_sub_moved_events(
  function generate_sub_created_events (line 525) | def generate_sub_created_events(src_dir_path: bytes | str) -> Generator[...

FILE: src/watchdog/observers/__init__.py
  class ObserverType (line 49) | class ObserverType(Protocol):
    method __call__ (line 50) | def __call__(self, *, timeout: float = ...) -> BaseObserver: ...
  function _get_observer_cls (line 53) | def _get_observer_cls() -> ObserverType:

FILE: src/watchdog/observers/api.py
  class EventQueue (line 24) | class EventQueue(SkipRepeatsQueue):
  class ObservedWatch (line 33) | class ObservedWatch:
    method __init__ (line 44) | def __init__(
    method path (line 58) | def path(self) -> str:
    method is_recursive (line 63) | def is_recursive(self) -> bool:
    method follow_symlink (line 68) | def follow_symlink(self) -> bool:
    method event_filter (line 73) | def event_filter(self) -> frozenset[type[FileSystemEvent]] | None:
    method key (line 78) | def key(self) -> tuple[str, bool, frozenset[type[FileSystemEvent]] | N...
    method __eq__ (line 81) | def __eq__(self, watch: object) -> bool:
    method __ne__ (line 86) | def __ne__(self, watch: object) -> bool:
    method __hash__ (line 91) | def __hash__(self) -> int:
    method __repr__ (line 94) | def __repr__(self) -> str:
  class EventEmitter (line 104) | class EventEmitter(BaseThread):
    method __init__ (line 126) | def __init__(
    method timeout (line 141) | def timeout(self) -> float:
    method watch (line 146) | def watch(self) -> ObservedWatch:
    method queue_event (line 150) | def queue_event(self, event: FileSystemEvent) -> None:
    method queue_events (line 162) | def queue_events(self, timeout: float) -> None:
    method run (line 173) | def run(self) -> None:
  class EventDispatcher (line 178) | class EventDispatcher(BaseThread):
    method __init__ (line 192) | def __init__(self, *, timeout: float = DEFAULT_OBSERVER_TIMEOUT) -> None:
    method timeout (line 198) | def timeout(self) -> float:
    method stop (line 202) | def stop(self) -> None:
    method event_queue (line 208) | def event_queue(self) -> EventQueue:
    method dispatch_events (line 215) | def dispatch_events(self, event_queue: EventQueue) -> None:
    method run (line 227) | def run(self) -> None:
  class BaseObserver (line 235) | class BaseObserver(EventDispatcher):
    method __init__ (line 238) | def __init__(self, emitter_class: type[EventEmitter], *, timeout: floa...
    method _add_emitter (line 247) | def _add_emitter(self, emitter: EventEmitter) -> None:
    method _remove_emitter (line 251) | def _remove_emitter(self, emitter: EventEmitter) -> None:
    method _clear_emitters (line 258) | def _clear_emitters(self) -> None:
    method _add_handler_for_watch (line 267) | def _add_handler_for_watch(self, event_handler: FileSystemEventHandler...
    method _remove_handlers_for_watch (line 270) | def _remove_handlers_for_watch(self, watch: ObservedWatch) -> None:
    method emitters (line 274) | def emitters(self) -> set[EventEmitter]:
    method start (line 278) | def start(self) -> None:
    method __enter__ (line 287) | def __enter__(self) -> Self:
    method __exit__ (line 293) | def __exit__(
    method schedule (line 304) | def schedule(
    method add_handler_for_watch (line 352) | def add_handler_for_watch(self, event_handler: FileSystemEventHandler,...
    method remove_handler_for_watch (line 370) | def remove_handler_for_watch(self, event_handler: FileSystemEventHandl...
    method unschedule (line 388) | def unschedule(self, watch: ObservedWatch) -> None:
    method unschedule_all (line 403) | def unschedule_all(self) -> None:
    method on_thread_stop (line 410) | def on_thread_stop(self) -> None:
    method dispatch_events (line 413) | def dispatch_events(self, event_queue: EventQueue) -> None:

FILE: src/watchdog/observers/fsevents.py
  class FSEventsEmitter (line 44) | class FSEventsEmitter(EventEmitter):
    method __init__ (line 67) | def __init__(
    method on_thread_stop (line 84) | def on_thread_stop(self) -> None:
    method queue_event (line 88) | def queue_event(self, event: FileSystemEvent) -> None:
    method _is_recursive_event (line 97) | def _is_recursive_event(self, event: FileSystemEvent) -> bool:
    method _queue_created_event (line 111) | def _queue_created_event(self, event: FileSystemEvent, src_path: bytes...
    method _queue_deleted_event (line 116) | def _queue_deleted_event(self, event: FileSystemEvent, src_path: bytes...
    method _queue_modified_event (line 121) | def _queue_modified_event(self, event: FileSystemEvent, src_path: byte...
    method _queue_renamed_event (line 125) | def _queue_renamed_event(
    method _is_historic_created_event (line 139) | def _is_historic_created_event(self, event: _fsevents.NativeEvent) -> ...
    method _is_meta_mod (line 157) | def _is_meta_mod(event: _fsevents.NativeEvent) -> bool:
    method queue_events (line 161) | def queue_events(self, timeout: float, events: list[_fsevents.NativeEv...
    method events_callback (line 290) | def events_callback(self, paths: list[bytes], inodes: list[int], flags...
    method run (line 305) | def run(self) -> None:
    method on_thread_start (line 314) | def on_thread_start(self) -> None:
    method _encode_path (line 319) | def _encode_path(self, path: bytes | str) -> bytes | str:
  class FSEventsObserver (line 324) | class FSEventsObserver(BaseObserver):
    method __init__ (line 325) | def __init__(self, *, timeout: float = DEFAULT_OBSERVER_TIMEOUT) -> None:
    method schedule (line 328) | def schedule(

FILE: src/watchdog/observers/fsevents2.py
  class FSEventsQueue (line 72) | class FSEventsQueue(Thread):
    method __init__ (line 75) | def __init__(self, path: bytes | str) -> None:
    method run (line 99) | def run(self) -> None:
    method stop (line 117) | def stop(self) -> None:
    method _callback (line 121) | def _callback(
    method read_events (line 136) | def read_events(self) -> list[NativeEvent] | None:
  class NativeEvent (line 143) | class NativeEvent:
    method __init__ (line 144) | def __init__(self, path: bytes, flags: int, event_id: int) -> None:
    method _event_type (line 160) | def _event_type(self) -> str:
    method __repr__ (line 175) | def __repr__(self) -> str:
  class FSEventsEmitter (line 182) | class FSEventsEmitter(EventEmitter):
    method __init__ (line 185) | def __init__(
    method on_thread_stop (line 197) | def on_thread_stop(self) -> None:
    method queue_events (line 200) | def queue_events(self, timeout: float) -> None:
  class FSEventsObserver2 (line 251) | class FSEventsObserver2(BaseObserver):
    method __init__ (line 252) | def __init__(self, *, timeout: float = DEFAULT_OBSERVER_TIMEOUT) -> None:

FILE: src/watchdog/observers/inotify.py
  class FileSystemEventCtor (line 117) | class FileSystemEventCtor(Protocol):
    method __call__ (line 118) | def __call__(self, src_path: bytes | str, dest_path: bytes | str = "")...
  class InotifyWatchGroup (line 122) | class InotifyWatchGroup(WatchCallback):
    method __post_init__ (line 162) | def __post_init__(self) -> None:
    method build_event_mask (line 168) | def build_event_mask(event_mask: Mask, *, follow_symlink: bool) -> Mask:
    method is_active (line 176) | def is_active(self) -> bool:
    method _source_for_move (line 180) | def _source_for_move(self, cookie: int) -> bytes | None:
    method _callback (line 192) | def _callback(self) -> WatchCallback:
    method read_event (line 195) | def read_event(self) -> GroupedInotifyEvent | None:
    method on_watch_deleted (line 202) | def on_watch_deleted(self, wd: WatchDescriptor) -> None:
    method on_event (line 210) | def on_event(self, event: InotifyEvent) -> None:
    method _recursive_simulate (line 257) | def _recursive_simulate(self, src_path: bytes) -> list[InotifyEvent]:
    method deactivate (line 276) | def deactivate(self) -> None:
    method _activate (line 283) | def _activate(self) -> None:
    method _build_event_source_path (line 296) | def _build_event_source_path(self, event: InotifyEvent) -> bytes | None:
    method _move_watches (line 303) | def _move_watches(self, move_src_path: bytes, move_dst_path: bytes) ->...
    method _add_all_callbacks (line 319) | def _add_all_callbacks(self, path: bytes) -> None:
    method _add_callback (line 336) | def _add_callback(self, path: bytes) -> None:
    method _remove_callbacks (line 348) | def _remove_callbacks(self, wds: list[WatchDescriptor]) -> None:
    method _remove_watch_internally (line 358) | def _remove_watch_internally(self, wd: WatchDescriptor) -> None:
  function _select_event_type (line 368) | def _select_event_type(
  class InotifyEmitter (line 378) | class InotifyEmitter(EventEmitter):
    method __init__ (line 397) | def __init__(
    method on_thread_start (line 411) | def on_thread_start(self) -> None:
    method on_thread_stop (line 422) | def on_thread_stop(self) -> None:
    method queue_events (line 427) | def queue_events(self, timeout: float, *, full_events: bool = False) -...
    method build_and_queue_event (line 442) | def build_and_queue_event(self, event: GroupedInotifyEvent, *, full_ev...
    method _decode_path (line 498) | def _decode_path(self, path: bytes) -> bytes | str:
    method get_event_mask_from_filter (line 502) | def get_event_mask_from_filter(self) -> Mask:
  class InotifyFullEmitter (line 540) | class InotifyFullEmitter(InotifyEmitter):
    method build_and_queue_event (line 545) | def build_and_queue_event(self, event: GroupedInotifyEvent, *, full_ev...
  class InotifyObserver (line 549) | class InotifyObserver(BaseObserver):
    method __init__ (line 554) | def __init__(self, *, timeout: float = DEFAULT_OBSERVER_TIMEOUT, gener...

FILE: src/watchdog/observers/inotify_c.py
  class InotifyConstants (line 47) | class InotifyConstants:
  function _get_mask_string (line 128) | def _get_mask_string(mask: int) -> str:
  class InotifyEventStruct (line 132) | class InotifyEventStruct(ctypes.Structure):
  class WatchCallback (line 162) | class WatchCallback(Protocol):
    method on_event (line 163) | def on_event(self, event: InotifyEvent) -> None:
    method on_watch_deleted (line 167) | def on_watch_deleted(self, wd: WatchDescriptor) -> None:
  class Watch (line 174) | class Watch:
    method is_used (line 194) | def is_used(self) -> bool:
    method short_str (line 197) | def short_str(self) -> str:
  class InotifyFD (line 208) | class InotifyFD(BaseThread):
    method __init__ (line 221) | def __init__(self) -> None:
    method _create_inotify_fd (line 247) | def _create_inotify_fd(cls) -> int:
    method get_instance (line 254) | def get_instance(cls) -> InotifyFD:
    method add_callback (line 263) | def add_callback(self, path: bytes, mask: Mask, callback: WatchCallbac...
    method remove_callbacks (line 281) | def remove_callbacks(self, callbacks: list[tuple[WatchDescriptor, Call...
    method on_thread_stop (line 301) | def on_thread_stop(self) -> None:
    method run (line 304) | def run(self) -> None:
    method close (line 311) | def close(self) -> None:
    method handle_event (line 334) | def handle_event(self, event: InotifyEvent) -> None:
    method read_events (line 354) | def read_events(self, *, event_buffer_size: int = DEFAULT_EVENT_BUFFER...
    method _check_inotify_fd (line 368) | def _check_inotify_fd(self) -> bool:
    method _read_event_buffer (line 376) | def _read_event_buffer(self, event_buffer_size: int) -> bytes:
    method _close_resources (line 410) | def _close_resources(self) -> None:
    method _add_callback (line 415) | def _add_callback(self, path: bytes, mask: Mask, callback: WatchCallba...
    method _get_or_create_watch (line 438) | def _get_or_create_watch(self, path: bytes, mask: Mask) -> Watch:
    method _remove_callback (line 457) | def _remove_callback(self, wd: WatchDescriptor, id_: CallbackId) -> None:
    method _remove_watch (line 485) | def _remove_watch(self, wd: WatchDescriptor) -> Sequence[WatchCallback]:
    method _raise_error (line 492) | def _raise_error(*, ignore_invalid_argument: bool = False) -> None:
    method _parse_event_buffer (line 509) | def _parse_event_buffer(event_buffer: bytes) -> Generator[tuple[WatchD...
  class InotifyEvent (line 538) | class InotifyEvent:
    method is_modify (line 553) | def is_modify(self) -> bool:
    method is_close_write (line 557) | def is_close_write(self) -> bool:
    method is_close_nowrite (line 561) | def is_close_nowrite(self) -> bool:
    method is_open (line 565) | def is_open(self) -> bool:
    method is_access (line 569) | def is_access(self) -> bool:
    method is_delete (line 573) | def is_delete(self) -> bool:
    method is_delete_self (line 577) | def is_delete_self(self) -> bool:
    method is_create (line 581) | def is_create(self) -> bool:
    method is_moved_from (line 585) | def is_moved_from(self) -> bool:
    method is_moved_to (line 589) | def is_moved_to(self) -> bool:
    method is_move (line 593) | def is_move(self) -> bool:
    method is_move_self (line 597) | def is_move_self(self) -> bool:
    method is_attrib (line 601) | def is_attrib(self) -> bool:
    method is_ignored (line 605) | def is_ignored(self) -> bool:
    method is_directory (line 609) | def is_directory(self) -> bool:
    method __repr__ (line 615) | def __repr__(self) -> str:

FILE: src/watchdog/observers/inotify_move_event_grouper.py
  class PathedInotifyEvent (line 24) | class PathedInotifyEvent(NamedTuple):
  class InotifyMoveEventGrouper (line 34) | class InotifyMoveEventGrouper:
    method __init__ (line 42) | def __init__(self) -> None:
    method read_event (line 45) | def read_event(self) -> GroupedInotifyEvent | None:
    method put_event (line 52) | def put_event(self, event: PathedInotifyEvent) -> None:
    method _group_moved_to_event (line 65) | def _group_moved_to_event(self, to_event: PathedInotifyEvent) -> Group...
    method get_queued_moved_from_event (line 80) | def get_queued_moved_from_event(self, cookie: int) -> PathedInotifyEve...
    method close (line 89) | def close(self) -> None:

FILE: src/watchdog/observers/kqueue.py
  function absolute_path (line 115) | def absolute_path(path: bytes | str) -> bytes | str:
  function is_deleted (line 122) | def is_deleted(kev: select.kevent) -> bool:
  function is_modified (line 127) | def is_modified(kev: select.kevent) -> bool:
  function is_attrib_modified (line 133) | def is_attrib_modified(kev: select.kevent) -> bool:
  function is_renamed (line 138) | def is_renamed(kev: select.kevent) -> bool:
  class KeventDescriptorSet (line 143) | class KeventDescriptorSet:
    method __init__ (line 146) | def __init__(self) -> None:
    method kevents (line 154) | def kevents(self) -> list[select.kevent]:
    method paths (line 160) | def paths(self) -> list[bytes | str]:
    method get_for_fd (line 165) | def get_for_fd(self, fd: int) -> KeventDescriptor:
    method get (line 179) | def get(self, path: bytes | str) -> KeventDescriptor:
    method __contains__ (line 189) | def __contains__(self, path: bytes | str) -> bool:
    method add (line 200) | def add(self, path: bytes | str, *, is_directory: bool) -> None:
    method remove (line 217) | def remove(self, path: bytes | str) -> None:
    method clear (line 230) | def clear(self) -> None:
    method _get (line 241) | def _get(self, path: bytes | str) -> KeventDescriptor:
    method _has_path (line 245) | def _has_path(self, path: bytes | str) -> bool:
    method _add_descriptor (line 251) | def _add_descriptor(self, descriptor: KeventDescriptor) -> None:
    method _remove_descriptor (line 262) | def _remove_descriptor(self, descriptor: KeventDescriptor) -> None:
  class KeventDescriptor (line 275) | class KeventDescriptor:
    method __init__ (line 291) | def __init__(self, path: bytes | str, *, is_directory: bool) -> None:
    method fd (line 303) | def fd(self) -> int:
    method path (line 308) | def path(self) -> bytes | str:
    method kevent (line 313) | def kevent(self) -> select.kevent:
    method is_directory (line 318) | def is_directory(self) -> bool:
    method close (line 326) | def close(self) -> None:
    method key (line 332) | def key(self) -> tuple[bytes | str, bool]:
    method __eq__ (line 335) | def __eq__(self, descriptor: object) -> bool:
    method __ne__ (line 340) | def __ne__(self, descriptor: object) -> bool:
    method __hash__ (line 345) | def __hash__(self) -> int:
    method __repr__ (line 348) | def __repr__(self) -> str:
  class KqueueEmitter (line 352) | class KqueueEmitter(EventEmitter):
    method __init__ (line 400) | def __init__(
    method _register_kevent (line 424) | def _register_kevent(self, path: bytes | str, *, is_directory: bool) -...
    method _unregister_kevent (line 459) | def _unregister_kevent(self, path: bytes | str) -> None:
    method queue_event (line 468) | def queue_event(self, event: FileSystemEvent) -> None:
    method _gen_kqueue_events (line 488) | def _gen_kqueue_events(
    method _parent_dir_modified (line 534) | def _parent_dir_modified(self, src_path: bytes | str) -> DirModifiedEv...
    method _gen_renamed_events (line 538) | def _gen_renamed_events(
    method _read_events (line 593) | def _read_events(self, timeout: float) -> list[select.kevent]:
    method queue_events (line 604) | def queue_events(self, timeout: float) -> None:
    method on_thread_stop (line 642) | def on_thread_stop(self) -> None:
  class KqueueObserver (line 649) | class KqueueObserver(BaseObserver):
    method __init__ (line 654) | def __init__(self, *, timeout: float = DEFAULT_OBSERVER_TIMEOUT) -> None:

FILE: src/watchdog/observers/polling.py
  class PollingEmitter (line 46) | class PollingEmitter(EventEmitter):
    method __init__ (line 51) | def __init__(
    method on_thread_start (line 71) | def on_thread_start(self) -> None:
    method queue_events (line 74) | def queue_events(self, timeout: float) -> None:
  class PollingObserver (line 117) | class PollingObserver(BaseObserver):
    method __init__ (line 122) | def __init__(self, *, timeout: float = DEFAULT_OBSERVER_TIMEOUT) -> None:
  class PollingObserverVFS (line 126) | class PollingObserverVFS(BaseObserver):
    method __init__ (line 129) | def __init__(

FILE: src/watchdog/observers/read_directory_changes.py
  class WindowsApiEmitter (line 28) | class WindowsApiEmitter(EventEmitter):
    method __init__ (line 33) | def __init__(
    method on_thread_start (line 45) | def on_thread_start(self) -> None:
    method start (line 53) | def start(self) -> None:
    method on_thread_stop (line 60) | def on_thread_stop(self) -> None:
    method queue_events (line 67) | def queue_events(self, timeout: float) -> None:
  class WindowsApiObserver (line 106) | class WindowsApiObserver(BaseObserver):
    method __init__ (line 111) | def __init__(self, *, timeout: float = DEFAULT_OBSERVER_TIMEOUT) -> None:

FILE: src/watchdog/observers/winapi.py
  class OVERLAPPED (line 76) | class OVERLAPPED(ctypes.Structure):
  function _errcheck_bool (line 87) | def _errcheck_bool(value: Any | None, func: Any, args: Any) -> Any:
  function _errcheck_handle (line 93) | def _errcheck_handle(value: Any | None, func: Any, args: Any) -> Any:
  function _errcheck_dword (line 101) | def _errcheck_dword(value: Any | None, func: Any, args: Any) -> Any:
  class FileNotifyInformation (line 215) | class FileNotifyInformation(ctypes.Structure):
  function _parse_event_buffer (line 265) | def _parse_event_buffer(read_buffer: bytes) -> list[tuple[int, str]]:
  function _is_observed_path_deleted (line 281) | def _is_observed_path_deleted(handle: HANDLE, path: str) -> bool:
  function _generate_observed_path_deleted_event (line 290) | def _generate_observed_path_deleted_event() -> bytes:
  function _get_directory_handle (line 300) | def _get_directory_handle(path: str) -> HANDLE:
  function _cancel_handle_io (line 313) | def _cancel_handle_io(handle: HANDLE) -> None:
  function _close_directory_handle (line 323) | def _close_directory_handle(handle: HANDLE) -> None:
  class WinAPINativeEvent (line 329) | class WinAPINativeEvent:
    method is_added (line 334) | def is_added(self) -> bool:
    method is_removed (line 338) | def is_removed(self) -> bool:
    method is_modified (line 342) | def is_modified(self) -> bool:
    method is_renamed_old (line 346) | def is_renamed_old(self) -> bool:
    method is_renamed_new (line 350) | def is_renamed_new(self) -> bool:
    method is_removed_self (line 354) | def is_removed_self(self) -> bool:
  class DirectoryChangeReader (line 358) | class DirectoryChangeReader:
    method __init__ (line 365) | def __init__(self, path: str, *, recursive: bool) -> None:
    method _run_inner (line 374) | def _run_inner(self, handle: HANDLE, event_buffer: ctypes.Array[ctypes...
    method _run (line 407) | def _run(self) -> None:
    method start (line 427) | def start(self) -> None:
    method stop (line 440) | def stop(self) -> None:
    method get_events (line 460) | def get_events(self, timeout: float) -> list[WinAPINativeEvent]:

FILE: src/watchdog/tricks/__init__.py
  class Trick (line 46) | class Trick(PatternMatchingEventHandler):
    method __repr__ (line 49) | def __repr__(self) -> str:
    method generate_yaml (line 53) | def generate_yaml(cls) -> str:
  class LoggerTrick (line 68) | class LoggerTrick(Trick):
    method on_any_event (line 72) | def on_any_event(self, event: FileSystemEvent) -> None:
  class ShellCommandTrick (line 76) | class ShellCommandTrick(Trick):
    method __init__ (line 79) | def __init__(
    method on_any_event (line 101) | def on_any_event(self, event: FileSystemEvent) -> None:
    method is_process_running (line 143) | def is_process_running(self) -> bool:
  class AutoRestartTrick (line 147) | class AutoRestartTrick(Trick):
    method __init__ (line 157) | def __init__(
    method start (line 197) | def start(self) -> None:
    method stop (line 206) | def stop(self) -> None:
    method _start_process (line 224) | def _start_process(self) -> None:
    method _stop_process (line 234) | def _stop_process(self) -> None:
    method on_any_event (line 267) | def on_any_event(self, event: FileSystemEvent) -> None:
    method _restart_process (line 277) | def _restart_process(self) -> None:
  function kill_process (line 287) | def kill_process(pid: int, stop_signal: int) -> None:
  function kill_process (line 292) | def kill_process(pid: int, stop_signal: int) -> None:

FILE: src/watchdog/utils/__init__.py
  class UnsupportedLibcError (line 27) | class UnsupportedLibcError(Exception):
  class WatchdogShutdownError (line 31) | class WatchdogShutdownError(Exception):
  class BaseThread (line 35) | class BaseThread(threading.Thread):
    method __init__ (line 38) | def __init__(self) -> None:
    method stopped_event (line 47) | def stopped_event(self) -> threading.Event:
    method should_keep_running (line 50) | def should_keep_running(self) -> bool:
    method on_thread_stop (line 54) | def on_thread_stop(self) -> None:
    method stop (line 61) | def stop(self) -> None:
    method on_thread_start (line 66) | def on_thread_start(self) -> None:
    method start (line 74) | def start(self) -> None:
  function load_module (line 79) | def load_module(module_name: str) -> ModuleType:
  function load_class (line 89) | def load_class(dotted_path: str) -> type[Trick]:

FILE: src/watchdog/utils/backwards_compat.py
  function _translate (line 24) | def _translate(pat, STAR, QUESTION_MARK):
  function translate (line 96) | def translate(pat, *, recursive=False, include_hidden=False, seps=None):

FILE: src/watchdog/utils/bricks.py
  class SkipRepeatsQueue (line 29) | class SkipRepeatsQueue(queue.Queue):
    method __init__ (line 71) | def __init__(self, maxsize: int = 0) -> None:
    method put (line 75) | def put(self, item: Any, block: bool = True, timeout: float | None = N...
    method _put (line 82) | def _put(self, item: Any) -> None:
    method _get (line 86) | def _get(self) -> Any:

FILE: src/watchdog/utils/delayed_queue.py
  class DelayedQueue (line 16) | class DelayedQueue(Generic[T]):
    method __init__ (line 17) | def __init__(self, delay: float) -> None:
    method put (line 24) | def put(self, element: T, *, delay: bool = False) -> None:
    method close (line 31) | def close(self) -> None:
    method get (line 39) | def get(self) -> T | None:
    method find (line 68) | def find(self, predicate: Callable[[T], bool]) -> T | None:
    method remove (line 76) | def remove(self, predicate: Callable[[T], bool]) -> T | None:
    method _index_and_item (line 87) | def _index_and_item(self, predicate: Callable[[T], bool]) -> tuple[int...

FILE: src/watchdog/utils/dirsnapshot.py
  class DirectorySnapshotDiff (line 45) | class DirectorySnapshotDiff:
    method __init__ (line 70) | def __init__(
    method __str__ (line 136) | def __str__(self) -> str:
    method __repr__ (line 139) | def __repr__(self) -> str:
    method __len__ (line 156) | def __len__(self) -> int:
    method files_created (line 160) | def files_created(self) -> list[bytes | str]:
    method files_deleted (line 165) | def files_deleted(self) -> list[bytes | str]:
    method files_modified (line 170) | def files_modified(self) -> list[bytes | str]:
    method files_moved (line 175) | def files_moved(self) -> list[tuple[bytes | str, bytes | str]]:
    method dirs_modified (line 184) | def dirs_modified(self) -> list[bytes | str]:
    method dirs_moved (line 189) | def dirs_moved(self) -> list[tuple[bytes | str, bytes | str]]:
    method dirs_deleted (line 198) | def dirs_deleted(self) -> list[bytes | str]:
    method dirs_created (line 203) | def dirs_created(self) -> list[bytes | str]:
    class ContextManager (line 207) | class ContextManager:
      method __init__ (line 240) | def __init__(
      method __enter__ (line 255) | def __enter__(self) -> None:
      method __exit__ (line 258) | def __exit__(self, *args: object) -> None:
      method get_snapshot (line 266) | def get_snapshot(self) -> DirectorySnapshot:
  class DirectorySnapshot (line 275) | class DirectorySnapshot:
    method __init__ (line 297) | def __init__(
    method walk (line 321) | def walk(self, root: str) -> Iterator[tuple[str, os.stat_result]]:
    method paths (line 348) | def paths(self) -> set[bytes | str]:
    method path (line 352) | def path(self, uid: tuple[int, int]) -> bytes | str | None:
    method inode (line 356) | def inode(self, path: bytes | str) -> tuple[int, int]:
    method isdir (line 361) | def isdir(self, path: bytes | str) -> bool:
    method mtime (line 364) | def mtime(self, path: bytes | str) -> float:
    method size (line 367) | def size(self, path: bytes | str) -> int:
    method stat_info (line 370) | def stat_info(self, path: bytes | str) -> os.stat_result:
    method __sub__ (line 384) | def __sub__(self, previous_dirsnap: DirectorySnapshot) -> DirectorySna...
    method __str__ (line 393) | def __str__(self) -> str:
    method __repr__ (line 396) | def __repr__(self) -> str:
  class EmptyDirectorySnapshot (line 400) | class EmptyDirectorySnapshot(DirectorySnapshot):
    method __init__ (line 406) | def __init__(self) -> None:
    method path (line 410) | def path(_: Any) -> None:
    method paths (line 420) | def paths(self) -> set:

FILE: src/watchdog/utils/echo.py
  function format_arg_value (line 36) | def format_arg_value(arg_val: tuple[str, tuple[Any, ...]]) -> str:
  function echo (line 42) | def echo(fn: Callable, write: Callable[[str], int | None] = sys.stdout.w...

FILE: src/watchdog/utils/event_debouncer.py
  class EventDebouncer (line 17) | class EventDebouncer(BaseThread):
    method __init__ (line 27) | def __init__(
    method handle_event (line 39) | def handle_event(self, event: FileSystemEvent) -> None:
    method stop (line 44) | def stop(self) -> None:
    method run (line 49) | def run(self) -> None:

FILE: src/watchdog/utils/patterns.py
  function _get_sep (line 27) | def _get_sep(path: PurePath) -> str:
  function _full_match (line 39) | def _full_match(path: PurePath, pattern: str) -> bool:
  function _match_path (line 54) | def _match_path(
  function filter_paths (line 80) | def filter_paths(
  function match_any_paths (line 113) | def match_any_paths(

FILE: src/watchdog/utils/platform.py
  function get_platform_name (line 13) | def get_platform_name() -> str:
  function is_linux (line 39) | def is_linux() -> bool:
  function is_bsd (line 43) | def is_bsd() -> bool:
  function is_darwin (line 47) | def is_darwin() -> bool:
  function is_windows (line 51) | def is_windows() -> bool:

FILE: src/watchdog/utils/process_watcher.py
  class ProcessWatcher (line 15) | class ProcessWatcher(BaseThread):
    method __init__ (line 16) | def __init__(self, popen_obj: subprocess.Popen, process_termination_ca...
    method run (line 21) | def run(self) -> None:

FILE: src/watchdog/watchmedo.py
  class HelpFormatter (line 38) | class HelpFormatter(RawDescriptionHelpFormatter):
    method __init__ (line 48) | def __init__(self, *args: Any, max_help_position: int = 6, **kwargs: A...
    method __repr__ (line 53) | def __repr__(self) -> str:
    method _split_lines (line 56) | def _split_lines(self, text: str, width: int) -> list[str]:
  function argument (line 78) | def argument(*name_or_flags: str, **kwargs: Any) -> Argument:
  function command (line 85) | def command(
  function path_split (line 116) | def path_split(pathname_spec: str, *, separator: str = os.pathsep) -> li...
  function add_to_sys_path (line 127) | def add_to_sys_path(pathnames: list[str], *, index: int = 0) -> None:
  function load_config (line 140) | def load_config(tricks_file_pathname: str) -> dict:
  function parse_patterns (line 154) | def parse_patterns(
  function observe_with (line 167) | def observe_with(
  function schedule_tricks (line 196) | def schedule_tricks(observer: BaseObserver, tricks: list[dict], pathname...
  function tricks_from (line 263) | def tricks_from(args: Namespace) -> None:
  function tricks_generate_yaml (line 359) | def tricks_generate_yaml(args: Namespace) -> None:
  function log (line 457) | def log(args: Namespace) -> None:
  function shell_command (line 585) | def shell_command(args: Namespace) -> None:
  function auto_restart (line 707) | def auto_restart(args: Namespace) -> None:
  class LogLevelError (line 768) | class LogLevelError(Exception):
  function _get_log_level_from_args (line 772) | def _get_log_level_from_args(args: Namespace) -> str:
  function main (line 783) | def main() -> int:

FILE: src/watchdog_fsevents.c
  type StreamCallbackInfo (line 47) | typedef struct {
  type NativeEventObject (line 79) | typedef struct {
  function PyObject (line 87) | PyObject* NativeEventRepr(PyObject* instance) {
  function PyObject (line 99) | PyObject* NativeEventTypeFlags(PyObject* instance, void* closure)
  function PyObject (line 106) | PyObject* NativeEventTypePath(PyObject* instance, void* closure)
  function PyObject (line 113) | PyObject* NativeEventTypeInode(PyObject* instance, void* closure)
  function PyObject (line 121) | PyObject* NativeEventTypeID(PyObject* instance, void* closure)
  function PyObject (line 128) | PyObject* NativeEventTypeIsCoalesced(PyObject* instance, void* closure)
  function NativeEventInit (line 183) | static int NativeEventInit(NativeEventObject *self, PyObject *args, PyOb...
  function NativeEventDealloc (line 198) | static void NativeEventDealloc(NativeEventObject *self) {
  function watchdog_pycapsule_destructor (line 266) | static void watchdog_pycapsule_destructor(PyObject *ptr)
  function PyObject (line 284) | PyObject * CFString_AsPyUnicode(CFStringRef cf_string_ref)
  function PyObject (line 322) | PyObject * CFNumberRef_AsPyLong(CFNumberRef cf_number)
  function watchdog_FSEventStreamCallback (line 358) | static void
  function CFStringRef (line 467) | CFStringRef PyString_AsUTF8EncodedCFStringRef(PyObject *py_string)
  function CFMutableArrayRef (line 505) | static CFMutableArrayRef
  function FSEventStreamRef (line 563) | static FSEventStreamRef
  function PyObject (line 615) | static PyObject *
  function PyObject (line 719) | static PyObject *
  function PyObject (line 772) | static PyObject *
  function PyObject (line 800) | static PyObject *
  function PyObject (line 836) | static PyObject *
  function watchdog_module_init (line 897) | static void
  function watchdog_module_add_attributes (line 912) | static void
  type PyModuleDef (line 935) | struct PyModuleDef
  function PyMODINIT_FUNC (line 950) | PyMODINIT_FUNC

FILE: tests/conftest.py
  function p (line 15) | def p(tmpdir, *args):
  function _no_thread_leaks (line 24) | def _no_thread_leaks():
  function _no_warnings (line 36) | def _no_warnings(recwarn):
  function helper_fixture (line 58) | def helper_fixture(tmpdir):
  function p_fixture (line 64) | def p_fixture(helper: Helper) -> P:
  function event_queue_fixture (line 69) | def event_queue_fixture(helper: Helper) -> TestEventQueue:
  function start_watching_fixture (line 74) | def start_watching_fixture(helper: Helper) -> StartWatching:
  function expect_event_fixture (line 79) | def expect_event_fixture(helper: Helper) -> ExpectEvent:
  function events_checker_fixture (line 84) | def events_checker_fixture(helper: Helper) -> EventsChecker:

FILE: tests/isolated/eventlet_observer_stops.py
  function run_observer (line 15) | def run_observer():
  function on_alarm (line 23) | def on_alarm(signum, frame):

FILE: tests/shell.py
  function cd (line 18) | def cd(path):
  function pwd (line 22) | def pwd():
  function mkfile (line 26) | def mkfile(path):
  function mkdir (line 32) | def mkdir(path, *, parents=False):
  function symlink (line 45) | def symlink(source, destination, *, target_is_directory: bool = False):
  function rm (line 49) | def rm(path, *, recursive=False):
  function touch (line 60) | def touch(path, times=None):
  function truncate (line 69) | def truncate(path):
  function mv (line 75) | def mv(src_path, dest_path):
  function mkdtemp (line 85) | def mkdtemp():
  function ls (line 89) | def ls(path="."):
  function msize (line 93) | def msize(path):
  function mount_tmpfs (line 104) | def mount_tmpfs(path):
  function unmount (line 108) | def unmount(path):

FILE: tests/test_0_watchmedo.py
  function test_load_config_valid (line 25) | def test_load_config_valid(tmpdir):
  function test_load_config_invalid (line 41) | def test_load_config_invalid(tmpdir):
  function make_dummy_script (line 58) | def make_dummy_script(tmpdir, n=10):
  function test_kill_auto_restart (line 65) | def test_kill_auto_restart(tmpdir, capfd):
  function test_shell_command_wait_for_completion (line 78) | def test_shell_command_wait_for_completion(tmpdir, capfd):
  function test_shell_command_subprocess_termination_nowait (line 90) | def test_shell_command_subprocess_termination_nowait(tmpdir):
  function test_shell_command_subprocess_termination_not_happening_on_file_opened_event (line 101) | def test_shell_command_subprocess_termination_not_happening_on_file_open...
  function test_auto_restart_not_happening_on_file_opened_event (line 115) | def test_auto_restart_not_happening_on_file_opened_event(tmpdir, capfd):
  function test_auto_restart_on_file_change (line 131) | def test_auto_restart_on_file_change(tmpdir, capfd):
  function test_auto_restart_on_file_change_debounce (line 154) | def test_auto_restart_on_file_change_debounce(tmpdir, capfd):
  function test_auto_restart_subprocess_termination (line 190) | def test_auto_restart_subprocess_termination(tmpdir, capfd, restart_on_c...
  function test_auto_restart_arg_parsing_basic (line 209) | def test_auto_restart_arg_parsing_basic():
  function test_auto_restart_arg_parsing (line 218) | def test_auto_restart_arg_parsing():
  function test_auto_restart_events_echoed (line 237) | def test_auto_restart_events_echoed(tmpdir, caplog):
  function test_logger_events_echoed (line 254) | def test_logger_events_echoed(caplog):
  function test_shell_command_arg_parsing (line 269) | def test_shell_command_arg_parsing():
  function test_valid_verbosity (line 288) | def test_valid_verbosity(cmdline, verbosity):
  function test_invalid_verbosity (line 313) | def test_invalid_verbosity(cmdline, verbosity_cmdline_args):
  function test_tricks_from_file (line 321) | def test_tricks_from_file(command, tmp_path):

FILE: tests/test_delayed_queue.py
  function test_delayed_get (line 11) | def test_delayed_get():
  function test_nondelayed_get (line 22) | def test_nondelayed_get():

FILE: tests/test_echo.py
  function test_format_arg_value (line 14) | def test_format_arg_value(value: tuple[str, tuple[Any, ...]], expected: ...

FILE: tests/test_emitter.py
  function test_create (line 42) | def test_create(
  function test_closed (line 63) | def test_closed(
  function test_create_wrong_encoding (line 87) | def test_create_wrong_encoding(
  function test_delete (line 103) | def test_delete(
  function test_modify (line 120) | def test_modify(
  function test_chmod (line 141) | def test_chmod(p: P, event_queue: TestEventQueue, start_watching: StartW...
  function test_move_simple (line 156) | def test_move_simple(
  function test_case_change (line 177) | def test_case_change(
  function test_move_to (line 201) | def test_move_to(
  function test_move_to_full (line 218) | def test_move_to_full(
  function test_move_from (line 234) | def test_move_from(
  function test_move_from_full (line 251) | def test_move_from_full(
  function test_separate_consecutive_moves (line 267) | def test_separate_consecutive_moves(
  function test_delete_self (line 289) | def test_delete_self(
  function test_fast_subdirectory_creation_deletion (line 307) | def test_fast_subdirectory_creation_deletion(
  function test_passing_unicode_should_give_unicode (line 328) | def test_passing_unicode_should_give_unicode(p: P, event_queue: TestEven...
  function test_passing_bytes_should_give_bytes (line 339) | def test_passing_bytes_should_give_bytes(p: P, event_queue: TestEventQue...
  function test_recursive_on (line 346) | def test_recursive_on(
  function check_empty_queue (line 377) | def check_empty_queue(event_queue: TestEventQueue) -> None:
  function test_recursive_off (line 387) | def test_recursive_off(
  function test_renaming_top_level_directory (line 436) | def test_renaming_top_level_directory(
  function test_move_nested_subdirectories (line 480) | def test_move_nested_subdirectories(
  function test_move_nested_subdirectories_on_windows (line 513) | def test_move_nested_subdirectories_on_windows(
  function test_file_lifecyle (line 544) | def test_file_lifecyle(

FILE: tests/test_events.py
  function test_file_deleted_event (line 33) | def test_file_deleted_event():
  function test_file_delete_event_is_directory (line 41) | def test_file_delete_event_is_directory():
  function test_file_modified_event (line 48) | def test_file_modified_event():
  function test_file_modified_event_is_directory (line 56) | def test_file_modified_event_is_directory():
  function test_file_created_event (line 63) | def test_file_created_event():
  function test_file_moved_event (line 71) | def test_file_moved_event():
  function test_file_closed_event (line 80) | def test_file_closed_event():
  function test_file_closed_no_write_event (line 88) | def test_file_closed_no_write_event():
  function test_file_opened_event (line 96) | def test_file_opened_event():
  function test_dir_deleted_event (line 104) | def test_dir_deleted_event():
  function test_dir_modified_event (line 112) | def test_dir_modified_event():
  function test_dir_created_event (line 120) | def test_dir_created_event():
  function test_file_system_event_handler_dispatch (line 128) | def test_file_system_event_handler_dispatch():
  function test_event_comparison (line 206) | def test_event_comparison():
  function test_generate_sub_moved_events_repeated_dirname (line 227) | def test_generate_sub_moved_events_repeated_dirname():

FILE: tests/test_fsevents.py
  function observer (line 40) | def observer():
  function test_coalesced_event_check (line 72) | def test_coalesced_event_check(event, expectation):
  function test_add_watch_twice (line 76) | def test_add_watch_twice(observer: BaseObserver, p: P) -> None:
  function test_watcher_deletion_while_receiving_events_1 (line 97) | def test_watcher_deletion_while_receiving_events_1(
  function test_watcher_deletion_while_receiving_events_2 (line 131) | def test_watcher_deletion_while_receiving_events_2(
  function test_remove_watch_twice (line 186) | def test_remove_watch_twice(start_watching: StartWatching) -> None:
  function test_unschedule_removed_folder (line 210) | def test_unschedule_removed_folder(observer: BaseObserver, p: P) -> None:
  function test_converting_cfstring_to_pyunicode (line 232) | def test_converting_cfstring_to_pyunicode(p: P, start_watching: StartWat...
  function test_recursive_check_accepts_relative_paths (line 248) | def test_recursive_check_accepts_relative_paths(p: P) -> None:
  function test_watchdog_recursive (line 296) | def test_watchdog_recursive(p: P) -> None:

FILE: tests/test_inotify_c.py
  function struct_inotify (line 31) | def struct_inotify(wd, mask, cookie=0, length=0, name=b"") -> bytes:
  function test_late_double_deletion (line 44) | def test_late_double_deletion(helper: Helper, p: P, event_queue: TestEve...
  function test_raise_error (line 166) | def test_raise_error(error, pattern):
  function test_non_ascii_path (line 172) | def test_non_ascii_path(p: P, event_queue: TestEventQueue, start_watchin...
  function test_watch_file (line 186) | def test_watch_file(p: P, event_queue: TestEventQueue, start_watching: S...
  function test_event_equality (line 196) | def test_event_equality(p: P) -> None:
  function test_select_fd (line 207) | def test_select_fd(p: P, event_queue: TestEventQueue, start_watching: St...

FILE: tests/test_inotify_watch_group.py
  function wait_for_move_event (line 22) | def wait_for_move_event(read_event: Callable[[], GroupedInotifyEvent]) -...
  function create_inotify_watch (line 29) | def create_inotify_watch(path: bytes, *, recursive: bool = False, follow...
  function test_move_from (line 40) | def test_move_from(p):
  function test_move_to (line 52) | def test_move_to(p):
  function test_move_internal (line 64) | def test_move_internal(p):
  function test_move_internal_symlink_followed (line 78) | def test_move_internal_symlink_followed(p):
  function test_move_internal_batch (line 93) | def test_move_internal_batch(p):
  function test_delete_watched_directory (line 117) | def test_delete_watched_directory(p):
  function test_delete_watched_directory_symlink_followed (line 130) | def test_delete_watched_directory_symlink_followed(p):
  function test_delete_watched_directory_symlink_followed_recursive (line 149) | def test_delete_watched_directory_symlink_followed_recursive(p):
  function test_unmount_watched_directory_filesystem (line 170) | def test_unmount_watched_directory_filesystem(p):
  function assert_event (line 187) | def assert_event(inotify: InotifyWatchGroup, expected_path: str, expecte...
  function assert_touch_events (line 193) | def assert_touch_events(inotify: InotifyWatchGroup, expected_path: str):
  function test_watch_groups_are_independent (line 200) | def test_watch_groups_are_independent(p):

FILE: tests/test_isolated.py
  function test_observer_stops_in_eventlet (line 13) | def test_observer_stops_in_eventlet():
  function test_eventlet_skip_repeat_queue (line 21) | def test_eventlet_skip_repeat_queue():

FILE: tests/test_logging_event_handler.py
  class _TestableEventHandler (line 30) | class _TestableEventHandler(LoggingEventHandler):
    method on_any_event (line 31) | def on_any_event(self, event):
    method on_modified (line 34) | def on_modified(self, event):
    method on_deleted (line 38) | def on_deleted(self, event):
    method on_moved (line 42) | def on_moved(self, event):
    method on_created (line 46) | def on_created(self, event):
    method on_closed (line 50) | def on_closed(self, event):
    method on_closed_no_write (line 54) | def on_closed_no_write(self, event):
    method on_opened (line 58) | def on_opened(self, event):
  function test_logging_event_handler_dispatch (line 63) | def test_logging_event_handler_dispatch():

FILE: tests/test_observer.py
  function observer (line 18) | def observer() -> Iterator[BaseObserver]:
  function observer2 (line 27) | def observer2():
  function test_schedule_should_start_emitter_if_running (line 35) | def test_schedule_should_start_emitter_if_running(observer):
  function test_schedule_should_not_start_emitter_if_not_running (line 42) | def test_schedule_should_not_start_emitter_if_not_running(observer):
  function test_start_should_start_emitter (line 48) | def test_start_should_start_emitter(observer):
  function test_stop_should_stop_emitter (line 55) | def test_stop_should_stop_emitter(observer):
  function test_unschedule_self (line 66) | def test_unschedule_self(observer):
  function test_schedule_after_unschedule_all (line 88) | def test_schedule_after_unschedule_all(observer):
  function test_2_observers_on_the_same_path (line 100) | def test_2_observers_on_the_same_path(observer, observer2):
  function test_start_failure_should_not_prevent_further_try (line 110) | def test_start_failure_should_not_prevent_further_try(observer):
  function test_schedule_failure_should_not_prevent_future_schedules (line 135) | def test_schedule_failure_should_not_prevent_future_schedules(observer):
  function test_context_manager_starts_observer (line 152) | def test_context_manager_starts_observer():
  function test_context_manager_with_already_started_observer (line 168) | def test_context_manager_with_already_started_observer():
  function test_context_manager_stops_on_exit (line 186) | def test_context_manager_stops_on_exit():
  function test_context_manager_handles_exceptions (line 202) | def test_context_manager_handles_exceptions():
  function test_context_manager_with_scheduled_watches (line 222) | def test_context_manager_with_scheduled_watches():

FILE: tests/test_observers_api.py
  function test_observer_constructor (line 12) | def test_observer_constructor():
  function test_observer__eq__ (line 16) | def test_observer__eq__():
  function test_observer__ne__ (line 28) | def test_observer__ne__():
  function test_observer__repr__ (line 39) | def test_observer__repr__():
  function test_event_emitter (line 51) | def test_event_emitter():
  function test_event_dispatcher (line 58) | def test_event_dispatcher():
  function test_observer_basic (line 74) | def test_observer_basic():

FILE: tests/test_observers_polling.py
  function p (line 28) | def p(*args):
  function event_queue (line 37) | def event_queue():
  function emitter (line 42) | def emitter(event_queue):
  function test___init__ (line 50) | def test___init__(event_queue, emitter):
  function test_delete_watched_dir (line 132) | def test_delete_watched_dir(event_queue, emitter):

FILE: tests/test_observers_winapi.py
  function p (line 29) | def p(*args):
  function event_queue (line 38) | def event_queue():
  function emitter (line 43) | def emitter(event_queue):
  function test___init__ (line 50) | def test___init__(event_queue, emitter):
  function test_root_deleted (line 89) | def test_root_deleted(event_queue, emitter):

FILE: tests/test_pattern_matching_event_handler.py
  function assert_patterns (line 26) | def assert_patterns(event):
  function test_dispatch (line 37) | def test_dispatch():
  function test_handler (line 136) | def test_handler():
  function test_ignore_directories (line 149) | def test_ignore_directories():
  function test_ignore_patterns (line 160) | def test_ignore_patterns():
  function test_patterns (line 169) | def test_patterns():

FILE: tests/test_patterns.py
  function test_match_path (line 17) | def test_match_path(raw_path, included_patterns, excluded_patterns, case...
  function test_filter_paths (line 38) | def test_filter_paths(included_patterns, excluded_patterns, case_sensiti...
  function test_match_any_paths (line 66) | def test_match_any_paths(included_patterns, excluded_patterns, case_sens...

FILE: tests/test_regex_matching_event_handler.py
  function test_dispatch (line 27) | def test_dispatch():
  function test_handler (line 134) | def test_handler():
  function test_ignore_directories (line 147) | def test_ignore_directories():
  function test_ignore_regexes (line 158) | def test_ignore_regexes():
  function test_regexes (line 167) | def test_regexes():
  function test_str_regexes (line 176) | def test_str_regexes():
  function test_logging_event_handler_dispatch (line 185) | def test_logging_event_handler_dispatch():

FILE: tests/test_skip_repeats_queue.py
  function test_basic_queue (line 7) | def test_basic_queue():
  function test_allow_nonconsecutive (line 24) | def test_allow_nonconsecutive():
  function test_put_with_watchdog_events (line 40) | def test_put_with_watchdog_events():
  function test_prevent_consecutive (line 52) | def test_prevent_consecutive():
  function test_consecutives_allowed_across_empties (line 67) | def test_consecutives_allowed_across_empties():

FILE: tests/test_snapshot_diff.py
  function wait (line 15) | def wait():
  function test_pickle (line 27) | def test_pickle(p):
  function test_move_to (line 34) | def test_move_to(p):
  function test_move_to_with_context_manager (line 44) | def test_move_to_with_context_manager(p):
  function test_move_from (line 58) | def test_move_from(p):
  function test_move_internal (line 68) | def test_move_internal(p):
  function test_move_replace (line 80) | def test_move_replace(p):
  function test_dir_modify_on_create (line 93) | def test_dir_modify_on_create(p):
  function test_dir_modify_on_move (line 101) | def test_dir_modify_on_move(p):
  function test_detect_modify_for_moved_files (line 112) | def test_detect_modify_for_moved_files(p):
  function test_replace_dir_with_file (line 123) | def test_replace_dir_with_file(p):
  function test_permission_error (line 140) | def test_permission_error(p):
  function test_ignore_device (line 168) | def test_ignore_device(p):
  function test_empty_snapshot (line 205) | def test_empty_snapshot(p):

FILE: tests/utils.py
  class P (line 27) | class P(Protocol):
    method __call__ (line 28) | def __call__(self, *args: str) -> str: ...
  class StartWatching (line 31) | class StartWatching(Protocol):
    method __call__ (line 32) | def __call__(
  class ExpectEvent (line 41) | class ExpectEvent(Protocol):
    method __call__ (line 42) | def __call__(self, expected_event: FileSystemEvent, *, timeout: float ...
  class Helper (line 49) | class Helper:
    method joinpath (line 54) | def joinpath(self, *args: str) -> str:
    method start_watching (line 57) | def start_watching(
    method events_checker (line 84) | def events_checker(self, *, verbose: bool = False) -> _EventsChecker:
    method expect_event (line 94) | def expect_event(self, expected_event: FileSystemEvent, timeout: float...
    method close (line 101) | def close(self) -> None:
  function run_isolated_test (line 114) | def run_isolated_test(path):
  class EventsChecker (line 140) | class EventsChecker(Protocol):
    method __call__ (line 141) | def __call__(self) -> _EventsChecker: ...
  class _ExpectedEvent (line 145) | class _ExpectedEvent:
  class _EventsChecker (line 155) | class _EventsChecker:
    method __init__ (line 159) | def __init__(self, helper: Helper, *, verbose: bool = False):
    method allow_extra_events (line 175) | def allow_extra_events(self) -> None:
    method _debug (line 179) | def _debug(self, *args: Any) -> None:
    method _make_path (line 183) | def _make_path(self, path: str | None) -> str | None:
    method add (line 194) | def add(self, expected_class: type, src_path: str | None = None, dest_...
    method _match_event (line 206) | def _match_event(self, event: FileSystemEvent, expected_event: _Expect...
    method _check_events_without_order (line 218) | def _check_events_without_order( self, found_events: list[FileSystemEv...
    method _check_events_with_order (line 248) | def _check_events_with_order( self, found_events: list[FileSystemEvent...
    method check_events (line 255) | def check_events(self, timeout: float = 2) -> None:
    method __enter__ (line 281) | def __enter__(self) -> _EventsChecker:  # noqa: PYI034
    method __exit__ (line 286) | def __exit__(self, exc_type, exc_value, traceback) -> None:
Condensed preview — 92 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (619K chars).
[
  {
    "path": ".cirrus.yml",
    "chars": 697,
    "preview": "task:\n  matrix:\n    freebsd_instance:\n      image_family: freebsd-13-0\n    freebsd_instance:\n      image_family: freebsd"
  },
  {
    "path": ".gitattributes",
    "chars": 262,
    "preview": "# Language aware diff headers\n# https://tekin.co.uk/2020/10/better-git-diff-output-for-ruby-python-elixir-and-more\n# htt"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 35,
    "preview": "github: [BoboTiG]\npolar: tiger-222\n"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 130,
    "preview": "version: 2\nupdates:\n  # GitHub Actions\n  - package-ecosystem: github-actions\n    directory: /\n    schedule:\n      interv"
  },
  {
    "path": ".github/workflows/build-and-publish.yml",
    "chars": 4609,
    "preview": "# Because this library provides extension modules for macOS, but not for other\n# platforms, we want to provide built dis"
  },
  {
    "path": ".github/workflows/tests.yml",
    "chars": 2100,
    "preview": "name: Tests\n\non:\n  push:\n    branches:\n      - master\n  pull_request:\n  workflow_dispatch:\n\nconcurrency:\n  group: ${{ gi"
  },
  {
    "path": ".gitignore",
    "chars": 507,
    "preview": "# Ignore temporary files.\n*.bak\n*.bkp\n*.log\n*.py[co]\n*.swp\n*~\n.DS_Store\n.\\#*\n._*\n*.o\n*.so\nDesktop.ini\nThumbs.db\n\\#*\\#\n__"
  },
  {
    "path": ".well-known/funding-manifest-urls",
    "chars": 38,
    "preview": "https://www.tiger-222.fr/funding.json\n"
  },
  {
    "path": "AUTHORS",
    "chars": 2917,
    "preview": "Original Project Lead:\n----------------------\nYesudeep Mangalapilly <yesudeep@google.com>\n\nCurrent Project Lead:\n-------"
  },
  {
    "path": "COPYING",
    "chars": 702,
    "preview": "Copyright 2018-2025 Mickaël Schoentgen & contributors\nCopyright 2014-2018 Thomas Amland & contributors\nCopyright 2012-20"
  },
  {
    "path": "LICENSE",
    "chars": 11358,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "MANIFEST.in",
    "chars": 487,
    "preview": "include README.rst\ninclude changelog.rst\ninclude LICENSE\ninclude COPYING\ninclude AUTHORS\nrecursive-include src *.py *.h "
  },
  {
    "path": "README.rst",
    "chars": 9940,
    "preview": "Watchdog\n========\n\n|PyPI Version|\n|PyPI Status|\n|PyPI Python Versions|\n|GitHub Build Status|\n|GitHub License|\n\n.. tip::\n"
  },
  {
    "path": "THIRD_PARTY_LICENSES.md",
    "chars": 4029,
    "preview": "# Third Party Licenses\n\n## Python C-API compatibility header\n\nThis project includes the `pythoncapi_compat.h` header pro"
  },
  {
    "path": "changelog.rst",
    "chars": 35100,
    "preview": ".. :changelog:\n\nChangelog\n---------\n\n7.0.0-dev\n~~~~~~~~~\n\n202x-xx-xx • `full history <https://github.com/gorakhargosh/wa"
  },
  {
    "path": "docs/Makefile",
    "chars": 4602,
    "preview": "# Makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS    =\nSPHINXBUILD "
  },
  {
    "path": "docs/eclipse_cdt_style.xml",
    "chars": 16410,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<profiles version=\"1\">\n<profile kind=\"CodeFormatterProfile\" name="
  },
  {
    "path": "docs/make.bat",
    "chars": 4519,
    "preview": "@ECHO OFF\n\nREM Command file for Sphinx documentation\n\nif \"%SPHINXBUILD%\" == \"\" (\n\tset SPHINXBUILD=sphinx-build\n)\nset BUI"
  },
  {
    "path": "docs/source/api.rst",
    "chars": 1235,
    "preview": ".. include:: global.rst.inc\n\n.. api_reference:\n\n=============\nAPI Reference\n=============\n\n`watchdog.events`\n==========="
  },
  {
    "path": "docs/source/conf.py",
    "chars": 3382,
    "preview": "# watchdog documentation build configuration file, created by\n# sphinx-quickstart on Tue Nov 30 00:43:58 2010.\n#\n# This "
  },
  {
    "path": "docs/source/examples/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "docs/source/examples/logger.py",
    "chars": 328,
    "preview": "import sys\nimport time\n\nfrom watchdog.observers import Observer\nfrom watchdog.tricks import LoggerTrick\n\nevent_handler ="
  },
  {
    "path": "docs/source/examples/patterns.py",
    "chars": 659,
    "preview": "import logging\nimport sys\nimport time\n\nfrom watchdog.events import FileSystemEvent, PatternMatchingEventHandler\nfrom wat"
  },
  {
    "path": "docs/source/examples/simple.py",
    "chars": 1424,
    "preview": "from __future__ import annotations\n\nimport logging\nimport sys\nimport time\n\nfrom watchdog import events\nfrom watchdog.obs"
  },
  {
    "path": "docs/source/examples/tricks.json",
    "chars": 954,
    "preview": "[\n    {\n        \"watchdog.tricks.LoggerTrick\": {\n            \"patterns\": [\n                \"**/*.py\",\n                \"*"
  },
  {
    "path": "docs/source/examples/tricks.yaml",
    "chars": 680,
    "preview": "tricks:\n- watchdog.tricks.LoggerTrick:\n    patterns: [\"*.py\", \"*.js\"]\n- watchmedo_webtricks.GoogleClosureTrick:\n    patt"
  },
  {
    "path": "docs/source/global.rst.inc",
    "chars": 1800,
    "preview": ".. Global includes, substitutions, and common links.\n\n.. |author_name| replace:: Mickaël Schoentgen\n.. |author_email| re"
  },
  {
    "path": "docs/source/hacking.rst",
    "chars": 1220,
    "preview": ".. include:: global.rst.inc\n\n.. _hacking:\n\nContributing\n============\nWelcome hacker! So you have got something you would"
  },
  {
    "path": "docs/source/index.rst",
    "chars": 1281,
    "preview": ".. watchdog documentation master file, created by\n   sphinx-quickstart on Tue Nov 30 00:43:58 2010.\n   You can adapt thi"
  },
  {
    "path": "docs/source/installation.rst",
    "chars": 6039,
    "preview": ".. include:: global.rst.inc\n\n.. _installation:\n\nInstallation\n============\n|project_name| requires 3.9+ to work. See a li"
  },
  {
    "path": "docs/source/quickstart.rst",
    "chars": 2861,
    "preview": ".. include:: global.rst.inc\n\n.. _quickstart:\n\nQuickstart\n==========\nBelow we present a simple example that monitors the "
  },
  {
    "path": "pyproject.toml",
    "chars": 1552,
    "preview": "[build-system]\nrequires = [\n    # Pin to an older setuptools version for PyPy only, due to pypa/distutils#283\n    \"setup"
  },
  {
    "path": "requirements-tests.txt",
    "chars": 241,
    "preview": "eventlet==0.37.0; python_version < \"3.13\"\nflaky==3.8.1\npytest==8.3.3\npytest-cov==6.0.0\npytest-timeout==2.3.1\nruff==0.7.1"
  },
  {
    "path": "setup.cfg",
    "chars": 452,
    "preview": "[metadata]\nproject_urls =\n    Documentation=https://python-watchdog.readthedocs.io/en/stable/\n    Source=https://github."
  },
  {
    "path": "setup.py",
    "chars": 5008,
    "preview": "import importlib.util\nimport sys\nimport os\nimport os.path\nfrom platform import machine\nfrom setuptools import setup, fin"
  },
  {
    "path": "src/pythoncapi_compat.h",
    "chars": 63659,
    "preview": "// Header file providing new C API functions to old Python versions.\n//\n// File distributed under the Zero Clause BSD (0"
  },
  {
    "path": "src/watchdog/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/watchdog/events.py",
    "chars": 16320,
    "preview": "\"\"\":module: watchdog.events\n:synopsis: File system events and event handlers.\n:author: yesudeep@google.com (Yesudeep Man"
  },
  {
    "path": "src/watchdog/observers/__init__.py",
    "chars": 3255,
    "preview": "\"\"\":module: watchdog.observers\n:synopsis: Observer that picks a native implementation if available.\n:author: yesudeep@go"
  },
  {
    "path": "src/watchdog/observers/api.py",
    "chars": 14800,
    "preview": "from __future__ import annotations\n\nimport contextlib\nimport queue\nimport threading\nfrom collections import defaultdict\n"
  },
  {
    "path": "src/watchdog/observers/fsevents.py",
    "chars": 14411,
    "preview": "\"\"\":module: watchdog.observers.fsevents\n:synopsis: FSEvents based emitter implementation.\n:author: yesudeep@google.com ("
  },
  {
    "path": "src/watchdog/observers/fsevents2.py",
    "chars": 9438,
    "preview": "\"\"\":module: watchdog.observers.fsevents2\n:synopsis: FSEvents based emitter implementation.\n:author: thomas.amland@gmail."
  },
  {
    "path": "src/watchdog/observers/inotify.py",
    "chars": 24429,
    "preview": "\"\"\":module: watchdog.observers.inotify\n:synopsis: ``inotify(7)`` based emitter implementation.\n:author: Sebastien Martin"
  },
  {
    "path": "src/watchdog/observers/inotify_c.py",
    "chars": 23200,
    "preview": "from __future__ import annotations\n\nimport ctypes\nimport ctypes.util\nimport errno\nimport logging\nimport os\nimport select"
  },
  {
    "path": "src/watchdog/observers/inotify_move_event_grouper.py",
    "chars": 3319,
    "preview": "\"\"\":module: watchdog.observers.inotify_buffer\n:synopsis: queue-like class for ``Inotify`` to group move events.\n:author:"
  },
  {
    "path": "src/watchdog/observers/kqueue.py",
    "chars": 24424,
    "preview": "\"\"\":module: watchdog.observers.kqueue\n:synopsis: ``kqueue(2)`` based emitter implementation.\n:author: yesudeep@google.co"
  },
  {
    "path": "src/watchdog/observers/polling.py",
    "chars": 4931,
    "preview": "\"\"\":module: watchdog.observers.polling\n:synopsis: Polling emitter implementation.\n:author: yesudeep@google.com (Yesudeep"
  },
  {
    "path": "src/watchdog/observers/read_directory_changes.py",
    "chars": 4134,
    "preview": "from __future__ import annotations\n\nimport os.path\nimport platform\nimport threading\nfrom typing import TYPE_CHECKING\n\nfr"
  },
  {
    "path": "src/watchdog/observers/winapi.py",
    "chars": 15620,
    "preview": "\"\"\":module: watchdog.observers.winapi\n:synopsis: Windows API-Python interface (removes dependency on ``pywin32``).\n:auth"
  },
  {
    "path": "src/watchdog/py.typed",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/watchdog/tricks/__init__.py",
    "chars": 9491,
    "preview": "\"\"\":module: watchdog.tricks\n:synopsis: Utility event handlers.\n:author: yesudeep@google.com (Yesudeep Mangalapilly)\n:aut"
  },
  {
    "path": "src/watchdog/utils/__init__.py",
    "chars": 3512,
    "preview": "\"\"\":module: watchdog.utils\n:synopsis: Utility classes and functions.\n:author: yesudeep@google.com (Yesudeep Mangalapilly"
  },
  {
    "path": "src/watchdog/utils/backwards_compat.py",
    "chars": 5286,
    "preview": "# ruff: noqa\n# fmt: off\n# type: ignore\n\"\"\"\nThis file includes unmodified functions copied from Python 3.13's standard li"
  },
  {
    "path": "src/watchdog/utils/bricks.py",
    "chars": 2551,
    "preview": "\"\"\"Utility collections or \"bricks\".\n\n:module: watchdog.utils.bricks\n:author: yesudeep@google.com (Yesudeep Mangalapilly)"
  },
  {
    "path": "src/watchdog/utils/delayed_queue.py",
    "chars": 3309,
    "preview": "\"\"\":module: watchdog.utils.delayed_queue\n:author: thomas.amland@gmail.com (Thomas Amland)\n:author: Mickaël Schoentgen <c"
  },
  {
    "path": "src/watchdog/utils/dirsnapshot.py",
    "chars": 14902,
    "preview": "\"\"\":module: watchdog.utils.dirsnapshot\n:synopsis: Directory snapshots and comparison.\n:author: yesudeep@google.com (Yesu"
  },
  {
    "path": "src/watchdog/utils/echo.py",
    "chars": 2210,
    "preview": "# echo.py: Tracing function calls using Python decorators.\n#\n# Written by Thomas Guest <tag@wordaligned.org>\n# Please se"
  },
  {
    "path": "src/watchdog/utils/event_debouncer.py",
    "chars": 2079,
    "preview": "from __future__ import annotations\n\nimport logging\nimport threading\nfrom typing import TYPE_CHECKING\n\nfrom watchdog.util"
  },
  {
    "path": "src/watchdog/utils/patterns.py",
    "chars": 4839,
    "preview": "\"\"\":module: watchdog.utils.patterns\n:synopsis: Common wildcard searching/filtering functionality for files.\n:author: bor"
  },
  {
    "path": "src/watchdog/utils/platform.py",
    "chars": 1138,
    "preview": "from __future__ import annotations\n\nimport os\nimport sys\n\nPLATFORM_WINDOWS = \"windows\"\nPLATFORM_LINUX = \"linux\"\nPLATFORM"
  },
  {
    "path": "src/watchdog/utils/process_watcher.py",
    "chars": 925,
    "preview": "from __future__ import annotations\n\nimport logging\nfrom typing import TYPE_CHECKING\n\nfrom watchdog.utils import BaseThre"
  },
  {
    "path": "src/watchdog/version.py",
    "chars": 349,
    "preview": "from __future__ import annotations\n\n# When updating this version number, please update the\n# ``docs/source/global.rst.in"
  },
  {
    "path": "src/watchdog/watchmedo.py",
    "chars": 25450,
    "preview": "\"\"\":module: watchdog.watchmedo\n:author: yesudeep@google.com (Yesudeep Mangalapilly)\n:author: Mickaël Schoentgen <contact"
  },
  {
    "path": "src/watchdog_fsevents.c",
    "chars": 34216,
    "preview": "/**\n * watchdog_fsevents.c: Python-C bridge to the OS X FSEvents API.\n *\n * Copyright 2018-2025 Mickaël Schoentgen & con"
  },
  {
    "path": "tests/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/conftest.py",
    "chars": 2233,
    "preview": "from __future__ import annotations\n\nimport contextlib\nimport gc\nimport os\nimport threading\nfrom functools import partial"
  },
  {
    "path": "tests/isolated/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/isolated/eventlet_observer_stops.py",
    "chars": 823,
    "preview": "if __name__ == \"__main__\":\n    import eventlet\n\n    eventlet.monkey_patch()\n\n    import signal\n    import sys\n    import"
  },
  {
    "path": "tests/isolated/eventlet_skip_repeat_queue.py",
    "chars": 570,
    "preview": "if __name__ == \"__main__\":\n    import eventlet\n\n    eventlet.monkey_patch()\n\n    from watchdog.utils.bricks import SkipR"
  },
  {
    "path": "tests/shell.py",
    "chars": 2273,
    "preview": "\"\"\"\n:module: tests.shell\n:synopsis: Common shell operations for testing.\n:author: yesudeep@google.com (Yesudeep Mangalap"
  },
  {
    "path": "tests/test_0_watchmedo.py",
    "chars": 12209,
    "preview": "from __future__ import annotations\n\nimport logging\nimport os\nimport sys\nimport time\nfrom unittest.mock import patch\n\nimp"
  },
  {
    "path": "tests/test_delayed_queue.py",
    "chars": 647,
    "preview": "from __future__ import annotations\n\nfrom time import time\n\nimport pytest\n\nfrom watchdog.utils.delayed_queue import Delay"
  },
  {
    "path": "tests/test_echo.py",
    "chars": 322,
    "preview": "from typing import Any\n\nimport pytest\n\nfrom watchdog.utils import echo\n\n\n@pytest.mark.parametrize(\n    (\"value\", \"expect"
  },
  {
    "path": "tests/test_emitter.py",
    "chars": 17988,
    "preview": "from __future__ import annotations\n\nimport logging\nimport os\nimport stat\nimport time\nfrom queue import Empty\nfrom typing"
  },
  {
    "path": "tests/test_events.py",
    "chars": 7693,
    "preview": "from __future__ import annotations\n\nimport os\nimport tempfile\n\nfrom watchdog.events import (\n    EVENT_TYPE_CLOSED,\n    "
  },
  {
    "path": "tests/test_fsevents.py",
    "chars": 10569,
    "preview": "from __future__ import annotations\n\nimport contextlib\n\nimport pytest\n\nfrom watchdog.events import DirCreatedEvent\nfrom w"
  },
  {
    "path": "tests/test_inotify_c.py",
    "chars": 7494,
    "preview": "from __future__ import annotations\n\nfrom contextlib import ExitStack\n\nimport pytest\n\nfrom watchdog.utils import platform"
  },
  {
    "path": "tests/test_inotify_watch_group.py",
    "chars": 8160,
    "preview": "from __future__ import annotations\n\nfrom typing import Callable\n\nimport pytest\n\nfrom watchdog.utils import platform\n\nif "
  },
  {
    "path": "tests/test_isolated.py",
    "chars": 807,
    "preview": "import importlib\n\nimport pytest\n\nfrom watchdog.utils import platform\n\nfrom .utils import run_isolated_test\n\n\n# Kqueue is"
  },
  {
    "path": "tests/test_logging_event_handler.py",
    "chars": 2647,
    "preview": "from __future__ import annotations\n\nfrom watchdog.events import (\n    EVENT_TYPE_CLOSED,\n    EVENT_TYPE_CLOSED_NO_WRITE,"
  },
  {
    "path": "tests/test_observer.py",
    "chars": 6543,
    "preview": "from __future__ import annotations\n\nimport contextlib\nimport threading\nfrom typing import TYPE_CHECKING\nfrom unittest.mo"
  },
  {
    "path": "tests/test_observers_api.py",
    "chars": 3179,
    "preview": "from __future__ import annotations\n\nimport time\nfrom pathlib import Path\n\nimport pytest\n\nfrom watchdog.events import Fil"
  },
  {
    "path": "tests/test_observers_polling.py",
    "chars": 3569,
    "preview": "from __future__ import annotations\n\nimport os\nfrom queue import Empty, Queue\nfrom time import sleep\n\nimport pytest\n\nfrom"
  },
  {
    "path": "tests/test_observers_winapi.py",
    "chars": 3945,
    "preview": "from __future__ import annotations\n\nimport os\nimport os.path\nfrom queue import Empty, Queue\nfrom time import sleep\n\nimpo"
  },
  {
    "path": "tests/test_pattern_matching_event_handler.py",
    "chars": 6106,
    "preview": "from __future__ import annotations\n\nfrom watchdog.events import (\n    EVENT_TYPE_CREATED,\n    EVENT_TYPE_DELETED,\n    EV"
  },
  {
    "path": "tests/test_patterns.py",
    "chars": 2681,
    "preview": "from __future__ import annotations\n\nimport pytest\n\nfrom watchdog.utils.patterns import _match_path, filter_paths, match_"
  },
  {
    "path": "tests/test_regex_matching_event_handler.py",
    "chars": 7891,
    "preview": "from __future__ import annotations\n\nfrom watchdog.events import (\n    EVENT_TYPE_CREATED,\n    EVENT_TYPE_DELETED,\n    EV"
  },
  {
    "path": "tests/test_skip_repeats_queue.py",
    "chars": 1712,
    "preview": "from __future__ import annotations\n\nfrom watchdog import events\nfrom watchdog.utils.bricks import SkipRepeatsQueue\n\n\ndef"
  },
  {
    "path": "tests/test_snapshot_diff.py",
    "chars": 6922,
    "preview": "from __future__ import annotations\n\nimport errno\nimport os\nimport pickle\nimport time\nfrom unittest.mock import patch\n\nfr"
  },
  {
    "path": "tests/utils.py",
    "chars": 10950,
    "preview": "from __future__ import annotations\n\nimport dataclasses\nimport os\nimport subprocess\nimport sys\nfrom queue import Empty, Q"
  },
  {
    "path": "tools/watchmedo.bat",
    "chars": 987,
    "preview": "@REM Copyright 2018-2025 Mickaël Schoentgen & contributors\n@REM Copyright 2012-2018 Google, Inc.\n@REM Copyright 2011-201"
  },
  {
    "path": "tox.ini",
    "chars": 1496,
    "preview": "[tox]\nenvlist =\n    py3{9,10,11,12,13}\n    pypy3\n    docs\n    types\n    lint\nskip_missing_interpreters = True\n\n[testenv]"
  }
]

About this extraction

This page contains the full source code of the gorakhargosh/watchdog GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 92 files (576.3 KB), approximately 146.0k tokens, and a symbol index with 811 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!