diff --git a/schedule/__init__.py b/schedule/__init__.py index 45a6f1d2..31bc4b02 100644 --- a/schedule/__init__.py +++ b/schedule/__init__.py @@ -117,14 +117,15 @@ def cancel_job(self, job): except ValueError: pass - def every(self, interval=1): + def every(self, interval=1, till=None): """ Schedule a new periodic job. + :param till: :param interval: A quantity of a certain time unit :return: An unconfigured :class:`Job ` """ - job = Job(interval, self) + job = Job(interval, till, self) return job def _run_job(self, job): @@ -169,7 +170,7 @@ class Job(object): A job is usually created and returned by :meth:`Scheduler.every` method, which also defines its `interval`. """ - def __init__(self, interval, scheduler=None): + def __init__(self, interval, till=None, scheduler=None): self.interval = interval # pause interval * unit between runs self.latest = None # upper limit to the interval self.job_func = None # the job job_func to run @@ -181,6 +182,8 @@ def __init__(self, interval, scheduler=None): self.start_day = None # Specific day of the week to start on self.tags = set() # unique set of tags for the job self.scheduler = scheduler # scheduler to register with + self.till = till + self.counter = 0 def __lt__(self, other): """ @@ -396,6 +399,7 @@ def should_run(self): """ :return: ``True`` if the job should be run now. """ + # return datetime.datetime.now() >= self.next_run return datetime.datetime.now() >= self.next_run def run(self): @@ -404,10 +408,14 @@ def run(self): :return: The return value returned by the `job_func` """ + self.counter += 1 logger.info('Running job %s', self) ret = self.job_func() self.last_run = datetime.datetime.now() - self._schedule_next_run() + if self.counter is self.till: + cancel_job() + else: + self._schedule_next_run() return ret def _schedule_next_run(self): @@ -476,11 +484,11 @@ def _schedule_next_run(self): jobs = default_scheduler.jobs # todo: should this be a copy, e.g. jobs()? -def every(interval=1): +def every(interval=1, till=None): """Calls :meth:`every ` on the :data:`default scheduler instance `. """ - return default_scheduler.every(interval) + return default_scheduler.every(interval, till) def run_pending(): diff --git a/test_schedule.py b/test_schedule.py index 139745ff..d0615614 100644 --- a/test_schedule.py +++ b/test_schedule.py @@ -33,7 +33,9 @@ def __enter__(self): class MockDate(datetime.datetime): @classmethod def today(cls): - return cls(self.year, self.month, self.day) + return cls(self.year, + self.month, + self.day) @classmethod def now(cls): @@ -120,14 +122,17 @@ def test_next_run_time(self): assert every().friday.do(mock_job).next_run.day == 8 assert every().saturday.do(mock_job).next_run.day == 9 assert every().sunday.do(mock_job).next_run.day == 10 + assert every(2, 10).minutes.do(mock_job).till == 10 + assert every(2, 0).minutes.do(mock_job).till == 0 def test_run_all(self): mock_job = make_mock_job() every().minute.do(mock_job) every().hour.do(mock_job) every().day.at('11:00').do(mock_job) + every(1, 2).seconds.do(mock_job) schedule.run_all() - assert mock_job.call_count == 3 + assert mock_job.call_count == 4 def test_job_func_args_are_passed_on(self): mock_job = make_mock_job() @@ -136,8 +141,7 @@ def test_job_func_args_are_passed_on(self): mock_job.assert_called_once_with(1, 2, 'three', foo=23, bar={}) def test_to_string(self): - def job_fun(): - pass + def job_fun(): pass s = str(every().minute.do(job_fun, 'foo', bar=23)) assert 'job_fun' in s assert 'foo' in s @@ -148,8 +152,7 @@ def test_to_string_lambda_job_func(self): assert len(str(every().day.at('10:30').do(lambda: 1))) > 1 def test_to_string_functools_partial_job_func(self): - def job_fun(arg): - pass + def job_fun(arg): pass job_fun = functools.partial(job_fun, 'foo') job_repr = repr(every().minute.do(job_fun, bar=True, somekey=23)) assert 'functools.partial' in job_repr @@ -282,10 +285,16 @@ def stop_job(): schedule.cancel_job(mj) assert len(schedule.jobs) == 0 + # def test_terminate_job(self): + # mock_job = make_mock_job() + # + # every(1,5).second.do(mock_job) + # schedule.run_pending() + # print schedule. + def test_cancel_jobs(self): def stop_job(): return schedule.CancelJob - every().second.do(stop_job) every().second.do(stop_job) every().second.do(stop_job) @@ -327,4 +336,6 @@ def test_misconfigured_job_wont_break_scheduler(self): scheduler = schedule.Scheduler() scheduler.every() scheduler.every(10).seconds + scheduler.every(10).seconds + schedule.every(10, 1).seconds scheduler.run_pending()