Skip to content

Commit f14c28f

Browse files
authored
bpo-34011: Fixes missing venv files and other tests (pythonGH-9458)
1 parent bc85475 commit f14c28f

File tree

8 files changed

+148
-114
lines changed

8 files changed

+148
-114
lines changed

Lib/distutils/tests/test_bdist.py

+3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ def test_skip_build(self):
3939

4040
for name in names:
4141
subcmd = cmd.get_finalized_command(name)
42+
if getattr(subcmd, '_unsupported', False):
43+
# command is not supported on this build
44+
continue
4245
self.assertTrue(subcmd.skip_build,
4346
'%s should take --skip-build from bdist' % name)
4447

Lib/distutils/tests/test_bdist_wininst.py

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
from distutils.command.bdist_wininst import bdist_wininst
66
from distutils.tests import support
77

8+
@unittest.skipIf(getattr(bdist_wininst, '_unsupported', False),
9+
'bdist_wininst is not supported in this install')
810
class BuildWinInstTestCase(support.TempdirManager,
911
support.LoggingSilencer,
1012
unittest.TestCase):

Lib/test/test_platform.py

+21-15
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import platform
44
import subprocess
55
import sys
6+
import sysconfig
67
import tempfile
78
import unittest
89
import warnings
@@ -16,29 +17,34 @@ def test_architecture(self):
1617
@support.skip_unless_symlink
1718
def test_architecture_via_symlink(self): # issue3762
1819
# On Windows, the EXE needs to know where pythonXY.dll and *.pyd is at
19-
# so we add the directory to the path and PYTHONPATH.
20+
# so we add the directory to the path, PYTHONHOME and PYTHONPATH.
21+
env = None
2022
if sys.platform == "win32":
21-
def restore_environ(old_env):
22-
os.environ.clear()
23-
os.environ.update(old_env)
24-
25-
self.addCleanup(restore_environ, dict(os.environ))
26-
27-
os.environ["Path"] = "{};{}".format(
28-
os.path.dirname(sys.executable), os.environ["Path"])
29-
os.environ["PYTHONPATH"] = os.path.dirname(sys.executable)
30-
31-
def get(python):
23+
env = {k.upper(): os.environ[k] for k in os.environ}
24+
env["PATH"] = "{};{}".format(
25+
os.path.dirname(sys.executable), env.get("PATH", ""))
26+
env["PYTHONHOME"] = os.path.dirname(sys.executable)
27+
if sysconfig.is_python_build(True):
28+
env["PYTHONPATH"] = os.path.dirname(os.__file__)
29+
30+
def get(python, env=None):
3231
cmd = [python, '-c',
3332
'import platform; print(platform.architecture())']
34-
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
35-
return p.communicate()
33+
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
34+
stderr=subprocess.PIPE, env=env)
35+
r = p.communicate()
36+
if p.returncode:
37+
print(repr(r[0]))
38+
print(repr(r[1]), file=sys.stderr)
39+
self.fail('unexpected return code: {0} (0x{0:08X})'
40+
.format(p.returncode))
41+
return r
3642

3743
real = os.path.realpath(sys.executable)
3844
link = os.path.abspath(support.TESTFN)
3945
os.symlink(real, link)
4046
try:
41-
self.assertEqual(get(real), get(link))
47+
self.assertEqual(get(real), get(link, env=env))
4248
finally:
4349
os.remove(link)
4450

Lib/test/test_site.py

+43-35
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
"""
77
import unittest
88
import test.support
9-
from test.support import captured_stderr, TESTFN, EnvironmentVarGuard
9+
from test.support import (captured_stderr, TESTFN, EnvironmentVarGuard,
10+
change_cwd)
1011
import builtins
1112
import os
1213
import sys
@@ -346,40 +347,47 @@ def test_abs_paths(self):
346347
# __file__ if abs_paths() does not get run. sys and builtins (the
347348
# only other modules imported before site.py runs) do not have
348349
# __file__ or __cached__ because they are built-in.
349-
parent = os.path.relpath(os.path.dirname(os.__file__))
350-
env = os.environ.copy()
351-
env['PYTHONPATH'] = parent
352-
code = ('import os, sys',
353-
# use ASCII to avoid locale issues with non-ASCII directories
354-
'os_file = os.__file__.encode("ascii", "backslashreplace")',
355-
r'sys.stdout.buffer.write(os_file + b"\n")',
356-
'os_cached = os.__cached__.encode("ascii", "backslashreplace")',
357-
r'sys.stdout.buffer.write(os_cached + b"\n")')
358-
command = '\n'.join(code)
359-
# First, prove that with -S (no 'import site'), the paths are
360-
# relative.
361-
proc = subprocess.Popen([sys.executable, '-S', '-c', command],
362-
env=env,
363-
stdout=subprocess.PIPE)
364-
stdout, stderr = proc.communicate()
365-
366-
self.assertEqual(proc.returncode, 0)
367-
os__file__, os__cached__ = stdout.splitlines()[:2]
368-
self.assertFalse(os.path.isabs(os__file__))
369-
self.assertFalse(os.path.isabs(os__cached__))
370-
# Now, with 'import site', it works.
371-
proc = subprocess.Popen([sys.executable, '-c', command],
372-
env=env,
373-
stdout=subprocess.PIPE)
374-
stdout, stderr = proc.communicate()
375-
self.assertEqual(proc.returncode, 0)
376-
os__file__, os__cached__ = stdout.splitlines()[:2]
377-
self.assertTrue(os.path.isabs(os__file__),
378-
"expected absolute path, got {}"
379-
.format(os__file__.decode('ascii')))
380-
self.assertTrue(os.path.isabs(os__cached__),
381-
"expected absolute path, got {}"
382-
.format(os__cached__.decode('ascii')))
350+
try:
351+
parent = os.path.relpath(os.path.dirname(os.__file__))
352+
cwd = os.getcwd()
353+
except ValueError:
354+
# Failure to get relpath probably means we need to chdir
355+
# to the same drive.
356+
cwd, parent = os.path.split(os.path.dirname(os.__file__))
357+
with change_cwd(cwd):
358+
env = os.environ.copy()
359+
env['PYTHONPATH'] = parent
360+
code = ('import os, sys',
361+
# use ASCII to avoid locale issues with non-ASCII directories
362+
'os_file = os.__file__.encode("ascii", "backslashreplace")',
363+
r'sys.stdout.buffer.write(os_file + b"\n")',
364+
'os_cached = os.__cached__.encode("ascii", "backslashreplace")',
365+
r'sys.stdout.buffer.write(os_cached + b"\n")')
366+
command = '\n'.join(code)
367+
# First, prove that with -S (no 'import site'), the paths are
368+
# relative.
369+
proc = subprocess.Popen([sys.executable, '-S', '-c', command],
370+
env=env,
371+
stdout=subprocess.PIPE)
372+
stdout, stderr = proc.communicate()
373+
374+
self.assertEqual(proc.returncode, 0)
375+
os__file__, os__cached__ = stdout.splitlines()[:2]
376+
self.assertFalse(os.path.isabs(os__file__))
377+
self.assertFalse(os.path.isabs(os__cached__))
378+
# Now, with 'import site', it works.
379+
proc = subprocess.Popen([sys.executable, '-c', command],
380+
env=env,
381+
stdout=subprocess.PIPE)
382+
stdout, stderr = proc.communicate()
383+
self.assertEqual(proc.returncode, 0)
384+
os__file__, os__cached__ = stdout.splitlines()[:2]
385+
self.assertTrue(os.path.isabs(os__file__),
386+
"expected absolute path, got {}"
387+
.format(os__file__.decode('ascii')))
388+
self.assertTrue(os.path.isabs(os__cached__),
389+
"expected absolute path, got {}"
390+
.format(os__cached__.decode('ascii')))
383391

384392
def test_no_duplicate_paths(self):
385393
# No duplicate paths should exist in sys.path

Lib/test/test_sysconfig.py

+19-6
Original file line numberDiff line numberDiff line change
@@ -235,21 +235,34 @@ def test_get_scheme_names(self):
235235
def test_symlink(self):
236236
# On Windows, the EXE needs to know where pythonXY.dll is at so we have
237237
# to add the directory to the path.
238+
env = None
238239
if sys.platform == "win32":
239-
os.environ["PATH"] = "{};{}".format(
240-
os.path.dirname(sys.executable), os.environ["PATH"])
240+
env = {k.upper(): os.environ[k] for k in os.environ}
241+
env["PATH"] = "{};{}".format(
242+
os.path.dirname(sys.executable), env.get("PATH", ""))
243+
# Requires PYTHONHOME as well since we locate stdlib from the
244+
# EXE path and not the DLL path (which should be fixed)
245+
env["PYTHONHOME"] = os.path.dirname(sys.executable)
246+
if sysconfig.is_python_build(True):
247+
env["PYTHONPATH"] = os.path.dirname(os.__file__)
241248

242249
# Issue 7880
243-
def get(python):
250+
def get(python, env=None):
244251
cmd = [python, '-c',
245252
'import sysconfig; print(sysconfig.get_platform())']
246-
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=os.environ)
247-
return p.communicate()
253+
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
254+
stderr=subprocess.PIPE, env=env)
255+
out, err = p.communicate()
256+
if p.returncode:
257+
print((out, err))
258+
self.fail('Non-zero return code {0} (0x{0:08X})'
259+
.format(p.returncode))
260+
return out, err
248261
real = os.path.realpath(sys.executable)
249262
link = os.path.abspath(TESTFN)
250263
os.symlink(real, link)
251264
try:
252-
self.assertEqual(get(real), get(link))
265+
self.assertEqual(get(real), get(link, env))
253266
finally:
254267
unlink(link)
255268

Lib/test/test_venv.py

+32-35
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,17 @@
2727
skipInVenv = unittest.skipIf(sys.prefix != sys.base_prefix,
2828
'Test not appropriate in a venv')
2929

30+
def check_output(cmd, encoding=None):
31+
p = subprocess.Popen(cmd,
32+
stdout=subprocess.PIPE,
33+
stderr=subprocess.PIPE,
34+
encoding=encoding)
35+
out, err = p.communicate()
36+
if p.returncode:
37+
raise subprocess.CalledProcessError(
38+
p.returncode, cmd, None, out, err)
39+
return out, err
40+
3041
class BaseTest(unittest.TestCase):
3142
"""Base class for venv tests."""
3243
maxDiff = 80 * 50
@@ -134,9 +145,7 @@ def test_prefixes(self):
134145
('base_prefix', sys.prefix),
135146
('base_exec_prefix', sys.exec_prefix)):
136147
cmd[2] = 'import sys; print(sys.%s)' % prefix
137-
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
138-
stderr=subprocess.PIPE)
139-
out, err = p.communicate()
148+
out, err = check_output(cmd)
140149
self.assertEqual(out.strip(), expected.encode())
141150

142151
if sys.platform == 'win32':
@@ -259,11 +268,10 @@ def test_executable(self):
259268
"""
260269
rmtree(self.env_dir)
261270
self.run_with_capture(venv.create, self.env_dir)
262-
envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe)
263-
cmd = [envpy, '-c', 'import sys; print(sys.executable)']
264-
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
265-
stderr=subprocess.PIPE)
266-
out, err = p.communicate()
271+
envpy = os.path.join(os.path.realpath(self.env_dir),
272+
self.bindir, self.exe)
273+
out, err = check_output([envpy, '-c',
274+
'import sys; print(sys.executable)'])
267275
self.assertEqual(out.strip(), envpy.encode())
268276

269277
@unittest.skipUnless(can_symlink(), 'Needs symlinks')
@@ -274,30 +282,27 @@ def test_executable_symlinks(self):
274282
rmtree(self.env_dir)
275283
builder = venv.EnvBuilder(clear=True, symlinks=True)
276284
builder.create(self.env_dir)
277-
envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe)
278-
cmd = [envpy, '-c', 'import sys; print(sys.executable)']
279-
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
280-
stderr=subprocess.PIPE)
281-
out, err = p.communicate()
285+
envpy = os.path.join(os.path.realpath(self.env_dir),
286+
self.bindir, self.exe)
287+
out, err = check_output([envpy, '-c',
288+
'import sys; print(sys.executable)'])
282289
self.assertEqual(out.strip(), envpy.encode())
283290

284291
@unittest.skipUnless(os.name == 'nt', 'only relevant on Windows')
285292
def test_unicode_in_batch_file(self):
286293
"""
287-
Test isolation from system site-packages
294+
Test handling of Unicode paths
288295
"""
289296
rmtree(self.env_dir)
290297
env_dir = os.path.join(os.path.realpath(self.env_dir), 'ϼўТλФЙ')
291298
builder = venv.EnvBuilder(clear=True)
292299
builder.create(env_dir)
293300
activate = os.path.join(env_dir, self.bindir, 'activate.bat')
294301
envpy = os.path.join(env_dir, self.bindir, self.exe)
295-
cmd = [activate, '&', self.exe, '-c', 'print(0)']
296-
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
297-
stderr=subprocess.PIPE, encoding='oem',
298-
shell=True)
299-
out, err = p.communicate()
300-
print(err)
302+
out, err = check_output(
303+
[activate, '&', self.exe, '-c', 'print(0)'],
304+
encoding='oem',
305+
)
301306
self.assertEqual(out.strip(), '0')
302307

303308
@skipInVenv
@@ -306,11 +311,8 @@ class EnsurePipTest(BaseTest):
306311
def assert_pip_not_installed(self):
307312
envpy = os.path.join(os.path.realpath(self.env_dir),
308313
self.bindir, self.exe)
309-
try_import = 'try:\n import pip\nexcept ImportError:\n print("OK")'
310-
cmd = [envpy, '-c', try_import]
311-
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
312-
stderr=subprocess.PIPE)
313-
out, err = p.communicate()
314+
out, err = check_output([envpy, '-c',
315+
'try:\n import pip\nexcept ImportError:\n print("OK")'])
314316
# We force everything to text, so unittest gives the detailed diff
315317
# if we get unexpected results
316318
err = err.decode("latin-1") # Force to text, prevent decoding errors
@@ -388,11 +390,8 @@ def do_test_with_pip(self, system_site_packages):
388390
# Ensure pip is available in the virtual environment
389391
envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe)
390392
# Ignore DeprecationWarning since pip code is not part of Python
391-
cmd = [envpy, '-W', 'ignore::DeprecationWarning', '-I',
392-
'-m', 'pip', '--version']
393-
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
394-
stderr=subprocess.PIPE)
395-
out, err = p.communicate()
393+
out, err = check_output([envpy, '-W', 'ignore::DeprecationWarning', '-I',
394+
'-m', 'pip', '--version'])
396395
# We force everything to text, so unittest gives the detailed diff
397396
# if we get unexpected results
398397
err = err.decode("latin-1") # Force to text, prevent decoding errors
@@ -406,12 +405,10 @@ def do_test_with_pip(self, system_site_packages):
406405
# http://bugs.python.org/issue19728
407406
# Check the private uninstall command provided for the Windows
408407
# installers works (at least in a virtual environment)
409-
cmd = [envpy, '-W', 'ignore::DeprecationWarning', '-I',
410-
'-m', 'ensurepip._uninstall']
411408
with EnvironmentVarGuard() as envvars:
412-
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
413-
stderr=subprocess.PIPE)
414-
out, err = p.communicate()
409+
out, err = check_output([envpy,
410+
'-W', 'ignore::DeprecationWarning', '-I',
411+
'-m', 'ensurepip._uninstall'])
415412
# We force everything to text, so unittest gives the detailed diff
416413
# if we get unexpected results
417414
err = err.decode("latin-1") # Force to text, prevent decoding errors

0 commit comments

Comments
 (0)