Search code examples
pythonpython-watchdog

Python watchdog loops forever on os.system()


I try to build a throw-away script which automatically compiles my latex document after every change.

The relevant code:

class LatexCompiler(FileSystemEventHandler):
    def on_modified(self, event):
        if isinstance(event, watchdog.events.FileModifiedEvent):
            print event
            os.system("pdflatex Thesis.tex")

if __name__ == "__main__":
    path = sys.argv[1] if len(sys.argv) > 1 else '.'

    os.chdir("/path/to/my/tex/file")
    observer = Observer()
    observer.schedule(LatexCompiler(), path, recursive=True)
    observer.start()

    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()

    observer.join()

As soon as I add the os.system(...) line the on_modified() method starts to loop forever after triggering. To ensure that on_modified() is called only once I've omitted the call to os.system() and there it is, just one line got printed describing the event.

So what is going wrong?


Solution

  • The event handler on_modified() is called whenever any existing file in the monitored directory is modified.

    I'm guessing, but its likely that pdflatex creates intermediate files which it then modifies. Or it could just be that the output pdf file exists from a previous run and is then modified by pdflatex. Either way this would trigger the on_modified() handler, which in turn runs pdflatex again (modifying file(s)), which triggers another call to on_modified() .... you get the idea.

    You can monitor a specific set of files, your input tex files, and then trigger pdflatex only if one of those files is modified. There are some details to clean up, but the following should give you an idea.

    import os, time, sys
    import watchdog.events
    from watchdog.events import FileSystemEventHandler
    from watchdog.observers import Observer
    
    
    class LatexCompiler(FileSystemEventHandler):
        def __init__(self, files, *args, **kwargs):
            super(LatexCompiler, self).__init__(*args, **kwargs)
            self._files = files
            print "LatexCompiler(): monitoring files %r" % self._files
    
        def on_modified(self, event):
            if (isinstance(event, watchdog.events.FileModifiedEvent) and
                    event.src_path in self._files):
                print event
                os.system("pdflatex %s" % event.src_path)
    
    if __name__ == "__main__":
        path = sys.argv[1] if len(sys.argv) > 1 else '.'
    
        observer = Observer()
        files = [os.path.join(path, f) for f in ['Thesis.tex', 'Resume.tex']]
        observer.schedule(LatexCompiler(files), path, recursive=True)
        observer.start()
    
        try:
            while True:
                time.sleep(1)
        except KeyboardInterrupt:
            observer.stop()
    
        observer.join()