From c5589ee01f3603f1c87b46cf0fa3ce26af2191a4 Mon Sep 17 00:00:00 2001 From: Matthew Hardwick Date: Sat, 20 Jul 2013 06:08:48 -0500 Subject: [PATCH 1/4] Added a conditional check for exceptional case in next_run() when the self.jobs queue is empty. No longer throws a ValueError exception, but rather returns a None object when no jobs are available. --- schedule/__init__.py | 4 ++++ test_schedule.py | 1 + 2 files changed, 5 insertions(+) diff --git a/schedule/__init__.py b/schedule/__init__.py index e6ebe156..1b56f12d 100644 --- a/schedule/__init__.py +++ b/schedule/__init__.py @@ -111,6 +111,10 @@ def every(self, interval=1): @property def next_run(self): """Datetime when the next job should run.""" + if self.jobs.__len__() > 0: + date_time = min(self.jobs).next_run + else: + return None return min(self.jobs).next_run @property diff --git a/test_schedule.py b/test_schedule.py index 6f86011e..895d7254 100644 --- a/test_schedule.py +++ b/test_schedule.py @@ -55,6 +55,7 @@ def now(cls): datetime.datetime = MockDate mock_job = make_mock_job() + assert schedule.next_run() is None assert every().minute.do(mock_job).next_run.minute == 16 assert every(5).minutes.do(mock_job).next_run.minute == 20 assert every().hour.do(mock_job).next_run.hour == 13 From 87aa15c7c2e8ca26181d2c6be3971233c83dbe44 Mon Sep 17 00:00:00 2001 From: Matthew Hardwick Date: Mon, 22 Jul 2013 21:21:47 -0500 Subject: [PATCH 2/4] Adjusted a small syntax flavor problem. Simpler, more understandable syntax is preferred. --- schedule/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schedule/__init__.py b/schedule/__init__.py index 1b56f12d..43b54d6d 100644 --- a/schedule/__init__.py +++ b/schedule/__init__.py @@ -111,7 +111,7 @@ def every(self, interval=1): @property def next_run(self): """Datetime when the next job should run.""" - if self.jobs.__len__() > 0: + if self.jobs: date_time = min(self.jobs).next_run else: return None From 41d1bfee9aa776dc7976cf85b5dfc009c0aac60d Mon Sep 17 00:00:00 2001 From: dilberry Date: Thu, 21 Nov 2013 13:54:38 +1000 Subject: [PATCH 3/4] Changed the continuous thread to be a Daemon type, so to allow the program to close when the main thread does. --HG-- extra : rebase_source : 603a1fb36b5c5365427ea278945dada0ef5d8433 --- schedule/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/schedule/__init__.py b/schedule/__init__.py index 43b54d6d..f7dc7ee0 100644 --- a/schedule/__init__.py +++ b/schedule/__init__.py @@ -83,6 +83,7 @@ def run(cls): time.sleep(interval) continuous_thread = ScheduleThread() + continuous_thread.setDaemon(True) continuous_thread.start() return cease_continuous_run From b556f57558026bd36b7d5100b2b46142601d74e3 Mon Sep 17 00:00:00 2001 From: dilberry Date: Fri, 22 Nov 2013 15:30:07 +1000 Subject: [PATCH 4/4] Added pause/unpause functionality to Job class. --HG-- extra : rebase_source : 7312a2c8aeab64d6a2e452d568e9c018d4bc4091 --- schedule/__init__.py | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/schedule/__init__.py b/schedule/__init__.py index f7dc7ee0..63ab9ab1 100644 --- a/schedule/__init__.py +++ b/schedule/__init__.py @@ -42,7 +42,6 @@ logger = logging.getLogger('schedule') - class Scheduler(object): def __init__(self): self.jobs = [] @@ -127,18 +126,19 @@ def idle_seconds(self): class Job(object): """A periodic job as used by `Scheduler`.""" def __init__(self, interval): - self.interval = interval # pause interval * unit between runs - self.job_func = None # the job job_func to run - self.unit = None # time units, e.g. 'minutes', 'hours', ... - self.at_time = None # optional time at which this job runs - self.last_run = None # datetime of the last run - self.next_run = None # datetime of the next run - self.period = None # timedelta between runs, only valid for + self.interval = interval # pause interval * unit between runs + self.job_func = None # the job job_func to run + self.unit = None # time units, e.g. 'minutes', 'hours', ... + self.at_time = None # optional time at which this job runs + self.last_run = None # datetime of the last run + self.next_run = None # datetime of the next run + self.period = None # timedelta between runs, only valid for + self.paused = False # job paused state def __lt__(self, other): """PeriodicJobs are sortable based on the scheduled time they run next.""" - return self.next_run < other.next_run + return (self.next_run < other.next_run) and (not self.paused) def __repr__(self): def format_time(t): @@ -242,7 +242,7 @@ def do(self, job_func, *args, **kwargs): @property def should_run(self): """True if the job should be run now.""" - return datetime.datetime.now() >= self.next_run + return (datetime.datetime.now() >= self.next_run) and (not self.paused) def run(self): """Run the job and immediately reschedule it.""" @@ -270,6 +270,13 @@ def _schedule_next_run(self): self.at_time > datetime.datetime.now().time()): self.next_run = self.next_run - datetime.timedelta(days=1) + def pause(self): + self.paused = True + self.next_run_save = self.next_run - datetime.datetime.now() + + def unpause(self): + self.paused = False + self.next_run = datetime.datetime.now() + self.next_run_save # The following methods are shortcuts for not having to # create a Scheduler instance: