From 752e96fbeffbf72611f2cd57ad10dfcd070066ed Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Thu, 21 Sep 2023 10:39:36 +0300 Subject: [PATCH] [3.11] gh-109625: Move _ready_to_import() from test_import to support.import_helper (GH-109626). (cherry picked from commit 115c49ad5a5ccfb628fef3ae06a566f7a0197f97) Co-authored-by: Nikita Sobolev --- Lib/test/support/import_helper.py | 25 +++++++++++++++++++- Lib/test/test_import/__init__.py | 38 ++++++++----------------------- Lib/test/test_inspect.py | 6 ++--- 3 files changed, 35 insertions(+), 34 deletions(-) diff --git a/Lib/test/support/import_helper.py b/Lib/test/support/import_helper.py index 5201dc84cf6df4..a803d9f1b4039a 100644 --- a/Lib/test/support/import_helper.py +++ b/Lib/test/support/import_helper.py @@ -8,7 +8,7 @@ import unittest import warnings -from .os_helper import unlink +from .os_helper import unlink, temp_dir @contextlib.contextmanager @@ -246,3 +246,26 @@ def modules_cleanup(oldmodules): # do currently). Implicitly imported *real* modules should be left alone # (see issue 10556). sys.modules.update(oldmodules) + + +@contextlib.contextmanager +def ready_to_import(name=None, source=""): + from test.support import script_helper + + # 1. Sets up a temporary directory and removes it afterwards + # 2. Creates the module file + # 3. Temporarily clears the module from sys.modules (if any) + # 4. Reverts or removes the module when cleaning up + name = name or "spam" + with temp_dir() as tempdir: + path = script_helper.make_script(tempdir, name, source) + old_module = sys.modules.pop(name, None) + try: + sys.path.insert(0, tempdir) + yield name, path + sys.path.remove(tempdir) + finally: + if old_module is not None: + sys.modules[name] = old_module + else: + sys.modules.pop(name, None) diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index 6e2606cdb05bc6..131aebbd4e1f56 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -24,9 +24,10 @@ STDLIB_DIR, is_jython, swap_attr, swap_item, cpython_only, is_emscripten, is_wasi) from test.support.import_helper import ( - forget, make_legacy_pyc, unlink, unload, DirsOnSysPath, CleanImport) + forget, make_legacy_pyc, unlink, unload, ready_to_import, + DirsOnSysPath, CleanImport) from test.support.os_helper import ( - TESTFN, rmtree, temp_umask, TESTFN_UNENCODABLE, temp_dir) + TESTFN, rmtree, temp_umask, TESTFN_UNENCODABLE) from test.support import script_helper from test.support import threading_helper from test.test_importlib.util import uncache @@ -46,27 +47,6 @@ def remove_files(name): rmtree('__pycache__') -@contextlib.contextmanager -def _ready_to_import(name=None, source=""): - # sets up a temporary directory and removes it - # creates the module file - # temporarily clears the module from sys.modules (if any) - # reverts or removes the module when cleaning up - name = name or "spam" - with temp_dir() as tempdir: - path = script_helper.make_script(tempdir, name, source) - old_module = sys.modules.pop(name, None) - try: - sys.path.insert(0, tempdir) - yield name, path - sys.path.remove(tempdir) - finally: - if old_module is not None: - sys.modules[name] = old_module - elif name in sys.modules: - del sys.modules[name] - - class ImportTests(unittest.TestCase): def setUp(self): @@ -130,7 +110,7 @@ def test_from_import_missing_attr_path_is_canonical(self): def test_from_import_star_invalid_type(self): import re - with _ready_to_import() as (name, path): + with ready_to_import() as (name, path): with open(path, 'w', encoding='utf-8') as f: f.write("__all__ = [b'invalid_type']") globals = {} @@ -139,7 +119,7 @@ def test_from_import_star_invalid_type(self): ): exec(f"from {name} import *", globals) self.assertNotIn(b"invalid_type", globals) - with _ready_to_import() as (name, path): + with ready_to_import() as (name, path): with open(path, 'w', encoding='utf-8') as f: f.write("globals()[b'invalid_type'] = object()") globals = {} @@ -550,7 +530,7 @@ class FilePermissionTests(unittest.TestCase): ) def test_creation_mode(self): mask = 0o022 - with temp_umask(mask), _ready_to_import() as (name, path): + with temp_umask(mask), ready_to_import() as (name, path): cached_path = importlib.util.cache_from_source(path) module = __import__(name) if not os.path.exists(cached_path): @@ -569,7 +549,7 @@ def test_creation_mode(self): def test_cached_mode_issue_2051(self): # permissions of .pyc should match those of .py, regardless of mask mode = 0o600 - with temp_umask(0o022), _ready_to_import() as (name, path): + with temp_umask(0o022), ready_to_import() as (name, path): cached_path = importlib.util.cache_from_source(path) os.chmod(path, mode) __import__(name) @@ -585,7 +565,7 @@ def test_cached_mode_issue_2051(self): @os_helper.skip_unless_working_chmod def test_cached_readonly(self): mode = 0o400 - with temp_umask(0o022), _ready_to_import() as (name, path): + with temp_umask(0o022), ready_to_import() as (name, path): cached_path = importlib.util.cache_from_source(path) os.chmod(path, mode) __import__(name) @@ -600,7 +580,7 @@ def test_cached_readonly(self): def test_pyc_always_writable(self): # Initially read-only .pyc files on Windows used to cause problems # with later updates, see issue #6074 for details - with _ready_to_import() as (name, path): + with ready_to_import() as (name, path): # Write a Python file, make it read-only and import it with open(path, 'w', encoding='utf-8') as f: f.write("x = 'original'\n") diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index f5824778d1e5d6..650d56e39c415c 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -27,7 +27,7 @@ from test.support import cpython_only from test.support import MISSING_C_DOCSTRINGS, ALWAYS_EQ -from test.support.import_helper import DirsOnSysPath +from test.support.import_helper import DirsOnSysPath, ready_to_import from test.support.os_helper import TESTFN from test.support.script_helper import assert_python_ok, assert_python_failure from test import inspect_fodder as mod @@ -37,8 +37,6 @@ from test import inspect_stringized_annotations from test import inspect_stringized_annotations_2 -from test.test_import import _ready_to_import - # Functions tested in this suite: # ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode, @@ -4505,7 +4503,7 @@ def assertInspectEqual(self, path, source): def test_getsource_reload(self): # see issue 1218234 - with _ready_to_import('reload_bug', self.src_before) as (name, path): + with ready_to_import('reload_bug', self.src_before) as (name, path): module = importlib.import_module(name) self.assertInspectEqual(path, module) with open(path, 'w', encoding='utf-8') as src: