Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-APScheduler for openSUSE:Factory checked in at 2021-02-02 14:25:28 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-APScheduler (Old) and /work/SRC/openSUSE:Factory/.python-APScheduler.new.28504 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "python-APScheduler" Tue Feb 2 14:25:28 2021 rev:13 rq:868433 version:3.7.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-APScheduler/python-APScheduler.changes 2021-01-22 21:52:58.581904591 +0100 +++ /work/SRC/openSUSE:Factory/.python-APScheduler.new.28504/python-APScheduler.changes 2021-02-02 14:25:42.815395725 +0100 @@ -1,0 +2,30 @@ +Mon Feb 1 17:38:33 UTC 2021 - Dirk M��ller <dmueller@suse.com> + +- update to 3.7.0: + * Dropped support for Python 3.4 + * Added PySide2 support (PR by Abdulla Ibrahim) + * Pinned ``tzlocal`` to a version compatible with pytz + * Ensured that jitter is always non-negative to prevent triggers from firing + more often than intended + * Changed ``AsyncIOScheduler`` to obtain the event loop in ``start()`` + instead of ``__init__()``, + to prevent situations where the scheduler won't run because it's using a + different event loop than then one currently running + * Made it possible to create weak references to ``Job`` instances + * Made the schedulers explicitly raise a descriptive ``TypeError`` when serialization is attempted + * Fixed Zookeeper job store using backslashes instead of forward slashes for paths + on Windows + * Fixed deprecation warnings on the MongoDB job store and increased the minimum PyMongo + * Fixed ``BlockingScheduler`` and ``BackgroundScheduler`` shutdown hanging after the user has + erroneously tried to start it twice + * Fixed memory leak when coroutine jobs raise exceptions + * Fixed inability to schedule wrapped functions with extra arguments when the wrapped function + cannot accept them but the wrapper can (original PR by Egor Malykh) + * Fixed potential ``where`` clause error in the SQLAlchemy job store when a subclass uses more than + one search condition + * Fixed a problem where bound methods added as jobs via textual references were called with an + unwanted extra ``self`` argument (PR by Pengjie Song) + * Fixed ``BrokenPoolError`` in ``ProcessPoolExecutor`` so that it will automatically replace the + broken pool with a fresh instance + +------------------------------------------------------------------- Old: ---- APScheduler-3.6.3.tar.gz New: ---- APScheduler-3.7.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-APScheduler.spec ++++++ --- /var/tmp/diff_new_pack.KoocFM/_old 2021-02-02 14:25:43.531396839 +0100 +++ /var/tmp/diff_new_pack.KoocFM/_new 2021-02-02 14:25:43.531396839 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-APScheduler # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2021 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -19,7 +19,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %bcond_without python2 Name: python-APScheduler -Version: 3.6.3 +Version: 3.7.0 Release: 0 Summary: In-process task scheduler with Cron-like capabilities License: MIT @@ -28,27 +28,27 @@ BuildRequires: %{python_module SQLAlchemy >= 0.8} BuildRequires: %{python_module Twisted} BuildRequires: %{python_module gevent} +BuildRequires: %{python_module pytest < 6} BuildRequires: %{python_module pytest-asyncio} BuildRequires: %{python_module pytest-cov} BuildRequires: %{python_module pytest-tornado} -BuildRequires: %{python_module pytest} BuildRequires: %{python_module pytz} BuildRequires: %{python_module setuptools >= 36.2.7} BuildRequires: %{python_module setuptools_scm >= 1.7.0} BuildRequires: %{python_module six >= 1.4.0} BuildRequires: %{python_module tornado} -BuildRequires: %{python_module tzlocal >= 1.2} +BuildRequires: %{python_module tzlocal >= 2.0} BuildRequires: fdupes BuildRequires: python-rpm-macros BuildRequires: python3-pytest-asyncio Requires: python-pytz Requires: python-six >= 1.4.0 -Requires: python-tzlocal >= 1.2 +Requires: python-tzlocal >= 2.0 Recommends: python-SQLAlchemy >= 0.8 Recommends: python-Twisted Recommends: python-gevent Suggests: python-kazoo -Suggests: python-pymongo >= 2.8 +Suggests: python-pymongo >= 3.0 Suggests: python-redis Suggests: python-tornado >= 4.3 BuildArch: noarch ++++++ APScheduler-3.6.3.tar.gz -> APScheduler-3.7.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/.travis.yml new/APScheduler-3.7.0/.travis.yml --- old/APScheduler-3.6.3/.travis.yml 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/.travis.yml 2021-01-19 15:34:44.000000000 +0100 @@ -17,7 +17,7 @@ - &test stage: test env: TOXENV=pypy - python: pypy2.7-6.0 + python: pypy before_install: docker-compose up -d after_success: - pip install coveralls @@ -25,17 +25,13 @@ - <<: *test env: TOXENV=pypy3 - python: pypy3.5-6.0 + python: pypy3 - <<: *test env: TOXENV=py27 python: "2.7" - <<: *test - env: TOXENV=py34 - python: "3.4" - - - <<: *test env: TOXENV=py35 python: "3.5" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/APScheduler.egg-info/PKG-INFO new/APScheduler-3.7.0/APScheduler.egg-info/PKG-INFO --- old/APScheduler-3.6.3/APScheduler.egg-info/PKG-INFO 2019-11-05 08:51:47.000000000 +0100 +++ new/APScheduler-3.7.0/APScheduler.egg-info/PKG-INFO 2021-01-19 15:35:14.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: APScheduler -Version: 3.6.3 +Version: 3.7.0 Summary: In-process task scheduler with Cron-like capabilities Home-page: https://github.com/agronholm/apscheduler Author: Alex Gr��nholm @@ -49,9 +49,16 @@ * `Tornado <http://www.tornadoweb.org/>`_ * `Twisted <http://twistedmatrix.com/>`_ * `Qt <http://qt-project.org/>`_ (using either - `PyQt <http://www.riverbankcomputing.com/software/pyqt/intro>`_ or + `PyQt <http://www.riverbankcomputing.com/software/pyqt/intro>`_ , + `PySide2 <https://wiki.qt.io/Qt_for_Python>`_ or `PySide <http://qt-project.org/wiki/PySide>`_) + There are third party solutions for integrating APScheduler with other frameworks: + + * `Django <https://github.com/jarekwg/django-apscheduler>`_ + * `Flask <https://github.com/viniciuschiele/flask-apscheduler>`_ + + .. [#f1] The cutoff period for this is also configurable. @@ -91,10 +98,10 @@ Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4 Provides-Extra: asyncio Provides-Extra: gevent Provides-Extra: mongodb diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/APScheduler.egg-info/requires.txt new/APScheduler-3.7.0/APScheduler.egg-info/requires.txt --- old/APScheduler-3.6.3/APScheduler.egg-info/requires.txt 2019-11-05 08:51:47.000000000 +0100 +++ new/APScheduler-3.7.0/APScheduler.egg-info/requires.txt 2021-01-19 15:35:14.000000000 +0100 @@ -1,11 +1,13 @@ setuptools>=0.7 six>=1.4.0 pytz -tzlocal>=1.2 +tzlocal~=2.0 + +[:python_version < "3.5"] +funcsigs [:python_version == "2.7"] futures -funcsigs [asyncio:python_version == "2.7"] trollius @@ -18,7 +20,7 @@ gevent [mongodb] -pymongo>=2.8 +pymongo>=3.0 [redis] redis>=3.0 @@ -30,7 +32,7 @@ sqlalchemy>=0.8 [testing] -pytest +pytest<6 pytest-cov pytest-tornado5 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/PKG-INFO new/APScheduler-3.7.0/PKG-INFO --- old/APScheduler-3.6.3/PKG-INFO 2019-11-05 08:51:47.000000000 +0100 +++ new/APScheduler-3.7.0/PKG-INFO 2021-01-19 15:35:15.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: APScheduler -Version: 3.6.3 +Version: 3.7.0 Summary: In-process task scheduler with Cron-like capabilities Home-page: https://github.com/agronholm/apscheduler Author: Alex Gr��nholm @@ -49,9 +49,16 @@ * `Tornado <http://www.tornadoweb.org/>`_ * `Twisted <http://twistedmatrix.com/>`_ * `Qt <http://qt-project.org/>`_ (using either - `PyQt <http://www.riverbankcomputing.com/software/pyqt/intro>`_ or + `PyQt <http://www.riverbankcomputing.com/software/pyqt/intro>`_ , + `PySide2 <https://wiki.qt.io/Qt_for_Python>`_ or `PySide <http://qt-project.org/wiki/PySide>`_) + There are third party solutions for integrating APScheduler with other frameworks: + + * `Django <https://github.com/jarekwg/django-apscheduler>`_ + * `Flask <https://github.com/viniciuschiele/flask-apscheduler>`_ + + .. [#f1] The cutoff period for this is also configurable. @@ -91,10 +98,10 @@ Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4 Provides-Extra: asyncio Provides-Extra: gevent Provides-Extra: mongodb diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/README.rst new/APScheduler-3.7.0/README.rst --- old/APScheduler-3.6.3/README.rst 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/README.rst 2021-01-19 15:34:44.000000000 +0100 @@ -41,9 +41,16 @@ * `Tornado <http://www.tornadoweb.org/>`_ * `Twisted <http://twistedmatrix.com/>`_ * `Qt <http://qt-project.org/>`_ (using either - `PyQt <http://www.riverbankcomputing.com/software/pyqt/intro>`_ or + `PyQt <http://www.riverbankcomputing.com/software/pyqt/intro>`_ , + `PySide2 <https://wiki.qt.io/Qt_for_Python>`_ or `PySide <http://qt-project.org/wiki/PySide>`_) +There are third party solutions for integrating APScheduler with other frameworks: + +* `Django <https://github.com/jarekwg/django-apscheduler>`_ +* `Flask <https://github.com/viniciuschiele/flask-apscheduler>`_ + + .. [#f1] The cutoff period for this is also configurable. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/apscheduler/executors/base_py3.py new/APScheduler-3.7.0/apscheduler/executors/base_py3.py --- old/APScheduler-3.6.3/apscheduler/executors/base_py3.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/apscheduler/executors/base_py3.py 2021-01-19 15:34:44.000000000 +0100 @@ -1,5 +1,6 @@ import logging import sys +import traceback from datetime import datetime, timedelta from traceback import format_tb @@ -33,6 +34,7 @@ events.append(JobExecutionEvent(EVENT_JOB_ERROR, job.id, jobstore_alias, run_time, exception=exc, traceback=formatted_tb)) logger.exception('Job "%s" raised an exception', job) + traceback.clear_frames(tb) else: events.append(JobExecutionEvent(EVENT_JOB_EXECUTED, job.id, jobstore_alias, run_time, retval=retval)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/apscheduler/executors/pool.py new/APScheduler-3.7.0/apscheduler/executors/pool.py --- old/APScheduler-3.6.3/apscheduler/executors/pool.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/apscheduler/executors/pool.py 2021-01-19 15:34:44.000000000 +0100 @@ -3,6 +3,11 @@ from apscheduler.executors.base import BaseExecutor, run_job +try: + from concurrent.futures.process import BrokenProcessPool +except ImportError: + BrokenProcessPool = None + class BasePoolExecutor(BaseExecutor): @abstractmethod @@ -19,7 +24,13 @@ else: self._run_job_success(job.id, f.result()) - f = self._pool.submit(run_job, job, job._jobstore_alias, run_times, self._logger.name) + try: + f = self._pool.submit(run_job, job, job._jobstore_alias, run_times, self._logger.name) + except BrokenProcessPool: + self._logger.warning('Process pool is broken; replacing pool with a fresh instance') + self._pool = self._pool.__class__(self._pool._max_workers) + f = self._pool.submit(run_job, job, job._jobstore_alias, run_times, self._logger.name) + f.add_done_callback(callback) def shutdown(self, wait=True): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/apscheduler/job.py new/APScheduler-3.7.0/apscheduler/job.py --- old/APScheduler-3.6.3/apscheduler/job.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/apscheduler/job.py 2021-01-19 15:34:44.000000000 +0100 @@ -28,7 +28,7 @@ :var trigger: the trigger object that controls the schedule of this job :var str executor: the name of the executor that will run this job :var int misfire_grace_time: the time (in seconds) how much this job's execution is allowed to - be late + be late (``None`` means "allow the job to run no matter how late it is") :var int max_instances: the maximum number of concurrently executing instances allowed for this job :var datetime.datetime next_run_time: the next scheduled run time of this job @@ -40,7 +40,7 @@ __slots__ = ('_scheduler', '_jobstore_alias', 'id', 'trigger', 'executor', 'func', 'func_ref', 'args', 'kwargs', 'name', 'misfire_grace_time', 'coalesce', 'max_instances', - 'next_run_time') + 'next_run_time', '__weakref__') def __init__(self, scheduler, id=None, **kwargs): super(Job, self).__init__() @@ -242,8 +242,9 @@ # Instance methods cannot survive serialization as-is, so store the "self" argument # explicitly - if ismethod(self.func) and not isclass(self.func.__self__): - args = (self.func.__self__,) + tuple(self.args) + func = self.func + if ismethod(func) and not isclass(func.__self__) and obj_to_ref(func) == self.func_ref: + args = (func.__self__,) + tuple(self.args) else: args = self.args diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/apscheduler/jobstores/mongodb.py new/APScheduler-3.7.0/apscheduler/jobstores/mongodb.py --- old/APScheduler-3.6.3/apscheduler/jobstores/mongodb.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/apscheduler/jobstores/mongodb.py 2021-01-19 15:34:44.000000000 +0100 @@ -54,7 +54,7 @@ def start(self, scheduler, alias): super(MongoDBJobStore, self).start(scheduler, alias) - self.collection.ensure_index('next_run_time', sparse=True) + self.collection.create_index('next_run_time', sparse=True) @property def connection(self): @@ -83,7 +83,7 @@ def add_job(self, job): try: - self.collection.insert({ + self.collection.insert_one({ '_id': job.id, 'next_run_time': datetime_to_utc_timestamp(job.next_run_time), 'job_state': Binary(pickle.dumps(job.__getstate__(), self.pickle_protocol)) @@ -96,13 +96,13 @@ 'next_run_time': datetime_to_utc_timestamp(job.next_run_time), 'job_state': Binary(pickle.dumps(job.__getstate__(), self.pickle_protocol)) } - result = self.collection.update({'_id': job.id}, {'$set': changes}) - if result and result['n'] == 0: + result = self.collection.update_one({'_id': job.id}, {'$set': changes}) + if result and result.matched_count == 0: raise JobLookupError(job.id) def remove_job(self, job_id): - result = self.collection.remove(job_id) - if result and result['n'] == 0: + result = self.collection.delete_one({'_id': job_id}) + if result and result.deleted_count == 0: raise JobLookupError(job_id) def remove_all_jobs(self): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/apscheduler/jobstores/sqlalchemy.py new/APScheduler-3.7.0/apscheduler/jobstores/sqlalchemy.py --- old/APScheduler-3.6.3/apscheduler/jobstores/sqlalchemy.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/apscheduler/jobstores/sqlalchemy.py 2021-01-19 15:34:44.000000000 +0100 @@ -11,7 +11,7 @@ try: from sqlalchemy import ( - create_engine, Table, Column, MetaData, Unicode, Float, LargeBinary, select) + create_engine, Table, Column, MetaData, Unicode, Float, LargeBinary, select, and_) from sqlalchemy.exc import IntegrityError from sqlalchemy.sql.expression import null except ImportError: # pragma: nocover @@ -134,7 +134,7 @@ jobs = [] selectable = select([self.jobs_t.c.id, self.jobs_t.c.job_state]).\ order_by(self.jobs_t.c.next_run_time) - selectable = selectable.where(*conditions) if conditions else selectable + selectable = selectable.where(and_(*conditions)) if conditions else selectable failed_job_ids = set() for row in self.engine.execute(selectable): try: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/apscheduler/jobstores/zookeeper.py new/APScheduler-3.7.0/apscheduler/jobstores/zookeeper.py --- old/APScheduler-3.6.3/apscheduler/jobstores/zookeeper.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/apscheduler/jobstores/zookeeper.py 2021-01-19 15:34:44.000000000 +0100 @@ -1,6 +1,5 @@ from __future__ import absolute_import -import os from datetime import datetime from pytz import utc @@ -65,7 +64,7 @@ def lookup_job(self, job_id): self._ensure_paths() - node_path = os.path.join(self.path, job_id) + node_path = self.path + "/" + str(job_id) try: content, _ = self.client.get(node_path) doc = pickle.loads(content) @@ -92,7 +91,7 @@ def add_job(self, job): self._ensure_paths() - node_path = os.path.join(self.path, str(job.id)) + node_path = self.path + "/" + str(job.id) value = { 'next_run_time': datetime_to_utc_timestamp(job.next_run_time), 'job_state': job.__getstate__() @@ -105,7 +104,7 @@ def update_job(self, job): self._ensure_paths() - node_path = os.path.join(self.path, str(job.id)) + node_path = self.path + "/" + str(job.id) changes = { 'next_run_time': datetime_to_utc_timestamp(job.next_run_time), 'job_state': job.__getstate__() @@ -118,7 +117,7 @@ def remove_job(self, job_id): self._ensure_paths() - node_path = os.path.join(self.path, str(job_id)) + node_path = self.path + "/" + str(job_id) try: self.client.delete(node_path) except NoNodeError: @@ -151,7 +150,7 @@ all_ids = self.client.get_children(self.path) for node_name in all_ids: try: - node_path = os.path.join(self.path, node_name) + node_path = self.path + "/" + node_name content, _ = self.client.get(node_path) doc = pickle.loads(content) job_def = { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/apscheduler/schedulers/asyncio.py new/APScheduler-3.7.0/apscheduler/schedulers/asyncio.py --- old/APScheduler-3.6.3/apscheduler/schedulers/asyncio.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/apscheduler/schedulers/asyncio.py 2021-01-19 15:34:44.000000000 +0100 @@ -38,13 +38,19 @@ _eventloop = None _timeout = None + def start(self, paused=False): + if not self._eventloop: + self._eventloop = asyncio.get_event_loop() + + super(AsyncIOScheduler, self).start(paused) + @run_in_event_loop def shutdown(self, wait=True): super(AsyncIOScheduler, self).shutdown(wait) self._stop_timer() def _configure(self, config): - self._eventloop = maybe_ref(config.pop('event_loop', None)) or asyncio.get_event_loop() + self._eventloop = maybe_ref(config.pop('event_loop', None)) super(AsyncIOScheduler, self)._configure(config) def _start_timer(self, wait_seconds): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/apscheduler/schedulers/background.py new/APScheduler-3.7.0/apscheduler/schedulers/background.py --- old/APScheduler-3.6.3/apscheduler/schedulers/background.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/apscheduler/schedulers/background.py 2021-01-19 15:34:44.000000000 +0100 @@ -29,7 +29,9 @@ super(BackgroundScheduler, self)._configure(config) def start(self, *args, **kwargs): - self._event = Event() + if self._event is None or self._event.is_set(): + self._event = Event() + BaseScheduler.start(self, *args, **kwargs) self._thread = Thread(target=self._main_loop, name='APScheduler') self._thread.daemon = self._daemon diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/apscheduler/schedulers/base.py new/APScheduler-3.7.0/apscheduler/schedulers/base.py --- old/APScheduler-3.6.3/apscheduler/schedulers/base.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/apscheduler/schedulers/base.py 2021-01-19 15:34:44.000000000 +0100 @@ -86,6 +86,11 @@ self.state = STATE_STOPPED self.configure(gconfig, **options) + def __getstate__(self): + raise TypeError("Schedulers cannot be serialized. Ensure that you are not passing a " + "scheduler instance as an argument to a job, or scheduling an instance " + "method where the instance contains a scheduler as an attribute.") + def configure(self, gconfig={}, prefix='apscheduler.', **options): """ Reconfigures the scheduler with the given options. @@ -402,7 +407,7 @@ :param str|unicode id: explicit identifier for the job (for modifying it later) :param str|unicode name: textual description of the job :param int misfire_grace_time: seconds after the designated runtime that the job is still - allowed to be run + allowed to be run (or ``None`` to allow the job to run no matter how late it is) :param bool coalesce: run once instead of many times if the scheduler determines that the job should be run more than once in succession :param int max_instances: maximum number of concurrently running instances allowed for this diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/apscheduler/schedulers/blocking.py new/APScheduler-3.7.0/apscheduler/schedulers/blocking.py --- old/APScheduler-3.6.3/apscheduler/schedulers/blocking.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/apscheduler/schedulers/blocking.py 2021-01-19 15:34:44.000000000 +0100 @@ -14,7 +14,9 @@ _event = None def start(self, *args, **kwargs): - self._event = Event() + if self._event is None or self._event.is_set(): + self._event = Event() + super(BlockingScheduler, self).start(*args, **kwargs) self._main_loop() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/apscheduler/schedulers/qt.py new/APScheduler-3.7.0/apscheduler/schedulers/qt.py --- old/APScheduler-3.6.3/apscheduler/schedulers/qt.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/apscheduler/schedulers/qt.py 2021-01-19 15:34:44.000000000 +0100 @@ -9,9 +9,13 @@ from PyQt4.QtCore import QObject, QTimer except ImportError: try: - from PySide.QtCore import QObject, QTimer # noqa + from PySide2.QtCore import QObject, QTimer # noqa except ImportError: - raise ImportError('QtScheduler requires either PyQt5, PyQt4 or PySide installed') + try: + from PySide.QtCore import QObject, QTimer # noqa + except ImportError: + raise ImportError('QtScheduler requires either PyQt5, PyQt4, PySide2 ' + 'or PySide installed') class QtScheduler(BaseScheduler): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/apscheduler/triggers/base.py new/APScheduler-3.7.0/apscheduler/triggers/base.py --- old/APScheduler-3.6.3/apscheduler/triggers/base.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/apscheduler/triggers/base.py 2021-01-19 15:34:44.000000000 +0100 @@ -22,27 +22,16 @@ def _apply_jitter(self, next_fire_time, jitter, now): """ - Randomize ``next_fire_time`` by adding or subtracting a random value (the jitter). If the - resulting datetime is in the past, returns the initial ``next_fire_time`` without jitter. - - ``next_fire_time - jitter <= result <= next_fire_time + jitter`` + Randomize ``next_fire_time`` by adding a random value (the jitter). :param datetime.datetime|None next_fire_time: next fire time without jitter applied. If ``None``, returns ``None``. - :param int|None jitter: maximum number of seconds to add or subtract to - ``next_fire_time``. If ``None`` or ``0``, returns ``next_fire_time`` + :param int|None jitter: maximum number of seconds to add to ``next_fire_time`` + (if ``None`` or ``0``, returns ``next_fire_time``) :param datetime.datetime now: current datetime :return datetime.datetime|None: next fire time with a jitter. """ if next_fire_time is None or not jitter: return next_fire_time - next_fire_time_with_jitter = next_fire_time + timedelta( - seconds=random.uniform(-jitter, jitter)) - - if next_fire_time_with_jitter < now: - # Next fire time with jitter is in the past. - # Ignore jitter to avoid false misfire. - return next_fire_time - - return next_fire_time_with_jitter + return next_fire_time + timedelta(seconds=random.uniform(0, jitter)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/apscheduler/triggers/combining.py new/APScheduler-3.7.0/apscheduler/triggers/combining.py --- old/APScheduler-3.6.3/apscheduler/triggers/combining.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/apscheduler/triggers/combining.py 2021-01-19 15:34:44.000000000 +0100 @@ -45,7 +45,7 @@ Trigger alias: ``and`` :param list triggers: triggers to combine - :param int|None jitter: advance or delay the job execution by ``jitter`` seconds at most. + :param int|None jitter: delay the job execution by ``jitter`` seconds at most """ __slots__ = () @@ -73,7 +73,7 @@ Trigger alias: ``or`` :param list triggers: triggers to combine - :param int|None jitter: advance or delay the job execution by ``jitter`` seconds at most. + :param int|None jitter: delay the job execution by ``jitter`` seconds at most .. note:: Triggers that depends on the previous fire time, such as the interval trigger, may seem to behave strangely since they are always passed the previous fire time produced by diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/apscheduler/triggers/cron/__init__.py new/APScheduler-3.7.0/apscheduler/triggers/cron/__init__.py --- old/APScheduler-3.6.3/apscheduler/triggers/cron/__init__.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/apscheduler/triggers/cron/__init__.py 2021-01-19 15:34:44.000000000 +0100 @@ -16,7 +16,7 @@ :param int|str year: 4-digit year :param int|str month: month (1-12) - :param int|str day: day of the (1-31) + :param int|str day: day of month (1-31) :param int|str week: ISO week (1-53) :param int|str day_of_week: number or name of weekday (0-6 or mon,tue,wed,thu,fri,sat,sun) :param int|str hour: hour (0-23) @@ -26,7 +26,7 @@ :param datetime|str end_date: latest possible date/time to trigger on (inclusive) :param datetime.tzinfo|str timezone: time zone to use for the date/time calculations (defaults to scheduler timezone) - :param int|None jitter: advance or delay the job execution by ``jitter`` seconds at most. + :param int|None jitter: delay the job execution by ``jitter`` seconds at most .. note:: The first weekday is always **monday**. """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/apscheduler/triggers/interval.py new/APScheduler-3.7.0/apscheduler/triggers/interval.py --- old/APScheduler-3.6.3/apscheduler/triggers/interval.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/apscheduler/triggers/interval.py 2021-01-19 15:34:44.000000000 +0100 @@ -20,7 +20,7 @@ :param datetime|str start_date: starting point for the interval calculation :param datetime|str end_date: latest possible date/time to trigger on :param datetime.tzinfo|str timezone: time zone to use for the date/time calculations - :param int|None jitter: advance or delay the job execution by ``jitter`` seconds at most. + :param int|None jitter: delay the job execution by ``jitter`` seconds at most """ __slots__ = 'timezone', 'start_date', 'end_date', 'interval', 'interval_length', 'jitter' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/apscheduler/util.py new/APScheduler-3.7.0/apscheduler/util.py --- old/APScheduler-3.6.3/apscheduler/util.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/apscheduler/util.py 2021-01-19 15:34:44.000000000 +0100 @@ -7,6 +7,7 @@ from functools import partial from inspect import isclass, ismethod import re +import sys from pytz import timezone, utc, FixedOffset import six @@ -352,7 +353,10 @@ has_varargs = has_var_kwargs = False try: - sig = signature(func) + if sys.version_info >= (3, 5): + sig = signature(func, follow_wrapped=False) + else: + sig = signature(func) except ValueError: # signature() doesn't work against every kind of callable return diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/docs/modules/schedulers/qt.rst new/APScheduler-3.7.0/docs/modules/schedulers/qt.rst --- old/APScheduler-3.6.3/docs/modules/schedulers/qt.rst 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/docs/modules/schedulers/qt.rst 2021-01-19 15:34:44.000000000 +0100 @@ -13,7 +13,7 @@ Introduction ------------ -QtScheduler lets you integrate APScheduler with your `PySide <https://en.wikipedia.org/wiki/PySide>` or +QtScheduler lets you integrate APScheduler with your `PySide2 <https://wiki.qt.io/Qt_for_Python>`, `PySide <https://en.wikipedia.org/wiki/PySide>` or `PyQt <http://www.riverbankcomputing.co.uk/software/pyqt/intro>`_ application. .. list-table:: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/docs/modules/triggers/combining.rst new/APScheduler-3.7.0/docs/modules/triggers/combining.rst --- old/APScheduler-3.6.3/docs/modules/triggers/combining.rst 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/docs/modules/triggers/combining.rst 2021-01-19 15:34:44.000000000 +0100 @@ -28,8 +28,8 @@ CronTrigger(day_of_week='sat,sun')]) scheduler.add_job(job_function, trigger) -Run ``job_function`` every Monday at 2pm and every Tuesday at 3pm:: +Run ``job_function`` every Monday at 2am and every Tuesday at 3pm:: trigger = OrTrigger([CronTrigger(day_of_week='mon', hour=2), - CronTrigger(day_of_week='tue', hour=3)]) + CronTrigger(day_of_week='tue', hour=15)]) scheduler.add_job(job_function, trigger) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/docs/modules/triggers/interval.rst new/APScheduler-3.7.0/docs/modules/triggers/interval.rst --- old/APScheduler-3.6.3/docs/modules/triggers/interval.rst 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/docs/modules/triggers/interval.rst 2021-01-19 15:34:44.000000000 +0100 @@ -54,8 +54,7 @@ The :meth:`~apscheduler.schedulers.base.BaseScheduler.scheduled_job` decorator works nicely too:: - from apscheduler.scheduler import BlockingScheduler - + @sched.scheduled_job('interval', id='my_job_id', hours=2) def job_function(): print("Hello World") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/docs/versionhistory.rst new/APScheduler-3.7.0/docs/versionhistory.rst --- old/APScheduler-3.6.3/docs/versionhistory.rst 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/docs/versionhistory.rst 2021-01-19 15:34:44.000000000 +0100 @@ -4,6 +4,36 @@ To find out how to migrate your application from a previous version of APScheduler, see the :doc:`migration section <migration>`. +3.7.0 +----- + +* Dropped support for Python 3.4 +* Added PySide2 support (PR by Abdulla Ibrahim) +* Pinned ``tzlocal`` to a version compatible with pytz +* Ensured that jitter is always non-negative to prevent triggers from firing more often than + intended +* Changed ``AsyncIOScheduler`` to obtain the event loop in ``start()`` instead of ``__init__()``, + to prevent situations where the scheduler won't run because it's using a different event loop + than then one currently running +* Made it possible to create weak references to ``Job`` instances +* Made the schedulers explicitly raise a descriptive ``TypeError`` when serialization is attempted +* Fixed Zookeeper job store using backslashes instead of forward slashes for paths + on Windows (PR by Laurel-rao) +* Fixed deprecation warnings on the MongoDB job store and increased the minimum PyMongo + version to 3.0 +* Fixed ``BlockingScheduler`` and ``BackgroundScheduler`` shutdown hanging after the user has + erroneously tried to start it twice +* Fixed memory leak when coroutine jobs raise exceptions (due to reference cycles in tracebacks) +* Fixed inability to schedule wrapped functions with extra arguments when the wrapped function + cannot accept them but the wrapper can (original PR by Egor Malykh) +* Fixed potential ``where`` clause error in the SQLAlchemy job store when a subclass uses more than + one search condition +* Fixed a problem where bound methods added as jobs via textual references were called with an + unwanted extra ``self`` argument (PR by Pengjie Song) +* Fixed ``BrokenPoolError`` in ``ProcessPoolExecutor`` so that it will automatically replace the + broken pool with a fresh instance + + 3.6.3 ----- @@ -343,7 +373,7 @@ * Added optional job execution coalescing for situations where several executions of the job are due -* Added an option to limit the maximum number of concurrenctly executing +* Added an option to limit the maximum number of concurrently executing instances of the job * Allowed configuration of misfire grace times on a per-job basis diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/examples/schedulers/qt.py new/APScheduler-3.7.0/examples/schedulers/qt.py --- old/APScheduler-3.6.3/examples/schedulers/qt.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/examples/schedulers/qt.py 2021-01-19 15:34:44.000000000 +0100 @@ -15,7 +15,10 @@ try: from PyQt4.QtGui import QApplication, QLabel except ImportError: - from PySide.QtGui import QApplication, QLabel + try: + from PySide2.QtWidgets import QApplication, QLabel + except ImportError: + from PySide.QtGui import QApplication, QLabel def tick(): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/setup.py new/APScheduler-3.7.0/setup.py --- old/APScheduler-3.6.3/setup.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/setup.py 2021-01-19 15:34:44.000000000 +0100 @@ -26,7 +26,6 @@ 'Programming Language :: Python', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7' @@ -34,6 +33,7 @@ keywords='scheduling cron', license='MIT', packages=find_packages(exclude=['tests']), + python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4', setup_requires=[ 'setuptools_scm' ], @@ -41,13 +41,14 @@ 'setuptools >= 0.7', 'six >= 1.4.0', 'pytz', - 'tzlocal >= 1.2', + 'tzlocal ~= 2.0', ], extras_require={ - ':python_version == "2.7"': ['futures', 'funcsigs'], + ':python_version == "2.7"': ['futures'], + ':python_version < "3.5"': ['funcsigs'], 'asyncio:python_version == "2.7"': ['trollius'], 'gevent': ['gevent'], - 'mongodb': ['pymongo >= 2.8'], + 'mongodb': ['pymongo >= 3.0'], 'redis': ['redis >= 3.0'], 'rethinkdb': ['rethinkdb >= 2.4.0'], 'sqlalchemy': ['sqlalchemy >= 0.8'], @@ -55,7 +56,7 @@ 'twisted': ['twisted'], 'zookeeper': ['kazoo'], 'testing': [ - 'pytest', + 'pytest < 6', 'pytest-cov', 'pytest-tornado5' ], diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/tests/test_executors.py new/APScheduler-3.7.0/tests/test_executors.py --- old/APScheduler-3.6.3/tests/test_executors.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/tests/test_executors.py 2021-01-19 15:34:44.000000000 +0100 @@ -2,15 +2,20 @@ from threading import Event from types import TracebackType import gc +import os +import signal import time import pytest from pytz import UTC -from apscheduler.events import EVENT_JOB_ERROR, EVENT_JOB_MISSED, EVENT_JOB_EXECUTED +from apscheduler.events import EVENT_JOB_ERROR, EVENT_JOB_EXECUTED, EVENT_JOB_MISSED from apscheduler.executors.base import MaxInstancesReachedError, run_job +from apscheduler.executors.pool import ProcessPoolExecutor from apscheduler.job import Job +from apscheduler.schedulers.background import BackgroundScheduler from apscheduler.schedulers.base import BaseScheduler +from tests.conftest import minpython try: from unittest.mock import Mock, MagicMock, patch @@ -144,3 +149,31 @@ foos = [x for x in gc.get_objects() if type(x) is FooBar] assert len(foos) == 0 + + +@minpython(3, 3) +def test_broken_pool(): + def listener(evt): + pid[0] = evt.retval + event.set() + + pid = [None] + event = Event() + scheduler = BackgroundScheduler(executors={'default': ProcessPoolExecutor(1)}) + scheduler.add_listener(listener, EVENT_JOB_EXECUTED) + scheduler.add_job(os.getpid, 'date', run_date=datetime.now(UTC)) + scheduler.start() + + event.wait(3) + killed_pid = pid[0] + os.kill(pid[0], signal.SIGTERM) + try: + os.waitpid(pid[0], 0) + except OSError: + pass + + event.clear() + scheduler.add_job(os.getpid, 'date', run_date=datetime.now(UTC)) + event.wait(3) + assert pid[0] != killed_pid + scheduler.shutdown(True) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/tests/test_executors_py35.py new/APScheduler-3.7.0/tests/test_executors_py35.py --- old/APScheduler-3.6.3/tests/test_executors_py35.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/tests/test_executors_py35.py 2021-01-19 15:34:44.000000000 +0100 @@ -1,13 +1,18 @@ """Contains test functions using Python 3.3+ syntax.""" +import gc from asyncio import CancelledError from datetime import datetime +from unittest.mock import Mock, patch import pytest +from pytz import utc + from apscheduler.executors.asyncio import AsyncIOExecutor +from apscheduler.executors.base_py3 import run_coroutine_job from apscheduler.executors.tornado import TornadoExecutor +from apscheduler.job import Job from apscheduler.schedulers.asyncio import AsyncIOScheduler from apscheduler.schedulers.tornado import TornadoScheduler -from pytz import utc @pytest.fixture @@ -100,3 +105,21 @@ asyncio_executor.shutdown() with pytest.raises(CancelledError): await futures.pop() + + +@pytest.mark.asyncio +async def test_run_job_memory_leak(): + class FooBar: + pass + + async def func(): + foo = FooBar() # noqa: F841 + raise Exception('dummy') + + fake_job = Mock(Job, func=func, args=(), kwargs={}, misfire_grace_time=1) + with patch('logging.getLogger'): + for _ in range(5): + await run_coroutine_job(fake_job, 'foo', [datetime.now(utc)], __name__) + + foos = [x for x in gc.get_objects() if type(x) is FooBar] + assert len(foos) == 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/tests/test_job.py new/APScheduler-3.7.0/tests/test_job.py --- old/APScheduler-3.6.3/tests/test_job.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/tests/test_job.py 2021-01-19 15:34:44.000000000 +0100 @@ -1,4 +1,6 @@ # coding: utf-8 +import gc +import weakref from datetime import datetime, timedelta from functools import partial @@ -64,6 +66,14 @@ job._scheduler.remove_job.assert_called_once_with(job.id, None) +def test_weakref(create_job): + job = create_job(func=dummyfunc) + ref = weakref.ref(job) + del job + gc.collect() + assert ref() is None + + def test_pending(job): """ Tests that the "pending" property return True when _jobstore_alias is a string, ``False`` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/tests/test_jobstores.py new/APScheduler-3.7.0/tests/test_jobstores.py --- old/APScheduler-3.6.3/tests/test_jobstores.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/tests/test_jobstores.py 2021-01-19 15:34:44.000000000 +0100 @@ -27,6 +27,9 @@ return a + b +dummy_instance = DummyClass() + + @pytest.fixture def memjobstore(): yield MemoryJobStore() @@ -112,18 +115,32 @@ return create -def test_add_instance_method_job(jobstore, create_add_job): +def test_add_callable_instance_method_job(jobstore, create_add_job): instance = DummyClass() initial_job = create_add_job(jobstore, instance.dummy_method, kwargs={'a': 1, 'b': 2}) job = jobstore.lookup_job(initial_job.id) assert job.func(*job.args, **job.kwargs) == 3 -def test_add_class_method_job(jobstore, create_add_job): +def test_add_callable_class_method_job(jobstore, create_add_job): initial_job = create_add_job(jobstore, DummyClass.dummy_classmethod, kwargs={'a': 1, 'b': 2}) job = jobstore.lookup_job(initial_job.id) assert job.func(*job.args, **job.kwargs) == 3 + +def test_add_textual_instance_method_job(jobstore, create_add_job): + initial_job = create_add_job(jobstore, 'tests.test_jobstores:dummy_instance.dummy_method', + kwargs={'a': 1, 'b': 2}) + job = jobstore.lookup_job(initial_job.id) + assert job.func(*job.args, **job.kwargs) == 3 + + +def test_add_textual_class_method_job(jobstore, create_add_job): + initial_job = create_add_job(jobstore, 'tests.test_jobstores:DummyClass.dummy_classmethod', + kwargs={'a': 1, 'b': 2}) + job = jobstore.lookup_job(initial_job.id) + assert job.func(*job.args, **job.kwargs) == 3 + def test_lookup_job(jobstore, create_add_job): initial_job = create_add_job(jobstore) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/tests/test_schedulers.py new/APScheduler-3.7.0/tests/test_schedulers.py --- old/APScheduler-3.6.3/tests/test_schedulers.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/tests/test_schedulers.py 2021-01-19 15:34:44.000000000 +0100 @@ -1,4 +1,5 @@ import logging +import pickle from datetime import datetime, timedelta from threading import Thread @@ -772,6 +773,9 @@ assert len(scheduler_events) == 1 assert scheduler_events[0].scheduled_run_times == [freeze_time.get(scheduler.timezone)] + def test_serialize_scheduler(self, scheduler): + pytest.raises(TypeError, pickle.dumps, scheduler).match('Schedulers cannot be serialized') + class TestProcessJobs(object): @pytest.fixture diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/tests/test_triggers.py new/APScheduler-3.7.0/tests/test_triggers.py --- old/APScheduler-3.6.3/tests/test_triggers.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/tests/test_triggers.py 2021-01-19 15:34:44.000000000 +0100 @@ -50,16 +50,6 @@ trigger = _DummyTriggerWithJitter(dt, 60) assert trigger.get_next_fire_time(None, now) == expected_dt - def test_jitter_in_past_but_initial_date_in_future(self, monkeypatch): - monkeypatch.setattr(random, 'uniform', lambda a, b: -30.) - - now = datetime(2017, 5, 25, 13, 40, 44) - dt = datetime(2017, 5, 25, 13, 40, 47) - expected_dt = dt - - trigger = _DummyTriggerWithJitter(dt, 60) - assert trigger.get_next_fire_time(None, now) == expected_dt - def test_jitter_in_future_but_initial_date_in_past(self, monkeypatch): monkeypatch.setattr(random, 'uniform', lambda a, b: 30.) @@ -69,16 +59,6 @@ trigger = _DummyTriggerWithJitter(dt, 60) assert trigger.get_next_fire_time(None, now) == expected_dt - - def test_jitter_misfire(self, monkeypatch): - monkeypatch.setattr(random, 'uniform', lambda a, b: -30.) - - now = datetime(2017, 5, 25, 13, 40, 44) - dt = datetime(2017, 5, 25, 13, 40, 40) - expected_dt = dt - - trigger = _DummyTriggerWithJitter(dt, 60) - assert trigger.get_next_fire_time(None, now) == expected_dt def test_jitter_is_now(self, monkeypatch): monkeypatch.setattr(random, 'uniform', lambda a, b: 4.) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/tests/test_util.py new/APScheduler-3.7.0/tests/test_util.py --- old/APScheduler-3.6.3/tests/test_util.py 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/tests/test_util.py 2021-01-19 15:34:44.000000000 +0100 @@ -1,20 +1,22 @@ # coding: utf-8 import platform +import sys from datetime import date, datetime, timedelta, tzinfo -from functools import partial +from functools import partial, wraps from types import ModuleType import pytest import pytz import six -import sys from apscheduler.job import Job -from apscheduler.util import ( - asint, asbool, astimezone, convert_to_datetime, datetime_to_utc_timestamp, - utc_timestamp_to_datetime, timedelta_seconds, datetime_ceil, get_callable_name, obj_to_ref, - ref_to_obj, maybe_ref, check_callable_args, datetime_repr, repr_escape) -from tests.conftest import minpython, maxpython +from apscheduler.util import (asbool, asint, astimezone, check_callable_args, + convert_to_datetime, datetime_ceil, + datetime_repr, datetime_to_utc_timestamp, + get_callable_name, maybe_ref, obj_to_ref, + ref_to_obj, repr_escape, timedelta_seconds, + utc_timestamp_to_datetime) +from tests.conftest import maxpython, minpython try: from unittest.mock import Mock @@ -351,3 +353,17 @@ exc = pytest.raises(ValueError, check_callable_args, func, [1], {}) assert str(exc.value) == ('The following keyword-only arguments have not been supplied in ' 'kwargs: y') + + def test_wrapped_func(self): + """ + Test that a wrapped function can be scheduled even if it cannot accept the arguments given + in add_job() if the wrapper can. + """ + def func(): + pass + + @wraps(func) + def wrapper(arg): + func() + + check_callable_args(wrapper, (1,), {}) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.6.3/tox.ini new/APScheduler-3.7.0/tox.ini --- old/APScheduler-3.6.3/tox.ini 2019-11-05 08:51:24.000000000 +0100 +++ new/APScheduler-3.7.0/tox.ini 2021-01-19 15:34:44.000000000 +0100 @@ -1,8 +1,9 @@ [tox] -envlist = py27, py34, py35, py36, py37, pypy, pypy3, flake8 +envlist = py27, py35, py36, py37, pypy, pypy3, flake8 skip_missing_interpreters = true [testenv] +download = true commands = pytest {posargs} extras = testing asyncio