WATCHDOG(3)

WATCHDOG(3) β€” the watchdog manual, bestie edition πŸ’–

okay so. <pink>watchdog</pink> is the watchdog documentation, and it's literally your new best friend if you've ever wanted to know when a file changes. It's a Python API library and shell utilities to monitor file system events. ✨

It works on 3.9+. no cap.


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 Quickstart. (It's right below, bestie, keep scrolling 🫢)


EASY INSTALLATION πŸ’…

You can use pip to install watchdog quickly and easily:

$ python -m pip install -U watchdog

Need more help with installing? See Installation.


INSTALLATION πŸ¦‹

watchdog requires 3.9+ to work. See a list of Dependencies.

Installing from PyPI using pip

$ python -m pip install -U watchdog

# or to install the watchmedo utility:
$ python -m pip install -U 'watchdog[watchmedo]'

Installing from source tarballs

$ wget -c https://pypi.python.org/packages/source/w/watchdog/watchdog-5.0.4.tar.gz
$ tar zxvf watchdog-5.0.4.tar.gz
$ cd watchdog-5.0.4
$ 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]'

Dependencies πŸ“

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

  • XCode β€” needed on macOS Darwin (that's it, that's the whole row πŸ’€). Nothing needed on Windows, Linux 2.6 or BSD.

The following is a list of dependencies you need based on the operating system you are using the watchmedo utility.

  • PyYAML β€” needed on Windows, Linux 2.6, macOS Darwin, and BSD. Yeah. Every single one. slay, universal dependency ✨

Supported Platforms (and Caveats) πŸ™ˆ

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

watchdog 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 watchdog uses kqueue(2) is noted in BSD Unix variants. Much of this information applies to macOS as well.

BSD variants πŸ‘‘

BSD variants come with kqueue which programs can use to monitor changes to open file descriptors. Because of the way kqueue(2) works, watchdog needs to open these files and directories in read-only non-blocking mode and keep books about them.

watchdog 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 watchdog'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. watchdog 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, watchdog 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, watchdog 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 🌈

watchdog also includes a fallback-implementation that polls watched directories for changes by periodically comparing snapshots of the directory tree.


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 watchdog.observers.Observer thread class.
  2. Implement a subclass of 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 watchdog.observers.Observer instance will not monitor sub-directories. By passing recursive=True in the call to 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.

Typing πŸ¦‹

If you are using type annotations it is important to note that watchdog.observers.Observer is not actually a class; it is a variable that hold the "best" observer class available on your platform. (iconic behavior honestly, but it will confuse your type checker if you're not ready)

In order to correctly type your own code your should use 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)

API REFERENCE πŸŽ€

watchdog.events

module watchdog.events

synopsis

File system events and event handlers.

author yesudeep@google.com (Yesudeep Mangalapilly)

author contact@tiger-222.fr (MickaΓ«l Schoentgen)


Event Classes πŸ’…

class watchdog.events.FileSystemEvent(src_path: bytes | str, dest_path: bytes | str = '', is_synthetic: bool = False)

Bases: object

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. (immutable queen behavior πŸ‘‘)

  • is_directory: bool = 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.

class watchdog.events.FileSystemMovedEvent(src_path: bytes | str, dest_path: bytes | str = '', is_synthetic: bool = False)

Bases: FileSystemEvent

File system event representing any kind of file system movement.

class watchdog.events.FileMovedEvent(src_path: bytes | str, dest_path: bytes | str = '', is_synthetic: bool = False)

Bases: FileSystemMovedEvent

File system event representing file movement on the file system.

class watchdog.events.DirMovedEvent(src_path: bytes | str, dest_path: bytes | str = '', is_synthetic: bool = False)

Bases: FileSystemMovedEvent

File system event representing directory movement on the file system.

  • is_directory: bool = True β€” 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.

πŸ¦‹ watchdog.events.FileModifiedEvent πŸ¦‹

class watchdog.events.FileModifiedEvent(src_path: bytes | str, dest_path: bytes | str = '', is_synthetic: bool = False)

Bases: FileSystemEvent

File system event representing file modification on the file system. Somebody touched a file, bestie, and we are witnesses. πŸ’…


🌸 watchdog.events.DirModifiedEvent 🌸

class watchdog.events.DirModifiedEvent(src_path: bytes | str, dest_path: bytes | str = '', is_synthetic: bool = False)

Bases: FileSystemEvent

File system event representing directory modification on the file system.

  • is_directory: bool = True β€” 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.

πŸŽ€ watchdog.events.FileCreatedEvent πŸŽ€

class watchdog.events.FileCreatedEvent(src_path: bytes | str, dest_path: bytes | str = '', is_synthetic: bool = False)

Bases: FileSystemEvent

File system event representing file creation on the file system. New file just dropped ✨


πŸ’œ watchdog.events.FileClosedEvent πŸ’œ

class watchdog.events.FileClosedEvent(src_path: bytes | str, dest_path: bytes | str = '', is_synthetic: bool = False)

Bases: FileSystemEvent

File system event representing file close on the file system.


🌈 watchdog.events.FileClosedNoWriteEvent 🌈

class watchdog.events.FileClosedNoWriteEvent(src_path: bytes | str, dest_path: bytes | str = '', is_synthetic: bool = False)

Bases: FileSystemEvent

File system event representing an unmodified file close on the file system. Nothing got written, the file just got closed. Respect.


🫢 watchdog.events.FileOpenedEvent 🫢

class watchdog.events.FileOpenedEvent(src_path: bytes | str, dest_path: bytes | str = '', is_synthetic: bool = False)

Bases: FileSystemEvent

File system event representing file close on the file system.

Okay so the docs literally say "file close" right there for FileOpenedEvent, and I am not about to gaslight you by pretending otherwise β€” bestie I'm just the messenger πŸ’€.

⭐ watchdog.events.DirCreatedEvent ⭐

class watchdog.events.DirCreatedEvent(src_path: bytes | str, dest_path: bytes | str = '', is_synthetic: bool = False)

Bases: FileSystemEvent

File system event representing directory creation on the file system.

  • is_directory: bool = True β€” 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.

πŸ“ watchdog.events.FileDeletedEvent πŸ“

class watchdog.events.FileDeletedEvent(src_path: bytes | str, dest_path: bytes | str = '', is_synthetic: bool = False)

Bases: FileSystemEvent

File system event representing file deletion on the file system. Gone. Poof. Not me crying over a temp file 😭


πŸŒ™ watchdog.events.DirDeletedEvent πŸŒ™

class watchdog.events.DirDeletedEvent(src_path: bytes | str, dest_path: bytes | str = '', is_synthetic: bool = False)

Bases: FileSystemEvent

File system event representing directory deletion on the file system.

  • is_directory: bool = True β€” 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.

πŸ’– Event Handler Classes πŸ’–

πŸ‘‘ watchdog.events.FileSystemEventHandler πŸ‘‘

Bases: object

Base file system event handler that you can override methods from. This is the main character β€” everything else is a remix of her. ✨

  • dispatch(event: FileSystemEvent) -> None β€” Dispatches events to the appropriate methods.
    • event (FileSystemEvent) β€” The event object representing the file system event.
  • on_any_event(event: FileSystemEvent) -> None β€” Catch-all event handler.
    • event (FileSystemEvent) β€” The event object representing the file system event.
  • on_closed(event: FileClosedEvent) -> None β€” Called when a file opened for writing is closed.
    • event (FileClosedEvent) β€” Event representing file closing.
  • on_closed_no_write(event: FileClosedNoWriteEvent) -> None β€” Called when a file opened for reading is closed.
    • event (FileClosedNoWriteEvent) β€” Event representing file closing.
  • on_created(event: DirCreatedEvent | FileCreatedEvent) -> None β€” Called when a file or directory is created.
    • event (DirCreatedEvent or FileCreatedEvent) β€” Event representing file/directory creation.
  • on_deleted(event: DirDeletedEvent | FileDeletedEvent) -> None β€” Called when a file or directory is deleted.
    • event (DirDeletedEvent or FileDeletedEvent) β€” Event representing file/directory deletion.
  • on_modified(event: DirModifiedEvent | FileModifiedEvent) -> None β€” Called when a file or directory is modified.
    • event (DirModifiedEvent or FileModifiedEvent) β€” Event representing file/directory modification.
  • on_moved(event: DirMovedEvent | FileMovedEvent) -> None β€” Called when a file or a directory is moved or renamed.
    • event (DirMovedEvent or FileMovedEvent) β€” Event representing file/directory movement.
  • on_opened(event: FileOpenedEvent) -> None β€” Called when a file is opened.
    • event (FileOpenedEvent) β€” Event representing file opening.

🧚 watchdog.events.PatternMatchingEventHandler 🧚

class watchdog.events.PatternMatchingEventHandler(*, patterns: list[str] | None = None, ignore_patterns: list[str] | None = None, ignore_directories: bool = False, case_sensitive: bool = False)

Bases: FileSystemEventHandler

Matches given patterns with file paths associated with occurring events. Uses pathlib's PurePath.match() method. patterns and ignore_patterns are expected to be a list of strings. Glob vibes only, no regex drama.

  • property case_sensitive: bool β€” (Read-only) True if path names should be matched sensitive to case; False otherwise.
  • dispatch(event: FileSystemEvent) -> None β€” Dispatches events to the appropriate methods.
    • event (FileSystemEvent) β€” The event object representing the file system event.
  • property ignore_directories: bool β€” (Read-only) True if directories should be ignored; False otherwise.
  • property ignore_patterns: list[str] | None β€” (Read-only) Patterns to ignore matching event paths.
  • property patterns: list[str] | None β€” (Read-only) Patterns to allow matching event paths.

🌈 watchdog.events.RegexMatchingEventHandler 🌈

class watchdog.events.RegexMatchingEventHandler(*, regexes: list[str] | None = None, ignore_regexes: list[str] | None = None, ignore_directories: bool = False, case_sensitive: bool = False)

Bases: FileSystemEventHandler

Matches given regexes with file paths associated with occurring events. Uses the re module. For the girls who think in character classes. I see you. πŸ‘‘

  • property case_sensitive: bool β€” (Read-only) True if path names should be matched sensitive to case; False otherwise.
  • dispatch(event: FileSystemEvent) -> None β€” Dispatches events to the appropriate methods.
    • event (FileSystemEvent) β€” The event object representing the file system event.
  • property ignore_directories: bool β€” (Read-only) True if directories should be ignored; False otherwise.
  • property ignore_regexes: list[Pattern[str]] β€” (Read-only) Regexes to ignore matching event paths.
  • property regexes: list[Pattern[str]] β€” (Read-only) Regexes to allow matching event paths.

πŸŽ€ watchdog.events.LoggingEventHandler πŸŽ€

class watchdog.events.LoggingEventHandler(*, logger: Logger | None = None)

Bases: FileSystemEventHandler

Logs all the events captured. It's giving "narrator of your filesystem". πŸ’…

  • on_closed(event: FileClosedEvent) -> None β€” Called when a file opened for writing is closed.
    • event (FileClosedEvent) β€” Event representing file closing.
  • on_closed_no_write(event: FileClosedNoWriteEvent) -> None β€” Called when a file opened for reading is closed.
    • event (FileClosedNoWriteEvent) β€” Event representing file closing.
  • on_created(event: DirCreatedEvent | FileCreatedEvent) -> None β€” Called when a file or directory is created.
    • event (DirCreatedEvent or FileCreatedEvent) β€” Event representing file/directory creation.
  • on_deleted(event: DirDeletedEvent | FileDeletedEvent) -> None β€” Called when a file or directory is deleted.
    • event (DirDeletedEvent or FileDeletedEvent) β€” Event representing file/directory deletion.
  • on_modified(event: DirModifiedEvent | FileModifiedEvent) -> None β€” Called when a file or directory is modified.
    • event (DirModifiedEvent or FileModifiedEvent) β€” Event representing file/directory modification.
  • on_moved(event: DirMovedEvent | FileMovedEvent) -> None β€” Called when a file or a directory is moved or renamed.
    • event (DirMovedEvent or FileMovedEvent) β€” Event representing file/directory movement.
  • on_opened(event: FileOpenedEvent) -> None β€” Called when a file is opened.
    • event (FileOpenedEvent) β€” Event representing file opening.

πŸ¦‹ watchdog.observers.api πŸ¦‹

πŸ“ Immutables πŸ“

✨ watchdog.observers.api.ObservedWatch ✨

class watchdog.observers.api.ObservedWatch(path: str | Path, *, recursive: bool, event_filter: list[type[FileSystemEvent]] | None = None)

Bases: object

A scheduled watch. Set it and forget it, bestie.

Parameters:

  • path β€” Path string.
  • recursive β€” True if watch is recursive; False otherwise.
  • event_filter β€” Optional collection of watchdog.events.FileSystemEvent to watch
  • property event_filter: frozenset[type[FileSystemEvent]] | None β€” the lil collection of event types we're πŸ‘€ watching for on this path.
  • property is_recursive: bool β€” tells you whether subdirectories get watched for this path too. yes bestie, it goes deep.
  • property path: str β€” the path this watch is monitoring. literally the whole point. πŸ’…

πŸŽ€ Collections πŸŽ€

class watchdog.observers.api.EventQueue(maxsize=0)

Bases: SkipRepeatsQueue

okay so this is a thread-safe event queue built on top of a ✨special✨ queue that skips adding the same event (FileSystemEvent) more than once consecutively. why does that matter? because it means we don't dispatch a bajillion identical event-handling calls when the same identical events show up faster than an observer can actually consume them. it's giving self-care. it's giving not-spamming-your-handler. 🧚


✨ Classes ✨

class watchdog.observers.api.EventEmitter(event_queue: EventQueue, watch: ObservedWatch, *, timeout: float = 1.0, event_filter: list[type[FileSystemEvent]] | None = None)

Bases: BaseThread

this is the producer thread base class β€” the one that gets subclassed by event emitters that generate events and then populate a queue with them. it makes the events, bestie. that's its whole job. 🫢

Parameters:

  • event_queue (watchdog.events.EventQueue) β€” the event queue you're populating with the generated events.
  • watch (ObservedWatch) β€” the watch to observe and produce events for.
  • timeout (float) β€” timeout (in seconds) between successive attempts at reading events.
  • event_filter (Iterable[watchdog.events.FileSystemEvent] | None) β€” collection of event types to emit, or None for no filtering (that's the default).

queue_event(event: FileSystemEvent) -> None

Queues up a single event. one. singular. iconic.

Parameters:

  • event (An instance of watchdog.events.FileSystemEvent or a subclass.) β€” the event to be queued.

queue_events(timeout: float) -> None

override this method to populate the event queue with events per interval period. your moment to shine. ✨

Parameters:

  • timeout (float) β€” timeout (in seconds) between successive attempts at reading events.

run() -> None

method representing the thread's activity.

you may override this method in a subclass. the standard run() method invokes the callable object passed to the object's constructor as the target argument, if any, with sequential and keyword arguments taken from the args and kwargs arguments, respectively.

property timeout: float

blocking timeout for reading events.

property watch: ObservedWatch

the watch associated with this emitter. it's their whole situationship. πŸ’œ


class watchdog.observers.api.EventDispatcher(*, timeout: float = 1.0)

Bases: BaseThread

the consumer thread base class β€” subclassed by event observer threads that take events off an event queue and dispatch them to the appropriate event handlers. producer's counterpart. the other half of the ship. 😭

Parameters:

  • timeout (float) β€” timeout value (in seconds) passed to emitters constructions in the child class BaseObserver.

dispatch_events(event_queue: EventQueue) -> None

override this method to consume events from an event queue, blocking on the queue for the specified timeout before raising queue.Empty.

Parameters:

  • event_queue (EventQueue) β€” event queue to populate with one set of events.

Raises: queue.Empty

property event_queue: EventQueue

the event queue which is populated with file system events by emitters, and from which events are dispatched by a dispatcher thread. it's the middle of the relay race, fr fr. πŸƒβ€β™€οΈ

run() -> None

method representing the thread's activity.

you may override this method in a subclass. the standard run() method invokes the callable object passed to the object's constructor as the target argument, if any, with sequential and keyword arguments taken from the args and kwargs arguments, respectively.

stop() -> None

signals the thread to stop. that's it. that's the whole function.

stop_event = <object object>

the event inserted into the queue to signal a requested stop. lowkey just a sentinel object doing sentinel things. πŸ›‘

property timeout: float

timeout value to construct emitters with.


class watchdog.observers.api.BaseObserver(emitter_class: type[EventEmitter], *, timeout: float = 1.0)

Bases: EventDispatcher

base observer. the blueprint. the mother of observers. πŸ‘‘

add_handler_for_watch(event_handler: FileSystemEventHandler, watch: ObservedWatch) -> None

adds a handler for the given watch. now that watch has someone listening to it. πŸ₯Ή

Parameters:

  • event_handler (watchdog.events.FileSystemEventHandler or a subclass) β€” an event handler instance that has appropriate event handling methods which will be called by the observer in response to file system events.
  • watch (An instance of ObservedWatch or a subclass of ObservedWatch) β€” the watch to add a handler for.

dispatch_events(event_queue: EventQueue) -> None

override this method to consume events from an event queue, blocking on the queue for the specified timeout before raising queue.Empty.

Parameters:

  • event_queue (EventQueue) β€” event queue to populate with one set of events.

Raises: queue.Empty

property emitters: set[EventEmitter]

returns event emitter created by this observer. yes, the emitters. plural. a whole squad. πŸ«‚

on_thread_stop() -> None

override this method instead of stop(). stop() calls this method.

this method is called immediately after the thread is signaled to stop.

remove_handler_for_watch(event_handler: FileSystemEventHandler, watch: ObservedWatch) -> None

removes a handler for the given watch. it's giving mutual breakup energy. πŸ’”

Parameters:

  • event_handler (watchdog.events.FileSystemEventHandler or a subclass) β€” an event handler instance that has appropriate event handling methods which will be called by the observer in response to file system events.
  • watch (An instance of ObservedWatch or a subclass of ObservedWatch) β€” the watch to remove a handler for.

schedule(event_handler: FileSystemEventHandler, path: str, *, recursive: bool = False, event_filter: list[type[FileSystemEvent]] | None = None) -> ObservedWatch

schedules watching a path and calls the appropriate methods specified in the given event handler in response to file system events. this is the main character of this class, no cap. 🌟

Parameters:

  • event_handler (watchdog.events.FileSystemEventHandler or a subclass) β€” an event handler instance that has appropriate event handling methods which will be called by the observer in response to file system events.
  • path (str) β€” directory path that will be monitored.
  • recursive (bool) β€” True if events will be emitted for sub-directories traversed recursively; False otherwise.
  • event_filter (Iterable[watchdog.events.FileSystemEvent] | None) β€” collection of event types to emit, or None for no filtering (that's the default).

Returns: An ObservedWatch object instance representing a watch.

start() -> None

start the thread's activity.

it must be called at most once per thread object. it arranges for the object's run() method to be invoked in a separate thread of control.

⚠️ this method will raise a RuntimeError if called more than once on the same thread object. so like... don't do that. once and done, bestie. 😭

unschedule(watch: ObservedWatch) -> None

unschedules a watch.

Parameters:

  • watch (An instance of ObservedWatch or a subclass of ObservedWatch) β€” the watch to unschedule.

unschedule_all() -> None

unschedules all watches and detaches all associated event handlers. the nuclear option. the "i'm cleaning my room and throwing everything out" option. 🧹✨


πŸ‘‘ watchdog.observers πŸ‘‘

module watchdog.observers

synopsis

Observer that picks a native implementation if available. like it just knows which one to use. iykyk. πŸ’…

author

yesudeep@google.com (Yesudeep Mangalapilly)

author

contact@tiger-222.fr (MickaΓ«l Schoentgen)


🌈 Classes 🌈

watchdog.observers.Observer

alias of InotifyObserver

Observer thread that schedules watching directories and dispatches calls to event handlers.

you can also import platform specific classes directly and use it instead of Observer. here's the list of implemented observer classes, bestie, take notes πŸ“:

  • inotify.InotifyObserver β€” Platforms: Linux 2.6.13+ β€” Note: inotify(7) based observer
  • fsevents.FSEventsObserver β€” platform: macOS Β· it's the FSEvents based observer πŸ’…
  • kqueue.KqueueObserver β€” platform: macOS and BSD with kqueue(2) Β· it's the kqueue(2) based observer πŸ¦‹
  • read_directory_changes.WindowsApiObserver β€” platform: Microsoft Windows Β· it's the Windows API-based observer πŸͺŸ
  • polling.PollingObserver β€” platform: Any Β· this is the fallback implementation, bestie, the one that always shows up 🫢

🌸 module watchdog.observers.polling

okay so, module watchdog.observers.polling β€” say hi πŸ‘‹

synopsis β€” Polling emitter implementation.

author β€” yesudeep@google.com (Yesudeep Mangalapilly)

author β€” contact@tiger-222.fr (MickaΓ«l Schoentgen)

πŸ’– Classes

  • class watchdog.observers.polling.PollingObserver(*, timeout: float = 1.0)

Bases: BaseObserver

Platform-independent observer that polls a directory to detect file system changes. no cap, it just keeps checking, like a bestie refreshing your story πŸ’…

  • class watchdog.observers.polling.PollingObserverVFS(stat: Callable[[str], os.stat_result], listdir: Callable[[str | None], Iterator[os.DirEntry]], *, polling_interval: int = 1)

Bases: BaseObserver

File system independent observer that polls a directory to detect changes. it does not care what filesystem you're on, it simply ✨polls✨

__init__(stat: Callable[[str], os.stat_result], listdir: Callable[[str | None], Iterator[os.DirEntry]], *, polling_interval: int = 1) -> None

Parameters

  • stat -- stat function. See os.stat for details.
  • listdir -- listdir function. See os.scandir for details.
  • polling_interval (int) -- interval in seconds between polling the file system.

πŸŽ€ module watchdog.utils

module watchdog.utils β€” the little helper drawer everyone digs through πŸ”₯

synopsis β€” Utility classes and functions.

author β€” yesudeep@google.com (Yesudeep Mangalapilly)

author β€” contact@tiger-222.fr (MickaΓ«l Schoentgen)

🌈 Classes

  • class watchdog.utils.BaseThread

Bases: Thread

Convenience class for creating stoppable threads. a thread that you can actually tell to chill πŸ’…

  • property daemon β€” A boolean value indicating whether this thread is a daemon thread.

This must be set before start() is called, otherwise RuntimeError is raised. Its initial value is inherited from the creating thread; the main thread is not a daemon thread and therefore all threads created in the main thread default to daemon = False.

The entire Python program exits when only daemon threads are left. 😭 that's the vibe, they go down with the ship

  • getName() β€” Return a string used for identification purposes only.
This method is deprecated, use the name attribute instead.
  • property ident β€” Thread identifier of this thread or None if it has not been started.

This is a nonzero integer. See the get_ident() function. Thread identifiers may be recycled when a thread exits and another thread is created. The identifier is available even after the thread has exited. iconic, it lingers πŸ’€

  • isDaemon() β€” Return whether this thread is a daemon.
This method is deprecated, use the daemon attribute instead.
  • is_alive() β€” Return whether the thread is alive.

This method returns True just before the run() method starts until just after the run() method terminates. See also the module function enumerate().

  • join(timeout=None) β€” Wait until the thread terminates.

This blocks the calling thread until the thread whose join() method is called terminates -- either normally or through an unhandled exception or until the optional timeout occurs.

When the timeout argument is present and not None, it should be a floating-point number specifying a timeout for the operation in seconds (or fractions thereof). As join() always returns None, you must call is_alive() after join() to decide whether a timeout happened -- if the thread is still alive, the join() call timed out.

When the timeout argument is not present or None, the operation will block until the thread terminates.

A thread can be join()ed many times. yes queen, do it as many times as you want ✨

join() raises a RuntimeError if an attempt is made to join the current thread as that would cause a deadlock. It is also an error to join() a thread before it has been started and attempts to do so raises the same exception.

⚠️ joining yourself = deadlock, and joining a thread that never started = error. do not do either, fr fr
  • property name β€” A string used for identification purposes only.

It has no semantics. Multiple threads may be given the same name. The initial name is set by the constructor.

  • property native_id β€” Native integral thread ID of this thread, or None if it has not been started.

This is a non-negative integer. See the get_native_id() function. This represents the Thread ID as reported by the kernel. 🧚 that's the real one, straight from the kernel

  • on_thread_start() -> None β€” Override this method instead of start(). start() calls this method.

This method is called right before this thread is started and this object's run() method is invoked.

  • on_thread_stop() -> None β€” Override this method instead of stop(). stop() calls this method.

This method is called immediately after the thread is signaled to stop.

  • run() β€” Method representing the thread's activity.

You may override this method in a subclass. The standard run() method invokes the callable object passed to the object's constructor as the target argument, if any, with sequential and keyword arguments taken from the args and kwargs arguments, respectively.

  • setDaemon(daemonic) β€” Set whether this thread is a daemon.
This method is deprecated, use the .daemon property instead.
  • setName(name) β€” Set the name string for this thread.
This method is deprecated, use the name attribute instead.
  • should_keep_running() -> bool β€” Determines whether the thread should continue running. 🫢 vibe check for your loop
  • start() -> None β€” Start the thread's activity.

It must be called at most once per thread object. It arranges for the object's run() method to be invoked in a separate thread of control.

This method will raise a RuntimeError if called more than once on the same thread object.

  • stop() -> None β€” Signals the thread to stop.

πŸ¦‹ module watchdog.utils.dirsnapshot

module watchdog.utils.dirsnapshot β€” the memory-keeping one, lowkey the main character of diffing πŸ“Έ

synopsis β€” Directory snapshots and comparison.

author β€” yesudeep@google.com (Yesudeep Mangalapilly)

author β€” contact@tiger-222.fr (MickaΓ«l Schoentgen)

### 😭 Where are the moved events? They 'disappeared' This implementation does not take partition boundaries into consideration. It will only work when the directory tree is entirely on the same file system. More specifically, any part of the code that depends on inode numbers can break if partition boundaries are crossed. In these cases, the snapshot diff will represent file/directory movement as created and deleted events. bestie read this twice. cross a partition boundary and your "moved" file shows up as a brand new file plus a whole deleted file. not a move. πŸ’€

🌸 Classes

  • class watchdog.utils.dirsnapshot.DirectorySnapshot(path: str, *, recursive: bool = True, stat: Callable[[str], os.stat_result] = <built-in function stat>, listdir: Callable[[str | None], Iterator[os.DirEntry]] = <built-in function scandir>)

Bases: object

A snapshot of stat information of files in a directory. like a screenshot but for every stat in the tree πŸ“Έ

Parameters

  • path (str) -- The directory path for which a snapshot should be taken.
  • recursive (bool) -- True if the entire directory tree should be included in the snapshot; False otherwise.
  • stat --

Use custom stat function that returns a stat structure for path. Currently only st_dev, st_ino, st_mode and st_mtime are needed.

A function taking a path as argument which will be called for every entry in the directory tree.

  • listdir -- Use custom listdir function. For details see os.scandir.
  • inode(path: bytes | str) -> tuple[int, int] β€” Returns an id for path.
  • path(uid: tuple[int, int]) -> bytes | str | None β€” Returns path for id. None if id is unknown to this snapshot. πŸ™ˆ no idea who that is, never met them
  • property paths: set[bytes | str] β€” Set of file/directory paths in the snapshot.
  • stat_info(path: bytes | str) -> stat_result β€” Returns a stat information object for the specified path from the snapshot.
Heads up bestie: attached info is subject to change. Do NOT use it unless you specify stat in the constructor. Use inode(), mtime(), isdir() instead. ✨

Parameters

  • path β€” the path you want the stat info for, pulled straight out of a snapshot. 🫢

πŸ’… class watchdog.utils.dirsnapshot.DirectorySnapshotDiff(ref: DirectorySnapshot, snapshot: DirectorySnapshot, *, ignore_device: bool = False)

Bases: object

Okay so this one compares two directory snapshots and makes you an object that represents the difference between the two. It's giving "spot the difference" but make it filesystem. πŸ”₯

Parameters

  • ref (DirectorySnapshot) β€” the reference directory snapshot.
  • snapshot (DirectorySnapshot) β€” the directory snapshot that's gonna get compared against the reference one.
  • ignore_device (bool) β€” a boolean saying whether to ignore the device id or not. By default, a file can be uniquely identified by a combo of its first inode and its device id. The problem? The device id may (or may not 😭) change between system boots. That would make DirectorySnapshotDiff think a file got deleted and created again when it's literally the exact same file. Only set this to True if you're 100% sure you'll always use the same device.

πŸ¦‹ class ContextManager(path: str, *, recursive: bool = True, stat: Callable[[str], os.stat_result] = <built-in function stat>, listdir: Callable[[str | None], Iterator[os.DirEntry]] = <built-in function scandir>, ignore_device: bool = False)

Bases: object

A context manager that creates two directory snapshots plus a diff object representing the difference between them. So much slay in one context manager fr fr. πŸ’–

Parameters

  • path (str) β€” the directory path you want a snapshot taken of.
  • recursive (bool) β€” True if the entire directory tree should be in the snapshot; False otherwise.
  • stat β€” use a custom stat function that returns a stat structure for path. Currently only st_dev, st_ino, st_mode and st_mtime are needed.

A function taking a path as argument which will be called for every entry in the directory tree.

  • listdir β€” use a custom listdir function. For details see os.scandir.
  • ignore_device (bool) β€” a boolean saying whether to ignore the device id or not. By default, a file can be uniquely identified by a combo of its first inode and its device id. The problem? The device id may (or may not 😭) change between system boots. That would make DirectorySnapshotDiff think a file got deleted and created again when it's literally the exact same file. Only set this to True if you're 100% sure you'll always use the same device.

πŸŽ€ the properties, bestie

  • property dirs_created: list[bytes | str] β€” list of directories that were created. πŸ‘‘
  • property dirs_deleted: list[bytes | str] β€” list of directories that were deleted. πŸ’€
  • property dirs_modified: list[bytes | str] β€” list of directories that were modified.
  • property dirs_moved: list[tuple[bytes | str, bytes | str]] β€” list of directories that were moved.

Each event is a two-tuple where the first item is the path that's been renamed to the second item in the tuple. iykyk.

  • property files_created: list[bytes | str] β€” list of files that were created. ✨
  • property files_deleted: list[bytes | str] β€” list of files that were deleted.
  • property files_modified: list[bytes | str] β€” list of files that were modified.
  • property files_moved: list[tuple[bytes | str, bytes | str]] β€” list of files that were moved.

Each event is a two-tuple where the first item is the path that's been renamed to the second item in the tuple. Same vibe as dirs_moved, no cap.


🌸 class watchdog.utils.dirsnapshot.EmptyDirectorySnapshot

Bases: DirectorySnapshot

A class that implements an empty snapshot. It gets used together with DirectorySnapshot and DirectorySnapshotDiff so you can get all the files/folders in the directory as created. Iconic, honestly. 🫢

  • static path(_: Any) -> None β€” mock-up method that returns the path of the received inode. Since the snapshot is meant to be empty, it always returns None.

Returns: None.

  • property paths: set β€” mock-up method that returns a set of file/directory paths in the snapshot. Since the snapshot is meant to be empty, it always returns an empty set.

Returns: an empty set.


🧚 watchdog.tricks

module watchdog.tricks

synopsis β€” utility event handlers. That's the whole vibe. πŸ“

author yesudeep@google.com (Yesudeep Mangalapilly)

author contact@tiger-222.fr (MickaΓ«l Schoentgen)


πŸ’œ Classes

class watchdog.tricks.Trick(*, patterns: list[str] | None = None, ignore_patterns: list[str] | None = None, ignore_directories: bool = False, case_sensitive: bool = False)

Bases: PatternMatchingEventHandler

Your tricks should subclass this class. Yes, your tricks. Go off. πŸ‘‘


class watchdog.tricks.LoggerTrick(*, patterns: list[str] | None = None, ignore_patterns: list[str] | None = None, ignore_directories: bool = False, case_sensitive: bool = False)

Bases: Trick

A simple trick that does nothing but log events. Lowkey the chillest trick in the lineup.

  • on_any_event(event: FileSystemEvent) -> None β€” catch-all event handler.

Parameters

  • event (FileSystemEvent) β€” the event object representing the file system event.

class watchdog.tricks.ShellCommandTrick(shell_command: str, *, patterns: list[str] | None = None, ignore_patterns: list[str] | None = None, ignore_directories: bool = False, wait_for_process: bool = False, drop_during_process: bool = False)

Bases: Trick

Executes shell commands in response to matched events. Main character energy fr. πŸ’…

  • on_any_event(event: FileSystemEvent) -> None β€” catch-all event handler.

Parameters

  • event (FileSystemEvent) β€” the event object representing the file system event.

class watchdog.tricks.AutoRestartTrick(command: list[str], *, patterns: list[str] | None = None, ignore_patterns: list[str] | None = None, ignore_directories: bool = False, stop_signal: Signals | int = Signals.SIGINT, kill_after: int = 10, debounce_interval_seconds: int = 0, restart_on_command_exit: bool = True)

Bases: Trick

Starts a long-running subprocess and restarts it on matched events. It's giving "server that refuses to die". πŸ”₯

The command parameter is a list of command arguments, like ['bin/myserver', '-c', 'etc/myconfig.ini'].

Call start() after creating the Trick. Call stop() when you're stopping the process. Don't forget, bestie. πŸ™ˆ

  • on_any_event(event: FileSystemEvent) -> None β€” catch-all event handler.

Parameters

  • event (FileSystemEvent) β€” the event object representing the file system event.

🌈 CONTRIBUTING

Welcome hacker! So you've got something you'd like to see in watchdog? Whee. πŸŽ‰ This document will help you get started.

Important URLs

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

Before you start

Make sure your system has the following programs and libraries installed before you start hacking:

  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:
$ git clone https://github.com/gorakhargosh/watchdog.git
$ cd watchdog
$ python -m venv venv
  1. Linux
$ . venv/bin/activate
(venv)$ python -m pip instal -e '.'
  1. Windows
> venv\Scripts\activate
(venv)> python -m pip instal -e '.'

That's it with the setup. Now you're ready to hack on watchdog. 🫢

Happy hacking!

Found a bug in or want a feature added to watchdog? You can fork the official code repository or file an issue ticket at the issue tracker. You may also want to refer to Contributing for info about contributing code or documentation to watchdog. ✨

  • Index
  • Module Index
  • Search Page

πŸ‘‘ AUTHOR

Yesudeep Mangalapilly, MickaΓ«l Schoentgen, and contributors

2010-2024, Yesudeep Mangalapilly, MickaΓ«l Schoentgen, and contributors


and that's the whole page, bestie!! 🌸 this one's WATCHDOG(3), version 6.0.0, dated Nov 20, 2024 β€” go forth and watch those directories, you absolute icon. slay πŸ’…βœ¨

πŸ“¦ where this page comes from