Skip to content

Commit

Permalink
Code quality changes
Browse files Browse the repository at this point in the history
  • Loading branch information
Panos Kittenis committed Nov 25, 2013
1 parent e8ebde3 commit 8f89608
Showing 1 changed file with 41 additions and 38 deletions.
79 changes: 41 additions & 38 deletions cronify/cronify.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,20 @@ class EventHandler(pyinotify.ProcessEvent):
# 'somefile.txt' : [ { 'action1' : { 'cmd' : 'echo', <..> } }, ],
# 'otherfile.txt' : [ { 'action1' : { 'cmd' : 'cat', <..> } }, ],
# }
def __init__(self, filemask_actions, threadpool,
def __init__(self, filemask_actions, thread_pool,
callback_func = None,
file_tz = None,
local_tz = None):
pyinotify.ProcessEvent.__init__(self)
self.filemask_actions, self.threadpool = filemask_actions, threadpool
self.filemask_actions, self.thread_pool = filemask_actions, thread_pool
self.callback_func = callback_func
for filemask in self.filemask_actions.copy():
new_filemask = self._parse_filemask(filemask)
self.filemask_actions[new_filemask] = self.filemask_actions[filemask]
del self.filemask_actions[filemask]
self.file_tz = file_tz
self.local_tz = local_tz
logger.debug("Got local tz %s" % (self.local_tz,))
logger.debug("Got local tz %s", (self.local_tz,))

def process_IN_CLOSE_WRITE(self, event):
"""IN_CLOSE_WRITE event handler
Expand All @@ -83,10 +83,10 @@ def handle_event(self, event):
"""Check triggered event against filemask, do actions if filemask is accepted"""
for filemask in self.filemask_actions:
if not filemask.match(event.name):
logger.debug("Filename %s did not match filemask pattern %s" % (event.name, filemask.pattern,))
logger.debug("Filename %s did not match filemask pattern %s", event.name, filemask.pattern,)
continue
logger.debug("Matched filename %s with filemask %s from event %s" % (event.name, filemask.pattern, event.maskname,))
self.threadpool.add_task_to_queue(self.do_actions, event, self.filemask_actions[filemask]['actions'])
logger.debug("Matched filename %s with filemask %s from event %s", event.name, filemask.pattern, event.maskname,)
self.thread_pool.add_task_to_queue(self.do_actions, event, self.filemask_actions[filemask]['actions'])

def _parse_action_args(self, event, action_args):
"""Parse action_args, return args with expanded keywords and file metadata
Expand All @@ -102,8 +102,8 @@ def _parse_action_args(self, event, action_args):
if not file_datestamp:
logger.debug("Could not parse datestamp from filename, falling back to file's modified time")
file_datestamp = datetime.date.fromtimestamp(os.stat(event.pathname).st_mtime)
logger.debug("Parsed datestamp %s for file %s" % (file_datestamp.strftime(self._datestamp_keyword_fmt[1]),
event.pathname,))
logger.debug("Parsed datestamp %s for file %s", file_datestamp.strftime(self._datestamp_keyword_fmt[1]),
event.pathname,)
action_args[i] = file_datestamp.strftime(self._datestamp_keyword_fmt[1])
file_metadata['datestamp'] = file_datestamp
return action_args, file_metadata
Expand All @@ -114,10 +114,10 @@ def _parse_action_metadata(self, action):
for key in action:
if key == 'start_time':
metadata['start_time'] = self._parse_isoformat_time(action[key])
logger.debug("Parsed action start time %s" % (metadata['start_time'],))
logger.debug("Parsed action start time %s", (metadata['start_time'],))
elif key == 'end_time':
metadata['end_time'] = self._parse_isoformat_time(action[key])
logger.debug("Parsed action end time %s" % (metadata['end_time'],))
logger.debug("Parsed action end time %s", (metadata['end_time'],))
return metadata

def _parse_filemask(self, filemask):
Expand Down Expand Up @@ -145,31 +145,31 @@ def _parse_datestamp(self, filename):
except ValueError:
return
else:
logger.debug("Parsed file datestamp from date in filename - %s from %s" % (file_datestamp, filename,))
logger.debug("Parsed file datestamp from date in filename - %s from %s", file_datestamp, filename,)
return datetime.date(file_datestamp.year, file_datestamp.month, file_datestamp.day)

def do_actions(self, event, actions):
"""Perform actions"""
logger.debug("Starting actions %s" % (actions,))
logger.debug("Starting actions %s", (actions,))
[self._do_action(event, action, action_data) for action in actions
for action_data in action.itervalues()]

def _do_action(self, event, action, action_data):
"""Perform a single action"""
action_metadata = self._parse_action_metadata(action_data)
action_args, file_metadata = self._parse_action_args(event, action_data['args'][:])
logger.debug("Made expanded action arguments %s" % (action_args,))
logger.debug("Made expanded action arguments %s", (action_args,))
action_args.insert(0, action_data['cmd'])
if action_metadata and 'start_time' in action_metadata and 'end_time' in action_metadata:
utc = datetime.datetime.utcnow()
now = datetime.datetime(utc.year, utc.month, utc.day, utc.hour, utc.minute, utc.second,
tzinfo = pytz.utc)
logger.debug("Local tz is %s" % (self.local_tz,))
logger.debug("Local tz is %s", (self.local_tz,))
if self.local_tz:
now = self.local_tz.normalize(now.astimezone(self.local_tz))
# Convert tz-aware datetime into naive datetime or datetime arithmetic will fail
now = datetime.datetime(now.year, now.month, now.day, now.hour, now.minute, now.second)
logger.debug("Have local_tz configuration, converted 'now' time to %s" %
logger.debug("Have local_tz configuration, converted 'now' time to %s",
(now,))
else:
logger.debug("No local_tz config, using system timezone")
Expand All @@ -182,20 +182,20 @@ def _do_action(self, event, action, action_data):
file_metadata['datestamp'].day, action_metadata['end_time'].hour,
action_metadata['end_time'].minute, action_metadata['end_time'].second)
if now < start_time:
logger.info("Action start time %s is in the future, waiting for %s hh:mm:SS" %
(start_time, start_time - now,))
logger.info("Action start time %s is in the future, waiting for %s hh:mm:SS",
start_time, start_time - now,)
time.sleep((start_time - now).seconds)
elif now > start_time and now > end_time:
logger.info("Action start time %s is in the past and end time %s has passed, not triggering action" %
(start_time, end_time))
logger.info("Action start time %s is in the past and end time %s has passed, not triggering action",
start_time, end_time)
return
if self.callback_func:
self.callback_func(event)
returncode, stdout, stderr = run_script(action_args)
logger.info("Got result from action %s - %s" % (action_data, stdout,))
logger.info("Got result from action %s - %s", action_data, stdout,)
if returncode:
logger.error("Action %s failed with exit code %s, stderr %s" %
(action, returncode, stderr,))
logger.error("Action %s failed with exit code %s, stderr %s",
action, returncode, stderr,)

class Watcher(object):

Expand Down Expand Up @@ -225,12 +225,13 @@ def __init__(self, watch_data, callback_func = None):
sys.exit(1)
self.watch_data = watch_data
[self._check_timezone_info(self.watch_data[watch]) for watch in self.watch_data]
self.threadpool = threadpool.ThreadPool(num_workers = 10)
self.thread_pool = threadpool.ThreadPool(num_workers = 10)
self.start_watchers(self.watch_data)
signal.signal(signal.SIGUSR1, self.reload_signal_handler)

def reload_signal_handler(self, signalnum, frame):
logger.info("Reloading watchers from configuration file %s" % (CFG_FILE,))
"""Signal handler for reloading configuration file and watchers"""
logger.info("Reloading watchers from configuration file %s", (CFG_FILE,))
self.update_watchers()

def check_watch_data(self, watch_data):
Expand Down Expand Up @@ -272,12 +273,12 @@ def _check_data_fields(self, data, req_fields):
:returns: False if any required fields are missing
:returns: True if all required fields are present"""
if not data:
logger.critical("Configuration data for %s is empty, cannot continue" % (req_fields,))
logger.critical("Configuration data for %s is empty, cannot continue", (req_fields,))
return False
for _key in data:
if not [True for field in req_fields if field in data[_key]] == [True for field in req_fields]:
logger.critical("Configuration data for %s is missing required fields from %s. Data is %s" %
(_key, req_fields, data[_key],))
logger.critical("Configuration data for %s is missing required fields from %s. Data is %s",
_key, req_fields, data[_key],)
return False
return True

Expand All @@ -286,23 +287,23 @@ def start_watchers(self, watch_data):
for watcher in watch_data:
watch_dir = self._check_dir(watcher)
if not watch_dir:
logger.critical("Desired directory to watch %s does not exist or is not a directory. Exiting." % (watcher,))
logger.critical("Desired directory to watch %s does not exist or is not a directory. Exiting.", (watcher,))
sys.exit(1)
recurse = watch_data[watcher]['recurse'] if 'recurse' in watch_data[watcher] else False
watch_manager = pyinotify.WatchManager()
local_tz = watch_data[watcher]['local_tz'] if 'local_tz' in watch_data[watcher] else None
notifier = pyinotify.ThreadedNotifier(watch_manager, EventHandler(watch_data[watcher]['filemasks'].copy(),
self.threadpool,
self.thread_pool,
callback_func = self.callback_func,
local_tz = local_tz
))
notifier.daemon = True
notifier.start()
watch_manager.add_watch(watch_dir, _MASKS, rec = recurse, auto_add = True)
logger.info("Started watching directory %s with filemasks and actions %s, recurse %s.." %
(watch_dir,
watch_data[watcher]['filemasks'],
recurse,))
logger.info("Started watching directory %s with filemasks and actions %s, recurse %s..",
watch_dir,
watch_data[watcher]['filemasks'],
recurse,)
self.notifiers.append(notifier)
self.watch_managers.append(watch_manager)

Expand All @@ -319,7 +320,8 @@ def update_watchers(self, watch_data = None):
for watcher in watch_data:
watch_dir = self._check_dir(watcher)
if not watch_dir:
logger.critical("Desired directory to watch %s does not exist or is not a directory, cannot continue with watcher reload." % (watcher,))
logger.critical("Desired directory to watch %s does not exist or is not a directory, cannot continue with watcher reload.",
(watcher,))
self.cleanup()
self.start_watchers(watch_data)
self.watch_data = watch_data
Expand All @@ -334,11 +336,11 @@ def _check_timezone_info(self, watch_data):
try:
watch_data[tz_key] = pytz.timezone(watch_data[tz_key])
except pytz.UnknownTimeZoneError:
logger.error("Invalid timezone %s given as '%s' configuration, cannot continue" % (
watch_data[tz_key], tz_key, ))
logger.error("Invalid timezone %s given as '%s' configuration, cannot continue",
watch_data[tz_key], tz_key,)
sys.exit(1)
else:
logger.debug("Got timezone configuration for %s = %s" % (tz_key, watch_data[tz_key],))
logger.debug("Got timezone configuration for %s = %s", tz_key, watch_data[tz_key],)

def _check_dir(self, dirpath):
"""Make absolute path, check is directory"""
Expand All @@ -354,7 +356,7 @@ def cleanup(self):
[notifier.stop() for notifier in self.notifiers]
self.watch_managers, self.notifiers = [], []

def callback_func(event):
def _callback_func(event):
"""Test function for callback_func optional parameter of Watcher class"""
print "Got event for %s" % (event.name,)

Expand Down Expand Up @@ -392,6 +394,7 @@ def test():
try:
time.sleep(5)
except KeyboardInterrupt:
watcher.cleanup()
sys.exit(0)

if __name__ == "__main__":
Expand Down

0 comments on commit 8f89608

Please sign in to comment.