[PATCH 2 of 5] run-tests: add --with-python3 to define a Python 3 interpreter

Gregory Szorc gregory.szorc at gmail.com
Sat Mar 12 17:11:33 EST 2016


# HG changeset patch
# User Gregory Szorc <gregory.szorc at gmail.com>
# Date 1457818877 28800
#      Sat Mar 12 13:41:17 2016 -0800
# Node ID 8f46c2b82dee58117e861f1c374c8c229a8fd12d
# Parent  afb4d2d519921346fd33b05880c677740ac8f086
run-tests: add --with-python3 to define a Python 3 interpreter

Currently, very few parts of Mercurial run under Python 3, notably the
test harness.

We want to write tests that run Python 3. For example, we want to
extend test-check-py3-compat.t to parse and load Python files.
However, we have a problem: finding appropriate files requires
running `hg files` and this requires Python 2 until `hg` works
with Python 3.

As a temporary workaround, we add --with-python3 to the test harness
to allow us to define the path to a Python 3 interpreter. This
interpreter is made available to the test environment via $PYTHON3 so
tests can run things with Python 3 while the test harness and `hg`
invocations continue to run from Python 2. To round out the feature,
a "py3exe" hghave check has been added.

diff --git a/tests/hghave.py b/tests/hghave.py
--- a/tests/hghave.py
+++ b/tests/hghave.py
@@ -438,16 +438,20 @@ def has_absimport():
     import __future__
     from mercurial import util
     return util.safehasattr(__future__, "absolute_import")
 
 @check("py3k", "running with Python 3.x")
 def has_py3k():
     return 3 == sys.version_info[0]
 
+ at check("py3exe", "a Python 3.x interpreter is available")
+def has_python3exe():
+    return 'PYTHON3' in os.environ
+
 @check("pure", "running with pure Python code")
 def has_pure():
     return any([
         os.environ.get("HGMODULEPOLICY") == "py",
         os.environ.get("HGTEST_RUN_TESTS_PURE") == "--pure",
     ])
 
 @check("slow", "allow slow tests")
diff --git a/tests/run-tests.py b/tests/run-tests.py
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -250,16 +250,18 @@ def getparser():
         help="test using specified hg script rather than a "
              "temporary installation")
     parser.add_option("--chg", action="store_true",
                       help="install and use chg wrapper in place of hg")
     parser.add_option("--with-chg", metavar="CHG",
                       help="use specified chg wrapper in place of hg")
     parser.add_option("-3", "--py3k-warnings", action="store_true",
         help="enable Py3k warnings on Python 2.6+")
+    parser.add_option("--with-python3", metavar="PYTHON3",
+                      help="Python 3 interpreter (if running under Python 2)")
     parser.add_option('--extra-config-opt', action="append",
                       help='set the given config opt in the test hgrc')
     parser.add_option('--random', action="store_true",
                       help='run tests in random order')
     parser.add_option('--profile-runner', action='store_true',
                       help='run statprof on run-tests')
     parser.add_option('--allow-slow-tests', action='store_true',
                       help='allow extremely slow tests')
@@ -348,16 +350,37 @@ def parseargs(args, parser):
             sys.stderr.write(
                 'warning: --slowtimeout option ignored with --debug\n')
         options.timeout = 0
         options.slowtimeout = 0
     if options.py3k_warnings:
         if PYTHON3:
             parser.error(
                 '--py3k-warnings can only be used on Python 2.6 and 2.7')
+    if options.with_python3:
+        if PYTHON3:
+            parser.error('--with-python3 cannot be used when executing with '
+                         'Python 3')
+
+        # Verify Python3 executable is acceptable.
+        proc = subprocess.Popen([options.with_python3, b'--version'],
+                                stdout=subprocess.PIPE,
+                                stderr=subprocess.STDOUT)
+        out, _err = proc.communicate()
+        ret = proc.wait()
+        if ret != 0:
+            parser.error('could not determine version of python 3')
+        if not out.startswith('Python '):
+            parser.error('unexpected output from python3 --version: %s' %
+                         out)
+        vers = version.LooseVersion(out[len('Python '):])
+        if vers < version.LooseVersion('3.5.0'):
+            parser.error('--with-python3 version must be 3.5.0 or greater; '
+                         'got %s' % out)
+
     if options.blacklist:
         options.blacklist = parselistfiles(options.blacklist, 'blacklist')
     if options.whitelist:
         options.whitelisted = parselistfiles(options.whitelist, 'whitelist')
     else:
         options.whitelisted = {}
 
     if options.showchannels:
@@ -1970,16 +1993,19 @@ class TestRunner(object):
             self._hgcommand = b'chg'
         elif self.options.with_chg:
             chgbindir = os.path.dirname(os.path.realpath(self.options.with_chg))
             self._hgcommand = os.path.basename(self.options.with_chg)
 
         osenvironb[b"BINDIR"] = self._bindir
         osenvironb[b"PYTHON"] = PYTHON
 
+        if self.options.with_python3:
+            osenvironb[b'PYTHON3'] = self.options.with_python3
+
         fileb = _bytespath(__file__)
         runtestdir = os.path.abspath(os.path.dirname(fileb))
         osenvironb[b'RUNTESTDIR'] = runtestdir
         if PYTHON3:
             sepb = _bytespath(os.pathsep)
         else:
             sepb = os.pathsep
         path = [self._bindir, runtestdir] + osenvironb[b"PATH"].split(sepb)


More information about the Mercurial-devel mailing list