From 231cb63a283fe651383a48ac158657a894f3aa28 Mon Sep 17 00:00:00 2001 From: tusenka Date: Sun, 11 May 2025 20:19:19 +0300 Subject: [PATCH 01/27] 13403: Disable assertion rewriting for external modules --- changelog/13403.bugfix.rst | 1 + src/_pytest/assertion/rewrite.py | 16 ++++++++++++++++ testing/test_assertrewrite.py | 23 +++++++++++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 changelog/13403.bugfix.rst diff --git a/changelog/13403.bugfix.rst b/changelog/13403.bugfix.rst new file mode 100644 index 00000000000..132cbfe0010 --- /dev/null +++ b/changelog/13403.bugfix.rst @@ -0,0 +1 @@ +Disable assertion rewriting of external modules diff --git a/src/_pytest/assertion/rewrite.py b/src/_pytest/assertion/rewrite.py index b07f8b24b57..9d704409e3c 100644 --- a/src/_pytest/assertion/rewrite.py +++ b/src/_pytest/assertion/rewrite.py @@ -218,6 +218,10 @@ def _early_rewrite_bailout(self, name: str, state: AssertionState) -> bool: if fnmatch_ex(pat, path): return False + root_path = self._get_root_path() + if not path.is_relative_to(root_path): + return True + if self._is_marked_for_rewrite(name, state): return False @@ -238,6 +242,10 @@ def _should_rewrite(self, name: str, fn: str, state: AssertionState) -> bool: # modules not passed explicitly on the command line are only # rewritten if they match the naming convention for test files fn_path = PurePath(fn) + root_path = self._get_root_path() + if not fn_path.is_relative_to(root_path): + return False + for pat in self.fnpats: if fnmatch_ex(pat, fn_path): state.trace(f"matched test file {fn!r}") @@ -245,6 +253,14 @@ def _should_rewrite(self, name: str, fn: str, state: AssertionState) -> bool: return self._is_marked_for_rewrite(name, state) + @staticmethod + def _get_root_path(): + try: + root_path = os.getcwd() + return root_path + except FileNotFoundError: + return os.path.dirname(os.path.abspath(sys.argv[0])) + def _is_marked_for_rewrite(self, name: str, state: AssertionState) -> bool: try: return self._marked_for_rewrite_cache[name] diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index e2e448fe5e6..c63b2ff78ee 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -22,6 +22,8 @@ from unittest import mock import zipfile +from _pytest.monkeypatch import MonkeyPatch + import _pytest._code from _pytest._io.saferepr import DEFAULT_REPR_MAX_SIZE from _pytest.assertion import util @@ -1971,6 +1973,27 @@ def test_simple_failure(): assert hook.find_spec("file") is not None assert self.find_spec_calls == ["file"] + + def test_assert_excluded_rootpath( + self, pytester: Pytester, hook: AssertionRewritingHook, monkeypatch + ) -> None: + """ + If test files contained outside rootdir, then skip them + """ + pytester.makepyfile( + **{ + "file.py": """\ + def test_simple_failure(): + assert 1 + 1 == 3 + """ + } + ) + root_path= "{0}/tests".format(os.getcwd()) + monkeypatch.setattr("os.getcwd", lambda: root_path) + with mock.patch.object(hook, "fnpats", ["*.py"]): + assert hook.find_spec("file") is None + + @pytest.mark.skipif( sys.platform.startswith("win32"), reason="cannot remove cwd on Windows" ) From bdc096c6295fae4a8db9d46373c5e25dafb011c0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 13 May 2025 03:16:21 +0000 Subject: [PATCH 02/27] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- testing/test_assertrewrite.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index c63b2ff78ee..6db7cb77f51 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -22,8 +22,6 @@ from unittest import mock import zipfile -from _pytest.monkeypatch import MonkeyPatch - import _pytest._code from _pytest._io.saferepr import DEFAULT_REPR_MAX_SIZE from _pytest.assertion import util @@ -1973,7 +1971,6 @@ def test_simple_failure(): assert hook.find_spec("file") is not None assert self.find_spec_calls == ["file"] - def test_assert_excluded_rootpath( self, pytester: Pytester, hook: AssertionRewritingHook, monkeypatch ) -> None: @@ -1988,12 +1985,11 @@ def test_simple_failure(): """ } ) - root_path= "{0}/tests".format(os.getcwd()) + root_path = f"{os.getcwd()}/tests" monkeypatch.setattr("os.getcwd", lambda: root_path) with mock.patch.object(hook, "fnpats", ["*.py"]): assert hook.find_spec("file") is None - @pytest.mark.skipif( sys.platform.startswith("win32"), reason="cannot remove cwd on Windows" ) From 0701fcb6e6c2cdf54a343bda5268cbe8a85c9cb1 Mon Sep 17 00:00:00 2001 From: tusenka Date: Tue, 13 May 2025 16:44:56 +0300 Subject: [PATCH 03/27] 13403: Disable assertion rewriting for external modules - move root path to AssertState --- src/_pytest/assertion/__init__.py | 3 ++- src/_pytest/assertion/rewrite.py | 15 +++------------ testing/test_assertrewrite.py | 4 +++- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/_pytest/assertion/__init__.py b/src/_pytest/assertion/__init__.py index 22f3ca8e258..80a8074cc71 100644 --- a/src/_pytest/assertion/__init__.py +++ b/src/_pytest/assertion/__init__.py @@ -3,6 +3,7 @@ from __future__ import annotations +import os from collections.abc import Generator import sys from typing import Any @@ -111,7 +112,7 @@ def __init__(self, config: Config, mode) -> None: self.mode = mode self.trace = config.trace.root.get("assertion") self.hook: rewrite.AssertionRewritingHook | None = None - + self.root_path=os.getcwd() def install_importhook(config: Config) -> rewrite.AssertionRewritingHook: """Try to install the rewrite hook, raise SystemError if it fails.""" diff --git a/src/_pytest/assertion/rewrite.py b/src/_pytest/assertion/rewrite.py index 9d704409e3c..783a779dbad 100644 --- a/src/_pytest/assertion/rewrite.py +++ b/src/_pytest/assertion/rewrite.py @@ -133,7 +133,7 @@ def find_spec( return importlib.util.spec_from_file_location( name, - fn, + fn , loader=self, submodule_search_locations=spec.submodule_search_locations, ) @@ -218,8 +218,7 @@ def _early_rewrite_bailout(self, name: str, state: AssertionState) -> bool: if fnmatch_ex(pat, path): return False - root_path = self._get_root_path() - if not path.is_relative_to(root_path): + if not path.is_relative_to(state.root_path): return True if self._is_marked_for_rewrite(name, state): @@ -242,8 +241,7 @@ def _should_rewrite(self, name: str, fn: str, state: AssertionState) -> bool: # modules not passed explicitly on the command line are only # rewritten if they match the naming convention for test files fn_path = PurePath(fn) - root_path = self._get_root_path() - if not fn_path.is_relative_to(root_path): + if not fn_path.is_relative_to(state.root_path): return False for pat in self.fnpats: @@ -253,13 +251,6 @@ def _should_rewrite(self, name: str, fn: str, state: AssertionState) -> bool: return self._is_marked_for_rewrite(name, state) - @staticmethod - def _get_root_path(): - try: - root_path = os.getcwd() - return root_path - except FileNotFoundError: - return os.path.dirname(os.path.abspath(sys.argv[0])) def _is_marked_for_rewrite(self, name: str, state: AssertionState) -> bool: try: diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index 6db7cb77f51..fe9c83ad646 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -12,6 +12,7 @@ import inspect import marshal import os +from os import mkdir from pathlib import Path import py_compile import re @@ -1986,7 +1987,8 @@ def test_simple_failure(): } ) root_path = f"{os.getcwd()}/tests" - monkeypatch.setattr("os.getcwd", lambda: root_path) + mkdir(root_path) + monkeypatch.chdir(root_path) with mock.patch.object(hook, "fnpats", ["*.py"]): assert hook.find_spec("file") is None From 0d0551e55569ba108ecfb1e2c797637025fcd347 Mon Sep 17 00:00:00 2001 From: tusenka Date: Sun, 11 May 2025 20:19:19 +0300 Subject: [PATCH 04/27] 13403: Disable assertion rewriting for external modules --- testing/test_assertrewrite.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index fe9c83ad646..9118abcb3bb 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -23,6 +23,8 @@ from unittest import mock import zipfile +from _pytest.monkeypatch import MonkeyPatch + import _pytest._code from _pytest._io.saferepr import DEFAULT_REPR_MAX_SIZE from _pytest.assertion import util From 3ec4da8a4806345fea4180ce1520c9ae264b7cf1 Mon Sep 17 00:00:00 2001 From: tusenka Date: Thu, 15 May 2025 08:55:59 +0300 Subject: [PATCH 05/27] 13403: Disable assertion rewriting for external modules - refactor --- src/_pytest/assertion/__init__.py | 11 ++++++++++- testing/test_assertrewrite.py | 18 ++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/_pytest/assertion/__init__.py b/src/_pytest/assertion/__init__.py index 80a8074cc71..5ce92d5b15f 100644 --- a/src/_pytest/assertion/__init__.py +++ b/src/_pytest/assertion/__init__.py @@ -112,7 +112,16 @@ def __init__(self, config: Config, mode) -> None: self.mode = mode self.trace = config.trace.root.get("assertion") self.hook: rewrite.AssertionRewritingHook | None = None - self.root_path=os.getcwd() + + @property + def root_path(self): + try: + return os.getcwd() + except FileNotFoundError: + # Fixes for py's trying to os.getcwd() on py34 + # when current working directory doesn't exist (previously triggered via xdist only). + # Ref: https://github.com/pytest-dev/py/pull/207 + return os.path.dirname(os.path.abspath(sys.argv[0])) def install_importhook(config: Config) -> rewrite.AssertionRewritingHook: """Try to install the rewrite hook, raise SystemError if it fails.""" diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index 9118abcb3bb..49256f205c4 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -1900,7 +1900,6 @@ def hook( if PathFinder.find_spec has been called. """ import importlib.machinery - self.find_spec_calls: list[str] = [] self.initial_paths: set[Path] = set() @@ -1974,6 +1973,7 @@ def test_simple_failure(): assert hook.find_spec("file") is not None assert self.find_spec_calls == ["file"] + def test_assert_excluded_rootpath( self, pytester: Pytester, hook: AssertionRewritingHook, monkeypatch ) -> None: @@ -1988,12 +1988,26 @@ def test_simple_failure(): """ } ) + with mock.patch.object(hook, "fnpats", ["*.py"]): + assert hook.find_spec("file") is not None root_path = f"{os.getcwd()}/tests" - mkdir(root_path) + + if not os.path.exists(root_path): + mkdir(root_path) monkeypatch.chdir(root_path) with mock.patch.object(hook, "fnpats", ["*.py"]): assert hook.find_spec("file") is None + + def test_assert_excluded_rewrite_for_plugins( + self, pytester: Pytester, hook: AssertionRewritingHook, monkeypatch + ) -> None: + plugins= {"ayncio", "fnpats", "pytest_bdd", "django", "mock", "pytest_twisted", "trio"} + with mock.patch.object(hook, "fnpats", ["*.py"]): + for plugin in plugins: + assert hook.find_spec(plugin) is None + + @pytest.mark.skipif( sys.platform.startswith("win32"), reason="cannot remove cwd on Windows" ) From f03f24ef9a445e5c3a680cac4e577742292824e8 Mon Sep 17 00:00:00 2001 From: tusenka Date: Fri, 16 May 2025 19:10:24 +0300 Subject: [PATCH 06/27] 13403: Disable assertion rewriting for external modules - refactor --- src/_pytest/assertion/rewrite.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/_pytest/assertion/rewrite.py b/src/_pytest/assertion/rewrite.py index 783a779dbad..f898cea2c81 100644 --- a/src/_pytest/assertion/rewrite.py +++ b/src/_pytest/assertion/rewrite.py @@ -218,12 +218,13 @@ def _early_rewrite_bailout(self, name: str, state: AssertionState) -> bool: if fnmatch_ex(pat, path): return False - if not path.is_relative_to(state.root_path): - return True if self._is_marked_for_rewrite(name, state): return False + if not path.is_relative_to(state.root_path): + return True + state.trace(f"early skip of rewriting module: {name}") return True @@ -241,11 +242,9 @@ def _should_rewrite(self, name: str, fn: str, state: AssertionState) -> bool: # modules not passed explicitly on the command line are only # rewritten if they match the naming convention for test files fn_path = PurePath(fn) - if not fn_path.is_relative_to(state.root_path): - return False for pat in self.fnpats: - if fnmatch_ex(pat, fn_path): + if fnmatch_ex(pat, fn_path) and fn_path.is_relative_to(state.root_path): state.trace(f"matched test file {fn!r}") return True From b6db3880294d714c430796fbf28d35fa8f561329 Mon Sep 17 00:00:00 2001 From: tusenka Date: Fri, 16 May 2025 19:12:34 +0300 Subject: [PATCH 07/27] 13403: Disable assertion rewriting for external modules - refactor --- src/_pytest/assertion/rewrite.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/_pytest/assertion/rewrite.py b/src/_pytest/assertion/rewrite.py index f898cea2c81..87e9522bd2e 100644 --- a/src/_pytest/assertion/rewrite.py +++ b/src/_pytest/assertion/rewrite.py @@ -222,9 +222,6 @@ def _early_rewrite_bailout(self, name: str, state: AssertionState) -> bool: if self._is_marked_for_rewrite(name, state): return False - if not path.is_relative_to(state.root_path): - return True - state.trace(f"early skip of rewriting module: {name}") return True From 13465004e6eca30e9118245376eafedfcd6f1d8a Mon Sep 17 00:00:00 2001 From: tusenka Date: Sun, 18 May 2025 06:51:36 +0300 Subject: [PATCH 08/27] 13403: Disable assertion rewriting for external modules - add tests --- src/_pytest/assertion/__init__.py | 5 ++- src/_pytest/assertion/rewrite.py | 3 +- testing/test_assertrewrite.py | 54 +++++++++++++++++++++++++------ 3 files changed, 50 insertions(+), 12 deletions(-) diff --git a/src/_pytest/assertion/__init__.py b/src/_pytest/assertion/__init__.py index 5ce92d5b15f..4195144ca20 100644 --- a/src/_pytest/assertion/__init__.py +++ b/src/_pytest/assertion/__init__.py @@ -114,7 +114,10 @@ def __init__(self, config: Config, mode) -> None: self.hook: rewrite.AssertionRewritingHook | None = None @property - def root_path(self): + def rootpath(self): + """ + get current root path (current working dir) + """ try: return os.getcwd() except FileNotFoundError: diff --git a/src/_pytest/assertion/rewrite.py b/src/_pytest/assertion/rewrite.py index 87e9522bd2e..041a111a942 100644 --- a/src/_pytest/assertion/rewrite.py +++ b/src/_pytest/assertion/rewrite.py @@ -218,7 +218,6 @@ def _early_rewrite_bailout(self, name: str, state: AssertionState) -> bool: if fnmatch_ex(pat, path): return False - if self._is_marked_for_rewrite(name, state): return False @@ -241,7 +240,7 @@ def _should_rewrite(self, name: str, fn: str, state: AssertionState) -> bool: fn_path = PurePath(fn) for pat in self.fnpats: - if fnmatch_ex(pat, fn_path) and fn_path.is_relative_to(state.root_path): + if fnmatch_ex(pat, fn_path) and fn_path.is_relative_to(state.rootpath): state.trace(f"matched test file {fn!r}") return True diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index 49256f205c4..364140e9f03 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -1974,11 +1974,11 @@ def test_simple_failure(): assert self.find_spec_calls == ["file"] - def test_assert_excluded_rootpath( + def test_assert_rewrites_only_rootpath( self, pytester: Pytester, hook: AssertionRewritingHook, monkeypatch ) -> None: """ - If test files contained outside rootdir, then skip them + If test files contained outside the rootpath, then skip them """ pytester.makepyfile( **{ @@ -1990,22 +1990,58 @@ def test_simple_failure(): ) with mock.patch.object(hook, "fnpats", ["*.py"]): assert hook.find_spec("file") is not None - root_path = f"{os.getcwd()}/tests" - if not os.path.exists(root_path): - mkdir(root_path) - monkeypatch.chdir(root_path) + rootpath = f"{os.getcwd()}/tests" + if not os.path.exists(rootpath): + mkdir(rootpath) + monkeypatch.chdir(rootpath) with mock.patch.object(hook, "fnpats", ["*.py"]): assert hook.find_spec("file") is None + def test_assert_correct_for_conftfest( + self, pytester: Pytester, hook: AssertionRewritingHook, monkeypatch + ) -> None: + """ + Conftest is always rewritten regardless of the working dir + """ + pytester.makeconftest( + """ + import pytest + @pytest.fixture + def fix(): return 1 + """ + ) + + rootpath = f"{os.getcwd()}/tests" + if not os.path.exists(rootpath): + mkdir(rootpath) + monkeypatch.chdir(rootpath) + + with mock.patch.object(hook, "fnpats", ["*.py"]): + assert hook.find_spec("conftest") is not None + + def test_assert_excluded_rewrite_for_plugins( self, pytester: Pytester, hook: AssertionRewritingHook, monkeypatch ) -> None: - plugins= {"ayncio", "fnpats", "pytest_bdd", "django", "mock", "pytest_twisted", "trio"} + pkgdir = pytester.mkpydir("plugin") + pkgdir.joinpath("__init__.py").write_text( + "import pytest\n" + "@pytest.fixture\n" + "def special_asserter():\n" + " def special_assert(x, y):\n" + " assert x == y\n" + " return special_assert\n", + encoding="utf-8", + ) + pytester.makeconftest('pytest_plugins = ["plugin"]') + rootpath = f"{os.getcwd()}/tests" + if not os.path.exists(rootpath): + mkdir(rootpath) + monkeypatch.chdir(rootpath) with mock.patch.object(hook, "fnpats", ["*.py"]): - for plugin in plugins: - assert hook.find_spec(plugin) is None + assert hook.find_spec("plugin") is not None @pytest.mark.skipif( From 023dfdbea7ca8080d232d73cd242231b28218eae Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 16 May 2025 16:13:51 +0000 Subject: [PATCH 09/27] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/_pytest/assertion/__init__.py | 3 ++- src/_pytest/assertion/rewrite.py | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/_pytest/assertion/__init__.py b/src/_pytest/assertion/__init__.py index 4195144ca20..c359d5c7b83 100644 --- a/src/_pytest/assertion/__init__.py +++ b/src/_pytest/assertion/__init__.py @@ -3,8 +3,8 @@ from __future__ import annotations -import os from collections.abc import Generator +import os import sys from typing import Any from typing import Protocol @@ -126,6 +126,7 @@ def rootpath(self): # Ref: https://github.com/pytest-dev/py/pull/207 return os.path.dirname(os.path.abspath(sys.argv[0])) + def install_importhook(config: Config) -> rewrite.AssertionRewritingHook: """Try to install the rewrite hook, raise SystemError if it fails.""" config.stash[assertstate_key] = AssertionState(config, "rewrite") diff --git a/src/_pytest/assertion/rewrite.py b/src/_pytest/assertion/rewrite.py index 041a111a942..e838bc67929 100644 --- a/src/_pytest/assertion/rewrite.py +++ b/src/_pytest/assertion/rewrite.py @@ -133,7 +133,7 @@ def find_spec( return importlib.util.spec_from_file_location( name, - fn , + fn, loader=self, submodule_search_locations=spec.submodule_search_locations, ) @@ -246,7 +246,6 @@ def _should_rewrite(self, name: str, fn: str, state: AssertionState) -> bool: return self._is_marked_for_rewrite(name, state) - def _is_marked_for_rewrite(self, name: str, state: AssertionState) -> bool: try: return self._marked_for_rewrite_cache[name] From 1fee11d00924ceaf9593006e9bc4917b1c51b9d9 Mon Sep 17 00:00:00 2001 From: tusenka Date: Mon, 19 May 2025 06:48:02 +0300 Subject: [PATCH 10/27] 13403: Disable assertion rewriting for external modules - add test for plugins --- testing/test_assertrewrite.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index 364140e9f03..775c5b2d877 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -373,6 +373,7 @@ def test_rewrites_plugin_as_a_package(self, pytester: Pytester) -> None: pytester.makeconftest('pytest_plugins = ["plugin"]') pytester.makepyfile("def test(special_asserter): special_asserter(1, 2)\n") result = pytester.runpytest() + result.stdout.fnmatch_lines(["*assert 1 == 2*"]) def test_honors_pep_235(self, pytester: Pytester, monkeypatch) -> None: @@ -1999,11 +2000,11 @@ def test_simple_failure(): assert hook.find_spec("file") is None - def test_assert_correct_for_conftfest( + def test_assert_rewrite_correct_for_conftfest( self, pytester: Pytester, hook: AssertionRewritingHook, monkeypatch ) -> None: """ - Conftest is always rewritten regardless of the working dir + Conftest is always rewritten regardless of the root dir """ pytester.makeconftest( """ @@ -2022,9 +2023,12 @@ def fix(): return 1 assert hook.find_spec("conftest") is not None - def test_assert_excluded_rewrite_for_plugins( + def test_assert_rewrite_correct_for_plugins( self, pytester: Pytester, hook: AssertionRewritingHook, monkeypatch ) -> None: + """ + Plugins has always been rewritten regardless of the root dir + """ pkgdir = pytester.mkpydir("plugin") pkgdir.joinpath("__init__.py").write_text( "import pytest\n" @@ -2035,10 +2039,10 @@ def test_assert_excluded_rewrite_for_plugins( " return special_assert\n", encoding="utf-8", ) - pytester.makeconftest('pytest_plugins = ["plugin"]') + hook.mark_rewrite("plugin") rootpath = f"{os.getcwd()}/tests" if not os.path.exists(rootpath): - mkdir(rootpath) + mkdir(rootpath) monkeypatch.chdir(rootpath) with mock.patch.object(hook, "fnpats", ["*.py"]): assert hook.find_spec("plugin") is not None From ba419634bebe50cb0f5207021b721b4a78f9fdad Mon Sep 17 00:00:00 2001 From: tusenka Date: Thu, 22 May 2025 07:11:34 +0300 Subject: [PATCH 11/27] 13403: Disable assertion rewriting for external modules - add test for plugins --- src/_pytest/assertion/__init__.py | 2 +- testing/test_assertrewrite.py | 37 +++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/_pytest/assertion/__init__.py b/src/_pytest/assertion/__init__.py index c359d5c7b83..e01e6bd55bd 100644 --- a/src/_pytest/assertion/__init__.py +++ b/src/_pytest/assertion/__init__.py @@ -124,7 +124,7 @@ def rootpath(self): # Fixes for py's trying to os.getcwd() on py34 # when current working directory doesn't exist (previously triggered via xdist only). # Ref: https://github.com/pytest-dev/py/pull/207 - return os.path.dirname(os.path.abspath(sys.argv[0])) + return os.path.abspath(os.sep) def install_importhook(config: Config) -> rewrite.AssertionRewritingHook: diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index 775c5b2d877..b1ef304951b 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -22,6 +22,7 @@ from typing import cast from unittest import mock import zipfile +from mock.mock import Mock from _pytest.monkeypatch import MonkeyPatch @@ -38,6 +39,7 @@ from _pytest.assertion.rewrite import rewrite_asserts from _pytest.config import Config from _pytest.config import ExitCode +from _pytest.monkeypatch import MonkeyPatch from _pytest.pathlib import make_numbered_dir from _pytest.pytester import Pytester import pytest @@ -1298,6 +1300,41 @@ def test_meta_path(): ) assert pytester.runpytest().ret == 0 + + def test_rootpath_base(self, pytester: Pytester, monkeypatch: MonkeyPatch) -> None: + """ + Base cases for get rootpath from AssertionState + """ + from _pytest.assertion import AssertionState + config = pytester.parseconfig() + monkeypatch.chdir(pytester.path) + state = AssertionState(config, "rewrite") + assert state.rootpath == str(pytester.path) + new_rootpath = pytester.path + "/test" + if not os.path.exists(new_rootpath): + os.mkdir(new_rootpath) + monkeypatch.chdir(new_rootpath) + state = AssertionState(config, "rewrite") + assert state.rootpath == new_rootpath + + + @pytest.mark.skipif( + sys.platform.startswith("win32"), reason="cannot remove cwd on Windows" + ) + @pytest.mark.skipif( + sys.platform.startswith("sunos5"), reason="cannot remove cwd on Solaris" + ) + def test_rootpath_cwd_removed(self, pytester: Pytester, monkeypatch: MonkeyPatch) -> None: + # Setup conditions for py's trying to os.getcwd() on py34 + # when current working directory doesn't exist (previously triggered via xdist only). + # Ref: https://github.com/pytest-dev/py/pull/207 + from _pytest.assertion import AssertionState + config = pytester.parseconfig() + monkeypatch.setattr(target=os, name="getcwd", value=Mock(side_effect=FileNotFoundError)) + state = AssertionState(config, "rewrite") + assert state.rootpath == os.path.abspath(os.sep) + + def test_write_pyc(self, pytester: Pytester, tmp_path) -> None: from _pytest.assertion import AssertionState from _pytest.assertion.rewrite import _write_pyc From 253497e461d9733ed75824463c5ce5c1e1fada49 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 04:12:42 +0000 Subject: [PATCH 12/27] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/_pytest/assertion/__init__.py | 2 +- testing/test_assertrewrite.py | 27 ++++++++++++++------------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/_pytest/assertion/__init__.py b/src/_pytest/assertion/__init__.py index e01e6bd55bd..05ded1a798b 100644 --- a/src/_pytest/assertion/__init__.py +++ b/src/_pytest/assertion/__init__.py @@ -116,7 +116,7 @@ def __init__(self, config: Config, mode) -> None: @property def rootpath(self): """ - get current root path (current working dir) + Get current root path (current working dir) """ try: return os.getcwd() diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index b1ef304951b..c66f837be02 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -22,6 +22,7 @@ from typing import cast from unittest import mock import zipfile + from mock.mock import Mock from _pytest.monkeypatch import MonkeyPatch @@ -1300,12 +1301,12 @@ def test_meta_path(): ) assert pytester.runpytest().ret == 0 - def test_rootpath_base(self, pytester: Pytester, monkeypatch: MonkeyPatch) -> None: """ Base cases for get rootpath from AssertionState """ from _pytest.assertion import AssertionState + config = pytester.parseconfig() monkeypatch.chdir(pytester.path) state = AssertionState(config, "rewrite") @@ -1317,23 +1318,26 @@ def test_rootpath_base(self, pytester: Pytester, monkeypatch: MonkeyPatch) -> No state = AssertionState(config, "rewrite") assert state.rootpath == new_rootpath - @pytest.mark.skipif( sys.platform.startswith("win32"), reason="cannot remove cwd on Windows" ) @pytest.mark.skipif( sys.platform.startswith("sunos5"), reason="cannot remove cwd on Solaris" ) - def test_rootpath_cwd_removed(self, pytester: Pytester, monkeypatch: MonkeyPatch) -> None: + def test_rootpath_cwd_removed( + self, pytester: Pytester, monkeypatch: MonkeyPatch + ) -> None: # Setup conditions for py's trying to os.getcwd() on py34 # when current working directory doesn't exist (previously triggered via xdist only). # Ref: https://github.com/pytest-dev/py/pull/207 from _pytest.assertion import AssertionState + config = pytester.parseconfig() - monkeypatch.setattr(target=os, name="getcwd", value=Mock(side_effect=FileNotFoundError)) + monkeypatch.setattr( + target=os, name="getcwd", value=Mock(side_effect=FileNotFoundError) + ) state = AssertionState(config, "rewrite") - assert state.rootpath == os.path.abspath(os.sep) - + assert state.rootpath == os.path.abspath(os.sep) def test_write_pyc(self, pytester: Pytester, tmp_path) -> None: from _pytest.assertion import AssertionState @@ -1938,6 +1942,7 @@ def hook( if PathFinder.find_spec has been called. """ import importlib.machinery + self.find_spec_calls: list[str] = [] self.initial_paths: set[Path] = set() @@ -2011,7 +2016,6 @@ def test_simple_failure(): assert hook.find_spec("file") is not None assert self.find_spec_calls == ["file"] - def test_assert_rewrites_only_rootpath( self, pytester: Pytester, hook: AssertionRewritingHook, monkeypatch ) -> None: @@ -2031,12 +2035,11 @@ def test_simple_failure(): rootpath = f"{os.getcwd()}/tests" if not os.path.exists(rootpath): - mkdir(rootpath) + mkdir(rootpath) monkeypatch.chdir(rootpath) with mock.patch.object(hook, "fnpats", ["*.py"]): assert hook.find_spec("file") is None - def test_assert_rewrite_correct_for_conftfest( self, pytester: Pytester, hook: AssertionRewritingHook, monkeypatch ) -> None: @@ -2053,12 +2056,11 @@ def fix(): return 1 rootpath = f"{os.getcwd()}/tests" if not os.path.exists(rootpath): - mkdir(rootpath) + mkdir(rootpath) monkeypatch.chdir(rootpath) with mock.patch.object(hook, "fnpats", ["*.py"]): assert hook.find_spec("conftest") is not None - def test_assert_rewrite_correct_for_plugins( self, pytester: Pytester, hook: AssertionRewritingHook, monkeypatch @@ -2079,12 +2081,11 @@ def test_assert_rewrite_correct_for_plugins( hook.mark_rewrite("plugin") rootpath = f"{os.getcwd()}/tests" if not os.path.exists(rootpath): - mkdir(rootpath) + mkdir(rootpath) monkeypatch.chdir(rootpath) with mock.patch.object(hook, "fnpats", ["*.py"]): assert hook.find_spec("plugin") is not None - @pytest.mark.skipif( sys.platform.startswith("win32"), reason="cannot remove cwd on Windows" ) From 67e7a69272ddc4eb324f6a57062969b852ca915e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 16 May 2025 16:13:51 +0000 Subject: [PATCH 13/27] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/_pytest/assertion/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/_pytest/assertion/__init__.py b/src/_pytest/assertion/__init__.py index 05ded1a798b..be570144e96 100644 --- a/src/_pytest/assertion/__init__.py +++ b/src/_pytest/assertion/__init__.py @@ -127,6 +127,7 @@ def rootpath(self): return os.path.abspath(os.sep) + def install_importhook(config: Config) -> rewrite.AssertionRewritingHook: """Try to install the rewrite hook, raise SystemError if it fails.""" config.stash[assertstate_key] = AssertionState(config, "rewrite") From ee836adb2b7d75d9e2837301ac87ebd4abf0e4b7 Mon Sep 17 00:00:00 2001 From: tusenka Date: Sat, 24 May 2025 14:15:54 +0300 Subject: [PATCH 14/27] 13403: Disable assertion rewriting for external modules - add test for plugins --- src/_pytest/assertion/__init__.py | 1 - testing/test_assertrewrite.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/_pytest/assertion/__init__.py b/src/_pytest/assertion/__init__.py index be570144e96..05ded1a798b 100644 --- a/src/_pytest/assertion/__init__.py +++ b/src/_pytest/assertion/__init__.py @@ -127,7 +127,6 @@ def rootpath(self): return os.path.abspath(os.sep) - def install_importhook(config: Config) -> rewrite.AssertionRewritingHook: """Try to install the rewrite hook, raise SystemError if it fails.""" config.stash[assertstate_key] = AssertionState(config, "rewrite") diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index c66f837be02..81b8923f642 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -1311,7 +1311,7 @@ def test_rootpath_base(self, pytester: Pytester, monkeypatch: MonkeyPatch) -> No monkeypatch.chdir(pytester.path) state = AssertionState(config, "rewrite") assert state.rootpath == str(pytester.path) - new_rootpath = pytester.path + "/test" + new_rootpath = str(pytester.path) + "/test" if not os.path.exists(new_rootpath): os.mkdir(new_rootpath) monkeypatch.chdir(new_rootpath) From e7a98bbf354a83c1702a8b11bab31b019996fea6 Mon Sep 17 00:00:00 2001 From: tusenka Date: Sun, 25 May 2025 19:04:28 +0300 Subject: [PATCH 15/27] 13403: Disable assertion rewriting for external modules - eliminate os.getcwd --- src/_pytest/assertion/__init__.py | 12 ++----- src/_pytest/pytester.py | 5 +++ testing/test_assertrewrite.py | 52 ++++++++++++++++++------------- 3 files changed, 38 insertions(+), 31 deletions(-) diff --git a/src/_pytest/assertion/__init__.py b/src/_pytest/assertion/__init__.py index 05ded1a798b..1ab3dd7891e 100644 --- a/src/_pytest/assertion/__init__.py +++ b/src/_pytest/assertion/__init__.py @@ -111,20 +111,14 @@ class AssertionState: def __init__(self, config: Config, mode) -> None: self.mode = mode self.trace = config.trace.root.get("assertion") + self.config=config self.hook: rewrite.AssertionRewritingHook | None = None @property def rootpath(self): + """Get current root path (current working dir) """ - Get current root path (current working dir) - """ - try: - return os.getcwd() - except FileNotFoundError: - # Fixes for py's trying to os.getcwd() on py34 - # when current working directory doesn't exist (previously triggered via xdist only). - # Ref: https://github.com/pytest-dev/py/pull/207 - return os.path.abspath(os.sep) + return str(self.config.invocation_params.dir) def install_importhook(config: Config) -> rewrite.AssertionRewritingHook: diff --git a/src/_pytest/pytester.py b/src/_pytest/pytester.py index 38f4643bd8b..a39ec048bc0 100644 --- a/src/_pytest/pytester.py +++ b/src/_pytest/pytester.py @@ -749,6 +749,11 @@ def chdir(self) -> None: This is done automatically upon instantiation. """ self._monkeypatch.chdir(self.path) + self._monkeypatch.setattr(self._request.config,"invocation_params", Config.InvocationParams( + args= self._request.config.invocation_params.args, + plugins=self._request.config.invocation_params.plugins, + dir=Path(self._path), + )) def _makefile( self, diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index 81b8923f642..b0a02ba980a 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -1308,13 +1308,16 @@ def test_rootpath_base(self, pytester: Pytester, monkeypatch: MonkeyPatch) -> No from _pytest.assertion import AssertionState config = pytester.parseconfig() - monkeypatch.chdir(pytester.path) state = AssertionState(config, "rewrite") - assert state.rootpath == str(pytester.path) - new_rootpath = str(pytester.path) + "/test" + assert state.rootpath == str(config.invocation_params.dir) + new_rootpath =str(pytester.path / "test") if not os.path.exists(new_rootpath): os.mkdir(new_rootpath) - monkeypatch.chdir(new_rootpath) + monkeypatch.setattr(config,"invocation_params", Config.InvocationParams( + args= (), + plugins=(), + dir=Path(new_rootpath), + )) state = AssertionState(config, "rewrite") assert state.rootpath == new_rootpath @@ -1324,20 +1327,6 @@ def test_rootpath_base(self, pytester: Pytester, monkeypatch: MonkeyPatch) -> No @pytest.mark.skipif( sys.platform.startswith("sunos5"), reason="cannot remove cwd on Solaris" ) - def test_rootpath_cwd_removed( - self, pytester: Pytester, monkeypatch: MonkeyPatch - ) -> None: - # Setup conditions for py's trying to os.getcwd() on py34 - # when current working directory doesn't exist (previously triggered via xdist only). - # Ref: https://github.com/pytest-dev/py/pull/207 - from _pytest.assertion import AssertionState - - config = pytester.parseconfig() - monkeypatch.setattr( - target=os, name="getcwd", value=Mock(side_effect=FileNotFoundError) - ) - state = AssertionState(config, "rewrite") - assert state.rootpath == os.path.abspath(os.sep) def test_write_pyc(self, pytester: Pytester, tmp_path) -> None: from _pytest.assertion import AssertionState @@ -2036,7 +2025,11 @@ def test_simple_failure(): rootpath = f"{os.getcwd()}/tests" if not os.path.exists(rootpath): mkdir(rootpath) - monkeypatch.chdir(rootpath) + monkeypatch.setattr(pytester._request.config,"invocation_params", Config.InvocationParams( + args= (), + plugins=(), + dir=Path(rootpath), + )) with mock.patch.object(hook, "fnpats", ["*.py"]): assert hook.find_spec("file") is None @@ -2057,8 +2050,15 @@ def fix(): return 1 rootpath = f"{os.getcwd()}/tests" if not os.path.exists(rootpath): mkdir(rootpath) - monkeypatch.chdir(rootpath) - + monkeypatch.setattr( + pytester._request.config, + "invocation_params", + Config.InvocationParams( + args= (), + plugins=(), + dir=Path(rootpath), + ) + ) with mock.patch.object(hook, "fnpats", ["*.py"]): assert hook.find_spec("conftest") is not None @@ -2082,7 +2082,15 @@ def test_assert_rewrite_correct_for_plugins( rootpath = f"{os.getcwd()}/tests" if not os.path.exists(rootpath): mkdir(rootpath) - monkeypatch.chdir(rootpath) + monkeypatch.setattr( + pytester._request.config, + "invocation_params", + Config.InvocationParams( + args= (), + plugins=(), + dir=Path(rootpath), + ) + ) with mock.patch.object(hook, "fnpats", ["*.py"]): assert hook.find_spec("plugin") is not None From c947f9a19463cda94bacb61a2bf43600897fa8e4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 27 May 2025 15:54:29 +0000 Subject: [PATCH 16/27] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/_pytest/assertion/__init__.py | 5 +-- src/_pytest/pytester.py | 10 +++-- testing/test_assertrewrite.py | 63 ++++++++++++++++--------------- 3 files changed, 42 insertions(+), 36 deletions(-) diff --git a/src/_pytest/assertion/__init__.py b/src/_pytest/assertion/__init__.py index 1ab3dd7891e..122838f0eab 100644 --- a/src/_pytest/assertion/__init__.py +++ b/src/_pytest/assertion/__init__.py @@ -111,13 +111,12 @@ class AssertionState: def __init__(self, config: Config, mode) -> None: self.mode = mode self.trace = config.trace.root.get("assertion") - self.config=config + self.config = config self.hook: rewrite.AssertionRewritingHook | None = None @property def rootpath(self): - """Get current root path (current working dir) - """ + """Get current root path (current working dir)""" return str(self.config.invocation_params.dir) diff --git a/src/_pytest/pytester.py b/src/_pytest/pytester.py index a39ec048bc0..eefe5ba41ee 100644 --- a/src/_pytest/pytester.py +++ b/src/_pytest/pytester.py @@ -749,11 +749,15 @@ def chdir(self) -> None: This is done automatically upon instantiation. """ self._monkeypatch.chdir(self.path) - self._monkeypatch.setattr(self._request.config,"invocation_params", Config.InvocationParams( - args= self._request.config.invocation_params.args, + self._monkeypatch.setattr( + self._request.config, + "invocation_params", + Config.InvocationParams( + args=self._request.config.invocation_params.args, plugins=self._request.config.invocation_params.plugins, dir=Path(self._path), - )) + ), + ) def _makefile( self, diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index b0a02ba980a..260e836d554 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -23,10 +23,6 @@ from unittest import mock import zipfile -from mock.mock import Mock - -from _pytest.monkeypatch import MonkeyPatch - import _pytest._code from _pytest._io.saferepr import DEFAULT_REPR_MAX_SIZE from _pytest.assertion import util @@ -1310,14 +1306,18 @@ def test_rootpath_base(self, pytester: Pytester, monkeypatch: MonkeyPatch) -> No config = pytester.parseconfig() state = AssertionState(config, "rewrite") assert state.rootpath == str(config.invocation_params.dir) - new_rootpath =str(pytester.path / "test") + new_rootpath = str(pytester.path / "test") if not os.path.exists(new_rootpath): os.mkdir(new_rootpath) - monkeypatch.setattr(config,"invocation_params", Config.InvocationParams( - args= (), - plugins=(), - dir=Path(new_rootpath), - )) + monkeypatch.setattr( + config, + "invocation_params", + Config.InvocationParams( + args=(), + plugins=(), + dir=Path(new_rootpath), + ), + ) state = AssertionState(config, "rewrite") assert state.rootpath == new_rootpath @@ -1327,7 +1327,6 @@ def test_rootpath_base(self, pytester: Pytester, monkeypatch: MonkeyPatch) -> No @pytest.mark.skipif( sys.platform.startswith("sunos5"), reason="cannot remove cwd on Solaris" ) - def test_write_pyc(self, pytester: Pytester, tmp_path) -> None: from _pytest.assertion import AssertionState from _pytest.assertion.rewrite import _write_pyc @@ -2025,11 +2024,15 @@ def test_simple_failure(): rootpath = f"{os.getcwd()}/tests" if not os.path.exists(rootpath): mkdir(rootpath) - monkeypatch.setattr(pytester._request.config,"invocation_params", Config.InvocationParams( - args= (), - plugins=(), - dir=Path(rootpath), - )) + monkeypatch.setattr( + pytester._request.config, + "invocation_params", + Config.InvocationParams( + args=(), + plugins=(), + dir=Path(rootpath), + ), + ) with mock.patch.object(hook, "fnpats", ["*.py"]): assert hook.find_spec("file") is None @@ -2051,13 +2054,13 @@ def fix(): return 1 if not os.path.exists(rootpath): mkdir(rootpath) monkeypatch.setattr( - pytester._request.config, - "invocation_params", - Config.InvocationParams( - args= (), - plugins=(), - dir=Path(rootpath), - ) + pytester._request.config, + "invocation_params", + Config.InvocationParams( + args=(), + plugins=(), + dir=Path(rootpath), + ), ) with mock.patch.object(hook, "fnpats", ["*.py"]): assert hook.find_spec("conftest") is not None @@ -2083,13 +2086,13 @@ def test_assert_rewrite_correct_for_plugins( if not os.path.exists(rootpath): mkdir(rootpath) monkeypatch.setattr( - pytester._request.config, - "invocation_params", - Config.InvocationParams( - args= (), - plugins=(), - dir=Path(rootpath), - ) + pytester._request.config, + "invocation_params", + Config.InvocationParams( + args=(), + plugins=(), + dir=Path(rootpath), + ), ) with mock.patch.object(hook, "fnpats", ["*.py"]): assert hook.find_spec("plugin") is not None From abd69acdff395b3a9ed67e8bb365653a38fdb9ef Mon Sep 17 00:00:00 2001 From: tusenka Date: Sun, 1 Jun 2025 07:18:52 +0300 Subject: [PATCH 17/27] 13403: Disable assertion rewriting for external modules - fix ruff --- src/_pytest/assertion/__init__.py | 14 ++++---------- src/_pytest/assertion/rewrite.py | 1 - testing/test_assertrewrite.py | 12 +++--------- 3 files changed, 7 insertions(+), 20 deletions(-) diff --git a/src/_pytest/assertion/__init__.py b/src/_pytest/assertion/__init__.py index 122838f0eab..73f6a013737 100644 --- a/src/_pytest/assertion/__init__.py +++ b/src/_pytest/assertion/__init__.py @@ -3,23 +3,17 @@ from __future__ import annotations -from collections.abc import Generator -import os import sys -from typing import Any +from collections.abc import Generator +from typing import Any, TYPE_CHECKING from typing import Protocol -from typing import TYPE_CHECKING -from _pytest.assertion import rewrite -from _pytest.assertion import truncate -from _pytest.assertion import util +from _pytest.assertion import rewrite, truncate, util from _pytest.assertion.rewrite import assertstate_key -from _pytest.config import Config -from _pytest.config import hookimpl +from _pytest.config import Config, hookimpl from _pytest.config.argparsing import Parser from _pytest.nodes import Item - if TYPE_CHECKING: from _pytest.main import Session diff --git a/src/_pytest/assertion/rewrite.py b/src/_pytest/assertion/rewrite.py index e838bc67929..df6171959dd 100644 --- a/src/_pytest/assertion/rewrite.py +++ b/src/_pytest/assertion/rewrite.py @@ -238,7 +238,6 @@ def _should_rewrite(self, name: str, fn: str, state: AssertionState) -> bool: # modules not passed explicitly on the command line are only # rewritten if they match the naming convention for test files fn_path = PurePath(fn) - for pat in self.fnpats: if fnmatch_ex(pat, fn_path) and fn_path.is_relative_to(state.rootpath): state.trace(f"matched test file {fn!r}") diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index 260e836d554..0439ec3c1b1 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -1298,9 +1298,7 @@ def test_meta_path(): assert pytester.runpytest().ret == 0 def test_rootpath_base(self, pytester: Pytester, monkeypatch: MonkeyPatch) -> None: - """ - Base cases for get rootpath from AssertionState - """ + """Base cases for get rootpath from AssertionState""" from _pytest.assertion import AssertionState config = pytester.parseconfig() @@ -2007,9 +2005,7 @@ def test_simple_failure(): def test_assert_rewrites_only_rootpath( self, pytester: Pytester, hook: AssertionRewritingHook, monkeypatch ) -> None: - """ - If test files contained outside the rootpath, then skip them - """ + """If test files contained outside the rootpath, then skip them""" pytester.makepyfile( **{ "file.py": """\ @@ -2039,9 +2035,7 @@ def test_simple_failure(): def test_assert_rewrite_correct_for_conftfest( self, pytester: Pytester, hook: AssertionRewritingHook, monkeypatch ) -> None: - """ - Conftest is always rewritten regardless of the root dir - """ + """Conftest is always rewritten regardless of the root dir""" pytester.makeconftest( """ import pytest From fd59d87fe3ea7730ff37428b36992439d63c426e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 1 Jun 2025 04:29:41 +0000 Subject: [PATCH 18/27] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/_pytest/assertion/__init__.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/_pytest/assertion/__init__.py b/src/_pytest/assertion/__init__.py index 73f6a013737..5a7e5fe4f58 100644 --- a/src/_pytest/assertion/__init__.py +++ b/src/_pytest/assertion/__init__.py @@ -3,17 +3,22 @@ from __future__ import annotations -import sys from collections.abc import Generator -from typing import Any, TYPE_CHECKING +import sys +from typing import Any +from typing import TYPE_CHECKING from typing import Protocol -from _pytest.assertion import rewrite, truncate, util +from _pytest.assertion import rewrite +from _pytest.assertion import truncate +from _pytest.assertion import util from _pytest.assertion.rewrite import assertstate_key -from _pytest.config import Config, hookimpl +from _pytest.config import Config +from _pytest.config import hookimpl from _pytest.config.argparsing import Parser from _pytest.nodes import Item + if TYPE_CHECKING: from _pytest.main import Session From 3da821d10979bf814fe19dbeecad560e5f599d61 Mon Sep 17 00:00:00 2001 From: Irina Date: Sun, 1 Jun 2025 18:24:49 +0300 Subject: [PATCH 19/27] Update testing/test_assertrewrite.py Co-authored-by: Bruno Oliveira --- testing/test_assertrewrite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index 0439ec3c1b1..539d76a7b46 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -2005,7 +2005,7 @@ def test_simple_failure(): def test_assert_rewrites_only_rootpath( self, pytester: Pytester, hook: AssertionRewritingHook, monkeypatch ) -> None: - """If test files contained outside the rootpath, then skip them""" + """Do not rewrite assertions in tests outside `AssertState.rootpath` (#13403).""" pytester.makepyfile( **{ "file.py": """\ From 48cfbc3e4d9acbb01c847c899935345fd55c5a94 Mon Sep 17 00:00:00 2001 From: tusenka Date: Tue, 3 Jun 2025 07:48:46 +0300 Subject: [PATCH 20/27] 13403: Disable assertion rewriting for external modules - add tests --- changelog/13403.bugfix.rst | 2 +- src/_pytest/assertion/__init__.py | 2 +- src/_pytest/assertion/rewrite.py | 2 +- src/_pytest/helpconfig.py | 2 +- testing/example_scripts/rewrite/pytest.ini | 2 ++ .../example_scripts/rewrite/some_plugin/__init__.py | 7 +++++++ testing/example_scripts/rewrite/src/__init__.py | 0 testing/example_scripts/rewrite/src/main.py | 4 ++++ testing/example_scripts/rewrite/tests/__init__.py | 0 testing/example_scripts/rewrite/tests/conftest.py | 12 ++++++++++++ testing/example_scripts/rewrite/tests/test_main.py | 10 ++++++++++ .../site-packages/external_lib/__init__.py | 0 .../site-packages/external_lib/external_lib.py | 3 +++ testing/example_scripts/rewrite/venv/pyvenv.cfg | 5 +++++ testing/test_assertrewrite.py | 12 +++++------- 15 files changed, 52 insertions(+), 11 deletions(-) create mode 100644 testing/example_scripts/rewrite/pytest.ini create mode 100644 testing/example_scripts/rewrite/some_plugin/__init__.py create mode 100644 testing/example_scripts/rewrite/src/__init__.py create mode 100644 testing/example_scripts/rewrite/src/main.py create mode 100644 testing/example_scripts/rewrite/tests/__init__.py create mode 100644 testing/example_scripts/rewrite/tests/conftest.py create mode 100644 testing/example_scripts/rewrite/tests/test_main.py create mode 100644 testing/example_scripts/rewrite/venv/lib64/python3.11/site-packages/external_lib/__init__.py create mode 100644 testing/example_scripts/rewrite/venv/lib64/python3.11/site-packages/external_lib/external_lib.py create mode 100644 testing/example_scripts/rewrite/venv/pyvenv.cfg diff --git a/changelog/13403.bugfix.rst b/changelog/13403.bugfix.rst index 132cbfe0010..8b3cb7d92b4 100644 --- a/changelog/13403.bugfix.rst +++ b/changelog/13403.bugfix.rst @@ -1 +1 @@ -Disable assertion rewriting of external modules +Disable assertion for modules outside current working dir(cwd) diff --git a/src/_pytest/assertion/__init__.py b/src/_pytest/assertion/__init__.py index 5a7e5fe4f58..67b153e5c40 100644 --- a/src/_pytest/assertion/__init__.py +++ b/src/_pytest/assertion/__init__.py @@ -114,7 +114,7 @@ def __init__(self, config: Config, mode) -> None: self.hook: rewrite.AssertionRewritingHook | None = None @property - def rootpath(self): + def invocation_path( self ): """Get current root path (current working dir)""" return str(self.config.invocation_params.dir) diff --git a/src/_pytest/assertion/rewrite.py b/src/_pytest/assertion/rewrite.py index df6171959dd..8bc0ec85cff 100644 --- a/src/_pytest/assertion/rewrite.py +++ b/src/_pytest/assertion/rewrite.py @@ -239,7 +239,7 @@ def _should_rewrite(self, name: str, fn: str, state: AssertionState) -> bool: # rewritten if they match the naming convention for test files fn_path = PurePath(fn) for pat in self.fnpats: - if fnmatch_ex(pat, fn_path) and fn_path.is_relative_to(state.rootpath): + if fnmatch_ex(pat, fn_path) and fn_path.is_relative_to( state.invocation_path ): state.trace(f"matched test file {fn!r}") return True diff --git a/src/_pytest/helpconfig.py b/src/_pytest/helpconfig.py index b5ac0e6a50c..d584810d2ad 100644 --- a/src/_pytest/helpconfig.py +++ b/src/_pytest/helpconfig.py @@ -87,7 +87,7 @@ def pytest_addoption(parser: Parser) -> None: help="Trace considerations of conftest.py files", ) group.addoption( - "--debug", + "--debug", action="store", nargs="?", const="pytestdebug.log", diff --git a/testing/example_scripts/rewrite/pytest.ini b/testing/example_scripts/rewrite/pytest.ini new file mode 100644 index 00000000000..5f5fa6afde9 --- /dev/null +++ b/testing/example_scripts/rewrite/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +python_files = *.py \ No newline at end of file diff --git a/testing/example_scripts/rewrite/some_plugin/__init__.py b/testing/example_scripts/rewrite/some_plugin/__init__.py new file mode 100644 index 00000000000..b68fdcc9b75 --- /dev/null +++ b/testing/example_scripts/rewrite/some_plugin/__init__.py @@ -0,0 +1,7 @@ +import pytest + +@pytest.fixture +def special_asserter(): + def special_assert(x, y): + assert {'x': x} == {'x': y} + return special_assert \ No newline at end of file diff --git a/testing/example_scripts/rewrite/src/__init__.py b/testing/example_scripts/rewrite/src/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testing/example_scripts/rewrite/src/main.py b/testing/example_scripts/rewrite/src/main.py new file mode 100644 index 00000000000..7d328a0e844 --- /dev/null +++ b/testing/example_scripts/rewrite/src/main.py @@ -0,0 +1,4 @@ +def func(x: int, y: int): + assert x>0 + assert y>0 + return 0 if x == y else 1 if x>y else -1 \ No newline at end of file diff --git a/testing/example_scripts/rewrite/tests/__init__.py b/testing/example_scripts/rewrite/tests/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testing/example_scripts/rewrite/tests/conftest.py b/testing/example_scripts/rewrite/tests/conftest.py new file mode 100644 index 00000000000..373213f3ed9 --- /dev/null +++ b/testing/example_scripts/rewrite/tests/conftest.py @@ -0,0 +1,12 @@ +from _pytest.fixtures import fixture + +pytest_plugins = ["pytester", "some_plugin"] + + +@fixture +def b(): + return 1 + +@fixture +def a(): + return 2 diff --git a/testing/example_scripts/rewrite/tests/test_main.py b/testing/example_scripts/rewrite/tests/test_main.py new file mode 100644 index 00000000000..330b6e2c417 --- /dev/null +++ b/testing/example_scripts/rewrite/tests/test_main.py @@ -0,0 +1,10 @@ +from typing import Callable + +from testing.example_scripts.rewrite.src.main import func + + +def test_plugin(a: int, b: int, special_asserter: Callable[[int, int], bool]): + special_asserter(a, b) + +def test_func(a: int, b: int, special_asserter: Callable[[int, int], bool]): + assert {'res': func(a, b)} == {'res': 0} \ No newline at end of file diff --git a/testing/example_scripts/rewrite/venv/lib64/python3.11/site-packages/external_lib/__init__.py b/testing/example_scripts/rewrite/venv/lib64/python3.11/site-packages/external_lib/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testing/example_scripts/rewrite/venv/lib64/python3.11/site-packages/external_lib/external_lib.py b/testing/example_scripts/rewrite/venv/lib64/python3.11/site-packages/external_lib/external_lib.py new file mode 100644 index 00000000000..ea6f9c1fcd8 --- /dev/null +++ b/testing/example_scripts/rewrite/venv/lib64/python3.11/site-packages/external_lib/external_lib.py @@ -0,0 +1,3 @@ +def some_check(a: int): + assert abs(a)<2 + return a in set(0, 1, -1) \ No newline at end of file diff --git a/testing/example_scripts/rewrite/venv/pyvenv.cfg b/testing/example_scripts/rewrite/venv/pyvenv.cfg new file mode 100644 index 00000000000..40596f6c142 --- /dev/null +++ b/testing/example_scripts/rewrite/venv/pyvenv.cfg @@ -0,0 +1,5 @@ +home = /usr/bin +include-system-site-packages = false +version = 3.11.0 +executable = /usr/bin/python3.11 +command = /home/cas12/PycharmProjects/pytest-play/.venv/bin/python3 -m venv /home/cas12/PycharmProjects/pytest-play/testing/example_scripts/rewrite/venv diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index 539d76a7b46..b5484b65661 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -1297,13 +1297,13 @@ def test_meta_path(): ) assert pytester.runpytest().ret == 0 - def test_rootpath_base(self, pytester: Pytester, monkeypatch: MonkeyPatch) -> None: - """Base cases for get rootpath from AssertionState""" + def test_invocation_dir(self, pytester: Pytester, monkeypatch: MonkeyPatch) -> None: + """Test get invocation param afrom AssertionState""" from _pytest.assertion import AssertionState config = pytester.parseconfig() state = AssertionState(config, "rewrite") - assert state.rootpath == str(config.invocation_params.dir) + assert state.invocation_path == str( config.invocation_params.dir ) new_rootpath = str(pytester.path / "test") if not os.path.exists(new_rootpath): os.mkdir(new_rootpath) @@ -1317,7 +1317,7 @@ def test_rootpath_base(self, pytester: Pytester, monkeypatch: MonkeyPatch) -> No ), ) state = AssertionState(config, "rewrite") - assert state.rootpath == new_rootpath + assert state.invocation_path == new_rootpath @pytest.mark.skipif( sys.platform.startswith("win32"), reason="cannot remove cwd on Windows" @@ -2062,9 +2062,7 @@ def fix(): return 1 def test_assert_rewrite_correct_for_plugins( self, pytester: Pytester, hook: AssertionRewritingHook, monkeypatch ) -> None: - """ - Plugins has always been rewritten regardless of the root dir - """ + """Plugins has always been rewritten regardless of the root dir""" pkgdir = pytester.mkpydir("plugin") pkgdir.joinpath("__init__.py").write_text( "import pytest\n" From eceae2e9262923bafa4ecb41b3541065011f76d2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 12 Jun 2025 06:02:30 +0000 Subject: [PATCH 21/27] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/_pytest/assertion/__init__.py | 2 +- src/_pytest/assertion/rewrite.py | 4 +++- src/_pytest/helpconfig.py | 2 +- testing/example_scripts/rewrite/pytest.ini | 2 +- testing/example_scripts/rewrite/some_plugin/__init__.py | 8 ++++++-- testing/example_scripts/rewrite/src/main.py | 9 ++++++--- testing/example_scripts/rewrite/tests/conftest.py | 4 ++++ testing/example_scripts/rewrite/tests/test_main.py | 5 ++++- .../site-packages/external_lib/external_lib.py | 2 +- testing/test_assertrewrite.py | 2 +- 10 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/_pytest/assertion/__init__.py b/src/_pytest/assertion/__init__.py index 67b153e5c40..d99b8357365 100644 --- a/src/_pytest/assertion/__init__.py +++ b/src/_pytest/assertion/__init__.py @@ -114,7 +114,7 @@ def __init__(self, config: Config, mode) -> None: self.hook: rewrite.AssertionRewritingHook | None = None @property - def invocation_path( self ): + def invocation_path(self): """Get current root path (current working dir)""" return str(self.config.invocation_params.dir) diff --git a/src/_pytest/assertion/rewrite.py b/src/_pytest/assertion/rewrite.py index 8bc0ec85cff..d8dcbb91e41 100644 --- a/src/_pytest/assertion/rewrite.py +++ b/src/_pytest/assertion/rewrite.py @@ -239,7 +239,9 @@ def _should_rewrite(self, name: str, fn: str, state: AssertionState) -> bool: # rewritten if they match the naming convention for test files fn_path = PurePath(fn) for pat in self.fnpats: - if fnmatch_ex(pat, fn_path) and fn_path.is_relative_to( state.invocation_path ): + if fnmatch_ex(pat, fn_path) and fn_path.is_relative_to( + state.invocation_path + ): state.trace(f"matched test file {fn!r}") return True diff --git a/src/_pytest/helpconfig.py b/src/_pytest/helpconfig.py index d584810d2ad..b5ac0e6a50c 100644 --- a/src/_pytest/helpconfig.py +++ b/src/_pytest/helpconfig.py @@ -87,7 +87,7 @@ def pytest_addoption(parser: Parser) -> None: help="Trace considerations of conftest.py files", ) group.addoption( - "--debug", + "--debug", action="store", nargs="?", const="pytestdebug.log", diff --git a/testing/example_scripts/rewrite/pytest.ini b/testing/example_scripts/rewrite/pytest.ini index 5f5fa6afde9..7c479554025 100644 --- a/testing/example_scripts/rewrite/pytest.ini +++ b/testing/example_scripts/rewrite/pytest.ini @@ -1,2 +1,2 @@ [pytest] -python_files = *.py \ No newline at end of file +python_files = *.py diff --git a/testing/example_scripts/rewrite/some_plugin/__init__.py b/testing/example_scripts/rewrite/some_plugin/__init__.py index b68fdcc9b75..78907bea437 100644 --- a/testing/example_scripts/rewrite/some_plugin/__init__.py +++ b/testing/example_scripts/rewrite/some_plugin/__init__.py @@ -1,7 +1,11 @@ +from __future__ import annotations + import pytest + @pytest.fixture def special_asserter(): def special_assert(x, y): - assert {'x': x} == {'x': y} - return special_assert \ No newline at end of file + assert {"x": x} == {"x": y} + + return special_assert diff --git a/testing/example_scripts/rewrite/src/main.py b/testing/example_scripts/rewrite/src/main.py index 7d328a0e844..223f2c1374f 100644 --- a/testing/example_scripts/rewrite/src/main.py +++ b/testing/example_scripts/rewrite/src/main.py @@ -1,4 +1,7 @@ +from __future__ import annotations + + def func(x: int, y: int): - assert x>0 - assert y>0 - return 0 if x == y else 1 if x>y else -1 \ No newline at end of file + assert x > 0 + assert y > 0 + return 0 if x == y else 1 if x > y else -1 diff --git a/testing/example_scripts/rewrite/tests/conftest.py b/testing/example_scripts/rewrite/tests/conftest.py index 373213f3ed9..484da9202c1 100644 --- a/testing/example_scripts/rewrite/tests/conftest.py +++ b/testing/example_scripts/rewrite/tests/conftest.py @@ -1,5 +1,8 @@ +from __future__ import annotations + from _pytest.fixtures import fixture + pytest_plugins = ["pytester", "some_plugin"] @@ -7,6 +10,7 @@ def b(): return 1 + @fixture def a(): return 2 diff --git a/testing/example_scripts/rewrite/tests/test_main.py b/testing/example_scripts/rewrite/tests/test_main.py index 330b6e2c417..8b33575fa1d 100644 --- a/testing/example_scripts/rewrite/tests/test_main.py +++ b/testing/example_scripts/rewrite/tests/test_main.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from typing import Callable from testing.example_scripts.rewrite.src.main import func @@ -6,5 +8,6 @@ def test_plugin(a: int, b: int, special_asserter: Callable[[int, int], bool]): special_asserter(a, b) + def test_func(a: int, b: int, special_asserter: Callable[[int, int], bool]): - assert {'res': func(a, b)} == {'res': 0} \ No newline at end of file + assert {"res": func(a, b)} == {"res": 0} diff --git a/testing/example_scripts/rewrite/venv/lib64/python3.11/site-packages/external_lib/external_lib.py b/testing/example_scripts/rewrite/venv/lib64/python3.11/site-packages/external_lib/external_lib.py index ea6f9c1fcd8..80663d59a5a 100644 --- a/testing/example_scripts/rewrite/venv/lib64/python3.11/site-packages/external_lib/external_lib.py +++ b/testing/example_scripts/rewrite/venv/lib64/python3.11/site-packages/external_lib/external_lib.py @@ -1,3 +1,3 @@ def some_check(a: int): assert abs(a)<2 - return a in set(0, 1, -1) \ No newline at end of file + return a in set(0, 1, -1) diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index b5484b65661..96c6418ba59 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -1303,7 +1303,7 @@ def test_invocation_dir(self, pytester: Pytester, monkeypatch: MonkeyPatch) -> N config = pytester.parseconfig() state = AssertionState(config, "rewrite") - assert state.invocation_path == str( config.invocation_params.dir ) + assert state.invocation_path == str(config.invocation_params.dir) new_rootpath = str(pytester.path / "test") if not os.path.exists(new_rootpath): os.mkdir(new_rootpath) From 8c95bcdd0e64e5e4e40611c07bf5ddc01a8a6390 Mon Sep 17 00:00:00 2001 From: tusenka Date: Thu, 12 Jun 2025 09:21:26 +0300 Subject: [PATCH 22/27] 13403: Disable assertion rewriting for external modules - add tests --- src/_pytest/pytester.py | 7 ++- testing/example_scripts/rewrite/src/main.py | 4 +- testing/test_assertrewrite.py | 57 --------------------- 3 files changed, 4 insertions(+), 64 deletions(-) diff --git a/src/_pytest/pytester.py b/src/_pytest/pytester.py index eefe5ba41ee..4cb801a242e 100644 --- a/src/_pytest/pytester.py +++ b/src/_pytest/pytester.py @@ -12,6 +12,7 @@ from collections.abc import Iterable from collections.abc import Sequence import contextlib +import dataclasses from fnmatch import fnmatch import gc import importlib @@ -752,10 +753,8 @@ def chdir(self) -> None: self._monkeypatch.setattr( self._request.config, "invocation_params", - Config.InvocationParams( - args=self._request.config.invocation_params.args, - plugins=self._request.config.invocation_params.plugins, - dir=Path(self._path), + dataclasses.replace( + self._request.config.invocation_params, dir=Path(self._path) ), ) diff --git a/testing/example_scripts/rewrite/src/main.py b/testing/example_scripts/rewrite/src/main.py index 223f2c1374f..21901e04f54 100644 --- a/testing/example_scripts/rewrite/src/main.py +++ b/testing/example_scripts/rewrite/src/main.py @@ -1,7 +1,5 @@ from __future__ import annotations -def func(x: int, y: int): - assert x > 0 - assert y > 0 +def func(x: int, y: int) -> int: return 0 if x == y else 1 if x > y else -1 diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index 96c6418ba59..5c4e8887bf7 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -2032,63 +2032,6 @@ def test_simple_failure(): with mock.patch.object(hook, "fnpats", ["*.py"]): assert hook.find_spec("file") is None - def test_assert_rewrite_correct_for_conftfest( - self, pytester: Pytester, hook: AssertionRewritingHook, monkeypatch - ) -> None: - """Conftest is always rewritten regardless of the root dir""" - pytester.makeconftest( - """ - import pytest - @pytest.fixture - def fix(): return 1 - """ - ) - - rootpath = f"{os.getcwd()}/tests" - if not os.path.exists(rootpath): - mkdir(rootpath) - monkeypatch.setattr( - pytester._request.config, - "invocation_params", - Config.InvocationParams( - args=(), - plugins=(), - dir=Path(rootpath), - ), - ) - with mock.patch.object(hook, "fnpats", ["*.py"]): - assert hook.find_spec("conftest") is not None - - def test_assert_rewrite_correct_for_plugins( - self, pytester: Pytester, hook: AssertionRewritingHook, monkeypatch - ) -> None: - """Plugins has always been rewritten regardless of the root dir""" - pkgdir = pytester.mkpydir("plugin") - pkgdir.joinpath("__init__.py").write_text( - "import pytest\n" - "@pytest.fixture\n" - "def special_asserter():\n" - " def special_assert(x, y):\n" - " assert x == y\n" - " return special_assert\n", - encoding="utf-8", - ) - hook.mark_rewrite("plugin") - rootpath = f"{os.getcwd()}/tests" - if not os.path.exists(rootpath): - mkdir(rootpath) - monkeypatch.setattr( - pytester._request.config, - "invocation_params", - Config.InvocationParams( - args=(), - plugins=(), - dir=Path(rootpath), - ), - ) - with mock.patch.object(hook, "fnpats", ["*.py"]): - assert hook.find_spec("plugin") is not None - @pytest.mark.skipif( sys.platform.startswith("win32"), reason="cannot remove cwd on Windows" ) From 1d5a612695f26919e4e41c1c9b4ec0f92bf06926 Mon Sep 17 00:00:00 2001 From: tusenka Date: Thu, 12 Jun 2025 09:52:23 +0300 Subject: [PATCH 23/27] 13403: Disable assertion rewriting for external modules - add tests --- testing/example_scripts/rewrite/src/main.py | 4 ++++ testing/example_scripts/rewrite/venv/pyvenv.cfg | 5 ----- 2 files changed, 4 insertions(+), 5 deletions(-) delete mode 100644 testing/example_scripts/rewrite/venv/pyvenv.cfg diff --git a/testing/example_scripts/rewrite/src/main.py b/testing/example_scripts/rewrite/src/main.py index 21901e04f54..b76c92bc424 100644 --- a/testing/example_scripts/rewrite/src/main.py +++ b/testing/example_scripts/rewrite/src/main.py @@ -1,5 +1,9 @@ +"""Stub file for testing""" + from __future__ import annotations def func(x: int, y: int) -> int: + """Stub function""" + assert (x) > 0 return 0 if x == y else 1 if x > y else -1 diff --git a/testing/example_scripts/rewrite/venv/pyvenv.cfg b/testing/example_scripts/rewrite/venv/pyvenv.cfg deleted file mode 100644 index 40596f6c142..00000000000 --- a/testing/example_scripts/rewrite/venv/pyvenv.cfg +++ /dev/null @@ -1,5 +0,0 @@ -home = /usr/bin -include-system-site-packages = false -version = 3.11.0 -executable = /usr/bin/python3.11 -command = /home/cas12/PycharmProjects/pytest-play/.venv/bin/python3 -m venv /home/cas12/PycharmProjects/pytest-play/testing/example_scripts/rewrite/venv From c1f377213c3ade1e57532f6c8f83d412b3b653e7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 13 Jun 2025 05:00:49 +0000 Subject: [PATCH 24/27] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/_pytest/assertion/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_pytest/assertion/__init__.py b/src/_pytest/assertion/__init__.py index d99b8357365..38b7bb7ef42 100644 --- a/src/_pytest/assertion/__init__.py +++ b/src/_pytest/assertion/__init__.py @@ -6,8 +6,8 @@ from collections.abc import Generator import sys from typing import Any -from typing import TYPE_CHECKING from typing import Protocol +from typing import TYPE_CHECKING from _pytest.assertion import rewrite from _pytest.assertion import truncate From edcf48462e48718d6016d488b22378b7e93970c8 Mon Sep 17 00:00:00 2001 From: tusenka Date: Fri, 13 Jun 2025 09:21:54 +0300 Subject: [PATCH 25/27] 13403: Disable assertion rewriting for external modules - refactor AssertionStatus --- src/_pytest/assertion/__init__.py | 7 +------ src/_pytest/pytester.py | 8 ++------ 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/_pytest/assertion/__init__.py b/src/_pytest/assertion/__init__.py index 38b7bb7ef42..a205dbaf032 100644 --- a/src/_pytest/assertion/__init__.py +++ b/src/_pytest/assertion/__init__.py @@ -110,14 +110,9 @@ class AssertionState: def __init__(self, config: Config, mode) -> None: self.mode = mode self.trace = config.trace.root.get("assertion") - self.config = config + self.invocation_path = str(config.invocation_params.dir) self.hook: rewrite.AssertionRewritingHook | None = None - @property - def invocation_path(self): - """Get current root path (current working dir)""" - return str(self.config.invocation_params.dir) - def install_importhook(config: Config) -> rewrite.AssertionRewritingHook: """Try to install the rewrite hook, raise SystemError if it fails.""" diff --git a/src/_pytest/pytester.py b/src/_pytest/pytester.py index 4cb801a242e..760d22050dd 100644 --- a/src/_pytest/pytester.py +++ b/src/_pytest/pytester.py @@ -12,7 +12,6 @@ from collections.abc import Iterable from collections.abc import Sequence import contextlib -import dataclasses from fnmatch import fnmatch import gc import importlib @@ -41,6 +40,7 @@ from _pytest import timing from _pytest._code import Source +from _pytest.assertion.rewrite import assertstate_key from _pytest.capture import _get_multicapture from _pytest.compat import NOTSET from _pytest.compat import NotSetType @@ -751,11 +751,7 @@ def chdir(self) -> None: """ self._monkeypatch.chdir(self.path) self._monkeypatch.setattr( - self._request.config, - "invocation_params", - dataclasses.replace( - self._request.config.invocation_params, dir=Path(self._path) - ), + self._request.config.stash[assertstate_key], "invocation_path", self.path ) def _makefile( From 511684193b1a8812c27be512bd5363ca735c2fd3 Mon Sep 17 00:00:00 2001 From: tusenka Date: Sun, 15 Jun 2025 14:42:43 +0300 Subject: [PATCH 26/27] 13403: Disable assertion rewriting for external modules - refactor AssertionStatus --- testing/test_assertrewrite.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index 5c4e8887bf7..832ed5760f2 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -30,6 +30,7 @@ from _pytest.assertion.rewrite import _get_maxsize_for_saferepr from _pytest.assertion.rewrite import _saferepr from _pytest.assertion.rewrite import AssertionRewritingHook +from _pytest.assertion.rewrite import assertstate_key from _pytest.assertion.rewrite import get_cache_dir from _pytest.assertion.rewrite import PYC_TAIL from _pytest.assertion.rewrite import PYTEST_TAG @@ -2002,7 +2003,7 @@ def test_simple_failure(): assert hook.find_spec("file") is not None assert self.find_spec_calls == ["file"] - def test_assert_rewrites_only_rootpath( + def test_assert_rewrites_only_invocation_path( self, pytester: Pytester, hook: AssertionRewritingHook, monkeypatch ) -> None: """Do not rewrite assertions in tests outside `AssertState.rootpath` (#13403).""" @@ -2014,21 +2015,19 @@ def test_simple_failure(): """ } ) + with mock.patch.object(hook, "fnpats", ["*.py"]): assert hook.find_spec("file") is not None - rootpath = f"{os.getcwd()}/tests" - if not os.path.exists(rootpath): - mkdir(rootpath) + invocation_path = f"{os.getcwd()}/tests" + if not os.path.exists(invocation_path): + mkdir(invocation_path) monkeypatch.setattr( - pytester._request.config, - "invocation_params", - Config.InvocationParams( - args=(), - plugins=(), - dir=Path(rootpath), - ), + pytester._request.config.stash[assertstate_key], + "invocation_path", + invocation_path, ) + with mock.patch.object(hook, "fnpats", ["*.py"]): assert hook.find_spec("file") is None From 6a67526d90e44eacb368f92297b870f16ef9db0b Mon Sep 17 00:00:00 2001 From: tusenka Date: Mon, 16 Jun 2025 19:23:43 +0300 Subject: [PATCH 27/27] 13403: Disable assertion rewriting for external modules - refactor AssertionStatus --- testing/test_assertrewrite.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index 832ed5760f2..bbbc9a3f0e5 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -12,7 +12,6 @@ import inspect import marshal import os -from os import mkdir from pathlib import Path import py_compile import re @@ -1299,13 +1298,15 @@ def test_meta_path(): assert pytester.runpytest().ret == 0 def test_invocation_dir(self, pytester: Pytester, monkeypatch: MonkeyPatch) -> None: - """Test get invocation param afrom AssertionState""" + """Test get invocation param from AssertionState""" from _pytest.assertion import AssertionState config = pytester.parseconfig() state = AssertionState(config, "rewrite") + assert state.invocation_path == str(config.invocation_params.dir) - new_rootpath = str(pytester.path / "test") + + new_rootpath = pytester.path / "test" if not os.path.exists(new_rootpath): os.mkdir(new_rootpath) monkeypatch.setattr( @@ -1314,11 +1315,11 @@ def test_invocation_dir(self, pytester: Pytester, monkeypatch: MonkeyPatch) -> N Config.InvocationParams( args=(), plugins=(), - dir=Path(new_rootpath), + dir=new_rootpath, ), ) state = AssertionState(config, "rewrite") - assert state.invocation_path == new_rootpath + assert state.invocation_path == str(new_rootpath) @pytest.mark.skipif( sys.platform.startswith("win32"), reason="cannot remove cwd on Windows" @@ -2020,8 +2021,6 @@ def test_simple_failure(): assert hook.find_spec("file") is not None invocation_path = f"{os.getcwd()}/tests" - if not os.path.exists(invocation_path): - mkdir(invocation_path) monkeypatch.setattr( pytester._request.config.stash[assertstate_key], "invocation_path",