Skip to content

Commit

Permalink
Merge 65c6962 into c57abf2
Browse files Browse the repository at this point in the history
  • Loading branch information
connorskees committed Jan 21, 2019
2 parents c57abf2 + 65c6962 commit 70a3eaa
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 48 deletions.
3 changes: 2 additions & 1 deletion AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ Thanks to all the wonderful folks who have contributed to schedule over the year
- schnepp <https://github.com/schnepp> <https://bitbucket.org/saschaschnepp>
- grampajoe <https://github.com/grampajoe>
- gilbsgilbs <https://github.com/gilbsgilbs>
- Nathan Wailes <https://github.com/NathanWailes>
- Nathan Wailes <https://github.com/NathanWailes>
- Connor Skees <https://github.com/ConnorSkees>
93 changes: 64 additions & 29 deletions schedule/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,21 @@
logger = logging.getLogger('schedule')


class ScheduleError(Exception):
"""Base schedule exception"""
pass


class ScheduleValueError(ScheduleError):
"""Base schedule value error"""
pass


class IntervalError(ScheduleValueError):
"""An improper interval was used"""
pass


class CancelJob(object):
"""
Can be returned from a job to unschedule itself.
Expand Down Expand Up @@ -228,7 +243,8 @@ def format_time(t):

@property
def second(self):
assert self.interval == 1, 'Use seconds instead of second'
if self.interval != 1:
raise IntervalError('Use seconds instead of second')
return self.seconds

@property
Expand All @@ -238,7 +254,8 @@ def seconds(self):

@property
def minute(self):
assert self.interval == 1, 'Use minutes instead of minute'
if self.interval != 1:
raise IntervalError('Use minutes instead of minute')
return self.minutes

@property
Expand All @@ -248,7 +265,8 @@ def minutes(self):

@property
def hour(self):
assert self.interval == 1, 'Use hours instead of hour'
if self.interval != 1:
raise IntervalError('Use hours instead of hour')
return self.hours

@property
Expand All @@ -258,7 +276,8 @@ def hours(self):

@property
def day(self):
assert self.interval == 1, 'Use days instead of day'
if self.interval != 1:
raise IntervalError('Use days instead of day')
return self.days

@property
Expand All @@ -268,7 +287,8 @@ def days(self):

@property
def week(self):
assert self.interval == 1, 'Use weeks instead of week'
if self.interval != 1:
raise IntervalError('Use weeks instead of week')
return self.weeks

@property
Expand All @@ -278,43 +298,50 @@ def weeks(self):

@property
def monday(self):
assert self.interval == 1, 'Use mondays instead of monday'
if self.interval != 1:
raise IntervalError('Use mondays instead of monday')
self.start_day = 'monday'
return self.weeks

@property
def tuesday(self):
assert self.interval == 1, 'Use tuesdays instead of tuesday'
if self.interval != 1:
raise IntervalError('Use tuesdays instead of tuesday')
self.start_day = 'tuesday'
return self.weeks

@property
def wednesday(self):
assert self.interval == 1, 'Use wednesdays instead of wednesday'
if self.interval != 1:
raise IntervalError('Use wednesdays instead of wednesday')
self.start_day = 'wednesday'
return self.weeks

@property
def thursday(self):
assert self.interval == 1, 'Use thursdays instead of thursday'
if self.interval != 1:
raise IntervalError('Use thursdays instead of thursday')
self.start_day = 'thursday'
return self.weeks

@property
def friday(self):
assert self.interval == 1, 'Use fridays instead of friday'
if self.interval != 1:
raise IntervalError('Use fridays instead of friday')
self.start_day = 'friday'
return self.weeks

@property
def saturday(self):
assert self.interval == 1, 'Use saturdays instead of saturday'
if self.interval != 1:
raise IntervalError('Use saturdays instead of saturday')
self.start_day = 'saturday'
return self.weeks

@property
def sunday(self):
assert self.interval == 1, 'Use sundays instead of sunday'
if self.interval != 1:
raise IntervalError('Use sundays instead of sunday')
self.start_day = 'sunday'
return self.weeks

Expand Down Expand Up @@ -344,18 +371,22 @@ def at(self, time_str):
(e.g. `every().hour.at(':30')` vs. `every().minute.at(':30')`).
:return: The invoked job instance
"""
assert self.unit in ('days', 'hours', 'minutes') or self.start_day
if (self.unit not in ('days', 'hours', 'minutes')
and not self.start_day):
raise ScheduleValueError('Invalid unit.')
if not isinstance(time_str, str):
raise TypeError("at() should be passed a string.")
if self.unit == 'days' or self.start_day:
assert re.match(r'^([0-2]\d:)?[0-5]\d:[0-5]\d$', time_str), \
ValueError("Invalid time format.")
if not re.match(r'^([0-2]\d:)?[0-5]\d:[0-5]\d$', time_str):
raise ScheduleValueError("Invalid time format.")
if self.unit == 'hours':
assert re.match(r'^([0-5]\d)?:[0-5]\d$', time_str), \
ValueError("Invalid time format for an hourly job.")
if not re.match(r'^([0-5]\d)?:[0-5]\d$', time_str):
raise ScheduleValueError(("Invalid time format for"
" an hourly job."))
if self.unit == 'minutes':
assert re.match(r'^:[0-5]\d$', time_str), \
ValueError("Invalid time format for a minutely job.")
if not re.match(r'^:[0-5]\d$', time_str):
raise ScheduleValueError(("Invalid time format for"
" a minutely job."))
time_values = time_str.split(':')
if len(time_values) == 3:
hour, minute, second = time_values
Expand All @@ -368,16 +399,15 @@ def at(self, time_str):
second = 0
if self.unit == 'days' or self.start_day:
hour = int(hour)
assert 0 <= hour <= 23
if 0 > hour or hour > 23:
raise ScheduleValueError("Invalid number of hours.")
elif self.unit == 'hours':
hour = 0
elif self.unit == 'minutes':
hour = 0
minute = 0
minute = int(minute)
assert 0 <= minute <= 59
second = int(second)
assert 0 <= second <= 59
self.at_time = datetime.time(hour, minute, second)
return self

Expand Down Expand Up @@ -442,19 +472,21 @@ def _schedule_next_run(self):
"""
Compute the instant when this job should run next.
"""
assert self.unit in ('seconds', 'minutes', 'hours', 'days',
'weeks')
if self.unit not in ('seconds', 'minutes', 'hours', 'days', 'weeks'):
raise ScheduleValueError("Invalid unit.")

if self.latest is not None:
assert self.latest >= self.interval
if not (self.latest >= self.interval):
raise ScheduleError("`latest` is greater than `interval`.")
interval = random.randint(self.interval, self.latest)
else:
interval = self.interval

self.period = datetime.timedelta(**{self.unit: interval})
self.next_run = datetime.datetime.now() + self.period
if self.start_day is not None:
assert self.unit == 'weeks'
if self.unit != 'weeks':
raise ScheduleValueError("`unit` should be 'weeks'")
weekdays = (
'monday',
'tuesday',
Expand All @@ -464,15 +496,18 @@ def _schedule_next_run(self):
'saturday',
'sunday'
)
assert self.start_day in weekdays
if self.start_day not in weekdays:
raise ScheduleValueError("Invalid start day.")
weekday = weekdays.index(self.start_day)
days_ahead = weekday - self.next_run.weekday()
if days_ahead <= 0: # Target day already happened this week
days_ahead += 7
self.next_run += datetime.timedelta(days_ahead) - self.period
if self.at_time is not None:
assert self.unit in ('days', 'hours', 'minutes') \
or self.start_day is not None
if (self.unit not in ('days', 'hours', 'minutes')
and self.start_day is None):
raise ScheduleValueError(("Invalid unit without"
" specifying start day."))
kwargs = {
'second': self.at_time.second,
'microsecond': 0
Expand Down
Loading

0 comments on commit 70a3eaa

Please sign in to comment.