Skip to content

Commit

Permalink
Add test_imp.ImportTests.test_singlephase_multiple_interpreters.
Browse files Browse the repository at this point in the history
  • Loading branch information
ericsnowcurrently committed Feb 14, 2023
1 parent 096d009 commit 49e4bfe
Showing 1 changed file with 57 additions and 0 deletions.
57 changes: 57 additions & 0 deletions Lib/test/test_imp.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import gc
import importlib
import importlib.util
import shutil
import os
import os.path
import py_compile
import sys
import tempfile
from test import support
from test.support import import_helper
from test.support import os_helper
from test.support import script_helper
from test.support import warnings_helper
import textwrap
import unittest
import warnings
imp = warnings_helper.import_deprecated('imp')
import _imp
import _xxsubinterpreters as _interpreters


OS_PATH_NAME = os.path.__name__
Expand Down Expand Up @@ -67,6 +71,17 @@ def setUp(self):
self.test_strings = mod.test_strings
self.test_path = mod.__path__

def _copy_extension(self, name):
fileobj, pathname, _ = imp.find_module('_testsinglephase')
fileobj.close()

dirname = tempfile.mkdtemp()
self.addCleanup(os_helper.rmtree, dirname)

copied = os.path.join(dirname, os.path.basename(pathname))
shutil.copyfile(pathname, copied)
return copied

# test_import_encoded_module moved to test_source_encoding.py

def test_find_module_encoding(self):
Expand Down Expand Up @@ -251,6 +266,48 @@ def test_issue16421_multiple_modules_in_one_dll(self):
with self.assertRaises(ImportError):
imp.load_dynamic('nonexistent', pathname)

@requires_load_dynamic
def test_singlephase_multiple_interpreters(self):
# Currently, for every single-phrase init module loaded
# in multiple interpreters, those interpreters share a
# PyModuleDef for that object, which can be a problem.

# This single-phase module has global state, which is shared
# by the interpreters.
name = '_testsinglephase'
filename = self._copy_extension(name)

interp1 = _interpreters.create(isolated=False)
self.addCleanup(_interpreters.destroy, interp1)
interp2 = _interpreters.create(isolated=False)
self.addCleanup(_interpreters.destroy, interp2)

script = textwrap.dedent(f'''
from test.support import warnings_helper
imp = warnings_helper.import_deprecated('imp')
module = imp.load_dynamic({name!r}, {filename!r})
init_count = module.initialized_count()
if init_count != %d:
raise Exception(init_count)
lookedup = module.look_up_self()
if lookedup is not module:
raise Exception((module, lookedup))
''')
# Use an interpreter that gets destroyed right away.
ret = support.run_in_subinterp(script % 1)
self.assertEqual(ret, 0)

# The module's init func gets run again.
# The module's globals did not get destroyed.
_interpreters.run_string(interp1, script % 2)

# The module's init func is not run again.
# The second interpreter copies the module's m_copy.
# However, globals are still shared.
_interpreters.run_string(interp2, script % 2)

@requires_load_dynamic
def test_singlephase_variants(self):
'''Exercise the most meaningful variants described in Python/import.c.'''
Expand Down

0 comments on commit 49e4bfe

Please sign in to comment.