Puoi semplicemente usare il normale argomento Python passando la sintassi per specificare il tuo crontab. Ad esempio, supponiamo di definire una classe Event come di seguito:
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: non accuratamente testato)
Quindi il tuo CronTab può essere specificato nella normale sintassi di Python come:
c = CronTab(
Event(perform_backup, 0, 2, dow=6 ),
Event(purge_temps, 0, range(9,18,2), dow=range(0,5))
)
In questo modo ottieni tutta la potenza della meccanica degli argomenti di Python (mescolando argomenti posizionali e parole chiave, e puoi usare nomi simbolici per nomi di settimane e mesi)
La classe CronTab sarebbe definita semplicemente dormendo in incrementi di minuto e chiamando check () su ciascun evento. (Ci sono probabilmente alcune sottigliezze con l'ora legale / fusi orari di cui fare attenzione però). Ecco una rapida implementazione:
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)
Alcune cose da notare: i giorni della settimana / i mesi di Python sono indicizzati a zero (a differenza di cron) e quell'intervallo esclude l'ultimo elemento, quindi la sintassi come "1-5" diventa intervallo (0,5) - vale a dire [0,1,2, 3,4]. Se preferisci la sintassi cron, analizzarla non dovrebbe essere troppo difficile.