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 2023-09-20 13:28:48 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-APScheduler (Old) and /work/SRC/openSUSE:Factory/.python-APScheduler.new.16627 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-APScheduler" Wed Sep 20 13:28:48 2023 rev:22 rq:1112069 version:3.10.4 Changes: -------- --- /work/SRC/openSUSE:Factory/python-APScheduler/python-APScheduler.changes 2023-08-17 19:44:52.622938803 +0200 +++ /work/SRC/openSUSE:Factory/.python-APScheduler.new.16627/python-APScheduler.changes 2023-09-20 13:31:19.275227464 +0200 @@ -1,0 +2,20 @@ +Mon Sep 18 19:32:28 UTC 2023 - Dirk Müller <dmuel...@suse.com> + +- update to 3.10.4: + * Fixed incorrect module name being generated for references to + class methods via a subclass where the subclass does not + override the method + * Fixed ``TypeError`` related to entry point iteration on + Python 3.9 + * Ensured consistent support for both PySide and PyQt (v6 to + v2) on QtScheduler + * Replaced uses of the deprecated ``pkg_resources`` module with + ``importlib.metadata`` + * Fixed scheduling class methods like ``B.methodname`` where + the ``B`` class inherits from class ``A`` and ``methodname`` + is a class method of class ``A`` + * Fixed scheduler sleeping for too long (and thus jobs missing + their scheduled run times) if its wakeup cycle takes too much + time + +------------------------------------------------------------------- Old: ---- APScheduler-3.10.1.tar.gz New: ---- APScheduler-3.10.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-APScheduler.spec ++++++ --- /var/tmp/diff_new_pack.FUj2NE/_old 2023-09-20 13:31:20.455269739 +0200 +++ /var/tmp/diff_new_pack.FUj2NE/_new 2023-09-20 13:31:20.459269883 +0200 @@ -18,7 +18,7 @@ %{?sle15_python_module_pythons} Name: python-APScheduler -Version: 3.10.1 +Version: 3.10.4 Release: 0 Summary: In-process task scheduler with Cron-like capabilities License: MIT ++++++ APScheduler-3.10.1.tar.gz -> APScheduler-3.10.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/.github/workflows/codeqa_test.yaml new/APScheduler-3.10.4/.github/workflows/codeqa_test.yaml --- old/APScheduler-3.10.1/.github/workflows/codeqa_test.yaml 2023-03-03 10:02:56.000000000 +0100 +++ new/APScheduler-3.10.4/.github/workflows/codeqa_test.yaml 1970-01-01 01:00:00.000000000 +0100 @@ -1,48 +0,0 @@ -name: Python codeqa/test - -on: - push: - branches: [3.x] - pull_request: - -jobs: - lint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: 3.x - - uses: actions/cache@v3 - with: - path: ~/.cache/pip - key: pip-lint - - name: Install dependencies - run: pip install tox - - name: Run flake8 - run: tox -e flake8 - - test-linux: - needs: [lint] - strategy: - fail-fast: false - matrix: - python-version: ["3.7", "3.11"] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - uses: actions/cache@v3 - with: - path: ~/.cache/pip - key: pip-test-${{ matrix.python-version }}-ubuntu-latest - - name: Start external services - run: docker-compose up -d - - name: Install the project and its dependencies - run: pip install -e .[testing,asyncio,gevent,mongodb,redis,rethinkdb,sqlalchemy,tornado,twisted,zookeeper] - - name: Test with pytest - run: pytest diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/.github/workflows/publish.yml new/APScheduler-3.10.4/.github/workflows/publish.yml --- old/APScheduler-3.10.1/.github/workflows/publish.yml 2023-03-03 10:02:56.000000000 +0100 +++ new/APScheduler-3.10.4/.github/workflows/publish.yml 2023-08-19 18:44:04.000000000 +0200 @@ -4,13 +4,14 @@ push: tags: - "[0-9]+.[0-9]+.[0-9]+" - - "[0-9]+.[0-9]+.[0-9].post[0-9]+" - - "[0-9]+.[0-9]+.[0-9][a-b][0-9]+" - - "[0-9]+.[0-9]+.[0-9]rc[0-9]+" + - "[0-9]+.[0-9]+.[0-9]+.post[0-9]+" + - "[0-9]+.[0-9]+.[0-9]+[a-b][0-9]+" + - "[0-9]+.[0-9]+.[0-9]+rc[0-9]+" jobs: - publish: + build: runs-on: ubuntu-latest + environment: release steps: - uses: actions/checkout@v3 - name: Set up Python @@ -20,8 +21,21 @@ - name: Install dependencies run: pip install build - name: Create packages - run: python -m build -s -w . + run: python -m build + - name: Archive packages + uses: actions/upload-artifact@v3 + with: + name: dist + path: dist + + publish: + needs: build + runs-on: ubuntu-latest + environment: release + permissions: + id-token: write + steps: + - name: Retrieve packages + uses: actions/download-artifact@v3 - name: Upload packages uses: pypa/gh-action-pypi-publish@release/v1 - with: - password: ${{ secrets.pypi_password }} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/.github/workflows/test.yaml new/APScheduler-3.10.4/.github/workflows/test.yaml --- old/APScheduler-3.10.1/.github/workflows/test.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/APScheduler-3.10.4/.github/workflows/test.yaml 2023-08-19 18:44:04.000000000 +0200 @@ -0,0 +1,28 @@ +name: test suite + +on: + push: + branches: [3.x] + pull_request: + +jobs: + test: + strategy: + fail-fast: false + matrix: + python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + cache: pip + cache-dependency-path: setup.py + - name: Start external services + run: docker-compose up -d + - name: Install the project and its dependencies + run: pip install -e .[testing,asyncio,gevent,mongodb,redis,rethinkdb,sqlalchemy,tornado,twisted,zookeeper] + - name: Test with pytest + run: pytest diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/.pre-commit-config.yaml new/APScheduler-3.10.4/.pre-commit-config.yaml --- old/APScheduler-3.10.1/.pre-commit-config.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/APScheduler-3.10.4/.pre-commit-config.yaml 2023-08-19 18:44:04.000000000 +0200 @@ -0,0 +1,32 @@ +# This is the configuration file for pre-commit (https://pre-commit.com/). +# To use: +# * Install pre-commit (https://pre-commit.com/#installation) +# * Copy this file as ".pre-commit-config.yaml" +# * Run "pre-commit install". +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: check-added-large-files + - id: check-case-conflict + - id: check-merge-conflict + - id: check-symlinks + - id: check-toml + - id: check-yaml + - id: debug-statements + - id: end-of-file-fixer + - id: mixed-line-ending + args: [ "--fix=lf" ] + - id: trailing-whitespace + + - repo: https://github.com/codespell-project/codespell + rev: v2.2.5 + hooks: + - id: codespell + + - repo: https://github.com/pre-commit/pygrep-hooks + rev: v1.10.0 + hooks: + - id: rst-backticks + - id: rst-directive-colons + - id: rst-inline-touching-normal diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/.readthedocs.yml new/APScheduler-3.10.4/.readthedocs.yml --- old/APScheduler-3.10.1/.readthedocs.yml 2023-03-03 10:02:56.000000000 +0100 +++ new/APScheduler-3.10.4/.readthedocs.yml 2023-08-19 18:44:04.000000000 +0200 @@ -1,14 +1,24 @@ -type: sphinx +version: 2 + +build: + os: ubuntu-22.04 + tools: + python: "3.7" + +sphinx: + configuration: docs/conf.py + python: - version: "3.5" - pip_install: true - extra_requirements: - - gevent - - mongodb - - redis - - rethinkdb - - sqlalchemy - - tornado - - twisted - - zookeeper - - doc + install: + - method: pip + path: . + extra_requirements: + - gevent + - mongodb + - redis + - rethinkdb + - sqlalchemy + - tornado + - twisted + - zookeeper + - doc diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/APScheduler.egg-info/PKG-INFO new/APScheduler-3.10.4/APScheduler.egg-info/PKG-INFO --- old/APScheduler-3.10.1/APScheduler.egg-info/PKG-INFO 2023-03-03 10:03:06.000000000 +0100 +++ new/APScheduler-3.10.4/APScheduler.egg-info/PKG-INFO 2023-08-19 18:44:14.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: APScheduler -Version: 3.10.1 +Version: 3.10.4 Summary: In-process task scheduler with Cron-like capabilities Home-page: https://github.com/agronholm/apscheduler Author: Alex Grönholm diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/APScheduler.egg-info/SOURCES.txt new/APScheduler-3.10.4/APScheduler.egg-info/SOURCES.txt --- old/APScheduler-3.10.1/APScheduler.egg-info/SOURCES.txt 2023-03-03 10:03:06.000000000 +0100 +++ new/APScheduler-3.10.4/APScheduler.egg-info/SOURCES.txt 2023-08-19 18:44:14.000000000 +0200 @@ -1,5 +1,6 @@ .gitignore .mailmap +.pre-commit-config.yaml .readthedocs.yml LICENSE.txt README.rst @@ -8,8 +9,8 @@ setup.py tox.ini .github/ISSUE_TEMPLATE.md -.github/workflows/codeqa_test.yaml .github/workflows/publish.yml +.github/workflows/test.yaml APScheduler.egg-info/PKG-INFO APScheduler.egg-info/SOURCES.txt APScheduler.egg-info/dependency_links.txt @@ -118,5 +119,4 @@ tests/test_jobstores.py tests/test_schedulers.py tests/test_triggers.py -tests/test_util.py -tests/test_util_py35.py \ No newline at end of file +tests/test_util.py \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/APScheduler.egg-info/requires.txt new/APScheduler-3.10.4/APScheduler.egg-info/requires.txt --- old/APScheduler-3.10.1/APScheduler.egg-info/requires.txt 2023-03-03 10:03:06.000000000 +0100 +++ new/APScheduler-3.10.4/APScheduler.egg-info/requires.txt 2023-08-19 18:44:14.000000000 +0200 @@ -1,8 +1,10 @@ -setuptools>=0.7 six>=1.4.0 pytz tzlocal!=3.*,>=2.0 +[:python_version < "3.8"] +importlib-metadata>=3.6.0 + [doc] sphinx sphinx-rtd-theme diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/PKG-INFO new/APScheduler-3.10.4/PKG-INFO --- old/APScheduler-3.10.1/PKG-INFO 2023-03-03 10:03:06.213973800 +0100 +++ new/APScheduler-3.10.4/PKG-INFO 2023-08-19 18:44:14.539897200 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: APScheduler -Version: 3.10.1 +Version: 3.10.4 Summary: In-process task scheduler with Cron-like capabilities Home-page: https://github.com/agronholm/apscheduler Author: Alex Grönholm diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/apscheduler/__init__.py new/APScheduler-3.10.4/apscheduler/__init__.py --- old/APScheduler-3.10.1/apscheduler/__init__.py 2023-03-03 10:02:56.000000000 +0100 +++ new/APScheduler-3.10.4/apscheduler/__init__.py 2023-08-19 18:44:04.000000000 +0200 @@ -1,10 +1,15 @@ -from pkg_resources import get_distribution, DistributionNotFound +import sys +if sys.version_info >= (3, 8): + import importlib.metadata as importlib_metadata +else: + import importlib_metadata + try: - release = get_distribution('APScheduler').version.split('-')[0] -except DistributionNotFound: + release = importlib_metadata.version('APScheduler').split('-')[0] +except importlib_metadata.PackageNotFoundError: release = '3.5.0' version_info = tuple(int(x) if x.isdigit() else x for x in release.split('.')) version = __version__ = '.'.join(str(x) for x in version_info[:3]) -del get_distribution, DistributionNotFound +del sys, importlib_metadata diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/apscheduler/schedulers/base.py new/APScheduler-3.10.4/apscheduler/schedulers/base.py --- old/APScheduler-3.10.1/apscheduler/schedulers/base.py 2023-03-03 10:02:56.000000000 +0100 +++ new/APScheduler-3.10.4/apscheduler/schedulers/base.py 2023-08-19 18:44:04.000000000 +0200 @@ -7,7 +7,6 @@ import warnings import sys -from pkg_resources import iter_entry_points from tzlocal import get_localzone import six @@ -31,6 +30,11 @@ except ImportError: from collections import MutableMapping +try: + from importlib.metadata import entry_points +except ModuleNotFoundError: + from importlib_metadata import entry_points + #: constant indicating a scheduler's stopped state STATE_STOPPED = 0 #: constant indicating a scheduler's running state (started and processing jobs) @@ -62,12 +66,18 @@ .. seealso:: :ref:`scheduler-config` """ + # The `group=...` API is only available in the backport, used in <=3.7, and in std>=3.10. + if (3, 8) <= sys.version_info < (3, 10): + _trigger_plugins = {ep.name: ep for ep in entry_points()['apscheduler.triggers']} + _executor_plugins = {ep.name: ep for ep in entry_points()['apscheduler.executors']} + _jobstore_plugins = {ep.name: ep for ep in entry_points()['apscheduler.jobstores']} + else: + _trigger_plugins = {ep.name: ep for ep in entry_points(group='apscheduler.triggers')} + _executor_plugins = {ep.name: ep for ep in entry_points(group='apscheduler.executors')} + _jobstore_plugins = {ep.name: ep for ep in entry_points(group='apscheduler.jobstores')} - _trigger_plugins = dict((ep.name, ep) for ep in iter_entry_points('apscheduler.triggers')) _trigger_classes = {} - _executor_plugins = dict((ep.name, ep) for ep in iter_entry_points('apscheduler.executors')) _executor_classes = {} - _jobstore_plugins = dict((ep.name, ep) for ep in iter_entry_points('apscheduler.jobstores')) _jobstore_classes = {} # @@ -1019,6 +1029,7 @@ wait_seconds = None self._logger.debug('No jobs; waiting until a job is added') else: + now = datetime.now(self.timezone) wait_seconds = min(max(timedelta_seconds(next_wakeup_time - now), 0), TIMEOUT_MAX) self._logger.debug('Next wakeup is due at %s (in %f seconds)', next_wakeup_time, wait_seconds) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/apscheduler/schedulers/qt.py new/APScheduler-3.10.4/apscheduler/schedulers/qt.py --- old/APScheduler-3.10.1/apscheduler/schedulers/qt.py 2023-03-03 10:02:56.000000000 +0100 +++ new/APScheduler-3.10.4/apscheduler/schedulers/qt.py 2023-08-19 18:44:04.000000000 +0200 @@ -1,24 +1,22 @@ from __future__ import absolute_import +from importlib import import_module +from itertools import product + from apscheduler.schedulers.base import BaseScheduler -try: - from PyQt5.QtCore import QObject, QTimer -except (ImportError, RuntimeError): # pragma: nocover +for version, pkgname in product(range(6, 1, -1), ("PySide", "PyQt")): try: - from PyQt4.QtCore import QObject, QTimer + qtcore = import_module(pkgname + str(version) + ".QtCore") except ImportError: - try: - from PySide6.QtCore import QObject, QTimer # noqa - except ImportError: - try: - from PySide2.QtCore import QObject, QTimer # noqa - except ImportError: - try: - from PySide.QtCore import QObject, QTimer # noqa - except ImportError: - raise ImportError('QtScheduler requires either PyQt5, PyQt4, PySide6, PySide2 ' - 'or PySide installed') + pass + else: + QTimer = qtcore.QTimer + break +else: + raise ImportError( + "QtScheduler requires either PySide/PyQt (v6 to v2) installed" + ) class QtScheduler(BaseScheduler): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/apscheduler/util.py new/APScheduler-3.10.4/apscheduler/util.py --- old/APScheduler-3.10.1/apscheduler/util.py 2023-03-03 10:02:56.000000000 +0100 +++ new/APScheduler-3.10.4/apscheduler/util.py 2023-08-19 18:44:04.000000000 +0200 @@ -6,7 +6,7 @@ from datetime import date, datetime, time, timedelta, tzinfo from calendar import timegm from functools import partial -from inspect import isclass, ismethod +from inspect import isbuiltin, isclass, isfunction, ismethod import re import sys @@ -214,28 +214,15 @@ :rtype: str """ - # the easy case (on Python 3.3+) - if hasattr(func, '__qualname__'): + if ismethod(func): + self = func.__self__ + cls = self if isclass(self) else type(self) + return f"{cls.__qualname__}.{func.__name__}" + elif isclass(func) or isfunction(func) or isbuiltin(func): return func.__qualname__ - - # class methods, bound and unbound methods - f_self = getattr(func, '__self__', None) or getattr(func, 'im_self', None) - if f_self and hasattr(func, '__name__'): - f_class = f_self if isclass(f_self) else f_self.__class__ - else: - f_class = getattr(func, 'im_class', None) - - if f_class and hasattr(func, '__name__'): - return '%s.%s' % (f_class.__name__, func.__name__) - - # class or class instance - if hasattr(func, '__call__'): - # class - if hasattr(func, '__name__'): - return func.__name__ - + elif hasattr(func, '__call__') and callable(func.__call__): # instance of a class with a __call__ method - return func.__class__.__name__ + return type(func).__qualname__ raise TypeError('Unable to determine a name for %r -- maybe it is not a callable?' % func) @@ -260,16 +247,10 @@ raise ValueError('Cannot create a reference to a nested function') if ismethod(obj): - if hasattr(obj, 'im_self') and obj.im_self: - # bound method - module = obj.im_self.__module__ - elif hasattr(obj, 'im_class') and obj.im_class: - # unbound method - module = obj.im_class.__module__ - else: - module = obj.__module__ + module = obj.__self__.__module__ else: module = obj.__module__ + return '%s:%s' % (module, name) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/docs/modules/executors/base.rst new/APScheduler-3.10.4/docs/modules/executors/base.rst --- old/APScheduler-3.10.1/docs/modules/executors/base.rst 2023-03-03 10:02:56.000000000 +0100 +++ new/APScheduler-3.10.4/docs/modules/executors/base.rst 2023-08-19 18:44:04.000000000 +0200 @@ -8,4 +8,3 @@ .. autoclass:: BaseExecutor :members: - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/docs/modules/schedulers/asyncio.rst new/APScheduler-3.10.4/docs/modules/schedulers/asyncio.rst --- old/APScheduler-3.10.1/docs/modules/schedulers/asyncio.rst 2023-03-03 10:02:56.000000000 +0100 +++ new/APScheduler-3.10.4/docs/modules/schedulers/asyncio.rst 2023-08-19 18:44:04.000000000 +0200 @@ -24,9 +24,7 @@ * - Default executor - :class:`~apscheduler.executors.asyncio.AsyncIOExecutor` * - External dependencies - - * Python >= 3.4: none - * Python 3.3: `asyncio <https://pypi.python.org/pypi/asyncio/>`_ - * Python <= 3.2: `trollius <https://pypi.python.org/pypi/trollius/>`_ + - none * - Example - ``examples/schedulers/asyncio_.py`` (`view online <https://github.com/agronholm/apscheduler/tree/3.x/examples/schedulers/asyncio_.py>`_). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/docs/modules/schedulers/qt.rst new/APScheduler-3.10.4/docs/modules/schedulers/qt.rst --- old/APScheduler-3.10.1/docs/modules/schedulers/qt.rst 2023-03-03 10:02:56.000000000 +0100 +++ new/APScheduler-3.10.4/docs/modules/schedulers/qt.rst 2023-08-19 18:44:04.000000000 +0200 @@ -13,7 +13,7 @@ Introduction ------------ -QtScheduler lets you integrate APScheduler with your `PySide2 <https://wiki.qt.io/Qt_for_Python>`, `PySide <https://en.wikipedia.org/wiki/PySide>` or +QtScheduler lets you integrate APScheduler with your `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.10.1/docs/modules/triggers/cron.rst new/APScheduler-3.10.4/docs/modules/triggers/cron.rst --- old/APScheduler-3.10.1/docs/modules/triggers/cron.rst 2023-03-03 10:02:56.000000000 +0100 +++ new/APScheduler-3.10.4/docs/modules/triggers/cron.rst 2023-08-19 18:44:04.000000000 +0200 @@ -66,8 +66,8 @@ forward, depending on the time zone. Likewise, when switching back to standard time, clocks are moved one hour or half an hour backward. This will cause some time periods to either not exist at all, or be repeated. If your schedule would have the job executed on either one of these periods, it may execute more often or less often than expected. -This is not a bug. If you wish to avoid this, either use a timezone that does not observe DST, for instance UTC. -Alternatively, just find out about the DST switch times and avoid them in your scheduling. +This is not a bug. If you wish to avoid this, either use a timezone that does not observe DST, e.g. UTC, or find out +about the DST-switch times and avoid using them in your scheduling. For example, the following schedule may be problematic:: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/docs/modules/triggers/interval.rst new/APScheduler-3.10.4/docs/modules/triggers/interval.rst --- old/APScheduler-3.10.1/docs/modules/triggers/interval.rst 2023-03-03 10:02:56.000000000 +0100 +++ new/APScheduler-3.10.4/docs/modules/triggers/interval.rst 2023-08-19 18:44:04.000000000 +0200 @@ -54,7 +54,7 @@ The :meth:`~apscheduler.schedulers.base.BaseScheduler.scheduled_job` decorator works nicely too:: - + @sched.scheduled_job('interval', id='my_job_id', hours=2) def job_function(): print("Hello World") @@ -64,5 +64,5 @@ multiple servers and don't want them to run a job at the exact same moment or if you want to prevent multiple jobs with similar options from always running concurrently:: - # Run the `job_function` every hour with an extra-delay picked randomly in a [-120,+120] seconds window. + # Run the `job_function` every hour with an extra delay picked randomly between 0 and 120 seconds. sched.add_job(job_function, 'interval', hours=1, jitter=120) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/docs/userguide.rst new/APScheduler-3.10.4/docs/userguide.rst --- old/APScheduler-3.10.1/docs/userguide.rst 2023-03-03 10:02:56.000000000 +0100 +++ new/APScheduler-3.10.4/docs/userguide.rst 2023-08-19 18:44:04.000000000 +0200 @@ -420,7 +420,7 @@ scheduler) to see if the execution should still be triggered. This can lead into the job being executed several times in succession. -If this behavior is undesirable for your particular use case, it is possible to use `coalescing` to +If this behavior is undesirable for your particular use case, it is possible to use ``coalescing`` to roll all these missed executions into one. In other words, if coalescing is enabled for the job and the scheduler sees one or more queued executions for the job, it will only trigger it once. No misfire events will be sent for the "bypassed" runs. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/docs/versionhistory.rst new/APScheduler-3.10.4/docs/versionhistory.rst --- old/APScheduler-3.10.1/docs/versionhistory.rst 2023-03-03 10:02:56.000000000 +0100 +++ new/APScheduler-3.10.4/docs/versionhistory.rst 2023-08-19 18:44:04.000000000 +0200 @@ -4,6 +4,32 @@ To find out how to migrate your application from a previous version of APScheduler, see the :doc:`migration section <migration>`. +3.10.4 +------ + +- Fixed incorrect module name being generated for references to class methods via a + subclass where the subclass does not override the method + + +3.10.3 +------ + +- Fixed ``TypeError`` related to entry point iteration on Python 3.9 + (PR by CrypticDriver) + + +3.10.2 +------ + +* Ensured consistent support for both PySide and PyQt (v6 to v2) on QtScheduler +* Replaced uses of the deprecated ``pkg_resources`` module with ``importlib.metadata`` + (PR by Ran Benita) +* Fixed scheduling class methods like ``B.methodname`` where the ``B`` class inherits + from class ``A`` and ``methodname`` is a class method of class ``A`` +* Fixed scheduler sleeping for too long (and thus jobs missing their scheduled run + times) if its wakeup cycle takes too much time (fix by kbasten) + + 3.10.1 ------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/examples/schedulers/asyncio_.py new/APScheduler-3.10.4/examples/schedulers/asyncio_.py --- old/APScheduler-3.10.1/examples/schedulers/asyncio_.py 2023-03-03 10:02:56.000000000 +0100 +++ new/APScheduler-3.10.4/examples/schedulers/asyncio_.py 2023-08-19 18:44:04.000000000 +0200 @@ -4,28 +4,28 @@ """ from datetime import datetime +import asyncio import os from apscheduler.schedulers.asyncio import AsyncIOScheduler -try: - import asyncio -except ImportError: - import trollius as asyncio - def tick(): print('Tick! The time is: %s' % datetime.now()) -if __name__ == '__main__': +async def main(): scheduler = AsyncIOScheduler() scheduler.add_job(tick, 'interval', seconds=3) scheduler.start() print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C')) + while True: + await asyncio.sleep(1000) + +if __name__ == '__main__': # Execution will block here until Ctrl+C (Ctrl+Break on Windows) is pressed. try: - asyncio.get_event_loop().run_forever() + asyncio.run(main()) except (KeyboardInterrupt, SystemExit): pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/examples/schedulers/qt.py new/APScheduler-3.10.4/examples/schedulers/qt.py --- old/APScheduler-3.10.1/examples/schedulers/qt.py 2023-03-03 10:02:56.000000000 +0100 +++ new/APScheduler-3.10.4/examples/schedulers/qt.py 2023-08-19 18:44:04.000000000 +0200 @@ -6,22 +6,24 @@ from datetime import datetime import signal import sys +from importlib import import_module +from itertools import product from apscheduler.schedulers.qt import QtScheduler -try: - from PyQt5.QtWidgets import QApplication, QLabel -except ImportError: +for version, pkgname in product(range(6, 1, -1), ("PySide", "PyQt")): try: - from PyQt4.QtGui import QApplication, QLabel + qtwidgets = import_module(pkgname + str(version) + ".QtWidgets") except ImportError: - try: - from PySide6.QtWidgets import QApplication, QLabel - except ImportError: - try: - from PySide2.QtWidgets import QApplication, QLabel - except ImportError: - from PySide.QtGui import QApplication, QLabel + pass + else: + QApplication = qtwidgets.QApplication + QLabel = qtwidgets.QLabel + break +else: + raise ImportError( + "Could not import the QtWidgets module from either PySide or PyQt" + ) def tick(): @@ -44,4 +46,4 @@ scheduler.start() # Execution will block here until the user closes the windows or Ctrl+C is pressed. - app.exec_() + app.exec() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/setup.py new/APScheduler-3.10.4/setup.py --- old/APScheduler-3.10.1/setup.py 2023-03-03 10:02:56.000000000 +0100 +++ new/APScheduler-3.10.4/setup.py 2023-08-19 18:44:04.000000000 +0200 @@ -39,10 +39,10 @@ 'setuptools_scm' ], install_requires=[ - 'setuptools >= 0.7', 'six >= 1.4.0', 'pytz', - 'tzlocal >= 2.0, != 3.*' + 'tzlocal >= 2.0, != 3.*', + 'importlib-metadata >= 3.6.0; python_version < "3.8"', ], extras_require={ 'gevent': ['gevent'], diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/tests/conftest.py new/APScheduler-3.10.4/tests/conftest.py --- old/APScheduler-3.10.1/tests/conftest.py 2023-03-03 10:02:56.000000000 +0100 +++ new/APScheduler-3.10.4/tests/conftest.py 2023-08-19 18:44:04.000000000 +0200 @@ -1,43 +1,13 @@ -# coding: utf-8 from datetime import datetime -import sys import pytest import pytz +from unittest.mock import Mock from apscheduler.job import Job from apscheduler.schedulers.base import BaseScheduler from apscheduler.schedulers.blocking import BlockingScheduler -try: - from unittest.mock import Mock -except ImportError: - from mock import Mock - - -def pytest_ignore_collect(path, config): - return path.basename.endswith('_py35.py') and sys.version_info < (3, 5) - - -def minpython(*version): - version_str = '.'.join([str(num) for num in version]) - - def outer(func): - dec = pytest.mark.skipif(sys.version_info < version, - reason='Requires Python >= %s' % version_str) - return dec(func) - return outer - - -def maxpython(*version): - version_str = '.'.join([str(num) for num in version]) - - def outer(func): - dec = pytest.mark.skipif(sys.version_info >= version, - reason='Requires Python < %s' % version_str) - return dec(func) - return outer - @pytest.fixture def timezone(monkeypatch): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/tests/test_executors.py new/APScheduler-3.10.4/tests/test_executors.py --- old/APScheduler-3.10.1/tests/test_executors.py 2023-03-03 10:02:56.000000000 +0100 +++ new/APScheduler-3.10.4/tests/test_executors.py 2023-08-19 18:44:04.000000000 +0200 @@ -15,7 +15,6 @@ 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 @@ -151,7 +150,6 @@ assert len(foos) == 0 -@minpython(3, 3) def test_broken_pool(): def listener(evt): pid[0] = evt.retval diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/tests/test_util.py new/APScheduler-3.10.4/tests/test_util.py --- old/APScheduler-3.10.1/tests/test_util.py 2023-03-03 10:02:56.000000000 +0100 +++ new/APScheduler-3.10.4/tests/test_util.py 2023-08-19 18:44:04.000000000 +0200 @@ -1,27 +1,22 @@ -# coding: utf-8 +import os import platform import sys from datetime import date, datetime, timedelta, tzinfo from functools import partial, wraps from types import ModuleType +from unittest.mock import Mock import pytest import pytz -import six -from apscheduler.job import Job -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 -except ImportError: - from mock import Mock +from apscheduler.util import ( + asbool, asint, astimezone, check_callable_args, + convert_to_datetime, datetime_ceil, + datetime_repr, datetime_to_utc_timestamp, + get_callable_name, iscoroutinefunction_partial, maybe_ref, obj_to_ref, + ref_to_obj, timedelta_seconds, + utc_timestamp_to_datetime, +) class DummyClass(object): @@ -45,7 +40,7 @@ pass -class InheritedDummyClass(Job): +class InheritedDummyClass(DummyClass): pass @@ -182,15 +177,18 @@ class TestGetCallableName(object): @pytest.mark.parametrize('input,expected', [ (asint, 'asint'), - (DummyClass.staticmeth, 'DummyClass.staticmeth' if - hasattr(DummyClass, '__qualname__') else 'staticmeth'), + (os.getpid, "getpid"), + (DummyClass.staticmeth, 'DummyClass.staticmeth'), (DummyClass.classmeth, 'DummyClass.classmeth'), - (DummyClass.meth, 'meth' if sys.version_info[:2] == (3, 2) else 'DummyClass.meth'), + (DummyClass.meth, 'DummyClass.meth'), (DummyClass().meth, 'DummyClass.meth'), (DummyClass, 'DummyClass'), - (DummyClass(), 'DummyClass') - ], ids=['function', 'static method', 'class method', 'unbounded method', 'bounded method', - 'class', 'instance']) + (DummyClass(), 'DummyClass'), + (InheritedDummyClass.classmeth, 'InheritedDummyClass.classmeth'), + (DummyClass.InnerDummyClass.innerclassmeth, 'DummyClass.InnerDummyClass.innerclassmeth'), + ], ids=['function', 'builtin', 'static method', 'class method', 'unbounded method', + 'bounded method', 'class', 'instance', 'class method in inherited', + 'inner class method']) def test_inputs(self, input, expected): assert get_callable_name(input) == expected @@ -199,6 +197,11 @@ class TestObjToRef(object): + class InnerInheritedDummy(DummyClass): + pass + + InnerInheritedDummy.__module__ = "foo" + @pytest.mark.parametrize('obj, error', [ (partial(DummyClass.meth), 'Cannot create a reference to a partial()'), (lambda: None, 'Cannot create a reference to a lambda') @@ -237,6 +240,11 @@ def test_valid_refs(self, input, expected): assert obj_to_ref(input) == expected + def test_inherited_classmethod(self): + assert obj_to_ref(TestObjToRef.InnerInheritedDummy.classmeth) == ( + "foo:TestObjToRef.InnerInheritedDummy.classmeth" + ) + class TestRefToObj(object): def test_valid_ref(self): @@ -269,15 +277,6 @@ assert maybe_ref(input) == expected -@pytest.mark.parametrize('input,expected', [ - (b'T\xc3\xa9st'.decode('utf-8'), 'T\\xe9st' if six.PY2 else 'Tést'), - (1, 1) -], ids=['string', 'int']) -@maxpython(3) -def test_repr_escape_py2(input, expected): - assert repr_escape(input) == expected - - class TestCheckCallableArgs(object): def test_invalid_callable_args(self): """ @@ -323,7 +322,6 @@ """Tests that a function where signature() fails is accepted.""" check_callable_args(object().__setattr__, ('blah', 1), {}) - @minpython(3, 4) @pytest.mark.skipif(platform.python_implementation() == 'PyPy', reason='PyPy does not expose signatures of builtins') def test_positional_only_args(self): @@ -337,7 +335,6 @@ assert str(exc.value) == ('The following arguments cannot be given as keyword arguments: ' 'value') - @minpython(3) def test_unfulfilled_kwargs(self): """ Tests that attempting to schedule a job where not all keyword-only arguments are fulfilled @@ -362,3 +359,22 @@ func() check_callable_args(wrapper, (1,), {}) + + +class TestIsCoroutineFunctionPartial: + @staticmethod + def not_a_coro(x): + pass + + @staticmethod + async def a_coro(x): + pass + + def test_non_coro(self): + assert not iscoroutinefunction_partial(self.not_a_coro) + + def test_coro(self): + assert iscoroutinefunction_partial(self.a_coro) + + def test_coro_partial(self): + assert iscoroutinefunction_partial(partial(self.a_coro, 1)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/APScheduler-3.10.1/tests/test_util_py35.py new/APScheduler-3.10.4/tests/test_util_py35.py --- old/APScheduler-3.10.1/tests/test_util_py35.py 2023-03-03 10:02:56.000000000 +0100 +++ new/APScheduler-3.10.4/tests/test_util_py35.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,22 +0,0 @@ -from functools import partial - -from apscheduler.util import iscoroutinefunction_partial - - -class TestIsCoroutineFunctionPartial: - @staticmethod - def not_a_coro(x): - pass - - @staticmethod - async def a_coro(x): - pass - - def test_non_coro(self): - assert not iscoroutinefunction_partial(self.not_a_coro) - - def test_coro(self): - assert iscoroutinefunction_partial(self.a_coro) - - def test_coro_partial(self): - assert iscoroutinefunction_partial(partial(self.a_coro, 1))