ekl
ekl

Reputation: 1051

Watchdog library in Python on OS X -- not showing full event path

I just started working with the Watchdog library in Python on Mac, and am doing some basic tests to make sure things are working like I would expect. Unfortunately, they're not -- I can only seem to obtain the path to the folder containing the file where an event was registered, not the path to the file itself.

Below is a simple test program (slightly modified from the example provided by Watchdog) to print out the event type, path, and time whenever an event is registered.

import time
from watchdog.observers import Observer
from watchdog.events import LoggingEventHandler
from watchdog.events import FileSystemEventHandler

class TestEventHandler(FileSystemEventHandler):

def on_any_event(self, event):
    print("event noticed: " + event.event_type + 
                 " on file " + event.src_path + " at " + time.asctime())

if __name__ == "__main__":
    event_handler = TestEventHandler()
    observer = Observer()
    observer.schedule(event_handler, path='~/test', recursive=True)
    observer.start()
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
    observer.join()

The src_path variable should contain the path of the file that had the event happen to it.

However, in my testing, when I modify a file, src_path only prints the path to the folder containing the file, not the path to the file itself. For example, when I modify the file moon.txt in the folder europa, the program prints the following output:

event noticed: modified on file ~/test/europa at Mon Jul  8 15:32:07 2013

What do I need to change in order to obtain the full path to the modified file?

Upvotes: 3

Views: 2398

Answers (2)

Thomas Walther
Thomas Walther

Reputation: 556

Thanks ekl for providing your solution. I just stumbled across the same problem. However, I used to use PatternMatchingEventHandler, which requires small changes to your solution:

  • subclass from FileSystemEventHandler
  • create an attribute pattern where you store your pattern matching. This is not as flexible as the original PatternMatchingEventHandler, but should suffice most needs, and you will get the idea anyway if you want to extend it.

Here's the code you have to put in your FileSystemEventHandlersubclass:

def __init__(self, pattern='*'):
    super(MidiEventHandler, self).__init__()
    self.pattern = pattern


def on_modified(self, event):
    super(MidiEventHandler, self).on_modified(event)

    if event.is_directory:
        files_in_dir = [event.src_path+"/"+f for f in os.listdir(event.src_path)]
        if len(files_in_dir) > 0:
            modifiedFilename = max(files_in_dir, key=os.path.getmtime)
        else:
            return
    else:
        modifiedFilename = event.src_path

    if fnmatch.fnmatch(os.path.basename(modifiedFilename), self.pattern):
        print "Modified MIDI file: %s" % modifiedFilename

One other thing I changed is that I check whether the directory is empty or not before running max() on the file list. max() does not work with empty lists.

Upvotes: 1

ekl
ekl

Reputation: 1051

Problem solved. As it turns out, FSEvents in OS X returns only the directory for file modified events, leaving you to scan the directory yourself to find out which file was modified. This is not mentioned in Watchdog documentation, though it's found easily in FSEvents documentation.

To get the full path to the file, I added the following snippet of code (inspired by this StackOverflow thread) to find the most recently modified file in a directory, to be used whenever event.src_path returns a directory.

if(event.is_directory):
    files_in_dir = [event.src_path+"/"+f for f in os.listdir(event.src_path)]
    mod_file_path = max(files_in_dir, key=os.path.getmtime)

mod_file_path contains the full path to the modified file.

Upvotes: 5

Related Questions