diff --git a/AUTHORS b/AUTHORS index bb27dd1d7..f78c4b3f9 100644 --- a/AUTHORS +++ b/AUTHORS @@ -128,6 +128,7 @@ Edison Gustavo Muenz Edoardo Batini Edson Tadeu M. Manoel Eduardo Schettino +Edward Haigh Eero Vaher Eli Boyarski Elizaveta Shashkova diff --git a/README.rst b/README.rst index fba23872e..a81e082cd 100644 --- a/README.rst +++ b/README.rst @@ -99,7 +99,7 @@ Features - Python 3.8+ or PyPy3 -- Rich plugin architecture, with over 850+ `external plugins `_ and thriving community +- Rich plugin architecture, with over 1300+ `external plugins `_ and thriving community Documentation diff --git a/changelog/11653.feature.rst b/changelog/11653.feature.rst new file mode 100644 index 000000000..f165c3f8e --- /dev/null +++ b/changelog/11653.feature.rst @@ -0,0 +1,2 @@ +Added the new :confval:`verbosity_test_cases` configuration option for fine-grained control of test execution verbosity. +See :ref:`Fine-grained verbosity ` for more details. diff --git a/changelog/11850.improvement.rst b/changelog/11850.improvement.rst new file mode 100644 index 000000000..87fc0953c --- /dev/null +++ b/changelog/11850.improvement.rst @@ -0,0 +1 @@ +Added support for :data:`sys.last_exc` for post-mortem debugging on Python>=3.12. diff --git a/changelog/11895.bugfix.rst b/changelog/11895.bugfix.rst deleted file mode 100644 index 4211213c1..000000000 --- a/changelog/11895.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix collection on Windows where initial paths contain the short version of a path (for example ``c:\PROGRA~1\tests``). diff --git a/changelog/11904.bugfix.rst b/changelog/11904.bugfix.rst new file mode 100644 index 000000000..2aed9bcb0 --- /dev/null +++ b/changelog/11904.bugfix.rst @@ -0,0 +1,3 @@ +Fixed a regression in pytest 8.0.0 that would cause test collection to fail due to permission errors when using ``--pyargs``. + +This change improves the collection tree for tests specified using ``--pyargs``, see :pull:`12043` for a comparison with pytest 8.0 and <8. diff --git a/changelog/11953.bugfix.rst b/changelog/11953.bugfix.rst deleted file mode 100644 index 5aff5f7fd..000000000 --- a/changelog/11953.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix an ``IndexError`` crash raising from ``getstatementrange_ast``. diff --git a/doc/en/announce/index.rst b/doc/en/announce/index.rst index 780451146..5374e8c75 100644 --- a/doc/en/announce/index.rst +++ b/doc/en/announce/index.rst @@ -6,6 +6,7 @@ Release announcements :maxdepth: 2 + release-8.0.2 release-8.0.1 release-8.0.0 release-8.0.0rc2 diff --git a/doc/en/announce/release-8.0.2.rst b/doc/en/announce/release-8.0.2.rst new file mode 100644 index 000000000..c42159c57 --- /dev/null +++ b/doc/en/announce/release-8.0.2.rst @@ -0,0 +1,18 @@ +pytest-8.0.2 +======================================= + +pytest 8.0.2 has just been released to PyPI. + +This is a bug-fix release, being a drop-in replacement. To upgrade:: + + pip install --upgrade pytest + +The full changelog is available at https://docs.pytest.org/en/stable/changelog.html. + +Thanks to all of the contributors to this release: + +* Ran Benita + + +Happy testing, +The pytest Development Team diff --git a/doc/en/changelog.rst b/doc/en/changelog.rst index 6ed764207..bdf5a1550 100644 --- a/doc/en/changelog.rst +++ b/doc/en/changelog.rst @@ -28,6 +28,21 @@ with advance notice in the **Deprecations** section of releases. .. towncrier release notes start +pytest 8.0.2 (2024-02-24) +========================= + +Bug Fixes +--------- + +- `#11895 `_: Fix collection on Windows where initial paths contain the short version of a path (for example ``c:\PROGRA~1\tests``). + + +- `#11953 `_: Fix an ``IndexError`` crash raising from ``getstatementrange_ast``. + + +- `#12021 `_: Reverted a fix to `--maxfail` handling in pytest 8.0.0 because it caused a regression in pytest-xdist whereby session fixture teardowns may get executed multiple times when the max-fails is reached. + + pytest 8.0.1 (2024-02-16) ========================= @@ -85,6 +100,8 @@ Bug Fixes - `#11706 `_: Fix reporting of teardown errors in higher-scoped fixtures when using `--maxfail` or `--stepwise`. + NOTE: This change was reverted in pytest 8.0.2 to fix a `regression `_ it caused in pytest-xdist. + - `#11758 `_: Fixed ``IndexError: string index out of range`` crash in ``if highlighted[-1] == "\n" and source[-1] != "\n"``. This bug was introduced in pytest 8.0.0rc1. diff --git a/doc/en/example/parametrize.rst b/doc/en/example/parametrize.rst index 99afaded8..c6ac64899 100644 --- a/doc/en/example/parametrize.rst +++ b/doc/en/example/parametrize.rst @@ -162,7 +162,7 @@ objects, they are still using the default pytest representation: rootdir: /home/sweet/project collected 8 items - + @@ -239,7 +239,7 @@ If you just collect tests you'll also nicely see 'advanced' and 'basic' as varia rootdir: /home/sweet/project collected 4 items - + @@ -318,7 +318,7 @@ Let's first see how it looks like at collection time: rootdir: /home/sweet/project collected 2 items - + diff --git a/doc/en/example/pythoncollection.rst b/doc/en/example/pythoncollection.rst index 89acb7d3b..7207ca2ae 100644 --- a/doc/en/example/pythoncollection.rst +++ b/doc/en/example/pythoncollection.rst @@ -152,7 +152,7 @@ The test collection would look like this: configfile: pytest.ini collected 2 items - + @@ -215,7 +215,7 @@ You can always peek at the collection tree without running tests like this: configfile: pytest.ini collected 3 items - + diff --git a/doc/en/getting-started.rst b/doc/en/getting-started.rst index 114d69328..f19198864 100644 --- a/doc/en/getting-started.rst +++ b/doc/en/getting-started.rst @@ -22,7 +22,7 @@ Install ``pytest`` .. code-block:: bash $ pytest --version - pytest 8.0.1 + pytest 8.0.2 .. _`simpletest`: diff --git a/doc/en/how-to/fixtures.rst b/doc/en/how-to/fixtures.rst index bc45c3a29..329c568c0 100644 --- a/doc/en/how-to/fixtures.rst +++ b/doc/en/how-to/fixtures.rst @@ -1418,7 +1418,7 @@ Running the above tests results in the following test IDs being used: rootdir: /home/sweet/project collected 12 items - + diff --git a/doc/en/how-to/output.rst b/doc/en/how-to/output.rst index 76b2a53dd..5b47a5c77 100644 --- a/doc/en/how-to/output.rst +++ b/doc/en/how-to/output.rst @@ -325,7 +325,9 @@ This is done by setting a verbosity level in the configuration file for the spec ``pytest --no-header`` with a value of ``2`` would have the same output as the previous example, but each test inside the file is shown by a single character in the output. -(Note: currently this is the only option available, but more might be added in the future). +:confval:`verbosity_test_cases`: Controls how verbose the test execution output should be when pytest is executed. +Running ``pytest --no-header`` with a value of ``2`` would have the same output as the first verbosity example, but each +test inside the file gets its own line in the output. .. _`pytest.detailed_failed_tests_usage`: diff --git a/doc/en/index.rst b/doc/en/index.rst index bc0bd56bf..9d97dfaa6 100644 --- a/doc/en/index.rst +++ b/doc/en/index.rst @@ -81,7 +81,7 @@ Features - Python 3.8+ or PyPy 3 -- Rich plugin architecture, with over 800+ :ref:`external plugins ` and thriving community +- Rich plugin architecture, with over 1300+ :ref:`external plugins ` and thriving community Documentation diff --git a/doc/en/reference/plugin_list.rst b/doc/en/reference/plugin_list.rst index b89a9b05f..e02080eb2 100644 --- a/doc/en/reference/plugin_list.rst +++ b/doc/en/reference/plugin_list.rst @@ -7,7 +7,7 @@ Pytest Plugin List ================== Below is an automated compilation of ``pytest``` plugins available on `PyPI `_. -It includes PyPI projects whose names begin with ``"pytest-"`` or ``"pytest_"`` and a handful of manually selected projects. +It includes PyPI projects whose names begin with ``pytest-`` or ``pytest_`` and a handful of manually selected projects. Packages classified as inactive are excluded. For detailed insights into how this list is generated, @@ -27,7 +27,7 @@ please refer to `the update script =7,<9) ; extra == "pytest" + :pypi:`logot` Test whether your code is logging correctly 🪵 Feb 19, 2024 5 - Production/Stable pytest (>=7,<9) ; extra == "pytest" :pypi:`nuts` Network Unit Testing System Aug 11, 2023 N/A pytest (>=7.3.0,<8.0.0) :pypi:`pytest-abq` Pytest integration for the ABQ universal test runner. Apr 07, 2023 N/A N/A :pypi:`pytest-abstracts` A contextmanager pytest fixture for handling multiple mock abstracts May 25, 2022 N/A N/A @@ -68,7 +68,7 @@ This list contains 1394 plugins. :pypi:`pytest-allure-intersection` Oct 27, 2022 N/A pytest (<5) :pypi:`pytest-allure-spec-coverage` The pytest plugin aimed to display test coverage of the specs(requirements) in Allure Oct 26, 2021 N/A pytest :pypi:`pytest-alphamoon` Static code checks used at Alphamoon Dec 30, 2021 5 - Production/Stable pytest (>=3.5.0) - :pypi:`pytest-analyzer` this plugin allows to analyze tests in pytest project, collect test metadata and sync it with testomat.io TCM system Feb 12, 2024 N/A pytest >=7.3.1 + :pypi:`pytest-analyzer` this plugin allows to analyze tests in pytest project, collect test metadata and sync it with testomat.io TCM system Feb 21, 2024 N/A pytest <8.0.0,>=7.3.1 :pypi:`pytest-android` This fixture provides a configured "driver" for Android Automated Testing, using uiautomator2. Feb 21, 2019 3 - Alpha pytest :pypi:`pytest-anki` A pytest plugin for testing Anki add-ons Jul 31, 2022 4 - Beta pytest (>=3.5.0) :pypi:`pytest-annotate` pytest-annotate: Generate PyAnnotate annotations from your pytest tests. Jun 07, 2022 3 - Alpha pytest (<8.0.0,>=3.2.0) @@ -138,7 +138,7 @@ This list contains 1394 plugins. :pypi:`pytest-bdd` BDD for pytest Dec 02, 2023 6 - Mature pytest (>=6.2.0) :pypi:`pytest-bdd-html` pytest plugin to display BDD info in HTML test report Nov 22, 2022 3 - Alpha pytest (!=6.0.0,>=5.0) :pypi:`pytest-bdd-ng` BDD for pytest Dec 31, 2023 4 - Beta pytest >=5.0 - :pypi:`pytest-bdd-report` A pytest-bdd plugin for generating useful and informative BDD test reports Nov 15, 2023 N/A pytest >=7.1.3 + :pypi:`pytest-bdd-report` A pytest-bdd plugin for generating useful and informative BDD test reports Feb 19, 2024 N/A pytest >=7.1.3 :pypi:`pytest-bdd-splinter` Common steps for pytest bdd and splinter integration Aug 12, 2019 5 - Production/Stable pytest (>=4.0.0) :pypi:`pytest-bdd-web` A simple plugin to use with pytest Jan 02, 2020 4 - Beta pytest (>=3.5.0) :pypi:`pytest-bdd-wrappers` Feb 11, 2020 2 - Pre-Alpha N/A @@ -146,7 +146,6 @@ This list contains 1394 plugins. :pypi:`pytest-beartype` Pytest plugin to run your tests with beartype checking enabled. Jan 25, 2024 N/A pytest :pypi:`pytest-beds` Fixtures for testing Google Appengine (GAE) apps Jun 07, 2016 4 - Beta N/A :pypi:`pytest-beeprint` use icdiff for better error messages in pytest assertions Jul 04, 2023 4 - Beta N/A - :pypi:`pytest-behave` A powerful test automation framework designed to provide a comprehensive solution for testing user interfaces and APIs Feb 15, 2024 N/A N/A :pypi:`pytest-bench` Benchmark utility that plugs into pytest. Jul 21, 2014 3 - Alpha N/A :pypi:`pytest-benchmark` A \`\`pytest\`\` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer. Oct 25, 2022 5 - Production/Stable pytest (>=3.8) :pypi:`pytest-better-datadir` A small example package Mar 13, 2023 N/A N/A @@ -212,7 +211,7 @@ This list contains 1394 plugins. :pypi:`pytest-check-libs` check your missing library Jul 17, 2022 N/A N/A :pypi:`pytest-check-links` Check links in files Jul 29, 2020 N/A pytest>=7.0 :pypi:`pytest-check-mk` pytest plugin to test Check_MK checks Nov 19, 2015 4 - Beta pytest - :pypi:`pytest-check-requirements` A package to prevent Dependency Confusion attacks against Yandex. Feb 10, 2023 N/A N/A + :pypi:`pytest-check-requirements` A package to prevent Dependency Confusion attacks against Yandex. Feb 20, 2024 N/A N/A :pypi:`pytest-chic-report` A pytest plugin to send a report and printing summary of tests. Jan 31, 2023 5 - Production/Stable N/A :pypi:`pytest-choose` Provide the pytest with the ability to collect use cases based on rules in text files Feb 04, 2024 N/A pytest >=7.0.0 :pypi:`pytest-chunks` Run only a chunk of your test suite Jul 05, 2022 N/A pytest (>=6.0.0) @@ -292,7 +291,7 @@ This list contains 1394 plugins. :pypi:`pytest-custom-scheduling` Custom grouping for pytest-xdist, rename test cases name and test cases nodeid, support allure report Mar 01, 2021 N/A N/A :pypi:`pytest-cython` A plugin for testing Cython extension modules Feb 16, 2023 5 - Production/Stable pytest (>=4.6.0) :pypi:`pytest-cython-collect` Jun 17, 2022 N/A pytest - :pypi:`pytest-darker` A pytest plugin for checking of modified code using Darker Aug 16, 2020 N/A pytest (>=6.0.1) ; extra == 'test' + :pypi:`pytest-darker` A pytest plugin for checking of modified code using Darker Feb 24, 2024 N/A pytest <8,>=6.0.1 :pypi:`pytest-dash` pytest fixtures to run dash applications. Mar 18, 2019 N/A N/A :pypi:`pytest-data` Useful functions for managing data for pytest fixtures Nov 01, 2016 5 - Production/Stable N/A :pypi:`pytest-databricks` Pytest plugin for remote Databricks notebooks testing Jul 29, 2020 N/A pytest @@ -337,7 +336,7 @@ This list contains 1394 plugins. :pypi:`pytest-dicom` pytest plugin to provide DICOM fixtures Dec 19, 2018 3 - Alpha pytest :pypi:`pytest-dictsdiff` Jul 26, 2019 N/A N/A :pypi:`pytest-diff` A simple plugin to use with pytest Mar 30, 2019 4 - Beta pytest (>=3.5.0) - :pypi:`pytest-diffeo` A package to prevent Dependency Confusion attacks against Yandex. Feb 10, 2023 N/A N/A + :pypi:`pytest-diffeo` A package to prevent Dependency Confusion attacks against Yandex. Feb 20, 2024 N/A N/A :pypi:`pytest-diff-selector` Get tests affected by code changes (using git) Feb 24, 2022 4 - Beta pytest (>=6.2.2) ; extra == 'all' :pypi:`pytest-difido` PyTest plugin for generating Difido reports Oct 23, 2022 4 - Beta pytest (>=4.0.0) :pypi:`pytest-dir-equal` pytest-dir-equals is a pytest plugin providing helpers to assert directories equality allowing golden testing Dec 11, 2023 4 - Beta pytest>=7.3.2 @@ -423,14 +422,14 @@ This list contains 1394 plugins. :pypi:`pytest-eliot` An eliot plugin for pytest. Aug 31, 2022 1 - Planning pytest (>=5.4.0) :pypi:`pytest-elk-reporter` A simple plugin to use with pytest Jan 24, 2021 4 - Beta pytest (>=3.5.0) :pypi:`pytest-email` Send execution result email Jul 08, 2020 N/A pytest - :pypi:`pytest-embedded` A pytest plugin that designed for embedded testing. Feb 14, 2024 5 - Production/Stable pytest>=7.0 - :pypi:`pytest-embedded-arduino` Make pytest-embedded plugin work with Arduino. Feb 14, 2024 5 - Production/Stable N/A - :pypi:`pytest-embedded-idf` Make pytest-embedded plugin work with ESP-IDF. Feb 14, 2024 5 - Production/Stable N/A - :pypi:`pytest-embedded-jtag` Make pytest-embedded plugin work with JTAG. Feb 14, 2024 5 - Production/Stable N/A - :pypi:`pytest-embedded-qemu` Make pytest-embedded plugin work with QEMU. Feb 14, 2024 5 - Production/Stable N/A - :pypi:`pytest-embedded-serial` Make pytest-embedded plugin work with Serial. Feb 14, 2024 5 - Production/Stable N/A - :pypi:`pytest-embedded-serial-esp` Make pytest-embedded plugin work with Espressif target boards. Feb 14, 2024 5 - Production/Stable N/A - :pypi:`pytest-embedded-wokwi` Make pytest-embedded plugin work with the Wokwi CLI. Feb 14, 2024 5 - Production/Stable N/A + :pypi:`pytest-embedded` A pytest plugin that designed for embedded testing. Feb 23, 2024 5 - Production/Stable pytest>=7.0 + :pypi:`pytest-embedded-arduino` Make pytest-embedded plugin work with Arduino. Feb 23, 2024 5 - Production/Stable N/A + :pypi:`pytest-embedded-idf` Make pytest-embedded plugin work with ESP-IDF. Feb 23, 2024 5 - Production/Stable N/A + :pypi:`pytest-embedded-jtag` Make pytest-embedded plugin work with JTAG. Feb 23, 2024 5 - Production/Stable N/A + :pypi:`pytest-embedded-qemu` Make pytest-embedded plugin work with QEMU. Feb 23, 2024 5 - Production/Stable N/A + :pypi:`pytest-embedded-serial` Make pytest-embedded plugin work with Serial. Feb 23, 2024 5 - Production/Stable N/A + :pypi:`pytest-embedded-serial-esp` Make pytest-embedded plugin work with Espressif target boards. Feb 23, 2024 5 - Production/Stable N/A + :pypi:`pytest-embedded-wokwi` Make pytest-embedded plugin work with the Wokwi CLI. Feb 23, 2024 5 - Production/Stable N/A :pypi:`pytest-embrace` 💝 Dataclasses-as-tests. Describe the runtime once and multiply coverage with no boilerplate. Mar 25, 2023 N/A pytest (>=7.0,<8.0) :pypi:`pytest-emoji` A pytest plugin that adds emojis to your test result report Feb 19, 2019 4 - Beta pytest (>=4.2.1) :pypi:`pytest-emoji-output` Pytest plugin to represent test output with emoji support Apr 09, 2023 4 - Beta pytest (==7.0.1) @@ -462,6 +461,7 @@ This list contains 1394 plugins. :pypi:`pytest-exception-script` Walk your code through exception script to check it's resiliency to failures. Aug 04, 2020 3 - Alpha pytest :pypi:`pytest-executable` pytest plugin for testing executables Oct 07, 2023 N/A pytest <8,>=5 :pypi:`pytest-execution-timer` A timer for the phases of Pytest's execution. Dec 24, 2021 4 - Beta N/A + :pypi:`pytest-exit-code` A pytest plugin that overrides the built-in exit codes to retain more information about the test results. Feb 23, 2024 4 - Beta pytest >=6.2.0 :pypi:`pytest-expect` py.test plugin to store test expectations and mark tests based on them Apr 21, 2016 4 - Beta N/A :pypi:`pytest-expectdir` A pytest plugin to provide initial/expected directories, and check a test transforms the initial directory to the expected one Mar 19, 2023 5 - Production/Stable pytest (>=5.0) :pypi:`pytest-expecter` Better testing with expecter and pytest. Sep 18, 2022 5 - Production/Stable N/A @@ -477,7 +477,7 @@ This list contains 1394 plugins. :pypi:`pytest-extra-durations` A pytest plugin to get durations on a per-function basis and per module basis. Apr 21, 2020 4 - Beta pytest (>=3.5.0) :pypi:`pytest-extra-markers` Additional pytest markers to dynamically enable/disable tests viia CLI flags Mar 05, 2023 4 - Beta pytest :pypi:`pytest-fabric` Provides test utilities to run fabric task tests by using docker containers Sep 12, 2018 5 - Production/Stable N/A - :pypi:`pytest-factor` A package to prevent Dependency Confusion attacks against Yandex. Feb 10, 2023 N/A N/A + :pypi:`pytest-factor` A package to prevent Dependency Confusion attacks against Yandex. Feb 20, 2024 N/A N/A :pypi:`pytest-factory` Use factories for test setup with py.test Sep 06, 2020 3 - Alpha pytest (>4.3) :pypi:`pytest-factoryboy` Factory Boy support for pytest. Oct 10, 2023 6 - Mature pytest (>=6.2) :pypi:`pytest-factoryboy-fixtures` Generates pytest fixtures that allow the use of type hinting Jun 25, 2020 N/A N/A @@ -488,7 +488,7 @@ This list contains 1394 plugins. :pypi:`pytest-fail-slow` Fail tests that take too long to run Feb 11, 2024 N/A pytest>=7.0 :pypi:`pytest-faker` Faker integration with the pytest framework. Dec 19, 2016 6 - Mature N/A :pypi:`pytest-falcon` Pytest helpers for Falcon. Sep 07, 2016 4 - Beta N/A - :pypi:`pytest-falcon-client` Pytest \`client\` fixture for the Falcon Framework Mar 19, 2019 N/A N/A + :pypi:`pytest-falcon-client` A package to prevent Dependency Confusion attacks against Yandex. Feb 21, 2024 N/A N/A :pypi:`pytest-fantasy` Pytest plugin for Flask Fantasy Framework Mar 14, 2019 N/A N/A :pypi:`pytest-fastapi` Dec 27, 2020 N/A N/A :pypi:`pytest-fastapi-deps` A fixture which allows easy replacement of fastapi dependencies for testing Jul 20, 2022 5 - Production/Stable pytest @@ -507,7 +507,7 @@ This list contains 1394 plugins. :pypi:`pytest-finer-verdicts` A pytest plugin to treat non-assertion failures as test errors. Jun 18, 2020 N/A pytest (>=5.4.3) :pypi:`pytest-firefox` pytest plugin to manipulate firefox Aug 08, 2017 3 - Alpha pytest (>=3.0.2) :pypi:`pytest-fixture-classes` Fixtures as classes that work well with dependency injection, autocompletetion, type checkers, and language servers Sep 02, 2023 5 - Production/Stable pytest - :pypi:`pytest-fixturecollection` A pytest plugin to collect tests based on fixtures being used by tests Nov 09, 2023 4 - Beta pytest >=3.5.0 + :pypi:`pytest-fixturecollection` A pytest plugin to collect tests based on fixtures being used by tests Feb 22, 2024 4 - Beta pytest >=3.5.0 :pypi:`pytest-fixture-config` Fixture configuration utils for py.test May 28, 2019 5 - Production/Stable pytest :pypi:`pytest-fixture-maker` Pytest plugin to load fixtures from YAML files Sep 21, 2021 N/A N/A :pypi:`pytest-fixture-marker` A pytest plugin to add markers based on fixtures used. Oct 11, 2020 5 - Production/Stable N/A @@ -551,6 +551,7 @@ This list contains 1394 plugins. :pypi:`pytest-gather-fixtures` set up asynchronous pytest fixtures concurrently Apr 12, 2022 N/A pytest (>=6.0.0) :pypi:`pytest-gc` The garbage collector plugin for py.test Feb 01, 2018 N/A N/A :pypi:`pytest-gcov` Uses gcov to measure test coverage of a C library Feb 01, 2018 3 - Alpha N/A + :pypi:`pytest-gcs` GCS fixtures and fixture factories for Pytest. Feb 18, 2024 5 - Production/Stable pytest >=6.2 :pypi:`pytest-gee` The Python plugin for your GEE based packages. Feb 15, 2024 3 - Alpha pytest :pypi:`pytest-gevent` Ensure that gevent is properly patched when invoking pytest Feb 25, 2020 N/A pytest :pypi:`pytest-gherkin` A flexible framework for executing BDD gherkin tests Jul 27, 2019 3 - Alpha pytest (>=5.0.0) @@ -595,7 +596,7 @@ This list contains 1394 plugins. :pypi:`pytest-history` Pytest plugin to keep a history of your pytest runs Jan 14, 2024 N/A pytest (>=7.4.3,<8.0.0) :pypi:`pytest-home` Home directory fixtures Oct 09, 2023 5 - Production/Stable pytest :pypi:`pytest-homeassistant` A pytest plugin for use with homeassistant custom components. Aug 12, 2020 4 - Beta N/A - :pypi:`pytest-homeassistant-custom-component` Experimental package to automatically extract test plugins for Home Assistant custom components Feb 17, 2024 3 - Alpha pytest ==7.4.4 + :pypi:`pytest-homeassistant-custom-component` Experimental package to automatically extract test plugins for Home Assistant custom components Feb 24, 2024 3 - Alpha pytest ==7.4.4 :pypi:`pytest-honey` A simple plugin to use with pytest Jan 07, 2022 4 - Beta pytest (>=3.5.0) :pypi:`pytest-honors` Report on tests that honor constraints, and guard against regressions Mar 06, 2020 4 - Beta N/A :pypi:`pytest-hot-reloading` Jan 06, 2024 N/A N/A @@ -620,7 +621,7 @@ This list contains 1394 plugins. :pypi:`pytest-httpretty` A thin wrapper of HTTPretty for pytest Feb 16, 2014 3 - Alpha N/A :pypi:`pytest_httpserver` pytest-httpserver is a httpserver for pytest Feb 13, 2024 3 - Alpha N/A :pypi:`pytest-httptesting` http_testing framework on top of pytest Jul 24, 2023 N/A pytest (>=7.2.0,<8.0.0) - :pypi:`pytest-httpx` Send responses to httpx. Jan 29, 2024 5 - Production/Stable pytest <9,>=7 + :pypi:`pytest-httpx` Send responses to httpx. Feb 21, 2024 5 - Production/Stable pytest <9,>=7 :pypi:`pytest-httpx-blockage` Disable httpx requests during a test run Feb 16, 2023 N/A pytest (>=7.2.1) :pypi:`pytest-httpx-recorder` Recorder feature based on pytest_httpx, like recorder feature in responses. Jan 04, 2024 5 - Production/Stable pytest :pypi:`pytest-hue` Visualise PyTest status via your Phillips Hue lights May 09, 2019 N/A N/A @@ -646,11 +647,11 @@ This list contains 1394 plugins. :pypi:`pytest-inline` A pytest plugin for writing inline tests. Oct 19, 2023 4 - Beta pytest >=7.0.0 :pypi:`pytest-inmanta` A py.test plugin providing fixtures to simplify inmanta modules testing. Dec 13, 2023 5 - Production/Stable pytest :pypi:`pytest-inmanta-extensions` Inmanta tests package Feb 09, 2024 5 - Production/Stable N/A - :pypi:`pytest-inmanta-lsm` Common fixtures for inmanta LSM related modules Nov 29, 2023 5 - Production/Stable N/A - :pypi:`pytest-inmanta-yang` Common fixtures used in inmanta yang related modules Jun 16, 2022 4 - Beta N/A + :pypi:`pytest-inmanta-lsm` Common fixtures for inmanta LSM related modules Feb 20, 2024 5 - Production/Stable N/A + :pypi:`pytest-inmanta-yang` Common fixtures used in inmanta yang related modules Feb 22, 2024 4 - Beta pytest :pypi:`pytest-Inomaly` A simple image diff plugin for pytest Feb 13, 2018 4 - Beta N/A :pypi:`pytest-insper` Pytest plugin for courses at Insper Feb 01, 2024 N/A pytest - :pypi:`pytest-insta` A practical snapshot testing plugin for pytest Nov 02, 2022 N/A pytest (>=7.2.0,<8.0.0) + :pypi:`pytest-insta` A practical snapshot testing plugin for pytest Feb 19, 2024 N/A pytest (>=7.2.0,<9.0.0) :pypi:`pytest-instafail` pytest plugin to show failures instantly Mar 31, 2023 4 - Beta pytest (>=5) :pypi:`pytest-instrument` pytest plugin to instrument tests Apr 05, 2020 5 - Production/Stable pytest (>=5.1.0) :pypi:`pytest-integration` Organizing pytests by integration or not Nov 17, 2022 N/A N/A @@ -684,7 +685,7 @@ This list contains 1394 plugins. :pypi:`pytest-json-report` A pytest plugin to report test results as JSON files Mar 15, 2022 4 - Beta pytest (>=3.8.0) :pypi:`pytest-json-report-wip` A pytest plugin to report test results as JSON files Oct 28, 2023 4 - Beta pytest >=3.8.0 :pypi:`pytest-jtr` pytest plugin supporting json test report output Nov 29, 2022 N/A pytest (>=7.1.2,<8.0.0) - :pypi:`pytest-jupyter` A pytest plugin for testing Jupyter libraries and extensions. Dec 05, 2023 4 - Beta pytest + :pypi:`pytest-jupyter` A pytest plugin for testing Jupyter libraries and extensions. Feb 21, 2024 4 - Beta pytest :pypi:`pytest-jupyterhub` A reusable JupyterHub pytest plugin Apr 25, 2023 5 - Production/Stable pytest :pypi:`pytest-kafka` Zookeeper, Kafka server, and Kafka consumer fixtures for Pytest Jun 14, 2023 N/A pytest :pypi:`pytest-kafkavents` A plugin to send pytest events to Kafka Sep 08, 2021 4 - Beta pytest @@ -735,7 +736,7 @@ This list contains 1394 plugins. :pypi:`pytest-logbook` py.test plugin to capture logbook log messages Nov 23, 2015 5 - Production/Stable pytest (>=2.8) :pypi:`pytest-logdog` Pytest plugin to test logging Jun 15, 2021 1 - Planning pytest (>=6.2.0) :pypi:`pytest-logfest` Pytest plugin providing three logger fixtures with basic or full writing to log files Jul 21, 2019 4 - Beta pytest (>=3.5.0) - :pypi:`pytest-logger` Plugin configuring handlers for loggers from Python logging module. Feb 12, 2024 5 - Production/Stable pytest (>=3.2) + :pypi:`pytest-logger` Plugin configuring handlers for loggers from Python logging module. Feb 21, 2024 5 - Production/Stable pytest (>=3.2) :pypi:`pytest-logging` Configures logging and allows tweaking the log level with a py.test flag Nov 04, 2015 4 - Beta N/A :pypi:`pytest-logging-end-to-end-test-tool` Sep 23, 2022 N/A pytest (>=7.1.2,<8.0.0) :pypi:`pytest-logikal` Common testing environment Feb 05, 2024 5 - Production/Stable pytest ==8.0.0 @@ -773,7 +774,7 @@ This list contains 1394 plugins. :pypi:`pytest-messenger` Pytest to Slack reporting plugin Nov 24, 2022 5 - Production/Stable N/A :pypi:`pytest-metadata` pytest plugin for test session metadata Feb 12, 2024 5 - Production/Stable pytest>=7.0.0 :pypi:`pytest-metrics` Custom metrics report for pytest Apr 04, 2020 N/A pytest - :pypi:`pytest-mh` Pytest multihost plugin Feb 15, 2024 N/A pytest + :pypi:`pytest-mh` Pytest multihost plugin Feb 21, 2024 N/A pytest :pypi:`pytest-mimesis` Mimesis integration with the pytest test runner Mar 21, 2020 5 - Production/Stable pytest (>=4.2) :pypi:`pytest-minecraft` A pytest plugin for running tests against Minecraft releases Apr 06, 2022 N/A pytest (>=6.0.1) :pypi:`pytest-mini` A plugin to test mp Feb 06, 2023 N/A pytest (>=7.2.0,<8.0.0) @@ -872,7 +873,7 @@ This list contains 1394 plugins. :pypi:`pytest-ordering` pytest plugin to run your tests in a specific order Nov 14, 2018 4 - Beta pytest :pypi:`pytest-order-modify` 新增run_marker 来自定义用例的执行顺序 Nov 04, 2022 N/A N/A :pypi:`pytest-osxnotify` OS X notifications for py.test results. May 15, 2015 N/A N/A - :pypi:`pytest-otel` OpenTelemetry plugin for Pytest Feb 16, 2024 N/A pytest==7.1.3 + :pypi:`pytest-otel` OpenTelemetry plugin for Pytest Feb 19, 2024 N/A pytest==8.0.1 :pypi:`pytest-override-env-var` Pytest mark to override a value of an environment variable. Feb 25, 2023 N/A N/A :pypi:`pytest-owner` Add owner mark for tests Apr 25, 2022 N/A N/A :pypi:`pytest-pact` A simple plugin to use with pytest Jan 07, 2019 4 - Beta N/A @@ -924,6 +925,7 @@ This list contains 1394 plugins. :pypi:`pytest-playwright` A pytest wrapper with fixtures for Playwright to automate web browsers Feb 02, 2024 N/A pytest (<9.0.0,>=6.2.4) :pypi:`pytest-playwright-async` ASYNC Pytest plugin for Playwright Feb 06, 2024 N/A N/A :pypi:`pytest-playwright-asyncio` Aug 29, 2023 N/A N/A + :pypi:`pytest-playwright-enhanced` A pytest plugin for playwright python Feb 24, 2024 N/A pytest (>=8.0.0,<9.0.0) :pypi:`pytest-playwrights` A pytest wrapper with fixtures for Playwright to automate web browsers Dec 02, 2021 N/A N/A :pypi:`pytest-playwright-snapshot` A pytest wrapper for snapshot testing with playwright Aug 19, 2021 N/A N/A :pypi:`pytest-playwright-visual` A pytest fixture for visual testing with Playwright Apr 28, 2022 N/A N/A @@ -986,6 +988,7 @@ This list contains 1394 plugins. :pypi:`pytest-pyspec` A plugin that transforms the pytest output into a result similar to the RSpec. It enables the use of docstrings to display results and also enables the use of the prefixes "describe", "with" and "it". Jan 02, 2024 N/A pytest (>=7.2.1,<8.0.0) :pypi:`pytest-pystack` Plugin to run pystack after a timeout for a test suite. Jan 04, 2024 N/A pytest >=3.5.0 :pypi:`pytest-pytestrail` Pytest plugin for interaction with TestRail Aug 27, 2020 4 - Beta pytest (>=3.8.0) + :pypi:`pytest-pythonhashseed` Pytest plugin to set PYTHONHASHSEED env var. Feb 18, 2024 4 - Beta pytest>=3.0.0 :pypi:`pytest-pythonpath` pytest plugin for adding to the PYTHONPATH from command line or configs. Feb 10, 2022 5 - Production/Stable pytest (<7,>=2.5.2) :pypi:`pytest-pytorch` pytest plugin for a better developer experience when working with the PyTorch test suite May 25, 2021 4 - Beta pytest :pypi:`pytest-pyvista` Pytest-pyvista package Sep 29, 2023 4 - Beta pytest>=3.5.0 @@ -1085,7 +1088,7 @@ This list contains 1394 plugins. :pypi:`pytest-rmsis` Sycronise pytest results to Jira RMsis Aug 10, 2022 N/A pytest (>=5.3.5) :pypi:`pytest-rng` Fixtures for seeding tests and making randomness reproducible Aug 08, 2019 5 - Production/Stable pytest :pypi:`pytest-roast` pytest plugin for ROAST configuration override and fixtures Nov 09, 2022 5 - Production/Stable pytest - :pypi:`pytest_robotframework` a pytest plugin that can run both python and robotframework tests while generating robot reports for them Feb 08, 2024 N/A pytest<9,>=7 + :pypi:`pytest_robotframework` a pytest plugin that can run both python and robotframework tests while generating robot reports for them Feb 22, 2024 N/A pytest<9,>=7 :pypi:`pytest-rocketchat` Pytest to Rocket.Chat reporting plugin Apr 18, 2021 5 - Production/Stable N/A :pypi:`pytest-rotest` Pytest integration with rotest Sep 08, 2019 N/A pytest (>=3.5.0) :pypi:`pytest-rpc` Extend py.test for RPC OpenStack testing. Feb 22, 2019 4 - Beta pytest (~=3.6) @@ -1109,7 +1112,7 @@ This list contains 1394 plugins. :pypi:`pytest-sanity` Dec 07, 2020 N/A N/A :pypi:`pytest-sa-pg` May 14, 2019 N/A N/A :pypi:`pytest_sauce` pytest_sauce provides sane and helpful methods worked out in clearcode to run py.test tests with selenium/saucelabs Jul 14, 2014 3 - Alpha N/A - :pypi:`pytest-sbase` A complete web automation framework for end-to-end testing. Feb 17, 2024 5 - Production/Stable N/A + :pypi:`pytest-sbase` A complete web automation framework for end-to-end testing. Feb 23, 2024 5 - Production/Stable N/A :pypi:`pytest-scenario` pytest plugin for test scenarios Feb 06, 2017 3 - Alpha N/A :pypi:`pytest-schedule` The job of test scheduling for humans. Jan 07, 2023 5 - Production/Stable N/A :pypi:`pytest-schema` 👍 Validate return values against a schema-like object in testing Feb 16, 2024 5 - Production/Stable pytest >=3.5.0 @@ -1118,7 +1121,7 @@ This list contains 1394 plugins. :pypi:`pytest-select` A pytest plugin which allows to (de-)select tests from a file. Jan 18, 2019 3 - Alpha pytest (>=3.0) :pypi:`pytest-selenium` pytest plugin for Selenium Feb 01, 2024 5 - Production/Stable pytest>=6.0.0 :pypi:`pytest-selenium-auto` pytest plugin to automatically capture screenshots upon selenium webdriver events Nov 07, 2023 N/A pytest >= 7.0.0 - :pypi:`pytest-seleniumbase` A complete web automation framework for end-to-end testing. Feb 17, 2024 5 - Production/Stable N/A + :pypi:`pytest-seleniumbase` A complete web automation framework for end-to-end testing. Feb 23, 2024 5 - Production/Stable N/A :pypi:`pytest-selenium-enhancer` pytest plugin for Selenium Apr 29, 2022 5 - Production/Stable N/A :pypi:`pytest-selenium-pdiff` A pytest package implementing perceptualdiff for Selenium tests. Apr 06, 2017 2 - Pre-Alpha N/A :pypi:`pytest-send-email` Send pytest execution result email Dec 04, 2019 N/A N/A @@ -1137,7 +1140,7 @@ This list contains 1394 plugins. :pypi:`pytest-share-hdf` Plugin to save test data in HDF files and retrieve them for comparison Sep 21, 2022 4 - Beta pytest (>=3.5.0) :pypi:`pytest-sharkreport` this is pytest report plugin. Jul 11, 2022 N/A pytest (>=3.5) :pypi:`pytest-shell` A pytest plugin to help with testing shell scripts / black box commands Mar 27, 2022 N/A N/A - :pypi:`pytest-shell-utilities` Pytest plugin to simplify running shell commands against the system Jul 02, 2023 5 - Production/Stable pytest (>=7.1.0) + :pypi:`pytest-shell-utilities` Pytest plugin to simplify running shell commands against the system Feb 23, 2024 5 - Production/Stable pytest >=7.4.0 :pypi:`pytest-sheraf` Versatile ZODB abstraction layer - pytest fixtures Feb 11, 2020 N/A pytest :pypi:`pytest-sherlock` pytest plugin help to find coupled tests Aug 14, 2023 5 - Production/Stable pytest >=3.5.1 :pypi:`pytest-shortcuts` Expand command-line shortcuts listed in pytest configuration Oct 29, 2020 4 - Beta pytest (>=3.5.0) @@ -1193,7 +1196,7 @@ This list contains 1394 plugins. :pypi:`pytest-split-tests` A Pytest plugin for running a subset of your tests by splitting them in to equally sized groups. Forked from Mark Adams' original project pytest-test-groups. Jul 30, 2021 5 - Production/Stable pytest (>=2.5) :pypi:`pytest-split-tests-tresorit` Feb 22, 2021 1 - Planning N/A :pypi:`pytest-splunk-addon` A Dynamic test tool for Splunk Apps and Add-ons Jan 12, 2024 N/A pytest (>5.4.0,<8) - :pypi:`pytest-splunk-addon-ui-smartx` Library to support testing Splunk Add-on UX Feb 13, 2024 N/A N/A + :pypi:`pytest-splunk-addon-ui-smartx` Library to support testing Splunk Add-on UX Feb 23, 2024 N/A N/A :pypi:`pytest-splunk-env` pytest fixtures for interaction with Splunk Enterprise and Splunk Cloud Oct 22, 2020 N/A pytest (>=6.1.1,<7.0.0) :pypi:`pytest-sqitch` sqitch for pytest Apr 06, 2020 4 - Beta N/A :pypi:`pytest-sqlalchemy` pytest plugin with sqlalchemy related fixtures Mar 13, 2018 3 - Alpha N/A @@ -1205,7 +1208,7 @@ This list contains 1394 plugins. :pypi:`pytest-srcpaths` Add paths to sys.path Oct 15, 2021 N/A pytest>=6.2.0 :pypi:`pytest-ssh` pytest plugin for ssh command run May 27, 2019 N/A pytest :pypi:`pytest-start-from` Start pytest run from a given point Apr 11, 2016 N/A N/A - :pypi:`pytest-star-track-issue` A package to prevent Dependency Confusion attacks against Yandex. Feb 10, 2023 N/A N/A + :pypi:`pytest-star-track-issue` A package to prevent Dependency Confusion attacks against Yandex. Feb 20, 2024 N/A N/A :pypi:`pytest-static` pytest-static Jan 15, 2024 1 - Planning pytest (>=7.4.3,<8.0.0) :pypi:`pytest-statsd` pytest plugin for reporting to graphite Nov 30, 2018 5 - Production/Stable pytest (>=3.0.0) :pypi:`pytest-stepfunctions` A small description May 08, 2021 4 - Beta pytest @@ -1408,7 +1411,7 @@ This list contains 1394 plugins. :pypi:`pytest-xray` May 30, 2019 3 - Alpha N/A :pypi:`pytest-xrayjira` Mar 17, 2020 3 - Alpha pytest (==4.3.1) :pypi:`pytest-xray-server` May 03, 2022 3 - Alpha pytest (>=5.3.1) - :pypi:`pytest-xskynet` A package to prevent Dependency Confusion attacks against Yandex. Feb 10, 2023 N/A N/A + :pypi:`pytest-xskynet` A package to prevent Dependency Confusion attacks against Yandex. Feb 20, 2024 N/A N/A :pypi:`pytest-xvfb` A pytest plugin to run Xvfb (or Xephyr/Xvnc) for tests. May 29, 2023 4 - Beta pytest (>=2.8.1) :pypi:`pytest-xvirt` A pytest plugin to virtualize test. For example to transparently running them on a remote box. Oct 01, 2023 4 - Beta pytest >=7.1.0 :pypi:`pytest-yaml` This plugin is used to load yaml output to your test using pytest framework. Oct 05, 2018 N/A pytest @@ -1441,7 +1444,7 @@ This list contains 1394 plugins. Simple but powerful assertion and verification of logged lines. :pypi:`logot` - *last release*: Feb 17, 2024, + *last release*: Feb 19, 2024, *status*: 5 - Production/Stable, *requires*: pytest (>=7,<9) ; extra == "pytest" @@ -1672,9 +1675,9 @@ This list contains 1394 plugins. Static code checks used at Alphamoon :pypi:`pytest-analyzer` - *last release*: Feb 12, 2024, + *last release*: Feb 21, 2024, *status*: N/A, - *requires*: pytest >=7.3.1 + *requires*: pytest <8.0.0,>=7.3.1 this plugin allows to analyze tests in pytest project, collect test metadata and sync it with testomat.io TCM system @@ -2162,7 +2165,7 @@ This list contains 1394 plugins. BDD for pytest :pypi:`pytest-bdd-report` - *last release*: Nov 15, 2023, + *last release*: Feb 19, 2024, *status*: N/A, *requires*: pytest >=7.1.3 @@ -2217,13 +2220,6 @@ This list contains 1394 plugins. use icdiff for better error messages in pytest assertions - :pypi:`pytest-behave` - *last release*: Feb 15, 2024, - *status*: N/A, - *requires*: N/A - - A powerful test automation framework designed to provide a comprehensive solution for testing user interfaces and APIs - :pypi:`pytest-bench` *last release*: Jul 21, 2014, *status*: 3 - Alpha, @@ -2680,7 +2676,7 @@ This list contains 1394 plugins. pytest plugin to test Check_MK checks :pypi:`pytest-check-requirements` - *last release*: Feb 10, 2023, + *last release*: Feb 20, 2024, *status*: N/A, *requires*: N/A @@ -3240,9 +3236,9 @@ This list contains 1394 plugins. :pypi:`pytest-darker` - *last release*: Aug 16, 2020, + *last release*: Feb 24, 2024, *status*: N/A, - *requires*: pytest (>=6.0.1) ; extra == 'test' + *requires*: pytest <8,>=6.0.1 A pytest plugin for checking of modified code using Darker @@ -3555,7 +3551,7 @@ This list contains 1394 plugins. A simple plugin to use with pytest :pypi:`pytest-diffeo` - *last release*: Feb 10, 2023, + *last release*: Feb 20, 2024, *status*: N/A, *requires*: N/A @@ -4157,56 +4153,56 @@ This list contains 1394 plugins. Send execution result email :pypi:`pytest-embedded` - *last release*: Feb 14, 2024, + *last release*: Feb 23, 2024, *status*: 5 - Production/Stable, *requires*: pytest>=7.0 A pytest plugin that designed for embedded testing. :pypi:`pytest-embedded-arduino` - *last release*: Feb 14, 2024, + *last release*: Feb 23, 2024, *status*: 5 - Production/Stable, *requires*: N/A Make pytest-embedded plugin work with Arduino. :pypi:`pytest-embedded-idf` - *last release*: Feb 14, 2024, + *last release*: Feb 23, 2024, *status*: 5 - Production/Stable, *requires*: N/A Make pytest-embedded plugin work with ESP-IDF. :pypi:`pytest-embedded-jtag` - *last release*: Feb 14, 2024, + *last release*: Feb 23, 2024, *status*: 5 - Production/Stable, *requires*: N/A Make pytest-embedded plugin work with JTAG. :pypi:`pytest-embedded-qemu` - *last release*: Feb 14, 2024, + *last release*: Feb 23, 2024, *status*: 5 - Production/Stable, *requires*: N/A Make pytest-embedded plugin work with QEMU. :pypi:`pytest-embedded-serial` - *last release*: Feb 14, 2024, + *last release*: Feb 23, 2024, *status*: 5 - Production/Stable, *requires*: N/A Make pytest-embedded plugin work with Serial. :pypi:`pytest-embedded-serial-esp` - *last release*: Feb 14, 2024, + *last release*: Feb 23, 2024, *status*: 5 - Production/Stable, *requires*: N/A Make pytest-embedded plugin work with Espressif target boards. :pypi:`pytest-embedded-wokwi` - *last release*: Feb 14, 2024, + *last release*: Feb 23, 2024, *status*: 5 - Production/Stable, *requires*: N/A @@ -4429,6 +4425,13 @@ This list contains 1394 plugins. A timer for the phases of Pytest's execution. + :pypi:`pytest-exit-code` + *last release*: Feb 23, 2024, + *status*: 4 - Beta, + *requires*: pytest >=6.2.0 + + A pytest plugin that overrides the built-in exit codes to retain more information about the test results. + :pypi:`pytest-expect` *last release*: Apr 21, 2016, *status*: 4 - Beta, @@ -4535,7 +4538,7 @@ This list contains 1394 plugins. Provides test utilities to run fabric task tests by using docker containers :pypi:`pytest-factor` - *last release*: Feb 10, 2023, + *last release*: Feb 20, 2024, *status*: N/A, *requires*: N/A @@ -4612,11 +4615,11 @@ This list contains 1394 plugins. Pytest helpers for Falcon. :pypi:`pytest-falcon-client` - *last release*: Mar 19, 2019, + *last release*: Feb 21, 2024, *status*: N/A, *requires*: N/A - Pytest \`client\` fixture for the Falcon Framework + A package to prevent Dependency Confusion attacks against Yandex. :pypi:`pytest-fantasy` *last release*: Mar 14, 2019, @@ -4745,7 +4748,7 @@ This list contains 1394 plugins. Fixtures as classes that work well with dependency injection, autocompletetion, type checkers, and language servers :pypi:`pytest-fixturecollection` - *last release*: Nov 09, 2023, + *last release*: Feb 22, 2024, *status*: 4 - Beta, *requires*: pytest >=3.5.0 @@ -5052,6 +5055,13 @@ This list contains 1394 plugins. Uses gcov to measure test coverage of a C library + :pypi:`pytest-gcs` + *last release*: Feb 18, 2024, + *status*: 5 - Production/Stable, + *requires*: pytest >=6.2 + + GCS fixtures and fixture factories for Pytest. + :pypi:`pytest-gee` *last release*: Feb 15, 2024, *status*: 3 - Alpha, @@ -5361,7 +5371,7 @@ This list contains 1394 plugins. A pytest plugin for use with homeassistant custom components. :pypi:`pytest-homeassistant-custom-component` - *last release*: Feb 17, 2024, + *last release*: Feb 24, 2024, *status*: 3 - Alpha, *requires*: pytest ==7.4.4 @@ -5536,7 +5546,7 @@ This list contains 1394 plugins. http_testing framework on top of pytest :pypi:`pytest-httpx` - *last release*: Jan 29, 2024, + *last release*: Feb 21, 2024, *status*: 5 - Production/Stable, *requires*: pytest <9,>=7 @@ -5718,16 +5728,16 @@ This list contains 1394 plugins. Inmanta tests package :pypi:`pytest-inmanta-lsm` - *last release*: Nov 29, 2023, + *last release*: Feb 20, 2024, *status*: 5 - Production/Stable, *requires*: N/A Common fixtures for inmanta LSM related modules :pypi:`pytest-inmanta-yang` - *last release*: Jun 16, 2022, + *last release*: Feb 22, 2024, *status*: 4 - Beta, - *requires*: N/A + *requires*: pytest Common fixtures used in inmanta yang related modules @@ -5746,9 +5756,9 @@ This list contains 1394 plugins. Pytest plugin for courses at Insper :pypi:`pytest-insta` - *last release*: Nov 02, 2022, + *last release*: Feb 19, 2024, *status*: N/A, - *requires*: pytest (>=7.2.0,<8.0.0) + *requires*: pytest (>=7.2.0,<9.0.0) A practical snapshot testing plugin for pytest @@ -5984,7 +5994,7 @@ This list contains 1394 plugins. pytest plugin supporting json test report output :pypi:`pytest-jupyter` - *last release*: Dec 05, 2023, + *last release*: Feb 21, 2024, *status*: 4 - Beta, *requires*: pytest @@ -6341,7 +6351,7 @@ This list contains 1394 plugins. Pytest plugin providing three logger fixtures with basic or full writing to log files :pypi:`pytest-logger` - *last release*: Feb 12, 2024, + *last release*: Feb 21, 2024, *status*: 5 - Production/Stable, *requires*: pytest (>=3.2) @@ -6607,7 +6617,7 @@ This list contains 1394 plugins. Custom metrics report for pytest :pypi:`pytest-mh` - *last release*: Feb 15, 2024, + *last release*: Feb 21, 2024, *status*: N/A, *requires*: pytest @@ -7300,9 +7310,9 @@ This list contains 1394 plugins. OS X notifications for py.test results. :pypi:`pytest-otel` - *last release*: Feb 16, 2024, + *last release*: Feb 19, 2024, *status*: N/A, - *requires*: pytest==7.1.3 + *requires*: pytest==8.0.1 OpenTelemetry plugin for Pytest @@ -7663,6 +7673,13 @@ This list contains 1394 plugins. + :pypi:`pytest-playwright-enhanced` + *last release*: Feb 24, 2024, + *status*: N/A, + *requires*: pytest (>=8.0.0,<9.0.0) + + A pytest plugin for playwright python + :pypi:`pytest-playwrights` *last release*: Dec 02, 2021, *status*: N/A, @@ -8097,6 +8114,13 @@ This list contains 1394 plugins. Pytest plugin for interaction with TestRail + :pypi:`pytest-pythonhashseed` + *last release*: Feb 18, 2024, + *status*: 4 - Beta, + *requires*: pytest>=3.0.0 + + Pytest plugin to set PYTHONHASHSEED env var. + :pypi:`pytest-pythonpath` *last release*: Feb 10, 2022, *status*: 5 - Production/Stable, @@ -8791,7 +8815,7 @@ This list contains 1394 plugins. pytest plugin for ROAST configuration override and fixtures :pypi:`pytest_robotframework` - *last release*: Feb 08, 2024, + *last release*: Feb 22, 2024, *status*: N/A, *requires*: pytest<9,>=7 @@ -8959,7 +8983,7 @@ This list contains 1394 plugins. pytest_sauce provides sane and helpful methods worked out in clearcode to run py.test tests with selenium/saucelabs :pypi:`pytest-sbase` - *last release*: Feb 17, 2024, + *last release*: Feb 23, 2024, *status*: 5 - Production/Stable, *requires*: N/A @@ -9022,7 +9046,7 @@ This list contains 1394 plugins. pytest plugin to automatically capture screenshots upon selenium webdriver events :pypi:`pytest-seleniumbase` - *last release*: Feb 17, 2024, + *last release*: Feb 23, 2024, *status*: 5 - Production/Stable, *requires*: N/A @@ -9155,9 +9179,9 @@ This list contains 1394 plugins. A pytest plugin to help with testing shell scripts / black box commands :pypi:`pytest-shell-utilities` - *last release*: Jul 02, 2023, + *last release*: Feb 23, 2024, *status*: 5 - Production/Stable, - *requires*: pytest (>=7.1.0) + *requires*: pytest >=7.4.0 Pytest plugin to simplify running shell commands against the system @@ -9547,7 +9571,7 @@ This list contains 1394 plugins. A Dynamic test tool for Splunk Apps and Add-ons :pypi:`pytest-splunk-addon-ui-smartx` - *last release*: Feb 13, 2024, + *last release*: Feb 23, 2024, *status*: N/A, *requires*: N/A @@ -9631,7 +9655,7 @@ This list contains 1394 plugins. Start pytest run from a given point :pypi:`pytest-star-track-issue` - *last release*: Feb 10, 2023, + *last release*: Feb 20, 2024, *status*: N/A, *requires*: N/A @@ -11052,7 +11076,7 @@ This list contains 1394 plugins. :pypi:`pytest-xskynet` - *last release*: Feb 10, 2023, + *last release*: Feb 20, 2024, *status*: N/A, *requires*: N/A diff --git a/doc/en/reference/reference.rst b/doc/en/reference/reference.rst index 1076026c2..bba4a399c 100644 --- a/doc/en/reference/reference.rst +++ b/doc/en/reference/reference.rst @@ -1865,6 +1865,19 @@ passed multiple times. The expected format is ``name=value``. For example:: "auto" can be used to explicitly use the global verbosity level. +.. confval:: verbosity_test_cases + + Set a verbosity level specifically for test case execution related output, overriding the application wide level. + + .. code-block:: ini + + [pytest] + verbosity_test_cases = 2 + + Defaults to application wide verbosity level (via the ``-v`` command-line option). A special value of + "auto" can be used to explicitly use the global verbosity level. + + .. confval:: xfail_strict If set to ``True``, tests marked with ``@pytest.mark.xfail`` that actually succeed will by default fail the diff --git a/scripts/update-plugin-list.py b/scripts/update-plugin-list.py index 6226bc8c9..6831fc984 100644 --- a/scripts/update-plugin-list.py +++ b/scripts/update-plugin-list.py @@ -29,7 +29,7 @@ Pytest Plugin List ================== Below is an automated compilation of ``pytest``` plugins available on `PyPI `_. -It includes PyPI projects whose names begin with "pytest-" or "pytest_" and a handful of manually selected projects. +It includes PyPI projects whose names begin with ``pytest-`` or ``pytest_`` and a handful of manually selected projects. Packages classified as inactive are excluded. For detailed insights into how this list is generated, diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index f8eea936a..069e2196d 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -1657,6 +1657,8 @@ class Config: #: Verbosity type for failed assertions (see :confval:`verbosity_assertions`). VERBOSITY_ASSERTIONS: Final = "assertions" + #: Verbosity type for test case execution (see :confval:`verbosity_test_cases`). + VERBOSITY_TEST_CASES: Final = "test_cases" _VERBOSITY_INI_DEFAULT: Final = "auto" def get_verbosity(self, verbosity_type: Optional[str] = None) -> int: diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index 43f36817f..f724af6ba 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -2,7 +2,6 @@ import abc from collections import defaultdict from collections import deque -from contextlib import suppress import dataclasses import functools import inspect @@ -414,9 +413,7 @@ class FixtureRequest(abc.ABC): # We arrive here because of a dynamic call to # getfixturevalue(argname) usage which was naturally # not known at parsing/collection time. - parent = self._pyfuncitem.parent - assert parent is not None - fixturedefs = self._fixturemanager.getfixturedefs(argname, parent) + fixturedefs = self._fixturemanager.getfixturedefs(argname, self._pyfuncitem) if fixturedefs is not None: self._arg2fixturedefs[argname] = fixturedefs # No fixtures defined with this name. @@ -579,7 +576,6 @@ class FixtureRequest(abc.ABC): # (latter managed by fixturedef) argname = fixturedef.argname funcitem = self._pyfuncitem - scope = fixturedef._scope try: callspec = funcitem.callspec except AttributeError: @@ -587,13 +583,13 @@ class FixtureRequest(abc.ABC): if callspec is not None and argname in callspec.params: param = callspec.params[argname] param_index = callspec.indices[argname] - # If a parametrize invocation set a scope it will override - # the static scope defined with the fixture function. - with suppress(KeyError): - scope = callspec._arg2scope[argname] + # The parametrize invocation scope overrides the fixture's scope. + scope = callspec._arg2scope[argname] else: param = NOTSET param_index = 0 + scope = fixturedef._scope + has_params = fixturedef.params is not None fixtures_not_supported = getattr(funcitem, "nofuncargs", False) if has_params and fixtures_not_supported: diff --git a/src/_pytest/main.py b/src/_pytest/main.py index 639bf26c1..b7ed72ddc 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -5,6 +5,7 @@ import dataclasses import fnmatch import functools import importlib +import importlib.util import os from pathlib import Path import sys @@ -563,7 +564,7 @@ class Session(nodes.Collector): self._initialpaths: FrozenSet[Path] = frozenset() self._initialpaths_with_parents: FrozenSet[Path] = frozenset() self._notfound: List[Tuple[str, Sequence[nodes.Collector]]] = [] - self._initial_parts: List[Tuple[Path, List[str]]] = [] + self._initial_parts: List[CollectionArgument] = [] self._collection_cache: Dict[nodes.Collector, CollectReport] = {} self.items: List[nodes.Item] = [] @@ -769,15 +770,15 @@ class Session(nodes.Collector): initialpaths: List[Path] = [] initialpaths_with_parents: List[Path] = [] for arg in args: - fspath, parts = resolve_collection_argument( + collection_argument = resolve_collection_argument( self.config.invocation_params.dir, arg, as_pypath=self.config.option.pyargs, ) - self._initial_parts.append((fspath, parts)) - initialpaths.append(fspath) - initialpaths_with_parents.append(fspath) - initialpaths_with_parents.extend(fspath.parents) + self._initial_parts.append(collection_argument) + initialpaths.append(collection_argument.path) + initialpaths_with_parents.append(collection_argument.path) + initialpaths_with_parents.extend(collection_argument.path.parents) self._initialpaths = frozenset(initialpaths) self._initialpaths_with_parents = frozenset(initialpaths_with_parents) @@ -839,21 +840,35 @@ class Session(nodes.Collector): pm = self.config.pluginmanager - for argpath, names in self._initial_parts: - self.trace("processing argument", (argpath, names)) + for collection_argument in self._initial_parts: + self.trace("processing argument", collection_argument) self.trace.root.indent += 1 + argpath = collection_argument.path + names = collection_argument.parts + module_name = collection_argument.module_name + # resolve_collection_argument() ensures this. if argpath.is_dir(): assert not names, f"invalid arg {(argpath, names)!r}" - # Match the argpath from the root, e.g. + paths = [argpath] + # Add relevant parents of the path, from the root, e.g. # /a/b/c.py -> [/, /a, /a/b, /a/b/c.py] - paths = [*reversed(argpath.parents), argpath] - # Paths outside of the confcutdir should not be considered, unless - # it's the argpath itself. - while len(paths) > 1 and not pm._is_in_confcutdir(paths[0]): - paths = paths[1:] + if module_name is None: + # Paths outside of the confcutdir should not be considered. + for path in argpath.parents: + if not pm._is_in_confcutdir(path): + break + paths.insert(0, path) + else: + # For --pyargs arguments, only consider paths matching the module + # name. Paths beyond the package hierarchy are not included. + module_name_parts = module_name.split(".") + for i, path in enumerate(argpath.parents, 2): + if i > len(module_name_parts) or path.stem != module_name_parts[-i]: + break + paths.insert(0, path) # Start going over the parts from the root, collecting each level # and discarding all nodes which don't match the level's part. @@ -861,7 +876,7 @@ class Session(nodes.Collector): notfound_collectors = [] work: List[ Tuple[Union[nodes.Collector, nodes.Item], List[Union[Path, str]]] - ] = [(self, paths + names)] + ] = [(self, [*paths, *names])] while work: matchnode, matchparts = work.pop() @@ -953,26 +968,36 @@ class Session(nodes.Collector): node.ihook.pytest_collectreport(report=rep) -def search_pypath(module_name: str) -> str: - """Search sys.path for the given a dotted module name, and return its file system path.""" +def search_pypath(module_name: str) -> Optional[str]: + """Search sys.path for the given a dotted module name, and return its file + system path if found.""" try: spec = importlib.util.find_spec(module_name) # AttributeError: looks like package module, but actually filename # ImportError: module does not exist # ValueError: not a module name except (AttributeError, ImportError, ValueError): - return module_name + return None if spec is None or spec.origin is None or spec.origin == "namespace": - return module_name + return None elif spec.submodule_search_locations: return os.path.dirname(spec.origin) else: return spec.origin +@dataclasses.dataclass(frozen=True) +class CollectionArgument: + """A resolved collection argument.""" + + path: Path + parts: Sequence[str] + module_name: Optional[str] + + def resolve_collection_argument( invocation_path: Path, arg: str, *, as_pypath: bool = False -) -> Tuple[Path, List[str]]: +) -> CollectionArgument: """Parse path arguments optionally containing selection parts and return (fspath, names). Command-line arguments can point to files and/or directories, and optionally contain @@ -980,9 +1005,13 @@ def resolve_collection_argument( "pkg/tests/test_foo.py::TestClass::test_foo" - This function ensures the path exists, and returns a tuple: + This function ensures the path exists, and returns a resolved `CollectionArgument`: - (Path("/full/path/to/pkg/tests/test_foo.py"), ["TestClass", "test_foo"]) + CollectionArgument( + path=Path("/full/path/to/pkg/tests/test_foo.py"), + parts=["TestClass", "test_foo"], + module_name=None, + ) When as_pypath is True, expects that the command-line argument actually contains module paths instead of file-system paths: @@ -990,7 +1019,13 @@ def resolve_collection_argument( "pkg.tests.test_foo::TestClass::test_foo" In which case we search sys.path for a matching module, and then return the *path* to the - found module. + found module, which may look like this: + + CollectionArgument( + path=Path("/home/u/myvenv/lib/site-packages/pkg/tests/test_foo.py"), + parts=["TestClass", "test_foo"], + module_name="pkg.tests.test_foo", + ) If the path doesn't exist, raise UsageError. If the path is a directory and selection parts are present, raise UsageError. @@ -999,8 +1034,12 @@ def resolve_collection_argument( strpath, *parts = base.split("::") if parts: parts[-1] = f"{parts[-1]}{squacket}{rest}" + module_name = None if as_pypath: - strpath = search_pypath(strpath) + pyarg_strpath = search_pypath(strpath) + if pyarg_strpath is not None: + module_name = strpath + strpath = pyarg_strpath fspath = invocation_path / strpath fspath = absolutepath(fspath) if not safe_exists(fspath): @@ -1017,4 +1056,8 @@ def resolve_collection_argument( else "directory argument cannot contain :: selection parts: {arg}" ) raise UsageError(msg.format(arg=arg)) - return fspath, parts + return CollectionArgument( + path=fspath, + parts=parts, + module_name=module_name, + ) diff --git a/src/_pytest/runner.py b/src/_pytest/runner.py index d25fdb738..b60af9dd3 100644 --- a/src/_pytest/runner.py +++ b/src/_pytest/runner.py @@ -132,10 +132,6 @@ def runtestprotocol( show_test_item(item) if not item.config.getoption("setuponly", False): reports.append(call_and_report(item, "call", log)) - # If the session is about to fail or stop, teardown everything - this is - # necessary to correctly report fixture teardown errors (see #11706) - if item.session.shouldfail or item.session.shouldstop: - nextitem = None reports.append(call_and_report(item, "teardown", log, nextitem=nextitem)) # After all teardown hooks have been called # want funcargs and request info to go away. @@ -168,6 +164,8 @@ def pytest_runtest_call(item: Item) -> None: del sys.last_type del sys.last_value del sys.last_traceback + if sys.version_info >= (3, 12, 0): + del sys.last_exc # type: ignore[attr-defined] except AttributeError: pass try: @@ -176,6 +174,8 @@ def pytest_runtest_call(item: Item) -> None: # Store trace info to allow postmortem debugging sys.last_type = type(e) sys.last_value = e + if sys.version_info >= (3, 12, 0): + sys.last_exc = e # type: ignore[attr-defined] assert e.__traceback__ is not None # Skip *this* frame sys.last_traceback = e.__traceback__.tb_next diff --git a/src/_pytest/terminal.py b/src/_pytest/terminal.py index 8909d95ef..75d57197a 100644 --- a/src/_pytest/terminal.py +++ b/src/_pytest/terminal.py @@ -255,6 +255,14 @@ def pytest_addoption(parser: Parser) -> None: "progress even when capture=no)", default="progress", ) + Config._add_verbosity_ini( + parser, + Config.VERBOSITY_TEST_CASES, + help=( + "Specify a verbosity level for test case execution, overriding the main level. " + "Higher levels will provide more detailed information about each test case executed." + ), + ) def pytest_configure(config: Config) -> None: @@ -408,7 +416,7 @@ class TerminalReporter: @property def showfspath(self) -> bool: if self._showfspath is None: - return self.verbosity >= 0 + return self.config.get_verbosity(Config.VERBOSITY_TEST_CASES) >= 0 return self._showfspath @showfspath.setter @@ -417,7 +425,7 @@ class TerminalReporter: @property def showlongtestinfo(self) -> bool: - return self.verbosity > 0 + return self.config.get_verbosity(Config.VERBOSITY_TEST_CASES) > 0 def hasopt(self, char: str) -> bool: char = {"xfailed": "x", "skipped": "s"}.get(char, char) @@ -595,7 +603,7 @@ class TerminalReporter: markup = {"yellow": True} else: markup = {} - if self.verbosity <= 0: + if self.config.get_verbosity(Config.VERBOSITY_TEST_CASES) <= 0: self._tw.write(letter, **markup) else: self._progress_nodeids_reported.add(rep.nodeid) @@ -604,7 +612,7 @@ class TerminalReporter: self.write_ensure_prefix(line, word, **markup) if rep.skipped or hasattr(report, "wasxfail"): reason = _get_raw_skip_reason(rep) - if self.config.option.verbose < 2: + if self.config.get_verbosity(Config.VERBOSITY_TEST_CASES) < 2: available_width = ( (self._tw.fullwidth - self._tw.width_of_current_line) - len(" [100%]") @@ -641,7 +649,10 @@ class TerminalReporter: def pytest_runtest_logfinish(self, nodeid: str) -> None: assert self._session - if self.verbosity <= 0 and self._show_progress_info: + if ( + self.config.get_verbosity(Config.VERBOSITY_TEST_CASES) <= 0 + and self._show_progress_info + ): if self._show_progress_info == "count": num_tests = self._session.testscollected progress_length = len(f" [{num_tests}/{num_tests}]") @@ -819,8 +830,9 @@ class TerminalReporter: rep.toterminal(self._tw) def _printcollecteditems(self, items: Sequence[Item]) -> None: - if self.config.option.verbose < 0: - if self.config.option.verbose < -1: + test_cases_verbosity = self.config.get_verbosity(Config.VERBOSITY_TEST_CASES) + if test_cases_verbosity < 0: + if test_cases_verbosity < -1: counts = Counter(item.nodeid.split("::", 1)[0] for item in items) for name, count in sorted(counts.items()): self._tw.line("%s: %d" % (name, count)) @@ -840,7 +852,7 @@ class TerminalReporter: stack.append(col) indent = (len(stack) - 1) * " " self._tw.line(f"{indent}{col}") - if self.config.option.verbose >= 1: + if test_cases_verbosity >= 1: obj = getattr(col, "obj", None) doc = inspect.getdoc(obj) if obj else None if doc: diff --git a/testing/plugins_integration/requirements.txt b/testing/plugins_integration/requirements.txt index 61c423ce6..42ab2af99 100644 --- a/testing/plugins_integration/requirements.txt +++ b/testing/plugins_integration/requirements.txt @@ -1,4 +1,4 @@ -anyio[curio,trio]==4.2.0 +anyio[curio,trio]==4.3.0 django==5.0.2 pytest-asyncio==0.23.5 # Temporarily not installed until pytest-bdd is fixed: diff --git a/testing/test_collection.py b/testing/test_collection.py index 050740045..fbc8543e9 100644 --- a/testing/test_collection.py +++ b/testing/test_collection.py @@ -1787,3 +1787,48 @@ def test_collect_short_file_windows(pytester: Pytester) -> None: test_file.write_text("def test(): pass", encoding="UTF-8") result = pytester.runpytest(short_path) assert result.parseoutcomes() == {"passed": 1} + + +def test_pyargs_collection_tree(pytester: Pytester, monkeypatch: MonkeyPatch) -> None: + """When using `--pyargs`, the collection tree of a pyargs collection + argument should only include parents in the import path, not up to confcutdir. + + Regression test for #11904. + """ + site_packages = pytester.path / "venv/lib/site-packages" + site_packages.mkdir(parents=True) + monkeypatch.syspath_prepend(site_packages) + pytester.makepyfile( + **{ + "venv/lib/site-packages/pkg/__init__.py": "", + "venv/lib/site-packages/pkg/sub/__init__.py": "", + "venv/lib/site-packages/pkg/sub/test_it.py": "def test(): pass", + } + ) + + result = pytester.runpytest("--pyargs", "--collect-only", "pkg.sub.test_it") + assert result.ret == ExitCode.OK + result.stdout.fnmatch_lines( + [ + "", + " ", + " ", + " ", + ], + consecutive=True, + ) + + # Now with an unrelated rootdir with unrelated files. + monkeypatch.chdir(tempfile.gettempdir()) + + result = pytester.runpytest("--pyargs", "--collect-only", "pkg.sub.test_it") + assert result.ret == ExitCode.OK + result.stdout.fnmatch_lines( + [ + "", + " ", + " ", + " ", + ], + consecutive=True, + ) diff --git a/testing/test_main.py b/testing/test_main.py index d92fa21d3..345aa1e62 100644 --- a/testing/test_main.py +++ b/testing/test_main.py @@ -8,6 +8,7 @@ from typing import Optional from _pytest.config import ExitCode from _pytest.config import UsageError +from _pytest.main import CollectionArgument from _pytest.main import resolve_collection_argument from _pytest.main import validate_basetemp from _pytest.pytester import Pytester @@ -133,26 +134,43 @@ class TestResolveCollectionArgument: def test_file(self, invocation_path: Path) -> None: """File and parts.""" - assert resolve_collection_argument(invocation_path, "src/pkg/test.py") == ( - invocation_path / "src/pkg/test.py", - [], + assert resolve_collection_argument( + invocation_path, "src/pkg/test.py" + ) == CollectionArgument( + path=invocation_path / "src/pkg/test.py", + parts=[], + module_name=None, ) - assert resolve_collection_argument(invocation_path, "src/pkg/test.py::") == ( - invocation_path / "src/pkg/test.py", - [""], + assert resolve_collection_argument( + invocation_path, "src/pkg/test.py::" + ) == CollectionArgument( + path=invocation_path / "src/pkg/test.py", + parts=[""], + module_name=None, ) assert resolve_collection_argument( invocation_path, "src/pkg/test.py::foo::bar" - ) == (invocation_path / "src/pkg/test.py", ["foo", "bar"]) + ) == CollectionArgument( + path=invocation_path / "src/pkg/test.py", + parts=["foo", "bar"], + module_name=None, + ) assert resolve_collection_argument( invocation_path, "src/pkg/test.py::foo::bar::" - ) == (invocation_path / "src/pkg/test.py", ["foo", "bar", ""]) + ) == CollectionArgument( + path=invocation_path / "src/pkg/test.py", + parts=["foo", "bar", ""], + module_name=None, + ) def test_dir(self, invocation_path: Path) -> None: """Directory and parts.""" - assert resolve_collection_argument(invocation_path, "src/pkg") == ( - invocation_path / "src/pkg", - [], + assert resolve_collection_argument( + invocation_path, "src/pkg" + ) == CollectionArgument( + path=invocation_path / "src/pkg", + parts=[], + module_name=None, ) with pytest.raises( @@ -169,13 +187,24 @@ class TestResolveCollectionArgument: """Dotted name and parts.""" assert resolve_collection_argument( invocation_path, "pkg.test", as_pypath=True - ) == (invocation_path / "src/pkg/test.py", []) + ) == CollectionArgument( + path=invocation_path / "src/pkg/test.py", + parts=[], + module_name="pkg.test", + ) assert resolve_collection_argument( invocation_path, "pkg.test::foo::bar", as_pypath=True - ) == (invocation_path / "src/pkg/test.py", ["foo", "bar"]) - assert resolve_collection_argument(invocation_path, "pkg", as_pypath=True) == ( - invocation_path / "src/pkg", - [], + ) == CollectionArgument( + path=invocation_path / "src/pkg/test.py", + parts=["foo", "bar"], + module_name="pkg.test", + ) + assert resolve_collection_argument( + invocation_path, "pkg", as_pypath=True + ) == CollectionArgument( + path=invocation_path / "src/pkg", + parts=[], + module_name="pkg", ) with pytest.raises( @@ -186,10 +215,13 @@ class TestResolveCollectionArgument: ) def test_parametrized_name_with_colons(self, invocation_path: Path) -> None: - ret = resolve_collection_argument( + assert resolve_collection_argument( invocation_path, "src/pkg/test.py::test[a::b]" + ) == CollectionArgument( + path=invocation_path / "src/pkg/test.py", + parts=["test[a::b]"], + module_name=None, ) - assert ret == (invocation_path / "src/pkg/test.py", ["test[a::b]"]) def test_does_not_exist(self, invocation_path: Path) -> None: """Given a file/module that does not exist raises UsageError.""" @@ -209,9 +241,12 @@ class TestResolveCollectionArgument: def test_absolute_paths_are_resolved_correctly(self, invocation_path: Path) -> None: """Absolute paths resolve back to absolute paths.""" full_path = str(invocation_path / "src") - assert resolve_collection_argument(invocation_path, full_path) == ( - Path(os.path.abspath("src")), - [], + assert resolve_collection_argument( + invocation_path, full_path + ) == CollectionArgument( + path=Path(os.path.abspath("src")), + parts=[], + module_name=None, ) # ensure full paths given in the command-line without the drive letter resolve @@ -219,7 +254,11 @@ class TestResolveCollectionArgument: drive, full_path_without_drive = os.path.splitdrive(full_path) assert resolve_collection_argument( invocation_path, full_path_without_drive - ) == (Path(os.path.abspath("src")), []) + ) == CollectionArgument( + path=Path(os.path.abspath("src")), + parts=[], + module_name=None, + ) def test_module_full_path_without_drive(pytester: Pytester) -> None: diff --git a/testing/test_runner.py b/testing/test_runner.py index 6b2b3105b..8cc496f70 100644 --- a/testing/test_runner.py +++ b/testing/test_runner.py @@ -926,6 +926,9 @@ def test_store_except_info_on_error() -> None: # Check that exception info is stored on sys assert sys.last_type is IndexError assert isinstance(sys.last_value, IndexError) + if sys.version_info >= (3, 12, 0): + assert isinstance(sys.last_exc, IndexError) # type: ignore[attr-defined] + assert sys.last_value.args[0] == "TEST" assert sys.last_traceback @@ -934,6 +937,8 @@ def test_store_except_info_on_error() -> None: runner.pytest_runtest_call(ItemMightRaise()) # type: ignore[arg-type] assert not hasattr(sys, "last_type") assert not hasattr(sys, "last_value") + if sys.version_info >= (3, 12, 0): + assert not hasattr(sys, "last_exc") assert not hasattr(sys, "last_traceback") @@ -1089,53 +1094,3 @@ def test_outcome_exception_bad_msg() -> None: with pytest.raises(TypeError) as excinfo: OutcomeException(func) # type: ignore assert str(excinfo.value) == expected - - -def test_teardown_session_failed(pytester: Pytester) -> None: - """Test that higher-scoped fixture teardowns run in the context of the last - item after the test session bails early due to --maxfail. - - Regression test for #11706. - """ - pytester.makepyfile( - """ - import pytest - - @pytest.fixture(scope="module") - def baz(): - yield - pytest.fail("This is a failing teardown") - - def test_foo(baz): - pytest.fail("This is a failing test") - - def test_bar(): pass - """ - ) - result = pytester.runpytest("--maxfail=1") - result.assert_outcomes(failed=1, errors=1) - - -def test_teardown_session_stopped(pytester: Pytester) -> None: - """Test that higher-scoped fixture teardowns run in the context of the last - item after the test session bails early due to --stepwise. - - Regression test for #11706. - """ - pytester.makepyfile( - """ - import pytest - - @pytest.fixture(scope="module") - def baz(): - yield - pytest.fail("This is a failing teardown") - - def test_foo(baz): - pytest.fail("This is a failing test") - - def test_bar(): pass - """ - ) - result = pytester.runpytest("--stepwise") - result.assert_outcomes(failed=1, errors=1) diff --git a/testing/test_terminal.py b/testing/test_terminal.py index bc457c398..b311d6c9b 100644 --- a/testing/test_terminal.py +++ b/testing/test_terminal.py @@ -2611,6 +2611,239 @@ def test_format_trimmed() -> None: assert _format_trimmed(" ({}) ", msg, len(msg) + 3) == " (unconditional ...) " +class TestFineGrainedTestCase: + DEFAULT_FILE_CONTENTS = """ + import pytest + + @pytest.mark.parametrize("i", range(4)) + def test_ok(i): + ''' + some docstring + ''' + pass + + def test_fail(): + assert False + """ + LONG_SKIP_FILE_CONTENTS = """ + import pytest + + @pytest.mark.skip( + "some long skip reason that will not fit on a single line with other content that goes" + " on and on and on and on and on" + ) + def test_skip(): + pass + """ + + @pytest.mark.parametrize("verbosity", [1, 2]) + def test_execute_positive(self, verbosity, pytester: Pytester) -> None: + # expected: one test case per line (with file name), word describing result + p = TestFineGrainedTestCase._initialize_files(pytester, verbosity=verbosity) + result = pytester.runpytest(p) + + result.stdout.fnmatch_lines( + [ + "collected 5 items", + "", + f"{p.name}::test_ok[0] PASSED [ 20%]", + f"{p.name}::test_ok[1] PASSED [ 40%]", + f"{p.name}::test_ok[2] PASSED [ 60%]", + f"{p.name}::test_ok[3] PASSED [ 80%]", + f"{p.name}::test_fail FAILED [100%]", + ], + consecutive=True, + ) + + def test_execute_0_global_1(self, pytester: Pytester) -> None: + # expected: one file name per line, single character describing result + p = TestFineGrainedTestCase._initialize_files(pytester, verbosity=0) + result = pytester.runpytest("-v", p) + + result.stdout.fnmatch_lines( + [ + "collecting ... collected 5 items", + "", + f"{p.name} ....F [100%]", + ], + consecutive=True, + ) + + @pytest.mark.parametrize("verbosity", [-1, -2]) + def test_execute_negative(self, verbosity, pytester: Pytester) -> None: + # expected: single character describing result + p = TestFineGrainedTestCase._initialize_files(pytester, verbosity=verbosity) + result = pytester.runpytest(p) + + result.stdout.fnmatch_lines( + [ + "collected 5 items", + "....F [100%]", + ], + consecutive=True, + ) + + def test_execute_skipped_positive_2(self, pytester: Pytester) -> None: + # expected: one test case per line (with file name), word describing result, full reason + p = TestFineGrainedTestCase._initialize_files( + pytester, + verbosity=2, + file_contents=TestFineGrainedTestCase.LONG_SKIP_FILE_CONTENTS, + ) + result = pytester.runpytest(p) + + result.stdout.fnmatch_lines( + [ + "collected 1 item", + "", + f"{p.name}::test_skip SKIPPED (some long skip", + "reason that will not fit on a single line with other content that goes", + "on and on and on and on and on) [100%]", + ], + consecutive=True, + ) + + def test_execute_skipped_positive_1(self, pytester: Pytester) -> None: + # expected: one test case per line (with file name), word describing result, reason truncated + p = TestFineGrainedTestCase._initialize_files( + pytester, + verbosity=1, + file_contents=TestFineGrainedTestCase.LONG_SKIP_FILE_CONTENTS, + ) + result = pytester.runpytest(p) + + result.stdout.fnmatch_lines( + [ + "collected 1 item", + "", + f"{p.name}::test_skip SKIPPED (some long ski...) [100%]", + ], + consecutive=True, + ) + + def test_execute_skipped__0_global_1(self, pytester: Pytester) -> None: + # expected: one file name per line, single character describing result (no reason) + p = TestFineGrainedTestCase._initialize_files( + pytester, + verbosity=0, + file_contents=TestFineGrainedTestCase.LONG_SKIP_FILE_CONTENTS, + ) + result = pytester.runpytest("-v", p) + + result.stdout.fnmatch_lines( + [ + "collecting ... collected 1 item", + "", + f"{p.name} s [100%]", + ], + consecutive=True, + ) + + @pytest.mark.parametrize("verbosity", [-1, -2]) + def test_execute_skipped_negative(self, verbosity, pytester: Pytester) -> None: + # expected: single character describing result (no reason) + p = TestFineGrainedTestCase._initialize_files( + pytester, + verbosity=verbosity, + file_contents=TestFineGrainedTestCase.LONG_SKIP_FILE_CONTENTS, + ) + result = pytester.runpytest(p) + + result.stdout.fnmatch_lines( + [ + "collected 1 item", + "s [100%]", + ], + consecutive=True, + ) + + @pytest.mark.parametrize("verbosity", [1, 2]) + def test__collect_only_positive(self, verbosity, pytester: Pytester) -> None: + p = TestFineGrainedTestCase._initialize_files(pytester, verbosity=verbosity) + result = pytester.runpytest("--collect-only", p) + + result.stdout.fnmatch_lines( + [ + "collected 5 items", + "", + f"", + f" ", + " ", + " some docstring", + " ", + " some docstring", + " ", + " some docstring", + " ", + " some docstring", + " ", + ], + consecutive=True, + ) + + def test_collect_only_0_global_1(self, pytester: Pytester) -> None: + p = TestFineGrainedTestCase._initialize_files(pytester, verbosity=0) + result = pytester.runpytest("-v", "--collect-only", p) + + result.stdout.fnmatch_lines( + [ + "collecting ... collected 5 items", + "", + f"", + f" ", + " ", + " ", + " ", + " ", + " ", + ], + consecutive=True, + ) + + def test_collect_only_negative_1(self, pytester: Pytester) -> None: + p = TestFineGrainedTestCase._initialize_files(pytester, verbosity=-1) + result = pytester.runpytest("--collect-only", p) + + result.stdout.fnmatch_lines( + [ + "collected 5 items", + "", + f"{p.name}::test_ok[0]", + f"{p.name}::test_ok[1]", + f"{p.name}::test_ok[2]", + f"{p.name}::test_ok[3]", + f"{p.name}::test_fail", + ], + consecutive=True, + ) + + def test_collect_only_negative_2(self, pytester: Pytester) -> None: + p = TestFineGrainedTestCase._initialize_files(pytester, verbosity=-2) + result = pytester.runpytest("--collect-only", p) + + result.stdout.fnmatch_lines( + [ + "collected 5 items", + "", + f"{p.name}: 5", + ], + consecutive=True, + ) + + @staticmethod + def _initialize_files( + pytester: Pytester, verbosity: int, file_contents: str = DEFAULT_FILE_CONTENTS + ) -> Path: + p = pytester.makepyfile(file_contents) + pytester.makeini( + f""" + [pytest] + verbosity_test_cases = {verbosity} + """ + ) + return p + + def test_summary_xfail_reason(pytester: Pytester) -> None: pytester.makepyfile( """