From 5c6a9a65049a7e39cec86822e55bcf82a71b0f4c Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 25 Oct 2022 11:27:36 -0400 Subject: [PATCH 01/15] [7.2.x] upgrade pygments-pytest for 7.2.x coloring --- doc/en/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/en/requirements.txt b/doc/en/requirements.txt index a0d54cd4c1d..0523772d4b0 100644 --- a/doc/en/requirements.txt +++ b/doc/en/requirements.txt @@ -1,6 +1,6 @@ pallets-sphinx-themes pluggy>=1.0 -pygments-pytest>=2.2.0 +pygments-pytest>=2.3.0 sphinx-removed-in>=0.2.0 sphinx>=5,<6 sphinxcontrib-trio From 1f08cd72259cd9ed8c83dc0ef8fe5599972ef318 Mon Sep 17 00:00:00 2001 From: Santiago Castro Date: Tue, 25 Oct 2022 09:43:59 -0700 Subject: [PATCH 02/15] [7.2.x] Add the PyPI classifier for Python 3.11 --- .pre-commit-config.yaml | 2 +- setup.cfg | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index de612d96988..d7f522d2965 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -52,7 +52,7 @@ repos: rev: v2.1.0 hooks: - id: setup-cfg-fmt - args: ["--max-py-version=3.10", "--include-version-classifiers"] + args: ["--max-py-version=3.11", "--include-version-classifiers"] - repo: https://github.com/pre-commit/pygrep-hooks rev: v1.9.0 hooks: diff --git a/setup.cfg b/setup.cfg index 39ade4dff4c..ceb02877af5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -21,6 +21,7 @@ classifiers = Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 + Programming Language :: Python :: 3.11 Topic :: Software Development :: Libraries Topic :: Software Development :: Testing Topic :: Utilities From 651c7bf932cefbc3ab9780458bba6be7a64b11ac Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 25 Oct 2022 18:11:35 +0000 Subject: [PATCH 03/15] [7.2.x] Edit changelog for 7.2.0 (#10429) Co-authored-by: Florian Bruhin --- doc/en/changelog.rst | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/doc/en/changelog.rst b/doc/en/changelog.rst index 53ddafc52e7..e922dff71da 100644 --- a/doc/en/changelog.rst +++ b/doc/en/changelog.rst @@ -57,6 +57,7 @@ Deprecations .. _`with-setup-nose`: https://nose.readthedocs.io/en/latest/testing_tools.html?highlight=with_setup#nose.tools.with_setup +- `#7337 `_: A deprecation warning is now emitted if a test function returns something other than `None`. This prevents a common mistake among beginners that expect that returning a `bool` (for example `return foo(a, b) == result`) would cause a test to pass or fail, instead of using `assert`. The plan is to make returning non-`None` from tests an error in the future. Features @@ -79,10 +80,7 @@ Improvements - `#10381 `_: The ``--no-showlocals`` flag has been added. This can be passed directly to tests to override ``--showlocals`` declared through ``addopts``. -- `#3426 `_: Assertion failures with strings in NFC and NFD forms that normalize to the same string now have a dedicated error message detailing the issue, and their utf-8 representation is expresed instead. - - -- `#7337 `_: A warning is now emitted if a test function returns something other than `None`. This prevents a common mistake among beginners that expect that returning a `bool` (for example `return foo(a, b) == result`) would cause a test to pass or fail, instead of using `assert`. +- `#3426 `_: Assertion failures with strings in NFC and NFD forms that normalize to the same string now have a dedicated error message detailing the issue, and their utf-8 representation is expressed instead. - `#8508 `_: Introduce multiline display for warning matching via :py:func:`pytest.warns` and @@ -95,7 +93,7 @@ Improvements - `#9741 `_: On Python 3.11, use the standard library's :mod:`tomllib` to parse TOML. - :mod:`tomli`` is no longer a dependency on Python 3.11. + :mod:`tomli` is no longer a dependency on Python 3.11. - `#9742 `_: Display assertion message without escaped newline characters with ``-vv``. @@ -110,7 +108,7 @@ Improvements - `#9883 `_: Normalize the help description of all command-line options. -- `#9920 `_: Display full crash messages in ``short test summary info``, when runng in a CI environment. +- `#9920 `_: Display full crash messages in ``short test summary info``, when running in a CI environment. - `#9987 `_: Added support for hidden configuration file by allowing ``.pytest.ini`` as an alternative to ``pytest.ini``. @@ -156,9 +154,6 @@ Improved Documentation Trivial/Internal Changes ------------------------ -- `#10196 `_: :class:`~pytest.PytestReturnNotNoneWarning` is now a subclass of :class:`~pytest.PytestRemovedIn8Warning`: the plan is to make returning non-``None`` from tests an error in the future. - - - `#10313 `_: Made ``_pytest.doctest.DoctestItem`` export ``pytest.DoctestItem`` for type check and runtime purposes. Made `_pytest.doctest` use internal APIs to avoid circular imports. @@ -173,7 +168,7 @@ Trivial/Internal Changes - `#9984 `_: Improve the error message when we attempt to access a fixture that has been torn down. Add an additional sentence to the docstring explaining when it's not a good - idea to call getfixturevalue. + idea to call ``getfixturevalue``. pytest 7.1.3 (2022-08-31) From 23bbd5a628f34b1eed1a88d76bf916a7d67afe8a Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Tue, 25 Oct 2022 08:11:33 -0300 Subject: [PATCH 04/15] Merge pull request #10417 from nicoddemus/publish-action-pin Use specific tag in the gh-action-pypi-publish action --- .github/workflows/deploy.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 54c74863f84..01b6fb4089b 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -43,9 +43,8 @@ jobs: python -m build - name: Publish package to PyPI - uses: pypa/gh-action-pypi-publish@master + uses: pypa/gh-action-pypi-publish@release/v1 with: - user: __token__ password: ${{ secrets.pypi_token }} - name: Publish GitHub release notes From 6a5076db9fb81f10a1392ba3d7f15644765ddbf2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 31 Oct 2022 16:16:34 +0000 Subject: [PATCH 05/15] [7.2.x] Fix 'importlib.abc.TraversableResources' deprecation warning in Python 3.12 (#10453) Co-authored-by: Hugo van Kemenade --- changelog/10452.bugfix.rst | 1 + src/_pytest/assertion/rewrite.py | 7 ++++++- tox.ini | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 changelog/10452.bugfix.rst diff --git a/changelog/10452.bugfix.rst b/changelog/10452.bugfix.rst new file mode 100644 index 00000000000..d8f7dded455 --- /dev/null +++ b/changelog/10452.bugfix.rst @@ -0,0 +1 @@ +Fix 'importlib.abc.TraversableResources' deprecation warning in Python 3.12. diff --git a/src/_pytest/assertion/rewrite.py b/src/_pytest/assertion/rewrite.py index 63f9dd8f27b..cb64a33c078 100644 --- a/src/_pytest/assertion/rewrite.py +++ b/src/_pytest/assertion/rewrite.py @@ -275,7 +275,12 @@ def get_data(self, pathname: Union[str, bytes]) -> bytes: if sys.version_info >= (3, 10): - def get_resource_reader(self, name: str) -> importlib.abc.TraversableResources: # type: ignore + if sys.version_info >= (3, 12): + from importlib.resources.abc import TraversableResources + else: + from importlib.abc import TraversableResources + + def get_resource_reader(self, name: str) -> TraversableResources: # type: ignore if sys.version_info < (3, 11): from importlib.readers import FileReader else: diff --git a/tox.ini b/tox.ini index f04242c5c43..c80fdfcd1a4 100644 --- a/tox.ini +++ b/tox.ini @@ -9,6 +9,7 @@ envlist = py39 py310 py311 + py312 pypy3 py37-{pexpect,xdist,unittestextras,numpy,pluggymain,pylib} doctesting From b2271afa650e73585aecdcda2a18dcf90af8b7fa Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 4 Nov 2022 18:50:45 +0100 Subject: [PATCH 06/15] [7.2.x] Remove done trainings (#10472) Co-authored-by: Florian Bruhin --- doc/en/index.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/en/index.rst b/doc/en/index.rst index 60fbf99aed6..0c94d9d4625 100644 --- a/doc/en/index.rst +++ b/doc/en/index.rst @@ -2,7 +2,6 @@ .. sidebar:: Next Open Trainings - - Professionelles Testen für Python mit pytest, part of `enterPy `__ (German), `October 28th `__ (sold out) and `November 4th `__, online - `Professional Testing with Python `_, via `Python Academy `_, March 7th to 9th 2023 (3 day in-depth training), Remote and Leipzig, Germany Also see :doc:`previous talks and blogposts `. From dbd4c5fb2f7048196808bf0ac83be3f7b56bf164 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 9 Nov 2022 20:20:05 -0300 Subject: [PATCH 07/15] [7.2.x] Fix test_raising_repr test --- testing/test_assertion.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/testing/test_assertion.py b/testing/test_assertion.py index d8844f2e41d..75745922108 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -1664,15 +1664,7 @@ def test_raising_repr(): """ ) result = pytester.runpytest() - if sys.version_info >= (3, 11): - # python 3.11 has native support for un-str-able exceptions - result.stdout.fnmatch_lines( - ["E AssertionError: "] - ) - else: - result.stdout.fnmatch_lines( - ["E AssertionError: "] - ) + result.stdout.fnmatch_lines(["E AssertionError: "]) def test_issue_1944(pytester: Pytester) -> None: From f5d2edc1fc90553f1ad0e2fef7ffa8f3251acb1c Mon Sep 17 00:00:00 2001 From: Daniel Valenzuela Date: Fri, 18 Nov 2022 09:20:38 -0300 Subject: [PATCH 08/15] [7.2.x] issue-10457/show test name when skipping from fixture --- AUTHORS | 1 + changelog/10457.bugfix.rst | 1 + src/_pytest/fixtures.py | 5 +++++ testing/test_skipping.py | 21 +++++++++++++++++++++ 4 files changed, 28 insertions(+) create mode 100644 changelog/10457.bugfix.rst diff --git a/AUTHORS b/AUTHORS index 7da1f8a0c57..37272c44840 100644 --- a/AUTHORS +++ b/AUTHORS @@ -88,6 +88,7 @@ Daniel Grana Daniel Hahler Daniel Nuri Daniel Sánchez Castelló +Daniel Valenzuela Zenteno Daniel Wandschneider Daniele Procida Danielle Jenkins diff --git a/changelog/10457.bugfix.rst b/changelog/10457.bugfix.rst new file mode 100644 index 00000000000..26522e9f0e1 --- /dev/null +++ b/changelog/10457.bugfix.rst @@ -0,0 +1 @@ +If a test is skipped from inside a fixture, the test summary now shows the test location instead of the fixture location. diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index d79895c262b..7ef261b969a 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -58,6 +58,7 @@ from _pytest.mark import ParameterSet from _pytest.mark.structures import MarkDecorator from _pytest.outcomes import fail +from _pytest.outcomes import skip from _pytest.outcomes import TEST_OUTCOME from _pytest.pathlib import absolutepath from _pytest.pathlib import bestrelpath @@ -1129,6 +1130,10 @@ def pytest_fixture_setup( except TEST_OUTCOME: exc_info = sys.exc_info() assert exc_info[0] is not None + if isinstance( + exc_info[1], skip.Exception + ) and not fixturefunc.__name__.startswith("xunit_setup"): + exc_info[1]._use_item_location = True # type: ignore[attr-defined] fixturedef.cached_result = (None, my_cache_key, exc_info) raise fixturedef.cached_result = (result, my_cache_key, None) diff --git a/testing/test_skipping.py b/testing/test_skipping.py index 6415480ef4f..892ed85476b 100644 --- a/testing/test_skipping.py +++ b/testing/test_skipping.py @@ -1439,6 +1439,27 @@ def test_pass(): ) +def test_skip_from_fixture(pytester: Pytester) -> None: + pytester.makepyfile( + **{ + "tests/test_1.py": """ + import pytest + def test_pass(arg): + pass + @pytest.fixture + def arg(): + condition = True + if condition: + pytest.skip("Fixture conditional skip") + """, + } + ) + result = pytester.runpytest("-rs", "tests/test_1.py", "--rootdir=tests") + result.stdout.fnmatch_lines( + ["SKIPPED [[]1[]] tests/test_1.py:2: Fixture conditional skip"] + ) + + def test_skip_using_reason_works_ok(pytester: Pytester) -> None: p = pytester.makepyfile( """ From c3b0080c87067a057ad442dcc8caaeae3f85c88d Mon Sep 17 00:00:00 2001 From: Prerak Patel <62869089+PrerakPatelCS@users.noreply.github.com> Date: Wed, 23 Nov 2022 12:46:00 -0500 Subject: [PATCH 09/15] [7.2.x] Issue #10506 --- changelog/10506.bugfix.rst | 1 + src/_pytest/config/findpaths.py | 11 +++++++++-- testing/test_findpaths.py | 17 +++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 changelog/10506.bugfix.rst diff --git a/changelog/10506.bugfix.rst b/changelog/10506.bugfix.rst new file mode 100644 index 00000000000..6b161f69282 --- /dev/null +++ b/changelog/10506.bugfix.rst @@ -0,0 +1 @@ +Fix bug where sometimes pytest would use the file system root directory as :ref:`rootdir ` on Windows. diff --git a/src/_pytest/config/findpaths.py b/src/_pytest/config/findpaths.py index 43c2367793e..234b9e12906 100644 --- a/src/_pytest/config/findpaths.py +++ b/src/_pytest/config/findpaths.py @@ -203,8 +203,7 @@ def determine_setup( else: cwd = Path.cwd() rootdir = get_common_ancestor([cwd, ancestor]) - is_fs_root = os.path.splitdrive(str(rootdir))[1] == "/" - if is_fs_root: + if is_fs_root(rootdir): rootdir = ancestor if rootdir_cmd_arg: rootdir = absolutepath(os.path.expandvars(rootdir_cmd_arg)) @@ -216,3 +215,11 @@ def determine_setup( ) assert rootdir is not None return rootdir, inipath, inicfg or {} + + +def is_fs_root(p: Path) -> bool: + r""" + Return True if the given path is pointing to the root of the + file system ("/" on Unix and "C:\\" on Windows for example). + """ + return os.path.splitdrive(str(p))[1] == os.sep diff --git a/testing/test_findpaths.py b/testing/test_findpaths.py index 3a2917261a2..8287de603ed 100644 --- a/testing/test_findpaths.py +++ b/testing/test_findpaths.py @@ -1,3 +1,4 @@ +import os from pathlib import Path from textwrap import dedent @@ -5,6 +6,7 @@ from _pytest.config import UsageError from _pytest.config.findpaths import get_common_ancestor from _pytest.config.findpaths import get_dirs_from_args +from _pytest.config.findpaths import is_fs_root from _pytest.config.findpaths import load_config_dict_from_file @@ -133,3 +135,18 @@ def test_get_dirs_from_args(tmp_path): assert get_dirs_from_args( [str(fn), str(tmp_path / "does_not_exist"), str(d), option, xdist_rsync_option] ) == [fn.parent, d] + + +@pytest.mark.parametrize( + "path, expected", + [ + pytest.param( + f"e:{os.sep}", True, marks=pytest.mark.skipif("sys.platform != 'win32'") + ), + (f"{os.sep}", True), + (f"e:{os.sep}projects", False), + (f"{os.sep}projects", False), + ], +) +def test_is_fs_root(path: Path, expected: bool) -> None: + assert is_fs_root(Path(path)) is expected From f1989747b7d7873bd69effdc6a41ed71db8ffc4b Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 14 Dec 2022 08:57:07 -0300 Subject: [PATCH 10/15] Fix tox 4.0 support and docs Also includes pre-commit autoupdate --- .pre-commit-config.yaml | 4 ++-- .readthedocs.yml | 9 ++++++--- doc/en/explanation/goodpractices.rst | 4 ++-- doc/en/requirements.txt | 4 ++++ tox.ini | 14 +++++++++++--- 5 files changed, 25 insertions(+), 10 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d7f522d2965..df0c6e338b6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ default_language_version: python: "3.10" repos: - repo: https://github.com/psf/black - rev: 22.10.0 + rev: 22.12.0 hooks: - id: black args: [--safe, --quiet] @@ -44,7 +44,7 @@ repos: - id: reorder-python-imports args: ['--application-directories=.:src', --py37-plus] - repo: https://github.com/asottile/pyupgrade - rev: v3.1.0 + rev: v3.3.1 hooks: - id: pyupgrade args: [--py37-plus] diff --git a/.readthedocs.yml b/.readthedocs.yml index bc44d38b4c7..b506c5f4039 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -2,9 +2,12 @@ version: 2 python: install: - - requirements: doc/en/requirements.txt - - method: pip - path: . + # Install pytest first, then doc/en/requirements.txt. + # This order is important to honor any pins in doc/en/requirements.txt + # when the pinned library is also a dependency of pytest. + - method: pip + path: . + - requirements: doc/en/requirements.txt build: os: ubuntu-20.04 diff --git a/doc/en/explanation/goodpractices.rst b/doc/en/explanation/goodpractices.rst index 6b3af861a0d..6b32875d3d1 100644 --- a/doc/en/explanation/goodpractices.rst +++ b/doc/en/explanation/goodpractices.rst @@ -270,8 +270,8 @@ tox Once you are done with your work and want to make sure that your actual package passes all tests you may want to look into :doc:`tox `, the -virtualenv test automation tool and its :doc:`pytest support `. -tox helps you to setup virtualenv environments with pre-defined +virtualenv test automation tool. +``tox`` helps you to setup virtualenv environments with pre-defined dependencies and then executing a pre-configured test command with options. It will run tests against the installed package and not against your source code checkout, helping to detect packaging diff --git a/doc/en/requirements.txt b/doc/en/requirements.txt index 0523772d4b0..b6059723cd5 100644 --- a/doc/en/requirements.txt +++ b/doc/en/requirements.txt @@ -5,3 +5,7 @@ sphinx-removed-in>=0.2.0 sphinx>=5,<6 sphinxcontrib-trio sphinxcontrib-svg2pdfconverter +# Pin packaging because it no longer handles 'latest' version, which +# is the version that is assigned to the docs. +# See https://github.com/pytest-dev/pytest/pull/10578#issuecomment-1348249045. +packaging <22 diff --git a/tox.ini b/tox.ini index c80fdfcd1a4..f619287fbcb 100644 --- a/tox.ini +++ b/tox.ini @@ -30,7 +30,11 @@ commands = doctesting: {env:_PYTEST_TOX_COVERAGE_RUN:} pytest --doctest-modules --pyargs _pytest coverage: coverage combine coverage: coverage report -m -passenv = USER USERNAME COVERAGE_* PYTEST_ADDOPTS TERM SETUPTOOLS_SCM_PRETEND_VERSION_FOR_PYTEST +passenv = + COVERAGE_* + PYTEST_ADDOPTS + TERM + SETUPTOOLS_SCM_PRETEND_VERSION_FOR_PYTEST setenv = _PYTEST_TOX_DEFAULT_POSARGS={env:_PYTEST_TOX_POSARGS_DOCTESTING:} {env:_PYTEST_TOX_POSARGS_LSOF:} {env:_PYTEST_TOX_POSARGS_XDIST:} @@ -93,7 +97,8 @@ commands = [testenv:regen] changedir = doc/en basepython = python3 -passenv = SETUPTOOLS_SCM_PRETEND_VERSION_FOR_PYTEST +passenv = + SETUPTOOLS_SCM_PRETEND_VERSION_FOR_PYTEST deps = dataclasses PyYAML @@ -161,7 +166,10 @@ commands = python scripts/prepare-release-pr.py {posargs} description = create GitHub release after deployment basepython = python3 usedevelop = True -passenv = GH_RELEASE_NOTES_TOKEN GITHUB_REF GITHUB_REPOSITORY +passenv = + GH_RELEASE_NOTES_TOKEN + GITHUB_REF + GITHUB_REPOSITORY deps = github3.py pypandoc From 405fd151280eef099c5801e4671380236d9fba9e Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 5 Jan 2023 12:59:24 -0300 Subject: [PATCH 11/15] [7.2.x] Fix tests pygments 2.14.0 --- testing/conftest.py | 1 + testing/io/test_terminalwriter.py | 2 +- testing/test_terminal.py | 24 ++++++++++++------------ 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/testing/conftest.py b/testing/conftest.py index 107aad86b25..8a9816799d9 100644 --- a/testing/conftest.py +++ b/testing/conftest.py @@ -157,6 +157,7 @@ class ColorMapping: "number": "\x1b[94m", "str": "\x1b[33m", "print": "\x1b[96m", + "endline": "\x1b[90m\x1b[39;49;00m", } RE_COLORS = {k: re.escape(v) for k, v in COLORS.items()} diff --git a/testing/io/test_terminalwriter.py b/testing/io/test_terminalwriter.py index 6fe718b5341..b5a04a99f18 100644 --- a/testing/io/test_terminalwriter.py +++ b/testing/io/test_terminalwriter.py @@ -254,7 +254,7 @@ def test_combining(self) -> None: pytest.param( True, True, - "{kw}assert{hl-reset} {number}0{hl-reset}\n", + "{kw}assert{hl-reset} {number}0{hl-reset}{endline}\n", id="with markup and code_highlight", ), pytest.param( diff --git a/testing/test_terminal.py b/testing/test_terminal.py index 9de9a85f093..453f183236f 100644 --- a/testing/test_terminal.py +++ b/testing/test_terminal.py @@ -1265,14 +1265,14 @@ def test_this(): "=*= FAILURES =*=", "{red}{bold}_*_ test_this _*_{reset}", "", - " {kw}def{hl-reset} {function}test_this{hl-reset}():", - "> fail()", + " {kw}def{hl-reset} {function}test_this{hl-reset}():{endline}", + "> fail(){endline}", "", "{bold}{red}test_color_yes.py{reset}:5: ", "_ _ * _ _*", "", - " {kw}def{hl-reset} {function}fail{hl-reset}():", - "> {kw}assert{hl-reset} {number}0{hl-reset}", + " {kw}def{hl-reset} {function}fail{hl-reset}():{endline}", + "> {kw}assert{hl-reset} {number}0{hl-reset}{endline}", "{bold}{red}E assert 0{reset}", "", "{bold}{red}test_color_yes.py{reset}:2: AssertionError", @@ -1292,9 +1292,9 @@ def test_this(): "=*= FAILURES =*=", "{red}{bold}_*_ test_this _*_{reset}", "{bold}{red}test_color_yes.py{reset}:5: in test_this", - " fail()", + " fail(){endline}", "{bold}{red}test_color_yes.py{reset}:2: in fail", - " {kw}assert{hl-reset} {number}0{hl-reset}", + " {kw}assert{hl-reset} {number}0{hl-reset}{endline}", "{bold}{red}E assert 0{reset}", "{red}=*= {red}{bold}1 failed{reset}{red} in *s{reset}{red} =*={reset}", ] @@ -2472,8 +2472,8 @@ def test_foo(): result.stdout.fnmatch_lines( color_mapping.format_for_fnmatch( [ - " {kw}def{hl-reset} {function}test_foo{hl-reset}():", - "> {kw}assert{hl-reset} {number}1{hl-reset} == {number}10{hl-reset}", + " {kw}def{hl-reset} {function}test_foo{hl-reset}():{endline}", + "> {kw}assert{hl-reset} {number}1{hl-reset} == {number}10{hl-reset}{endline}", "{bold}{red}E assert 1 == 10{reset}", ] ) @@ -2494,9 +2494,9 @@ def test_foo(): result.stdout.fnmatch_lines( color_mapping.format_for_fnmatch( [ - " {kw}def{hl-reset} {function}test_foo{hl-reset}():", + " {kw}def{hl-reset} {function}test_foo{hl-reset}():{endline}", " {print}print{hl-reset}({str}'''{hl-reset}{str}{hl-reset}", - "> {str} {hl-reset}{str}'''{hl-reset}); {kw}assert{hl-reset} {number}0{hl-reset}", + "> {str} {hl-reset}{str}'''{hl-reset}); {kw}assert{hl-reset} {number}0{hl-reset}{endline}", "{bold}{red}E assert 0{reset}", ] ) @@ -2517,8 +2517,8 @@ def test_foo(): result.stdout.fnmatch_lines( color_mapping.format_for_fnmatch( [ - " {kw}def{hl-reset} {function}test_foo{hl-reset}():", - "> {kw}assert{hl-reset} {number}1{hl-reset} == {number}10{hl-reset}", + " {kw}def{hl-reset} {function}test_foo{hl-reset}():{endline}", + "> {kw}assert{hl-reset} {number}1{hl-reset} == {number}10{hl-reset}{endline}", "{bold}{red}E assert 1 == 10{reset}", ] ) From a6f85a0e3eabb07f79959455485d3a31c8526d53 Mon Sep 17 00:00:00 2001 From: Kadino Date: Fri, 6 Jan 2023 04:12:24 -0800 Subject: [PATCH 12/15] [7.2.x] Mitigate directory creation race condition --- changelog/10607.bugfix.rst | 1 + src/_pytest/junitxml.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 changelog/10607.bugfix.rst diff --git a/changelog/10607.bugfix.rst b/changelog/10607.bugfix.rst new file mode 100644 index 00000000000..e89504695c2 --- /dev/null +++ b/changelog/10607.bugfix.rst @@ -0,0 +1 @@ +Fix a race condition when creating junitxml reports, which could occur when multiple instances of pytest execute in parallel. diff --git a/src/_pytest/junitxml.py b/src/_pytest/junitxml.py index 7a5170f328b..9242d46d9df 100644 --- a/src/_pytest/junitxml.py +++ b/src/_pytest/junitxml.py @@ -645,8 +645,8 @@ def pytest_sessionstart(self) -> None: def pytest_sessionfinish(self) -> None: dirname = os.path.dirname(os.path.abspath(self.logfile)) - if not os.path.isdir(dirname): - os.makedirs(dirname) + # exist_ok avoids filesystem race conditions between checking path existence and requesting creation + os.makedirs(dirname, exist_ok=True) with open(self.logfile, "w", encoding="utf-8") as logfile: suite_stop_time = timing.time() From f22fbbf9f161e7e1d4cdf8c38bf04c57c43c1a09 Mon Sep 17 00:00:00 2001 From: s-padmanaban <73488630+s-padmanaban@users.noreply.github.com> Date: Fri, 13 Jan 2023 02:14:52 -0800 Subject: [PATCH 13/15] [7.2.x] Dont update cache from xdist worker --- AUTHORS | 1 + changelog/10641.bugfix.rst | 1 + src/_pytest/stepwise.py | 8 ++++ testing/test_stepwise.py | 77 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+) create mode 100644 changelog/10641.bugfix.rst diff --git a/AUTHORS b/AUTHORS index 37272c44840..fa99cd7dd0e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -311,6 +311,7 @@ Samuel Searles-Bryant Samuele Pedroni Sanket Duthade Sankt Petersbug +Saravanan Padmanaban Segev Finer Serhii Mozghovyi Seth Junot diff --git a/changelog/10641.bugfix.rst b/changelog/10641.bugfix.rst new file mode 100644 index 00000000000..ac293f6ae68 --- /dev/null +++ b/changelog/10641.bugfix.rst @@ -0,0 +1 @@ +Fix a race condition when creating or updating the stepwise plugin's cache, which could occur when multiple xdist worker nodes try to simultaneously update the stepwise plugin's cache. diff --git a/src/_pytest/stepwise.py b/src/_pytest/stepwise.py index 84f1a6ce8fe..74ad9dbd4dd 100644 --- a/src/_pytest/stepwise.py +++ b/src/_pytest/stepwise.py @@ -48,6 +48,10 @@ def pytest_configure(config: Config) -> None: def pytest_sessionfinish(session: Session) -> None: if not session.config.getoption("stepwise"): assert session.config.cache is not None + if hasattr(session.config, "workerinput"): + # Do not update cache if this process is a xdist worker to prevent + # race conditions (#10641). + return # Clear the list of failing tests if the plugin is not active. session.config.cache.set(STEPWISE_CACHE_DIR, []) @@ -119,4 +123,8 @@ def pytest_report_collectionfinish(self) -> Optional[str]: return None def pytest_sessionfinish(self) -> None: + if hasattr(self.config, "workerinput"): + # Do not update cache if this process is a xdist worker to prevent + # race conditions (#10641). + return self.cache.set(STEPWISE_CACHE_DIR, self.lastfailed) diff --git a/testing/test_stepwise.py b/testing/test_stepwise.py index 20781d42cce..2094abc4e50 100644 --- a/testing/test_stepwise.py +++ b/testing/test_stepwise.py @@ -1,6 +1,10 @@ +from pathlib import Path + import pytest +from _pytest.cacheprovider import Cache from _pytest.monkeypatch import MonkeyPatch from _pytest.pytester import Pytester +from _pytest.stepwise import STEPWISE_CACHE_DIR @pytest.fixture @@ -278,3 +282,76 @@ def test_three(): def test_sw_skip_help(pytester: Pytester) -> None: result = pytester.runpytest("-h") result.stdout.fnmatch_lines("*Implicitly enables --stepwise.") + + +def test_stepwise_xdist_dont_store_lastfailed(pytester: Pytester) -> None: + pytester.makefile( + ext=".ini", + pytest=f"[pytest]\ncache_dir = {pytester.path}\n", + ) + + pytester.makepyfile( + conftest=""" +import pytest + +@pytest.hookimpl(tryfirst=True) +def pytest_configure(config) -> None: + config.workerinput = True +""" + ) + pytester.makepyfile( + test_one=""" +def test_one(): + assert False +""" + ) + result = pytester.runpytest("--stepwise") + assert result.ret == pytest.ExitCode.INTERRUPTED + + stepwise_cache_file = ( + pytester.path / Cache._CACHE_PREFIX_VALUES / STEPWISE_CACHE_DIR + ) + assert not Path(stepwise_cache_file).exists() + + +def test_disabled_stepwise_xdist_dont_clear_cache(pytester: Pytester) -> None: + pytester.makefile( + ext=".ini", + pytest=f"[pytest]\ncache_dir = {pytester.path}\n", + ) + + stepwise_cache_file = ( + pytester.path / Cache._CACHE_PREFIX_VALUES / STEPWISE_CACHE_DIR + ) + stepwise_cache_dir = stepwise_cache_file.parent + stepwise_cache_dir.mkdir(exist_ok=True, parents=True) + + stepwise_cache_file_relative = f"{Cache._CACHE_PREFIX_VALUES}/{STEPWISE_CACHE_DIR}" + + expected_value = '"test_one.py::test_one"' + content = {f"{stepwise_cache_file_relative}": expected_value} + + pytester.makefile(ext="", **content) + + pytester.makepyfile( + conftest=""" +import pytest + +@pytest.hookimpl(tryfirst=True) +def pytest_configure(config) -> None: + config.workerinput = True +""" + ) + pytester.makepyfile( + test_one=""" +def test_one(): + assert True +""" + ) + result = pytester.runpytest() + assert result.ret == 0 + + assert Path(stepwise_cache_file).exists() + with stepwise_cache_file.open() as file_handle: + observed_value = file_handle.readlines() + assert [expected_value] == observed_value From e8055c16095f6481ded825eb60cb572f45cbc5fb Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 13 Jan 2023 07:15:41 -0300 Subject: [PATCH 14/15] [7.2.x] Fix regen tox environment --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index f619287fbcb..663ada60caf 100644 --- a/tox.ini +++ b/tox.ini @@ -104,7 +104,7 @@ deps = PyYAML regendoc>=0.8.1 sphinx -whitelist_externals = +allowlist_externals = make commands = make regen From 1ae778f13ec8350e224ae6a365f21cc0d83af018 Mon Sep 17 00:00:00 2001 From: pytest bot Date: Fri, 13 Jan 2023 11:01:33 +0000 Subject: [PATCH 15/15] Prepare release version 7.2.1 --- changelog/10452.bugfix.rst | 1 - changelog/10457.bugfix.rst | 1 - changelog/10506.bugfix.rst | 1 - changelog/10607.bugfix.rst | 1 - changelog/10641.bugfix.rst | 1 - doc/en/announce/index.rst | 1 + doc/en/announce/release-7.2.1.rst | 25 +++++++++++++++++++++++++ doc/en/builtin.rst | 2 +- doc/en/changelog.rst | 21 +++++++++++++++++++++ doc/en/example/parametrize.rst | 8 ++++---- doc/en/getting-started.rst | 2 +- 11 files changed, 53 insertions(+), 11 deletions(-) delete mode 100644 changelog/10452.bugfix.rst delete mode 100644 changelog/10457.bugfix.rst delete mode 100644 changelog/10506.bugfix.rst delete mode 100644 changelog/10607.bugfix.rst delete mode 100644 changelog/10641.bugfix.rst create mode 100644 doc/en/announce/release-7.2.1.rst diff --git a/changelog/10452.bugfix.rst b/changelog/10452.bugfix.rst deleted file mode 100644 index d8f7dded455..00000000000 --- a/changelog/10452.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix 'importlib.abc.TraversableResources' deprecation warning in Python 3.12. diff --git a/changelog/10457.bugfix.rst b/changelog/10457.bugfix.rst deleted file mode 100644 index 26522e9f0e1..00000000000 --- a/changelog/10457.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -If a test is skipped from inside a fixture, the test summary now shows the test location instead of the fixture location. diff --git a/changelog/10506.bugfix.rst b/changelog/10506.bugfix.rst deleted file mode 100644 index 6b161f69282..00000000000 --- a/changelog/10506.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix bug where sometimes pytest would use the file system root directory as :ref:`rootdir ` on Windows. diff --git a/changelog/10607.bugfix.rst b/changelog/10607.bugfix.rst deleted file mode 100644 index e89504695c2..00000000000 --- a/changelog/10607.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a race condition when creating junitxml reports, which could occur when multiple instances of pytest execute in parallel. diff --git a/changelog/10641.bugfix.rst b/changelog/10641.bugfix.rst deleted file mode 100644 index ac293f6ae68..00000000000 --- a/changelog/10641.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a race condition when creating or updating the stepwise plugin's cache, which could occur when multiple xdist worker nodes try to simultaneously update the stepwise plugin's cache. diff --git a/doc/en/announce/index.rst b/doc/en/announce/index.rst index 021cbd1af39..4df3228822c 100644 --- a/doc/en/announce/index.rst +++ b/doc/en/announce/index.rst @@ -6,6 +6,7 @@ Release announcements :maxdepth: 2 + release-7.2.1 release-7.2.0 release-7.1.3 release-7.1.2 diff --git a/doc/en/announce/release-7.2.1.rst b/doc/en/announce/release-7.2.1.rst new file mode 100644 index 00000000000..80ac7aff07f --- /dev/null +++ b/doc/en/announce/release-7.2.1.rst @@ -0,0 +1,25 @@ +pytest-7.2.1 +======================================= + +pytest 7.2.1 has just been released to PyPI. + +This is a bug-fix release, being a drop-in replacement. To upgrade:: + + pip install --upgrade pytest + +The full changelog is available at https://docs.pytest.org/en/stable/changelog.html. + +Thanks to all of the contributors to this release: + +* Anthony Sottile +* Bruno Oliveira +* Daniel Valenzuela +* Kadino +* Prerak Patel +* Ronny Pfannschmidt +* Santiago Castro +* s-padmanaban + + +Happy testing, +The pytest Development Team diff --git a/doc/en/builtin.rst b/doc/en/builtin.rst index 1f55ea156fc..4b6d8d84457 100644 --- a/doc/en/builtin.rst +++ b/doc/en/builtin.rst @@ -119,7 +119,7 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a For more details: :ref:`doctest_namespace`. - pytestconfig [session scope] -- .../_pytest/fixtures.py:1351 + pytestconfig [session scope] -- .../_pytest/fixtures.py:1356 Session-scoped fixture that returns the session's :class:`pytest.Config` object. diff --git a/doc/en/changelog.rst b/doc/en/changelog.rst index e922dff71da..988e083d0e5 100644 --- a/doc/en/changelog.rst +++ b/doc/en/changelog.rst @@ -28,6 +28,27 @@ with advance notice in the **Deprecations** section of releases. .. towncrier release notes start +pytest 7.2.1 (2023-01-13) +========================= + +Bug Fixes +--------- + +- `#10452 `_: Fix 'importlib.abc.TraversableResources' deprecation warning in Python 3.12. + + +- `#10457 `_: If a test is skipped from inside a fixture, the test summary now shows the test location instead of the fixture location. + + +- `#10506 `_: Fix bug where sometimes pytest would use the file system root directory as :ref:`rootdir ` on Windows. + + +- `#10607 `_: Fix a race condition when creating junitxml reports, which could occur when multiple instances of pytest execute in parallel. + + +- `#10641 `_: Fix a race condition when creating or updating the stepwise plugin's cache, which could occur when multiple xdist worker nodes try to simultaneously update the stepwise plugin's cache. + + pytest 7.2.0 (2022-10-23) ========================= diff --git a/doc/en/example/parametrize.rst b/doc/en/example/parametrize.rst index f8147683975..df2859b14e0 100644 --- a/doc/en/example/parametrize.rst +++ b/doc/en/example/parametrize.rst @@ -504,9 +504,9 @@ Running it results in some skips if we don't have all the python interpreters in . $ pytest -rs -q multipython.py sssssssssssssssssssssssssss [100%] ========================= short test summary info ========================== - SKIPPED [9] multipython.py:29: 'python3.5' not found - SKIPPED [9] multipython.py:29: 'python3.6' not found - SKIPPED [9] multipython.py:29: 'python3.7' not found + SKIPPED [9] multipython.py:69: 'python3.5' not found + SKIPPED [9] multipython.py:69: 'python3.6' not found + SKIPPED [9] multipython.py:69: 'python3.7' not found 27 skipped in 0.12s Indirect parametrization of optional implementations/imports @@ -574,7 +574,7 @@ If you run this with reporting for skips enabled: test_module.py .s [100%] ========================= short test summary info ========================== - SKIPPED [1] conftest.py:12: could not import 'opt2': No module named 'opt2' + SKIPPED [1] test_module.py:3: could not import 'opt2': No module named 'opt2' ======================= 1 passed, 1 skipped in 0.12s ======================= You'll see that we don't have an ``opt2`` module and thus the second test run diff --git a/doc/en/getting-started.rst b/doc/en/getting-started.rst index 971982c2ce8..e109839bf3e 100644 --- a/doc/en/getting-started.rst +++ b/doc/en/getting-started.rst @@ -22,7 +22,7 @@ Install ``pytest`` .. code-block:: bash $ pytest --version - pytest 7.2.0 + pytest 7.2.1 .. _`simpletest`: