diff --git a/.gitattributes b/.gitattributes
index 7ca49c3e44fe4bd..d41390e814096f1 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -102,6 +102,7 @@ Modules/_testinternalcapi/test_cases.c.h generated
Modules/_testinternalcapi/test_targets.h generated
PC/python3dll.c generated
Parser/parser.c generated
+Parser/parser_invalid.c generated
Parser/token.c generated
Programs/test_frozenmain.h generated
Python/Python-ast.c generated
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 6b8a900f49a23a7..a63ca1b0ae562e2 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -283,11 +283,10 @@ Programs/_bootstrap_python.c @ericsnowcurrently @FFY00
Programs/python.c @ericsnowcurrently @FFY00
# JIT
-.github/workflows/jit.yml @savannahostrowski
-Include/internal/pycore_jit.h @brandtbucher @savannahostrowski @diegorusso
-Python/jit.c @brandtbucher @savannahostrowski @diegorusso
-Tools/jit/ @brandtbucher @savannahostrowski @diegorusso
-InternalDocs/jit.md @brandtbucher @savannahostrowski @diegorusso @AA-Turner
+Include/internal/pycore_jit.h @brandtbucher @diegorusso
+Python/jit.c @brandtbucher @diegorusso
+Tools/jit/ @brandtbucher @diegorusso
+InternalDocs/jit.md @brandtbucher @diegorusso @AA-Turner
# Lazy imports (PEP 810)
.github/workflows/reusable-test-lazy-imports-all.yml @yhg1s @DinoV @pablogsal
@@ -297,12 +296,13 @@ Lib/test/test_lazy_import @yhg1s @DinoV @pablogsal
# Micro-op / μop / Tier 2 Optimiser
Python/optimizer.c @markshannon @Fidget-Spinner
-Python/optimizer_analysis.c @markshannon @tomasr8 @Fidget-Spinner @savannahostrowski
-Python/optimizer_bytecodes.c @markshannon @tomasr8 @Fidget-Spinner @savannahostrowski
-Python/optimizer_symbols.c @markshannon @tomasr8 @Fidget-Spinner @savannahostrowski
+Python/optimizer_analysis.c @markshannon @tomasr8 @Fidget-Spinner
+Python/optimizer_bytecodes.c @markshannon @tomasr8 @Fidget-Spinner
+Python/optimizer_symbols.c @markshannon @tomasr8 @Fidget-Spinner
# Parser, Lexer, and Grammar
Grammar/python.gram @pablogsal @lysnikolaou
+Grammar/invalid.gram @pablogsal @lysnikolaou
Lib/test/test_peg_generator/ @pablogsal @lysnikolaou
Lib/test/test_tokenize.py @pablogsal @lysnikolaou
Lib/tokenize.py @pablogsal @lysnikolaou
@@ -432,6 +432,7 @@ Lib/test/test_*time.py @pganssle @StanFromIreland
Modules/*zoneinfo* @pganssle @StanFromIreland
Modules/*time* @pganssle @StanFromIreland
Python/pytime.c @pganssle @StanFromIreland
+Python/_strptime.c @pganssle @StanFromIreland
# Dbm
Doc/library/dbm.rst @corona10 @erlend-aasland @serhiy-storchaka
diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml
index fe1273804a5acb1..61e4e04ba272dc8 100644
--- a/.github/ISSUE_TEMPLATE/bug.yml
+++ b/.github/ISSUE_TEMPLATE/bug.yml
@@ -34,7 +34,6 @@ body:
label: "CPython versions tested on:"
multiple: true
options:
- - "3.10"
- "3.11"
- "3.12"
- "3.13"
diff --git a/.github/ISSUE_TEMPLATE/crash.yml b/.github/ISSUE_TEMPLATE/crash.yml
index 690fe7721fdb8ed..973d4c38528f3e6 100644
--- a/.github/ISSUE_TEMPLATE/crash.yml
+++ b/.github/ISSUE_TEMPLATE/crash.yml
@@ -28,7 +28,6 @@ body:
label: "CPython versions tested on:"
multiple: true
options:
- - "3.10"
- "3.11"
- "3.12"
- "3.13"
diff --git a/.github/VULNERABILITY_REPORT.yml b/.github/VULNERABILITY_REPORT.yml
new file mode 100644
index 000000000000000..55f2157a77f00ef
--- /dev/null
+++ b/.github/VULNERABILITY_REPORT.yml
@@ -0,0 +1,71 @@
+name: Vulnerability report
+description: Privately report a potential security vulnerability in CPython
+body:
+ - type: markdown
+ attributes:
+ value: |
+ **Not all bugs are vulnerabilities.** Before submitting, read the [Python security policy](https://devguide.python.org/security/policy/) to understand which issues are vulnerabilities and what versions of Python accept reports.
+
+ Keep the report short and in plain text: no headers, tables, PDFs, binaries, or severity and CVSS information.
+
+ Reports that do not contain a potential security vulnerability will be discarded without a reply.
+
+ To report vulnerabilities that affect other projects (such as pip or python.org), or if you are not sure where to send your report, email [security@python.org](mailto:security@python.org).
+ - type: textarea
+ id: summary
+ attributes:
+ label: Summary
+ description: A few sentences describing the vulnerability.
+ validations:
+ required: true
+ - type: textarea
+ id: threat_model
+ attributes:
+ label: Threat model
+ description: >
+ What does the attacker control, and what do they gain? Describe the code, configuration, or deployment that may exist in the real world and is exploitable. Where possible, cite the relevant part of the [security policy](https://devguide.python.org/security/policy/#what-types-of-bugs-are-vulnerabilities).
+ validations:
+ required: true
+ - type: textarea
+ id: proof_of_concept
+ attributes:
+ label: Proof of concept
+ description: >
+ A script that reproduces the issue and clearly indicates whether the vulnerability is present, such as exiting with `1` if vulnerable and `0` if not. If it depends on a specially constructed binary file, include a script to construct the file rather than the file itself.
+
+ Wrap scripts longer than a few lines in a [collapsed section](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/organizing-information-with-collapsed-sections) using ` ... `.
+ validations:
+ required: true
+ - type: dropdown
+ id: versions
+ attributes:
+ label: "CPython versions tested on:"
+ description: >
+ If any tested version was not vulnerable, say which in the summary. Only [supported versions](https://devguide.python.org/versions/) accept reports.
+ multiple: true
+ options:
+ - "3.11"
+ - "3.12"
+ - "3.13"
+ - "3.14"
+ - "3.15"
+ - "3.16"
+ - "CPython main branch"
+ - type: textarea
+ id: patch
+ attributes:
+ label: Suggested fix
+ description: Ideally, a minimal patch with the mitigation.
+ validations:
+ required: false
+ - type: checkboxes
+ id: checklist
+ attributes:
+ label: Before submitting
+ options:
+ - label: I have read the security policy and evaluated this report against it.
+ required: true
+ - label: I have checked that this issue is not already resolved on the `main` branch.
+ required: true
+ - label: I have verified the factual validity of everything in this report, including any content produced by an LLM.
+ required: true
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 5f9e3c323e30b82..0d367e01bca224f 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -28,6 +28,17 @@ updates:
cooldown:
default-days: 14
+ - package-ecosystem: "npm"
+ directory: "/Platforms/emscripten/browser_test/"
+ schedule:
+ interval: "quarterly"
+ labels: ["OS-emscripten", "skip issue", "skip news"]
+ groups:
+ npm:
+ patterns: ["*"]
+ cooldown:
+ default-days: 14
+
# Release branches: Dependabot only reads this file from the default
# branch, so each branch that should get its own actions bumps needs an
# entry here with `target-branch`. Add one when a new release branch is
@@ -92,18 +103,6 @@ updates:
cooldown:
default-days: 14
- - package-ecosystem: "github-actions"
- target-branch: "3.10"
- directory: "/"
- schedule:
- interval: "quarterly"
- labels: ["skip issue", "skip news"]
- groups:
- actions:
- patterns: ["*"]
- cooldown:
- default-days: 14
-
# Only bump bugfix branches for pip. Remove
# the entry when branch goes security-only.
- package-ecosystem: "pip"
@@ -130,14 +129,28 @@ updates:
cooldown:
default-days: 14
- - package-ecosystem: "pip"
- target-branch: "3.13"
- directory: "/Tools/"
+ # Only bump bugfix branches for npm. Remove
+ # the entry when branch goes security-only.
+ - package-ecosystem: "npm"
+ target-branch: "3.15"
+ directory: "/Platforms/emscripten/browser_test/"
schedule:
interval: "quarterly"
- labels: ["skip issue", "skip news"]
+ labels: ["OS-emscripten", "skip issue", "skip news"]
groups:
- pip:
+ npm:
+ patterns: ["*"]
+ cooldown:
+ default-days: 14
+
+ - package-ecosystem: "npm"
+ target-branch: "3.14"
+ directory: "/Platforms/emscripten/browser_test/"
+ schedule:
+ interval: "quarterly"
+ labels: ["OS-emscripten", "skip issue", "skip news"]
+ groups:
+ npm:
patterns: ["*"]
cooldown:
default-days: 14
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 9ab0473f4b9c598..07087b836cb597e 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -346,18 +346,28 @@ jobs:
run: python3 Platforms/Android ci --fast-ci ${{ matrix.arch }}-linux-android
build-ios:
- name: iOS
+ name: >-
+ iOS
+ ${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }}
needs: build-context
if: needs.build-context.outputs.run-ios == 'true'
timeout-minutes: 60
runs-on: macos-26
+ strategy:
+ fail-fast: false
+ matrix:
+ free-threading:
+ - false
+ - true
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Build and test
- run: python3 Platforms/Apple ci iOS --fast-ci
+ run: >-
+ python3 Platforms/Apple ci iOS --fast-ci
+ ${{ fromJSON(matrix.free-threading) && '--abiflags t' || '' }}
build-emscripten:
name: 'Emscripten'
@@ -481,53 +491,6 @@ jobs:
if: fromJSON(needs.build-context.outputs.run-tests)
uses: ./.github/workflows/reusable-test-lazy-imports-all.yml
- build-asan:
- name: 'Address sanitizer'
- runs-on: ${{ matrix.os }}
- timeout-minutes: 60
- needs: build-context
- if: needs.build-context.outputs.run-ubuntu == 'true'
- strategy:
- fail-fast: false
- matrix:
- os: [ubuntu-26.04]
- env:
- OPENSSL_VER: 3.5.9
- PYTHONSTRICTEXTENSIONBUILD: 1
- ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0
- steps:
- - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- with:
- persist-credentials: false
- - name: Runner image version
- run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- - name: Register gcc problem matcher
- run: echo "::add-matcher::.github/problem-matchers/gcc.json"
- - name: Install dependencies
- run: sudo ./.github/workflows/posix-deps-apt.sh
- - name: Configure OpenSSL env vars
- run: |
- echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> "$GITHUB_ENV"
- echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> "$GITHUB_ENV"
- echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> "$GITHUB_ENV"
- - name: 'Restore OpenSSL build'
- id: cache-openssl
- uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
- with:
- path: ./multissl/openssl/${{ env.OPENSSL_VER }}
- key: ${{ matrix.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
- - name: Install OpenSSL
- if: steps.cache-openssl.outputs.cache-hit != 'true'
- run: python3 Tools/ssl/multissltests.py --steps=library --base-directory "$MULTISSL_DIR" --openssl "$OPENSSL_VER" --system Linux
- - name: Configure CPython
- run: ./configure --config-cache --with-address-sanitizer --without-pymalloc --with-openssl="$OPENSSL_DIR"
- - name: Build CPython
- run: make -j4
- - name: Display build info
- run: make pythoninfo
- - name: Tests
- run: xvfb-run make ci
-
build-san:
# ${{ '' } is a hack to nest jobs under the same sidebar category.
name: Sanitizers${{ '' }} # zizmor: ignore[obfuscation]
@@ -544,9 +507,15 @@ jobs:
sanitizer:
- TSan
include:
+ - check-name: Address
+ sanitizer: ASan
+ free-threading: false
- check-name: Undefined behavior
sanitizer: UBSan
free-threading: false
+ - check-name: Memory
+ sanitizer: MSan
+ free-threading: false
uses: ./.github/workflows/reusable-san.yml
with:
sanitizer: ${{ matrix.sanitizer }}
@@ -654,7 +623,6 @@ jobs:
- build-wasi
- test-hypothesis
- test-lazy-imports-all
- - build-asan
- build-san
- cross-build-linux
- cifuzz
@@ -701,7 +669,6 @@ jobs:
build-ubuntu-installed,
build-ubuntu-ssltests,
test-hypothesis,
- build-asan,
build-san,
cross-build-linux,
'
diff --git a/.github/workflows/jit.yml b/.github/workflows/jit.yml
index 36fe3fb69a7e8a6..381b00185b1ae87 100644
--- a/.github/workflows/jit.yml
+++ b/.github/workflows/jit.yml
@@ -87,24 +87,16 @@ jobs:
./PCbuild/rt.bat ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }} -q --multiprocess 0 --timeout 4500 --verbose2 --verbose3
macos:
- name: ${{ matrix.target }} (${{ matrix.debug && 'Debug' || 'Release' }})
+ name: aarch64-apple-darwin/clang (${{ matrix.debug && 'Debug' || 'Release' }})
- runs-on: ${{ matrix.runner }}
+ runs-on: macos-26
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
- target:
- - x86_64-apple-darwin/clang
- - aarch64-apple-darwin/clang
debug:
- true
- false
- include:
- - target: x86_64-apple-darwin/clang
- runner: macos-26-intel
- - target: aarch64-apple-darwin/clang
- runner: macos-26
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml
index 2650e7a8116804e..a8c95627c2417de 100644
--- a/.github/workflows/mypy.yml
+++ b/.github/workflows/mypy.yml
@@ -69,7 +69,7 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- - uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
+ - uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
with:
python-version: "3.15"
activate-environment: true
diff --git a/.github/workflows/reusable-cifuzz.yml b/.github/workflows/reusable-cifuzz.yml
index 4a05396f3463e9f..a70b75eebc4a989 100644
--- a/.github/workflows/reusable-cifuzz.yml
+++ b/.github/workflows/reusable-cifuzz.yml
@@ -43,7 +43,7 @@ jobs:
path: ./out/artifacts
- name: Upload SARIF
if: always() && steps.build.outcome == 'success'
- uses: github/codeql-action/upload-sarif@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0
+ uses: github/codeql-action/upload-sarif@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
with:
sarif_file: cifuzz-sarif/results.sarif
checkout_path: cifuzz-sarif
diff --git a/.github/workflows/reusable-emscripten.yml b/.github/workflows/reusable-emscripten.yml
index 18afdb5278a766e..f4fb5d4a5b0b6ab 100644
--- a/.github/workflows/reusable-emscripten.yml
+++ b/.github/workflows/reusable-emscripten.yml
@@ -79,3 +79,5 @@ jobs:
run: python3 Platforms/emscripten run --test
- name: "Test Repl"
run: Platforms/emscripten/browser_test/run_test.sh
+ - name: "Test embedding"
+ run: Platforms/emscripten/web_embed_test/run_test.sh
diff --git a/.github/workflows/reusable-macos.yml b/.github/workflows/reusable-macos.yml
index 2e6e4d6e4c69240..2883a20b612f852 100644
--- a/.github/workflows/reusable-macos.yml
+++ b/.github/workflows/reusable-macos.yml
@@ -51,6 +51,7 @@ jobs:
--enable-slower-safety \
--enable-safety \
${{ inputs.free-threading && '--disable-gil' || '' }} \
+ --with-tail-call-interp \
--prefix=/opt/python-dev \
--with-openssl="$(brew --prefix openssl@3.5)"
- name: Build CPython
diff --git a/.github/workflows/reusable-san.yml b/.github/workflows/reusable-san.yml
index 6b4a43b259638e2..9c31241498a75e9 100644
--- a/.github/workflows/reusable-san.yml
+++ b/.github/workflows/reusable-san.yml
@@ -43,6 +43,15 @@ jobs:
# please update the versions in `Tools/pixi-packages/variants.yaml` too.
echo "CC=clang" >> "$GITHUB_ENV"
echo "CXX=clang++" >> "$GITHUB_ENV"
+ - name: ASan option setup
+ if: inputs.sanitizer == 'ASan'
+ run: |
+ echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> "$GITHUB_ENV"
+ echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> "$GITHUB_ENV"
+ echo "ASAN_OPTIONS=${SAN_LOG_OPTION} detect_leaks=0 allocator_may_return_null=1 handle_segv=0" >> "$GITHUB_ENV"
+ echo "PYTHONSTRICTEXTENSIONBUILD=1" >> "$GITHUB_ENV"
+ env:
+ SAN_LOG_OPTION: log_path=${{ github.workspace }}/san_log
- name: TSan option setup
if: inputs.sanitizer == 'TSan'
run: |
@@ -60,7 +69,7 @@ jobs:
|| ''
}}
- name: UBSan option setup
- if: inputs.sanitizer != 'TSan'
+ if: inputs.sanitizer == 'UBSan'
run: >-
echo
"UBSAN_OPTIONS=${SAN_LOG_OPTION}
@@ -69,19 +78,38 @@ jobs:
>> "$GITHUB_ENV"
env:
SAN_LOG_OPTION: log_path=${{ github.workspace }}/san_log
+ - name: MSan option setup
+ if: inputs.sanitizer == 'MSan'
+ run: |
+ sudo sysctl -w vm.mmap_rnd_bits=28 # Reduce ASLR to avoid MSan re-executing
+
+ echo "MSAN_OPTIONS=${SAN_LOG_OPTION} allocator_may_return_null=1 handle_segv=0" >> "$GITHUB_ENV"
+ # MSan reports false positives for memory initialized by libraries
+ # that are not built with MSan, so disable modules that use them.
+ # _remote_debugging links to libzstd directly, but we unpoision the memory.
+ {
+ echo '*disabled*'
+ echo '_bz2 _ctypes _curses _curses_panel _dbm _decimal _gdbm _hashlib'
+ echo '_lzma _sqlite3 _ssl _tkinter _uuid _zstd readline zlib'
+ } > Modules/Setup.local
+ env:
+ SAN_LOG_OPTION: log_path=${{ github.workspace }}/san_log
- name: Add ccache to PATH
run: |
echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
- - name: 'Restore OpenSSL build (TSan)'
+ - name: 'Restore OpenSSL build'
id: cache-openssl
- if: inputs.sanitizer == 'TSan'
+ if: inputs.sanitizer == 'TSan' || inputs.sanitizer == 'ASan'
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
- key: ${{ env.IMAGE_OS_VERSION }}-multissl-openssl-tsan-${{ env.OPENSSL_VER }}
- - name: Install OpenSSL (TSan)
+ key: >-
+ ${{ env.IMAGE_OS_VERSION }}-multissl-openssl-${{
+ inputs.sanitizer == 'TSan' && 'tsan-' || ''
+ }}${{ env.OPENSSL_VER }}
+ - name: Install OpenSSL
if: >-
- inputs.sanitizer == 'TSan'
+ (inputs.sanitizer == 'TSan' || inputs.sanitizer == 'ASan')
&& steps.cache-openssl.outputs.cache-hit != 'true'
run: >-
python3 Tools/ssl/multissltests.py
@@ -89,18 +117,32 @@ jobs:
--base-directory="${MULTISSL_DIR}"
--openssl="${OPENSSL_VER}"
--system=Linux
- --tsan
+ ${{ inputs.sanitizer == 'TSan' && '--tsan' || '' }}
+ # gh-157958: -O2 instead of the pydebug default -Og to avoid a clang 21
+ # compile-time blowup on some interpreter files.
+ # (https://github.com/llvm/llvm-project/issues/179695)
+ # MSan uses --with-assertions instead of --with-pydebug because its
+ # hooks on the Python memory allocators hide uninitialized reads.
- name: Configure CPython
run: >-
./configure
--config-cache
+ OPT="-O2 -g"
${{
- inputs.sanitizer == 'TSan'
+ inputs.sanitizer == 'ASan'
+ && '--with-address-sanitizer --without-pymalloc'
+ || inputs.sanitizer == 'TSan'
&& '--with-thread-sanitizer'
+ || inputs.sanitizer == 'MSan'
+ && '--with-memory-sanitizer'
|| '--with-undefined-behavior-sanitizer --with-strict-overflow'
}}
- --with-pydebug
- ${{ inputs.sanitizer == 'TSan' && '--with-openssl="$OPENSSL_DIR" --with-openssl-rpath=auto' || '' }}
+ ${{ inputs.sanitizer == 'MSan' && '--with-assertions' || '--with-pydebug' }}
+ ${{
+ (inputs.sanitizer == 'TSan' || inputs.sanitizer == 'ASan')
+ && '--with-openssl="$OPENSSL_DIR" --with-openssl-rpath=auto'
+ || ''
+ }}
${{ inputs.free-threading && '--disable-gil' || '' }}
- name: Build CPython
run: make -j4
diff --git a/.github/workflows/reusable-test-lazy-imports-all.yml b/.github/workflows/reusable-test-lazy-imports-all.yml
index c0851aeddc59aef..b30a776f1a98581 100644
--- a/.github/workflows/reusable-test-lazy-imports-all.yml
+++ b/.github/workflows/reusable-test-lazy-imports-all.yml
@@ -64,6 +64,8 @@ jobs:
- name: Verify excluded tests still need exclusion
run: |
set -euo pipefail
+ # Failures are expected here, don't report them to the job summary
+ unset GITHUB_STEP_SUMMARY
unexpected_passes=()
while IFS= read -r test_name; do
[ -n "$test_name" ] || continue
diff --git a/.github/workflows/reusable-wasi.yml b/.github/workflows/reusable-wasi.yml
index e4b3794346207d2..12dd790897ad392 100644
--- a/.github/workflows/reusable-wasi.yml
+++ b/.github/workflows/reusable-wasi.yml
@@ -16,7 +16,6 @@ jobs:
timeout-minutes: 60
env:
WASMTIME_VERSION: 48.0.2
- CROSS_BUILD_WASI: cross-build/wasm32-wasip1
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
@@ -65,4 +64,6 @@ jobs:
- name: "Display build info of the host/WASI Python"
run: python3 Platforms/WASI pythoninfo-host
- name: "Test"
- run: make --directory "${CROSS_BUILD_WASI}" test
+ run: |
+ CROSS_BUILD_WASI=$(python3 Platforms/WASI path)
+ make --directory "${CROSS_BUILD_WASI}" test
diff --git a/.github/workflows/tail-call.yml b/.github/workflows/tail-call.yml
index ccededfc397b369..1dc5ea1bc51356c 100644
--- a/.github/workflows/tail-call.yml
+++ b/.github/workflows/tail-call.yml
@@ -23,40 +23,6 @@ env:
LLVM_VERSION: 21
jobs:
- macos:
- name: ${{ matrix.target }}
- runs-on: ${{ matrix.runner }}
- timeout-minutes: 60
- strategy:
- fail-fast: false
- matrix:
- include:
- - target: x86_64-apple-darwin/clang
- runner: macos-26-intel
- - target: aarch64-apple-darwin/clang
- runner: macos-26
- steps:
- - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- with:
- persist-credentials: false
- - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
- with:
- python-version: '3.11'
- - name: Install dependencies
- run: |
- brew update
- brew install llvm@${{ env.LLVM_VERSION }}
- - name: Build
- run: |
- export SDKROOT="$(xcrun --show-sdk-path)"
- export PATH="/usr/local/opt/llvm@${{ env.LLVM_VERSION }}/bin:$PATH"
- export PATH="/opt/homebrew/opt/llvm@${{ env.LLVM_VERSION }}/bin:$PATH"
- CC=clang-${{ env.LLVM_VERSION }} ./configure --with-tail-call-interp
- make all --jobs 4
- - name: Test
- run: |
- ./python.exe -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
-
linux:
name: ${{ matrix.target }}
runs-on: ${{ matrix.runner }}
diff --git a/.gitignore b/.gitignore
index 00813f9d1b6b00a..d82d89cd2df782a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -72,16 +72,19 @@ Lib/test/data/*
/_bootstrap_python
/Makefile
/Makefile.pre
-/iOSTestbed.*
-Apple/iOS/Frameworks/
-Apple/iOS/Resources/Info.plist
-Apple/testbed/build
-Apple/testbed/Python.xcframework/*/bin
-Apple/testbed/Python.xcframework/*/include
-Apple/testbed/Python.xcframework/*/lib
-Apple/testbed/Python.xcframework/*/Python.framework
-Apple/testbed/*Testbed.xcodeproj/project.xcworkspace
-Apple/testbed/*Testbed.xcodeproj/xcuserdata
+/AppleTestbed.*
+Platforms/Apple/iOS/Frameworks/*
+Platforms/Apple/iOS/Resources/Info.plist
+Platforms/Apple/testbed/Python*.xcframework/*/bin
+Platforms/Apple/testbed/Python*.xcframework/*/include
+Platforms/Apple/testbed/Python*.xcframework/*/lib
+Platforms/Apple/testbed/Python*.xcframework/*/Python*.framework
+Platforms/Apple/tvOS/Frameworks/*
+Platforms/Apple/tvOS/Resources/Info.plist
+Platforms/Apple/visionOS/Frameworks/*
+Platforms/Apple/visionOS/Resources/Info.plist
+Platforms/Apple/watchOS/Frameworks/*
+Platforms/Apple/watchOS/Resources/Info.plist
Mac/Makefile
Mac/PythonLauncher/Info.plist
Mac/PythonLauncher/Makefile
@@ -99,6 +102,7 @@ Modules/Setup.config
Modules/Setup.local
Modules/Setup.stdlib
Modules/config.c
+Modules/config_bootstrap.c
Modules/ld_so_aix
Programs/_freeze_module
Programs/_testembed
@@ -180,6 +184,7 @@ Python/frozen_modules/MANIFEST
# Local AI agent scratch state (per-PR and per-branch notebooks, sandbox
# experiments) and personal agent overrides, none of which are committed.
+/do-not-commit/
/.claude/pr-*
/.claude/branch-*
/.claude/sandbox/
diff --git a/Doc/Makefile b/Doc/Makefile
index 881719394b63662..0d5fd41627ff292 100644
--- a/Doc/Makefile
+++ b/Doc/Makefile
@@ -189,12 +189,13 @@ venv:
.PHONY: lock
lock:
# Dependencies have a 14 day cooldown period to mitigate supply chain attacks,
-# except for sphinx_linklint and python-docs-theme, which are maintained by
+# except for blurb, python-docs-theme and sphinx_linklint, which are maintained by
# core team members.
$(UV) pip compile requirements.txt \
--upgrade --exclude-newer P14D \
- --exclude-newer-package sphinx_linklint=PT0S \
+ --exclude-newer-package blurb=PT0S \
--exclude-newer-package python-docs-theme=PT0S \
+ --exclude-newer-package sphinx_linklint=PT0S \
--no-cache --output-file $(REQUIREMENTS) \
--python-version 3.12 --universal \
--custom-compile-command="make lock"
diff --git a/Doc/README.rst b/Doc/README.rst
index 2d1148753e0c6bb..e33569f298ca3c0 100644
--- a/Doc/README.rst
+++ b/Doc/README.rst
@@ -21,6 +21,7 @@ tree but are maintained separately and are available from
* `Sphinx `_
* `blurb `_
* `python-docs-theme `_
+* `sphinx-linklint `_
The easiest way to install these tools is to create a virtual environment and
install the tools into there.
@@ -57,6 +58,8 @@ Available make targets are:
* "venv", which creates a virtual environment with all necessary tools
installed.
+* "lock", which regenerates the pinned dependencies in ``pylock.toml``.
+
* "html", which builds standalone HTML files for offline viewing.
* "htmlview", which re-uses the "html" builder, but then opens the main page
@@ -79,6 +82,9 @@ Available make targets are:
* "text", which builds a plain text file for each source file.
+* "texinfo", which builds Texinfo source files as input to ``makeinfo`` to
+ produce Info documents.
+
* "epub", which builds an EPUB document, suitable to be viewed on e-book
readers.
@@ -97,6 +103,10 @@ Available make targets are:
plain text documentation for the labels defined in
``tools/pyspecific.py`` -- pydoc needs these to show topic and keyword help.
+* "doctest", which runs doctests in the documentation.
+
+* "gettext", which generates gettext message catalog templates.
+
* "check", which checks for frequent markup errors.
* "dist", (Unix only) which creates distributable archives of HTML, text,
diff --git a/Doc/_static/tachyon-example-flamegraph.html b/Doc/_static/tachyon-example-flamegraph.html
index 701c959bda3ccc0..0563e7ce4acfe6e 100644
--- a/Doc/_static/tachyon-example-flamegraph.html
+++ b/Doc/_static/tachyon-example-flamegraph.html
@@ -1,5 +1,5 @@
-
+
@@ -166,6 +166,14 @@
/* Heatmap span highlighting colors */
--span-hot-base: 255, 100, 50;
--span-cold-base: 150, 150, 150;
+
+ /* Summary card colors - optimized for 4.5:1 contrast on light bg */
+ --card-blue: 44, 102, 149;
+ --card-green: 26, 116, 49;
+ --card-yellow: 134, 100, 4;
+ --card-purple: 102, 57, 166;
+ --card-red: 180, 40, 50;
+ --card-orange: 166, 90, 0;
}
/* Dark theme */
@@ -190,15 +198,15 @@
--header-gradient: linear-gradient(135deg, #21262d 0%, #30363d 100%);
- /* Dark mode heat palette - muted colors that provide sufficient contrast with light text */
- --heat-1: rgba(74, 123, 167, 0.35);
- --heat-2: rgba(90, 159, 168, 0.38);
- --heat-3: rgba(106, 181, 181, 0.40);
- --heat-4: rgba(126, 196, 136, 0.42);
- --heat-5: rgba(160, 216, 120, 0.45);
- --heat-6: rgba(196, 222, 106, 0.48);
- --heat-7: rgba(244, 212, 77, 0.50);
- --heat-8: rgba(255, 107, 53, 0.55);
+ /* Dark mode heat palette - cool to warm gradient for visualization */
+ --heat-1: rgba(90, 123, 167, 1);
+ --heat-2: rgba(106, 148, 168, 1);
+ --heat-3: rgba(122, 172, 172, 1);
+ --heat-4: rgba(142, 196, 152, 1);
+ --heat-5: rgba(168, 216, 136, 1);
+ --heat-6: rgba(200, 222, 122, 1);
+ --heat-7: rgba(244, 212, 93, 1);
+ --heat-8: rgba(255, 122, 69, 1);
/* Code view specific - dark mode */
--code-bg: #0d1117;
@@ -228,6 +236,14 @@
/* Heatmap span highlighting colors - dark theme */
--span-hot-base: 255, 107, 53;
--span-cold-base: 189, 189, 189;
+
+ /* Summary card colors - optimized for 4.5:1 contrast on dark bg */
+ --card-blue: 88, 166, 255;
+ --card-green: 63, 185, 80;
+ --card-yellow: 210, 153, 34;
+ --card-purple: 163, 113, 247;
+ --card-red: 248, 113, 113;
+ --card-orange: 251, 146, 60;
}
/* --------------------------------------------------------------------------
@@ -571,6 +587,46 @@
This file extends the shared foundation with flamegraph-specific styles.
========================================================================== */
+/* --------------------------------------------------------------------------
+ Differential Flamegraph
+ -------------------------------------------------------------------------- */
+
+:root {
+ /* Regression colors */
+ --diff-regression-deep: #d32f2f;
+ --diff-regression-medium: #e57373;
+ --diff-regression-light: #ef9a9a;
+ --diff-regression-verylight: #ffcdd2;
+
+ /* Improvement colors */
+ --diff-improvement-deep: #1976d2;
+ --diff-improvement-medium: #42a5f5;
+ --diff-improvement-light: #64b5f6;
+ --diff-improvement-verylight: #90caf9;
+
+ /* Other differential colors */
+ --diff-neutral: #bdbdbd;
+ --diff-new: #9575cd;
+ --diff-elided: #b39ddb;
+}
+
+/* Dark mode differential colors - adjusted for contrast against dark backgrounds */
+[data-theme="dark"] {
+ --diff-regression-deep: #ef5350;
+ --diff-regression-medium: #e57373;
+ --diff-regression-light: #ef9a9a;
+ --diff-regression-verylight: #ffcdd2;
+
+ --diff-improvement-deep: #42a5f5;
+ --diff-improvement-medium: #64b5f6;
+ --diff-improvement-light: #90caf9;
+ --diff-improvement-verylight: #bbdefb;
+
+ --diff-neutral: #757575;
+ --diff-new: #b39ddb;
+ --diff-elided: #ce93d8;
+}
+
/* --------------------------------------------------------------------------
Layout Overrides (Flamegraph-specific)
-------------------------------------------------------------------------- */
@@ -841,9 +897,17 @@
}
/* View Mode Section */
+.view-mode-section {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+
.view-mode-section .section-content {
display: flex;
- justify-content: center;
+ flex-direction: column;
+ gap: 10px;
+ align-items: center;
}
/* Collapsible sections */
@@ -912,10 +976,10 @@
position: relative;
}
-.summary-card:nth-child(1) { --i: 0; --card-color: 55, 118, 171; }
-.summary-card:nth-child(2) { --i: 1; --card-color: 40, 167, 69; }
-.summary-card:nth-child(3) { --i: 2; --card-color: 255, 193, 7; }
-.summary-card:nth-child(4) { --i: 3; --card-color: 111, 66, 193; }
+.summary-card:nth-child(1) { --i: 0; --card-color: var(--card-blue); }
+.summary-card:nth-child(2) { --i: 1; --card-color: var(--card-green); }
+.summary-card:nth-child(3) { --i: 2; --card-color: var(--card-yellow); }
+.summary-card:nth-child(4) { --i: 3; --card-color: var(--card-purple); }
.summary-card:hover {
border-color: rgba(var(--card-color), 0.6);
@@ -971,21 +1035,18 @@
text-overflow: ellipsis;
}
-/* Efficiency Bar */
-.efficiency-section {
- margin-top: 10px;
- padding-top: 10px;
- border-top: 1px solid var(--border);
-}
+/* --------------------------------------------------------------------------
+ Progress Bars
+ -------------------------------------------------------------------------- */
-.efficiency-header {
+.bar-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 5px;
}
-.efficiency-label {
+.bar-label {
font-size: 9px;
font-weight: 600;
color: var(--text-secondary);
@@ -993,21 +1054,21 @@
letter-spacing: 0.2px;
}
-.efficiency-value {
+.bar-value {
font-family: var(--font-mono);
font-size: 11px;
font-weight: 700;
color: var(--accent);
}
-.efficiency-bar {
+.bar {
height: 6px;
background: var(--bg-tertiary);
border-radius: 3px;
overflow: hidden;
}
-.efficiency-fill {
+.bar-fill {
height: 100%;
background: linear-gradient(90deg, #28a745 0%, #20c997 50%, #17a2b8 100%);
border-radius: 3px;
@@ -1016,7 +1077,7 @@
overflow: hidden;
}
-.efficiency-fill::after {
+.bar-fill::after {
content: '';
position: absolute;
top: 0;
@@ -1033,68 +1094,56 @@
}
/* --------------------------------------------------------------------------
- Thread Stats Grid (in Sidebar)
+ Efficiency Section Container
+ -------------------------------------------------------------------------- */
+
+.efficiency-section {
+ margin-top: 10px;
+ padding-top: 10px;
+ border-top: 1px solid var(--border);
+}
+
+/* --------------------------------------------------------------------------
+ Thread Stats Progress Bars (in Sidebar)
-------------------------------------------------------------------------- */
.thread-stats-section {
display: block;
}
-.stats-grid {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 8px;
+.stats-container {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
}
-.stat-tile {
- background: var(--bg-primary);
- border-radius: 8px;
- padding: 10px;
- text-align: center;
- border: 2px solid var(--border);
- transition: all var(--transition-fast);
+.stat-item {
animation: fadeIn 0.4s ease-out backwards;
animation-delay: calc(var(--i, 0) * 0.05s);
}
-.stat-tile:nth-child(1) { --i: 0; }
-.stat-tile:nth-child(2) { --i: 1; }
-.stat-tile:nth-child(3) { --i: 2; }
-.stat-tile:nth-child(4) { --i: 3; }
+.stat-item:nth-child(1) { --i: 0; }
+.stat-item:nth-child(2) { --i: 1; }
+.stat-item:nth-child(3) { --i: 2; }
+.stat-item:nth-child(4) { --i: 3; }
+.stat-item:nth-child(5) { --i: 4; }
-.stat-tile:hover {
- transform: translateY(-2px);
- box-shadow: var(--shadow-sm);
+/* Color variants for bar-fill */
+.bar-fill--green {
+ background: linear-gradient(90deg, #28a745 0%, #20c997 100%);
}
-.stat-tile-value {
- font-family: var(--font-mono);
- font-size: 16px;
- font-weight: 700;
- color: var(--text-primary);
- line-height: 1.2;
+.bar-fill--yellow {
+ background: linear-gradient(90deg, #ffc107 0%, #ffdb4d 100%);
}
-.stat-tile-label {
- font-size: 9px;
- font-weight: 600;
- text-transform: uppercase;
- letter-spacing: 0.3px;
- color: var(--text-muted);
- margin-top: 2px;
+.bar-fill--purple {
+ background: linear-gradient(90deg, #6f42c1 0%, #9b6dd6 100%);
}
-/* Stat tile color variants */
-.stat-tile--green { --tile-color: 40, 167, 69; --tile-text: #28a745; }
-.stat-tile--red { --tile-color: 220, 53, 69; --tile-text: #dc3545; }
-.stat-tile--yellow { --tile-color: 255, 193, 7; --tile-text: #d39e00; }
-.stat-tile--purple { --tile-color: 111, 66, 193; --tile-text: #6f42c1; }
-
-.stat-tile[class*="--"] {
- border-color: rgba(var(--tile-color), 0.4);
- background: linear-gradient(135deg, rgba(var(--tile-color), 0.08) 0%, var(--bg-primary) 100%);
+.bar-fill--red {
+ background: linear-gradient(90deg, #dc3545 0%, #ff6b7a 100%);
}
-.stat-tile[class*="--"] .stat-tile-value { color: var(--tile-text); }
/* --------------------------------------------------------------------------
Hotspot Cards
@@ -1396,6 +1445,41 @@
color: var(--accent);
}
+.tooltip-diff {
+ margin-top: 12px;
+ padding-top: 12px;
+ border-top: 1px solid var(--border);
+}
+
+.tooltip-diff-title {
+ font-size: 11px;
+ font-weight: 600;
+ color: var(--accent);
+ margin-bottom: 8px;
+}
+
+.tooltip-diff-row {
+ display: grid;
+ grid-template-columns: auto 1fr;
+ gap: 4px 14px;
+ font-size: 12px;
+ margin-bottom: 4px;
+}
+
+.tooltip-diff-row.regression .tooltip-stat-value {
+ color: var(--diff-regression-deep);
+ font-weight: 700;
+}
+
+.tooltip-diff-row.improvement .tooltip-stat-value {
+ color: var(--diff-improvement-deep);
+ font-weight: 700;
+}
+
+.tooltip-diff-row.neutral .tooltip-stat-value {
+ color: var(--text-secondary);
+}
+
.tooltip-source {
margin-top: 10px;
padding-top: 10px;
@@ -1551,10 +1635,6 @@
.brand-info {
display: none;
}
-
- .stats-grid {
- grid-template-columns: 1fr;
- }
}
/* --------------------------------------------------------------------------
@@ -1574,7 +1654,9 @@
Flamegraph-Specific Toggle Override
-------------------------------------------------------------------------- */
-#toggle-invert .toggle-track.on {
+#toggle-invert .toggle-track.on,
+#toggle-elided .toggle-track.on,
+#toggle-path-display .toggle-track.on {
background: #8e44ad;
border-color: #8e44ad;
box-shadow: 0 0 8px rgba(142, 68, 173, 0.3);
@@ -1674,7 +1756,7 @@