Merge branch 'main' into gh-56809-load-tests-example

This commit is contained in:
jkersell 2024-05-21 08:37:05 -04:00 committed by GitHub
commit e274f3a1a0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4001 changed files with 646815 additions and 363492 deletions

View file

@ -1,97 +1,16 @@
variables:
coverage: false
trigger: ['main', '3.10', '3.9', '3.8', '3.7']
trigger: ['main', '3.12', '3.11', '3.10', '3.9', '3.8', '3.7']
jobs:
- job: Prebuild
displayName: Pre-build checks
pool:
vmImage: ubuntu-20.04
vmImage: ubuntu-22.04
steps:
- template: ./prebuild-checks.yml
- job: Docs_PR
displayName: Docs PR
dependsOn: Prebuild
condition: and(succeeded(), eq(dependencies.Prebuild.outputs['docs.run'], 'true'))
pool:
vmImage: ubuntu-20.04
steps:
- template: ./docs-steps.yml
parameters:
upload: true
- job: macOS_CI_Tests
displayName: macOS CI Tests
dependsOn: Prebuild
#condition: and(succeeded(), eq(dependencies.Prebuild.outputs['tests.run'], 'true'))
# bpo-39837: macOS tests on Azure Pipelines are disabled
condition: false
variables:
testRunTitle: '$(build.sourceBranchName)-macos'
testRunPlatform: macos
pool:
vmImage: macos-10.15
steps:
- template: ./macos-steps.yml
- job: Ubuntu_CI_Tests
displayName: Ubuntu CI Tests
dependsOn: Prebuild
condition: and(succeeded(), eq(dependencies.Prebuild.outputs['tests.run'], 'true'))
pool:
vmImage: ubuntu-20.04
variables:
testRunTitle: '$(build.sourceBranchName)-linux'
testRunPlatform: linux
openssl_version: 1.1.1n
steps:
- template: ./posix-steps.yml
parameters:
dependencies: apt
- job: Ubuntu_Coverage_CI_Tests
displayName: Ubuntu CI Tests (coverage)
dependsOn: Prebuild
condition: |
and(
and(
succeeded(),
eq(variables['coverage'], 'true')
),
eq(dependencies.Prebuild.outputs['tests.run'], 'true')
)
pool:
vmImage: ubuntu-20.04
variables:
testRunTitle: '$(Build.SourceBranchName)-linux-coverage'
testRunPlatform: linux-coverage
openssl_version: 1.1.1n
steps:
- template: ./posix-steps.yml
parameters:
dependencies: apt
coverage: true
- job: Windows_CI_Tests
displayName: Windows CI Tests
dependsOn: Prebuild

View file

@ -1,47 +0,0 @@
parameters:
latex: false
upload: false
steps:
- checkout: self
clean: true
fetchDepth: 5
- task: UsePythonVersion@0
displayName: 'Use Python 3.6 or later'
inputs:
versionSpec: '>=3.6'
- script: python -m pip install -r requirements.txt
workingDirectory: '$(build.sourcesDirectory)/Doc'
displayName: 'Install build dependencies'
- ${{ if ne(parameters.latex, 'true') }}:
- script: make check html PYTHON=python
workingDirectory: '$(build.sourcesDirectory)/Doc'
displayName: 'Build documentation'
- ${{ if eq(parameters.latex, 'true') }}:
- script: sudo apt-get update && sudo apt-get install -qy --force-yes texlive-full
displayName: 'Install LaTeX'
- script: make dist PYTHON=python SPHINXBUILD='python -m sphinx' BLURB='python -m blurb'
workingDirectory: '$(build.sourcesDirectory)/Doc'
displayName: 'Build documentation'
- ${{ if eq(parameters.upload, 'true') }}:
- task: PublishBuildArtifacts@1
displayName: 'Publish docs'
inputs:
PathToPublish: '$(build.sourcesDirectory)/Doc/build'
ArtifactName: docs
publishLocation: Container
- ${{ if eq(parameters.latex, 'true') }}:
- task: PublishBuildArtifacts@1
displayName: 'Publish dist'
inputs:
PathToPublish: '$(build.sourcesDirectory)/Doc/dist'
ArtifactName: docs_dist
publishLocation: Container

View file

@ -1,26 +0,0 @@
# Locate a set of the tools used for builds
steps:
- template: windows-release/find-sdk.yml
parameters:
toolname: 'signtool.exe'
- powershell: |
$vcvarsall = (& "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" `
-prerelease `
-latest `
-requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 `
-find VC\Auxiliary\Build\vcvarsall.bat)
Write-Host "Found vcvarsall at $vcvarsall"
Write-Host "##vso[task.setVariable variable=vcvarsall]$vcvarsall"
displayName: 'Find vcvarsall.bat'
- powershell: |
$msbuild = (& "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" `
-prerelease `
-latest `
-requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 `
-find MSBuild\Current\Bin\msbuild.exe)
Write-Host "Found MSBuild at $msbuild"
Write-Host "##vso[task.setVariable variable=msbuild]$msbuild"
displayName: 'Find MSBuild'

View file

@ -1,86 +0,0 @@
name: $(SourceTag)_$(Date:yyyyMMdd)$(Rev:.rr)
variables:
IntDir: '$(Build.BinariesDirectory)'
OutDir: '$(Build.ArtifactStagingDirectory)'
# MUST BE SET AT QUEUE TIME
# SigningCertificate: 'Python Software Foundation'
# SourcesRepo: 'https://github.com/python/cpython-source-deps'
# SourceTag: 'libffi-3.4.2'
jobs:
- job: Build_LibFFI
displayName: LibFFI
pool:
vmImage: windows-latest
workspace:
clean: all
steps:
- checkout: none
- template: ./find-tools.yml
- powershell: |
mkdir -Force "$(IntDir)\script"
iwr "https://github.com/python/cpython/raw/main/PCbuild/prepare_libffi.bat" `
-outfile "$(IntDir)\script\prepare_libffi.bat"
displayName: 'Download build script'
- powershell: |
git clone $(SourcesRepo) -b $(SourceTag) --depth 1 -c core.autocrlf=false -c core.eol=lf .
displayName: 'Check out LibFFI sources'
- script: 'prepare_libffi.bat --install-cygwin'
workingDirectory: '$(IntDir)\script'
displayName: 'Install Cygwin and build'
env:
VCVARSALL: '$(vcvarsall)'
LIBFFI_SOURCE: '$(Build.SourcesDirectory)'
LIBFFI_OUT: '$(OutDir)'
- powershell: |
if ((gci *\*.dll).Count -lt 4) {
Write-Error "Did not generate enough DLL files"
}
if ((gci *\Include\ffi.h).Count -lt 4) {
Write-Error "Did not generate enough include files"
}
failOnStderr: true
workingDirectory: '$(OutDir)'
displayName: 'Verify files were created'
- publish: '$(OutDir)'
artifact: 'unsigned'
displayName: 'Publish unsigned build'
- job: Sign_LibFFI
displayName: Sign LibFFI
dependsOn: Build_LibFFI
pool:
name: 'Windows Release'
workspace:
clean: all
steps:
- checkout: none
- download: current
artifact: unsigned
- template: ./find-tools.yml
- powershell: |
signtool sign /q /a `
/n "Python Software Foundation" `
/fd sha256 `
/tr http://timestamp.digicert.com/ /td sha256 `
/d "LibFFI for Python" `
(gci "$(Pipeline.Workspace)\unsigned\*.dll" -r)
displayName: 'Sign files'
- publish: '$(Pipeline.Workspace)\unsigned'
artifact: 'libffi'
displayName: 'Publish libffi'

View file

@ -1,27 +0,0 @@
steps:
- checkout: self
clean: true
fetchDepth: 5
- script: ./configure --with-pydebug --with-openssl=/usr/local/opt/openssl --prefix=/opt/python-azdev
displayName: 'Configure CPython (debug)'
- script: make -j4
displayName: 'Build CPython'
- script: make pythoninfo
displayName: 'Display build info'
- script: make buildbottest TESTOPTS="-j4 -uall,-cpu --junit-xml=$(build.binariesDirectory)/test-results.xml"
displayName: 'Tests'
continueOnError: true
timeoutInMinutes: 30
- task: PublishTestResults@2
displayName: 'Publish Test Results'
inputs:
testResultsFiles: '$(build.binariesDirectory)/test-results.xml'
mergeTestResults: true
testRunTitle: $(testRunTitle)
platform: $(testRunPlatform)
condition: succeededOrFailed()

View file

@ -1,110 +0,0 @@
name: $(SourceTag)_$(Date:yyyyMMdd)$(Rev:.rr)
variables:
IntDir: '$(Build.BinariesDirectory)'
OutDir: '$(Build.ArtifactStagingDirectory)'
# MUST BE SET AT QUEUE TIME
# SigningCertificate: 'Python Software Foundation'
# SourcesRepo: 'https://github.com/python/cpython-source-deps'
# SourceTag: 'openssl-1.1.1k'
jobs:
- job: Build_SSL
displayName: OpenSSL
pool:
name: 'Windows Release'
#vmImage: windows-latest
strategy:
matrix:
win32:
Platform: 'win32'
VCPlatform: 'amd64_x86'
OpenSSLPlatform: 'VC-WIN32 no-asm'
amd64:
Platform: 'amd64'
VCPlatform: 'amd64'
OpenSSLPlatform: 'VC-WIN64A-masm'
arm32:
Platform: 'arm32'
VCPlatform: 'amd64_arm'
OpenSSLPlatform: 'VC-WIN32-ARM'
arm64:
Platform: 'arm64'
VCPlatform: 'amd64_arm64'
OpenSSLPlatform: 'VC-WIN64-ARM'
workspace:
clean: all
steps:
- checkout: none
- template: ./find-tools.yml
- powershell: |
git clone $(SourcesRepo) -b $(SourceTag) --depth 1 .
displayName: 'Check out OpenSSL sources'
- powershell: |
$f = gi ms\uplink.c
$c1 = gc $f
$c2 = $c1 -replace '\(\(h = GetModuleHandle\(NULL\)\) == NULL\)', '((h = GetModuleHandleA("_ssl.pyd")) == NULL) if ((h = GetModuleHandleA("_ssl_d.pyd")) == NULL) if ((h = GetModuleHandle(NULL)) == NULL /*patched*/)'
if ($c2 -ne $c1) {
$c2 | Out-File $f -Encoding ASCII
} else {
Write-Host '##warning Failed to patch uplink.c'
}
displayName: 'Apply uplink.c patch'
- script: |
call "$(vcvarsall)" $(VCPlatform)
perl "$(Build.SourcesDirectory)\Configure" $(OpenSSLPlatform)
nmake
workingDirectory: '$(IntDir)'
displayName: 'Build OpenSSL'
- script: |
call "$(vcvarsall)" $(VCPlatform)
signtool sign /q /a /n "$(SigningCertificate)" /fd sha256 /tr http://timestamp.digicert.com/ /td sha256 /d "OpenSSL for Python" *.dll
workingDirectory: '$(IntDir)'
displayName: 'Sign OpenSSL Build'
condition: and(succeeded(), variables['SigningCertificate'])
- task: CopyFiles@2
displayName: 'Copy built libraries for upload'
inputs:
SourceFolder: '$(IntDir)'
Contents: |
lib*.dll
lib*.pdb
lib*.lib
include\openssl\*.h
TargetFolder: '$(OutDir)'
- task: CopyFiles@2
displayName: 'Copy header files for upload'
inputs:
SourceFolder: '$(Build.SourcesDirectory)'
Contents: |
include\openssl\*
TargetFolder: '$(OutDir)'
- task: CopyFiles@2
displayName: 'Copy applink files for upload'
inputs:
SourceFolder: '$(Build.SourcesDirectory)\ms'
Contents: applink.c
TargetFolder: '$(OutDir)\include'
- task: CopyFiles@2
displayName: 'Copy LICENSE for upload'
inputs:
SourceFolder: '$(Build.SourcesDirectory)'
Contents: LICENSE
TargetFolder: '$(OutDir)'
- publish: '$(OutDir)'
artifact: '$(Platform)'
displayName: 'Publishing $(Platform)'

View file

@ -1,10 +1,3 @@
parameters:
coverage: false
sudo_dependencies: sudo
dependencies: apt
patchcheck: true
xvfb: true
steps:
- checkout: self
clean: true
@ -14,7 +7,7 @@ steps:
- script: sudo setfacl -Rb /home/vsts
displayName: 'Workaround ACL issue'
- script: ${{ parameters.sudo_dependencies }} ./.azure-pipelines/posix-deps-${{ parameters.dependencies }}.sh $(openssl_version)
- script: sudo ./.azure-pipelines/posix-deps-apt.sh $(openssl_version)
displayName: 'Install dependencies'
- script: ./configure --with-pydebug
@ -23,61 +16,11 @@ steps:
- script: make -j4
displayName: 'Build CPython'
- ${{ if eq(parameters.coverage, 'true') }}:
- script: ./python -m venv venv && ./venv/bin/python -m pip install -U coverage
displayName: 'Set up virtual environment'
- script: make pythoninfo
displayName: 'Display build info'
- script: ./venv/bin/python -m test.pythoninfo
displayName: 'Display build info'
- script: |
$COMMAND -m coverage run --pylib -m test \
--fail-env-changed \
-uall,-cpu \
--junit-xml=$(build.binariesDirectory)/test-results.xml \
-x test_multiprocessing_fork \
-x test_multiprocessing_forkserver \
-x test_multiprocessing_spawn \
-x test_concurrent_futures
displayName: 'Tests with coverage'
env:
${{ if eq(parameters.xvfb, 'true') }}:
COMMAND: xvfb-run ./venv/bin/python
${{ if ne(parameters.xvfb, 'true') }}:
COMMAND: ./venv/bin/python
- script: ./venv/bin/python -m coverage xml
displayName: 'Generate coverage.xml'
- script: source ./venv/bin/activate && bash <(curl -s https://codecov.io/bash) -y .github/codecov.yml
displayName: 'Publish code coverage results'
- ${{ if ne(parameters.coverage, 'true') }}:
- script: make pythoninfo
displayName: 'Display build info'
- script: $COMMAND buildbottest TESTOPTS="-j4 -uall,-cpu --junit-xml=$(build.binariesDirectory)/test-results.xml"
displayName: 'Tests'
env:
${{ if eq(parameters.xvfb, 'true') }}:
COMMAND: xvfb-run make
${{ if ne(parameters.xvfb, 'true') }}:
COMMAND: make
- ${{ if eq(parameters.patchcheck, 'true') }}:
- script: |
git fetch origin
./python Tools/scripts/patchcheck.py --ci true
displayName: 'Run patchcheck.py'
condition: and(succeeded(), eq(variables['Build.Reason'], 'PullRequest'))
- task: PublishTestResults@2
displayName: 'Publish Test Results'
inputs:
testResultsFiles: '$(build.binariesDirectory)/test-results.xml'
mergeTestResults: true
testRunTitle: $(testRunTitle)
platform: $(testRunPlatform)
condition: succeededOrFailed()
- script: |
git fetch origin
./python Tools/patchcheck/patchcheck.py --ci true
displayName: 'Run patchcheck.py'
condition: and(succeeded(), eq(variables['Build.Reason'], 'PullRequest'))

View file

@ -1,123 +1,28 @@
variables:
coverage: false
pr: ['main', '3.10', '3.9', '3.8', '3.7']
pr: ['main', '3.12', '3.11', '3.10', '3.9', '3.8', '3.7']
jobs:
- job: Prebuild
displayName: Pre-build checks
pool:
vmImage: ubuntu-20.04
vmImage: ubuntu-22.04
steps:
- template: ./prebuild-checks.yml
- job: Docs_PR
displayName: Docs PR
dependsOn: Prebuild
condition: and(succeeded(), eq(dependencies.Prebuild.outputs['docs.run'], 'true'))
pool:
vmImage: ubuntu-20.04
steps:
- template: ./docs-steps.yml
- job: macOS_PR_Tests
displayName: macOS PR Tests
dependsOn: Prebuild
#condition: and(succeeded(), eq(dependencies.Prebuild.outputs['tests.run'], 'true'))
# bpo-39837: macOS tests on Azure Pipelines are disabled
condition: false
variables:
testRunTitle: '$(system.pullRequest.TargetBranch)-macos'
testRunPlatform: macos
pool:
vmImage: macos-10.15
steps:
- template: ./macos-steps.yml
parameters:
targetBranch: $(System.PullRequest.TargetBranch)
- job: Ubuntu_PR_Tests
displayName: Ubuntu PR Tests
- job: Ubuntu_Patchcheck
displayName: Ubuntu patchcheck
dependsOn: Prebuild
condition: and(succeeded(), eq(dependencies.Prebuild.outputs['tests.run'], 'true'))
pool:
vmImage: ubuntu-20.04
vmImage: ubuntu-22.04
variables:
testRunTitle: '$(system.pullRequest.TargetBranch)-linux'
testRunPlatform: linux
openssl_version: 1.1.1n
openssl_version: 1.1.1u
steps:
- template: ./posix-steps.yml
parameters:
dependencies: apt
- job: Ubuntu_Coverage_PR_Tests
displayName: Ubuntu PR Tests (coverage)
dependsOn: Prebuild
condition: |
and(
and(
succeeded(),
eq(variables['coverage'], 'true')
),
eq(dependencies.Prebuild.outputs['tests.run'], 'true')
)
pool:
vmImage: ubuntu-20.04
variables:
testRunTitle: '$(Build.SourceBranchName)-linux-coverage'
testRunPlatform: linux-coverage
openssl_version: 1.1.1n
steps:
- template: ./posix-steps.yml
parameters:
dependencies: apt
coverage: true
- job: Windows_PR_Tests
displayName: Windows PR Tests
dependsOn: Prebuild
condition: and(succeeded(), eq(dependencies.Prebuild.outputs['tests.run'], 'true'))
pool:
vmImage: windows-2022
strategy:
matrix:
win32:
arch: win32
buildOpt: '-p Win32'
testRunTitle: '$(System.PullRequest.TargetBranch)-win32'
testRunPlatform: win32
win64:
arch: amd64
buildOpt: '-p x64'
testRunTitle: '$(System.PullRequest.TargetBranch)-win64'
testRunPlatform: win64
winarm64:
arch: arm64
buildOpt: '-p arm64'
maxParallel: 4
steps:
- template: ./windows-steps.yml
parameters:
targetBranch: $(System.PullRequest.TargetBranch)

View file

@ -11,18 +11,6 @@ steps:
displayName: Fetch comparison tree
condition: and(succeeded(), variables['System.PullRequest.TargetBranch'])
- script: |
if ! git diff --name-only $(diffTarget) | grep -qE '(\.rst$|^Doc|^Misc)'
then
echo "No docs were updated: docs.run=false"
echo "##vso[task.setvariable variable=run;isOutput=true]false"
else
echo "Docs were updated: docs.run=true"
echo "##vso[task.setvariable variable=run;isOutput=true]true"
fi
displayName: Detect documentation changes
name: docs
- script: |
if ! git diff --name-only $(diffTarget) | grep -qvE '(\.rst$|^Doc|^Misc)'
then

View file

@ -1,71 +0,0 @@
name: tcl$(TkSourceTag)_$(Date:yyyyMMdd)$(Rev:.rr)
variables:
IntDir: '$(Build.BinariesDirectory)\obj'
ExternalsDir: '$(Build.BinariesDirectory)\externals'
OutDir: '$(Build.ArtifactStagingDirectory)'
Configuration: 'Release'
# MUST BE SET AT QUEUE TIME
# SigningCertificate: 'Python Software Foundation'
# SourcesRepo: 'https://github.com/python/cpython-source-deps'
# TclSourceTag: 'tcl-core-8.6.12.0'
# TkSourceTag: 'tk-8.6.12.0'
# TixSourceTag: 'tix-8.4.3.6'
jobs:
- job: Build_TclTk
displayName: 'Tcl/Tk'
pool:
name: 'Windows Release'
#vmImage: windows-latest
workspace:
clean: all
steps:
- template: ./find-tools.yml
- powershell: |
git clone $(SourcesRepo) -b $(TclSourceTag) --depth 1 "$(ExternalsDir)\$(TclSourceTag)"
displayName: 'Check out Tcl sources'
- powershell: |
git clone $(SourcesRepo) -b $(TkSourceTag) --depth 1 "$(ExternalsDir)\$(TkSourceTag)"
displayName: 'Check out Tk sources'
- powershell: |
git clone $(SourcesRepo) -b $(TixSourceTag) --depth 1 "$(ExternalsDir)\$(TixSourceTag)"
displayName: 'Check out Tix sources'
# This msbuild.rsp file will be used by the build to forcibly override these variables
- powershell: |
del -Force -EA 0 msbuild.rsp
"/p:IntDir=$(IntDir)\" >> msbuild.rsp
"/p:ExternalsDir=$(ExternalsDir)\" >> msbuild.rsp
"/p:tclDir=$(ExternalsDir)\$(TclSourceTag)\" >> msbuild.rsp
"/p:tkDir=$(ExternalsDir)\$(TkSourceTag)\" >> msbuild.rsp
"/p:tixDir=$(ExternalsDir)\$(TixSourceTag)\" >> msbuild.rsp
displayName: 'Generate msbuild.rsp'
- powershell: |
& "$(msbuild)" PCbuild\tcl.vcxproj "@msbuild.rsp" /p:Platform=Win32 /p:tcltkDir="$(OutDir)\win32"
& "$(msbuild)" PCbuild\tk.vcxproj "@msbuild.rsp" /p:Platform=Win32 /p:tcltkDir="$(OutDir)\win32"
& "$(msbuild)" PCbuild\tix.vcxproj "@msbuild.rsp" /p:Platform=Win32 /p:tcltkDir="$(OutDir)\win32"
displayName: 'Build for win32'
- powershell: |
& "$(msbuild)" PCbuild\tcl.vcxproj "@msbuild.rsp" /p:Platform=x64 /p:tcltkDir="$(OutDir)\amd64"
& "$(msbuild)" PCbuild\tk.vcxproj "@msbuild.rsp" /p:Platform=x64 /p:tcltkDir="$(OutDir)\amd64"
& "$(msbuild)" PCbuild\tix.vcxproj "@msbuild.rsp" /p:Platform=x64 /p:tcltkDir="$(OutDir)\amd64"
displayName: 'Build for amd64'
- powershell: |
& "$(msbuild)" PCbuild\tcl.vcxproj "@msbuild.rsp" /p:Platform=ARM64 /p:tcltkDir="$(OutDir)\arm64"
& "$(msbuild)" PCbuild\tk.vcxproj "@msbuild.rsp" /p:Platform=ARM64 /p:tcltkDir="$(OutDir)\arm64"
& "$(msbuild)" PCbuild\tix.vcxproj "@msbuild.rsp" /p:Platform=ARM64 /p:tcltkDir="$(OutDir)\arm64"
displayName: 'Build for arm64'
- publish: '$(OutDir)'
artifact: 'tcltk'
displayName: 'Publishing tcltk'

View file

@ -12,7 +12,7 @@ steps:
displayName: Show layout info (${{ parameters.kind }})
- ${{ if eq(parameters.fulltest, 'true') }}:
- script: .\python.exe -m test -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0 --junit-xml="$(Build.BinariesDirectory)\test-results-${{ parameters.kind }}.xml" --tempdir "$(Build.BinariesDirectory)\tmp-${{ parameters.kind }}-$(arch)"
- script: .\python.exe -m test -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0 --junit-xml="$(Build.BinariesDirectory)\test-results-${{ parameters.kind }}.xml" --tempdir "$(Build.BinariesDirectory)\tmp-${{ parameters.kind }}-$(arch)" -i test_launcher
workingDirectory: $(Build.BinariesDirectory)\layout-${{ parameters.kind }}-$(arch)
displayName: ${{ parameters.kind }} Tests
env:

View file

@ -1,220 +0,0 @@
name: Release_$(Build.SourceBranchName)_$(SourceTag)_$(Date:yyyyMMdd)$(Rev:.rr)
parameters:
- name: GitRemote
displayName: "Git remote"
type: string
default: python
values:
- 'python'
- 'pablogsal'
- 'ambv'
- '(Other)'
- name: GitRemote_Other
displayName: "If Other, specify Git remote"
type: string
default: 'python'
- name: SourceTag
displayName: "Git tag"
type: string
default: main
- name: DoPublish
displayName: "Publish release"
type: boolean
default: false
- name: SigningCertificate
displayName: "Code signing certificate"
type: string
default: 'Python Software Foundation'
values:
- 'Python Software Foundation'
- 'TestSign'
- 'Unsigned'
- name: SigningDescription
displayName: "Signature description"
type: string
default: 'Built: $(Build.BuildNumber)'
- name: DoARM64
displayName: "Publish ARM64 build"
type: boolean
default: true
# Because there is no ARM64 Tcl/Tk pre-3.11, we need a separate option
# to keep those builds working when the files are going to be absent.
# Eventually when we stop releasing anything that old, we can drop this
# argument (and make it implicitly always 'true')
- name: ARM64TclTk
displayName: "Use Tcl/Tk for ARM64 (3.11 and later)"
type: boolean
default: true
- name: DoPGO
displayName: "Run PGO"
type: boolean
default: true
- name: DoCHM
displayName: "Produce compiled help document (pre-3.11)"
type: boolean
default: false
- name: DoLayout
displayName: "Produce full layout artifact"
type: boolean
default: true
- name: DoMSIX
displayName: "Produce Store packages"
type: boolean
default: true
- name: DoNuget
displayName: "Produce Nuget packages"
type: boolean
default: true
- name: DoEmbed
displayName: "Produce embeddable package"
type: boolean
default: true
- name: DoMSI
displayName: "Produce EXE/MSI installer"
type: boolean
default: true
- name: BuildToPublish
displayName: "Build number to publish (0 to skip)"
type: number
default: '0'
variables:
__RealSigningCertificate: 'Python Software Foundation'
${{ if ne(parameters.GitRemote, '(Other)') }}:
GitRemote: ${{ parameters.GitRemote }}
${{ else }}:
GitRemote: ${{ parameters.GitRemote_Other }}
SourceTag: ${{ parameters.SourceTag }}
DoPGO: ${{ parameters.DoPGO }}
${{ if ne(parameters.SigningCertificate, 'Unsigned') }}:
SigningCertificate: ${{ parameters.SigningCertificate }}
SigningDescription: ${{ parameters.SigningDescription }}
DoCHM: ${{ parameters.DoCHM }}
DoLayout: ${{ parameters.DoLayout }}
DoMSIX: ${{ parameters.DoMSIX }}
DoNuget: ${{ parameters.DoNuget }}
DoEmbed: ${{ parameters.DoEmbed }}
DoMSI: ${{ parameters.DoMSI }}
DoPublish: ${{ parameters.DoPublish }}
PublishARM64: ${{ parameters.DoARM64 }}
# QUEUE TIME VARIABLES
# PyDotOrgUsername: ''
# PyDotOrgServer: ''
trigger: none
pr: none
stages:
- ${{ if eq(parameters.BuildToPublish, '0') }}:
- stage: Build
displayName: Build binaries
jobs:
- template: windows-release/stage-build.yml
parameters:
ARM64TclTk: ${{ parameters.ARM64TclTk }}
- stage: Sign
displayName: Sign binaries
dependsOn: Build
jobs:
- template: windows-release/stage-sign.yml
- stage: Layout
displayName: Generate layouts
dependsOn: Sign
jobs:
- template: windows-release/stage-layout-full.yml
parameters:
ARM64TclTk: ${{ parameters.ARM64TclTk }}
- template: windows-release/stage-layout-embed.yml
- template: windows-release/stage-layout-nuget.yml
- stage: Pack
dependsOn: Layout
jobs:
- template: windows-release/stage-pack-nuget.yml
- stage: Test
dependsOn: Pack
jobs:
- template: windows-release/stage-test-embed.yml
- template: windows-release/stage-test-nuget.yml
- ${{ if eq(parameters.DoMSIX, 'true') }}:
- stage: Layout_MSIX
displayName: Generate MSIX layouts
dependsOn: Sign
jobs:
- template: windows-release/stage-layout-msix.yml
parameters:
ARM64TclTk: ${{ parameters.ARM64TclTk }}
- stage: Pack_MSIX
displayName: Package MSIX
dependsOn: Layout_MSIX
jobs:
- template: windows-release/stage-pack-msix.yml
- ${{ if eq(parameters.DoMSI, 'true') }}:
- stage: Build_MSI
displayName: Build MSI installer
dependsOn: Sign
jobs:
- template: windows-release/stage-msi.yml
parameters:
ARM64TclTk: ${{ parameters.ARM64TclTk }}
- stage: Test_MSI
displayName: Test MSI installer
dependsOn: Build_MSI
jobs:
- template: windows-release/stage-test-msi.yml
- ${{ if eq(parameters.DoPublish, 'true') }}:
- ${{ if eq(parameters.DoMSI, 'true') }}:
- stage: PublishPyDotOrg
displayName: Publish to python.org
dependsOn: ['Test_MSI', 'Test']
jobs:
- template: windows-release/stage-publish-pythonorg.yml
- ${{ if eq(parameters.DoNuget, 'true') }}:
- stage: PublishNuget
displayName: Publish to nuget.org
${{ if eq(parameters.DoMSI, 'true') }}:
dependsOn: ['Test_MSI', 'Test']
${{ else }}:
dependsOn: 'Test'
jobs:
- template: windows-release/stage-publish-nugetorg.yml
- ${{ if eq(parameters.DoMSIX, 'true') }}:
- stage: PublishStore
displayName: Publish to Store
${{ if eq(parameters.DoMSI, 'true') }}:
dependsOn: ['Test_MSI', 'Pack_MSIX']
${{ else }}:
dependsOn: 'Pack_MSIX'
jobs:
- template: windows-release/stage-publish-store.yml
- ${{ else }}:
- stage: PublishExisting
displayName: Publish existing build
dependsOn: []
jobs:
- ${{ if eq(parameters.DoMSI, 'true') }}:
- template: windows-release/stage-publish-pythonorg.yml
parameters:
BuildToPublish: ${{ parameters.BuildToPublish }}
- ${{ if eq(parameters.DoNuget, 'true') }}:
- template: windows-release/stage-publish-nugetorg.yml
parameters:
BuildToPublish: ${{ parameters.BuildToPublish }}
- ${{ if eq(parameters.DoMSIX, 'true') }}:
- template: windows-release/stage-publish-store.yml
parameters:
BuildToPublish: ${{ parameters.BuildToPublish }}

View file

@ -1,84 +0,0 @@
parameters:
ShouldPGO: false
steps:
- template: ./checkout.yml
- powershell: |
$d = (.\PCbuild\build.bat -V) | %{ if($_ -match '\s+(\w+):\s*(.+)\s*$') { @{$Matches[1] = $Matches[2];} }};
Write-Host "##vso[task.setvariable variable=VersionText]$($d.PythonVersion)"
Write-Host "##vso[task.setvariable variable=VersionNumber]$($d.PythonVersionNumber)"
Write-Host "##vso[task.setvariable variable=VersionHex]$($d.PythonVersionHex)"
Write-Host "##vso[task.setvariable variable=VersionUnique]$($d.PythonVersionUnique)"
Write-Host "##vso[build.addbuildtag]$($d.PythonVersion)"
Write-Host "##vso[build.addbuildtag]$($d.PythonVersion)-$(Name)"
displayName: 'Extract version numbers'
- ${{ if eq(parameters.ShouldPGO, 'false') }}:
- powershell: |
$env:SigningCertificate = $null
.\PCbuild\build.bat -v -p $(Platform) -c $(Configuration)
displayName: 'Run build'
env:
IncludeUwp: true
Py_OutDir: '$(Build.BinariesDirectory)\bin'
- ${{ if eq(parameters.ShouldPGO, 'true') }}:
- powershell: |
$env:SigningCertificate = $null
.\PCbuild\build.bat -v -p $(Platform) --pgo
displayName: 'Run build with PGO'
env:
IncludeUwp: true
Py_OutDir: '$(Build.BinariesDirectory)\bin'
- powershell: |
$kitroot = (gp 'HKLM:\SOFTWARE\Microsoft\Windows Kits\Installed Roots\').KitsRoot10
$tool = (gci -r "$kitroot\Bin\*\x64\signtool.exe" | sort FullName -Desc | select -First 1)
if (-not $tool) {
throw "SDK is not available"
}
Write-Host "##vso[task.prependpath]$($tool.Directory)"
displayName: 'Add WinSDK tools to path'
- powershell: |
$env:SigningCertificate = $null
$(_HostPython) PC\layout -vv -b "$(Build.BinariesDirectory)\bin" -t "$(Build.BinariesDirectory)\catalog" --catalog "${env:CAT}.cdf" --preset-default --arch $(Arch)
makecat "${env:CAT}.cdf"
del "${env:CAT}.cdf"
if (-not (Test-Path "${env:CAT}.cat")) {
throw "Failed to build catalog file"
}
displayName: 'Generate catalog'
env:
CAT: $(Build.BinariesDirectory)\bin\$(Arch)\python
PYTHON_HEXVERSION: $(VersionHex)
- task: PublishPipelineArtifact@0
displayName: 'Publish binaries'
condition: and(succeeded(), not(and(eq(variables['Configuration'], 'Release'), variables['SigningCertificate'])))
inputs:
targetPath: '$(Build.BinariesDirectory)\bin\$(Arch)'
artifactName: bin_$(Name)
- task: PublishPipelineArtifact@0
displayName: 'Publish binaries for signing'
condition: and(succeeded(), and(eq(variables['Configuration'], 'Release'), variables['SigningCertificate']))
inputs:
targetPath: '$(Build.BinariesDirectory)\bin\$(Arch)'
artifactName: unsigned_bin_$(Name)
- task: CopyFiles@2
displayName: 'Layout Artifact: symbols'
inputs:
sourceFolder: $(Build.BinariesDirectory)\bin\$(Arch)
targetFolder: $(Build.ArtifactStagingDirectory)\symbols\$(Name)
flatten: true
contents: |
**\*.pdb
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: symbols'
inputs:
PathToPublish: '$(Build.ArtifactStagingDirectory)\symbols'
ArtifactName: symbols

View file

@ -1,21 +0,0 @@
parameters:
depth: 3
steps:
- checkout: none
- script: git clone --progress -v --depth ${{ parameters.depth }} --branch $(SourceTag) --single-branch https://github.com/$(GitRemote)/cpython.git .
displayName: 'git clone ($(GitRemote)/$(SourceTag))'
condition: and(succeeded(), and(variables['GitRemote'], variables['SourceTag']))
- script: git clone --progress -v --depth ${{ parameters.depth }} --branch $(SourceTag) --single-branch $(Build.Repository.Uri) .
displayName: 'git clone (<default>/$(SourceTag))'
condition: and(succeeded(), and(not(variables['GitRemote']), variables['SourceTag']))
- script: git clone --progress -v --depth ${{ parameters.depth }} --branch $(Build.SourceBranchName) --single-branch https://github.com/$(GitRemote)/cpython.git .
displayName: 'git clone ($(GitRemote)/<default>)'
condition: and(succeeded(), and(variables['GitRemote'], not(variables['SourceTag'])))
- script: git clone --progress -v --depth ${{ parameters.depth }} --branch $(Build.SourceBranchName) --single-branch $(Build.Repository.Uri) .
displayName: 'git clone'
condition: and(succeeded(), and(not(variables['GitRemote']), not(variables['SourceTag'])))

View file

@ -1,17 +0,0 @@
# Locate the Windows SDK and add its binaries directory to PATH
#
# `toolname` can be overridden to use a different marker file.
parameters:
toolname: signtool.exe
steps:
- powershell: |
$kitroot = (gp 'HKLM:\SOFTWARE\Microsoft\Windows Kits\Installed Roots\').KitsRoot10
$tool = (gci -r "$kitroot\Bin\*\${{ parameters.toolname }}" | sort FullName -Desc | select -First 1)
if (-not $tool) {
throw "SDK is not available"
}
Write-Host "##vso[task.prependpath]$($tool.Directory)"
Write-Host "Adding $($tool.Directory) to PATH"
displayName: 'Add WinSDK tools to path'

View file

@ -1,23 +0,0 @@
steps:
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: bin_$(HostArch)'
condition: and(succeeded(), variables['HostArch'])
inputs:
artifactName: bin_$(HostArch)
targetPath: $(Build.BinariesDirectory)\bin_$(HostArch)
- powershell: >
Write-Host (
'##vso[task.setvariable variable=LayoutCmd]&
"$(Python)"
"{1}\PC\layout"
-vv
--source "{1}"
--build "{0}\bin"
--arch "$(Name)"
--temp "{0}\layout-temp"
--include-cat "{0}\bin\python.cat"
--doc-build "{0}\doc"'
-f ("$(Build.BinariesDirectory)", "$(Build.SourcesDirectory)")
)
displayName: 'Set LayoutCmd'

View file

@ -1,13 +0,0 @@
parameters:
DllToolOpt: -m i386:x86-64
#DllToolOpt: -m i386 --as-flags=--32
steps:
- powershell: |
git clone https://github.com/python/cpython-bin-deps --branch binutils --single-branch --depth 1 --progress -v "binutils"
gci "bin\$(Arch)\python*.dll" | %{
& "binutils\gendef.exe" $_ | Out-File -Encoding ascii tmp.def
& "binutils\dlltool.exe" --dllname $($_.BaseName).dll --def tmp.def --output-lib "$($_.Directory)\lib$($_.BaseName).a" ${{ parameters.DllToolOpt }}
}
displayName: 'Generate MinGW import library'
workingDirectory: $(Build.BinariesDirectory)

View file

@ -1,181 +0,0 @@
parameters:
ARM64TclTk: true
steps:
- template: ./checkout.yml
- powershell: |
$d = (.\PCbuild\build.bat -V) | %{ if($_ -match '\s+(\w+):\s*(.+)\s*$') { @{$Matches[1] = $Matches[2];} }};
Write-Host "##vso[task.setvariable variable=SigningDescription]Python $($d.PythonVersion)"
displayName: 'Update signing description'
condition: and(succeeded(), not(variables['SigningDescription']))
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: doc'
inputs:
artifactName: doc
targetPath: $(Build.BinariesDirectory)\doc
- task: CopyFiles@2
displayName: 'Merge documentation files'
inputs:
sourceFolder: $(Build.BinariesDirectory)\doc
targetFolder: $(Build.SourcesDirectory)\Doc\build
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: bin_win32'
inputs:
artifactName: bin_win32
targetPath: $(Build.BinariesDirectory)\win32
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: bin_win32_d'
inputs:
artifactName: bin_win32_d
targetPath: $(Build.BinariesDirectory)\win32
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: bin_amd64'
inputs:
artifactName: bin_amd64
targetPath: $(Build.BinariesDirectory)\amd64
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: bin_amd64_d'
inputs:
artifactName: bin_amd64_d
targetPath: $(Build.BinariesDirectory)\amd64
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: bin_arm64'
condition: and(succeeded(), eq(variables['PublishARM64'], 'true'))
inputs:
artifactName: bin_arm64
targetPath: $(Build.BinariesDirectory)\arm64
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: bin_arm64_d'
condition: and(succeeded(), eq(variables['PublishARM64'], 'true'))
inputs:
artifactName: bin_arm64_d
targetPath: $(Build.BinariesDirectory)\arm64
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: tcltk_lib_win32'
inputs:
artifactName: tcltk_lib_win32
targetPath: $(Build.BinariesDirectory)\tcltk_lib_win32
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: tcltk_lib_amd64'
inputs:
artifactName: tcltk_lib_amd64
targetPath: $(Build.BinariesDirectory)\tcltk_lib_amd64
- ${{ if eq(parameters.ARM64TclTk, true) }}:
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: tcltk_lib_arm64'
condition: and(succeeded(), eq(variables['PublishARM64'], 'true'))
inputs:
artifactName: tcltk_lib_arm64
targetPath: $(Build.BinariesDirectory)\tcltk_lib_arm64
- powershell: |
copy $(Build.BinariesDirectory)\amd64\Activate.ps1 Lib\venv\scripts\common\Activate.ps1 -Force
displayName: 'Copy signed files into sources'
condition: and(succeeded(), variables['SigningCertificate'])
- script: |
call Tools\msi\get_externals.bat
call PCbuild\find_python.bat
echo ##vso[task.setvariable variable=PYTHON]%PYTHON%
call PCbuild/find_msbuild.bat
echo ##vso[task.setvariable variable=MSBUILD]%MSBUILD%
displayName: 'Get external dependencies'
- script: |
%PYTHON% -m pip install blurb
%PYTHON% -m blurb merge -f Misc\NEWS
displayName: 'Merge NEWS file'
- script: |
%MSBUILD% Tools\msi\launcher\launcher.wixproj
displayName: 'Build launcher installer'
env:
Platform: x86
Py_OutDir: $(Build.BinariesDirectory)
- script: |
%MSBUILD% Tools\msi\bundle\releaselocal.wixproj /t:Rebuild /p:RebuildAll=true
displayName: 'Build win32 installer'
env:
Platform: x86
Py_OutDir: $(Build.BinariesDirectory)
PYTHON: $(Build.BinariesDirectory)\win32\python.exe
PythonForBuild: $(Build.BinariesDirectory)\win32\python.exe
PYTHONHOME: $(Build.SourcesDirectory)
TclTkLibraryDir: $(Build.BinariesDirectory)\tcltk_lib_win32
BuildForRelease: true
- script: |
%MSBUILD% Tools\msi\bundle\releaselocal.wixproj /t:Rebuild /p:RebuildAll=true
displayName: 'Build amd64 installer'
env:
Platform: x64
Py_OutDir: $(Build.BinariesDirectory)
PYTHON: $(Build.BinariesDirectory)\amd64\python.exe
PythonForBuild: $(Build.BinariesDirectory)\amd64\python.exe
PYTHONHOME: $(Build.SourcesDirectory)
TclTkLibraryDir: $(Build.BinariesDirectory)\tcltk_lib_amd64
BuildForRelease: true
- script: |
%MSBUILD% Tools\msi\bundle\releaselocal.wixproj /t:Rebuild /p:RebuildAll=true
displayName: 'Build arm64 installer'
condition: and(succeeded(), eq(variables['PublishARM64'], 'true'))
env:
Platform: ARM64
Py_OutDir: $(Build.BinariesDirectory)
PYTHON: $(Build.BinariesDirectory)\win32\python.exe
PythonForBuild: $(Build.BinariesDirectory)\win32\python.exe
PYTHONHOME: $(Build.SourcesDirectory)
BuildForRelease: true
${{ if eq(parameters.ARM64TclTk, true) }}:
TclTkLibraryDir: $(Build.BinariesDirectory)\tcltk_lib_arm64
- task: CopyFiles@2
displayName: 'Assemble artifact: msi (win32)'
inputs:
sourceFolder: $(Build.BinariesDirectory)\win32\en-us
targetFolder: $(Build.ArtifactStagingDirectory)\msi\win32
contents: |
*.msi
*.cab
*.exe
- task: CopyFiles@2
displayName: 'Assemble artifact: msi (amd64)'
inputs:
sourceFolder: $(Build.BinariesDirectory)\amd64\en-us
targetFolder: $(Build.ArtifactStagingDirectory)\msi\amd64
contents: |
*.msi
*.cab
*.exe
- task: CopyFiles@2
displayName: 'Assemble artifact: msi (arm64)'
condition: and(succeeded(), eq(variables['PublishARM64'], 'true'))
inputs:
sourceFolder: $(Build.BinariesDirectory)\arm64\en-us
targetFolder: $(Build.ArtifactStagingDirectory)\msi\arm64
contents: |
*.msi
*.cab
*.exe
- task: PublishPipelineArtifact@0
displayName: 'Publish MSI'
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)\msi'
artifactName: msi

View file

@ -1,193 +0,0 @@
parameters:
ARM64TclTk: true
jobs:
- job: Build_Docs
displayName: Docs build
pool:
vmImage: windows-2022
workspace:
clean: all
steps:
- template: ./checkout.yml
- script: Doc\make.bat html
displayName: 'Build HTML docs'
env:
BUILDDIR: $(Build.BinariesDirectory)\Doc
- script: Doc\make.bat htmlhelp
displayName: 'Build CHM docs'
condition: and(succeeded(), eq(variables['DoCHM'], 'true'))
env:
BUILDDIR: $(Build.BinariesDirectory)\Doc
- task: CopyFiles@2
displayName: 'Assemble artifact: Doc'
inputs:
sourceFolder: $(Build.BinariesDirectory)\Doc
targetFolder: $(Build.ArtifactStagingDirectory)\Doc
contents: |
html\**\*
htmlhelp\*.chm
- task: PublishPipelineArtifact@0
displayName: 'Publish artifact: doc'
inputs:
targetPath: $(Build.ArtifactStagingDirectory)\Doc
artifactName: doc
- job: Build_Python
displayName: Python build
pool:
vmImage: windows-2022
workspace:
clean: all
strategy:
matrix:
win32:
Name: win32
Arch: win32
Platform: x86
Configuration: Release
_HostPython: .\python
win32_d:
Name: win32_d
Arch: win32
Platform: x86
Configuration: Debug
_HostPython: .\python
amd64_d:
Name: amd64_d
Arch: amd64
Platform: x64
Configuration: Debug
_HostPython: .\python
arm64:
Name: arm64
Arch: arm64
Platform: ARM64
Configuration: Release
_HostPython: python
arm64_d:
Name: arm64_d
Arch: arm64
Platform: ARM64
Configuration: Debug
_HostPython: python
steps:
- template: ./build-steps.yml
- job: Build_Python_NonPGO
displayName: Python non-PGO build
condition: and(succeeded(), ne(variables['DoPGO'], 'true'))
pool:
vmImage: windows-2022
workspace:
clean: all
strategy:
matrix:
amd64:
Name: amd64
Arch: amd64
Platform: x64
Configuration: Release
_HostPython: .\python
steps:
- template: ./build-steps.yml
- job: Build_Python_PGO
displayName: Python PGO build
condition: and(succeeded(), eq(variables['DoPGO'], 'true'))
# Allow up to five hours for PGO
timeoutInMinutes: 300
pool:
name: 'Windows Release'
workspace:
clean: all
strategy:
matrix:
amd64:
Name: amd64
Arch: amd64
Platform: x64
Configuration: Release
_HostPython: .\python
steps:
- template: ./build-steps.yml
parameters:
ShouldPGO: true
- job: TclTk_Lib
displayName: Publish Tcl/Tk Library
pool:
vmImage: windows-2022
workspace:
clean: all
steps:
- template: ./checkout.yml
- script: PCbuild\get_externals.bat --no-openssl --no-libffi
displayName: 'Get external dependencies'
- task: MSBuild@1
displayName: 'Copy Tcl/Tk lib for publish'
inputs:
solution: PCbuild\tcltk.props
platform: x86
msbuildArguments: /t:CopyTclTkLib /p:OutDir="$(Build.ArtifactStagingDirectory)\tcl_win32"
- task: MSBuild@1
displayName: 'Copy Tcl/Tk lib for publish'
inputs:
solution: PCbuild\tcltk.props
platform: x64
msbuildArguments: /t:CopyTclTkLib /p:OutDir="$(Build.ArtifactStagingDirectory)\tcl_amd64"
- ${{ if eq(parameters.ARM64TclTk, true) }}:
- task: MSBuild@1
displayName: 'Copy Tcl/Tk lib for publish'
inputs:
solution: PCbuild\tcltk.props
platform: ARM64
msbuildArguments: /t:CopyTclTkLib /p:OutDir="$(Build.ArtifactStagingDirectory)\tcl_arm64"
- task: PublishPipelineArtifact@0
displayName: 'Publish artifact: tcltk_lib_win32'
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)\tcl_win32'
artifactName: tcltk_lib_win32
- task: PublishPipelineArtifact@0
displayName: 'Publish artifact: tcltk_lib_amd64'
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)\tcl_amd64'
artifactName: tcltk_lib_amd64
- ${{ if eq(parameters.ARM64TclTk, true) }}:
- task: PublishPipelineArtifact@0
displayName: 'Publish artifact: tcltk_lib_arm64'
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)\tcl_arm64'
artifactName: tcltk_lib_arm64

View file

@ -1,61 +0,0 @@
jobs:
- job: Make_Embed_Layout
displayName: Make embeddable layout
condition: and(succeeded(), eq(variables['DoEmbed'], 'true'))
pool:
vmImage: windows-2022
workspace:
clean: all
strategy:
matrix:
win32:
Name: win32
Python: $(Build.BinariesDirectory)\bin\python.exe
PYTHONHOME: $(Build.SourcesDirectory)
amd64:
Name: amd64
Python: $(Build.BinariesDirectory)\bin\python.exe
PYTHONHOME: $(Build.SourcesDirectory)
arm64:
Name: arm64
HostArch: amd64
Python: $(Build.BinariesDirectory)\bin_amd64\python.exe
PYTHONHOME: $(Build.SourcesDirectory)
steps:
- template: ./checkout.yml
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: bin_$(Name)'
inputs:
artifactName: bin_$(Name)
targetPath: $(Build.BinariesDirectory)\bin
- template: ./layout-command.yml
- powershell: |
$d = (.\PCbuild\build.bat -V) | %{ if($_ -match '\s+(\w+):\s*(.+)\s*$') { @{$Matches[1] = $Matches[2];} }};
Write-Host "##vso[task.setvariable variable=VersionText]$($d.PythonVersion)"
displayName: 'Extract version numbers'
- powershell: >
$(LayoutCmd)
--copy "$(Build.ArtifactStagingDirectory)\layout"
--zip "$(Build.ArtifactStagingDirectory)\embed\python-$(VersionText)-embed-$(Name).zip"
--preset-embed
displayName: 'Generate embeddable layout'
- task: PublishPipelineArtifact@0
displayName: 'Publish Artifact: layout_embed_$(Name)'
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)\layout'
artifactName: layout_embed_$(Name)
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: embed'
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)\embed'
ArtifactName: embed

View file

@ -1,80 +0,0 @@
parameters:
ARM64TclTk: true
jobs:
- job: Make_Layouts
displayName: Make layouts
condition: and(succeeded(), eq(variables['DoLayout'], 'true'))
pool:
vmImage: windows-2022
workspace:
clean: all
strategy:
matrix:
win32:
Name: win32
Python: $(Build.BinariesDirectory)\bin\python.exe
PYTHONHOME: $(Build.SourcesDirectory)
TclLibrary: $(Build.BinariesDirectory)\tcltk_lib\tcl8
amd64:
Name: amd64
Python: $(Build.BinariesDirectory)\bin\python.exe
PYTHONHOME: $(Build.SourcesDirectory)
TclLibrary: $(Build.BinariesDirectory)\tcltk_lib\tcl8
arm64:
Name: arm64
HostArch: amd64
Python: $(Build.BinariesDirectory)\bin_amd64\python.exe
PYTHONHOME: $(Build.SourcesDirectory)
${{ if eq(parameters.ARM64TclTk, true) }}:
TclLibrary: $(Build.BinariesDirectory)\tcltk_lib\tcl8
steps:
- template: ./checkout.yml
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: bin_$(Name)'
inputs:
artifactName: bin_$(Name)
targetPath: $(Build.BinariesDirectory)\bin
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: bin_$(Name)_d'
inputs:
artifactName: bin_$(Name)_d
targetPath: $(Build.BinariesDirectory)\bin
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: doc'
inputs:
artifactName: doc
targetPath: $(Build.BinariesDirectory)\doc
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: tcltk_lib_$(Name)'
condition: and(succeeded(), variables['TclLibrary'])
inputs:
artifactName: tcltk_lib_$(Name)
targetPath: $(Build.BinariesDirectory)\tcltk_lib
- powershell: |
copy "$(Build.BinariesDirectory)\bin\Activate.ps1" Lib\venv\scripts\common\Activate.ps1 -Force
displayName: 'Copy signed files into sources'
condition: and(succeeded(), variables['SigningCertificate'])
- template: ./layout-command.yml
- powershell: |
$(LayoutCmd) --copy "$(Build.ArtifactStagingDirectory)\layout" --preset-default
displayName: 'Generate full layout'
env:
TCL_LIBRARY: $(TclLibrary)
- task: PublishPipelineArtifact@0
displayName: 'Publish Artifact: layout_full_$(Name)'
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)\layout'
artifactName: layout_full_$(Name)

View file

@ -1,102 +0,0 @@
parameters:
ARM64TclTk: true
jobs:
- job: Make_MSIX_Layout
displayName: Make MSIX layout
pool:
vmImage: windows-2022
workspace:
clean: all
strategy:
matrix:
#win32:
# Name: win32
# Python: $(Build.BinariesDirectory)\bin\python.exe
# PYTHONHOME: $(Build.SourcesDirectory)
# TclLibrary: $(Build.BinariesDirectory)\tcltk_lib\tcl8
amd64:
Name: amd64
Python: $(Build.BinariesDirectory)\bin\python.exe
PYTHONHOME: $(Build.SourcesDirectory)
TclLibrary: $(Build.BinariesDirectory)\tcltk_lib\tcl8
arm64:
Name: arm64
HostArch: amd64
Python: $(Build.BinariesDirectory)\bin_amd64\python.exe
PYTHONHOME: $(Build.SourcesDirectory)
${{ if eq(parameters.ARM64TclTk, true) }}:
TclLibrary: $(Build.BinariesDirectory)\tcltk_lib\tcl8
steps:
- template: ./checkout.yml
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: bin_$(Name)'
inputs:
artifactName: bin_$(Name)
targetPath: $(Build.BinariesDirectory)\bin
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: bin_$(Name)_d'
inputs:
artifactName: bin_$(Name)_d
targetPath: $(Build.BinariesDirectory)\bin
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: tcltk_lib_$(Name)'
condition: and(succeeded(), variables['TclLibrary'])
inputs:
artifactName: tcltk_lib_$(Name)
targetPath: $(Build.BinariesDirectory)\tcltk_lib
- powershell: |
copy "$(Build.BinariesDirectory)\bin\Activate.ps1" Lib\venv\scripts\common\Activate.ps1 -Force
displayName: 'Copy signed files into sources'
condition: and(succeeded(), variables['SigningCertificate'])
- template: ./layout-command.yml
- powershell: |
Remove-Item "$(Build.ArtifactStagingDirectory)\appx-store" -Recurse -Force -EA 0
$(LayoutCmd) --copy "$(Build.ArtifactStagingDirectory)\appx-store" --preset-appx --precompile
displayName: 'Generate store APPX layout'
env:
TCL_LIBRARY: $(TclLibrary)
- task: PublishPipelineArtifact@0
displayName: 'Publish Artifact: layout_appxstore_$(Name)'
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)\appx-store'
artifactName: layout_appxstore_$(Name)
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: cert'
condition: and(succeeded(), variables['SigningCertificate'])
inputs:
artifactName: cert
targetPath: $(Build.BinariesDirectory)\cert
- powershell: |
$info = (gc "$(Build.BinariesDirectory)\cert\certinfo.json" | ConvertFrom-JSON)
Write-Host "Side-loadable APPX must be signed with '$($info.Subject)'"
Write-Host "##vso[task.setvariable variable=APPX_DATA_PUBLISHER]$($info.Subject)"
Write-Host "##vso[task.setvariable variable=APPX_DATA_SHA256]$($info.SHA256)"
displayName: 'Override signing parameters'
condition: and(succeeded(), variables['SigningCertificate'])
- powershell: |
Remove-Item "$(Build.ArtifactStagingDirectory)\appx" -Recurse -Force -EA 0
$(LayoutCmd) --copy "$(Build.ArtifactStagingDirectory)\appx" --preset-appx --precompile --include-symbols --include-tests
displayName: 'Generate sideloading APPX layout'
env:
TCL_LIBRARY: $(TclLibrary)
- task: PublishPipelineArtifact@0
displayName: 'Publish Artifact: layout_appx_$(Name)'
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)\appx'
artifactName: layout_appx_$(Name)

View file

@ -1,52 +0,0 @@
jobs:
- job: Make_Nuget_Layout
displayName: Make Nuget layout
condition: and(succeeded(), eq(variables['DoNuget'], 'true'))
pool:
vmImage: windows-2022
workspace:
clean: all
strategy:
matrix:
win32:
Name: win32
Python: $(Build.BinariesDirectory)\bin\python.exe
PYTHONHOME: $(Build.SourcesDirectory)
amd64:
Name: amd64
Python: $(Build.BinariesDirectory)\bin\python.exe
PYTHONHOME: $(Build.SourcesDirectory)
arm64:
Name: arm64
HostArch: amd64
Python: $(Build.BinariesDirectory)\bin_amd64\python.exe
PYTHONHOME: $(Build.SourcesDirectory)
steps:
- template: ./checkout.yml
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: bin_$(Name)'
inputs:
artifactName: bin_$(Name)
targetPath: $(Build.BinariesDirectory)\bin
- powershell: |
copy $(Build.BinariesDirectory)\bin\Activate.ps1 Lib\venv\scripts\common\Activate.ps1 -Force
displayName: 'Copy signed files into sources'
condition: and(succeeded(), variables['SigningCertificate'])
- template: ./layout-command.yml
- powershell: |
$(LayoutCmd) --copy "$(Build.ArtifactStagingDirectory)\nuget" --preset-nuget
displayName: 'Generate nuget layout'
- task: PublishPipelineArtifact@0
displayName: 'Publish Artifact: layout_nuget_$(Name)'
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)\nuget'
artifactName: layout_nuget_$(Name)

View file

@ -1,43 +0,0 @@
parameters:
ARM64TclTk: true
jobs:
- job: Make_MSI
displayName: Make MSI
condition: and(succeeded(), not(variables['SigningCertificate']))
pool:
vmImage: windows-2022
variables:
ReleaseUri: http://www.python.org/{arch}
DownloadUrl: https://www.python.org/ftp/python/{version}/{arch}{releasename}/{msi}
Py_OutDir: $(Build.BinariesDirectory)
workspace:
clean: all
steps:
- template: msi-steps.yml
parameters:
ARM64TclTk: ${{ parameters.ARM64TclTk }}
- job: Make_Signed_MSI
displayName: Make signed MSI
condition: and(succeeded(), variables['SigningCertificate'])
pool:
name: 'Windows Release'
variables:
ReleaseUri: http://www.python.org/{arch}
DownloadUrl: https://www.python.org/ftp/python/{version}/{arch}{releasename}/{msi}
Py_OutDir: $(Build.BinariesDirectory)
workspace:
clean: all
steps:
- template: msi-steps.yml
parameters:
ARM64TclTk: ${{ parameters.ARM64TclTk }}

View file

@ -1,148 +0,0 @@
jobs:
- job: Pack_MSIX
displayName: Pack MSIX bundles
pool:
vmImage: windows-2022
workspace:
clean: all
strategy:
matrix:
amd64:
Name: amd64
Artifact: appx
Suffix:
ShouldSign: true
amd64_store:
Name: amd64
Artifact: appxstore
Suffix: -store
Upload: true
arm64:
Name: arm64
Artifact: appx
Suffix:
ShouldSign: true
arm64_store:
Name: arm64
Artifact: appxstore
Suffix: -store
Upload: true
steps:
- template: ./checkout.yml
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: layout_$(Artifact)_$(Name)'
inputs:
artifactName: layout_$(Artifact)_$(Name)
targetPath: $(Build.BinariesDirectory)\layout
- task: DownloadBuildArtifacts@0
displayName: 'Download artifact: symbols'
inputs:
artifactName: symbols
downloadPath: $(Build.BinariesDirectory)
- powershell: |
$d = (.\PCbuild\build.bat -V) | %{ if($_ -match '\s+(\w+):\s*(.+)\s*$') { @{$Matches[1] = $Matches[2];} }};
Write-Host "##vso[task.setvariable variable=VersionText]$($d.PythonVersion)"
Write-Host "##vso[task.setvariable variable=VersionNumber]$($d.PythonVersionNumber)"
Write-Host "##vso[task.setvariable variable=VersionHex]$($d.PythonVersionHex)"
Write-Host "##vso[task.setvariable variable=VersionUnique]$($d.PythonVersionUnique)"
Write-Host "##vso[task.setvariable variable=Filename]python-$($d.PythonVersion)-$(Name)$(Suffix)"
displayName: 'Extract version numbers'
- powershell: |
./Tools/msi/make_appx.ps1 -layout "$(Build.BinariesDirectory)\layout" -msix "$(Build.ArtifactStagingDirectory)\msix\$(Filename).msix"
displayName: 'Build msix'
- powershell: |
7z a -tzip "$(Build.ArtifactStagingDirectory)\msix\$(Filename).appxsym" *.pdb
displayName: 'Build appxsym'
workingDirectory: $(Build.BinariesDirectory)\symbols\$(Name)
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: MSIX'
condition: and(succeeded(), or(ne(variables['ShouldSign'], 'true'), not(variables['SigningCertificate'])))
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)\msix'
ArtifactName: msix
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: MSIX'
condition: and(succeeded(), and(eq(variables['ShouldSign'], 'true'), variables['SigningCertificate']))
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)\msix'
ArtifactName: unsigned_msix
- powershell: |
7z a -tzip "$(Build.ArtifactStagingDirectory)\msixupload\$(Filename).msixupload" *
displayName: 'Build msixupload'
condition: and(succeeded(), eq(variables['Upload'], 'true'))
workingDirectory: $(Build.ArtifactStagingDirectory)\msix
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: MSIXUpload'
condition: and(succeeded(), eq(variables['Upload'], 'true'))
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)\msixupload'
ArtifactName: msixupload
- job: Sign_MSIX
displayName: Sign side-loadable MSIX bundles
dependsOn:
- Pack_MSIX
condition: and(succeeded(), variables['SigningCertificate'])
pool:
name: 'Windows Release'
workspace:
clean: all
steps:
- template: ./checkout.yml
- template: ./find-sdk.yml
- powershell: |
$d = (.\PCbuild\build.bat -V) | %{ if($_ -match '\s+(\w+):\s*(.+)\s*$') { @{$Matches[1] = $Matches[2];} }};
Write-Host "##vso[task.setvariable variable=SigningDescription]Python $($d.PythonVersion)"
displayName: 'Update signing description'
condition: and(succeeded(), not(variables['SigningDescription']))
- task: DownloadBuildArtifacts@0
displayName: 'Download Artifact: unsigned_msix'
inputs:
artifactName: unsigned_msix
downloadPath: $(Build.BinariesDirectory)
# MSIX must be signed and timestamped simultaneously
#
# Getting "Error: SignerSign() failed." (-2147024885/0x8007000b)"?
# It may be that the certificate info collected in stage-sign.yml is wrong. Check that
# you do not have multiple matches for the certificate name you have specified.
- powershell: |
$failed = $true
foreach ($retry in 1..3) {
signtool sign /a /n "$(SigningCertificate)" /fd sha256 /tr http://timestamp.digicert.com/ /td sha256 /d "$(SigningDescription)" (gi *.msix)
if ($?) {
$failed = $false
break
}
sleep 1
}
if ($failed) {
throw "Failed to sign MSIX"
}
displayName: 'Sign MSIX'
workingDirectory: $(Build.BinariesDirectory)\unsigned_msix
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: MSIX'
inputs:
PathtoPublish: '$(Build.BinariesDirectory)\unsigned_msix'
ArtifactName: msix

View file

@ -1,66 +0,0 @@
jobs:
- job: Pack_Nuget
displayName: Pack Nuget bundles
condition: and(succeeded(), eq(variables['DoNuget'], 'true'))
pool:
name: 'Windows Release'
workspace:
clean: all
strategy:
matrix:
amd64:
Name: amd64
win32:
Name: win32
arm64:
Name: arm64
steps:
- checkout: none
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: layout_nuget_$(Name)'
inputs:
artifactName: layout_nuget_$(Name)
targetPath: $(Build.BinariesDirectory)\layout
- task: NugetToolInstaller@0
displayName: 'Install Nuget'
inputs:
versionSpec: '>=5.0'
- powershell: >
nuget pack
"$(Build.BinariesDirectory)\layout\python.nuspec"
-OutputDirectory $(Build.ArtifactStagingDirectory)
-NoPackageAnalysis
-NonInteractive
condition: and(succeeded(), not(variables['OverrideNugetVersion']))
displayName: 'Create nuget package'
- powershell: >
nuget pack
"$(Build.BinariesDirectory)\layout\python.nuspec"
-OutputDirectory $(Build.ArtifactStagingDirectory)
-NoPackageAnalysis
-NonInteractive
-Version "$(OverrideNugetVersion)"
condition: and(succeeded(), variables['OverrideNugetVersion'])
displayName: 'Create nuget package'
- powershell: |
gci *.nupkg | %{
nuget sign "$_" -CertificateSubjectName "$(SigningCertificate)" -Timestamper http://timestamp.digicert.com/ -Overwrite
}
displayName: 'Sign nuget package'
workingDirectory: $(Build.ArtifactStagingDirectory)
condition: and(succeeded(), variables['SigningCertificate'])
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: nuget'
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: nuget

View file

@ -1,50 +0,0 @@
parameters:
BuildToPublish: ''
jobs:
- job: Publish_Nuget
displayName: Publish Nuget packages
condition: and(succeeded(), eq(variables['DoNuget'], 'true'), ne(variables['SkipNugetPublish'], 'true'))
pool:
vmImage: windows-2022
workspace:
clean: all
steps:
- checkout: none
- ${{ if parameters.BuildToPublish }}:
- task: DownloadBuildArtifacts@0
displayName: 'Download artifact from ${{ parameters.BuildToPublish }}'
inputs:
artifactName: nuget
downloadPath: $(Build.BinariesDirectory)
buildType: specific
project: $(System.TeamProject)
pipeline: $(Build.DefinitionName)
buildVersionToDownload: specific
buildId: ${{ parameters.BuildToPublish }}
- ${{ else }}:
- task: DownloadBuildArtifacts@0
displayName: 'Download artifact: nuget'
inputs:
artifactName: nuget
downloadPath: $(Build.BinariesDirectory)
- powershell: 'gci pythonarm*.nupkg | %{ Write-Host "Not publishing: $($_.Name)"; gi $_ } | del'
displayName: 'Prevent publishing ARM64 packages'
workingDirectory: '$(Build.BinariesDirectory)\nuget'
condition: and(succeeded(), ne(variables['PublishARM64'], 'true'))
- task: NuGetCommand@2
displayName: Push packages
condition: and(succeeded(), eq(variables['SigningCertificate'], variables['__RealSigningCertificate']))
inputs:
command: push
packagesToPush: '$(Build.BinariesDirectory)\nuget\*.nupkg'
nuGetFeedType: external
publishFeedCredentials: 'Python on Nuget'

View file

@ -1,192 +0,0 @@
parameters:
BuildToPublish: ''
jobs:
- job: Publish_Python
displayName: Publish python.org packages
condition: and(succeeded(), eq(variables['DoMSI'], 'true'), eq(variables['DoEmbed'], 'true'), ne(variables['SkipPythonOrgPublish'], 'true'))
pool:
#vmImage: windows-2022
name: 'Windows Release'
workspace:
clean: all
steps:
- template: ./checkout.yml
- task: UsePythonVersion@0
displayName: 'Use Python 3.6 or later'
inputs:
versionSpec: '>=3.6'
- ${{ if parameters.BuildToPublish }}:
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact from ${{ parameters.BuildToPublish }}: Doc'
inputs:
artifactName: Doc
targetPath: $(Build.BinariesDirectory)\Doc
buildType: specific
project: $(System.TeamProject)
pipeline: $(Build.DefinitionName)
buildVersionToDownload: specific
buildId: ${{ parameters.BuildToPublish }}
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact from ${{ parameters.BuildToPublish }}: msi'
inputs:
artifactName: msi
targetPath: $(Build.BinariesDirectory)\msi
buildType: specific
project: $(System.TeamProject)
pipeline: $(Build.DefinitionName)
buildVersionToDownload: specific
buildId: ${{ parameters.BuildToPublish }}
# Note that embed is a 'build' artifact, not a 'pipeline' artifact
- task: DownloadBuildArtifacts@0
displayName: 'Download artifact from ${{ parameters.BuildToPublish }}: embed'
inputs:
artifactName: embed
downloadPath: $(Build.BinariesDirectory)
buildType: specific
project: $(System.TeamProject)
pipeline: $(Build.DefinitionName)
buildVersionToDownload: specific
buildId: ${{ parameters.BuildToPublish }}
- ${{ else }}:
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: Doc'
inputs:
artifactName: Doc
targetPath: $(Build.BinariesDirectory)\Doc
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: msi'
inputs:
artifactName: msi
targetPath: $(Build.BinariesDirectory)\msi
# Note that embed is a 'build' artifact, not a 'pipeline' artifact
- task: DownloadBuildArtifacts@0
displayName: 'Download artifact: embed'
inputs:
artifactName: embed
downloadPath: $(Build.BinariesDirectory)
# Note that ARM64 MSIs are skipped at build when this option is specified
- powershell: 'gci *embed-arm*.zip | %{ Write-Host "Not publishing: $($_.Name)"; gi $_ } | del'
displayName: 'Prevent publishing ARM64 packages'
workingDirectory: '$(Build.BinariesDirectory)\embed'
condition: and(succeeded(), ne(variables['PublishARM64'], 'true'))
- task: DownloadSecureFile@1
name: gpgkey
inputs:
secureFile: 'python-signing.key'
displayName: 'Download GPG key'
- powershell: |
git clone https://github.com/python/cpython-bin-deps --branch gpg --single-branch --depth 1 --progress -v "gpg"
gpg/gpg2.exe --import "$(gpgkey.secureFilePath)"
$files = gci -File "msi\*\*", "embed\*.zip"
if ("$(DoCHM)" -ieq "true") {
$files = $files + (gci -File "doc\htmlhelp\*.chm")
}
$files.FullName | %{
gpg/gpg2.exe -ba --batch --passphrase $(GPGPassphrase) $_
"Made signature for $_"
}
displayName: 'Generate GPG signatures'
workingDirectory: $(Build.BinariesDirectory)
- powershell: |
$p = gps "gpg-agent" -EA 0
if ($p) { $p.Kill() }
displayName: 'Kill GPG agent'
condition: true
- powershell: >
$(Build.SourcesDirectory)\Tools\msi\uploadrelease.ps1
-build msi
-user $(PyDotOrgUsername)
-server $(PyDotOrgServer)
-doc_htmlhelp doc\htmlhelp
-embed embed
-skippurge
-skiptest
-skiphash
condition: and(succeeded(), eq(variables['SigningCertificate'], variables['__RealSigningCertificate']))
workingDirectory: $(Build.BinariesDirectory)
displayName: 'Upload files to python.org'
- powershell: >
python
"$(Build.SourcesDirectory)\Tools\msi\purge.py"
(gci msi\*\python-*.exe | %{ $_.Name -replace 'python-(.+?)(-|\.exe).+', '$1' } | select -First 1)
workingDirectory: $(Build.BinariesDirectory)
condition: and(succeeded(), eq(variables['SigningCertificate'], variables['__RealSigningCertificate']))
displayName: 'Purge CDN'
- powershell: |
$failures = 0
gci "msi\*\*.exe" -File | %{
$d = mkdir "tests\$($_.BaseName)" -Force
gci $d -r -File | del
$ic = copy $_ $d -PassThru
"Checking layout for $($ic.Name)"
Start-Process -wait $ic "/passive", "/layout", "$d\layout", "/log", "$d\log\install.log"
if (-not $?) {
Write-Error "Failed to validate layout of $($inst.Name)"
$failures += 1
}
}
if ($failures) {
Write-Error "Failed to validate $failures installers"
exit 1
}
condition: and(succeeded(), eq(variables['SigningCertificate'], variables['__RealSigningCertificate']))
workingDirectory: $(Build.BinariesDirectory)
displayName: 'Test layouts'
- powershell: |
$files = gci -File "msi\*\*.exe", "embed\*.zip"
if ("$(DoCHM)" -ieq "true") {
$files = $files + (gci -File "doc\htmlhelp\python*.chm")
}
$hashes = $files | `
Sort-Object Name | `
Format-Table Name, @{
Label="MD5";
Expression={(Get-FileHash $_ -Algorithm MD5).Hash}
}, Length -AutoSize | `
Out-String -Width 4096
$d = mkdir "$(Build.ArtifactStagingDirectory)\hashes" -Force
$hashes | Out-File "$d\hashes.txt" -Encoding ascii
$hashes
workingDirectory: $(Build.BinariesDirectory)
displayName: 'Generate hashes'
- powershell: |
"Copying:"
$files = gci -File "msi\*\python*.asc", "embed\*.asc"
if ("$(DoCHM)" -ieq "true") {
$files = $files + (gci -File "doc\htmlhelp\*.asc")
}
$files.FullName
$d = mkdir "$(Build.ArtifactStagingDirectory)\hashes" -Force
move $files $d -Force
gci msi -Directory | %{ move "msi\$_\*.asc" (mkdir "$d\$_" -Force) }
workingDirectory: $(Build.BinariesDirectory)
displayName: 'Copy GPG signatures for build'
- task: PublishPipelineArtifact@0
displayName: 'Publish Artifact: hashes'
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)\hashes'
artifactName: hashes

View file

@ -1,38 +0,0 @@
parameters:
BuildToPublish: ''
jobs:
- job: Publish_Store
displayName: Publish Store packages
condition: and(succeeded(), eq(variables['DoMSIX'], 'true'), ne(variables['SkipMSIXPublish'], 'true'))
pool:
vmImage: windows-2022
workspace:
clean: all
steps:
- checkout: none
- ${{ if parameters.BuildToPublish }}:
- task: DownloadBuildArtifacts@0
displayName: 'Download artifact: msixupload'
inputs:
artifactName: msixupload
downloadPath: $(Build.BinariesDirectory)
buildType: specific
project: cpython
pipeline: Windows-Release
buildVersionToDownload: specific
buildId: ${{ parameters.BuildToPublish }}
- ${{ else }}:
- task: DownloadBuildArtifacts@0
displayName: 'Download artifact: msixupload'
inputs:
artifactName: msixupload
downloadPath: $(Build.BinariesDirectory)
# TODO: eq(variables['SigningCertificate'], variables['__RealSigningCertificate'])
# If we are not real-signed, DO NOT PUBLISH

View file

@ -1,130 +0,0 @@
parameters:
Include: '*.exe, *.dll, *.pyd, *.cat, *.ps1'
Exclude: 'vcruntime*, libffi*, libcrypto*, libssl*'
jobs:
- job: Sign_Python
displayName: Sign Python binaries
condition: and(succeeded(), variables['SigningCertificate'])
pool:
name: 'Windows Release'
workspace:
clean: all
strategy:
matrix:
win32:
Name: win32
amd64:
Name: amd64
arm64:
Name: arm64
steps:
- template: ./checkout.yml
- template: ./find-sdk.yml
- powershell: |
$d = (.\PCbuild\build.bat -V) | %{ if($_ -match '\s+(\w+):\s*(.+)\s*$') { @{$Matches[1] = $Matches[2];} }};
Write-Host "##vso[task.setvariable variable=SigningDescription]Python $($d.PythonVersion)"
displayName: 'Update signing description'
condition: and(succeeded(), not(variables['SigningDescription']))
- powershell: |
Write-Host "##vso[build.addbuildtag]signed"
displayName: 'Add build tags'
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: unsigned_bin_$(Name)'
inputs:
artifactName: unsigned_bin_$(Name)
targetPath: $(Build.BinariesDirectory)\bin
- powershell: |
copy "$(Build.SourcesDirectory)\Lib\venv\scripts\common\Activate.ps1" .
displayName: 'Copy files from source'
workingDirectory: $(Build.BinariesDirectory)\bin
- powershell: |
$files = (gi ${{ parameters.Include }} -Exclude ${{ parameters.Exclude }})
signtool sign /a /n "$(SigningCertificate)" /fd sha256 /d "$(SigningDescription)" $files
displayName: 'Sign binaries'
workingDirectory: $(Build.BinariesDirectory)\bin
- powershell: |
$files = (gi ${{ parameters.Include }} -Exclude ${{ parameters.Exclude }})
$failed = $true
foreach ($retry in 1..10) {
signtool timestamp /tr http://timestamp.digicert.com/ /td sha256 $files
if ($?) {
$failed = $false
break
}
sleep 5
}
if ($failed) {
Write-Host "##vso[task.logissue type=error]Failed to timestamp files"
}
displayName: 'Timestamp binaries'
workingDirectory: $(Build.BinariesDirectory)\bin
continueOnError: true
- task: PublishPipelineArtifact@0
displayName: 'Publish artifact: bin_$(Name)'
inputs:
targetPath: '$(Build.BinariesDirectory)\bin'
artifactName: bin_$(Name)
- job: Dump_CertInfo
displayName: Capture certificate info
condition: and(succeeded(), variables['SigningCertificate'])
pool:
name: 'Windows Release'
steps:
- checkout: none
- powershell: |
$m = 'CN=$(SigningCertificate)'
$c = ((gci Cert:\CurrentUser\My), (gci Cert:\LocalMachine\My)) | %{ $_ } | `
?{ $_.Subject -match $m -and $_.NotBefore -lt (Get-Date) -and $_.NotAfter -gt (Get-Date) } | `
select -First 1
if (-not $c) {
Write-Host "Failed to find certificate for $(SigningCertificate)"
exit
}
$d = mkdir "$(Build.BinariesDirectory)\tmp" -Force
$cf = "$d\cert.cer"
[IO.File]::WriteAllBytes($cf, $c.Export("Cer"))
$csha = (certutil -dump $cf | sls "Cert Hash\(sha256\): (.+)").Matches.Groups[1].Value
$info = @{ Subject=$c.Subject; SHA256=$csha; }
$d = mkdir "$(Build.BinariesDirectory)\cert" -Force
$info | ConvertTo-JSON -Compress | Out-File -Encoding utf8 "$d\certinfo.json"
displayName: "Extract certificate info"
- task: PublishPipelineArtifact@0
displayName: 'Publish artifact: cert'
inputs:
targetPath: '$(Build.BinariesDirectory)\cert'
artifactName: cert
- job: Mark_Unsigned
displayName: Tag unsigned build
condition: and(succeeded(), not(variables['SigningCertificate']))
pool:
vmImage: windows-2022
steps:
- checkout: none
- powershell: |
Write-Host "##vso[build.addbuildtag]unsigned"
displayName: 'Add build tag'

View file

@ -1,41 +0,0 @@
jobs:
- job: Test_Embed
displayName: Test Embed
condition: and(succeeded(), eq(variables['DoEmbed'], 'true'))
pool:
vmImage: windows-2022
workspace:
clean: all
strategy:
matrix:
win32:
Name: win32
amd64:
Name: amd64
steps:
- checkout: none
- task: DownloadBuildArtifacts@0
displayName: 'Download artifact: embed'
inputs:
artifactName: embed
downloadPath: $(Build.BinariesDirectory)
- powershell: |
$p = gi "$(Build.BinariesDirectory)\embed\python*embed-$(Name).zip"
Expand-Archive -Path $p -DestinationPath "$(Build.BinariesDirectory)\Python"
$p = gi "$(Build.BinariesDirectory)\Python\python.exe"
Write-Host "##vso[task.prependpath]$(Split-Path -Parent $p)"
displayName: 'Install Python and add to PATH'
- script: |
python -c "import sys; print(sys.version)"
displayName: 'Collect version number'
- script: |
python -m site
displayName: 'Collect site'

View file

@ -1,108 +0,0 @@
jobs:
- job: Test_MSI
displayName: Test MSI
pool:
vmImage: windows-2022
workspace:
clean: all
strategy:
matrix:
win32_User:
ExeMatch: 'python-[\dabrc.]+\.exe'
Logs: $(Build.ArtifactStagingDirectory)\logs\win32_User
InstallAllUsers: 0
win32_Machine:
ExeMatch: 'python-[\dabrc.]+\.exe'
Logs: $(Build.ArtifactStagingDirectory)\logs\win32_Machine
InstallAllUsers: 1
amd64_User:
ExeMatch: 'python-[\dabrc.]+-amd64\.exe'
Logs: $(Build.ArtifactStagingDirectory)\logs\amd64_User
InstallAllUsers: 0
amd64_Machine:
ExeMatch: 'python-[\dabrc.]+-amd64\.exe'
Logs: $(Build.ArtifactStagingDirectory)\logs\amd64_Machine
InstallAllUsers: 1
steps:
- checkout: none
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: msi'
inputs:
artifactName: msi
targetPath: $(Build.BinariesDirectory)\msi
- powershell: |
$p = (gci -r *.exe | ?{ $_.Name -match '$(ExeMatch)' } | select -First 1)
Write-Host "##vso[task.setvariable variable=SetupExe]$($p.FullName)"
Write-Host "##vso[task.setvariable variable=SetupExeName]$($p.Name)"
displayName: 'Find installer executable'
workingDirectory: $(Build.BinariesDirectory)\msi
- script: >
"$(SetupExe)"
/passive
/log "$(Logs)\install\log.txt"
TargetDir="$(Build.BinariesDirectory)\Python"
Include_debug=1
Include_symbols=1
InstallAllUsers=$(InstallAllUsers)
displayName: 'Install Python'
- powershell: |
$p = gi "$(Build.BinariesDirectory)\Python\python.exe"
Write-Host "##vso[task.prependpath]$(Split-Path -Parent $p)"
displayName: 'Add test Python to PATH'
- script: |
python -c "import sys; print(sys.version)"
displayName: 'Collect version number'
- script: |
python -m site
displayName: 'Collect site'
- powershell: |
gci -r "${env:PROGRAMDATA}\Microsoft\Windows\Start Menu\Programs\Python*"
displayName: 'Capture per-machine Start Menu items'
- powershell: |
gci -r "${env:APPDATA}\Microsoft\Windows\Start Menu\Programs\Python*"
displayName: 'Capture per-user Start Menu items'
- powershell: |
gci -r "HKLM:\Software\WOW6432Node\Python"
displayName: 'Capture per-machine 32-bit registry'
- powershell: |
gci -r "HKLM:\Software\Python"
displayName: 'Capture per-machine native registry'
- powershell: |
gci -r "HKCU:\Software\Python"
displayName: 'Capture current-user registry'
- script: |
python -m pip install "azure<0.10"
python -m pip uninstall -y azure python-dateutil six
displayName: 'Test (un)install package'
- script: |
python -m test -uall -v test_ttk_guionly test_tk test_idle
displayName: 'Test Tkinter and Idle'
- script: >
"$(SetupExe)"
/passive
/uninstall
/log "$(Logs)\uninstall\log.txt"
displayName: 'Uninstall Python'
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: logs'
condition: true
continueOnError: true
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)\logs'
ArtifactName: msi_testlogs

View file

@ -1,58 +0,0 @@
jobs:
- job: Test_Nuget
displayName: Test Nuget
condition: and(succeeded(), eq(variables['DoNuget'], 'true'))
pool:
vmImage: windows-2022
workspace:
clean: all
strategy:
matrix:
win32:
Package: pythonx86
amd64:
Package: python
steps:
- checkout: none
- task: DownloadBuildArtifacts@0
displayName: 'Download artifact: nuget'
inputs:
artifactName: nuget
downloadPath: $(Build.BinariesDirectory)
- task: NugetToolInstaller@0
inputs:
versionSpec: '>= 5'
- powershell: >
nuget install
$(Package)
-Source "$(Build.BinariesDirectory)\nuget"
-OutputDirectory "$(Build.BinariesDirectory)\install"
-Prerelease
-ExcludeVersion
-NonInteractive
displayName: 'Install Python'
- powershell: |
$p = gi "$(Build.BinariesDirectory)\install\$(Package)\tools\python.exe"
Write-Host "##vso[task.prependpath]$(Split-Path -Parent $p)"
displayName: 'Add test Python to PATH'
- script: |
python -c "import sys; print(sys.version)"
displayName: 'Collect version number'
- script: |
python -m site
displayName: 'Collect site'
- script: |
python -m pip install "azure<0.10"
python -m pip uninstall -y azure python-dateutil six
displayName: 'Test (un)install package'

24
.coveragerc Normal file
View file

@ -0,0 +1,24 @@
[run]
branch = True
[report]
# Regexes for lines to exclude from consideration
exclude_lines =
# Don't complain if non-runnable code isn't run:
if 0:
if __name__ == .__main__.:
raise AssertionError\(
# Empty bodies in protocols or abstract methods
^\s*def [a-zA-Z0-9_]+\(.*\)(\s*->.*)?:\s*\.\.\.(\s*#.*)?$
^\s*\.\.\.(\s*#.*)?$
.*# pragma: no cover
.*# pragma: no branch
# Additions for IDLE:
.*# htest #
if not (_htest or _utest):
if not .*_utest:
if .*_htest:

24
.devcontainer/Dockerfile Normal file
View file

@ -0,0 +1,24 @@
FROM docker.io/library/fedora:40
ENV CC=clang
ENV WASI_SDK_VERSION=21
ENV WASI_SDK_PATH=/opt/wasi-sdk
ENV WASMTIME_HOME=/opt/wasmtime
ENV WASMTIME_VERSION=18.0.3
ENV WASMTIME_CPU_ARCH=x86_64
RUN dnf -y --nodocs --setopt=install_weak_deps=False install /usr/bin/{blurb,clang,curl,git,ln,tar,xz} 'dnf-command(builddep)' && \
dnf -y --nodocs --setopt=install_weak_deps=False builddep python3 && \
dnf -y clean all
RUN mkdir ${WASI_SDK_PATH} && \
curl --location https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VERSION}/wasi-sdk-${WASI_SDK_VERSION}.0-linux.tar.gz | \
tar --strip-components 1 --directory ${WASI_SDK_PATH} --extract --gunzip
RUN mkdir --parents ${WASMTIME_HOME} && \
curl --location "https://github.com/bytecodealliance/wasmtime/releases/download/v${WASMTIME_VERSION}/wasmtime-v${WASMTIME_VERSION}-${WASMTIME_CPU_ARCH}-linux.tar.xz" | \
xz --decompress | \
tar --strip-components 1 --directory ${WASMTIME_HOME} -x && \
ln -s ${WASMTIME_HOME}/wasmtime /usr/local/bin

View file

@ -0,0 +1,88 @@
{
"build": {
"dockerfile": "Dockerfile"
},
"onCreateCommand": [
// Install common tooling.
"dnf",
"install",
"-y",
"which",
"zsh",
"fish",
// For umask fix below.
"/usr/bin/setfacl"
],
"updateContentCommand": {
// Using the shell for `nproc` usage.
"python": "./configure --config-cache --with-pydebug && make -s -j `nproc`",
"docs": [
"make",
"--directory",
"Doc",
"venv",
"html"
]
},
"postCreateCommand": {
// https://github.com/orgs/community/discussions/26026
"umask fix: workspace": ["sudo", "setfacl", "-bnR", "."],
"umask fix: /tmp": ["sudo", "setfacl", "-bnR", "/tmp"]
},
"customizations": {
"vscode": {
"extensions": [
// Highlighting for Parser/Python.asdl.
"brettcannon.zephyr-asdl",
// Highlighting for configure.ac.
"maelvalais.autoconf",
// C auto-complete.
"ms-vscode.cpptools",
// To view HTML build of docs.
"ms-vscode.live-server",
// Python auto-complete.
"ms-python.python"
],
"settings": {
"C_Cpp.default.compilerPath": "/usr/bin/clang",
"C_Cpp.default.cStandard": "c11",
"C_Cpp.default.defines": [
"CONFIG_64",
"Py_BUILD_CORE"
],
"C_Cpp.default.includePath": [
"${workspaceFolder}/*",
"${workspaceFolder}/Include/**"
],
// https://github.com/microsoft/vscode-cpptools/issues/10732
"C_Cpp.errorSquiggles": "disabled",
"editor.insertSpaces": true,
"editor.rulers": [
80
],
"editor.tabSize": 4,
"editor.trimAutoWhitespace": true,
"files.associations": {
"*.h": "c"
},
"files.encoding": "utf8",
"files.eol": "\n",
"files.insertFinalNewline": true,
"files.trimTrailingWhitespace": true,
"python.analysis.diagnosticSeverityOverrides": {
// Complains about shadowing the stdlib w/ the stdlib.
"reportShadowedImports": "none",
// Doesn't like _frozen_importlib.
"reportMissingImports": "none"
},
"python.analysis.extraPaths": [
"Lib"
],
"python.defaultInterpreterPath": "./python",
"[restructuredtext]": {
"editor.tabSize": 3
}
}
}
}
}

View file

@ -1,6 +1,6 @@
root = true
[*.{py,c,cpp,h,rst,md,yml}]
[*.{py,c,cpp,h,js,rst,md,yml}]
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
@ -8,5 +8,8 @@ indent_style = space
[*.{py,c,cpp,h}]
indent_size = 4
[*.yml]
[*.rst]
indent_size = 3
[*.{js,yml}]
indent_size = 2

71
.gitattributes vendored
View file

@ -18,20 +18,23 @@
*.zip binary
# Specific binary files
Lib/test/sndhdrdata/sndhdr.* binary
PC/classicAppCompat.* binary
# Text files that should not be subject to eol conversion
[attr]noeol -text
Lib/test/cjkencodings/* noeol
Lib/test/coding20731.py noeol
Lib/test/tokenizedata/coding20731.py noeol
Lib/test/decimaltestdata/*.decTest noeol
Lib/test/test_email/data/*.txt noeol
Lib/test/test_importlib/data01/* noeol
Lib/test/test_importlib/namespacedata01/* noeol
Lib/test/test_importlib/resources/data01/* noeol
Lib/test/test_importlib/resources/namespacedata01/* noeol
Lib/test/xmltestdata/* noeol
# Shell scripts should have LF even on Windows because of Cygwin
Lib/venv/scripts/common/activate text eol=lf
Lib/venv/scripts/posix/* text eol=lf
# CRLF files
[attr]dos text eol=crlf
@ -62,25 +65,41 @@ PCbuild/readme.txt dos
#
[attr]generated linguist-generated=true diff=generated
**/clinic/*.c.h generated
*_db.h generated
Doc/data/stable_abi.dat generated
Doc/library/token-list.inc generated
Include/internal/pycore_ast.h generated
Include/internal/pycore_ast_state.h generated
Include/opcode.h generated
Include/token.h generated
Lib/keyword.py generated
Lib/test/test_stable_abi_ctypes.py generated
Lib/token.py generated
Objects/typeslots.inc generated
PC/python3dll.c generated
Parser/parser.c generated
Parser/token.c generated
Programs/test_frozenmain.h generated
Python/Python-ast.c generated
Python/opcode_targets.h generated
Python/stdlib_module_names.h generated
Tools/peg_generator/pegen/grammar_parser.py generated
aclocal.m4 generated
configure generated
**/clinic/*.c.h generated
**/clinic/*.cpp.h generated
**/clinic/*.h.h generated
*_db.h generated
Doc/data/stable_abi.dat generated
Doc/library/token-list.inc generated
Include/internal/pycore_ast.h generated
Include/internal/pycore_ast_state.h generated
Include/internal/pycore_opcode.h generated
Include/internal/pycore_opcode_metadata.h generated
Include/internal/pycore_*_generated.h generated
Include/internal/pycore_uop_ids.h generated
Include/internal/pycore_uop_metadata.h generated
Include/opcode.h generated
Include/opcode_ids.h generated
Include/token.h generated
Lib/_opcode_metadata.py generated
Lib/keyword.py generated
Lib/test/certdata/*.pem generated
Lib/test/certdata/*.0 generated
Lib/test/levenshtein_examples.json generated
Lib/test/test_stable_abi_ctypes.py generated
Lib/token.py generated
Misc/sbom.spdx.json generated
Objects/typeslots.inc generated
PC/python3dll.c generated
Parser/parser.c generated
Parser/token.c generated
Programs/test_frozenmain.h generated
Python/Python-ast.c generated
Python/executor_cases.c.h generated
Python/generated_cases.c.h generated
Python/optimizer_cases.c.h generated
Python/opcode_targets.h generated
Python/stdlib_module_names.h generated
Tools/peg_generator/pegen/grammar_parser.py generated
aclocal.m4 generated
configure generated

169
.github/CODEOWNERS vendored
View file

@ -4,24 +4,72 @@
# It uses the same pattern rule for gitignore file
# https://git-scm.com/docs/gitignore#_pattern_format
# GitHub
.github/** @ezio-melotti @hugovk
# pre-commit
.pre-commit-config.yaml @hugovk @AlexWaygood
.ruff.toml @hugovk @AlexWaygood
# Build system
configure* @erlend-aasland @corona10
# asyncio
**/*asyncio* @1st1 @asvetlov
**/*asyncio* @1st1 @asvetlov @gvanrossum @kumaraditya303 @willingc
# Core
**/*context* @1st1
**/*genobject* @1st1 @markshannon
**/*genobject* @markshannon
**/*hamt* @1st1
**/*jit* @brandtbucher
Objects/set* @rhettinger
Objects/dict* @methane @markshannon
Objects/typevarobject.c @JelleZijlstra
Objects/type* @markshannon
Objects/codeobject.c @markshannon
Objects/frameobject.c @markshannon
Objects/call.c @markshannon
Python/ceval.c @markshannon
Python/compile.c @markshannon
Python/ceval*.c @markshannon @gvanrossum
Python/ceval*.h @markshannon @gvanrossum
Python/compile.c @markshannon @iritkatriel
Python/assemble.c @markshannon @iritkatriel
Python/flowgraph.c @markshannon @iritkatriel
Python/ast_opt.c @isidentical
Python/bytecodes.c @markshannon @gvanrossum
Python/optimizer*.c @markshannon @gvanrossum
Python/optimizer_analysis.c @Fidget-Spinner
Python/optimizer_bytecodes.c @Fidget-Spinner
Lib/test/test_patma.py @brandtbucher
Lib/test/test_peepholer.py @brandtbucher
Lib/test/test_type_*.py @JelleZijlstra
Lib/test/test_capi/test_misc.py @markshannon @gvanrossum
Tools/c-analyzer/ @ericsnowcurrently
# dbm
**/*dbm* @corona10 @erlend-aasland @serhiy-storchaka
# runtime state/lifecycle
**/*pylifecycle* @ericsnowcurrently
**/*pystate* @ericsnowcurrently
**/*preconfig* @ericsnowcurrently
**/*initconfig* @ericsnowcurrently
**/*pathconfig* @ericsnowcurrently
**/*sysmodule* @ericsnowcurrently
**/*bltinmodule* @ericsnowcurrently
**/*gil* @ericsnowcurrently
Include/internal/pycore_runtime.h @ericsnowcurrently
Include/internal/pycore_interp.h @ericsnowcurrently
Include/internal/pycore_tstate.h @ericsnowcurrently
Include/internal/pycore_*_state.h @ericsnowcurrently
Include/internal/pycore_*_init.h @ericsnowcurrently
Include/internal/pycore_atexit.h @ericsnowcurrently
Include/internal/pycore_freelist.h @ericsnowcurrently
Include/internal/pycore_global_objects.h @ericsnowcurrently
Include/internal/pycore_obmalloc.h @ericsnowcurrently
Include/internal/pycore_pymem.h @ericsnowcurrently
Modules/main.c @ericsnowcurrently
Programs/_bootstrap_python.c @ericsnowcurrently
Programs/python.c @ericsnowcurrently
Tools/build/generate_global_objects.py @ericsnowcurrently
# Exceptions
Lib/traceback.py @iritkatriel
@ -29,16 +77,15 @@ Lib/test/test_except*.py @iritkatriel
Lib/test/test_traceback.py @iritkatriel
Objects/exceptions.c @iritkatriel
Python/traceback.c @iritkatriel
Python/pythonrun.c @iritkatriel
# Hashing
**/*hashlib* @tiran
**/*pyhash* @tiran
**/*sha* @tiran
**/*md5* @tiran
**/*blake* @tiran
/Modules/_blake2/** @tiran
/Modules/_sha3/** @tiran
**/*hashlib* @gpshead @tiran
**/*pyhash* @gpshead @tiran
**/sha* @gpshead @tiran
Modules/md5* @gpshead @tiran
**/*blake* @gpshead @tiran
Modules/_blake2/** @gpshead @tiran
Modules/_hacl/** @gpshead
# logging
**/*logging* @vsajip
@ -53,13 +100,26 @@ Python/pythonrun.c @iritkatriel
/Lib/html/ @ezio-melotti
/Lib/_markupbase.py @ezio-melotti
/Lib/test/test_html*.py @ezio-melotti
/Tools/build/parse_html5_entities.py @ezio-melotti
# Import (including importlib).
# Ignoring importlib.h so as to not get flagged on
# all pull requests that change the emitted
# bytecode.
**/*import*.c @brettcannon @encukou @ericsnowcurrently @ncoghlan @warsaw
**/*import*.py @brettcannon @encukou @ericsnowcurrently @ncoghlan @warsaw
**/*import* @brettcannon @ericsnowcurrently @ncoghlan @warsaw
/Python/import.c @kumaraditya303
Python/dynload_*.c @ericsnowcurrently
**/*freeze* @ericsnowcurrently
**/*frozen* @ericsnowcurrently
**/*modsupport* @ericsnowcurrently
**/*modulefinder* @ericsnowcurrently
**/*moduleobject* @ericsnowcurrently
**/*multiphase* @ericsnowcurrently
**/*pkgutil* @ericsnowcurrently
**/*pythonrun* @ericsnowcurrently
**/*runpy* @ericsnowcurrently
**/*singlephase* @ericsnowcurrently
Lib/test/test_module/ @ericsnowcurrently
Doc/c-api/module.rst @ericsnowcurrently
**/*importlib/resources/* @jaraco @warsaw @FFY00
**/*importlib/metadata/* @jaraco @warsaw
# Dates and times
**/*datetime* @pganssle @abalkin
@ -68,7 +128,7 @@ Doc/library/time.rst @pganssle @abalkin
Lib/test/test_time.py @pganssle @abalkin
Modules/timemodule.c @pganssle @abalkin
Python/pytime.c @pganssle @abalkin
Include/pytime.h @pganssle @abalkin
Include/internal/pycore_time.h @pganssle @abalkin
# Email and related
**/*mail* @python/email-team
@ -86,6 +146,11 @@ Include/pytime.h @pganssle @abalkin
/Tools/peg_generator/ @pablogsal @lysnikolaou
/Lib/test/test_peg_generator/ @pablogsal @lysnikolaou
/Grammar/python.gram @pablogsal @lysnikolaou
/Lib/tokenize.py @pablogsal @lysnikolaou
/Lib/test/test_tokenize.py @pablogsal @lysnikolaou
# Code generator
/Tools/cases_generator/ @gvanrossum
# AST
Python/ast.c @isidentical
@ -95,16 +160,25 @@ Lib/ast.py @isidentical
# Mock
/Lib/unittest/mock.py @cjw296
/Lib/unittest/test/testmock/* @cjw296
/Lib/test/test_unittest/testmock/* @cjw296
# multiprocessing
**/*multiprocessing* @gpshead
# SQLite 3
**/*sqlite* @berkerpeksag
**/*sqlite* @berkerpeksag @erlend-aasland
# subprocess
/Lib/subprocess.py @gpshead
/Lib/test/test_subprocess.py @gpshead
/Modules/*subprocess* @gpshead
# Limited C API & stable ABI
Tools/build/stable_abi.py @encukou
Misc/stable_abi.toml @encukou
Doc/data/*.abi @encukou
Doc/c-api/stable.rst @encukou
# Windows
/PC/ @python/windows-team
/PCbuild/ @python/windows-team
@ -128,12 +202,12 @@ Lib/ast.py @isidentical
**/*dataclasses* @ericvsmith
**/*ensurepip* @pfmoore @pradyunsg
**/*idlelib* @terryjreedy
**/*typing* @gvanrossum @Fidget-Spinner @JelleZijlstra
**/*typing* @JelleZijlstra @AlexWaygood
**/*asyncore @giampaolo
**/*asynchat @giampaolo
**/*ftplib @giampaolo
**/*shutil @giampaolo
@ -141,11 +215,54 @@ Lib/ast.py @isidentical
**/*cgi* @ethanfurman
**/*tarfile* @ethanfurman
**/*tomllib* @encukou
**/*tomllib* @encukou @hauntsaninja
**/*sysconfig* @FFY00
**/*cjkcodecs* @corona10
# macOS
/Mac/ @python/macos-team
**/*osx_support* @python/macos-team
# pathlib
**/*pathlib* @brettcannon
**/*pathlib* @barneygale
# zipfile.Path
**/*zipfile/_path/* @jaraco
# Argument Clinic
/Tools/clinic/** @erlend-aasland
/Lib/test/test_clinic.py @erlend-aasland
Doc/howto/clinic.rst @erlend-aasland
# Subinterpreters
**/*interpreteridobject.* @ericsnowcurrently
**/*crossinterp* @ericsnowcurrently
Lib/test/support/interpreters/ @ericsnowcurrently
Modules/_xx*interp*module.c @ericsnowcurrently
Lib/test/test_interpreters/ @ericsnowcurrently
# Android
**/*Android* @mhsmith
**/*android* @mhsmith
# iOS (but not termios)
**/iOS* @freakboy3742
**/ios* @freakboy3742
**/*_iOS* @freakboy3742
**/*_ios* @freakboy3742
**/*-iOS* @freakboy3742
**/*-ios* @freakboy3742
# WebAssembly
/Tools/wasm/ @brettcannon
# SBOM
/Misc/externals.spdx.json @sethmlarson
/Misc/sbom.spdx.json @sethmlarson
/Tools/build/generate_sbom.py @sethmlarson
# Config Parser
Lib/configparser.py @jaraco
Lib/test/test_configparser.py @jaraco

View file

@ -4,21 +4,9 @@ Contributing to Python
Build Status
------------
- main
- `Buildbot status overview <https://buildbot.python.org/all/#/release_status>`_
+ `Stable buildbots <http://buildbot.python.org/3.x.stable/>`_
- 3.9
+ `Stable buildbots <http://buildbot.python.org/3.9.stable/>`_
- 3.8
+ `Stable buildbots <http://buildbot.python.org/3.8.stable/>`_
- 3.7
+ `Stable buildbots <http://buildbot.python.org/3.7.stable/>`_
- `GitHub Actions status <https://github.com/python/cpython/actions/workflows/build.yml>`_
Thank You
@ -38,7 +26,7 @@ also suggestions on how you can most effectively help the project.
Please be aware that our workflow does deviate slightly from the typical GitHub
project. Details on how to properly submit a pull request are covered in
`Lifecycle of a Pull Request <https://devguide.python.org/pullrequest/>`_.
`Lifecycle of a Pull Request <https://devguide.python.org/getting-started/pull-request-lifecycle.html>`_.
We utilize various bots and status checks to help with this, so do follow the
comments they leave and their "Details" links, respectively. The key points of
our workflow that are not covered by a bot or status check are:

View file

@ -1,32 +0,0 @@
---
name: Bug report
about: Submit a bug report
labels: "type-bug"
---
<!--
If you're new to Python and you're not sure whether what you're experiencing is a bug, the CPython issue tracker is not
the right place to seek help. Consider the following options instead:
- reading the Python tutorial: https://docs.python.org/3/tutorial/
- posting in the "Users" category on discuss.python.org: https://discuss.python.org/c/users/7
- emailing the Python-list mailing list: https://mail.python.org/mailman/listinfo/python-list
- searching our issue tracker (https://github.com/python/cpython/issues) to see if
your problem has already been reported
-->
**Bug report**
A clear and concise description of what the bug is.
Include a minimal, reproducible example (https://stackoverflow.com/help/minimal-reproducible-example), if possible.
**Your environment**
<!-- Include as many relevant details as possible about the environment you experienced the bug in -->
- CPython versions tested on:
- Operating system and architecture:
<!--
You can freely edit this text. Remove any lines you believe are unnecessary.
-->

56
.github/ISSUE_TEMPLATE/bug.yml vendored Normal file
View file

@ -0,0 +1,56 @@
name: Bug report
description: Submit a bug report
labels: ["type-bug"]
body:
- type: markdown
attributes:
value: |
**New to Python?**
For help or advice on using Python, try one of the following options instead of opening a GitHub issue:
- Asking on [Discourse](https://discuss.python.org/c/users/7) or [Stack Overflow](https://stackoverflow.com)
- Reading the [Python tutorial](https://docs.python.org/3/tutorial/)
- Emailing [python-list](https://mail.python.org/mailman/listinfo/python-list)
Make sure to also search the [CPython issue tracker](https://github.com/python/cpython/issues?q=is%3Aissue+sort%3Acreated-desc) to check that the bug has not already been reported.
- type: textarea
attributes:
label: "Bug description:"
description: >
Give a clear and concise description of what happened.
Include a [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) if possible.
[Copy and paste code where possible rather than using screenshots](https://meta.stackoverflow.com/a/285557/13990016),
and put any code blocks inside triple backticks.
value: |
```python
# Add a code block here, if required
```
validations:
required: true
- type: dropdown
attributes:
label: "CPython versions tested on:"
multiple: true
options:
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "3.12"
- "3.13"
- "CPython main branch"
validations:
required: true
- type: dropdown
attributes:
label: "Operating systems tested on:"
multiple: true
options:
- Linux
- macOS
- Windows
- Other
validations:
required: false

View file

@ -1,33 +0,0 @@
---
name: Crash report
about: A hard crash of the interpreter, possibly with a core dump
labels: "type-crash"
---
<!--
Use this template for hard crashes of the interpreter, segmentation faults, failed C-level assertions, and similar.
Do not submit this form if you encounter an exception being unexpectedly raised from a Python function.
Most of the time, these should be filed as bugs, rather than crashes.
The CPython interpreter is itself written in a different programming language, C.
For CPython, a "crash" is when Python itself fails, leading to a traceback in the C stack.
-->
**Crash report**
Tell us what happened, ideally including a minimal, reproducible example (https://stackoverflow.com/help/minimal-reproducible-example).
**Error messages**
Enter any relevant error message caused by the crash, including a core dump if there is one.
**Your environment**
<!-- Include as many relevant details as possible about the environment you experienced the bug in -->
- CPython versions tested on:
- Operating system and architecture:
<!--
You can freely edit this text. Remove any lines you believe are unnecessary.
-->

54
.github/ISSUE_TEMPLATE/crash.yml vendored Normal file
View file

@ -0,0 +1,54 @@
name: Crash report
description: A hard crash of the interpreter, possibly with a core dump
labels: ["type-crash"]
body:
- type: markdown
attributes:
value: |
This form is for hard crashes of the Python interpreter, segmentation faults, failed C-level assertions, and similar. Unexpected exceptions raised from Python functions in the standard library count as bugs rather than crashes.
The CPython interpreter is written in a different programming language, C. A "CPython crash" is when Python itself fails, leading to a traceback in the C stack.
- type: textarea
attributes:
label: What happened?
description: >
Include a [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) if possible.
[Copy and paste code where possible rather than using screenshots](https://meta.stackoverflow.com/a/285557/13990016),
and put any code blocks inside triple backticks.
value: |
```python
# Add a code block here, if required
```
validations:
required: true
- type: dropdown
attributes:
label: "CPython versions tested on:"
multiple: true
options:
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "3.12"
- "CPython main branch"
validations:
required: true
- type: dropdown
attributes:
label: "Operating systems tested on:"
multiple: true
options:
- Linux
- macOS
- Windows
- Other
validations:
required: false
- type: input
attributes:
label: "Output from running 'python -VV' on the command line:"
description: If you tested with multiple operating systems or architectures, feel free to provide details in the main bug description.
validations:
required: false

View file

@ -4,6 +4,6 @@ about: Report a problem with the documentation
labels: "docs"
---
**Documentation**
# Documentation
(A clear and concise description of the issue.)

View file

@ -1,28 +0,0 @@
---
name: Feature or enhancement
about: Submit a proposal for a new CPython feature or enhancement
labels: "type-feature"
---
**Feature or enhancement**
(A clear and concise description of your proposal.)
**Pitch**
(Explain why this feature or enhacement should be implemented and how it would be used.
Add examples, if applicable.)
**Previous discussion**
<!--
New features to Python should first be discussed elsewhere before creating issues on GitHub,
for example in the "ideas" category (https://discuss.python.org/c/ideas/6) of discuss.python.org,
or the python-ideas mailing list (https://mail.python.org/mailman3/lists/python-ideas.python.org/).
Use this space to post links to the places where you have already discussed this feature proposal:
-->
<!--
You can freely edit this text. Remove any lines you believe are unnecessary.
-->

40
.github/ISSUE_TEMPLATE/feature.yml vendored Normal file
View file

@ -0,0 +1,40 @@
name: Feature or enhancement
description: Submit a proposal for a new CPython feature or enhancement
labels: ["type-feature"]
body:
- type: markdown
attributes:
value: |
# Proposing a feature to CPython?
You'll need to demonstrate widespread support for your idea among the community.
Major feature proposals should generally be discussed on [Discourse](https://discuss.python.org/c/ideas/6) before opening a GitHub issue. Wait until it's clear that most people support your idea before filling in this form.
- type: textarea
attributes:
label: "Proposal:"
description: >
Explain your proposal, why it should be implemented, and how it would be used.
Add examples, if applicable.
Put any code blocks inside triple backticks.
value: |
```python
# Add a code block here, if required
```
validations:
required: true
- type: dropdown
attributes:
label: Has this already been discussed elsewhere?
options:
- No response given
- I have already discussed this feature proposal on Discourse
- This is a minor feature, which does not need previous discussion elsewhere
multiple: false
validations:
required: true
- type: textarea
attributes:
label: "Links to previous discussion of this feature:"
validations:
required: false

2
.github/SECURITY.md vendored
View file

@ -4,7 +4,7 @@
The Python team applies security fixes according to the table
in [the devguide](
https://devguide.python.org/#status-of-python-branches
https://devguide.python.org/versions/#supported-versions
).
## Reporting a Vulnerability

View file

@ -7,3 +7,15 @@ updates:
labels:
- "skip issue"
- "skip news"
ignore:
- dependency-name: "*"
update-types:
- "version-update:semver-minor"
- "version-update:semver-patch"
- package-ecosystem: "pip"
directory: "/Tools/"
schedule:
interval: "monthly"
labels:
- "skip issue"
- "skip news"

View file

@ -1,40 +0,0 @@
{
"problemMatcher": [
{
"owner": "sphinx-problem-matcher",
"pattern": [
{
"regexp": "^(.*):(\\d+):\\s+(\\w*):\\s+(.*)$",
"file": 1,
"line": 2,
"severity": 3,
"message": 4
}
]
},
{
"owner": "sphinx-problem-matcher-loose",
"pattern": [
{
"_comment": "A bit of a looser pattern, doesn't look for line numbers, just looks for file names relying on them to start with / and end with .rst",
"regexp": "(\/.*\\.rst):\\s+(\\w*):\\s+(.*)$",
"file": 1,
"severity": 2,
"message": 3
}
]
},
{
"owner": "sphinx-problem-matcher-loose-no-severity",
"pattern": [
{
"_comment": "Looks for file names ending with .rst and line numbers but without severity",
"regexp": "^(.*\\.rst):(\\d+):(.*)$",
"file": 1,
"line": 2,
"message": 3
}
]
}
]
}

53
.github/workflows/add-issue-header.yml vendored Normal file
View file

@ -0,0 +1,53 @@
name: Add issue header
# Automatically edits an issue's descriptions with a header,
# one of:
#
# - Bug report
# - Crash report
# - Feature or enhancement
on:
issues:
types:
# Only ever run once
- opened
jobs:
add-header:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- uses: actions/github-script@v7
with:
# language=JavaScript
script: |
// https://devguide.python.org/triage/labels/#type-labels
const HEADERS = new Map([
['type-bug', 'Bug report'],
['type-crash', 'Crash report'],
['type-feature', 'Feature or enhancement'],
]);
let issue_data = await github.rest.issues.get({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo
}).then(issue => issue.data);
let header = '';
for (const label_data of issue_data.labels) {
const label_name = (typeof label_data === 'string') ? label_data : label_data.name;
if (HEADERS.has(label_name)) {
header = HEADERS.get(label_name);
break;
}
}
if (header !== '') {
console.log(`Setting new header: ${header}`);
await github.rest.issues.update({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `# ${header}\n\n${issue_data.body.replaceAll('\r', '')}`
});
}

View file

@ -8,33 +8,37 @@ on:
push:
branches:
- 'main'
- '3.10'
- '3.9'
- '3.8'
- '3.7'
- '3.*'
pull_request:
branches:
- 'main'
- '3.10'
- '3.9'
- '3.8'
- '3.7'
- '3.*'
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}-reusable
cancel-in-progress: true
jobs:
check_source:
name: 'Check for source changes'
runs-on: ubuntu-latest
timeout-minutes: 10
outputs:
run-docs: ${{ steps.docs-changes.outputs.run-docs || false }}
run_tests: ${{ steps.check.outputs.run_tests }}
run_ssl_tests: ${{ steps.check.outputs.run_ssl_tests }}
run_hypothesis: ${{ steps.check.outputs.run_hypothesis }}
run_cifuzz: ${{ steps.check.outputs.run_cifuzz }}
config_hash: ${{ steps.config_hash.outputs.hash }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Check for source changes
id: check
run: |
if [ -z "$GITHUB_BASE_REF" ]; then
echo '::set-output name=run_tests::true'
echo '::set-output name=run_ssl_tests::true'
echo "run_tests=true" >> $GITHUB_OUTPUT
else
git fetch origin $GITHUB_BASE_REF --depth=1
# git diff "origin/$GITHUB_BASE_REF..." (3 dots) may be more
@ -50,43 +54,108 @@ jobs:
# into the PR branch anyway.
#
# https://github.com/python/core-workflow/issues/373
git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qvE '(\.rst$|^Doc|^Misc)' && echo '::set-output name=run_tests::true' || true
git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qE '(ssl|hashlib|hmac|^.github)' && echo '::set-output name=run_ssl_tests::true' || true
git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qvE '(\.rst$|^Doc|^Misc|^\.pre-commit-config\.yaml$|\.ruff\.toml$)' && echo "run_tests=true" >> $GITHUB_OUTPUT || true
fi
# Check if we should run hypothesis tests
GIT_BRANCH=${GITHUB_BASE_REF:-${GITHUB_REF#refs/heads/}}
echo $GIT_BRANCH
if $(echo "$GIT_BRANCH" | grep -q -w '3\.\(8\|9\|10\|11\)'); then
echo "Branch too old for hypothesis tests"
echo "run_hypothesis=false" >> $GITHUB_OUTPUT
else
echo "Run hypothesis tests"
echo "run_hypothesis=true" >> $GITHUB_OUTPUT
fi
# oss-fuzz maintains a configuration for fuzzing the main branch of
# CPython, so CIFuzz should be run only for code that is likely to be
# merged into the main branch; compatibility with older branches may
# be broken.
FUZZ_RELEVANT_FILES='(\.c$|\.h$|\.cpp$|^configure$|^\.github/workflows/build\.yml$|^Modules/_xxtestfuzz)'
if [ "$GITHUB_BASE_REF" = "main" ] && [ "$(git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qE $FUZZ_RELEVANT_FILES; echo $?)" -eq 0 ]; then
# The tests are pretty slow so they are executed only for PRs
# changing relevant files.
echo "Run CIFuzz tests"
echo "run_cifuzz=true" >> $GITHUB_OUTPUT
else
echo "Branch too old for CIFuzz tests; or no C files were changed"
echo "run_cifuzz=false" >> $GITHUB_OUTPUT
fi
- name: Compute hash for config cache key
id: config_hash
run: |
echo "hash=${{ hashFiles('configure', 'configure.ac', '.github/workflows/build.yml') }}" >> $GITHUB_OUTPUT
- name: Get a list of the changed documentation-related files
if: github.event_name == 'pull_request'
id: changed-docs-files
uses: Ana06/get-changed-files@v2.3.0
with:
filter: |
Doc/**
Misc/**
.github/workflows/reusable-docs.yml
format: csv # works for paths with spaces
- name: Check for docs changes
if: >-
github.event_name == 'pull_request'
&& steps.changed-docs-files.outputs.added_modified_renamed != ''
id: docs-changes
run: |
echo "run-docs=true" >> "${GITHUB_OUTPUT}"
check-docs:
name: Docs
needs: check_source
if: fromJSON(needs.check_source.outputs.run-docs)
uses: ./.github/workflows/reusable-docs.yml
check_generated_files:
name: 'Check if generated files are up to date'
runs-on: ubuntu-latest
# Don't use ubuntu-latest but a specific version to make the job
# reproducible: to get the same tools versions (autoconf, aclocal, ...)
runs-on: ubuntu-22.04
timeout-minutes: 60
needs: check_source
if: needs.check_source.outputs.run_tests == 'true'
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Runner image version
run: echo "IMAGE_VERSION=${ImageVersion}" >> $GITHUB_ENV
- name: Restore config.cache
uses: actions/cache@v4
with:
path: config.cache
# Include env.pythonLocation in key to avoid changes in environment when setup-python updates Python
key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-${{ needs.check_source.outputs.config_hash }}-${{ env.pythonLocation }}
- name: Install Dependencies
run: sudo ./.github/workflows/posix-deps-apt.sh
- name: Add ccache to PATH
run: echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV
- name: Configure ccache action
uses: hendrikmuhs/ccache-action@v1
- name: Check Autoconf version 2.69 and aclocal 1.16.3
uses: hendrikmuhs/ccache-action@v1.2
with:
save: false
- name: Check Autoconf and aclocal versions
run: |
grep "Generated by GNU Autoconf 2.69" configure
grep "aclocal 1.16.3" aclocal.m4
grep "Generated by GNU Autoconf 2.71" configure
grep "aclocal 1.16.5" aclocal.m4
grep -q "runstatedir" configure
grep -q "PKG_PROG_PKG_CONFIG" aclocal.m4
- name: Configure CPython
run: |
# Build Python with the libpython dynamic library
./configure --with-pydebug --enable-shared
- name: Regenerate autoconf files with container image
run: make regen-configure
./configure --config-cache --with-pydebug --enable-shared
- name: Regenerate autoconf files
# Same command used by Tools/build/regen-configure.sh ($AUTORECONF)
run: autoreconf -ivf -Werror
- name: Build CPython
run: |
# Deepfreeze will usually cause global objects to be added or removed,
# so we run it before regen-global-objects gets rum (in regen-all).
make regen-deepfreeze
make -j4 regen-all
make regen-stdlib-module-names
make regen-stdlib-module-names regen-sbom
- name: Check for changes
run: |
git add -u
@ -105,75 +174,96 @@ jobs:
run: make smelly
- name: Check limited ABI symbols
run: make check-limited-abi
- name: Check for unsupported C global variables
if: github.event_name == 'pull_request' # $GITHUB_EVENT_NAME
run: make check-c-globals
build_win32:
name: 'Windows (x86)'
runs-on: windows-latest
build_windows:
name: 'Windows'
needs: check_source
if: needs.check_source.outputs.run_tests == 'true'
env:
IncludeUwp: 'true'
steps:
- uses: actions/checkout@v2
- name: Build CPython
run: .\PCbuild\build.bat -e -d -p Win32
timeout-minutes: 30
- name: Display build info
run: .\python.bat -m test.pythoninfo
- name: Tests
run: .\PCbuild\rt.bat -p Win32 -d -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0
uses: ./.github/workflows/reusable-windows.yml
build_win_amd64:
name: 'Windows (x64)'
runs-on: windows-latest
build_windows_free_threading:
name: 'Windows (free-threading)'
needs: check_source
if: needs.check_source.outputs.run_tests == 'true'
env:
IncludeUwp: 'true'
steps:
- uses: actions/checkout@v2
- name: Register MSVC problem matcher
run: echo "::add-matcher::.github/problem-matchers/msvc.json"
- name: Build CPython
run: .\PCbuild\build.bat -e -d -p x64
timeout-minutes: 30
- name: Display build info
run: .\python.bat -m test.pythoninfo
- name: Tests
run: .\PCbuild\rt.bat -p x64 -d -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0
uses: ./.github/workflows/reusable-windows.yml
with:
free-threading: true
build_macos:
name: 'macOS'
runs-on: macos-latest
needs: check_source
if: needs.check_source.outputs.run_tests == 'true'
env:
PYTHONSTRICTEXTENSIONBUILD: 1
steps:
- uses: actions/checkout@v2
- name: Prepare homebrew environment variables
run: |
echo "LDFLAGS=-L$(brew --prefix tcl-tk)/lib" >> $GITHUB_ENV
echo "PKG_CONFIG_PATH=$(brew --prefix openssl@1.1)/lib/pkgconfig:$(brew --prefix tcl-tk)/lib/pkgconfig" >> $GITHUB_ENV
- name: Configure CPython
run: ./configure --with-pydebug --prefix=/opt/python-dev
- name: Build CPython
run: make -j4
- name: Display build info
run: make pythoninfo
- name: Tests
run: make buildbottest TESTOPTS="-j4 -uall,-cpu"
uses: ./.github/workflows/reusable-macos.yml
with:
config_hash: ${{ needs.check_source.outputs.config_hash }}
# macos-14 is M1, macos-13 is Intel
os-matrix: '["macos-14", "macos-13"]'
build_macos_free_threading:
name: 'macOS (free-threading)'
needs: check_source
if: needs.check_source.outputs.run_tests == 'true'
uses: ./.github/workflows/reusable-macos.yml
with:
config_hash: ${{ needs.check_source.outputs.config_hash }}
free-threading: true
# macos-14-large is Intel with 12 cores (most parallelism)
os-matrix: '["macos-14"]'
build_ubuntu:
name: 'Ubuntu'
runs-on: ubuntu-20.04
needs: check_source
if: needs.check_source.outputs.run_tests == 'true'
uses: ./.github/workflows/reusable-ubuntu.yml
with:
config_hash: ${{ needs.check_source.outputs.config_hash }}
options: |
../cpython-ro-srcdir/configure \
--config-cache \
--with-pydebug \
--with-openssl=$OPENSSL_DIR
build_ubuntu_free_threading:
name: 'Ubuntu (free-threading)'
needs: check_source
if: needs.check_source.outputs.run_tests == 'true'
uses: ./.github/workflows/reusable-ubuntu.yml
with:
config_hash: ${{ needs.check_source.outputs.config_hash }}
options: |
../cpython-ro-srcdir/configure \
--config-cache \
--with-pydebug \
--with-openssl=$OPENSSL_DIR \
--disable-gil
build_ubuntu_ssltests:
name: 'Ubuntu SSL tests with OpenSSL'
runs-on: ubuntu-22.04
timeout-minutes: 60
needs: check_source
if: needs.check_source.outputs.run_tests == 'true'
strategy:
fail-fast: false
matrix:
openssl_ver: [1.1.1w, 3.0.13, 3.1.5, 3.2.1]
env:
OPENSSL_VER: 1.1.1n
PYTHONSTRICTEXTENSIONBUILD: 1
OPENSSL_VER: ${{ matrix.openssl_ver }}
MULTISSL_DIR: ${{ github.workspace }}/multissl
OPENSSL_DIR: ${{ github.workspace }}/multissl/openssl/${{ matrix.openssl_ver }}
LD_LIBRARY_PATH: ${{ github.workspace }}/multissl/openssl/${{ matrix.openssl_ver }}/lib
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Runner image version
run: echo "IMAGE_VERSION=${ImageVersion}" >> $GITHUB_ENV
- name: Restore config.cache
uses: actions/cache@v4
with:
path: config.cache
key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-${{ needs.check_source.outputs.config_hash }}
- name: Register gcc problem matcher
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
- name: Install Dependencies
@ -185,7 +275,7 @@ jobs:
echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> $GITHUB_ENV
- name: 'Restore OpenSSL build'
id: cache-openssl
uses: actions/cache@v2.1.7
uses: actions/cache@v4
with:
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
@ -196,7 +286,62 @@ jobs:
run: |
echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV
- name: Configure ccache action
uses: hendrikmuhs/ccache-action@v1
uses: hendrikmuhs/ccache-action@v1.2
with:
save: false
- name: Configure CPython
run: ./configure --config-cache --with-pydebug --with-openssl=$OPENSSL_DIR
- name: Build CPython
run: make -j4
- name: Display build info
run: make pythoninfo
- name: SSL tests
run: ./python Lib/test/ssltests.py
build_wasi:
name: 'WASI'
needs: check_source
if: needs.check_source.outputs.run_tests == 'true'
uses: ./.github/workflows/reusable-wasi.yml
with:
config_hash: ${{ needs.check_source.outputs.config_hash }}
test_hypothesis:
name: "Hypothesis tests on Ubuntu"
runs-on: ubuntu-22.04
timeout-minutes: 60
needs: check_source
if: needs.check_source.outputs.run_tests == 'true' && needs.check_source.outputs.run_hypothesis == 'true'
env:
OPENSSL_VER: 3.0.13
PYTHONSTRICTEXTENSIONBUILD: 1
steps:
- uses: actions/checkout@v4
- 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@v4
with:
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
key: ${{ runner.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: Add ccache to PATH
run: |
echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV
- name: Configure ccache action
uses: hendrikmuhs/ccache-action@v1.2
with:
save: false
- name: Setup directory envs for out-of-tree builds
run: |
echo "CPYTHON_RO_SRCDIR=$(realpath -m ${GITHUB_WORKSPACE}/../cpython-ro-srcdir)" >> $GITHUB_ENV
@ -205,9 +350,20 @@ jobs:
run: mkdir -p $CPYTHON_RO_SRCDIR $CPYTHON_BUILDDIR
- name: Bind mount sources read-only
run: sudo mount --bind -o ro $GITHUB_WORKSPACE $CPYTHON_RO_SRCDIR
- name: Runner image version
run: echo "IMAGE_VERSION=${ImageVersion}" >> $GITHUB_ENV
- name: Restore config.cache
uses: actions/cache@v4
with:
path: ${{ env.CPYTHON_BUILDDIR }}/config.cache
key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-${{ needs.check_source.outputs.config_hash }}
- name: Configure CPython out-of-tree
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: ../cpython-ro-srcdir/configure --with-pydebug --with-openssl=$OPENSSL_DIR
run: |
../cpython-ro-srcdir/configure \
--config-cache \
--with-pydebug \
--with-openssl=$OPENSSL_DIR
- name: Build CPython out-of-tree
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: make -j4
@ -217,74 +373,79 @@ jobs:
- name: Remount sources writable for tests
# some tests write to srcdir, lack of pyc files slows down testing
run: sudo mount $CPYTHON_RO_SRCDIR -oremount,rw
- name: Tests
- name: Setup directory envs for out-of-tree builds
run: |
echo "CPYTHON_BUILDDIR=$(realpath -m ${GITHUB_WORKSPACE}/../cpython-builddir)" >> $GITHUB_ENV
- name: "Create hypothesis venv"
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: xvfb-run make buildbottest TESTOPTS="-j4 -uall,-cpu"
build_ubuntu_ssltests:
name: 'Ubuntu SSL tests with OpenSSL'
runs-on: ubuntu-20.04
needs: check_source
if: needs.check_source.outputs.run_tests == 'true' && needs.check_source.outputs.run_ssl_tests == 'true'
strategy:
fail-fast: false
matrix:
openssl_ver: [1.1.1n, 3.0.2]
env:
OPENSSL_VER: ${{ matrix.openssl_ver }}
MULTISSL_DIR: ${{ github.workspace }}/multissl
OPENSSL_DIR: ${{ github.workspace }}/multissl/openssl/${{ matrix.openssl_ver }}
LD_LIBRARY_PATH: ${{ github.workspace }}/multissl/openssl/${{ matrix.openssl_ver }}/lib
steps:
- uses: actions/checkout@v2
- 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@v2.1.7
VENV_LOC=$(realpath -m .)/hypovenv
VENV_PYTHON=$VENV_LOC/bin/python
echo "HYPOVENV=${VENV_LOC}" >> $GITHUB_ENV
echo "VENV_PYTHON=${VENV_PYTHON}" >> $GITHUB_ENV
./python -m venv $VENV_LOC && $VENV_PYTHON -m pip install -r ${GITHUB_WORKSPACE}/Tools/requirements-hypothesis.txt
- name: 'Restore Hypothesis database'
id: cache-hypothesis-database
uses: actions/cache@v4
with:
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
key: ${{ runner.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: Add ccache to PATH
path: ./hypothesis
key: hypothesis-database-${{ github.head_ref || github.run_id }}
restore-keys: |
- hypothesis-database-
- name: "Run tests"
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: |
echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV
- name: Configure ccache action
uses: hendrikmuhs/ccache-action@v1
- name: Configure CPython
run: ./configure --with-pydebug --with-openssl=$OPENSSL_DIR
- name: Build CPython
run: make -j4
- name: Display build info
run: make pythoninfo
- name: SSL tests
run: ./python Lib/test/ssltests.py
# Most of the excluded tests are slow test suites with no property tests
#
# (GH-104097) test_sysconfig is skipped because it has tests that are
# failing when executed from inside a virtual environment.
${{ env.VENV_PYTHON }} -m test \
-W \
-o \
-j4 \
-x test_asyncio \
-x test_multiprocessing_fork \
-x test_multiprocessing_forkserver \
-x test_multiprocessing_spawn \
-x test_concurrent_futures \
-x test_socket \
-x test_subprocess \
-x test_signal \
-x test_sysconfig
- uses: actions/upload-artifact@v4
if: always()
with:
name: hypothesis-example-db
path: .hypothesis/examples/
build_asan:
name: 'Address sanitizer'
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
timeout-minutes: 60
needs: check_source
if: needs.check_source.outputs.run_tests == 'true'
env:
OPENSSL_VER: 1.1.1n
OPENSSL_VER: 3.0.13
PYTHONSTRICTEXTENSIONBUILD: 1
ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Runner image version
run: echo "IMAGE_VERSION=${ImageVersion}" >> $GITHUB_ENV
- name: Restore config.cache
uses: actions/cache@v4
with:
path: config.cache
key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-${{ needs.check_source.outputs.config_hash }}
- 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: Set up GCC-10 for ASAN
uses: egor-tensin/setup-gcc@v1
with:
version: 10
- name: Configure OpenSSL env vars
run: |
echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> $GITHUB_ENV
@ -292,7 +453,7 @@ jobs:
echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> $GITHUB_ENV
- name: 'Restore OpenSSL build'
id: cache-openssl
uses: actions/cache@v2.1.7
uses: actions/cache@v4
with:
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
@ -303,12 +464,151 @@ jobs:
run: |
echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV
- name: Configure ccache action
uses: hendrikmuhs/ccache-action@v1
uses: hendrikmuhs/ccache-action@v1.2
with:
save: ${{ github.event_name == 'push' }}
max-size: "200M"
- name: Configure CPython
run: ./configure --with-address-sanitizer --without-pymalloc
run: ./configure --config-cache --with-address-sanitizer --without-pymalloc
- name: Build CPython
run: make -j4
- name: Display build info
run: make pythoninfo
- name: Tests
run: xvfb-run make buildbottest TESTOPTS="-j4 -uall,-cpu"
run: xvfb-run make test
build_tsan:
name: 'Thread sanitizer'
needs: check_source
if: needs.check_source.outputs.run_tests == 'true'
uses: ./.github/workflows/reusable-tsan.yml
with:
config_hash: ${{ needs.check_source.outputs.config_hash }}
options: ./configure --config-cache --with-thread-sanitizer --with-pydebug
suppressions_path: Tools/tsan/supressions.txt
tsan_logs_artifact_name: tsan-logs-default
build_tsan_free_threading:
name: 'Thread sanitizer (free-threading)'
needs: check_source
if: needs.check_source.outputs.run_tests == 'true'
uses: ./.github/workflows/reusable-tsan.yml
with:
config_hash: ${{ needs.check_source.outputs.config_hash }}
options: ./configure --config-cache --disable-gil --with-thread-sanitizer --with-pydebug
suppressions_path: Tools/tsan/suppressions_free_threading.txt
tsan_logs_artifact_name: tsan-logs-free-threading
# CIFuzz job based on https://google.github.io/oss-fuzz/getting-started/continuous-integration/
cifuzz:
name: CIFuzz
runs-on: ubuntu-latest
timeout-minutes: 60
needs: check_source
if: needs.check_source.outputs.run_cifuzz == 'true'
permissions:
security-events: write
strategy:
fail-fast: false
matrix:
sanitizer: [address, undefined, memory]
steps:
- name: Build fuzzers (${{ matrix.sanitizer }})
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: cpython3
sanitizer: ${{ matrix.sanitizer }}
- name: Run fuzzers (${{ matrix.sanitizer }})
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
fuzz-seconds: 600
oss-fuzz-project-name: cpython3
output-sarif: true
sanitizer: ${{ matrix.sanitizer }}
- name: Upload crash
uses: actions/upload-artifact@v4
if: failure() && steps.build.outcome == 'success'
with:
name: ${{ matrix.sanitizer }}-artifacts
path: ./out/artifacts
- name: Upload SARIF
if: always() && steps.build.outcome == 'success'
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: cifuzz-sarif/results.sarif
checkout_path: cifuzz-sarif
all-required-green: # This job does nothing and is only used for the branch protection
name: All required checks pass
if: always()
needs:
- check_source # Transitive dependency, needed to access `run_tests` value
- check-docs
- check_generated_files
- build_macos
- build_macos_free_threading
- build_ubuntu
- build_ubuntu_free_threading
- build_ubuntu_ssltests
- build_wasi
- build_windows
- build_windows_free_threading
- test_hypothesis
- build_asan
- build_tsan
- build_tsan_free_threading
- cifuzz
runs-on: ubuntu-latest
steps:
- name: Check whether the needed jobs succeeded or failed
uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe
with:
allowed-failures: >-
build_ubuntu_ssltests,
cifuzz,
test_hypothesis,
allowed-skips: >-
${{
!fromJSON(needs.check_source.outputs.run-docs)
&& '
check-docs,
'
|| ''
}}
${{
needs.check_source.outputs.run_tests != 'true'
&& '
check_generated_files,
build_macos,
build_macos_free_threading,
build_ubuntu,
build_ubuntu_free_threading,
build_ubuntu_ssltests,
build_wasi,
build_windows,
build_windows_free_threading,
build_asan,
build_tsan,
build_tsan_free_threading,
'
|| ''
}}
${{
!fromJSON(needs.check_source.outputs.run_cifuzz)
&& '
cifuzz,
'
|| ''
}}
${{
!fromJSON(needs.check_source.outputs.run_hypothesis)
&& '
test_hypothesis,
'
|| ''
}}
jobs: ${{ toJSON(needs) }}

View file

@ -5,43 +5,36 @@ on:
push:
branches:
- 'main'
- '3.10'
- '3.9'
- '3.8'
- '3.7'
- '3.*'
paths:
- 'Tools/msi/**'
- '.github/workflows/build_msi.yml'
pull_request:
branches:
- 'main'
- '3.10'
- '3.9'
- '3.8'
- '3.7'
- '3.*'
paths:
- 'Tools/msi/**'
- '.github/workflows/build_msi.yml'
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
build_win32:
name: 'Windows (x86) Installer'
build:
name: Windows Installer
runs-on: windows-latest
timeout-minutes: 60
strategy:
matrix:
type: [x86, x64, arm64]
env:
IncludeFreethreaded: true
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Build CPython installer
run: .\Tools\msi\build.bat -x86
build_win_amd64:
name: 'Windows (x64) Installer'
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Build CPython installer
run: .\Tools\msi\build.bat -x64
build_win_arm64:
name: 'Windows (ARM64) Installer'
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Build CPython installer
run: .\Tools\msi\build.bat -arm64
run: .\Tools\msi\build.bat --doc -${{ matrix.type }}

View file

@ -1,54 +0,0 @@
name: Docs
on:
workflow_dispatch:
#push:
# branches:
# - 'main'
# - '3.10'
# - '3.9'
# - '3.8'
# - '3.7'
# paths:
# - 'Doc/**'
pull_request:
branches:
- 'main'
- '3.10'
- '3.9'
- '3.8'
- '3.7'
paths:
- 'Doc/**'
- 'Misc/**'
jobs:
build_doc:
name: 'Docs'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Register Sphinx problem matcher
run: echo "::add-matcher::.github/problem-matchers/sphinx.json"
- name: 'Install Dependencies'
run: sudo ./.github/workflows/posix-deps-apt.sh && sudo apt-get install wamerican
- name: 'Configure CPython'
run: ./configure --with-pydebug
- name: 'Build CPython'
run: make -j4
- name: 'Install build dependencies'
run: make -C Doc/ PYTHON=../python venv
# Run "check doctest html" as 3 steps to get a more readable output
# in the web UI
- name: 'Check documentation'
run: make -C Doc/ PYTHON=../python SPHINXOPTS="-q -W --keep-going -j4" check
# Use "xvfb-run" since some doctest tests open GUI windows
- name: 'Run documentation doctest'
run: xvfb-run make -C Doc/ PYTHON=../python SPHINXOPTS="-q -W --keep-going -j4" doctest
- name: 'Build HTML documentation'
run: make -C Doc/ PYTHON=../python SPHINXOPTS="-q -W --keep-going -j4" html
- name: 'Upload'
uses: actions/upload-artifact@v2.3.1
with:
name: doc-html
path: Doc/build/html

View file

@ -0,0 +1,27 @@
name: Read the Docs PR preview
# Automatically edits a pull request's descriptions with a link
# to the documentation's preview on Read the Docs.
on:
pull_request_target:
types:
- opened
paths:
- 'Doc/**'
- '.github/workflows/doc.yml'
permissions:
pull-requests: write
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
documentation-links:
runs-on: ubuntu-latest
steps:
- uses: readthedocs/actions/preview@v1
with:
project-slug: "cpython-previews"
single-version: "true"

152
.github/workflows/jit.yml vendored Normal file
View file

@ -0,0 +1,152 @@
name: JIT
on:
pull_request:
paths:
- '**jit**'
- 'Python/bytecodes.c'
- 'Python/optimizer*.c'
- '!Python/perf_jit_trampoline.c'
- '!**/*.md'
- '!**/*.ini'
push:
paths:
- '**jit**'
- 'Python/bytecodes.c'
- 'Python/optimizer*.c'
- '!Python/perf_jit_trampoline.c'
- '!**/*.md'
- '!**/*.ini'
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
jit:
name: ${{ matrix.target }} (${{ matrix.debug && 'Debug' || 'Release' }})
runs-on: ${{ matrix.runner }}
timeout-minutes: 90
strategy:
fail-fast: false
matrix:
target:
- i686-pc-windows-msvc/msvc
- x86_64-pc-windows-msvc/msvc
- aarch64-pc-windows-msvc/msvc
- x86_64-apple-darwin/clang
- aarch64-apple-darwin/clang
- x86_64-unknown-linux-gnu/gcc
- x86_64-unknown-linux-gnu/clang
- aarch64-unknown-linux-gnu/gcc
- aarch64-unknown-linux-gnu/clang
debug:
- true
- false
llvm:
- 18
include:
- target: i686-pc-windows-msvc/msvc
architecture: Win32
runner: windows-latest
compiler: msvc
- target: x86_64-pc-windows-msvc/msvc
architecture: x64
runner: windows-latest
compiler: msvc
- target: aarch64-pc-windows-msvc/msvc
architecture: ARM64
runner: windows-latest
compiler: msvc
- target: x86_64-apple-darwin/clang
architecture: x86_64
runner: macos-13
compiler: clang
- target: aarch64-apple-darwin/clang
architecture: aarch64
runner: macos-14
compiler: clang
- target: x86_64-unknown-linux-gnu/gcc
architecture: x86_64
runner: ubuntu-latest
compiler: gcc
- target: x86_64-unknown-linux-gnu/clang
architecture: x86_64
runner: ubuntu-latest
compiler: clang
- target: aarch64-unknown-linux-gnu/gcc
architecture: aarch64
runner: ubuntu-latest
compiler: gcc
- target: aarch64-unknown-linux-gnu/clang
architecture: aarch64
runner: ubuntu-latest
compiler: clang
env:
CC: ${{ matrix.compiler }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Native Windows
if: runner.os == 'Windows' && matrix.architecture != 'ARM64'
run: |
choco upgrade llvm -y
choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}
./PCbuild/build.bat --experimental-jit ${{ matrix.debug && '-d' || '--pgo' }} -p ${{ matrix.architecture }}
./PCbuild/rt.bat ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }} -q --multiprocess 0 --timeout 4500 --verbose2 --verbose3
# No PGO or tests (yet):
- name: Emulated Windows
if: runner.os == 'Windows' && matrix.architecture == 'ARM64'
run: |
choco upgrade llvm -y
choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}
./PCbuild/build.bat --experimental-jit ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }}
- name: Native macOS
if: runner.os == 'macOS'
run: |
brew update
brew install llvm@${{ matrix.llvm }}
SDKROOT="$(xcrun --show-sdk-path)" \
./configure --enable-experimental-jit ${{ matrix.debug && '--with-pydebug' || '--enable-optimizations --with-lto' }}
make all --jobs 4
./python.exe -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
# --with-lto has been removed temporarily as a result of an open issue in LLVM 18 (see https://github.com/llvm/llvm-project/issues/87553)
- name: Native Linux
if: runner.os == 'Linux' && matrix.architecture == 'x86_64'
run: |
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ matrix.llvm }}
export PATH="$(llvm-config-${{ matrix.llvm }} --bindir):$PATH"
./configure --enable-experimental-jit ${{ matrix.debug && '--with-pydebug' || '--enable-optimizations' }}
make all --jobs 4
./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
# --with-lto has been removed temporarily as a result of an open issue in LLVM 18 (see https://github.com/llvm/llvm-project/issues/87553)
- name: Emulated Linux
if: runner.os == 'Linux' && matrix.architecture != 'x86_64'
# The --ignorefile on ./python -m test is used to exclude tests known to fail when running on an emulated Linux.
run: |
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ matrix.llvm }}
export PATH="$(llvm-config-${{ matrix.llvm }} --bindir):$PATH"
./configure --prefix="$(pwd)/../build"
make install --jobs 4
make clean --jobs 4
export HOST=${{ matrix.architecture }}-linux-gnu
sudo apt install --yes "gcc-$HOST" qemu-user
${{ !matrix.debug && matrix.compiler == 'clang' && './configure --enable-optimizations' || '' }}
${{ !matrix.debug && matrix.compiler == 'clang' && 'make profile-run-stamp --jobs 4' || '' }}
export QEMU_LD_PREFIX="/usr/$HOST"
CC="${{ matrix.compiler == 'clang' && 'clang --target=$HOST' || '$HOST-gcc' }}" \
CPP="$CC --preprocess" \
HOSTRUNNER=qemu-${{ matrix.architecture }} \
./configure --enable-experimental-jit ${{ matrix.debug && '--with-pydebug' || '--enable-optimizations ' }} --build=x86_64-linux-gnu --host="$HOST" --with-build-python=../build/bin/python3 --with-pkg-config=no ac_cv_buggy_getaddrinfo=no ac_cv_file__dev_ptc=no ac_cv_file__dev_ptmx=yes
make all --jobs 4
./python -m test --ignorefile=Tools/jit/ignore-tests-emulated-linux.txt --multiprocess 0 --timeout 4500 --verbose2 --verbose3

26
.github/workflows/lint.yml vendored Normal file
View file

@ -0,0 +1,26 @@
name: Lint
on: [push, pull_request, workflow_dispatch]
permissions:
contents: read
env:
FORCE_COLOR: 1
RUFF_OUTPUT_FORMAT: github
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
lint:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.x"
- uses: pre-commit/action@v3.0.1

60
.github/workflows/mypy.yml vendored Normal file
View file

@ -0,0 +1,60 @@
# Workflow to run mypy on select parts of the CPython repo
name: mypy
on:
push:
branches:
- main
pull_request:
paths:
- ".github/workflows/mypy.yml"
- "Lib/_pyrepl/**"
- "Lib/test/libregrtest/**"
- "Tools/build/generate_sbom.py"
- "Tools/cases_generator/**"
- "Tools/clinic/**"
- "Tools/jit/**"
- "Tools/peg_generator/**"
- "Tools/requirements-dev.txt"
- "Tools/wasm/**"
workflow_dispatch:
permissions:
contents: read
env:
PIP_DISABLE_PIP_VERSION_CHECK: 1
FORCE_COLOR: 1
TERM: xterm-256color # needed for FORCE_COLOR to work on mypy on Ubuntu, see https://github.com/python/mypy/issues/13817
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
mypy:
strategy:
fail-fast: false
matrix:
target: [
"Lib/_pyrepl",
"Lib/test/libregrtest",
"Tools/build",
"Tools/cases_generator",
"Tools/clinic",
"Tools/jit",
"Tools/peg_generator",
"Tools/wasm",
]
name: Run mypy on ${{ matrix.target }}
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip
cache-dependency-path: Tools/requirements-dev.txt
- run: pip install -r Tools/requirements-dev.txt
- run: mypy --config-file ${{ matrix.target }}/mypy.ini

View file

@ -5,24 +5,28 @@ on:
types:
- opened
permissions:
issues: read
jobs:
notify-new-bugs-announce:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/setup-node@v2
- uses: actions/setup-node@v4
with:
node-version: 14
node-version: 20
- run: npm install mailgun.js form-data
- name: Send notification
uses: actions/github-script@v5
uses: actions/github-script@v7
env:
MAILGUN_API_KEY: ${{ secrets.PSF_MAILGUN_KEY }}
MAILGUN_API_KEY: ${{ secrets.MAILGUN_PYTHON_ORG_MAILGUN_KEY }}
with:
script: |
const Mailgun = require("mailgun.js");
const formData = require('form-data');
const mailgun = new Mailgun(formData);
const DOMAIN = "mg.python.org";
const DOMAIN = "mailgun.python.org";
const mg = mailgun.client({username: 'api', key: process.env.MAILGUN_API_KEY});
github.rest.issues.get({
issue_number: context.issue.number,
@ -37,11 +41,14 @@ jobs:
url : issue.data.html_url,
labels : issue.data.labels.map(label => { return label.name }).join(", "),
assignee : issue.data.assignees.map(assignee => { return assignee.login }),
body : issue.data.body
// We need to truncate the body size, because the max size for
// the whole payload is 16kb. We want to be safe and assume that
// body can take up to ~8kb of space.
body : issue.data.body.substring(0, 8000)
};
const data = {
from: "CPython Issues <github@mg.python.org>",
from: "CPython Issues <github@mailgun.python.org>",
to: "new-bugs-announce@python.org",
subject: `[Issue ${issue.data.number}] ${issue.data.title}`,
template: "new-github-issue",

View file

@ -1,9 +1,11 @@
#!/bin/sh
apt-get update
# autoconf-archive is needed by autoreconf (check_generated_files job)
apt-get -yq install \
build-essential \
pkg-config \
autoconf-archive \
ccache \
gdb \
lcov \
@ -13,12 +15,14 @@ apt-get -yq install \
libgdbm-dev \
libgdbm-compat-dev \
liblzma-dev \
libmpdec-dev \
libncurses5-dev \
libreadline6-dev \
libsqlite3-dev \
libssl-dev \
lzma \
lzma-dev \
strace \
tk-dev \
uuid-dev \
xvfb \

30
.github/workflows/project-updater.yml vendored Normal file
View file

@ -0,0 +1,30 @@
name: Update GH projects
on:
issues:
types:
- opened
- labeled
permissions:
contents: read
jobs:
add-to-project:
name: Add issues to projects
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
matrix:
include:
# if an issue has any of these labels, it will be added
# to the corresponding project
- { project: 2, label: "release-blocker, deferred-blocker" }
- { project: 32, label: sprint }
steps:
- uses: actions/add-to-project@v1.0.0
with:
project-url: https://github.com/orgs/python/projects/${{ matrix.project }}
github-token: ${{ secrets.ADD_TO_PROJECT_PAT }}
labeled: ${{ matrix.label }}

8
.github/workflows/regen-abidump.sh vendored Normal file
View file

@ -0,0 +1,8 @@
set -ex
export DEBIAN_FRONTEND=noninteractive
./.github/workflows/posix-deps-apt.sh
apt-get install -yq abigail-tools python3
export CFLAGS="-g3 -O0"
./configure --enable-shared && make
make regen-abidump

23
.github/workflows/require-pr-label.yml vendored Normal file
View file

@ -0,0 +1,23 @@
name: Check labels
on:
pull_request:
types: [opened, reopened, labeled, unlabeled, synchronize]
permissions:
issues: write
pull-requests: write
jobs:
label:
name: DO-NOT-MERGE / unresolved review
if: github.repository_owner == 'python'
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: mheap/github-action-required-labels@v5
with:
mode: exactly
count: 0
labels: "DO-NOT-MERGE, awaiting changes, awaiting change review"

109
.github/workflows/reusable-docs.yml vendored Normal file
View file

@ -0,0 +1,109 @@
name: Docs
on:
workflow_call:
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
build_doc:
name: 'Docs'
runs-on: ubuntu-latest
timeout-minutes: 60
env:
branch_base: 'origin/${{ github.event.pull_request.base.ref }}'
branch_pr: 'origin/${{ github.event.pull_request.head.ref }}'
refspec_base: '+${{ github.event.pull_request.base.sha }}:remotes/origin/${{ github.event.pull_request.base.ref }}'
refspec_pr: '+${{ github.event.pull_request.head.sha }}:remotes/origin/${{ github.event.pull_request.head.ref }}'
steps:
- name: 'Check out latest PR branch commit'
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
# Adapted from https://github.com/actions/checkout/issues/520#issuecomment-1167205721
- name: 'Fetch commits to get branch diff'
run: |
# Fetch enough history to find a common ancestor commit (aka merge-base):
git fetch origin ${{ env.refspec_pr }} --depth=$(( ${{ github.event.pull_request.commits }} + 1 )) \
--no-tags --prune --no-recurse-submodules
# This should get the oldest commit in the local fetched history (which may not be the commit the PR branched from):
COMMON_ANCESTOR=$( git rev-list --first-parent --max-parents=0 --max-count=1 ${{ env.branch_pr }} )
DATE=$( git log --date=iso8601 --format=%cd "${COMMON_ANCESTOR}" )
# Get all commits since that commit date from the base branch (eg: master or main):
git fetch origin ${{ env.refspec_base }} --shallow-since="${DATE}" \
--no-tags --prune --no-recurse-submodules
- name: 'Set up Python'
uses: actions/setup-python@v5
with:
python-version: '3'
cache: 'pip'
cache-dependency-path: 'Doc/requirements.txt'
- name: 'Install build dependencies'
run: make -C Doc/ venv
# To annotate PRs with Sphinx nitpicks (missing references)
- name: 'Build HTML documentation'
continue-on-error: true
run: |
set -Eeuo pipefail
# Build docs with the '-n' (nit-picky) option; write warnings to file
make -C Doc/ PYTHON=../python SPHINXOPTS="-q -n -W --keep-going -w sphinx-warnings.txt" html
- name: 'Check warnings'
if: github.event_name == 'pull_request'
run: |
python Doc/tools/check-warnings.py \
--annotate-diff '${{ env.branch_base }}' '${{ env.branch_pr }}' \
--fail-if-regression \
--fail-if-improved \
--fail-if-new-news-nit
# This build doesn't use problem matchers or check annotations
build_doc_oldest_supported_sphinx:
name: 'Docs (Oldest Sphinx)'
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
- name: 'Set up Python'
uses: actions/setup-python@v5
with:
python-version: '3.12' # known to work with Sphinx 6.2.1
cache: 'pip'
cache-dependency-path: 'Doc/requirements-oldest-sphinx.txt'
- name: 'Install build dependencies'
run: make -C Doc/ venv REQUIREMENTS="requirements-oldest-sphinx.txt"
- name: 'Build HTML documentation'
run: make -C Doc/ SPHINXOPTS="-q" SPHINXERRORHANDLING="-W --keep-going" html
# Run "doctest" on HEAD as new syntax doesn't exist in the latest stable release
doctest:
name: 'Doctest'
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ubuntu-doc-${{ hashFiles('Doc/requirements.txt') }}
restore-keys: |
ubuntu-doc-
- name: 'Install Dependencies'
run: sudo ./.github/workflows/posix-deps-apt.sh && sudo apt-get install wamerican
- name: 'Configure CPython'
run: ./configure --with-pydebug
- name: 'Build CPython'
run: make -j4
- name: 'Install build dependencies'
run: make -C Doc/ PYTHON=../python venv
# Use "xvfb-run" since some doctest tests open GUI windows
- name: 'Run documentation doctest'
run: xvfb-run make -C Doc/ PYTHON=../python SPHINXERRORHANDLING="-W --keep-going" doctest

57
.github/workflows/reusable-macos.yml vendored Normal file
View file

@ -0,0 +1,57 @@
on:
workflow_call:
inputs:
config_hash:
required: true
type: string
free-threading:
required: false
type: boolean
default: false
os-matrix:
required: false
type: string
jobs:
build_macos:
name: 'build and test'
timeout-minutes: 60
env:
HOMEBREW_NO_ANALYTICS: 1
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
PYTHONSTRICTEXTENSIONBUILD: 1
TERM: linux
strategy:
fail-fast: false
matrix:
os: ${{fromJson(inputs.os-matrix)}}
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Runner image version
run: echo "IMAGE_VERSION=${ImageVersion}" >> $GITHUB_ENV
- name: Restore config.cache
uses: actions/cache@v4
with:
path: config.cache
key: ${{ github.job }}-${{ matrix.os }}-${{ env.IMAGE_VERSION }}-${{ inputs.config_hash }}
- name: Install Homebrew dependencies
run: brew install pkg-config openssl@3.0 xz gdbm tcl-tk
- name: Configure CPython
run: |
GDBM_CFLAGS="-I$(brew --prefix gdbm)/include" \
GDBM_LIBS="-L$(brew --prefix gdbm)/lib -lgdbm" \
./configure \
--config-cache \
--with-pydebug \
${{ inputs.free-threading && '--disable-gil' || '' }} \
--prefix=/opt/python-dev \
--with-openssl="$(brew --prefix openssl@3.0)"
- name: Build CPython
run: make -j8
- name: Display build info
run: make pythoninfo
- name: Tests
run: make test

76
.github/workflows/reusable-tsan.yml vendored Normal file
View file

@ -0,0 +1,76 @@
on:
workflow_call:
inputs:
config_hash:
required: true
type: string
options:
required: true
type: string
suppressions_path:
description: 'A repo relative path to the suppressions file'
required: true
type: string
tsan_logs_artifact_name:
description: 'Name of the TSAN logs artifact. Must be unique for each job.'
required: true
type: string
jobs:
build_tsan_reusable:
name: 'Thread sanitizer'
runs-on: ubuntu-22.04
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
- name: Runner image version
run: echo "IMAGE_VERSION=${ImageVersion}" >> $GITHUB_ENV
- name: Restore config.cache
uses: actions/cache@v4
with:
path: config.cache
key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-${{ inputs.config_hash }}
- name: Install Dependencies
run: |
sudo ./.github/workflows/posix-deps-apt.sh
# Install clang-18
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 18
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-18 100
sudo update-alternatives --set clang /usr/bin/clang-18
sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-18 100
sudo update-alternatives --set clang++ /usr/bin/clang++-18
# Reduce ASLR to avoid TSAN crashing
sudo sysctl -w vm.mmap_rnd_bits=28
- name: TSAN Option Setup
run: |
echo "TSAN_OPTIONS=log_path=${GITHUB_WORKSPACE}/tsan_log suppressions=${GITHUB_WORKSPACE}/${{ inputs.suppressions_path }} handle_segv=0" >> $GITHUB_ENV
echo "CC=clang" >> $GITHUB_ENV
echo "CXX=clang++" >> $GITHUB_ENV
- name: Add ccache to PATH
run: |
echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV
- name: Configure ccache action
uses: hendrikmuhs/ccache-action@v1.2
with:
save: ${{ github.event_name == 'push' }}
max-size: "200M"
- name: Configure CPython
run: ${{ inputs.options }}
- name: Build CPython
run: make -j4
- name: Display build info
run: make pythoninfo
- name: Tests
run: ./python -m test --tsan -j4
- name: Display TSAN logs
if: always()
run: find ${GITHUB_WORKSPACE} -name 'tsan_log.*' | xargs head -n 1000
- name: Archive TSAN logs
if: always()
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.tsan_logs_artifact_name }}
path: tsan_log.*
if-no-files-found: ignore

78
.github/workflows/reusable-ubuntu.yml vendored Normal file
View file

@ -0,0 +1,78 @@
on:
workflow_call:
inputs:
config_hash:
required: true
type: string
options:
required: true
type: string
jobs:
build_ubuntu_reusable:
name: 'build and test'
timeout-minutes: 60
runs-on: ubuntu-22.04
env:
FORCE_COLOR: 1
OPENSSL_VER: 3.0.13
PYTHONSTRICTEXTENSIONBUILD: 1
TERM: linux
steps:
- uses: actions/checkout@v4
- 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@v4
with:
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
key: ${{ runner.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: Add ccache to PATH
run: |
echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV
- name: Configure ccache action
uses: hendrikmuhs/ccache-action@v1.2
with:
save: ${{ github.event_name == 'push' }}
max-size: "200M"
- name: Setup directory envs for out-of-tree builds
run: |
echo "CPYTHON_RO_SRCDIR=$(realpath -m ${GITHUB_WORKSPACE}/../cpython-ro-srcdir)" >> $GITHUB_ENV
echo "CPYTHON_BUILDDIR=$(realpath -m ${GITHUB_WORKSPACE}/../cpython-builddir)" >> $GITHUB_ENV
- name: Create directories for read-only out-of-tree builds
run: mkdir -p $CPYTHON_RO_SRCDIR $CPYTHON_BUILDDIR
- name: Bind mount sources read-only
run: sudo mount --bind -o ro $GITHUB_WORKSPACE $CPYTHON_RO_SRCDIR
- name: Runner image version
run: echo "IMAGE_VERSION=${ImageVersion}" >> $GITHUB_ENV
- name: Restore config.cache
uses: actions/cache@v4
with:
path: ${{ env.CPYTHON_BUILDDIR }}/config.cache
key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-${{ inputs.config_hash }}
- name: Configure CPython out-of-tree
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: ${{ inputs.options }}
- name: Build CPython out-of-tree
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: make -j4
- name: Display build info
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: make pythoninfo
- name: Remount sources writable for tests
# some tests write to srcdir, lack of pyc files slows down testing
run: sudo mount $CPYTHON_RO_SRCDIR -oremount,rw
- name: Tests
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: xvfb-run make test

73
.github/workflows/reusable-wasi.yml vendored Normal file
View file

@ -0,0 +1,73 @@
on:
workflow_call:
inputs:
config_hash:
required: true
type: string
jobs:
build_wasi_reusable:
name: 'build and test'
timeout-minutes: 60
runs-on: ubuntu-22.04
env:
WASMTIME_VERSION: 18.0.3
WASI_SDK_VERSION: 21
WASI_SDK_PATH: /opt/wasi-sdk
CROSS_BUILD_PYTHON: cross-build/build
CROSS_BUILD_WASI: cross-build/wasm32-wasi
steps:
- uses: actions/checkout@v4
# No problem resolver registered as one doesn't currently exist for Clang.
- name: "Install wasmtime"
uses: jcbhmr/setup-wasmtime@v2
with:
wasmtime-version: ${{ env.WASMTIME_VERSION }}
- name: "Restore WASI SDK"
id: cache-wasi-sdk
uses: actions/cache@v4
with:
path: ${{ env.WASI_SDK_PATH }}
key: ${{ runner.os }}-wasi-sdk-${{ env.WASI_SDK_VERSION }}
- name: "Install WASI SDK"
if: steps.cache-wasi-sdk.outputs.cache-hit != 'true'
run: |
mkdir ${{ env.WASI_SDK_PATH }} && \
curl -s -S --location https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${{ env.WASI_SDK_VERSION }}/wasi-sdk-${{ env.WASI_SDK_VERSION }}.0-linux.tar.gz | \
tar --strip-components 1 --directory ${{ env.WASI_SDK_PATH }} --extract --gunzip
- name: "Configure ccache action"
uses: hendrikmuhs/ccache-action@v1.2
with:
save: ${{ github.event_name == 'push' }}
max-size: "200M"
- name: "Add ccache to PATH"
run: echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV
- name: "Install Python"
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: "Restore Python build config.cache"
uses: actions/cache@v4
with:
path: ${{ env.CROSS_BUILD_PYTHON }}/config.cache
# Include env.pythonLocation in key to avoid changes in environment when setup-python updates Python
key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-${{ inputs.config_hash }}-${{ env.pythonLocation }}
- name: "Configure build Python"
run: python3 Tools/wasm/wasi.py configure-build-python -- --config-cache --with-pydebug
- name: "Make build Python"
run: python3 Tools/wasm/wasi.py make-build-python
- name: "Restore host config.cache"
uses: actions/cache@v4
with:
path: ${{ env.CROSS_BUILD_WASI }}/config.cache
# Include env.pythonLocation in key to avoid changes in environment when setup-python updates Python
key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-wasi-sdk-${{ env.WASI_SDK_VERSION }}-${{ inputs.config_hash }}-${{ env.pythonLocation }}
- name: "Configure host"
# `--with-pydebug` inferred from configure-build-python
run: python3 Tools/wasm/wasi.py configure-host -- --config-cache
- name: "Make host"
run: python3 Tools/wasm/wasi.py make-host
- name: "Display build info"
run: make --directory ${{ env.CROSS_BUILD_WASI }} pythoninfo
- name: "Test"
run: make --directory ${{ env.CROSS_BUILD_WASI }} test

53
.github/workflows/reusable-windows.yml vendored Normal file
View file

@ -0,0 +1,53 @@
on:
workflow_call:
inputs:
free-threading:
required: false
type: boolean
default: false
jobs:
build_win32:
name: 'build and test (x86)'
runs-on: windows-latest
timeout-minutes: 60
env:
IncludeUwp: 'true'
steps:
- uses: actions/checkout@v4
- name: Build CPython
run: .\PCbuild\build.bat -e -d -v -p Win32 ${{ inputs.free-threading && '--disable-gil' || '' }}
- name: Display build info
run: .\python.bat -m test.pythoninfo
- name: Tests
run: .\PCbuild\rt.bat -p Win32 -d -q --fast-ci ${{ inputs.free-threading && '--disable-gil' || '' }}
build_win_amd64:
name: 'build and test (x64)'
runs-on: windows-latest
timeout-minutes: 60
env:
IncludeUwp: 'true'
steps:
- uses: actions/checkout@v4
- name: Register MSVC problem matcher
run: echo "::add-matcher::.github/problem-matchers/msvc.json"
- name: Build CPython
run: .\PCbuild\build.bat -e -d -v -p x64 ${{ inputs.free-threading && '--disable-gil' || '' }}
- name: Display build info
run: .\python.bat -m test.pythoninfo
- name: Tests
run: .\PCbuild\rt.bat -p x64 -d -q --fast-ci ${{ inputs.free-threading && '--disable-gil' || '' }}
build_win_arm64:
name: 'build (arm64)'
runs-on: windows-latest
timeout-minutes: 60
env:
IncludeUwp: 'true'
steps:
- uses: actions/checkout@v4
- name: Register MSVC problem matcher
run: echo "::add-matcher::.github/problem-matchers/msvc.json"
- name: Build CPython
run: .\PCbuild\build.bat -e -d -v -p arm64 ${{ inputs.free-threading && '--disable-gil' || '' }}

View file

@ -2,7 +2,7 @@ name: Mark stale pull requests
on:
schedule:
- cron: "0 0 * * *"
- cron: "0 */6 * * *"
permissions:
pull-requests: write
@ -12,15 +12,17 @@ jobs:
if: github.repository_owner == 'python'
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: "Check PRs"
uses: actions/stale@v4
uses: actions/stale@v9
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-pr-message: 'This PR is stale because it has been open for 30 days with no activity.'
stale-pr-label: 'stale'
days-before-stale: 30
days-before-issue-stale: -1
days-before-pr-stale: 30
days-before-close: -1
ascending: true
operations-per-run: 120

View file

@ -0,0 +1,33 @@
name: Verify bundled wheels
on:
workflow_dispatch:
push:
paths:
- 'Lib/ensurepip/_bundled/**'
- '.github/workflows/verify-ensurepip-wheels.yml'
- 'Tools/build/verify_ensurepip_wheels.py'
pull_request:
paths:
- 'Lib/ensurepip/_bundled/**'
- '.github/workflows/verify-ensurepip-wheels.yml'
- 'Tools/build/verify_ensurepip_wheels.py'
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
verify:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3'
- name: Compare checksum of bundled wheels to the ones published on PyPI
run: ./Tools/build/verify_ensurepip_wheels.py

31
.gitignore vendored
View file

@ -5,10 +5,12 @@
*.cover
*.iml
*.o
*.lto
*.a
*.so
*.so.*
*.dylib
*.dSYM
*.dll
*.wasm
*.orig
@ -21,6 +23,10 @@
*.gc??
*.profclang?
*.profraw
# Copies of binaries before BOLT optimizations.
*.prebolt
# BOLT profile data.
*.fdata
*.dyn
.gdb_history
.purify
@ -36,10 +42,10 @@ gmon.out
.coverage
.mypy_cache/
.pytest_cache/
.ruff_cache/
.DS_Store
*.exe
!Lib/distutils/command/*.exe
# Ignore core dumps... but not Tools/msi/core/ or the like.
core
@ -56,8 +62,6 @@ Doc/.venv/
Doc/env/
Doc/.env/
Include/pydtrace_probes.h
Lib/distutils/command/*.pdb
Lib/lib2to3/*.pickle
Lib/site-packages/*
!Lib/site-packages/README.txt
Lib/test/data/*
@ -65,6 +69,17 @@ Lib/test/data/*
/_bootstrap_python
/Makefile
/Makefile.pre
/iOSTestbed.*
iOS/Frameworks/
iOS/Resources/Info.plist
iOS/testbed/build
iOS/testbed/Python.xcframework/ios-*/bin
iOS/testbed/Python.xcframework/ios-*/include
iOS/testbed/Python.xcframework/ios-*/lib
iOS/testbed/Python.xcframework/ios-*/Python.framework
iOS/testbed/iOSTestbed.xcodeproj/project.xcworkspace
iOS/testbed/iOSTestbed.xcodeproj/xcuserdata
iOS/testbed/iOSTestbed.xcodeproj/xcshareddata
Mac/Makefile
Mac/PythonLauncher/Info.plist
Mac/PythonLauncher/Makefile
@ -114,16 +129,19 @@ PCbuild/win32/
Tools/unicode/data/
/autom4te.cache
/build/
/builddir/
/config.cache
/config.log
/config.status
/config.status.lineno
# hendrikmuhs/ccache-action@v1
/.ccache
/cross-build/
/jit_stencils.h
/platform
/profile-clean-stamp
/profile-run-stamp
/Python/deepfreeze/*.c
/profile-bolt-stamp
/pybuilddir.txt
/pyconfig.h
/python-config
@ -141,7 +159,7 @@ Tools/ssl/win32
Tools/freeze/test/outdir
# The frozen modules are always generated by the build so we don't
# keep them in the repo. Also see Tools/scripts/freeze_modules.py.
# keep them in the repo. Also see Tools/build/freeze_modules.py.
Python/frozen_modules/*.h
# The manifest can be generated at any time with "make regen-frozen".
Python/frozen_modules/MANIFEST
@ -150,3 +168,6 @@ Python/frozen_modules/MANIFEST
# Ignore ./python binary on Unix but still look into ./Python/ directory.
/python
!/Python/
# main branch only: ABI files are not checked/maintained.
Doc/data/python*.abi

3
.mailmap Normal file
View file

@ -0,0 +1,3 @@
# This file sets the canonical name for contributors to the repository.
# Documentation: https://git-scm.com/docs/gitmailmap
Amethyst Reese <amethyst@n7.gg> <john@noswap.com>

46
.pre-commit-config.yaml Normal file
View file

@ -0,0 +1,46 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.3.4
hooks:
- id: ruff
name: Run Ruff on Lib/test/
args: [--exit-non-zero-on-fix]
files: ^Lib/test/
- id: ruff
name: Run Ruff on Argument Clinic
args: [--exit-non-zero-on-fix, --config=Tools/clinic/.ruff.toml]
files: ^Tools/clinic/|Lib/test/test_clinic.py
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 24.4.2
hooks:
- id: black
name: Run Black on Tools/jit/
files: ^Tools/jit/
language_version: python3.12
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: check-case-conflict
- id: check-merge-conflict
- id: check-toml
exclude: ^Lib/test/test_tomllib/
- id: check-yaml
- id: end-of-file-fixer
types: [python]
exclude: Lib/test/tokenizedata/coding20731.py
- id: trailing-whitespace
types_or: [c, inc, python, rst]
- repo: https://github.com/sphinx-contrib/sphinx-lint
rev: v0.9.1
hooks:
- id: sphinx-lint
args: [--enable=default-role]
files: ^Doc/|^Misc/NEWS.d/
- repo: meta
hooks:
- id: check-hooks-apply
- id: check-useless-excludes

32
.readthedocs.yml Normal file
View file

@ -0,0 +1,32 @@
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Project page: https://readthedocs.org/projects/cpython-previews/
version: 2
sphinx:
configuration: Doc/conf.py
build:
os: ubuntu-22.04
tools:
python: "3"
commands:
# https://docs.readthedocs.io/en/stable/build-customization.html#cancel-build-based-on-a-condition
#
# Cancel building pull requests when there aren't changes in the Doc directory.
#
# If there are no changes (git diff exits with 0) we force the command to return with 183.
# This is a special exit code on Read the Docs that will cancel the build immediately.
- |
if [ "$READTHEDOCS_VERSION_TYPE" = "external" ] && [ "$(git diff --quiet origin/main -- Doc/ .readthedocs.yml; echo $?)" -eq 0 ];
then
echo "No changes to Doc/ - exiting the build.";
exit 183;
fi
- make -C Doc venv html
- mkdir _readthedocs
- mv Doc/build/html _readthedocs/html

97
Android/README.md Normal file
View file

@ -0,0 +1,97 @@
# Python for Android
These instructions are only needed if you're planning to compile Python for
Android yourself. Most users should *not* need to do this. If you're looking to
use Python on Android, one of the following tools will provide a much more
approachable user experience:
* [Briefcase](https://briefcase.readthedocs.io), from the BeeWare project
* [Buildozer](https://buildozer.readthedocs.io), from the Kivy project
* [Chaquopy](https://chaquo.com/chaquopy/)
## Prerequisites
Export the `ANDROID_HOME` environment variable to point at your Android SDK. If
you don't already have the SDK, here's how to install it:
* Download the "Command line tools" from <https://developer.android.com/studio>.
* Create a directory `android-sdk/cmdline-tools`, and unzip the command line
tools package into it.
* Rename `android-sdk/cmdline-tools/cmdline-tools` to
`android-sdk/cmdline-tools/latest`.
* `export ANDROID_HOME=/path/to/android-sdk`
The `android.py` script also requires the following commands to be on the `PATH`:
* `curl`
* `java`
* `tar`
* `unzip`
## Building
Python can be built for Android on any POSIX platform supported by the Android
development tools, which currently means Linux or macOS. This involves doing a
cross-build where you use a "build" Python (for your development machine) to
help produce a "host" Python for Android.
First, make sure you have all the usual tools and libraries needed to build
Python for your development machine. The only Android tool you need to install
is the command line tools package above: the build script will download the
rest.
The easiest way to do a build is to use the `android.py` script. You can either
have it perform the entire build process from start to finish in one step, or
you can do it in discrete steps that mirror running `configure` and `make` for
each of the two builds of Python you end up producing.
The discrete steps for building via `android.py` are:
```sh
./android.py configure-build
./android.py make-build
./android.py configure-host HOST
./android.py make-host HOST
```
`HOST` identifies which architecture to build. To see the possible values, run
`./android.py configure-host --help`.
To do all steps in a single command, run:
```sh
./android.py build HOST
```
In the end you should have a build Python in `cross-build/build`, and an Android
build in `cross-build/HOST`.
You can use `--` as a separator for any of the `configure`-related commands
including `build` itself to pass arguments to the underlying `configure`
call. For example, if you want a pydebug build that also caches the results from
`configure`, you can do:
```sh
./android.py build HOST -- -C --with-pydebug
```
## Testing
To run the Python test suite on Android:
* Install Android Studio, if you don't already have it.
* Follow the instructions in the previous section to build all supported
architectures.
* Run `./android.py setup-testbed` to download the Gradle wrapper.
* Open the `testbed` directory in Android Studio.
* In the *Device Manager* dock, connect a device or start an emulator.
Then select it from the drop-down list in the toolbar.
* Click the "Run" button in the toolbar.
* The testbed app displays nothing on screen while running. To see its output,
open the [Logcat window](https://developer.android.com/studio/debug/logcat).
To run specific tests, or pass any other arguments to the test suite, edit the
command line in testbed/app/src/main/python/main.py.

93
Android/android-env.sh Normal file
View file

@ -0,0 +1,93 @@
# This script must be sourced with the following variables already set:
: ${ANDROID_HOME:?} # Path to Android SDK
: ${HOST:?} # GNU target triplet
# You may also override the following:
: ${api_level:=21} # Minimum Android API level the build will run on
: ${PREFIX:-} # Path in which to find required libraries
# Print all messages on stderr so they're visible when running within build-wheel.
log() {
echo "$1" >&2
}
fail() {
log "$1"
exit 1
}
# When moving to a new version of the NDK, carefully review the following:
#
# * https://developer.android.com/ndk/downloads/revision_history
#
# * https://android.googlesource.com/platform/ndk/+/ndk-rXX-release/docs/BuildSystemMaintainers.md
# where XX is the NDK version. Do a diff against the version you're upgrading from, e.g.:
# https://android.googlesource.com/platform/ndk/+/ndk-r25-release..ndk-r26-release/docs/BuildSystemMaintainers.md
ndk_version=26.2.11394342
ndk=$ANDROID_HOME/ndk/$ndk_version
if ! [ -e $ndk ]; then
log "Installing NDK: this may take several minutes"
yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "ndk;$ndk_version"
fi
if [ $HOST = "arm-linux-androideabi" ]; then
clang_triplet=armv7a-linux-androideabi
else
clang_triplet=$HOST
fi
# These variables are based on BuildSystemMaintainers.md above, and
# $ndk/build/cmake/android.toolchain.cmake.
toolchain=$(echo $ndk/toolchains/llvm/prebuilt/*)
export AR="$toolchain/bin/llvm-ar"
export AS="$toolchain/bin/llvm-as"
export CC="$toolchain/bin/${clang_triplet}${api_level}-clang"
export CXX="${CC}++"
export LD="$toolchain/bin/ld"
export NM="$toolchain/bin/llvm-nm"
export RANLIB="$toolchain/bin/llvm-ranlib"
export READELF="$toolchain/bin/llvm-readelf"
export STRIP="$toolchain/bin/llvm-strip"
# The quotes make sure the wildcard in the `toolchain` assignment has been expanded.
for path in "$AR" "$AS" "$CC" "$CXX" "$LD" "$NM" "$RANLIB" "$READELF" "$STRIP"; do
if ! [ -e "$path" ]; then
fail "$path does not exist"
fi
done
export CFLAGS=""
export LDFLAGS="-Wl,--build-id=sha1 -Wl,--no-rosegment"
# Unlike Linux, Android does not implicitly use a dlopened library to resolve
# relocations in subsequently-loaded libraries, even if RTLD_GLOBAL is used
# (https://github.com/android/ndk/issues/1244). So any library that fails to
# build with this flag, would also fail to load at runtime.
LDFLAGS="$LDFLAGS -Wl,--no-undefined"
# Many packages get away with omitting -lm on Linux, but Android is stricter.
LDFLAGS="$LDFLAGS -lm"
# -mstackrealign is included where necessary in the clang launcher scripts which are
# pointed to by $CC, so we don't need to include it here.
if [ $HOST = "arm-linux-androideabi" ]; then
CFLAGS="$CFLAGS -march=armv7-a -mthumb"
fi
if [ -n "${PREFIX:-}" ]; then
abs_prefix=$(realpath $PREFIX)
CFLAGS="$CFLAGS -I$abs_prefix/include"
LDFLAGS="$LDFLAGS -L$abs_prefix/lib"
export PKG_CONFIG="pkg-config --define-prefix"
export PKG_CONFIG_LIBDIR="$abs_prefix/lib/pkgconfig"
fi
# Use the same variable name as conda-build
if [ $(uname) = "Darwin" ]; then
export CPU_COUNT=$(sysctl -n hw.ncpu)
else
export CPU_COUNT=$(nproc)
fi

237
Android/android.py Executable file
View file

@ -0,0 +1,237 @@
#!/usr/bin/env python3
import argparse
import os
import re
import shutil
import subprocess
import sys
import sysconfig
from os.path import basename, relpath
from pathlib import Path
from tempfile import TemporaryDirectory
SCRIPT_NAME = Path(__file__).name
CHECKOUT = Path(__file__).resolve().parent.parent
CROSS_BUILD_DIR = CHECKOUT / "cross-build"
def delete_if_exists(path):
if path.exists():
print(f"Deleting {path} ...")
shutil.rmtree(path)
def subdir(name, *, clean=None):
path = CROSS_BUILD_DIR / name
if clean:
delete_if_exists(path)
if not path.exists():
if clean is None:
sys.exit(
f"{path} does not exist. Create it by running the appropriate "
f"`configure` subcommand of {SCRIPT_NAME}.")
else:
path.mkdir(parents=True)
return path
def run(command, *, host=None, **kwargs):
env = os.environ.copy()
if host:
env_script = CHECKOUT / "Android/android-env.sh"
env_output = subprocess.run(
f"set -eu; "
f"HOST={host}; "
f"PREFIX={subdir(host)}/prefix; "
f". {env_script}; "
f"export",
check=True, shell=True, text=True, stdout=subprocess.PIPE
).stdout
for line in env_output.splitlines():
# We don't require every line to match, as there may be some other
# output from installing the NDK.
if match := re.search(
"^(declare -x |export )?(\\w+)=['\"]?(.*?)['\"]?$", line
):
key, value = match[2], match[3]
if env.get(key) != value:
print(line)
env[key] = value
if env == os.environ:
raise ValueError(f"Found no variables in {env_script.name} output:\n"
+ env_output)
print(">", " ".join(map(str, command)))
try:
subprocess.run(command, check=True, env=env, **kwargs)
except subprocess.CalledProcessError as e:
sys.exit(e)
def build_python_path():
"""The path to the build Python binary."""
build_dir = subdir("build")
binary = build_dir / "python"
if not binary.is_file():
binary = binary.with_suffix(".exe")
if not binary.is_file():
raise FileNotFoundError("Unable to find `python(.exe)` in "
f"{build_dir}")
return binary
def configure_build_python(context):
os.chdir(subdir("build", clean=context.clean))
command = [relpath(CHECKOUT / "configure")]
if context.args:
command.extend(context.args)
run(command)
def make_build_python(context):
os.chdir(subdir("build"))
run(["make", "-j", str(os.cpu_count())])
def unpack_deps(host):
deps_url = "https://github.com/beeware/cpython-android-source-deps/releases/download"
for name_ver in ["bzip2-1.0.8-1", "libffi-3.4.4-2", "openssl-3.0.13-1",
"sqlite-3.45.1-0", "xz-5.4.6-0"]:
filename = f"{name_ver}-{host}.tar.gz"
download(f"{deps_url}/{name_ver}/{filename}")
run(["tar", "-xf", filename])
os.remove(filename)
def download(url, target_dir="."):
out_path = f"{target_dir}/{basename(url)}"
run(["curl", "-Lf", "-o", out_path, url])
return out_path
def configure_host_python(context):
host_dir = subdir(context.host, clean=context.clean)
prefix_dir = host_dir / "prefix"
if not prefix_dir.exists():
prefix_dir.mkdir()
os.chdir(prefix_dir)
unpack_deps(context.host)
build_dir = host_dir / "build"
build_dir.mkdir(exist_ok=True)
os.chdir(build_dir)
command = [
# Basic cross-compiling configuration
relpath(CHECKOUT / "configure"),
f"--host={context.host}",
f"--build={sysconfig.get_config_var('BUILD_GNU_TYPE')}",
f"--with-build-python={build_python_path()}",
"--without-ensurepip",
# Android always uses a shared libpython.
"--enable-shared",
"--without-static-libpython",
# Dependent libraries. The others are found using pkg-config: see
# android-env.sh.
f"--with-openssl={prefix_dir}",
]
if context.args:
command.extend(context.args)
run(command, host=context.host)
def make_host_python(context):
host_dir = subdir(context.host)
os.chdir(host_dir / "build")
run(["make", "-j", str(os.cpu_count())], host=context.host)
run(["make", "install", f"prefix={host_dir}/prefix"], host=context.host)
def build_all(context):
steps = [configure_build_python, make_build_python, configure_host_python,
make_host_python]
for step in steps:
step(context)
def clean_all(context):
delete_if_exists(CROSS_BUILD_DIR)
# To avoid distributing compiled artifacts without corresponding source code,
# the Gradle wrapper is not included in the CPython repository. Instead, we
# extract it from the Gradle release.
def setup_testbed(context):
ver_long = "8.7.0"
ver_short = ver_long.removesuffix(".0")
testbed_dir = CHECKOUT / "Android/testbed"
for filename in ["gradlew", "gradlew.bat"]:
out_path = download(
f"https://raw.githubusercontent.com/gradle/gradle/v{ver_long}/{filename}",
testbed_dir)
os.chmod(out_path, 0o755)
with TemporaryDirectory(prefix=SCRIPT_NAME) as temp_dir:
os.chdir(temp_dir)
bin_zip = download(
f"https://services.gradle.org/distributions/gradle-{ver_short}-bin.zip")
outer_jar = f"gradle-{ver_short}/lib/plugins/gradle-wrapper-{ver_short}.jar"
run(["unzip", bin_zip, outer_jar])
run(["unzip", "-o", "-d", f"{testbed_dir}/gradle/wrapper", outer_jar,
"gradle-wrapper.jar"])
def main():
parser = argparse.ArgumentParser()
subcommands = parser.add_subparsers(dest="subcommand")
build = subcommands.add_parser("build", help="Build everything")
configure_build = subcommands.add_parser("configure-build",
help="Run `configure` for the "
"build Python")
make_build = subcommands.add_parser("make-build",
help="Run `make` for the build Python")
configure_host = subcommands.add_parser("configure-host",
help="Run `configure` for Android")
make_host = subcommands.add_parser("make-host",
help="Run `make` for Android")
subcommands.add_parser(
"clean", help="Delete the cross-build directory")
subcommands.add_parser(
"setup-testbed", help="Download the testbed Gradle wrapper")
for subcommand in build, configure_build, configure_host:
subcommand.add_argument(
"--clean", action="store_true", default=False, dest="clean",
help="Delete any relevant directories before building")
for subcommand in build, configure_host, make_host:
subcommand.add_argument(
"host", metavar="HOST",
choices=["aarch64-linux-android", "x86_64-linux-android"],
help="Host triplet: choices=[%(choices)s]")
for subcommand in build, configure_build, configure_host:
subcommand.add_argument("args", nargs="*",
help="Extra arguments to pass to `configure`")
context = parser.parse_args()
dispatch = {"configure-build": configure_build_python,
"make-build": make_build_python,
"configure-host": configure_host_python,
"make-host": make_host_python,
"build": build_all,
"clean": clean_all,
"setup-testbed": setup_testbed}
dispatch[context.subcommand](context)
if __name__ == "__main__":
main()

21
Android/testbed/.gitignore vendored Normal file
View file

@ -0,0 +1,21 @@
# The Gradle wrapper should be downloaded by running `../android.py setup-testbed`.
/gradlew
/gradlew.bat
/gradle/wrapper/gradle-wrapper.jar
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/deploymentTargetDropdown.xml
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties

1
Android/testbed/app/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/build

View file

@ -0,0 +1,129 @@
import com.android.build.api.variant.*
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
}
val PYTHON_DIR = File(projectDir, "../../..").canonicalPath
val PYTHON_CROSS_DIR = "$PYTHON_DIR/cross-build"
val ABIS = mapOf(
"arm64-v8a" to "aarch64-linux-android",
"x86_64" to "x86_64-linux-android",
)
val PYTHON_VERSION = File("$PYTHON_DIR/Include/patchlevel.h").useLines {
for (line in it) {
val match = """#define PY_VERSION\s+"(\d+\.\d+)""".toRegex().find(line)
if (match != null) {
return@useLines match.groupValues[1]
}
}
throw GradleException("Failed to find Python version")
}
android {
namespace = "org.python.testbed"
compileSdk = 34
defaultConfig {
applicationId = "org.python.testbed"
minSdk = 21
targetSdk = 34
versionCode = 1
versionName = "1.0"
ndk.abiFilters.addAll(ABIS.keys)
externalNativeBuild.cmake.arguments(
"-DPYTHON_CROSS_DIR=$PYTHON_CROSS_DIR",
"-DPYTHON_VERSION=$PYTHON_VERSION")
}
externalNativeBuild.cmake {
path("src/main/c/CMakeLists.txt")
}
// Set this property to something non-empty, otherwise it'll use the default
// list, which ignores asset directories beginning with an underscore.
aaptOptions.ignoreAssetsPattern = ".git"
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
}
dependencies {
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.11.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
}
// Create some custom tasks to copy Python and its standard library from
// elsewhere in the repository.
androidComponents.onVariants { variant ->
generateTask(variant, variant.sources.assets!!) {
into("python") {
for (triplet in ABIS.values) {
for (subDir in listOf("include", "lib")) {
into(subDir) {
from("$PYTHON_CROSS_DIR/$triplet/prefix/$subDir")
include("python$PYTHON_VERSION/**")
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
}
}
into("lib/python$PYTHON_VERSION") {
// Uncomment this to pick up edits from the source directory
// without having to rerun `make install`.
// from("$PYTHON_DIR/Lib")
// duplicatesStrategy = DuplicatesStrategy.INCLUDE
into("site-packages") {
from("$projectDir/src/main/python")
}
}
}
exclude("**/__pycache__")
}
generateTask(variant, variant.sources.jniLibs!!) {
for ((abi, triplet) in ABIS.entries) {
into(abi) {
from("$PYTHON_CROSS_DIR/$triplet/prefix/lib")
include("libpython*.*.so")
include("lib*_python.so")
}
}
}
}
fun generateTask(
variant: ApplicationVariant, directories: SourceDirectories,
configure: GenerateTask.() -> Unit
) {
val taskName = "generate" +
listOf(variant.name, "Python", directories.name)
.map { it.replaceFirstChar(Char::uppercase) }
.joinToString("")
directories.addGeneratedSourceDirectory(
tasks.register<GenerateTask>(taskName) {
into(outputDir)
configure()
},
GenerateTask::outputDir)
}
// addGeneratedSourceDirectory requires the task to have a DirectoryProperty.
abstract class GenerateTask: Sync() {
@get:OutputDirectory
abstract val outputDir: DirectoryProperty
}

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.Material3.Light.NoActionBar">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View file

@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.4.1)
project(testbed)
set(PREFIX_DIR ${PYTHON_CROSS_DIR}/${CMAKE_LIBRARY_ARCHITECTURE}/prefix)
include_directories(${PREFIX_DIR}/include/python${PYTHON_VERSION})
link_directories(${PREFIX_DIR}/lib)
link_libraries(log python${PYTHON_VERSION})
add_library(main_activity SHARED main_activity.c)

View file

@ -0,0 +1,147 @@
#include <android/log.h>
#include <errno.h>
#include <jni.h>
#include <pthread.h>
#include <Python.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
static void throw_runtime_exception(JNIEnv *env, const char *message) {
(*env)->ThrowNew(
env,
(*env)->FindClass(env, "java/lang/RuntimeException"),
message);
}
// --- Stdio redirection ------------------------------------------------------
// Most apps won't need this, because the Python-level sys.stdout and sys.stderr
// are redirected to the Android logcat by Python itself. However, in the
// testbed it's useful to redirect the native streams as well, to debug problems
// in the Python startup or redirection process.
//
// Based on
// https://github.com/beeware/briefcase-android-gradle-template/blob/v0.3.11/%7B%7B%20cookiecutter.safe_formal_name%20%7D%7D/app/src/main/cpp/native-lib.cpp
typedef struct {
FILE *file;
int fd;
android_LogPriority priority;
char *tag;
int pipe[2];
} StreamInfo;
static StreamInfo STREAMS[] = {
{stdout, STDOUT_FILENO, ANDROID_LOG_INFO, "native.stdout", {-1, -1}},
{stderr, STDERR_FILENO, ANDROID_LOG_WARN, "native.stderr", {-1, -1}},
{NULL, -1, ANDROID_LOG_UNKNOWN, NULL, {-1, -1}},
};
// The maximum length of a log message in bytes, including the level marker and
// tag, is defined as LOGGER_ENTRY_MAX_PAYLOAD in
// platform/system/logging/liblog/include/log/log.h. As of API level 30, messages
// longer than this will be be truncated by logcat. This limit has already been
// reduced at least once in the history of Android (from 4076 to 4068 between API
// level 23 and 26), so leave some headroom.
static const int MAX_BYTES_PER_WRITE = 4000;
static void *redirection_thread(void *arg) {
StreamInfo *si = (StreamInfo*)arg;
ssize_t read_size;
char buf[MAX_BYTES_PER_WRITE];
while ((read_size = read(si->pipe[0], buf, sizeof buf - 1)) > 0) {
buf[read_size] = '\0'; /* add null-terminator */
__android_log_write(si->priority, si->tag, buf);
}
return 0;
}
static char *redirect_stream(StreamInfo *si) {
/* make the FILE unbuffered, to ensure messages are never lost */
if (setvbuf(si->file, 0, _IONBF, 0)) {
return "setvbuf";
}
/* create the pipe and redirect the file descriptor */
if (pipe(si->pipe)) {
return "pipe";
}
if (dup2(si->pipe[1], si->fd) == -1) {
return "dup2";
}
/* start the logging thread */
pthread_t thr;
if ((errno = pthread_create(&thr, 0, redirection_thread, si))) {
return "pthread_create";
}
if ((errno = pthread_detach(thr))) {
return "pthread_detach";
}
return 0;
}
JNIEXPORT void JNICALL Java_org_python_testbed_MainActivity_redirectStdioToLogcat(
JNIEnv *env, jobject obj
) {
for (StreamInfo *si = STREAMS; si->file; si++) {
char *error_prefix;
if ((error_prefix = redirect_stream(si))) {
char error_message[1024];
snprintf(error_message, sizeof(error_message),
"%s: %s", error_prefix, strerror(errno));
throw_runtime_exception(env, error_message);
return;
}
}
}
// --- Python intialization ----------------------------------------------------
static PyStatus set_config_string(
JNIEnv *env, PyConfig *config, wchar_t **config_str, jstring value
) {
const char *value_utf8 = (*env)->GetStringUTFChars(env, value, NULL);
PyStatus status = PyConfig_SetBytesString(config, config_str, value_utf8);
(*env)->ReleaseStringUTFChars(env, value, value_utf8);
return status;
}
static void throw_status(JNIEnv *env, PyStatus status) {
throw_runtime_exception(env, status.err_msg ? status.err_msg : "");
}
JNIEXPORT void JNICALL Java_org_python_testbed_MainActivity_runPython(
JNIEnv *env, jobject obj, jstring home, jstring runModule
) {
PyConfig config;
PyStatus status;
PyConfig_InitIsolatedConfig(&config);
status = set_config_string(env, &config, &config.home, home);
if (PyStatus_Exception(status)) {
throw_status(env, status);
return;
}
status = set_config_string(env, &config, &config.run_module, runModule);
if (PyStatus_Exception(status)) {
throw_status(env, status);
return;
}
// Some tests generate SIGPIPE and SIGXFSZ, which should be ignored.
config.install_signal_handlers = 1;
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
throw_status(env, status);
return;
}
Py_RunMain();
}

View file

@ -0,0 +1,61 @@
package org.python.testbed
import android.os.*
import android.system.Os
import android.widget.TextView
import androidx.appcompat.app.*
import java.io.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Python needs this variable to help it find the temporary directory,
// but Android only sets it on API level 33 and later.
Os.setenv("TMPDIR", cacheDir.toString(), false)
val pythonHome = extractAssets()
System.loadLibrary("main_activity")
redirectStdioToLogcat()
runPython(pythonHome.toString(), "main")
findViewById<TextView>(R.id.tvHello).text = "Python complete"
}
private fun extractAssets() : File {
val pythonHome = File(filesDir, "python")
if (pythonHome.exists() && !pythonHome.deleteRecursively()) {
throw RuntimeException("Failed to delete $pythonHome")
}
extractAssetDir("python", filesDir)
return pythonHome
}
private fun extractAssetDir(path: String, targetDir: File) {
val names = assets.list(path)
?: throw RuntimeException("Failed to list $path")
val targetSubdir = File(targetDir, path)
if (!targetSubdir.mkdirs()) {
throw RuntimeException("Failed to create $targetSubdir")
}
for (name in names) {
val subPath = "$path/$name"
val input: InputStream
try {
input = assets.open(subPath)
} catch (e: FileNotFoundException) {
extractAssetDir(subPath, targetDir)
continue
}
input.use {
File(targetSubdir, name).outputStream().use { output ->
input.copyTo(output)
}
}
}
}
private external fun redirectStdioToLogcat()
private external fun runPython(home: String, runModule: String)
}

View file

@ -0,0 +1,17 @@
import runpy
import signal
import sys
# Some tests use SIGUSR1, but that's blocked by default in an Android app in
# order to make it available to `sigwait` in the "Signal Catcher" thread. That
# thread's functionality is only relevant to the JVM ("forcing GC (no HPROF) and
# profile save"), so disabling it should not weaken the tests.
signal.pthread_sigmask(signal.SIG_UNBLOCK, [signal.SIGUSR1])
# To run specific tests, or pass any other arguments to the test suite, edit
# this command line.
sys.argv[1:] = [
"--use", "all,-cpu",
"--verbose3",
]
runpy.run_module("test")

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/tvHello"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,3 @@
<resources>
<string name="app_name">Python testbed</string>
</resources>

View file

@ -0,0 +1,5 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("com.android.application") version "8.2.2" apply false
id("org.jetbrains.kotlin.android") version "1.9.22" apply false
}

View file

@ -0,0 +1,23 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true

View file

@ -0,0 +1,6 @@
#Mon Feb 19 20:29:06 GMT 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View file

@ -0,0 +1,18 @@
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "Python testbed"
include(":app")

View file

@ -7,31 +7,34 @@
PYTHON = python3
VENVDIR = ./venv
SPHINXBUILD = PATH=$(VENVDIR)/bin:$$PATH sphinx-build
SPHINXLINT = PATH=$(VENVDIR)/bin:$$PATH sphinx-lint
BLURB = PATH=$(VENVDIR)/bin:$$PATH blurb
JOBS = auto
PAPER =
SOURCES =
DISTVERSION = $(shell $(PYTHON) tools/extensions/patchlevel.py)
REQUIREMENTS = requirements.txt
SPHINXERRORHANDLING = -W
SERVE_PORT =
# Internal variables.
PAPEROPT_a4 = -D latex_elements.papersize=a4paper
PAPEROPT_letter = -D latex_elements.papersize=letterpaper
ALLSPHINXOPTS = -b $(BUILDER) -d build/doctrees $(PAPEROPT_$(PAPER)) \
$(SPHINXOPTS) $(SPHINXERRORHANDLING) . build/$(BUILDER) $(SOURCES)
.PHONY: help build html htmlhelp latex text texinfo changes linkcheck \
suspicious coverage doctest pydoc-topics htmlview clean dist check serve \
autobuild-dev autobuild-stable venv
ALLSPHINXOPTS = -b $(BUILDER) \
-d build/doctrees \
-j $(JOBS) \
$(PAPEROPT_$(PAPER)) \
$(SPHINXOPTS) $(SPHINXERRORHANDLING) \
. build/$(BUILDER) $(SOURCES)
.PHONY: help
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " clean to remove build files"
@echo " venv to create a venv with necessary tools"
@echo " html to make standalone HTML files"
@echo " gettext to generate POT files"
@echo " htmlview to open the index page built by the html target in your browser"
@echo " htmllive to rebuild and reload HTML files in your browser"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " text to make plain text files"
@ -43,10 +46,9 @@ help:
@echo " doctest to run doctests in the documentation"
@echo " pydoc-topics to regenerate the pydoc topics file"
@echo " dist to create a \"dist\" directory with archived docs for download"
@echo " suspicious to check for suspicious markup in output text"
@echo " check to run a check for frequent markup errors"
@echo " serve to serve the documentation on the localhost (8000)"
.PHONY: build
build:
-mkdir -p build
# Look first for a Misc/NEWS file (building from a source release tarball
@ -73,38 +75,46 @@ build:
$(SPHINXBUILD) $(ALLSPHINXOPTS)
@echo
.PHONY: html
html: BUILDER = html
html: build
@echo "Build finished. The HTML pages are in build/html."
.PHONY: htmlhelp
htmlhelp: BUILDER = htmlhelp
htmlhelp: build
@echo "Build finished; now you can run HTML Help Workshop with the" \
"build/htmlhelp/pydoc.hhp project file."
.PHONY: latex
latex: BUILDER = latex
latex: build
@echo "Build finished; the LaTeX files are in build/latex."
@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
"run these through (pdf)latex."
.PHONY: text
text: BUILDER = text
text: build
@echo "Build finished; the text files are in build/text."
.PHONY: texinfo
texinfo: BUILDER = texinfo
texinfo: build
@echo "Build finished; the python.texi file is in build/texinfo."
@echo "Run \`make info' in that directory to run it through makeinfo."
.PHONY: epub
epub: BUILDER = epub
epub: build
@echo "Build finished; the epub files are in build/epub."
.PHONY: changes
changes: BUILDER = changes
changes: build
@echo "The overview file is in build/changes."
.PHONY: linkcheck
linkcheck: BUILDER = linkcheck
linkcheck:
@$(MAKE) build BUILDER=$(BUILDER) || { \
@ -112,22 +122,12 @@ linkcheck:
"or in build/$(BUILDER)/output.txt"; \
false; }
suspicious: BUILDER = suspicious
suspicious:
@$(MAKE) build BUILDER=$(BUILDER) || { \
echo "Suspicious check complete; look for any errors in the above output" \
"or in build/$(BUILDER)/suspicious.csv. If all issues are false" \
"positives, append that file to tools/susp-ignored.csv."; \
false; }
@echo "⚠ make suspicious is deprecated and will be removed soon."
@echo "⚠ Use:"
@echo "⚠ make check"
@echo "⚠ instead."
.PHONY: coverage
coverage: BUILDER = coverage
coverage: build
@echo "Coverage finished; see c.txt and python.txt in build/coverage"
.PHONY: doctest
doctest: BUILDER = doctest
doctest:
@$(MAKE) build BUILDER=$(BUILDER) || { \
@ -135,31 +135,48 @@ doctest:
"results in build/doctest/output.txt"; \
false; }
.PHONY: pydoc-topics
pydoc-topics: BUILDER = pydoc-topics
pydoc-topics: build
@echo "Building finished; now run this:" \
"cp build/pydoc-topics/topics.py ../Lib/pydoc_data/topics.py"
htmlview: html
$(PYTHON) -c "import webbrowser; webbrowser.open('build/html/index.html')"
.PHONY: gettext
gettext: BUILDER = gettext
gettext: SPHINXOPTS += '-d build/doctrees-gettext'
gettext: build
.PHONY: htmlview
htmlview: html
$(PYTHON) -c "import os, webbrowser; webbrowser.open('file://' + os.path.realpath('build/html/index.html'))"
.PHONY: htmllive
htmllive: SPHINXBUILD = $(VENVDIR)/bin/sphinx-autobuild
htmllive: SPHINXOPTS = --re-ignore="/venv/" --open-browser --delay 0
htmllive: html
.PHONY: clean
clean: clean-venv
-rm -rf build/*
.PHONY: clean-venv
clean-venv:
rm -rf $(VENVDIR)
.PHONY: venv
venv:
@if [ -d $(VENVDIR) ] ; then \
echo "venv already exists."; \
echo "To recreate it, remove it first with \`make clean-venv'."; \
else \
echo "Creating venv in $(VENVDIR)"; \
$(PYTHON) -m venv $(VENVDIR); \
$(VENVDIR)/bin/python3 -m pip install -U pip setuptools; \
$(VENVDIR)/bin/python3 -m pip install -r requirements.txt; \
$(VENVDIR)/bin/python3 -m pip install --upgrade pip; \
$(VENVDIR)/bin/python3 -m pip install -r $(REQUIREMENTS); \
echo "The venv has been created in the $(VENVDIR) directory"; \
fi
.PHONY: dist
dist:
rm -rf dist
mkdir -p dist
@ -214,12 +231,14 @@ dist:
rm -r dist/python-$(DISTVERSION)-docs-texinfo
rm dist/python-$(DISTVERSION)-docs-texinfo.tar
check:
$(SPHINXLINT) -i tools -i $(VENVDIR) -i README.rst
$(SPHINXLINT) ../Misc/NEWS.d/next/
.PHONY: check
check: venv
$(VENVDIR)/bin/python3 -m pre_commit --version > /dev/null || $(VENVDIR)/bin/python3 -m pip install pre-commit
$(VENVDIR)/bin/python3 -m pre_commit run --all-files
.PHONY: serve
serve:
$(PYTHON) ../Tools/scripts/serve.py build/html $(SERVE_PORT)
@echo "The serve target was removed, use htmlview instead (see bpo-36329)"
# Targets for daily automated doc build
# By default, Sphinx only rebuilds pages where the page content has changed.
@ -229,15 +248,18 @@ serve:
# output files)
# for development releases: always build
.PHONY: autobuild-dev
autobuild-dev:
make dist SPHINXOPTS='$(SPHINXOPTS) -Ea -A daily=1'
# for quick rebuilds (HTML only)
.PHONY: autobuild-dev-html
autobuild-dev-html:
make html SPHINXOPTS='$(SPHINXOPTS) -Ea -A daily=1'
# for stable releases: only build if not in pre-release stage (alpha, beta)
# release candidate downloads are okay, since the stable tree can be in that stage
.PHONY: autobuild-stable
autobuild-stable:
@case $(DISTVERSION) in *[ab]*) \
echo "Not building; $(DISTVERSION) is not a release version."; \
@ -245,6 +267,7 @@ autobuild-stable:
esac
@make autobuild-dev
.PHONY: autobuild-stable-html
autobuild-stable-html:
@case $(DISTVERSION) in *[ab]*) \
echo "Not building; $(DISTVERSION) is not a release version."; \

View file

@ -40,7 +40,7 @@ If you'd like to create the virtual environment in a different location,
you can specify it using the ``VENVDIR`` variable.
You can also skip creating the virtual environment altogether, in which case
the Makefile will look for instances of ``sphinxbuild`` and ``blurb``
the Makefile will look for instances of ``sphinx-build`` and ``blurb``
installed on your process ``PATH`` (configurable with the ``SPHINXBUILD`` and
``BLURB`` variables).
@ -93,9 +93,6 @@ Available make targets are:
plain text documentation for the labels defined in
``tools/pyspecific.py`` -- pydoc needs these to show topic and keyword help.
* "suspicious", which checks the parsed markup for text that looks like
malformed and thus unconverted reST.
* "check", which checks for frequent markup errors.
* "serve", which serves the build/html directory on port 8000.
@ -130,7 +127,7 @@ Contributing
============
Bugs in the content should be reported to the
`Python bug tracker <https://bugs.python.org>`_.
`Python bug tracker <https://github.com/python/cpython/issues>`_.
Bugs in the toolset should be reported to the tools themselves.

BIN
Doc/_static/og-image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -6,8 +6,8 @@ About these documents
These documents are generated from `reStructuredText`_ sources by `Sphinx`_, a
document processor specifically written for the Python documentation.
.. _reStructuredText: http://docutils.sourceforge.net/rst.html
.. _Sphinx: http://sphinx-doc.org/
.. _reStructuredText: https://docutils.sourceforge.io/rst.html
.. _Sphinx: https://www.sphinx-doc.org/
.. In the online version of these documents, you can submit comments and suggest
changes directly on the documentation pages.
@ -21,7 +21,7 @@ Many thanks go to:
* Fred L. Drake, Jr., the creator of the original Python documentation toolset
and writer of much of the content;
* the `Docutils <http://docutils.sourceforge.net/>`_ project for creating
* the `Docutils <https://docutils.sourceforge.io/>`_ project for creating
reStructuredText and the Docutils suite;
* Fredrik Lundh for his Alternative Python Reference project from which Sphinx
got many good ideas.

View file

@ -19,6 +19,13 @@ If you find a bug in this documentation or would like to propose an improvement,
please submit a bug report on the :ref:`tracker <using-the-tracker>`. If you
have a suggestion on how to fix it, include that as well.
You can also open a discussion item on our
`Documentation Discourse forum <https://discuss.python.org/c/documentation/26>`_.
If you find a bug in the theme (HTML / CSS / JavaScript) of the
documentation, please submit a bug report on the `python-doc-theme bug
tracker <https://github.com/python/python-docs-theme>`_.
If you're short on time, you can also email documentation bug reports to
docs@python.org (behavioral bugs can be sent to python-list@python.org).
'docs@' is a mailing list run by volunteers; your request will be noticed,
@ -35,7 +42,7 @@ though it may take a while to be processed.
`Helping with Documentation <https://devguide.python.org/docquality/#helping-with-documentation>`_
Comprehensive guide for individuals that are interested in contributing to Python documentation.
`Documentation Translations <https://devguide.python.org/documenting/#translating>`_
`Documentation Translations <https://devguide.python.org/documentation/translating/>`_
A list of GitHub pages for documentation translation and their primary contacts.
@ -67,7 +74,7 @@ Click on the "New issue" button in the top bar to report a new issue.
The submission form has two fields, "Title" and "Comment".
For the "Title" field, enter a *very* short description of the problem;
less than ten words is good.
fewer than ten words is good.
In the "Comment" field, describe the problem in detail, including what you
expected to happen and what did happen. Be sure to include whether any

View file

@ -24,4 +24,3 @@ but whose items have not been set to some non-\ ``NULL`` value yet.
mapping.rst
iter.rst
buffer.rst
objbuffer.rst

View file

@ -14,7 +14,7 @@ Allocating Objects on the Heap
.. c:function:: PyObject* PyObject_Init(PyObject *op, PyTypeObject *type)
Initialize a newly-allocated object *op* with its type and initial
Initialize a newly allocated object *op* with its type and initial
reference. Returns the initialized object. If *type* indicates that the
object participates in the cyclic garbage detector, it is added to the
detector's set of observed objects. Other fields of the object are not
@ -27,22 +27,26 @@ Allocating Objects on the Heap
length information for a variable-size object.
.. c:function:: TYPE* PyObject_New(TYPE, PyTypeObject *type)
.. c:macro:: PyObject_New(TYPE, typeobj)
Allocate a new Python object using the C structure type *TYPE*
and the Python type object *typeobj* (``PyTypeObject*``).
Fields not defined by the Python object header are not initialized.
The caller will own the only reference to the object
(i.e. its reference count will be one).
The size of the memory allocation is determined from the
:c:member:`~PyTypeObject.tp_basicsize` field of the type object.
.. c:macro:: PyObject_NewVar(TYPE, typeobj, size)
Allocate a new Python object using the C structure type *TYPE* and the
Python type object *type*. Fields not defined by the Python object header
are not initialized; the object's reference count will be one. The size of
the memory allocation is determined from the :c:member:`~PyTypeObject.tp_basicsize` field of
the type object.
.. c:function:: TYPE* PyObject_NewVar(TYPE, PyTypeObject *type, Py_ssize_t size)
Allocate a new Python object using the C structure type *TYPE* and the
Python type object *type*. Fields not defined by the Python object header
Python type object *typeobj* (``PyTypeObject*``).
Fields not defined by the Python object header
are not initialized. The allocated memory allows for the *TYPE* structure
plus *size* fields of the size given by the :c:member:`~PyTypeObject.tp_itemsize` field of
*type*. This is useful for implementing objects like tuples, which are
plus *size* (``Py_ssize_t``) fields of the size
given by the :c:member:`~PyTypeObject.tp_itemsize` field of
*typeobj*. This is useful for implementing objects like tuples, which are
able to determine their size at construction time. Embedding the array of
fields into the same allocation decreases the number of allocations,
improving the memory management efficiency.
@ -50,8 +54,8 @@ Allocating Objects on the Heap
.. c:function:: void PyObject_Del(void *op)
Releases memory allocated to an object using :c:func:`PyObject_New` or
:c:func:`PyObject_NewVar`. This is normally called from the
Releases memory allocated to an object using :c:macro:`PyObject_New` or
:c:macro:`PyObject_NewVar`. This is normally called from the
:c:member:`~PyTypeObject.tp_dealloc` handler specified in the object's type. The fields of
the object should not be accessed after this call as the memory is no
longer a valid Python object.

Some files were not shown because too many files have changed in this diff Show more