commit python-pytest-qt for openSUSE:Factory
Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-pytest-qt for openSUSE:Factory checked in at 2022-11-30 15:00:28 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-pytest-qt (Old) and /work/SRC/openSUSE:Factory/.python-pytest-qt.new.1597 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "python-pytest-qt" Wed Nov 30 15:00:28 2022 rev:10 rq:1039106 version:4.2.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-pytest-qt/python-pytest-qt.changes 2022-07-05 12:10:24.388636554 +0200 +++ /work/SRC/openSUSE:Factory/.python-pytest-qt.new.1597/python-pytest-qt.changes 2022-11-30 15:01:21.669842828 +0100 @@ -1,0 +2,20 @@ +Wed Nov 30 12:26:35 UTC 2022 - Daniel Garcia <daniel.garcia@suse.com> + +- Remove python_module macro definition +- Update to 4.2.0: + * Import the code sub-package from the correct location rather than the + deprecated py package, restoring compatibility with pytest 7.2.0, where py + was dropped. Thanks @The-Compiler for the PR. + * Use pytest.hookimpl to configure hooks, avoiding a deprecation warning in + pytest 7.2.0. Thanks @The-Compiler for the PR. + * Now pytest-qt will check if any of the Qt libraries is already imported by + the time the plugin loads, and use it if that is the case (#412). Thanks + @eyllanesc for the PR. + * Most custom pytest-qt exceptions can be accessed via qtbot (for example + qtbot.TimeoutError), but it was not always explicit in the documentation + that this is the recommended way to access those exceptions, instead of + importing them from pytestqt.exceptions. This is now clarified in the + documentation and examples, and an alias to ScreenshotError has been added + to qtbot so it can be accessed in the same way (#460). + +------------------------------------------------------------------- Old: ---- pytest-qt-4.1.0.tar.gz New: ---- pytest-qt-4.2.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-pytest-qt.spec ++++++ --- /var/tmp/diff_new_pack.03lJer/_old 2022-11-30 15:01:22.117845457 +0100 +++ /var/tmp/diff_new_pack.03lJer/_new 2022-11-30 15:01:22.125845504 +0100 @@ -16,7 +16,6 @@ # -%{?!python_module:%define python_module() python3-%{**}} %define skip_python2 1 %global flavor @BUILD_FLAVOR@%{nil} %if "%{flavor}" == "" @@ -65,7 +64,7 @@ %endif Name: python-pytest-qt%{psuffix} -Version: 4.1.0 +Version: 4.2.0 Release: 0 Summary: Pytest support for PyQt and PySide applications License: MIT ++++++ pytest-qt-4.1.0.tar.gz -> pytest-qt-4.2.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-qt-4.1.0/.pre-commit-config.yaml new/pytest-qt-4.2.0/.pre-commit-config.yaml --- old/pytest-qt-4.1.0/.pre-commit-config.yaml 2022-06-23 16:39:11.000000000 +0200 +++ new/pytest-qt-4.2.0/.pre-commit-config.yaml 2022-10-25 17:01:03.000000000 +0200 @@ -1,6 +1,25 @@ repos: +- repo: https://github.com/PyCQA/autoflake + rev: v1.7.6 + hooks: + - id: autoflake + name: autoflake + args: ["--in-place", "--remove-unused-variables", "--remove-all-unused-imports"] + language: python + files: \.py$ +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.3.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: debug-statements +- repo: https://github.com/asottile/pyupgrade + rev: v3.1.0 + hooks: + - id: pyupgrade - repo: https://github.com/psf/black - rev: 22.3.0 + rev: 22.10.0 hooks: - id: black args: [--safe, --quiet] @@ -11,19 +30,8 @@ - id: blacken-docs additional_dependencies: [black==20.8b1] language_version: python3 -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.2.0 - hooks: - - id: trailing-whitespace - - id: end-of-file-fixer - - id: check-yaml - - id: debug-statements -- repo: https://github.com/asottile/pyupgrade - rev: v2.32.1 - hooks: - - id: pyupgrade - repo: https://github.com/PyCQA/flake8 - rev: 4.0.1 + rev: 5.0.4 hooks: - id: flake8 - repo: https://github.com/pre-commit/pygrep-hooks diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-qt-4.1.0/CHANGELOG.rst new/pytest-qt-4.2.0/CHANGELOG.rst --- old/pytest-qt-4.1.0/CHANGELOG.rst 2022-06-23 16:39:11.000000000 +0200 +++ new/pytest-qt-4.2.0/CHANGELOG.rst 2022-10-25 17:01:03.000000000 +0200 @@ -1,5 +1,25 @@ -UNRELEASED ----------- +4.2.0 (2022-10-25) +------------------ + +- Import the ``code`` sub-package from the correct location rather than the + deprecated ``py`` package, restoring compatibility with pytest 7.2.0, where + ``py`` was dropped. Thanks `@The-Compiler`_ for the PR. + +- Use ``pytest.hookimpl`` to configure hooks, avoiding a deprecation warning in + pytest 7.2.0. Thanks `@The-Compiler`_ for the PR. + +- Now ``pytest-qt`` will check if any of the Qt libraries is already imported by the time the plugin loads, + and use it if that is the case (`#412`_). Thanks `@eyllanesc`_ for the PR. + +- Most custom ``pytest-qt`` exceptions can be accessed via ``qtbot`` (for example ``qtbot.TimeoutError``), + but it was not always explicit in the documentation that this is the recommended way to access those exceptions, instead + of importing them from ``pytestqt.exceptions``. + This is now clarified in the documentation and examples, and an alias to ``ScreenshotError`` has been + added to ``qtbot`` so it can be accessed in the same way (`#460`_). + +.. _#412: https://github.com/pytest-dev/pytest-qt/pull/412 +.. _#460: https://github.com/pytest-dev/pytest-qt/pull/460 +.. _@eyllanesc: https://github.com/eyllanesc 4.1.0 (2022-06-23) ------------------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-qt-4.1.0/PKG-INFO new/pytest-qt-4.2.0/PKG-INFO --- old/pytest-qt-4.1.0/PKG-INFO 2022-06-23 16:39:27.000000000 +0200 +++ new/pytest-qt-4.2.0/PKG-INFO 2022-10-25 17:01:14.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: pytest-qt -Version: 4.1.0 +Version: 4.2.0 Summary: pytest support for PyQt and PySide applications Home-page: http://github.com/pytest-dev/pytest-qt Author: Bruno Oliveira @@ -104,9 +104,11 @@ Since version 4.1.0, ``pytest-qt`` requires Python 3.7+. -Works with either PySide6_, PySide2_, PyQt6_ or PyQt5_, picking whichever -is available on the system, giving preference to the first one installed in -this order: +Works with either PySide6_, PySide2_, PyQt6_ or PyQt5_. + +If any of the above libraries is already imported by the time the tests execute, that library will be used. + +If not, pytest-qt will try to import and use the Qt APIs, in this order: - ``PySide6`` - ``PySide2`` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-qt-4.1.0/README.rst new/pytest-qt-4.2.0/README.rst --- old/pytest-qt-4.1.0/README.rst 2022-06-23 16:39:11.000000000 +0200 +++ new/pytest-qt-4.2.0/README.rst 2022-10-25 17:01:03.000000000 +0200 @@ -76,9 +76,11 @@ Since version 4.1.0, ``pytest-qt`` requires Python 3.7+. -Works with either PySide6_, PySide2_, PyQt6_ or PyQt5_, picking whichever -is available on the system, giving preference to the first one installed in -this order: +Works with either PySide6_, PySide2_, PyQt6_ or PyQt5_. + +If any of the above libraries is already imported by the time the tests execute, that library will be used. + +If not, pytest-qt will try to import and use the Qt APIs, in this order: - ``PySide6`` - ``PySide2`` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-qt-4.1.0/docs/conf.py new/pytest-qt-4.2.0/docs/conf.py --- old/pytest-qt-4.1.0/docs/conf.py 2022-06-23 16:39:11.000000000 +0200 +++ new/pytest-qt-4.2.0/docs/conf.py 2022-10-25 17:01:03.000000000 +0200 @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # # pytest-qt documentation build configuration file, created by # sphinx-quickstart on Mon Mar 04 22:54:36 2013. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-qt-4.1.0/docs/reference.rst new/pytest-qt-4.2.0/docs/reference.rst --- old/pytest-qt-4.1.0/docs/reference.rst 2022-06-23 16:39:11.000000000 +0200 +++ new/pytest-qt-4.2.0/docs/reference.rst 2022-10-25 17:01:03.000000000 +0200 @@ -12,6 +12,24 @@ .. autoclass:: TimeoutError +ScreenshotError +------------------ + +.. autoclass:: ScreenshotError + + +SignalEmittedError +------------------ + +.. autoclass:: SignalEmittedError + + +CallbackCalledTwiceError +------------------------ + +.. autoclass:: CallbackCalledTwiceError + + SignalBlocker ------------- @@ -23,10 +41,6 @@ .. autoclass:: MultiSignalBlocker -SignalEmittedError ------------------- - -.. autoclass:: SignalEmittedError Record ------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-qt-4.1.0/docs/signals.rst new/pytest-qt-4.2.0/docs/signals.rst --- old/pytest-qt-4.1.0/docs/signals.rst 2022-06-23 16:39:11.000000000 +0200 +++ new/pytest-qt-4.2.0/docs/signals.rst 2022-10-25 17:01:03.000000000 +0200 @@ -21,7 +21,7 @@ app.worker.start() # Test will block at this point until either the "finished" or the # "failed" signal is emitted. If 10 seconds passed without a signal, - # TimeoutError will be raised. + # qtbot.TimeoutError will be raised. assert_application_results(app) @@ -34,7 +34,7 @@ .. versionchanged:: 2.0 You can pass ``raising=False`` to avoid raising a -:class:`qtbot.TimeoutError <TimeoutError>` if the timeout is +:class:`qtbot.TimeoutError <pytestqt.exceptions.TimeoutError>` if the timeout is reached before the signal is triggered: .. code-block:: python diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-qt-4.1.0/docs/troubleshooting.rst new/pytest-qt-4.2.0/docs/troubleshooting.rst --- old/pytest-qt-4.1.0/docs/troubleshooting.rst 2022-06-23 16:39:11.000000000 +0200 +++ new/pytest-qt-4.2.0/docs/troubleshooting.rst 2022-10-25 17:01:03.000000000 +0200 @@ -62,7 +62,7 @@ .. _issue #206: https://github.com/pytest-dev/pytest-qt/issues/206 GitHub Actions ----------------- +-------------- When using ``ubuntu-latest`` on Github Actions, the package ``libxkbcommon-x11-0`` has to be installed, ``DISPLAY`` should be set and ``xvfb`` run. More details can be found in `issue #293`_. @@ -70,7 +70,7 @@ Since Qt in version 5.15 ``xcb`` libraries are not distributed with Qt so this library in version at least 1.11 on runner. See more in https://codereview.qt-project.org/c/qt/qtbase/+/253905 -For Github Actions, Azure pipelines and Travis-CI you will need to install ``libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0`` +For Github Actions, Azure pipelines and Travis-CI you will need to install ``libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0 x11-utils`` As an example, here is a working config : @@ -84,21 +84,25 @@ strategy: matrix: os : [ubuntu-latest] - python: [3.7] + python: ["3.10"] env: DISPLAY: ':99.0' steps: - name: get repo - uses: actions/checkout@v1 + uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v1 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} - name: setup ${{ matrix.os }} run: | - sudo apt install libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0 + sudo apt install libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0 x11-utils /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -screen 0 1920x1200x24 -ac +extension GLX +``tlambert03/setup-qt-libs`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Instead manually curate list of used packages you may use ``tlambert03/setup-qt-libs`` github action: https://github.com/tlambert03/setup-qt-libs + pytest-xvfb ~~~~~~~~~~~ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-qt-4.1.0/docs/wait_callback.rst new/pytest-qt-4.2.0/docs/wait_callback.rst --- old/pytest-qt-4.1.0/docs/wait_callback.rst 2022-06-23 16:39:11.000000000 +0200 +++ new/pytest-qt-4.2.0/docs/wait_callback.rst 2022-10-25 17:01:03.000000000 +0200 @@ -25,8 +25,8 @@ Anything following the ``with`` block will be run only after the callback has been called. If the callback doesn't get called during the given timeout, -:class:`qtbot.TimeoutError <TimeoutError>` is raised. If it is called more than once, -:class:`qtbot.CallbackCalledTwiceError <CallbackCalledTwiceError>` is raised. +:class:`qtbot.TimeoutError <pytestqt.exceptions.TimeoutError>` is raised. If it is called more than once, +:class:`qtbot.CallbackCalledTwiceError <pytestqt.wait_signal.CallbackCalledTwiceError>` is raised. raising parameter ----------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-qt-4.1.0/docs/wait_until.rst new/pytest-qt-4.2.0/docs/wait_until.rst --- old/pytest-qt-4.1.0/docs/wait_until.rst 2022-06-23 16:39:11.000000000 +0200 +++ new/pytest-qt-4.2.0/docs/wait_until.rst 2022-10-25 17:01:03.000000000 +0200 @@ -46,7 +46,7 @@ ``qtbot.waitUntil`` will periodically call ``check_label`` until it no longer raises ``AssertionError`` or a timeout is reached. If a timeout is reached, a -:class:`qtbot.TimeoutError <TimeoutError>` +:class:`qtbot.TimeoutError <pytestqt.exceptions.TimeoutError>` is raised from the last assertion error and the test will fail: :: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-qt-4.1.0/src/pytest_qt.egg-info/PKG-INFO new/pytest-qt-4.2.0/src/pytest_qt.egg-info/PKG-INFO --- old/pytest-qt-4.1.0/src/pytest_qt.egg-info/PKG-INFO 2022-06-23 16:39:26.000000000 +0200 +++ new/pytest-qt-4.2.0/src/pytest_qt.egg-info/PKG-INFO 2022-10-25 17:01:14.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: pytest-qt -Version: 4.1.0 +Version: 4.2.0 Summary: pytest support for PyQt and PySide applications Home-page: http://github.com/pytest-dev/pytest-qt Author: Bruno Oliveira @@ -104,9 +104,11 @@ Since version 4.1.0, ``pytest-qt`` requires Python 3.7+. -Works with either PySide6_, PySide2_, PyQt6_ or PyQt5_, picking whichever -is available on the system, giving preference to the first one installed in -this order: +Works with either PySide6_, PySide2_, PyQt6_ or PyQt5_. + +If any of the above libraries is already imported by the time the tests execute, that library will be used. + +If not, pytest-qt will try to import and use the Qt APIs, in this order: - ``PySide6`` - ``PySide2`` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-qt-4.1.0/src/pytestqt/_version.py new/pytest-qt-4.2.0/src/pytestqt/_version.py --- old/pytest-qt-4.1.0/src/pytestqt/_version.py 2022-06-23 16:39:25.000000000 +0200 +++ new/pytest-qt-4.2.0/src/pytestqt/_version.py 2022-10-25 17:01:14.000000000 +0200 @@ -1,5 +1,5 @@ # coding: utf-8 # file generated by setuptools_scm # don't change, don't track in version control -__version__ = version = '4.1.0' -__version_tuple__ = version_tuple = (4, 1, 0) +__version__ = version = '4.2.0' +__version_tuple__ = version_tuple = (4, 2, 0) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-qt-4.1.0/src/pytestqt/exceptions.py new/pytest-qt-4.2.0/src/pytestqt/exceptions.py --- old/pytest-qt-4.1.0/src/pytestqt/exceptions.py 2022-06-23 16:39:11.000000000 +0200 +++ new/pytest-qt-4.2.0/src/pytestqt/exceptions.py 2022-10-25 17:01:03.000000000 +0200 @@ -98,17 +98,19 @@ .. versionadded:: 2.1 Exception thrown by :class:`pytestqt.qtbot.QtBot` methods. - """ - pass + Access via ``qtbot.TimeoutError``. + """ class ScreenshotError(Exception): """ .. versionadded:: 4.1 - Exception thrown by :method:`pytestqt.qtbot.QtBot.screenshot` if taking the + Exception thrown by :meth:`pytestqt.qtbot.QtBot.screenshot` if taking the screenshot failed. - """ - pass + .. versionchanged:: 4.2 + + Access via ``qtbot.ScreenshotError``. + """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-qt-4.1.0/src/pytestqt/logging.py new/pytest-qt-4.2.0/src/pytestqt/logging.py --- old/pytest-qt-4.1.0/src/pytestqt/logging.py 2022-06-23 16:39:11.000000000 +0200 +++ new/pytest-qt-4.2.0/src/pytestqt/logging.py 2022-10-25 17:01:03.000000000 +0200 @@ -2,7 +2,7 @@ from contextlib import contextmanager import datetime import re -from py._code.code import TerminalRepr, ReprFileLocation +from _pytest._code.code import TerminalRepr, ReprFileLocation import pytest from pytestqt.qt_compat import qt_api from pytestqt.utils import get_marker @@ -39,7 +39,7 @@ item.qt_log_capture = _QtMessageCapture(ignore_regexes) item.qt_log_capture._start() - @pytest.mark.hookwrapper + @pytest.hookimpl(hookwrapper=True) def pytest_runtest_makereport(self, item, call): """Add captured Qt messages to test item report if the call failed.""" outcome = yield diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-qt-4.1.0/src/pytestqt/plugin.py new/pytest-qt-4.2.0/src/pytestqt/plugin.py --- old/pytest-qt-4.1.0/src/pytestqt/plugin.py 2022-06-23 16:39:11.000000000 +0200 +++ new/pytest-qt-4.2.0/src/pytestqt/plugin.py 2022-10-25 17:01:03.000000000 +0200 @@ -157,8 +157,7 @@ ) -@pytest.mark.hookwrapper -@pytest.mark.tryfirst +@pytest.hookimpl(hookwrapper=True, tryfirst=True) def pytest_runtest_setup(item): """ Hook called after before test setup starts, to start capturing exceptions @@ -174,8 +173,7 @@ item.qt_exception_capture_manager.fail_if_exceptions_occurred("SETUP") -@pytest.mark.hookwrapper -@pytest.mark.tryfirst +@pytest.hookimpl(hookwrapper=True, tryfirst=True) def pytest_runtest_call(item): yield _process_events() @@ -184,8 +182,7 @@ item.qt_exception_capture_manager.fail_if_exceptions_occurred("CALL") -@pytest.mark.hookwrapper -@pytest.mark.trylast +@pytest.hookimpl(hookwrapper=True, trylast=True) def pytest_runtest_teardown(item): """ Hook called after each test tear down, to process any pending events and diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-qt-4.1.0/src/pytestqt/qt_compat.py new/pytest-qt-4.2.0/src/pytestqt/qt_compat.py --- old/pytest-qt-4.1.0/src/pytestqt/qt_compat.py 2022-06-23 16:39:11.000000000 +0200 +++ new/pytest-qt-4.2.0/src/pytestqt/qt_compat.py 2022-10-25 17:01:03.000000000 +0200 @@ -1,6 +1,6 @@ """ Provide a common way to import Qt classes used by pytest-qt in a unique manner, -abstracting API differences between PyQt5 and PySide2/6. +abstracting API differences between PyQt5/6 and PySide2/6. .. note:: This module is not part of pytest-qt public API, hence its interface may change between releases and users should not rely on it. @@ -9,20 +9,31 @@ """ -from collections import namedtuple +from collections import namedtuple, OrderedDict import os +import sys import pytest VersionTuple = namedtuple("VersionTuple", "qt_api, qt_api_version, runtime, compiled") +QT_APIS = OrderedDict() +QT_APIS["pyside6"] = "PySide6" +QT_APIS["pyside2"] = "PySide2" +QT_APIS["pyqt6"] = "PyQt6" +QT_APIS["pyqt5"] = "PyQt5" + def _import(name): """Think call so we can mock it during testing""" return __import__(name) +def _is_library_loaded(name): + return name in sys.modules + + class _QtApi: """ Interface to the underlying Qt API currently configured for pytest-qt. @@ -36,12 +47,7 @@ def _get_qt_api_from_env(self): api = os.environ.get("PYTEST_QT_API") - supported_apis = [ - "pyside6", - "pyside2", - "pyqt6", - "pyqt5", - ] + supported_apis = QT_APIS.keys() if api is not None: api = api.lower() @@ -50,6 +56,12 @@ raise pytest.UsageError(msg) return api + def _get_already_loaded_backend(self): + for api, backend in QT_APIS.items(): + if _is_library_loaded(backend): + return api + return None + def _guess_qt_api(self): # pragma: no cover def _can_import(name): try: @@ -61,18 +73,18 @@ # Note, not importing only the root namespace because when uninstalling from conda, # the namespace can still be there. - if _can_import("PySide6.QtCore"): - return "pyside6" - elif _can_import("PySide2.QtCore"): - return "pyside2" - elif _can_import("PyQt6.QtCore"): - return "pyqt6" - elif _can_import("PyQt5.QtCore"): - return "pyqt5" + for api, backend in QT_APIS.items(): + if _can_import(f"{backend}.QtCore"): + return api return None def set_qt_api(self, api): - self.pytest_qt_api = self._get_qt_api_from_env() or api or self._guess_qt_api() + self.pytest_qt_api = ( + self._get_qt_api_from_env() + or api + or self._get_already_loaded_backend() + or self._guess_qt_api() + ) self.is_pyside = self.pytest_qt_api in ["pyside2", "pyside6"] self.is_pyqt = self.pytest_qt_api in ["pyqt5", "pyqt6"] @@ -88,13 +100,7 @@ ) raise pytest.UsageError(msg) - _root_modules = { - "pyside6": "PySide6", - "pyside2": "PySide2", - "pyqt6": "PyQt6", - "pyqt5": "PyQt5", - } - _root_module = _root_modules[self.pytest_qt_api] + _root_module = QT_APIS[self.pytest_qt_api] def _import_module(module_name): m = __import__(_root_module, globals(), locals(), [module_name], 0) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-qt-4.1.0/src/pytestqt/qtbot.py new/pytest-qt-4.2.0/src/pytestqt/qtbot.py --- old/pytest-qt-4.1.0/src/pytestqt/qtbot.py 2022-06-23 16:39:11.000000000 +0200 +++ new/pytest-qt-4.2.0/src/pytestqt/qtbot.py 2022-10-25 17:01:03.000000000 +0200 @@ -182,7 +182,8 @@ def waitActive(self, widget, *, timeout=5000): """ Context manager that waits for ``timeout`` milliseconds or until the window is active. - If window is not exposed within ``timeout`` milliseconds, raise ``TimeoutError``. + If window is not exposed within ``timeout`` milliseconds, raise + :class:`qtbot.TimeoutError <pytestqt.exceptions.TimeoutError>` This is mainly useful for asynchronous systems like X11, where a window will be mapped to screen some time after being asked to show itself on the screen. @@ -208,7 +209,8 @@ def waitExposed(self, widget, *, timeout=5000): """ Context manager that waits for ``timeout`` milliseconds or until the window is exposed. - If the window is not exposed within ``timeout`` milliseconds, raise ``TimeoutError``. + If the window is not exposed within ``timeout`` milliseconds, raise + :class:`qtbot.TimeoutError <pytestqt.exceptions.TimeoutError>` This is mainly useful for asynchronous systems like X11, where a window will be mapped to screen some time after being asked to show itself on the screen. @@ -238,10 +240,11 @@ show itself on the screen. .. warning:: - This method does **not** raise ``TimeoutError`` if the window wasn't shown. + This method does **not** raise :class:`qtbot.TimeoutError <pytestqt.exceptions.TimeoutError>` if + the window wasn't shown. .. deprecated:: 4.0 - Use the qtbot.waitForWindowExposed context manager instead. + Use the ``qtbot.waitExposed`` context manager instead. :param QWidget widget: Widget to wait on. @@ -255,7 +258,7 @@ warnings.warn( "waitForWindowShown is deprecated, as the underlying Qt method was " "obsoleted in Qt 5.0 and removed in Qt 6.0. Its name is imprecise and " - "the pytest-qt wrapper does not raise TimeoutError if the window " + "the pytest-qt wrapper does not raise qtbot.TimeoutError if the window " "wasn't shown. Please use the qtbot.waitExposed context manager " "instead.", DeprecationWarning, @@ -315,11 +318,11 @@ :param Signal signal: A signal to wait for, or a tuple ``(signal, signal_name_as_str)`` to improve the error message that is part - of ``TimeoutError``. + of :class:`qtbot.TimeoutError <pytestqt.exceptions.TimeoutError>`. :param int timeout: How many milliseconds to wait before resuming control flow. :param bool raising: - If :class:`QtBot.TimeoutError <pytestqt.plugin.TimeoutError>` + If :class:`qtbot.TimeoutError <pytestqt.exceptions.TimeoutError>` should be raised if a timeout occurred. This defaults to ``True`` unless ``qt_default_raising = false`` is set in the config. @@ -376,11 +379,11 @@ :param list signals: A list of :class:`Signal` objects to wait for. Alternatively: a list of (``Signal, str``) tuples of the form - ``(signal, signal_name_as_str)`` to improve the error message that is part of ``TimeoutError``. + ``(signal, signal_name_as_str)`` to improve the error message that is part of ``qtbot.TimeoutError``. :param int timeout: How many milliseconds to wait before resuming control flow. :param bool raising: - If :class:`QtBot.TimeoutError <pytestqt.plugin.TimeoutError>` + If :class:`qtbot.TimeoutError <pytestqt.exceptions.TimeoutError>` should be raised if a timeout occurred. This defaults to ``True`` unless ``qt_default_raising = false`` is set in the config. @@ -566,7 +569,7 @@ :param int timeout: How many milliseconds to wait before resuming control flow. :param bool raising: - If :class:`QtBot.TimeoutError <pytestqt.plugin.TimeoutError>` + If :class:`qtbot.TimeoutError <pytestqt.exceptions.TimeoutError>` should be raised if a timeout occurred. This defaults to ``True`` unless ``qt_default_raising = false`` is set in the config. @@ -616,6 +619,9 @@ ``objectName()`` of the widget if set, as well as its class name. A custom ``suffix`` can be given to add to the generated name. + Raises :class:`qtbot.ScreenshotError <pytestqt.exceptions.ScreenshotError>` + if taking the screenshot or saving the file failed. + :param QWidget widget: The widget to take a screenshot of. :param str suffix: @@ -625,7 +631,6 @@ contained. :returns: A ``pathlib.Path`` object with the taken screenshot. - :raises ScreenshotError: if taking the screenshot or saving the file failed. """ pixmap = widget.grab() if region is None else widget.grab(region) if pixmap.isNull(): @@ -711,6 +716,7 @@ # provide easy access to exceptions to qtbot fixtures QtBot.SignalEmittedError = SignalEmittedError QtBot.TimeoutError = TimeoutError +QtBot.ScreenshotError = ScreenshotError QtBot.CallbackCalledTwiceError = CallbackCalledTwiceError diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-qt-4.1.0/src/pytestqt/wait_signal.py new/pytest-qt-4.2.0/src/pytestqt/wait_signal.py --- old/pytest-qt-4.1.0/src/pytestqt/wait_signal.py 2022-06-23 16:39:11.000000000 +0200 +++ new/pytest-qt-4.2.0/src/pytestqt/wait_signal.py 2022-10-25 17:01:03.000000000 +0200 @@ -164,7 +164,8 @@ this is set to ``None``. :ivar bool raising: - If :class:`TimeoutError` should be raised if a timeout occurred. + If :class:`qtbot.TimeoutError <pytestqt.exceptions.TimeoutError>` should be raised + if a timeout occurred. .. note:: contrary to the parameter of same name in :meth:`pytestqt.qtbot.QtBot.waitSignal`, this parameter does not @@ -626,7 +627,8 @@ :ivar int timeout: maximum time to wait for the callback to be called. :ivar bool raising: - If :class:`TimeoutError` should be raised if a timeout occurred. + If :class:`qtbot.TimeoutError <pytestqt.exceptions.TimeoutError>` should be raised if + a timeout occurred. .. note:: contrary to the parameter of same name in :meth:`pytestqt.qtbot.QtBot.waitCallback`, this parameter does not @@ -722,8 +724,6 @@ signal was emitted unexpectedly. """ - pass - class CallbackCalledTwiceError(Exception): """ @@ -733,8 +733,6 @@ callback was called twice. """ - pass - def _silent_disconnect(signal, slot): """Disconnects a signal from a slot, ignoring errors. Sometimes diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-qt-4.1.0/tests/test_basics.py new/pytest-qt-4.2.0/tests/test_basics.py --- old/pytest-qt-4.1.0/tests/test_basics.py 2022-06-23 16:39:11.000000000 +0200 +++ new/pytest-qt-4.2.0/tests/test_basics.py 2022-10-25 17:01:03.000000000 +0200 @@ -563,8 +563,12 @@ def _fake_import(name, *args): raise ModuleNotFoundError(f"Failed to import {name}") + def _fake_is_library_loaded(name, *args): + return False + monkeypatch.delenv("PYTEST_QT_API", raising=False) monkeypatch.setattr(qt_compat, "_import", _fake_import) + monkeypatch.setattr(qt_compat, "_is_library_loaded", _fake_is_library_loaded) expected = ( "pytest-qt requires either PySide2, PySide6, PyQt5 or PyQt6 installed.\n" @@ -578,6 +582,73 @@ qt_api.set_qt_api(api=None) +@pytest.mark.parametrize( + "option_api, backend", + [ + ("pyqt5", "PyQt5"), + ("pyqt6", "PyQt6"), + ("pyside2", "PySide2"), + ("pyside6", "PySide6"), + ], +) +def test_already_loaded_backend(monkeypatch, option_api, backend): + + import builtins + + class Mock: + pass + + qtcore = Mock() + for method_name in ( + "qInstallMessageHandler", + "qDebug", + "qWarning", + "qCritical", + "qFatal", + ): + setattr(qtcore, method_name, lambda *_: None) + + if backend in ("PyQt5", "PyQt6"): + pyqt_version = 0x050B00 if backend == "PyQt5" else 0x060000 + qtcore.PYQT_VERSION = pyqt_version + 1 + qtcore.pyqtSignal = object() + qtcore.pyqtSlot = object() + qtcore.pyqtProperty = object() + else: + qtcore.Signal = object() + qtcore.Slot = object() + qtcore.Property = object() + + qtwidgets = Mock() + qapplication = Mock() + qapplication.instance = lambda *_: None + qtwidgets.QApplication = qapplication + + qbackend = Mock() + qbackend.QtCore = qtcore + qbackend.QtGui = object() + qbackend.QtTest = object() + qbackend.QtWidgets = qtwidgets + + import_orig = builtins.__import__ + + def _fake_import(name, *args, **kwargs): + if name == backend: + return qbackend + return import_orig(name, *args, **kwargs) + + def _fake_is_library_loaded(name, *args): + return name == backend + + monkeypatch.delenv("PYTEST_QT_API", raising=False) + monkeypatch.setattr(qt_compat, "_is_library_loaded", _fake_is_library_loaded) + monkeypatch.setattr(builtins, "__import__", _fake_import) + + qt_api.set_qt_api(api=None) + + assert qt_api.pytest_qt_api == option_api + + def test_before_close_func(testdir): """ Test the `before_close_func` argument of qtbot.addWidget. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-qt-4.1.0/tests/test_logging.py new/pytest-qt-4.2.0/tests/test_logging.py --- old/pytest-qt-4.1.0/tests/test_logging.py 2022-06-23 16:39:11.000000000 +0200 +++ new/pytest-qt-4.2.0/tests/test_logging.py 2022-10-25 17:01:03.000000000 +0200 @@ -541,7 +541,7 @@ conftest=""" import pytest - @pytest.mark.hookwrapper(tryfirst=True) + @pytest.hookimpl(hookwrapper=True, tryfirst=True) def pytest_runtest_makereport(call): if call.when == 'call': raise Exception("This should not be hidden") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-qt-4.1.0/tests/test_modeltest.py new/pytest-qt-4.2.0/tests/test_modeltest.py --- old/pytest-qt-4.1.0/tests/test_modeltest.py 2022-06-23 16:39:11.000000000 +0200 +++ new/pytest-qt-4.2.0/tests/test_modeltest.py 2022-10-25 17:01:03.000000000 +0200 @@ -267,7 +267,6 @@ def test_nop(qtmodeltester): """We should not get a crash on cleanup with no model.""" - pass def test_overridden_methods(qtmodeltester): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-qt-4.1.0/tests/test_screenshot.py new/pytest-qt-4.2.0/tests/test_screenshot.py --- old/pytest-qt-4.1.0/tests/test_screenshot.py 2022-06-23 16:39:11.000000000 +0200 +++ new/pytest-qt-4.2.0/tests/test_screenshot.py 2022-10-25 17:01:03.000000000 +0200 @@ -3,7 +3,6 @@ import pytest from pytestqt.qt_compat import qt_api -from pytestqt.exceptions import ScreenshotError @pytest.fixture @@ -60,12 +59,12 @@ def test_filename_endless(qtbot, widget, monkeypatch): monkeypatch.setattr(pathlib.Path, "exists", lambda _self: True) - with pytest.raises(ScreenshotError, match="Failed to find unique filename"): + with pytest.raises(qtbot.ScreenshotError, match="Failed to find unique filename"): qtbot.screenshot(widget, suffix="before") def test_filename_invalid(qtbot, widget): - with pytest.raises(ScreenshotError, match="Saving to .* failed"): + with pytest.raises(qtbot.ScreenshotError, match="Saving to .* failed"): qtbot.screenshot(widget, suffix=r"invalid/path\everywhere") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-qt-4.1.0/tests/test_wait_until.py new/pytest-qt-4.2.0/tests/test_wait_until.py --- old/pytest-qt-4.1.0/tests/test_wait_until.py 2022-06-23 16:39:11.000000000 +0200 +++ new/pytest-qt-4.2.0/tests/test_wait_until.py 2022-10-25 17:01:03.000000000 +0200 @@ -1,7 +1,5 @@ import pytest -from pytestqt.exceptions import TimeoutError - def test_wait_until(qtbot, wait_4_ticks_callback, tick_counter): tick_counter.start(100) @@ -11,7 +9,7 @@ def test_wait_until_timeout(qtbot, wait_4_ticks_callback, tick_counter): tick_counter.start(200) - with pytest.raises(TimeoutError): + with pytest.raises(qtbot.TimeoutError): qtbot.waitUntil(wait_4_ticks_callback, timeout=100) assert tick_counter.ticks < 4
participants (1)
-
Source-Sync