From 98d9c18fdad250bc916d57c70554dd616cf55073 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 23 Jun 2018 14:38:29 -0700 Subject: [PATCH] Make py2 and py3 aliases also resolve via `py` on windows --- changelog/856.feature.rst | 1 + src/tox/interpreters.py | 13 ++++++------ tests/test_interpreters.py | 41 +++++++++++++++++++++++++++----------- 3 files changed, 37 insertions(+), 18 deletions(-) create mode 100644 changelog/856.feature.rst diff --git a/changelog/856.feature.rst b/changelog/856.feature.rst new file mode 100644 index 000000000..0cf2b18d4 --- /dev/null +++ b/changelog/856.feature.rst @@ -0,0 +1 @@ +Make ``py2`` and ``py3`` aliases also resolve via ``py`` on windows diff --git a/src/tox/interpreters.py b/src/tox/interpreters.py index 1bff7ab54..9fc116037 100644 --- a/src/tox/interpreters.py +++ b/src/tox/interpreters.py @@ -143,11 +143,12 @@ def tox_get_python_executable(envconfig): return p actual = None # Is this a standard PythonX.Y name? - m = re.match(r"python(\d)\.(\d)", name) + m = re.match(r"python(\d)(?:\.(\d))?", name) + groups = [g for g in m.groups() if g] if m else [] if m: # The standard names are in predictable places. - actual = r"c:\python{}{}\python.exe".format(*m.groups()) - if not actual: + actual = r"c:\python{}\python.exe".format("".join(groups)) + else: actual = win32map.get(name, None) if actual: actual = py.path.local(actual) @@ -156,13 +157,13 @@ def tox_get_python_executable(envconfig): # The standard executables can be found as a last resort via the # Python launcher py.exe if m: - return locate_via_py(*m.groups()) + return locate_via_py(*groups) # Exceptions to the usual windows mapping win32map = {"python": sys.executable, "jython": r"c:\jython2.5.1\jython.bat"} - def locate_via_py(v_maj, v_min): - ver = "-{}.{}".format(v_maj, v_min) + def locate_via_py(*parts): + ver = "-{}".format(".".join(parts)) script = "import sys; print(sys.executable)" py_exe = distutils.spawn.find_executable("py") if py_exe: diff --git a/tests/test_interpreters.py b/tests/test_interpreters.py index 1dd6474bb..bcc27450f 100644 --- a/tests/test_interpreters.py +++ b/tests/test_interpreters.py @@ -36,7 +36,7 @@ def fake_find_exe(exe): return "py" def fake_popen(cmd, stdout, stderr): - assert cmd[:3] == ("py", "-3.2", "-c") + fake_popen.last_call = cmd[:3] # need to pipe all stdout to collect the version information & need to # do the same for stderr output to avoid it being forwarded as the @@ -56,7 +56,10 @@ def communicate(): monkeypatch.setattr(distutils.spawn, "find_executable", fake_find_exe) monkeypatch.setattr(subprocess, "Popen", fake_popen) - assert locate_via_py("3", "2") == sys.executable + assert locate_via_py("3", "6") == sys.executable + assert fake_popen.last_call == ("py", "-3.6", "-c") + assert locate_via_py("3") == sys.executable + assert fake_popen.last_call == ("py", "-3", "-c") def test_tox_get_python_executable(): @@ -64,6 +67,16 @@ class envconfig: basepython = sys.executable envname = "pyxx" + def get_exe(name): + envconfig.basepython = name + p = tox_get_python_executable(envconfig) + assert p + return str(p) + + def assert_version_in_output(exe, version): + out = subprocess.check_output((exe, "-V"), stderr=subprocess.STDOUT) + assert version in out.decode() + p = tox_get_python_executable(envconfig) assert p == py.path.local(sys.executable) for major, minor in tox.PYTHON.CPYTHON_VERSION_TUPLES: @@ -71,20 +84,24 @@ class envconfig: if tox.INFO.IS_WIN: pydir = "python{}{}".format(major, minor) x = py.path.local(r"c:\{}".format(pydir)) - print(x) if not x.check(): continue else: - if not py.path.local.sysfind(name): + if not py.path.local.sysfind(name) or subprocess.call((name, "-c", "")): continue - envconfig.basepython = name - p = tox_get_python_executable(envconfig) - assert p - popen = subprocess.Popen([str(p), "-V"], stderr=subprocess.PIPE, stdout=subprocess.PIPE) - stdout, stderr = popen.communicate() - assert not stdout or not stderr - all_output = stderr.decode("ascii") + stdout.decode("ascii") - assert "{}.{}".format(major, minor) in all_output + exe = get_exe(name) + assert_version_in_output(exe, "{}.{}".format(major, minor)) + + for major in (2, 3): + name = "python{}".format(major) + if tox.INFO.IS_WIN: + if subprocess.call(("py", "-{}".format(major), "-c", "")): + continue + elif not py.path.local.sysfind(name): + continue + + exe = get_exe(name) + assert_version_in_output(exe, str(major)) def test_find_executable_extra(monkeypatch):