summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_capi
diff options
context:
space:
mode:
authorEric Snow <ericsnowcurrently@gmail.com>2024-03-21 17:15:02 (GMT)
committerGitHub <noreply@github.com>2024-03-21 17:15:02 (GMT)
commit617158e07811edfd6fd552a3d84b0beedd8f1d18 (patch)
treeda45d921852f67ce2cc7a086c5c1b79ad20b4b2d /Lib/test/test_capi
parentabdd1f938f08e536864532b2071f144515ecc88b (diff)
downloadcpython-617158e07811edfd6fd552a3d84b0beedd8f1d18.zip
cpython-617158e07811edfd6fd552a3d84b0beedd8f1d18.tar.gz
cpython-617158e07811edfd6fd552a3d84b0beedd8f1d18.tar.bz2
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.
Diffstat (limited to 'Lib/test/test_capi')
-rw-r--r--Lib/test/test_capi/test_misc.py308
1 files changed, 220 insertions, 88 deletions
diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py
index fe5e19d..55a1ab6 100644
--- a/Lib/test/test_capi/test_misc.py
+++ b/Lib/test/test_capi/test_misc.py
@@ -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)
-
- self.assertEqual(int(id), 10)
+ def test_conversion_int(self):
+ convert = _testinternalcapi.normalize_interp_id
+ interpid = convert(10)
+ self.assertEqual(interpid, 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_str(self):
- id = self.InterpreterID(10, force=True)
- self.assertEqual(str(id), '10')
-
- def test_repr(self):
- id = self.InterpreterID(10, force=True)
- self.assertEqual(repr(id), 'InterpreterID(10)')
-
- def test_equality(self):
- id1 = self.new_interpreter()
- id2 = self.InterpreterID(id1)
- id3 = self.InterpreterID(
- self.new_interpreter())
-
- 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)
-
- self.assertFalse(id2 != id2)
- self.assertFalse(id2 != id1)
- self.assertFalse(id1 != id2)
- self.assertTrue(id2 != id3)
-
- def test_linked_lifecycle(self):
- id1 = _interpreters.create()
- _testinternalcapi.unlink_interpreter_refcount(id1)
+ def test_lookup_destroyed(self):
+ interpid = _interpreters.create()
+ _interpreters.destroy(interpid)
+ self.assertFalse(
+ _testinternalcapi.interpreter_exists(interpid))
+
+ 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
+
+ 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)
+
+ 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)
+
+ def test_linked_lifecycle_initial(self):
+ is_linked = _testinternalcapi.interpreter_refcount_linked
+ 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)
+ linked = is_linked(interpid)
+ refcount = get_refcount(interpid)
+
+ 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(
+ 1, get_refcount(interpid))
+
+ # It isn't linked so it isn't destroyed.
+ decref(interpid)
+ self.assertTrue(
+ exists(interpid))
+ self.assertFalse(
+ is_linked(interpid))
+ self.assertEqual(
+ 0, get_refcount(interpid))
+
+ 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))
- id2 = self.InterpreterID(id1)
+ # Decref with a refcount of 0 is not allowed.
+ incref(interpid)
self.assertEqual(
- _testinternalcapi.get_interpreter_refcount(id1),
- 1)
+ 1, get_refcount(interpid))
- # The interpreter isn't linked to ID objects, so it isn't destroyed.
- del id2
+ # 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),
- 0)
+ 1, get_refcount(interpid))
- _testinternalcapi.link_interpreter_refcount(id1)
+ # Linking it will not reset the refcount.
+ link(interpid)
+ self.assertTrue(
+ is_linked(interpid))
self.assertEqual(
- _testinternalcapi.get_interpreter_refcount(id1),
- 0)
+ 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)
- id3 = self.InterpreterID(id1)
+ 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(
- _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)
+ # 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):