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 @@