Você pode usar o argumento normal do Python passando a sintaxe para especificar seu crontab. Por exemplo, suponha que definimos uma classe Event como abaixo:
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: Não testado completamente)
Em seguida, seu CronTab pode ser especificado na sintaxe python normal como:
c = CronTab(
Event(perform_backup, 0, 2, dow=6 ),
Event(purge_temps, 0, range(9,18,2), dow=range(0,5))
)
Dessa forma, você obtém todo o poder da mecânica de argumentos do Python (misturando argumentos posicionais e de palavras-chave e pode usar nomes simbólicos para nomes de semanas e meses)
A classe CronTab seria definida como simplesmente dormir em incrementos de minutos e chamar check () em cada evento. (Provavelmente existem algumas sutilezas com o horário de verão / fusos horários para se ter cuidado). Aqui está uma implementação 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)
Algumas coisas a serem observadas: os dias da semana / meses do Python são zero indexados (diferente do cron), e esse intervalo exclui o último elemento; portanto, sintaxe como "1-5" se torna intervalo (0,5) - ou seja, [0,1,2, 3,4] Se você preferir a sintaxe do cron, a análise não deve ser muito difícil.