[3.13] Bump pre-commit hooks (GH-144576) (GH-144593)

(cherry picked from commit e682141c49)

Co-authored-by: Savannah Ostrowski <savannah@python.org>
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Co-authored-by: Xianpeng Shen <xianpeng.shen@gmail.com>
Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com>
This commit is contained in:
Hugo van Kemenade 2026-03-24 03:49:26 +02:00 committed by GitHub
parent 793a86f8a0
commit 2ea48506a2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 97 additions and 109 deletions

View file

@ -1,8 +1,3 @@
self-hosted-runner:
# Pending https://github.com/rhysd/actionlint/issues/533
# and https://github.com/rhysd/actionlint/issues/571
labels: ["windows-11-arm", "macos-15-intel"]
config-variables: null
paths:

2
.github/zizmor.yml vendored
View file

@ -1,5 +1,5 @@
# Configuration for the zizmor static analysis tool, run via prek in CI
# https://woodruffw.github.io/zizmor/configuration/
# https://docs.zizmor.sh/configuration/
rules:
dangerous-triggers:
ignore:

View file

@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.10
rev: a27a2e47c7751b639d2b5badf0ef6ff11fee893f # frozen: v0.15.4
hooks:
- id: ruff-check
name: Run Ruff (lint) on Doc/
@ -36,14 +36,14 @@ repos:
files: ^Tools/wasm/
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 25.12.0
rev: ea488cebbfd88a5f50b8bd95d5c829d0bb76feb8 # frozen: 26.1.0
hooks:
- id: black
name: Run Black on Tools/jit/
files: ^Tools/jit/
- repo: https://github.com/Lucas-C/pre-commit-hooks
rev: v1.5.5
rev: ad1b27d73581aa16cca06fc4a0761fc563ffe8e8 # frozen: v1.5.6
hooks:
- id: remove-tabs
types: [python]
@ -66,7 +66,7 @@ repos:
files: Misc/NEWS.d/next/Core and Builtins/20.*.rst
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.0.0
hooks:
- id: check-case-conflict
- id: check-merge-conflict
@ -84,24 +84,24 @@ repos:
files: '^\.github/CODEOWNERS|\.(gram)$'
- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.36.0
rev: 9f48a48aa91a6040d749ad68ec70907d907a5a7f # frozen: 0.37.0
hooks:
- id: check-dependabot
- id: check-github-workflows
- id: check-readthedocs
- repo: https://github.com/rhysd/actionlint
rev: v1.7.9
rev: 393031adb9afb225ee52ae2ccd7a5af5525e03e8 # frozen: v1.7.11
hooks:
- id: actionlint
- repo: https://github.com/woodruffw/zizmor-pre-commit
rev: v1.19.0
- repo: https://github.com/zizmorcore/zizmor-pre-commit
rev: b546b77c44c466a54a42af5499dcc0dcc1a3193f # frozen: v1.22.0
hooks:
- id: zizmor
- repo: https://github.com/sphinx-contrib/sphinx-lint
rev: v1.0.2
rev: c883505f64b59c3c5c9375191e4ad9f98e727ccd # frozen: v1.0.2
hooks:
- id: sphinx-lint
args: [--enable=default-role]

View file

@ -30,10 +30,15 @@
import sys
import sysconfig
import warnings
from collections.abc import Iterable
from importlib._bootstrap import _load as bootstrap_load # type: ignore[attr-defined]
from importlib.machinery import BuiltinImporter, ExtensionFileLoader, ModuleSpec
from importlib._bootstrap import ( # type: ignore[attr-defined]
_load as bootstrap_load,
)
from importlib.machinery import (
BuiltinImporter,
ExtensionFileLoader,
ModuleSpec,
)
from importlib.util import spec_from_file_location, spec_from_loader
from typing import NamedTuple
@ -201,7 +206,7 @@ def print_three_column(modinfos: list[ModuleInfo]) -> None:
# guarantee zip() doesn't drop anything
while len(names) % 3:
names.append("")
for l, m, r in zip(names[::3], names[1::3], names[2::3]):
for l, m, r in zip(names[::3], names[1::3], names[2::3]): # noqa: E741
print("%-*s %-*s %-*s" % (longest, l, longest, m, longest, r))
if verbose and self.builtin_ok:
@ -433,7 +438,7 @@ def check_module_import(self, modinfo: ModuleInfo) -> None:
except ImportError as e:
logger.error("%s failed to import: %s", modinfo.name, e)
raise
except Exception as e:
except Exception:
if not hasattr(_imp, 'create_dynamic'):
logger.warning("Dynamic extension '%s' ignored", modinfo.name)
return

View file

@ -16,12 +16,13 @@
import re
import time
import types
import umarshal
TYPE_CHECKING = False
if TYPE_CHECKING:
from collections.abc import Iterator
from typing import Any, TextIO, Dict, FrozenSet, TextIO, Tuple
from typing import Any, TextIO
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
@ -63,8 +64,8 @@ def get_localsplus(code: types.CodeType) -> tuple[tuple[str, ...], bytes]:
def get_localsplus_counts(code: types.CodeType,
names: Tuple[str, ...],
kinds: bytes) -> Tuple[int, int, int]:
names: tuple[str, ...],
kinds: bytes) -> tuple[int, int, int]:
nlocals = 0
ncellvars = 0
nfreevars = 0
@ -90,7 +91,7 @@ def get_localsplus_counts(code: types.CodeType,
PyUnicode_4BYTE_KIND = 4
def analyze_character_width(s: str) -> Tuple[int, bool]:
def analyze_character_width(s: str) -> tuple[int, bool]:
maxchar = ' '
for c in s:
maxchar = max(maxchar, c)
@ -115,7 +116,7 @@ class Printer:
def __init__(self, file: TextIO) -> None:
self.level = 0
self.file = file
self.cache: Dict[tuple[type, object, str], str] = {}
self.cache: dict[tuple[type, object, str], str] = {}
self.hits, self.misses = 0, 0
self.finis: list[str] = []
self.inits: list[str] = []
@ -319,7 +320,7 @@ def generate_code(self, name: str, code: types.CodeType) -> str:
self.inits.append(f"_PyStaticCode_Init({name_as_code})")
return f"& {name}.ob_base.ob_base"
def generate_tuple(self, name: str, t: Tuple[object, ...]) -> str:
def generate_tuple(self, name: str, t: tuple[object, ...]) -> str:
if len(t) == 0:
return f"(PyObject *)& _Py_SINGLETON(tuple_empty)"
items = [self.generate(f"{name}_{i}", it) for i, it in enumerate(t)]
@ -393,7 +394,7 @@ def generate_complex(self, name: str, z: complex) -> str:
self.write(f".cval = {{ {z.real}, {z.imag} }},")
return f"&{name}.ob_base"
def generate_frozenset(self, name: str, fs: FrozenSet[Any]) -> str:
def generate_frozenset(self, name: str, fs: frozenset[Any]) -> str:
try:
fs_sorted = sorted(fs)
except TypeError:
@ -479,7 +480,7 @@ def generate(args: list[str], output: TextIO) -> None:
printer = Printer(output)
for arg in args:
file, modname = arg.rsplit(':', 1)
with open(file, "r", encoding="utf8") as fd:
with open(file, encoding="utf8") as fd:
source = fd.read()
if is_frozen_header(source):
code = decode_frozen_data(source)
@ -527,7 +528,7 @@ def main() -> None:
if args.file:
if verbose:
print(f"Reading targets from {args.file}")
with open(args.file, "rt", encoding="utf-8-sig") as fin:
with open(args.file, encoding="utf-8-sig") as fin:
rules = [x.strip() for x in fin]
else:
rules = args.args

View file

@ -3,14 +3,13 @@
See the notes at the top of Python/frozen.c for more info.
"""
from collections import namedtuple
import hashlib
import os
import ntpath
import os
import posixpath
import argparse
from update_file import updating_file_with_tmpfile
from collections import namedtuple
from update_file import updating_file_with_tmpfile
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
ROOT_DIR = os.path.abspath(ROOT_DIR)
@ -485,7 +484,6 @@ def regen_frozen(modules):
header = relpath_for_posix_display(src.frozenfile, parentdir)
headerlines.append(f'#include "{header}"')
externlines = UniqueList()
bootstraplines = []
stdliblines = []
testlines = []
@ -628,7 +626,6 @@ def regen_makefile(modules):
def regen_pcbuild(modules):
projlines = []
filterlines = []
corelines = []
for src in _iter_sources(modules):
pyfile = relpath_for_windows_display(src.pyfile, ROOT_DIR)
header = relpath_for_windows_display(src.frozenfile, ROOT_DIR)

View file

@ -286,7 +286,8 @@ def generate_runtime_init(identifiers, strings):
break
else:
raise NotImplementedError
assert nsmallposints and nsmallnegints
assert nsmallposints
assert nsmallnegints
# Then target the runtime initializer.
filename = os.path.join(INTERNAL, 'pycore_runtime_init_generated.h')
@ -434,7 +435,7 @@ def get_identifiers_and_strings() -> 'tuple[set[str], dict[str, str]]':
# To cover tricky cases (like "\n") we also generate C asserts.
raise ValueError(
'do not use &_PyID or &_Py_STR for one-character latin-1 '
+ f'strings, use _Py_LATIN1_CHR instead: {string!r}')
f'strings, use _Py_LATIN1_CHR instead: {string!r}')
if string not in strings:
strings[string] = name
elif name != strings[string]:

View file

@ -1,12 +1,11 @@
"""Generate 10,000 unique examples for the Levenshtein short-circuit tests."""
import argparse
from functools import lru_cache
import json
import os.path
from functools import lru_cache
from random import choices, randrange
# This should be in sync with Lib/traceback.py. It's not importing those values
# because this script is being executed by PYTHON_FOR_REGEN and not by the in-tree
# build of Python.

View file

@ -9,7 +9,7 @@
def update_file(file, content):
try:
with open(file, 'r', encoding='utf-8') as fobj:
with open(file, encoding='utf-8') as fobj:
if fobj.read() == content:
return False
except (OSError, ValueError):
@ -50,7 +50,7 @@ def main(outfile='Lib/re/_casefix.py'):
# List of codes of lowercased characters which have the same uppercase.
equivalent_lower_codes = [sorted(t)
for s in equivalent_chars
for t in [set(ord(c.lower()) for c in s)]
for t in [{ord(c.lower()) for c in s}]
if len(t) > 1]
bad_codes = []

View file

@ -1,18 +1,18 @@
"""Tool for generating Software Bill of Materials (SBOM) for Python's dependencies"""
import glob
import hashlib
import json
import os
import random
import re
import hashlib
import json
import glob
from pathlib import Path, PurePosixPath, PureWindowsPath
import subprocess
import sys
import time
import typing
import urllib.error
import urllib.request
import typing
from pathlib import Path, PurePosixPath, PureWindowsPath
CPYTHON_ROOT_DIR = Path(__file__).parent.parent.parent
@ -274,7 +274,7 @@ def check_sbom_packages(sbom_data: dict[str, typing.Any]) -> None:
license_concluded = package["licenseConcluded"]
error_if(
license_concluded != "NOASSERTION",
f"License identifier must be 'NOASSERTION'"
"License identifier must be 'NOASSERTION'"
)

View file

@ -6,7 +6,7 @@
def update_file(file, content):
try:
with open(file, 'r') as fobj:
with open(file) as fobj:
if fobj.read() == content:
return False
except (OSError, ValueError):

View file

@ -10,7 +10,6 @@
from check_extension_modules import ModuleChecker
SCRIPT_NAME = 'Tools/build/generate_stdlib_module_names.py'
SRC_DIR = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))

View file

@ -13,7 +13,6 @@
import re
SCRIPT_NAME = 'Tools/build/generate_token.py'
AUTO_GENERATED_BY_SCRIPT = f'Auto-generated by {SCRIPT_NAME}'
NT_OFFSET = 256
@ -46,7 +45,7 @@ def load_tokens(path):
def update_file(file, content):
try:
with open(file, 'r') as fobj:
with open(file) as fobj:
if fobj.read() == content:
return False
except (OSError, ValueError):

View file

@ -12,11 +12,11 @@
Written by Ezio Melotti and Iuliia Proskurnia.
"""
import json
import os
import sys
import json
from urllib.request import urlopen
from html.entities import html5
from urllib.request import urlopen
SCRIPT_NAME = 'Tools/build/parse_html5_entities.py'
PAGE_URL = 'https://html.spec.whatwg.org/multipage/named-characters.html'
@ -40,20 +40,20 @@ def compare_dicts(old, new):
"""Compare the old and new dicts and print the differences."""
added = new.keys() - old.keys()
if added:
print('{} entitie(s) have been added:'.format(len(added)))
print(f'{len(added)} entitie(s) have been added:')
for name in sorted(added):
print(' {!r}: {!r}'.format(name, new[name]))
print(f' {name!r}: {new[name]!r}')
removed = old.keys() - new.keys()
if removed:
print('{} entitie(s) have been removed:'.format(len(removed)))
print(f'{len(removed)} entitie(s) have been removed:')
for name in sorted(removed):
print(' {!r}: {!r}'.format(name, old[name]))
print(f' {name!r}: {old[name]!r}')
changed = set()
for name in (old.keys() & new.keys()):
if old[name] != new[name]:
changed.add((name, old[name], new[name]))
if changed:
print('{} entitie(s) have been modified:'.format(len(changed)))
print(f'{len(changed)} entitie(s) have been modified:')
for item in sorted(changed):
print(' {!r}: {!r} -> {!r}'.format(*item))
@ -111,5 +111,5 @@ def write_items(entities, file=sys.stdout):
print('The current dictionary is updated.')
else:
compare_dicts(html5, new_html5)
print('Run "./python {0} --patch" to update Lib/html/entities.html '
'or "./python {0} --create" to see the generated ' 'dictionary.'.format(__file__))
print(f'Run "./python {__file__} --patch" to update Lib/html/entities.html '
f'or "./python {__file__} --create" to see the generated dictionary.')

View file

@ -6,7 +6,6 @@
import sys
import sysconfig
ALLOWED_PREFIXES = ('Py', '_Py')
if sys.platform == 'darwin':
ALLOWED_PREFIXES += ('__Py',)
@ -52,8 +51,8 @@ def get_exported_symbols(library, dynamic=False):
if dynamic:
args.append('--dynamic')
args.append(library)
print("+ %s" % ' '.join(args))
proc = subprocess.run(args, stdout=subprocess.PIPE, universal_newlines=True)
print(f"+ {' '.join(args)}")
proc = subprocess.run(args, stdout=subprocess.PIPE, text=True)
if proc.returncode:
sys.stdout.write(proc.stdout)
sys.exit(proc.returncode)
@ -80,7 +79,7 @@ def get_smelly_symbols(stdout, dynamic=False):
symtype = parts[1].strip()
symbol = parts[-1]
result = '%s (type: %s)' % (symbol, symtype)
result = f'{symbol} (type: {symtype})'
if (symbol.startswith(ALLOWED_PREFIXES) or
symbol in EXCEPTIONS or
@ -111,10 +110,10 @@ def check_library(library, dynamic=False):
print()
smelly_symbols.sort()
for symbol in smelly_symbols:
print("Smelly symbol: %s" % symbol)
print(f"Smelly symbol: {symbol}")
print()
print("ERROR: Found %s smelly symbols!" % len(smelly_symbols))
print(f"ERROR: Found {len(smelly_symbols)} smelly symbols!")
return len(smelly_symbols)

View file

@ -7,22 +7,22 @@
(relative to the manifest file, as they appear in the CPython codebase).
"""
from functools import partial
from pathlib import Path
import dataclasses
import subprocess
import sysconfig
import argparse
import textwrap
import tomllib
import csv
import dataclasses
import difflib
import pprint
import sys
import io
import os
import os.path
import io
import pprint
import re
import csv
import subprocess
import sys
import sysconfig
import textwrap
import tomllib
from functools import partial
from pathlib import Path
SCRIPT_NAME = 'Tools/build/stable_abi.py'
MISSING = object()
@ -55,7 +55,7 @@
class Manifest:
"""Collection of `ABIItem`s forming the stable ABI/limited API."""
def __init__(self):
self.contents = dict()
self.contents = {}
def add(self, item):
if item.name in self.contents:
@ -402,22 +402,20 @@ def do_unixy_check(manifest, args):
# Get all macros first: we'll need feature macros like HAVE_FORK and
# MS_WINDOWS for everything else
present_macros = gcc_get_limited_api_macros(['Include/Python.h'])
feature_macros = set(m.name for m in manifest.select({'feature_macro'}))
feature_macros = {m.name for m in manifest.select({'feature_macro'})}
feature_macros &= present_macros
# Check that we have all needed macros
expected_macros = set(
item.name for item in manifest.select({'macro'})
)
expected_macros = {item.name for item in manifest.select({'macro'})}
missing_macros = expected_macros - present_macros
okay &= _report_unexpected_items(
missing_macros,
'Some macros from are not defined from "Include/Python.h"'
+ 'with Py_LIMITED_API:')
'Some macros from are not defined from "Include/Python.h" '
'with Py_LIMITED_API:')
expected_symbols = set(item.name for item in manifest.select(
expected_symbols = {item.name for item in manifest.select(
{'function', 'data'}, include_abi_only=True, ifdef=feature_macros,
))
)}
# Check the static library (*.a)
LIBRARY = sysconfig.get_config_var("LIBRARY")
@ -435,15 +433,15 @@ def do_unixy_check(manifest, args):
manifest, LDLIBRARY, expected_symbols, dynamic=False)
# Check definitions in the header files
expected_defs = set(item.name for item in manifest.select(
expected_defs = {item.name for item in manifest.select(
{'function', 'data'}, include_abi_only=False, ifdef=feature_macros,
))
)}
found_defs = gcc_get_limited_api_definitions(['Include/Python.h'])
missing_defs = expected_defs - found_defs
okay &= _report_unexpected_items(
missing_defs,
'Some expected declarations were not declared in '
+ '"Include/Python.h" with Py_LIMITED_API:')
'"Include/Python.h" with Py_LIMITED_API:')
# Some Limited API macros are defined in terms of private symbols.
# These are not part of Limited API (even though they're defined with
@ -453,7 +451,7 @@ def do_unixy_check(manifest, args):
okay &= _report_unexpected_items(
extra_defs,
'Some extra declarations were found in "Include/Python.h" '
+ 'with Py_LIMITED_API:')
'with Py_LIMITED_API:')
return okay
@ -475,7 +473,7 @@ def binutils_get_exported_symbols(library, dynamic=False):
if dynamic:
args.append("--dynamic")
args.append(library)
proc = subprocess.run(args, stdout=subprocess.PIPE, universal_newlines=True)
proc = subprocess.run(args, stdout=subprocess.PIPE, text=True)
if proc.returncode:
sys.stdout.write(proc.stdout)
sys.exit(proc.returncode)
@ -548,12 +546,7 @@ def gcc_get_limited_api_macros(headers):
text=True,
)
return {
target
for target in re.findall(
r"#define (\w+)", preprocessor_output_with_macros
)
}
return set(re.findall(r"#define (\w+)", preprocessor_output_with_macros))
def gcc_get_limited_api_definitions(headers):
@ -611,7 +604,7 @@ def check_private_names(manifest):
if name.startswith('_') and not item.abi_only:
raise ValueError(
f'`{name}` is private (underscore-prefixed) and should be '
+ 'removed from the stable ABI list or marked `abi_only`')
'removed from the stable ABI list or marked `abi_only`')
def check_dump(manifest, filename):
"""Check that manifest.dump() corresponds to the data.
@ -622,7 +615,7 @@ def check_dump(manifest, filename):
with filename.open('rb') as file:
from_file = tomllib.load(file)
if dumped != from_file:
print(f'Dump differs from loaded data!', file=sys.stderr)
print('Dump differs from loaded data!', file=sys.stderr)
diff = difflib.unified_diff(
pprint.pformat(dumped).splitlines(),
pprint.pformat(from_file).splitlines(),
@ -651,7 +644,7 @@ def main():
parser.add_argument(
"--generate-all", action='store_true',
help="as --generate, but generate all file(s) using default filenames."
+ " (unlike --all, does not run any extra checks)",
" (unlike --all, does not run any extra checks)",
)
parser.add_argument(
"-a", "--all", action='store_true',

View file

@ -1,8 +1,7 @@
# Implementation of marshal.loads() in pure Python
import ast
from typing import Any, Tuple
from typing import Any
class Type:
@ -55,10 +54,10 @@ def __init__(self, **kwds: Any):
def __repr__(self) -> str:
return f"Code(**{self.__dict__})"
co_localsplusnames: Tuple[str]
co_localspluskinds: Tuple[int]
co_localsplusnames: tuple[str]
co_localspluskinds: tuple[int]
def get_localsplus_names(self, select_kind: int) -> Tuple[str, ...]:
def get_localsplus_names(self, select_kind: int) -> tuple[str, ...]:
varnames: list[str] = []
for name, kind in zip(self.co_localsplusnames,
self.co_localspluskinds):
@ -67,15 +66,15 @@ def get_localsplus_names(self, select_kind: int) -> Tuple[str, ...]:
return tuple(varnames)
@property
def co_varnames(self) -> Tuple[str, ...]:
def co_varnames(self) -> tuple[str, ...]:
return self.get_localsplus_names(CO_FAST_LOCAL)
@property
def co_cellvars(self) -> Tuple[str, ...]:
def co_cellvars(self) -> tuple[str, ...]:
return self.get_localsplus_names(CO_FAST_CELL)
@property
def co_freevars(self) -> Tuple[str, ...]:
def co_freevars(self) -> tuple[str, ...]:
return self.get_localsplus_names(CO_FAST_FREE)
@property
@ -309,7 +308,8 @@ def loads(data: bytes) -> Any:
def main() -> None:
# Test
import marshal, pprint
import marshal
import pprint
sample = {'foo': {(42, "bar", 3.14)}}
data = marshal.dumps(sample)
retval = loads(data)