1
0
Fork 0

Merging upstream version 2.18.1.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-09 21:33:11 +01:00
parent 131d7bde70
commit 3396d2e509
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
116 changed files with 718 additions and 410 deletions

View file

@ -1,12 +1,10 @@
from __future__ import annotations
import os.path
import re
from typing import Any
from typing import Dict
from typing import List
from typing import NamedTuple
from typing import Optional
from typing import Sequence
from typing import Tuple
import pre_commit.constants as C
from pre_commit import git
@ -29,13 +27,13 @@ from pre_commit.util import yaml_load
class RevInfo(NamedTuple):
repo: str
rev: str
frozen: Optional[str]
frozen: str | None
@classmethod
def from_config(cls, config: Dict[str, Any]) -> 'RevInfo':
def from_config(cls, config: dict[str, Any]) -> RevInfo:
return cls(config['repo'], config['rev'], None)
def update(self, tags_only: bool, freeze: bool) -> 'RevInfo':
def update(self, tags_only: bool, freeze: bool) -> RevInfo:
git_cmd = ('git', *git.NO_FS_MONITOR)
if tags_only:
@ -61,6 +59,9 @@ class RevInfo(NamedTuple):
except CalledProcessError:
cmd = (*git_cmd, 'rev-parse', 'FETCH_HEAD')
rev = cmd_output(*cmd, cwd=tmp)[1].strip()
else:
if tags_only:
rev = git.get_best_candidate_tag(rev, tmp)
frozen = None
if freeze:
@ -76,7 +77,7 @@ class RepositoryCannotBeUpdatedError(RuntimeError):
def _check_hooks_still_exist_at_rev(
repo_config: Dict[str, Any],
repo_config: dict[str, Any],
info: RevInfo,
store: Store,
) -> None:
@ -101,9 +102,9 @@ REV_LINE_RE = re.compile(r'^(\s+)rev:(\s*)([\'"]?)([^\s#]+)(.*)(\r?\n)$')
def _original_lines(
path: str,
rev_infos: List[Optional[RevInfo]],
rev_infos: list[RevInfo | None],
retry: bool = False,
) -> Tuple[List[str], List[int]]:
) -> tuple[list[str], list[int]]:
"""detect `rev:` lines or reformat the file"""
with open(path, newline='') as f:
original = f.read()
@ -120,7 +121,7 @@ def _original_lines(
return _original_lines(path, rev_infos, retry=True)
def _write_new_config(path: str, rev_infos: List[Optional[RevInfo]]) -> None:
def _write_new_config(path: str, rev_infos: list[RevInfo | None]) -> None:
lines, idxs = _original_lines(path, rev_infos)
for idx, rev_info in zip(idxs, rev_infos):
@ -152,7 +153,7 @@ def autoupdate(
"""Auto-update the pre-commit config to the latest versions of repos."""
migrate_config(config_file, quiet=True)
retv = 0
rev_infos: List[Optional[RevInfo]] = []
rev_infos: list[RevInfo | None] = []
changed = False
config = load_config(config_file)

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import os.path
from pre_commit import output

View file

@ -1,8 +1,7 @@
from __future__ import annotations
import os.path
from typing import Any
from typing import Dict
from typing import Set
from typing import Tuple
import pre_commit.constants as C
from pre_commit import output
@ -17,9 +16,9 @@ from pre_commit.store import Store
def _mark_used_repos(
store: Store,
all_repos: Dict[Tuple[str, str], str],
unused_repos: Set[Tuple[str, str]],
repo: Dict[str, Any],
all_repos: dict[tuple[str, str], str],
unused_repos: set[tuple[str, str]],
repo: dict[str, Any],
) -> None:
if repo['repo'] == META:
return

View file

@ -1,10 +1,10 @@
from __future__ import annotations
import argparse
import os.path
import subprocess
import sys
from typing import Optional
from typing import Sequence
from typing import Tuple
from pre_commit.commands.run import run
from pre_commit.envcontext import envcontext
@ -18,7 +18,7 @@ def _run_legacy(
hook_type: str,
hook_dir: str,
args: Sequence[str],
) -> Tuple[int, bytes]:
) -> tuple[int, bytes]:
if os.environ.get('PRE_COMMIT_RUNNING_LEGACY'):
raise SystemExit(
f"bug: pre-commit's script is installed in migration mode\n"
@ -69,16 +69,16 @@ def _ns(
color: bool,
*,
all_files: bool = False,
remote_branch: Optional[str] = None,
local_branch: Optional[str] = None,
from_ref: Optional[str] = None,
to_ref: Optional[str] = None,
remote_name: Optional[str] = None,
remote_url: Optional[str] = None,
commit_msg_filename: Optional[str] = None,
checkout_type: Optional[str] = None,
is_squash_merge: Optional[str] = None,
rewrite_command: Optional[str] = None,
remote_branch: str | None = None,
local_branch: str | None = None,
from_ref: str | None = None,
to_ref: str | None = None,
remote_name: str | None = None,
remote_url: str | None = None,
commit_msg_filename: str | None = None,
checkout_type: str | None = None,
is_squash_merge: str | None = None,
rewrite_command: str | None = None,
) -> argparse.Namespace:
return argparse.Namespace(
color=color,
@ -109,7 +109,7 @@ def _pre_push_ns(
color: bool,
args: Sequence[str],
stdin: bytes,
) -> Optional[argparse.Namespace]:
) -> argparse.Namespace | None:
remote_name = args[0]
remote_url = args[1]
@ -197,7 +197,7 @@ def _run_ns(
color: bool,
args: Sequence[str],
stdin: bytes,
) -> Optional[argparse.Namespace]:
) -> argparse.Namespace | None:
_check_args_length(hook_type, args)
if hook_type == 'pre-push':
return _pre_push_ns(color, args, stdin)

View file

@ -1,6 +1,7 @@
from __future__ import annotations
import logging
import os.path
from typing import Sequence
from pre_commit.commands.install_uninstall import install
from pre_commit.store import Store
@ -14,7 +15,7 @@ def init_templatedir(
config_file: str,
store: Store,
directory: str,
hook_types: Sequence[str],
hook_types: list[str] | None,
skip_on_missing_config: bool = True,
) -> int:
install(

View file

@ -1,14 +1,14 @@
from __future__ import annotations
import logging
import os.path
import shlex
import shutil
import sys
from typing import Optional
from typing import Sequence
from typing import Tuple
from pre_commit import git
from pre_commit import output
from pre_commit.clientlib import InvalidConfigError
from pre_commit.clientlib import load_config
from pre_commit.repository import all_hooks
from pre_commit.repository import install_hook_envs
@ -32,11 +32,23 @@ TEMPLATE_START = '# start templated\n'
TEMPLATE_END = '# end templated\n'
def _hook_types(cfg_filename: str, hook_types: list[str] | None) -> list[str]:
if hook_types is not None:
return hook_types
else:
try:
cfg = load_config(cfg_filename)
except InvalidConfigError:
return ['pre-commit']
else:
return cfg['default_install_hook_types']
def _hook_paths(
hook_type: str,
git_dir: Optional[str] = None,
) -> Tuple[str, str]:
git_dir = git_dir if git_dir is not None else git.get_git_dir()
git_dir: str | None = None,
) -> tuple[str, str]:
git_dir = git_dir if git_dir is not None else git.get_git_common_dir()
pth = os.path.join(git_dir, 'hooks', hook_type)
return pth, f'{pth}.legacy'
@ -54,7 +66,7 @@ def _install_hook_script(
hook_type: str,
overwrite: bool = False,
skip_on_missing_config: bool = False,
git_dir: Optional[str] = None,
git_dir: str | None = None,
) -> None:
hook_path, legacy_path = _hook_paths(hook_type, git_dir=git_dir)
@ -103,11 +115,11 @@ def _install_hook_script(
def install(
config_file: str,
store: Store,
hook_types: Sequence[str],
hook_types: list[str] | None,
overwrite: bool = False,
hooks: bool = False,
skip_on_missing_config: bool = False,
git_dir: Optional[str] = None,
git_dir: str | None = None,
) -> int:
if git_dir is None and git.has_core_hookpaths_set():
logger.error(
@ -116,7 +128,7 @@ def install(
)
return 1
for hook_type in hook_types:
for hook_type in _hook_types(config_file, hook_types):
_install_hook_script(
config_file, hook_type,
overwrite=overwrite,
@ -150,7 +162,7 @@ def _uninstall_hook_script(hook_type: str) -> None:
output.write_line(f'Restored previous hooks to {hook_path}')
def uninstall(hook_types: Sequence[str]) -> int:
for hook_type in hook_types:
def uninstall(config_file: str, hook_types: list[str] | None) -> int:
for hook_type in _hook_types(config_file, hook_types):
_uninstall_hook_script(hook_type)
return 0

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import re
import textwrap

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import argparse
import contextlib
import functools
@ -9,12 +11,8 @@ import time
import unicodedata
from typing import Any
from typing import Collection
from typing import Dict
from typing import List
from typing import MutableMapping
from typing import Sequence
from typing import Set
from typing import Tuple
from identify.identify import tags_from_path
@ -62,7 +60,7 @@ def filter_by_include_exclude(
names: Collection[str],
include: str,
exclude: str,
) -> List[str]:
) -> list[str]:
include_re, exclude_re = re.compile(include), re.compile(exclude)
return [
filename for filename in names
@ -76,7 +74,7 @@ class Classifier:
self.filenames = [f for f in filenames if os.path.lexists(f)]
@functools.lru_cache(maxsize=None)
def _types_for_file(self, filename: str) -> Set[str]:
def _types_for_file(self, filename: str) -> set[str]:
return tags_from_path(filename)
def by_types(
@ -85,7 +83,7 @@ class Classifier:
types: Collection[str],
types_or: Collection[str],
exclude_types: Collection[str],
) -> List[str]:
) -> list[str]:
types = frozenset(types)
types_or = frozenset(types_or)
exclude_types = frozenset(exclude_types)
@ -100,7 +98,7 @@ class Classifier:
ret.append(filename)
return ret
def filenames_for_hook(self, hook: Hook) -> Tuple[str, ...]:
def filenames_for_hook(self, hook: Hook) -> tuple[str, ...]:
names = self.filenames
names = filter_by_include_exclude(names, hook.files, hook.exclude)
names = self.by_types(
@ -117,7 +115,7 @@ class Classifier:
filenames: Collection[str],
include: str,
exclude: str,
) -> 'Classifier':
) -> Classifier:
# on windows we normalize all filenames to use forward slashes
# this makes it easier to filter using the `files:` regex
# this also makes improperly quoted shell-based hooks work better
@ -128,7 +126,7 @@ class Classifier:
return Classifier(filenames)
def _get_skips(environ: MutableMapping[str, str]) -> Set[str]:
def _get_skips(environ: MutableMapping[str, str]) -> set[str]:
skips = environ.get('SKIP', '')
return {skip.strip() for skip in skips.split(',') if skip.strip()}
@ -144,12 +142,12 @@ def _subtle_line(s: str, use_color: bool) -> None:
def _run_single_hook(
classifier: Classifier,
hook: Hook,
skips: Set[str],
skips: set[str],
cols: int,
diff_before: bytes,
verbose: bool,
use_color: bool,
) -> Tuple[bool, bytes]:
) -> tuple[bool, bytes]:
filenames = classifier.filenames_for_hook(hook)
if hook.id in skips or hook.alias in skips:
@ -271,9 +269,9 @@ def _get_diff() -> bytes:
def _run_hooks(
config: Dict[str, Any],
config: dict[str, Any],
hooks: Sequence[Hook],
skips: Set[str],
skips: set[str],
args: argparse.Namespace,
) -> int:
"""Actually run the hooks."""

View file

@ -2,6 +2,7 @@
# determine the latest revision? This adds ~200ms from my tests (and is
# significantly faster than https:// or http://). For now, periodically
# manually updating the revision is fine.
from __future__ import annotations
SAMPLE_CONFIG = '''\
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks

View file

@ -1,8 +1,8 @@
from __future__ import annotations
import argparse
import logging
import os.path
from typing import Optional
from typing import Tuple
import pre_commit.constants as C
from pre_commit import git
@ -18,7 +18,7 @@ from pre_commit.xargs import xargs
logger = logging.getLogger(__name__)
def _repo_ref(tmpdir: str, repo: str, ref: Optional[str]) -> Tuple[str, str]:
def _repo_ref(tmpdir: str, repo: str, ref: str | None) -> tuple[str, str]:
# if `ref` is explicitly passed, use it
if ref is not None:
return repo, ref