Combining inotify and python with pyinotify

While working on a python project recently, I got to the point where I had to monitor a file for modifications. For example, I want to monitor an sqlite database (which is a normal file) to check if I’m the only one modifying it. Fortunately, pyinotify comes to the rescue! Unfortunately, the documentation on their website is a little outdated. Something important to be noted is that pyinotify is based on a Linux Kernel feature called inotify; this means that it’s only available under Linux.

Anyway, after several tries and failures I manage to come up with a decent implementation of a watcher class. The example I’m about to provide uses ThreadedNotifier, since my watcher is supposed to allow my GUI application to run in parallel. Also, please note that you can’t monitor the file itself, but instead you need to monitor the changes to files in a directory! This part was somehow omitted from the documentation; I wonder why.

Here is the code for the class:

import os.path
import pyinotify

class FileWatcher(object):
    def __init__(self, file_list):
        self.file_list = set([os.path.abspath(f) for f in file_list])
        self.watch_dirs = set([os.path.dirname(f) for f in self.file_list])

    def handler(self, event):
        if event.pathname in self.file_list:
            print "Event: ", event.maskname, ", triggered by: ", event.pathname

    def start(self):
        handler = self.handler
        class EventHandler(pyinotify.ProcessEvent):
            def process_default(self, event):
                handler(event)

        wm = pyinotify.WatchManager()  # Watch Manager

        mask = pyinotify.IN_MODIFY

        ev = EventHandler()
        self.notifier = pyinotify.ThreadedNotifier(wm, ev)

        for watch_this in self.watch_dirs:
            wm.add_watch(watch_this, mask, rec=True)

        self.notifier.start()

    def stop(self):
        self.notifier.stop()

All that is left now is to run it inside your program’s main loop:

#!/usr/bin/python
...
from <file containing the FileWatcher class> import FileWatcher

...

watcher = FileWatcher([file1, file2, ...])
watcher.start()

# your application code goes here
... 

# in your cleanup sequence
watcher.stop()

</file>

Enjoy!

Andrei~

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>