Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 92ca90b

Browse filesBrowse files
gh-76785: Support Running Some Functions in Subinterpreters (gh-110251)
This specifically refers to `test.support.interpreters.Interpreter.run()`.
1 parent de10522 commit 92ca90b
Copy full SHA for 92ca90b

File tree

3 files changed

+439
-26
lines changed
Filter options

3 files changed

+439
-26
lines changed

‎Lib/test/support/interpreters.py

Copy file name to clipboardExpand all lines: Lib/test/support/interpreters.py
+16-2Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,26 @@ def close(self):
9191
"""
9292
return _interpreters.destroy(self._id)
9393

94+
# XXX Rename "run" to "exec"?
9495
def run(self, src_str, /, *, channels=None):
9596
"""Run the given source code in the interpreter.
9697
97-
This blocks the current Python thread until done.
98+
This is essentially the same as calling the builtin "exec"
99+
with this interpreter, using the __dict__ of its __main__
100+
module as both globals and locals.
101+
102+
There is no return value.
103+
104+
If the code raises an unhandled exception then a RunFailedError
105+
is raised, which summarizes the unhandled exception. The actual
106+
exception is discarded because objects cannot be shared between
107+
interpreters.
108+
109+
This blocks the current Python thread until done. During
110+
that time, the previous interpreter is allowed to run
111+
in other threads.
98112
"""
99-
_interpreters.run_string(self._id, src_str, channels)
113+
_interpreters.exec(self._id, src_str, channels)
100114

101115

102116
def create_channel():

‎Lib/test/test__xxsubinterpreters.py

Copy file name to clipboardExpand all lines: Lib/test/test__xxsubinterpreters.py
+105Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -925,5 +925,110 @@ def f():
925925
self.assertEqual(retcode, 0)
926926

927927

928+
class RunFuncTests(TestBase):
929+
930+
def setUp(self):
931+
super().setUp()
932+
self.id = interpreters.create()
933+
934+
def test_success(self):
935+
r, w = os.pipe()
936+
def script():
937+
global w
938+
import contextlib
939+
with open(w, 'w', encoding="utf-8") as spipe:
940+
with contextlib.redirect_stdout(spipe):
941+
print('it worked!', end='')
942+
interpreters.run_func(self.id, script, shared=dict(w=w))
943+
944+
with open(r, encoding="utf-8") as outfile:
945+
out = outfile.read()
946+
947+
self.assertEqual(out, 'it worked!')
948+
949+
def test_in_thread(self):
950+
r, w = os.pipe()
951+
def script():
952+
global w
953+
import contextlib
954+
with open(w, 'w', encoding="utf-8") as spipe:
955+
with contextlib.redirect_stdout(spipe):
956+
print('it worked!', end='')
957+
def f():
958+
interpreters.run_func(self.id, script, shared=dict(w=w))
959+
t = threading.Thread(target=f)
960+
t.start()
961+
t.join()
962+
963+
with open(r, encoding="utf-8") as outfile:
964+
out = outfile.read()
965+
966+
self.assertEqual(out, 'it worked!')
967+
968+
def test_code_object(self):
969+
r, w = os.pipe()
970+
971+
def script():
972+
global w
973+
import contextlib
974+
with open(w, 'w', encoding="utf-8") as spipe:
975+
with contextlib.redirect_stdout(spipe):
976+
print('it worked!', end='')
977+
code = script.__code__
978+
interpreters.run_func(self.id, code, shared=dict(w=w))
979+
980+
with open(r, encoding="utf-8") as outfile:
981+
out = outfile.read()
982+
983+
self.assertEqual(out, 'it worked!')
984+
985+
def test_closure(self):
986+
spam = True
987+
def script():
988+
assert spam
989+
990+
with self.assertRaises(ValueError):
991+
interpreters.run_func(self.id, script)
992+
993+
# XXX This hasn't been fixed yet.
994+
@unittest.expectedFailure
995+
def test_return_value(self):
996+
def script():
997+
return 'spam'
998+
with self.assertRaises(ValueError):
999+
interpreters.run_func(self.id, script)
1000+
1001+
def test_args(self):
1002+
with self.subTest('args'):
1003+
def script(a, b=0):
1004+
assert a == b
1005+
with self.assertRaises(ValueError):
1006+
interpreters.run_func(self.id, script)
1007+
1008+
with self.subTest('*args'):
1009+
def script(*args):
1010+
assert not args
1011+
with self.assertRaises(ValueError):
1012+
interpreters.run_func(self.id, script)
1013+
1014+
with self.subTest('**kwargs'):
1015+
def script(**kwargs):
1016+
assert not kwargs
1017+
with self.assertRaises(ValueError):
1018+
interpreters.run_func(self.id, script)
1019+
1020+
with self.subTest('kwonly'):
1021+
def script(*, spam=True):
1022+
assert spam
1023+
with self.assertRaises(ValueError):
1024+
interpreters.run_func(self.id, script)
1025+
1026+
with self.subTest('posonly'):
1027+
def script(spam, /):
1028+
assert spam
1029+
with self.assertRaises(ValueError):
1030+
interpreters.run_func(self.id, script)
1031+
1032+
9281033
if __name__ == '__main__':
9291034
unittest.main()

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.