Simplemente podría usar la sintaxis de paso de argumento normal de Python para especificar su crontab. Por ejemplo, supongamos que definimos una clase de evento de la siguiente manera:
from datetime import datetime, timedelta
import time
# Some utility classes / functions first
class AllMatch(set):
"""Universal set - match everything"""
def __contains__(self, item): return True
allMatch = AllMatch()
def conv_to_set(obj): # Allow single integer to be provided
if isinstance(obj, (int,long)):
return set([obj]) # Single item
if not isinstance(obj, set):
obj = set(obj)
return obj
# The actual Event class
class Event(object):
def __init__(self, action, min=allMatch, hour=allMatch,
day=allMatch, month=allMatch, dow=allMatch,
args=(), kwargs={}):
self.mins = conv_to_set(min)
self.hours= conv_to_set(hour)
self.days = conv_to_set(day)
self.months = conv_to_set(month)
self.dow = conv_to_set(dow)
self.action = action
self.args = args
self.kwargs = kwargs
def matchtime(self, t):
"""Return True if this event should trigger at the specified datetime"""
return ((t.minute in self.mins) and
(t.hour in self.hours) and
(t.day in self.days) and
(t.month in self.months) and
(t.weekday() in self.dow))
def check(self, t):
if self.matchtime(t):
self.action(*self.args, **self.kwargs)
(Nota: no probado exhaustivamente)
Entonces su CronTab se puede especificar en la sintaxis normal de Python como:
c = CronTab(
Event(perform_backup, 0, 2, dow=6 ),
Event(purge_temps, 0, range(9,18,2), dow=range(0,5))
)
De esta manera, obtienes todo el poder de la mecánica de argumento de Python (mezclando argumentos posicionales y de palabras clave, y puedes usar nombres simbólicos para nombres de semanas y meses)
La clase CronTab se definiría simplemente como dormir en incrementos de minutos y llamar a check () en cada evento. (Probablemente hay algunas sutilezas con el horario de verano / zonas horarias a tener en cuenta). Aquí hay una implementación rápida:
class CronTab(object):
def __init__(self, *events):
self.events = events
def run(self):
t=datetime(*datetime.now().timetuple()[:5])
while 1:
for e in self.events:
e.check(t)
t += timedelta(minutes=1)
while datetime.now() < t:
time.sleep((t - datetime.now()).seconds)
Algunas cosas a tener en cuenta: los días de semana / meses de Python están indexados a cero (a diferencia de cron), y ese rango excluye el último elemento, por lo tanto, una sintaxis como "1-5" se convierte en rango (0,5), es decir, [0,1,2, 3,4]. Sin embargo, si prefiere la sintaxis cron, el análisis no debería ser demasiado difícil.