def test_mutate_exception(self): """ Exceptions saved in global module state get shared between individual module instances. This test checks whether or not a change in one interpreter's module gets reflected into the other ones. """ import binascii support.run_in_subinterp("import binascii; binascii.Error.foobar = 'foobar'") self.assertFalse(hasattr(binascii.Error, "foobar"))
def test_module_state_shared_in_global(self): """ bpo-44050: Extension module state should be shared between interpreters when it doesn't support sub-interpreters. """ r, w = os.pipe() self.addCleanup(os.close, r) self.addCleanup(os.close, w) script = textwrap.dedent(f""" import importlib.machinery import importlib.util import os fullname = '_test_module_state_shared' origin = importlib.util.find_spec('_testmultiphase').origin loader = importlib.machinery.ExtensionFileLoader(fullname, origin) spec = importlib.util.spec_from_loader(fullname, loader) module = importlib.util.module_from_spec(spec) attr_id = str(id(module.Error)).encode() os.write({w}, attr_id) """) exec(script) main_attr_id = os.read(r, 100) ret = support.run_in_subinterp(script) self.assertEqual(ret, 0) subinterp_attr_id = os.read(r, 100) self.assertEqual(main_attr_id, subinterp_attr_id)
def test_callbacks_leak_refcycle(self): n = atexit._ncallbacks() code = """if 1: import atexit def f(): pass atexit.register(f) atexit.__atexit = atexit """ ret = support.run_in_subinterp(code) self.assertEqual(ret, 0) self.assertEqual(atexit._ncallbacks(), n)
def test_subinterps(self): import builtins r, w = os.pipe() code = """if 1: import sys, builtins, pickle with open({:d}, "wb") as f: pickle.dump(id(sys.modules), f) pickle.dump(id(builtins), f) """.format(w) with open(r, "rb") as f: ret = support.run_in_subinterp(code) self.assertEqual(ret, 0) self.assertNotEqual(pickle.load(f), id(sys.modules)) self.assertNotEqual(pickle.load(f), id(builtins))
def test_callbacks_leak_refcycle(self): # Similar to the above, but with a refcycle through the atexit # module. n = atexit._ncallbacks() code = textwrap.dedent(r""" import atexit def f(): pass atexit.register(f) atexit.__atexit = atexit """) ret = support.run_in_subinterp(code) self.assertEqual(ret, 0) self.assertEqual(atexit._ncallbacks(), n)
def test_callbacks_leak_refcycle(self): # Similar to the above, but with a refcycle through the atexit # module. n = atexit._ncallbacks() code = r"""if 1: import atexit def f(): pass atexit.register(f) atexit.__atexit = atexit """ ret = support.run_in_subinterp(code) self.assertEqual(ret, 0) self.assertEqual(atexit._ncallbacks(), n)
def test_callbacks_leak(self): # This test shows a leak in refleak mode if atexit doesn't # take care to free callbacks in its per-subinterpreter module # state. n = atexit._ncallbacks() code = textwrap.dedent(r""" import atexit def f(): pass atexit.register(f) del atexit """) ret = support.run_in_subinterp(code) self.assertEqual(ret, 0) self.assertEqual(atexit._ncallbacks(), n)
def test_callbacks_leak(self): # This test shows a leak in refleak mode if atexit doesn't # take care to free callbacks in its per-subinterpreter module # state. n = atexit._ncallbacks() code = r"""if 1: import atexit def f(): pass atexit.register(f) del atexit """ ret = support.run_in_subinterp(code) self.assertEqual(ret, 0) self.assertEqual(atexit._ncallbacks(), n)
def test_callback_on_subinterpreter_teardown(self): # This tests if a callback is called on # subinterpreter teardown. expected = b"The test has passed!" r, w = os.pipe() code = textwrap.dedent(r""" import os import atexit def callback(): os.write({:d}, b"The test has passed!") atexit.register(callback) """.format(w)) ret = support.run_in_subinterp(code) os.close(w) self.assertEqual(os.read(r, len(expected)), expected) os.close(r)
def test_callback_on_subinterpreter_teardown(self): # This tests if a callback is called on # subinterpreter teardown. expected = b"The test has passed!" r, w = os.pipe() code = r"""if 1: import os import atexit def callback(): os.write({:d}, b"The test has passed!") atexit.register(callback) """.format(w) ret = support.run_in_subinterp(code) os.close(w) self.assertEqual(os.read(r, len(expected)), expected) os.close(r)
def test_subinterps_recent_language_features(self): r, w = os.pipe() code = """if 1: import pickle with open({:d}, "wb") as f: def noop(x): return x a = (b := f'1{{2}}3') + noop('x') # Py 3.8 (:=) / 3.6 (f'') async def foo(arg): return await arg # Py 3.5 pickle.dump(dict(a=a, b=b), f) """.format(w) with open(r, "rb") as f: ret = support.run_in_subinterp(code) self.assertEqual(ret, 0) self.assertEqual(pickle.load(f), {'a': '123x', 'b': '123'})
def run_payload(payload: str) -> None: support.run_in_subinterp(payload)