Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-76785: Consolidate Some Interpreter-related Testing Helpers #117485

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Lib/test/support/interpreters/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def __str__(self):

def create():
"""Return a new (idle) Python interpreter."""
id = _interpreters.create(isolated=True)
id = _interpreters.create(reqrefs=True)
return Interpreter(id)


Expand Down Expand Up @@ -109,13 +109,13 @@ def __new__(cls, id, /):
assert hasattr(self, '_ownsref')
except KeyError:
# This may raise InterpreterNotFoundError:
_interpreters._incref(id)
_interpreters.incref(id)
try:
self = super().__new__(cls)
self._id = id
self._ownsref = True
except BaseException:
_interpreters._deccref(id)
_interpreters.decref(id)
raise
_known[id] = self
return self
Expand All @@ -142,7 +142,7 @@ def _decref(self):
return
self._ownsref = False
try:
_interpreters._decref(self.id)
_interpreters.decref(self.id)
except InterpreterNotFoundError:
pass

Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test__xxsubinterpreters.py
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,7 @@ def f():
def test_create_daemon_thread(self):
with self.subTest('isolated'):
expected = 'spam spam spam spam spam'
subinterp = interpreters.create(isolated=True)
subinterp = interpreters.create('isolated')
script, file = _captured_script(f"""
import threading
def f():
Expand All @@ -604,7 +604,7 @@ def f():
self.assertEqual(out, expected)

with self.subTest('not isolated'):
subinterp = interpreters.create(isolated=False)
subinterp = interpreters.create('legacy')
script, file = _captured_script("""
import threading
def f():
Expand Down
83 changes: 37 additions & 46 deletions Lib/test/test_capi/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2204,6 +2204,7 @@ def test_module_state_shared_in_global(self):
self.assertEqual(main_attr_id, subinterp_attr_id)


@requires_subinterpreters
class InterpreterConfigTests(unittest.TestCase):

supported = {
Expand Down Expand Up @@ -2277,11 +2278,11 @@ def check(name, expected):
expected = self.supported[expected]
args = (name,) if name else ()

config1 = _testinternalcapi.new_interp_config(*args)
config1 = _interpreters.new_config(*args)
self.assert_ns_equal(config1, expected)
self.assertIsNot(config1, expected)

config2 = _testinternalcapi.new_interp_config(*args)
config2 = _interpreters.new_config(*args)
self.assert_ns_equal(config2, expected)
self.assertIsNot(config2, expected)
self.assertIsNot(config2, config1)
Expand All @@ -2298,7 +2299,7 @@ def test_update_from_dict(self):
with self.subTest(f'noop ({name})'):
expected = vanilla
overrides = vars(vanilla)
config = _testinternalcapi.new_interp_config(name, **overrides)
config = _interpreters.new_config(name, **overrides)
self.assert_ns_equal(config, expected)

with self.subTest(f'change all ({name})'):
Expand All @@ -2308,7 +2309,7 @@ def test_update_from_dict(self):
continue
overrides['gil'] = gil
expected = types.SimpleNamespace(**overrides)
config = _testinternalcapi.new_interp_config(
config = _interpreters.new_config(
name, **overrides)
self.assert_ns_equal(config, expected)

Expand All @@ -2324,14 +2325,14 @@ def test_update_from_dict(self):
expected = types.SimpleNamespace(
**dict(vars(vanilla), **overrides),
)
config = _testinternalcapi.new_interp_config(
config = _interpreters.new_config(
name, **overrides)
self.assert_ns_equal(config, expected)

with self.subTest('unsupported field'):
for name in self.supported:
with self.assertRaises(ValueError):
_testinternalcapi.new_interp_config(name, spam=True)
_interpreters.new_config(name, spam=True)

# Bad values for bool fields.
for field, value in vars(self.supported['empty']).items():
Expand All @@ -2341,19 +2342,18 @@ def test_update_from_dict(self):
for value in [1, '', 'spam', 1.0, None, object()]:
with self.subTest(f'unsupported value ({field}={value!r})'):
with self.assertRaises(TypeError):
_testinternalcapi.new_interp_config(**{field: value})
_interpreters.new_config(**{field: value})

# Bad values for .gil.
for value in [True, 1, 1.0, None, object()]:
with self.subTest(f'unsupported value(gil={value!r})'):
with self.assertRaises(TypeError):
_testinternalcapi.new_interp_config(gil=value)
_interpreters.new_config(gil=value)
for value in ['', 'spam']:
with self.subTest(f'unsupported value (gil={value!r})'):
with self.assertRaises(ValueError):
_testinternalcapi.new_interp_config(gil=value)
_interpreters.new_config(gil=value)

@requires_subinterpreters
def test_interp_init(self):
questionable = [
# strange
Expand Down Expand Up @@ -2412,11 +2412,10 @@ def check(config):
with self.subTest(f'valid: {config}'):
check(config)

@requires_subinterpreters
def test_get_config(self):
@contextlib.contextmanager
def new_interp(config):
interpid = _testinternalcapi.new_interpreter(config)
interpid = _interpreters.create(config, reqrefs=False)
try:
yield interpid
finally:
Expand All @@ -2426,32 +2425,32 @@ def new_interp(config):
pass

with self.subTest('main'):
expected = _testinternalcapi.new_interp_config('legacy')
expected = _interpreters.new_config('legacy')
expected.gil = 'own'
interpid = _interpreters.get_main()
config = _testinternalcapi.get_interp_config(interpid)
config = _interpreters.get_config(interpid)
self.assert_ns_equal(config, expected)

with self.subTest('isolated'):
expected = _testinternalcapi.new_interp_config('isolated')
expected = _interpreters.new_config('isolated')
with new_interp('isolated') as interpid:
config = _testinternalcapi.get_interp_config(interpid)
config = _interpreters.get_config(interpid)
self.assert_ns_equal(config, expected)

with self.subTest('legacy'):
expected = _testinternalcapi.new_interp_config('legacy')
expected = _interpreters.new_config('legacy')
with new_interp('legacy') as interpid:
config = _testinternalcapi.get_interp_config(interpid)
config = _interpreters.get_config(interpid)
self.assert_ns_equal(config, expected)

with self.subTest('custom'):
orig = _testinternalcapi.new_interp_config(
orig = _interpreters.new_config(
'empty',
use_main_obmalloc=True,
gil='shared',
)
with new_interp(orig) as interpid:
config = _testinternalcapi.get_interp_config(interpid)
config = _interpreters.get_config(interpid)
self.assert_ns_equal(config, orig)


Expand Down Expand Up @@ -2529,14 +2528,19 @@ def test_lookup_destroyed(self):
self.assertFalse(
_testinternalcapi.interpreter_exists(interpid))

def get_refcount_helpers(self):
return (
_testinternalcapi.get_interpreter_refcount,
(lambda id: _interpreters.incref(id, implieslink=False)),
_interpreters.decref,
)

def test_linked_lifecycle_does_not_exist(self):
exists = _testinternalcapi.interpreter_exists
is_linked = _testinternalcapi.interpreter_refcount_linked
link = _testinternalcapi.link_interpreter_refcount
unlink = _testinternalcapi.unlink_interpreter_refcount
get_refcount = _testinternalcapi.get_interpreter_refcount
incref = _testinternalcapi.interpreter_incref
decref = _testinternalcapi.interpreter_decref
get_refcount, incref, decref = self.get_refcount_helpers()

with self.subTest('never existed'):
interpid = _testinternalcapi.unused_interpreter_id()
Expand Down Expand Up @@ -2578,8 +2582,7 @@ def test_linked_lifecycle_initial(self):
get_refcount = _testinternalcapi.get_interpreter_refcount

# A new interpreter will start out not linked, with a refcount of 0.
interpid = _testinternalcapi.new_interpreter()
self.add_interp_cleanup(interpid)
interpid = self.new_interpreter()
linked = is_linked(interpid)
refcount = get_refcount(interpid)

Expand All @@ -2589,12 +2592,9 @@ def test_linked_lifecycle_initial(self):
def test_linked_lifecycle_never_linked(self):
exists = _testinternalcapi.interpreter_exists
is_linked = _testinternalcapi.interpreter_refcount_linked
get_refcount = _testinternalcapi.get_interpreter_refcount
incref = _testinternalcapi.interpreter_incref
decref = _testinternalcapi.interpreter_decref
get_refcount, incref, decref = self.get_refcount_helpers()

interpid = _testinternalcapi.new_interpreter()
self.add_interp_cleanup(interpid)
interpid = self.new_interpreter()

# Incref will not automatically link it.
incref(interpid)
Expand All @@ -2618,8 +2618,7 @@ def test_linked_lifecycle_link_unlink(self):
link = _testinternalcapi.link_interpreter_refcount
unlink = _testinternalcapi.unlink_interpreter_refcount

interpid = _testinternalcapi.new_interpreter()
self.add_interp_cleanup(interpid)
interpid = self.new_interpreter()

# Linking at refcount 0 does not destroy the interpreter.
link(interpid)
Expand All @@ -2639,12 +2638,9 @@ def test_linked_lifecycle_link_incref_decref(self):
exists = _testinternalcapi.interpreter_exists
is_linked = _testinternalcapi.interpreter_refcount_linked
link = _testinternalcapi.link_interpreter_refcount
get_refcount = _testinternalcapi.get_interpreter_refcount
incref = _testinternalcapi.interpreter_incref
decref = _testinternalcapi.interpreter_decref
get_refcount, incref, decref = self.get_refcount_helpers()

interpid = _testinternalcapi.new_interpreter()
self.add_interp_cleanup(interpid)
interpid = self.new_interpreter()

# Linking it will not change the refcount.
link(interpid)
Expand All @@ -2666,11 +2662,9 @@ def test_linked_lifecycle_link_incref_decref(self):
def test_linked_lifecycle_incref_link(self):
is_linked = _testinternalcapi.interpreter_refcount_linked
link = _testinternalcapi.link_interpreter_refcount
get_refcount = _testinternalcapi.get_interpreter_refcount
incref = _testinternalcapi.interpreter_incref
get_refcount, incref, _ = self.get_refcount_helpers()

interpid = _testinternalcapi.new_interpreter()
self.add_interp_cleanup(interpid)
interpid = self.new_interpreter()

incref(interpid)
self.assertEqual(
Expand All @@ -2688,12 +2682,9 @@ def test_linked_lifecycle_link_incref_unlink_decref(self):
is_linked = _testinternalcapi.interpreter_refcount_linked
link = _testinternalcapi.link_interpreter_refcount
unlink = _testinternalcapi.unlink_interpreter_refcount
get_refcount = _testinternalcapi.get_interpreter_refcount
incref = _testinternalcapi.interpreter_incref
decref = _testinternalcapi.interpreter_decref
get_refcount, incref, decref = self.get_refcount_helpers()

interpid = _testinternalcapi.new_interpreter()
self.add_interp_cleanup(interpid)
interpid = self.new_interpreter()

link(interpid)
self.assertTrue(
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_import/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2163,7 +2163,7 @@ def re_load(self, name, mod):
# subinterpreters

def add_subinterpreter(self):
interpid = _interpreters.create(isolated=False)
interpid = _interpreters.create('legacy')
def ensure_destroyed():
try:
_interpreters.destroy(interpid)
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_importlib/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,7 @@ def test_magic_number(self):
class IncompatibleExtensionModuleRestrictionsTests(unittest.TestCase):

def run_with_own_gil(self, script):
interpid = _interpreters.create(isolated=True)
interpid = _interpreters.create('isolated')
def ensure_destroyed():
try:
_interpreters.destroy(interpid)
Expand All @@ -669,7 +669,7 @@ def ensure_destroyed():
raise ImportError(excsnap.msg)

def run_with_shared_gil(self, script):
interpid = _interpreters.create(isolated=False)
interpid = _interpreters.create('legacy')
def ensure_destroyed():
try:
_interpreters.destroy(interpid)
Expand Down
Loading
Loading