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.watchdogneeds one per directory to monitor. To change this limit, edit/etc/sysctl.confand add:
fs.inotify.max_user_watches=16384
macOS π
The Darwin kernel/OS X API maintains two ways to monitor directories for file system events:
kqueueFSEvents
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 howwatchdoguseskqueue(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 hinderwatchdog'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~/.profileconfiguration 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,watchdogtries hard to convert renames to movement events. Also, because theReadDirectoryChangesWAPI function returns rename/movement events for directories even before the underlying I/O is complete,watchdogmay 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:
- Create an instance of the
watchdog.observers.Observerthread class. - Implement a subclass of
watchdog.events.FileSystemEventHandler. - Schedule monitoring a few paths with the observer instance attaching the event handler.
- 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.
- event (
on_any_event(event: FileSystemEvent) -> Noneβ Catch-all event handler.- event (
FileSystemEvent) β The event object representing the file system event.
- event (
on_closed(event: FileClosedEvent) -> Noneβ Called when a file opened for writing is closed.- event (
FileClosedEvent) β Event representing file closing.
- event (
on_closed_no_write(event: FileClosedNoWriteEvent) -> Noneβ Called when a file opened for reading is closed.- event (
FileClosedNoWriteEvent) β Event representing file closing.
- event (
on_created(event: DirCreatedEvent | FileCreatedEvent) -> Noneβ Called when a file or directory is created.- event (
DirCreatedEventorFileCreatedEvent) β Event representing file/directory creation.
- event (
on_deleted(event: DirDeletedEvent | FileDeletedEvent) -> Noneβ Called when a file or directory is deleted.- event (
DirDeletedEventorFileDeletedEvent) β Event representing file/directory deletion.
- event (
on_modified(event: DirModifiedEvent | FileModifiedEvent) -> Noneβ Called when a file or directory is modified.- event (
DirModifiedEventorFileModifiedEvent) β Event representing file/directory modification.
- event (
on_moved(event: DirMovedEvent | FileMovedEvent) -> Noneβ Called when a file or a directory is moved or renamed.- event (
DirMovedEventorFileMovedEvent) β Event representing file/directory movement.
- event (
on_opened(event: FileOpenedEvent) -> Noneβ Called when a file is opened.- event (
FileOpenedEvent) β Event representing file opening.
- event (
π§ 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.
- 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.
- 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.
- event (
on_closed_no_write(event: FileClosedNoWriteEvent) -> Noneβ Called when a file opened for reading is closed.- event (
FileClosedNoWriteEvent) β Event representing file closing.
- event (
on_created(event: DirCreatedEvent | FileCreatedEvent) -> Noneβ Called when a file or directory is created.- event (
DirCreatedEventorFileCreatedEvent) β Event representing file/directory creation.
- event (
on_deleted(event: DirDeletedEvent | FileDeletedEvent) -> Noneβ Called when a file or directory is deleted.- event (
DirDeletedEventorFileDeletedEvent) β Event representing file/directory deletion.
- event (
on_modified(event: DirModifiedEvent | FileModifiedEvent) -> Noneβ Called when a file or directory is modified.- event (
DirModifiedEventorFileModifiedEvent) β Event representing file/directory modification.
- event (
on_moved(event: DirMovedEvent | FileMovedEvent) -> Noneβ Called when a file or a directory is moved or renamed.- event (
DirMovedEventorFileMovedEvent) β Event representing file/directory movement.
- event (
on_opened(event: FileOpenedEvent) -> Noneβ Called when a file is opened.- event (
FileOpenedEvent) β Event representing file opening.
- event (
π¦ 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.FileSystemEventto 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, orNonefor no filtering (that's the default).
queue_event(event: FileSystemEvent) -> None
Queues up a single event. one. singular. iconic.
Parameters:
event(An instance ofwatchdog.events.FileSystemEventor 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 classBaseObserver.
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.FileSystemEventHandleror 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 ofObservedWatchor a subclass ofObservedWatch) β 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.FileSystemEventHandleror 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 ofObservedWatchor a subclass ofObservedWatch) β 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.FileSystemEventHandleror 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) βTrueif events will be emitted for sub-directories traversed recursively;Falseotherwise.event_filter(Iterable[watchdog.events.FileSystemEvent] | None) β collection of event types to emit, orNonefor 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 ofObservedWatchor a subclass ofObservedWatch) β 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 observerfsevents.FSEventsObserverβ platform: macOS Β· it's the FSEvents based observer πkqueue.KqueueObserverβ platform: macOS and BSD withkqueue(2)Β· it's thekqueue(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.statfor details. - listdir -- listdir function. See
os.scandirfor 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 orNoneif 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, orNoneif 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 ofstart().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 ofstop().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 loopstart() -> 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) --Trueif the entire directory tree should be included in the snapshot;Falseotherwise. - 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 forpath.path(uid: tuple[int, int]) -> bytes | str | Noneβ Returns path for id.Noneif 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 specifystatin the constructor. Useinode(),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 makeDirectorySnapshotDiffthink a file got deleted and created again when it's literally the exact same file. Only set this toTrueif 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) βTrueif the entire directory tree should be in the snapshot;Falseotherwise.statβ use a custom stat function that returns a stat structure forpath. Currently onlyst_dev,st_ino,st_modeandst_mtimeare 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 seeos.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 makeDirectorySnapshotDiffthink a file got deleted and created again when it's literally the exact same file. Only set this toTrueif 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 returnsNone.
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:
- Python
- git
- XCode (on macOS)
Setting up the Work Environment
Steps to setting up a clean environment:
- Fork the code repository into your github account.
- Clone fork and create virtual environment:
$ git clone https://github.com/gorakhargosh/watchdog.git
$ cd watchdog
$ python -m venv venv
- Linux
$ . venv/bin/activate
(venv)$ python -m pip instal -e '.'
- 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
π COPYRIGHT
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
- debian trixie: python3-watchdog 6.0.0-1 Β· Apache-2
- ubuntu questing: python3-watchdog 6.0.0-1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms