Generating multiple observers with Python watchdog

Great question. This thread is older but I found it while looking up the exact thing and I expanded on your work and added the ability to pass in a file with a list of directories to watch. By default I do not look recursively, I leave that to someone else to test. Hopefully this helps anyone looking up the same topic. Great work!

Run using python watcher.py filename.

Where watcher.py is what I called my script and filename is the name of the file with my paths.

I list the full paths in the file and these are separated by newlines.

i.e.:

C:\path1
C:\Path2\subpath1
C:\PATH3

watcher.py

import logging
import sys
import time
from watchdog.observers import Observer
from watchdog.events import LoggingEventHandler

# Attach a logging event AKA FileSystemEventHandler
event_handler = LoggingEventHandler()

# Create Observer to watch directories
observer = Observer()

# Take in list of paths. If none given, watch CWD
paths = open(sys.argv[1], 'r') if len(sys.argv) > 1 else '.'

# Empty list of observers
observers = []

# Base logging configuration
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s - %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S')

# Iterate through paths and attach observers
for line in paths:

    # Convert line into string and strip newline character
    targetPath = str(line).rstrip()

    # Schedules watching of a given path
    observer.schedule(event_handler, targetPath)

    # Add observable to list of observers
    observers.append(observer)

# Start observer
observer.start()

try:
    while True:

        # Poll every second
        time.sleep(1)

except KeyboardInterrupt:
    for o in observers:
        o.unschedule_all()

        # Stop observer if interrupted
        o.stop()

for o in observers:

    # Wait until the thread terminates before exit
    o.join()

Here's the code I use to watch multiple directories.

import sys
import time
import logging
from watchdog.observers.polling import PollingObserver as Observer
from watchdog.events import LoggingEventHandler

if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO,
                        format='%(asctime)s - %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S')
    event_handler = LoggingEventHandler()
    observer = Observer()
    if len(sys.argv) > 1:
        for i in range(1, len(sys.argv)):
            observer.schedule(event_handler, sys.argv[i], recursive=True)
    else:
        observer.schedule(event_handler, '.', recursive=True)
    observer.start()
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
    observer.join()

The example code here shows a function called start, not start_new_thread. Have you tried that?

https://pypi.python.org/pypi/watchdog

Also, you should probably call start just once, after the for loop, not inside of it.


Just wanna add some notes:

The threading lib and threads list in the code can be a little bit confusing for people who just start using watchdog (including myself). They are actually not necessary in the solution. A simple way to explain it is just:

  • create one observer
  • schedule multiple "watching events"
  • and start the observer.

That's it.