Skip to content

Commit ab8f175

Browse files
Add get_current() and enumerate().
1 parent 777838a commit ab8f175

File tree

3 files changed

+97
-28
lines changed

3 files changed

+97
-28
lines changed

Doc/library/_interpreters.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ support multiple interpreters.
3131

3232
It defines the following functions:
3333

34+
.. function:: enumerate()
35+
36+
Return a list of the IDs of every existing interpreter.
37+
38+
39+
.. function:: get_current()
40+
41+
Return the ID of the currently running interpreter.
42+
43+
3444
.. function:: create()
3545

3646
Initialize a new Python interpreter and return its identifier. The

Lib/test/test__interpreters.py

Lines changed: 62 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def test_still_running_at_exit(self):
6767
class TestBase(unittest.TestCase):
6868

6969
def tearDown(self):
70-
for id in interpreters._enumerate():
70+
for id in interpreters.enumerate():
7171
if id == 0: # main
7272
continue
7373
try:
@@ -76,13 +76,49 @@ def tearDown(self):
7676
pass # already destroyed
7777

7878

79+
class EnumerateTests(TestBase):
80+
81+
def test_multiple(self):
82+
main, = interpreters.enumerate()
83+
id1 = interpreters.create()
84+
id2 = interpreters.create()
85+
ids = interpreters.enumerate()
86+
87+
self.assertEqual(set(ids), {main, id1, id2})
88+
89+
def test_main_only(self):
90+
main, = interpreters.enumerate()
91+
92+
self.assertEqual(main, 0)
93+
94+
95+
class GetCurrentTests(TestBase):
96+
97+
def test_main(self):
98+
main, = interpreters.enumerate()
99+
id = interpreters.get_current()
100+
101+
self.assertEqual(id, main)
102+
103+
def test_sub(self):
104+
id1 = interpreters.create()
105+
ns = interpreters.run_string_unrestricted(id1, dedent("""
106+
import _interpreters
107+
id = _interpreters.get_current()
108+
"""))
109+
id2 = ns['id']
110+
111+
self.assertEqual(id2, id1)
112+
113+
79114
class CreateTests(TestBase):
80115

81116
def test_in_main(self):
82117
id = interpreters.create()
83118

84-
self.assertIn(id, interpreters._enumerate())
119+
self.assertIn(id, interpreters.enumerate())
85120

121+
@unittest.skip('enable this test when working on pystate.c')
86122
def test_unique_id(self):
87123
seen = set()
88124
for _ in range(100):
@@ -105,21 +141,21 @@ def f():
105141
with lock:
106142
t.start()
107143
t.join()
108-
self.assertIn(id, interpreters._enumerate())
144+
self.assertIn(id, interpreters.enumerate())
109145

110146
def test_in_subinterpreter(self):
111-
main, = interpreters._enumerate()
147+
main, = interpreters.enumerate()
112148
id1 = interpreters.create()
113149
ns = interpreters.run_string_unrestricted(id1, dedent("""
114150
import _interpreters
115151
id = _interpreters.create()
116152
"""))
117153
id2 = ns['id']
118154

119-
self.assertEqual(set(interpreters._enumerate()), {main, id1, id2})
155+
self.assertEqual(set(interpreters.enumerate()), {main, id1, id2})
120156

121157
def test_in_threaded_subinterpreter(self):
122-
main, = interpreters._enumerate()
158+
main, = interpreters.enumerate()
123159
id1 = interpreters.create()
124160
ns = None
125161
script = dedent("""
@@ -135,11 +171,11 @@ def f():
135171
t.join()
136172
id2 = ns['id']
137173

138-
self.assertEqual(set(interpreters._enumerate()), {main, id1, id2})
174+
self.assertEqual(set(interpreters.enumerate()), {main, id1, id2})
139175

140176

141177
def test_after_destroy_all(self):
142-
before = set(interpreters._enumerate())
178+
before = set(interpreters.enumerate())
143179
# Create 3 subinterpreters.
144180
ids = []
145181
for _ in range(3):
@@ -150,10 +186,10 @@ def test_after_destroy_all(self):
150186
interpreters.destroy(id)
151187
# Finally, create another.
152188
id = interpreters.create()
153-
self.assertEqual(set(interpreters._enumerate()), before | {id})
189+
self.assertEqual(set(interpreters.enumerate()), before | {id})
154190

155191
def test_after_destroy_some(self):
156-
before = set(interpreters._enumerate())
192+
before = set(interpreters.enumerate())
157193
# Create 3 subinterpreters.
158194
id1 = interpreters.create()
159195
id2 = interpreters.create()
@@ -163,7 +199,7 @@ def test_after_destroy_some(self):
163199
interpreters.destroy(id3)
164200
# Finally, create another.
165201
id = interpreters.create()
166-
self.assertEqual(set(interpreters._enumerate()), before | {id, id2})
202+
self.assertEqual(set(interpreters.enumerate()), before | {id, id2})
167203

168204

169205
class DestroyTests(TestBase):
@@ -172,25 +208,25 @@ def test_one(self):
172208
id1 = interpreters.create()
173209
id2 = interpreters.create()
174210
id3 = interpreters.create()
175-
self.assertIn(id2, interpreters._enumerate())
211+
self.assertIn(id2, interpreters.enumerate())
176212
interpreters.destroy(id2)
177-
self.assertNotIn(id2, interpreters._enumerate())
178-
self.assertIn(id1, interpreters._enumerate())
179-
self.assertIn(id3, interpreters._enumerate())
213+
self.assertNotIn(id2, interpreters.enumerate())
214+
self.assertIn(id1, interpreters.enumerate())
215+
self.assertIn(id3, interpreters.enumerate())
180216

181217
def test_all(self):
182-
before = set(interpreters._enumerate())
218+
before = set(interpreters.enumerate())
183219
ids = set()
184220
for _ in range(3):
185221
id = interpreters.create()
186222
ids.add(id)
187-
self.assertEqual(set(interpreters._enumerate()), before | ids)
223+
self.assertEqual(set(interpreters.enumerate()), before | ids)
188224
for id in ids:
189225
interpreters.destroy(id)
190-
self.assertEqual(set(interpreters._enumerate()), before)
226+
self.assertEqual(set(interpreters.enumerate()), before)
191227

192228
def test_main(self):
193-
main, = interpreters._enumerate()
229+
main, = interpreters.enumerate()
194230
with self.assertRaises(RuntimeError):
195231
interpreters.destroy(main)
196232

@@ -217,7 +253,7 @@ def test_bad_id(self):
217253
interpreters.destroy(-1)
218254

219255
def test_from_current(self):
220-
main, = interpreters._enumerate()
256+
main, = interpreters.enumerate()
221257
id = interpreters.create()
222258
script = dedent("""
223259
import _interpreters
@@ -226,10 +262,10 @@ def test_from_current(self):
226262

227263
with self.assertRaises(RuntimeError):
228264
interpreters.run_string(id, script)
229-
self.assertEqual(set(interpreters._enumerate()), {main, id})
265+
self.assertEqual(set(interpreters.enumerate()), {main, id})
230266

231267
def test_from_sibling(self):
232-
main, = interpreters._enumerate()
268+
main, = interpreters.enumerate()
233269
id1 = interpreters.create()
234270
id2 = interpreters.create()
235271
script = dedent("""
@@ -238,7 +274,7 @@ def test_from_sibling(self):
238274
""").format(id2)
239275
interpreters.run_string(id1, script)
240276

241-
self.assertEqual(set(interpreters._enumerate()), {main, id1})
277+
self.assertEqual(set(interpreters.enumerate()), {main, id1})
242278

243279
def test_from_other_thread(self):
244280
id = interpreters.create()
@@ -252,7 +288,7 @@ def f():
252288
def test_still_running(self):
253289
# XXX Rewrite this test without files by using
254290
# run_string_unrestricted().
255-
main, = interpreters._enumerate()
291+
main, = interpreters.enumerate()
256292
id = interpreters.create()
257293
def f():
258294
interpreters.run_string(id, wait_script)
@@ -265,7 +301,7 @@ def f():
265301
interpreters.destroy(id)
266302

267303
t.join()
268-
self.assertEqual(set(interpreters._enumerate()), {main, id})
304+
self.assertEqual(set(interpreters.enumerate()), {main, id})
269305

270306

271307
class RunStringTests(TestBase):
@@ -389,7 +425,7 @@ def f():
389425

390426
def test_does_not_exist(self):
391427
id = 0
392-
while id in interpreters._enumerate():
428+
while id in interpreters.enumerate():
393429
id += 1
394430
with self.assertRaises(RuntimeError):
395431
interpreters.run_string(id, 'print("spam")')

Modules/_interpretersmodule.c

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,27 @@ interp_enumerate(PyObject *self)
446446
return ids;
447447
}
448448

449+
PyDoc_STRVAR(enumerate_doc,
450+
"enumerate() -> [ID]\n\
451+
\n\
452+
Return a list containing the ID of every existing interpreter.");
453+
454+
455+
static PyObject *
456+
interp_get_current(PyObject *self)
457+
{
458+
PyInterpreterState *interp =_get_current();
459+
if (interp == NULL)
460+
return NULL;
461+
return _get_id(interp);
462+
}
463+
464+
PyDoc_STRVAR(get_current_doc,
465+
"get_current() -> ID\n\
466+
\n\
467+
Return the ID of current interpreter.");
468+
469+
449470
static PyObject *
450471
interp_run_string(PyObject *self, PyObject *args)
451472
{
@@ -518,8 +539,10 @@ static PyMethodDef module_functions[] = {
518539
{"destroy", (PyCFunction)interp_destroy,
519540
METH_VARARGS, destroy_doc},
520541

521-
{"_enumerate", (PyCFunction)interp_enumerate,
522-
METH_NOARGS, NULL},
542+
{"enumerate", (PyCFunction)interp_enumerate,
543+
METH_NOARGS, enumerate_doc},
544+
{"get_current", (PyCFunction)interp_get_current,
545+
METH_NOARGS, get_current_doc},
523546

524547
{"run_string", (PyCFunction)interp_run_string,
525548
METH_VARARGS, run_string_doc},

0 commit comments

Comments
 (0)