[Python-checkins] Fixes tests requiring extra environment values on Windows (GH-9462)

Steve Dower webhook-mailer at python.org
Thu Sep 20 17:39:28 EDT 2018


https://github.com/python/cpython/commit/a73e790c7894ab68311aef296074518db4778b46
commit: a73e790c7894ab68311aef296074518db4778b46
branch: 3.7
author: Steve Dower <steve.dower at microsoft.com>
committer: GitHub <noreply at github.com>
date: 2018-09-20T14:39:21-07:00
summary:

Fixes tests requiring extra environment values on Windows (GH-9462)

files:
M Lib/distutils/tests/test_bdist.py
M Lib/distutils/tests/test_bdist_wininst.py
M Lib/test/test_platform.py
M Lib/test/test_site.py
M Lib/test/test_sysconfig.py
M Lib/test/test_venv.py
M Tools/msi/distutils.command.bdist_wininst.py

diff --git a/Lib/distutils/tests/test_bdist.py b/Lib/distutils/tests/test_bdist.py
index f762f5d98730..c80b3edc0220 100644
--- a/Lib/distutils/tests/test_bdist.py
+++ b/Lib/distutils/tests/test_bdist.py
@@ -39,6 +39,9 @@ def test_skip_build(self):
 
         for name in names:
             subcmd = cmd.get_finalized_command(name)
+            if getattr(subcmd, '_unsupported', False):
+                # command is not supported on this build
+                continue
             self.assertTrue(subcmd.skip_build,
                             '%s should take --skip-build from bdist' % name)
 
diff --git a/Lib/distutils/tests/test_bdist_wininst.py b/Lib/distutils/tests/test_bdist_wininst.py
index 5d17ab19a9d8..4c19bbab219b 100644
--- a/Lib/distutils/tests/test_bdist_wininst.py
+++ b/Lib/distutils/tests/test_bdist_wininst.py
@@ -5,6 +5,8 @@
 from distutils.command.bdist_wininst import bdist_wininst
 from distutils.tests import support
 
+ at unittest.skipIf(getattr(bdist_wininst, '_unsupported', False),
+    'bdist_wininst is not supported in this install')
 class BuildWinInstTestCase(support.TempdirManager,
                            support.LoggingSilencer,
                            unittest.TestCase):
diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py
index 509d8865c068..010ed6c6342b 100644
--- a/Lib/test/test_platform.py
+++ b/Lib/test/test_platform.py
@@ -3,6 +3,7 @@
 import platform
 import subprocess
 import sys
+import sysconfig
 import tempfile
 import unittest
 import warnings
@@ -16,29 +17,34 @@ def test_architecture(self):
     @support.skip_unless_symlink
     def test_architecture_via_symlink(self): # issue3762
         # On Windows, the EXE needs to know where pythonXY.dll and *.pyd is at
-        # so we add the directory to the path and PYTHONPATH.
+        # so we add the directory to the path, PYTHONHOME and PYTHONPATH.
+        env = None
         if sys.platform == "win32":
-            def restore_environ(old_env):
-                os.environ.clear()
-                os.environ.update(old_env)
-
-            self.addCleanup(restore_environ, dict(os.environ))
-
-            os.environ["Path"] = "{};{}".format(
-                os.path.dirname(sys.executable), os.environ["Path"])
-            os.environ["PYTHONPATH"] = os.path.dirname(sys.executable)
-
-        def get(python):
+            env = {k.upper(): os.environ[k] for k in os.environ}
+            env["PATH"] = "{};{}".format(
+                os.path.dirname(sys.executable), env.get("PATH", ""))
+            env["PYTHONHOME"] = os.path.dirname(sys.executable)
+            if sysconfig.is_python_build(True):
+                env["PYTHONPATH"] = os.path.dirname(os.__file__)
+
+        def get(python, env=None):
             cmd = [python, '-c',
                 'import platform; print(platform.architecture())']
-            p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
-            return p.communicate()
+            p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+                                 stderr=subprocess.PIPE, env=env)
+            r = p.communicate()
+            if p.returncode:
+                print(repr(r[0]))
+                print(repr(r[1]), file=sys.stderr)
+                self.fail('unexpected return code: {0} (0x{0:08X})'
+                          .format(p.returncode))
+            return r
 
         real = os.path.realpath(sys.executable)
         link = os.path.abspath(support.TESTFN)
         os.symlink(real, link)
         try:
-            self.assertEqual(get(real), get(link))
+            self.assertEqual(get(real), get(link, env=env))
         finally:
             os.remove(link)
 
diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py
index e3c9deebf08c..6cea58d934fb 100644
--- a/Lib/test/test_site.py
+++ b/Lib/test/test_site.py
@@ -6,7 +6,8 @@
 """
 import unittest
 import test.support
-from test.support import captured_stderr, TESTFN, EnvironmentVarGuard
+from test.support import (captured_stderr, TESTFN, EnvironmentVarGuard,
+                          change_cwd)
 import builtins
 import os
 import sys
@@ -348,40 +349,47 @@ def test_abs_paths(self):
         # __file__ if abs_paths() does not get run.  sys and builtins (the
         # only other modules imported before site.py runs) do not have
         # __file__ or __cached__ because they are built-in.
-        parent = os.path.relpath(os.path.dirname(os.__file__))
-        env = os.environ.copy()
-        env['PYTHONPATH'] = parent
-        code = ('import os, sys',
-            # use ASCII to avoid locale issues with non-ASCII directories
-            'os_file = os.__file__.encode("ascii", "backslashreplace")',
-            r'sys.stdout.buffer.write(os_file + b"\n")',
-            'os_cached = os.__cached__.encode("ascii", "backslashreplace")',
-            r'sys.stdout.buffer.write(os_cached + b"\n")')
-        command = '\n'.join(code)
-        # First, prove that with -S (no 'import site'), the paths are
-        # relative.
-        proc = subprocess.Popen([sys.executable, '-S', '-c', command],
-                                env=env,
-                                stdout=subprocess.PIPE)
-        stdout, stderr = proc.communicate()
-
-        self.assertEqual(proc.returncode, 0)
-        os__file__, os__cached__ = stdout.splitlines()[:2]
-        self.assertFalse(os.path.isabs(os__file__))
-        self.assertFalse(os.path.isabs(os__cached__))
-        # Now, with 'import site', it works.
-        proc = subprocess.Popen([sys.executable, '-c', command],
-                                env=env,
-                                stdout=subprocess.PIPE)
-        stdout, stderr = proc.communicate()
-        self.assertEqual(proc.returncode, 0)
-        os__file__, os__cached__ = stdout.splitlines()[:2]
-        self.assertTrue(os.path.isabs(os__file__),
-                        "expected absolute path, got {}"
-                        .format(os__file__.decode('ascii')))
-        self.assertTrue(os.path.isabs(os__cached__),
-                        "expected absolute path, got {}"
-                        .format(os__cached__.decode('ascii')))
+        try:
+            parent = os.path.relpath(os.path.dirname(os.__file__))
+            cwd = os.getcwd()
+        except ValueError:
+            # Failure to get relpath probably means we need to chdir
+            # to the same drive.
+            cwd, parent = os.path.split(os.path.dirname(os.__file__))
+        with change_cwd(cwd):
+            env = os.environ.copy()
+            env['PYTHONPATH'] = parent
+            code = ('import os, sys',
+                # use ASCII to avoid locale issues with non-ASCII directories
+                'os_file = os.__file__.encode("ascii", "backslashreplace")',
+                r'sys.stdout.buffer.write(os_file + b"\n")',
+                'os_cached = os.__cached__.encode("ascii", "backslashreplace")',
+                r'sys.stdout.buffer.write(os_cached + b"\n")')
+            command = '\n'.join(code)
+            # First, prove that with -S (no 'import site'), the paths are
+            # relative.
+            proc = subprocess.Popen([sys.executable, '-S', '-c', command],
+                                    env=env,
+                                    stdout=subprocess.PIPE)
+            stdout, stderr = proc.communicate()
+
+            self.assertEqual(proc.returncode, 0)
+            os__file__, os__cached__ = stdout.splitlines()[:2]
+            self.assertFalse(os.path.isabs(os__file__))
+            self.assertFalse(os.path.isabs(os__cached__))
+            # Now, with 'import site', it works.
+            proc = subprocess.Popen([sys.executable, '-c', command],
+                                    env=env,
+                                    stdout=subprocess.PIPE)
+            stdout, stderr = proc.communicate()
+            self.assertEqual(proc.returncode, 0)
+            os__file__, os__cached__ = stdout.splitlines()[:2]
+            self.assertTrue(os.path.isabs(os__file__),
+                            "expected absolute path, got {}"
+                            .format(os__file__.decode('ascii')))
+            self.assertTrue(os.path.isabs(os__cached__),
+                            "expected absolute path, got {}"
+                            .format(os__cached__.decode('ascii')))
 
     def test_no_duplicate_paths(self):
         # No duplicate paths should exist in sys.path
diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py
index 20252be0a41b..1b1929885edd 100644
--- a/Lib/test/test_sysconfig.py
+++ b/Lib/test/test_sysconfig.py
@@ -235,21 +235,34 @@ def test_get_scheme_names(self):
     def test_symlink(self):
         # On Windows, the EXE needs to know where pythonXY.dll is at so we have
         # to add the directory to the path.
+        env = None
         if sys.platform == "win32":
-            os.environ["PATH"] = "{};{}".format(
-                os.path.dirname(sys.executable), os.environ["PATH"])
+            env = {k.upper(): os.environ[k] for k in os.environ}
+            env["PATH"] = "{};{}".format(
+                os.path.dirname(sys.executable), env.get("PATH", ""))
+            # Requires PYTHONHOME as well since we locate stdlib from the
+            # EXE path and not the DLL path (which should be fixed)
+            env["PYTHONHOME"] = os.path.dirname(sys.executable)
+            if sysconfig.is_python_build(True):
+                env["PYTHONPATH"] = os.path.dirname(os.__file__)
 
         # Issue 7880
-        def get(python):
+        def get(python, env=None):
             cmd = [python, '-c',
                    'import sysconfig; print(sysconfig.get_platform())']
-            p = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=os.environ)
-            return p.communicate()
+            p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+                                 stderr=subprocess.PIPE, env=env)
+            out, err = p.communicate()
+            if p.returncode:
+                print((out, err))
+                self.fail('Non-zero return code {0} (0x{0:08X})'
+                            .format(p.returncode))
+            return out, err
         real = os.path.realpath(sys.executable)
         link = os.path.abspath(TESTFN)
         os.symlink(real, link)
         try:
-            self.assertEqual(get(real), get(link))
+            self.assertEqual(get(real), get(link, env))
         finally:
             unlink(link)
 
diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py
index 9cea87e2fefa..c86f7a1a07ae 100644
--- a/Lib/test/test_venv.py
+++ b/Lib/test/test_venv.py
@@ -27,6 +27,17 @@
 skipInVenv = unittest.skipIf(sys.prefix != sys.base_prefix,
                              'Test not appropriate in a venv')
 
+def check_output(cmd, encoding=None):
+    p = subprocess.Popen(cmd,
+        stdout=subprocess.PIPE,
+        stderr=subprocess.PIPE,
+        encoding=encoding)
+    out, err = p.communicate()
+    if p.returncode:
+        raise subprocess.CalledProcessError(
+            p.returncode, cmd, None, out, err)
+    return out, err
+
 class BaseTest(unittest.TestCase):
     """Base class for venv tests."""
     maxDiff = 80 * 50
@@ -134,9 +145,7 @@ def test_prefixes(self):
             ('base_prefix', sys.prefix),
             ('base_exec_prefix', sys.exec_prefix)):
             cmd[2] = 'import sys; print(sys.%s)' % prefix
-            p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
-                                 stderr=subprocess.PIPE)
-            out, err = p.communicate()
+            out, err = check_output(cmd)
             self.assertEqual(out.strip(), expected.encode())
 
     if sys.platform == 'win32':
@@ -259,11 +268,10 @@ def test_executable(self):
         """
         rmtree(self.env_dir)
         self.run_with_capture(venv.create, self.env_dir)
-        envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe)
-        cmd = [envpy, '-c', 'import sys; print(sys.executable)']
-        p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
-                             stderr=subprocess.PIPE)
-        out, err = p.communicate()
+        envpy = os.path.join(os.path.realpath(self.env_dir),
+                             self.bindir, self.exe)
+        out, err = check_output([envpy, '-c',
+            'import sys; print(sys.executable)'])
         self.assertEqual(out.strip(), envpy.encode())
 
     @unittest.skipUnless(can_symlink(), 'Needs symlinks')
@@ -274,17 +282,16 @@ def test_executable_symlinks(self):
         rmtree(self.env_dir)
         builder = venv.EnvBuilder(clear=True, symlinks=True)
         builder.create(self.env_dir)
-        envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe)
-        cmd = [envpy, '-c', 'import sys; print(sys.executable)']
-        p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
-                             stderr=subprocess.PIPE)
-        out, err = p.communicate()
+        envpy = os.path.join(os.path.realpath(self.env_dir),
+                             self.bindir, self.exe)
+        out, err = check_output([envpy, '-c',
+            'import sys; print(sys.executable)'])
         self.assertEqual(out.strip(), envpy.encode())
 
     @unittest.skipUnless(os.name == 'nt', 'only relevant on Windows')
     def test_unicode_in_batch_file(self):
         """
-        Test isolation from system site-packages
+        Test handling of Unicode paths
         """
         rmtree(self.env_dir)
         env_dir = os.path.join(os.path.realpath(self.env_dir), 'ϼўТλФЙ')
@@ -292,12 +299,10 @@ def test_unicode_in_batch_file(self):
         builder.create(env_dir)
         activate = os.path.join(env_dir, self.bindir, 'activate.bat')
         envpy = os.path.join(env_dir, self.bindir, self.exe)
-        cmd = [activate, '&', self.exe, '-c', 'print(0)']
-        p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
-                             stderr=subprocess.PIPE, encoding='oem',
-                             shell=True)
-        out, err = p.communicate()
-        print(err)
+        out, err = check_output(
+            [activate, '&', self.exe, '-c', 'print(0)'],
+            encoding='oem',
+        )
         self.assertEqual(out.strip(), '0')
 
 @skipInVenv
@@ -306,11 +311,8 @@ class EnsurePipTest(BaseTest):
     def assert_pip_not_installed(self):
         envpy = os.path.join(os.path.realpath(self.env_dir),
                              self.bindir, self.exe)
-        try_import = 'try:\n import pip\nexcept ImportError:\n print("OK")'
-        cmd = [envpy, '-c', try_import]
-        p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
-                             stderr=subprocess.PIPE)
-        out, err = p.communicate()
+        out, err = check_output([envpy, '-c',
+            'try:\n import pip\nexcept ImportError:\n print("OK")'])
         # We force everything to text, so unittest gives the detailed diff
         # if we get unexpected results
         err = err.decode("latin-1") # Force to text, prevent decoding errors
@@ -388,11 +390,8 @@ def do_test_with_pip(self, system_site_packages):
         # Ensure pip is available in the virtual environment
         envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe)
         # Ignore DeprecationWarning since pip code is not part of Python
-        cmd = [envpy, '-W', 'ignore::DeprecationWarning', '-I',
-               '-m', 'pip', '--version']
-        p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
-                                  stderr=subprocess.PIPE)
-        out, err = p.communicate()
+        out, err = check_output([envpy, '-W', 'ignore::DeprecationWarning', '-I',
+               '-m', 'pip', '--version'])
         # We force everything to text, so unittest gives the detailed diff
         # if we get unexpected results
         err = err.decode("latin-1") # Force to text, prevent decoding errors
@@ -406,12 +405,10 @@ def do_test_with_pip(self, system_site_packages):
         # http://bugs.python.org/issue19728
         # Check the private uninstall command provided for the Windows
         # installers works (at least in a virtual environment)
-        cmd = [envpy, '-W', 'ignore::DeprecationWarning', '-I',
-               '-m', 'ensurepip._uninstall']
         with EnvironmentVarGuard() as envvars:
-            p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
-                                      stderr=subprocess.PIPE)
-            out, err = p.communicate()
+            out, err = check_output([envpy,
+                '-W', 'ignore::DeprecationWarning', '-I',
+                '-m', 'ensurepip._uninstall'])
         # We force everything to text, so unittest gives the detailed diff
         # if we get unexpected results
         err = err.decode("latin-1") # Force to text, prevent decoding errors
diff --git a/Tools/msi/distutils.command.bdist_wininst.py b/Tools/msi/distutils.command.bdist_wininst.py
index d586e34fec82..548fdd0cc432 100644
--- a/Tools/msi/distutils.command.bdist_wininst.py
+++ b/Tools/msi/distutils.command.bdist_wininst.py
@@ -9,6 +9,9 @@
 class bdist_wininst(Command):
     description = "create an executable installer for MS Windows"
 
+    # Marker for tests that we have the unsupported bdist_wininst
+    _unsupported = True
+
     def initialize_options(self):
         pass
 



More information about the Python-checkins mailing list