1
0
Fork 0

Adding upstream version 4.2.0.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-03-20 08:17:13 +01:00
parent a38bf5d420
commit 2ddebfdc93
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
9 changed files with 121 additions and 18 deletions

View file

@ -36,7 +36,7 @@ jobs:
matrix: matrix:
include: ${{ fromJSON(needs.vars.outputs.languages) }} include: ${{ fromJSON(needs.vars.outputs.languages) }}
steps: steps:
- uses: asottile/workflows/.github/actions/fast-checkout@v1.4.0 - uses: asottile/workflows/.github/actions/fast-checkout@v1.8.1
- uses: actions/setup-python@v4 - uses: actions/setup-python@v4
with: with:
python-version: 3.9 python-version: 3.9

View file

@ -12,12 +12,12 @@ concurrency:
jobs: jobs:
main-windows: main-windows:
uses: asottile/workflows/.github/workflows/tox.yml@v1.6.0 uses: asottile/workflows/.github/workflows/tox.yml@v1.8.1
with: with:
env: '["py39"]' env: '["py39"]'
os: windows-latest os: windows-latest
main-linux: main-linux:
uses: asottile/workflows/.github/workflows/tox.yml@v1.6.0 uses: asottile/workflows/.github/workflows/tox.yml@v1.8.1
with: with:
env: '["py39", "py310", "py311", "py312"]' env: '["py39", "py310", "py311", "py312"]'
os: ubuntu-latest os: ubuntu-latest

View file

@ -29,15 +29,15 @@ repos:
- id: pyupgrade - id: pyupgrade
args: [--py39-plus] args: [--py39-plus]
- repo: https://github.com/hhatto/autopep8 - repo: https://github.com/hhatto/autopep8
rev: v2.3.1 rev: v2.3.2
hooks: hooks:
- id: autopep8 - id: autopep8
- repo: https://github.com/PyCQA/flake8 - repo: https://github.com/PyCQA/flake8
rev: 7.1.1 rev: 7.1.2
hooks: hooks:
- id: flake8 - id: flake8
- repo: https://github.com/pre-commit/mirrors-mypy - repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.14.1 rev: v1.15.0
hooks: hooks:
- id: mypy - id: mypy
additional_dependencies: [types-pyyaml] additional_dependencies: [types-pyyaml]

View file

@ -1,3 +1,16 @@
4.2.0 - 2025-03-18
==================
### Features
- For `language: python` first attempt a versioned python executable for
the default language version before consulting a potentially unversioned
`sys.executable`.
- #3430 PR by @asottile.
### Fixes
- Handle error during conflict detection when a file is named "HEAD"
- #3425 PR by @tusharsadhwani.
4.1.0 - 2025-01-20 4.1.0 - 2025-01-20
================== ==================

View file

@ -126,7 +126,7 @@ def get_conflicted_files() -> set[str]:
merge_diff_filenames = zsplit( merge_diff_filenames = zsplit(
cmd_output( cmd_output(
'git', 'diff', '--name-only', '--no-ext-diff', '-z', 'git', 'diff', '--name-only', '--no-ext-diff', '-z',
'-m', tree_hash, 'HEAD', 'MERGE_HEAD', '-m', tree_hash, 'HEAD', 'MERGE_HEAD', '--',
)[1], )[1],
) )
return set(merge_conflict_filenames) | set(merge_diff_filenames) return set(merge_conflict_filenames) | set(merge_diff_filenames)

View file

@ -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,16 +107,23 @@ 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):
exe = f'{_impl_exe_name()}{potential}'
if find_executable(exe): if find_executable(exe):
return exe return exe
# next try `sys.executable` (or the realpath)
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): if _find_by_py_launcher(exe):
return exe return exe

View file

@ -1,6 +1,6 @@
[metadata] [metadata]
name = pre_commit name = pre_commit
version = 4.1.0 version = 4.2.0
description = A framework for managing and maintaining multi-language pre-commit hooks. description = A framework for managing and maintaining multi-language pre-commit hooks.
long_description = file: README.md long_description = file: README.md
long_description_content_type = text/markdown long_description_content_type = text/markdown

View file

@ -141,6 +141,15 @@ def test_get_conflicted_files_unstaged_files(in_merge_conflict):
assert ret == {'conflict_file'} assert ret == {'conflict_file'}
def test_get_conflicted_files_with_file_named_head(in_merge_conflict):
resolve_conflict()
open('HEAD', 'w').close()
cmd_output('git', 'add', 'HEAD')
ret = set(git.get_conflicted_files())
assert ret == {'conflict_file', 'HEAD'}
MERGE_MSG = b"Merge branch 'foo' into bar\n\nConflicts:\n\tconflict_file\n" MERGE_MSG = b"Merge branch 'foo' into bar\n\nConflicts:\n\tconflict_file\n"
OTHER_MERGE_MSG = MERGE_MSG + b'\tother_conflict_file\n' OTHER_MERGE_MSG = MERGE_MSG + b'\tother_conflict_file\n'

View file

@ -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