summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Grönholm <alex.gronholm@nextday.fi>2017-12-12 00:26:33 +0200
committerAlex Grönholm <alex.gronholm@nextday.fi>2017-12-12 00:26:33 +0200
commit39cb1a5f65a2d5970b9639e3e324ad7953d261f9 (patch)
treec511cca2f7af557a008ad9d604efcfe1a80a102d
parent858204838d78ac15ee6f9461ad26c57bbe96db4a (diff)
downloadapscheduler-39cb1a5f65a2d5970b9639e3e324ad7953d261f9.tar.gz
Added support for creating cron triggers from crontab expressions
Fixes #240.
-rw-r--r--apscheduler/triggers/cron/__init__.py20
-rw-r--r--docs/modules/triggers/cron.rst3
-rw-r--r--docs/versionhistory.rst2
-rw-r--r--tests/test_triggers.py12
4 files changed, 37 insertions, 0 deletions
diff --git a/apscheduler/triggers/cron/__init__.py b/apscheduler/triggers/cron/__init__.py
index 66424cf..e7f6ae8 100644
--- a/apscheduler/triggers/cron/__init__.py
+++ b/apscheduler/triggers/cron/__init__.py
@@ -82,6 +82,26 @@ class CronTrigger(BaseTrigger):
field = field_class(field_name, exprs, is_default)
self.fields.append(field)
+ @classmethod
+ def from_crontab(cls, expr, timezone=None):
+ """
+ Create a :class:`~CronTrigger` from a standard crontab expression.
+
+ See https://en.wikipedia.org/wiki/Cron for more information on the format accepted here.
+
+ :param expr: minute, hour, day of month, month, day of week
+ :param datetime.tzinfo|str timezone: time zone to use for the date/time calculations (
+ defaults to scheduler timezone)
+ :return: a :class:`~CronTrigger` instance
+
+ """
+ values = expr.split(' ')
+ if len(values) != 5:
+ raise ValueError('Wrong number of fields; got {}, expected 5'.format(len(values)))
+
+ return cls(minute=values[0], hour=values[1], day=values[2], month=values[3],
+ day_of_week=values[4], timezone=timezone)
+
def _increment_field_value(self, dateval, fieldnum):
"""
Increments the designated field and resets all less significant fields to their minimum
diff --git a/docs/modules/triggers/cron.rst b/docs/modules/triggers/cron.rst
index acc9295..a410bc2 100644
--- a/docs/modules/triggers/cron.rst
+++ b/docs/modules/triggers/cron.rst
@@ -108,6 +108,9 @@ The :meth:`~apscheduler.schedulers.base.BaseScheduler.scheduled_job` decorator w
def some_decorated_task():
print("I am printed at 00:00:00 on the last Sunday of every month!")
+To schedule a job using a standard crontab expression::
+
+ sched.add_job(job_function, CronTrigger.from_crontab('0 0 1-15 may-aug *'))
The ``jitter`` option enables you to add a random component to the execution time. This might be useful if you have
multiple servers and don't want them to run a job at the exact same moment or if you want to prevent jobs from running
diff --git a/docs/versionhistory.rst b/docs/versionhistory.rst
index 141f47c..7dc3473 100644
--- a/docs/versionhistory.rst
+++ b/docs/versionhistory.rst
@@ -15,6 +15,8 @@ APScheduler, see the :doc:`migration section <migration>`.
* Added support for named months (``january`` – ``december``) in ``CronTrigger`` month expressions
+* Added support for creating a ``CronTrigger`` from a crontab expression
+
* 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 ca07963..34372a5 100644
--- a/tests/test_triggers.py
+++ b/tests/test_triggers.py
@@ -387,6 +387,18 @@ class TestCronTrigger(object):
def test_invalid_ranges(self, values, expected):
pytest.raises(ValueError, CronTrigger, **values).match(expected)
+ @pytest.mark.parametrize('expr, expected_repr', [
+ ('* * * * *',
+ "<CronTrigger (month='*', day='*', day_of_week='*', hour='*', minute='*', "
+ "timezone='Europe/Berlin', jitter='None')>"),
+ ('0-14 * 14-28 jul fri',
+ "<CronTrigger (month='jul', day='14-28', day_of_week='fri', hour='*', minute='0-14', "
+ "timezone='Europe/Berlin', jitter='None')>")
+ ], ids=['always', 'assorted'])
+ def test_from_crontab(self, expr, expected_repr, timezone):
+ trigger = CronTrigger.from_crontab(expr, timezone)
+ assert repr(trigger) == expected_repr
+
class TestDateTrigger(object):
@pytest.mark.parametrize('run_date,alter_tz,previous,now,expected', [