This is a (relatively) cleaned-up version of a Python script I've been working on for the past day or two based on Tim Golden's first solution to the above problem. I know about watchdog but I'm trying to keep dependencies down to a minimum.
I'm concerned about how Pythonic my code is, as this is the first "real" script I've worked on. I'm also unsure of whether I have any redundancies (like all the if not ignored else Nones) or inefficiencies in my code.
Any comments on how I can properly refactor the script are appreciated.
ianus.py
import os
def ianus(path, interval=60, recursive=True, ignore_dirs=False, ignore_files=False):
import time
def path_join(root, dest):
return os.path.join(root, dest)
def path_replace(path):
return path.replace('\\', '/') + ['', '/'][os.path.isdir(path)]
def pathify(root, dest):
return path_replace(path_join(root, dest))
def mod_time(root, dest):
return os.stat(pathify(root, dest)).st_mtime
def build(path, recursive=True, ignore_dirs=False, ignore_files=False):
def flatten(list):
return [item for sublist in list for item in sublist]
if recursive:
walk = list(os.walk(path)) if recursive else None
rdirs = flatten(
[[pathify(root, dir) for dir in dirs] for (root, dirs) in \
[(root, dirs) for (root, dirs, files) in walk]]) \
if not ignore_dirs else None
rfiles = flatten(
[[pathify(root, f) for f in files] for (root, files) in \
[(root, files) for (root, dirs, files) in walk]]) \
if not ignore_files else None
else:
l = [pathify(path, u) for u in os.listdir(path)]
rdirs = [d for d in l if os.path.isdir(d)] \
if not ignore_dirs else None
rfiles = [f for f in l if os.path.isfile(f)] \
if not ignore_files else None
return rdirs, rfiles
path = path_replace(path)
print 'Watching ' + path + '...'
print '---'
dirs_before, files_before = build(path, recursive, ignore_files, ignore_dirs)
dir_times = [(d, mod_time(path, d)) for d in dirs_before] \
if not ignore_dirs else None
file_times = [(f, mod_time(path, f)) for f in files_before] \
if not ignore_files else None
while True:
time.sleep(interval)
dirs_after, files_after = build(path, recursive, ignore_dirs, ignore_files)
new_dir_times = [(d, mod_time(path, d)) for d in dirs_after] \
if not ignore_dirs else None
new_file_times = [(f, mod_time(path, f)) for f in files_after] \
if not ignore_files else None
msg = [None, None]
if not ignore_dirs:
dirs_added = [d for d in dirs_after if not d in dirs_before]
dirs_removed = [d for d in dirs_before if not d in dirs_after]
dirs_updated = [d[0] for d in new_dir_times if not \
((d in dir_times) or (d[0] in files_added))]
msg[0] = (dirs_added, dirs_removed, dirs_updated)
if not ignore_files:
files_added = [f for f in files_after if not f in files_before]
files_removed = [f for f in files_before if not f in files_after]
files_updated = [f[0] for f in new_file_times if not \
((f in file_times) or (f[0] in files_added))]
msg[1] = (files_added, files_removed, files_updated)
print msg
print '---'
dirs_before = dirs_after
files_before = files_after
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-p', type=str,
help='Set the path to be watched.')
parser.add_argument('-intr', type=int,
help='Set the poll interval of the watching thread.')
parser.add_argument('-rec',
help='Checks all subdirectories for changes.')
parser.add_argument('--ignd',
help='Ignores directories. Leaves msg[0] as None.',
action='store_true')
parser.add_argument('--ignf',
help='Ignores files. Leaves msg[1] as None.',
action='store_true')
args = parser.parse_args()
path = os.getcwd()
interval = 60
recursive, ignore_dirs, ignore_files = False, False, False
if args.p:
if os.path.isdir(args.p):
path = args.p
else:
print 'Not a valid directory.'
sys.exit(1)
if args.intr:
if args.intr < 10:
print 'Too short an interval.'
sys.exit(1)
else:
interval = args.intr
if args.rec:
recursive = True
if args.ignd:
ignore_dirs = True
if args.ignf:
ignore_files = True
if(ignore_dirs and ignore_files):
print 'Both directories and files are ignored. Nothing is watched.'
sys.exit(1)
ianus(path, interval, recursive, ignore_dirs, ignore_files)