170 lines
7.3 KiB
Python
170 lines
7.3 KiB
Python
|
"""
|
||
|
Scheduler works only on a weekly scale. This is due to the use of the schedule package.
|
||
|
|
||
|
Target format: wD:HH:MM:SS, where:
|
||
|
wD - day of week unit: '1', '2', ... , '6', '7', '*'
|
||
|
HH - hour unit in 24-hours format: '00', '01', ... , '22', '23', '**'
|
||
|
MM - minute unit: '00', '01', ... , '58', '59', '**'
|
||
|
SS - second unit: '00', '01', ... , '58', '59', '**'
|
||
|
Units can be listed separated by commas.
|
||
|
|
||
|
Examples:
|
||
|
'*:**:**:**' - every second of every minute of every hour of every day
|
||
|
'*:**:**:*5' - every 05,15,25,35,45,55 seconds of every minute of every hour of every day
|
||
|
'*:2*:**:**' - every second of every minute of every 20,21,22,23 hours of every day
|
||
|
'*:2*:**:*5' - every 05,15,25,35,45,55 seconds of every minute of every 20,21,22,23 hours of every day
|
||
|
'3,5:2*:**:*5' - every 05,15,25,35,45,55 seconds every minute every 20,21,22,23 hours of Wednesday, Friday
|
||
|
'1,7:12:00:**' - every second 00 minutes 12 hours of Monday, Sunday
|
||
|
'1:07:00:00' - every 00 seconds 00 minutes 07 hours Monday
|
||
|
"""
|
||
|
|
||
|
from itertools import cycle
|
||
|
from time import sleep
|
||
|
from threading import Event, Thread
|
||
|
from . import schedule
|
||
|
|
||
|
|
||
|
class Scheduler:
|
||
|
"""
|
||
|
Control wrapper for the schedule package
|
||
|
"""
|
||
|
def __init__(self):
|
||
|
"""
|
||
|
Object constructor
|
||
|
"""
|
||
|
self.scheduler_entity = schedule.Scheduler()
|
||
|
self.scheduler_signal = None
|
||
|
|
||
|
def _start_thread(self, interval: int = 1):
|
||
|
"""
|
||
|
Running the scheduler with a thread in the background
|
||
|
:param interval: an integer specifying the period in seconds to start pending jobs
|
||
|
"""
|
||
|
signal = Event()
|
||
|
|
||
|
class ScheduleThread(Thread):
|
||
|
@classmethod
|
||
|
def run(cls):
|
||
|
while not signal.is_set():
|
||
|
self.scheduler_entity.run_pending()
|
||
|
sleep(interval)
|
||
|
|
||
|
ScheduleThread().start()
|
||
|
return signal
|
||
|
|
||
|
def start(self):
|
||
|
"""
|
||
|
Scheduler launch
|
||
|
"""
|
||
|
self.scheduler_signal = self._start_thread()
|
||
|
|
||
|
def stop(self):
|
||
|
"""
|
||
|
Stopping the Scheduler
|
||
|
"""
|
||
|
self.scheduler_signal.set()
|
||
|
|
||
|
def add(self, target: str, action):
|
||
|
"""
|
||
|
Adding a job to the execution queue
|
||
|
:param target: a string in the format wD:HH:MM:SS specifying the target of the launch time
|
||
|
:param action: a string with the name of the function to run
|
||
|
"""
|
||
|
target_undefined = target.split(':')
|
||
|
if len(target_undefined) == 4:
|
||
|
wd, hh, mm, ss = target_undefined[0], target_undefined[1], target_undefined[2], target_undefined[3]
|
||
|
if '*' in wd and '**' in hh and '**' in mm and '**' in ss:
|
||
|
self.scheduler_entity.every().seconds.do(action)
|
||
|
elif '*' in wd and '**' in hh and '**' in mm:
|
||
|
for element in self._expand_target(wd.split(','),
|
||
|
hh.split(','),
|
||
|
mm.split(','),
|
||
|
self._expand_time(ss, 'ss')):
|
||
|
ss = element[3]
|
||
|
self.scheduler_entity.every().minute.at(':' + ss).do(action)
|
||
|
elif '*' in wd and '**' in hh:
|
||
|
for element in self._expand_target(wd.split(','),
|
||
|
hh.split(','),
|
||
|
self._expand_time(mm, 'mm'),
|
||
|
self._expand_time(ss, 'ss')):
|
||
|
mm, ss = element[2], element[3]
|
||
|
self.scheduler_entity.every().hour.at(mm + ':' + ss).do(action)
|
||
|
pass
|
||
|
elif '*' in wd:
|
||
|
for element in self._expand_target(wd.split(','),
|
||
|
self._expand_time(hh, 'hh'),
|
||
|
self._expand_time(mm, 'mm'),
|
||
|
self._expand_time(ss, 'ss')):
|
||
|
hh, mm, ss = element[1], element[2], element[3]
|
||
|
self.scheduler_entity.every().day.at(hh + ':' + mm + ':' + ss).do(action)
|
||
|
else:
|
||
|
for element in self._expand_target(self._expand_time(wd, 'wd'),
|
||
|
self._expand_time(hh, 'hh'),
|
||
|
self._expand_time(mm, 'mm'),
|
||
|
self._expand_time(ss, 'ss')):
|
||
|
wd, hh, mm, ss = element[0], element[1], element[2], element[3]
|
||
|
if wd == '1':
|
||
|
self.scheduler_entity.every().monday.at(hh + ':' + mm + ':' + ss).do(action)
|
||
|
elif wd == '2':
|
||
|
self.scheduler_entity.every().tuesday.at(hh + ':' + mm + ':' + ss).do(action)
|
||
|
elif wd == '3':
|
||
|
self.scheduler_entity.every().wednesday.at(hh + ':' + mm + ':' + ss).do(action)
|
||
|
elif wd == '4':
|
||
|
self.scheduler_entity.every().thursday.at(hh + ':' + mm + ':' + ss).do(action)
|
||
|
elif wd == '5':
|
||
|
self.scheduler_entity.every().friday.at(hh + ':' + mm + ':' + ss).do(action)
|
||
|
elif wd == '6':
|
||
|
self.scheduler_entity.every().saturday.at(hh + ':' + mm + ':' + ss).do(action)
|
||
|
elif wd == '7':
|
||
|
self.scheduler_entity.every().sunday.at(hh + ':' + mm + ':' + ss).do(action)
|
||
|
|
||
|
@classmethod
|
||
|
def _expand_time(cls, time_raw: str, unit: str):
|
||
|
"""
|
||
|
Converts an undefined time units to a list of specific time units
|
||
|
:param time_raw: a string with time unit
|
||
|
:param unit: string description of the time unit
|
||
|
:return: list of specific time units
|
||
|
"""
|
||
|
if ',' in time_raw:
|
||
|
pass
|
||
|
elif '*' in time_raw and (unit == 'wd' or unit == 'hh' or unit == 'mm' or unit == 'ss'):
|
||
|
time_out, time_min, time_max = [], 0, 60
|
||
|
if unit == 'hh':
|
||
|
time_max = 24
|
||
|
if unit == 'wd':
|
||
|
time_min, time_max = 1, 8
|
||
|
for i in range(time_max):
|
||
|
out = time_raw.replace('**', format(i, '02d')).replace('*', str(i))
|
||
|
if 0 <= int(out) < time_max:
|
||
|
time_out.append(out)
|
||
|
return time_out
|
||
|
return time_raw.split(',')
|
||
|
|
||
|
@classmethod
|
||
|
def _expand_target(cls, wd: list, hh: list, mm: list, ss: list):
|
||
|
"""
|
||
|
Converts an undefined target to a list of specific target
|
||
|
:param wd: list with day of week time units
|
||
|
:param hh: list with hour time units
|
||
|
:param mm: list with minute time units
|
||
|
:param ss: list with second time units
|
||
|
:return: list of specific time targets
|
||
|
"""
|
||
|
cwd, chh, cmm, css = cycle(wd), cycle(hh), cycle(mm), cycle(ss)
|
||
|
target_defined = []
|
||
|
for a in range(len(wd)):
|
||
|
a_wd = next(cwd)
|
||
|
for b in range(len(hh)):
|
||
|
b_hh = next(chh)
|
||
|
for c in range(len(mm)):
|
||
|
c_mm = next(cmm)
|
||
|
for d in range(len(ss)):
|
||
|
d_ss = next(css)
|
||
|
target_defined.append([a_wd, b_hh, c_mm, d_ss])
|
||
|
return target_defined
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
pass
|