Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b05327e

Browse files
Add restrictions.
1 parent fa297ef commit b05327e

4 files changed

Lines changed: 214 additions & 120 deletions

File tree

Lib/test/support/interpreters/__init__.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ class Interpreter:
106106
"id" - the unique process-global ID number for the interpreter
107107
"owned" - indicates whether or not the interpreter was created
108108
by interpreters.create()
109+
110+
If interp.owned is false then any method that modifies the
111+
interpreter will fail, i.e. .close(), .prepare_main(), .exec(),
112+
and .call()
109113
"""
110114

111115
def __new__(cls, id, /, _owned=None):
@@ -165,23 +169,27 @@ def owned(self):
165169

166170
def is_running(self):
167171
"""Return whether or not the identified interpreter is running."""
168-
return _interpreters.is_running(self._id)
172+
# require_owned is okay since this doesn't modify the interpreter.
173+
return _interpreters.is_running(self._id, require_owned=False)
174+
175+
# Everything past here is available only to interpreters created by
176+
# interpreters.create().
169177

170178
def close(self):
171179
"""Finalize and destroy the interpreter.
172180
173181
Attempting to destroy the current interpreter results
174182
in an InterpreterError.
175183
"""
176-
return _interpreters.destroy(self._id)
184+
return _interpreters.destroy(self._id, require_owned=True)
177185

178186
def prepare_main(self, ns=None, /, **kwargs):
179187
"""Bind the given values into the interpreter's __main__.
180188
181189
The values must be shareable.
182190
"""
183191
ns = dict(ns, **kwargs) if ns is not None else kwargs
184-
_interpreters.set___main___attrs(self._id, ns)
192+
_interpreters.set___main___attrs(self._id, ns, require_owned=True)
185193

186194
def exec(self, code, /):
187195
"""Run the given source code in the interpreter.
@@ -201,7 +209,7 @@ def exec(self, code, /):
201209
that time, the previous interpreter is allowed to run
202210
in other threads.
203211
"""
204-
excinfo = _interpreters.exec(self._id, code)
212+
excinfo = _interpreters.exec(self._id, code, require_owned=True)
205213
if excinfo is not None:
206214
raise ExecutionFailed(excinfo)
207215

@@ -221,7 +229,7 @@ def call(self, callable, /):
221229
# XXX Support args and kwargs.
222230
# XXX Support arbitrary callables.
223231
# XXX Support returning the return value (e.g. via pickle).
224-
excinfo = _interpreters.call(self._id, callable)
232+
excinfo = _interpreters.call(self._id, callable, require_owned=True)
225233
if excinfo is not None:
226234
raise ExecutionFailed(excinfo)
227235

Lib/test/test_interpreters/test_api.py

Lines changed: 62 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,7 @@ def test_created_with_capi(self):
597597
def check_results(err, text):
598598
self.assertIsNot(err, None)
599599
self.assertEqual(err.type.__name__, 'InterpreterError')
600-
self.assertIn('current', err.msg)
600+
self.assertIn('unrecognized', err.msg)
601601
self.assertEqual(text, '')
602602

603603
with self.subTest('running __main__ (from self)'):
@@ -612,30 +612,31 @@ def check_results(err, text):
612612
with self.subTest('running __main__ (from other)'):
613613
with self.interpreter_obj_from_capi() as (interp, interpid):
614614
with self.running_from_capi(interpid, main=True):
615-
with self.assertRaisesRegex(InterpreterError, 'running'):
615+
with self.assertRaisesRegex(InterpreterError, 'unrecognized'):
616616
interp.close()
617617
# Make sure it wssn't closed.
618618
self.assertTrue(
619-
interp.is_running())
619+
self.interp_exists(interpid))
620620

621-
# The rest must be skipped until we deal with running threads when
622-
# interp.close() is called.
623-
return
621+
# The rest would be skipped until we deal with running threads when
622+
# interp.close() is called. However, the "owned" restrictions
623+
# trigger first.
624624

625625
with self.subTest('running, but not __main__ (from other)'):
626626
with self.interpreter_obj_from_capi() as (interp, interpid):
627627
with self.running_from_capi(interpid, main=False):
628-
with self.assertRaisesRegex(InterpreterError, 'not managed'):
628+
with self.assertRaisesRegex(InterpreterError, 'unrecognized'):
629629
interp.close()
630630
# Make sure it wssn't closed.
631-
self.assertFalse(interp.is_running())
631+
self.assertTrue(
632+
self.interp_exists(interpid))
632633

633634
with self.subTest('not running (from other)'):
634-
with self.interpreter_obj_from_capi() as (interp, _):
635-
with self.assertRaisesRegex(InterpreterError, 'not managed'):
635+
with self.interpreter_obj_from_capi() as (interp, interpid):
636+
with self.assertRaisesRegex(InterpreterError, 'unrecognized'):
636637
interp.close()
637-
# Make sure it wssn't closed.
638-
self.assertFalse(interp.is_running())
638+
self.assertTrue(
639+
self.interp_exists(interpid))
639640

640641

641642
class TestInterpreterPrepareMain(TestBase):
@@ -702,14 +703,13 @@ def test_running(self):
702703
interp.prepare_main({'spam': False})
703704
interp.exec('assert spam is True')
704705

705-
@requires__testinternalcapi
706706
def test_created_with_capi(self):
707-
with self.interpreter_from_capi() as interpid:
708-
interp = interpreters.Interpreter(interpid)
709-
interp.prepare_main({'spam': True})
710-
rc = _testinternalcapi.exec_interpreter(interpid,
711-
'assert spam is True')
712-
assert rc == 0, rc
707+
with self.interpreter_obj_from_capi() as (interp, interpid):
708+
with self.assertRaisesRegex(InterpreterError, 'unrecognized'):
709+
interp.prepare_main({'spam': True})
710+
err, text = self.run_from_capi(interpid, 'assert spam is True')
711+
self.assertIsNot(err, None)
712+
self.assertEqual(err.type.__name__, 'NameError')
713713

714714

715715
class TestInterpreterExec(TestBase):
@@ -864,7 +864,7 @@ def task():
864864

865865
def test_created_with_capi(self):
866866
with self.interpreter_obj_from_capi() as (interp, _):
867-
with self.assertRaisesRegex(ExecutionFailed, 'it worked'):
867+
with self.assertRaisesRegex(InterpreterError, 'unrecognized'):
868868
interp.exec('raise Exception("it worked!")')
869869

870870
# test_xxsubinterpreters covers the remaining
@@ -1143,14 +1143,6 @@ class LowLevelTests(TestBase):
11431143
# encountered by the high-level module, thus they
11441144
# mostly shouldn't matter as much.
11451145

1146-
def interp_exists(self, interpid):
1147-
try:
1148-
_interpreters.is_owned(interpid)
1149-
except InterpreterNotFoundError:
1150-
return False
1151-
else:
1152-
return True
1153-
11541146
def test_new_config(self):
11551147
# This test overlaps with
11561148
# test.test_capi.test_misc.InterpreterConfigTests.
@@ -1443,7 +1435,11 @@ def test_destroy(self):
14431435

14441436
with self.subTest('from C-API'):
14451437
interpid = _testinternalcapi.create_interpreter()
1446-
_interpreters.destroy(interpid)
1438+
with self.assertRaisesRegex(InterpreterError, 'unrecognized'):
1439+
_interpreters.destroy(interpid)
1440+
self.assertTrue(
1441+
self.interp_exists(interpid))
1442+
_interpreters.destroy(interpid, require_owned=False)
14471443
self.assertFalse(
14481444
self.interp_exists(interpid))
14491445

@@ -1455,14 +1451,7 @@ def test_get_config(self):
14551451
expected = _interpreters.new_config('legacy')
14561452
expected.gil = 'own'
14571453
interpid, *_ = _interpreters.get_main()
1458-
config = _interpreters.get_config(interpid)
1459-
self.assert_ns_equal(config, expected)
1460-
1461-
with self.subTest('main'):
1462-
expected = _interpreters.new_config('legacy')
1463-
expected.gil = 'own'
1464-
interpid, *_ = _interpreters.get_main()
1465-
config = _interpreters.get_config(interpid)
1454+
config = _interpreters.get_config(interpid, require_owned=False)
14661455
self.assert_ns_equal(config, expected)
14671456

14681457
with self.subTest('isolated'):
@@ -1480,42 +1469,46 @@ def test_get_config(self):
14801469
with self.subTest('from C-API'):
14811470
orig = _interpreters.new_config('isolated')
14821471
with self.interpreter_from_capi(orig) as interpid:
1483-
config = _interpreters.get_config(interpid)
1472+
with self.assertRaisesRegex(InterpreterError, 'unrecognized'):
1473+
_interpreters.get_config(interpid)
1474+
config = _interpreters.get_config(interpid, require_owned=False)
14841475
self.assert_ns_equal(config, orig)
14851476

14861477
def test_is_running(self):
1487-
with self.subTest('main'):
1488-
interpid, *_ = _interpreters.get_main()
1489-
running = _interpreters.is_running(interpid)
1490-
self.assertTrue(running)
1478+
def check(interpid, expected):
1479+
with self.assertRaisesRegex(InterpreterError, 'unrecognized'):
1480+
_interpreters.is_running(interpid)
1481+
running = _interpreters.is_running(interpid, require_owned=False)
1482+
self.assertIs(running, expected)
14911483

14921484
with self.subTest('from _interpreters (running)'):
14931485
interpid = _interpreters.create()
14941486
with self.running(interpid):
14951487
running = _interpreters.is_running(interpid)
1496-
self.assertTrue(running)
1488+
self.assertTrue(running)
14971489

14981490
with self.subTest('from _interpreters (not running)'):
14991491
interpid = _interpreters.create()
15001492
running = _interpreters.is_running(interpid)
15011493
self.assertFalse(running)
15021494

1495+
with self.subTest('main'):
1496+
interpid, *_ = _interpreters.get_main()
1497+
check(interpid, True)
1498+
15031499
with self.subTest('from C-API (running __main__)'):
15041500
with self.interpreter_from_capi() as interpid:
15051501
with self.running_from_capi(interpid, main=True):
1506-
running = _interpreters.is_running(interpid)
1507-
self.assertTrue(running)
1502+
check(interpid, True)
15081503

15091504
with self.subTest('from C-API (running, but not __main__)'):
15101505
with self.interpreter_from_capi() as interpid:
15111506
with self.running_from_capi(interpid, main=False):
1512-
running = _interpreters.is_running(interpid)
1513-
self.assertFalse(running)
1507+
check(interpid, False)
15141508

15151509
with self.subTest('from C-API (not running)'):
15161510
with self.interpreter_from_capi() as interpid:
1517-
running = _interpreters.is_running(interpid)
1518-
self.assertFalse(running)
1511+
check(interpid, False)
15191512

15201513
def test_exec(self):
15211514
with self.subTest('run script'):
@@ -1551,7 +1544,13 @@ def test_exec(self):
15511544

15521545
with self.subTest('from C-API'):
15531546
with self.interpreter_from_capi() as interpid:
1554-
exc = _interpreters.exec(interpid, 'raise Exception("it worked!")')
1547+
with self.assertRaisesRegex(InterpreterError, 'unrecognized'):
1548+
_interpreters.exec(interpid, 'raise Exception("it worked!")')
1549+
exc = _interpreters.exec(
1550+
interpid,
1551+
'raise Exception("it worked!")',
1552+
require_owned=False,
1553+
)
15551554
self.assertIsNot(exc, None)
15561555
self.assertEqual(exc.msg, 'it worked!')
15571556

@@ -1576,6 +1575,7 @@ def test_call(self):
15761575
errdisplay=exc.errdisplay,
15771576
))
15781577

1578+
@requires__testinternalcapi
15791579
def test_set___main___attrs(self):
15801580
with self.subTest('from _interpreters'):
15811581
interpid = _interpreters.create()
@@ -1597,9 +1597,18 @@ def test_set___main___attrs(self):
15971597

15981598
with self.subTest('from C-API'):
15991599
with self.interpreter_from_capi() as interpid:
1600-
_interpreters.set___main___attrs(interpid, {'spam': True})
1601-
exc = _interpreters.exec(interpid, 'assert spam is True')
1602-
self.assertIsNone(exc)
1600+
with self.assertRaisesRegex(InterpreterError, 'unrecognized'):
1601+
_interpreters.set___main___attrs(interpid, {'spam': True})
1602+
_interpreters.set___main___attrs(
1603+
interpid,
1604+
{'spam': True},
1605+
require_owned=False,
1606+
)
1607+
rc = _testinternalcapi.exec_interpreter(
1608+
interpid,
1609+
'assert spam is True',
1610+
)
1611+
self.assertEqual(rc, 0)
16031612

16041613

16051614
if __name__ == '__main__':

Lib/test/test_interpreters/utils.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,14 @@ def run_and_capture(self, interp, script):
495495
else:
496496
return text
497497

498+
def interp_exists(self, interpid):
499+
try:
500+
_interpreters.is_owned(interpid)
501+
except _interpreters.InterpreterNotFoundError:
502+
return False
503+
else:
504+
return True
505+
498506
@requires__testinternalcapi
499507
@contextlib.contextmanager
500508
def interpreter_from_capi(self, config='legacy'):

0 commit comments

Comments
 (0)