10000 gh-109853: Fix sys.path[0] For Subinterpreters by ericsnowcurrently · Pull Request #109994 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-109853: Fix sys.path[0] For Subinterpreters #109994

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Next Next commit
Add a test.
  • Loading branch information
ericsnowcurrently committed Sep 27, 2023
commit 204d712aea6698a3f2e47a18f67a5448ff2fcadf
100 changes: 100 additions & 0 deletions Lib/test/test_interpreters.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import contextlib
import json
import os
import os.path
import sys
import threading
from textwrap import dedent
Expand All @@ -9,6 +11,7 @@
from test import support
from test.support import import_helper
from test.support import threading_helper
from test.support import os_helper
_interpreters = import_helper.import_module('_xxsubinterpreters')
_channels = import_helper.import_module('_xxinterpchannels')
from test.support import interpreters
Expand Down Expand Up @@ -488,6 +491,103 @@ def task():
pass


class StartupTests(TestBase):

# We want to ensure the initial state of subinterpreters
# matches expectations.

def create_temp_dir(self):
import tempfile
tmp = tempfile.mkdtemp(prefix='test_interpreters_')
tmp = os.path.realpath(tmp)
self.addCleanup(os_helper.rmtree, tmp)
return tmp

def write_script(self, *path, text):
filename = os.path.join(*path)
dirname = os.path.dirname(filename)
if dirname:
os.makedirs(dirname, exist_ok=True)
with open(filename, 'w', encoding='utf-8') as outfile:
outfile.write(dedent(text))
return filename

def run_cmd(self, cmd, *, cwd=None):
# This method is inspired by
# EmbeddingTestsMixin.run_embedded_interpreter() in test_embed.py.
import shlex
import subprocess
assert cmd.startswith('python3 '), repr(cmd)
if cmd.startswith('python3 '):
cmd = cmd.replace('python3', sys.executable, 1)
argv = shlex.split(cmd)
proc = subprocess.run(
argv,
cwd=cwd,
capture_output=True,
text=True,
)
if proc.stderr != '':
# This is a hack until _PyThreadState_MustExit() is fixed.
proc.returncode = 1
if proc.returncode != 0 and support.verbose:
print(f'--- {cmd} failed ---')
print(f'stdout:\n{proc.stdout}')
print(f'stderr:\n{proc.stderr}')
print('------')
self.assertEqual(proc.returncode, 0)
self.assertEqual(proc.stderr, '')
return proc.stdout

def test_sys_path_0(self):
# The main interpreter's sys.path[0] should be used by subinterpreters.

script = '''
import sys
from test.support import interpreters

orig = sys.path[0]

interp = interpreters.create()
interp.run(f"""if True:
import json
import sys
print(json.dumps({{
'main': {orig!r},
'sub': sys.path[0],
}}, indent=4), flush=True)
""")
'''

# <tmp>/
# pkg/
# __init__.py
# __main__.py
# script.py
# script.py
cwd = self.create_temp_dir()
self.write_script(cwd, 'pkg', '__init__.py', text='')
self.write_script(cwd, 'pkg', '__main__.py', text=script)
self.write_script(cwd, 'pkg', 'script.py', text=script)
self.write_script(cwd, 'script.py', text=script)

cases = [
('python3 script.py', cwd),
('python3 -m script', cwd),
('python3 -m pkg', cwd),
('python3 -m pkg.script', cwd),
('python3 -c "import script"', ''),
]
for cmd, expected in cases:
with self.subTest(cmd):
out = self.run_cmd(cmd, cwd=cwd)
data = json.loads(out)
sp0_main, sp0_sub = data['main'], data['sub']
self.assertEqual(sp0_sub, sp0_main)
self.assertEqual(sp0_sub, expected)
# XXX Also check them all with the -P cmdline flag?


class FinalizationTests(TestBase):

def test_gh_109793(self):
Expand Down
0