From 869bb6948eb501b19db53cb27c523c3203a5ab11 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com> Date: Fri, 17 Oct 2025 07:55:12 +0100 Subject: [PATCH 1/5] Standardize translation of `Doc/bugs.rst` (GH-137449) --- Doc/bugs.rst | 6 ++++++ Doc/conf.py | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/Doc/bugs.rst b/Doc/bugs.rst index faf13eeb6a7..0683eebbaf6 100644 --- a/Doc/bugs.rst +++ b/Doc/bugs.rst @@ -19,6 +19,12 @@ If you find a bug in this documentation or would like to propose an improvement, please submit a bug report on the :ref:`issue tracker `. If you have a suggestion on how to fix it, include that as well. +.. only:: translation + + If the bug or suggested improvement concerns the translation of this + documentation, submit the report to the + `translation’s repository `_ instead. + You can also open a discussion item on our `Documentation Discourse forum `_. diff --git a/Doc/conf.py b/Doc/conf.py index c1b07df08b1..a8e376c0ae4 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -444,6 +444,25 @@ # https://github.com/sphinx-doc/sphinx/issues/12359 epub_use_index = False +# translation tag +# --------------- + +language_code = None +for arg in sys.argv: + if arg.startswith('language='): + language_code = arg.split('=', 1)[1] + +if language_code: + tags.add('translation') # noqa: F821 + + rst_epilog += f"""\ +.. _TRANSLATION_REPO: https://github.com/python/python-docs-{language_code.replace("_", "-").lower()} +""" # noqa: F821 +else: + rst_epilog += """\ +.. _TRANSLATION_REPO: https://github.com/python +""" + # Options for the coverage checker # -------------------------------- From 999ab8926bd344a3c7f73b130ac773e2462f8320 Mon Sep 17 00:00:00 2001 From: Albert N Date: Fri, 17 Oct 2025 11:48:53 +0300 Subject: [PATCH 2/5] gh-133059: Fix `Tools/build/deepfreeze.py` for new nsmallposints (#139906) --- .github/workflows/mypy.yml | 1 + Tools/build/consts_getter.py | 20 ++++++++++++++++++++ Tools/build/deepfreeze.py | 5 ++++- Tools/build/generate_global_objects.py | 17 +++-------------- Tools/build/mypy.ini | 1 + 5 files changed, 29 insertions(+), 15 deletions(-) create mode 100644 Tools/build/consts_getter.py diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml index 5d5d77f29f6..fac0fa8aba3 100644 --- a/.github/workflows/mypy.yml +++ b/.github/workflows/mypy.yml @@ -16,6 +16,7 @@ on: - "Tools/build/check_extension_modules.py" - "Tools/build/check_warnings.py" - "Tools/build/compute-changes.py" + - "Tools/build/consts_getter.py" - "Tools/build/deepfreeze.py" - "Tools/build/generate-build-details.py" - "Tools/build/generate_sbom.py" diff --git a/Tools/build/consts_getter.py b/Tools/build/consts_getter.py new file mode 100644 index 00000000000..4cd454448ba --- /dev/null +++ b/Tools/build/consts_getter.py @@ -0,0 +1,20 @@ +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[2] +INTERNAL = ROOT / "Include" / "internal" + +def get_nsmallnegints_and_nsmallposints() -> tuple[int, int]: + nsmallposints = None + nsmallnegints = None + with open(INTERNAL / "pycore_runtime_structs.h") as infile: + for line in infile: + if line.startswith("#define _PY_NSMALLPOSINTS"): + nsmallposints = int(line.split()[-1]) + elif line.startswith("#define _PY_NSMALLNEGINTS"): + nsmallnegints = int(line.split()[-1]) + break + else: + raise NotImplementedError + assert nsmallposints + assert nsmallnegints + return nsmallnegints, nsmallposints diff --git a/Tools/build/deepfreeze.py b/Tools/build/deepfreeze.py index 2b9f03aebb6..477c3d0f5b3 100644 --- a/Tools/build/deepfreeze.py +++ b/Tools/build/deepfreeze.py @@ -17,6 +17,7 @@ import time import types +import consts_getter import umarshal TYPE_CHECKING = False @@ -362,7 +363,9 @@ def _generate_int_for_bits(self, name: str, i: int, digit: int) -> None: self.write(f".ob_digit = {{ {ds} }},") def generate_int(self, name: str, i: int) -> str: - if -5 <= i <= 256: + nsmallnegints, nsmallposints = consts_getter.get_nsmallnegints_and_nsmallposints() + + if -nsmallnegints <= i <= nsmallposints: return f"(PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + {i}]" if i >= 0: name = f"const_int_{i}" diff --git a/Tools/build/generate_global_objects.py b/Tools/build/generate_global_objects.py index 94905b3756d..5b188e338ba 100644 --- a/Tools/build/generate_global_objects.py +++ b/Tools/build/generate_global_objects.py @@ -3,6 +3,8 @@ import os.path import re +import consts_getter + SCRIPT_NAME = 'Tools/build/generate_global_objects.py' __file__ = os.path.abspath(__file__) ROOT = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) @@ -274,20 +276,7 @@ def generate_global_strings(identifiers, strings): def generate_runtime_init(identifiers, strings): - # First get some info from the declarations. - nsmallposints = None - nsmallnegints = None - with open(os.path.join(INTERNAL, 'pycore_runtime_structs.h')) as infile: - for line in infile: - if line.startswith('#define _PY_NSMALLPOSINTS'): - nsmallposints = int(line.split()[-1]) - elif line.startswith('#define _PY_NSMALLNEGINTS'): - nsmallnegints = int(line.split()[-1]) - break - else: - raise NotImplementedError - assert nsmallposints - assert nsmallnegints + nsmallnegints, nsmallposints = consts_getter.get_nsmallnegints_and_nsmallposints() # Then target the runtime initializer. filename = os.path.join(INTERNAL, 'pycore_runtime_init_generated.h') diff --git a/Tools/build/mypy.ini b/Tools/build/mypy.ini index 331bada6f47..7d341afd1cd 100644 --- a/Tools/build/mypy.ini +++ b/Tools/build/mypy.ini @@ -6,6 +6,7 @@ files = Tools/build/check_extension_modules.py, Tools/build/check_warnings.py, Tools/build/compute-changes.py, + Tools/build/consts_getter.py, Tools/build/deepfreeze.py, Tools/build/generate-build-details.py, Tools/build/generate_sbom.py, From f1883852ed4cd1923e619e71437641d06873503d Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 17 Oct 2025 11:26:17 +0100 Subject: [PATCH 3/5] GH-135904: Implement assembler optimization for AArch64. (GH-139855) --- Python/jit.c | 27 ++++++++++++++++++----- Tools/jit/_optimizers.py | 47 ++++++++++++++++++++++++++++++++++++++-- Tools/jit/_schema.py | 2 ++ Tools/jit/_stencils.py | 2 ++ Tools/jit/_targets.py | 5 +++-- 5 files changed, 74 insertions(+), 9 deletions(-) diff --git a/Python/jit.c b/Python/jit.c index 01ec9c1fa6e..ebd0d90385e 100644 --- a/Python/jit.c +++ b/Python/jit.c @@ -167,11 +167,13 @@ set_bits(uint32_t *loc, uint8_t loc_start, uint64_t value, uint8_t value_start, // See https://developer.arm.com/documentation/ddi0602/2023-09/Base-Instructions // for instruction encodings: -#define IS_AARCH64_ADD_OR_SUB(I) (((I) & 0x11C00000) == 0x11000000) -#define IS_AARCH64_ADRP(I) (((I) & 0x9F000000) == 0x90000000) -#define IS_AARCH64_BRANCH(I) (((I) & 0x7C000000) == 0x14000000) -#define IS_AARCH64_LDR_OR_STR(I) (((I) & 0x3B000000) == 0x39000000) -#define IS_AARCH64_MOV(I) (((I) & 0x9F800000) == 0x92800000) +#define IS_AARCH64_ADD_OR_SUB(I) (((I) & 0x11C00000) == 0x11000000) +#define IS_AARCH64_ADRP(I) (((I) & 0x9F000000) == 0x90000000) +#define IS_AARCH64_BRANCH(I) (((I) & 0x7C000000) == 0x14000000) +#define IS_AARCH64_BRANCH_COND(I) (((I) & 0x7C000000) == 0x54000000) +#define IS_AARCH64_TEST_AND_BRANCH(I) (((I) & 0x7E000000) == 0x36000000) +#define IS_AARCH64_LDR_OR_STR(I) (((I) & 0x3B000000) == 0x39000000) +#define IS_AARCH64_MOV(I) (((I) & 0x9F800000) == 0x92800000) // LLD is a great reference for performing relocations... just keep in // mind that Tools/jit/build.py does filtering and preprocessing for us! @@ -332,6 +334,21 @@ patch_aarch64_21rx(unsigned char *location, uint64_t value) patch_aarch64_21r(location, value); } +// 21-bit relative branch. +void +patch_aarch64_19r(unsigned char *location, uint64_t value) +{ + uint32_t *loc32 = (uint32_t *)location; + assert(IS_AARCH64_BRANCH_COND(*loc32)); + value -= (uintptr_t)location; + // Check that we're not out of range of 21 signed bits: + assert((int64_t)value >= -(1 << 20)); + assert((int64_t)value < (1 << 20)); + // Since instructions are 4-byte aligned, only use 19 bits: + assert(get_bits(value, 0, 2) == 0); + set_bits(loc32, 5, value, 2, 19); +} + // 28-bit relative branch. void patch_aarch64_26r(unsigned char *location, uint64_t value) diff --git a/Tools/jit/_optimizers.py b/Tools/jit/_optimizers.py index 33db110b728..866417398b0 100644 --- a/Tools/jit/_optimizers.py +++ b/Tools/jit/_optimizers.py @@ -39,6 +39,34 @@ # Update with all of the inverted branches, too: _X86_BRANCHES |= {v: k for k, v in _X86_BRANCHES.items() if v} +_AARCH64_COND_CODES = { + # https://developer.arm.com/documentation/dui0801/b/CJAJIHAD?lang=en + "eq": "ne", + "ne": "eq", + "lt": "ge", + "ge": "lt", + "gt": "le", + "le": "gt", + "vs": "vc", + "vc": "vs", + "mi": "pl", + "pl": "mi", + "cs": "cc", + "cc": "cs", + "hs": "lo", + "lo": "hs", + "hi": "ls", + "ls": "hi", +} +# Branches are either b.{cond} or bc.{cond} +_AARCH64_BRANCHES = { + "b." + cond: ("b." + inverse if inverse else None) + for (cond, inverse) in _AARCH64_COND_CODES.items() +} | { + "bc." + cond: ("bc." + inverse if inverse else None) + for (cond, inverse) in _AARCH64_COND_CODES.items() +} + @dataclasses.dataclass class _Block: @@ -283,13 +311,28 @@ def run(self) -> None: self.path.write_text(self._body()) -class OptimizerAArch64(Optimizer): # pylint: disable = too-few-public-methods - """aarch64-apple-darwin/aarch64-pc-windows-msvc/aarch64-unknown-linux-gnu""" +# Mach-O does not support the 19 bit branch locations needed for branch reordering +class OptimizerAArch64_MachO(Optimizer): # pylint: disable = too-few-public-methods + """aarch64-apple-darwin""" # https://developer.arm.com/documentation/ddi0602/2025-03/Base-Instructions/B--Branch- _re_jump = re.compile(r"\s*b\s+(?P[\w.]+)") +class OptimizerAArch64(Optimizer): # pylint: disable = too-few-public-methods + """aarch64-pc-windows-msvc/aarch64-unknown-linux-gnu""" + + _branches = _AARCH64_BRANCHES + _re_branch = re.compile( + rf"\s*(?P{'|'.join(_AARCH64_BRANCHES)})\s+(.+,\s+)*(?P[\w.]+)" + ) + + # https://developer.arm.com/documentation/ddi0602/2025-03/Base-Instructions/B--Branch- + _re_jump = re.compile(r"\s*b\s+(?P[\w.]+)") + # https://developer.arm.com/documentation/ddi0602/2025-09/Base-Instructions/RET--Return-from-subroutine- + _re_return = re.compile(r"\s*ret\b") + + class OptimizerX86(Optimizer): # pylint: disable = too-few-public-methods """i686-pc-windows-msvc/x86_64-apple-darwin/x86_64-unknown-linux-gnu""" diff --git a/Tools/jit/_schema.py b/Tools/jit/_schema.py index 228fc389584..c47e9af924a 100644 --- a/Tools/jit/_schema.py +++ b/Tools/jit/_schema.py @@ -10,6 +10,7 @@ "ARM64_RELOC_PAGEOFF12", "ARM64_RELOC_UNSIGNED", "IMAGE_REL_AMD64_REL32", + "IMAGE_REL_ARM64_BRANCH19", "IMAGE_REL_ARM64_BRANCH26", "IMAGE_REL_ARM64_PAGEBASE_REL21", "IMAGE_REL_ARM64_PAGEOFFSET_12A", @@ -20,6 +21,7 @@ "R_AARCH64_ADR_GOT_PAGE", "R_AARCH64_ADR_PREL_PG_HI21", "R_AARCH64_CALL26", + "R_AARCH64_CONDBR19", "R_AARCH64_JUMP26", "R_AARCH64_ADD_ABS_LO12_NC", "R_AARCH64_LD64_GOT_LO12_NC", diff --git a/Tools/jit/_stencils.py b/Tools/jit/_stencils.py index 14606b036db..16bc1ea4e17 100644 --- a/Tools/jit/_stencils.py +++ b/Tools/jit/_stencils.py @@ -61,6 +61,7 @@ class HoleValue(enum.Enum): # x86_64-pc-windows-msvc: "IMAGE_REL_AMD64_REL32": "patch_x86_64_32rx", # aarch64-pc-windows-msvc: + "IMAGE_REL_ARM64_BRANCH19": "patch_aarch64_19r", "IMAGE_REL_ARM64_BRANCH26": "patch_aarch64_26r", "IMAGE_REL_ARM64_PAGEBASE_REL21": "patch_aarch64_21rx", "IMAGE_REL_ARM64_PAGEOFFSET_12A": "patch_aarch64_12", @@ -74,6 +75,7 @@ class HoleValue(enum.Enum): "R_AARCH64_ADR_GOT_PAGE": "patch_aarch64_21rx", "R_AARCH64_ADR_PREL_PG_HI21": "patch_aarch64_21r", "R_AARCH64_CALL26": "patch_aarch64_26r", + "R_AARCH64_CONDBR19": "patch_aarch64_19r", "R_AARCH64_JUMP26": "patch_aarch64_26r", "R_AARCH64_LD64_GOT_LO12_NC": "patch_aarch64_12x", "R_AARCH64_MOVW_UABS_G0_NC": "patch_aarch64_16a", diff --git a/Tools/jit/_targets.py b/Tools/jit/_targets.py index 9fc3522d23d..7ff7c4fba49 100644 --- a/Tools/jit/_targets.py +++ b/Tools/jit/_targets.py @@ -335,7 +335,8 @@ def _handle_relocation( "Offset": offset, "Symbol": s, "Type": { - "Name": "IMAGE_REL_ARM64_BRANCH26" + "Name": "IMAGE_REL_ARM64_BRANCH19" + | "IMAGE_REL_ARM64_BRANCH26" | "IMAGE_REL_ARM64_PAGEBASE_REL21" | "IMAGE_REL_ARM64_PAGEOFFSET_12A" | "IMAGE_REL_ARM64_PAGEOFFSET_12L" as kind @@ -564,7 +565,7 @@ def get_target(host: str) -> _COFF32 | _COFF64 | _ELF | _MachO: if re.fullmatch(r"aarch64-apple-darwin.*", host): host = "aarch64-apple-darwin" condition = "defined(__aarch64__) && defined(__APPLE__)" - optimizer = _optimizers.OptimizerAArch64 + optimizer = _optimizers.OptimizerAArch64_MachO target = _MachO(host, condition, optimizer=optimizer) elif re.fullmatch(r"aarch64-pc-windows-msvc", host): host = "aarch64-pc-windows-msvc" From 67c98ad8ef5530ddfd332a7e9d4257791dc35b1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C4=85dela?= <39437649+tdadela@users.noreply.github.com> Date: Fri, 17 Oct 2025 12:32:02 +0200 Subject: [PATCH 4/5] gh-133059: Update documentation of preallocated integer range in `long.rst` (GH-140231) --- Doc/c-api/long.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index 8370dcecad3..fcb20f7c93c 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -43,7 +43,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. impl-detail:: CPython keeps an array of integer objects for all integers - between ``-5`` and ``256``. When you create an int in that range + between ``-5`` and ``1024``. When you create an int in that range you actually just get back a reference to the existing object. From fbf0843e39e01ec8a8295f6475065b08053f13dd Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 17 Oct 2025 14:21:39 +0300 Subject: [PATCH 5/5] gh-135801: Add tests for filtering warnings by module (GH-140240) --- Lib/test/test_warnings/__init__.py | 79 ++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py index 260fae8fe24..157852cfa91 100644 --- a/Lib/test/test_warnings/__init__.py +++ b/Lib/test/test_warnings/__init__.py @@ -241,6 +241,85 @@ def test_once(self): 42) self.assertEqual(len(w), 0) + def test_filter_module(self): + MS_WINDOWS = (sys.platform == 'win32') + with self.module.catch_warnings(record=True) as w: + self.module.simplefilter('error') + self.module.filterwarnings('always', module=r'package\.module\z') + self.module.warn_explicit('msg', UserWarning, 'filename', 42, + module='package.module') + self.assertEqual(len(w), 1) + with self.assertRaises(UserWarning): + self.module.warn_explicit('msg', UserWarning, '/path/to/package/module', 42) + with self.assertRaises(UserWarning): + self.module.warn_explicit('msg', UserWarning, '/path/to/package/module.py', 42) + + with self.module.catch_warnings(record=True) as w: + self.module.simplefilter('error') + self.module.filterwarnings('always', module='package') + self.module.warn_explicit('msg', UserWarning, 'filename', 42, + module='package.module') + self.assertEqual(len(w), 1) + with self.assertRaises(UserWarning): + self.module.warn_explicit('msg', UserWarning, 'filename', 42, + module='other.package.module') + with self.assertRaises(UserWarning): + self.module.warn_explicit('msg', UserWarning, '/path/to/otherpackage/module.py', 42) + + with self.module.catch_warnings(record=True) as w: + self.module.simplefilter('error') + self.module.filterwarnings('always', module=r'/path/to/package/module\z') + self.module.warn_explicit('msg', UserWarning, '/path/to/package/module', 42) + self.assertEqual(len(w), 1) + self.module.warn_explicit('msg', UserWarning, '/path/to/package/module.py', 42) + self.assertEqual(len(w), 2) + with self.assertRaises(UserWarning): + self.module.warn_explicit('msg', UserWarning, '/PATH/TO/PACKAGE/MODULE', 42) + if MS_WINDOWS: + if self.module is py_warnings: + self.module.warn_explicit('msg', UserWarning, r'/path/to/package/module.PY', 42) + self.assertEqual(len(w), 3) + with self.assertRaises(UserWarning): + self.module.warn_explicit('msg', UserWarning, r'/path/to/package/module/__init__.py', 42) + with self.assertRaises(UserWarning): + self.module.warn_explicit('msg', UserWarning, r'/path/to/package/module.pyw', 42) + with self.assertRaises(UserWarning): + self.module.warn_explicit('msg', UserWarning, r'\path\to\package\module', 42) + + with self.module.catch_warnings(record=True) as w: + self.module.simplefilter('error') + self.module.filterwarnings('always', module=r'/path/to/package/__init__\z') + self.module.warn_explicit('msg', UserWarning, '/path/to/package/__init__.py', 42) + self.assertEqual(len(w), 1) + self.module.warn_explicit('msg', UserWarning, '/path/to/package/__init__', 42) + self.assertEqual(len(w), 2) + + if MS_WINDOWS: + with self.module.catch_warnings(record=True) as w: + self.module.simplefilter('error') + self.module.filterwarnings('always', module=r'C:\\path\\to\\package\\module\z') + self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module', 42) + self.assertEqual(len(w), 1) + self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module.py', 42) + self.assertEqual(len(w), 2) + if self.module is py_warnings: + self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module.PY', 42) + self.assertEqual(len(w), 3) + with self.assertRaises(UserWarning): + self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module.pyw', 42) + with self.assertRaises(UserWarning): + self.module.warn_explicit('msg', UserWarning, r'C:\PATH\TO\PACKAGE\MODULE', 42) + with self.assertRaises(UserWarning): + self.module.warn_explicit('msg', UserWarning, r'C:/path/to/package/module', 42) + with self.assertRaises(UserWarning): + self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module\__init__.py', 42) + + with self.module.catch_warnings(record=True) as w: + self.module.simplefilter('error') + self.module.filterwarnings('always', module=r'\z') + self.module.warn_explicit('msg', UserWarning, '', 42) + self.assertEqual(len(w), 1) + def test_module_globals(self): with self.module.catch_warnings(record=True) as w: self.module.simplefilter("always", UserWarning)