diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4914725f778..b7f0634d08d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -277,11 +277,15 @@ jobs: - name: Test without coverage if: "! matrix.use_coverage" shell: bash + env: + _PYTEST_TOX_POSARGS_JUNIT: --junitxml=junit.xml run: tox run -e ${{ matrix.tox_env }} --installpkg `find dist/*.tar.gz` - name: Test with coverage if: "matrix.use_coverage" shell: bash + env: + _PYTEST_TOX_POSARGS_JUNIT: --junitxml=junit.xml run: tox run -e ${{ matrix.tox_env }}-coverage --installpkg `find dist/*.tar.gz` - name: Generate coverage report @@ -296,6 +300,14 @@ jobs: files: ./coverage.xml verbose: true + - name: Upload JUnit report to Codecov + uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 + with: + fail_ci_if_error: false + files: junit.xml + report_type: test_results + verbose: true + check: # This job does nothing and is only used for the branch protection if: always() @@ -306,6 +318,6 @@ jobs: steps: - name: Decide whether the needed jobs succeeded or failed - uses: re-actors/alls-green@2765efec08f0fd63e83ad900f5fd75646be69ff6 + uses: re-actors/alls-green@a638d6464689bbb24c325bb3fe9404d63a913030 with: jobs: ${{ toJSON(needs) }} diff --git a/.gitignore b/.gitignore index c4557b33a1c..d0e8dc54ba1 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,7 @@ coverage.xml .vscode __pycache__/ .python-version +.claude/settings.local.json # generated by pip pip-wheel-metadata/ diff --git a/.mailmap b/.mailmap new file mode 100644 index 00000000000..682334c7430 --- /dev/null +++ b/.mailmap @@ -0,0 +1,2 @@ +Freya Bruhin +Freya Bruhin diff --git a/AUTHORS b/AUTHORS index a089ca678f7..e8140292aa4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -14,6 +14,7 @@ Ahn Ki-Wook Akhilesh Ramakrishnan Akiomi Kamakura Alan Velasco +Alejandro Villate Alessio Izzo Alex Jones Alex Lambson @@ -130,6 +131,7 @@ David Szotten David Vierra Daw-Ran Liou Debi Mishra +Denis Cherednichenko Denis Kirisov Denivy Braiam Rück Deysha Rivera @@ -170,11 +172,11 @@ faph Felix Hofstätter Felix Nieuwenhuizen Feng Ma -Florian Bruhin Florian Dahlitz Floris Bruynooghe Frank Hoffmann Fraser Stark +Freya Bruhin Gabriel Landau Gabriel Reis Garvit Shubham @@ -311,6 +313,7 @@ Michael Goerz Michael Krebs Michael Seifert Michael Vogt +Michael Reznik Michal Wajszczuk Michał Górny Michał Zięba @@ -379,6 +382,7 @@ Ralf Schmitt Ralph Giles Ram Rachum Ran Benita +Randy Döring Raphael Castaneda Raphael Pierzina Rafal Semik diff --git a/CITATION b/CITATION index 98beee72209..ac7c5d6f312 100644 --- a/CITATION +++ b/CITATION @@ -10,19 +10,19 @@ BibLaTeX: @software{pytest, title = {pytest x.y}, - author = {Holger Krekel and Bruno Oliveira and Ronny Pfannschmidt and Floris Bruynooghe and Brianna Laugher and Florian Bruhin}, + author = {Holger Krekel and Bruno Oliveira and Ronny Pfannschmidt and Floris Bruynooghe and Brianna Laugher and Freya Bruhin}, year = {2004}, version = {x.y}, url = {https://github.com/pytest-dev/pytest}, - note = {Contributors: Holger Krekel and Bruno Oliveira and Ronny Pfannschmidt and Floris Bruynooghe and Brianna Laugher and Florian Bruhin and others} + note = {Contributors: Holger Krekel and Bruno Oliveira and Ronny Pfannschmidt and Floris Bruynooghe and Brianna Laugher and Freya Bruhin and others} } BibTeX: @misc{pytest, - author = {Holger Krekel and Bruno Oliveira and Ronny Pfannschmidt and Floris Bruynooghe and Brianna Laugher and Florian Bruhin}, + author = {Holger Krekel and Bruno Oliveira and Ronny Pfannschmidt and Floris Bruynooghe and Brianna Laugher and Freya Bruhin}, title = {pytest x.y}, year = {2004}, howpublished = {\url{https://github.com/pytest-dev/pytest}}, - note = {Version x.y. Contributors include Holger Krekel, Bruno Oliveira, Ronny Pfannschmidt, Floris Bruynooghe, Brianna Laugher, Florian Bruhin, and others.} + note = {Version x.y. Contributors include Holger Krekel, Bruno Oliveira, Ronny Pfannschmidt, Floris Bruynooghe, Brianna Laugher, Freya Bruhin, and others.} } diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index f0ca304be4e..14d56263449 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -70,7 +70,7 @@ contacted individually: - Brianna Laugher ([@pfctdayelise](https://github.com/pfctdayelise)): brianna@laugher.id.au - Bruno Oliveira ([@nicoddemus](https://github.com/nicoddemus)): nicoddemus@gmail.com -- Florian Bruhin ([@the-compiler](https://github.com/the-compiler)): pytest@the-compiler.org +- Freya Bruhin ([@the-compiler](https://github.com/the-compiler)): pytest@the-compiler.org ## Attribution diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index f31c14aec49..fb9f7f4d53d 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -146,7 +146,7 @@ the following: - PyPI presence with packaging metadata that contains a ``pytest-`` prefixed name, version number, authors, short and long description. -- a `tox configuration `_ +- a `tox configuration `_ for running tests using `tox `_. - a ``README`` describing how to use the plugin and on which @@ -280,7 +280,7 @@ Here is a simple overview, with pytest-specific bits: #. You can now edit your local working copy and run the tests again as necessary. Please follow `PEP-8 `_ for naming. You can pass different options to ``tox``. For example, to run tests on Python 3.13 and pass options to pytest - (e.g. enter pdb on failure) to pytest you can do:: + (e.g. enter pdb on failure) you can do:: $ tox -e py313 -- --pdb @@ -346,7 +346,7 @@ For example, to ensure a simple test passes you can write: result.assert_outcomes(failed=0, passed=1) -Alternatively, it is possible to make checks based on the actual output of the termal using +Alternatively, it is possible to make checks based on the actual output of the terminal using *glob-like* expressions: .. code-block:: python @@ -479,10 +479,10 @@ above? to do the backport. 2. However, often the merge is done by another maintainer, in which case it is nice of them to do the backport procedure if they have the time. -3. For bugs submitted by non-maintainers, it is expected that a core developer will to do +3. For bugs submitted by non-maintainers, it is expected that a core developer will do the backport, normally the one that merged the PR on ``main``. -4. If a non-maintainers notices a bug which is fixed on ``main`` but has not been backported - (due to maintainers forgetting to apply the *needs backport* label, or just plain missing it), +4. If a non-maintainer notices a bug which is fixed on ``main`` but has not been backported + (due to maintainers forgetting to apply the *needs backport* or *backport x.x.x* labels, or just plain missing it), they are also welcome to open a PR with the backport. The procedure is simple and really helps with the maintenance of the project. @@ -512,7 +512,7 @@ can always reopen the issue/pull request in their own time later if it makes sen When to close ~~~~~~~~~~~~~ -Here are a few general rules the maintainers use deciding when to close issues/PRs because +Here are a few general rules the maintainers use to decide when to close issues/PRs because of lack of inactivity: * Issues labeled ``question`` or ``needs information``: closed after 14 days inactive. @@ -524,7 +524,7 @@ The above are **not hard rules**, but merely **guidelines**, and can be (and oft Closing pull requests ~~~~~~~~~~~~~~~~~~~~~ -When closing a Pull Request, it needs to be acknowledging the time, effort, and interest demonstrated by the person which submitted it. As mentioned previously, it is not the intent of the team to dismiss a stalled pull request entirely but to merely to clear up our queue, so a message like the one below is warranted when closing a pull request that went stale: +When closing a Pull Request, we should acknowledge the time, effort, and interest demonstrated by the person who submitted it. As mentioned previously, it is not the intent of the team to dismiss a stalled pull request entirely but to merely to clear up our queue, so a message like the one below is warranted when closing a pull request that went stale: Hi , @@ -532,7 +532,7 @@ When closing a Pull Request, it needs to be acknowledging the time, effort, and We noticed it has been awhile since you have updated this PR, however. pytest is a high activity project, with many issues/PRs being opened daily, so it is hard for us maintainers to track which PRs are ready for merging, for review, or need more attention. - So for those reasons we, think it is best to close the PR for now, but with the only intention to clean up our queue, it is by no means a rejection of your changes. We still encourage you to re-open this PR (it is just a click of a button away) when you are ready to get back to it. + So for those reasons, we think it is best to close the PR for now, but with the only intention to clean up our queue, it is by no means a rejection of your changes. We still encourage you to re-open this PR (it is just a click of a button away) when you are ready to get back to it. Again we appreciate your time for working on this, and hope you might get back to this at a later time! diff --git a/RELEASING.rst b/RELEASING.rst index 79b4e2f764d..2b00e658e7a 100644 --- a/RELEASING.rst +++ b/RELEASING.rst @@ -117,7 +117,7 @@ To release a version ``MAJOR.MINOR.PATCH``, follow these steps: #. Create a branch ``release-MAJOR.MINOR.PATCH`` from the ``MAJOR.MINOR.x`` branch. - Ensure your are updated and in a clean working tree. + Ensure your local checkout is up to date and in a clean working tree. #. Using ``tox``, generate docs, changelog, announcements:: diff --git a/changelog/README.rst b/changelog/README.rst index fdaa573d427..f1ba2cbd0bd 100644 --- a/changelog/README.rst +++ b/changelog/README.rst @@ -16,12 +16,12 @@ Each file should be named like ``..rst``, where * ``feature``: new user facing features, like new command-line options and new behavior. * ``improvement``: improvement of existing functionality, usually without requiring user intervention (for example, new fields being written in ``--junit-xml``, improved colors in terminal, etc). * ``bugfix``: fixes a bug. -* ``doc``: documentation improvement, like rewording an entire session or adding missing docs. +* ``doc``: documentation improvement, like rewording an entire section or adding missing docs. * ``deprecation``: feature deprecation. * ``breaking``: a change which may break existing suites, such as feature removal or behavior change. * ``vendor``: changes in packages vendored in pytest. * ``packaging``: notes for downstreams about unobvious side effects - and tooling. changes in the test invocation considerations and + and tooling. Changes in the test invocation considerations and runtime assumptions. * ``contrib``: stuff that affects the contributor experience. e.g. Running tests, building the docs, setting up the development diff --git a/doc/en/announce/index.rst b/doc/en/announce/index.rst index b92b8d4a56b..4a5e8b86544 100644 --- a/doc/en/announce/index.rst +++ b/doc/en/announce/index.rst @@ -6,6 +6,7 @@ Release announcements :maxdepth: 2 + release-9.0.3 release-9.0.2 release-9.0.1 release-9.0.0 diff --git a/doc/en/announce/release-2.8.2.rst b/doc/en/announce/release-2.8.2.rst index e4726338852..f64ea9bb29a 100644 --- a/doc/en/announce/release-2.8.2.rst +++ b/doc/en/announce/release-2.8.2.rst @@ -17,7 +17,7 @@ Thanks to all who contributed to this release, among them: Bruno Oliveira Demian Brecht - Florian Bruhin + Freya Bruhin Ionel Cristian Mărieș Raphael Pierzina Ronny Pfannschmidt diff --git a/doc/en/announce/release-2.8.3.rst b/doc/en/announce/release-2.8.3.rst index 3f357252bb6..1ea7aac6d74 100644 --- a/doc/en/announce/release-2.8.3.rst +++ b/doc/en/announce/release-2.8.3.rst @@ -16,7 +16,7 @@ As usual, you can upgrade from pypi via:: Thanks to all who contributed to this release, among them: Bruno Oliveira - Florian Bruhin + Freya Bruhin Gabe Hollombe Gabriel Reis Hartmut Goebel diff --git a/doc/en/announce/release-2.8.4.rst b/doc/en/announce/release-2.8.4.rst index adbdecc87ea..0605c986928 100644 --- a/doc/en/announce/release-2.8.4.rst +++ b/doc/en/announce/release-2.8.4.rst @@ -16,7 +16,7 @@ As usual, you can upgrade from pypi via:: Thanks to all who contributed to this release, among them: Bruno Oliveira - Florian Bruhin + Freya Bruhin Jeff Widman Mehdy Khoshnoody Nicholas Chammas @@ -43,10 +43,10 @@ The py.test Development Team non-ascii characters. Thanks Bruno Oliveira for the PR. - fix #1204: another error when collecting with a nasty __getattr__(). - Thanks Florian Bruhin for the PR. + Thanks Freya Bruhin for the PR. - fix the summary printed when no tests did run. - Thanks Florian Bruhin for the PR. + Thanks Freya Bruhin for the PR. - a number of documentation modernizations wrt good practices. Thanks Bruno Oliveira for the PR. diff --git a/doc/en/announce/release-2.8.6.rst b/doc/en/announce/release-2.8.6.rst index 5d6565b16a3..a63c7f1e38d 100644 --- a/doc/en/announce/release-2.8.6.rst +++ b/doc/en/announce/release-2.8.6.rst @@ -18,7 +18,7 @@ Thanks to all who contributed to this release, among them: AMiT Kumar Bruno Oliveira Erik M. Bray - Florian Bruhin + Freya Bruhin Georgy Dyuldin Jeff Widman Kartik Singhal diff --git a/doc/en/announce/release-2.9.0.rst b/doc/en/announce/release-2.9.0.rst index 753bb7bf6f0..9477f0a9ba3 100644 --- a/doc/en/announce/release-2.9.0.rst +++ b/doc/en/announce/release-2.9.0.rst @@ -18,7 +18,7 @@ Thanks to all who contributed to this release, among them: Bruno Oliveira Buck Golemon David Vierra - Florian Bruhin + Freya Bruhin Galaczi Endre Georgy Dyuldin Lukas Bednar diff --git a/doc/en/announce/release-2.9.1.rst b/doc/en/announce/release-2.9.1.rst index 7a46d2ae690..3880218d233 100644 --- a/doc/en/announce/release-2.9.1.rst +++ b/doc/en/announce/release-2.9.1.rst @@ -17,7 +17,7 @@ Thanks to all who contributed to this release, among them: Bruno Oliveira Daniel Hahler Dmitry Malinovsky - Florian Bruhin + Freya Bruhin Floris Bruynooghe Matt Bachmann Ronny Pfannschmidt diff --git a/doc/en/announce/release-2.9.2.rst b/doc/en/announce/release-2.9.2.rst index 3e75af7fe69..3dc00b46729 100644 --- a/doc/en/announce/release-2.9.2.rst +++ b/doc/en/announce/release-2.9.2.rst @@ -17,7 +17,7 @@ Thanks to all who contributed to this release, among them: Adam Chainz Benjamin Dopplinger Bruno Oliveira - Florian Bruhin + Freya Bruhin John Towler Martin Prusse Meng Jue diff --git a/doc/en/announce/release-3.0.0.rst b/doc/en/announce/release-3.0.0.rst index 5de38911482..b201b901eb7 100644 --- a/doc/en/announce/release-3.0.0.rst +++ b/doc/en/announce/release-3.0.0.rst @@ -39,7 +39,7 @@ Thanks to all who contributed to this release, among them: Dmitry Dygalo Edoardo Batini Eli Boyarski - Florian Bruhin + Freya Bruhin Floris Bruynooghe Greg Price Guyzmo diff --git a/doc/en/announce/release-3.0.1.rst b/doc/en/announce/release-3.0.1.rst index 8f5cfe411aa..b36587f983a 100644 --- a/doc/en/announce/release-3.0.1.rst +++ b/doc/en/announce/release-3.0.1.rst @@ -17,7 +17,7 @@ Thanks to all who contributed to this release, among them: Bruno Oliveira Daniel Hahler Dmitry Dygalo - Florian Bruhin + Freya Bruhin Marcin Bachry Ronny Pfannschmidt matthiasha diff --git a/doc/en/announce/release-3.0.2.rst b/doc/en/announce/release-3.0.2.rst index 86ba82ca6e6..9b1f2acd60d 100644 --- a/doc/en/announce/release-3.0.2.rst +++ b/doc/en/announce/release-3.0.2.rst @@ -14,7 +14,7 @@ Thanks to all who contributed to this release, among them: * Ahn Ki-Wook * Bruno Oliveira -* Florian Bruhin +* Freya Bruhin * Jordan Guymon * Raphael Pierzina * Ronny Pfannschmidt diff --git a/doc/en/announce/release-3.0.3.rst b/doc/en/announce/release-3.0.3.rst index 89a2e0c744e..05bdf4dcd16 100644 --- a/doc/en/announce/release-3.0.3.rst +++ b/doc/en/announce/release-3.0.3.rst @@ -13,7 +13,7 @@ The changelog is available at http://doc.pytest.org/en/stable/changelog.html. Thanks to all who contributed to this release, among them: * Bruno Oliveira -* Florian Bruhin +* Freya Bruhin * Floris Bruynooghe * Huayi Zhang * Lev Maximov diff --git a/doc/en/announce/release-3.0.4.rst b/doc/en/announce/release-3.0.4.rst index 72c2d29464d..ba37bba2111 100644 --- a/doc/en/announce/release-3.0.4.rst +++ b/doc/en/announce/release-3.0.4.rst @@ -14,7 +14,7 @@ Thanks to all who contributed to this release, among them: * Bruno Oliveira * Dan Wandschneider -* Florian Bruhin +* Freya Bruhin * Georgy Dyuldin * Grigorii Eremeev * Jason R. Coombs diff --git a/doc/en/announce/release-3.0.7.rst b/doc/en/announce/release-3.0.7.rst index 4b7e075e76a..782910ae6a4 100644 --- a/doc/en/announce/release-3.0.7.rst +++ b/doc/en/announce/release-3.0.7.rst @@ -14,7 +14,7 @@ Thanks to all who contributed to this release, among them: * Anthony Sottile * Barney Gale * Bruno Oliveira -* Florian Bruhin +* Freya Bruhin * Floris Bruynooghe * Ionel Cristian Mărieș * Katerina Koukiou diff --git a/doc/en/announce/release-3.1.0.rst b/doc/en/announce/release-3.1.0.rst index 55277067948..454c04c6430 100644 --- a/doc/en/announce/release-3.1.0.rst +++ b/doc/en/announce/release-3.1.0.rst @@ -27,7 +27,7 @@ Thanks to all who contributed to this release, among them: * David Giese * David Szotten * Dmitri Pribysh -* Florian Bruhin +* Freya Bruhin * Florian Schulze * Floris Bruynooghe * John Towler diff --git a/doc/en/announce/release-3.1.1.rst b/doc/en/announce/release-3.1.1.rst index 135b2fe8443..99fb0d0f801 100644 --- a/doc/en/announce/release-3.1.1.rst +++ b/doc/en/announce/release-3.1.1.rst @@ -12,7 +12,7 @@ The full changelog is available at http://doc.pytest.org/en/stable/changelog.htm Thanks to all who contributed to this release, among them: * Bruno Oliveira -* Florian Bruhin +* Freya Bruhin * Floris Bruynooghe * Jason R. Coombs * Ronny Pfannschmidt diff --git a/doc/en/announce/release-3.1.2.rst b/doc/en/announce/release-3.1.2.rst index a9b85c4715c..3e988b17e84 100644 --- a/doc/en/announce/release-3.1.2.rst +++ b/doc/en/announce/release-3.1.2.rst @@ -14,7 +14,7 @@ Thanks to all who contributed to this release, among them: * Andreas Pelme * ApaDoctor * Bruno Oliveira -* Florian Bruhin +* Freya Bruhin * Ronny Pfannschmidt * Segev Finer diff --git a/doc/en/announce/release-3.2.0.rst b/doc/en/announce/release-3.2.0.rst index edc66a28e78..68694493907 100644 --- a/doc/en/announce/release-3.2.0.rst +++ b/doc/en/announce/release-3.2.0.rst @@ -25,7 +25,7 @@ Thanks to all who contributed to this release, among them: * Andras Tim * Bruno Oliveira * Daniel Hahler -* Florian Bruhin +* Freya Bruhin * Floris Bruynooghe * John Still * Jordan Moldow diff --git a/doc/en/announce/release-3.2.1.rst b/doc/en/announce/release-3.2.1.rst index c40217d311d..a492390fa58 100644 --- a/doc/en/announce/release-3.2.1.rst +++ b/doc/en/announce/release-3.2.1.rst @@ -13,7 +13,7 @@ Thanks to all who contributed to this release, among them: * Alex Gaynor * Bruno Oliveira -* Florian Bruhin +* Freya Bruhin * Ronny Pfannschmidt * Srinivas Reddy Thatiparthy diff --git a/doc/en/announce/release-3.2.4.rst b/doc/en/announce/release-3.2.4.rst index ff0b35781b1..9bde3afab3b 100644 --- a/doc/en/announce/release-3.2.4.rst +++ b/doc/en/announce/release-3.2.4.rst @@ -15,7 +15,7 @@ Thanks to all who contributed to this release, among them: * Christian Boelsen * Christoph Buchner * Daw-Ran Liou -* Florian Bruhin +* Freya Bruhin * Franck Michea * Leonard Lausen * Matty G diff --git a/doc/en/announce/release-3.3.0.rst b/doc/en/announce/release-3.3.0.rst index 1cbf2c448c8..d54910bea4c 100644 --- a/doc/en/announce/release-3.3.0.rst +++ b/doc/en/announce/release-3.3.0.rst @@ -27,7 +27,7 @@ Thanks to all who contributed to this release, among them: * Daniel Hahler * Dirk Thomas * Dmitry Malinovsky -* Florian Bruhin +* Freya Bruhin * George Y. Kussumoto * Hugo * Jesús Espino diff --git a/doc/en/announce/release-3.3.1.rst b/doc/en/announce/release-3.3.1.rst index 98b6fa6c1ba..a1a0a6d6f45 100644 --- a/doc/en/announce/release-3.3.1.rst +++ b/doc/en/announce/release-3.3.1.rst @@ -14,7 +14,7 @@ Thanks to all who contributed to this release, among them: * Bruno Oliveira * Daniel Hahler * Eugene Prikazchikov -* Florian Bruhin +* Freya Bruhin * Roland Puntaier * Ronny Pfannschmidt * Sebastian Rahlf diff --git a/doc/en/announce/release-3.3.2.rst b/doc/en/announce/release-3.3.2.rst index 7a2577d1ff8..8c4110cc350 100644 --- a/doc/en/announce/release-3.3.2.rst +++ b/doc/en/announce/release-3.3.2.rst @@ -15,7 +15,7 @@ Thanks to all who contributed to this release, among them: * Antony Lee * Austin * Bruno Oliveira -* Florian Bruhin +* Freya Bruhin * Floris Bruynooghe * Henk-Jaap Wagenaar * Jurko Gospodnetić diff --git a/doc/en/announce/release-3.4.0.rst b/doc/en/announce/release-3.4.0.rst index 6ab5b124a25..8a8582f7a00 100644 --- a/doc/en/announce/release-3.4.0.rst +++ b/doc/en/announce/release-3.4.0.rst @@ -30,7 +30,7 @@ Thanks to all who contributed to this release, among them: * Brian Maissy * Bruno Oliveira * Cyrus Maden -* Florian Bruhin +* Freya Bruhin * Henk-Jaap Wagenaar * Ian Lesperance * Jon Dufresne diff --git a/doc/en/announce/release-3.4.1.rst b/doc/en/announce/release-3.4.1.rst index d83949453a2..bef05752698 100644 --- a/doc/en/announce/release-3.4.1.rst +++ b/doc/en/announce/release-3.4.1.rst @@ -16,7 +16,7 @@ Thanks to all who contributed to this release, among them: * Andy Freeland * Brian Maissy * Bruno Oliveira -* Florian Bruhin +* Freya Bruhin * Jason R. Coombs * Marcin Bachry * Pedro Algarvio diff --git a/doc/en/announce/release-3.4.2.rst b/doc/en/announce/release-3.4.2.rst index 07cd9d3a8ba..5ab73986617 100644 --- a/doc/en/announce/release-3.4.2.rst +++ b/doc/en/announce/release-3.4.2.rst @@ -13,7 +13,7 @@ Thanks to all who contributed to this release, among them: * Allan Feldman * Bruno Oliveira -* Florian Bruhin +* Freya Bruhin * Jason R. Coombs * Kyle Altendorf * Maik Figura diff --git a/doc/en/announce/release-3.5.0.rst b/doc/en/announce/release-3.5.0.rst index 6bc2f3cd0cb..7ce2fe3dfe0 100644 --- a/doc/en/announce/release-3.5.0.rst +++ b/doc/en/announce/release-3.5.0.rst @@ -26,7 +26,7 @@ Thanks to all who contributed to this release, among them: * Bruno Oliveira * Carlos Jenkins * Daniel Hahler -* Florian Bruhin +* Freya Bruhin * Jason R. Coombs * Jeffrey Rackauckas * Jordan Speicher diff --git a/doc/en/announce/release-5.0.0.rst b/doc/en/announce/release-5.0.0.rst index f5e593e9d88..166d4e565c3 100644 --- a/doc/en/announce/release-5.0.0.rst +++ b/doc/en/announce/release-5.0.0.rst @@ -26,7 +26,7 @@ Thanks to all who contributed to this release, among them: * Daniel Hahler * Dirk Thomas * Evan Kepner -* Florian Bruhin +* Freya Bruhin * Hugo * Kevin J. Foley * Pulkit Goyal diff --git a/doc/en/announce/release-5.0.1.rst b/doc/en/announce/release-5.0.1.rst index e16a8f716f1..f0ffb791545 100644 --- a/doc/en/announce/release-5.0.1.rst +++ b/doc/en/announce/release-5.0.1.rst @@ -15,7 +15,7 @@ Thanks to all who contributed to this release, among them: * Andreu Vallbona Plazas * Anthony Sottile * Bruno Oliveira -* Florian Bruhin +* Freya Bruhin * Michael Moore * Niklas Meinzer * Thomas Grainger diff --git a/doc/en/announce/release-5.1.0.rst b/doc/en/announce/release-5.1.0.rst index 9ab54ff9730..6170023604a 100644 --- a/doc/en/announce/release-5.1.0.rst +++ b/doc/en/announce/release-5.1.0.rst @@ -27,7 +27,7 @@ Thanks to all who contributed to this release, among them: * Bruno Oliveira * Daniel Hahler * David Röthlisberger -* Florian Bruhin +* Freya Bruhin * Ilya Stepin * Jon Dufresne * Kaiqi diff --git a/doc/en/announce/release-5.1.1.rst b/doc/en/announce/release-5.1.1.rst index bb8de48014a..1262e94fd00 100644 --- a/doc/en/announce/release-5.1.1.rst +++ b/doc/en/announce/release-5.1.1.rst @@ -14,7 +14,7 @@ Thanks to all who contributed to this release, among them: * Anthony Sottile * Bruno Oliveira * Daniel Hahler -* Florian Bruhin +* Freya Bruhin * Hugo van Kemenade * Ran Benita * Ronny Pfannschmidt diff --git a/doc/en/announce/release-5.2.1.rst b/doc/en/announce/release-5.2.1.rst index fe42b9bf15f..904e1b59893 100644 --- a/doc/en/announce/release-5.2.1.rst +++ b/doc/en/announce/release-5.2.1.rst @@ -13,7 +13,7 @@ Thanks to all who contributed to this release, among them: * Anthony Sottile * Bruno Oliveira -* Florian Bruhin +* Freya Bruhin * Hynek Schlawack * Kevin J. Foley * tadashigaki diff --git a/doc/en/announce/release-5.2.2.rst b/doc/en/announce/release-5.2.2.rst index 89fd6a534d4..015baba52e7 100644 --- a/doc/en/announce/release-5.2.2.rst +++ b/doc/en/announce/release-5.2.2.rst @@ -16,7 +16,7 @@ Thanks to all who contributed to this release, among them: * Anthony Sottile * Bruno Oliveira * Daniel Hahler -* Florian Bruhin +* Freya Bruhin * Nattaphoom Chaipreecha * Oliver Bestwalter * Philipp Loose diff --git a/doc/en/announce/release-5.2.3.rst b/doc/en/announce/release-5.2.3.rst index bab174495d9..8c89e04540a 100644 --- a/doc/en/announce/release-5.2.3.rst +++ b/doc/en/announce/release-5.2.3.rst @@ -17,7 +17,7 @@ Thanks to all who contributed to this release, among them: * Daniel Hahler * Daniil Galiev * David Szotten -* Florian Bruhin +* Freya Bruhin * Patrick Harmon * Ran Benita * Zac Hatfield-Dodds diff --git a/doc/en/announce/release-5.3.1.rst b/doc/en/announce/release-5.3.1.rst index d575bb70e3f..5dc82ab7d88 100644 --- a/doc/en/announce/release-5.3.1.rst +++ b/doc/en/announce/release-5.3.1.rst @@ -15,7 +15,7 @@ Thanks to all who contributed to this release, among them: * Bruno Oliveira * Daniel Hahler * Felix Yan -* Florian Bruhin +* Freya Bruhin * Mark Dickinson * Nikolay Kondratyev * Steffen Schroeder diff --git a/doc/en/announce/release-6.0.0rc1.rst b/doc/en/announce/release-6.0.0rc1.rst index 5690b514baf..6f0a745cd00 100644 --- a/doc/en/announce/release-6.0.0rc1.rst +++ b/doc/en/announce/release-6.0.0rc1.rst @@ -25,7 +25,7 @@ Thanks to all who contributed to this release, among them: * David Diaz Barquero * Fabio Zadrozny * Felix Nieuwenhuizen -* Florian Bruhin +* Freya Bruhin * Florian Dahlitz * Gleb Nikonorov * Hugo van Kemenade diff --git a/doc/en/announce/release-6.1.0.rst b/doc/en/announce/release-6.1.0.rst index f4b571ae846..0c787d0bd15 100644 --- a/doc/en/announce/release-6.1.0.rst +++ b/doc/en/announce/release-6.1.0.rst @@ -23,7 +23,7 @@ Thanks to all of the contributors to this release: * C. Titus Brown * Drew Devereux * Faris A Chugthai -* Florian Bruhin +* Freya Bruhin * Hugo van Kemenade * Hynek Schlawack * Joseph Lucas diff --git a/doc/en/announce/release-6.2.0.rst b/doc/en/announce/release-6.2.0.rst index af16b830ddd..8e99d8fcda5 100644 --- a/doc/en/announce/release-6.2.0.rst +++ b/doc/en/announce/release-6.2.0.rst @@ -30,7 +30,7 @@ Thanks to all of the contributors to this release: * Cserna Zsolt * Dominic Mortlock * Emiel van de Laar -* Florian Bruhin +* Freya Bruhin * Garvit Shubham * Gustavo Camargo * Hugo Martins diff --git a/doc/en/announce/release-6.2.4.rst b/doc/en/announce/release-6.2.4.rst index fa2e3e78132..129368e73cd 100644 --- a/doc/en/announce/release-6.2.4.rst +++ b/doc/en/announce/release-6.2.4.rst @@ -14,7 +14,7 @@ Thanks to all of the contributors to this release: * Anthony Sottile * Bruno Oliveira * Christian Maurer -* Florian Bruhin +* Freya Bruhin * Ran Benita diff --git a/doc/en/announce/release-6.2.5.rst b/doc/en/announce/release-6.2.5.rst index bc6b4cf4222..daf9731c800 100644 --- a/doc/en/announce/release-6.2.5.rst +++ b/doc/en/announce/release-6.2.5.rst @@ -15,7 +15,7 @@ Thanks to all of the contributors to this release: * Bruno Oliveira * Brylie Christopher Oxley * Daniel Asztalos -* Florian Bruhin +* Freya Bruhin * Jason Haugen * MapleCCC * Michał Górny diff --git a/doc/en/announce/release-7.0.0.rst b/doc/en/announce/release-7.0.0.rst index 3ce4335564f..934064df745 100644 --- a/doc/en/announce/release-7.0.0.rst +++ b/doc/en/announce/release-7.0.0.rst @@ -34,7 +34,7 @@ Thanks to all of the contributors to this release: * Emmanuel Arias * Emmanuel Meric de Bellefon * Eric Liu -* Florian Bruhin +* Freya Bruhin * GergelyKalmar * Graeme Smecher * Harshna diff --git a/doc/en/announce/release-7.0.0rc1.rst b/doc/en/announce/release-7.0.0rc1.rst index a5bf0ed3c44..dd6ecdd131b 100644 --- a/doc/en/announce/release-7.0.0rc1.rst +++ b/doc/en/announce/release-7.0.0rc1.rst @@ -38,7 +38,7 @@ Thanks to all the contributors to this release: * Emmanuel Arias * Emmanuel Meric de Bellefon * Eric Liu -* Florian Bruhin +* Freya Bruhin * GergelyKalmar * Graeme Smecher * Harshna diff --git a/doc/en/announce/release-7.1.0.rst b/doc/en/announce/release-7.1.0.rst index 3361e1c8a32..f138524c564 100644 --- a/doc/en/announce/release-7.1.0.rst +++ b/doc/en/announce/release-7.1.0.rst @@ -28,7 +28,7 @@ Thanks to all of the contributors to this release: * Elijah DeLee * Emmanuel Arias * Fabian Egli -* Florian Bruhin +* Freya Bruhin * Gabor Szabo * Hasan Ramezani * Hugo van Kemenade diff --git a/doc/en/announce/release-7.2.0.rst b/doc/en/announce/release-7.2.0.rst index eca84aeb669..44cd553ec0f 100644 --- a/doc/en/announce/release-7.2.0.rst +++ b/doc/en/announce/release-7.2.0.rst @@ -33,7 +33,7 @@ Thanks to all of the contributors to this release: * EmptyRabbit * Ezio Melotti * Florian Best -* Florian Bruhin +* Freya Bruhin * Fredrik Berndtsson * Gabriel Landau * Gergely Kalmár diff --git a/doc/en/announce/release-7.3.0.rst b/doc/en/announce/release-7.3.0.rst index 33258dabade..b6d8379d5b5 100644 --- a/doc/en/announce/release-7.3.0.rst +++ b/doc/en/announce/release-7.3.0.rst @@ -42,7 +42,7 @@ Thanks to all of the contributors to this release: * Ezio Melotti * Felix Hofstätter * Florian Best -* Florian Bruhin +* Freya Bruhin * Fredrik Berndtsson * Gabriel Landau * Garvit Shubham diff --git a/doc/en/announce/release-7.4.0.rst b/doc/en/announce/release-7.4.0.rst index 5a0d18267d3..fef2ad6cb3d 100644 --- a/doc/en/announce/release-7.4.0.rst +++ b/doc/en/announce/release-7.4.0.rst @@ -27,7 +27,7 @@ Thanks to all of the contributors to this release: * Bryan Ricker * Chris Mahoney * Facundo Batista -* Florian Bruhin +* Freya Bruhin * Jarrett Keifer * Kenny Y * Miro Hrončok diff --git a/doc/en/announce/release-7.4.1.rst b/doc/en/announce/release-7.4.1.rst index efadcf919e8..4e22d3ead66 100644 --- a/doc/en/announce/release-7.4.1.rst +++ b/doc/en/announce/release-7.4.1.rst @@ -12,7 +12,7 @@ The full changelog is available at https://docs.pytest.org/en/stable/changelog.h Thanks to all of the contributors to this release: * Bruno Oliveira -* Florian Bruhin +* Freya Bruhin * Ran Benita diff --git a/doc/en/announce/release-8.0.0rc1.rst b/doc/en/announce/release-8.0.0rc1.rst index 547c8cbc53b..0cbfc3dad59 100644 --- a/doc/en/announce/release-8.0.0rc1.rst +++ b/doc/en/announce/release-8.0.0rc1.rst @@ -31,7 +31,7 @@ Thanks to all of the contributors to this release: * Christoph Anton Mitterer * DetachHead * Erik Hasse -* Florian Bruhin +* Freya Bruhin * Fraser Stark * Ha Pam * Hugo van Kemenade diff --git a/doc/en/announce/release-8.1.0.rst b/doc/en/announce/release-8.1.0.rst index 62cafdd78bb..6762bd412fe 100644 --- a/doc/en/announce/release-8.1.0.rst +++ b/doc/en/announce/release-8.1.0.rst @@ -28,7 +28,7 @@ Thanks to all of the contributors to this release: * Eric Larson * Fabian Sturm * Faisal Fawad -* Florian Bruhin +* Freya Bruhin * Franck Charras * Joachim B Haga * John Litborn diff --git a/doc/en/announce/release-8.2.0.rst b/doc/en/announce/release-8.2.0.rst index 2a63c8d8722..7aba492d7da 100644 --- a/doc/en/announce/release-8.2.0.rst +++ b/doc/en/announce/release-8.2.0.rst @@ -20,7 +20,7 @@ Thanks to all of the contributors to this release: * Bruno Oliveira * Daniel Miller -* Florian Bruhin +* Freya Bruhin * HolyMagician03-UMich * John Litborn * Levon Saldamli diff --git a/doc/en/announce/release-8.3.0.rst b/doc/en/announce/release-8.3.0.rst index ec5cd3d0db9..0589aedfa89 100644 --- a/doc/en/announce/release-8.3.0.rst +++ b/doc/en/announce/release-8.3.0.rst @@ -24,7 +24,7 @@ Thanks to all of the contributors to this release: * Bruno Oliveira * Cornelius Riemenschneider * Farbod Ahmadian -* Florian Bruhin +* Freya Bruhin * Hynek Schlawack * James Frost * Jason R. Coombs diff --git a/doc/en/announce/release-8.3.3.rst b/doc/en/announce/release-8.3.3.rst index 5e3eb36b921..6e73714d4f9 100644 --- a/doc/en/announce/release-8.3.3.rst +++ b/doc/en/announce/release-8.3.3.rst @@ -16,7 +16,7 @@ Thanks to all of the contributors to this release: * Bruno Oliveira * Christian Clauss * Eugene Mwangi -* Florian Bruhin +* Freya Bruhin * GTowers1 * Nauman Ahmed * Pierre Sassoulas diff --git a/doc/en/announce/release-8.3.4.rst b/doc/en/announce/release-8.3.4.rst index f76d60396dc..3ec21d73f5e 100644 --- a/doc/en/announce/release-8.3.4.rst +++ b/doc/en/announce/release-8.3.4.rst @@ -12,7 +12,7 @@ The full changelog is available at https://docs.pytest.org/en/stable/changelog.h Thanks to all of the contributors to this release: * Bruno Oliveira -* Florian Bruhin +* Freya Bruhin * Frank Hoffmann * Jakob van Santen * Leonardus Chen diff --git a/doc/en/announce/release-8.3.5.rst b/doc/en/announce/release-8.3.5.rst index 3de02c1d7a4..21bae869180 100644 --- a/doc/en/announce/release-8.3.5.rst +++ b/doc/en/announce/release-8.3.5.rst @@ -10,7 +10,7 @@ The full changelog is available at https://docs.pytest.org/en/stable/changelog.h Thanks to all of the contributors to this release: * Bruno Oliveira -* Florian Bruhin +* Freya Bruhin * John Litborn * Kenny Y * Ran Benita diff --git a/doc/en/announce/release-8.4.0.rst b/doc/en/announce/release-8.4.0.rst index 65e80a55919..f492d45070a 100644 --- a/doc/en/announce/release-8.4.0.rst +++ b/doc/en/announce/release-8.4.0.rst @@ -38,7 +38,7 @@ Thanks to all of the contributors to this release: * Deysha Rivera * Emil Hjelm * Eugene Mwangi -* Florian Bruhin +* Freya Bruhin * Frank Hoffmann * GTowers1 * Guillaume Gauvrit diff --git a/doc/en/announce/release-8.4.2.rst b/doc/en/announce/release-8.4.2.rst index 58a842c4d4b..3111e85bd0f 100644 --- a/doc/en/announce/release-8.4.2.rst +++ b/doc/en/announce/release-8.4.2.rst @@ -12,7 +12,7 @@ Thanks to all of the contributors to this release: * AD * Aditi De * Bruno Oliveira -* Florian Bruhin +* Freya Bruhin * John Litborn * Liam DeVoe * Marc Mueller diff --git a/doc/en/announce/release-9.0.0.rst b/doc/en/announce/release-9.0.0.rst index 86dd828f045..67d4f95a56d 100644 --- a/doc/en/announce/release-9.0.0.rst +++ b/doc/en/announce/release-9.0.0.rst @@ -27,7 +27,7 @@ Thanks to all of the contributors to this release: * CoretexShadow * Cornelius Roemer * Eero Vaher -* Florian Bruhin +* Freya Bruhin * Harsha Sai * Hossein * Israël Hallé diff --git a/doc/en/announce/release-9.0.2.rst b/doc/en/announce/release-9.0.2.rst index f15a2dc8e13..f184e1aa4b2 100644 --- a/doc/en/announce/release-9.0.2.rst +++ b/doc/en/announce/release-9.0.2.rst @@ -12,7 +12,7 @@ Thanks to all of the contributors to this release: * Alex Waygood * Bruno Oliveira * Fazeel Usmani -* Florian Bruhin +* Freya Bruhin * Ran Benita * Tom Most * 🇺🇦 Sviatoslav Sydorenko (Святослав Сидоренко) diff --git a/doc/en/announce/release-9.0.3.rst b/doc/en/announce/release-9.0.3.rst new file mode 100644 index 00000000000..c9540218764 --- /dev/null +++ b/doc/en/announce/release-9.0.3.rst @@ -0,0 +1,38 @@ +pytest-9.0.3 +======================================= + +pytest 9.0.3 has just been released to PyPI. + +This is a bug-fix release, being a drop-in replacement. + +The full changelog is available at https://docs.pytest.org/en/stable/changelog.html. + +Thanks to all of the contributors to this release: + +* Aditya Giri +* Alejandro Villate +* Bruno Oliveira +* Bubble-Interface +* Charles-Meldhine Madi Mnemoi +* DavidAG +* Denis Cherednichenko +* Dr Alex Mitre +* Freya +* Freya Bruhin +* Hugo van Kemenade +* John Litborn +* Liam DeVoe +* Lily Wu +* Maxime Grenu +* Ran Benita +* Randy Döring +* Ronald Eddy Jr +* Samuel Newbold +* Tejas Verma +* Vladimir +* jxramos +* 🇺🇦 Sviatoslav Sydorenko (Святослав Сидоренко) + + +Happy testing, +The pytest Development Team diff --git a/doc/en/backwards-compatibility.rst b/doc/en/backwards-compatibility.rst index d79d112df2d..a7ee2253d67 100644 --- a/doc/en/backwards-compatibility.rst +++ b/doc/en/backwards-compatibility.rst @@ -53,8 +53,8 @@ History ========= -Focus primary on smooth transition - stance (pre 6.0) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Focus primarily on smooth transition - stance (pre 6.0) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Keeping backwards compatibility has a very high priority in the pytest project. Although we have deprecated functionality over the years, most of it is still supported. All deprecations in pytest were done because simpler or more efficient ways of accomplishing the same tasks have emerged, making the old way of doing things unnecessary. @@ -83,9 +83,10 @@ Released pytest versions support all Python versions that are actively maintaine ============== =================== pytest version min. Python version ============== =================== -8.4+ 3.9+ -8.0+ 3.8+ -7.1+ 3.7+ +9.0+ 3.10+ +8.4 3.9+ +8.0 - 8.3 3.8+ +7.1 - 7.4 3.7+ 6.2 - 7.0 3.6+ 5.0 - 6.1 3.5+ 3.3 - 4.6 2.7, 3.4+ diff --git a/doc/en/builtin.rst b/doc/en/builtin.rst index 6a96bb0a304..9d38b329454 100644 --- a/doc/en/builtin.rst +++ b/doc/en/builtin.rst @@ -257,10 +257,10 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a subtests -- .../_pytest/subtests.py:129 Provides subtests functionality. - tmp_path_factory [session scope] -- .../_pytest/tmpdir.py:243 + tmp_path_factory [session scope] -- .../_pytest/tmpdir.py:265 Return a :class:`pytest.TempPathFactory` instance for the test session. - tmp_path -- .../_pytest/tmpdir.py:258 + tmp_path -- .../_pytest/tmpdir.py:280 Return a temporary directory (as :class:`pathlib.Path` object) which is unique to each test function invocation. The temporary directory is created as a subdirectory diff --git a/doc/en/changelog.rst b/doc/en/changelog.rst index b4e5cee694e..5bcd44c4226 100644 --- a/doc/en/changelog.rst +++ b/doc/en/changelog.rst @@ -31,6 +31,58 @@ with advance notice in the **Deprecations** section of releases. .. towncrier release notes start +pytest 9.0.3 (2026-04-07) +========================= + +Bug fixes +--------- + +- `#12444 `_: Fixed :func:`pytest.approx` which now correctly takes into account :class:`~collections.abc.Mapping` keys order to compare them. + + +- `#13634 `_: Blocking a ``conftest.py`` file using the ``-p no:`` option is now explicitly disallowed. + + Previously this resulted in an internal assertion failure during plugin loading. + + Pytest now raises a clear ``UsageError`` explaining that conftest files are not plugins and cannot be disabled via ``-p``. + + +- `#13734 `_: Fixed crash when a test raises an exceptiongroup with ``__tracebackhide__ = True``. + + +- `#14195 `_: Fixed an issue where non-string messages passed to `unittest.TestCase.subTest()` were not printed. + + +- `#14343 `_: Fixed use of insecure temporary directory (CVE-2025-71176). + + + +Improved documentation +---------------------- + +- `#13388 `_: Clarified documentation for ``-p`` vs ``PYTEST_PLUGINS`` plugin loading and fixed an incorrect ``-p`` example. + + +- `#13731 `_: Clarified that capture fixtures (e.g. ``capsys`` and ``capfd``) take precedence over the ``-s`` / ``--capture=no`` command-line options in :ref:`Accessing captured output from a test function `. + + +- `#14088 `_: Clarified that the default :hook:`pytest_collection` hook sets ``session.items`` before it calls :hook:`pytest_collection_finish`, not after. + + +- `#14255 `_: TOML integer log levels must be quoted: Updating reference documentation. + + + +Contributor-facing changes +-------------------------- + +- `#12689 `_: The test reports are now published to Codecov from GitHub Actions. + The test statistics is visible `on the web interface + `__. + + -- by :user:`aleguy02` + + pytest 9.0.2 (2025-12-06) ========================= @@ -2805,6 +2857,7 @@ Breaking Changes - `#8246 `_: ``--version`` now writes version information to ``stdout`` rather than ``stderr``. +- `#8592 `_: The ``pytest_cmdline_preparse`` hook has been removed following its deprecation. See :ref:`the deprecation note ` for more details. - `#8733 `_: Drop a workaround for `pyreadline `__ that made it work with ``--pdb``. @@ -9373,10 +9426,10 @@ time or change existing behaviors in order to make them less surprising/more use non-ascii characters. Thanks Bruno Oliveira for the PR. - fix #1204: another error when collecting with a nasty __getattr__(). - Thanks Florian Bruhin for the PR. + Thanks Freya Bruhin for the PR. - fix the summary printed when no tests did run. - Thanks Florian Bruhin for the PR. + Thanks Freya Bruhin for the PR. - fix #1185 - ensure MANIFEST.in exactly matches what should go to a sdist - a number of documentation modernizations wrt good practices. @@ -9498,7 +9551,7 @@ time or change existing behaviors in order to make them less surprising/more use - fix issue934: when string comparison fails and a diff is too large to display without passing -vv, still show a few lines of the diff. - Thanks Florian Bruhin for the report and Bruno Oliveira for the PR. + Thanks Freya Bruhin for the report and Bruno Oliveira for the PR. - fix issue736: Fix a bug where fixture params would be discarded when combined with parametrization markers. @@ -9511,7 +9564,7 @@ time or change existing behaviors in order to make them less surprising/more use - parametrize now also generates meaningful test IDs for enum, regex and class objects (as opposed to class instances). - Thanks to Florian Bruhin for the PR. + Thanks to Freya Bruhin for the PR. - Add 'warns' to assert that warnings are thrown (like 'raises'). Thanks to Eric Hunsberger for the PR. @@ -9638,7 +9691,7 @@ time or change existing behaviors in order to make them less surprising/more use one will also have a "reprec" attribute with the recorded events/reports. - fix monkeypatch.setattr("x.y", raising=False) to actually not raise - if "y" is not a preexisting attribute. Thanks Florian Bruhin. + if "y" is not a preexisting attribute. Thanks Freya Bruhin. - fix issue741: make running output from testdir.run copy/pasteable Thanks Bruno Oliveira. @@ -9698,7 +9751,7 @@ time or change existing behaviors in order to make them less surprising/more use - fix issue833: --fixtures now shows all fixtures of collected test files, instead of just the fixtures declared on the first one. - Thanks Florian Bruhin for reporting and Bruno Oliveira for the PR. + Thanks Freya Bruhin for reporting and Bruno Oliveira for the PR. - fix issue863: skipped tests now report the correct reason when a skip/xfail condition is met when using multiple markers. diff --git a/doc/en/contact.rst b/doc/en/contact.rst index b2a1368eaba..311224eeef0 100644 --- a/doc/en/contact.rst +++ b/doc/en/contact.rst @@ -40,7 +40,7 @@ Mail in the pytest core team, who can also be contacted individually: * Bruno Oliveira (:user:`nicoddemus`, `bruno@pytest.org `_) - * Florian Bruhin (:user:`The-Compiler`, `florian@pytest.org `_) + * Freya Bruhin (:user:`The-Compiler`, `freya@pytest.org `_) * Pierre Sassoulas (:user:`Pierre-Sassoulas`, `pierre@pytest.org `_) * Ran Benita (:user:`bluetech`, `ran@pytest.org `_) * Ronny Pfannschmidt (:user:`RonnyPfannschmidt`, `ronny@pytest.org `_) @@ -51,7 +51,7 @@ Other - The :doc:`contribution guide ` for help on submitting pull requests to GitHub. -- Florian Bruhin (:user:`The-Compiler`) offers pytest professional teaching and +- Freya Bruhin (:user:`The-Compiler`) offers pytest professional teaching and consulting via `Bruhin Software `_. .. _`pytest issue tracker`: https://github.com/pytest-dev/pytest/issues diff --git a/doc/en/deprecations.rst b/doc/en/deprecations.rst index 65a05823517..57c583fd852 100644 --- a/doc/en/deprecations.rst +++ b/doc/en/deprecations.rst @@ -139,7 +139,7 @@ In ``8.2`` the ``exc_type`` parameter has been added, giving users the ability o to skip tests only if the module cannot really be found, and not because of some other error. Catching only :class:`ModuleNotFoundError` by default (and letting other errors propagate) would be the best solution, -however for backward compatibility, pytest will keep the existing behavior but raise an warning if: +however for backward compatibility, pytest will keep the existing behavior but raise a warning if: 1. The captured exception is of type :class:`ImportError`, and: 2. The user does not pass ``exc_type`` explicitly. @@ -358,7 +358,7 @@ The ``yield_fixture`` function/decorator ``pytest.yield_fixture`` is a deprecated alias for :func:`pytest.fixture`. -It has been so for a very long time, so can be search/replaced safely. +It has been so for a very long time, so it can be searched/replaced safely. Removed Features and Breaking Changes @@ -774,7 +774,7 @@ The ``pytest._fillfuncargs`` function This function was kept for backward compatibility with an older plugin. -It's functionality is not meant to be used directly, but if you must replace +Its functionality is not meant to be used directly, but if you must replace it, use `function._request._fillfixtures()` instead, though note this is not a public API and may break in the future. @@ -805,7 +805,7 @@ The ``--result-log`` option produces a stream of test reports which can be analysed at runtime, but it uses a custom format which requires users to implement their own parser. -The `pytest-reportlog `__ plugin provides a ``--report-log`` option, a more standard and extensible alternative, producing +The :pypi:`pytest-reportlog` plugin provides a ``--report-log`` option, a more standard and extensible alternative, producing one JSON object per-line, and should cover the same use cases. Please try it out and provide feedback. The ``pytest-reportlog`` plugin might even be merged into the core diff --git a/doc/en/example/attic.rst b/doc/en/example/attic.rst index 2b1f2766dce..3a2e228337e 100644 --- a/doc/en/example/attic.rst +++ b/doc/en/example/attic.rst @@ -75,7 +75,7 @@ decorate its result. This mechanism allows us to stay ignorant of how/where the function argument is provided - in our example from a `conftest plugin`_. -sidenote: the temporary directory used here are instances of +Side note: the temporary directories used here are instances of the `py.path.local`_ class which provides many of the os.path methods in a convenient way. diff --git a/doc/en/example/customdirectory.rst b/doc/en/example/customdirectory.rst index 6e326352a7e..705a3373654 100644 --- a/doc/en/example/customdirectory.rst +++ b/doc/en/example/customdirectory.rst @@ -36,7 +36,7 @@ You can create a ``manifest.json`` file and some test files: .. include:: customdirectory/tests/test_third.py :literal: -An you can now execute the test specification: +And you can now execute the test specification: .. code-block:: pytest diff --git a/doc/en/example/markers.rst b/doc/en/example/markers.rst index 4f6738207e1..c8e4172a696 100644 --- a/doc/en/example/markers.rst +++ b/doc/en/example/markers.rst @@ -411,7 +411,7 @@ A test file using this local plugin: def test_basic_db_operation(): pass -and an example invocations specifying a different environment than what +and an example invocation specifying a different environment than what the test needs: .. code-block:: pytest diff --git a/doc/en/example/nonpython.rst b/doc/en/example/nonpython.rst index bb879fb51ab..54391d72fd4 100644 --- a/doc/en/example/nonpython.rst +++ b/doc/en/example/nonpython.rst @@ -58,7 +58,12 @@ your own domain specific testing language this way. will be reported as a (red) string. ``reportinfo()`` is used for representing the test location and is also -consulted when reporting in ``verbose`` mode: +consulted when reporting in ``verbose`` mode. It should return a tuple +``(path, lineno, description)``, where: + +* ``path`` is the path shown in reports (usually ``self.path`` or ``self.fspath``). +* ``lineno`` is a zero-based line number, or ``0`` when no specific line applies. +* ``description`` is a short label shown for the collected item: .. code-block:: pytest diff --git a/doc/en/example/parametrize.rst b/doc/en/example/parametrize.rst index 7aec1364953..ae64a7c62d5 100644 --- a/doc/en/example/parametrize.rst +++ b/doc/en/example/parametrize.rst @@ -4,7 +4,7 @@ Parametrizing tests ================================================= -``pytest`` allows to easily parametrize test functions. +``pytest`` allows you to easily parametrize test functions. For basic docs, see :ref:`parametrize-basics`. In the following we provide some examples using @@ -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 - + @@ -642,7 +642,7 @@ As the result: - Four tests were collected - One test was deselected because it doesn't have the ``basic`` mark. -- Three tests with the ``basic`` mark was selected. +- Three tests with the ``basic`` mark were selected. - The test ``test_eval[1+7-8]`` passed, but the name is autogenerated and confusing. - The test ``test_eval[basic_2+4]`` passed. - The test ``test_eval[basic_6*9]`` was expected to fail and did fail. diff --git a/doc/en/example/pythoncollection.rst b/doc/en/example/pythoncollection.rst index 339944c4758..48ee2c8533f 100644 --- a/doc/en/example/pythoncollection.rst +++ b/doc/en/example/pythoncollection.rst @@ -142,7 +142,7 @@ The test collection would look like this: configfile: pytest.toml collected 2 items - + @@ -161,7 +161,7 @@ You can check for multiple glob patterns by adding a space between the patterns: .. note:: - the ``python_functions`` and ``python_classes`` options has no effect + the ``python_functions`` and ``python_classes`` options have no effect for ``unittest.TestCase`` test discovery because pytest delegates discovery of test case methods to unittest code. @@ -205,7 +205,7 @@ You can always peek at the collection tree without running tests like this: configfile: pytest.toml collected 3 items - + diff --git a/doc/en/example/simple.rst b/doc/en/example/simple.rst index 8b35f0ebca5..a07927280ae 100644 --- a/doc/en/example/simple.rst +++ b/doc/en/example/simple.rst @@ -416,10 +416,10 @@ running from a test you can do this: if os.environ.get("PYTEST_VERSION") is not None: - # Things you want to to do if your code is called by pytest. + # Things you want to do if your code is called by pytest. ... else: - # Things you want to to do if your code is not called by pytest. + # Things you want to do if your code is not called by pytest. ... @@ -553,12 +553,10 @@ an ``incremental`` marker which is to be used on classes: # content of conftest.py - from typing import Dict, Tuple - import pytest # store history of failures per test class name and per index in parametrize (if parametrize used) - _test_failed_incremental: Dict[str, Dict[Tuple[int, ...], str]] = {} + _test_failed_incremental: dict[str, dict[tuple[int, ...], str]] = {} def pytest_runtest_makereport(item, call): @@ -775,7 +773,7 @@ The two test modules in the ``a`` directory see the same ``db`` fixture instance while the one test in the sister-directory ``b`` doesn't see it. We could of course also define a ``db`` fixture in that sister directory's ``conftest.py`` file. Note that each fixture is only instantiated if there is a test actually needing -it (unless you use "autouse" fixture which are always executed ahead of the first test +it (unless you use "autouse" fixtures which are always executed ahead of the first test executing). @@ -883,11 +881,10 @@ here is a little example implemented via a local plugin: .. code-block:: python # content of conftest.py - from typing import Dict import pytest from pytest import StashKey, CollectReport - phase_report_key = StashKey[Dict[str, CollectReport]]() + phase_report_key = StashKey[dict[str, CollectReport]]() @pytest.hookimpl(wrapper=True, tryfirst=True) diff --git a/doc/en/explanation/ci.rst b/doc/en/explanation/ci.rst index 6f6734f395b..1c03f840b43 100644 --- a/doc/en/explanation/ci.rst +++ b/doc/en/explanation/ci.rst @@ -8,7 +8,7 @@ Rationale The goal of testing in a CI pipeline is different from testing locally. Indeed, you can quickly edit some code and run your tests again on your computer, but -it is not possible with CI pipeline. They run on a separate server and are +it is not possible with CI pipelines. They run on a separate server and are triggered by specific actions. From that observation, pytest can detect when it is in a CI environment and @@ -17,10 +17,10 @@ adapt some of its behaviours. How CI is detected ------------------ -Pytest knows it is in a CI environment when either one of these environment variables are set to a non-empty value: +Pytest knows it is in a CI environment when either one of these environment variables is set to a non-empty value: -* `CI`: used by many CI systems. -* `BUILD_NUMBER`: used by Jenkins. +* :envvar:`CI`: used by many CI systems. +* :envvar:`BUILD_NUMBER`: used by Jenkins. Effects on CI ------------- @@ -50,7 +50,7 @@ Running this locally, without any extra options, will output: $ pytest test_ci.py ... ========================= short test summary info ========================== - FAILED test_backends.py::test_db_initialized[d2] - Failed: deliberately f... + FAILED test_ci.py::test_db_initialized - Failed: deliberately f... *(Note the truncated text)* @@ -63,7 +63,7 @@ While running this on CI will output: $ pytest test_ci.py ... ========================= short test summary info ========================== - FAILED test_backends.py::test_db_initialized[d2] - Failed: deliberately failing + FAILED test_ci.py::test_db_initialized - Failed: deliberately failing for demo purpose, Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras facilisis, massa in suscipit dignissim, mauris lacus molestie nisi, quis varius metus nulla ut ipsum. diff --git a/doc/en/explanation/flaky.rst b/doc/en/explanation/flaky.rst index 8369e1d9311..918d6f10b36 100644 --- a/doc/en/explanation/flaky.rst +++ b/doc/en/explanation/flaky.rst @@ -42,7 +42,7 @@ It is of course possible (and common) for tests and fixtures to spawn threads th * Make sure to eventually wait on any spawned threads -- for example at the end of a test, or during the teardown of a fixture. * Avoid using primitives provided by pytest (:func:`pytest.warns`, :func:`pytest.raises`, etc) from multiple threads, as they are not thread-safe. -If your test suite uses threads and your are seeing flaky test results, do not discount the possibility that the test is implicitly using global state in pytest itself. +If your test suite uses threads and you are seeing flaky test results, do not discount the possibility that the test is implicitly using global state in pytest itself. Related features ^^^^^^^^^^^^^^^^ diff --git a/doc/en/explanation/goodpractices.rst b/doc/en/explanation/goodpractices.rst index bbc64ec662d..52474d148c6 100644 --- a/doc/en/explanation/goodpractices.rst +++ b/doc/en/explanation/goodpractices.rst @@ -143,13 +143,18 @@ which are better explained in this excellent `blog post`_ by Ionel Cristian Măr .. note:: - If you do not use an editable install and not use the ``src`` layout (``mypkg`` directly in the root + If you do not use an editable install and do not use the ``src`` layout (``mypkg`` directly in the root directory) you can rely on the fact that Python by default puts the current directory in ``sys.path`` to import your package and run ``python -m pytest`` to execute the tests against the local copy directly. See :ref:`pytest vs python -m pytest` for more information about the difference between calling ``pytest`` and ``python -m pytest``. +.. seealso:: + + :doc:`packaging:discussions/src-layout-vs-flat-layout` + The Python Packaging User Guide discusses the trade-offs between the ``src`` layout and ``flat`` layout. + Tests as part of application code ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -376,7 +381,7 @@ If you don't want to automatically pick up new options, you can enable options i strict_parametrization_ids = true strict_xfail = true -If you want to use strict mode but having trouble with a specific option, you can turn it off individually: +If you want to use strict mode but are having trouble with a specific option, you can turn it off individually: .. tab:: toml diff --git a/doc/en/funcarg_compare.rst b/doc/en/funcarg_compare.rst index bc5e7d3c515..7cd4c0f1676 100644 --- a/doc/en/funcarg_compare.rst +++ b/doc/en/funcarg_compare.rst @@ -18,7 +18,7 @@ The pre pytest-2.3 funcarg mechanism calls a factory each time a funcarg for a test function is required. If a factory wants to reuse a resource across different scopes, it often used the ``request.cached_setup()`` helper to manage caching of -resources. Here is a basic example how we could implement +resources. Here is a basic example of how we could implement a per-session Database object: .. code-block:: python @@ -39,10 +39,10 @@ a per-session Database object: There are several limitations and difficulties with this approach: -1. Scoping funcarg resource creation is not straight forward, instead one must +1. Scoping funcarg resource creation is not straightforward, instead one must understand the intricate cached_setup() method mechanics. -2. parametrizing the "db" resource is not straight forward: +2. parametrizing the "db" resource is not straightforward: you need to apply a "parametrize" decorator or implement a :hook:`pytest_generate_tests` hook calling :py:func:`~pytest.Metafunc.parametrize` which @@ -55,7 +55,7 @@ There are several limitations and difficulties with this approach: at the same time, making it hard for them to affect global state of the application under test. -4. there is no way how you can make use of funcarg factories +4. there is no way you can make use of funcarg factories in xUnit setup methods. 5. A non-parametrized fixture function cannot use a parametrized diff --git a/doc/en/getting-started.rst b/doc/en/getting-started.rst index 3ba30a90b34..76a4428c163 100644 --- a/doc/en/getting-started.rst +++ b/doc/en/getting-started.rst @@ -20,7 +20,7 @@ Install ``pytest`` .. code-block:: bash $ pytest --version - pytest 9.0.2 + pytest 9.0.3 .. _`simpletest`: diff --git a/doc/en/historical-notes.rst b/doc/en/historical-notes.rst index be67036d6ca..d93c7b94793 100644 --- a/doc/en/historical-notes.rst +++ b/doc/en/historical-notes.rst @@ -263,20 +263,24 @@ configuration value which you might have added: @pytest.mark.skipif("not config.getvalue('db')") def test_function(): ... -The equivalent with "boolean conditions" is: +The equivalent with "boolean conditions" using ``request.config`` is: .. code-block:: python - @pytest.mark.skipif(not pytest.config.getvalue("db"), reason="--db was not specified") + @pytest.fixture(autouse=True) + def skip_if_no_db(request): + if not request.config.getoption("--db", default=False): + pytest.skip("--db was not specified") + + def test_function(): pass .. note:: - You cannot use ``pytest.config.getvalue()`` in code - imported before pytest's argument parsing takes place. For example, - ``conftest.py`` files are imported before command line parsing and thus - ``config.getvalue()`` will not execute correctly. + ``pytest.config`` was removed in pytest 5.0. Use ``request.config`` + (via the ``request`` fixture) or the ``pytestconfig`` fixture instead. + See :ref:`pytest.config global deprecated` for details. ``pytest.set_trace()`` ---------------------- @@ -304,7 +308,7 @@ For more details see :ref:`breakpoints`. -Access of ``Module``, ``Function``, ``Class``, ``Instance``, ``File`` and ``Item`` through ``Node`` instances have long +Access of ``Module``, ``Function``, ``Class``, ``Instance``, ``File`` and ``Item`` through ``Node`` instances has long been documented as deprecated, but started to emit warnings from pytest ``3.9`` and onward. Users should just ``import pytest`` and access those objects using the ``pytest`` module. diff --git a/doc/en/how-to/assert.rst b/doc/en/how-to/assert.rst index 4ef2664b1d5..006cf475b02 100644 --- a/doc/en/how-to/assert.rst +++ b/doc/en/how-to/assert.rst @@ -218,7 +218,7 @@ To specify more details about the contained exception you can use :class:`pytest with pytest.RaisesGroup(pytest.RaisesExc(ValueError, match="foo")): raise ExceptionGroup("", (ValueError("foo"))) -They both supply a method :meth:`pytest.RaisesGroup.matches` :meth:`pytest.RaisesExc.matches` if you want to do matching outside of using it as a contextmanager. This can be helpful when checking ``.__context__`` or ``.__cause__``. +They both supply a method :meth:`pytest.RaisesGroup.matches` :meth:`pytest.RaisesExc.matches` if you want to do matching outside of using it as a :external+python:std:ref:`context manager `. This can be helpful when checking ``.__context__`` or ``.__cause__``. .. code-block:: python @@ -436,6 +436,10 @@ Special comparisons are done for a number of cases: * comparing long sequences: first failing indices * comparing dicts: different entries +In string context diffs, lines prefixed with ``-`` come from the left-hand side +of ``assert left == right``, while lines prefixed with ``+`` come from the +right-hand side. + See the :ref:`reporting demo ` for many more examples. Defining your own explanation for failed assertions diff --git a/doc/en/how-to/cache.rst b/doc/en/how-to/cache.rst index 4271ab469dc..ca345916fc5 100644 --- a/doc/en/how-to/cache.rst +++ b/doc/en/how-to/cache.rst @@ -33,7 +33,7 @@ Other plugins may access the `config.cache`_ object to set/get Rerunning only failures or failures first ----------------------------------------------- -First, let's create 50 test invocation of which only 2 fail: +First, let's create 50 test invocations of which only 2 fail: .. code-block:: python diff --git a/doc/en/how-to/capture-stdout-stderr.rst b/doc/en/how-to/capture-stdout-stderr.rst index 14807b9b777..5de89bc0e3f 100644 --- a/doc/en/how-to/capture-stdout-stderr.rst +++ b/doc/en/how-to/capture-stdout-stderr.rst @@ -6,7 +6,7 @@ How to capture stdout/stderr output Pytest intercepts stdout and stderr as configured by the :option:`--capture=` command-line argument or by using fixtures. The ``--capture=`` flag configures -reporting, whereas the fixtures offer more granular control and allows +reporting, whereas the fixtures offer more granular control and allow inspection of output during testing. The reports can be customized with the :option:`-r` flag. @@ -23,7 +23,7 @@ fail on attempts to read from it because it is rarely desired to wait for interactive input when running automated tests. By default capturing is done by intercepting writes to low level -file descriptors. This allows to capture output from simple +file descriptors. This allows capturing output from simple print statements as well as output from a subprocess started by a test. @@ -109,6 +109,8 @@ of the failing function and hide the other one: FAILED test_module.py::test_func2 - assert False ======================= 1 failed, 1 passed in 0.12s ======================== +.. _accessing-captured-output: + Accessing captured output from a test function --------------------------------------------------- @@ -162,3 +164,13 @@ as a context manager, disabling capture inside the ``with`` block: with capsys.disabled(): print("output not captured, going directly to sys.stdout") print("this output is also captured") + +.. note:: + + When a capture fixture such as :fixture:`capsys` or :fixture:`capfd` is used, + it takes precedence over the global capturing configuration set via + command-line options such as ``-s`` or ``--capture=no``. + + This means that output produced within a test using a capture fixture will + still be captured and available via ``readouterr()``, even if global capturing + is disabled. diff --git a/doc/en/how-to/capture-warnings.rst b/doc/en/how-to/capture-warnings.rst index 3f55467b434..b0ff6a74892 100644 --- a/doc/en/how-to/capture-warnings.rst +++ b/doc/en/how-to/capture-warnings.rst @@ -160,6 +160,15 @@ You can specify multiple filters with separate decorators: def test_one(): assert api_v1() == 1 +You can also pass multiple filters to a single mark by providing multiple arguments: + +.. code-block:: python + + # Later arguments take precedence, matching warnings.filterwarnings behavior. + @pytest.mark.filterwarnings("error", "ignore:api v1") + def test_one(): + assert api_v1() == 1 + .. important:: Regarding decorator order and filter precedence: @@ -220,7 +229,7 @@ This plugin is enabled by default but can be disabled entirely in your configura [pytest] addopts = -p no:warnings -Or passing ``-p no:warnings`` in the command-line. This might be useful if your test suites handles warnings +Or passing ``-p no:warnings`` in the command-line. This might be useful if your test suite handles warnings using an external system. @@ -286,8 +295,8 @@ Ensuring code triggers a deprecation warning -------------------------------------------- You can also use :func:`pytest.deprecated_call` for checking -that a certain function call triggers a ``DeprecationWarning`` or -``PendingDeprecationWarning``: +that a certain function call triggers a ``DeprecationWarning``, ``PendingDeprecationWarning`` or +``FutureWarning``: .. code-block:: python diff --git a/doc/en/how-to/doctest.rst b/doc/en/how-to/doctest.rst index 433b35b61ce..59d1033ed4f 100644 --- a/doc/en/how-to/doctest.rst +++ b/doc/en/how-to/doctest.rst @@ -185,7 +185,7 @@ Output format ------------- You can change the diff output format on failure for your doctests -by using one of standard doctest modules format in options +by using one of the standard doctest module's format options (see :data:`python:doctest.REPORT_UDIFF`, :data:`python:doctest.REPORT_CDIFF`, :data:`python:doctest.REPORT_NDIFF`, :data:`python:doctest.REPORT_ONLY_FIRST_FAILURE`): diff --git a/doc/en/how-to/fixtures.rst b/doc/en/how-to/fixtures.rst index 5c5a239e8d4..2f554fb8c60 100644 --- a/doc/en/how-to/fixtures.rst +++ b/doc/en/how-to/fixtures.rst @@ -471,7 +471,7 @@ marked ``smtp_connection`` fixture function. Running the test looks like this: ============================ 2 failed in 0.12s ============================= You see the two ``assert 0`` failing and more importantly you can also see -that the **exactly same** ``smtp_connection`` object was passed into the +that the **exact same** ``smtp_connection`` object was passed into the two test functions because pytest shows the incoming argument values in the traceback. As a result, the two test functions using ``smtp_connection`` run as quick as a single one because they reuse the same instance. @@ -1423,7 +1423,7 @@ Running the above tests results in the following test IDs being used: rootdir: /home/sweet/project collected 12 items - + @@ -1645,7 +1645,7 @@ Let's run the tests in verbose mode and with looking at the print-output: ============================ 8 passed in 0.12s ============================= You can see that the parametrized module-scoped ``modarg`` resource caused an -ordering of test execution that lead to the fewest possible "active" resources. +ordering of test execution that led to the fewest possible "active" resources. The finalizer for the ``mod1`` parametrized resource was executed before the ``mod2`` resource was setup. @@ -1654,7 +1654,7 @@ Then test_1 is executed with ``mod1``, then test_2 with ``mod1``, then test_1 with ``mod2`` and finally test_2 with ``mod2``. The ``otherarg`` parametrized resource (having function scope) was set up before -and teared down after every test that used it. +and torn down after every test that used it. .. _`usefixtures`: @@ -1762,8 +1762,8 @@ into a configuration file: Overriding fixtures on various levels ------------------------------------- -In relatively large test suite, you most likely need to ``override`` a ``global`` or ``root`` fixture with a ``locally`` -defined one, keeping the test code readable and maintainable. +In a relatively large test suite, you may want to *override* a fixture, to augment +or change its behavior inside of certain test modules or directories. Override a fixture on a folder (conftest) level ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1800,7 +1800,7 @@ Given the tests file structure is: def test_username(username): assert username == 'overridden-username' -As you can see, a fixture with the same name can be overridden for certain test folder level. +As you can see, a fixture with the same name can be overridden for a certain test directory level. Note that the ``base`` or ``super`` fixture can be accessed from the ``overriding`` fixture easily - used in the example above. @@ -1842,7 +1842,7 @@ Given the tests file structure is: def test_username(username): assert username == 'overridden-else-username' -In the example above, a fixture with the same name can be overridden for certain test module. +In the example above, a fixture with the same name can be overridden for a certain test module. Override a fixture with direct test parametrization diff --git a/doc/en/how-to/logging.rst b/doc/en/how-to/logging.rst index c0762e60928..25b4e9017e2 100644 --- a/doc/en/how-to/logging.rst +++ b/doc/en/how-to/logging.rst @@ -216,8 +216,8 @@ option names are: * :confval:`log_cli_date_format` If you need to record the whole test suite logging calls to a file, you can pass -:option:`--log-file=/path/to/log/file`. This log file is opened in write mode by default which -means that it will be overwritten at each run tests session. +:option:`--log-file=/path/to/log/file`. This log file is opened in write mode by default, which +means that it will be overwritten at each test session. If you'd like the file opened in append mode instead, then you can pass :option:`--log-file-mode=a`. Note that relative paths for the log-file location, whether passed on the CLI or declared in a config file, are always resolved relative to the current working directory. @@ -312,7 +312,7 @@ made in ``3.4`` after community feedback: * :ref:`Live Logs ` are now sent to ``sys.stdout`` and no longer require the :option:`-s` command-line option to work. -If you want to partially restore the logging behavior of version ``3.3``, you can add this options to your configuration +If you want to partially restore the logging behavior of version ``3.3``, you can add these options to your configuration file: .. tab:: toml @@ -331,4 +331,4 @@ file: log_cli = true log_level = NOTSET -More details about the discussion that lead to this changes can be read in :issue:`3013`. +More details about the discussion that led to these changes can be read in :issue:`3013`. diff --git a/doc/en/how-to/monkeypatch.rst b/doc/en/how-to/monkeypatch.rst index ad0c6e0e1c5..7442a85c10e 100644 --- a/doc/en/how-to/monkeypatch.rst +++ b/doc/en/how-to/monkeypatch.rst @@ -382,7 +382,7 @@ You can use the :py:meth:`monkeypatch.delitem ` to remove v def test_missing_user(monkeypatch): - # patch the DEFAULT_CONFIG t be missing the 'user' key + # patch the DEFAULT_CONFIG to be missing the 'user' key monkeypatch.delitem(app.DEFAULT_CONFIG, "user", raising=False) # Key error expected because a config is not passed, and the diff --git a/doc/en/how-to/output.rst b/doc/en/how-to/output.rst index d92b2131701..a594fcb3aab 100644 --- a/doc/en/how-to/output.rst +++ b/doc/en/how-to/output.rst @@ -771,7 +771,7 @@ record_testsuite_property .. versionadded:: 4.5 -If you want to add a properties node at the test-suite level, which may contains properties +If you want to add a properties node at the test-suite level, which may contain properties that are relevant to all tests, you can use the ``record_testsuite_property`` session-scoped fixture: The ``record_testsuite_property`` session-scoped fixture can be used to add properties relevant diff --git a/doc/en/how-to/plugins.rst b/doc/en/how-to/plugins.rst index 48a45619324..c6641eb8484 100644 --- a/doc/en/how-to/plugins.rst +++ b/doc/en/how-to/plugins.rst @@ -158,7 +158,7 @@ manually specify each plugin with :option:`-p` or :envvar:`PYTEST_PLUGINS`, you .. code-block:: bash - pytest --disable-plugin-autoload -p NAME,NAME2 + pytest --disable-plugin-autoload -p NAME -p NAME2 .. tab:: toml @@ -180,3 +180,31 @@ manually specify each plugin with :option:`-p` or :envvar:`PYTEST_PLUGINS`, you .. versionadded:: 8.4 The :option:`--disable-plugin-autoload` command-line flag. + +.. note:: + + :option:`-p` and :envvar:`PYTEST_PLUGINS` are both ways to explicitly control which + plugins are loaded, but they serve slightly different use-cases. + + * :option:`-p` loads (or disables with ``-p no:``) a plugin by name or entry point + for a specific pytest invocation, and is processed early during startup. + * :envvar:`PYTEST_PLUGINS` is a comma-separated list of Python modules that are imported + and registered as plugins during startup. This mechanism is commonly used by test + suites, for example when testing a plugin. + + When explicitly controlling plugin loading (especially with + :envvar:`PYTEST_DISABLE_PLUGIN_AUTOLOAD` or :option:`--disable-plugin-autoload`), + avoid specifying the same plugin via multiple mechanisms. Registering the same plugin + more than once can lead to errors during plugin registration. + +Examples: + +.. code-block:: bash + + # Disable auto-loading and load only specific plugins for this invocation + PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 pytest -p xdist + +.. code-block:: bash + + # Disable auto-loading and load plugin modules during startup + PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 PYTEST_PLUGINS=mymodule.plugin,xdist pytest diff --git a/doc/en/how-to/skipping.rst b/doc/en/how-to/skipping.rst index 3b4d412843d..488f71b09f9 100644 --- a/doc/en/how-to/skipping.rst +++ b/doc/en/how-to/skipping.rst @@ -311,7 +311,7 @@ even executed, use the ``run`` parameter as ``False``: @pytest.mark.xfail(run=False) def test_function(): ... -This is specially useful for xfailing tests that are crashing the interpreter and should be +This is particularly useful for xfailing tests that are crashing the interpreter and should be investigated later. .. _`xfail strict tutorial`: diff --git a/doc/en/how-to/subtests.rst b/doc/en/how-to/subtests.rst index 5a08dbc4769..93b9d052afd 100644 --- a/doc/en/how-to/subtests.rst +++ b/doc/en/how-to/subtests.rst @@ -136,4 +136,4 @@ Subtests This feature was originally implemented as a separate plugin in `pytest-subtests `__, but since ``9.0`` has been merged into the core. - The core implementation should be compatible to the plugin implementation, except it does not contain custom command-line options to control subtest output. + The core implementation should be compatible with the plugin implementation, except it does not contain custom command-line options to control subtest output. diff --git a/doc/en/how-to/usage.rst b/doc/en/how-to/usage.rst index 94e6d94d834..35b07bfe8c1 100644 --- a/doc/en/how-to/usage.rst +++ b/doc/en/how-to/usage.rst @@ -7,7 +7,7 @@ How to invoke pytest .. seealso:: :ref:`Complete pytest command-line flags reference ` In general, pytest is invoked with the command ``pytest`` (see below for :ref:`other ways to invoke pytest -`). This will execute all tests in all files whose names follow the form ``test_*.py`` or ``\*_test.py`` +`). This will execute all tests in all files whose names follow the form ``test_*.py`` or ``*_test.py`` in the current directory and its subdirectories. More generally, pytest follows :ref:`standard test discovery rules `. diff --git a/doc/en/how-to/writing_hook_functions.rst b/doc/en/how-to/writing_hook_functions.rst index cd18301ce84..d5d6d2ae4f7 100644 --- a/doc/en/how-to/writing_hook_functions.rst +++ b/doc/en/how-to/writing_hook_functions.rst @@ -94,7 +94,7 @@ around the actual hook implementations, in which case it can return the result value of the ``yield``. The simplest (though useless) hook wrapper is ``return (yield)``. -In other cases, the wrapper wants the adjust or adapt the result, in which case +In other cases, the wrapper wants to adjust or adapt the result, in which case it can return a new value. If the result of the underlying hook is a mutable object, the wrapper may modify that result, but it's probably better to avoid it. diff --git a/doc/en/how-to/writing_plugins.rst b/doc/en/how-to/writing_plugins.rst index 6b7e2a7e496..56043a14f97 100644 --- a/doc/en/how-to/writing_plugins.rst +++ b/doc/en/how-to/writing_plugins.rst @@ -48,7 +48,7 @@ Plugin discovery order at tool startup 5. by loading all plugins specified through the :envvar:`PYTEST_PLUGINS` environment variable. -6. by loading all "initial ":file:`conftest.py` files: +6. by loading all "initial" :file:`conftest.py` files: - determine the test paths: specified on the command line, otherwise in :confval:`testpaths` if defined and running from the rootdir, otherwise the diff --git a/doc/en/index.rst b/doc/en/index.rst index b98c886d981..1140640c80a 100644 --- a/doc/en/index.rst +++ b/doc/en/index.rst @@ -2,7 +2,7 @@ .. sidebar:: **Next Open Trainings and Events** - - `Professional Testing with Python `_, via `Python Academy `_ (3 day in-depth training), **March 3th -- 5th 2026**, Leipzig (DE) / Remote + - `Professional Testing with Python `_, via `Python Academy `_ (3 day in-depth training), **March 9th -- 11th 2027**, Leipzig (DE) / Remote Also see :doc:`previous talks and blogposts ` diff --git a/doc/en/reference/customize.rst b/doc/en/reference/customize.rst index b2e7d64cc26..8903ceadf68 100644 --- a/doc/en/reference/customize.rst +++ b/doc/en/reference/customize.rst @@ -103,6 +103,10 @@ pyproject.toml "integration", ] + For projects that still run pytest versions older than 6.0, keep + ``minversion`` in ``pytest.ini`` or ``setup.cfg`` too. Those versions + do not read ``pyproject.toml``. + tox.ini ~~~~~~~ @@ -160,7 +164,7 @@ the command line arguments (specified test files, paths) and on the existence of configuration files. The determined ``rootdir`` and ``configfile`` are printed as part of the pytest header during startup. -Here's a summary what ``pytest`` uses ``rootdir`` for: +Here's a summary of what ``pytest`` uses ``rootdir`` for: * Construct *nodeids* during collection; each test is assigned a unique *nodeid* which is rooted at the ``rootdir`` and takes into account @@ -204,7 +208,7 @@ Here is the algorithm which finds the rootdir from ``args``: directory. This allows the use of pytest in structures that are not part of a package and don't have any particular configuration file. -If no ``args`` are given, pytest collects test below the current working +If no ``args`` are given, pytest collects tests below the current working directory and also starts determining the ``rootdir`` from there. Files will only be matched for configuration if: @@ -274,7 +278,7 @@ check for configuration files as follows: ``pytest --log-output ../../test.log args``. Then ``args`` is mandatory, otherwise pytest uses the folder of test.log for rootdir determination (see also :issue:`1435`). - A dot ``.`` for referencing to the current working directory is also + A dot ``.`` for referencing the current working directory is also possible. diff --git a/doc/en/reference/exit-codes.rst b/doc/en/reference/exit-codes.rst index b695ca3702e..49aaca19121 100644 --- a/doc/en/reference/exit-codes.rst +++ b/doc/en/reference/exit-codes.rst @@ -20,7 +20,7 @@ They are represented by the :class:`pytest.ExitCode` enum. The exit codes being .. note:: - If you would like to customize the exit code in some scenarios, specially when + If you would like to customize the exit code in some scenarios, specifically when no tests are collected, consider using the `pytest-custom_exit_code `__ plugin. diff --git a/doc/en/reference/fixtures.rst b/doc/en/reference/fixtures.rst index b0fa8660f9b..c4a8d01ff0e 100644 --- a/doc/en/reference/fixtures.rst +++ b/doc/en/reference/fixtures.rst @@ -277,10 +277,10 @@ the test's search for fixtures would look like: pytest will only search for ``a_fix`` and ``b_fix`` in the plugins after searching for them first in the scopes inside ``tests/``. -.. note: +.. note:: pytest can tell you what fixtures are available for a given test if you call - ``pytests`` along with the test's name (or the scope it's in), and provide + ``pytest`` along with the test's name (or the scope it's in), and provide the :option:`--fixtures` flag, e.g. ``pytest --fixtures test_something.py`` (fixtures with names that start with ``_`` will only be shown if you also provide the :option:`-v` flag). @@ -354,7 +354,7 @@ an order of operations for a given test. If there's any ambiguity, and the order of operations can be interpreted more than one way, you should assume pytest could go with any one of those interpretations at any point. -For example, if ``d`` didn't request ``c``, i.e.the graph would look like this: +For example, if ``d`` didn't request ``c``, i.e. the graph would look like this: .. image:: /example/fixtures/test_fixtures_order_dependencies_unclear.* :align: center @@ -448,10 +448,10 @@ for the tests inside ``TestClassWithoutAutouse``, since they can reference can't see ``c3``. -.. note: +.. note:: pytest can tell you what order the fixtures will execute in for a given test - if you call ``pytests`` along with the test's name (or the scope it's in), + if you call ``pytest`` along with the test's name (or the scope it's in), and provide the :option:`--setup-plan` flag, e.g. ``pytest --setup-plan test_something.py`` (fixtures with names that start with ``_`` will only be shown if you also provide the :option:`-v` flag). diff --git a/doc/en/reference/reference.rst b/doc/en/reference/reference.rst index 9d14e9147fc..3760add53cf 100644 --- a/doc/en/reference/reference.rst +++ b/doc/en/reference/reference.rst @@ -18,7 +18,7 @@ The current pytest version, as a string:: >>> import pytest >>> pytest.__version__ - '7.0.0' + '9.0.2' .. _`hidden-param`: @@ -757,6 +757,7 @@ items, delete or otherwise amend the test items: If this hook is implemented in ``conftest.py`` files, it always receives all collected items, not only those under the ``conftest.py`` where it is implemented. +.. hook:: pytest_collection_finish .. autofunction:: pytest_collection_finish Test running (runtest) hooks @@ -1178,77 +1179,77 @@ Environment variables that can be used to change pytest's behavior. .. envvar:: CI -When set to a non-empty value, pytest acknowledges that is running in a CI process. See also :ref:`ci-pipelines`. + When set to a non-empty value, pytest acknowledges that it is running in a CI process. See also :ref:`ci-pipelines`. .. envvar:: BUILD_NUMBER -When set to a non-empty value, pytest acknowledges that is running in a CI process. Alternative to :envvar:`CI`. See also :ref:`ci-pipelines`. + When set to a non-empty value, pytest acknowledges that it is running in a CI process. Alternative to :envvar:`CI`. See also :ref:`ci-pipelines`. .. envvar:: PYTEST_ADDOPTS -This contains a command-line (parsed by the py:mod:`shlex` module) that will be **prepended** to the command line given -by the user, see :ref:`adding default options` for more information. + This contains a command-line (parsed by the py:mod:`shlex` module) that will be **prepended** to the command line given + by the user, see :ref:`adding default options` for more information. .. envvar:: PYTEST_VERSION -This environment variable is defined at the start of the pytest session and is undefined afterwards. -It contains the value of ``pytest.__version__``, and among other things can be used to easily check if a code is running from within a pytest run. + This environment variable is defined at the start of the pytest session and is undefined afterwards. + It contains the value of ``pytest.__version__``, and among other things can be used to easily check if a code is running from within a pytest run. .. envvar:: PYTEST_CURRENT_TEST -This is not meant to be set by users, but is set by pytest internally with the name of the current test so other -processes can inspect it, see :ref:`pytest current test env` for more information. + This is not meant to be set by users, but is set by pytest internally with the name of the current test so other + processes can inspect it, see :ref:`pytest current test env` for more information. .. envvar:: PYTEST_DEBUG -When set, pytest will print tracing and debug information. + When set, pytest will print tracing and debug information. .. envvar:: PYTEST_DEBUG_TEMPROOT -Root for temporary directories produced by fixtures like :fixture:`tmp_path` -as discussed in :ref:`temporary directory location and retention`. + Root for temporary directories produced by fixtures like :fixture:`tmp_path` + as discussed in :ref:`temporary directory location and retention`. .. envvar:: PYTEST_DISABLE_PLUGIN_AUTOLOAD -When set, disables plugin auto-loading through :std:doc:`entry point packaging -metadata `. Only plugins -explicitly specified in :envvar:`PYTEST_PLUGINS` or with :option:`-p` will be loaded. -See also :ref:`--disable-plugin-autoload `. + When set, disables plugin auto-loading through :std:doc:`entry point packaging + metadata `. Only plugins + explicitly specified in :envvar:`PYTEST_PLUGINS` or with :option:`-p` will be loaded. + See also :ref:`--disable-plugin-autoload `. .. envvar:: PYTEST_PLUGINS -Contains comma-separated list of modules that should be loaded as plugins: + Contains comma-separated list of modules that should be loaded as plugins: -.. code-block:: bash + .. code-block:: bash - export PYTEST_PLUGINS=mymodule.plugin,xdist + export PYTEST_PLUGINS=mymodule.plugin,xdist -See also :option:`-p`. + See also :option:`-p`. .. envvar:: PYTEST_THEME -Sets a `pygment style `_ to use for the code output. + Sets a `pygment style `_ to use for the code output. .. envvar:: PYTEST_THEME_MODE -Sets the :envvar:`PYTEST_THEME` to be either *dark* or *light*. + Sets the :envvar:`PYTEST_THEME` to be either *dark* or *light*. .. envvar:: PY_COLORS -When set to ``1``, pytest will use color in terminal output. -When set to ``0``, pytest will not use color. -``PY_COLORS`` takes precedence over ``NO_COLOR`` and ``FORCE_COLOR``. + When set to ``1``, pytest will use color in terminal output. + When set to ``0``, pytest will not use color. + ``PY_COLORS`` takes precedence over ``NO_COLOR`` and ``FORCE_COLOR``. .. envvar:: NO_COLOR -When set to a non-empty string (regardless of value), pytest will not use color in terminal output. -``PY_COLORS`` takes precedence over ``NO_COLOR``, which takes precedence over ``FORCE_COLOR``. -See `no-color.org `__ for other libraries supporting this community standard. + When set to a non-empty string (regardless of value), pytest will not use color in terminal output. + ``PY_COLORS`` takes precedence over ``NO_COLOR``, which takes precedence over ``FORCE_COLOR``. + See `no-color.org `__ for other libraries supporting this community standard. .. envvar:: FORCE_COLOR -When set to a non-empty string (regardless of value), pytest will use color in terminal output. -``PY_COLORS`` and ``NO_COLOR`` take precedence over ``FORCE_COLOR``. + When set to a non-empty string (regardless of value), pytest will use color in terminal output. + ``PY_COLORS`` and ``NO_COLOR`` take precedence over ``FORCE_COLOR``. Exceptions ---------- @@ -1314,7 +1315,7 @@ Configuration Options Here is a list of builtin configuration options that may be written in a ``pytest.ini`` (or ``.pytest.ini``), ``pyproject.toml``, ``tox.ini``, or ``setup.cfg`` file, usually located at the root of your repository. -To see each file format in details, see :ref:`config file formats`. +To see each file format in detail, see :ref:`config file formats`. .. warning:: Usage of ``setup.cfg`` is not recommended except for very simple use cases. ``.cfg`` @@ -1585,7 +1586,6 @@ passed multiple times. The expected format is ``name=value``. For example:: faulthandler_timeout = 5 For more information please refer to :ref:`faulthandler`. - For more information please refer to :ref:`faulthandler`. .. confval:: filterwarnings @@ -1836,7 +1836,8 @@ passed multiple times. The expected format is ``name=value``. For example:: Sets the minimum log message level that should be captured for live logging. The integer value or - the names of the levels can be used. + the names of the levels can be used. Note in TOML the integer must be quoted, as there is no support + for config parameters of mixed type. .. tab:: toml @@ -1844,6 +1845,7 @@ passed multiple times. The expected format is ``name=value``. For example:: [pytest] log_cli_level = "INFO" + log_cli_level = "10" .. tab:: ini @@ -1851,6 +1853,7 @@ passed multiple times. The expected format is ``name=value``. For example:: [pytest] log_cli_level = INFO + log_cli_level = 10 For more information, see :ref:`live_logs`. @@ -1951,7 +1954,8 @@ passed multiple times. The expected format is ``name=value``. For example:: Sets the minimum log message level that should be captured for the logging file. The integer value or - the names of the levels can be used. + the names of the levels can be used. Note in TOML the integer must be quoted, as there is no support + for config parameters of mixed type. .. tab:: toml @@ -1959,6 +1963,7 @@ passed multiple times. The expected format is ``name=value``. For example:: [pytest] log_file_level = "INFO" + log_cli_level = "10" .. tab:: ini @@ -1966,6 +1971,7 @@ passed multiple times. The expected format is ``name=value``. For example:: [pytest] log_file_level = INFO + log_cli_level = 10 For more information, see :ref:`logging`. @@ -2020,7 +2026,8 @@ passed multiple times. The expected format is ``name=value``. For example:: Sets the minimum log message level that should be captured for logging capture. The integer value or - the names of the levels can be used. + the names of the levels can be used. Note in TOML the integer must be quoted, as there is no support + for config parameters of mixed type. .. tab:: toml @@ -2028,6 +2035,7 @@ passed multiple times. The expected format is ``name=value``. For example:: [pytest] log_level = "INFO" + log_cli_level = "10" .. tab:: ini @@ -2035,6 +2043,7 @@ passed multiple times. The expected format is ``name=value``. For example:: [pytest] log_level = INFO + log_cli_level = 10 For more information, see :ref:`logging`. @@ -2538,7 +2547,7 @@ passed multiple times. The expected format is ``name=value``. For example:: .. confval:: truncation_limit_lines - Controls maximum number of linesto truncate assertion message contents. + Controls maximum number of lines to truncate assertion message contents. Setting value to ``0`` disables the lines limit for truncation. @@ -3174,7 +3183,7 @@ See :ref:`logging` for a guide on using these flags. .. option:: --log-file=PATH - Path to a file when logging will be written to. + Path to a file logging will be written to. .. option:: --log-file-mode diff --git a/doc/en/requirements.txt b/doc/en/requirements.txt index fcaaee695c9..d672a9d7e15 100644 --- a/doc/en/requirements.txt +++ b/doc/en/requirements.txt @@ -2,7 +2,8 @@ pluggy>=1.5.0 pygments-pytest>=2.5.0 sphinx-removed-in>=0.2.0 -sphinx>=7 +# Pinning to <9.0 due to https://github.com/python-trio/sphinxcontrib-trio/issues/399. +sphinx>=7,<9.0 sphinxcontrib-trio sphinxcontrib-svg2pdfconverter furo diff --git a/doc/en/sponsor.rst b/doc/en/sponsor.rst index 8362a7f0a3a..6ad722be94c 100644 --- a/doc/en/sponsor.rst +++ b/doc/en/sponsor.rst @@ -2,7 +2,7 @@ Sponsor ======= pytest is maintained by a team of volunteers from all around the world in their free time. While -we work on pytest because we love the project and use it daily at our daily jobs, monetary +we work on pytest because we love the project and use it daily in our jobs, monetary compensation when possible is welcome to justify time away from friends, family and personal time. Money is also used to fund local sprints, merchandising (stickers to distribute in conferences for example) @@ -12,7 +12,7 @@ OpenCollective -------------- `Open Collective`_ is an online funding platform for open and transparent communities. -It provide tools to raise money and share your finances in full transparency. +It provides tools to raise money and share your finances in full transparency. It is the platform of choice for individuals and companies that want to make one-time or monthly donations directly to the project. diff --git a/doc/en/talks.rst b/doc/en/talks.rst index b9b153a792e..a45c05c6f2f 100644 --- a/doc/en/talks.rst +++ b/doc/en/talks.rst @@ -17,19 +17,19 @@ Books Talks and blog postings --------------------------------------------- -- Training: `pytest - simple, rapid and fun testing with Python `_, Florian Bruhin, PyConDE 2022 +- Training: `pytest - simple, rapid and fun testing with Python `_, Freya Bruhin, PyConDE 2022 -- `pytest: Simple, rapid and fun testing with Python, `_ (@ 4:22:32), Florian Bruhin, WeAreDevelopers World Congress 2021 +- `pytest: Simple, rapid and fun testing with Python, `_ (@ 4:22:32), Freya Bruhin, WeAreDevelopers World Congress 2021 -- Webinar: `pytest: Test Driven Development für Python (German) `_, Florian Bruhin, via mylearning.ch, 2020 +- Webinar: `pytest: Test Driven Development für Python (German) `_, Freya Bruhin, via mylearning.ch, 2020 - Webinar: `Simplify Your Tests with Fixtures `_, Oliver Bestwalter, via JetBrains, 2020 -- Training: `Introduction to pytest - simple, rapid and fun testing with Python `_, Florian Bruhin, PyConDE 2019 +- Training: `Introduction to pytest - simple, rapid and fun testing with Python `_, Freya Bruhin, PyConDE 2019 - Abridged metaprogramming classics - this episode: pytest, Oliver Bestwalter, PyConDE 2019 (`repository `__, `recording `__) -- Testing PySide/PyQt code easily using the pytest framework, Florian Bruhin, Qt World Summit 2019 (`slides `__, `recording `__) +- Testing PySide/PyQt code easily using the pytest framework, Freya Bruhin, Qt World Summit 2019 (`slides `__, `recording `__) - `pytest: recommendations, basic packages for testing in Python and Django, Andreu Vallbona, PyBCN June 2019 `_. @@ -41,7 +41,7 @@ Talks and blog postings - `Pythonic testing, Igor Starikov (Russian, PyNsk, November 2016) `_. -- `pytest - Rapid Simple Testing, Florian Bruhin, Swiss Python Summit 2016 +- `pytest - Rapid Simple Testing, Freya Bruhin, Swiss Python Summit 2016 `_. - `Improve your testing with Pytest and Mock, Gabe Hollombe, PyCon SG 2015 diff --git a/pyproject.toml b/pyproject.toml index f57d7e8e85b..31b8a029ec5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ authors = [ { name = "Ronny Pfannschmidt" }, { name = "Floris Bruynooghe" }, { name = "Brianna Laugher" }, - { name = "Florian Bruhin" }, + { name = "Freya Bruhin" }, { name = "Others (See AUTHORS)" }, ] requires-python = ">=3.10" diff --git a/src/_pytest/_code/code.py b/src/_pytest/_code/code.py index add2a493ca7..4cf99a77340 100644 --- a/src/_pytest/_code/code.py +++ b/src/_pytest/_code/code.py @@ -1193,9 +1193,15 @@ def repr_excinfo(self, excinfo: ExceptionInfo[BaseException]) -> ExceptionChainR format_exception( type(excinfo.value), excinfo.value, - traceback[0]._rawentry, + traceback[0]._rawentry if traceback else None, ) ) + if not traceback: + reprtraceback.extraline = ( + "All traceback entries are hidden. " + "Pass `--full-trace` to see hidden and internal frames." + ) + else: reprtraceback = self.repr_traceback(excinfo_) reprcrash = excinfo_._getreprcrash() diff --git a/src/_pytest/_py/path.py b/src/_pytest/_py/path.py index b7131b08a20..998a7819972 100644 --- a/src/_pytest/_py/path.py +++ b/src/_pytest/_py/path.py @@ -137,7 +137,7 @@ class NeverRaised(Exception): class Visitor: def __init__(self, fil, rec, ignore, bf, sort): - if isinstance(fil, str): + if isinstance(fil, (str, bytes)): fil = FNMatcher(fil) if isinstance(rec, str): self.rec: Callable[[LocalPath], bool] = FNMatcher(rec) diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 6b02e160e1a..a027dbc02a4 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -814,6 +814,12 @@ def consider_pluginarg(self, arg: str) -> None: if name in essential_plugins: raise UsageError(f"plugin {name} cannot be disabled") + if name.endswith("conftest.py"): + raise UsageError( + f"Blocking conftest files using -p is not supported: -p no:{name}\n" + "conftest.py files are not plugins and cannot be disabled via -p.\n" + ) + # PR #4304: remove stepwise if cacheprovider is blocked. if name == "cacheprovider": self.set_blocked("stepwise") diff --git a/src/_pytest/hookspec.py b/src/_pytest/hookspec.py index c5bcc36ad4b..dab3fb698a2 100644 --- a/src/_pytest/hookspec.py +++ b/src/_pytest/hookspec.py @@ -251,8 +251,8 @@ def pytest_collection(session: Session) -> object | None: 1. ``pytest_deselected(items)`` for any deselected items (may be called multiple times) - 3. ``pytest_collection_finish(session)`` - 4. Set ``session.items`` to the list of collected items + 3. Set ``session.items`` to the list of collected items + 4. ``pytest_collection_finish(session)`` 5. Set ``session.testscollected`` to the number of collected items You can implement this hook to only perform some action before collection, diff --git a/src/_pytest/mark/structures.py b/src/_pytest/mark/structures.py index 16bb6d81119..97842fc5704 100644 --- a/src/_pytest/mark/structures.py +++ b/src/_pytest/mark/structures.py @@ -496,7 +496,7 @@ def __call__(self, arg: Markable) -> Markable: ... @overload def __call__( self, - condition: str | bool = False, + condition: str | bool = True, *conditions: str | bool, reason: str = ..., run: bool = ..., diff --git a/src/_pytest/python_api.py b/src/_pytest/python_api.py index 1e389eb0663..bab70aa4a8c 100644 --- a/src/_pytest/python_api.py +++ b/src/_pytest/python_api.py @@ -242,7 +242,7 @@ def _repr_compare(self, other_side: Mapping[object, float]) -> list[str]: f"Lengths: {len(self.expected)} and {len(other_side)}", ] - if set(self.expected.keys()) != set(other_side.keys()): + if self.expected.keys() != other_side.keys(): return [ "comparison failed.", f"Mappings has different keys: expected {self.expected.keys()} but got {other_side.keys()}", @@ -256,9 +256,8 @@ def _repr_compare(self, other_side: Mapping[object, float]) -> list[str]: max_abs_diff = -math.inf max_rel_diff = -math.inf different_ids = [] - for (approx_key, approx_value), other_value in zip( - approx_side_as_map.items(), other_side.values(), strict=True - ): + for approx_key, approx_value in approx_side_as_map.items(): + other_value = other_side[approx_key] if approx_value != other_value: if approx_value.expected is not None and other_value is not None: try: diff --git a/src/_pytest/tmpdir.py b/src/_pytest/tmpdir.py index 855ad273ecf..66ca9f190e3 100644 --- a/src/_pytest/tmpdir.py +++ b/src/_pytest/tmpdir.py @@ -9,6 +9,7 @@ from pathlib import Path import re from shutil import rmtree +import stat import tempfile from typing import Any from typing import final @@ -170,16 +171,37 @@ def getbasetemp(self) -> Path: # Also, to keep things private, fixup any world-readable temp # rootdir's permissions. Historically 0o755 was used, so we can't # just error out on this, at least for a while. + # Don't follow symlinks, otherwise we're open to symlink-swapping + # TOCTOU vulnerability. + # This check makes us vulnerable to a DoS - a user can `mkdir + # /tmp/pytest-of-otheruser` and then `otheruser` will fail this + # check. For now we don't consider it a real problem. otheruser can + # change their TMPDIR or --basetemp, and maybe give the prankster a + # good scolding. uid = get_user_id() if uid is not None: - rootdir_stat = rootdir.stat() + stat_follow_symlinks = ( + False if os.stat in os.supports_follow_symlinks else True + ) + rootdir_stat = rootdir.stat(follow_symlinks=stat_follow_symlinks) + if stat.S_ISLNK(rootdir_stat.st_mode): + raise OSError( + f"The temporary directory {rootdir} is a symbolic link. " + "Fix this and try again." + ) if rootdir_stat.st_uid != uid: raise OSError( f"The temporary directory {rootdir} is not owned by the current user. " "Fix this and try again." ) if (rootdir_stat.st_mode & 0o077) != 0: - os.chmod(rootdir, rootdir_stat.st_mode & ~0o077) + chmod_follow_symlinks = ( + False if os.chmod in os.supports_follow_symlinks else True + ) + rootdir.chmod( + rootdir_stat.st_mode & ~0o077, + follow_symlinks=chmod_follow_symlinks, + ) keep = self._retention_count if self._retention_policy == "none": keep = 0 diff --git a/src/_pytest/unittest.py b/src/_pytest/unittest.py index 23b92724f5d..31be8847821 100644 --- a/src/_pytest/unittest.py +++ b/src/_pytest/unittest.py @@ -409,6 +409,10 @@ def addSubTest( | tuple[type[BaseException], BaseException, TracebackType] | None, ) -> None: + # Importing this private symbol locally in case this symbol is renamed/removed in the future; importing + # it globally would break pytest entirely, importing it locally only will break unittests using `addSubTest`. + from unittest.case import _subtest_msg_sentinel # type: ignore[attr-defined] + exception_info: ExceptionInfo[BaseException] | None match exc_info: case tuple(): @@ -427,7 +431,7 @@ def addSubTest( when="call", _ispytest=True, ) - msg = test._message if isinstance(test._message, str) else None # type: ignore[attr-defined] + msg = None if test._message is _subtest_msg_sentinel else str(test._message) # type: ignore[attr-defined] report = self.ihook.pytest_runtest_makereport(item=self, call=call_info) sub_report = SubtestReport._new( report, diff --git a/testing/code/test_excinfo.py b/testing/code/test_excinfo.py index 476720f0bbe..70499fec893 100644 --- a/testing/code/test_excinfo.py +++ b/testing/code/test_excinfo.py @@ -1897,19 +1897,23 @@ def test_nested_multiple() -> None: @pytest.mark.parametrize("tbstyle", ("long", "short", "auto", "line", "native")) -def test_all_entries_hidden(pytester: Pytester, tbstyle: str) -> None: +@pytest.mark.parametrize("group", (True, False), ids=("group", "bare")) +def test_all_entries_hidden(pytester: Pytester, tbstyle: str, group: bool) -> None: """Regression test for #10903.""" pytester.makepyfile( - """ + f""" + import sys + if sys.version_info < (3, 11): + from exceptiongroup import ExceptionGroup def test(): __tracebackhide__ = True - 1 / 0 + raise {'ExceptionGroup("", [ValueError("bar")])' if group else 'ValueError("bar")'} """ ) result = pytester.runpytest("--tb", tbstyle) assert result.ret == 1 if tbstyle != "line": - result.stdout.fnmatch_lines(["*ZeroDivisionError: division by zero"]) + result.stdout.fnmatch_lines(["*ValueError: bar"]) if tbstyle not in ("line", "native"): result.stdout.fnmatch_lines(["All traceback entries are hidden.*"]) diff --git a/testing/python/approx.py b/testing/python/approx.py index f870b9bd4d8..481df80565c 100644 --- a/testing/python/approx.py +++ b/testing/python/approx.py @@ -1062,6 +1062,46 @@ def test_approx_dicts_with_mismatch_on_keys(self) -> None: ): assert actual == approx(expected) + def test_approx_on_unordered_mapping_with_mismatch( + self, pytester: Pytester + ) -> None: + """https://github.com/pytest-dev/pytest/issues/12444""" + pytester.makepyfile( + """ + import pytest + + def test_approx_on_unordered_mapping_with_mismatch(): + expected = {"a": 1, "b": 2, "c": 3, "d": 4} + actual = {"d": 4, "c": 5, "a": 8, "b": 2} + assert actual == pytest.approx(expected) + """ + ) + result = pytester.runpytest() + result.assert_outcomes(failed=1) + result.stdout.fnmatch_lines( + [ + "*comparison failed.**Mismatched elements: 2 / 4:*", + "*Max absolute difference: 7*", + "*Index | Obtained | Expected *", + "* a * | 8 * | 1 *", + "* c * | 5 * | 3 *", + ] + ) + + def test_approx_on_unordered_mapping_matching(self, pytester: Pytester) -> None: + """https://github.com/pytest-dev/pytest/issues/12444""" + pytester.makepyfile( + """ + import pytest + def test_approx_on_unordered_mapping_matching(): + expected = {"a": 1, "b": 2, "c": 3, "d": 4} + actual = {"d": 4, "c": 3, "a": 1, "b": 2} + assert actual == pytest.approx(expected) + """ + ) + result = pytester.runpytest() + result.assert_outcomes(passed=1) + class MyVec3: # incomplete """sequence like""" diff --git a/testing/test_config.py b/testing/test_config.py index 2556e4e00aa..f086778ad1e 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -2460,6 +2460,10 @@ def test_config_does_not_load_blocked_plugin_from_args(pytester: Pytester) -> No result.stderr.fnmatch_lines(["*: error: unrecognized arguments: -s"]) assert result.ret == ExitCode.USAGE_ERROR + result = pytester.runpytest(str(p), "-p no:/path/to/conftest.py", "-s") + result.stderr.fnmatch_lines(["ERROR:*Blocking conftest files*"]) + assert result.ret == ExitCode.USAGE_ERROR + def test_invocation_args(pytester: Pytester) -> None: """Ensure that Config.invocation_* arguments are correctly defined""" diff --git a/testing/test_subtests.py b/testing/test_subtests.py index 6849df53622..06de9f009d8 100644 --- a/testing/test_subtests.py +++ b/testing/test_subtests.py @@ -370,6 +370,36 @@ def test_foo(subtests): ) +def test_msg_not_a_string( + pytester: pytest.Pytester, monkeypatch: pytest.MonkeyPatch +) -> None: + """ + Using a non-string in subtests.test() should still show it in the terminal (#14195). + + Note: this was not a problem originally with the subtests fixture, only with TestCase.subTest; this test + was added for symmetry. + """ + monkeypatch.setenv("COLUMNS", "120") + pytester.makepyfile( + """ + def test_int_msg(subtests): + with subtests.test(42): + assert False, "subtest failure" + + def test_no_msg(subtests): + with subtests.test(): + assert False, "subtest failure" + """ + ) + result = pytester.runpytest() + result.stdout.fnmatch_lines( + [ + "SUBFAILED[[]42[]] test_msg_not_a_string.py::test_int_msg - AssertionError: subtest failure", + "SUBFAILED() test_msg_not_a_string.py::test_no_msg - AssertionError: subtest failure", + ] + ) + + @pytest.mark.parametrize("flag", ["--last-failed", "--stepwise"]) def test_subtests_last_failed_step_wise(pytester: pytest.Pytester, flag: str) -> None: """Check that --last-failed and --step-wise correctly rerun tests with failed subtests.""" @@ -619,6 +649,33 @@ def test_foo(self): "SUBSKIPPED[[]subtest 1[]] [[]1[]] *.py:*: skip subtest 1" ) + def test_msg_not_a_string( + self, pytester: pytest.Pytester, monkeypatch: pytest.MonkeyPatch + ) -> None: + """Using a non-string in TestCase.subTest should still show it in the terminal (#14195).""" + monkeypatch.setenv("COLUMNS", "120") + pytester.makepyfile( + """ + from unittest import TestCase + + class T(TestCase): + def test_int_msg(self): + with self.subTest(42): + assert False, "subtest failure" + + def test_no_msg(self): + with self.subTest(): + assert False, "subtest failure" + """ + ) + result = pytester.runpytest() + result.stdout.fnmatch_lines( + [ + "SUBFAILED[[]42[]] test_msg_not_a_string.py::T::test_int_msg - AssertionError: subtest failure", + "SUBFAILED() test_msg_not_a_string.py::T::test_no_msg - AssertionError: subtest failure", + ] + ) + class TestCapture: def create_file(self, pytester: pytest.Pytester) -> None: diff --git a/testing/test_tmpdir.py b/testing/test_tmpdir.py index 363172110d3..789e8005184 100644 --- a/testing/test_tmpdir.py +++ b/testing/test_tmpdir.py @@ -5,6 +5,7 @@ import dataclasses import os from pathlib import Path +import shutil import stat import sys from typing import cast @@ -619,3 +620,33 @@ def test_tmp_path_factory_fixes_up_world_readable_permissions( # After - fixed. assert (basetemp.parent.stat().st_mode & 0o077) == 0 + + +@pytest.mark.skipif( + not hasattr(os, "getuid") or os.stat not in os.supports_follow_symlinks, + reason="checks unix permissions and symlinks", +) +def test_tmp_path_factory_doesnt_follow_symlinks( + tmp_path: Path, monkeypatch: MonkeyPatch +) -> None: + """Verify that if a /tmp/pytest-of-foo directory is a symbolic link, + it is rejected (#13669, CVE-2025-71176).""" + attacker_controlled = tmp_path / "attacker_controlled" + attacker_controlled.mkdir() + + # Use the test's tmp_path as the system temproot (/tmp). + monkeypatch.setenv("PYTEST_DEBUG_TEMPROOT", str(tmp_path)) + + # First just get the pytest-of-user path. + tmp_factory = TempPathFactory(None, 3, "all", lambda *args: None, _ispytest=True) + pytest_of_user = tmp_factory.getbasetemp().parent + # Just for safety in the test, before we nuke it. + assert "pytest-of-" in str(pytest_of_user) + shutil.rmtree(pytest_of_user) + + pytest_of_user.symlink_to(attacker_controlled) + + # This now tries to use the directory when it's a symlink. + tmp_factory = TempPathFactory(None, 3, "all", lambda *args: None, _ispytest=True) + with pytest.raises(OSError, match=r"temporary directory .* is a symbolic link"): + tmp_factory.getbasetemp() diff --git a/tox.ini b/tox.ini index 70b439f7573..e2e09fa8b7f 100644 --- a/tox.ini +++ b/tox.ini @@ -62,7 +62,7 @@ description = doctesting: including doctests commands = {env:_PYTEST_TOX_COVERAGE_RUN:} pytest {posargs:{env:_PYTEST_TOX_DEFAULT_POSARGS:}} - doctesting: {env:_PYTEST_TOX_COVERAGE_RUN:} pytest --doctest-modules --pyargs _pytest + doctesting: {env:_PYTEST_TOX_COVERAGE_RUN:} pytest --doctest-modules {env:_PYTEST_TOX_POSARGS_JUNIT:} --pyargs _pytest coverage: coverage combine coverage: coverage report -m passenv = @@ -71,7 +71,7 @@ passenv = TERM CI setenv = - _PYTEST_TOX_DEFAULT_POSARGS={env:_PYTEST_TOX_POSARGS_DOCTESTING:} {env:_PYTEST_TOX_POSARGS_LSOF:} {env:_PYTEST_TOX_POSARGS_XDIST:} {env:_PYTEST_FILES:} + _PYTEST_TOX_DEFAULT_POSARGS={env:_PYTEST_TOX_POSARGS_DOCTESTING:} {env:_PYTEST_TOX_POSARGS_JUNIT:} {env:_PYTEST_TOX_POSARGS_LSOF:} {env:_PYTEST_TOX_POSARGS_XDIST:} {env:_PYTEST_FILES:} # See https://docs.python.org/3/library/io.html#io-encoding-warning # If we don't enable this, neither can any of our downstream users!