summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Grönholm <alex.gronholm@nextday.fi>2017-12-11 23:42:39 +0200
committerAlex Grönholm <alex.gronholm@nextday.fi>2017-12-12 00:18:36 +0200
commit858204838d78ac15ee6f9461ad26c57bbe96db4a (patch)
tree5b7a92d450a7704cae07c08cb7ad7fb1c65f455e
parentd6cbfa816f4217bc74609faadcb37bf040f059a3 (diff)
downloadapscheduler-858204838d78ac15ee6f9461ad26c57bbe96db4a.tar.gz
Added support for named months
-rw-r--r--apscheduler/triggers/cron/__init__.py4
-rw-r--r--apscheduler/triggers/cron/expressions.py32
-rw-r--r--apscheduler/triggers/cron/fields.py6
-rw-r--r--docs/modules/triggers/cron.rst3
-rw-r--r--docs/versionhistory.rst2
-rw-r--r--tests/test_triggers.py4
6 files changed, 46 insertions, 5 deletions
diff --git a/apscheduler/triggers/cron/__init__.py b/apscheduler/triggers/cron/__init__.py
index e936190..66424cf 100644
--- a/apscheduler/triggers/cron/__init__.py
+++ b/apscheduler/triggers/cron/__init__.py
@@ -5,7 +5,7 @@ import six
from apscheduler.triggers.base import BaseTrigger
from apscheduler.triggers.cron.fields import (
- BaseField, WeekField, DayOfMonthField, DayOfWeekField, DEFAULT_VALUES)
+ BaseField, MonthField, WeekField, DayOfMonthField, DayOfWeekField, DEFAULT_VALUES)
from apscheduler.util import datetime_ceil, convert_to_datetime, datetime_repr, astimezone
@@ -34,7 +34,7 @@ class CronTrigger(BaseTrigger):
FIELD_NAMES = ('year', 'month', 'day', 'week', 'day_of_week', 'hour', 'minute', 'second')
FIELDS_MAP = {
'year': BaseField,
- 'month': BaseField,
+ 'month': MonthField,
'week': WeekField,
'day': DayOfMonthField,
'day_of_week': DayOfWeekField,
diff --git a/apscheduler/triggers/cron/expressions.py b/apscheduler/triggers/cron/expressions.py
index 131a80f..55a3716 100644
--- a/apscheduler/triggers/cron/expressions.py
+++ b/apscheduler/triggers/cron/expressions.py
@@ -10,6 +10,7 @@ __all__ = ('AllExpression', 'RangeExpression', 'WeekdayRangeExpression',
WEEKDAYS = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']
+MONTHS = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec']
class AllExpression(object):
@@ -125,6 +126,37 @@ class RangeExpression(AllExpression):
return "%s(%s)" % (self.__class__.__name__, ', '.join(args))
+class MonthRangeExpression(RangeExpression):
+ value_re = re.compile(r'(?P<first>[a-z]+)(?:-(?P<last>[a-z]+))?', re.IGNORECASE)
+
+ def __init__(self, first, last=None):
+ try:
+ first_num = MONTHS.index(first.lower()) + 1
+ except ValueError:
+ raise ValueError('Invalid month name "%s"' % first)
+
+ if last:
+ try:
+ last_num = MONTHS.index(last.lower()) + 1
+ except ValueError:
+ raise ValueError('Invalid month name "%s"' % last)
+ else:
+ last_num = None
+
+ super(MonthRangeExpression, self).__init__(first_num, last_num)
+
+ def __str__(self):
+ if self.last != self.first and self.last is not None:
+ return '%s-%s' % (MONTHS[self.first - 1], MONTHS[self.last - 1])
+ return MONTHS[self.first - 1]
+
+ def __repr__(self):
+ args = ["'%s'" % MONTHS[self.first]]
+ if self.last != self.first and self.last is not None:
+ args.append("'%s'" % MONTHS[self.last - 1])
+ return "%s(%s)" % (self.__class__.__name__, ', '.join(args))
+
+
class WeekdayRangeExpression(RangeExpression):
value_re = re.compile(r'(?P<first>[a-z]+)(?:-(?P<last>[a-z]+))?', re.IGNORECASE)
diff --git a/apscheduler/triggers/cron/fields.py b/apscheduler/triggers/cron/fields.py
index 811127b..27674c8 100644
--- a/apscheduler/triggers/cron/fields.py
+++ b/apscheduler/triggers/cron/fields.py
@@ -6,7 +6,7 @@ import six
from apscheduler.triggers.cron.expressions import (
AllExpression, RangeExpression, WeekdayPositionExpression, LastDayOfMonthExpression,
- WeekdayRangeExpression)
+ WeekdayRangeExpression, MonthRangeExpression)
__all__ = ('MIN_VALUES', 'MAX_VALUES', 'DEFAULT_VALUES', 'BaseField', 'WeekField',
@@ -107,3 +107,7 @@ class DayOfWeekField(BaseField):
def get_value(self, dateval):
return dateval.weekday()
+
+
+class MonthField(BaseField):
+ COMPILERS = BaseField.COMPILERS + [MonthRangeExpression]
diff --git a/docs/modules/triggers/cron.rst b/docs/modules/triggers/cron.rst
index 791156d..acc9295 100644
--- a/docs/modules/triggers/cron.rst
+++ b/docs/modules/triggers/cron.rst
@@ -53,6 +53,9 @@ Expression Field Description
``x,y,z`` any Fire on any matching expression; can combine any number of any of the above expressions
============== ===== =======================================================================================
+.. note:: The ``month`` and ``day_of_week`` fields accept abbreviated English month and weekday names
+ (``jan`` – ``dec`` and ``mon`` – ``sun``) respectively.
+
Daylight saving time behavior
-----------------------------
diff --git a/docs/versionhistory.rst b/docs/versionhistory.rst
index 98b8ea5..141f47c 100644
--- a/docs/versionhistory.rst
+++ b/docs/versionhistory.rst
@@ -13,6 +13,8 @@ APScheduler, see the :doc:`migration section <migration>`.
* Added better validation for the steps and ranges of different expressions in ``CronTrigger``
+* Added support for named months (``january`` – ``december``) in ``CronTrigger`` month expressions
+
* Fixed memory leak due to a cyclic reference when jobs raise exceptions
(thanks to gilbsgilbs for help on solving this)
diff --git a/tests/test_triggers.py b/tests/test_triggers.py
index 0632d92..ca07963 100644
--- a/tests/test_triggers.py
+++ b/tests/test_triggers.py
@@ -116,8 +116,8 @@ class TestCronTrigger(object):
assert trigger.get_next_fire_time(None, start_date) == correct_next_date
def test_cron_trigger_3(self, timezone):
- trigger = CronTrigger(year='2009', month='2', hour='8-10', timezone=timezone)
- assert repr(trigger) == ("<CronTrigger (year='2009', month='2', hour='8-10', "
+ trigger = CronTrigger(year='2009', month='feb-dec', hour='8-10', timezone=timezone)
+ assert repr(trigger) == ("<CronTrigger (year='2009', month='feb-dec', hour='8-10', "
"timezone='Europe/Berlin', jitter='None')>")
start_date = timezone.localize(datetime(2009, 1, 1))
correct_next_date = timezone.localize(datetime(2009, 2, 1, 8))