https://github.com/python/cpython/commit/2ea48506a26b7463e8469e6936d03e4f85cd28b9
commit: 2ea48506a26b7463e8469e6936d03e4f85cd28b9
branch: 3.13
author: Hugo van Kemenade <[email protected]>
committer: ambv <[email protected]>
date: 2026-03-24T02:49:26+01:00
summary:

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

(cherry picked from commit e682141c495c2e52368c4341ae54eea041070356)

Co-authored-by: Savannah Ostrowski <[email protected]>
Co-authored-by: Hugo van Kemenade <[email protected]>
Co-authored-by: Xianpeng Shen <[email protected]>
Co-authored-by: Stan Ulbrych <[email protected]>

files:
M .github/actionlint.yaml
M .github/zizmor.yml
M .pre-commit-config.yaml
M Tools/build/check_extension_modules.py
M Tools/build/deepfreeze.py
M Tools/build/freeze_modules.py
M Tools/build/generate_global_objects.py
M Tools/build/generate_levenshtein_examples.py
M Tools/build/generate_re_casefix.py
M Tools/build/generate_sbom.py
M Tools/build/generate_sre_constants.py
M Tools/build/generate_stdlib_module_names.py
M Tools/build/generate_token.py
M Tools/build/parse_html5_entities.py
M Tools/build/smelly.py
M Tools/build/stable_abi.py
M Tools/build/umarshal.py

diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml
index 267ff6b42a8655..eacfff24889021 100644
--- a/.github/actionlint.yaml
+++ b/.github/actionlint.yaml
@@ -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:
diff --git a/.github/zizmor.yml b/.github/zizmor.yml
index fab3abcb355dfe..8b7b4de0fc8f31 100644
--- a/.github/zizmor.yml
+++ b/.github/zizmor.yml
@@ -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:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index fa49526ad51ad3..055f8854a970f8 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -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]
diff --git a/Tools/build/check_extension_modules.py 
b/Tools/build/check_extension_modules.py
index e0c7a9209ead27..668db8df0bd181 100644
--- a/Tools/build/check_extension_modules.py
+++ b/Tools/build/check_extension_modules.py
@@ -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
diff --git a/Tools/build/deepfreeze.py b/Tools/build/deepfreeze.py
index 35decd97d33d59..fb059748c02fd2 100644
--- a/Tools/build/deepfreeze.py
+++ b/Tools/build/deepfreeze.py
@@ -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
diff --git a/Tools/build/freeze_modules.py b/Tools/build/freeze_modules.py
index eef2d0af046f51..b3e64746947835 100644
--- a/Tools/build/freeze_modules.py
+++ b/Tools/build/freeze_modules.py
@@ -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)
diff --git a/Tools/build/generate_global_objects.py 
b/Tools/build/generate_global_objects.py
index 882918fafb1edd..5925fb7fb883f4 100644
--- a/Tools/build/generate_global_objects.py
+++ b/Tools/build/generate_global_objects.py
@@ -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]:
diff --git a/Tools/build/generate_levenshtein_examples.py 
b/Tools/build/generate_levenshtein_examples.py
index 778eb458c541c0..30dcc7cf1a1479 100644
--- a/Tools/build/generate_levenshtein_examples.py
+++ b/Tools/build/generate_levenshtein_examples.py
@@ -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.
diff --git a/Tools/build/generate_re_casefix.py 
b/Tools/build/generate_re_casefix.py
index 6cebfbd025c58c..9345b8f4efe09d 100755
--- a/Tools/build/generate_re_casefix.py
+++ b/Tools/build/generate_re_casefix.py
@@ -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 = []
diff --git a/Tools/build/generate_sbom.py b/Tools/build/generate_sbom.py
index f8ddebf84a00b1..519fca02a047a3 100644
--- a/Tools/build/generate_sbom.py
+++ b/Tools/build/generate_sbom.py
@@ -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'"
         )
 
 
diff --git a/Tools/build/generate_sre_constants.py 
b/Tools/build/generate_sre_constants.py
index abea069c8bc0c5..f51339db333c4f 100755
--- a/Tools/build/generate_sre_constants.py
+++ b/Tools/build/generate_sre_constants.py
@@ -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):
diff --git a/Tools/build/generate_stdlib_module_names.py 
b/Tools/build/generate_stdlib_module_names.py
index 93a9fbe2dd67e7..c2f6469da71f6c 100644
--- a/Tools/build/generate_stdlib_module_names.py
+++ b/Tools/build/generate_stdlib_module_names.py
@@ -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__)))
diff --git a/Tools/build/generate_token.py b/Tools/build/generate_token.py
index a5f9828c466eda..7316333dcd452e 100755
--- a/Tools/build/generate_token.py
+++ b/Tools/build/generate_token.py
@@ -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):
diff --git a/Tools/build/parse_html5_entities.py 
b/Tools/build/parse_html5_entities.py
index d2bf29091030a5..aca98497381a43 100755
--- a/Tools/build/parse_html5_entities.py
+++ b/Tools/build/parse_html5_entities.py
@@ -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.')
diff --git a/Tools/build/smelly.py b/Tools/build/smelly.py
index 7c534269c57a09..17e070c7b7fb8a 100755
--- a/Tools/build/smelly.py
+++ b/Tools/build/smelly.py
@@ -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)
 
 
diff --git a/Tools/build/stable_abi.py b/Tools/build/stable_abi.py
index cb9ca5b2097c74..4b4f06b9e92f01 100644
--- a/Tools/build/stable_abi.py
+++ b/Tools/build/stable_abi.py
@@ -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',
diff --git a/Tools/build/umarshal.py b/Tools/build/umarshal.py
index e89ba027c5d843..52db6cae80e23a 100644
--- a/Tools/build/umarshal.py
+++ b/Tools/build/umarshal.py
@@ -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)

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to