Skip to content

Commit e022504

Browse files
committed
gh-156495: Don't warn about a non-normalized sys.prefix in a venv
1 parent eb08902 commit e022504

3 files changed

Lines changed: 58 additions & 2 deletions

File tree

Lib/site.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,11 +1031,14 @@ def _venv(state):
10311031
)
10321032
break
10331033

1034-
if sys.prefix != site_prefix:
1034+
# site_prefix is already normalised by the abspath() above, but sys.prefix
1035+
# isn't. Normalise before comparing, or two spellings of the same directory
1036+
# look like a mismatch.
1037+
if os.path.normpath(sys.prefix) != site_prefix:
10351038
_warn(
10361039
f'Unexpected value in sys.prefix, expected {site_prefix}, got {sys.prefix}',
10371040
RuntimeWarning)
1038-
if sys.exec_prefix != site_prefix:
1041+
if os.path.normpath(sys.exec_prefix) != site_prefix:
10391042
_warn(
10401043
f'Unexpected value in sys.exec_prefix, expected {site_prefix}, got {sys.exec_prefix}',
10411044
RuntimeWarning)

Lib/test/test_venv.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,55 @@ def test_prefixes(self):
302302
self.assertEqual(pathlib.Path(out.strip().decode()),
303303
pathlib.Path(expected), prefix)
304304

305+
@requireVenvCreate
306+
def test_prefixes_with_non_normalised_executable(self):
307+
"""
308+
Test that a non-normalised executable path isn't counted as a mismatch.
309+
"""
310+
# gh-156495: sys.prefix isn't normalised, but the prefix derived from
311+
# sys.executable is, so a string comparison flagged two spellings of the
312+
# same directory.
313+
rmtree(self.env_dir)
314+
self.run_with_capture(venv.create, self.env_dir)
315+
# Run from a directory next to the env so argv[0] starts with '..',
316+
# which normpath() can't collapse.
317+
subdir = tempfile.mkdtemp(dir=os.path.dirname(self.env_dir))
318+
self.addCleanup(rmtree, subdir)
319+
relative_exe = os.path.join(
320+
os.pardir, os.path.basename(self.env_dir), self.bindir, self.exe)
321+
p = subprocess.run(
322+
[relative_exe, '-c',
323+
'import sys; print(sys.prefix); print(sys.exec_prefix)'],
324+
cwd=subdir, capture_output=True, encoding='utf-8',
325+
env={**os.environ, 'PYTHONHOME': ''})
326+
self.assertEqual(p.returncode, 0, p.stderr)
327+
self.assertNotIn('Unexpected value in sys.prefix', p.stderr)
328+
self.assertNotIn('Unexpected value in sys.exec_prefix', p.stderr)
329+
prefix, exec_prefix = p.stdout.splitlines()
330+
for name, value in (('prefix', prefix), ('exec_prefix', exec_prefix)):
331+
self.assertEqual(os.path.realpath(value),
332+
os.path.realpath(self.env_dir), name)
333+
334+
@requireVenvCreate
335+
def test_prefixes_mismatch_is_still_reported(self):
336+
"""
337+
Test that a genuine prefix mismatch is still reported.
338+
"""
339+
rmtree(self.env_dir)
340+
self.run_with_capture(venv.create, self.env_dir)
341+
# Move pyvenv.cfg next to the interpreter instead of leaving it in the
342+
# prefix, so that sys.prefix and the prefix derived from sys.executable
343+
# differ for real and not only in spelling.
344+
os.rename(os.path.join(self.env_dir, 'pyvenv.cfg'),
345+
os.path.join(self.env_dir, self.bindir, 'pyvenv.cfg'))
346+
p = subprocess.run(
347+
[self.envpy(), '-c', 'import sys; print(sys.prefix)'],
348+
capture_output=True, encoding='utf-8',
349+
env={**os.environ, 'PYTHONHOME': ''})
350+
self.assertEqual(p.returncode, 0, p.stderr)
351+
self.assertIn('Unexpected value in sys.prefix', p.stderr)
352+
self.assertIn('Unexpected value in sys.exec_prefix', p.stderr)
353+
305354
@requireVenvCreate
306355
def test_sysconfig(self):
307356
"""
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Fix a false-positive :exc:`RuntimeWarning` from :mod:`site` when a virtual
2+
environment interpreter is started through a non-normalised path such as
3+
``../.venv/bin/python``. ``sys.prefix`` and the prefix derived from
4+
:data:`sys.executable` are now compared in normalised form.

0 commit comments

Comments
 (0)