mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
gh-76785: Drop PyInterpreterID_Type (gh-117101)
I added it quite a while ago as a strategy for managing interpreter lifetimes relative to the PEP 554 (now 734) implementation. Relatively recently I refactored that implementation to no longer rely on InterpreterID objects. Thus now I'm removing it.
This commit is contained in:
parent
abdd1f938f
commit
617158e078
18 changed files with 357 additions and 443 deletions
|
@ -2207,132 +2207,264 @@ class SubinterpreterTest(unittest.TestCase):
|
|||
@requires_subinterpreters
|
||||
class InterpreterIDTests(unittest.TestCase):
|
||||
|
||||
InterpreterID = _testcapi.get_interpreterid_type()
|
||||
|
||||
def new_interpreter(self):
|
||||
def ensure_destroyed(interpid):
|
||||
def add_interp_cleanup(self, interpid):
|
||||
def ensure_destroyed():
|
||||
try:
|
||||
_interpreters.destroy(interpid)
|
||||
except _interpreters.InterpreterNotFoundError:
|
||||
pass
|
||||
self.addCleanup(ensure_destroyed)
|
||||
|
||||
def new_interpreter(self):
|
||||
id = _interpreters.create()
|
||||
self.addCleanup(lambda: ensure_destroyed(id))
|
||||
self.add_interp_cleanup(id)
|
||||
return id
|
||||
|
||||
def test_with_int(self):
|
||||
id = self.InterpreterID(10, force=True)
|
||||
def test_conversion_int(self):
|
||||
convert = _testinternalcapi.normalize_interp_id
|
||||
interpid = convert(10)
|
||||
self.assertEqual(interpid, 10)
|
||||
|
||||
self.assertEqual(int(id), 10)
|
||||
|
||||
def test_coerce_id(self):
|
||||
class Int(str):
|
||||
def test_conversion_coerced(self):
|
||||
convert = _testinternalcapi.normalize_interp_id
|
||||
class MyInt(str):
|
||||
def __index__(self):
|
||||
return 10
|
||||
interpid = convert(MyInt())
|
||||
self.assertEqual(interpid, 10)
|
||||
|
||||
id = self.InterpreterID(Int(), force=True)
|
||||
self.assertEqual(int(id), 10)
|
||||
def test_conversion_from_interpreter(self):
|
||||
convert = _testinternalcapi.normalize_interp_id
|
||||
interpid = self.new_interpreter()
|
||||
converted = convert(interpid)
|
||||
self.assertEqual(converted, interpid)
|
||||
|
||||
def test_conversion_bad(self):
|
||||
convert = _testinternalcapi.normalize_interp_id
|
||||
|
||||
def test_bad_id(self):
|
||||
for badid in [
|
||||
object(),
|
||||
10.0,
|
||||
'10',
|
||||
b'10',
|
||||
]:
|
||||
with self.subTest(badid):
|
||||
with self.subTest(f'bad: {badid!r}'):
|
||||
with self.assertRaises(TypeError):
|
||||
self.InterpreterID(badid)
|
||||
convert(badid)
|
||||
|
||||
badid = -1
|
||||
with self.subTest(badid):
|
||||
with self.subTest(f'bad: {badid!r}'):
|
||||
with self.assertRaises(ValueError):
|
||||
self.InterpreterID(badid)
|
||||
convert(badid)
|
||||
|
||||
badid = 2**64
|
||||
with self.subTest(badid):
|
||||
with self.subTest(f'bad: {badid!r}'):
|
||||
with self.assertRaises(OverflowError):
|
||||
self.InterpreterID(badid)
|
||||
convert(badid)
|
||||
|
||||
def test_exists(self):
|
||||
id = self.new_interpreter()
|
||||
with self.assertRaises(_interpreters.InterpreterNotFoundError):
|
||||
self.InterpreterID(int(id) + 1) # unforced
|
||||
def test_lookup_exists(self):
|
||||
interpid = self.new_interpreter()
|
||||
self.assertTrue(
|
||||
_testinternalcapi.interpreter_exists(interpid))
|
||||
|
||||
def test_does_not_exist(self):
|
||||
id = self.new_interpreter()
|
||||
with self.assertRaises(_interpreters.InterpreterNotFoundError):
|
||||
self.InterpreterID(int(id) + 1) # unforced
|
||||
def test_lookup_does_not_exist(self):
|
||||
interpid = _testinternalcapi.unused_interpreter_id()
|
||||
self.assertFalse(
|
||||
_testinternalcapi.interpreter_exists(interpid))
|
||||
|
||||
def test_destroyed(self):
|
||||
id = _interpreters.create()
|
||||
_interpreters.destroy(id)
|
||||
with self.assertRaises(_interpreters.InterpreterNotFoundError):
|
||||
self.InterpreterID(id) # unforced
|
||||
def test_lookup_destroyed(self):
|
||||
interpid = _interpreters.create()
|
||||
_interpreters.destroy(interpid)
|
||||
self.assertFalse(
|
||||
_testinternalcapi.interpreter_exists(interpid))
|
||||
|
||||
def test_str(self):
|
||||
id = self.InterpreterID(10, force=True)
|
||||
self.assertEqual(str(id), '10')
|
||||
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
|
||||
|
||||
def test_repr(self):
|
||||
id = self.InterpreterID(10, force=True)
|
||||
self.assertEqual(repr(id), 'InterpreterID(10)')
|
||||
with self.subTest('never existed'):
|
||||
interpid = _testinternalcapi.unused_interpreter_id()
|
||||
self.assertFalse(
|
||||
exists(interpid))
|
||||
with self.assertRaises(_interpreters.InterpreterNotFoundError):
|
||||
is_linked(interpid)
|
||||
with self.assertRaises(_interpreters.InterpreterNotFoundError):
|
||||
link(interpid)
|
||||
with self.assertRaises(_interpreters.InterpreterNotFoundError):
|
||||
unlink(interpid)
|
||||
with self.assertRaises(_interpreters.InterpreterNotFoundError):
|
||||
get_refcount(interpid)
|
||||
with self.assertRaises(_interpreters.InterpreterNotFoundError):
|
||||
incref(interpid)
|
||||
with self.assertRaises(_interpreters.InterpreterNotFoundError):
|
||||
decref(interpid)
|
||||
|
||||
def test_equality(self):
|
||||
id1 = self.new_interpreter()
|
||||
id2 = self.InterpreterID(id1)
|
||||
id3 = self.InterpreterID(
|
||||
self.new_interpreter())
|
||||
with self.subTest('destroyed'):
|
||||
interpid = _interpreters.create()
|
||||
_interpreters.destroy(interpid)
|
||||
self.assertFalse(
|
||||
exists(interpid))
|
||||
with self.assertRaises(_interpreters.InterpreterNotFoundError):
|
||||
is_linked(interpid)
|
||||
with self.assertRaises(_interpreters.InterpreterNotFoundError):
|
||||
link(interpid)
|
||||
with self.assertRaises(_interpreters.InterpreterNotFoundError):
|
||||
unlink(interpid)
|
||||
with self.assertRaises(_interpreters.InterpreterNotFoundError):
|
||||
get_refcount(interpid)
|
||||
with self.assertRaises(_interpreters.InterpreterNotFoundError):
|
||||
incref(interpid)
|
||||
with self.assertRaises(_interpreters.InterpreterNotFoundError):
|
||||
decref(interpid)
|
||||
|
||||
self.assertTrue(id2 == id2) # identity
|
||||
self.assertTrue(id2 == id1) # int-equivalent
|
||||
self.assertTrue(id1 == id2) # reversed
|
||||
self.assertTrue(id2 == int(id2))
|
||||
self.assertTrue(id2 == float(int(id2)))
|
||||
self.assertTrue(float(int(id2)) == id2)
|
||||
self.assertFalse(id2 == float(int(id2)) + 0.1)
|
||||
self.assertFalse(id2 == str(int(id2)))
|
||||
self.assertFalse(id2 == 2**1000)
|
||||
self.assertFalse(id2 == float('inf'))
|
||||
self.assertFalse(id2 == 'spam')
|
||||
self.assertFalse(id2 == id3)
|
||||
def test_linked_lifecycle_initial(self):
|
||||
is_linked = _testinternalcapi.interpreter_refcount_linked
|
||||
get_refcount = _testinternalcapi.get_interpreter_refcount
|
||||
|
||||
self.assertFalse(id2 != id2)
|
||||
self.assertFalse(id2 != id1)
|
||||
self.assertFalse(id1 != id2)
|
||||
self.assertTrue(id2 != id3)
|
||||
# A new interpreter will start out not linked, with a refcount of 0.
|
||||
interpid = _testinternalcapi.new_interpreter()
|
||||
self.add_interp_cleanup(interpid)
|
||||
linked = is_linked(interpid)
|
||||
refcount = get_refcount(interpid)
|
||||
|
||||
def test_linked_lifecycle(self):
|
||||
id1 = _interpreters.create()
|
||||
_testinternalcapi.unlink_interpreter_refcount(id1)
|
||||
self.assertFalse(linked)
|
||||
self.assertEqual(refcount, 0)
|
||||
|
||||
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
|
||||
|
||||
interpid = _testinternalcapi.new_interpreter()
|
||||
self.add_interp_cleanup(interpid)
|
||||
|
||||
# Incref will not automatically link it.
|
||||
incref(interpid)
|
||||
self.assertFalse(
|
||||
is_linked(interpid))
|
||||
self.assertEqual(
|
||||
_testinternalcapi.get_interpreter_refcount(id1),
|
||||
0)
|
||||
1, get_refcount(interpid))
|
||||
|
||||
id2 = self.InterpreterID(id1)
|
||||
# It isn't linked so it isn't destroyed.
|
||||
decref(interpid)
|
||||
self.assertTrue(
|
||||
exists(interpid))
|
||||
self.assertFalse(
|
||||
is_linked(interpid))
|
||||
self.assertEqual(
|
||||
_testinternalcapi.get_interpreter_refcount(id1),
|
||||
1)
|
||||
0, get_refcount(interpid))
|
||||
|
||||
# The interpreter isn't linked to ID objects, so it isn't destroyed.
|
||||
del id2
|
||||
def test_linked_lifecycle_link_unlink(self):
|
||||
exists = _testinternalcapi.interpreter_exists
|
||||
is_linked = _testinternalcapi.interpreter_refcount_linked
|
||||
link = _testinternalcapi.link_interpreter_refcount
|
||||
unlink = _testinternalcapi.unlink_interpreter_refcount
|
||||
|
||||
interpid = _testinternalcapi.new_interpreter()
|
||||
self.add_interp_cleanup(interpid)
|
||||
|
||||
# Linking at refcount 0 does not destroy the interpreter.
|
||||
link(interpid)
|
||||
self.assertTrue(
|
||||
exists(interpid))
|
||||
self.assertTrue(
|
||||
is_linked(interpid))
|
||||
|
||||
# Unlinking at refcount 0 does not destroy the interpreter.
|
||||
unlink(interpid)
|
||||
self.assertTrue(
|
||||
exists(interpid))
|
||||
self.assertFalse(
|
||||
is_linked(interpid))
|
||||
|
||||
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
|
||||
|
||||
interpid = _testinternalcapi.new_interpreter()
|
||||
self.add_interp_cleanup(interpid)
|
||||
|
||||
# Linking it will not change the refcount.
|
||||
link(interpid)
|
||||
self.assertTrue(
|
||||
is_linked(interpid))
|
||||
self.assertEqual(
|
||||
_testinternalcapi.get_interpreter_refcount(id1),
|
||||
0)
|
||||
0, get_refcount(interpid))
|
||||
|
||||
_testinternalcapi.link_interpreter_refcount(id1)
|
||||
# Decref with a refcount of 0 is not allowed.
|
||||
incref(interpid)
|
||||
self.assertEqual(
|
||||
_testinternalcapi.get_interpreter_refcount(id1),
|
||||
0)
|
||||
1, get_refcount(interpid))
|
||||
|
||||
id3 = self.InterpreterID(id1)
|
||||
# When linked, decref back to 0 destroys the interpreter.
|
||||
decref(interpid)
|
||||
self.assertFalse(
|
||||
exists(interpid))
|
||||
|
||||
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
|
||||
|
||||
interpid = _testinternalcapi.new_interpreter()
|
||||
self.add_interp_cleanup(interpid)
|
||||
|
||||
incref(interpid)
|
||||
self.assertEqual(
|
||||
_testinternalcapi.get_interpreter_refcount(id1),
|
||||
1)
|
||||
1, get_refcount(interpid))
|
||||
|
||||
# The interpreter is linked now so is destroyed.
|
||||
del id3
|
||||
with self.assertRaises(_interpreters.InterpreterNotFoundError):
|
||||
_testinternalcapi.get_interpreter_refcount(id1)
|
||||
# Linking it will not reset the refcount.
|
||||
link(interpid)
|
||||
self.assertTrue(
|
||||
is_linked(interpid))
|
||||
self.assertEqual(
|
||||
1, get_refcount(interpid))
|
||||
|
||||
def test_linked_lifecycle_link_incref_unlink_decref(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
|
||||
|
||||
interpid = _testinternalcapi.new_interpreter()
|
||||
self.add_interp_cleanup(interpid)
|
||||
|
||||
link(interpid)
|
||||
self.assertTrue(
|
||||
is_linked(interpid))
|
||||
|
||||
incref(interpid)
|
||||
self.assertEqual(
|
||||
1, get_refcount(interpid))
|
||||
|
||||
# Unlinking it will not change the refcount.
|
||||
unlink(interpid)
|
||||
self.assertFalse(
|
||||
is_linked(interpid))
|
||||
self.assertEqual(
|
||||
1, get_refcount(interpid))
|
||||
|
||||
# Unlinked: decref back to 0 does not destroys the interpreter.
|
||||
decref(interpid)
|
||||
self.assertTrue(
|
||||
exists(interpid))
|
||||
self.assertEqual(
|
||||
0, get_refcount(interpid))
|
||||
|
||||
|
||||
class BuiltinStaticTypesTests(unittest.TestCase):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue