From 121ef6ba07c0a8e6302e50aabca16c747f036fff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= <bgabor8@bloomberg.net> Date: Sat, 6 Jun 2020 09:37:02 +0100 Subject: [PATCH] PyPy 7.3.1 now generates Scripts instead of bin on Windows (#1597) --- .pre-commit-config.yaml | 8 ++++---- docs/changelog/1597.bugfix.rst | 1 + src/tox/config/__init__.py | 15 +++++++++++---- src/tox/helper/get_version.py | 4 +++- src/tox/interpreters/__init__.py | 15 +++++++++++---- src/tox/interpreters/via_path.py | 2 +- tests/unit/interpreters/test_interpreters.py | 9 +++++---- 7 files changed, 36 insertions(+), 18 deletions(-) create mode 100644 docs/changelog/1597.bugfix.rst diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 072b3a3fa..c3beeb26c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,10 +13,6 @@ repos: - id: debug-statements - id: end-of-file-fixer - id: trailing-whitespace -- repo: https://github.com/asottile/add-trailing-comma - rev: v2.0.1 - hooks: - - id: add-trailing-comma - repo: https://github.com/asottile/pyupgrade rev: v2.4.3 hooks: @@ -46,6 +42,10 @@ repos: additional_dependencies: - black==19.10b0 language_version: python3.8 +- repo: https://github.com/asottile/add-trailing-comma + rev: v2.0.1 + hooks: + - id: add-trailing-comma - repo: https://github.com/pre-commit/pygrep-hooks rev: v1.5.1 hooks: diff --git a/docs/changelog/1597.bugfix.rst b/docs/changelog/1597.bugfix.rst new file mode 100644 index 000000000..7482e0882 --- /dev/null +++ b/docs/changelog/1597.bugfix.rst @@ -0,0 +1 @@ +PyPy 7.3.1 on Windows uses the ``Script`` folder instead of ``bin``. - by :user:`gaborbernat` diff --git a/src/tox/config/__init__.py b/src/tox/config/__init__.py index f42a68d57..2ac4cf3aa 100644 --- a/src/tox/config/__init__.py +++ b/src/tox/config/__init__.py @@ -955,10 +955,17 @@ def __init__(self, envname, config, factors, reader): def get_envbindir(self): """Path to directory where scripts/binaries reside.""" - if tox.INFO.IS_WIN and "jython" not in self.basepython and "pypy" not in self.basepython: - return self.envdir.join("Scripts") - else: - return self.envdir.join("bin") + is_bin = ( + isinstance(self.python_info, NoInterpreterInfo) + or tox.INFO.IS_WIN is False + or self.python_info.implementation == "Jython" + or ( + tox.INFO.IS_WIN + and self.python_info.implementation == "PyPy" + and self.python_info.extra_version_info < (7, 3, 1) + ) + ) + return self.envdir.join("bin" if is_bin else "Scripts") @property def envbindir(self): diff --git a/src/tox/helper/get_version.py b/src/tox/helper/get_version.py index 3fcc37e43..b1a8455a4 100644 --- a/src/tox/helper/get_version.py +++ b/src/tox/helper/get_version.py @@ -1,15 +1,17 @@ from __future__ import unicode_literals import json +import platform import sys info = { "executable": sys.executable, - "name": "pypy" if hasattr(sys, "pypy_version_info") else "python", + "implementation": platform.python_implementation(), "version_info": list(sys.version_info), "version": sys.version, "is_64": sys.maxsize > 2 ** 32, "sysplatform": sys.platform, + "extra_version_info": getattr(sys, "pypy_version_info", None), } info_as_dump = json.dumps(info) print(info_as_dump) diff --git a/src/tox/interpreters/__init__.py b/src/tox/interpreters/__init__.py index 797e5ae57..c03431989 100644 --- a/src/tox/interpreters/__init__.py +++ b/src/tox/interpreters/__init__.py @@ -59,13 +59,16 @@ def run_and_get_interpreter_info(name, executable): try: result = get_python_info(str(executable)) result["version_info"] = tuple(result["version_info"]) # fix json dump transformation - del result["name"] + if result["extra_version_info"] is not None: + result["extra_version_info"] = tuple( + result["extra_version_info"], + ) # fix json dump transformation del result["version"] result["executable"] = str(executable) except ExecFailed as e: return NoInterpreterInfo(name, executable=e.executable, out=e.out, err=e.err) else: - return InterpreterInfo(name, **result) + return InterpreterInfo(**result) def exec_on_interpreter(*args): @@ -93,12 +96,16 @@ def __init__(self, executable, source, out, err): class InterpreterInfo: - def __init__(self, name, executable, version_info, sysplatform, is_64): - self.name = name + def __init__( + self, implementation, executable, version_info, sysplatform, is_64, extra_version_info, + ): + self.implementation = implementation self.executable = executable + self.version_info = version_info self.sysplatform = sysplatform self.is_64 = is_64 + self.extra_version_info = extra_version_info def __str__(self): return "<executable at {}, version_info {}>".format(self.executable, self.version_info) diff --git a/src/tox/interpreters/via_path.py b/src/tox/interpreters/via_path.py index 670833208..8634d697d 100644 --- a/src/tox/interpreters/via_path.py +++ b/src/tox/interpreters/via_path.py @@ -38,7 +38,7 @@ def exe_spec(python_exe, base): info = get_python_info(python_exe) if info is not None: found = PythonSpec( - info["name"], + "pypy" if info["implementation"] == "PyPy" else "python", info["version_info"][0], info["version_info"][1], 64 if info["is_64"] else 32, diff --git a/tests/unit/interpreters/test_interpreters.py b/tests/unit/interpreters/test_interpreters.py index 5d532e0bd..fd364bafb 100644 --- a/tests/unit/interpreters/test_interpreters.py +++ b/tests/unit/interpreters/test_interpreters.py @@ -1,6 +1,7 @@ from __future__ import unicode_literals import os +import platform import stat import subprocess import sys @@ -101,7 +102,7 @@ def test_run_and_get_interpreter_info(): name = os.path.basename(sys.executable) info = run_and_get_interpreter_info(name, sys.executable) assert info.version_info == tuple(sys.version_info) - assert info.name == name + assert info.implementation == platform.python_implementation() assert info.executable == sys.executable @@ -186,16 +187,16 @@ def test_exec_failed(): class TestInterpreterInfo: @staticmethod def info( - name="my-name", + implementation="CPython", executable="my-executable", version_info="my-version-info", sysplatform="my-sys-platform", ): - return InterpreterInfo(name, executable, version_info, sysplatform, True) + return InterpreterInfo(implementation, executable, version_info, sysplatform, True, None) def test_data(self): x = self.info("larry", "moe", "shemp", "curly") - assert x.name == "larry" + assert x.implementation == "larry" assert x.executable == "moe" assert x.version_info == "shemp" assert x.sysplatform == "curly"