#
import os
import time
from collections import namedtuple
#
class SourceFile(namedtuple('SourceFile', 'destination source process prefix')):

    def __new__(cls, destination, source, process=True, prefix=None):
        return super(SourceFile, cls).__new__(cls,
                                              source=source,
                                              destination=destination,
                                              process=process,
                                              prefix=prefix)
#

Descriptor (non-data) for building an attribute on-demand on first use.

class cached_property(object):
#

is called such: factory(instance) to build the attribute.

    def __init__(self, factory):

        self._attr_name = factory.__name__
        self._factory = factory
#

Build the attribute.

    def __get__(self, instance, owner):

        attr = self._factory(instance)
#

Cache the value; hide ourselves.

        setattr(instance, self._attr_name, attr)

        return attr
#

Shift items off the front of the array until it is empty, then return default.

def shift(array, default):

    try:
        return array.pop(0)
    except IndexError:
        return default
#

Ensure directory

Ensure that the destination directory exists.

def ensure_directory(directory):

    if not os.path.isdir(directory):
        os.makedirs(directory)
#

Monitor each source file and re-generate documentation on change.

def monitor(path, file_modified, file_changed):
#

The watchdog modules are imported in main() but we need to re-import here to bring them into the local namespace.

    import watchdog.events
    import watchdog.observers

    path = os.path.normpath(path)
#

A handler for recompiling files which triggered watchdog events

    class RegenerateHandler(watchdog.events.FileSystemEventHandler):
#

Skip files and directories starting with

        def dispatch(self, event):

            if any([f.startswith('.')
                    for f in os.path.relpath(event.src_path, path).split(os.sep)]):
                return

            task = None
            if event.event_type == "modified":
                if not event.is_directory:
                    task = file_modified
                else:
                    return
            else:
                task = file_changed

            if task:
                print("\n")
                print("{} \"{}\" was {}, generating documentation...".format(
                    "Directory" if event.is_directory else "File",
                    event.src_path,
                    event.event_type
                ))
                task()
#

Set up an observer which monitors all directories for files given on the command line and notifies the handler defined above.

    event_handler = RegenerateHandler()
    observer = watchdog.observers.Observer()
    observer.schedule(event_handler, path=path, recursive=True)
#

Run the file change monitoring loop until the user hits Ctrl-C.

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