mirror of
https://github.com/pre-commit/pre-commit.git
synced 2026-02-17 00:04:42 +04:00
adjust python default_language_version to prefer versioned exe
This commit is contained in:
parent
ff7256cedf
commit
3e8d0f5e1c
2 changed files with 91 additions and 10 deletions
|
|
@ -75,6 +75,13 @@ def _find_by_py_launcher(
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _impl_exe_name() -> str:
|
||||||
|
if sys.implementation.name == 'cpython': # pragma: cpython cover
|
||||||
|
return 'python'
|
||||||
|
else: # pragma: cpython no cover
|
||||||
|
return sys.implementation.name # pypy mostly
|
||||||
|
|
||||||
|
|
||||||
def _find_by_sys_executable() -> str | None:
|
def _find_by_sys_executable() -> str | None:
|
||||||
def _norm(path: str) -> str | None:
|
def _norm(path: str) -> str | None:
|
||||||
_, exe = os.path.split(path.lower())
|
_, exe = os.path.split(path.lower())
|
||||||
|
|
@ -100,18 +107,25 @@ def _find_by_sys_executable() -> str | None:
|
||||||
|
|
||||||
@functools.lru_cache(maxsize=1)
|
@functools.lru_cache(maxsize=1)
|
||||||
def get_default_version() -> str: # pragma: no cover (platform dependent)
|
def get_default_version() -> str: # pragma: no cover (platform dependent)
|
||||||
# First attempt from `sys.executable` (or the realpath)
|
v_major = f'{sys.version_info[0]}'
|
||||||
exe = _find_by_sys_executable()
|
v_minor = f'{sys.version_info[0]}.{sys.version_info[1]}'
|
||||||
if exe:
|
|
||||||
return exe
|
|
||||||
|
|
||||||
# Next try the `pythonX.X` executable
|
# attempt the likely implementation exe
|
||||||
exe = f'python{sys.version_info[0]}.{sys.version_info[1]}'
|
for potential in (v_minor, v_major):
|
||||||
if find_executable(exe):
|
exe = f'{_impl_exe_name()}{potential}'
|
||||||
return exe
|
if find_executable(exe):
|
||||||
|
return exe
|
||||||
|
|
||||||
if _find_by_py_launcher(exe):
|
# next try `sys.executable` (or the realpath)
|
||||||
return exe
|
maybe_exe = _find_by_sys_executable()
|
||||||
|
if maybe_exe:
|
||||||
|
return maybe_exe
|
||||||
|
|
||||||
|
# maybe on windows we can find it via py launcher?
|
||||||
|
if sys.platform == 'win32': # pragma: win32 cover
|
||||||
|
exe = f'python{v_minor}'
|
||||||
|
if _find_by_py_launcher(exe):
|
||||||
|
return exe
|
||||||
|
|
||||||
# We tried!
|
# We tried!
|
||||||
return C.DEFAULT
|
return C.DEFAULT
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ from pre_commit.languages import python
|
||||||
from pre_commit.prefix import Prefix
|
from pre_commit.prefix import Prefix
|
||||||
from pre_commit.util import make_executable
|
from pre_commit.util import make_executable
|
||||||
from pre_commit.util import win_exe
|
from pre_commit.util import win_exe
|
||||||
|
from testing.auto_namedtuple import auto_namedtuple
|
||||||
from testing.language_helpers import run_language
|
from testing.language_helpers import run_language
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -34,6 +35,72 @@ def test_read_pyvenv_cfg_non_utf8(tmpdir):
|
||||||
assert python._read_pyvenv_cfg(pyvenv_cfg) == expected
|
assert python._read_pyvenv_cfg(pyvenv_cfg) == expected
|
||||||
|
|
||||||
|
|
||||||
|
def _get_default_version(
|
||||||
|
*,
|
||||||
|
impl: str,
|
||||||
|
exe: str,
|
||||||
|
found: set[str],
|
||||||
|
version: tuple[int, int],
|
||||||
|
) -> str:
|
||||||
|
sys_exe = f'/fake/path/{exe}'
|
||||||
|
sys_impl = auto_namedtuple(name=impl)
|
||||||
|
sys_ver = auto_namedtuple(major=version[0], minor=version[1])
|
||||||
|
|
||||||
|
def find_exe(s):
|
||||||
|
if s in found:
|
||||||
|
return f'/fake/path/found/{exe}'
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
with (
|
||||||
|
mock.patch.object(sys, 'implementation', sys_impl),
|
||||||
|
mock.patch.object(sys, 'executable', sys_exe),
|
||||||
|
mock.patch.object(sys, 'version_info', sys_ver),
|
||||||
|
mock.patch.object(python, 'find_executable', find_exe),
|
||||||
|
):
|
||||||
|
return python.get_default_version.__wrapped__()
|
||||||
|
|
||||||
|
|
||||||
|
def test_default_version_sys_executable_found():
|
||||||
|
ret = _get_default_version(
|
||||||
|
impl='cpython',
|
||||||
|
exe='python3.12',
|
||||||
|
found={'python3.12'},
|
||||||
|
version=(3, 12),
|
||||||
|
)
|
||||||
|
assert ret == 'python3.12'
|
||||||
|
|
||||||
|
|
||||||
|
def test_default_version_picks_specific_when_found():
|
||||||
|
ret = _get_default_version(
|
||||||
|
impl='cpython',
|
||||||
|
exe='python3',
|
||||||
|
found={'python3', 'python3.12'},
|
||||||
|
version=(3, 12),
|
||||||
|
)
|
||||||
|
assert ret == 'python3.12'
|
||||||
|
|
||||||
|
|
||||||
|
def test_default_version_picks_pypy_versioned_exe():
|
||||||
|
ret = _get_default_version(
|
||||||
|
impl='pypy',
|
||||||
|
exe='python',
|
||||||
|
found={'pypy3.12', 'python3'},
|
||||||
|
version=(3, 12),
|
||||||
|
)
|
||||||
|
assert ret == 'pypy3.12'
|
||||||
|
|
||||||
|
|
||||||
|
def test_default_version_picks_pypy_unversioned_exe():
|
||||||
|
ret = _get_default_version(
|
||||||
|
impl='pypy',
|
||||||
|
exe='python',
|
||||||
|
found={'pypy3', 'python3'},
|
||||||
|
version=(3, 12),
|
||||||
|
)
|
||||||
|
assert ret == 'pypy3'
|
||||||
|
|
||||||
|
|
||||||
def test_norm_version_expanduser():
|
def test_norm_version_expanduser():
|
||||||
home = os.path.expanduser('~')
|
home = os.path.expanduser('~')
|
||||||
if sys.platform == 'win32': # pragma: win32 cover
|
if sys.platform == 'win32': # pragma: win32 cover
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue