{"id":595,"library":"watchdog","title":"Watchdog","description":"Watchdog is a Python library and shell utility that provides an API for monitoring file system events in real-time. It supports various operating systems by utilizing native APIs like inotify (Linux), FSEvents (macOS), and ReadDirectoryChangesW (Windows), falling back to polling when native APIs are unavailable. Currently at version 6.0.0, the library maintains an active development pace with major releases approximately annually.","status":"active","version":"6.0.0","language":"python","source_language":"en","source_url":"https://github.com/gorakhargosh/watchdog/","tags":["filesystem monitoring","event handler","real-time","file changes"],"install":[{"cmd":"pip install watchdog","lang":"bash","label":"Install core library"},{"cmd":"pip install 'watchdog[watchmedo]'","lang":"bash","label":"Install with watchmedo utility"}],"dependencies":[{"reason":"Requires Python 3.9 or above.","package":"Python","optional":false},{"reason":"Optional dependency for the 'watchmedo' shell utility.","package":"PyYAML","optional":true},{"reason":"Required on macOS when installing from sources.","package":"XCode","optional":true}],"imports":[{"symbol":"Observer","correct":"from watchdog.observers import Observer"},{"symbol":"FileSystemEventHandler","correct":"from watchdog.events import FileSystemEventHandler"},{"note":"A built-in event handler for simple logging.","symbol":"LoggingEventHandler","correct":"from watchdog.events import LoggingEventHandler"}],"quickstart":{"code":"import time\nfrom watchdog.observers import Observer\nfrom watchdog.events import FileSystemEventHandler\n\nclass MyEventHandler(FileSystemEventHandler):\n    def on_any_event(self, event):\n        # Log any event for demonstration\n        print(f\"Event type: {event.event_type} | Path: {event.src_path} | Is directory: {event.is_directory}\")\n\nif __name__ == \"__main__\":\n    path_to_watch = \".\"\n    event_handler = MyEventHandler()\n    observer = Observer()\n    observer.schedule(event_handler, path_to_watch, recursive=True)\n    observer.start()\n    try:\n        print(f\"Monitoring directory: {path_to_watch}\")\n        while True:\n            time.sleep(1)\n    except KeyboardInterrupt:\n        observer.stop()\n    observer.join()\n","lang":"python","description":"This quickstart monitors the current directory ('.') recursively for any filesystem events using a custom event handler and prints them to the console. The observer runs in a separate thread until a KeyboardInterrupt is received."},"warnings":[{"fix":"Upgrade your Python interpreter to version 3.9 or later.","message":"Python 3.8 support was dropped in Watchdog v5.0.0. Python 3.7 support was dropped in v4.0.0. Ensure your Python environment is 3.9 or newer.","severity":"breaking","affected_versions":">=5.0.0, >=4.0.0"},{"fix":"Update class/exception names and ensure keyword arguments are used for API calls.","message":"In v5.0.0, several core classes and exceptions were renamed (e.g., `BaseObserverSubclassCallable` to `ObserverType`, `UnsupportedLibc` to `UnsupportedLibcError`). Keyword arguments are now enforced in core API calls. `InotifyConstants.IN_CLOSE` was also removed.","severity":"breaking","affected_versions":">=5.0.0"},{"fix":"Update any custom `inotify` implementations to reflect `select.poll()` usage if directly interacting with low-level components. Remove any calls to the deprecated `echo` module functions.","message":"In v6.0.0, the `inotify` backend now uses `select.poll()` instead of the deprecated `select.select()`, if available. Additionally, several unused functions from the `watchdog.utils.echo` module were removed.","severity":"breaking","affected_versions":">=6.0.0"},{"fix":"Configure your editor to disable features that involve backup files or temporary swaps, or consider monitoring the parent directory for `on_moved` events if file replacement is the expected pattern.","message":"Text editors like Vim often write to temporary files and then swap them in to replace the original, which may not trigger `on_modified` events.","severity":"gotcha","affected_versions":"All"},{"fix":"Increase the per-process file descriptor limit on your operating system (`ulimit -n` on Unix-like systems) or adjust your monitoring strategy to cover fewer paths if possible.","message":"On BSD/macOS systems using `kqueue`, Watchdog opens file descriptors for monitored items. Hitting the operating system's maximum open file descriptor limit can prevent Watchdog from monitoring new files or directories.","severity":"gotcha","affected_versions":"All (BSD/macOS specific)"},{"fix":"Implement robust error handling and potentially introduce small delays when processing Windows-specific move/delete events to account for eventual consistency, and be prepared to infer directory deletions from file deletion events.","message":"On Windows, the `ReadDirectoryChangesW` API has limitations: rename/movement events for directories may be reported before I/O is complete, and delete events for directories might be reported as file deletion events.","severity":"gotcha","affected_versions":"All (Windows specific)"},{"fix":"Ensure that the directory or file path passed to `observer.schedule()` exists before starting the observer. Verify permissions if the path exists but is inaccessible, as this can also lead to similar errors.","message":"Watchdog will raise a `FileNotFoundError` if the path being monitored does not exist when the observer is started (`observer.start()`). Ensure all paths passed to `observer.schedule()` are valid and accessible.","severity":"breaking","affected_versions":"All"},{"fix":"Verify that the directory or file path you are attempting to monitor exists and is accessible before calling `observer.start()` or scheduling the watch. This error often suggests a typo in the path argument or that the target filesystem item was deleted unexpectedly.","message":"Watchdog raises `FileNotFoundError: [Errno 2] No such file or directory` if the path specified for monitoring (either through `observer.schedule()` or directly to an `Inotify` backend) does not exist on the filesystem at the time monitoring starts. This is a common error indicating an invalid or non-existent path.","severity":"gotcha","affected_versions":"All"}],"env_vars":null,"last_verified":"2026-05-12T16:25:04.719Z","next_check":"2026-06-26T00:00:00.000Z","problems":[{"fix":"pip install watchdog","cause":"The `watchdog` library has not been installed in your Python environment.","error":"ModuleNotFoundError: No module named 'watchdog'"},{"fix":"from watchdog.observers import Observer","cause":"The `Observer` class is located within the `watchdog.observers` submodule, not directly under the top-level `watchdog` package.","error":"ImportError: cannot import name 'Observer' from 'watchdog'"},{"fix":"Increase the `fs.inotify.max_user_watches` kernel parameter, e.g., by running `echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf; sudo sysctl -p`","cause":"On Linux, this misleading error often indicates that the system's `inotify` watch limit (the maximum number of files/directories that can be monitored) has been reached.","error":"OSError: [Errno 28] No space left on device"},{"fix":"Ensure `observer.start()` is called before `observer.stop()` and `observer.join()`, and avoid calling `stop()` or `join()` multiple times on the same observer instance.","cause":"This occurs when you attempt to call `stop()` or `join()` on an `Observer` instance that has either not been started yet or has already been stopped.","error":"RuntimeError: Observer is not running."}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":0,"quickstart_tag":"stale","pypi_latest":"6.0.0","install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"watchmedo","exit_code":0,"wheel_type":"sdist","failure_reason":null,"install_time_s":null,"import_time_s":0.08,"mem_mb":3.8,"disk_size":"20.5M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"sdist","failure_reason":null,"install_time_s":null,"import_time_s":0.08,"mem_mb":3.8,"disk_size":"18.4M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"watchmedo","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.08,"mem_mb":3.8,"disk_size":"20.5M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.08,"mem_mb":3.8,"disk_size":"18.4M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"watchmedo","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.7,"import_time_s":0.07,"mem_mb":3.9,"disk_size":"22M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.6,"import_time_s":0.06,"mem_mb":3.9,"disk_size":"19M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"watchmedo","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.06,"mem_mb":3.9,"disk_size":"22M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.06,"mem_mb":3.9,"disk_size":"19M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"watchmedo","exit_code":0,"wheel_type":"sdist","failure_reason":null,"install_time_s":null,"import_time_s":0.14,"mem_mb":4.4,"disk_size":"22.7M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"sdist","failure_reason":null,"install_time_s":null,"import_time_s":0.14,"mem_mb":4.4,"disk_size":"20.3M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"watchmedo","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.17,"mem_mb":4.4,"disk_size":"22.7M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.16,"mem_mb":4.4,"disk_size":"20.3M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"watchmedo","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.8,"import_time_s":0.14,"mem_mb":4.4,"disk_size":"24M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.6,"import_time_s":0.15,"mem_mb":4.4,"disk_size":"21M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"watchmedo","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.14,"mem_mb":4.4,"disk_size":"24M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.14,"mem_mb":4.4,"disk_size":"21M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"watchmedo","exit_code":0,"wheel_type":"sdist","failure_reason":null,"install_time_s":null,"import_time_s":0.13,"mem_mb":4.3,"disk_size":"14.5M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"sdist","failure_reason":null,"install_time_s":null,"import_time_s":0.12,"mem_mb":4.3,"disk_size":"12.1M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"watchmedo","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.13,"mem_mb":4.3,"disk_size":"14.5M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.13,"mem_mb":4.3,"disk_size":"12.1M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"watchmedo","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.6,"import_time_s":0.14,"mem_mb":4.4,"disk_size":"16M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.5,"import_time_s":0.15,"mem_mb":4.4,"disk_size":"13M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"watchmedo","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.15,"mem_mb":4.4,"disk_size":"16M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.14,"mem_mb":4.4,"disk_size":"13M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"watchmedo","exit_code":0,"wheel_type":"sdist","failure_reason":null,"install_time_s":null,"import_time_s":0.12,"mem_mb":4.5,"disk_size":"14.3M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"sdist","failure_reason":null,"install_time_s":null,"import_time_s":0.12,"mem_mb":4.5,"disk_size":"11.9M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"watchmedo","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.12,"mem_mb":4.5,"disk_size":"14.2M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.12,"mem_mb":4.5,"disk_size":"11.8M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"watchmedo","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.6,"import_time_s":0.12,"mem_mb":4.5,"disk_size":"15M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.5,"import_time_s":0.12,"mem_mb":4.5,"disk_size":"12M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"watchmedo","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.13,"mem_mb":4.5,"disk_size":"15M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.14,"mem_mb":4.5,"disk_size":"12M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"watchmedo","exit_code":0,"wheel_type":"sdist","failure_reason":null,"install_time_s":null,"import_time_s":0.08,"mem_mb":3.7,"disk_size":"20.0M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"sdist","failure_reason":null,"install_time_s":null,"import_time_s":0.07,"mem_mb":3.7,"disk_size":"17.9M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"watchmedo","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.08,"mem_mb":3.7,"disk_size":"20.0M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.1,"mem_mb":3.7,"disk_size":"17.9M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"watchmedo","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":2,"import_time_s":0.07,"mem_mb":3.7,"disk_size":"21M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.9,"import_time_s":0.08,"mem_mb":3.7,"disk_size":"18M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"watchmedo","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.08,"mem_mb":3.7,"disk_size":"21M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.07,"mem_mb":3.7,"disk_size":"18M"}]},"quickstart_checks":{"last_tested":"2026-04-23","tag":"stale","tag_description":"widespread failures or data too old to trust","results":[{"runtime":"python:3.10-alpine","exit_code":1},{"runtime":"python:3.10-slim","exit_code":1},{"runtime":"python:3.11-alpine","exit_code":1},{"runtime":"python:3.11-slim","exit_code":1},{"runtime":"python:3.12-alpine","exit_code":1},{"runtime":"python:3.12-slim","exit_code":1},{"runtime":"python:3.13-alpine","exit_code":1},{"runtime":"python:3.13-slim","exit_code":1},{"runtime":"python:3.9-alpine","exit_code":1},{"runtime":"python:3.9-slim","exit_code":1}]}}