Skip to content

Commit cd66545

Browse files
Update the tests
1 parent 2370c16 commit cd66545

File tree

3 files changed

+303
-98
lines changed

3 files changed

+303
-98
lines changed

Include/internal/pycore_interp.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -295,12 +295,11 @@ _PyInterpreterState_SetFinalizing(PyInterpreterState *interp, PyThreadState *tst
295295
}
296296

297297

298-
extern int64_t _PyInterpreterState_ObjectToID(PyObject *);
299298

300-
// Export for the _xxinterpchannels module.
299+
// Exports for the _testinternalcapi module.
300+
PyAPI_FUNC(int64_t) _PyInterpreterState_ObjectToID(PyObject *);
301301
PyAPI_FUNC(PyInterpreterState *) _PyInterpreterState_LookUpID(int64_t);
302302
PyAPI_FUNC(PyInterpreterState *) _PyInterpreterState_LookUpIDObject(PyObject *);
303-
304303
PyAPI_FUNC(int) _PyInterpreterState_IDInitref(PyInterpreterState *);
305304
PyAPI_FUNC(int) _PyInterpreterState_IDIncref(PyInterpreterState *);
306305
PyAPI_FUNC(void) _PyInterpreterState_IDDecref(PyInterpreterState *);

Lib/test/test_capi/test_misc.py

Lines changed: 182 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -2207,132 +2207,219 @@ def test_module_state_shared_in_global(self):
22072207
@requires_subinterpreters
22082208
class InterpreterIDTests(unittest.TestCase):
22092209

2210-
InterpreterID = _testcapi.get_interpreterid_type()
2210+
# InterpreterID = _testcapi.get_interpreterid_type()
22112211

2212-
def new_interpreter(self):
2213-
def ensure_destroyed(interpid):
2212+
def check_id(self, interpid, *, force=False):
2213+
if force:
2214+
return
2215+
2216+
def add_interp_cleanup(self, interpid):
2217+
def ensure_destroyed():
22142218
try:
22152219
_interpreters.destroy(interpid)
22162220
except _interpreters.InterpreterNotFoundError:
22172221
pass
2222+
self.addCleanup(ensure_destroyed)
2223+
2224+
def new_interpreter(self):
22182225
id = _interpreters.create()
2219-
self.addCleanup(lambda: ensure_destroyed(id))
2226+
self.add_interp_cleanup(id)
22202227
return id
22212228

2222-
def test_with_int(self):
2223-
id = self.InterpreterID(10, force=True)
2229+
def test_conversion(self):
2230+
convert = _testinternalcapi.normalize_interp_id
22242231

2225-
self.assertEqual(int(id), 10)
2232+
with self.subTest('int'):
2233+
interpid = convert(10)
2234+
self.assertEqual(interpid, 10)
22262235

2227-
def test_coerce_id(self):
2228-
class Int(str):
2229-
def __index__(self):
2230-
return 10
2236+
with self.subTest('coerced'):
2237+
class MyInt(str):
2238+
def __index__(self):
2239+
return 10
22312240

2232-
id = self.InterpreterID(Int(), force=True)
2233-
self.assertEqual(int(id), 10)
2241+
interpid = convert(MyInt())
2242+
self.assertEqual(interpid, 10)
22342243

2235-
def test_bad_id(self):
22362244
for badid in [
22372245
object(),
22382246
10.0,
22392247
'10',
22402248
b'10',
22412249
]:
2242-
with self.subTest(badid):
2250+
with self.subTest(f'bad: {badid!r}'):
22432251
with self.assertRaises(TypeError):
2244-
self.InterpreterID(badid)
2252+
convert(badid)
22452253

22462254
badid = -1
2247-
with self.subTest(badid):
2255+
with self.subTest(f'bad: {badid!r}'):
22482256
with self.assertRaises(ValueError):
2249-
self.InterpreterID(badid)
2257+
convert(badid)
22502258

22512259
badid = 2**64
2252-
with self.subTest(badid):
2260+
with self.subTest(f'bad: {badid!r}'):
22532261
with self.assertRaises(OverflowError):
2254-
self.InterpreterID(badid)
2262+
convert(badid)
22552263

2256-
def test_exists(self):
2257-
id = self.new_interpreter()
2258-
with self.assertRaises(_interpreters.InterpreterNotFoundError):
2259-
self.InterpreterID(int(id) + 1) # unforced
2264+
def test_lookup(self):
2265+
with self.subTest('exists'):
2266+
interpid = self.new_interpreter()
2267+
self.assertTrue(
2268+
_testinternalcapi.interpreter_exists(interpid))
22602269

2261-
def test_does_not_exist(self):
2262-
id = self.new_interpreter()
2263-
with self.assertRaises(_interpreters.InterpreterNotFoundError):
2264-
self.InterpreterID(int(id) + 1) # unforced
2270+
with self.subTest('does not exist'):
2271+
interpid = _testinternalcapi.unused_interpreter_id()
2272+
self.assertFalse(
2273+
_testinternalcapi.interpreter_exists(interpid))
22652274

2266-
def test_destroyed(self):
2267-
id = _interpreters.create()
2268-
_interpreters.destroy(id)
2269-
with self.assertRaises(_interpreters.InterpreterNotFoundError):
2270-
self.InterpreterID(id) # unforced
2271-
2272-
def test_str(self):
2273-
id = self.InterpreterID(10, force=True)
2274-
self.assertEqual(str(id), '10')
2275-
2276-
def test_repr(self):
2277-
id = self.InterpreterID(10, force=True)
2278-
self.assertEqual(repr(id), 'InterpreterID(10)')
2279-
2280-
def test_equality(self):
2281-
id1 = self.new_interpreter()
2282-
id2 = self.InterpreterID(id1)
2283-
id3 = self.InterpreterID(
2284-
self.new_interpreter())
2285-
2286-
self.assertTrue(id2 == id2) # identity
2287-
self.assertTrue(id2 == id1) # int-equivalent
2288-
self.assertTrue(id1 == id2) # reversed
2289-
self.assertTrue(id2 == int(id2))
2290-
self.assertTrue(id2 == float(int(id2)))
2291-
self.assertTrue(float(int(id2)) == id2)
2292-
self.assertFalse(id2 == float(int(id2)) + 0.1)
2293-
self.assertFalse(id2 == str(int(id2)))
2294-
self.assertFalse(id2 == 2**1000)
2295-
self.assertFalse(id2 == float('inf'))
2296-
self.assertFalse(id2 == 'spam')
2297-
self.assertFalse(id2 == id3)
2298-
2299-
self.assertFalse(id2 != id2)
2300-
self.assertFalse(id2 != id1)
2301-
self.assertFalse(id1 != id2)
2302-
self.assertTrue(id2 != id3)
2275+
with self.subTest('destroyed'):
2276+
interpid = _interpreters.create()
2277+
_interpreters.destroy(interpid)
2278+
self.assertFalse(
2279+
_testinternalcapi.interpreter_exists(interpid))
23032280

23042281
def test_linked_lifecycle(self):
2305-
id1 = _interpreters.create()
2306-
_testinternalcapi.unlink_interpreter_refcount(id1)
2307-
self.assertEqual(
2308-
_testinternalcapi.get_interpreter_refcount(id1),
2309-
0)
2310-
2311-
id2 = self.InterpreterID(id1)
2282+
def create():
2283+
interpid = _testinternalcapi.new_interpreter()
2284+
self.add_interp_cleanup(interpid)
2285+
return interpid
2286+
2287+
exists = _testinternalcapi.interpreter_exists
2288+
is_linked = _testinternalcapi.interpreter_refcount_linked
2289+
link = _testinternalcapi.link_interpreter_refcount
2290+
unlink = _testinternalcapi.unlink_interpreter_refcount
2291+
get_refcount = _testinternalcapi.get_interpreter_refcount
2292+
incref = _testinternalcapi.interpreter_incref
2293+
decref = _testinternalcapi.interpreter_decref
2294+
2295+
with self.subTest('does not exist'):
2296+
interpid = _testinternalcapi.unused_interpreter_id()
2297+
self.assertFalse(
2298+
exists(interpid))
2299+
with self.assertRaises(_interpreters.InterpreterNotFoundError):
2300+
is_linked(interpid)
2301+
with self.assertRaises(_interpreters.InterpreterNotFoundError):
2302+
link(interpid)
2303+
with self.assertRaises(_interpreters.InterpreterNotFoundError):
2304+
unlink(interpid)
2305+
with self.assertRaises(_interpreters.InterpreterNotFoundError):
2306+
get_refcount(interpid)
2307+
with self.assertRaises(_interpreters.InterpreterNotFoundError):
2308+
incref(interpid)
2309+
with self.assertRaises(_interpreters.InterpreterNotFoundError):
2310+
decref(interpid)
2311+
2312+
with self.subTest('destroyed'):
2313+
interpid = _interpreters.create()
2314+
_interpreters.destroy(interpid)
2315+
self.assertFalse(
2316+
exists(interpid))
2317+
with self.assertRaises(_interpreters.InterpreterNotFoundError):
2318+
is_linked(interpid)
2319+
with self.assertRaises(_interpreters.InterpreterNotFoundError):
2320+
link(interpid)
2321+
with self.assertRaises(_interpreters.InterpreterNotFoundError):
2322+
unlink(interpid)
2323+
with self.assertRaises(_interpreters.InterpreterNotFoundError):
2324+
get_refcount(interpid)
2325+
with self.assertRaises(_interpreters.InterpreterNotFoundError):
2326+
incref(interpid)
2327+
with self.assertRaises(_interpreters.InterpreterNotFoundError):
2328+
decref(interpid)
2329+
2330+
# A new interpreter will start out not linked, with a refcount of 0.
2331+
interpid = create()
2332+
self.assertFalse(
2333+
is_linked(interpid))
23122334
self.assertEqual(
2313-
_testinternalcapi.get_interpreter_refcount(id1),
2314-
1)
2315-
2316-
# The interpreter isn't linked to ID objects, so it isn't destroyed.
2317-
del id2
2318-
self.assertEqual(
2319-
_testinternalcapi.get_interpreter_refcount(id1),
2320-
0)
2321-
2322-
_testinternalcapi.link_interpreter_refcount(id1)
2323-
self.assertEqual(
2324-
_testinternalcapi.get_interpreter_refcount(id1),
2325-
0)
2326-
2327-
id3 = self.InterpreterID(id1)
2328-
self.assertEqual(
2329-
_testinternalcapi.get_interpreter_refcount(id1),
2330-
1)
2331-
2332-
# The interpreter is linked now so is destroyed.
2333-
del id3
2334-
with self.assertRaises(_interpreters.InterpreterNotFoundError):
2335-
_testinternalcapi.get_interpreter_refcount(id1)
2335+
0, get_refcount(interpid))
2336+
2337+
with self.subTest('never linked'):
2338+
interpid = create()
2339+
2340+
# Incref will not automatically link it.
2341+
incref(interpid)
2342+
self.assertFalse(
2343+
is_linked(interpid))
2344+
self.assertEqual(
2345+
1, get_refcount(interpid))
2346+
2347+
# It isn't linked so it isn't destroyed.
2348+
decref(interpid)
2349+
self.assertTrue(
2350+
exists(interpid))
2351+
self.assertFalse(
2352+
is_linked(interpid))
2353+
self.assertEqual(
2354+
0, get_refcount(interpid))
2355+
2356+
with self.subTest('linking/unlinking at refcount 0 does not destroy'):
2357+
interpid = create()
2358+
2359+
link(interpid)
2360+
self.assertTrue(
2361+
exists(interpid))
2362+
2363+
unlink(interpid)
2364+
self.assertTrue(
2365+
exists(interpid))
2366+
2367+
with self.subTest('link -> incref -> decref => destroyed'):
2368+
interpid = create()
2369+
2370+
# Linking it will not change the refcount.
2371+
link(interpid)
2372+
self.assertTrue(
2373+
is_linked(interpid))
2374+
self.assertEqual(
2375+
0, get_refcount(interpid))
2376+
2377+
# Decref with a refcount of 0 is not allowed.
2378+
incref(interpid)
2379+
self.assertEqual(
2380+
1, get_refcount(interpid))
2381+
2382+
# When linked, decref back to 0 destroys the interpreter.
2383+
decref(interpid)
2384+
self.assertFalse(
2385+
exists(interpid))
2386+
2387+
with self.subTest('linked after incref'):
2388+
interpid = create()
2389+
2390+
incref(interpid)
2391+
self.assertEqual(
2392+
1, get_refcount(interpid))
2393+
2394+
# Linking it will not reset the refcount.
2395+
link(interpid)
2396+
self.assertEqual(
2397+
1, get_refcount(interpid))
2398+
2399+
with self.subTest('decref to 0 after unlink does not destroy'):
2400+
interpid = create()
2401+
2402+
link(interpid)
2403+
self.assertTrue(
2404+
is_linked(interpid))
2405+
2406+
incref(interpid)
2407+
self.assertEqual(
2408+
1, get_refcount(interpid))
2409+
2410+
# Unlinking it will not change the refcount.
2411+
unlink(interpid)
2412+
self.assertFalse(
2413+
is_linked(interpid))
2414+
self.assertEqual(
2415+
1, get_refcount(interpid))
2416+
2417+
# When linked, decref back to 0 destroys the interpreter.
2418+
decref(interpid)
2419+
self.assertTrue(
2420+
exists(interpid))
2421+
self.assertEqual(
2422+
0, get_refcount(interpid))
23362423

23372424

23382425
class BuiltinStaticTypesTests(unittest.TestCase):

0 commit comments

Comments
 (0)