@@ -97,7 +97,6 @@ def require_frozen(module, *, skip=True):
97
97
def require_pure_python (module , * , skip = False ):
98
98
_require_loader (module , SourceFileLoader , skip )
99
99
100
-
101
100
def remove_files (name ):
102
101
for f in (name + ".py" ,
103
102
name + ".pyc" ,
@@ -147,19 +146,34 @@ def _ready_to_import(name=None, source=""):
147
146
del sys .modules [name ]
148
147
149
148
150
- def requires_subinterpreters (meth ):
151
- """Decorator to skip a test if subinterpreters are not supported."""
152
- return unittest .skipIf (_interpreters is None ,
153
- 'subinterpreters required' )(meth )
149
+ if _testsinglephase is not None :
150
+ def restore__testsinglephase (* , _orig = _testsinglephase ):
151
+ # We started with the module imported and want to restore
152
+ # it to its nominal state.
153
+ _orig ._clear_globals ()
154
+ _testinternalcapi .clear_extension ('_testsinglephase' , _orig .__file__ )
155
+ import _testsinglephase
154
156
155
157
156
158
def requires_singlephase_init (meth ):
157
159
"""Decorator to skip if single-phase init modules are not supported."""
160
+ if not isinstance (meth , type ):
161
+ def meth (self , _meth = meth ):
162
+ try :
163
+ return _meth (self )
164
+ finally :
165
+ restore__testsinglephase ()
158
166
meth = cpython_only (meth )
159
167
return unittest .skipIf (_testsinglephase is None ,
160
168
'test requires _testsinglephase module' )(meth )
161
169
162
170
171
+ def requires_subinterpreters (meth ):
172
+ """Decorator to skip a test if subinterpreters are not supported."""
173
+ return unittest .skipIf (_interpreters is None ,
174
+ 'subinterpreters required' )(meth )
175
+
176
+
163
177
class ModuleSnapshot (types .SimpleNamespace ):
164
178
"""A representation of a module for testing.
165
179
@@ -1962,6 +1976,20 @@ def test_isolated_config(self):
1962
1976
with self .subTest (f'{ module } : strict, fresh' ):
1963
1977
self .check_compatible_fresh (module , strict = True , isolated = True )
1964
1978
1979
+ @requires_subinterpreters
1980
+ @requires_singlephase_init
1981
+ def test_disallowed_reimport (self ):
1982
+ # See https://github.com/python/cpython/issues/104621.
1983
+ script = textwrap .dedent ('''
1984
+ import _testsinglephase
1985
+ print(_testsinglephase)
1986
+ ''' )
1987
+ interpid = _interpreters .create ()
1988
+ with self .assertRaises (_interpreters .RunFailedError ):
1989
+ _interpreters .run_string (interpid , script )
1990
+ with self .assertRaises (_interpreters .RunFailedError ):
1991
+ _interpreters .run_string (interpid , script )
1992
+
1965
1993
1966
1994
class TestSinglePhaseSnapshot (ModuleSnapshot ):
1967
1995
@@ -2017,6 +2045,10 @@ def setUpClass(cls):
2017
2045
# Start fresh.
2018
2046
cls .clean_up ()
2019
2047
2048
+ @classmethod
2049
+ def tearDownClass (cls ):
2050
+ restore__testsinglephase ()
2051
+
2020
2052
def tearDown (self ):
2021
2053
# Clean up the module.
2022
2054
self .clean_up ()
0 commit comments