From a5d623d7e6729e49b1328a50bef6773bfc689198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Thu, 7 Oct 2021 09:25:41 +0100 Subject: [PATCH 1/4] Support the importlib.resources files API on rewritten MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernát Gábor --- src/_pytest/assertion/rewrite.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/_pytest/assertion/rewrite.py b/src/_pytest/assertion/rewrite.py index 1f7de90d5a9..d5c3c8ae725 100644 --- a/src/_pytest/assertion/rewrite.py +++ b/src/_pytest/assertion/rewrite.py @@ -64,7 +64,7 @@ def __init__(self, config: Config) -> None: except ValueError: self.fnpats = ["test_*.py", "*_test.py"] self.session: Optional[Session] = None - self._rewritten_names: Set[str] = set() + self._rewritten_names: Dict[str, Path] = {} self._must_rewrite: Set[str] = set() # flag to guard against trying to rewrite a pyc file while we are already writing another pyc file, # which might result in infinite recursion (#3506) @@ -134,7 +134,7 @@ def exec_module(self, module: types.ModuleType) -> None: fn = Path(module.__spec__.origin) state = self.config.stash[assertstate_key] - self._rewritten_names.add(module.__name__) + self._rewritten_names[module.__name__] = fn # The requested module looks like a test file, so rewrite it. This is # the most magical part of the process: load the source, rewrite the @@ -276,6 +276,14 @@ def get_data(self, pathname: Union[str, bytes]) -> bytes: with open(pathname, "rb") as f: return f.read() + if sys.version_info >= (3, 9): + + def get_resource_reader(self, name: str) -> importlib.abc.TraversableResources: + from argparse import Namespace + from importlib.readers import FileReader + + return FileReader(Namespace(path=self._rewritten_names[name])) + def _write_pyc_fp( fp: IO[bytes], source_stat: os.stat_result, co: types.CodeType From 48ed5d7d27fd12698b0b3c03fa684064f48fa876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Fri, 8 Oct 2021 00:22:37 +0100 Subject: [PATCH 2/4] PR Feedback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernát Gábor --- changelog/9169.bugfix.rst | 1 + src/_pytest/assertion/rewrite.py | 6 +++--- testing/test_assertrewrite.py | 26 ++++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 changelog/9169.bugfix.rst diff --git a/changelog/9169.bugfix.rst b/changelog/9169.bugfix.rst new file mode 100644 index 00000000000..83fce0a3893 --- /dev/null +++ b/changelog/9169.bugfix.rst @@ -0,0 +1 @@ +Support for the ``files`` API from ``importlib.resources`` within rewritten files. diff --git a/src/_pytest/assertion/rewrite.py b/src/_pytest/assertion/rewrite.py index d5c3c8ae725..5fb076d4885 100644 --- a/src/_pytest/assertion/rewrite.py +++ b/src/_pytest/assertion/rewrite.py @@ -278,11 +278,11 @@ def get_data(self, pathname: Union[str, bytes]) -> bytes: if sys.version_info >= (3, 9): - def get_resource_reader(self, name: str) -> importlib.abc.TraversableResources: - from argparse import Namespace + def get_resource_reader(self, name: str) -> importlib.abc.TraversableResources: # type: ignore + from types import SimpleNamespace from importlib.readers import FileReader - return FileReader(Namespace(path=self._rewritten_names[name])) + return FileReader(SimpleNamespace(path=self._rewritten_names[name])) def _write_pyc_fp( diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index 5e63d61fa30..94fc1e24c92 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -795,6 +795,32 @@ def test_zipfile(self, pytester: Pytester) -> None: ) assert pytester.runpytest().ret == ExitCode.NO_TESTS_COLLECTED + if sys.version_info >= (3, 9): + + def test_load_resource_via_files_with_rewrite(self, pytester: Pytester) -> None: + example = pytester.path.joinpath("demo") / "example" + init = pytester.path.joinpath("demo") / "__init__.py" + pytester.makepyfile( + **{ + "demo/__init__.py": """ + from importlib.resources import files + + def load(): + return files(__name__) + """, + "test_load": f""" + pytest_plugins = ["demo"] + + def test_load(): + from demo import load + assert list(str(i) for i in load().iterdir()) == [{str(example)!r}, {str(init)!r}] + """, + } + ) + example.mkdir() + + assert pytester.runpytest("-vv").ret == ExitCode.OK + def test_readonly(self, pytester: Pytester) -> None: sub = pytester.mkdir("testing") sub.joinpath("test_readonly.py").write_bytes( From d23ccb30b5c99a9c536bc3e317ac1e56bbb0e5f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Fri, 8 Oct 2021 00:26:22 +0100 Subject: [PATCH 3/4] More feedback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernát Gábor --- testing/test_assertrewrite.py | 50 ++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index 94fc1e24c92..d7bcb2f928e 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -795,31 +795,33 @@ def test_zipfile(self, pytester: Pytester) -> None: ) assert pytester.runpytest().ret == ExitCode.NO_TESTS_COLLECTED - if sys.version_info >= (3, 9): - - def test_load_resource_via_files_with_rewrite(self, pytester: Pytester) -> None: - example = pytester.path.joinpath("demo") / "example" - init = pytester.path.joinpath("demo") / "__init__.py" - pytester.makepyfile( - **{ - "demo/__init__.py": """ - from importlib.resources import files - - def load(): - return files(__name__) - """, - "test_load": f""" - pytest_plugins = ["demo"] - - def test_load(): - from demo import load - assert list(str(i) for i in load().iterdir()) == [{str(example)!r}, {str(init)!r}] - """, - } - ) - example.mkdir() + @pytest.mark.skipif( + sys.version_info < (3, 9), + reason="importlib.resources.files was introduced in 3.9", + ) + def test_load_resource_via_files_with_rewrite(self, pytester: Pytester) -> None: + example = pytester.path.joinpath("demo") / "example" + init = pytester.path.joinpath("demo") / "__init__.py" + pytester.makepyfile( + **{ + "demo/__init__.py": """ + from importlib.resources import files + + def load(): + return files(__name__) + """, + "test_load": f""" + pytest_plugins = ["demo"] + + def test_load(): + from demo import load + assert list(str(i) for i in load().iterdir()) == [{str(example)!r}, {str(init)!r}] + """, + } + ) + example.mkdir() - assert pytester.runpytest("-vv").ret == ExitCode.OK + assert pytester.runpytest("-vv").ret == ExitCode.OK def test_readonly(self, pytester: Pytester) -> None: sub = pytester.mkdir("testing") From 59b64766db0239e0239a22db929172a406b84b7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Fri, 8 Oct 2021 00:54:16 +0100 Subject: [PATCH 4/4] Fix failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernát Gábor --- testing/test_assertrewrite.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index d7bcb2f928e..ebe1220bb00 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -815,7 +815,8 @@ def load(): def test_load(): from demo import load - assert list(str(i) for i in load().iterdir()) == [{str(example)!r}, {str(init)!r}] + found = {{str(i) for i in load().iterdir() if i.name != "__pycache__"}} + assert found == {{{str(example)!r}, {str(init)!r}}} """, } )