inotify-simple
inotify-simple is a lightweight Python wrapper around the Linux `inotify` API, implemented using `ctypes`. It provides a direct, low-level interface to filesystem events without much abstraction, making it efficient and close to the kernel's behavior. The library is currently at version 2.0.1 and is actively maintained with a stable release cadence.
Warnings
- gotcha inotify, and by extension `inotify-simple`, does not recursively monitor subdirectories. To monitor an entire directory tree, you must explicitly add watches for each subdirectory. New subdirectories created after the initial setup will also require new watches to be added programmatically.
- gotcha The `INotify.read()` method is blocking by default when `timeout` is `None` or negative. If your application needs to perform other tasks while waiting for events, use a non-blocking approach (e.g., `timeout=0` or a positive timeout) or integrate with `select.select()`/`selectors` to monitor multiple file descriptors, including the `inotify` instance.
- gotcha The kernel's `inotify` event queue has a limited size (`/proc/sys/fs/inotify/max_queued_events`). If events are generated faster than they are consumed by the application, the queue can overflow, leading to lost events. Robust applications should anticipate and handle this possibility.
- gotcha `inotify` events are reported with a watch descriptor (`wd`) and a `name` (filename). The `name` field might refer to a file that has already been deleted or renamed by the time the event is processed. It is the application's responsibility to maintain a mapping between `wd`s and current file paths if needed, and to handle stale `name` references.
- gotcha The `inotify` API does not provide information about the user or process that triggered a filesystem event. All events appear to originate from the kernel. Also, it does not monitor events on network filesystems.
Install
-
pip install inotify-simple
Imports
- INotify
from inotify_simple import INotify
- flags
from inotify_simple import flags
- Event
from inotify_simple import Event
Quickstart
import os
import time
from inotify_simple import INotify, flags
# Create a temporary directory to watch
watch_dir = '/tmp/inotify_test_simple'
os.makedirs(watch_dir, exist_ok=True)
inotify = INotify()
# Add a watch for create, delete, and modify events
# flags.CLOSE_WRITE is often useful for 'file saved' events
watch_flags = flags.CREATE | flags.DELETE | flags.MODIFY | flags.CLOSE_WRITE
wd = inotify.add_watch(watch_dir, watch_flags)
print(f"Watching directory: {watch_dir} (watch descriptor: {wd})")
print("Create, modify, or delete files in this directory. Press Ctrl+C to exit.")
try:
while True:
# Read events with a timeout (e.g., 1000 ms = 1 second)
# Events are returned as a list of namedtuple objects
events = inotify.read(timeout=1000)
if not events:
# print("No events in the last second.") # Uncomment for verbose output
continue
for event in events:
print(f"Event: wd={event.wd}, mask={event.mask} ({flags.from_mask(event.mask)}), cookie={event.cookie}, name='{event.name}'")
# Example: react to a file creation
if flags.CREATE in flags.from_mask(event.mask):
print(f" New file/directory created: {os.path.join(watch_dir, event.name)}")
if flags.DELETE in flags.from_mask(event.mask):
print(f" File/directory deleted: {os.path.join(watch_dir, event.name)}")
if flags.CLOSE_WRITE in flags.from_mask(event.mask):
print(f" File written and closed: {os.path.join(watch_dir, event.name)}")
except KeyboardInterrupt:
print("Monitoring stopped.")
finally:
inotify.rm_watch(wd)
inotify.close()
# Clean up the temporary directory
# os.rmdir(watch_dir) # Only if empty
print(f"Removed watch for {watch_dir} and closed inotify instance.")