Compare commits

..

218 Commits

Author SHA1 Message Date
pre-commit-ci[bot]
3a1e17355b [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.4.10 → v0.5.0](https://github.com/astral-sh/ruff-pre-commit/compare/v0.4.10...v0.5.0)
- [github.com/adamchainz/blacken-docs: 1.16.0 → 1.18.0](https://github.com/adamchainz/blacken-docs/compare/1.16.0...1.18.0)
- [github.com/pre-commit/mirrors-mypy: v1.10.0 → v1.10.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.10.0...v1.10.1)
2024-07-02 00:16:55 +00:00
Sviatoslav Sydorenko (Святослав Сидоренко)
51ee3880c7 Merge pull request #12553 from pytest-dev/revert-12516-maintenance/hotfix/gha-codecov-token 2024-07-01 17:20:45 +02:00
Sviatoslav Sydorenko (Святослав Сидоренко)
90459a8fd3 Merge pull request #12472 from pbrezina/testresult-markup 2024-07-01 17:06:07 +02:00
Sviatoslav Sydorenko (Святослав Сидоренко)
de4e3cffc2 Revert "🚑🧪 Set the Codecov token directly in GHA" 2024-07-01 16:47:47 +02:00
Sviatoslav Sydorenko (Святослав Сидоренко)
1a8394ed89 Merge pull request #12531 from webknjaz/maintenance/xfail-no-cover 2024-07-01 16:21:35 +02:00
Bruno Oliveira
f502f1db31 Update src/_pytest/reports.py 2024-07-01 13:23:53 +02:00
Bruno Oliveira
201ed9f6a5 Update src/_pytest/reports.py 2024-07-01 13:23:53 +02:00
pre-commit-ci[bot]
2c1ed505d9 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2024-07-01 13:23:53 +02:00
Bruno Oliveira
269ded17a6 Update src/_pytest/reports.py 2024-07-01 13:23:53 +02:00
Pavel Březina
41ca4dd44e testresult: correctly apply verbose word markup and avoid crash
The following snippet would have resulted in crash on multiple places since
`_get_verbose_word` expects only string, not a tuple.

```python
    @pytest.hookimpl(tryfirst=True)
    def pytest_report_teststatus(report: pytest.CollectReport | pytest.TestReport, config: pytest.Config):
        if report.when == "call":
            return ("error", "A",  ("AVC", {"bold": True, "red": True}))

        return None
```

```
Traceback (most recent call last):
  File "/home/pbrezina/workspace/sssd/.venv/bin/pytest", line 8, in <module>
    sys.exit(console_main())
             ^^^^^^^^^^^^^^
  File "/home/pbrezina/workspace/pytest/src/_pytest/config/__init__.py", line 207, in console_main
    code = main()
           ^^^^^^
  File "/home/pbrezina/workspace/pytest/src/_pytest/config/__init__.py", line 179, in main
    ret: Union[ExitCode, int] = config.hook.pytest_cmdline_main(
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/pbrezina/workspace/sssd/.venv/lib64/python3.11/site-packages/pluggy/_hooks.py", line 513, in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/pbrezina/workspace/sssd/.venv/lib64/python3.11/site-packages/pluggy/_manager.py", line 120, in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/pbrezina/workspace/sssd/.venv/lib64/python3.11/site-packages/pluggy/_callers.py", line 139, in _multicall
    raise exception.with_traceback(exception.__traceback__)
  File "/home/pbrezina/workspace/sssd/.venv/lib64/python3.11/site-packages/pluggy/_callers.py", line 103, in _multicall
    res = hook_impl.function(*args)
          ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/pbrezina/workspace/pytest/src/_pytest/main.py", line 333, in pytest_cmdline_main
    return wrap_session(config, _main)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/pbrezina/workspace/pytest/src/_pytest/main.py", line 321, in wrap_session
    config.hook.pytest_sessionfinish(
  File "/home/pbrezina/workspace/sssd/.venv/lib64/python3.11/site-packages/pluggy/_hooks.py", line 513, in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/pbrezina/workspace/sssd/.venv/lib64/python3.11/site-packages/pluggy/_manager.py", line 120, in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/pbrezina/workspace/sssd/.venv/lib64/python3.11/site-packages/pluggy/_callers.py", line 139, in _multicall
    raise exception.with_traceback(exception.__traceback__)
  File "/home/pbrezina/workspace/sssd/.venv/lib64/python3.11/site-packages/pluggy/_callers.py", line 122, in _multicall
    teardown.throw(exception)  # type: ignore[union-attr]
    ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/pbrezina/workspace/pytest/src/_pytest/logging.py", line 872, in pytest_sessionfinish
    return (yield)
            ^^^^^
  File "/home/pbrezina/workspace/sssd/.venv/lib64/python3.11/site-packages/pluggy/_callers.py", line 124, in _multicall
    teardown.send(result)  # type: ignore[union-attr]
    ^^^^^^^^^^^^^^^^^^^^^
  File "/home/pbrezina/workspace/pytest/src/_pytest/terminal.py", line 899, in pytest_sessionfinish
    self.config.hook.pytest_terminal_summary(
  File "/home/pbrezina/workspace/sssd/.venv/lib64/python3.11/site-packages/pluggy/_hooks.py", line 513, in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/pbrezina/workspace/sssd/.venv/lib64/python3.11/site-packages/pluggy/_manager.py", line 120, in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/pbrezina/workspace/sssd/.venv/lib64/python3.11/site-packages/pluggy/_callers.py", line 139, in _multicall
    raise exception.with_traceback(exception.__traceback__)
  File "/home/pbrezina/workspace/sssd/.venv/lib64/python3.11/site-packages/pluggy/_callers.py", line 124, in _multicall
    teardown.send(result)  # type: ignore[union-attr]
    ^^^^^^^^^^^^^^^^^^^^^
  File "/home/pbrezina/workspace/pytest/src/_pytest/terminal.py", line 923, in pytest_terminal_summary
    self.short_test_summary()
  File "/home/pbrezina/workspace/pytest/src/_pytest/terminal.py", line 1272, in short_test_summary
    action(lines)
  File "/home/pbrezina/workspace/pytest/src/_pytest/terminal.py", line 1205, in show_simple
    line = _get_line_with_reprcrash_message(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/pbrezina/workspace/pytest/src/_pytest/terminal.py", line 1429, in _get_line_with_reprcrash_message
    word = tw.markup(verbose_word, **word_markup)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/pbrezina/workspace/pytest/src/_pytest/_io/terminalwriter.py", line 114, in markup
    text = "".join(f"\x1b[{cod}m" for cod in esc) + text + "\x1b[0m"
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~
TypeError: can only concatenate str (not "tuple") to str
```

Signed-off-by: Pavel Březina <pbrezina@redhat.com>
2024-07-01 13:23:53 +02:00
github-actions[bot]
dbf7dee8c8 [automated] Update plugin list (#12547)
Co-authored-by: pytest bot <pytestbot@users.noreply.github.com>
2024-06-30 12:05:11 +00:00
Zach Snicker
0adcc21f48 Support venv detection on Windows with mingw Python (#12545)
Closes #12544
2024-06-29 00:30:51 +03:00
joseph-sentry
0ed2d79457 junitxml: add timezone to testsuite timestamp (#12491)
Signed-off-by: joseph-sentry <joseph.sawaya@sentry.io>
Co-authored-by: Ronny Pfannschmidt <opensource@ronnypfannschmidt.de>
2024-06-27 09:41:02 -03:00
Sviatoslav Sydorenko (Святослав Сидоренко)
f74e947c1f Merge pull request #12533 from webknjaz/docs/drop-extlinks-bpo 2024-06-26 14:39:31 +02:00
Sviatoslav Sydorenko
d75fa9f9b4 📝 Add a change note for PE #12533 2024-06-26 14:22:56 +02:00
Sviatoslav Sydorenko
29e4b6b9f0 📝🔥 Remove the :bpo: RST role declaration
BPO is in read-only mode and all issues have been migrated to GitHub.
This patch replaces the use of that role with `:issue:`, recently
integrated via #12522. It also disables the built-in `extlinks` Sphinx
extension, as it's no longer in use.
2024-06-26 14:19:13 +02:00
Sviatoslav Sydorenko
f2acc65485 📝 Add a change note for PR #12531 2024-06-25 23:33:43 +02:00
Sviatoslav Sydorenko
634a83df94 🧪 Unmeasure xfail tests
These tests are known to only be executed partially or not at all. So
we always get incomplete, missing, and sometimes flaky, coverage in
the test functions that are expected to fail.

This change updates the ``coverage.py`` config to prevent said tests
from influencing the coverage level measurement.
2024-06-25 23:25:04 +02:00
Florian Bruhin
53bf188999 Merge pull request #12523 from lovetheguitar/fix/follow_up_to_pr_#12500
Improve documentation & other kinks of marker keyword expression PR #12500
2024-06-25 10:17:07 +02:00
lovetheguitar
36b384afc7 docs(expression.py): simplify grammar documentation by defining kwargs separately 2024-06-25 09:18:18 +02:00
lovetheguitar
3d07791c36 chore: remove obsolete TODOs 2024-06-25 09:18:18 +02:00
lovetheguitar
dd57196953 perf(expression): define TokenType.STRING as "string literal" for clearer errors 2024-06-25 09:18:18 +02:00
lovetheguitar
540ede3439 docs(expression.py): describe new name & value productions 2024-06-25 09:18:18 +02:00
Florian Bruhin
2b7eadf090 Update trainings (#12514) 2024-06-25 07:24:50 +02:00
pre-commit-ci[bot]
77416d64f5 [pre-commit.ci] pre-commit autoupdate (#12528)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.4.9 → v0.4.10](https://github.com/astral-sh/ruff-pre-commit/compare/v0.4.9...v0.4.10)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-06-25 04:26:26 +00:00
dependabot[bot]
d582dcfc16 build(deps): Bump peter-evans/create-pull-request from 6.0.5 to 6.1.0 (#12527)
Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 6.0.5 to 6.1.0.
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](6d6857d369...c5a7806660)

---
updated-dependencies:
- dependency-name: peter-evans/create-pull-request
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-24 18:21:02 -03:00
Sviatoslav Sydorenko (Святослав Сидоренко)
237152552e Merge pull request #12522 from webknjaz/docs/sphinx-issues-ext
📝 Replace GH/PyPI `extlinks` w/ `sphinx-issues`
2024-06-23 16:55:51 +02:00
github-actions[bot]
175340e06b [automated] Update plugin list (#12524)
Co-authored-by: pytest bot <pytestbot@users.noreply.github.com>
2024-06-23 06:22:44 +00:00
Sviatoslav Sydorenko
8f2ef30f4a 🚑 Stop setting PR/issue prefix @ sphinx-issues
Apparently, the extension only supports one of the pre-defined
prefixes.
2024-06-22 22:16:40 +02:00
Sviatoslav Sydorenko
0971a95902 📝 Add a change note for PR #12522 2024-06-22 22:14:33 +02:00
Sviatoslav Sydorenko
b919a711a4 📝 Replace GH/PyPI extlinks w/ sphinx_issues
This extension implements more generic roles that can also be used
more flexibly. Relying on an external extension allows to stop
maintaining an in-repo copy of the commonly used behavior.
2024-06-22 22:11:43 +02:00
Sviatoslav Sydorenko
66dbab697b 📝 Rename :pull: RST role to :pr:
This is a preparatory patch for integrating the third party
`sphinx-issues` extension.
2024-06-22 21:54:45 +02:00
lovetheguitar
3cce243774 docs(expression.py): fix typo 2024-06-22 20:16:24 +02:00
lovetheguitar
73bc35ce2b docs(expression.py): correct grammar definition of lexer 2024-06-22 20:16:24 +02:00
lovetheguitar
66eff85e54 docs: use double quotes for cross-platform compatibility in example code 2024-06-22 19:48:15 +02:00
Sviatoslav Sydorenko (Святослав Сидоренко)
f75e3fe63f Merge pull request #12516 from webknjaz/maintenance/hotfix/gha-codecov-token 2024-06-22 12:32:18 +02:00
Sviatoslav Sydorenko (Святослав Сидоренко)
6448d30fa1 Merge pull request #12517 from webknjaz/maintenance/gha-check-223e4bb7 2024-06-22 11:58:41 +02:00
Sviatoslav Sydorenko (Святослав Сидоренко)
fbdf9c887c Merge pull request #12455 from stdedos/patch-1
Update `contact.rst`: Update Matrix link
2024-06-21 23:26:32 +02:00
Sviatoslav Sydorenko
c716e0baef 🧪 Bump the alls-green action to 223erbb7
This version drops the use of the outdated GHA syntax for setting
action output values.
2024-06-21 23:06:26 +02:00
Sviatoslav Sydorenko
1b85ac126e 🚑🧪 Set the Codecov token directly in GHA
It's necessary since it seems that the currently used Codecov uploader
doesn't read the token from config sometimes.

This is a follow-up for #12508 which wasn't enough.
2024-06-21 22:52:17 +02:00
Ronny Pfannschmidt
9f134fc6ad Merge pull request #12500 from lovetheguitar/feat/support_marker_kwarg_in_marker_expressions 2024-06-21 22:24:34 +02:00
Sviatoslav Sydorenko (Святослав Сидоренко)
75a2225ed1 🔥 Drop the missing kwargs case 2024-06-21 22:09:45 +02:00
Sviatoslav Sydorenko (Святослав Сидоренко)
329662e2ec 📝 Drop stray trailing period from the change note byline 2024-06-21 22:06:33 +02:00
Sviatoslav Sydorenko (Святослав Сидоренко)
24450e33e3 📝 Use explicit RST roles for built-in types in docs 2024-06-21 22:05:43 +02:00
lovetheguitar
b1255a9aae style(mark): type hint **kwargs as str | int | bool | None 2024-06-21 20:51:01 +02:00
lovetheguitar
c3e898353b docs(AUTHORS): add myself as contributor 2024-06-21 20:51:01 +02:00
lovetheguitar
9cf9cfabcb docs(12281.feature.rst): add changelog fragment 2024-06-21 20:51:01 +02:00
lovetheguitar
598d881c9c docs: document keyword argument support in marker expressions 2024-06-21 20:51:01 +02:00
lovetheguitar
7c7c36d7e0 test(test_mark.py): add sad case that -k doesn't support keyword expressions 2024-06-21 20:51:01 +02:00
lovetheguitar
3921d94316 test: use new MarkMatcher.from_markers method & register test markers 2024-06-21 20:51:01 +02:00
lovetheguitar
6dd8ad60a4 refactor(MarkMatcher): replace from_item with from_markers method 2024-06-21 20:51:01 +02:00
lovetheguitar
1e7eb20347 perf(expression): improve string lexing & error messages 2024-06-21 20:51:01 +02:00
lovetheguitar
f4897391ec refactor(mark): use existing NOT_SET sentinel 2024-06-21 20:51:01 +02:00
lovetheguitar
1cc35ecc3f test: add empty string keyword argument marker test cases 2024-06-21 20:51:01 +02:00
lovetheguitar
04f457c4f4 style: use @overload to get rid of mypy only assertions 2024-06-21 20:51:01 +02:00
lovetheguitar
15c33fbaa3 feat: support keyword arguments in marker expressions
Fixes #12281
2024-06-21 20:51:01 +02:00
Ronny Pfannschmidt
e8fa8dd31c Merge pull request #12509 from pytest-dev/update-plugin-list/patch-c8948fca6
[automated] Update plugin list
2024-06-21 20:34:00 +02:00
pytest bot
27b2550283 [automated] Update plugin list 2024-06-21 20:19:10 +02:00
Farbod Ahmadian
34e28295a7 refactor: simplify bound method representation (#12492)
Co-authored-by: Sviatoslav Sydorenko <webknjaz@redhat.com>
Co-authored-by: Farbod Ahmadian <farbod@datachef.com>
2024-06-21 18:20:44 +02:00
Sviatoslav Sydorenko (Святослав Сидоренко)
9947ec3ad1 🧪🚑 Pass a Codecov config to the action @ GHA (#12508)
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>
2024-06-21 17:47:23 +02:00
Ronny Pfannschmidt
c8948fca65 Merge pull request #12502 from webknjaz/maintenance/ci-plugin-update-draft-ux
🧪 Make a draft based plugin bump PR CI trigger
2024-06-21 15:48:49 +02:00
Ronny Pfannschmidt
dab29d39d7 Merge pull request #12507 from webknjaz/maintenance/hotfixes/note/sphinx-towncrier-draft
📝 Add a change note for PR #12493
2024-06-21 15:26:11 +02:00
Oliver Bestwalter
b864e50138 Merge pull request #12498 from webknjaz/maintenance/tox-descriptions 2024-06-21 15:17:40 +02:00
Sviatoslav Sydorenko
5d95f09b2a 📝 Add a change note for PR #12493 2024-06-21 15:11:12 +02:00
Sviatoslav Sydorenko
a67327ac8e 📝 Add a change note to PR #12498 2024-06-21 14:14:28 +02:00
Sviatoslav Sydorenko
a69230ea5f 🎨 Add descriptions to all tox environments
Previously, a part of the environments weren't documented in the
config, making it difficult for the newbies to figure out what
their purposes are. This patch sets the descriptions for all the
envs listed with the `tox -av` command, leveraging the dynamic
factor-dependent explanation fragments.

```console
default environments:
linting                   -> run pre-commit-defined linters under `python3`
py38                      -> run the tests under `py38`
py39                      -> run the tests under `py39`
py310                     -> run the tests under `py310`
py311                     -> run the tests under `py311`
py312                     -> run the tests under `py312`
py313                     -> run the tests under `py313`
pypy3                     -> run the tests under `pypy3`
py38-pexpect              -> run the tests against `pexpect` under `py38`
py38-xdist                -> run the tests with pytest in parallel mode under `py38`
py38-unittestextras       -> run the tests against the unit test extras under `py38`
py38-numpy                -> run the tests against `numpy` under `py38`
py38-pluggymain           -> run the tests against the bleeding edge `pluggy` from Git under `py38`
py38-pylib                -> run the tests against `py` lib under `py38`
doctesting                -> run the tests under `~/.pyenv/versions/3.12.3/envs/pytest-pyenv-py3.12.3/bin/python` including doctests
doctesting-coverage       -> run the tests collecting coverage under `~/.pyenv/versions/3.12.3/envs/pytest-pyenv-py3.12.3/bin/python` including doctests
plugins                   -> run reverse dependency testing against pytest plugins under `~/.pyenv/versions/3.12.3/envs/pytest-pyenv-py3.12.3/bin/python`
py38-freeze               -> test pytest frozen with `pyinstaller` under `py38`
docs                      -> build the documentation site under `~/src/github/pytest-dev/pytest/doc/en/_build/html` with `python3`
docs-checklinks           -> check the links in the documentation with `python3`
py311-exceptiongroup      -> run the tests against `exceptiongroup` under `py311`

additional environments:
regen                     -> regenerate documentation examples under `python3`
release                   -> do a release, required posarg of the version number
prepare-release-pr        -> prepare a release PR from a manual trigger in GitHub actions
generate-gh-release-notes -> generate release notes that can be published as GitHub Release
nobyte                    -> run the tests in no-bytecode mode under `~/.pyenv/versions/3.12.3/envs/pytest-pyenv-py3.12.3/bin/python`
lsof                      -> run the tests with `--lsof` pytest CLI option under `~/.pyenv/versions/3.12.3/envs/pytest-pyenv-py3.12.3/bin/python`
```
2024-06-21 14:14:26 +02:00
Sviatoslav Sydorenko
072cb5250e 📝 Add a change note for PR #12502 2024-06-21 14:11:07 +02:00
Sviatoslav Sydorenko
323b0bd853 🧪 Make a draft based plugin bump PR CI trigger
Normally, PRs/commits published using the default GitHub Actions CI/CD
API token are not propagated to any integrations. This patch marks the
plugin update PR as a draft and leaves a comment asking the maintainers to
mark it as ready for review in order to actually trigger a CI run.

This idea is found in GitHub's own repos:
* https://github.com/github/codeql-action/pull/2263#issuecomment-2078311173
* https://github.com/github/codeql-action/blob/4ebadbc7/.github/workflows/update-dependencies.yml#L38-L41
* https://github.com/github/codeql-action/pull/1868
* https://github.com/github/codeql-action/pull/679
2024-06-21 14:11:06 +02:00
Ronny Pfannschmidt
b08b6d122f Merge pull request #12501 from webknjaz/maintenance/changelog-categories
📝💅 Split trivial change log category into 3
2024-06-21 13:50:07 +02:00
Sviatoslav Sydorenko
e73db68642 📝 Add a change note for PR #12501 2024-06-21 13:35:47 +02:00
Sviatoslav Sydorenko
3ce1d658bd 🎨 Set up Git to only allow certain change notes 2024-06-21 13:35:47 +02:00
Sviatoslav Sydorenko
03be1ed8b1 📝💅 Split trivial change log category into 3
The new change note types are `packaging`, `contrib` and `misc`.
`packaging` is intended for the audience of downstream redistributors.
The `contrib` notes are meant to be documenting news affecting the
project contributors, their development, and processes.
Finally, `misc` is for things that don't fit anywhere but are still
desired to be documented for some reason.
2024-06-21 13:35:47 +02:00
Sviatoslav Sydorenko
45a89ec61f 📝 Extend change log title meanings
This patch makes them more verbose so that they are clearer to the
readers.
2024-06-21 13:34:38 +02:00
Sviatoslav Sydorenko
0cf92cfa4c 📝 Add comments to change note categories 2024-06-21 13:34:38 +02:00
Ronny Pfannschmidt
bbe6b4a218 Merge pull request #12467 from RonnyPfannschmidt/ronny/new-annotations-try-2
from __future__ import annotations + migrate
2024-06-21 10:24:56 +02:00
Oliver Bestwalter
2f92da9190 Merge pull request #12503 from webknjaz/maintenance/hotfixes/sphinx-towncrier-draft 2024-06-21 10:08:50 +02:00
Ronny Pfannschmidt
6a8e9ed43a fixup: Config.cache cannot be None 2024-06-21 09:42:24 +02:00
Sviatoslav Sydorenko
dc2568a683 🚑🧪📝 Stop capping Towncrier @ local docs builds
It is uncapped in RTD. Apparently, `tox -e docs` is not invoked in CI,
neither is it called in RTD, resulting in the regression having been
caught only in local development environments.

This is a follow-up for #12493.
2024-06-20 22:13:43 +02:00
Sviatoslav Sydorenko
43815b6fc2 🚑🧪📝 Allow invoking git in tox
It is called when building the docs. Apparently, `tox -e docs` is not
invoked in CI, neither is it called in RTD, resulting in the
regression having been caught only in local development environments.

This is a follow-up for #12493.
2024-06-20 22:13:43 +02:00
Ronny Pfannschmidt
f426c0b35a Merge pull request #12469 from webknjaz/maintenance/non-setuptools-entry-points
📝 Make "setuptools entrypoint" term generic
2024-06-20 11:31:13 +02:00
Ronny Pfannschmidt
85e451a2cc add changelog entry 2024-06-20 11:10:04 +02:00
Ronny Pfannschmidt
4e54f19be1 update tox:docs python to rtd python 2024-06-20 11:04:38 +02:00
Ronny Pfannschmidt
5e1649f59a resolve most sphinx lookup errors
add the extra sphinx annotations to refer to Path instances

add Path to nitpicky ignore
2024-06-20 11:04:33 +02:00
Ronny Pfannschmidt
b7c0295e1a use runtime union for EXCEPTION_OR_MORE 2024-06-20 11:03:07 +02:00
Ronny Pfannschmidt
9295f9ffff RFC: from __future__ import annotations + migrate 2024-06-20 11:03:03 +02:00
Sviatoslav Sydorenko
cb179472bb 📝 Add change notes for PR #12469 2024-06-20 11:01:10 +02:00
Sviatoslav Sydorenko
39b548e6ea 📝 Make "setuptools entrypoint" term generic
This feature grew out of `setuptools` but the modern interface for
extracting this information from the distribution package metadata
is `importlib.metadata`. So the patch attempts to reflect this in
the documentation messaging.

Refs:
* https://docs.python.org/3/library/importlib.metadata.html#entry-points
* https://packaging.python.org/en/latest/guides/creating-and-discovering-plugins/#using-package-metadata
* https://packaging.python.org/en/latest/specifications/entry-points/#entry-points
2024-06-20 11:01:10 +02:00
Ronny Pfannschmidt
20dd1d6738 Merge pull request #12493 from webknjaz/maintenance/sphinx-towncrier-draft
📝💅 Always render changelog draft @ Sphinx docs
2024-06-20 10:59:04 +02:00
Sviatoslav Sydorenko
e702079fd5 📝💅 Always render changelog draft @ Sphinx docs
The earlier implementation was generating a temporary file, when
the docs site was being built with `tox`. However, this was not
enabled in RTD and is hackish.
This patch integrates the `sphinxcontrib-towncrier` extension to
make it work in any environment where Sphinx docs are being built.
2024-06-20 10:44:32 +02:00
Ronny Pfannschmidt
63dfa4bb84 Merge pull request #12494 from webknjaz/maintenance/rtd-conf-name
📝 Rename the RTD config to canonical filename
2024-06-20 10:39:34 +02:00
Sviatoslav Sydorenko
0470c387a9 📝 Rename the RTD config to canonical filename
Previously, it was possible to use several different config file name
variants. However, there is one canonical name now and the others are
being deprecated [[1]].

[1]: https://docs.rtfd.io/en/stable/config-file/index.html
2024-06-20 10:22:17 +02:00
Ronny Pfannschmidt
57bc6df510 Merge pull request #12488 from webknjaz/maintenance/gha-check-allowed-failures
🧪 Make required CI jobs match branch protection
2024-06-19 12:42:36 +02:00
Sviatoslav Sydorenko
6a95bcaa58 🧪 Make required CI jobs match branch protection 2024-06-19 12:10:20 +02:00
Ronny Pfannschmidt
ff133f6baa Merge pull request #12486 from webknjaz/maintenance/rm-legacy-backport-gha-workflow
🔥 Exterminate legacy backport GHA workflow
2024-06-19 11:59:28 +02:00
Sviatoslav Sydorenko
bab3c2c291 📝 Add myself to the authors file 2024-06-19 11:31:55 +02:00
Ronny Pfannschmidt
08a39bf9b7 Merge pull request #11818 from RonnyPfannschmidt/ronny/issue-11797-approx-sequence-like
fix #11797: be more lenient on SequenceLike approx
2024-06-19 11:25:55 +02:00
Sviatoslav Sydorenko
19715bf313 🔥 Exterminate legacy backport GHA workflow
Previously, this workflow was being used to cherry-pick PRs made
against `main` into older stable branches. Now that #12475 integrated
the Patchback GitHub App, it's no longer needed as it's making
duplicate pull requests which don't even trigger CI runs automatically
due to #10354. So this patch removes said workflow to address the
problem.
2024-06-19 11:22:55 +02:00
Ronny Pfannschmidt
c46a3a9920 Merge pull request #12477 from webknjaz/maintenance/chronographer-config
💅 Add a config for the Chronographer GitHub App
2024-06-19 09:49:11 +02:00
Sviatoslav Sydorenko (Святослав Сидоренко)
d7b4010638 💅 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
2024-06-19 00:41:33 +00:00
Sviatoslav Sydorenko
f479afc5c0 💅 Add a config for the Chronographer GitHub App
This app allows requiring changelog fragments to be included with
each pull request.
2024-06-19 00:40:11 +02:00
Ronny Pfannschmidt
ea87bd6302 Merge pull request #12476 from webknjaz/maintenance/rtd-latest-env
🧪 Bump RTD env to the latest LTS Ubuntu & Python
2024-06-19 00:18:12 +02:00
Sviatoslav Sydorenko
9e98b6db5b 🧪 Bump RTD env to the latest LTS Ubuntu & Python 2024-06-18 18:39:13 +02:00
Ronny Pfannschmidt
76f3f3da00 fix #11797: be more lenient on SequenceLike approx
this needs a validation as it allows partially implemented sequences
2024-06-18 17:01:24 +02:00
Ronny Pfannschmidt
dc65bb6a66 Merge pull request #10315 from webknjaz/maintenance/gha-check
Introduce a gate/check GHA job
2024-06-18 16:30:54 +02:00
pre-commit-ci[bot]
807d16abfd [pre-commit.ci] pre-commit autoupdate (#12470)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.4.8 → v0.4.9](https://github.com/astral-sh/ruff-pre-commit/compare/v0.4.8...v0.4.9)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-06-18 08:29:53 -03:00
Sviatoslav Sydorenko (Святослав Сидоренко)
49374ec7a0 🚑 Clarify patch condition for doctest finder hack (#12471)
There was a regression caused by #12431 that excluded the patch on
broken CPython patch version ranges 3.11.0–3.11.8 and 3.12.0–3.12.2.

This change fixes that by adjusting the patching conditional clause
to include said versions.

Closes #12430.

Co-authored-by: Florian Bruhin <me@the-compiler.org>
2024-06-18 09:21:25 +00:00
Sviatoslav Sydorenko (Святослав Сидоренко)
fe4961afae Modernize the skipped test_issue_9765 regression test (#12468)
* 🚑 Explicitly set encoding @ `subprocess.run()`

This invocation is present in the `test_issue_9765` regression test
that is always skipped unconditionally, resulting in the
`EncodingWarning` never manifesting itself in CI or development
environments of the contributors.

* Change `setup.py` call w/ `pip install` @ tests

Using this CLI interface has been deprecated in `setuptools` [[1]].

[1]: https://blog.ganssle.io/articles/2021/10/setup-py-deprecated.html
2024-06-17 15:44:14 +00:00
dependabot[bot]
80b7657b2a build(deps): Bump pypa/gh-action-pypi-publish from 1.8.14 to 1.9.0 (#12464)
Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.8.14 to 1.9.0.
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/v1.8.14...v1.9.0)

---
updated-dependencies:
- dependency-name: pypa/gh-action-pypi-publish
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-17 09:58:23 +02:00
github-actions[bot]
5037f8d114 [automated] Update plugin list (#12462)
Co-authored-by: pytest bot <pytestbot@users.noreply.github.com>
2024-06-16 05:24:06 +00:00
neutraljump
2effd8cb2c Docs: clean up various documentation pages (#12451)
* Change Contribution doc title to match sidebar

* Rearrange sentence for clarity

* Update backwards-compatibility.rst

some minor grammar changes

* Update pythonpath.rst

fixed some gramatical errors

* Update AUTHORS

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

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

* Update doc/en/explanation/pythonpath.rst

From a quick overview it looks like lowercase is more consistent, although some pages do use `pytest` in code blocks

Co-authored-by: Bruno Oliveira <bruno@soliv.dev>

---------

Co-authored-by: Mackerello <82668740+Mackerello@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Bruno Oliveira <bruno@soliv.dev>
2024-06-13 09:09:02 -03:00
Stavros Ntentos
037aaa7d45 Update contact.rst: Update Matrix link 2024-06-13 11:18:40 +03:00
pre-commit-ci[bot]
ff75980135 [pre-commit.ci] pre-commit autoupdate (#12447)
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/astral-sh/ruff-pre-commit: v0.4.7 → v0.4.8](https://github.com/astral-sh/ruff-pre-commit/compare/v0.4.7...v0.4.8)
- [github.com/asottile/pyupgrade: v3.15.2 → v3.16.0](https://github.com/asottile/pyupgrade/compare/v3.15.2...v3.16.0)

* Apply pyupgrade automatically

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
2024-06-11 12:36:39 -03:00
Ran Benita
23ca9798f7 doc: fix broken code blocks (#12449)
Caused by 4588653b24.

The issue was fixed in https://github.com/astral-sh/ruff/issues/11577,
so won't trigger again.

Fix #12437.
2024-06-11 12:36:20 -03:00
Ran Benita
f3946dce07 Merge pull request #12443 from bluetech/pygments-refactor
terminalwriter: small refactor of pygments code, improve usage errors
2024-06-10 14:13:46 +03:00
Ran Benita
7ef9da1f02 terminalwriter: improve PYTEST_THEME, PYTEST_THEME_MODE usage errors 2024-06-10 11:50:08 +03:00
Ran Benita
67a570aea9 terminalwriter: factor out pygments lexer & formatter selection to own functions
We intend to add some more logic here.
2024-06-10 11:48:19 +03:00
dependabot[bot]
3d91e42229 build(deps): Bump pytest-bdd in /testing/plugins_integration (#12442)
Bumps [pytest-bdd](https://github.com/pytest-dev/pytest-bdd) from 7.1.2 to 7.2.0.
- [Release notes](https://github.com/pytest-dev/pytest-bdd/releases)
- [Changelog](https://github.com/pytest-dev/pytest-bdd/blob/master/CHANGES.rst)
- [Commits](https://github.com/pytest-dev/pytest-bdd/compare/7.1.2...7.2.0)

---
updated-dependencies:
- dependency-name: pytest-bdd
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-10 08:28:57 +02:00
github-actions[bot]
9bfcca6f48 [automated] Update plugin list (#12441)
Co-authored-by: pytest bot <pytestbot@users.noreply.github.com>
2024-06-09 22:49:33 -03:00
Ran Benita
f85289ba87 Merge pull request #12436 from bluetech/unittest-rerun-assertion
unittest: fix assertion errors on unittest reruns
2024-06-08 02:11:20 +03:00
Ran Benita
18f15a38fc Merge pull request #12435 from bluetech/avoid-type-checking
Avoid some `TYPE_CHECKING`
2024-06-08 02:11:06 +03:00
Ran Benita
db67107090 Merge pull request #12434 from bluetech/register-fixture-scope-none
fixtures: change `register_fixture` to not accept `scope=None`
2024-06-07 12:11:56 +03:00
Ran Benita
de47b73520 unittest: fix assertion errors on unittest reruns
This fixes unittest test reruns when using plugins like
pytest-rerunfailures.

The `instance` property uses AttributeError to check if the instance
needs to be initialized, so `del` is the correct way to clear it, not
setting to `None`.

Regressed in 8.2.2.
2024-06-07 10:21:15 +03:00
Ran Benita
8585c58826 Merge pull request #10470 from pytest-dev/dependabot/pip/testing/plugins_integration/pytest-trio-0.8.0
build(deps): Bump pytest-trio from 0.7.0 to 0.8.0 in /testing/plugins_integration
2024-06-07 10:20:42 +03:00
dependabot[bot]
13f97632c6 build(deps): Bump pytest-trio in /testing/plugins_integration
Bumps [pytest-trio](https://github.com/python-trio/pytest-trio) from 0.7.0 to 0.8.0.
- [Release notes](https://github.com/python-trio/pytest-trio/releases)
- [Commits](https://github.com/python-trio/pytest-trio/compare/v0.7.0...v0.8.0)

---
updated-dependencies:
- dependency-name: pytest-trio
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-07 07:03:09 +00:00
Ran Benita
c07bbdfa5b Avoid some TYPE_CHECKING
It's better not to use it when possible.
2024-06-07 09:36:55 +03:00
Jason R. Coombs
f941099371 Cleanup MockAwareDocTestFinder. (#12431)
* Only rely on _find_lineno on Python 3.10 and earlier.

* Update docstring to reflect current expectation.

* Only rely on _find on Python 3.9 and earlier.

* Mark line as uncovered.

* Remove empty else block (implicit is better than explicit).

Closes #12430
Closes #12432
2024-06-07 09:32:33 +03:00
Tomasz Kłoczko
6b2daaa2e9 [pre-commit] Add pyupgrade back as a manual stage (#12418)
Launchable with ``pre-commit run --hook-stage manual pyupgrade -a``

---------

Signed-off-by: Tomasz Kłoczko <kloczek@github.com>
Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
2024-06-06 23:52:29 +02:00
holger krekel
043ff9abc6 Remove hp42 contact details from the documentation (#12427) 2024-06-06 10:24:31 +00:00
Ran Benita
c9d8765381 fixtures: change register_fixture to not accept scope=None
There is no reason to allow this.
2024-06-04 23:22:18 +03:00
Ran Benita
0070151c63 Merge pull request #12416 from bluetech/cherry-pick-release
Cherry-pick 8.2.2 release notes
2024-06-04 17:22:29 +03:00
Ran Benita
4cd80e19c5 Merge pull request #12415 from pytest-dev/release-8.2.2
Prepare release 8.2.2

(cherry picked from commit f3a494cca3)
2024-06-04 16:52:15 +03:00
Ran Benita
d4dbe771f0 Merge pull request #12409 from bluetech/reorder-items-perf
fixtures: fix catastrophic performance problem in `reorder_items`
2024-06-04 10:16:19 +03:00
Ran Benita
e89d23b247 fixtures: fix catastrophic performance problem in reorder_items
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:15:50 +03:00
pre-commit-ci[bot]
3433c7adf5 [pre-commit.ci] pre-commit autoupdate (#12413)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.4.5 → v0.4.7](https://github.com/astral-sh/ruff-pre-commit/compare/v0.4.5...v0.4.7)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-06-04 09:06:33 +02:00
Michael Vogt
7be95f9b30 code: do not truncate args when running with -vvv (#12241)
Related to #2871.
2024-06-03 12:11:41 +00:00
Ran Benita
177f2ae6c4 Merge pull request #12408 from bluetech/cache-race
cacheprovider: fix "Directory not empty" crash from cache directory creation
2024-06-03 12:43:59 +03:00
Ran Benita
1eee63a891 fixtures: minor cleanups to reorder_items
This makes some minor clarity and performance improvements to the code.
2024-06-02 18:31:54 +03:00
Ran Benita
17065cb008 cacheprovider: fix "Directory not empty" crash from cache directory creation
Fix #12381

Test plan:
It's possible to write a deterministic test case for this, but somewhat
of a hassle so I tested it manually. I reproduced by removing existing
`.pytest_cache`, adding a sleep before the rename and running two
pytests. I verified that it doesn't reproduce after the fix.
2024-06-02 17:05:36 +03:00
github-actions[bot]
98021838fd [automated] Update plugin list (#12405)
Co-authored-by: pytest bot <pytestbot@users.noreply.github.com>
2024-06-02 09:31:40 -03:00
Florian Bruhin
10c6db2df2 doc: Update trainings/events (#12401) 2024-05-30 16:48:37 +02:00
Pierre Sassoulas
0ba3e91fbd Merge pull request #12379 from Pierre-Sassoulas/more-pylint-fixes
[pylint] Fix ``consider-using-sys-exit``, ``use-yield-from``, and ``implicit-str-concat``
2024-05-29 15:07:04 +02:00
Pierre Sassoulas
908e112999 [pylint 'implicit-str-concat'] fix existing unwanted implicit str concat 2024-05-29 14:36:01 +02:00
Pierre Sassoulas
0d33cdf02a [pylint] Disable the only 'misplaced-bare-raise' 2024-05-29 14:36:01 +02:00
Pierre Sassoulas
c45afde35d [pylint 'consider-using-sys-exit'] Fix all occurences in existing code 2024-05-29 14:36:01 +02:00
Pierre Sassoulas
db67d5c874 [pylint 'use-yield-from'] Fix all occurences in existing code 2024-05-29 14:36:01 +02:00
dependabot[bot]
383659d0be build(deps): Bump hynek/build-and-inspect-python-package (#12373)
Bumps [hynek/build-and-inspect-python-package](https://github.com/hynek/build-and-inspect-python-package) from 2.5.0 to 2.6.0.
- [Release notes](https://github.com/hynek/build-and-inspect-python-package/releases)
- [Changelog](https://github.com/hynek/build-and-inspect-python-package/blob/main/CHANGELOG.md)
- [Commits](https://github.com/hynek/build-and-inspect-python-package/compare/v2.5.0...v2.6.0)

---
updated-dependencies:
- dependency-name: hynek/build-and-inspect-python-package
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-29 13:39:29 +02:00
Bruno Oliveira
9f121e85a7 Clarify pytest_ignore_collect docs (#12385)
Fixes #12383

Co-authored-by: Ran Benita <ran@unusedvar.com>
2024-05-28 13:47:00 -03:00
pre-commit-ci[bot]
48cb8a2b32 [pre-commit.ci] pre-commit autoupdate (#12380)
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/astral-sh/ruff-pre-commit: v0.4.4 → v0.4.5](https://github.com/astral-sh/ruff-pre-commit/compare/v0.4.4...v0.4.5)

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-05-27 22:31:18 +00:00
Pierre Sassoulas
88fae23bdd [pylint] Fixes all `use-maxplit-args, consider-using-enumerate` (#12172)
* [pylint 'use-maxsplit-arg'] Do not split more than necessary when using the first element

* [pylint 'consider-using-enumerate'] Use zip when iterating on two iterators

* [pylint] 'cell-var-from-loop' and 'disallowed-name' permanent disable

* [pylint] Disable 'possibly-used-before-assignment' following 3.2.0 release
2024-05-27 12:18:03 -07:00
dependabot[bot]
24abe4eb03 build(deps): Bump anyio[curio,trio] in /testing/plugins_integration (#12374)
Bumps [anyio[curio,trio]](https://github.com/agronholm/anyio) from 4.3.0 to 4.4.0.
- [Release notes](https://github.com/agronholm/anyio/releases)
- [Changelog](https://github.com/agronholm/anyio/blob/master/docs/versionhistory.rst)
- [Commits](https://github.com/agronholm/anyio/compare/4.3.0...4.4.0)

---
updated-dependencies:
- dependency-name: anyio[curio,trio]
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-27 06:43:30 +02:00
James Frost
020db7ec04 Add html_baseurl to sphinx conf.py (#12364)
This is used to set the <link rel="canonical" href="X"> tag that points to the canonical version of the webpage. Including this indicates to search engines which version to include in their indexes, and should prevent older versions showing up.

Fixes #12363
2024-05-26 07:21:30 -03:00
Ran Benita
f8dfc1d5f0 Merge pull request #12368 from bluetech/unittest-clear-instance
unittest: fix class instances no longer released on test teardown since pytest 8.2.0
2024-05-26 10:34:11 +03:00
Ran Benita
c3c51037f0 unittest: fix class instances no longer released on test teardown since pytest 8.2.0
Fix #12367.
2024-05-26 10:18:42 +03:00
Ran Benita
3fbf4d3cbd Merge pull request #12369 from pytest-dev/update-plugin-list/patch-889d9b28d
[automated] Update plugin list
2024-05-26 10:14:35 +03:00
pytest bot
b83dd34ce1 [automated] Update plugin list 2024-05-26 00:21:28 +00:00
Nathan Goldbaum
889d9b28d7 Add thread safety section to flaky test docs (#12359)
Closes #12356
2024-05-24 08:16:44 -03:00
Sam Jirovec
cbf6bd9dd2 Issue #12290 - Docs using Furo Theme W/ Dark Mode (#12326)
* furo theme for docs site

* removing duplicate tocs from deprecations and reference pages

* removing pallets references in code and config

* reverting trainings to sidebar

* removed sphinx style and unpinned packaging version

* updated styles
2024-05-21 13:56:18 +00:00
pre-commit-ci[bot]
5d5c9dc858 [pre-commit.ci] pre-commit autoupdate (#12321)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.4.3 → v0.4.4](https://github.com/astral-sh/ruff-pre-commit/compare/v0.4.3...v0.4.4)
- [github.com/tox-dev/pyproject-fmt: 1.8.0 → 2.1.3](https://github.com/tox-dev/pyproject-fmt/compare/1.8.0...2.1.3)

Also fix the comment following autofix

Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
2024-05-21 07:04:09 +00:00
dependabot[bot]
00be7c0739 build(deps): Bump pytest-asyncio in /testing/plugins_integration (#12345)
Bumps [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) from 0.23.6 to 0.23.7.
- [Release notes](https://github.com/pytest-dev/pytest-asyncio/releases)
- [Commits](https://github.com/pytest-dev/pytest-asyncio/compare/v0.23.6...v0.23.7)

---
updated-dependencies:
- dependency-name: pytest-asyncio
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 07:11:04 +02:00
Hynek Schlawack
d4f827d86b Fix link in changelog (#12343) 2024-05-19 21:14:45 +00:00
Ran Benita
69fa9bae43 Merge pull request #12342 from bluetech/cherry-pick-release
Cherry pick 8.2.1 release notes
2024-05-19 22:37:32 +03:00
pytest bot
32baa0b93d Prepare release version 8.2.1
(cherry picked from commit 66ff8dffdf)
2024-05-19 22:11:09 +03:00
Ran Benita
d5b6d44d0e Merge pull request #12339 from pytest-dev/update-plugin-list/patch-ee9ea703f
[automated] Update plugin list
2024-05-19 12:47:55 +03:00
Ran Benita
c1d623cbff Merge pull request #12334 from bluetech/py313
Add Python 3.13 (beta) support
2024-05-19 09:45:09 +03:00
Ran Benita
1cb704ff2c Add Python 3.13 (beta1) support 2024-05-19 09:25:13 +03:00
pytest bot
cb732bbfb0 [automated] Update plugin list 2024-05-19 00:21:06 +00:00
Ran Benita
dbee3fa34a testing: remove conditionals for Python 3.11 beta releases
No need to support beta releases of an older version anymore.

Ref: 09b2c95320
2024-05-18 19:53:50 +03:00
Jelle Zijlstra
ee9ea703f9 Fix new typing issues in AST code (#12337)
python/typeshed#11880 adds more precise types for AST nodes. I'm submitting some changes to adapt pytest to these changes.
2024-05-18 19:07:06 +03:00
Bruno Oliveira
635fbe2bff Attest package provenance (#12333)
Use the new build provenance support added in [build-and-inspect-python-package 2.5.0](https://github.com/hynek/build-and-inspect-python-package/blob/main/CHANGELOG.md#250---2024-05-13).

More information: https://github.blog/2024-05-02-introducing-artifact-attestations-now-in-public-beta/

Tested also in https://github.com/pytest-dev/pytest-mock/pull/431.

Note: even though it is technically necessary only for the `deploy` workflow, as the `test` workflow does not publish its packages, decided to always attest the provenance in both cases to avoid any surprises related to this (say a misconfiguration) when deploying.
2024-05-17 08:19:13 -03:00
Ran Benita
fdf3aa3fc3 Merge pull request #12329 from pytest-dev/fix-package-scope-reorder
fixtures: fix non-working package-scope parametrization reordering
2024-05-16 10:30:34 +03:00
Josh Soref
8d00811822 Spelling and minor changes (#12122) 2024-05-15 13:49:34 -03:00
Ran Benita
1acf56d033 fixtures: fix non-working package-scope parametrization reordering
The `.parent` was incorrectly removed in
a21fb87a90, but it was actually correct
(well, it assumes that Module.path.parent == Package.path, which I'm not
sure is always correct, but that's a different matter). Restore it.

Fix #12328.
2024-05-15 17:29:43 +03:00
Ran Benita
fa1d5be3e8 Merge pull request #12325 from bluetech/pytest-cache-755
cacheprovider: fix `.pytest_cache` not being world-readable
2024-05-15 10:57:10 +03:00
Ran Benita
3a64c47f1f cacheprovider: fix .pytest_cache not being world-readable
Fix #12308.
2024-05-14 23:47:12 +03:00
Ran Benita
ae1a47e050 Merge pull request #12320 from pytest-dev/ut-breaking-change
changelog: document unittest 8.2 change as breaking
2024-05-14 23:06:48 +03:00
Ran Benita
ebe2e8eac9 changelog: document unittest 8.2 change as breaking 2024-05-13 22:34:35 +03:00
Ran Benita
93dd34e76d Merge pull request #12310 from pytest-dev/update-plugin-list/patch-5af46f3d4
[automated] Update plugin list
2024-05-13 20:34:35 +03:00
Ran Benita
704792ecbd Merge pull request #12311 from bluetech/pkg-collect-perm-error
python: add workaround for permission error crashes from non-selected directories
2024-05-13 20:32:23 +03:00
Ran Benita
d4223b9ae2 Merge pull request #12318 from bluetech/unittest-abc
python,unittest: don't collect abstract classes
2024-05-13 20:22:10 +03:00
Ran Benita
37489d3c6c python,unittest: don't collect abstract classes
Fix #12275.
2024-05-13 13:00:47 +03:00
dependabot[bot]
eea04c2891 build(deps): Bump django in /testing/plugins_integration (#12314)
Bumps [django](https://github.com/django/django) from 5.0.4 to 5.0.6.
- [Commits](https://github.com/django/django/compare/5.0.4...5.0.6)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-13 05:56:16 +02:00
Ran Benita
90a3ef2f36 python: add workaround for permission error crashes from non-selected directories
Fix #12120.
2024-05-12 22:38:49 +03:00
pytest bot
e20a08565f [automated] Update plugin list 2024-05-12 00:21:02 +00:00
Yutian Li
5af46f3d4e Fix crashing under squashfuse_ll read-only mounts (#12301)
Fixes #12300
2024-05-09 15:04:58 -03:00
Florian Bruhin
d49f1fc4db doc: update sprint repo link (#12296) 2024-05-08 10:13:30 -03:00
Brian Okken
8efbefb2d7 New --xfail-tb flag (#12280)
Fix #12231
2024-05-07 14:37:00 -03:00
pre-commit-ci[bot]
4080459f04 [pre-commit.ci] pre-commit autoupdate (#12292)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.4.2 → v0.4.3](https://github.com/astral-sh/ruff-pre-commit/compare/v0.4.2...v0.4.3)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-05-07 07:28:34 +02:00
Bruno Oliveira
84e59af8c8 Document exceptions raised by exit, skip, xfail, fail, and importorskip (#12285)
As commented on: https://github.com/pytest-dev/pytest/issues/7469#issuecomment-2094104215
2024-05-05 22:53:16 +00:00
github-actions[bot]
3d09c85df0 [automated] Update plugin list (#12286)
Co-authored-by: pytest bot <pytestbot@users.noreply.github.com>
2024-05-04 21:26:09 -03:00
Anita Hammer
97610067ac Handle KeyboardInterrupt and SystemExit at collection time (#12191) 2024-05-02 11:59:09 +00:00
Ben Brown
4c5298c395 Add back "Fix teardown error reporting when --maxfail=1 (#11721)" (#12279)
Closes #11706.

Originally fixed in #11721, but then reverted in #12022 due to a regression in pytest-xdist.

The regression was fixed on the pytest-xdist side in pytest-dev/pytest-xdist#1026.
2024-05-02 10:42:31 +03:00
Ran Benita
c3e9bd4518 Merge pull request #12271 from bluetech/restore-bdd
testing: restore integration testing with pytest-bdd
2024-05-02 10:27:08 +03:00
Pierre Sassoulas
1385ec117d Merge pull request #12274 from pytest-dev/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2024-04-30 18:32:12 +02:00
Pierre Sassoulas
65d7d6135e [ruff] Add change to format in the git blame ignore file 2024-04-30 18:13:04 +02:00
Pierre Sassoulas
2b6c946a2b [mypy 1.10.0] Remove 'type: ignore' that became useless 2024-04-30 18:11:06 +02:00
Pierre Sassoulas
4788165e69 [ruff UP031] Fix to use format specifiers instead of percent format 2024-04-30 18:06:26 +02:00
pre-commit-ci[bot]
da53e29780 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.4.1 → v0.4.2](https://github.com/astral-sh/ruff-pre-commit/compare/v0.4.1...v0.4.2)
- [github.com/pre-commit/mirrors-mypy: v1.9.0 → v1.10.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.9.0...v1.10.0)
2024-04-29 22:30:08 +00:00
Ran Benita
b660596f61 testing: restore integration testing with pytest-bdd
The problem was fixed.
2024-04-29 20:52:35 +03:00
Ran Benita
feaae2fb35 Merge pull request #12264 from bluetech/reraise-with-original-tb
fixtures,runner: fix tracebacks getting longer and longer
2024-04-29 20:02:44 +03:00
dependabot[bot]
cf90008a1a build(deps): Bump peter-evans/create-pull-request from 6.0.4 to 6.0.5 (#12268)
Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 6.0.4 to 6.0.5.
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](9153d834b6...6d6857d369)

---
updated-dependencies:
- dependency-name: peter-evans/create-pull-request
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-29 08:38:05 -03:00
dj
2ede8778d0 Document using PYTEST_VERSION to detect if a code is running inside pytest (#12153)
Related to #9502
2024-04-28 15:52:29 -03:00
Ran Benita
2e1dfb0c16 Merge pull request #12265 from bluetech/pre-commit-tweaks
pre-commit tweaks
2024-04-28 17:52:38 +03:00
Ran Benita
940b78232e pre-commit: fix misleading indentation 2024-04-28 17:11:11 +03:00
Ran Benita
e847b2a5a9 pre-commit: replace debug-statements hook with ruff
Ruff supports this functionality so we can use it.
2024-04-28 17:06:07 +03:00
Ran Benita
85bc9ca954 pre-commit: remove deprecated fix-encoding-pragma hook
Deprecated by pre-commit.
2024-04-28 17:06:07 +03:00
Ran Benita
ebc4540436 Merge pull request #12258 from bluetech/xdist-align
terminal: fix progress percentages not aligning correctly in xdist
2024-04-28 16:52:40 +03:00
Ran Benita
3e81cb2f45 runner: fix tracebacks for failed collectors getting longer and longer
Refs https://github.com/pytest-dev/pytest/issues/12204#issuecomment-2081239376
2024-04-28 13:30:05 +03:00
Ran Benita
0b91d5e3e8 fixtures: fix tracebacks for higher-scoped failed fixtures getting longer and longer
Fix #12204.
2024-04-28 13:06:32 +03:00
Ran Benita
50d1e81713 terminal: fix progress percentages not aligning correctly in xdist
Fix #7166
2024-04-28 11:33:18 +03:00
Ran Benita
1a84d233f3 terminal: some minor code cleanups
No logical changed intended.
2024-04-28 11:33:18 +03:00
Ran Benita
127a372928 Merge pull request #12259 from bluetech/plain-raise
runner: avoid adding uninteresting entry to tracebacks
2024-04-28 11:21:15 +03:00
Bruno Oliveira
2a809e6f8b Merge pull request #12261 from pytest-dev/update-plugin-list/patch-9eecdc7da
[automated] Update plugin list
2024-04-27 22:09:19 -03:00
pytest bot
852df0dc3e [automated] Update plugin list 2024-04-28 00:20:56 +00:00
Bruno Oliveira
9eecdc7dae Merge pull request #12260 from nicoddemus/cherry-pick-release
Cherry-pick release pytest-dev/release-8.2.0
2024-04-27 20:41:36 -03:00
Bruno Oliveira
79ca819e59 Merge pull request #12257 from pytest-dev/release-8.2.0
Prepare release 8.2.0

(cherry picked from commit 69c3bcea36)
2024-04-27 20:36:02 -03:00
Ran Benita
fc5c960304 runner: avoid adding uninteresting entry to tracebacks
In these two cases which re-raise an immediately-caught exception, do
the re-raising with `raise` instead of `raise exc`, because the `raise
exc` adds an uninteresting entry to the exception's traceback (that of
itself), while `raise` doesn't.
2024-04-28 01:42:43 +03:00
Sviatoslav Sydorenko
30ce631fb9 Securely pin re-actors/alls-green to v1.2 commit 2023-12-07 01:29:02 +01:00
Sviatoslav Sydorenko
b92fde37ce Introduce a gate/check GHA job
This adds a GHA job that reliably determines if all the required
dependencies have succeeded or not.

It also allows to reduce the list of required branch protection CI
statuses to just one — `check`. This reduces the maintenance burden
by a lot and have been battle-tested across a small bunch of projects
in its action form and in-house implementations of other people.

I was curious about the spread of use. And I've just discovered that
it is now in use in aiohttp (and other aio-libs projects), CherryPy,
some of the Ansible repositories, all of the jaraco's projects (like
`setuptools`, `importlib_metadata`), some PyCQA, PyCA and pytest
projects, a few AWS Labs projects. Admittedly, I maintain a few of
these but it seems to address some of the pain folks have:
https://github.com/jaraco/skeleton/pull/55#issuecomment-1106638475.

The story behind this is explained in more detail at
https://github.com/marketplace/actions/alls-green#why.
2023-12-07 01:29:02 +01:00
306 changed files with 4720 additions and 3167 deletions

View File

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

View File

@@ -31,3 +31,5 @@ c9df77cbd6a365dcb73c39618e4842711817e871
4546d5445aaefe6a03957db028c263521dfb5c4b
# Migration to ruff / ruff format
4588653b2497ed25976b7aaff225b889fb476756
# Use format specifiers instead of percent format
4788165e69d08e10fc6b9c0124083fb358e2e9b0

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

@@ -31,7 +31,7 @@ jobs:
persist-credentials: false
- name: Build and Check Package
uses: hynek/build-and-inspect-python-package@v2.5.0
uses: hynek/build-and-inspect-python-package@v2.6.0
with:
attest-build-provenance-github: 'true'
@@ -54,7 +54,7 @@ jobs:
path: dist
- name: Publish package to PyPI
uses: pypa/gh-action-pypi-publish@v1.8.14
uses: pypa/gh-action-pypi-publish@v1.9.0
- name: Push tag
run: |

View File

@@ -14,6 +14,11 @@ on:
branches:
- main
- "[0-9]+.[0-9]+.x"
types:
- opened # default
- synchronize # default
- reopened # default
- ready_for_review # used in PRs created from the release workflow
env:
PYTEST_ADDOPTS: "--color=yes"
@@ -35,7 +40,7 @@ jobs:
fetch-depth: 0
persist-credentials: false
- name: Build and Check Package
uses: hynek/build-and-inspect-python-package@v2.5.0
uses: hynek/build-and-inspect-python-package@v2.6.0
build:
needs: [package]
@@ -182,6 +187,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:
@@ -222,8 +247,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) }}

View File

@@ -46,7 +46,8 @@ jobs:
run: python scripts/update-plugin-list.py
- name: Create Pull Request
uses: peter-evans/create-pull-request@9153d834b60caba6d51c9b9510b087acf9f33f83
id: pr
uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c
with:
commit-message: '[automated] Update plugin list'
author: 'pytest bot <pytestbot@users.noreply.github.com>'
@@ -55,3 +56,13 @@ jobs:
branch-suffix: short-commit-hash
title: '[automated] Update plugin list'
body: '[automated] Update plugin list'
draft: true
- name: Instruct the maintainers to trigger CI by undrafting the PR
env:
GITHUB_TOKEN: ${{ github.token }}
run: >-
gh pr comment
--body 'Please mark the PR as ready for review to trigger PR checks.'
--repo '${{ github.repository }}'
'${{ steps.pr.outputs.pull-request-number }}'

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

@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: "v0.4.1"
rev: "v0.5.0"
hooks:
- id: ruff
args: ["--fix"]
@@ -10,14 +10,9 @@ repos:
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: fix-encoding-pragma
args: [--remove]
- id: check-yaml
- id: debug-statements
exclude: _pytest/(debugging|hookspec).py
language_version: python3
- repo: https://github.com/adamchainz/blacken-docs
rev: 1.16.0
rev: 1.18.0
hooks:
- id: blacken-docs
additional_dependencies: [black==24.1.1]
@@ -26,7 +21,7 @@ repos:
hooks:
- id: python-use-type-annotations
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.9.0
rev: v1.10.1
hooks:
- id: mypy
files: ^(src/|testing/|scripts/)
@@ -43,20 +38,25 @@ repos:
# on <3.11
- exceptiongroup>=1.0.0rc8
- repo: https://github.com/tox-dev/pyproject-fmt
rev: "1.8.0"
rev: "2.1.3"
hooks:
- id: pyproject-fmt
# https://pyproject-fmt.readthedocs.io/en/latest/#calculating-max-supported-python-version
additional_dependencies: ["tox>=4.9"]
- repo: https://github.com/asottile/pyupgrade
rev: v3.16.0
hooks:
- id: pyupgrade
stages: [manual]
- repo: local
hooks:
- id: pylint
name: pylint
entry: pylint
language: system
types: [python]
args: ["-rn", "-sn", "--fail-on=I"]
stages: [manual]
- id: pylint
name: pylint
entry: pylint
language: system
types: [python]
args: ["-rn", "-sn", "--fail-on=I"]
stages: [manual]
- id: rst
name: rst
entry: rst-lint --encoding utf-8
@@ -66,8 +66,41 @@ 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: py-deprecated
name: py library is deprecated

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

@@ -149,6 +149,7 @@ Evgeny Seliverstov
Fabian Sturm
Fabien Zarifian
Fabio Zadrozny
Farbod Ahmadian
faph
Felix Hofstätter
Felix Nieuwenhuizen
@@ -212,6 +213,7 @@ Jordan Guymon
Jordan Moldow
Jordan Speicher
Joseph Hunkeler
Joseph Sawaya
Josh Karpel
Joshua Bronson
Jurko Gospodnetić
@@ -244,6 +246,7 @@ Levon Saldamli
Lewis Cowles
Llandy Riveron Del Risco
Loic Esteve
lovetheguitar
Lukas Bednar
Luke Murphy
Maciek Fijalkowski
@@ -259,6 +262,7 @@ Marc Bresson
Marco Gorelli
Mark Abramowitz
Mark Dickinson
Mark Vong
Marko Pacak
Markus Unterwaditzer
Martijn Faassen
@@ -279,6 +283,7 @@ Michael Droettboom
Michael Goerz
Michael Krebs
Michael Seifert
Michael Vogt
Michal Wajszczuk
Michał Górny
Michał Zięba
@@ -300,6 +305,7 @@ Nicholas Devenish
Nicholas Murphy
Niclas Olofsson
Nicolas Delaby
Nico Vidal
Nikolay Kondratyev
Nipunn Koorapati
Oleg Pidsadnyi
@@ -389,6 +395,7 @@ Stefano Taschini
Steffen Allner
Stephan Obermann
Sven-Hendrik Haase
Sviatoslav Sydorenko
Sylvain Marié
Tadek Teleżyński
Takafumi Arakaki
@@ -447,6 +454,7 @@ Yusuke Kadowaki
Yutian Li
Yuval Shimon
Zac Hatfield-Dodds
Zach Snicker
Zachary Kneupper
Zachary OBrien
Zhouxin Qiu

View File

@@ -1,5 +1,5 @@
============================
Contribution getting started
Contributing
============================
Contributions are highly welcomed and appreciated. Every little bit of help counts,
@@ -124,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
@@ -8,7 +10,7 @@ if __name__ == "__main__":
import pytest # noqa: F401
script = sys.argv[1:] if len(sys.argv) > 1 else ["empty.py"]
cProfile.run("pytest.cmdline.main(%r)" % script, "prof")
cProfile.run(f"pytest.cmdline.main({script!r})", "prof")
p = pstats.Stats("prof")
p.strip_dirs()
p.sort_stats("cumulative")

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,4 @@
Fix reporting of teardown errors in higher-scoped fixtures when using `--maxfail` or `--stepwise`.
Originally added in pytest 8.0.0, but reverted in 8.0.2 due to a regression in pytest-xdist.
This regression was fixed in pytest-xdist 3.6.1.

View File

@@ -0,0 +1 @@
:func:`pytest.approx` now correctly handles :class:`Sequence <collections.abc.Sequence>`-like objects.

1
changelog/12153.doc.rst Normal file
View File

@@ -0,0 +1 @@
Documented using :envvar:`PYTEST_VERSION` to detect if code is running from within a pytest run.

View File

@@ -0,0 +1,7 @@
Fix a regression in pytest 8.0 where tracebacks get longer and longer when multiple tests fail due to a shared higher-scope fixture which raised.
Also fix a similar regression in pytest 5.4 for collectors which raise during setup.
The fix necessitated internal changes which may affect some plugins:
- ``FixtureDef.cached_result[2]`` is now a tuple ``(exc, tb)`` instead of ``exc``.
- ``SetupState.stack`` failures are now a tuple ``(exc, tb)`` instead of ``exc``.

View File

@@ -0,0 +1,11 @@
Added `--xfail-tb` flag, which turns on traceback output for XFAIL results.
* If the `--xfail-tb` flag is not sent, tracebacks for XFAIL results are NOT shown.
* The style of traceback for XFAIL is set with `--tb`, and can be `auto|long|short|line|native|no`.
* Note: Even if you have `--xfail-tb` set, you won't see them if `--tb=no`.
Some history:
With pytest 8.0, `-rx` or `-ra` would not only turn on summary reports for xfail, but also report the tracebacks for xfail results. This caused issues with some projects that utilize xfail, but don't want to see all of the xfail tracebacks.
This change detaches xfail tracebacks from `-rx`, and now we turn on xfail tracebacks with `--xfail-tb`. With this, the default `-rx`/ `-ra` behavior is identical to pre-8.0 with respect to xfail tracebacks. While this is a behavior change, it brings default behavior back to pre-8.0.0 behavior, which ultimately was considered the better course of action.

View File

@@ -0,0 +1 @@
Fix collection error upon encountering an :mod:`abstract <abc>` class, including abstract `unittest.TestCase` subclasses.

View File

@@ -0,0 +1,8 @@
Added support for keyword matching in marker expressions.
Now tests can be selected by marker keyword arguments.
Supported values are :class:`int`, (unescaped) :class:`str`, :class:`bool` & :data:`None`.
See :ref:`marker examples <marker_keyword_expression_example>` for more information.
-- by :user:`lovetheguitar`

View File

@@ -0,0 +1 @@
Fix a regression in pytest 8.0.0 where package-scoped parameterized items were not correctly reordered to minimize setups/teardowns in some cases.

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`

6
changelog/12469.doc.rst Normal file
View File

@@ -0,0 +1,6 @@
The external plugin mentions in the documentation now avoid mentioning
:std:doc:`setuptools entry-points <setuptools:index>` as the concept is
much more generic nowadays. Instead, the terminology of "external",
"installed", or "third-party" plugins (or packages) replaces that.
-- by :user:`webknjaz`

View File

@@ -0,0 +1,4 @@
The console output now uses the "third-party plugins" terminology,
replacing the previously established but confusing and outdated
reference to :std:doc:`setuptools <setuptools:index>`
-- by :user:`webknjaz`.

View File

@@ -0,0 +1 @@
Fixed a crash when returning category ``"error"`` or ``"failed"`` with a custom test status from :hook:`pytest_report_teststatus` hook -- :user:`pbrezina`.

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,7 @@
The UX of the GitHub automation making pull requests to update the
plugin list has been updated. Previously, the maintainers had to close
the automatically created pull requests and re-open them to trigger the
CI runs. From now on, they only need to click the `Ready for review`
button instead.
-- 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,4 @@
The _in_venv function now detects Python virtual environments by checking
for a pyvenv.cfg file, ensuring reliable detection on various platforms.
-- by :user:`zachsnickers`.

View File

@@ -0,0 +1 @@
Do not truncate arguments to functions in output when running with `-vvv`.

View File

@@ -0,0 +1,38 @@
The readability of assertion introspection of bound methods has been enhanced
-- by :user:`farbodahm`, :user:`webknjaz`, :user:`obestwalter`, :user:`flub`
and :user:`glyphack`.
Earlier, it was like:
.. code-block:: console
=================================== FAILURES ===================================
_____________________________________ test _____________________________________
def test():
> assert Help().fun() == 2
E assert 1 == 2
E + where 1 = <bound method Help.fun of <example.Help instance at 0x256a830>>()
E + where <bound method Help.fun of <example.Help instance at 0x256a830>> = <example.Help instance at 0x256a830>.fun
E + where <example.Help instance at 0x256a830> = Help()
example.py:7: AssertionError
=========================== 1 failed in 0.03 seconds ===========================
And now it's like:
.. code-block:: console
=================================== FAILURES ===================================
_____________________________________ test _____________________________________
def test():
> assert Help().fun() == 2
E assert 1 == 2
E + where 1 = fun()
E + where fun = <test_local.Help object at 0x1074be230>.fun
E + where <test_local.Help object at 0x1074be230> = Help()
test_local.py:13: AssertionError
=========================== 1 failed in 0.03 seconds ===========================

View File

@@ -0,0 +1 @@
Fixed progress percentages (the ``[ 87%]`` at the edge of the screen) sometimes not aligning correctly when running with pytest-xdist ``-n``.

View File

@@ -0,0 +1 @@
Added timezone information to the testsuite timestamp in the JUnit XML report.

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

@@ -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

@@ -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

@@ -19,12 +19,15 @@ 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
@@ -265,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.
@@ -1419,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.
@@ -2588,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.
@@ -2871,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.
@@ -3041,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.
@@ -3357,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).
@@ -4064,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.
@@ -4265,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.
@@ -7226,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.
@@ -7257,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
@@ -7266,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.
@@ -7520,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``
@@ -7575,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
@@ -7591,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``
@@ -7621,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`).
@@ -7629,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.
@@ -7663,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:
@@ -7707,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`).
@@ -7730,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.
@@ -7742,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.
@@ -7783,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`).
@@ -7854,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.
@@ -7866,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``.
@@ -7883,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
@@ -7917,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
@@ -7938,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.
@@ -7949,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`.
@@ -7988,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.

View File

@@ -15,17 +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
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,
@@ -66,12 +82,13 @@ extensions = [
"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
@@ -153,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?)
@@ -176,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"),
@@ -197,13 +205,16 @@ 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"),
]
@@ -226,7 +237,7 @@ html_theme = "furo"
html_title = "pytest documentation"
# A shorter title for the navigation bar. Default is the same as html_title.
html_short_title = "pytest-%s" % release
html_short_title = f"pytest-{release}"
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
@@ -422,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),
@@ -435,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",
@@ -488,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

@@ -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

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

@@ -25,10 +25,12 @@ You can "mark" a test function with custom metadata like this:
pass # perform some webtest test for your app
@pytest.mark.device(serial="123")
def test_something_quick():
pass
@pytest.mark.device(serial="abc")
def test_another():
pass
@@ -71,6 +73,28 @@ Or the inverse, running all tests except the webtest ones:
===================== 3 passed, 1 deselected in 0.12s ======================
.. _`marker_keyword_expression_example`:
Additionally, you can restrict a test run to only run tests matching one or multiple marker
keyword arguments, e.g. to run only tests marked with ``device`` and the specific ``serial="123"``:
.. code-block:: pytest
$ pytest -v -m "device(serial='123')"
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-8.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
cachedir: .pytest_cache
rootdir: /home/sweet/project
collecting ... collected 4 items / 3 deselected / 1 selected
test_server.py::test_something_quick PASSED [100%]
===================== 1 passed, 3 deselected in 0.12s ======================
.. note:: Only keyword argument matching is supported in marker expressions.
.. note:: Only :class:`int`, (unescaped) :class:`str`, :class:`bool` & :data:`None` values are supported in marker expressions.
Selecting tests based on their node ID
--------------------------------------

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

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

View File

@@ -212,7 +212,7 @@ the command line arguments before they get processed:
.. code-block:: python
# setuptools plugin
# installable external plugin
import sys
@@ -405,35 +405,20 @@ Detect if running from within a pytest run
Usually it is a bad idea to make application code
behave differently if called from a test. But if you
absolutely must find out if your application code is
running from a test you can do something like this:
running from a test you can do this:
.. code-block:: python
# content of your_module.py
import os
_called_from_test = False
.. code-block:: python
# content of conftest.py
def pytest_configure(config):
your_module._called_from_test = True
and then check for the ``your_module._called_from_test`` flag:
.. code-block:: python
if your_module._called_from_test:
# called from within a test run
if os.environ.get("PYTEST_VERSION") is not None:
# Things you want to to do if your code is called by pytest.
...
else:
# called "normally"
# Things you want to to do if your code is not called by pytest.
...
accordingly in your application.
Adding info to test report header
--------------------------------------------------------------
@@ -1088,8 +1073,8 @@ Instead of freezing the pytest runner as a separate executable, you can make
your frozen program work as the pytest runner by some clever
argument handling during program startup. This allows you to
have a single executable, which is usually more convenient.
Please note that the mechanism for plugin discovery used by pytest
(setuptools entry points) doesn't work with frozen executables so pytest
Please note that the mechanism for plugin discovery used by pytest (:ref:`entry
points <pip-installable plugins>`) doesn't work with frozen executables so pytest
can't find any third party plugins automatically. To include third party plugins
like ``pytest-timeout`` they must be imported explicitly and passed on to pytest.main.

View File

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

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

@@ -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

@@ -1931,7 +1931,7 @@ The same applies for the test folder level obviously.
Using fixtures from other projects
----------------------------------
Usually projects that provide pytest support will use :ref:`entry points <setuptools entry points>`,
Usually projects that provide pytest support will use :ref:`entry points <pip-installable plugins>`,
so just installing those projects into an environment will make those fixtures available for use.
In case you want to use fixtures from a project that does not use entry points, you can

View File

@@ -76,11 +76,19 @@ Specifying a specific parametrization of a test:
**Run tests by marker expressions**
To run all tests which are decorated with the ``@pytest.mark.slow`` decorator:
.. code-block:: bash
pytest -m slow
Will run all tests which are decorated with the ``@pytest.mark.slow`` decorator.
To run all tests which are decorated with the annotated ``@pytest.mark.slow(phase=1)`` decorator,
with the ``phase`` keyword argument set to ``1``:
.. code-block:: bash
pytest -m "slow(phase=1)"
For more information see :ref:`marks <mark>`.
@@ -154,7 +162,7 @@ You can early-load plugins (internal and external) explicitly in the command-lin
The option receives a ``name`` parameter, which can be:
* A full module dotted name, for example ``myproject.plugins``. This dotted name must be importable.
* The entry-point name of a plugin. This is the name passed to ``setuptools`` when the plugin is
* The entry-point name of a plugin. This is the name passed to ``importlib`` when the plugin is
registered. For example to early-load the :pypi:`pytest-cov` plugin you can use::
pytest -p pytest_cov

View File

@@ -16,8 +16,8 @@ reporting by calling :ref:`well specified hooks <hook-reference>` of the followi
* builtin plugins: loaded from pytest's internal ``_pytest`` directory.
* :ref:`external plugins <extplugins>`: modules discovered through
`setuptools entry points`_
* :ref:`external plugins <extplugins>`: installed third-party modules discovered
through :ref:`entry points <pip-installable plugins>` in their packaging metadata
* `conftest.py plugins`_: modules auto-discovered in test directories
@@ -42,7 +42,8 @@ Plugin discovery order at tool startup
3. by scanning the command line for the ``-p name`` option
and loading the specified plugin. This happens before normal command-line parsing.
4. by loading all plugins registered through `setuptools entry points`_.
4. by loading all plugins registered through installed third-party package
:ref:`entry points <pip-installable plugins>`.
5. by loading all plugins specified through the :envvar:`PYTEST_PLUGINS` environment variable.
@@ -142,7 +143,8 @@ Making your plugin installable by others
If you want to make your plugin externally available, you
may define a so-called entry point for your distribution so
that ``pytest`` finds your plugin module. Entry points are
a feature that is provided by :std:doc:`setuptools <setuptools:index>`.
a feature that is provided by :std:doc:`packaging tools
<packaging:specifications/entry-points>`.
pytest looks up the ``pytest11`` entrypoint to discover its
plugins, thus you can make your plugin available by defining
@@ -265,8 +267,9 @@ of the variable will also be loaded as plugins, and so on.
tests root directory is deprecated, and will raise a warning.
This mechanism makes it easy to share fixtures within applications or even
external applications without the need to create external plugins using
the ``setuptools``'s entry point technique.
external applications without the need to create external plugins using the
:std:doc:`entry point packaging metadata
<packaging:guides/creating-and-discovering-plugins>` technique.
Plugins imported by :globalvar:`pytest_plugins` will also automatically be marked
for assertion rewriting (see :func:`pytest.register_assert_rewrite`).

View File

@@ -4,8 +4,7 @@
.. sidebar:: **Next Open Trainings and Events**
- `pytest development sprint <https://github.com/pytest-dev/sprint>`_, **June 17th -- 22nd 2024**, Klaus (AT) / Remote
- `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 8th -- 14th 2024** (3h), Prague (CZ)
- `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

View File

@@ -90,7 +90,7 @@ and can also be used to hold pytest configuration if they have a ``[pytest]`` se
setup.cfg
~~~~~~~~~
``setup.cfg`` files are general purpose configuration files, used originally by ``distutils`` (now deprecated) and `setuptools <https://setuptools.pypa.io/en/latest/userguide/declarative_config.html>`__, and can also be used to hold pytest configuration
``setup.cfg`` files are general purpose configuration files, used originally by ``distutils`` (now deprecated) and :std:doc:`setuptools <setuptools:userguide/declarative_config>`, and can also be used to hold pytest configuration
if they have a ``[tool:pytest]`` section.
.. code-block:: ini

File diff suppressed because it is too large Load Diff

View File

@@ -650,7 +650,7 @@ Reference to all hooks which can be implemented by :ref:`conftest.py files <loca
Bootstrapping hooks
~~~~~~~~~~~~~~~~~~~
Bootstrapping hooks called for plugins registered early enough (internal and setuptools plugins).
Bootstrapping hooks called for plugins registered early enough (internal and third-party plugins).
.. hook:: pytest_load_initial_conftests
.. autofunction:: pytest_load_initial_conftests
@@ -1147,8 +1147,9 @@ When set, pytest will print tracing and debug information.
.. envvar:: PYTEST_DISABLE_PLUGIN_AUTOLOAD
When set, disables plugin auto-loading through setuptools entrypoints. Only explicitly specified plugins will be
loaded.
When set, disables plugin auto-loading through :std:doc:`entry point packaging
metadata <packaging:guides/creating-and-discovering-plugins>`. Only explicitly
specified plugins will be loaded.
.. envvar:: PYTEST_PLUGINS
@@ -1701,13 +1702,13 @@ passed multiple times. The expected format is ``name=value``. For example::
This would tell ``pytest`` to not look into typical subversion or
sphinx-build directories or into any ``tmp`` prefixed directory.
Additionally, ``pytest`` will attempt to intelligently identify and ignore a
virtualenv by the presence of an activation script. Any directory deemed to
be the root of a virtual environment will not be considered during test
collection unless ``--collect-in-virtualenv`` is given. Note also that
``norecursedirs`` takes precedence over ``--collect-in-virtualenv``; e.g. if
you intend to run tests in a virtualenv with a base directory that matches
``'.*'`` you *must* override ``norecursedirs`` in addition to using the
Additionally, ``pytest`` will attempt to intelligently identify and ignore
a virtualenv. Any directory deemed to be the root of a virtual environment
will not be considered during test collection unless
``--collect-in-virtualenv`` is given. Note also that ``norecursedirs``
takes precedence over ``--collect-in-virtualenv``; e.g. if you intend to
run tests in a virtualenv with a base directory that matches ``'.*'`` you
*must* override ``norecursedirs`` in addition to using the
``--collect-in-virtualenv`` flag.

View File

@@ -9,3 +9,5 @@ sphinxcontrib-svg2pdfconverter
# See https://github.com/pytest-dev/pytest/pull/10578#issuecomment-1348249045.
packaging
furo
sphinxcontrib-towncrier
sphinx-issues

View File

@@ -1,5 +1,8 @@
from __future__ import annotations
import json
from pathlib import Path
import sys
import requests
@@ -17,7 +20,7 @@ def get_issues():
if r.status_code == 403:
# API request limit exceeded
print(data["message"])
exit(1)
sys.exit(1)
issues.extend(data)
# Look for next page
@@ -60,7 +63,7 @@ def report(issues):
kind = _get_kind(issue)
status = issue["state"]
number = issue["number"]
link = "https://github.com/pytest-dev/pytest/issues/%s/" % number
link = f"https://github.com/pytest-dev/pytest/issues/{number}/"
print("----")
print(status, kind, link)
print(title)
@@ -69,7 +72,7 @@ def report(issues):
# print("\n".join(lines[:3]))
# if len(lines) > 3 or len(body) > 240:
# print("...")
print("\n\nFound %s open issues" % len(issues))
print(f"\n\nFound {len(issues)} open issues")
if __name__ == "__main__":

View File

@@ -1,3 +1,10 @@
[build-system]
build-backend = "setuptools.build_meta"
requires = [
"setuptools>=61",
"setuptools-scm[toml]>=6.2.3",
]
[project]
name = "pytest"
description = "pytest: simple powerful testing with Python"
@@ -6,15 +13,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,7 +38,6 @@ 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",
@@ -40,15 +46,14 @@ dynamic = [
"version",
]
dependencies = [
'colorama; sys_platform == "win32"',
'exceptiongroup>=1.0.0rc8; python_version < "3.11"',
"colorama; sys_platform=='win32'",
"exceptiongroup>=1.0.0rc8; python_version<'3.11'",
"iniconfig",
"packaging",
"pluggy<2.0,>=1.5",
'tomli>=1; python_version < "3.11"',
"pluggy<2,>=1.5",
"tomli>=1; python_version<'3.11'",
]
[project.optional-dependencies]
dev = [
optional-dependencies.dev = [
"argcomplete",
"attrs>=19.2",
"hypothesis>=3.56",
@@ -58,58 +63,55 @@ dev = [
"setuptools",
"xmlschema",
]
[project.urls]
Changelog = "https://docs.pytest.org/en/stable/changelog.html"
Homepage = "https://docs.pytest.org/en/latest/"
Source = "https://github.com/pytest-dev/pytest"
Tracker = "https://github.com/pytest-dev/pytest/issues"
Twitter = "https://twitter.com/pytestdotorg"
[project.scripts]
"py.test" = "pytest:console_main"
pytest = "pytest:console_main"
[build-system]
build-backend = "setuptools.build_meta"
requires = [
"setuptools>=61",
"setuptools-scm[toml]>=6.2.3",
]
urls.Changelog = "https://docs.pytest.org/en/stable/changelog.html"
urls.Homepage = "https://docs.pytest.org/en/latest/"
urls.Source = "https://github.com/pytest-dev/pytest"
urls.Tracker = "https://github.com/pytest-dev/pytest/issues"
urls.Twitter = "https://twitter.com/pytestdotorg"
scripts."py.test" = "pytest:console_main"
scripts.pytest = "pytest:console_main"
[tool.setuptools.package-data]
"_pytest" = ["py.typed"]
"pytest" = ["py.typed"]
"_pytest" = [
"py.typed",
]
"pytest" = [
"py.typed",
]
[tool.setuptools_scm]
write_to = "src/_pytest/_version.py"
[tool.black]
target-version = ['py38']
target-version = [
'py38',
]
[tool.ruff]
src = ["src"]
line-length = 88
[tool.ruff.format]
docstring-code-format = true
[tool.ruff.lint]
select = [
"B", # bugbear
"D", # pydocstyle
"E", # pycodestyle
"F", # pyflakes
"I", # isort
"PYI", # flake8-pyi
"UP", # pyupgrade
"RUF", # ruff
"W", # pycodestyle
"PIE", # flake8-pie
"PGH004", # pygrep-hooks - Use specific rule codes when using noqa
"PLE", # pylint error
"PLW", # pylint warning
"PLR1714", # Consider merging multiple comparisons
src = [
"src",
]
ignore = [
format.docstring-code-format = true
lint.select = [
"B", # bugbear
"D", # pydocstyle
"E", # pycodestyle
"F", # pyflakes
"FA100", # add future annotations
"I", # isort
"PGH004", # pygrep-hooks - Use specific rule codes when using noqa
"PIE", # flake8-pie
"PLE", # pylint error
"PLR1714", # Consider merging multiple comparisons
"PLW", # pylint warning
"PYI", # flake8-pyi
"RUF", # ruff
"T100", # flake8-debugger
"UP", # pyupgrade
"W", # pycodestyle
]
lint.ignore = [
# bugbear ignore
"B004", # Using `hasattr(x, "__call__")` to test if x is callable is unreliable.
"B007", # Loop control variable `i` not used within loop body
@@ -117,10 +119,6 @@ ignore = [
"B010", # [*] Do not call `setattr` with a constant attribute value.
"B011", # Do not `assert False` (`python -O` removes these calls)
"B028", # No explicit `stacklevel` keyword argument found
# pycodestyle ignore
# pytest can do weird low-level things, and we usually know
# what we're doing when we use type(..) is ...
"E721", # Do not compare types, use `isinstance()`
# pydocstyle ignore
"D100", # Missing docstring in public module
"D101", # Missing docstring in public class
@@ -130,46 +128,59 @@ ignore = [
"D105", # Missing docstring in magic method
"D106", # Missing docstring in public nested class
"D107", # Missing docstring in `__init__`
"D209", # [*] Multi-line docstring closing quotes should be on a separate line
"D205", # 1 blank line required between summary line and description
"D209", # [*] Multi-line docstring closing quotes should be on a separate line
"D400", # First line should end with a period
"D401", # First line of docstring should be in imperative mood
"D402", # First line should not be the function's signature
"D404", # First word of the docstring should not be "This"
"D415", # First line should end with a period, question mark, or exclamation point
# pytest can do weird low-level things, and we usually know
# what we're doing when we use type(..) is ...
"E721", # Do not compare types, use `isinstance()`
# pylint ignore
"PLR5501", # Use `elif` instead of `else` then `if`
"PLW0120", # remove the else and dedent its contents
"PLW0603", # Using the global statement
"PLW2901", # for loop variable overwritten by assignment target
# ruff ignore
"RUF012", # Mutable class attributes should be annotated with `typing.ClassVar`
# pylint ignore
"PLW0603", # Using the global statement
"PLW0120", # remove the else and dedent its contents
"PLW2901", # for loop variable overwritten by assignment target
"PLR5501", # Use `elif` instead of `else` then `if`
]
[tool.ruff.lint.pycodestyle]
lint.per-file-ignores."src/_pytest/_py/**/*.py" = [
"B",
"PYI",
]
lint.per-file-ignores."src/_pytest/_version.py" = [
"I001",
]
lint.per-file-ignores."testing/python/approx.py" = [
"B015",
]
lint.extend-safe-fixes = [
"UP006",
"UP007",
]
lint.isort.combine-as-imports = true
lint.isort.force-single-line = true
lint.isort.force-sort-within-sections = true
lint.isort.known-local-folder = [
"pytest",
"_pytest",
]
lint.isort.lines-after-imports = 2
lint.isort.order-by-type = false
lint.isort.required-imports = [
"from __future__ import annotations",
]
# In order to be able to format for 88 char in ruff format
max-line-length = 120
[tool.ruff.lint.pydocstyle]
convention = "pep257"
[tool.ruff.lint.isort]
force-single-line = true
combine-as-imports = true
force-sort-within-sections = true
order-by-type = false
known-local-folder = ["pytest", "_pytest"]
lines-after-imports = 2
[tool.ruff.lint.per-file-ignores]
"src/_pytest/_py/**/*.py" = ["B", "PYI"]
"src/_pytest/_version.py" = ["I001"]
"testing/python/approx.py" = ["B015"]
lint.pycodestyle.max-line-length = 120
lint.pydocstyle.convention = "pep257"
lint.pyupgrade.keep-runtime-typing = false
[tool.pylint.main]
# Maximum number of characters on a single line.
max-line-length = 120
disable= [
disable = [
"abstract-method",
"arguments-differ",
"arguments-renamed",
@@ -179,28 +190,25 @@ disable= [
"bad-mcs-method-argument",
"broad-exception-caught",
"broad-exception-raised",
"cell-var-from-loop",
"cell-var-from-loop", # B023 from ruff / flake8-bugbear
"comparison-of-constants",
"comparison-with-callable",
"comparison-with-itself",
"condition-evals-to-constant",
"consider-using-dict-items",
"consider-using-enumerate",
"consider-using-from-import",
"consider-using-f-string",
"consider-using-in",
"consider-using-sys-exit",
"consider-using-ternary",
"consider-using-with",
"cyclic-import",
"disallowed-name",
"disallowed-name", # foo / bar are used often in tests
"duplicate-code",
"eval-used",
"exec-used",
"expression-not-assigned",
"fixme",
"global-statement",
"implicit-str-concat",
"import-error",
"import-outside-toplevel",
"inconsistent-return-statements",
@@ -211,10 +219,9 @@ disable= [
"keyword-arg-before-vararg",
"line-too-long",
"method-hidden",
"misplaced-bare-raise",
"missing-docstring",
"missing-timeout",
"multiple-statements",
"multiple-statements", # multiple-statements-on-one-line-colon (E701) from ruff
"no-else-break",
"no-else-continue",
"no-else-raise",
@@ -227,6 +234,7 @@ disable= [
"pointless-exception-statement",
"pointless-statement",
"pointless-string-statement",
"possibly-used-before-assignment",
"protected-access",
"raise-missing-from",
"redefined-argument-from-local",
@@ -274,7 +282,6 @@ disable= [
"useless-else-on-loop",
"useless-import-alias",
"useless-return",
"use-maxsplit-arg",
"using-constant-test",
"wrong-import-order",
]
@@ -290,16 +297,27 @@ indent = 4
[tool.pytest.ini_options]
minversion = "2.0"
addopts = "-rfEX -p pytester --strict-markers"
python_files = ["test_*.py", "*_test.py", "testing/python/*.py"]
python_classes = ["Test", "Acceptance"]
python_functions = ["test"]
python_files = [
"test_*.py",
"*_test.py",
"testing/python/*.py",
]
python_classes = [
"Test",
"Acceptance",
]
python_functions = [
"test",
]
# NOTE: "doc" is not included here, but gets tested explicitly via "doctesting".
testpaths = ["testing"]
testpaths = [
"testing",
]
norecursedirs = [
"testing/example_scripts",
".*",
"build",
"dist",
"testing/example_scripts",
".*",
"build",
"dist",
]
xfail_strict = true
filterwarnings = [
@@ -340,6 +358,9 @@ markers = [
"foo",
"bar",
"baz",
"number_mark",
"builtin_matchers_mark",
"str_mark",
# conftest.py reorders tests moving slow ones to the end of the list
"slow",
# experimental mark for all tests using pexpect
@@ -354,49 +375,85 @@ 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"]
mypy_path = ["src"]
files = [
"src",
"testing",
"scripts",
]
mypy_path = [
"src",
]
check_untyped_defs = true
disallow_any_generics = true
disallow_untyped_defs = true

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
@@ -55,7 +54,9 @@ from _pytest.pathlib import bestrelpath
if sys.version_info < (3, 11):
from exceptiongroup import BaseExceptionGroup
_TracebackStyle = Literal["long", "short", "line", "no", "native", "value", "auto"]
TracebackStyle = Literal["long", "short", "line", "no", "native", "value", "auto"]
EXCEPTION_OR_MORE = Union[Type[Exception], Tuple[Type[Exception], ...]]
class Code:
@@ -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,10 +408,10 @@ 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
@@ -445,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:
@@ -469,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,
@@ -495,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):
@@ -510,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::
@@ -532,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
@@ -605,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):
@@ -628,15 +618,15 @@ class ExceptionInfo(Generic[E]):
def getrepr(
self,
showlocals: bool = False,
style: _TracebackStyle = "long",
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,
truncate_args: bool = True,
chain: bool = True,
) -> Union["ReprExceptionInfo", "ExceptionChainRepr"]:
) -> ReprExceptionInfo | ExceptionChainRepr:
"""Return str()able representation of this exception info.
:param bool showlocals:
@@ -665,6 +655,9 @@ class ExceptionInfo(Generic[E]):
:param bool truncate_locals:
With ``showlocals==True``, make sure locals can be safely represented as strings.
:param bool truncate_args:
With ``showargs==True``, make sure args can be safely represented as strings.
:param bool chain:
If chained exceptions in Python 3 should be shown.
@@ -691,6 +684,7 @@ class ExceptionInfo(Generic[E]):
tbfilter=tbfilter,
funcargs=funcargs,
truncate_locals=truncate_locals,
truncate_args=truncate_args,
chain=chain,
)
return fmt.repr_excinfo(self)
@@ -714,7 +708,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`.
@@ -732,9 +726,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."""
@@ -761,10 +755,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.
@@ -804,17 +798,18 @@ class FormattedExcinfo:
fail_marker: ClassVar = "E"
showlocals: bool = False
style: _TracebackStyle = "long"
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
truncate_args: 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))
@@ -829,27 +824,31 @@ 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):
args.append((argname, saferepr(argvalue)))
if self.truncate_args:
str_repr = saferepr(argvalue)
else:
str_repr = saferepr(argvalue, maxsize=None)
args.append((argname, str_repr))
return ReprFuncArgs(args)
return None
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:
@@ -878,7 +877,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.
@@ -890,7 +889,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] != "@"]
@@ -918,10 +917,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
@@ -939,7 +938,7 @@ class FormattedExcinfo:
s = self.get_source(source, line_index, excinfo, short=short)
lines.extend(s)
if short:
message = "in %s" % (entry.name)
message = f"in {entry.name}"
else:
message = excinfo and excinfo.typename or ""
entry_path = entry.path
@@ -956,7 +955,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)
@@ -966,7 +965,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)
@@ -997,7 +996,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.
@@ -1014,7 +1013,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"
@@ -1032,16 +1031,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))
@@ -1050,7 +1045,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),
@@ -1108,9 +1103,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
)
@@ -1125,13 +1120,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.
@@ -1152,8 +1145,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)
@@ -1162,9 +1155,9 @@ class ReprExceptionInfo(ExceptionRepr):
@dataclasses.dataclass(eq=False)
class ReprTraceback(TerminalRepr):
reprentries: Sequence[Union["ReprEntry", "ReprEntryNative"]]
extraline: Optional[str]
style: _TracebackStyle
reprentries: Sequence[ReprEntry | ReprEntryNative]
extraline: str | None
style: TracebackStyle
entrysep: ClassVar = "_ "
@@ -1198,7 +1191,7 @@ class ReprTracebackNative(ReprTraceback):
class ReprEntryNative(TerminalRepr):
lines: Sequence[str]
style: ClassVar[_TracebackStyle] = "native"
style: ClassVar[TracebackStyle] = "native"
def toterminal(self, tw: TerminalWriter) -> None:
tw.write("".join(self.lines))
@@ -1207,10 +1200,10 @@ class ReprEntryNative(TerminalRepr):
@dataclasses.dataclass(eq=False)
class ReprEntry(TerminalRepr):
lines: Sequence[str]
reprfuncargs: Optional["ReprFuncArgs"]
reprlocals: Optional["ReprLocals"]
reprfileloc: Optional["ReprFileLocation"]
style: _TracebackStyle
reprfuncargs: ReprFuncArgs | None
reprlocals: ReprLocals | None
reprfileloc: ReprFileLocation | None
style: TracebackStyle
def _write_entry_lines(self, tw: TerminalWriter) -> None:
"""Write the source code portions of a list of traceback entries with syntax highlighting.
@@ -1233,9 +1226,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:
@@ -1314,7 +1307,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:
@@ -1335,7 +1328,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:

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