Compare commits

..

89 Commits

Author SHA1 Message Date
Sviatoslav Sydorenko (Святослав Сидоренко)
8e3b8dc7e7 Merge pull request #12565 from pytest-dev/patchback/backports/8.2.x/4a75f65c7316bb135740456bc87173017c2ac998/pr-12560
[PR #12560/4a75f65c backport][8.2.x] Correct the `:user:` role @ PR #12531 change note
2024-07-02 21:27:59 +02:00
Sviatoslav Sydorenko (Святослав Сидоренко)
2e01db1fc1 Merge pull request #12566 from pytest-dev/patchback/backports/8.2.x/e8aee21384747bc75a393f24b7cd3571f1d7650a/pr-12562
[PR #12562/e8aee213 backport][8.2.x] 🧪 Lint for typos in `:user:` RST role
2024-07-02 21:26:55 +02:00
Sviatoslav Sydorenko (Святослав Сидоренко)
c45812ed93 Merge pull request #12562 from webknjaz/maintenance/docs/user-role-validation
(cherry picked from commit e8aee21384)
2024-07-02 18:52:17 +00:00
Sviatoslav Sydorenko (Святослав Сидоренко)
77e93c248a Merge pull request #12560 from webknjaz/maintenance/hotfixes/note/12531--xfail-no-cover
(cherry picked from commit 4a75f65c73)
2024-07-02 18:50:28 +00:00
Sviatoslav Sydorenko (Святослав Сидоренко)
60c92473af Merge pull request #12556 from pytest-dev/patchback/backports/8.2.x/51ee3880c7cf2552fa5e114d5c88e83a73901a1e/pr-12553 2024-07-01 17:52:22 +02:00
Sviatoslav Sydorenko (Святослав Сидоренко)
f484eaf1fd Merge pull request #12553 from pytest-dev/revert-12516-maintenance/hotfix/gha-codecov-token
(cherry picked from commit 51ee3880c7)
2024-07-01 15:20:56 +00:00
Sviatoslav Sydorenko (Святослав Сидоренко)
d4d4ca3213 Merge pull request #12551 from pytest-dev/patchback/backports/8.2.x/1a8394ed8964a43e2fe766df3a48fa0573362512/pr-12531 2024-07-01 16:40:02 +02:00
Sviatoslav Sydorenko (Святослав Сидоренко)
1dc3a28805 Merge pull request #12531 from webknjaz/maintenance/xfail-no-cover
(cherry picked from commit 1a8394ed89)
2024-07-01 14:21:47 +00:00
Sviatoslav Sydorenko (Святослав Сидоренко)
3980206012 Merge pull request #12534 from pytest-dev/patchback/backports/8.2.x/f74e947c1fdfef238235b7dd18c8fe52108268f2/pr-12533 2024-06-26 14:57:20 +02:00
Sviatoslav Sydorenko (Святослав Сидоренко)
09888fa263 Merge pull request #12533 from webknjaz/docs/drop-extlinks-bpo
(cherry picked from commit f74e947c1f)
2024-06-26 12:39:41 +00:00
patchback[bot]
2d5b20ac6c Update trainings (#12514) (#12529)
(cherry picked from commit 2b7eadf090)

Co-authored-by: Florian Bruhin <me@the-compiler.org>
2024-06-25 05:41:35 +00:00
Sviatoslav Sydorenko (Святослав Сидоренко)
90e70c3071 Merge pull request #12525 from pytest-dev/patchback/backports/8.2.x/237152552e1782bcfcae402e1540f12348ef9f0e/pr-12522
[PR #12522/23715255 backport][8.2.x] 📝 Replace GH/PyPI `extlinks` w/ `sphinx-issues`
2024-06-23 17:13:10 +02:00
Sviatoslav Sydorenko (Святослав Сидоренко)
64be38da80 Merge pull request #12522 from webknjaz/docs/sphinx-issues-ext
📝 Replace GH/PyPI `extlinks` w/ `sphinx-issues`

(cherry picked from commit 237152552e)
2024-06-23 14:55:59 +00:00
Sviatoslav Sydorenko (Святослав Сидоренко)
d68e0e4602 Merge pull request #12521 from pytest-dev/patchback/backports/8.2.x/ff133f6baa7880e0a10195e832f1ff3f96a6c092/pr-12486
[PR #12486/ff133f6b backport][8.2.x] 🔥 Exterminate legacy backport GHA workflow
2024-06-22 13:14:27 +02:00
Ronny Pfannschmidt
f8277264de Merge pull request #12486 from webknjaz/maintenance/rm-legacy-backport-gha-workflow
🔥 Exterminate legacy backport GHA workflow

(cherry picked from commit ff133f6baa)
2024-06-22 10:59:52 +00:00
Sviatoslav Sydorenko (Святослав Сидоренко)
8985f0475c Merge pull request #12520 from pytest-dev/patchback/backports/8.2.x/f75e3fe63f8d22422393888bd5b9094cab35f522/pr-12516
[PR #12516/f75e3fe6 backport][8.2.x] 🚑🧪 Set the Codecov token directly in GHA
2024-06-22 12:57:07 +02:00
Sviatoslav Sydorenko (Святослав Сидоренко)
e6884c80c3 Merge pull request #12516 from webknjaz/maintenance/hotfix/gha-codecov-token
(cherry picked from commit f75e3fe63f)
2024-06-22 10:32:27 +00:00
Sviatoslav Sydorenko (Святослав Сидоренко)
7f3469f7af Merge pull request #12519 from pytest-dev/patchback/backports/8.2.x/6448d30fa12e17c4c1a91d2b1157b72f9ae7e55a/pr-12517
[PR #12517/6448d30f backport][8.2.x] 🧪 Bump the `alls-green` action to 223erbb7
2024-06-22 12:25:41 +02:00
Sviatoslav Sydorenko (Святослав Сидоренко)
f48f31291b Merge pull request #12517 from webknjaz/maintenance/gha-check-223e4bb7
(cherry picked from commit 6448d30fa1)
2024-06-22 09:58:50 +00:00
Sviatoslav Sydorenko (Святослав Сидоренко)
8effd29884 Merge pull request #12518 from pytest-dev/patchback/backports/8.2.x/fbdf9c887c461d63868876a3092249b4e11a34bd/pr-12455
[PR #12455/fbdf9c88 backport][8.2.x] Update `contact.rst`: Update Matrix link
2024-06-21 23:44:38 +02:00
Sviatoslav Sydorenko (Святослав Сидоренко)
a177ba7905 Merge pull request #12455 from stdedos/patch-1
Update `contact.rst`: Update Matrix link

(cherry picked from commit fbdf9c887c)
2024-06-21 21:26:41 +00:00
Sviatoslav Sydorenko (Святослав Сидоренко)
68ea72b89c Merge pull request #12489 from pytest-dev/patchback/backports/8.2.x/57bc6df510899ba77de5129d975f148c4a868725/pr-12488
[PR #12488/57bc6df5 backport][8.2.x] 🧪 Make required CI jobs match branch protection
2024-06-21 23:22:28 +02:00
patchback[bot]
d3dacc74c9 🧪🚑 Pass a Codecov config to the action @ GHA (#12508) (#12513)
The #11921 update broke uploading coverage of the `main` branch (or
any in-repo pushes for that matter) to Codecov 4 months ago.
Version 4 requires an upload token to be provided and since there was
no configuration for it, the upload was failing. But the step itself
was showing up as successful due to `fail_ci_if_error: true` being
set. The error is visible in the console output, though.

This patch flips the setting to `fail_ci_if_error: false` and sets the
Codecov upload token in the config in clear text. The non-secret part
allows the PRs uploads to be more stable.

Co-authored-by: Ronny Pfannschmidt <opensource@ronnypfannschmidt.de>
(cherry picked from commit 9947ec3ad1)

Co-authored-by: Sviatoslav Sydorenko (Святослав Сидоренко) <wk@sydorenko.org.ua>
2024-06-21 16:08:43 +00:00
Sviatoslav Sydorenko (Святослав Сидоренко)
a22b8e196d Merge pull request #12511 from pytest-dev/patchback/backports/8.2.x/2f92da9190e488f40209c84bf37aca7bccb63235/pr-12503 2024-06-21 17:32:18 +02:00
Sviatoslav Sydorenko (Святослав Сидоренко)
29987a4e12 Merge pull request #12512 from pytest-dev/patchback/backports/8.2.x/dab29d39d7fe7505f43708532bedf37d7f616143/pr-12507 2024-06-21 17:26:45 +02:00
Sviatoslav Sydorenko (Святослав Сидоренко)
7a0cb6b37d Merge pull request #12510 from pytest-dev/patchback/backports/8.2.x/b864e50138a34ebaf188829f2a4fcdf4d9e0a541/pr-12498 2024-06-21 17:23:03 +02:00
Ronny Pfannschmidt
b19cbf3e36 Merge pull request #12507 from webknjaz/maintenance/hotfixes/note/sphinx-towncrier-draft
📝 Add a change note for PR #12493

(cherry picked from commit dab29d39d7)
2024-06-21 15:11:11 +00:00
Oliver Bestwalter
0f6118596d Merge pull request #12503 from webknjaz/maintenance/hotfixes/sphinx-towncrier-draft
(cherry picked from commit 2f92da9190)
2024-06-21 15:08:26 +00:00
Oliver Bestwalter
481aa764eb Merge pull request #12498 from webknjaz/maintenance/tox-descriptions
(cherry picked from commit b864e50138)
2024-06-21 15:05:55 +00:00
Ronny Pfannschmidt
780d0c10cd Merge pull request #12506 from webknjaz/backports/8.2.x/b08b6d1/pr-12501
[PR #12501/b08b6d1 backport][8.2.x] 📝💅 Split trivial change log category into 3
2024-06-21 15:41:57 +02:00
Ronny Pfannschmidt
277951fab9 Merge pull request #12501 from webknjaz/maintenance/changelog-categories
📝💅 Split trivial change log category into 3

(cherry picked from commit b08b6d122f)
2024-06-21 13:59:55 +02:00
Ronny Pfannschmidt
76065e5028 Merge pull request #12496 from RonnyPfannschmidt/ronny/backport-annotations-8.2
backport annotations to 8.2
2024-06-21 10:25:23 +02:00
Ronny Pfannschmidt
cffcbdfbba fixup: summary_failures_combined arg needed_opt is not kwonly on 8.2.x 2024-06-21 09:40:30 +02:00
Ronny Pfannschmidt
4f7ada5b6a fixup: restore comment for Config.cache 2024-06-21 09:39:34 +02:00
Ronny Pfannschmidt
e60afd5af2 fixup: pre-commit green again 2024-06-20 15:44:35 +02:00
Ronny Pfannschmidt
2b16e7b138 correct backport mistake 2024-06-20 15:27:15 +02:00
Ronny Pfannschmidt
fc6ba92c30 add changelog entry 2024-06-20 12:05:17 +02:00
Ronny Pfannschmidt
a36b74ead8 update tox:docs python to rtd python 2024-06-20 12:05:17 +02:00
Ronny Pfannschmidt
69936d32a5 resolve most sphinx lookup errors
add the extra sphinx annotations to refer to Path instances

add Path to nitpicky ignore
2024-06-20 12:05:17 +02:00
Ronny Pfannschmidt
d51fac48d6 use runtime union for EXCEPTION_OR_MORE 2024-06-20 12:05:17 +02:00
Ronny Pfannschmidt
8e495e32c6 fixup: remove remove unused alias in code 2024-06-20 12:05:10 +02:00
Ronny Pfannschmidt
2a75bab290 Merge pull request #12495 from pytest-dev/patchback/backports/8.2.x/20dd1d6738d0623fe3176e796805bbd6e36cf831/pr-12493
[PR #12493/20dd1d67 backport][8.2.x] 📝💅 Always render changelog draft @ Sphinx docs
2024-06-20 11:26:17 +02:00
Ronny Pfannschmidt
0fce6d4ddb Merge pull request #12493 from webknjaz/maintenance/sphinx-towncrier-draft
📝💅 Always render changelog draft @ Sphinx docs

(cherry picked from commit 20dd1d6738)
2024-06-20 08:59:13 +00:00
Ronny Pfannschmidt
f839730d22 Merge pull request #12488 from webknjaz/maintenance/gha-check-allowed-failures
🧪 Make required CI jobs match branch protection

(cherry picked from commit 57bc6df510)
2024-06-19 10:42:45 +00:00
Ronny Pfannschmidt
4716ba546f Merge pull request #12484 from pytest-dev/patchback/backports/8.2.x/dc65bb6a6699bdeb5ee7523245db1ee724670e29/pr-10315
[PR #10315/dc65bb6a backport][8.2.x] Introduce a gate/check GHA job
2024-06-19 11:18:48 +02:00
Ronny Pfannschmidt
c87707122c Merge pull request #12482 from pytest-dev/patchback/backports/8.2.x/ea87bd6302a1bb899e3e4c206b9c06b8014292ba/pr-12476
[PR #12476/ea87bd63 backport][8.2.x] 🧪 Bump RTD env to the latest LTS Ubuntu & Python
2024-06-19 11:17:44 +02:00
Ronny Pfannschmidt
31e07cf151 Merge pull request #12480 from pytest-dev/patchback/backports/8.2.x/d7b401063874141fcbcda78eaec3c28148e7dcd8/pr-12475
[PR #12475/d7b40106 backport][8.2.x] 💅 Add a config for the Patchback GitHub App
2024-06-19 11:16:14 +02:00
Ronny Pfannschmidt
3931fe2fbf Merge pull request #12478 from pytest-dev/patchback/backports/8.2.x/c46a3a9920b38164fea4e22ef99b4b66f42e77bf/pr-12477
[PR #12477/c46a3a99 backport][8.2.x] 💅 Add a config for the Chronographer GitHub App
2024-06-19 11:03:06 +02:00
Ronny Pfannschmidt
4f4bcc2e24 Merge pull request #10315 from webknjaz/maintenance/gha-check
Introduce a gate/check GHA job

(cherry picked from commit dc65bb6a66)
2024-06-19 08:50:06 +00:00
Ronny Pfannschmidt
65a8e4a744 Merge pull request #12476 from webknjaz/maintenance/rtd-latest-env
🧪 Bump RTD env to the latest LTS Ubuntu & Python

(cherry picked from commit ea87bd6302)
2024-06-19 08:49:18 +00:00
Sviatoslav Sydorenko (Святослав Сидоренко)
fdc53750f9 💅 Add a config for the Patchback GitHub App (#12475)
This patch prepares the project's backporting process to start being
handled by the Patchback GitHub App [[1]].

Ref #9384
Resolves #9385
Resolves #9553
Resolves #9554
Resolves #9555

[1]: https://github.com/apps/patchback

(cherry picked from commit d7b4010638)
2024-06-19 08:47:55 +00:00
Ronny Pfannschmidt
a64fb18305 Merge pull request #12477 from webknjaz/maintenance/chronographer-config
💅 Add a config for the Chronographer GitHub App

(cherry picked from commit c46a3a9920)
2024-06-19 07:50:04 +00:00
github-actions[bot]
53d2d4717d [8.2.x] Documentation: Clean up various documentation pages (#12458)
Co-authored-by: neutraljump <162650677+neutraljump@users.noreply.github.com>
2024-06-13 12:26:21 +00:00
github-actions[bot]
56c0b1db3a [8.2.x] doc: fix broken code blocks (#12450)
* [8.2.x] doc: fix broken code blocks

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: Ran Benita <ran@unusedvar.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-06-11 15:54:37 +00:00
github-actions[bot]
eb8721d387 [8.2.x] unittest: fix assertion errors on unittest reruns (#12438)
Co-authored-by: Ran Benita <ran@unusedvar.com>
2024-06-07 22:39:52 -03:00
github-actions[bot]
36f0ea10b4 [8.2.x] remove my contact details (#12428)
Co-authored-by: holger krekel <holger@merlinux.eu>
2024-06-06 09:34:17 -03:00
Ran Benita
f3a494cca3 Merge pull request #12415 from pytest-dev/release-8.2.2
Prepare release 8.2.2
2024-06-04 16:51:13 +03:00
pytest bot
329d371214 Prepare release version 8.2.2 2024-06-04 12:54:55 +00:00
Ran Benita
214d098fcc Merge pull request #12414 from bluetech/backport-12409
[8.2.x] fixtures: fix catastrophic performance problem in `reorder_items`
2024-06-04 12:47:12 +03:00
Ran Benita
153a436bc4 [8.2.x] fixtures: fix catastrophic performance problem in reorder_items
Manual minimal backport from commit e89d23b247.

Fix #12355.

In the issue, it was reported that the `reorder_items` has quadratic (or
worse...) behavior with certain simple parametrizations. After some
debugging I found that the problem happens because the "Fix
items_by_argkey order" loop keeps adding the same item to the deque,
and it reaches epic sizes which causes the slowdown.

I don't claim to understand how the `reorder_items` algorithm works, but
if as far as I understand, if an item already exists in the deque, the
correct thing to do is to move it to the front. Since a deque doesn't
have such an (efficient) operation, this switches to `OrderedDict` which
can efficiently append from both sides, deduplicate and move to front.
2024-06-04 10:33:50 +03:00
Ran Benita
b41d5a52bb Merge pull request #12412 from pytest-dev/backport-12408-to-8.2.x
[8.2.x] cacheprovider: fix "Directory not empty" crash from cache directory creation
2024-06-03 13:16:29 +03:00
Ran Benita
9bb73d734f [8.2.x] cacheprovider: fix "Directory not empty" crash from cache directory creation 2024-06-03 09:44:21 +00:00
github-actions[bot]
4569a01e3d [8.2.x] doc: Update trainings/events (#12402)
Co-authored-by: Florian Bruhin <me@the-compiler.org>
2024-05-30 17:05:32 +02:00
github-actions[bot]
1d103e5cdc [8.2.x] Clarify pytest_ignore_collect docs (#12386)
Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com>
2024-05-28 17:41:35 +00:00
github-actions[bot]
240a252d34 [8.2.x] Add html_baseurl to sphinx conf.py (#12372)
Co-authored-by: James Frost <james.frost@metoffice.gov.uk>
2024-05-26 10:38:25 +00:00
Ran Benita
a5ee3c4126 Merge pull request #12370 from pytest-dev/backport-12368-to-8.2.x
[8.2.x] unittest: fix class instances no longer released on test teardown since pytest 8.2.0
2024-05-26 11:04:09 +03:00
Ran Benita
f7358aec28 [8.2.x] unittest: fix class instances no longer released on test teardown since pytest 8.2.0 2024-05-26 07:34:33 +00:00
github-actions[bot]
558e4fa71a [8.2.x] Add thread safety section to flaky test docs (#12362)
Co-authored-by: Nathan Goldbaum <nathan.goldbaum@gmail.com>
2024-05-24 08:22:20 -03:00
github-actions[bot]
f0e7a07667 [8.2.x] Issue #12290 - Docs using Furo Theme W/ Dark Mode (#12348)
Co-authored-by: Sam Jirovec <47160720+samjirovec@users.noreply.github.com>
2024-05-21 16:11:45 +00:00
Bruno Oliveira
22e885f109 Fix link in changelog (#12343) (#12344)
Co-authored-by: Hynek Schlawack <hs@ox.cx>
2024-05-19 18:17:40 -03:00
Ran Benita
bddbeba74b Merge pull request #12341 from pytest-dev/release-8.2.1
Prepare release 8.2.1
2024-05-19 22:09:37 +03:00
pytest bot
66ff8dffdf Prepare release version 8.2.1 2024-05-19 16:43:40 +00:00
Ran Benita
3ffcfd122c Merge pull request #12340 from pytest-dev/backport-12334-to-8.2.x
[8.2.x] Add Python 3.13 (beta) support
2024-05-19 12:45:56 +03:00
Ran Benita
0b28313b46 [8.2.x] Add Python 3.13 (beta) support 2024-05-19 06:45:36 +00:00
github-actions[bot]
f3dd93ad8d [8.2.x] Attest package provenance (#12335)
Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com>
2024-05-17 08:20:32 -03:00
github-actions[bot]
bb5a1257b0 [8.2.x] Spelling (#12331)
Co-authored-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-05-15 18:25:57 +00:00
Ran Benita
f179bf252f Merge pull request #12327 from pytest-dev/backport-12325-to-8.2.x
[8.2.x] cacheprovider: fix `.pytest_cache` not being world-readable
2024-05-15 14:15:10 +03:00
Ran Benita
2b671b5f92 [8.2.x] cacheprovider: fix .pytest_cache not being world-readable 2024-05-15 07:57:34 +00:00
Ran Benita
65ab7cb96c Merge pull request #12324 from pytest-dev/backport-12320-to-8.2.x
[8.2.x] changelog: document unittest 8.2 change as breaking
2024-05-14 23:49:40 +03:00
Ran Benita
4d5fb7d71c Merge pull request #12319 from pytest-dev/backport-12311-to-8.2.x
[8.2.x] python: add workaround for permission error crashes from non-selected directories
2024-05-14 23:07:16 +03:00
Ran Benita
cbe5996cc6 [8.2.x] changelog: document unittest 8.2 change as breaking 2024-05-14 20:07:07 +00:00
Ran Benita
c9e9315725 [8.2.x] python: add workaround for permission error crashes from non-selected directories 2024-05-13 17:33:00 +00:00
github-actions[bot]
328001eab1 [8.2.x] Fixes crashing under a squashfuse_ll read-only mount (#12302)
Co-authored-by: Yutian Li <hotpxless@gmail.com>
2024-05-09 18:20:57 +00:00
github-actions[bot]
8fdb72947e [8.2.x] doc: update sprint repo link (#12297)
Co-authored-by: Florian Bruhin <me@the-compiler.org>
2024-05-08 10:16:22 -03:00
github-actions[bot]
5c1c73b961 [8.2.x] Document exceptions raised by exit, skip, xfail, fail, and importorskip (#12288)
Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com>
2024-05-06 01:32:21 +00:00
github-actions[bot]
a152c2cee4 [8.2.x] Consider KeyboardInterrupt/SystemExit at collection time (#12282)
Co-authored-by: Anita Hammer <166057949+anitahammer@users.noreply.github.com>
2024-05-02 12:18:05 +00:00
Bruno Oliveira
69c3bcea36 Merge pull request #12257 from pytest-dev/release-8.2.0
Prepare release 8.2.0
2024-04-27 20:35:29 -03:00
Bruno Oliveira
6bd3f31344 Tweak changelog for 8.2.0 2024-04-27 10:20:51 -03:00
pytest bot
9b6219b5e8 Prepare release version 8.2.0 2024-04-27 13:07:39 +00:00
307 changed files with 3021 additions and 2312 deletions

View File

@@ -29,3 +29,5 @@ exclude_lines =
^\s*if TYPE_CHECKING:
^\s*@overload( |$)
^\s*@pytest\.mark\.xfail

20
.github/chronographer.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
---
branch-protection-check-name: Changelog entry
action-hints:
check-title-prefix: "Chronographer: "
external-docs-url: >-
https://docs.pytest.org/en/latest/contributing.html#preparing-pull-requests
inline-markdown: >-
See
https://docs.pytest.org/en/latest/contributing.html#preparing-pull-requests
for details.
enforce-name:
suffix: .rst
exclude:
humans:
- pyup-bot
labels:
skip-changelog: skip news
...

7
.github/patchback.yml vendored Normal file
View File

@@ -0,0 +1,7 @@
---
backport_branch_prefix: patchback/backports/
backport_label_prefix: 'backport ' # IMPORTANT: the labels are space-delimited
# target_branch_prefix: '' # The project's backport branches are non-prefixed
...

View File

@@ -1,51 +0,0 @@
name: backport
on:
# Note that `pull_request_target` has security implications:
# https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
# In particular:
# - Only allow triggers that can be used only be trusted users
# - Don't execute any code from the target branch
# - Don't use cache
pull_request_target:
types: [labeled]
# Set permissions at the job level.
permissions: {}
jobs:
backport:
if: startsWith(github.event.label.name, 'backport ') && github.event.pull_request.merged
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: true
- name: Create backport PR
run: |
set -eux
git config --global user.name "pytest bot"
git config --global user.email "pytestbot@gmail.com"
label='${{ github.event.label.name }}'
target_branch="${label#backport }"
backport_branch=backport-${{ github.event.number }}-to-"${target_branch}"
subject="[$target_branch] $(gh pr view --json title -q .title ${{ github.event.number }})"
git checkout origin/"${target_branch}" -b "${backport_branch}"
git cherry-pick -x --mainline 1 ${{ github.event.pull_request.merge_commit_sha }}
git commit --amend --message "$subject"
git push --set-upstream origin --force-with-lease "${backport_branch}"
gh pr create \
--base "${target_branch}" \
--title "${subject}" \
--body "Backport of PR #${{ github.event.number }} to $target_branch branch. PR created by backport workflow."
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -19,6 +19,11 @@ jobs:
SETUPTOOLS_SCM_PRETEND_VERSION: ${{ github.event.inputs.version }}
timeout-minutes: 10
# Required by attest-build-provenance-github.
permissions:
id-token: write
attestations: write
steps:
- uses: actions/checkout@v4
with:
@@ -26,7 +31,9 @@ jobs:
persist-credentials: false
- name: Build and Check Package
uses: hynek/build-and-inspect-python-package@v2.4.0
uses: hynek/build-and-inspect-python-package@v2.5.0
with:
attest-build-provenance-github: 'true'
deploy:
if: github.repository == 'pytest-dev/pytest'

View File

@@ -35,7 +35,7 @@ jobs:
fetch-depth: 0
persist-credentials: false
- name: Build and Check Package
uses: hynek/build-and-inspect-python-package@v2.4.0
uses: hynek/build-and-inspect-python-package@v2.5.0
build:
needs: [package]
@@ -55,6 +55,7 @@ jobs:
"windows-py310",
"windows-py311",
"windows-py312",
"windows-py313",
"ubuntu-py38",
"ubuntu-py38-pluggy",
@@ -63,12 +64,14 @@ jobs:
"ubuntu-py310",
"ubuntu-py311",
"ubuntu-py312",
"ubuntu-py313",
"ubuntu-pypy3",
"macos-py38",
"macos-py39",
"macos-py310",
"macos-py312",
"macos-py313",
"doctesting",
"plugins",
@@ -97,9 +100,13 @@ jobs:
os: windows-latest
tox_env: "py311"
- name: "windows-py312"
python: "3.12-dev"
python: "3.12"
os: windows-latest
tox_env: "py312"
- name: "windows-py313"
python: "3.13-dev"
os: windows-latest
tox_env: "py313"
- name: "ubuntu-py38"
python: "3.8"
@@ -128,10 +135,15 @@ jobs:
tox_env: "py311"
use_coverage: true
- name: "ubuntu-py312"
python: "3.12-dev"
python: "3.12"
os: ubuntu-latest
tox_env: "py312"
use_coverage: true
- name: "ubuntu-py313"
python: "3.13-dev"
os: ubuntu-latest
tox_env: "py313"
use_coverage: true
- name: "ubuntu-pypy3"
python: "pypy-3.8"
os: ubuntu-latest
@@ -151,9 +163,13 @@ jobs:
os: macos-latest
tox_env: "py310-xdist"
- name: "macos-py312"
python: "3.12-dev"
python: "3.12"
os: macos-latest
tox_env: "py312-xdist"
- name: "macos-py313"
python: "3.13-dev"
os: macos-latest
tox_env: "py313-xdist"
- name: "plugins"
python: "3.12"
@@ -166,6 +182,26 @@ jobs:
tox_env: "doctesting"
use_coverage: true
continue-on-error: >-
${{
contains(
fromJSON(
'[
"windows-py38-pluggy",
"windows-py313",
"ubuntu-py38-pluggy",
"ubuntu-py38-freeze",
"ubuntu-py313",
"macos-py38",
"macos-py313"
]'
),
matrix.name
)
&& true
|| false
}}
steps:
- uses: actions/checkout@v4
with:
@@ -206,8 +242,21 @@ jobs:
- name: Upload coverage to Codecov
if: "matrix.use_coverage"
uses: codecov/codecov-action@v4
continue-on-error: true
with:
fail_ci_if_error: true
fail_ci_if_error: false
files: ./coverage.xml
verbose: true
check: # This job does nothing and is only used for the branch protection
if: always()
needs:
- build
runs-on: ubuntu-latest
steps:
- name: Decide whether the needed jobs succeeded or failed
uses: re-actors/alls-green@223e4bb7a751b91f43eda76992bcfbf23b8b0302
with:
jobs: ${{ toJSON(needs) }}

1
.gitignore vendored
View File

@@ -25,7 +25,6 @@ src/_pytest/_version.py
doc/*/_build
doc/*/.doctrees
doc/*/_changelog_towncrier_draft.rst
build/
dist/
*.egg-info

View File

@@ -66,9 +66,50 @@ repos:
- id: changelogs-rst
name: changelog filenames
language: fail
entry: 'changelog files must be named ####.(breaking|bugfix|deprecation|doc|feature|improvement|trivial|vendor).rst'
exclude: changelog/(\d+\.(breaking|bugfix|deprecation|doc|feature|improvement|trivial|vendor).rst|README.rst|_template.rst)
entry: >-
changelog files must be named
####.(
breaking
| deprecation
| feature
| improvement
| bugfix
| vendor
| doc
| packaging
| contrib
| misc
)(.#)?(.rst)?
exclude: >-
(?x)
^
changelog/(
\.gitignore
|\d+\.(
breaking
|deprecation
|feature
|improvement
|bugfix
|vendor
|doc
|packaging
|contrib
|misc
)(\.\d+)?(\.rst)?
|README\.rst
|_template\.rst
)
$
files: ^changelog/
- id: changelogs-user-role
name: Changelog files should use a non-broken :user:`name` role
language: pygrep
entry: :user:([^`]+`?|`[^`]+[\s,])
pass_filenames: true
types:
- file
- rst
- id: py-deprecated
name: py library is deprecated
language: pygrep

View File

@@ -14,11 +14,16 @@ sphinx:
fail_on_warning: true
build:
os: ubuntu-20.04
os: ubuntu-24.04
tools:
python: "3.9"
python: >-
3.12
apt_packages:
- inkscape
jobs:
post_checkout:
- git fetch --unshallow || true
- git fetch --tags || true
formats:
- epub

View File

@@ -36,6 +36,7 @@ Andrey Paramonov
Andrzej Klajnert
Andrzej Ostrowski
Andy Freeland
Anita Hammer
Anthon van der Neut
Anthony Shaw
Anthony Sottile
@@ -191,6 +192,7 @@ Jake VanderPlas
Jakob van Santen
Jakub Mitoraj
James Bourbeau
James Frost
Jan Balster
Janne Vanhala
Jason R. Coombs
@@ -257,6 +259,7 @@ Marc Bresson
Marco Gorelli
Mark Abramowitz
Mark Dickinson
Mark Vong
Marko Pacak
Markus Unterwaditzer
Martijn Faassen
@@ -288,6 +291,7 @@ Mike Lundy
Milan Lesnek
Miro Hrončok
mrbean-bremen
Nathan Goldbaum
Nathaniel Compton
Nathaniel Waisbrot
Ned Batchelder
@@ -297,6 +301,7 @@ Nicholas Devenish
Nicholas Murphy
Niclas Olofsson
Nicolas Delaby
Nico Vidal
Nikolay Kondratyev
Nipunn Koorapati
Oleg Pidsadnyi
@@ -357,6 +362,7 @@ Sadra Barikbin
Saiprasad Kale
Samuel Colvin
Samuel Dion-Girardeau
Samuel Jirovec
Samuel Searles-Bryant
Samuel Therrien (Avasam)
Samuele Pedroni
@@ -385,6 +391,7 @@ Stefano Taschini
Steffen Allner
Stephan Obermann
Sven-Hendrik Haase
Sviatoslav Sydorenko
Sylvain Marié
Tadek Teleżyński
Takafumi Arakaki
@@ -440,6 +447,7 @@ Yao Xiao
Yoav Caspi
Yuliang Shao
Yusuke Kadowaki
Yutian Li
Yuval Shimon
Zac Hatfield-Dodds
Zachary Kneupper

View File

@@ -1,14 +1,10 @@
============================
Contribution getting started
Contributing
============================
Contributions are highly welcomed and appreciated. Every little bit of help counts,
so do not hesitate!
.. contents::
:depth: 2
:backlinks: none
.. _submitfeedback:
@@ -128,7 +124,7 @@ For example:
Submitting Plugins to pytest-dev
--------------------------------
Pytest development of the core, some plugins and support code happens
Development of the pytest core, support code, and some plugins happens
in repositories living under the ``pytest-dev`` organisations:
- `pytest-dev on GitHub <https://github.com/pytest-dev>`_

View File

@@ -1,3 +1,5 @@
from __future__ import annotations
import sys

View File

@@ -2,6 +2,8 @@
# 2.7.5 3.3.2
# FilesCompleter 75.1109 69.2116
# FastFilesCompleter 0.7383 1.0760
from __future__ import annotations
import timeit

View File

@@ -1,2 +1,5 @@
from __future__ import annotations
for i in range(1000):
exec("def test_func_%d(): pass" % i)

View File

@@ -1,3 +1,5 @@
from __future__ import annotations
import pytest

View File

@@ -1,3 +1,5 @@
from __future__ import annotations
import pytest

View File

@@ -1,3 +1,5 @@
from __future__ import annotations
from unittest import TestCase # noqa: F401

View File

@@ -1,3 +1,6 @@
from __future__ import annotations
for i in range(5000):
exec(
f"""

34
changelog/.gitignore vendored Normal file
View File

@@ -0,0 +1,34 @@
*
!.gitignore
!_template.rst
!README.rst
!*.bugfix
!*.bugfix.rst
!*.bugfix.*.rst
!*.breaking
!*.breaking.rst
!*.breaking.*.rst
!*.contrib
!*.contrib.rst
!*.contrib.*.rst
!*.deprecation
!*.deprecation.rst
!*.deprecation.*.rst
!*.doc
!*.doc.rst
!*.doc.*.rst
!*.feature
!*.feature.rst
!*.feature.*.rst
!*.improvement
!*.improvement.rst
!*.improvement.*.rst
!*.misc
!*.misc.rst
!*.misc.*.rst
!*.packaging
!*.packaging.rst
!*.packaging.*.rst
!*.vendor
!*.vendor.rst
!*.vendor.*.rst

View File

@@ -0,0 +1 @@
Fix crash with `assert testcase is not None` assertion failure when re-running unittest tests using plugins like pytest-rerunfailures. Regressed in 8.2.2.

View File

@@ -0,0 +1,3 @@
Migrated all internal type-annotations to the python3.10+ style by using the `annotations` future import.
-- by :user:`RonnyPfannschmidt`

View File

@@ -0,0 +1,13 @@
The change log draft preview integration has been refactored to use a
third party extension ``sphinxcontib-towncrier``. The previous in-repo
script was putting the change log preview file at
:file:`doc/en/_changelog_towncrier_draft.rst`. Said file is no longer
ignored in Git and might show up among untracked files in the
development environments of the contributors. To address that, the
contributors can run the following command that will clean it up:
.. code-block:: console
$ git clean -x -i -- doc/en/_changelog_towncrier_draft.rst
-- by :user:`webknjaz`

View File

@@ -0,0 +1,5 @@
All the undocumented ``tox`` environments now have descriptions.
They can be listed in one's development environment by invoking
``tox -av`` in a terminal.
-- by :user:`webknjaz`

View File

@@ -0,0 +1,11 @@
The changelog configuration has been updated to introduce more accurate
audience-tailored categories. Previously, there was a ``trivial``
change log fragment type with an unclear and broad meaning. It was
removed and we now have ``contrib``, ``misc`` and ``packaging`` in
place of it.
The new change note types target the readers who are downstream
packagers and project contributors. Additionally, the miscellaneous
section is kept for unspecified updates that do not fit anywhere else.
-- by :user:`webknjaz`

View File

@@ -0,0 +1,4 @@
The ``:pull:`` RST role has been replaced with a shorter
``:pr:`` due to starting to use the implementation from
the third-party :pypi:`sphinx-issues` Sphinx extension
-- by :user:`webknjaz`.

View File

@@ -0,0 +1,6 @@
The coverage reporting configuration has been updated to exclude
pytest's own tests marked as expected to fail from the coverage
report. This has an effect of reducing the influence of flaky
tests on the resulting number.
-- by :user:`webknjaz`

View File

@@ -0,0 +1,7 @@
The ``extlinks`` Sphinx extension is no longer enabled. The ``:bpo:``
role it used to declare has been removed with that. BPO itself has
migrated to GitHub some years ago and it is possible to link the
respective issues by using their GitHub issue numbers and the
``:issue:`` role that the ``sphinx-issues`` extension implements.
-- by :user:`webknjaz`

View File

@@ -0,0 +1,2 @@
Possible typos in using the ``:user:`` RST role is now being linted
through the pre-commit tool integration -- by :user:`webknjaz`.

View File

@@ -20,10 +20,22 @@ Each file should be named like ``<ISSUE>.<TYPE>.rst``, where
* ``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.
* ``trivial``: fixing a small typo or internal change that might be noteworthy.
* ``packaging``: notes for downstreams about unobvious side effects
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
environment.
* ``misc``: changes that are hard to assign to any of the above
categories.
So for example: ``123.feature.rst``, ``456.bugfix.rst``.
.. tip::
See :file:`pyproject.toml` for all available categories
(``tool.towncrier.type``).
If your PR fixes an issue, use that number here. If there is no issue,
then after you submit the PR and get the PR number you can add a
changelog using that instead.

View File

@@ -1,4 +1,9 @@
# reference: https://docs.codecov.io/docs/codecovyml-reference
---
codecov:
token: 1eca3b1f-31a2-4fb8-a8c3-138b441b50a7 #repo token
coverage:
status:
patch: true

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

@@ -0,0 +1,7 @@
<style>
.logo {text-align: center;}
</style>
<a class="logo" href="{{ pathto('contents') }}">
<img src="{{ pathto('_static/pytest1.png', 1) }}" width="70%" height="70%" text="Pytest Logo"/>
</a>

View File

@@ -1,14 +0,0 @@
{#
basic/searchbox.html with heading removed.
#}
{%- if pagename != "search" and builder != "singlehtml" %}
<div id="searchbox" style="display: none" role="search">
<div class="searchformwrapper">
<form class="search" action="{{ pathto('search') }}" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
<input type="submit" value="{{ _('Go') }}" />
</form>
</div>
</div>
<script>document.getElementById('searchbox').style.display = "block"</script>
{%- endif %}

View File

@@ -0,0 +1,7 @@
<style>
ul {list-style: none;}
li {margin: 0.4em 0;}
@media (min-width: 46em) {
#features {width: 50%;}
}
</style>

View File

@@ -6,6 +6,8 @@ Release announcements
:maxdepth: 2
release-8.2.2
release-8.2.1
release-8.2.0
release-8.1.2
release-8.1.1

View File

@@ -62,7 +62,7 @@ New Features
- new "-q" option which decreases verbosity and prints a more
nose/unittest-style "dot" output.
- many many more detailed improvements details
- many, many, more detailed improvements details
Fixes
-----------------------
@@ -109,7 +109,7 @@ Important Notes
in conftest.py files. They will cause nothing special.
- removed support for calling the pre-1.0 collection API of "run()" and "join"
- removed reading option values from conftest.py files or env variables.
This can now be done much much better and easier through the ini-file
This can now be done much, much, better and easier through the ini-file
mechanism and the "addopts" entry in particular.
- removed the "disabled" attribute in test classes. Use the skipping
and pytestmark mechanism to skip or xfail a test class.

View File

@@ -4,7 +4,7 @@ pytest-2.2.2: bug fixes
pytest-2.2.2 (updated to 2.2.3 to fix packaging issues) is a minor
backward-compatible release of the versatile py.test testing tool. It
contains bug fixes and a few refinements particularly to reporting with
"--collectonly", see below for betails.
"--collectonly", see below for details.
For general information see here:

View File

@@ -181,7 +181,7 @@ Bug fixes:
partially failed (finalizers would not always be called before)
- fix issue320 - fix class scope for fixtures when mixed with
module-level functions. Thanks Anatloy Bubenkoff.
module-level functions. Thanks Anatoly Bubenkoff.
- you can specify "-q" or "-qq" to get different levels of "quieter"
reporting (thanks Katarzyna Jachim)

View File

@@ -83,7 +83,7 @@ holger krekel
Thanks Ralph Schmitt for the precise failure example.
- fix issue244 by implementing special index for parameters to only use
indices for paramentrized test ids
indices for parametrized test ids
- fix issue287 by running all finalizers but saving the exception
from the first failing finalizer and re-raising it so teardown will

View File

@@ -73,7 +73,7 @@ holger krekel
- cleanup setup.py a bit and specify supported versions. Thanks Jurko
Gospodnetic for the PR.
- change XPASS colour to yellow rather then red when tests are run
- change XPASS colour to yellow rather than red when tests are run
with -v.
- fix issue473: work around mock putting an unbound method into a class

View File

@@ -55,7 +55,7 @@ holger krekel
github. See https://pytest.org/en/stable/contributing.html .
Thanks to Anatoly for pushing and initial work on this.
- fix issue650: new option ``--docttest-ignore-import-errors`` which
- fix issue650: new option ``--doctest-ignore-import-errors`` which
will turn import errors in doctests into skips. Thanks Charles Cloud
for the complete PR.

View File

@@ -45,7 +45,7 @@ The py.test Development Team
**New Features**
* New ``pytest.mark.skip`` mark, which unconditionally skips marked tests.
Thanks :user:`MichaelAquilina` for the complete PR (:pull:`1040`).
Thanks :user:`MichaelAquilina` for the complete PR (:pr:`1040`).
* ``--doctest-glob`` may now be passed multiple times in the command-line.
Thanks :user:`jab` and :user:`nicoddemus` for the PR.

View File

@@ -44,7 +44,7 @@ The py.test Development Team
Thanks :user:`nicoddemus` for the PR.
* Fix (:issue:`469`): junit parses report.nodeid incorrectly, when params IDs
contain ``::``. Thanks :user:`tomviner` for the PR (:pull:`1431`).
contain ``::``. Thanks :user:`tomviner` for the PR (:pr:`1431`).
* Fix (:issue:`578`): SyntaxErrors
containing non-ascii lines at the point of failure generated an internal

View File

@@ -44,14 +44,14 @@ The py.test Development Team
* Fix Xfail does not work with condition keyword argument.
Thanks :user:`astraw38` for reporting the issue (:issue:`1496`) and :user:`tomviner`
for PR the (:pull:`1524`).
for PR the (:pr:`1524`).
* Fix win32 path issue when putting custom config file with absolute path
in ``pytest.main("-c your_absolute_path")``.
* Fix maximum recursion depth detection when raised error class is not aware
of unicode/encoded bytes.
Thanks :user:`prusse-martin` for the PR (:pull:`1506`).
Thanks :user:`prusse-martin` for the PR (:pr:`1506`).
* Fix ``pytest.mark.skip`` mark when used in strict mode.
Thanks :user:`pquentin` for the PR and :user:`RonnyPfannschmidt` for

View File

@@ -0,0 +1,19 @@
pytest-8.2.1
=======================================
pytest 8.2.1 has just been released to PyPI.
This is a bug-fix release, being a drop-in replacement. To upgrade::
pip install --upgrade pytest
The full changelog is available at https://docs.pytest.org/en/stable/changelog.html.
Thanks to all of the contributors to this release:
* Bruno Oliveira
* Ran Benita
Happy testing,
The pytest Development Team

View File

@@ -0,0 +1,19 @@
pytest-8.2.2
=======================================
pytest 8.2.2 has just been released to PyPI.
This is a bug-fix release, being a drop-in replacement. To upgrade::
pip install --upgrade pytest
The full changelog is available at https://docs.pytest.org/en/stable/changelog.html.
Thanks to all of the contributors to this release:
* Bruno Oliveira
* Ran Benita
Happy testing,
The pytest Development Team

View File

@@ -49,7 +49,7 @@ place on 20th, 21st, 22nd, 24th and 25th. On the 23rd we took a break
day for some hot hiking in the Black Forest.
Sprint activity was organised heavily around pairing, with plenty of group
discusssions to take advantage of the high bandwidth, and lightning talks
discussions to take advantage of the high bandwidth, and lightning talks
as well.

View File

@@ -5,30 +5,26 @@ Backwards Compatibility Policy
.. versionadded: 6.0
pytest is actively evolving and is a project that has been decades in the making,
we keep learning about new and better structures to express different details about testing.
Pytest is an actively evolving project that has been decades in the making.
We keep learning about new and better structures to express different details about testing.
While we implement those modifications we try to ensure an easy transition and don't want to impose unnecessary churn on our users and community/plugin authors.
While we implement those modifications, we try to ensure an easy transition and don't want to impose unnecessary churn on our users and community/plugin authors.
As of now, pytest considers multiple types of backward compatibility transitions:
a) trivial: APIs which trivially translate to the new mechanism,
and do not cause problematic changes.
a) trivial: APIs that trivially translate to the new mechanism and do not cause problematic changes.
We try to support those indefinitely while encouraging users to switch to newer/better mechanisms through documentation.
We try to support those indefinitely while encouraging users to switch to newer or better mechanisms through documentation.
b) transitional: the old and new API don't conflict
and we can help users transition by using warnings, while supporting both for a prolonged time.
b) transitional: the old and new APIs don't conflict, and we can help users transition by using warnings while supporting both for a prolonged period of time.
We will only start the removal of deprecated functionality in major releases (e.g. if we deprecate something in 3.0 we will start to remove it in 4.0), and keep it around for at least two minor releases (e.g. if we deprecate something in 3.9 and 4.0 is the next release, we start to remove it in 5.0, not in 4.0).
We will only start the removal of deprecated functionality in major releases (e.g., if we deprecate something in 3.0, we will start to remove it in 4.0), and keep it around for at least two minor releases (e.g., if we deprecate something in 3.9 and 4.0 is the next release, we start to remove it in 5.0, not in 4.0).
A deprecated feature scheduled to be removed in major version X will use the warning class `PytestRemovedInXWarning` (a subclass of :class:`~pytest.PytestDeprecationWarning`).
When the deprecation expires (e.g. 4.0 is released), we won't remove the deprecated functionality immediately, but will use the standard warning filters to turn `PytestRemovedInXWarning` (e.g. `PytestRemovedIn4Warning`) into **errors** by default. This approach makes it explicit that removal is imminent, and still gives you time to turn the deprecated feature into a warning instead of an error so it can be dealt with in your own time. In the next minor release (e.g. 4.1), the feature will be effectively removed.
When the deprecation expires (e.g., 4.0 is released), we won't remove the deprecated functionality immediately but will use the standard warning filters to turn `PytestRemovedInXWarning` (e.g., `PytestRemovedIn4Warning`) into **errors** by default. This approach makes it explicit that removal is imminent and still gives you time to turn the deprecated feature into a warning instead of an error so it can be dealt with in your own time. In the next minor release (e.g., 4.1), the feature will be effectively removed.
c) true breakage: should only be considered when normal transition is unreasonably unsustainable and would offset important development/features by years.
In addition, they should be limited to APIs where the number of actual users is very small (for example only impacting some plugins), and can be coordinated with the community in advance.
c) True breakage should only be considered when a normal transition is unreasonably unsustainable and would offset important developments or features by years. In addition, they should be limited to APIs where the number of actual users is very small (for example, only impacting some plugins) and can be coordinated with the community in advance.
Examples for such upcoming changes:
@@ -62,11 +58,11 @@ Focus primary 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.
With the pytest 3.0 release we introduced a clear communication scheme for when we will actually remove the old busted joint and politely ask you to use the new hotness instead, while giving you enough time to adjust your tests or raise concerns if there are valid reasons to keep deprecated functionality around.
With the pytest 3.0 release, we introduced a clear communication scheme for when we will actually remove the old busted joint and politely ask you to use the new hotness instead, while giving you enough time to adjust your tests or raise concerns if there are valid reasons to keep deprecated functionality around.
To communicate changes we issue deprecation warnings using a custom warning hierarchy (see :ref:`internal-warnings`). These warnings may be suppressed using the standard means: ``-W`` command-line flag or ``filterwarnings`` ini options (see :ref:`warnings`), but we suggest to use these sparingly and temporarily, and heed the warnings when possible.
To communicate changes, we issue deprecation warnings using a custom warning hierarchy (see :ref:`internal-warnings`). These warnings may be suppressed using the standard means: ``-W`` command-line flag or ``filterwarnings`` ini options (see :ref:`warnings`), but we suggest to use these sparingly and temporarily, and heed the warnings when possible.
We will only start the removal of deprecated functionality in major releases (e.g. if we deprecate something in 3.0 we will start to remove it in 4.0), and keep it around for at least two minor releases (e.g. if we deprecate something in 3.9 and 4.0 is the next release, we start to remove it in 5.0, not in 4.0).
We will only start the removal of deprecated functionality in major releases (e.g. if we deprecate something in 3.0, we will start to remove it in 4.0), and keep it around for at least two minor releases (e.g. if we deprecate something in 3.9 and 4.0 is the next release, we start to remove it in 5.0, not in 4.0).
When the deprecation expires (e.g. 4.0 is released), we won't remove the deprecated functionality immediately, but will use the standard warning filters to turn them into **errors** by default. This approach makes it explicit that removal is imminent, and still gives you time to turn the deprecated feature into a warning instead of an error so it can be dealt with in your own time. In the next minor release (e.g. 4.1), the feature will be effectively removed.

View File

@@ -22,7 +22,7 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
cachedir: .pytest_cache
rootdir: /home/sweet/project
collected 0 items
cache -- .../_pytest/cacheprovider.py:542
cache -- .../_pytest/cacheprovider.py:560
Return a cache object that can persist state between testing sessions.
cache.get(key, default)
@@ -115,7 +115,7 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
For more details: :ref:`doctest_namespace`.
pytestconfig [session scope] -- .../_pytest/fixtures.py:1335
pytestconfig [session scope] -- .../_pytest/fixtures.py:1338
Session-scoped fixture that returns the session's :class:`pytest.Config`
object.

View File

@@ -19,18 +19,100 @@ with advance notice in the **Deprecations** section of releases.
we named the news folder changelog
.. only:: changelog_towncrier_draft
.. only:: not is_release
.. The 'changelog_towncrier_draft' tag is included by our 'tox -e docs',
but not on readthedocs.
To be included in v\ |release| (if present)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. include:: _changelog_towncrier_draft.rst
.. towncrier-draft-entries:: |release| [UNRELEASED DRAFT]
Released versions
^^^^^^^^^^^^^^^^^
.. towncrier release notes start
pytest 8.2.2 (2024-06-04)
=========================
Bug Fixes
---------
- `#12355 <https://github.com/pytest-dev/pytest/issues/12355>`_: Fix possible catastrophic performance slowdown on a certain parametrization pattern involving many higher-scoped parameters.
- `#12367 <https://github.com/pytest-dev/pytest/issues/12367>`_: Fix a regression in pytest 8.2.0 where unittest class instances (a fresh one is created for each test) were not released promptly on test teardown but only on session teardown.
- `#12381 <https://github.com/pytest-dev/pytest/issues/12381>`_: Fix possible "Directory not empty" crashes arising from concurent cache dir (``.pytest_cache``) creation. Regressed in pytest 8.2.0.
Improved Documentation
----------------------
- `#12290 <https://github.com/pytest-dev/pytest/issues/12290>`_: Updated Sphinx theme to use Furo instead of Flask, enabling Dark mode theme.
- `#12356 <https://github.com/pytest-dev/pytest/issues/12356>`_: Added a subsection to the documentation for debugging flaky tests to mention
lack of thread safety in pytest as a possible source of flakyness.
- `#12363 <https://github.com/pytest-dev/pytest/issues/12363>`_: The documentation webpages now links to a canonical version to reduce outdated documentation in search engine results.
pytest 8.2.1 (2024-05-19)
=========================
Improvements
------------
- `#12334 <https://github.com/pytest-dev/pytest/issues/12334>`_: Support for Python 3.13 (beta1 at the time of writing).
Bug Fixes
---------
- `#12120 <https://github.com/pytest-dev/pytest/issues/12120>`_: Fix `PermissionError` crashes arising from directories which are not selected on the command-line.
- `#12191 <https://github.com/pytest-dev/pytest/issues/12191>`_: Keyboard interrupts and system exits are now properly handled during the test collection.
- `#12300 <https://github.com/pytest-dev/pytest/issues/12300>`_: Fixed handling of 'Function not implemented' error under squashfuse_ll, which is a different way to say that the mountpoint is read-only.
- `#12308 <https://github.com/pytest-dev/pytest/issues/12308>`_: Fix a regression in pytest 8.2.0 where the permissions of automatically-created ``.pytest_cache`` directories became ``rwx------`` instead of the expected ``rwxr-xr-x``.
Trivial/Internal Changes
------------------------
- `#12333 <https://github.com/pytest-dev/pytest/issues/12333>`_: pytest releases are now attested using the recent `Artifact Attestation <https://github.blog/2024-05-02-introducing-artifact-attestations-now-in-public-beta/>`_ support from GitHub, allowing users to verify the provenance of pytest's sdist and wheel artifacts.
pytest 8.2.0 (2024-04-27)
=========================
Breaking Changes
----------------
- `#12089 <https://github.com/pytest-dev/pytest/pull/12089>`_: pytest now requires that :class:`unittest.TestCase` subclasses can be instantiated freely using ``MyTestCase('runTest')``.
If the class doesn't allow this, you may see an error during collection such as ``AttributeError: 'MyTestCase' object has no attribute 'runTest'``.
Classes which do not override ``__init__``, or do not access the test method in ``__init__`` using ``getattr`` or similar, are unaffected.
Classes which do should take care to not crash when ``"runTest"`` is given, as is shown in `unittest.TestCases's implementation <https://github.com/python/cpython/blob/51aefc5bf907ddffaaf083ded0de773adcdf08c8/Lib/unittest/case.py#L419-L426>`_.
Alternatively, consider using :meth:`setUp <unittest.TestCase.setUp>` instead of ``__init__``.
If you run into this issue using ``tornado.AsyncTestCase``, please see `issue 12263 <https://github.com/pytest-dev/pytest/issues/12263>`_.
If you run into this issue using an abstract ``TestCase`` subclass, please see `issue 12275 <https://github.com/pytest-dev/pytest/issues/12275>`_.
Historical note: the effect of this change on custom TestCase implementations was not properly considered initially, this is why it was done in a minor release. We apologize for the inconvenience.
Deprecations
------------
@@ -150,7 +232,7 @@ Improvements
- `#11311 <https://github.com/pytest-dev/pytest/issues/11311>`_: When using ``--override-ini`` for paths in invocations without a configuration file defined, the current working directory is used
as the relative directory.
Previoulsy this would raise an :class:`AssertionError`.
Previously this would raise an :class:`AssertionError`.
- `#11475 <https://github.com/pytest-dev/pytest/issues/11475>`_: :ref:`--import-mode=importlib <import-mode-importlib>` now tries to import modules using the standard import mechanism (but still without changing :py:data:`sys.path`), falling back to importing modules directly only if that fails.
@@ -186,7 +268,7 @@ Bug Fixes
- `#11904 <https://github.com/pytest-dev/pytest/issues/11904>`_: Fixed a regression in pytest 8.0.0 that would cause test collection to fail due to permission errors when using ``--pyargs``.
This change improves the collection tree for tests specified using ``--pyargs``, see :pull:`12043` for a comparison with pytest 8.0 and <8.
This change improves the collection tree for tests specified using ``--pyargs``, see :pr:`12043` for a comparison with pytest 8.0 and <8.
- `#12011 <https://github.com/pytest-dev/pytest/issues/12011>`_: Fixed a regression in 8.0.1 whereby ``setup_module`` xunit-style fixtures are not executed when ``--doctest-modules`` is passed.
@@ -1340,7 +1422,7 @@ Bug Fixes
tests/link -> tests/real
running ``pytest tests`` now imports the conftest twice, once as ``tests/real/conftest.py`` and once as ``tests/link/conftest.py``.
This is a fix to match a similar change made to test collection itself in pytest 6.0 (see :pull:`6523` for details).
This is a fix to match a similar change made to test collection itself in pytest 6.0 (see :pr:`6523` for details).
- `#9626 <https://github.com/pytest-dev/pytest/issues/9626>`_: Fixed count of selected tests on terminal collection summary when there were errors or skipped modules.
@@ -1393,7 +1475,7 @@ Deprecations
``__init__`` method, they should take ``**kwargs``. See
:ref:`uncooperative-constructors-deprecated` for details.
Note that a deprection warning is only emitted when there is a conflict in the
Note that a deprecation warning is only emitted when there is a conflict in the
arguments pytest expected to pass. This deprecation was already part of pytest
7.0.0rc1 but wasn't documented.
@@ -1435,7 +1517,7 @@ Breaking Changes
- `#7259 <https://github.com/pytest-dev/pytest/issues/7259>`_: The :ref:`Node.reportinfo() <non-python tests>` function first return value type has been expanded from `py.path.local | str` to `os.PathLike[str] | str`.
Most plugins which refer to `reportinfo()` only define it as part of a custom :class:`pytest.Item` implementation.
Since `py.path.local` is an `os.PathLike[str]`, these plugins are unaffacted.
Since `py.path.local` is an `os.PathLike[str]`, these plugins are unaffected.
Plugins and users which call `reportinfo()`, use the first return value and interact with it as a `py.path.local`, would need to adjust by calling `py.path.local(fspath)`.
Although preferably, avoid the legacy `py.path.local` and use `pathlib.Path`, or use `item.location` or `item.path`, instead.
@@ -1943,7 +2025,7 @@ Bug Fixes
the ``tmp_path``/``tmpdir`` fixture). Now the directories are created with
private permissions.
pytest used to silently use a pre-existing ``/tmp/pytest-of-<username>`` directory,
pytest used to silently use a preexisting ``/tmp/pytest-of-<username>`` directory,
even if owned by another user. This means another user could pre-create such a
directory and gain control of another user's temporary directory. Now such a
condition results in an error.
@@ -2509,7 +2591,7 @@ Breaking Changes
Resolving symlinks for the current directory and during collection was introduced as a bugfix in 3.9.0, but it actually is a new feature which had unfortunate consequences in Windows and surprising results in other platforms.
The team decided to step back on resolving symlinks at all, planning to review this in the future with a more solid solution (see discussion in
:pull:`6523` for details).
:pr:`6523` for details).
This might break test suites which made use of this feature; the fix is to create a symlink
for the entire test tree, and not only to partial files/tress as it was possible previously.
@@ -2670,7 +2752,7 @@ Features
also changes ``sys.modules`` as a side-effect), which works but has a number of drawbacks, like requiring test modules
that don't live in packages to have unique names (as they need to reside under a unique name in ``sys.modules``).
``--import-mode=importlib`` uses more fine grained import mechanisms from ``importlib`` which don't
``--import-mode=importlib`` uses more fine-grained import mechanisms from ``importlib`` which don't
require pytest to change ``sys.path`` or ``sys.modules`` at all, eliminating much of the drawbacks
of the previous mode.
@@ -2687,7 +2769,7 @@ Improvements
------------
- :issue:`4375`: The ``pytest`` command now suppresses the ``BrokenPipeError`` error message that
is printed to stderr when the output of ``pytest`` is piped and and the pipe is
is printed to stderr when the output of ``pytest`` is piped and the pipe is
closed by the piped-to program (common examples are ``less`` and ``head``).
@@ -2792,7 +2874,7 @@ Bug Fixes
- :issue:`6871`: Fix crash with captured output when using :fixture:`capsysbinary`.
- :issue:`6909`: Revert the change introduced by :pull:`6330`, which required all arguments to ``@pytest.mark.parametrize`` to be explicitly defined in the function signature.
- :issue:`6909`: Revert the change introduced by :pr:`6330`, which required all arguments to ``@pytest.mark.parametrize`` to be explicitly defined in the function signature.
The intention of the original change was to remove what was expected to be an unintended/surprising behavior, but it turns out many people relied on it, so the restriction has been reverted.
@@ -2962,7 +3044,7 @@ pytest 5.4.1 (2020-03-13)
Bug Fixes
---------
- :issue:`6909`: Revert the change introduced by :pull:`6330`, which required all arguments to ``@pytest.mark.parametrize`` to be explicitly defined in the function signature.
- :issue:`6909`: Revert the change introduced by :pr:`6330`, which required all arguments to ``@pytest.mark.parametrize`` to be explicitly defined in the function signature.
The intention of the original change was to remove what was expected to be an unintended/surprising behavior, but it turns out many people relied on it, so the restriction has been reverted.
@@ -2989,7 +3071,7 @@ Breaking Changes
This hook has been marked as deprecated and not been even called by pytest for over 10 years now.
- :issue:`6673`: Reversed / fix meaning of "+/-" in error diffs. "-" means that sth. expected is missing in the result and "+" means that there are unexpected extras in the result.
- :issue:`6673`: Reversed / fix meaning of "+/-" in error diffs. "-" means that something expected is missing in the result and "+" means that there are unexpected extras in the result.
- :issue:`6737`: The ``cached_result`` attribute of ``FixtureDef`` is now set to ``None`` when
@@ -3278,7 +3360,9 @@ Bug Fixes
- :issue:`5914`: pytester: fix :py:func:`~pytest.LineMatcher.no_fnmatch_line` when used after positive matching.
- :issue:`6082`: Fix line detection for doctest samples inside :py:class:`python:property` docstrings, as a workaround to :bpo:`17446`.
- :issue:`6082`: Fix line detection for doctest samples inside
:py:class:`python:property` docstrings, as a workaround to
:issue:`python/cpython#61648`.
- :issue:`6254`: Fix compatibility with pytest-parallel (regression in pytest 5.3.0).
@@ -3985,7 +4069,7 @@ Bug Fixes
(``--collect-only``) when ``--log-cli-level`` is used.
- :issue:`5389`: Fix regressions of :pull:`5063` for ``importlib_metadata.PathDistribution`` which have their ``files`` attribute being ``None``.
- :issue:`5389`: Fix regressions of :pr:`5063` for ``importlib_metadata.PathDistribution`` which have their ``files`` attribute being ``None``.
- :issue:`5390`: Fix regression where the ``obj`` attribute of ``TestCase`` items was no longer bound to methods.
@@ -4186,7 +4270,7 @@ Bug Fixes
(``--collect-only``) when ``--log-cli-level`` is used.
- :issue:`5389`: Fix regressions of :pull:`5063` for ``importlib_metadata.PathDistribution`` which have their ``files`` attribute being ``None``.
- :issue:`5389`: Fix regressions of :pr:`5063` for ``importlib_metadata.PathDistribution`` which have their ``files`` attribute being ``None``.
- :issue:`5390`: Fix regression where the ``obj`` attribute of ``TestCase`` items was no longer bound to methods.
@@ -4594,7 +4678,7 @@ Bug Fixes
Improved Documentation
----------------------
- :issue:`4974`: Update docs for ``pytest_cmdline_parse`` hook to note availability liminations
- :issue:`4974`: Update docs for ``pytest_cmdline_parse`` hook to note availability limitations
@@ -6452,7 +6536,7 @@ Features
Bug Fixes
---------
- Fix hanging pexpect test on MacOS by using flush() instead of wait().
- Fix hanging pexpect test on macOS by using flush() instead of wait().
(:issue:`2022`)
- Fix restoring Python state after in-process pytest runs with the
@@ -6500,7 +6584,7 @@ Trivial/Internal Changes
------------------------
- Show a simple and easy error when keyword expressions trigger a syntax error
(for example, ``"-k foo and import"`` will show an error that you can not use
(for example, ``"-k foo and import"`` will show an error that you cannot use
the ``import`` keyword in expressions). (:issue:`2953`)
- Change parametrized automatic test id generation to use the ``__name__``
@@ -7147,10 +7231,10 @@ New Features
* Added ``junit_suite_name`` ini option to specify root ``<testsuite>`` name for JUnit XML reports (:issue:`533`).
* Added an ini option ``doctest_encoding`` to specify which encoding to use for doctest files.
Thanks :user:`wheerd` for the PR (:pull:`2101`).
Thanks :user:`wheerd` for the PR (:pr:`2101`).
* ``pytest.warns`` now checks for subclass relationship rather than
class equality. Thanks :user:`lesteve` for the PR (:pull:`2166`)
class equality. Thanks :user:`lesteve` for the PR (:pr:`2166`)
* ``pytest.raises`` now asserts that the error message matches a text or regex
with the ``match`` keyword argument. Thanks :user:`Kriechi` for the PR.
@@ -7178,7 +7262,7 @@ Changes
the failure. (:issue:`2228`) Thanks to :user:`kkoukiou` for the PR.
* Testcase reports with a ``url`` attribute will now properly write this to junitxml.
Thanks :user:`fushi` for the PR (:pull:`1874`).
Thanks :user:`fushi` for the PR (:pr:`1874`).
* Remove common items from dict comparison output when verbosity=1. Also update
the truncation message to make it clearer that pytest truncates all
@@ -7187,7 +7271,7 @@ Changes
* ``--pdbcls`` no longer implies ``--pdb``. This makes it possible to use
``addopts=--pdbcls=module.SomeClass`` on ``pytest.ini``. Thanks :user:`davidszotten` for
the PR (:pull:`1952`).
the PR (:pr:`1952`).
* fix :issue:`2013`: turn RecordedWarning into ``namedtuple``,
to give it a comprehensible repr while preventing unwarranted modification.
@@ -7441,7 +7525,7 @@ Bug Fixes
a sequence of strings) when modules are considered for assertion rewriting.
Due to this bug, much more modules were being rewritten than necessary
if a test suite uses ``pytest_plugins`` to load internal plugins (:issue:`1888`).
Thanks :user:`jaraco` for the report and :user:`nicoddemus` for the PR (:pull:`1891`).
Thanks :user:`jaraco` for the report and :user:`nicoddemus` for the PR (:pr:`1891`).
* Do not call tearDown and cleanups when running tests from
``unittest.TestCase`` subclasses with ``--pdb``
@@ -7496,12 +7580,12 @@ time or change existing behaviors in order to make them less surprising/more use
* ``--nomagic``: use ``--assert=plain`` instead;
* ``--report``: use ``-r`` instead;
Thanks to :user:`RedBeardCode` for the PR (:pull:`1664`).
Thanks to :user:`RedBeardCode` for the PR (:pr:`1664`).
* ImportErrors in plugins now are a fatal error instead of issuing a
pytest warning (:issue:`1479`). Thanks to :user:`The-Compiler` for the PR.
* Removed support code for Python 3 versions < 3.3 (:pull:`1627`).
* Removed support code for Python 3 versions < 3.3 (:pr:`1627`).
* Removed all ``py.test-X*`` entry points. The versioned, suffixed entry points
were never documented and a leftover from a pre-virtualenv era. These entry
@@ -7512,19 +7596,19 @@ time or change existing behaviors in order to make them less surprising/more use
* ``pytest.skip()`` now raises an error when used to decorate a test function,
as opposed to its original intent (to imperatively skip a test inside a test function). Previously
this usage would cause the entire module to be skipped (:issue:`607`).
Thanks :user:`omarkohl` for the complete PR (:pull:`1519`).
Thanks :user:`omarkohl` for the complete PR (:pr:`1519`).
* Exit tests if a collection error occurs. A poll indicated most users will hit CTRL-C
anyway as soon as they see collection errors, so pytest might as well make that the default behavior (:issue:`1421`).
A ``--continue-on-collection-errors`` option has been added to restore the previous behaviour.
Thanks :user:`olegpidsadnyi` and :user:`omarkohl` for the complete PR (:pull:`1628`).
Thanks :user:`olegpidsadnyi` and :user:`omarkohl` for the complete PR (:pr:`1628`).
* Renamed the pytest ``pdb`` module (plugin) into ``debugging`` to avoid clashes with the builtin ``pdb`` module.
* Raise a helpful failure message when requesting a parametrized fixture at runtime,
e.g. with ``request.getfixturevalue``. Previously these parameters were simply
never defined, so a fixture decorated like ``@pytest.fixture(params=[0, 1, 2])``
only ran once (:pull:`460`).
only ran once (:pr:`460`).
Thanks to :user:`nikratio` for the bug report, :user:`RedBeardCode` and :user:`tomviner` for the PR.
* ``_pytest.monkeypatch.monkeypatch`` class has been renamed to ``_pytest.monkeypatch.MonkeyPatch``
@@ -7542,7 +7626,7 @@ time or change existing behaviors in order to make them less surprising/more use
* New ``doctest_namespace`` fixture for injecting names into the
namespace in which doctests run.
Thanks :user:`milliams` for the complete PR (:pull:`1428`).
Thanks :user:`milliams` for the complete PR (:pr:`1428`).
* New ``--doctest-report`` option available to change the output format of diffs
when running (failing) doctests (implements :issue:`1749`).
@@ -7550,23 +7634,23 @@ time or change existing behaviors in order to make them less surprising/more use
* New ``name`` argument to ``pytest.fixture`` decorator which allows a custom name
for a fixture (to solve the funcarg-shadowing-fixture problem).
Thanks :user:`novas0x2a` for the complete PR (:pull:`1444`).
Thanks :user:`novas0x2a` for the complete PR (:pr:`1444`).
* New ``approx()`` function for easily comparing floating-point numbers in
tests.
Thanks :user:`kalekundert` for the complete PR (:pull:`1441`).
Thanks :user:`kalekundert` for the complete PR (:pr:`1441`).
* Ability to add global properties in the final xunit output file by accessing
the internal ``junitxml`` plugin (experimental).
Thanks :user:`tareqalayan` for the complete PR :pull:`1454`).
Thanks :user:`tareqalayan` for the complete PR :pr:`1454`).
* New ``ExceptionInfo.match()`` method to match a regular expression on the
string representation of an exception (:issue:`372`).
Thanks :user:`omarkohl` for the complete PR (:pull:`1502`).
Thanks :user:`omarkohl` for the complete PR (:pr:`1502`).
* ``__tracebackhide__`` can now also be set to a callable which then can decide
whether to filter the traceback based on the ``ExceptionInfo`` object passed
to it. Thanks :user:`The-Compiler` for the complete PR (:pull:`1526`).
to it. Thanks :user:`The-Compiler` for the complete PR (:pr:`1526`).
* New ``pytest_make_parametrize_id(config, val)`` hook which can be used by plugins to provide
friendly strings for custom types.
@@ -7584,7 +7668,7 @@ time or change existing behaviors in order to make them less surprising/more use
* Introduce ``pytest`` command as recommended entry point. Note that ``py.test``
still works and is not scheduled for removal. Closes proposal
:issue:`1629`. Thanks :user:`obestwalter` and :user:`davehunt` for the complete PR
(:pull:`1633`).
(:pr:`1633`).
* New cli flags:
@@ -7628,19 +7712,19 @@ time or change existing behaviors in order to make them less surprising/more use
* Change ``report.outcome`` for ``xpassed`` tests to ``"passed"`` in non-strict
mode and ``"failed"`` in strict mode. Thanks to :user:`hackebrot` for the PR
(:pull:`1795`) and :user:`gprasad84` for report (:issue:`1546`).
(:pr:`1795`) and :user:`gprasad84` for report (:issue:`1546`).
* Tests marked with ``xfail(strict=False)`` (the default) now appear in
JUnitXML reports as passing tests instead of skipped.
Thanks to :user:`hackebrot` for the PR (:pull:`1795`).
Thanks to :user:`hackebrot` for the PR (:pr:`1795`).
* Highlight path of the file location in the error report to make it easier to copy/paste.
Thanks :user:`suzaku` for the PR (:pull:`1778`).
Thanks :user:`suzaku` for the PR (:pr:`1778`).
* Fixtures marked with ``@pytest.fixture`` can now use ``yield`` statements exactly like
those marked with the ``@pytest.yield_fixture`` decorator. This change renders
``@pytest.yield_fixture`` deprecated and makes ``@pytest.fixture`` with ``yield`` statements
the preferred way to write teardown code (:pull:`1461`).
the preferred way to write teardown code (:pr:`1461`).
Thanks :user:`csaftoiu` for bringing this to attention and :user:`nicoddemus` for the PR.
* Explicitly passed parametrize ids do not get escaped to ascii (:issue:`1351`).
@@ -7651,11 +7735,11 @@ time or change existing behaviors in order to make them less surprising/more use
Thanks :user:`nicoddemus` for the PR.
* ``pytest_terminal_summary`` hook now receives the ``exitstatus``
of the test session as argument. Thanks :user:`blueyed` for the PR (:pull:`1809`).
of the test session as argument. Thanks :user:`blueyed` for the PR (:pr:`1809`).
* Parametrize ids can accept ``None`` as specific test id, in which case the
automatically generated id for that argument will be used.
Thanks :user:`palaviv` for the complete PR (:pull:`1468`).
Thanks :user:`palaviv` for the complete PR (:pr:`1468`).
* The parameter to xunit-style setup/teardown methods (``setup_method``,
``setup_module``, etc.) is now optional and may be omitted.
@@ -7663,32 +7747,32 @@ time or change existing behaviors in order to make them less surprising/more use
* Improved automatic id generation selection in case of duplicate ids in
parametrize.
Thanks :user:`palaviv` for the complete PR (:pull:`1474`).
Thanks :user:`palaviv` for the complete PR (:pr:`1474`).
* Now pytest warnings summary is shown up by default. Added a new flag
``--disable-pytest-warnings`` to explicitly disable the warnings summary (:issue:`1668`).
* Make ImportError during collection more explicit by reminding
the user to check the name of the test module/package(s) (:issue:`1426`).
Thanks :user:`omarkohl` for the complete PR (:pull:`1520`).
Thanks :user:`omarkohl` for the complete PR (:pr:`1520`).
* Add ``build/`` and ``dist/`` to the default ``--norecursedirs`` list. Thanks
:user:`mikofski` for the report and :user:`tomviner` for the PR (:issue:`1544`).
* ``pytest.raises`` in the context manager form accepts a custom
``message`` to raise when no exception occurred.
Thanks :user:`palaviv` for the complete PR (:pull:`1616`).
Thanks :user:`palaviv` for the complete PR (:pr:`1616`).
* ``conftest.py`` files now benefit from assertion rewriting; previously it
was only available for test modules. Thanks :user:`flub`, :user:`sober7` and
:user:`nicoddemus` for the PR (:issue:`1619`).
* Text documents without any doctests no longer appear as "skipped".
Thanks :user:`graingert` for reporting and providing a full PR (:pull:`1580`).
Thanks :user:`graingert` for reporting and providing a full PR (:pr:`1580`).
* Ensure that a module within a namespace package can be found when it
is specified on the command line together with the ``--pyargs``
option. Thanks to :user:`taschini` for the PR (:pull:`1597`).
option. Thanks to :user:`taschini` for the PR (:pr:`1597`).
* Always include full assertion explanation during assertion rewriting. The previous behaviour was hiding
sub-expressions that happened to be ``False``, assuming this was redundant information.
@@ -7704,20 +7788,20 @@ time or change existing behaviors in order to make them less surprising/more use
Thanks :user:`nicoddemus` for the PR.
* ``[pytest]`` sections in ``setup.cfg`` files should now be named ``[tool:pytest]``
to avoid conflicts with other distutils commands (see :pull:`567`). ``[pytest]`` sections in
to avoid conflicts with other distutils commands (see :pr:`567`). ``[pytest]`` sections in
``pytest.ini`` or ``tox.ini`` files are supported and unchanged.
Thanks :user:`nicoddemus` for the PR.
* Using ``pytest_funcarg__`` prefix to declare fixtures is considered deprecated and will be
removed in pytest-4.0 (:pull:`1684`).
removed in pytest-4.0 (:pr:`1684`).
Thanks :user:`nicoddemus` for the PR.
* Passing a command-line string to ``pytest.main()`` is considered deprecated and scheduled
for removal in pytest-4.0. It is recommended to pass a list of arguments instead (:pull:`1723`).
for removal in pytest-4.0. It is recommended to pass a list of arguments instead (:pr:`1723`).
* Rename ``getfuncargvalue`` to ``getfixturevalue``. ``getfuncargvalue`` is
still present but is now considered deprecated. Thanks to :user:`RedBeardCode` and :user:`tomviner`
for the PR (:pull:`1626`).
for the PR (:pr:`1626`).
* ``optparse`` type usage now triggers DeprecationWarnings (:issue:`1740`).
@@ -7775,11 +7859,11 @@ time or change existing behaviors in order to make them less surprising/more use
:user:`tomviner` for the PR.
* ``ConftestImportFailure`` now shows the traceback making it easier to
identify bugs in ``conftest.py`` files (:pull:`1516`). Thanks :user:`txomon` for
identify bugs in ``conftest.py`` files (:pr:`1516`). Thanks :user:`txomon` for
the PR.
* Text documents without any doctests no longer appear as "skipped".
Thanks :user:`graingert` for reporting and providing a full PR (:pull:`1580`).
Thanks :user:`graingert` for reporting and providing a full PR (:pr:`1580`).
* Fixed collection of classes with custom ``__new__`` method.
Fixes :issue:`1579`. Thanks to :user:`Stranger6667` for the PR.
@@ -7787,7 +7871,7 @@ time or change existing behaviors in order to make them less surprising/more use
* Fixed scope overriding inside metafunc.parametrize (:issue:`634`).
Thanks to :user:`Stranger6667` for the PR.
* Fixed the total tests tally in junit xml output (:pull:`1798`).
* Fixed the total tests tally in junit xml output (:pr:`1798`).
Thanks to :user:`cboelsen` for the PR.
* Fixed off-by-one error with lines from ``request.node.warn``.
@@ -7804,14 +7888,14 @@ time or change existing behaviors in order to make them less surprising/more use
* Fix Xfail does not work with condition keyword argument.
Thanks :user:`astraw38` for reporting the issue (:issue:`1496`) and :user:`tomviner`
for PR the (:pull:`1524`).
for PR the (:pr:`1524`).
* Fix win32 path issue when putting custom config file with absolute path
in ``pytest.main("-c your_absolute_path")``.
* Fix maximum recursion depth detection when raised error class is not aware
of unicode/encoded bytes.
Thanks :user:`prusse-martin` for the PR (:pull:`1506`).
Thanks :user:`prusse-martin` for the PR (:pr:`1506`).
* Fix ``pytest.mark.skip`` mark when used in strict mode.
Thanks :user:`pquentin` for the PR and :user:`RonnyPfannschmidt` for
@@ -7838,7 +7922,7 @@ time or change existing behaviors in order to make them less surprising/more use
Thanks :user:`nicoddemus` for the PR.
* Fix (:issue:`469`): junit parses report.nodeid incorrectly, when params IDs
contain ``::``. Thanks :user:`tomviner` for the PR (:pull:`1431`).
contain ``::``. Thanks :user:`tomviner` for the PR (:pr:`1431`).
* Fix (:issue:`578`): SyntaxErrors
containing non-ascii lines at the point of failure generated an internal
@@ -7859,7 +7943,7 @@ time or change existing behaviors in order to make them less surprising/more use
**New Features**
* New ``pytest.mark.skip`` mark, which unconditionally skips marked tests.
Thanks :user:`MichaelAquilina` for the complete PR (:pull:`1040`).
Thanks :user:`MichaelAquilina` for the complete PR (:pr:`1040`).
* ``--doctest-glob`` may now be passed multiple times in the command-line.
Thanks :user:`jab` and :user:`nicoddemus` for the PR.
@@ -7870,14 +7954,14 @@ time or change existing behaviors in order to make them less surprising/more use
* ``pytest.mark.xfail`` now has a ``strict`` option, which makes ``XPASS``
tests to fail the test suite (defaulting to ``False``). There's also a
``xfail_strict`` ini option that can be used to configure it project-wise.
Thanks :user:`rabbbit` for the request and :user:`nicoddemus` for the PR (:pull:`1355`).
Thanks :user:`rabbbit` for the request and :user:`nicoddemus` for the PR (:pr:`1355`).
* ``Parser.addini`` now supports options of type ``bool``.
Thanks :user:`nicoddemus` for the PR.
* New ``ALLOW_BYTES`` doctest option. This strips ``b`` prefixes from byte strings
in doctest output (similar to ``ALLOW_UNICODE``).
Thanks :user:`jaraco` for the request and :user:`nicoddemus` for the PR (:pull:`1287`).
Thanks :user:`jaraco` for the request and :user:`nicoddemus` for the PR (:pr:`1287`).
* Give a hint on ``KeyboardInterrupt`` to use the ``--fulltrace`` option to show the errors.
Fixes :issue:`1366`.
@@ -7909,7 +7993,7 @@ time or change existing behaviors in order to make them less surprising/more use
* Removed code and documentation for Python 2.5 or lower versions,
including removal of the obsolete ``_pytest.assertion.oldinterpret`` module.
Thanks :user:`nicoddemus` for the PR (:pull:`1226`).
Thanks :user:`nicoddemus` for the PR (:pr:`1226`).
* Comparisons now always show up in full when ``CI`` or ``BUILD_NUMBER`` is
found in the environment, even when ``-vv`` isn't used.
@@ -8276,7 +8360,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 pre-existing attribute. Thanks Florian Bruhin.
if "y" is not a preexisting attribute. Thanks Florian Bruhin.
- fix issue741: make running output from testdir.run copy/pasteable
Thanks Bruno Oliveira.
@@ -8332,7 +8416,7 @@ time or change existing behaviors in order to make them less surprising/more use
- fix issue854: autouse yield_fixtures defined as class members of
unittest.TestCase subclasses now work as expected.
Thannks xmo-odoo for the report and Bruno Oliveira for the PR.
Thanks xmo-odoo for the report and Bruno Oliveira for the PR.
- fix issue833: --fixtures now shows all fixtures of collected test files, instead of just the
fixtures declared on the first one.
@@ -8436,7 +8520,7 @@ time or change existing behaviors in order to make them less surprising/more use
github. See https://pytest.org/en/stable/contributing.html .
Thanks to Anatoly for pushing and initial work on this.
- fix issue650: new option ``--docttest-ignore-import-errors`` which
- fix issue650: new option ``--doctest-ignore-import-errors`` which
will turn import errors in doctests into skips. Thanks Charles Cloud
for the complete PR.
@@ -8624,7 +8708,7 @@ time or change existing behaviors in order to make them less surprising/more use
- cleanup setup.py a bit and specify supported versions. Thanks Jurko
Gospodnetic for the PR.
- change XPASS colour to yellow rather then red when tests are run
- change XPASS colour to yellow rather than red when tests are run
with -v.
- fix issue473: work around mock putting an unbound method into a class
@@ -8797,7 +8881,7 @@ time or change existing behaviors in order to make them less surprising/more use
Thanks Ralph Schmitt for the precise failure example.
- fix issue244 by implementing special index for parameters to only use
indices for paramentrized test ids
indices for parametrized test ids
- fix issue287 by running all finalizers but saving the exception
from the first failing finalizer and re-raising it so teardown will
@@ -8805,7 +8889,7 @@ time or change existing behaviors in order to make them less surprising/more use
it might be the cause for other finalizers to fail.
- fix ordering when mock.patch or other standard decorator-wrappings
are used with test methods. This fixues issue346 and should
are used with test methods. This fixes issue346 and should
help with random "xdist" collection failures. Thanks to
Ronny Pfannschmidt and Donald Stufft for helping to isolate it.
@@ -9062,7 +9146,7 @@ Bug fixes:
partially failed (finalizers would not always be called before)
- fix issue320 - fix class scope for fixtures when mixed with
module-level functions. Thanks Anatloy Bubenkoff.
module-level functions. Thanks Anatoly Bubenkoff.
- you can specify "-q" or "-qq" to get different levels of "quieter"
reporting (thanks Katarzyna Jachim)
@@ -9484,7 +9568,7 @@ Bug fixes:
unexpected exceptions
- fix issue47: timing output in junitxml for test cases is now correct
- fix issue48: typo in MarkInfo repr leading to exception
- fix issue49: avoid confusing error when initizaliation partially fails
- fix issue49: avoid confusing error when initialization partially fails
- fix issue44: env/username expansion for junitxml file path
- show releaselevel information in test runs for pypy
- reworked doc pages for better navigation and PDF generation
@@ -9609,7 +9693,7 @@ Bug fixes:
collection-before-running semantics were not
setup as with pytest 1.3.4. Note, however, that
the recommended and much cleaner way to do test
parametraization remains the "pytest_generate_tests"
parameterization remains the "pytest_generate_tests"
mechanism, see the docs.
2.0.0 (2010-11-25)

View File

@@ -15,19 +15,33 @@
#
# The full version, including alpha/beta/rc tags.
# The short X.Y version.
from __future__ import annotations
import os
from pathlib import Path
import shutil
import sys
from textwrap import dedent
from typing import TYPE_CHECKING
from _pytest import __version__ as version
from _pytest import __version__ as full_version
version = full_version.split("+")[0]
if TYPE_CHECKING:
import sphinx.application
PROJECT_ROOT_DIR = Path(__file__).parents[2].resolve()
IS_RELEASE_ON_RTD = (
os.getenv("READTHEDOCS", "False") == "True"
and os.environ["READTHEDOCS_VERSION_TYPE"] == "tag"
)
if IS_RELEASE_ON_RTD:
tags: set[str]
# pylint: disable-next=used-before-assignment
tags.add("is_release") # noqa: F821
release = ".".join(version.split(".")[:2])
# If extensions (or modules to document with autodoc) are in another directory,
@@ -65,16 +79,16 @@ latex_elements = {
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
"pallets_sphinx_themes",
"pygments_pytest",
"sphinx.ext.autodoc",
"sphinx.ext.autosummary",
"sphinx.ext.extlinks",
"sphinx.ext.intersphinx",
"sphinx.ext.todo",
"sphinx.ext.viewcode",
"sphinx_removed_in",
"sphinxcontrib_trio",
"sphinxcontrib.towncrier.ext", # provides `towncrier-draft-entries` directive
"sphinx_issues", # implements `:issue:`, `:pr:` and other GH-related roles
]
# Building PDF docs on readthedocs requires inkscape for svg to pdf
@@ -140,10 +154,6 @@ add_module_names = False
# output. They are ignored by default.
# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = "sphinx"
# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
@@ -160,16 +170,6 @@ linkcheck_ignore = [
linkcheck_workers = 5
_repo = "https://github.com/pytest-dev/pytest"
extlinks = {
"bpo": ("https://bugs.python.org/issue%s", "bpo-%s"),
"pypi": ("https://pypi.org/project/%s/", "%s"),
"issue": (f"{_repo}/issues/%s", "issue #%s"),
"pull": (f"{_repo}/pull/%s", "pull request #%s"),
"user": ("https://github.com/%s", "@%s"),
}
nitpicky = True
nitpick_ignore = [
# TODO (fix in pluggy?)
@@ -183,6 +183,7 @@ nitpick_ignore = [
("py:class", "SubRequest"),
("py:class", "TerminalReporter"),
("py:class", "_pytest._code.code.TerminalRepr"),
("py:class", "TerminalRepr"),
("py:class", "_pytest.fixtures.FixtureFunctionMarker"),
("py:class", "_pytest.logging.LogCaptureHandler"),
("py:class", "_pytest.mark.structures.ParameterSet"),
@@ -204,24 +205,24 @@ nitpick_ignore = [
("py:class", "_PluggyPlugin"),
# TypeVars
("py:class", "_pytest._code.code.E"),
("py:class", "E"), # due to delayed annotation
("py:class", "_pytest.fixtures.FixtureFunction"),
("py:class", "_pytest.nodes._NodeType"),
("py:class", "_NodeType"), # due to delayed annotation
("py:class", "_pytest.python_api.E"),
("py:class", "_pytest.recwarn.T"),
("py:class", "_pytest.runner.TResult"),
("py:obj", "_pytest.fixtures.FixtureValue"),
("py:obj", "_pytest.stash.T"),
("py:class", "_ScopeName"),
]
# -- Options for HTML output ---------------------------------------------------
sys.path.append(os.path.abspath("_themes"))
html_theme_path = ["_themes"]
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = "flask"
html_theme = "furo"
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
@@ -266,18 +267,24 @@ html_favicon = "img/favicon.png"
html_sidebars = {
"index": [
"slim_searchbox.html",
"sidebar/brand.html",
"sidebar/search.html",
"sidebar/scroll-start.html",
"sidebarintro.html",
"globaltoc.html",
"links.html",
"sourcelink.html",
"sidebar/scroll-end.html",
"style.html",
],
"**": [
"slim_searchbox.html",
"sidebar/brand.html",
"sidebar/search.html",
"sidebar/scroll-start.html",
"globaltoc.html",
"relations.html",
"links.html",
"sourcelink.html",
"sidebar/scroll-end.html",
"style.html",
],
}
@@ -316,6 +323,9 @@ html_show_sourcelink = False
# Output file base name for HTML help builder.
htmlhelp_basename = "pytestdoc"
# The base URL which points to the root of the HTML documentation. It is used
# to indicate the location of document using the canonical link relation (#12363).
html_baseurl = "https://docs.pytest.org/en/stable/"
# -- Options for LaTeX output --------------------------------------------------
@@ -337,10 +347,6 @@ latex_documents = [
)
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
latex_logo = "img/pytest1.png"
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
# latex_use_parts = False
@@ -427,6 +433,18 @@ texinfo_documents = [
)
]
# -- Options for towncrier_draft extension -----------------------------------
towncrier_draft_autoversion_mode = "draft" # or: 'sphinx-version', 'sphinx-release'
towncrier_draft_include_empty = True
towncrier_draft_working_directory = PROJECT_ROOT_DIR
towncrier_draft_config_path = "pyproject.toml" # relative to cwd
# -- Options for sphinx_issues extension -----------------------------------
issues_github_path = "pytest-dev/pytest"
intersphinx_mapping = {
"pluggy": ("https://pluggy.readthedocs.io/en/stable", None),
@@ -440,31 +458,7 @@ intersphinx_mapping = {
}
def configure_logging(app: "sphinx.application.Sphinx") -> None:
"""Configure Sphinx's WarningHandler to handle (expected) missing include."""
import logging
import sphinx.util.logging
class WarnLogFilter(logging.Filter):
def filter(self, record: logging.LogRecord) -> bool:
"""Ignore warnings about missing include with "only" directive.
Ref: https://github.com/sphinx-doc/sphinx/issues/2150."""
if (
record.msg.startswith('Problems with "include" directive path:')
and "_changelog_towncrier_draft.rst" in record.msg
):
return False
return True
logger = logging.getLogger(sphinx.util.logging.NAMESPACE)
warn_handler = [x for x in logger.handlers if x.level == logging.WARNING]
assert len(warn_handler) == 1, warn_handler
warn_handler[0].filters.insert(0, WarnLogFilter())
def setup(app: "sphinx.application.Sphinx") -> None:
def setup(app: sphinx.application.Sphinx) -> None:
app.add_crossref_type(
"fixture",
"fixture",
@@ -493,8 +487,6 @@ def setup(app: "sphinx.application.Sphinx") -> None:
indextemplate="pair: %s; hook",
)
configure_logging(app)
# legacypath.py monkey-patches pytest.Testdir in. Import the file so
# that autodoc can discover references to it.
import _pytest.legacypath # noqa: F401

View File

@@ -1 +1,4 @@
from __future__ import annotations
collect_ignore = ["conf.py"]

View File

@@ -22,23 +22,16 @@ Contact channels
requests to GitHub.
- ``#pytest`` `on irc.libera.chat <ircs://irc.libera.chat:6697/#pytest>`_ IRC
channel for random questions (using an IRC client, `via webchat
<https://web.libera.chat/#pytest>`_, or `via Matrix
<https://matrix.to/#/%23pytest:libera.chat>`_).
channel for random questions (using an IRC client, or `via webchat
<https://web.libera.chat/#pytest>`)
- ``#pytest`` `on Matrix https://matrix.to/#/#pytest:matrix.org>`.
- private mail to Holger.Krekel at gmail com if you want to communicate sensitive issues
- `merlinux.eu`_ offers pytest and tox-related professional teaching and
consulting.
.. _`pytest issue tracker`: https://github.com/pytest-dev/pytest/issues
.. _`old issue tracker`: https://bitbucket.org/hpk42/py-trunk/issues/
.. _`pytest discussions`: https://github.com/pytest-dev/pytest/discussions
.. _`merlinux.eu`: https://merlinux.eu/
.. _`get an account`:
.. _tetamap: https://tetamap.wordpress.com/

View File

@@ -7,10 +7,6 @@ This page lists all pytest features that are currently deprecated or have been r
The objective is to give users a clear rationale why a certain feature has been removed, and what alternatives
should be used instead.
.. contents::
:depth: 3
:local:
Deprecated Features
-------------------
@@ -462,7 +458,7 @@ Now :class:`~pytest.Class` collects the test methods directly.
Most plugins which reference ``Instance`` do so in order to ignore or skip it,
using a check such as ``if isinstance(node, Instance): return``.
Such plugins should simply remove consideration of ``Instance`` on pytest>=7.
However, to keep such uses working, a dummy type has been instanted in ``pytest.Instance`` and ``_pytest.python.Instance``,
However, to keep such uses working, a dummy type has been instanced in ``pytest.Instance`` and ``_pytest.python.Instance``,
and importing it emits a deprecation warning. This was removed in pytest 8.

View File

@@ -1,3 +1,5 @@
from __future__ import annotations
import pytest
from pytest import raises

View File

@@ -1,3 +1,5 @@
from __future__ import annotations
import os.path
import pytest

View File

@@ -1,3 +1,6 @@
from __future__ import annotations
hello = "world"

View File

@@ -1,3 +1,5 @@
from __future__ import annotations
import os.path
import shutil

View File

@@ -1,3 +1,6 @@
from __future__ import annotations
def setup_module(module):
module.TestStateFullThing.classcount = 0

View File

@@ -1 +1,4 @@
from __future__ import annotations
collect_ignore = ["nonpython", "customdirectory"]

View File

@@ -1,4 +1,6 @@
# content of conftest.py
from __future__ import annotations
import json
import pytest
@@ -21,7 +23,7 @@ class ManifestDirectory(pytest.Directory):
@pytest.hookimpl
def pytest_collect_directory(path, parent):
# Use our custom collector for directories containing a `mainfest.json` file.
# Use our custom collector for directories containing a `manifest.json` file.
if path.joinpath("manifest.json").is_file():
return ManifestDirectory.from_parent(parent=parent, path=path)
# Otherwise fallback to the standard behavior.

View File

@@ -1,3 +1,6 @@
# content of test_first.py
from __future__ import annotations
def test_1():
pass

View File

@@ -1,3 +1,6 @@
# content of test_second.py
from __future__ import annotations
def test_2():
pass

View File

@@ -1,3 +1,6 @@
# content of test_third.py
from __future__ import annotations
def test_3():
pass

View File

@@ -1,3 +1,5 @@
from __future__ import annotations
import pytest

View File

@@ -1,3 +1,5 @@
from __future__ import annotations
import pytest

View File

@@ -1,3 +1,5 @@
from __future__ import annotations
import pytest

View File

@@ -1,3 +1,5 @@
from __future__ import annotations
import pytest

View File

@@ -1,3 +1,5 @@
from __future__ import annotations
import pytest

View File

@@ -1,3 +1,5 @@
from __future__ import annotations
import pytest

View File

@@ -1,6 +1,8 @@
"""Module containing a parametrized tests testing cross-python serialization
via the pickle module."""
from __future__ import annotations
import shutil
import subprocess
import textwrap

View File

@@ -1,4 +1,6 @@
# content of conftest.py
from __future__ import annotations
import pytest

View File

@@ -162,7 +162,7 @@ objects, they are still using the default pytest representation:
rootdir: /home/sweet/project
collected 8 items
<Dir parametrize.rst-198>
<Dir parametrize.rst-200>
<Module test_time.py>
<Function test_timedistance_v0[a0-b0-expected0]>
<Function test_timedistance_v0[a1-b1-expected1]>
@@ -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
<Dir parametrize.rst-198>
<Dir parametrize.rst-200>
<Module test_scenarios.py>
<Class TestSampleWithScenarios>
<Function test_demo1[basic]>
@@ -318,7 +318,7 @@ Let's first see how it looks like at collection time:
rootdir: /home/sweet/project
collected 2 items
<Dir parametrize.rst-198>
<Dir parametrize.rst-200>
<Module test_backends.py>
<Function test_db_initialized[d1]>
<Function test_db_initialized[d2]>

View File

@@ -1,5 +1,6 @@
# run this with $ pytest --collect-only test_collectonly.py
#
from __future__ import annotations
def test_function():

View File

@@ -152,7 +152,7 @@ The test collection would look like this:
configfile: pytest.ini
collected 2 items
<Dir pythoncollection.rst-199>
<Dir pythoncollection.rst-201>
<Module check_myapp.py>
<Class CheckMyApp>
<Function simple_check>
@@ -215,7 +215,7 @@ You can always peek at the collection tree without running tests like this:
configfile: pytest.ini
collected 3 items
<Dir pythoncollection.rst-199>
<Dir pythoncollection.rst-201>
<Dir CWD>
<Module pythoncollection.py>
<Function test_function>

View File

@@ -1,3 +1,5 @@
from __future__ import annotations
import pytest

View File

@@ -18,7 +18,7 @@ System state
Broadly speaking, a flaky test indicates that the test relies on some system state that is not being appropriately controlled - the test environment is not sufficiently isolated. Higher level tests are more likely to be flaky as they rely on more state.
Flaky tests sometimes appear when a test suite is run in parallel (such as use of pytest-xdist). This can indicate a test is reliant on test ordering.
Flaky tests sometimes appear when a test suite is run in parallel (such as use of `pytest-xdist`_). This can indicate a test is reliant on test ordering.
- Perhaps a different test is failing to clean up after itself and leaving behind data which causes the flaky test to fail.
- The flaky test is reliant on data from a previous test that doesn't clean up after itself, and in parallel runs that previous test is not always present
@@ -30,9 +30,22 @@ Overly strict assertion
Overly strict assertions can cause problems with floating point comparison as well as timing issues. :func:`pytest.approx` is useful here.
Thread safety
~~~~~~~~~~~~~
Pytest features
^^^^^^^^^^^^^^^
pytest is single-threaded, executing its tests always in the same thread, sequentially, never spawning any threads itself.
Even in case of plugins which run tests in parallel, for example `pytest-xdist`_, usually work by spawning multiple *processes* and running tests in batches, without using multiple threads.
It is of course possible (and common) for tests and fixtures to spawn threads themselves as part of their testing workflow (for example, a fixture that starts a server thread in the background, or a test which executes production code that spawns threads), but some care must be taken:
* 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.
Related features
^^^^^^^^^^^^^^^^
Xfail strict
~~~~~~~~~~~~
@@ -123,3 +136,6 @@ Resources
* `Flaky Tests at Google and How We Mitigate Them <https://testing.googleblog.com/2016/05/flaky-tests-at-google-and-how-we.html>`_ by John Micco, 2016
* `Where do Google's flaky tests come from? <https://testing.googleblog.com/2017/04/where-do-our-flaky-tests-come-from.html>`_ by Jeff Listfield, 2017
.. _pytest-xdist: https://github.com/pytest-dev/pytest-xdist

View File

@@ -8,15 +8,15 @@ pytest import mechanisms and ``sys.path``/``PYTHONPATH``
Import modes
------------
pytest as a testing framework needs to import test modules and ``conftest.py`` files for execution.
pytest as a testing framework that needs to import test modules and ``conftest.py`` files for execution.
Importing files in Python is a non-trivial processes, so aspects of the
Importing files in Python is a non-trivial process, so aspects of the
import process can be controlled through the ``--import-mode`` command-line flag, which can assume
these values:
.. _`import-mode-prepend`:
* ``prepend`` (default): the directory path containing each module will be inserted into the *beginning*
* ``prepend`` (default): The directory path containing each module will be inserted into the *beginning*
of :py:data:`sys.path` if not already there, and then imported with
the :func:`importlib.import_module <importlib.import_module>` function.
@@ -34,7 +34,7 @@ these values:
* ``append``: the directory containing each module is appended to the end of :py:data:`sys.path` if not already
there, and imported with :func:`importlib.import_module <importlib.import_module>`.
This better allows to run test modules against installed versions of a package even if the
This better allows users to run test modules against installed versions of a package even if the
package under test has the same import root. For example:
::
@@ -45,7 +45,7 @@ these values:
the tests will run against the installed version
of ``pkg_under_test`` when ``--import-mode=append`` is used whereas
with ``prepend`` they would pick up the local version. This kind of confusion is why
with ``prepend``, they would pick up the local version. This kind of confusion is why
we advocate for using :ref:`src-layouts <src-layout>`.
Same as ``prepend``, requires test module names to be unique when the test directory tree is
@@ -67,7 +67,7 @@ these values:
are not importable. The recommendation in this case it to place testing utility modules together with the application/library
code, for example ``app.testing.helpers``.
Important: by "test utility modules" we mean functions/classes which are imported by
Important: by "test utility modules", we mean functions/classes which are imported by
other tests directly; this does not include fixtures, which should be placed in ``conftest.py`` files, along
with the test modules, and are discovered automatically by pytest.
@@ -76,8 +76,8 @@ these values:
1. Given a certain module path, for example ``tests/core/test_models.py``, derives a canonical name
like ``tests.core.test_models`` and tries to import it.
For non-test modules this will work if they are accessible via :py:data:`sys.path`, so
for example ``.env/lib/site-packages/app/core.py`` will be importable as ``app.core``.
For non-test modules, this will work if they are accessible via :py:data:`sys.path`. So
for example, ``.env/lib/site-packages/app/core.py`` will be importable as ``app.core``.
This is happens when plugins import non-test modules (for example doctesting).
If this step succeeds, the module is returned.

View File

@@ -22,7 +22,7 @@ Install ``pytest``
.. code-block:: bash
$ pytest --version
pytest 8.2.0
pytest 8.2.2
.. _`simpletest`:
@@ -274,7 +274,7 @@ Continue reading
Check out additional pytest resources to help you customize tests for your unique workflow:
* ":ref:`usage`" for command line invocation examples
* ":ref:`existingtestsuite`" for working with pre-existing tests
* ":ref:`existingtestsuite`" for working with preexisting tests
* ":ref:`mark`" for information on the ``pytest.mark`` mechanism
* ":ref:`fixtures`" for providing a functional baseline to your tests
* ":ref:`plugins`" for managing and writing plugins

View File

@@ -107,7 +107,7 @@ Here is a non-exhaustive list of issues fixed by the new implementation:
* Marker transfer incompatible with inheritance (:issue:`535`).
More details can be found in the :pull:`original PR <3317>`.
More details can be found in the :pr:`original PR <3317>`.
.. note::

View File

@@ -1418,7 +1418,7 @@ Running the above tests results in the following test IDs being used:
rootdir: /home/sweet/project
collected 12 items
<Dir fixtures.rst-217>
<Dir fixtures.rst-219>
<Module test_anothersmtp.py>
<Function test_showhelo[smtp.gmail.com]>
<Function test_showhelo[mail.python.org]>

View File

@@ -1,17 +1,15 @@
:orphan:
.. sidebar:: Next Open Trainings and Events
- `Professional Testing with Python <https://python-academy.com/courses/python_course_testing.html>`_, via `Python Academy <https://www.python-academy.com/>`_ (3 day in-depth training):
* **June 11th to 13th 2024**, Remote
* **March 4th to 6th 2025**, Leipzig, Germany / Remote
- `pytest development sprint <https://github.com/pytest-dev/pytest/discussions/11655>`_, **June 17th -- 22nd 2024**
- pytest tips and tricks for a better testsuite, `Europython 2024 <https://ep2024.europython.eu/>`_, **July 8th -- 14th 2024** (3h), Prague
Also see :doc:`previous talks and blogposts <talks>`.
.. _features:
.. sidebar:: **Next Open Trainings and Events**
- `pytest tips and tricks for a better testsuite <https://ep2024.europython.eu/session/pytest-tips-and-tricks-for-a-better-testsuite>`_, at `Europython 2024 <https://ep2024.europython.eu/>`_, **July 9th 2024** (3h), Prague (CZ)
- `pytest: Professionelles Testen (nicht nur) für Python <https://pretalx.com/workshoptage-2024/talk/9VUHYB/>`_, at `CH Open Workshoptage <https://workshoptage.ch/>`_, **September 2nd 2024**, HSLU Rotkreuz (CH)
- `Professional Testing with Python <https://python-academy.com/courses/python_course_testing.html>`_, via `Python Academy <https://www.python-academy.com/>`_ (3 day in-depth training), **March 4th -- 6th 2025**, Leipzig (DE) / Remote
Also see :doc:`previous talks and blogposts <talks>`
pytest: helps you write better programs
=======================================
@@ -25,7 +23,6 @@ scale to support complex functional testing for applications and libraries.
**PyPI package name**: :pypi:`pytest`
A quick example
---------------

View File

@@ -8,7 +8,7 @@ If you used older version of the ``py`` distribution (which
included the py.test command line tool and Python name space)
you accessed helpers and possibly collection classes through
the ``py.test`` Python namespaces. The new ``pytest``
Python module flaty provides the same objects, following
Python module flatly provides the same objects, following
these renaming rules::
py.test.XYZ -> pytest.XYZ

View File

@@ -39,7 +39,7 @@ Built-in fixtures
Store and retrieve values across pytest runs.
:fixture:`doctest_namespace`
Provide a dict injected into the docstests namespace.
Provide a dict injected into the doctests namespace.
:fixture:`monkeypatch`
Temporarily modify classes, functions, dictionaries,

View File

@@ -7,9 +7,6 @@ API Reference
This page contains the full reference to pytest's API.
.. contents::
:depth: 3
:local:
Constants
---------
@@ -59,11 +56,19 @@ pytest.fail
.. autofunction:: pytest.fail(reason, [pytrace=True, msg=None])
.. class:: pytest.fail.Exception
The exception raised by :func:`pytest.fail`.
pytest.skip
~~~~~~~~~~~
.. autofunction:: pytest.skip(reason, [allow_module_level=False, msg=None])
.. class:: pytest.skip.Exception
The exception raised by :func:`pytest.skip`.
.. _`pytest.importorskip ref`:
pytest.importorskip
@@ -76,11 +81,19 @@ pytest.xfail
.. autofunction:: pytest.xfail
.. class:: pytest.xfail.Exception
The exception raised by :func:`pytest.xfail`.
pytest.exit
~~~~~~~~~~~
.. autofunction:: pytest.exit(reason, [returncode=None, msg=None])
.. class:: pytest.exit.Exception
The exception raised by :func:`pytest.exit`.
pytest.main
~~~~~~~~~~~
@@ -246,9 +259,10 @@ Marks a test function as *expected to fail*.
to specify ``reason`` (see :ref:`condition string <string conditions>`).
:keyword str reason:
Reason why the test function is marked as xfail.
:keyword Type[Exception] raises:
:keyword raises:
Exception class (or tuple of classes) expected to be raised by the test function; other exceptions will fail the test.
Note that subclasses of the classes passed will also result in a match (similar to how the ``except`` statement works).
:type raises: Type[:py:exc:`Exception`]
:keyword bool run:
Whether the test function should actually be executed. If ``False``, the function will always xfail and will
@@ -1923,7 +1937,7 @@ All the command-line flags can be obtained by running ``pytest --help``::
general:
-k EXPRESSION Only run tests which match the given substring
expression. An expression is a Python evaluatable
expression. An expression is a Python evaluable
expression where all names are substring-matched
against test names and their parent classes.
Example: -k 'test_method or test_other' matches all

View File

@@ -1,4 +1,3 @@
pallets-sphinx-themes
pluggy>=1.5.0
pygments-pytest>=2.3.0
sphinx-removed-in>=0.2.0
@@ -8,4 +7,7 @@ sphinxcontrib-svg2pdfconverter
# Pin packaging because it no longer handles 'latest' version, which
# is the version that is assigned to the docs.
# See https://github.com/pytest-dev/pytest/pull/10578#issuecomment-1348249045.
packaging <22
packaging
furo
sphinxcontrib-towncrier
sphinx-issues

View File

@@ -1,3 +1,5 @@
from __future__ import annotations
import json
from pathlib import Path

View File

@@ -6,15 +6,15 @@ keywords = [
"test",
"unittest",
]
license = {text = "MIT"}
license = { text = "MIT" }
authors = [
{name = "Holger Krekel"},
{name = "Bruno Oliveira"},
{name = "Ronny Pfannschmidt"},
{name = "Floris Bruynooghe"},
{name = "Brianna Laugher"},
{name = "Florian Bruhin"},
{name = "Others (See AUTHORS)"},
{ name = "Holger Krekel" },
{ name = "Bruno Oliveira" },
{ name = "Ronny Pfannschmidt" },
{ name = "Floris Bruynooghe" },
{ name = "Brianna Laugher" },
{ name = "Florian Bruhin" },
{ name = "Others (See AUTHORS)" },
]
requires-python = ">=3.8"
classifiers = [
@@ -31,6 +31,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Software Development :: Libraries",
"Topic :: Software Development :: Testing",
"Topic :: Utilities",
@@ -98,6 +99,7 @@ select = [
"E", # pycodestyle
"F", # pyflakes
"I", # isort
"FA100", # add future annotations
"PYI", # flake8-pyi
"UP", # pyupgrade
"RUF", # ruff
@@ -168,7 +170,7 @@ lines-after-imports = 2
[tool.pylint.main]
# Maximum number of characters on a single line.
max-line-length = 120
disable= [
disable = [
"abstract-method",
"arguments-differ",
"arguments-renamed",
@@ -353,45 +355,75 @@ directory = "changelog/"
title_format = "pytest {version} ({project_date})"
template = "changelog/_template.rst"
[[tool.towncrier.type]]
directory = "breaking"
name = "Breaking Changes"
showcontent = true
# NOTE: The types are declared because:
# NOTE: - there is no mechanism to override just the value of
# NOTE: `tool.towncrier.type.misc.showcontent`;
# NOTE: - and, we want to declare extra non-default types for
# NOTE: clarity and flexibility.
[[tool.towncrier.type]]
directory = "deprecation"
name = "Deprecations"
showcontent = true
[[tool.towncrier.type]]
# When something public gets removed in a breaking way. Could be
# deprecated in an earlier release.
directory = "breaking"
name = "Removals and backward incompatible breaking changes"
showcontent = true
[[tool.towncrier.type]]
directory = "feature"
name = "Features"
showcontent = true
[[tool.towncrier.type]]
# Declarations of future API removals and breaking changes in behavior.
directory = "deprecation"
name = "Deprecations (removal in next major release)"
showcontent = true
[[tool.towncrier.type]]
directory = "improvement"
name = "Improvements"
showcontent = true
[[tool.towncrier.type]]
# New behaviors, public APIs. That sort of stuff.
directory = "feature"
name = "New features"
showcontent = true
[[tool.towncrier.type]]
directory = "bugfix"
name = "Bug Fixes"
showcontent = true
[[tool.towncrier.type]]
# New behaviors in existing features.
directory = "improvement"
name = "Improvements in existing functionality"
showcontent = true
[[tool.towncrier.type]]
directory = "vendor"
name = "Vendored Libraries"
showcontent = true
[[tool.towncrier.type]]
# Something we deemed an improper undesired behavior that got corrected
# in the release to match pre-agreed expectations.
directory = "bugfix"
name = "Bug fixes"
showcontent = true
[[tool.towncrier.type]]
directory = "doc"
name = "Improved Documentation"
showcontent = true
[[tool.towncrier.type]]
# Updates regarding bundling dependencies.
directory = "vendor"
name = "Vendored libraries"
showcontent = true
[[tool.towncrier.type]]
directory = "trivial"
name = "Trivial/Internal Changes"
showcontent = true
[[tool.towncrier.type]]
# Notable updates to the documentation structure or build process.
directory = "doc"
name = "Improved documentation"
showcontent = true
[[tool.towncrier.type]]
# Notes for downstreams about unobvious side effects and tooling. Changes
# in the test invocation considerations and runtime assumptions.
directory = "packaging"
name = "Packaging updates and notes for downstreams"
showcontent = true
[[tool.towncrier.type]]
# Stuff that affects the contributor experience. e.g. Running tests,
# building the docs, setting up the development environment.
directory = "contrib"
name = "Contributor-facing changes"
showcontent = true
[[tool.towncrier.type]]
# Changes that are hard to assign to any of the above categories.
directory = "misc"
name = "Miscellaneous internal changes"
showcontent = true
[tool.mypy]
files = ["src", "testing", "scripts"]

View File

@@ -9,6 +9,8 @@ our CHANGELOG) into Markdown (which is required by GitHub Releases).
Requires Python3.6+.
"""
from __future__ import annotations
from pathlib import Path
import re
import sys

View File

@@ -14,6 +14,8 @@ After that, it will create a release using the `release` tox environment, and pu
`pytest bot <pytestbot@gmail.com>` commit author.
"""
from __future__ import annotations
import argparse
from pathlib import Path
import re

View File

@@ -1,6 +1,8 @@
# mypy: disallow-untyped-defs
"""Invoke development tasks."""
from __future__ import annotations
import argparse
import os
from pathlib import Path

View File

@@ -1,18 +0,0 @@
# mypy: disallow-untyped-defs
from subprocess import call
import sys
def main() -> int:
"""
Platform-agnostic wrapper script for towncrier.
Fixes the issue (#7251) where Windows users are unable to natively run tox -e docs to build pytest docs.
"""
with open(
"doc/en/_changelog_towncrier_draft.rst", "w", encoding="utf-8"
) as draft_file:
return call(("towncrier", "--draft"), stdout=draft_file)
if __name__ == "__main__":
sys.exit(main())

View File

@@ -1,4 +1,6 @@
# mypy: disallow-untyped-defs
from __future__ import annotations
import datetime
import pathlib
import re

View File

@@ -1,3 +1,6 @@
from __future__ import annotations
__all__ = ["__version__", "version_tuple"]
try:

View File

@@ -62,13 +62,13 @@ If things do not work right away:
global argcomplete script).
"""
from __future__ import annotations
import argparse
from glob import glob
import os
import sys
from typing import Any
from typing import List
from typing import Optional
class FastFilesCompleter:
@@ -77,7 +77,7 @@ class FastFilesCompleter:
def __init__(self, directories: bool = True) -> None:
self.directories = directories
def __call__(self, prefix: str, **kwargs: Any) -> List[str]:
def __call__(self, prefix: str, **kwargs: Any) -> list[str]:
# Only called on non option completions.
if os.sep in prefix[1:]:
prefix_dir = len(os.path.dirname(prefix) + os.sep)
@@ -104,7 +104,7 @@ if os.environ.get("_ARGCOMPLETE"):
import argcomplete.completers
except ImportError:
sys.exit(-1)
filescompleter: Optional[FastFilesCompleter] = FastFilesCompleter()
filescompleter: FastFilesCompleter | None = FastFilesCompleter()
def try_argcomplete(parser: argparse.ArgumentParser) -> None:
argcomplete.autocomplete(parser, always_complete_options=False)

View File

@@ -1,5 +1,7 @@
"""Python inspection/code generation API."""
from __future__ import annotations
from .code import Code
from .code import ExceptionInfo
from .code import filter_traceback

View File

@@ -1,4 +1,6 @@
# mypy: allow-untyped-defs
from __future__ import annotations
import ast
import dataclasses
import inspect
@@ -17,7 +19,6 @@ from types import TracebackType
from typing import Any
from typing import Callable
from typing import ClassVar
from typing import Dict
from typing import Final
from typing import final
from typing import Generic
@@ -25,11 +26,9 @@ from typing import Iterable
from typing import List
from typing import Literal
from typing import Mapping
from typing import Optional
from typing import overload
from typing import Pattern
from typing import Sequence
from typing import Set
from typing import SupportsIndex
from typing import Tuple
from typing import Type
@@ -57,6 +56,8 @@ if sys.version_info < (3, 11):
_TracebackStyle = Literal["long", "short", "line", "no", "native", "value", "auto"]
EXCEPTION_OR_MORE = Union[Type[Exception], Tuple[Type[Exception], ...]]
class Code:
"""Wrapper around Python code objects."""
@@ -67,7 +68,7 @@ class Code:
self.raw = obj
@classmethod
def from_function(cls, obj: object) -> "Code":
def from_function(cls, obj: object) -> Code:
return cls(getrawcode(obj))
def __eq__(self, other):
@@ -85,7 +86,7 @@ class Code:
return self.raw.co_name
@property
def path(self) -> Union[Path, str]:
def path(self) -> Path | str:
"""Return a path object pointing to source code, or an ``str`` in
case of ``OSError`` / non-existing file."""
if not self.raw.co_filename:
@@ -102,17 +103,17 @@ class Code:
return self.raw.co_filename
@property
def fullsource(self) -> Optional["Source"]:
def fullsource(self) -> Source | None:
"""Return a _pytest._code.Source object for the full source file of the code."""
full, _ = findsource(self.raw)
return full
def source(self) -> "Source":
def source(self) -> Source:
"""Return a _pytest._code.Source object for the code object's source only."""
# return source only for that part of code
return Source(self.raw)
def getargs(self, var: bool = False) -> Tuple[str, ...]:
def getargs(self, var: bool = False) -> tuple[str, ...]:
"""Return a tuple with the argument names for the code object.
If 'var' is set True also return the names of the variable and
@@ -141,11 +142,11 @@ class Frame:
return self.raw.f_lineno - 1
@property
def f_globals(self) -> Dict[str, Any]:
def f_globals(self) -> dict[str, Any]:
return self.raw.f_globals
@property
def f_locals(self) -> Dict[str, Any]:
def f_locals(self) -> dict[str, Any]:
return self.raw.f_locals
@property
@@ -153,7 +154,7 @@ class Frame:
return Code(self.raw.f_code)
@property
def statement(self) -> "Source":
def statement(self) -> Source:
"""Statement this frame is at."""
if self.code.fullsource is None:
return Source("")
@@ -197,14 +198,14 @@ class TracebackEntry:
def __init__(
self,
rawentry: TracebackType,
repr_style: Optional['Literal["short", "long"]'] = None,
repr_style: Literal["short", "long"] | None = None,
) -> None:
self._rawentry: "Final" = rawentry
self._repr_style: "Final" = repr_style
self._rawentry: Final = rawentry
self._repr_style: Final = repr_style
def with_repr_style(
self, repr_style: Optional['Literal["short", "long"]']
) -> "TracebackEntry":
self, repr_style: Literal["short", "long"] | None
) -> TracebackEntry:
return TracebackEntry(self._rawentry, repr_style)
@property
@@ -223,19 +224,19 @@ class TracebackEntry:
return "<TracebackEntry %s:%d>" % (self.frame.code.path, self.lineno + 1)
@property
def statement(self) -> "Source":
def statement(self) -> Source:
"""_pytest._code.Source object for the current statement."""
source = self.frame.code.fullsource
assert source is not None
return source.getstatement(self.lineno)
@property
def path(self) -> Union[Path, str]:
def path(self) -> Path | str:
"""Path to the source code."""
return self.frame.code.path
@property
def locals(self) -> Dict[str, Any]:
def locals(self) -> dict[str, Any]:
"""Locals of underlying frame."""
return self.frame.f_locals
@@ -243,8 +244,8 @@ class TracebackEntry:
return self.frame.code.firstlineno
def getsource(
self, astcache: Optional[Dict[Union[str, Path], ast.AST]] = None
) -> Optional["Source"]:
self, astcache: dict[str | Path, ast.AST] | None = None
) -> Source | None:
"""Return failing source code."""
# we use the passed in astcache to not reparse asttrees
# within exception info printing
@@ -270,7 +271,7 @@ class TracebackEntry:
source = property(getsource)
def ishidden(self, excinfo: Optional["ExceptionInfo[BaseException]"]) -> bool:
def ishidden(self, excinfo: ExceptionInfo[BaseException] | None) -> bool:
"""Return True if the current frame has a var __tracebackhide__
resolving to True.
@@ -279,9 +280,7 @@ class TracebackEntry:
Mostly for internal use.
"""
tbh: Union[bool, Callable[[Optional[ExceptionInfo[BaseException]]], bool]] = (
False
)
tbh: bool | Callable[[ExceptionInfo[BaseException] | None], bool] = False
for maybe_ns_dct in (self.frame.f_locals, self.frame.f_globals):
# in normal cases, f_locals and f_globals are dictionaries
# however via `exec(...)` / `eval(...)` they can be other types
@@ -326,13 +325,13 @@ class Traceback(List[TracebackEntry]):
def __init__(
self,
tb: Union[TracebackType, Iterable[TracebackEntry]],
tb: TracebackType | Iterable[TracebackEntry],
) -> None:
"""Initialize from given python traceback object and ExceptionInfo."""
if isinstance(tb, TracebackType):
def f(cur: TracebackType) -> Iterable[TracebackEntry]:
cur_: Optional[TracebackType] = cur
cur_: TracebackType | None = cur
while cur_ is not None:
yield TracebackEntry(cur_)
cur_ = cur_.tb_next
@@ -343,11 +342,11 @@ class Traceback(List[TracebackEntry]):
def cut(
self,
path: Optional[Union["os.PathLike[str]", str]] = None,
lineno: Optional[int] = None,
firstlineno: Optional[int] = None,
excludepath: Optional["os.PathLike[str]"] = None,
) -> "Traceback":
path: os.PathLike[str] | str | None = None,
lineno: int | None = None,
firstlineno: int | None = None,
excludepath: os.PathLike[str] | None = None,
) -> Traceback:
"""Return a Traceback instance wrapping part of this Traceback.
By providing any combination of path, lineno and firstlineno, the
@@ -378,14 +377,12 @@ class Traceback(List[TracebackEntry]):
return self
@overload
def __getitem__(self, key: "SupportsIndex") -> TracebackEntry: ...
def __getitem__(self, key: SupportsIndex) -> TracebackEntry: ...
@overload
def __getitem__(self, key: slice) -> "Traceback": ...
def __getitem__(self, key: slice) -> Traceback: ...
def __getitem__(
self, key: Union["SupportsIndex", slice]
) -> Union[TracebackEntry, "Traceback"]:
def __getitem__(self, key: SupportsIndex | slice) -> TracebackEntry | Traceback:
if isinstance(key, slice):
return self.__class__(super().__getitem__(key))
else:
@@ -393,12 +390,9 @@ class Traceback(List[TracebackEntry]):
def filter(
self,
excinfo_or_fn: Union[
"ExceptionInfo[BaseException]",
Callable[[TracebackEntry], bool],
],
excinfo_or_fn: ExceptionInfo[BaseException] | Callable[[TracebackEntry], bool],
/,
) -> "Traceback":
) -> Traceback:
"""Return a Traceback instance with certain items removed.
If the filter is an `ExceptionInfo`, removes all the ``TracebackEntry``s
@@ -414,25 +408,24 @@ class Traceback(List[TracebackEntry]):
fn = excinfo_or_fn
return Traceback(filter(fn, self))
def recursionindex(self) -> Optional[int]:
def recursionindex(self) -> int | None:
"""Return the index of the frame/TracebackEntry where recursion originates if
appropriate, None if no recursion occurred."""
cache: Dict[Tuple[Any, int, int], List[Dict[str, Any]]] = {}
cache: dict[tuple[Any, int, int], list[dict[str, Any]]] = {}
for i, entry in enumerate(self):
# id for the code.raw is needed to work around
# the strange metaprogramming in the decorator lib from pypi
# which generates code objects that have hash/value equality
# XXX needs a test
key = entry.frame.code.path, id(entry.frame.code.raw), entry.lineno
# print "checking for recursion at", key
values = cache.setdefault(key, [])
# Since Python 3.13 f_locals is a proxy, freeze it.
loc = dict(entry.frame.f_locals)
if values:
f = entry.frame
loc = f.f_locals
for otherloc in values:
if otherloc == loc:
return i
values.append(entry.frame.f_locals)
values.append(loc)
return None
@@ -446,15 +439,15 @@ class ExceptionInfo(Generic[E]):
_assert_start_repr: ClassVar = "AssertionError('assert "
_excinfo: Optional[Tuple[Type["E"], "E", TracebackType]]
_excinfo: tuple[type[E], E, TracebackType] | None
_striptext: str
_traceback: Optional[Traceback]
_traceback: Traceback | None
def __init__(
self,
excinfo: Optional[Tuple[Type["E"], "E", TracebackType]],
excinfo: tuple[type[E], E, TracebackType] | None,
striptext: str = "",
traceback: Optional[Traceback] = None,
traceback: Traceback | None = None,
*,
_ispytest: bool = False,
) -> None:
@@ -470,8 +463,8 @@ class ExceptionInfo(Generic[E]):
# This is OK to ignore because this class is (conceptually) readonly.
# See https://github.com/python/mypy/issues/7049.
exception: E, # type: ignore[misc]
exprinfo: Optional[str] = None,
) -> "ExceptionInfo[E]":
exprinfo: str | None = None,
) -> ExceptionInfo[E]:
"""Return an ExceptionInfo for an existing exception.
The exception must have a non-``None`` ``__traceback__`` attribute,
@@ -496,9 +489,9 @@ class ExceptionInfo(Generic[E]):
@classmethod
def from_exc_info(
cls,
exc_info: Tuple[Type[E], E, TracebackType],
exprinfo: Optional[str] = None,
) -> "ExceptionInfo[E]":
exc_info: tuple[type[E], E, TracebackType],
exprinfo: str | None = None,
) -> ExceptionInfo[E]:
"""Like :func:`from_exception`, but using old-style exc_info tuple."""
_striptext = ""
if exprinfo is None and isinstance(exc_info[1], AssertionError):
@@ -511,9 +504,7 @@ class ExceptionInfo(Generic[E]):
return cls(exc_info, _striptext, _ispytest=True)
@classmethod
def from_current(
cls, exprinfo: Optional[str] = None
) -> "ExceptionInfo[BaseException]":
def from_current(cls, exprinfo: str | None = None) -> ExceptionInfo[BaseException]:
"""Return an ExceptionInfo matching the current traceback.
.. warning::
@@ -533,17 +524,17 @@ class ExceptionInfo(Generic[E]):
return ExceptionInfo.from_exc_info(exc_info, exprinfo)
@classmethod
def for_later(cls) -> "ExceptionInfo[E]":
def for_later(cls) -> ExceptionInfo[E]:
"""Return an unfilled ExceptionInfo."""
return cls(None, _ispytest=True)
def fill_unfilled(self, exc_info: Tuple[Type[E], E, TracebackType]) -> None:
def fill_unfilled(self, exc_info: tuple[type[E], E, TracebackType]) -> None:
"""Fill an unfilled ExceptionInfo created with ``for_later()``."""
assert self._excinfo is None, "ExceptionInfo was already filled"
self._excinfo = exc_info
@property
def type(self) -> Type[E]:
def type(self) -> type[E]:
"""The exception class."""
assert (
self._excinfo is not None
@@ -606,16 +597,14 @@ class ExceptionInfo(Generic[E]):
text = text[len(self._striptext) :]
return text
def errisinstance(
self, exc: Union[Type[BaseException], Tuple[Type[BaseException], ...]]
) -> bool:
def errisinstance(self, exc: EXCEPTION_OR_MORE) -> bool:
"""Return True if the exception is an instance of exc.
Consider using ``isinstance(excinfo.value, exc)`` instead.
"""
return isinstance(self.value, exc)
def _getreprcrash(self) -> Optional["ReprFileLocation"]:
def _getreprcrash(self) -> ReprFileLocation | None:
# Find last non-hidden traceback entry that led to the exception of the
# traceback, or None if all hidden.
for i in range(-1, -len(self.traceback) - 1, -1):
@@ -631,13 +620,12 @@ class ExceptionInfo(Generic[E]):
showlocals: bool = False,
style: _TracebackStyle = "long",
abspath: bool = False,
tbfilter: Union[
bool, Callable[["ExceptionInfo[BaseException]"], Traceback]
] = True,
tbfilter: bool
| Callable[[ExceptionInfo[BaseException]], _pytest._code.code.Traceback] = True,
funcargs: bool = False,
truncate_locals: bool = True,
chain: bool = True,
) -> Union["ReprExceptionInfo", "ExceptionChainRepr"]:
) -> ReprExceptionInfo | ExceptionChainRepr:
"""Return str()able representation of this exception info.
:param bool showlocals:
@@ -715,7 +703,7 @@ class ExceptionInfo(Generic[E]):
]
)
def match(self, regexp: Union[str, Pattern[str]]) -> "Literal[True]":
def match(self, regexp: str | Pattern[str]) -> Literal[True]:
"""Check whether the regular expression `regexp` matches the string
representation of the exception using :func:`python:re.search`.
@@ -733,9 +721,9 @@ class ExceptionInfo(Generic[E]):
def _group_contains(
self,
exc_group: BaseExceptionGroup[BaseException],
expected_exception: Union[Type[BaseException], Tuple[Type[BaseException], ...]],
match: Union[str, Pattern[str], None],
target_depth: Optional[int] = None,
expected_exception: EXCEPTION_OR_MORE,
match: str | Pattern[str] | None,
target_depth: int | None = None,
current_depth: int = 1,
) -> bool:
"""Return `True` if a `BaseExceptionGroup` contains a matching exception."""
@@ -762,10 +750,10 @@ class ExceptionInfo(Generic[E]):
def group_contains(
self,
expected_exception: Union[Type[BaseException], Tuple[Type[BaseException], ...]],
expected_exception: EXCEPTION_OR_MORE,
*,
match: Union[str, Pattern[str], None] = None,
depth: Optional[int] = None,
match: str | Pattern[str] | None = None,
depth: int | None = None,
) -> bool:
"""Check whether a captured exception group contains a matching exception.
@@ -807,15 +795,15 @@ class FormattedExcinfo:
showlocals: bool = False
style: _TracebackStyle = "long"
abspath: bool = True
tbfilter: Union[bool, Callable[[ExceptionInfo[BaseException]], Traceback]] = True
tbfilter: bool | Callable[[ExceptionInfo[BaseException]], Traceback] = True
funcargs: bool = False
truncate_locals: bool = True
chain: bool = True
astcache: Dict[Union[str, Path], ast.AST] = dataclasses.field(
astcache: dict[str | Path, ast.AST] = dataclasses.field(
default_factory=dict, init=False, repr=False
)
def _getindent(self, source: "Source") -> int:
def _getindent(self, source: Source) -> int:
# Figure out indent for the given source.
try:
s = str(source.getstatement(len(source) - 1))
@@ -830,13 +818,13 @@ class FormattedExcinfo:
return 0
return 4 + (len(s) - len(s.lstrip()))
def _getentrysource(self, entry: TracebackEntry) -> Optional["Source"]:
def _getentrysource(self, entry: TracebackEntry) -> Source | None:
source = entry.getsource(self.astcache)
if source is not None:
source = source.deindent()
return source
def repr_args(self, entry: TracebackEntry) -> Optional["ReprFuncArgs"]:
def repr_args(self, entry: TracebackEntry) -> ReprFuncArgs | None:
if self.funcargs:
args = []
for argname, argvalue in entry.frame.getargs(var=True):
@@ -846,11 +834,11 @@ class FormattedExcinfo:
def get_source(
self,
source: Optional["Source"],
source: Source | None,
line_index: int = -1,
excinfo: Optional[ExceptionInfo[BaseException]] = None,
excinfo: ExceptionInfo[BaseException] | None = None,
short: bool = False,
) -> List[str]:
) -> list[str]:
"""Return formatted and marked up source lines."""
lines = []
if source is not None and line_index < 0:
@@ -879,7 +867,7 @@ class FormattedExcinfo:
excinfo: ExceptionInfo[BaseException],
indent: int = 4,
markall: bool = False,
) -> List[str]:
) -> list[str]:
lines = []
indentstr = " " * indent
# Get the real exception information out.
@@ -891,7 +879,7 @@ class FormattedExcinfo:
failindent = indentstr
return lines
def repr_locals(self, locals: Mapping[str, object]) -> Optional["ReprLocals"]:
def repr_locals(self, locals: Mapping[str, object]) -> ReprLocals | None:
if self.showlocals:
lines = []
keys = [loc for loc in locals if loc[0] != "@"]
@@ -919,10 +907,10 @@ class FormattedExcinfo:
def repr_traceback_entry(
self,
entry: Optional[TracebackEntry],
excinfo: Optional[ExceptionInfo[BaseException]] = None,
) -> "ReprEntry":
lines: List[str] = []
entry: TracebackEntry | None,
excinfo: ExceptionInfo[BaseException] | None = None,
) -> ReprEntry:
lines: list[str] = []
style = (
entry._repr_style
if entry is not None and entry._repr_style is not None
@@ -957,7 +945,7 @@ class FormattedExcinfo:
lines.extend(self.get_exconly(excinfo, indent=4))
return ReprEntry(lines, None, None, None, style)
def _makepath(self, path: Union[Path, str]) -> str:
def _makepath(self, path: Path | str) -> str:
if not self.abspath and isinstance(path, Path):
try:
np = bestrelpath(Path.cwd(), path)
@@ -967,7 +955,7 @@ class FormattedExcinfo:
return np
return str(path)
def repr_traceback(self, excinfo: ExceptionInfo[BaseException]) -> "ReprTraceback":
def repr_traceback(self, excinfo: ExceptionInfo[BaseException]) -> ReprTraceback:
traceback = excinfo.traceback
if callable(self.tbfilter):
traceback = self.tbfilter(excinfo)
@@ -998,7 +986,7 @@ class FormattedExcinfo:
def _truncate_recursive_traceback(
self, traceback: Traceback
) -> Tuple[Traceback, Optional[str]]:
) -> tuple[Traceback, str | None]:
"""Truncate the given recursive traceback trying to find the starting
point of the recursion.
@@ -1015,7 +1003,7 @@ class FormattedExcinfo:
recursionindex = traceback.recursionindex()
except Exception as e:
max_frames = 10
extraline: Optional[str] = (
extraline: str | None = (
"!!! Recursion error detected, but an error occurred locating the origin of recursion.\n"
" The following exception happened when comparing locals in the stack frame:\n"
f" {type(e).__name__}: {e!s}\n"
@@ -1033,16 +1021,12 @@ class FormattedExcinfo:
return traceback, extraline
def repr_excinfo(
self, excinfo: ExceptionInfo[BaseException]
) -> "ExceptionChainRepr":
repr_chain: List[
Tuple[ReprTraceback, Optional[ReprFileLocation], Optional[str]]
] = []
e: Optional[BaseException] = excinfo.value
excinfo_: Optional[ExceptionInfo[BaseException]] = excinfo
def repr_excinfo(self, excinfo: ExceptionInfo[BaseException]) -> ExceptionChainRepr:
repr_chain: list[tuple[ReprTraceback, ReprFileLocation | None, str | None]] = []
e: BaseException | None = excinfo.value
excinfo_: ExceptionInfo[BaseException] | None = excinfo
descr = None
seen: Set[int] = set()
seen: set[int] = set()
while e is not None and id(e) not in seen:
seen.add(id(e))
@@ -1051,7 +1035,7 @@ class FormattedExcinfo:
# full support for exception groups added to ExceptionInfo.
# See https://github.com/pytest-dev/pytest/issues/9159
if isinstance(e, BaseExceptionGroup):
reprtraceback: Union[ReprTracebackNative, ReprTraceback] = (
reprtraceback: ReprTracebackNative | ReprTraceback = (
ReprTracebackNative(
traceback.format_exception(
type(excinfo_.value),
@@ -1109,9 +1093,9 @@ class TerminalRepr:
@dataclasses.dataclass(eq=False)
class ExceptionRepr(TerminalRepr):
# Provided by subclasses.
reprtraceback: "ReprTraceback"
reprcrash: Optional["ReprFileLocation"]
sections: List[Tuple[str, str, str]] = dataclasses.field(
reprtraceback: ReprTraceback
reprcrash: ReprFileLocation | None
sections: list[tuple[str, str, str]] = dataclasses.field(
init=False, default_factory=list
)
@@ -1126,13 +1110,11 @@ class ExceptionRepr(TerminalRepr):
@dataclasses.dataclass(eq=False)
class ExceptionChainRepr(ExceptionRepr):
chain: Sequence[Tuple["ReprTraceback", Optional["ReprFileLocation"], Optional[str]]]
chain: Sequence[tuple[ReprTraceback, ReprFileLocation | None, str | None]]
def __init__(
self,
chain: Sequence[
Tuple["ReprTraceback", Optional["ReprFileLocation"], Optional[str]]
],
chain: Sequence[tuple[ReprTraceback, ReprFileLocation | None, str | None]],
) -> None:
# reprcrash and reprtraceback of the outermost (the newest) exception
# in the chain.
@@ -1153,8 +1135,8 @@ class ExceptionChainRepr(ExceptionRepr):
@dataclasses.dataclass(eq=False)
class ReprExceptionInfo(ExceptionRepr):
reprtraceback: "ReprTraceback"
reprcrash: Optional["ReprFileLocation"]
reprtraceback: ReprTraceback
reprcrash: ReprFileLocation | None
def toterminal(self, tw: TerminalWriter) -> None:
self.reprtraceback.toterminal(tw)
@@ -1163,8 +1145,8 @@ class ReprExceptionInfo(ExceptionRepr):
@dataclasses.dataclass(eq=False)
class ReprTraceback(TerminalRepr):
reprentries: Sequence[Union["ReprEntry", "ReprEntryNative"]]
extraline: Optional[str]
reprentries: Sequence[ReprEntry | ReprEntryNative]
extraline: str | None
style: _TracebackStyle
entrysep: ClassVar = "_ "
@@ -1208,9 +1190,9 @@ class ReprEntryNative(TerminalRepr):
@dataclasses.dataclass(eq=False)
class ReprEntry(TerminalRepr):
lines: Sequence[str]
reprfuncargs: Optional["ReprFuncArgs"]
reprlocals: Optional["ReprLocals"]
reprfileloc: Optional["ReprFileLocation"]
reprfuncargs: ReprFuncArgs | None
reprlocals: ReprLocals | None
reprfileloc: ReprFileLocation | None
style: _TracebackStyle
def _write_entry_lines(self, tw: TerminalWriter) -> None:
@@ -1234,9 +1216,9 @@ class ReprEntry(TerminalRepr):
# such as "> assert 0"
fail_marker = f"{FormattedExcinfo.fail_marker} "
indent_size = len(fail_marker)
indents: List[str] = []
source_lines: List[str] = []
failure_lines: List[str] = []
indents: list[str] = []
source_lines: list[str] = []
failure_lines: list[str] = []
for index, line in enumerate(self.lines):
is_failure_line = line.startswith(fail_marker)
if is_failure_line:
@@ -1315,7 +1297,7 @@ class ReprLocals(TerminalRepr):
@dataclasses.dataclass(eq=False)
class ReprFuncArgs(TerminalRepr):
args: Sequence[Tuple[str, object]]
args: Sequence[tuple[str, object]]
def toterminal(self, tw: TerminalWriter) -> None:
if self.args:
@@ -1336,7 +1318,7 @@ class ReprFuncArgs(TerminalRepr):
tw.line("")
def getfslineno(obj: object) -> Tuple[Union[str, Path], int]:
def getfslineno(obj: object) -> tuple[str | Path, int]:
"""Return source location (path, lineno) for the given object.
If the source cannot be determined return ("", -1).

View File

@@ -1,4 +1,6 @@
# mypy: allow-untyped-defs
from __future__ import annotations
import ast
from bisect import bisect_right
import inspect
@@ -7,11 +9,7 @@ import tokenize
import types
from typing import Iterable
from typing import Iterator
from typing import List
from typing import Optional
from typing import overload
from typing import Tuple
from typing import Union
import warnings
@@ -23,7 +21,7 @@ class Source:
def __init__(self, obj: object = None) -> None:
if not obj:
self.lines: List[str] = []
self.lines: list[str] = []
elif isinstance(obj, Source):
self.lines = obj.lines
elif isinstance(obj, (tuple, list)):
@@ -50,9 +48,9 @@ class Source:
def __getitem__(self, key: int) -> str: ...
@overload
def __getitem__(self, key: slice) -> "Source": ...
def __getitem__(self, key: slice) -> Source: ...
def __getitem__(self, key: Union[int, slice]) -> Union[str, "Source"]:
def __getitem__(self, key: int | slice) -> str | Source:
if isinstance(key, int):
return self.lines[key]
else:
@@ -68,7 +66,7 @@ class Source:
def __len__(self) -> int:
return len(self.lines)
def strip(self) -> "Source":
def strip(self) -> Source:
"""Return new Source object with trailing and leading blank lines removed."""
start, end = 0, len(self)
while start < end and not self.lines[start].strip():
@@ -79,20 +77,20 @@ class Source:
source.lines[:] = self.lines[start:end]
return source
def indent(self, indent: str = " " * 4) -> "Source":
def indent(self, indent: str = " " * 4) -> Source:
"""Return a copy of the source object with all lines indented by the
given indent-string."""
newsource = Source()
newsource.lines = [(indent + line) for line in self.lines]
return newsource
def getstatement(self, lineno: int) -> "Source":
def getstatement(self, lineno: int) -> Source:
"""Return Source statement which contains the given linenumber
(counted from 0)."""
start, end = self.getstatementrange(lineno)
return self[start:end]
def getstatementrange(self, lineno: int) -> Tuple[int, int]:
def getstatementrange(self, lineno: int) -> tuple[int, int]:
"""Return (start, end) tuple which spans the minimal statement region
which containing the given lineno."""
if not (0 <= lineno < len(self)):
@@ -100,7 +98,7 @@ class Source:
ast, start, end = getstatementrange_ast(lineno, self)
return start, end
def deindent(self) -> "Source":
def deindent(self) -> Source:
"""Return a new Source object deindented."""
newsource = Source()
newsource.lines[:] = deindent(self.lines)
@@ -115,7 +113,7 @@ class Source:
#
def findsource(obj) -> Tuple[Optional[Source], int]:
def findsource(obj) -> tuple[Source | None, int]:
try:
sourcelines, lineno = inspect.findsource(obj)
except Exception:
@@ -138,14 +136,14 @@ def getrawcode(obj: object, trycall: bool = True) -> types.CodeType:
raise TypeError(f"could not get code object for {obj!r}")
def deindent(lines: Iterable[str]) -> List[str]:
def deindent(lines: Iterable[str]) -> list[str]:
return textwrap.dedent("\n".join(lines)).splitlines()
def get_statement_startend2(lineno: int, node: ast.AST) -> Tuple[int, Optional[int]]:
def get_statement_startend2(lineno: int, node: ast.AST) -> tuple[int, int | None]:
# Flatten all statements and except handlers into one lineno-list.
# AST's line numbers start indexing at 1.
values: List[int] = []
values: list[int] = []
for x in ast.walk(node):
if isinstance(x, (ast.stmt, ast.ExceptHandler)):
# The lineno points to the class/def, so need to include the decorators.
@@ -154,7 +152,7 @@ def get_statement_startend2(lineno: int, node: ast.AST) -> Tuple[int, Optional[i
values.append(d.lineno - 1)
values.append(x.lineno - 1)
for name in ("finalbody", "orelse"):
val: Optional[List[ast.stmt]] = getattr(x, name, None)
val: list[ast.stmt] | None = getattr(x, name, None)
if val:
# Treat the finally/orelse part as its own statement.
values.append(val[0].lineno - 1 - 1)
@@ -172,8 +170,8 @@ def getstatementrange_ast(
lineno: int,
source: Source,
assertion: bool = False,
astnode: Optional[ast.AST] = None,
) -> Tuple[ast.AST, int, int]:
astnode: ast.AST | None = None,
) -> tuple[ast.AST, int, int]:
if astnode is None:
content = str(source)
# See #4260:

View File

@@ -1,3 +1,5 @@
from __future__ import annotations
from .terminalwriter import get_terminal_width
from .terminalwriter import TerminalWriter

View File

@@ -13,6 +13,8 @@
# tuples with fairly non-descriptive content. This is modeled very much
# after Lisp/Scheme - style pretty-printing of lists. If you find it
# useful, thank small children who sleep at night.
from __future__ import annotations
import collections as _collections
import dataclasses as _dataclasses
from io import StringIO as _StringIO
@@ -20,13 +22,8 @@ import re
import types as _types
from typing import Any
from typing import Callable
from typing import Dict
from typing import IO
from typing import Iterator
from typing import List
from typing import Optional
from typing import Set
from typing import Tuple
class _safe_key:
@@ -64,7 +61,7 @@ class PrettyPrinter:
self,
indent: int = 4,
width: int = 80,
depth: Optional[int] = None,
depth: int | None = None,
) -> None:
"""Handle pretty printing operations onto a stream using a set of
configured parameters.
@@ -100,7 +97,7 @@ class PrettyPrinter:
stream: IO[str],
indent: int,
allowance: int,
context: Set[int],
context: set[int],
level: int,
) -> None:
objid = id(object)
@@ -136,7 +133,7 @@ class PrettyPrinter:
stream: IO[str],
indent: int,
allowance: int,
context: Set[int],
context: set[int],
level: int,
) -> None:
cls_name = object.__class__.__name__
@@ -149,9 +146,9 @@ class PrettyPrinter:
self._format_namespace_items(items, stream, indent, allowance, context, level)
stream.write(")")
_dispatch: Dict[
_dispatch: dict[
Callable[..., str],
Callable[["PrettyPrinter", Any, IO[str], int, int, Set[int], int], None],
Callable[[PrettyPrinter, Any, IO[str], int, int, set[int], int], None],
] = {}
def _pprint_dict(
@@ -160,7 +157,7 @@ class PrettyPrinter:
stream: IO[str],
indent: int,
allowance: int,
context: Set[int],
context: set[int],
level: int,
) -> None:
write = stream.write
@@ -177,7 +174,7 @@ class PrettyPrinter:
stream: IO[str],
indent: int,
allowance: int,
context: Set[int],
context: set[int],
level: int,
) -> None:
if not len(object):
@@ -196,7 +193,7 @@ class PrettyPrinter:
stream: IO[str],
indent: int,
allowance: int,
context: Set[int],
context: set[int],
level: int,
) -> None:
stream.write("[")
@@ -211,7 +208,7 @@ class PrettyPrinter:
stream: IO[str],
indent: int,
allowance: int,
context: Set[int],
context: set[int],
level: int,
) -> None:
stream.write("(")
@@ -226,7 +223,7 @@ class PrettyPrinter:
stream: IO[str],
indent: int,
allowance: int,
context: Set[int],
context: set[int],
level: int,
) -> None:
if not len(object):
@@ -252,7 +249,7 @@ class PrettyPrinter:
stream: IO[str],
indent: int,
allowance: int,
context: Set[int],
context: set[int],
level: int,
) -> None:
write = stream.write
@@ -311,7 +308,7 @@ class PrettyPrinter:
stream: IO[str],
indent: int,
allowance: int,
context: Set[int],
context: set[int],
level: int,
) -> None:
write = stream.write
@@ -340,7 +337,7 @@ class PrettyPrinter:
stream: IO[str],
indent: int,
allowance: int,
context: Set[int],
context: set[int],
level: int,
) -> None:
write = stream.write
@@ -358,7 +355,7 @@ class PrettyPrinter:
stream: IO[str],
indent: int,
allowance: int,
context: Set[int],
context: set[int],
level: int,
) -> None:
stream.write("mappingproxy(")
@@ -373,7 +370,7 @@ class PrettyPrinter:
stream: IO[str],
indent: int,
allowance: int,
context: Set[int],
context: set[int],
level: int,
) -> None:
if type(object) is _types.SimpleNamespace:
@@ -391,11 +388,11 @@ class PrettyPrinter:
def _format_dict_items(
self,
items: List[Tuple[Any, Any]],
items: list[tuple[Any, Any]],
stream: IO[str],
indent: int,
allowance: int,
context: Set[int],
context: set[int],
level: int,
) -> None:
if not items:
@@ -415,11 +412,11 @@ class PrettyPrinter:
def _format_namespace_items(
self,
items: List[Tuple[Any, Any]],
items: list[tuple[Any, Any]],
stream: IO[str],
indent: int,
allowance: int,
context: Set[int],
context: set[int],
level: int,
) -> None:
if not items:
@@ -452,11 +449,11 @@ class PrettyPrinter:
def _format_items(
self,
items: List[Any],
items: list[Any],
stream: IO[str],
indent: int,
allowance: int,
context: Set[int],
context: set[int],
level: int,
) -> None:
if not items:
@@ -473,7 +470,7 @@ class PrettyPrinter:
write("\n" + " " * indent)
def _repr(self, object: Any, context: Set[int], level: int) -> str:
def _repr(self, object: Any, context: set[int], level: int) -> str:
return self._safe_repr(object, context.copy(), self._depth, level)
def _pprint_default_dict(
@@ -482,7 +479,7 @@ class PrettyPrinter:
stream: IO[str],
indent: int,
allowance: int,
context: Set[int],
context: set[int],
level: int,
) -> None:
rdf = self._repr(object.default_factory, context, level)
@@ -498,7 +495,7 @@ class PrettyPrinter:
stream: IO[str],
indent: int,
allowance: int,
context: Set[int],
context: set[int],
level: int,
) -> None:
stream.write(object.__class__.__name__ + "(")
@@ -519,7 +516,7 @@ class PrettyPrinter:
stream: IO[str],
indent: int,
allowance: int,
context: Set[int],
context: set[int],
level: int,
) -> None:
if not len(object.maps) or (len(object.maps) == 1 and not len(object.maps[0])):
@@ -538,7 +535,7 @@ class PrettyPrinter:
stream: IO[str],
indent: int,
allowance: int,
context: Set[int],
context: set[int],
level: int,
) -> None:
stream.write(object.__class__.__name__ + "(")
@@ -557,7 +554,7 @@ class PrettyPrinter:
stream: IO[str],
indent: int,
allowance: int,
context: Set[int],
context: set[int],
level: int,
) -> None:
self._format(object.data, stream, indent, allowance, context, level - 1)
@@ -570,7 +567,7 @@ class PrettyPrinter:
stream: IO[str],
indent: int,
allowance: int,
context: Set[int],
context: set[int],
level: int,
) -> None:
self._format(object.data, stream, indent, allowance, context, level - 1)
@@ -583,7 +580,7 @@ class PrettyPrinter:
stream: IO[str],
indent: int,
allowance: int,
context: Set[int],
context: set[int],
level: int,
) -> None:
self._format(object.data, stream, indent, allowance, context, level - 1)
@@ -591,7 +588,7 @@ class PrettyPrinter:
_dispatch[_collections.UserString.__repr__] = _pprint_user_string
def _safe_repr(
self, object: Any, context: Set[int], maxlevels: Optional[int], level: int
self, object: Any, context: set[int], maxlevels: int | None, level: int
) -> str:
typ = type(object)
if typ in _builtin_scalars:
@@ -608,7 +605,7 @@ class PrettyPrinter:
if objid in context:
return _recursion(object)
context.add(objid)
components: List[str] = []
components: list[str] = []
append = components.append
level += 1
for k, v in sorted(object.items(), key=_safe_tuple):

Some files were not shown because too many files have changed in this diff Show More