Merge branch 'main' into __instancecheck__

This commit is contained in:
Erlend E. Aasland 2024-01-05 12:31:29 +01:00 committed by GitHub
commit 6c7026fc48
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3966 changed files with 602833 additions and 377737 deletions

View file

@ -1,104 +1,23 @@
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.1l
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.1l
steps:
- template: ./posix-steps.yml
parameters:
dependencies: apt
coverage: true
- job: Windows_CI_Tests
displayName: Windows CI Tests
dependsOn: Prebuild
condition: and(succeeded(), eq(dependencies.Prebuild.outputs['tests.run'], 'true'))
pool:
vmImage: windows-2019
vmImage: windows-2022
strategy:
matrix:

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,59 +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: ./python Tools/scripts/patchcheck.py --travis 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.1l
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.1l
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-2019
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,65 +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'
- 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,129 +0,0 @@
name: Release_$(Build.SourceBranchName)_$(SourceTag)_$(Date:yyyyMMdd)$(Rev:.rr)
variables:
__RealSigningCertificate: 'Python Software Foundation'
# QUEUE TIME VARIABLES
# GitRemote: python
# SourceTag:
# DoPGO: true
# SigningCertificate: 'Python Software Foundation'
# SigningDescription: 'Built: $(Build.BuildNumber)'
# DoLayout: true
# DoMSIX: true
# DoNuget: true
# DoEmbed: true
# DoMSI: true
# DoPublish: false
# PyDotOrgUsername: ''
# PyDotOrgServer: ''
# BuildToPublish: ''
trigger: none
pr: none
stages:
- stage: Build
displayName: Build binaries
condition: and(succeeded(), not(variables['BuildToPublish']))
jobs:
- template: windows-release/stage-build.yml
- stage: Sign
displayName: Sign binaries
dependsOn: Build
condition: and(succeeded(), not(variables['BuildToPublish']))
jobs:
- template: windows-release/stage-sign.yml
- stage: Layout
displayName: Generate layouts
dependsOn: Sign
condition: and(succeeded(), not(variables['BuildToPublish']))
jobs:
- template: windows-release/stage-layout-full.yml
- template: windows-release/stage-layout-embed.yml
- template: windows-release/stage-layout-nuget.yml
- stage: Pack
dependsOn: Layout
condition: and(succeeded(), not(variables['BuildToPublish']))
jobs:
- template: windows-release/stage-pack-nuget.yml
- stage: Test
dependsOn: Pack
condition: and(succeeded(), not(variables['BuildToPublish']))
jobs:
- template: windows-release/stage-test-embed.yml
- template: windows-release/stage-test-nuget.yml
- stage: Layout_MSIX
displayName: Generate MSIX layouts
dependsOn: Sign
condition: and(succeeded(), and(eq(variables['DoMSIX'], 'true'), not(variables['BuildToPublish'])))
jobs:
- template: windows-release/stage-layout-msix.yml
- stage: Pack_MSIX
displayName: Package MSIX
dependsOn: Layout_MSIX
condition: and(succeeded(), not(variables['BuildToPublish']))
jobs:
- template: windows-release/stage-pack-msix.yml
- stage: Build_MSI
displayName: Build MSI installer
dependsOn: Sign
condition: and(succeeded(), and(eq(variables['DoMSI'], 'true'), not(variables['BuildToPublish'])))
jobs:
- template: windows-release/stage-msi.yml
- stage: Test_MSI
displayName: Test MSI installer
dependsOn: Build_MSI
condition: and(succeeded(), not(variables['BuildToPublish']))
jobs:
- template: windows-release/stage-test-msi.yml
- stage: PublishPyDotOrg
displayName: Publish to python.org
dependsOn: ['Test_MSI', 'Test']
condition: and(succeeded(), and(eq(variables['DoPublish'], 'true'), not(variables['BuildToPublish'])))
jobs:
- template: windows-release/stage-publish-pythonorg.yml
- stage: PublishNuget
displayName: Publish to nuget.org
dependsOn: Test
condition: and(succeeded(), and(eq(variables['DoPublish'], 'true'), not(variables['BuildToPublish'])))
jobs:
- template: windows-release/stage-publish-nugetorg.yml
- stage: PublishStore
displayName: Publish to Store
dependsOn: Pack_MSIX
condition: and(succeeded(), and(eq(variables['DoPublish'], 'true'), not(variables['BuildToPublish'])))
jobs:
- template: windows-release/stage-publish-store.yml
- stage: PublishExistingPyDotOrg
displayName: Publish existing build to python.org
dependsOn: []
condition: and(succeeded(), and(eq(variables['DoPublish'], 'true'), variables['BuildToPublish']))
jobs:
- template: windows-release/stage-publish-pythonorg.yml
- stage: PublishExistingNuget
displayName: Publish existing build to nuget.org
dependsOn: []
condition: and(succeeded(), and(eq(variables['DoPublish'], 'true'), variables['BuildToPublish']))
jobs:
- template: windows-release/stage-publish-nugetorg.yml
- stage: PublishExistingStore
displayName: Publish existing build to Store
dependsOn: []
condition: and(succeeded(), and(eq(variables['DoPublish'], 'true'), variables['BuildToPublish']))
jobs:
- template: windows-release/stage-publish-store.yml

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,28 +0,0 @@
parameters:
GPGKeyFile: $(GPGKey)
GPGPassphrase: $(GPGPassphrase)
Files: '*'
WorkingDirectory: $(Build.BinariesDirectory)
steps:
- task: DownloadSecureFile@1
name: gpgkey
inputs:
secureFile: ${{ parameters.GPGKeyFile }}
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)"
(gci -File ${{ parameters.Files }}).FullName | %{
gpg/gpg2.exe -ba --batch --passphrase ${{ parameters.GPGPassphrase }} $_
"Made signature for $_"
}
displayName: 'Generate GPG signatures'
workingDirectory: ${{ parameters.WorkingDirectory }}
- powershell: |
$p = gps "gpg-agent" -EA 0
if ($p) { $p.Kill() }
displayName: 'Kill GPG agent'
condition: true

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,135 +0,0 @@
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
contents: |
htmlhelp\*.chm
- 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: 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
- 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
%MSBUILD% Tools\msi\bundle\releaseweb.wixproj /t:Rebuild /p:RebuildAll=false
displayName: 'Build win32 installer'
env:
Platform: x86
Py_OutDir: $(Build.BinariesDirectory)
PYTHON: $(Build.BinariesDirectory)\win32\python.exe
PYTHONHOME: $(Build.SourcesDirectory)
TclTkLibraryDir: $(Build.BinariesDirectory)\tcltk_lib_win32
BuildForRelease: true
SuppressMinGWLib: true
- script: |
%MSBUILD% Tools\msi\bundle\releaselocal.wixproj /t:Rebuild /p:RebuildAll=true
%MSBUILD% Tools\msi\bundle\releaseweb.wixproj /t:Rebuild /p:RebuildAll=false
displayName: 'Build amd64 installer'
env:
Platform: x64
Py_OutDir: $(Build.BinariesDirectory)
PYTHON: $(Build.BinariesDirectory)\amd64\python.exe
PYTHONHOME: $(Build.SourcesDirectory)
TclTkLibraryDir: $(Build.BinariesDirectory)\tcltk_lib_amd64
BuildForRelease: true
SuppressMinGWLib: true
- task: CopyFiles@2
displayName: 'Assemble artifact: msi (1/2)'
inputs:
sourceFolder: $(Build.BinariesDirectory)\win32\en-us
targetFolder: $(Build.ArtifactStagingDirectory)\msi\win32
contents: |
*.msi
*.cab
*.exe
- task: CopyFiles@2
displayName: 'Assemble artifact: msi (2/2)'
inputs:
sourceFolder: $(Build.BinariesDirectory)\amd64\en-us
targetFolder: $(Build.ArtifactStagingDirectory)\msi\amd64
contents: |
*.msi
*.cab
*.exe
- task: PublishPipelineArtifact@0
displayName: 'Publish MSI'
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)\msi'
artifactName: msi

View file

@ -1,179 +0,0 @@
jobs:
- job: Build_Docs
displayName: Docs build
pool:
name: 'Windows Release'
#vmImage: windows-2019
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'
env:
BUILDDIR: $(Build.BinariesDirectory)\Doc
#- powershell: |
# mkdir -Force "$(Build.BinariesDirectory)\Doc\htmlhelp"
# iwr "https://www.python.org/ftp/python/3.8.0/python380.chm" -OutFile "$(Build.BinariesDirectory)\Doc\htmlhelp\python390a0.chm"
# displayName: 'Cheat at building CHM docs'
- 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-2019
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-2019
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-2019
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"
- 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

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-2019
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,75 +0,0 @@
jobs:
- job: Make_Layouts
displayName: Make layouts
condition: and(succeeded(), eq(variables['DoLayout'], 'true'))
pool:
vmImage: windows-2019
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)
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,97 +0,0 @@
jobs:
- job: Make_MSIX_Layout
displayName: Make MSIX layout
pool:
vmImage: windows-2019
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)
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-2019
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,36 +0,0 @@
jobs:
- job: Make_MSI
displayName: Make MSI
condition: and(succeeded(), not(variables['SigningCertificate']))
pool:
vmImage: windows-2019
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
- 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

View file

@ -1,144 +0,0 @@
jobs:
- job: Pack_MSIX
displayName: Pack MSIX bundles
pool:
vmImage: windows-2019
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
- 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,51 +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
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,46 +0,0 @@
jobs:
- job: Publish_Nuget
displayName: Publish Nuget packages
condition: and(succeeded(), eq(variables['DoNuget'], 'true'))
pool:
vmImage: windows-2019
workspace:
clean: all
steps:
- checkout: none
- task: DownloadBuildArtifacts@0
displayName: 'Download artifact: nuget'
condition: and(succeeded(), not(variables['BuildToPublish']))
inputs:
artifactName: nuget
downloadPath: $(Build.BinariesDirectory)
- task: DownloadBuildArtifacts@0
displayName: 'Download artifact: nuget'
condition: and(succeeded(), variables['BuildToPublish'])
inputs:
artifactName: nuget
downloadPath: $(Build.BinariesDirectory)
buildType: specific
project: cpython
pipeline: Windows-Release
buildVersionToDownload: specific
buildId: $(BuildToPublish)
- powershell: 'gci pythonarm*.nupkg | %{ Write-Host "Not publishing: $($_.Name)"; gi $_ } | del'
displayName: 'Prevent publishing ARM/ARM64 packages'
workingDirectory: '$(Build.BinariesDirectory)\nuget'
condition: and(succeeded(), not(variables['PublishArmPackages']))
- 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,158 +0,0 @@
jobs:
- job: Publish_Python
displayName: Publish python.org packages
condition: and(succeeded(), and(eq(variables['DoMSI'], 'true'), eq(variables['DoEmbed'], 'true')))
pool:
#vmImage: windows-2019
name: 'Windows Release'
workspace:
clean: all
steps:
- template: ./checkout.yml
- task: UsePythonVersion@0
displayName: 'Use Python 3.6 or later'
inputs:
versionSpec: '>=3.6'
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: Doc'
condition: and(succeeded(), not(variables['BuildToPublish']))
inputs:
artifactName: Doc
targetPath: $(Build.BinariesDirectory)\Doc
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact: msi'
condition: and(succeeded(), not(variables['BuildToPublish']))
inputs:
artifactName: msi
targetPath: $(Build.BinariesDirectory)\msi
- task: DownloadBuildArtifacts@0
displayName: 'Download artifact: embed'
condition: and(succeeded(), not(variables['BuildToPublish']))
inputs:
artifactName: embed
downloadPath: $(Build.BinariesDirectory)
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact from $(BuildToPublish): Doc'
condition: and(succeeded(), variables['BuildToPublish'])
inputs:
artifactName: Doc
targetPath: $(Build.BinariesDirectory)\Doc
buildType: specific
project: cpython
pipeline: 21
buildVersionToDownload: specific
buildId: $(BuildToPublish)
- task: DownloadPipelineArtifact@1
displayName: 'Download artifact from $(BuildToPublish): msi'
condition: and(succeeded(), variables['BuildToPublish'])
inputs:
artifactName: msi
targetPath: $(Build.BinariesDirectory)\msi
buildType: specific
project: cpython
pipeline: 21
buildVersionToDownload: specific
buildId: $(BuildToPublish)
- task: DownloadBuildArtifacts@0
displayName: 'Download artifact from $(BuildToPublish): embed'
condition: and(succeeded(), variables['BuildToPublish'])
inputs:
artifactName: embed
downloadPath: $(Build.BinariesDirectory)
buildType: specific
project: cpython
pipeline: Windows-Release
buildVersionToDownload: specific
buildId: $(BuildToPublish)
- powershell: 'gci *embed-arm*.zip | %{ Write-Host "Not publishing: $($_.Name)"; gi $_ } | del'
displayName: 'Prevent publishing ARM/ARM64 packages'
workingDirectory: '$(Build.BinariesDirectory)\embed'
condition: and(succeeded(), not(variables['PublishArmPackages']))
- template: ./gpg-sign.yml
parameters:
GPGKeyFile: 'python-signing.key'
Files: 'doc\htmlhelp\*.chm, msi\*\*, embed\*.zip'
- 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)
displayName: 'Purge CDN'
- powershell: |
$failures = 0
gci "msi\*\*-webinstall.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: |
$hashes = gci doc\htmlhelp\python*.chm, msi\*\*.exe, embed\*.zip | `
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:"
(gci msi\*\python*.asc, doc\htmlhelp\*.asc, embed\*.asc).FullName
$d = mkdir "$(Build.ArtifactStagingDirectory)\hashes" -Force
move msi\*\python*.asc, doc\htmlhelp\*.asc, embed\*.asc $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,35 +0,0 @@
jobs:
- job: Publish_Store
displayName: Publish Store packages
condition: and(succeeded(), eq(variables['DoMSIX'], 'true'))
pool:
vmImage: windows-2019
workspace:
clean: all
steps:
- checkout: none
- task: DownloadBuildArtifacts@0
displayName: 'Download artifact: msixupload'
condition: and(succeeded(), not(variables['BuildToPublish']))
inputs:
artifactName: msixupload
downloadPath: $(Build.BinariesDirectory)
- task: DownloadBuildArtifacts@0
displayName: 'Download artifact: msixupload'
condition: and(succeeded(), variables['BuildToPublish'])
inputs:
artifactName: msixupload
downloadPath: $(Build.BinariesDirectory)
buildType: specific
project: cpython
pipeline: Windows-Release
buildVersionToDownload: specific
buildId: $(BuildToPublish)
# 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 } | `
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-2019
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-2019
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-2019
workspace:
clean: all
strategy:
matrix:
win32_User:
ExeMatch: 'python-[\dabrc.]+-webinstall\.exe'
Logs: $(Build.ArtifactStagingDirectory)\logs\win32_User
InstallAllUsers: 0
win32_Machine:
ExeMatch: 'python-[\dabrc.]+-webinstall\.exe'
Logs: $(Build.ArtifactStagingDirectory)\logs\win32_Machine
InstallAllUsers: 1
amd64_User:
ExeMatch: 'python-[\dabrc.]+-amd64-webinstall\.exe'
Logs: $(Build.ArtifactStagingDirectory)\logs\amd64_User
InstallAllUsers: 0
amd64_Machine:
ExeMatch: 'python-[\dabrc.]+-amd64-webinstall\.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-2019
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'

29
.cirrus-DISABLED.yml Normal file
View file

@ -0,0 +1,29 @@
# gh-91960: Job disabled since Python is out of free credit (September 2023):
# https://discuss.python.org/t/freebsd-gets-a-new-cirrus-ci-github-action-job-and-a-new-buildbot/33122/26
freebsd_task:
freebsd_instance:
matrix:
- image: freebsd-13-2-release-amd64
# Turn off TCP and UDP blackhole. It is not enabled by default in FreeBSD,
# but it is in the FreeBSD GCE images as used by Cirrus-CI. It causes even
# local local connections to fail with ETIMEDOUT instead of ECONNREFUSED.
# For more information see https://reviews.freebsd.org/D41751 and
# https://github.com/cirruslabs/cirrus-ci-docs/issues/483.
sysctl_script:
- sysctl net.inet.tcp.blackhole=0
- sysctl net.inet.udp.blackhole=0
configure_script:
- mkdir build
- cd build
- ../configure --with-pydebug
build_script:
- cd build
- make -j$(sysctl -n hw.ncpu)
pythoninfo_script:
- cd build
- make pythoninfo
test_script:
- cd build
# dtrace fails to build on FreeBSD - see gh-73263
- make buildbottest TESTOPTS="-j0 -x test_dtrace --timeout=600"

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:37
ENV CC=clang
ENV WASI_SDK_VERSION=20
ENV WASI_SDK_PATH=/opt/wasi-sdk
ENV WASMTIME_HOME=/opt/wasmtime
ENV WASMTIME_VERSION=14.0.4
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

@ -8,5 +8,8 @@ indent_style = space
[*.{py,c,cpp,h}]
indent_size = 4
[*.rst]
indent_size = 3
[*.yml]
indent_size = 2

101
.gitattributes vendored
View file

@ -18,48 +18,34 @@
*.zip binary
# Specific binary files
Lib/test/sndhdrdata/sndhdr.* binary
PC/classicAppCompat.* binary
# Text files that should not be subject to eol conversion
Lib/test/cjkencodings/* -text
Lib/test/decimaltestdata/*.decTest -text
Lib/test/test_email/data/*.txt -text
Lib/test/xmltestdata/* -text
Lib/test/coding20731.py -text
Lib/test/test_importlib/data01/* -text
Lib/test/test_importlib/namespacedata01/* -text
[attr]noeol -text
Lib/test/cjkencodings/* noeol
Lib/test/tokenizedata/coding20731.py noeol
Lib/test/decimaltestdata/*.decTest noeol
Lib/test/test_email/data/*.txt 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
*.bat text eol=crlf
*.ps1 text eol=crlf
*.sln text eol=crlf
*.vcxproj* text eol=crlf
*.props text eol=crlf
*.proj text eol=crlf
PCbuild/readme.txt text eol=crlf
PC/readme.txt text eol=crlf
[attr]dos text eol=crlf
# Generated files
# https://github.com/github/linguist#generated-code
Modules/clinic/*.h linguist-generated=true
Objects/clinic/*.h linguist-generated=true
PC/clinic/*.h linguist-generated=true
Python/clinic/*.h linguist-generated=true
Python/deepfreeze/*.c linguist-generated=true
Python/frozen_modules/*.h linguist-generated=true
Python/frozen_modules/MANIFEST linguist-generated=true
Include/internal/pycore_ast.h linguist-generated=true
Python/Python-ast.c linguist-generated=true
Include/opcode.h linguist-generated=true
Python/opcode_targets.h linguist-generated=true
Objects/typeslots.inc linguist-generated=true
*_db.h linguist-generated=true
Doc/library/token-list.inc linguist-generated=true
Include/token.h linguist-generated=true
Lib/token.py linguist-generated=true
Parser/token.c linguist-generated=true
Programs/test_frozenmain.h linguist-generated=true
*.bat dos
*.proj dos
*.props dos
*.ps1 dos
*.sln dos
*.vcxproj* dos
PC/readme.txt dos
PCbuild/readme.txt dos
# Language aware diff headers
# https://tekin.co.uk/2020/10/better-git-diff-output-for-ruby-python-elixir-and-more
@ -70,3 +56,46 @@ Programs/test_frozenmain.h linguist-generated=true
*.html diff=html
*.py diff=python
*.md diff=markdown
# Generated files
# https://github.com/github/linguist/blob/master/docs/overrides.md
#
# To always hide generated files in local diffs, mark them as binary:
# $ git config diff.generated.binary true
#
[attr]generated linguist-generated=true diff=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/opcode.h generated
Include/opcode_ids.h generated
Include/token.h generated
Lib/_opcode_metadata.py generated
Lib/keyword.py 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/opcode_targets.h generated
Python/stdlib_module_names.h generated
Tools/peg_generator/pegen/grammar_parser.py generated
aclocal.m4 generated
configure generated

122
.github/CODEOWNERS vendored
View file

@ -4,31 +4,59 @@
# 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
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
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
# Exceptions
Lib/traceback.py @iritkatriel
Lib/test/test_except*.py @iritkatriel
Lib/test/test_traceback.py @iritkatriel
Objects/exceptions.c @iritkatriel
Python/traceback.c @iritkatriel
# Hashing
**/*hashlib* @python/crypto-team @tiran
**/*pyhash* @python/crypto-team @tiran
**/*sha* @python/crypto-team @tiran
**/*md5* @python/crypto-team @tiran
**/*blake* @python/crypto-team @tiran
/Modules/_blake2/** @python/crypto-team @tiran
/Modules/_sha3/** @python/crypto-team @tiran
**/*hashlib* @tiran
**/*pyhash* @tiran
**/*sha* @tiran
**/*md5* @tiran
**/*blake* @tiran
/Modules/_blake2/** @tiran
/Modules/_sha3/** @tiran
# logging
**/*logging* @vsajip
@ -43,21 +71,13 @@ Python/ast_opt.c @isidentical
/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
# SSL
**/*ssl* @python/crypto-team
**/*.pem @python/crypto-team
# CSPRNG
Python/bootstrap_hash.c @python/crypto-team
**/*import* @brettcannon @ericsnowcurrently @ncoghlan @warsaw
/Python/import.c @kumaraditya303
**/*importlib/resources/* @jaraco @warsaw @FFY00
**/importlib/metadata/* @jaraco @warsaw
# Dates and times
**/*datetime* @pganssle @abalkin
@ -66,7 +86,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
@ -84,6 +104,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
@ -93,16 +118,22 @@ Lib/ast.py @isidentical
# Mock
/Lib/unittest/mock.py @cjw296
/Lib/unittest/test/testmock/* @cjw296
/Lib/test/test_unittest/testmock/* @cjw296
# 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
@ -122,16 +153,16 @@ Lib/ast.py @isidentical
**/*bisect* @rhettinger
**/*heapq* @rhettinger
**/*functools* @rhettinger
**/*decimal* @rhettinger @skrah
**/*decimal* @rhettinger
**/*dataclasses* @ericvsmith
**/*ensurepip* @pfmoore @pradyunsg
**/*idlelib* @terryjreedy
**/*typing* @gvanrossum @Fidget-Spinner
**/*typing* @JelleZijlstra @AlexWaygood
**/*asyncore @giampaolo
**/*asynchat @giampaolo
**/*ftplib @giampaolo
**/*shutil @giampaolo
@ -139,6 +170,35 @@ Lib/ast.py @isidentical
**/*cgi* @ethanfurman
**/*tarfile* @ethanfurman
**/*tomllib* @encukou @hauntsaninja
**/*sysconfig* @FFY00
**/*cjkcodecs* @corona10
# macOS
/Mac/ @python/macos-team
**/*osx_support* @python/macos-team
# pathlib
**/*pathlib* @barneygale
# zipfile.Path
**/*zipfile/_path/* @jaraco
# Argument Clinic
/Tools/clinic/** @erlend-aasland @AlexWaygood
/Lib/test/test_clinic.py @erlend-aasland @AlexWaygood
Doc/howto/clinic.rst @erlend-aasland
# Subinterpreters
Lib/test/support/interpreters/ @ericsnowcurrently
Modules/_xx*interp*module.c @ericsnowcurrently
Lib/test/test_interpreters/ @ericsnowcurrently
# WebAssembly
/Tools/wasm/ @brettcannon
# SBOM
/Misc/sbom.spdx.json @sethmlarson
/Tools/build/generate_sbom.py @sethmlarson

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,13 +26,13 @@ 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:
- All discussions that are not directly related to the code in the pull request
should happen on bugs.python.org
should happen on `GitHub Issues <https://github.com/python/cpython/issues>`_.
- Upon your first non-trivial pull request (which includes documentation changes),
feel free to add yourself to ``Misc/ACKS``

2
.github/FUNDING.yml vendored
View file

@ -1,2 +0,0 @@
custom: https://www.python.org/psf/donations/python-dev/
github: [python]

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

7
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View file

@ -0,0 +1,7 @@
contact_links:
- name: "Getting help"
about: "Ask questions about using Python and debugging errors on Discourse."
url: "https://discuss.python.org/c/users/7"
- name: "Proposing new features"
about: "Submit major feature proposal (e.g. syntax changes) to an ideas forum first."
url: "https://discuss.python.org/c/ideas/6"

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

@ -0,0 +1,9 @@
---
name: Documentation
about: Report a problem with the documentation
labels: "docs"
---
# Documentation
(A clear and concise description of the issue.)

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

View file

@ -7,10 +7,10 @@ Please read this comment in its entirety. It's quite important.
It should be in the following format:
```
bpo-NNNN: Summary of the changes made
gh-NNNNN: Summary of the changes made
```
Where: bpo-NNNN refers to the issue number in the https://bugs.python.org.
Where: gh-NNNNN refers to the GitHub issue number.
Most PRs will require an issue number. Trivial changes, like fixing a typo, do not need an issue.

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

@ -1,6 +1,6 @@
name: Tests
# bpo-40548: "paths-ignore" is not used to skip documentation-only PRs, because
# gh-84728: "paths-ignore" is not used to skip documentation-only PRs, because
# it prevents to mark a job as mandatory. A PR cannot be merged if a job is
# mandatory but not scheduled because of "paths-ignore".
on:
@ -8,33 +8,45 @@ on:
push:
branches:
- 'main'
- '3.12'
- '3.11'
- '3.10'
- '3.9'
- '3.8'
- '3.7'
pull_request:
branches:
- 'main'
- '3.12'
- '3.11'
- '3.10'
- '3.9'
- '3.8'
- '3.7'
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,24 +62,101 @@ 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.2.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: Restore config.cache
uses: actions/cache@v3
with:
path: config.cache
key: ${{ github.job }}-${{ runner.os }}-${{ needs.check_source.outputs.config_hash }}-${{ env.pythonLocation }}
- name: Install Dependencies
run: sudo ./.github/workflows/posix-deps-apt.sh
- name: Build CPython
- name: Add ccache to PATH
run: echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV
- name: Configure ccache action
uses: hendrikmuhs/ccache-action@v1.2
- name: Check Autoconf and aclocal versions
run: |
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
./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: |
make -j4 regen-all
make regen-stdlib-module-names
- name: Check for changes
@ -75,131 +164,103 @@ jobs:
git add -u
changes=$(git status --porcelain)
# Check for changes in regenerated files
if ! test -z "$changes"
then
echo "Generated files not up to date. Perhaps you forgot to run make regen-all or build.bat --regen ;)"
if test -n "$changes"; then
echo "Generated files not up to date."
echo "Perhaps you forgot to run make regen-all or build.bat --regen. ;)"
echo "configure files must be regenerated with a specific version of autoconf."
echo "$changes"
echo ""
git diff --staged || true
exit 1
fi
- name: Check exported libpython symbols
run: make smelly
- name: Check limited ABI symbols
run: make check-limited-abi
- name: Check Autoconf version 2.69
run: |
grep "Generated by GNU Autoconf 2.69" configure
grep "PKG_PROG_PKG_CONFIG" aclocal.m4
- 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'
steps:
- uses: actions/checkout@v2
- name: Build CPython
run: .\PCbuild\build.bat -e -p Win32
- name: Display build info
run: .\python.bat -m test.pythoninfo
- name: Tests
run: .\PCbuild\rt.bat -p Win32 -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'
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 -p x64
- name: Display build info
run: .\python.bat -m test.pythoninfo
- name: Tests
run: .\PCbuild\rt.bat -p x64 -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 }}
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
build_ubuntu:
name: 'Ubuntu'
runs-on: ubuntu-20.04
needs: check_source
if: needs.check_source.outputs.run_tests == 'true'
env:
OPENSSL_VER: 1.1.1l
PYTHONSTRICTEXTENSIONBUILD: 1
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.6
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
- 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: Tests
run: xvfb-run make buildbottest TESTOPTS="-j4 -uall,-cpu"
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-20.04
timeout-minutes: 60
needs: check_source
if: needs.check_source.outputs.run_tests == 'true' && needs.check_source.outputs.run_ssl_tests == 'true'
if: needs.check_source.outputs.run_tests == 'true'
strategy:
fail-fast: false
matrix:
openssl_ver: [1.1.1l, 3.0.0]
openssl_ver: [1.1.1w, 3.0.11, 3.1.3]
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
- uses: actions/checkout@v4
- name: Restore config.cache
uses: actions/cache@v3
with:
path: config.cache
key: ${{ github.job }}-${{ runner.os }}-${{ needs.check_source.outputs.config_hash }}
- name: Register gcc problem matcher
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
- name: Install Dependencies
@ -211,7 +272,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.6
uses: actions/cache@v3
with:
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
@ -222,9 +283,9 @@ 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
- name: Configure CPython
run: ./configure --with-pydebug --with-openssl=$OPENSSL_DIR
run: ./configure --config-cache --with-pydebug --with-openssl=$OPENSSL_DIR
- name: Build CPython
run: make -j4
- name: Display build info
@ -232,18 +293,17 @@ jobs:
- name: SSL tests
run: ./python Lib/test/ssltests.py
build_asan:
name: 'Address sanitizer'
test_hypothesis:
name: "Hypothesis tests on Ubuntu"
runs-on: ubuntu-20.04
timeout-minutes: 60
needs: check_source
if: needs.check_source.outputs.run_tests == 'true'
if: needs.check_source.outputs.run_tests == 'true' && needs.check_source.outputs.run_hypothesis == 'true'
env:
OPENSSL_VER: 1.1.1l
OPENSSL_VER: 3.0.11
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: Register gcc problem matcher
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
- name: Install Dependencies
@ -255,7 +315,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.6
uses: actions/cache@v3
with:
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
@ -266,12 +326,239 @@ 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
- 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: Restore config.cache
uses: actions/cache@v3
with:
path: ${{ env.CPYTHON_BUILDDIR }}/config.cache
key: ${{ github.job }}-${{ runner.os }}-${{ needs.check_source.outputs.config_hash }}
- name: Configure CPython out-of-tree
working-directory: ${{ env.CPYTHON_BUILDDIR }}
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
- 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: 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: |
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@v3
with:
path: ./hypothesis
key: hypothesis-database-${{ github.head_ref || github.run_id }}
restore-keys: |
- hypothesis-database-
- name: "Run tests"
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: |
# 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
timeout-minutes: 60
needs: check_source
if: needs.check_source.outputs.run_tests == 'true'
env:
OPENSSL_VER: 3.0.11
PYTHONSTRICTEXTENSIONBUILD: 1
ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0
steps:
- uses: actions/checkout@v4
- name: Restore config.cache
uses: actions/cache@v3
with:
path: config.cache
key: ${{ github.job }}-${{ runner.os }}-${{ 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
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@v3
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
- 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 -x test_ctypes test_crypt test_decimal test_faulthandler test_interpreters test___all__ test_idle test_tix test_tk test_ttk_guionly test_ttk_textonly test_multiprocessing_fork test_multiprocessing_forkserver test_multiprocessing_spawn"
run: xvfb-run make test
# 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_windows
- build_windows_free_threading
- test_hypothesis
- build_asan
- 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_windows,
build_windows_free_threading,
build_asan,
'
|| ''
}}
${{
!fromJSON(needs.check_source.outputs.run_cifuzz)
&& '
cifuzz,
'
|| ''
}}
${{
!fromJSON(needs.check_source.outputs.run_hypothesis)
&& '
test_hypothesis,
'
|| ''
}}
jobs: ${{ toJSON(needs) }}

View file

@ -5,35 +5,34 @@ 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]
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
run: .\Tools\msi\build.bat --doc -${{ matrix.type }}

View file

@ -1,47 +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
- name: 'Build documentation'
run: xvfb-run make -C Doc/ PYTHON=../python SPHINXOPTS="-q -W --keep-going -j4" doctest html
- name: 'Upload'
uses: actions/upload-artifact@v2.2.4
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"

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.0

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

@ -0,0 +1,55 @@
# 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/test/libregrtest/**"
- "Tools/build/generate_sbom.py"
- "Tools/cases_generator/**"
- "Tools/clinic/**"
- "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:
matrix:
target: [
"Lib/test/libregrtest",
"Tools/build/",
"Tools/cases_generator",
"Tools/clinic",
"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

@ -0,0 +1,60 @@
name: new-bugs-announce notifier
on:
issues:
types:
- opened
permissions:
issues: read
jobs:
notify-new-bugs-announce:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm install mailgun.js form-data
- name: Send notification
uses: actions/github-script@v7
env:
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 = "mailgun.python.org";
const mg = mailgun.client({username: 'api', key: process.env.MAILGUN_API_KEY});
github.rest.issues.get({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
})
.then(function(issue) {
const payload = {
author : issue.data.user.login,
issue : issue.data.number,
title : issue.data.title,
url : issue.data.html_url,
labels : issue.data.labels.map(label => { return label.name }).join(", "),
assignee : issue.data.assignees.map(assignee => { return assignee.login }),
// 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@mailgun.python.org>",
to: "new-bugs-announce@python.org",
subject: `[Issue ${issue.data.number}] ${issue.data.title}`,
template: "new-github-issue",
'o:tracking-clicks': 'no',
'h:X-Mailgun-Variables': JSON.stringify(payload)
};
return mg.messages.create(DOMAIN, data)
})
.then(msg => console.log(msg));

View file

@ -1,12 +1,15 @@
#!/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 \
libb2-dev \
libbz2-dev \
libffi-dev \
libgdbm-dev \
@ -18,6 +21,7 @@ apt-get -yq install \
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@v0.1.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

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

@ -0,0 +1,22 @@
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
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"

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

@ -0,0 +1,108 @@
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
# 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.11' # known to work with Sphinx 4.2
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@v3
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

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

@ -0,0 +1,46 @@
on:
workflow_call:
inputs:
config_hash:
required: true
type: string
free-threading:
required: false
type: boolean
default: false
jobs:
build_macos:
name: 'build and test'
runs-on: macos-latest
timeout-minutes: 60
env:
HOMEBREW_NO_ANALYTICS: 1
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
PYTHONSTRICTEXTENSIONBUILD: 1
steps:
- uses: actions/checkout@v4
- name: Restore config.cache
uses: actions/cache@v3
with:
path: config.cache
key: ${{ github.job }}-${{ runner.os }}-${{ 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 -j4
- name: Display build info
run: make pythoninfo
- name: Tests
run: make test

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

@ -0,0 +1,71 @@
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-20.04
env:
OPENSSL_VER: 3.0.11
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@v3
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
- 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: Restore config.cache
uses: actions/cache@v3
with:
path: ${{ env.CPYTHON_BUILDDIR }}/config.cache
key: ${{ github.job }}-${{ runner.os }}-${{ 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

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

@ -9,14 +9,20 @@ permissions:
jobs:
stale:
if: github.repository_owner == 'python'
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/stale@v4
- name: "Check PRs"
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

25
.gitignore vendored
View file

@ -5,11 +5,14 @@
*.cover
*.iml
*.o
*.lto
*.a
*.so
*.so.*
*.dylib
*.dSYM
*.dll
*.wasm
*.orig
*.pyc
*.pyd
@ -20,6 +23,10 @@
*.gc??
*.profclang?
*.profraw
# Copies of binaries before BOLT optimizations.
*.prebolt
# BOLT profile data.
*.fdata
*.dyn
.gdb_history
.purify
@ -35,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
@ -55,8 +62,8 @@ 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/*
!Lib/test/data/README
/_bootstrap_python
@ -74,8 +81,10 @@ Mac/pythonw
Misc/python.pc
Misc/python-embed.pc
Misc/python-config.sh
Modules/Setup.bootstrap
Modules/Setup.config
Modules/Setup.local
Modules/Setup.stdlib
Modules/config.c
Modules/ld_so_aix
Programs/_freeze_module
@ -109,13 +118,18 @@ 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/
/platform
/profile-clean-stamp
/profile-run-stamp
/profile-bolt-stamp
/Python/deepfreeze/*.c
/pybuilddir.txt
/pyconfig.h
@ -134,7 +148,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
@ -143,3 +157,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>

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

@ -0,0 +1,36 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.7
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/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- 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/next/
- 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

View file

@ -1,169 +0,0 @@
language: c
dist: bionic
# To cache doc-building dependencies and C compiler output.
cache:
- pip
- ccache
- directories:
- $HOME/multissl
env:
global:
- OPENSSL=1.1.1k
- OPENSSL_DIR="$HOME/multissl/openssl/${OPENSSL}"
- PATH="${OPENSSL_DIR}/bin:$PATH"
- CFLAGS="-I${OPENSSL_DIR}/include"
- LDFLAGS="-L${OPENSSL_DIR}/lib"
# Set rpath with env var instead of -Wl,-rpath linker flag
# OpenSSL ignores LDFLAGS when linking bin/openssl
- LD_RUN_PATH="${OPENSSL_DIR}/lib"
- PYTHONSTRICTEXTENSIONBUILD=1
branches:
only:
- main
- /^\d\.\d+$/
- buildbot-custom
matrix:
fast_finish: true
allow_failures:
- env: OPTIONAL=true
include:
- name: "CPython tests"
os: linux
language: c
compiler: clang
# gcc also works, but to keep the # of concurrent builds down, we use one C
# compiler here and the other to run the coverage build. Clang is preferred
# in this instance for its better error messages.
env: TESTING=cpython
addons:
apt:
packages:
- gdb
- xvfb
- name: "Documentation build"
os: linux
language: python
# Build the docs against a stable version of Python so code bugs don't hold up doc-related PRs.
python: 3.6
env: TESTING=docs
before_script:
- cd Doc
- make venv PYTHON=python
script:
- make check html SPHINXOPTS="-q -W -j4"
- name: "Documentation tests"
os: linux
language: c
compiler: clang
env: TESTING=doctest
addons:
apt:
packages:
- xvfb
before_script:
- ./configure
- make -j4
- make -C Doc/ PYTHON=../python venv
script:
xvfb-run make -C Doc/ PYTHON=../python SPHINXOPTS="-q -W -j4" doctest
before_install:
- set -e
- |
# Check short-circuit conditions
if [[ "${TESTING}" != "docs" && "${TESTING}" != "doctest" ]]
then
if [[ "$TRAVIS_PULL_REQUEST" == "false" ]]
then
echo "Not a PR, doing full build."
else
# Pull requests are slightly complicated because $TRAVIS_COMMIT_RANGE
# may include more changes than desired if the history is convoluted.
# Instead, explicitly fetch the base branch and compare against the
# merge-base commit.
git fetch -q origin +refs/heads/$TRAVIS_BRANCH
changes=$(git diff --name-only HEAD $(git merge-base HEAD FETCH_HEAD))
echo "Files changed:"
echo "$changes"
if ! echo "$changes" | grep -qvE '(\.rst$)|(^Doc)|(^Misc)'
then
echo "Only docs were updated, stopping build process."
exit
fi
fi
fi
install:
- |
# Install OpenSSL as necessary
# Note: doctest needs OpenSSL
if [[ "${TESTING}" != "docs" ]]
then
# clang complains about unused-parameter a lot, redirect stderr
python3 Tools/ssl/multissltests.py --steps=library \
--base-directory ${HOME}/multissl \
--openssl ${OPENSSL} >/dev/null 2>&1
fi
- openssl version
# Travis provides only 2 cores, so don't overdo the parallelism and waste memory.
before_script:
# -Og is much faster than -O0
- CFLAGS="${CFLAGS} -Og" ./configure --with-pydebug
- eval "$(pyenv init -)"
- pyenv global 3.8
- PYTHON_FOR_REGEN=python3.8 make -j4 regen-all
- make regen-stdlib-module-names
- changes=`git status --porcelain`
- |
# Check for changes in regenerated files
if ! test -z "$changes"
then
echo "Generated files not up to date"
echo "$changes"
exit 1
fi
- make -j4
- make pythoninfo
script:
# Using the built Python as patchcheck.py is built around the idea of using
# a checkout-build of CPython to know things like what base branch the changes
# should be compared against.
# Only run on Linux as the check only needs to be run once.
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./python Tools/scripts/patchcheck.py --travis $TRAVIS_PULL_REQUEST; fi
# Check that all symbols exported by libpython start with "Py" or "_Py"
- make smelly
# Check that all symbols in the limited abi are present
- make check-limited-abi
# `-r -w` implicitly provided through `make buildbottest`.
- |
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
XVFB_RUN=xvfb-run;
fi
$XVFB_RUN make buildbottest TESTOPTS="-j4 -uall,-cpu"
notifications:
email: false
irc:
channels:
# This is set to a secure variable to prevent forks from notifying the
# IRC channel whenever they fail a build. This can be removed when travis
# implements https://github.com/travis-ci/travis-ci/issues/1094.
# The actual value here is: irc.freenode.net#python-dev
- secure: "s7kAkpcom2yUJ8XqyjFI0obJmhAGrn1xmoivdaPdgBIA++X47TBp1x4pgDsbEsoalef7bEwa4l07KdT4qa+DOd/c4QxaWom7fbN3BuLVsZuVfODnl79+gYq/TAbGfyH+yDs18DXrUfPgwD7C5aW32ugsqAOd4iWzfGJQ5OrOZzqzGjYdYQUEkJFXgxDEIb4aHvxNDWGO3Po9uKISrhb5saQ0l776yLo1Ur7M4oxl8RTbCdgX0vf5TzPg52BgvZpOgt3DHOUYPeiJLKNjAE6ibg0U95sEvMfHX77nz4aFY4/3UI6FFaRla34rZ+mYKrn0TdxOhera1QOgPmM6HzdO4K44FpfK1DS0Xxk9U9/uApq+cG0bU3W+cVUHDBe5+90lpRBAXHeHCgT7TI8gec614aiT8lEr3+yH8OBRYGzkjNK8E2LJZ/SxnVxDe7aLF6AWcoWLfS6/ziAIBFQ5Nc4U72CT8fGVSkl8ywPiRlvixKdvTODMSZo0jMqlfZSNaAPTsNRx4wu5Uis4qekwe32Fz4aB6KGpsuuVjBi+H6v0RKxNJNGY3JKDiEH2TK0UE2auJ5GvLW48aUVFcQMB7euCWYXlSWVRHh3WLU8QXF29Dw4JduRZqUpOdRgMHU79UHRq+mkE0jAS/nBcS6CvsmxCpTSrfVYuMOu32yt18QQoTyU="
on_success: change
on_failure: always
skip_join: true
webhooks:
urls:
# For the same reasons as above for IRC, we encrypt the webhook address
# for Zulip. The actual value is:
# https://python.zulipchat.com/api/v1/external/travis?api_key=<api-key-redacted>&stream=core%2Ftest+runs
- secure: "vLz2TodSL7wQ8DsIu86koRS9i4dsK40PH8+wzY93PBCCAzJAz113LTxK3/9PamMv+ObDRUSe5OpXcquE3d5Gwpu8IymF113qK0I3uNr+O3FtmKlj/Kd1P/V+z4pTpS3zh3lW9gyKV9EMWXIWS0IYKKZQU144XqUlIiucWK2jHJF/cSz2cRAx/6Kx68X4mZwEC7hiMOF4ZsWUMbCglM89ybeS0pr0kK9mmh88qsPyRQov3mRKswmVPlePk7clVLNAL43qSe3SzmrmACZfQ9KJYmpYnr/cjo2b6svYHcQBAwAUarZZ9KBMXeV7HwGWsSXAvHH2ynR0P++braBHGEMTGMSitdVWzFTmeiHnrkp08WAB+uFs54iEx3VklTk9bCzozTm2S94TRxbrsG9SypMvQxG570JV6P2XYuR+taCb/GMtMqrtGQm2e1Ht+nDLtiUb+/+rwEbicJJ13knptOQZI4tPOZESI/kXkORkSNwFfLSNLSl9jTlMmO7KjAAPApURHEdx26RbItAn8mIX2NcHTRjKn2qV4h3C54nmHmKWn/ZudHHJc6ieZSEUBoaLGAYmcWJRqrM6jiy2h9I9TRrCKAiGh5jT47FYKLwosTtV245l/ZhDb6eTVfEFT6TSLEoyfx9cCtTUvfMtXYl8eN9wlFYYpH8MSWbMD14eEkKBTWg="
on_success: change
on_failure: always

View file

@ -1,12 +0,0 @@
# Code of Conduct
Please note that all interactions on
[Python Software Foundation](https://www.python.org/psf-landing/)-supported
infrastructure is [covered](https://www.python.org/psf/records/board/minutes/2014-01-06/#management-of-the-psfs-web-properties)
by the [PSF Code of Conduct](https://www.python.org/psf/codeofconduct/),
which includes all the infrastructure used in the development of Python itself
(e.g. mailing lists, issue trackers, GitHub, etc.).
In general, this means that everyone is expected to be **open**, **considerate**, and
**respectful** of others no matter what their position is within the project.

View file

@ -8,28 +8,32 @@ PYTHON = python3
VENVDIR = ./venv
SPHINXBUILD = PATH=$(VENVDIR)/bin:$$PATH sphinx-build
BLURB = PATH=$(VENVDIR)/bin:$$PATH blurb
JOBS = auto
PAPER =
SOURCES =
DISTVERSION = $(shell $(PYTHON) tools/extensions/patchlevel.py)
REQUIREMENTS = requirements.txt
SPHINXERRORHANDLING = -W
# 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 " 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"
@ -41,10 +45,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
@ -71,38 +74,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) || { \
@ -110,18 +121,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; }
.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) || { \
@ -129,31 +134,42 @@ 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"
.PHONY: htmlview
htmlview: html
$(PYTHON) -c "import webbrowser; webbrowser.open('build/html/index.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 \
$(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
@ -208,12 +224,14 @@ dist:
rm -r dist/python-$(DISTVERSION)-docs-texinfo
rm dist/python-$(DISTVERSION)-docs-texinfo.tar
check:
$(PYTHON) tools/rstlint.py -i tools -i $(VENVDIR) -i README.rst
$(PYTHON) tools/rstlint.py ../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
@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.
@ -223,15 +241,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."; \
@ -239,6 +260,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).
@ -91,10 +91,7 @@ Available make targets are:
* "pydoc-topics", which builds a Python module containing a dictionary with
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.
``tools/pyspecific.py`` -- pydoc needs these to show topic and keyword help.
* "check", which checks for frequent markup errors.
@ -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,9 @@ 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'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,43 +38,48 @@ 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/documentation/translating/>`_
A list of GitHub pages for documentation translation and their primary contacts.
.. _using-the-tracker:
Using the Python issue tracker
==============================
Bug reports for Python itself should be submitted via the Python Bug Tracker
(https://bugs.python.org/). The bug tracker offers a web form which allows
pertinent information to be entered and submitted to the developers.
Issue reports for Python itself should be submitted via the GitHub issues
tracker (https://github.com/python/cpython/issues).
The GitHub issues tracker offers a web form which allows pertinent information
to be entered and submitted to the developers.
The first step in filing a report is to determine whether the problem has
already been reported. The advantage in doing so, aside from saving the
developers time, is that you learn what has been done to fix it; it may be that
developers' time, is that you learn what has been done to fix it; it may be that
the problem has already been fixed for the next release, or additional
information is needed (in which case you are welcome to provide it if you can!).
To do this, search the bug database using the search box on the top of the page.
To do this, search the tracker using the search box at the top of the page.
If the problem you're reporting is not already in the bug tracker, go back to
the Python Bug Tracker and log in. If you don't already have a tracker account,
select the "Register" link or, if you use OpenID, one of the OpenID provider
logos in the sidebar. It is not possible to submit a bug report anonymously.
If the problem you're reporting is not already in the list, log in to GitHub.
If you don't already have a GitHub account, create a new account using the
"Sign up" link.
It is not possible to submit a bug report anonymously.
Being now logged in, you can submit a bug. Select the "Create New" link in the
sidebar to open the bug reporting form.
Being now logged in, you can submit an issue.
Click on the "New issue" button in the top bar to report a new issue.
The submission form has a number of fields. For the "Title" field, enter a
*very* short description of the problem; less than ten words is good. In the
"Type" field, select the type of your problem; also select the "Component" and
"Versions" to which the bug relates.
The submission form has two fields, "Title" and "Comment".
For the "Title" field, enter a *very* short description of the problem;
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
extension modules were involved, and what hardware and software platform you
were using (including version information as appropriate).
Each bug report will be assigned to a developer who will determine what needs to
be done to correct the problem. You will receive an update each time action is
taken on the bug.
Each issue report will be reviewed by a developer who will determine what needs to
be done to correct the problem. You will receive an update each time an action is
taken on the issue.
.. seealso::
@ -95,6 +103,6 @@ patching Python in the `Python Developer's Guide`_. If you have questions,
the `core-mentorship mailing list`_ is a friendly place to get answers to
any and all questions pertaining to the process of fixing issues in Python.
.. _Documentation bugs: https://bugs.python.org/issue?@filter=status&@filter=components&components=4&status=1&@columns=id,activity,title,status&@sort=-activity
.. _Documentation bugs: https://github.com/python/cpython/issues?q=is%3Aissue+is%3Aopen+label%3Adocs
.. _Python Developer's Guide: https://devguide.python.org/
.. _core-mentorship mailing list: https://mail.python.org/mailman3/lists/core-mentorship.python.org/

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.

View file

@ -58,5 +58,16 @@ See :ref:`stable` for a discussion of API and ABI stability across versions.
Thus ``3.4.1a2`` is hexversion ``0x030401a2`` and ``3.10.0`` is
hexversion ``0x030a00f0``.
Use this for numeric comparisons, e.g. ``#if PY_VERSION_HEX >= ...``.
This version is also available via the symbol :c:var:`Py_Version`.
.. c:var:: const unsigned long Py_Version
The Python runtime version number encoded in a single constant integer, with
the same format as the :c:macro:`PY_VERSION_HEX` macro.
This contains the Python version used at run time.
.. versionadded:: 3.11
All the given macros are defined in :source:`Include/patchlevel.h`.

View file

@ -27,40 +27,55 @@ unit; the entry in (round) parentheses is the Python object type that matches
the format unit; and the entry in [square] brackets is the type of the C
variable(s) whose address should be passed.
.. _arg-parsing-string-and-buffers:
Strings and buffers
-------------------
.. note::
On Python 3.12 and older, the macro :c:macro:`!PY_SSIZE_T_CLEAN` must be
defined before including :file:`Python.h` to use all ``#`` variants of
formats (``s#``, ``y#``, etc.) explained below.
This is not necessary on Python 3.13 and later.
These formats allow accessing an object as a contiguous chunk of memory.
You don't have to provide raw storage for the returned unicode or bytes
area.
In general, when a format sets a pointer to a buffer, the buffer is
managed by the corresponding Python object, and the buffer shares
the lifetime of this object. You won't have to release any memory yourself.
The only exceptions are ``es``, ``es#``, ``et`` and ``et#``.
However, when a :c:type:`Py_buffer` structure gets filled, the underlying
buffer is locked so that the caller can subsequently use the buffer even
inside a :c:type:`Py_BEGIN_ALLOW_THREADS` block without the risk of mutable data
being resized or destroyed. As a result, **you have to call**
:c:func:`PyBuffer_Release` after you have finished processing the data (or
in any early abort case).
Unless otherwise stated, buffers are not NUL-terminated.
Some formats require a read-only :term:`bytes-like object`, and set a
pointer instead of a buffer structure. They work by checking that
the object's :c:member:`PyBufferProcs.bf_releasebuffer` field is ``NULL``,
which disallows mutable objects such as :class:`bytearray`.
There are three ways strings and buffers can be converted to C:
.. note::
* Formats such as ``y*`` and ``s*`` fill a :c:type:`Py_buffer` structure.
This locks the underlying buffer so that the caller can subsequently use
the buffer even inside a :c:type:`Py_BEGIN_ALLOW_THREADS`
block without the risk of mutable data being resized or destroyed.
As a result, **you have to call** :c:func:`PyBuffer_Release` after you have
finished processing the data (or in any early abort case).
For all ``#`` variants of formats (``s#``, ``y#``, etc.), the macro
:c:macro:`PY_SSIZE_T_CLEAN` must be defined before including
:file:`Python.h`. On Python 3.9 and older, the type of the length argument
is :c:type:`Py_ssize_t` if the :c:macro:`PY_SSIZE_T_CLEAN` macro is defined,
or int otherwise.
* The ``es``, ``es#``, ``et`` and ``et#`` formats allocate the result buffer.
**You have to call** :c:func:`PyMem_Free` after you have finished
processing the data (or in any early abort case).
* .. _c-arg-borrowed-buffer:
Other formats take a :class:`str` or a read-only :term:`bytes-like object`,
such as :class:`bytes`, and provide a ``const char *`` pointer to
its buffer.
In this case the buffer is "borrowed": it is managed by the corresponding
Python object, and shares the lifetime of this object.
You won't have to release any memory yourself.
To ensure that the underlying buffer may be safely borrowed, the object's
:c:member:`PyBufferProcs.bf_releasebuffer` field must be ``NULL``.
This disallows common mutable objects such as :class:`bytearray`,
but also some read-only objects such as :class:`memoryview` of
:class:`bytes`.
Besides this ``bf_releasebuffer`` requirement, there is no check to verify
whether the input object is immutable (e.g. whether it would honor a request
for a writable buffer, or whether another thread can mutate the data).
``s`` (:class:`str`) [const char \*]
Convert a Unicode object to a C pointer to a character string.
@ -89,7 +104,7 @@ which disallows mutable objects such as :class:`bytearray`.
Unicode objects are converted to C strings using ``'utf-8'`` encoding.
``s#`` (:class:`str`, read-only :term:`bytes-like object`) [const char \*, :c:type:`Py_ssize_t`]
Like ``s*``, except that it doesn't accept mutable objects.
Like ``s*``, except that it provides a :ref:`borrowed buffer <c-arg-borrowed-buffer>`.
The result is stored into two C variables,
the first one a pointer to a C string, the second one its length.
The string may contain embedded null bytes. Unicode objects are converted
@ -108,8 +123,9 @@ which disallows mutable objects such as :class:`bytearray`.
pointer is set to ``NULL``.
``y`` (read-only :term:`bytes-like object`) [const char \*]
This format converts a bytes-like object to a C pointer to a character
string; it does not accept Unicode objects. The bytes buffer must not
This format converts a bytes-like object to a C pointer to a
:ref:`borrowed <c-arg-borrowed-buffer>` character string;
it does not accept Unicode objects. The bytes buffer must not
contain embedded null bytes; if it does, a :exc:`ValueError`
exception is raised.
@ -129,59 +145,17 @@ which disallows mutable objects such as :class:`bytearray`.
``S`` (:class:`bytes`) [PyBytesObject \*]
Requires that the Python object is a :class:`bytes` object, without
attempting any conversion. Raises :exc:`TypeError` if the object is not
a bytes object. The C variable may also be declared as :c:type:`PyObject*`.
a bytes object. The C variable may also be declared as :c:expr:`PyObject*`.
``Y`` (:class:`bytearray`) [PyByteArrayObject \*]
Requires that the Python object is a :class:`bytearray` object, without
attempting any conversion. Raises :exc:`TypeError` if the object is not
a :class:`bytearray` object. The C variable may also be declared as :c:type:`PyObject*`.
``u`` (:class:`str`) [const Py_UNICODE \*]
Convert a Python Unicode object to a C pointer to a NUL-terminated buffer of
Unicode characters. You must pass the address of a :c:type:`Py_UNICODE`
pointer variable, which will be filled with the pointer to an existing
Unicode buffer. Please note that the width of a :c:type:`Py_UNICODE`
character depends on compilation options (it is either 16 or 32 bits).
The Python string must not contain embedded null code points; if it does,
a :exc:`ValueError` exception is raised.
.. versionchanged:: 3.5
Previously, :exc:`TypeError` was raised when embedded null code points
were encountered in the Python string.
.. deprecated-removed:: 3.3 3.12
Part of the old-style :c:type:`Py_UNICODE` API; please migrate to using
:c:func:`PyUnicode_AsWideCharString`.
``u#`` (:class:`str`) [const Py_UNICODE \*, :c:type:`Py_ssize_t`]
This variant on ``u`` stores into two C variables, the first one a pointer to a
Unicode data buffer, the second one its length. This variant allows
null code points.
.. deprecated-removed:: 3.3 3.12
Part of the old-style :c:type:`Py_UNICODE` API; please migrate to using
:c:func:`PyUnicode_AsWideCharString`.
``Z`` (:class:`str` or ``None``) [const Py_UNICODE \*]
Like ``u``, but the Python object may also be ``None``, in which case the
:c:type:`Py_UNICODE` pointer is set to ``NULL``.
.. deprecated-removed:: 3.3 3.12
Part of the old-style :c:type:`Py_UNICODE` API; please migrate to using
:c:func:`PyUnicode_AsWideCharString`.
``Z#`` (:class:`str` or ``None``) [const Py_UNICODE \*, :c:type:`Py_ssize_t`]
Like ``u#``, but the Python object may also be ``None``, in which case the
:c:type:`Py_UNICODE` pointer is set to ``NULL``.
.. deprecated-removed:: 3.3 3.12
Part of the old-style :c:type:`Py_UNICODE` API; please migrate to using
:c:func:`PyUnicode_AsWideCharString`.
a :class:`bytearray` object. The C variable may also be declared as :c:expr:`PyObject*`.
``U`` (:class:`str`) [PyObject \*]
Requires that the Python object is a Unicode object, without attempting
any conversion. Raises :exc:`TypeError` if the object is not a Unicode
object. The C variable may also be declared as :c:type:`PyObject*`.
object. The C variable may also be declared as :c:expr:`PyObject*`.
``w*`` (read-write :term:`bytes-like object`) [Py_buffer]
This format accepts any object which implements the read-write buffer
@ -194,10 +168,10 @@ which disallows mutable objects such as :class:`bytearray`.
It only works for encoded data without embedded NUL bytes.
This format requires two arguments. The first is only used as input, and
must be a :c:type:`const char*` which points to the name of an encoding as a
must be a :c:expr:`const char*` which points to the name of an encoding as a
NUL-terminated string, or ``NULL``, in which case ``'utf-8'`` encoding is used.
An exception is raised if the named encoding is not known to Python. The
second argument must be a :c:type:`char**`; the value of the pointer it
second argument must be a :c:expr:`char**`; the value of the pointer it
references will be set to a buffer with the contents of the argument text.
The text will be encoded in the encoding specified by the first argument.
@ -217,10 +191,10 @@ which disallows mutable objects such as :class:`bytearray`.
characters.
It requires three arguments. The first is only used as input, and must be a
:c:type:`const char*` which points to the name of an encoding as a
:c:expr:`const char*` which points to the name of an encoding as a
NUL-terminated string, or ``NULL``, in which case ``'utf-8'`` encoding is used.
An exception is raised if the named encoding is not known to Python. The
second argument must be a :c:type:`char**`; the value of the pointer it
second argument must be a :c:expr:`char**`; the value of the pointer it
references will be set to a buffer with the contents of the argument text.
The text will be encoded in the encoding specified by the first argument.
The third argument must be a pointer to an integer; the referenced integer
@ -247,64 +221,69 @@ which disallows mutable objects such as :class:`bytearray`.
them. Instead, the implementation assumes that the byte string object uses the
encoding passed in as parameter.
.. versionchanged:: 3.12
``u``, ``u#``, ``Z``, and ``Z#`` are removed because they used a legacy
``Py_UNICODE*`` representation.
Numbers
-------
``b`` (:class:`int`) [unsigned char]
Convert a nonnegative Python integer to an unsigned tiny int, stored in a C
:c:type:`unsigned char`.
:c:expr:`unsigned char`.
``B`` (:class:`int`) [unsigned char]
Convert a Python integer to a tiny int without overflow checking, stored in a C
:c:type:`unsigned char`.
:c:expr:`unsigned char`.
``h`` (:class:`int`) [short int]
Convert a Python integer to a C :c:type:`short int`.
Convert a Python integer to a C :c:expr:`short int`.
``H`` (:class:`int`) [unsigned short int]
Convert a Python integer to a C :c:type:`unsigned short int`, without overflow
Convert a Python integer to a C :c:expr:`unsigned short int`, without overflow
checking.
``i`` (:class:`int`) [int]
Convert a Python integer to a plain C :c:type:`int`.
Convert a Python integer to a plain C :c:expr:`int`.
``I`` (:class:`int`) [unsigned int]
Convert a Python integer to a C :c:type:`unsigned int`, without overflow
Convert a Python integer to a C :c:expr:`unsigned int`, without overflow
checking.
``l`` (:class:`int`) [long int]
Convert a Python integer to a C :c:type:`long int`.
Convert a Python integer to a C :c:expr:`long int`.
``k`` (:class:`int`) [unsigned long]
Convert a Python integer to a C :c:type:`unsigned long` without
Convert a Python integer to a C :c:expr:`unsigned long` without
overflow checking.
``L`` (:class:`int`) [long long]
Convert a Python integer to a C :c:type:`long long`.
Convert a Python integer to a C :c:expr:`long long`.
``K`` (:class:`int`) [unsigned long long]
Convert a Python integer to a C :c:type:`unsigned long long`
Convert a Python integer to a C :c:expr:`unsigned long long`
without overflow checking.
``n`` (:class:`int`) [Py_ssize_t]
``n`` (:class:`int`) [:c:type:`Py_ssize_t`]
Convert a Python integer to a C :c:type:`Py_ssize_t`.
``c`` (:class:`bytes` or :class:`bytearray` of length 1) [char]
Convert a Python byte, represented as a :class:`bytes` or
:class:`bytearray` object of length 1, to a C :c:type:`char`.
:class:`bytearray` object of length 1, to a C :c:expr:`char`.
.. versionchanged:: 3.3
Allow :class:`bytearray` objects.
``C`` (:class:`str` of length 1) [int]
Convert a Python character, represented as a :class:`str` object of
length 1, to a C :c:type:`int`.
length 1, to a C :c:expr:`int`.
``f`` (:class:`float`) [float]
Convert a Python floating point number to a C :c:type:`float`.
Convert a Python floating point number to a C :c:expr:`float`.
``d`` (:class:`float`) [double]
Convert a Python floating point number to a C :c:type:`double`.
Convert a Python floating point number to a C :c:expr:`double`.
``D`` (:class:`complex`) [Py_complex]
Convert a Python complex number to a C :c:type:`Py_complex` structure.
@ -314,13 +293,15 @@ Other objects
``O`` (object) [PyObject \*]
Store a Python object (without any conversion) in a C object pointer. The C
program thus receives the actual object that was passed. The object's reference
count is not increased. The pointer stored is not ``NULL``.
program thus receives the actual object that was passed. A new
:term:`strong reference` to the object is not created
(i.e. its reference count is not increased).
The pointer stored is not ``NULL``.
``O!`` (object) [*typeobject*, PyObject \*]
Store a Python object in a C object pointer. This is similar to ``O``, but
takes two C arguments: the first is the address of a Python type object, the
second is the address of the C variable (of type :c:type:`PyObject*`) into which
second is the address of the C variable (of type :c:expr:`PyObject*`) into which
the object pointer is stored. If the Python object does not have the required
type, :exc:`TypeError` is raised.
@ -329,13 +310,13 @@ Other objects
``O&`` (object) [*converter*, *anything*]
Convert a Python object to a C variable through a *converter* function. This
takes two arguments: the first is a function, the second is the address of a C
variable (of arbitrary type), converted to :c:type:`void *`. The *converter*
variable (of arbitrary type), converted to :c:expr:`void *`. The *converter*
function in turn is called as follows::
status = converter(object, address);
where *object* is the Python object to be converted and *address* is the
:c:type:`void*` argument that was passed to the :c:func:`PyArg_Parse\*` function.
:c:expr:`void*` argument that was passed to the ``PyArg_Parse*`` function.
The returned *status* should be ``1`` for a successful conversion and ``0`` if
the conversion has failed. When the conversion fails, the *converter* function
should raise an exception and leave the content of *address* unmodified.
@ -364,7 +345,7 @@ Other objects
*items*. Format units for sequences may be nested.
It is possible to pass "long" integers (integers whose value exceeds the
platform's :const:`LONG_MAX`) however no proper range checking is done --- the
platform's :c:macro:`LONG_MAX`) however no proper range checking is done --- the
most significant bits are silently truncated when the receiving field is too
small to receive the value (actually, the semantics are inherited from downcasts
in C --- your mileage may vary).
@ -399,7 +380,8 @@ inside nested parentheses. They are:
mutually exclude each other.
Note that any Python object references which are provided to the caller are
*borrowed* references; do not decrement their reference count!
*borrowed* references; do not release them
(i.e. do not decrement their reference count)!
Additional arguments passed to these functions must be addresses of variables
whose type is determined by the format string; these are used to store values
@ -409,9 +391,9 @@ what is specified for the corresponding format unit in that case.
For the conversion to succeed, the *arg* object must match the format
and the format must be exhausted. On success, the
:c:func:`PyArg_Parse\*` functions return true, otherwise they return
``PyArg_Parse*`` functions return true, otherwise they return
false and raise an appropriate exception. When the
:c:func:`PyArg_Parse\*` functions fail due to conversion failure in one
``PyArg_Parse*`` functions fail due to conversion failure in one
of the format units, the variables at the addresses corresponding to that
and the following format units are left untouched.
@ -431,21 +413,35 @@ API Functions
than a variable number of arguments.
.. c:function:: int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, char *keywords[], ...)
.. c:function:: int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, char * const *keywords, ...)
Parse the parameters of a function that takes both positional and keyword
parameters into local variables. The *keywords* argument is a
``NULL``-terminated array of keyword parameter names. Empty names denote
parameters into local variables.
The *keywords* argument is a ``NULL``-terminated array of keyword parameter
names specified as null-terminated ASCII or UTF-8 encoded C strings.
Empty names denote
:ref:`positional-only parameters <positional-only_parameter>`.
Returns true on success; on failure, it returns false and raises the
appropriate exception.
.. note::
The *keywords* parameter declaration is :c:expr:`char * const *` in C and
:c:expr:`const char * const *` in C++.
This can be overridden with the :c:macro:`PY_CXX_CONST` macro.
.. versionchanged:: 3.6
Added support for :ref:`positional-only parameters
<positional-only_parameter>`.
.. versionchanged:: 3.13
The *keywords* parameter has now type :c:expr:`char * const *` in C and
:c:expr:`const char * const *` in C++, instead of :c:expr:`char **`.
Added support for non-ASCII keyword parameter names.
.. c:function:: int PyArg_VaParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, char *keywords[], va_list vargs)
.. c:function:: int PyArg_VaParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, char * const *keywords, va_list vargs)
Identical to :c:func:`PyArg_ParseTupleAndKeywords`, except that it accepts a
va_list rather than a variable number of arguments.
@ -460,28 +456,36 @@ API Functions
.. versionadded:: 3.2
.. XXX deprecated, will be removed
.. c:function:: int PyArg_Parse(PyObject *args, const char *format, ...)
Function used to deconstruct the argument lists of "old-style" functions ---
these are functions which use the :const:`METH_OLDARGS` parameter parsing
method, which has been removed in Python 3. This is not recommended for use
in parameter parsing in new code, and most code in the standard interpreter
has been modified to no longer use this for that purpose. It does remain a
convenient way to decompose other tuples, however, and may continue to be
used for that purpose.
Parse the parameter of a function that takes a single positional parameter
into a local variable. Returns true on success; on failure, it returns
false and raises the appropriate exception.
Example::
// Function using METH_O calling convention
static PyObject*
my_function(PyObject *module, PyObject *arg)
{
int value;
if (!PyArg_Parse(arg, "i:my_function", &value)) {
return NULL;
}
// ... use value ...
}
.. c:function:: int PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, ...)
A simpler form of parameter retrieval which does not use a format string to
specify the types of the arguments. Functions which use this method to retrieve
their parameters should be declared as :const:`METH_VARARGS` in function or
their parameters should be declared as :c:macro:`METH_VARARGS` in function or
method tables. The tuple containing the actual parameters should be passed as
*args*; it must actually be a tuple. The length of the tuple must be at least
*min* and no more than *max*; *min* and *max* may be equal. Additional
arguments must be passed to the function, each of which should be a pointer to a
:c:type:`PyObject*` variable; these will be filled in with the values from
:c:expr:`PyObject*` variable; these will be filled in with the values from
*args*; they will contain :term:`borrowed references <borrowed reference>`.
The variables which correspond
to optional parameters not given by *args* will not be filled in; these should
@ -490,7 +494,7 @@ API Functions
will be set if there was a failure.
This is an example of the use of this function, taken from the sources for the
:mod:`_weakref` helper module for weak references::
:mod:`!_weakref` helper module for weak references::
static PyObject *
weakref_ref(PyObject *self, PyObject *args)
@ -510,6 +514,19 @@ API Functions
PyArg_ParseTuple(args, "O|O:ref", &object, &callback)
.. c:macro:: PY_CXX_CONST
The value to be inserted, if any, before :c:expr:`char * const *`
in the *keywords* parameter declaration of
:c:func:`PyArg_ParseTupleAndKeywords` and
:c:func:`PyArg_VaParseTupleAndKeywords`.
Default empty for C and ``const`` for C++
(:c:expr:`const char * const *`).
To override, define it to the desired value before including
:file:`Python.h`.
.. versionadded:: 3.13
---------------
Building values
@ -518,7 +535,7 @@ Building values
.. c:function:: PyObject* Py_BuildValue(const char *format, ...)
Create a new value based on a format string similar to those accepted by the
:c:func:`PyArg_Parse\*` family of functions and a sequence of values. Returns
``PyArg_Parse*`` family of functions and a sequence of values. Returns
the value or ``NULL`` in the case of an error; an exception will be raised if
``NULL`` is returned.
@ -584,58 +601,60 @@ Building values
Same as ``s#``.
``i`` (:class:`int`) [int]
Convert a plain C :c:type:`int` to a Python integer object.
Convert a plain C :c:expr:`int` to a Python integer object.
``b`` (:class:`int`) [char]
Convert a plain C :c:type:`char` to a Python integer object.
Convert a plain C :c:expr:`char` to a Python integer object.
``h`` (:class:`int`) [short int]
Convert a plain C :c:type:`short int` to a Python integer object.
Convert a plain C :c:expr:`short int` to a Python integer object.
``l`` (:class:`int`) [long int]
Convert a C :c:type:`long int` to a Python integer object.
Convert a C :c:expr:`long int` to a Python integer object.
``B`` (:class:`int`) [unsigned char]
Convert a C :c:type:`unsigned char` to a Python integer object.
Convert a C :c:expr:`unsigned char` to a Python integer object.
``H`` (:class:`int`) [unsigned short int]
Convert a C :c:type:`unsigned short int` to a Python integer object.
Convert a C :c:expr:`unsigned short int` to a Python integer object.
``I`` (:class:`int`) [unsigned int]
Convert a C :c:type:`unsigned int` to a Python integer object.
Convert a C :c:expr:`unsigned int` to a Python integer object.
``k`` (:class:`int`) [unsigned long]
Convert a C :c:type:`unsigned long` to a Python integer object.
Convert a C :c:expr:`unsigned long` to a Python integer object.
``L`` (:class:`int`) [long long]
Convert a C :c:type:`long long` to a Python integer object.
Convert a C :c:expr:`long long` to a Python integer object.
``K`` (:class:`int`) [unsigned long long]
Convert a C :c:type:`unsigned long long` to a Python integer object.
Convert a C :c:expr:`unsigned long long` to a Python integer object.
``n`` (:class:`int`) [Py_ssize_t]
``n`` (:class:`int`) [:c:type:`Py_ssize_t`]
Convert a C :c:type:`Py_ssize_t` to a Python integer.
``c`` (:class:`bytes` of length 1) [char]
Convert a C :c:type:`int` representing a byte to a Python :class:`bytes` object of
Convert a C :c:expr:`int` representing a byte to a Python :class:`bytes` object of
length 1.
``C`` (:class:`str` of length 1) [int]
Convert a C :c:type:`int` representing a character to Python :class:`str`
Convert a C :c:expr:`int` representing a character to Python :class:`str`
object of length 1.
``d`` (:class:`float`) [double]
Convert a C :c:type:`double` to a Python floating point number.
Convert a C :c:expr:`double` to a Python floating point number.
``f`` (:class:`float`) [float]
Convert a C :c:type:`float` to a Python floating point number.
Convert a C :c:expr:`float` to a Python floating point number.
``D`` (:class:`complex`) [Py_complex \*]
Convert a C :c:type:`Py_complex` structure to a Python complex number.
``O`` (object) [PyObject \*]
Pass a Python object untouched (except for its reference count, which is
incremented by one). If the object passed in is a ``NULL`` pointer, it is assumed
Pass a Python object untouched but create a new
:term:`strong reference` to it
(i.e. its reference count is incremented by one).
If the object passed in is a ``NULL`` pointer, it is assumed
that this was caused because the call producing the argument found an error and
set an exception. Therefore, :c:func:`Py_BuildValue` will return ``NULL`` but won't
raise an exception. If no exception has been raised yet, :exc:`SystemError` is
@ -645,13 +664,13 @@ Building values
Same as ``O``.
``N`` (object) [PyObject \*]
Same as ``O``, except it doesn't increment the reference count on the object.
Same as ``O``, except it doesn't create a new :term:`strong reference`.
Useful when the object is created by a call to an object constructor in the
argument list.
``O&`` (object) [*converter*, *anything*]
Convert *anything* to a Python object through a *converter* function. The
function is called with *anything* (which should be compatible with :c:type:`void*`)
function is called with *anything* (which should be compatible with :c:expr:`void*`)
as its argument and should return a "new" Python object, or ``NULL`` if an
error occurred.

View file

@ -6,11 +6,17 @@ Boolean Objects
---------------
Booleans in Python are implemented as a subclass of integers. There are only
two booleans, :const:`Py_False` and :const:`Py_True`. As such, the normal
two booleans, :c:data:`Py_False` and :c:data:`Py_True`. As such, the normal
creation and deletion functions don't apply to booleans. The following macros
are available, however.
.. c:var:: PyTypeObject PyBool_Type
This instance of :c:type:`PyTypeObject` represents the Python boolean type; it
is the same object as :class:`bool` in the Python layer.
.. c:function:: int PyBool_Check(PyObject *o)
Return true if *o* is of type :c:data:`PyBool_Type`. This function always
@ -19,29 +25,32 @@ are available, however.
.. c:var:: PyObject* Py_False
The Python ``False`` object. This object has no methods. It needs to be
treated just like any other object with respect to reference counts.
The Python ``False`` object. This object has no methods and is
:term:`immortal`.
.. versionchanged:: 3.12
:c:data:`Py_False` is :term:`immortal`.
.. c:var:: PyObject* Py_True
The Python ``True`` object. This object has no methods. It needs to be treated
just like any other object with respect to reference counts.
The Python ``True`` object. This object has no methods and is
:term:`immortal`.
.. versionchanged:: 3.12
:c:data:`Py_True` is :term:`immortal`.
.. c:macro:: Py_RETURN_FALSE
Return :const:`Py_False` from a function, properly incrementing its reference
count.
Return :c:data:`Py_False` from a function.
.. c:macro:: Py_RETURN_TRUE
Return :const:`Py_True` from a function, properly incrementing its reference
count.
Return :c:data:`Py_True` from a function.
.. c:function:: PyObject* PyBool_FromLong(long v)
Return a new reference to :const:`Py_True` or :const:`Py_False` depending on the
truth value of *v*.
Return :c:data:`Py_True` or :c:data:`Py_False`, depending on the truth value of *v*.

View file

@ -44,7 +44,7 @@ the elements exposed by an :class:`array.array` can be multi-byte values.
An example consumer of the buffer interface is the :meth:`~io.BufferedIOBase.write`
method of file objects: any object that can export a series of bytes through
the buffer interface can be written to a file. While :meth:`write` only
the buffer interface can be written to a file. While :meth:`!write` only
needs read-only access to the internal contents of the object passed to it,
other methods such as :meth:`~io.BufferedIOBase.readinto` need write access
to the contents of their argument. The buffer interface allows objects to
@ -99,10 +99,12 @@ a buffer, see :c:func:`PyObject_GetBuffer`.
For :term:`contiguous` arrays, the value points to the beginning of
the memory block.
.. c:member:: void *obj
.. c:member:: PyObject *obj
A new reference to the exporting object. The reference is owned by
the consumer and automatically decremented and set to ``NULL`` by
the consumer and automatically released
(i.e. reference count decremented)
and set to ``NULL`` by
:c:func:`PyBuffer_Release`. The field is the equivalent of the return
value of any standard C-API function.
@ -159,10 +161,7 @@ a buffer, see :c:func:`PyObject_GetBuffer`.
If it is ``0``, :c:member:`~Py_buffer.buf` points to a single item representing
a scalar. In this case, :c:member:`~Py_buffer.shape`, :c:member:`~Py_buffer.strides`
and :c:member:`~Py_buffer.suboffsets` MUST be ``NULL``.
The macro :c:macro:`PyBUF_MAX_NDIM` limits the maximum number of dimensions
to 64. Exporters MUST respect this limit, consumers of multi-dimensional
buffers SHOULD be able to handle up to :c:macro:`PyBUF_MAX_NDIM` dimensions.
The maximum number of dimensions is given by :c:macro:`PyBUF_MAX_NDIM`.
.. c:member:: Py_ssize_t *shape
@ -215,6 +214,17 @@ a buffer, see :c:func:`PyObject_GetBuffer`.
freed when the buffer is released. The consumer MUST NOT alter this
value.
Constants:
.. c:macro:: PyBUF_MAX_NDIM
The maximum number of dimensions the memory represents.
Exporters MUST respect this limit, consumers of multi-dimensional
buffers SHOULD be able to handle up to :c:macro:`!PyBUF_MAX_NDIM` dimensions.
Currently set to 64.
.. _buffer-request-types:
Buffer request types
@ -225,7 +235,7 @@ object via :c:func:`PyObject_GetBuffer`. Since the complexity of the logical
structure of the memory can vary drastically, the consumer uses the *flags*
argument to specify the exact buffer type it can handle.
All :c:data:`Py_buffer` fields are unambiguously defined by the request
All :c:type:`Py_buffer` fields are unambiguously defined by the request
type.
request-independent fields
@ -438,7 +448,7 @@ Buffer-related functions
Send a request to *exporter* to fill in *view* as specified by *flags*.
If the exporter cannot provide a buffer of the exact type, it MUST raise
:c:data:`PyExc_BufferError`, set ``view->obj`` to ``NULL`` and
:exc:`BufferError`, set ``view->obj`` to ``NULL`` and
return ``-1``.
On success, fill in *view*, set ``view->obj`` to a new reference
@ -454,7 +464,8 @@ Buffer-related functions
.. c:function:: void PyBuffer_Release(Py_buffer *view)
Release the buffer *view* and decrement the reference count for
Release the buffer *view* and release the :term:`strong reference`
(i.e. decrement the reference count) to the view's supporting object,
``view->obj``. This function MUST be called when the buffer
is no longer being used, otherwise reference leaks may occur.
@ -464,33 +475,33 @@ Buffer-related functions
.. c:function:: Py_ssize_t PyBuffer_SizeFromFormat(const char *format)
Return the implied :c:data:`~Py_buffer.itemsize` from :c:data:`~Py_buffer.format`.
Return the implied :c:member:`~Py_buffer.itemsize` from :c:member:`~Py_buffer.format`.
On error, raise an exception and return -1.
.. versionadded:: 3.9
.. c:function:: int PyBuffer_IsContiguous(Py_buffer *view, char order)
.. c:function:: int PyBuffer_IsContiguous(const Py_buffer *view, char order)
Return ``1`` if the memory defined by the *view* is C-style (*order* is
``'C'``) or Fortran-style (*order* is ``'F'``) :term:`contiguous` or either one
(*order* is ``'A'``). Return ``0`` otherwise. This function always succeeds.
.. c:function:: void* PyBuffer_GetPointer(Py_buffer *view, Py_ssize_t *indices)
.. c:function:: void* PyBuffer_GetPointer(const Py_buffer *view, const Py_ssize_t *indices)
Get the memory area pointed to by the *indices* inside the given *view*.
*indices* must point to an array of ``view->ndim`` indices.
.. c:function:: int PyBuffer_FromContiguous(Py_buffer *view, void *buf, Py_ssize_t len, char fort)
.. c:function:: int PyBuffer_FromContiguous(const Py_buffer *view, const void *buf, Py_ssize_t len, char fort)
Copy contiguous *len* bytes from *buf* to *view*.
*fort* can be ``'C'`` or ``'F'`` (for C-style or Fortran-style ordering).
``0`` is returned on success, ``-1`` on error.
.. c:function:: int PyBuffer_ToContiguous(void *buf, Py_buffer *src, Py_ssize_t len, char order)
.. c:function:: int PyBuffer_ToContiguous(void *buf, const Py_buffer *src, Py_ssize_t len, char order)
Copy *len* bytes from *src* to its contiguous representation in *buf*.
*order* can be ``'C'`` or ``'F'`` or ``'A'`` (for C-style or Fortran-style
@ -499,6 +510,13 @@ Buffer-related functions
This function fails if *len* != *src->len*.
.. c:function:: int PyObject_CopyData(PyObject *dest, PyObject *src)
Copy data from *src* to *dest* buffer. Can convert between C-style and
or Fortran-style buffers.
``0`` is returned on success, ``-1`` on error.
.. c:function:: void PyBuffer_FillContiguousStrides(int ndims, Py_ssize_t *shape, Py_ssize_t *strides, int itemsize, char order)
Fill the *strides* array with byte-strides of a :term:`contiguous` (C-style if
@ -517,7 +535,7 @@ Buffer-related functions
and :c:macro:`PyBUF_WRITABLE` is set in *flags*.
On success, set ``view->obj`` to a new reference to *exporter* and
return 0. Otherwise, raise :c:data:`PyExc_BufferError`, set
return 0. Otherwise, raise :exc:`BufferError`, set
``view->obj`` to ``NULL`` and return ``-1``;
If this function is used as part of a :ref:`getbufferproc <buffer-structs>`,

View file

@ -5,7 +5,7 @@
Byte Array Objects
------------------
.. index:: object: bytearray
.. index:: pair: object; bytearray
.. c:type:: PyByteArrayObject
@ -42,8 +42,6 @@ Direct API functions
Return a new bytearray object from any object, *o*, that implements the
:ref:`buffer protocol <bufferobjects>`.
.. XXX expand about the buffer protocol, at least somewhere
.. c:function:: PyObject* PyByteArray_FromStringAndSize(const char *string, Py_ssize_t len)
@ -79,9 +77,9 @@ These macros trade safety for speed and they don't check pointers.
.. c:function:: char* PyByteArray_AS_STRING(PyObject *bytearray)
Macro version of :c:func:`PyByteArray_AsString`.
Similar to :c:func:`PyByteArray_AsString`, but without error checking.
.. c:function:: Py_ssize_t PyByteArray_GET_SIZE(PyObject *bytearray)
Macro version of :c:func:`PyByteArray_Size`.
Similar to :c:func:`PyByteArray_Size`, but without error checking.

View file

@ -5,10 +5,10 @@
Bytes Objects
-------------
These functions raise :exc:`TypeError` when expecting a bytes parameter and are
These functions raise :exc:`TypeError` when expecting a bytes parameter and
called with a non-bytes parameter.
.. index:: object: bytes
.. index:: pair: object; bytes
.. c:type:: PyBytesObject
@ -58,48 +58,45 @@ called with a non-bytes parameter.
.. % XXX: This should be exactly the same as the table in PyErr_Format.
.. % One should just refer to the other.
.. % XXX: The descriptions for %zd and %zu are wrong, but the truth is complicated
.. % because not all compilers support the %z width modifier -- we fake it
.. % when necessary via interpolating PY_FORMAT_SIZE_T.
.. tabularcolumns:: |l|l|L|
+-------------------+---------------+--------------------------------+
| Format Characters | Type | Comment |
+===================+===============+================================+
| :attr:`%%` | *n/a* | The literal % character. |
| ``%%`` | *n/a* | The literal % character. |
+-------------------+---------------+--------------------------------+
| :attr:`%c` | int | A single byte, |
| ``%c`` | int | A single byte, |
| | | represented as a C int. |
+-------------------+---------------+--------------------------------+
| :attr:`%d` | int | Equivalent to |
| ``%d`` | int | Equivalent to |
| | | ``printf("%d")``. [1]_ |
+-------------------+---------------+--------------------------------+
| :attr:`%u` | unsigned int | Equivalent to |
| ``%u`` | unsigned int | Equivalent to |
| | | ``printf("%u")``. [1]_ |
+-------------------+---------------+--------------------------------+
| :attr:`%ld` | long | Equivalent to |
| ``%ld`` | long | Equivalent to |
| | | ``printf("%ld")``. [1]_ |
+-------------------+---------------+--------------------------------+
| :attr:`%lu` | unsigned long | Equivalent to |
| ``%lu`` | unsigned long | Equivalent to |
| | | ``printf("%lu")``. [1]_ |
+-------------------+---------------+--------------------------------+
| :attr:`%zd` | Py_ssize_t | Equivalent to |
| | | ``printf("%zd")``. [1]_ |
| ``%zd`` | :c:type:`\ | Equivalent to |
| | Py_ssize_t` | ``printf("%zd")``. [1]_ |
+-------------------+---------------+--------------------------------+
| :attr:`%zu` | size_t | Equivalent to |
| ``%zu`` | size_t | Equivalent to |
| | | ``printf("%zu")``. [1]_ |
+-------------------+---------------+--------------------------------+
| :attr:`%i` | int | Equivalent to |
| ``%i`` | int | Equivalent to |
| | | ``printf("%i")``. [1]_ |
+-------------------+---------------+--------------------------------+
| :attr:`%x` | int | Equivalent to |
| ``%x`` | int | Equivalent to |
| | | ``printf("%x")``. [1]_ |
+-------------------+---------------+--------------------------------+
| :attr:`%s` | const char\* | A null-terminated C character |
| ``%s`` | const char\* | A null-terminated C character |
| | | array. |
+-------------------+---------------+--------------------------------+
| :attr:`%p` | const void\* | The hex representation of a C |
| ``%p`` | const void\* | The hex representation of a C |
| | | pointer. Mostly equivalent to |
| | | ``printf("%p")`` except that |
| | | it is guaranteed to start with |
@ -134,7 +131,7 @@ called with a non-bytes parameter.
.. c:function:: Py_ssize_t PyBytes_GET_SIZE(PyObject *o)
Macro form of :c:func:`PyBytes_Size` but without error checking.
Similar to :c:func:`PyBytes_Size`, but without error checking.
.. c:function:: char* PyBytes_AsString(PyObject *o)
@ -151,13 +148,14 @@ called with a non-bytes parameter.
.. c:function:: char* PyBytes_AS_STRING(PyObject *string)
Macro form of :c:func:`PyBytes_AsString` but without error checking.
Similar to :c:func:`PyBytes_AsString`, but without error checking.
.. c:function:: int PyBytes_AsStringAndSize(PyObject *obj, char **buffer, Py_ssize_t *length)
Return the null-terminated contents of the object *obj*
through the output variables *buffer* and *length*.
Returns ``0`` on success.
If *length* is ``NULL``, the bytes object
may not contain embedded null bytes;
@ -187,8 +185,8 @@ called with a non-bytes parameter.
.. c:function:: void PyBytes_ConcatAndDel(PyObject **bytes, PyObject *newpart)
Create a new bytes object in *\*bytes* containing the contents of *newpart*
appended to *bytes*. This version decrements the reference count of
*newpart*.
appended to *bytes*. This version releases the :term:`strong reference`
to *newpart* (i.e. decrements its reference count).
.. c:function:: int _PyBytes_Resize(PyObject **bytes, Py_ssize_t newsize)

View file

@ -26,7 +26,7 @@ This convention is not only used by *tp_call*:
:c:member:`~PyTypeObject.tp_new` and :c:member:`~PyTypeObject.tp_init`
also pass arguments this way.
To call an object, use :c:func:`PyObject_Call` or other
To call an object, use :c:func:`PyObject_Call` or another
:ref:`call API <capi-call>`.
@ -57,13 +57,22 @@ This bears repeating:
A class supporting vectorcall **must** also implement
:c:member:`~PyTypeObject.tp_call` with the same semantics.
.. versionchanged:: 3.12
The :c:macro:`Py_TPFLAGS_HAVE_VECTORCALL` flag is now removed from a class
when the class's :py:meth:`~object.__call__` method is reassigned.
(This internally sets :c:member:`~PyTypeObject.tp_call` only, and thus
may make it behave differently than the vectorcall function.)
In earlier Python versions, vectorcall should only be used with
:c:macro:`immutable <Py_TPFLAGS_IMMUTABLETYPE>` or static types.
A class should not implement vectorcall if that would be slower
than *tp_call*. For example, if the callee needs to convert
the arguments to an args tuple and kwargs dict anyway, then there is no point
in implementing vectorcall.
Classes can implement the vectorcall protocol by enabling the
:const:`Py_TPFLAGS_HAVE_VECTORCALL` flag and setting
:c:macro:`Py_TPFLAGS_HAVE_VECTORCALL` flag and setting
:c:member:`~PyTypeObject.tp_vectorcall_offset` to the offset inside the
object structure where a *vectorcallfunc* appears.
This is a pointer to a function with the following signature:
@ -75,7 +84,7 @@ This is a pointer to a function with the following signature:
values of the keyword arguments.
This can be *NULL* if there are no arguments.
- *nargsf* is the number of positional arguments plus possibly the
:const:`PY_VECTORCALL_ARGUMENTS_OFFSET` flag.
:c:macro:`PY_VECTORCALL_ARGUMENTS_OFFSET` flag.
To get the actual number of positional arguments from *nargsf*,
use :c:func:`PyVectorcall_NARGS`.
- *kwnames* is a tuple containing the names of the keyword arguments;
@ -95,28 +104,17 @@ This is a pointer to a function with the following signature:
``args[0]`` may be changed.
Whenever they can do so cheaply (without additional allocation), callers
are encouraged to use :const:`PY_VECTORCALL_ARGUMENTS_OFFSET`.
are encouraged to use :c:macro:`PY_VECTORCALL_ARGUMENTS_OFFSET`.
Doing so will allow callables such as bound methods to make their onward
calls (which include a prepended *self* argument) very efficiently.
.. versionadded:: 3.8
To call an object that implements vectorcall, use a :ref:`call API <capi-call>`
function as with any other callable.
:c:func:`PyObject_Vectorcall` will usually be most efficient.
.. note::
In CPython 3.8, the vectorcall API and related functions were available
provisionally under names with a leading underscore:
``_PyObject_Vectorcall``, ``_Py_TPFLAGS_HAVE_VECTORCALL``,
``_PyObject_VectorcallMethod``, ``_PyVectorcall_Function``,
``_PyObject_CallOneArg``, ``_PyObject_CallMethodNoArgs``,
``_PyObject_CallMethodOneArg``.
Additionally, ``PyObject_VectorcallDict`` was available as
``_PyObject_FastCallDict``.
The old names are still defined as aliases of the new, non-underscored names.
Recursion Control
.................
@ -144,8 +142,6 @@ Vectorcall Support API
However, the function ``PyVectorcall_NARGS`` should be used to allow
for future extensions.
This function is not part of the :ref:`limited API <stable>`.
.. versionadded:: 3.8
.. c:function:: vectorcallfunc PyVectorcall_Function(PyObject *op)
@ -158,9 +154,7 @@ Vectorcall Support API
This is mostly useful to check whether or not *op* supports vectorcall,
which can be done by checking ``PyVectorcall_Function(op) != NULL``.
This function is not part of the :ref:`limited API <stable>`.
.. versionadded:: 3.8
.. versionadded:: 3.9
.. c:function:: PyObject* PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *dict)
@ -169,11 +163,9 @@ Vectorcall Support API
This is a specialized function, intended to be put in the
:c:member:`~PyTypeObject.tp_call` slot or be used in an implementation of ``tp_call``.
It does not check the :const:`Py_TPFLAGS_HAVE_VECTORCALL` flag
It does not check the :c:macro:`Py_TPFLAGS_HAVE_VECTORCALL` flag
and it does not fall back to ``tp_call``.
This function is not part of the :ref:`limited API <stable>`.
.. versionadded:: 3.8
@ -256,8 +248,6 @@ please see individual documentation for details.
Return the result of the call on success, or raise an exception and return
*NULL* on failure.
This function is not part of the :ref:`limited API <stable>`.
.. versionadded:: 3.9
@ -283,7 +273,7 @@ please see individual documentation for details.
This is the equivalent of the Python expression: ``callable(*args)``.
Note that if you only pass :c:type:`PyObject *` args,
Note that if you only pass :c:expr:`PyObject *` args,
:c:func:`PyObject_CallFunctionObjArgs` is a faster alternative.
.. versionchanged:: 3.4
@ -304,7 +294,7 @@ please see individual documentation for details.
This is the equivalent of the Python expression:
``obj.name(arg1, arg2, ...)``.
Note that if you only pass :c:type:`PyObject *` args,
Note that if you only pass :c:expr:`PyObject *` args,
:c:func:`PyObject_CallMethodObjArgs` is a faster alternative.
.. versionchanged:: 3.4
@ -314,7 +304,7 @@ please see individual documentation for details.
.. c:function:: PyObject* PyObject_CallFunctionObjArgs(PyObject *callable, ...)
Call a callable Python object *callable*, with a variable number of
:c:type:`PyObject *` arguments. The arguments are provided as a variable number
:c:expr:`PyObject *` arguments. The arguments are provided as a variable number
of parameters followed by *NULL*.
Return the result of the call on success, or raise an exception and return
@ -328,7 +318,7 @@ please see individual documentation for details.
Call a method of the Python object *obj*, where the name of the method is given as a
Python string object in *name*. It is called with a variable number of
:c:type:`PyObject *` arguments. The arguments are provided as a variable number
:c:expr:`PyObject *` arguments. The arguments are provided as a variable number
of parameters followed by *NULL*.
Return the result of the call on success, or raise an exception and return
@ -343,8 +333,6 @@ please see individual documentation for details.
Return the result of the call on success, or raise an exception and return
*NULL* on failure.
This function is not part of the :ref:`limited API <stable>`.
.. versionadded:: 3.9
@ -357,8 +345,6 @@ please see individual documentation for details.
Return the result of the call on success, or raise an exception and return
*NULL* on failure.
This function is not part of the :ref:`limited API <stable>`.
.. versionadded:: 3.9
@ -372,8 +358,6 @@ please see individual documentation for details.
Return the result of the call on success, or raise an exception and return
*NULL* on failure.
This function is not part of the :ref:`limited API <stable>`.
.. versionadded:: 3.9
.. c:function:: PyObject* PyObject_VectorcallDict(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwdict)
@ -388,8 +372,6 @@ please see individual documentation for details.
already has a dictionary ready to use for the keyword arguments,
but not a tuple for the positional arguments.
This function is not part of the :ref:`limited API <stable>`.
.. versionadded:: 3.9
.. c:function:: PyObject* PyObject_VectorcallMethod(PyObject *name, PyObject *const *args, size_t nargsf, PyObject *kwnames)
@ -399,19 +381,17 @@ please see individual documentation for details.
*args[0]*, and the *args* array starting at *args[1]* represents the arguments
of the call. There must be at least one positional argument.
*nargsf* is the number of positional arguments including *args[0]*,
plus :const:`PY_VECTORCALL_ARGUMENTS_OFFSET` if the value of ``args[0]`` may
plus :c:macro:`PY_VECTORCALL_ARGUMENTS_OFFSET` if the value of ``args[0]`` may
temporarily be changed. Keyword arguments can be passed just like in
:c:func:`PyObject_Vectorcall`.
If the object has the :const:`Py_TPFLAGS_METHOD_DESCRIPTOR` feature,
If the object has the :c:macro:`Py_TPFLAGS_METHOD_DESCRIPTOR` feature,
this will call the unbound method object with the full
*args* vector as arguments.
Return the result of the call on success, or raise an exception and return
*NULL* on failure.
This function is not part of the :ref:`limited API <stable>`.
.. versionadded:: 3.9

View file

@ -5,7 +5,7 @@
Capsules
--------
.. index:: object: Capsule
.. index:: pair: object; Capsule
Refer to :ref:`using-capsules` for more information on using these objects.
@ -15,7 +15,7 @@ Refer to :ref:`using-capsules` for more information on using these objects.
.. c:type:: PyCapsule
This subtype of :c:type:`PyObject` represents an opaque value, useful for C
extension modules who need to pass an opaque value (as a :c:type:`void*`
extension modules who need to pass an opaque value (as a :c:expr:`void*`
pointer) through Python code to other C code. It is often used to make a C
function pointer defined in one module available to other modules, so the
regular import mechanism can be used to access C APIs defined in dynamically
@ -64,7 +64,7 @@ Refer to :ref:`using-capsules` for more information on using these objects.
The *name* parameter must compare exactly to the name stored in the capsule.
If the name stored in the capsule is ``NULL``, the *name* passed in must also
be ``NULL``. Python uses the C function :c:func:`strcmp` to compare capsule
be ``NULL``. Python uses the C function :c:func:`!strcmp` to compare capsule
names.
@ -103,13 +103,14 @@ Refer to :ref:`using-capsules` for more information on using these objects.
Import a pointer to a C object from a capsule attribute in a module. The
*name* parameter should specify the full name to the attribute, as in
``module.attribute``. The *name* stored in the capsule must match this
string exactly. If *no_block* is true, import the module without blocking
(using :c:func:`PyImport_ImportModuleNoBlock`). If *no_block* is false,
import the module conventionally (using :c:func:`PyImport_ImportModule`).
string exactly.
Return the capsule's internal *pointer* on success. On failure, set an
exception and return ``NULL``.
.. versionchanged:: 3.3
*no_block* has no effect anymore.
.. c:function:: int PyCapsule_IsValid(PyObject *capsule, const char *name)
@ -120,7 +121,7 @@ Refer to :ref:`using-capsules` for more information on using these objects.
compared.)
In other words, if :c:func:`PyCapsule_IsValid` returns a true value, calls to
any of the accessors (any function starting with :c:func:`PyCapsule_Get`) are
any of the accessors (any function starting with ``PyCapsule_Get``) are
guaranteed to succeed.
Return a nonzero value if the object is valid and matches the name passed in.

View file

@ -25,7 +25,7 @@ Cell objects are not likely to be useful elsewhere.
The type object corresponding to cell objects.
.. c:function:: int PyCell_Check(ob)
.. c:function:: int PyCell_Check(PyObject *ob)
Return true if *ob* is a cell object; *ob* must not be ``NULL``. This
function always succeeds.

View file

@ -1,9 +1,9 @@
.. highlight:: c
.. _codeobjects:
.. index:: object; code, code object
.. _codeobjects:
Code Objects
------------
@ -33,24 +33,52 @@ bound into a function.
Return the number of free variables in *co*.
.. c:function:: PyCodeObject* PyCode_New(int argcount, int kwonlyargcount, int nlocals, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, int firstlineno, PyObject *lnotab)
.. c:function:: PyCodeObject* PyUnstable_Code_New(int argcount, int kwonlyargcount, int nlocals, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, PyObject *qualname, int firstlineno, PyObject *linetable, PyObject *exceptiontable)
Return a new code object. If you need a dummy code object to create a frame,
use :c:func:`PyCode_NewEmpty` instead. Calling :c:func:`PyCode_New` directly
can bind you to a precise Python version since the definition of the bytecode
changes often.
use :c:func:`PyCode_NewEmpty` instead.
.. c:function:: PyCodeObject* PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount, int nlocals, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, int firstlineno, PyObject *lnotab)
Since the definition of the bytecode changes often, calling
:c:func:`PyUnstable_Code_New` directly can bind you to a precise Python version.
Similar to :c:func:`PyCode_New`, but with an extra "posonlyargcount" for positional-only arguments.
The many arguments of this function are inter-dependent in complex
ways, meaning that subtle changes to values are likely to result in incorrect
execution or VM crashes. Use this function only with extreme care.
.. versionadded:: 3.8
.. versionchanged:: 3.11
Added ``qualname`` and ``exceptiontable`` parameters.
.. index:: single: PyCode_New
.. versionchanged:: 3.12
Renamed from ``PyCode_New`` as part of :ref:`unstable-c-api`.
The old name is deprecated, but will remain available until the
signature changes again.
.. c:function:: PyCodeObject* PyUnstable_Code_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount, int nlocals, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, PyObject *qualname, int firstlineno, PyObject *linetable, PyObject *exceptiontable)
Similar to :c:func:`PyUnstable_Code_New`, but with an extra "posonlyargcount" for positional-only arguments.
The same caveats that apply to ``PyUnstable_Code_New`` also apply to this function.
.. index:: single: PyCode_NewWithPosOnlyArgs
.. versionadded:: 3.8 as ``PyCode_NewWithPosOnlyArgs``
.. versionchanged:: 3.11
Added ``qualname`` and ``exceptiontable`` parameters.
.. versionchanged:: 3.12
Renamed to ``PyUnstable_Code_NewWithPosOnlyArgs``.
The old name is deprecated, but will remain available until the
signature changes again.
.. c:function:: PyCodeObject* PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
Return a new empty code object with the specified filename,
function name, and first line number. It is illegal to
:func:`exec` or :func:`eval` the resulting code object.
function name, and first line number. The resulting code
object will raise an ``Exception`` if executed.
.. c:function:: int PyCode_Addr2Line(PyCodeObject *co, int byte_offset)
@ -58,7 +86,7 @@ bound into a function.
If you just need the line number of a frame, use :c:func:`PyFrame_GetLineNumber` instead.
For efficiently iterating over the line numbers in a code object, use `the API described in PEP 626
<https://www.python.org/dev/peps/pep-0626/#out-of-process-debuggers-and-profilers>`_.
<https://peps.python.org/pep-0626/#out-of-process-debuggers-and-profilers>`_.
.. c:function:: int PyCode_Addr2Location(PyObject *co, int byte_offset, int *start_line, int *start_column, int *end_line, int *end_column)
@ -67,3 +95,170 @@ bound into a function.
information is not available for any particular element.
Returns ``1`` if the function succeeds and 0 otherwise.
.. versionadded:: 3.11
.. c:function:: PyObject* PyCode_GetCode(PyCodeObject *co)
Equivalent to the Python code ``getattr(co, 'co_code')``.
Returns a strong reference to a :c:type:`PyBytesObject` representing the
bytecode in a code object. On error, ``NULL`` is returned and an exception
is raised.
This ``PyBytesObject`` may be created on-demand by the interpreter and does
not necessarily represent the bytecode actually executed by CPython. The
primary use case for this function is debuggers and profilers.
.. versionadded:: 3.11
.. c:function:: PyObject* PyCode_GetVarnames(PyCodeObject *co)
Equivalent to the Python code ``getattr(co, 'co_varnames')``.
Returns a new reference to a :c:type:`PyTupleObject` containing the names of
the local variables. On error, ``NULL`` is returned and an exception
is raised.
.. versionadded:: 3.11
.. c:function:: PyObject* PyCode_GetCellvars(PyCodeObject *co)
Equivalent to the Python code ``getattr(co, 'co_cellvars')``.
Returns a new reference to a :c:type:`PyTupleObject` containing the names of
the local variables that are referenced by nested functions. On error, ``NULL``
is returned and an exception is raised.
.. versionadded:: 3.11
.. c:function:: PyObject* PyCode_GetFreevars(PyCodeObject *co)
Equivalent to the Python code ``getattr(co, 'co_freevars')``.
Returns a new reference to a :c:type:`PyTupleObject` containing the names of
the free variables. On error, ``NULL`` is returned and an exception is raised.
.. versionadded:: 3.11
.. c:function:: int PyCode_AddWatcher(PyCode_WatchCallback callback)
Register *callback* as a code object watcher for the current interpreter.
Return an ID which may be passed to :c:func:`PyCode_ClearWatcher`.
In case of error (e.g. no more watcher IDs available),
return ``-1`` and set an exception.
.. versionadded:: 3.12
.. c:function:: int PyCode_ClearWatcher(int watcher_id)
Clear watcher identified by *watcher_id* previously returned from
:c:func:`PyCode_AddWatcher` for the current interpreter.
Return ``0`` on success, or ``-1`` and set an exception on error
(e.g. if the given *watcher_id* was never registered.)
.. versionadded:: 3.12
.. c:type:: PyCodeEvent
Enumeration of possible code object watcher events:
- ``PY_CODE_EVENT_CREATE``
- ``PY_CODE_EVENT_DESTROY``
.. versionadded:: 3.12
.. c:type:: int (*PyCode_WatchCallback)(PyCodeEvent event, PyCodeObject* co)
Type of a code object watcher callback function.
If *event* is ``PY_CODE_EVENT_CREATE``, then the callback is invoked
after `co` has been fully initialized. Otherwise, the callback is invoked
before the destruction of *co* takes place, so the prior state of *co*
can be inspected.
If *event* is ``PY_CODE_EVENT_DESTROY``, taking a reference in the callback
to the about-to-be-destroyed code object will resurrect it and prevent it
from being freed at this time. When the resurrected object is destroyed
later, any watcher callbacks active at that time will be called again.
Users of this API should not rely on internal runtime implementation
details. Such details may include, but are not limited to, the exact
order and timing of creation and destruction of code objects. While
changes in these details may result in differences observable by watchers
(including whether a callback is invoked or not), it does not change
the semantics of the Python code being executed.
If the callback sets an exception, it must return ``-1``; this exception will
be printed as an unraisable exception using :c:func:`PyErr_WriteUnraisable`.
Otherwise it should return ``0``.
There may already be a pending exception set on entry to the callback. In
this case, the callback should return ``0`` with the same exception still
set. This means the callback may not call any other API that can set an
exception unless it saves and clears the exception state first, and restores
it before returning.
.. versionadded:: 3.12
Extra information
-----------------
To support low-level extensions to frame evaluation, such as external
just-in-time compilers, it is possible to attach arbitrary extra data to
code objects.
These functions are part of the unstable C API tier:
this functionality is a CPython implementation detail, and the API
may change without deprecation warnings.
.. c:function:: Py_ssize_t PyUnstable_Eval_RequestCodeExtraIndex(freefunc free)
Return a new an opaque index value used to adding data to code objects.
You generally call this function once (per interpreter) and use the result
with ``PyCode_GetExtra`` and ``PyCode_SetExtra`` to manipulate
data on individual code objects.
If *free* is not ``NULL``: when a code object is deallocated,
*free* will be called on non-``NULL`` data stored under the new index.
Use :c:func:`Py_DecRef` when storing :c:type:`PyObject`.
.. index:: single: _PyEval_RequestCodeExtraIndex
.. versionadded:: 3.6 as ``_PyEval_RequestCodeExtraIndex``
.. versionchanged:: 3.12
Renamed to ``PyUnstable_Eval_RequestCodeExtraIndex``.
The old private name is deprecated, but will be available until the API
changes.
.. c:function:: int PyUnstable_Code_GetExtra(PyObject *code, Py_ssize_t index, void **extra)
Set *extra* to the extra data stored under the given index.
Return 0 on success. Set an exception and return -1 on failure.
If no data was set under the index, set *extra* to ``NULL`` and return
0 without setting an exception.
.. index:: single: _PyCode_GetExtra
.. versionadded:: 3.6 as ``_PyCode_GetExtra``
.. versionchanged:: 3.12
Renamed to ``PyUnstable_Code_GetExtra``.
The old private name is deprecated, but will be available until the API
changes.
.. c:function:: int PyUnstable_Code_SetExtra(PyObject *code, Py_ssize_t index, void *extra)
Set the extra data stored under the given index to *extra*.
Return 0 on success. Set an exception and return -1 on failure.
.. index:: single: _PyCode_SetExtra
.. versionadded:: 3.6 as ``_PyCode_SetExtra``
.. versionchanged:: 3.12
Renamed to ``PyUnstable_Code_SetExtra``.
The old private name is deprecated, but will be available until the API
changes.

View file

@ -7,7 +7,7 @@ Codec registry and support functions
Register a new codec search function.
As side effect, this tries to load the :mod:`encodings` package, if not yet
As side effect, this tries to load the :mod:`!encodings` package, if not yet
done, to make sure that it is always first in the list of search functions.
.. c:function:: int PyCodec_Unregister(PyObject *search_function)

View file

@ -5,7 +5,7 @@
Complex Number Objects
----------------------
.. index:: object: complex number
.. index:: pair: object; complex number
Python's complex number objects are implemented as two distinct types when
viewed from the C API: one is the Python object exposed to Python programs, and
@ -64,7 +64,7 @@ pointers. This is consistent throughout the API.
representation.
If *divisor* is null, this method returns zero and sets
:c:data:`errno` to :c:data:`EDOM`.
:c:data:`errno` to :c:macro:`!EDOM`.
.. c:function:: Py_complex _Py_c_pow(Py_complex num, Py_complex exp)
@ -73,7 +73,7 @@ pointers. This is consistent throughout the API.
representation.
If *num* is null and *exp* is not a positive real number,
this method returns zero and sets :c:data:`errno` to :c:data:`EDOM`.
this method returns zero and sets :c:data:`errno` to :c:macro:`!EDOM`.
Complex Numbers as Python Objects
@ -115,24 +115,24 @@ Complex Numbers as Python Objects
.. c:function:: double PyComplex_RealAsDouble(PyObject *op)
Return the real part of *op* as a C :c:type:`double`.
Return the real part of *op* as a C :c:expr:`double`.
.. c:function:: double PyComplex_ImagAsDouble(PyObject *op)
Return the imaginary part of *op* as a C :c:type:`double`.
Return the imaginary part of *op* as a C :c:expr:`double`.
.. c:function:: Py_complex PyComplex_AsCComplex(PyObject *op)
Return the :c:type:`Py_complex` value of the complex number *op*.
If *op* is not a Python complex number object but has a :meth:`__complex__`
If *op* is not a Python complex number object but has a :meth:`~object.__complex__`
method, this method will first be called to convert *op* to a Python complex
number object. If ``__complex__()`` is not defined then it falls back to
:meth:`__float__`. If ``__float__()`` is not defined then it falls back
to :meth:`__index__`. Upon failure, this method returns ``-1.0`` as a real
number object. If :meth:`!__complex__` is not defined then it falls back to
:meth:`~object.__float__`. If :meth:`!__float__` is not defined then it falls back
to :meth:`~object.__index__`. Upon failure, this method returns ``-1.0`` as a real
value.
.. versionchanged:: 3.8
Use :meth:`__index__` if available.
Use :meth:`~object.__index__` if available.

View file

@ -40,7 +40,7 @@ This section describes Python type objects and the singleton object ``None``.
Numeric Objects
===============
.. index:: object: numeric
.. index:: pair: object; numeric
.. toctree::
@ -55,7 +55,7 @@ Numeric Objects
Sequence Objects
================
.. index:: object: sequence
.. index:: pair: object; sequence
Generic operations on sequence objects were discussed in the previous chapter;
this section deals with the specific kinds of sequence objects that are
@ -77,7 +77,7 @@ intrinsic to the Python language.
Container Objects
=================
.. index:: object: mapping
.. index:: pair: object; mapping
.. toctree::
@ -111,6 +111,7 @@ Other Objects
memoryview.rst
weakref.rst
capsule.rst
frame.rst
gen.rst
coro.rst
contextvars.rst

View file

@ -28,7 +28,8 @@ not.
The wrappers ensure that ``str[size-1]`` is always ``'\0'`` upon return. They
never write more than *size* bytes (including the trailing ``'\0'``) into str.
Both functions require that ``str != NULL``, ``size > 0``, ``format != NULL``
and ``size < INT_MAX``.
and ``size < INT_MAX``. Note that this means there is no equivalent to the C99
``n = snprintf(NULL, 0, ...)`` which would determine the necessary buffer size.
The return value (*rv*) for these functions should be interpreted as follows:
@ -49,7 +50,7 @@ The following functions provide locale-independent string to number conversions.
.. c:function:: double PyOS_string_to_double(const char *s, char **endptr, PyObject *overflow_exception)
Convert a string ``s`` to a :c:type:`double`, raising a Python
Convert a string ``s`` to a :c:expr:`double`, raising a Python
exception on failure. The set of accepted strings corresponds to
the set of strings accepted by Python's :func:`float` constructor,
except that ``s`` must not have leading or trailing whitespace.
@ -83,7 +84,7 @@ The following functions provide locale-independent string to number conversions.
.. c:function:: char* PyOS_double_to_string(double val, char format_code, int precision, int flags, int *ptype)
Convert a :c:type:`double` *val* to a string using supplied
Convert a :c:expr:`double` *val* to a string using supplied
*format_code*, *precision*, and *flags*.
*format_code* must be one of ``'e'``, ``'E'``, ``'f'``, ``'F'``,
@ -118,10 +119,10 @@ The following functions provide locale-independent string to number conversions.
.. c:function:: int PyOS_stricmp(const char *s1, const char *s2)
Case insensitive comparison of strings. The function works almost
identically to :c:func:`strcmp` except that it ignores the case.
identically to :c:func:`!strcmp` except that it ignores the case.
.. c:function:: int PyOS_strnicmp(const char *s1, const char *s2, Py_ssize_t size)
Case insensitive comparison of strings. The function works almost
identically to :c:func:`strncmp` except that it ignores the case.
identically to :c:func:`!strncmp` except that it ignores the case.

View file

@ -8,11 +8,54 @@ DateTime Objects
Various date and time objects are supplied by the :mod:`datetime` module.
Before using any of these functions, the header file :file:`datetime.h` must be
included in your source (note that this is not included by :file:`Python.h`),
and the macro :c:macro:`PyDateTime_IMPORT` must be invoked, usually as part of
and the macro :c:macro:`!PyDateTime_IMPORT` must be invoked, usually as part of
the module initialisation function. The macro puts a pointer to a C structure
into a static variable, :c:data:`PyDateTimeAPI`, that is used by the following
into a static variable, :c:data:`!PyDateTimeAPI`, that is used by the following
macros.
.. c:type:: PyDateTime_Date
This subtype of :c:type:`PyObject` represents a Python date object.
.. c:type:: PyDateTime_DateTime
This subtype of :c:type:`PyObject` represents a Python datetime object.
.. c:type:: PyDateTime_Time
This subtype of :c:type:`PyObject` represents a Python time object.
.. c:type:: PyDateTime_Delta
This subtype of :c:type:`PyObject` represents the difference between two datetime values.
.. c:var:: PyTypeObject PyDateTime_DateType
This instance of :c:type:`PyTypeObject` represents the Python date type;
it is the same object as :class:`datetime.date` in the Python layer.
.. c:var:: PyTypeObject PyDateTime_DateTimeType
This instance of :c:type:`PyTypeObject` represents the Python datetime type;
it is the same object as :class:`datetime.datetime` in the Python layer.
.. c:var:: PyTypeObject PyDateTime_TimeType
This instance of :c:type:`PyTypeObject` represents the Python time type;
it is the same object as :class:`datetime.time` in the Python layer.
.. c:var:: PyTypeObject PyDateTime_DeltaType
This instance of :c:type:`PyTypeObject` represents Python type for
the difference between two datetime values;
it is the same object as :class:`datetime.timedelta` in the Python layer.
.. c:var:: PyTypeObject PyDateTime_TZInfoType
This instance of :c:type:`PyTypeObject` represents the Python time zone info type;
it is the same object as :class:`datetime.tzinfo` in the Python layer.
Macro for access to the UTC singleton:
.. c:var:: PyObject* PyDateTime_TimeZone_UTC
@ -28,7 +71,7 @@ Type-check macros:
.. c:function:: int PyDate_Check(PyObject *ob)
Return true if *ob* is of type :c:data:`PyDateTime_DateType` or a subtype of
:c:data:`PyDateTime_DateType`. *ob* must not be ``NULL``. This function always
:c:data:`!PyDateTime_DateType`. *ob* must not be ``NULL``. This function always
succeeds.
@ -41,7 +84,7 @@ Type-check macros:
.. c:function:: int PyDateTime_Check(PyObject *ob)
Return true if *ob* is of type :c:data:`PyDateTime_DateTimeType` or a subtype of
:c:data:`PyDateTime_DateTimeType`. *ob* must not be ``NULL``. This function always
:c:data:`!PyDateTime_DateTimeType`. *ob* must not be ``NULL``. This function always
succeeds.
@ -54,7 +97,7 @@ Type-check macros:
.. c:function:: int PyTime_Check(PyObject *ob)
Return true if *ob* is of type :c:data:`PyDateTime_TimeType` or a subtype of
:c:data:`PyDateTime_TimeType`. *ob* must not be ``NULL``. This function always
:c:data:`!PyDateTime_TimeType`. *ob* must not be ``NULL``. This function always
succeeds.
@ -67,7 +110,7 @@ Type-check macros:
.. c:function:: int PyDelta_Check(PyObject *ob)
Return true if *ob* is of type :c:data:`PyDateTime_DeltaType` or a subtype of
:c:data:`PyDateTime_DeltaType`. *ob* must not be ``NULL``. This function always
:c:data:`!PyDateTime_DeltaType`. *ob* must not be ``NULL``. This function always
succeeds.
@ -80,7 +123,7 @@ Type-check macros:
.. c:function:: int PyTZInfo_Check(PyObject *ob)
Return true if *ob* is of type :c:data:`PyDateTime_TZInfoType` or a subtype of
:c:data:`PyDateTime_TZInfoType`. *ob* must not be ``NULL``. This function always
:c:data:`!PyDateTime_TZInfoType`. *ob* must not be ``NULL``. This function always
succeeds.
@ -132,14 +175,16 @@ Macros to create objects:
resulting number of microseconds and seconds lie in the ranges documented for
:class:`datetime.timedelta` objects.
.. c:function:: PyObject* PyTimeZone_FromOffset(PyDateTime_DeltaType* offset)
.. c:function:: PyObject* PyTimeZone_FromOffset(PyObject *offset)
Return a :class:`datetime.timezone` object with an unnamed fixed offset
represented by the *offset* argument.
.. versionadded:: 3.7
.. c:function:: PyObject* PyTimeZone_FromOffsetAndName(PyDateTime_DeltaType* offset, PyUnicode* name)
.. c:function:: PyObject* PyTimeZone_FromOffsetAndName(PyObject *offset, PyObject *name)
Return a :class:`datetime.timezone` object with a fixed offset represented
by the *offset* argument and with tzname *name*.
@ -148,8 +193,8 @@ Macros to create objects:
Macros to extract fields from date objects. The argument must be an instance of
:c:data:`PyDateTime_Date`, including subclasses (such as
:c:data:`PyDateTime_DateTime`). The argument must not be ``NULL``, and the type is
:c:type:`PyDateTime_Date`, including subclasses (such as
:c:type:`PyDateTime_DateTime`). The argument must not be ``NULL``, and the type is
not checked:
.. c:function:: int PyDateTime_GET_YEAR(PyDateTime_Date *o)
@ -168,7 +213,7 @@ not checked:
Macros to extract fields from datetime objects. The argument must be an
instance of :c:data:`PyDateTime_DateTime`, including subclasses. The argument
instance of :c:type:`PyDateTime_DateTime`, including subclasses. The argument
must not be ``NULL``, and the type is not checked:
.. c:function:: int PyDateTime_DATE_GET_HOUR(PyDateTime_DateTime *o)
@ -190,14 +235,23 @@ must not be ``NULL``, and the type is not checked:
Return the microsecond, as an int from 0 through 999999.
.. c:function:: int PyDateTime_DATE_GET_FOLD(PyDateTime_DateTime *o)
Return the fold, as an int from 0 through 1.
.. versionadded:: 3.6
.. c:function:: PyObject* PyDateTime_DATE_GET_TZINFO(PyDateTime_DateTime *o)
Return the tzinfo (which may be ``None``).
.. versionadded:: 3.10
Macros to extract fields from time objects. The argument must be an instance of
:c:data:`PyDateTime_Time`, including subclasses. The argument must not be ``NULL``,
:c:type:`PyDateTime_Time`, including subclasses. The argument must not be ``NULL``,
and the type is not checked:
.. c:function:: int PyDateTime_TIME_GET_HOUR(PyDateTime_Time *o)
@ -219,6 +273,14 @@ and the type is not checked:
Return the microsecond, as an int from 0 through 999999.
.. c:function:: int PyDateTime_TIME_GET_FOLD(PyDateTime_Time *o)
Return the fold, as an int from 0 through 1.
.. versionadded:: 3.6
.. c:function:: PyObject* PyDateTime_TIME_GET_TZINFO(PyDateTime_Time *o)
Return the tzinfo (which may be ``None``).
@ -227,7 +289,7 @@ and the type is not checked:
Macros to extract fields from time delta objects. The argument must be an
instance of :c:data:`PyDateTime_Delta`, including subclasses. The argument must
instance of :c:type:`PyDateTime_Delta`, including subclasses. The argument must
not be ``NULL``, and the type is not checked:
.. c:function:: int PyDateTime_DELTA_GET_DAYS(PyDateTime_Delta *o)

View file

@ -5,7 +5,7 @@
Dictionary Objects
------------------
.. index:: object: dictionary
.. index:: pair: object; dictionary
.. c:type:: PyDictObject
@ -55,6 +55,15 @@ Dictionary Objects
This is equivalent to the Python expression ``key in p``.
.. c:function:: int PyDict_ContainsString(PyObject *p, const char *key)
This is the same as :c:func:`PyDict_Contains`, but *key* is specified as a
:c:expr:`const char*` UTF-8 encoded bytes string, rather than a
:c:expr:`PyObject*`.
.. versionadded:: 3.13
.. c:function:: PyObject* PyDict_Copy(PyObject *p)
Return a new dictionary that contains the same key-value pairs as *p*.
@ -70,17 +79,14 @@ Dictionary Objects
.. c:function:: int PyDict_SetItemString(PyObject *p, const char *key, PyObject *val)
.. index:: single: PyUnicode_FromString()
Insert *val* into the dictionary *p* using *key* as a key. *key* should
be a :c:type:`const char*`. The key object is created using
``PyUnicode_FromString(key)``. Return ``0`` on success or ``-1`` on
failure. This function *does not* steal a reference to *val*.
This is the same as :c:func:`PyDict_SetItem`, but *key* is
specified as a :c:expr:`const char*` UTF-8 encoded bytes string,
rather than a :c:expr:`PyObject*`.
.. c:function:: int PyDict_DelItem(PyObject *p, PyObject *key)
Remove the entry in dictionary *p* with key *key*. *key* must be hashable;
Remove the entry in dictionary *p* with key *key*. *key* must be :term:`hashable`;
if it isn't, :exc:`TypeError` is raised.
If *key* is not in the dictionary, :exc:`KeyError` is raised.
Return ``0`` on success or ``-1`` on failure.
@ -88,19 +94,37 @@ Dictionary Objects
.. c:function:: int PyDict_DelItemString(PyObject *p, const char *key)
Remove the entry in dictionary *p* which has a key specified by the string *key*.
If *key* is not in the dictionary, :exc:`KeyError` is raised.
Return ``0`` on success or ``-1`` on failure.
This is the same as :c:func:`PyDict_DelItem`, but *key* is
specified as a :c:expr:`const char*` UTF-8 encoded bytes string,
rather than a :c:expr:`PyObject*`.
.. c:function:: int PyDict_GetItemRef(PyObject *p, PyObject *key, PyObject **result)
Return a new :term:`strong reference` to the object from dictionary *p*
which has a key *key*:
* If the key is present, set *\*result* to a new :term:`strong reference`
to the value and return ``1``.
* If the key is missing, set *\*result* to ``NULL`` and return ``0``.
* On error, raise an exception and return ``-1``.
.. versionadded:: 3.13
See also the :c:func:`PyObject_GetItem` function.
.. c:function:: PyObject* PyDict_GetItem(PyObject *p, PyObject *key)
Return the object from dictionary *p* which has a key *key*. Return ``NULL``
if the key *key* is not present, but *without* setting an exception.
Return a :term:`borrowed reference` to the object from dictionary *p* which
has a key *key*. Return ``NULL`` if the key *key* is missing *without*
setting an exception.
Note that exceptions which occur while calling :meth:`__hash__` and
:meth:`__eq__` methods will get suppressed.
To get error reporting use :c:func:`PyDict_GetItemWithError()` instead.
.. note::
Exceptions that occur while this calls :meth:`~object.__hash__` and
:meth:`~object.__eq__` methods are silently ignored.
Prefer the :c:func:`PyDict_GetItemWithError` function instead.
.. versionchanged:: 3.10
Calling this API without :term:`GIL` held had been allowed for historical
@ -118,12 +142,25 @@ Dictionary Objects
.. c:function:: PyObject* PyDict_GetItemString(PyObject *p, const char *key)
This is the same as :c:func:`PyDict_GetItem`, but *key* is specified as a
:c:type:`const char*`, rather than a :c:type:`PyObject*`.
:c:expr:`const char*` UTF-8 encoded bytes string, rather than a
:c:expr:`PyObject*`.
Note that exceptions which occur while calling :meth:`__hash__` and
:meth:`__eq__` methods and creating a temporary string object
will get suppressed.
To get error reporting use :c:func:`PyDict_GetItemWithError()` instead.
.. note::
Exceptions that occur while this calls :meth:`~object.__hash__` and
:meth:`~object.__eq__` methods or while creating the temporary :class:`str`
object are silently ignored.
Prefer using the :c:func:`PyDict_GetItemWithError` function with your own
:c:func:`PyUnicode_FromString` *key* instead.
.. c:function:: int PyDict_GetItemStringRef(PyObject *p, const char *key, PyObject **result)
Similar than :c:func:`PyDict_GetItemRef`, but *key* is specified as a
:c:expr:`const char*` UTF-8 encoded bytes string, rather than a
:c:expr:`PyObject*`.
.. versionadded:: 3.13
.. c:function:: PyObject* PyDict_SetDefault(PyObject *p, PyObject *key, PyObject *defaultobj)
@ -136,6 +173,33 @@ Dictionary Objects
.. versionadded:: 3.4
.. c:function:: int PyDict_Pop(PyObject *p, PyObject *key, PyObject **result)
Remove *key* from dictionary *p* and optionally return the removed value.
Do not raise :exc:`KeyError` if the key missing.
- If the key is present, set *\*result* to a new reference to the removed
value if *result* is not ``NULL``, and return ``1``.
- If the key is missing, set *\*result* to ``NULL`` if *result* is not
``NULL``, and return ``0``.
- On error, raise an exception and return ``-1``.
This is similar to :meth:`dict.pop`, but without the default value and
not raising :exc:`KeyError` if the key missing.
.. versionadded:: 3.13
.. c:function:: int PyDict_PopString(PyObject *p, const char *key, PyObject **result)
Similar to :c:func:`PyDict_Pop`, but *key* is specified as a
:c:expr:`const char*` UTF-8 encoded bytes string, rather than a
:c:expr:`PyObject*`.
.. versionadded:: 3.13
.. c:function:: PyObject* PyDict_Items(PyObject *p)
Return a :c:type:`PyListObject` containing all the items from the dictionary.
@ -154,7 +218,7 @@ Dictionary Objects
.. c:function:: Py_ssize_t PyDict_Size(PyObject *p)
.. index:: builtin: len
.. index:: pair: built-in function; len
Return the number of items in the dictionary. This is equivalent to
``len(p)`` on a dictionary.
@ -167,7 +231,7 @@ Dictionary Objects
prior to the first call to this function to start the iteration; the
function returns true for each pair in the dictionary, and false once all
pairs have been reported. The parameters *pkey* and *pvalue* should either
point to :c:type:`PyObject*` variables that will be filled in with each key
point to :c:expr:`PyObject*` variables that will be filled in with each key
and value, respectively, or may be ``NULL``. Any references returned through
them are borrowed. *ppos* should not be altered during iteration. Its
value represents offsets within the internal dictionary structure, and
@ -238,3 +302,86 @@ Dictionary Objects
for key, value in seq2:
if override or key not in a:
a[key] = value
.. c:function:: int PyDict_AddWatcher(PyDict_WatchCallback callback)
Register *callback* as a dictionary watcher. Return a non-negative integer
id which must be passed to future calls to :c:func:`PyDict_Watch`. In case
of error (e.g. no more watcher IDs available), return ``-1`` and set an
exception.
.. versionadded:: 3.12
.. c:function:: int PyDict_ClearWatcher(int watcher_id)
Clear watcher identified by *watcher_id* previously returned from
:c:func:`PyDict_AddWatcher`. Return ``0`` on success, ``-1`` on error (e.g.
if the given *watcher_id* was never registered.)
.. versionadded:: 3.12
.. c:function:: int PyDict_Watch(int watcher_id, PyObject *dict)
Mark dictionary *dict* as watched. The callback granted *watcher_id* by
:c:func:`PyDict_AddWatcher` will be called when *dict* is modified or
deallocated. Return ``0`` on success or ``-1`` on error.
.. versionadded:: 3.12
.. c:function:: int PyDict_Unwatch(int watcher_id, PyObject *dict)
Mark dictionary *dict* as no longer watched. The callback granted
*watcher_id* by :c:func:`PyDict_AddWatcher` will no longer be called when
*dict* is modified or deallocated. The dict must previously have been
watched by this watcher. Return ``0`` on success or ``-1`` on error.
.. versionadded:: 3.12
.. c:type:: PyDict_WatchEvent
Enumeration of possible dictionary watcher events: ``PyDict_EVENT_ADDED``,
``PyDict_EVENT_MODIFIED``, ``PyDict_EVENT_DELETED``, ``PyDict_EVENT_CLONED``,
``PyDict_EVENT_CLEARED``, or ``PyDict_EVENT_DEALLOCATED``.
.. versionadded:: 3.12
.. c:type:: int (*PyDict_WatchCallback)(PyDict_WatchEvent event, PyObject *dict, PyObject *key, PyObject *new_value)
Type of a dict watcher callback function.
If *event* is ``PyDict_EVENT_CLEARED`` or ``PyDict_EVENT_DEALLOCATED``, both
*key* and *new_value* will be ``NULL``. If *event* is ``PyDict_EVENT_ADDED``
or ``PyDict_EVENT_MODIFIED``, *new_value* will be the new value for *key*.
If *event* is ``PyDict_EVENT_DELETED``, *key* is being deleted from the
dictionary and *new_value* will be ``NULL``.
``PyDict_EVENT_CLONED`` occurs when *dict* was previously empty and another
dict is merged into it. To maintain efficiency of this operation, per-key
``PyDict_EVENT_ADDED`` events are not issued in this case; instead a
single ``PyDict_EVENT_CLONED`` is issued, and *key* will be the source
dictionary.
The callback may inspect but must not modify *dict*; doing so could have
unpredictable effects, including infinite recursion. Do not trigger Python
code execution in the callback, as it could modify the dict as a side effect.
If *event* is ``PyDict_EVENT_DEALLOCATED``, taking a new reference in the
callback to the about-to-be-destroyed dictionary will resurrect it and
prevent it from being freed at this time. When the resurrected object is
destroyed later, any watcher callbacks active at that time will be called
again.
Callbacks occur before the notified modification to *dict* takes place, so
the prior state of *dict* can be inspected.
If the callback sets an exception, it must return ``-1``; this exception will
be printed as an unraisable exception using :c:func:`PyErr_WriteUnraisable`.
Otherwise it should return ``0``.
There may already be a pending exception set on entry to the callback. In
this case, the callback should return ``0`` with the same exception still
set. This means the callback may not call any other API that can set an
exception unless it saves and clears the exception state first, and restores
it before returning.
.. versionadded:: 3.12

View file

@ -14,7 +14,7 @@ there is a global indicator (per thread) of the last error that occurred. Most
C API functions don't clear this on success, but will set it to indicate the
cause of the error on failure. Most C API functions also return an error
indicator, usually ``NULL`` if they are supposed to return a pointer, or ``-1``
if they return an integer (exception: the :c:func:`PyArg_\*` functions
if they return an integer (exception: the ``PyArg_*`` functions
return ``1`` for success and ``0`` for failure).
Concretely, the error indicator consists of three object pointers: the
@ -60,9 +60,14 @@ Printing and clearing
Call this function **only** when the error indicator is set. Otherwise it
will cause a fatal error!
If *set_sys_last_vars* is nonzero, the variables :data:`sys.last_type`,
:data:`sys.last_value` and :data:`sys.last_traceback` will be set to the
type, value and traceback of the printed exception, respectively.
If *set_sys_last_vars* is nonzero, the variable :data:`sys.last_exc` is
set to the printed exception. For backwards compatibility, the
deprecated variables :data:`sys.last_type`, :data:`sys.last_value` and
:data:`sys.last_traceback` are also set to the type, value and traceback
of this exception, respectively.
.. versionchanged:: 3.12
The setting of :data:`sys.last_exc` was added.
.. c:function:: void PyErr_Print()
@ -78,14 +83,41 @@ Printing and clearing
This utility function prints a warning message to ``sys.stderr`` when an
exception has been set but it is impossible for the interpreter to actually
raise the exception. It is used, for example, when an exception occurs in an
:meth:`__del__` method.
:meth:`~object.__del__` method.
The function is called with a single argument *obj* that identifies the context
in which the unraisable exception occurred. If possible,
the repr of *obj* will be printed in the warning message.
If *obj* is ``NULL``, only the traceback is printed.
An exception must be set when calling this function.
.. versionchanged:: 3.4
Print a traceback. Print only traceback if *obj* is ``NULL``.
.. versionchanged:: 3.8
Use :func:`sys.unraisablehook`.
.. c:function:: void PyErr_FormatUnraisable(const char *format, ...)
Similar to :c:func:`PyErr_WriteUnraisable`, but the *format* and subsequent
parameters help format the warning message; they have the same meaning and
values as in :c:func:`PyUnicode_FromFormat`.
``PyErr_WriteUnraisable(obj)`` is roughtly equivalent to
``PyErr_FormatUnraisable("Exception ignored in: %R, obj)``.
If *format* is ``NULL``, only the traceback is printed.
.. versionadded:: 3.13
.. c:function:: void PyErr_DisplayException(PyObject *exc)
Print the standard traceback display of ``exc`` to ``sys.stderr``, including
chained exceptions and notes.
.. versionadded:: 3.12
Raising exceptions
==================
@ -99,7 +131,8 @@ For convenience, some of these functions will always return a
This is the most common way to set the error indicator. The first argument
specifies the exception type; it is normally one of the standard exceptions,
e.g. :c:data:`PyExc_RuntimeError`. You need not increment its reference count.
e.g. :c:data:`PyExc_RuntimeError`. You need not create a new
:term:`strong reference` to it (e.g. with :c:func:`Py_INCREF`).
The second argument is an error message; it is decoded from ``'utf-8'``.
@ -152,9 +185,9 @@ For convenience, some of these functions will always return a
This is a convenience function to raise an exception when a C library function
has returned an error and set the C variable :c:data:`errno`. It constructs a
tuple object whose first item is the integer :c:data:`errno` value and whose
second item is the corresponding error message (gotten from :c:func:`strerror`),
second item is the corresponding error message (gotten from :c:func:`!strerror`),
and then calls ``PyErr_SetObject(type, object)``. On Unix, when the
:c:data:`errno` value is :const:`EINTR`, indicating an interrupted system call,
:c:data:`errno` value is :c:macro:`!EINTR`, indicating an interrupted system call,
this calls :c:func:`PyErr_CheckSignals`, and if that set the error indicator,
leaves it set to that. The function always returns ``NULL``, so a wrapper
function around a system call can write ``return PyErr_SetFromErrno(type);``
@ -166,7 +199,7 @@ For convenience, some of these functions will always return a
Similar to :c:func:`PyErr_SetFromErrno`, with the additional behavior that if
*filenameObject* is not ``NULL``, it is passed to the constructor of *type* as
a third parameter. In the case of :exc:`OSError` exception,
this is used to define the :attr:`filename` attribute of the
this is used to define the :attr:`!filename` attribute of the
exception instance.
@ -189,12 +222,12 @@ For convenience, some of these functions will always return a
.. c:function:: PyObject* PyErr_SetFromWindowsErr(int ierr)
This is a convenience function to raise :exc:`WindowsError`. If called with
*ierr* of :c:data:`0`, the error code returned by a call to :c:func:`GetLastError`
is used instead. It calls the Win32 function :c:func:`FormatMessage` to retrieve
the Windows description of error code given by *ierr* or :c:func:`GetLastError`,
*ierr* of ``0``, the error code returned by a call to :c:func:`!GetLastError`
is used instead. It calls the Win32 function :c:func:`!FormatMessage` to retrieve
the Windows description of error code given by *ierr* or :c:func:`!GetLastError`,
then it constructs a tuple object whose first item is the *ierr* value and whose
second item is the corresponding error message (gotten from
:c:func:`FormatMessage`), and then calls ``PyErr_SetObject(PyExc_WindowsError,
:c:func:`!FormatMessage`), and then calls ``PyErr_SetObject(PyExc_WindowsError,
object)``. This function always returns ``NULL``.
.. availability:: Windows.
@ -210,17 +243,21 @@ For convenience, some of these functions will always return a
.. c:function:: PyObject* PyErr_SetFromWindowsErrWithFilename(int ierr, const char *filename)
Similar to :c:func:`PyErr_SetFromWindowsErrWithFilenameObject`, but the
filename is given as a C string. *filename* is decoded from the filesystem
encoding (:func:`os.fsdecode`).
Similar to :c:func:`PyErr_SetFromWindowsErr`, with the additional behavior
that if *filename* is not ``NULL``, it is decoded from the filesystem
encoding (:func:`os.fsdecode`) and passed to the constructor of
:exc:`OSError` as a third parameter to be used to define the
:attr:`!filename` attribute of the exception instance.
.. availability:: Windows.
.. c:function:: PyObject* PyErr_SetExcFromWindowsErrWithFilenameObject(PyObject *type, int ierr, PyObject *filename)
Similar to :c:func:`PyErr_SetFromWindowsErrWithFilenameObject`, with an
additional parameter specifying the exception type to be raised.
Similar to :c:func:`PyErr_SetExcFromWindowsErr`, with the additional behavior
that if *filename* is not ``NULL``, it is passed to the constructor of
:exc:`OSError` as a third parameter to be used to define the
:attr:`!filename` attribute of the exception instance.
.. availability:: Windows.
@ -253,6 +290,14 @@ For convenience, some of these functions will always return a
.. versionadded:: 3.3
.. c:function:: PyObject* PyErr_SetImportErrorSubclass(PyObject *exception, PyObject *msg, PyObject *name, PyObject *path)
Much like :c:func:`PyErr_SetImportError` but this function allows for
specifying a subclass of :exc:`ImportError` to raise.
.. versionadded:: 3.6
.. c:function:: void PyErr_SyntaxLocationObject(PyObject *filename, int lineno, int col_offset)
Set file, line, and offset information for the current exception. If the
@ -273,7 +318,7 @@ For convenience, some of these functions will always return a
.. c:function:: void PyErr_SyntaxLocation(const char *filename, int lineno)
Like :c:func:`PyErr_SyntaxLocationEx`, but the col_offset parameter is
Like :c:func:`PyErr_SyntaxLocationEx`, but the *col_offset* parameter is
omitted.
@ -320,19 +365,12 @@ an error value).
:mod:`warnings` module and the :option:`-W` option in the command line
documentation. There is no C API for warning control.
.. c:function:: PyObject* PyErr_SetImportErrorSubclass(PyObject *exception, PyObject *msg, PyObject *name, PyObject *path)
Much like :c:func:`PyErr_SetImportError` but this function allows for
specifying a subclass of :exc:`ImportError` to raise.
.. versionadded:: 3.6
.. c:function:: int PyErr_WarnExplicitObject(PyObject *category, PyObject *message, PyObject *filename, int lineno, PyObject *module, PyObject *registry)
Issue a warning message with explicit control over all warning attributes. This
is a straightforward wrapper around the Python function
:func:`warnings.warn_explicit`, see there for more information. The *module*
:func:`warnings.warn_explicit`; see there for more information. The *module*
and *registry* arguments may be set to ``NULL`` to get the default effect
described there.
@ -369,7 +407,7 @@ Querying the error indicator
.. c:function:: PyObject* PyErr_Occurred()
Test whether the error indicator is set. If set, return the exception *type*
(the first argument to the last call to one of the :c:func:`PyErr_Set\*`
(the first argument to the last call to one of the ``PyErr_Set*``
functions or to :c:func:`PyErr_Restore`). If not set, return ``NULL``. You do not
own a reference to the return value, so you do not need to :c:func:`Py_DECREF`
it.
@ -399,8 +437,48 @@ Querying the error indicator
recursively in subtuples) are searched for a match.
.. c:function:: PyObject *PyErr_GetRaisedException(void)
Return the exception currently being raised, clearing the error indicator at
the same time. Return ``NULL`` if the error indicator is not set.
This function is used by code that needs to catch exceptions,
or code that needs to save and restore the error indicator temporarily.
For example::
{
PyObject *exc = PyErr_GetRaisedException();
/* ... code that might produce other errors ... */
PyErr_SetRaisedException(exc);
}
.. seealso:: :c:func:`PyErr_GetHandledException`,
to save the exception currently being handled.
.. versionadded:: 3.12
.. c:function:: void PyErr_SetRaisedException(PyObject *exc)
Set *exc* as the exception currently being raised,
clearing the existing exception if one is set.
.. warning::
This call steals a reference to *exc*, which must be a valid exception.
.. versionadded:: 3.12
.. c:function:: void PyErr_Fetch(PyObject **ptype, PyObject **pvalue, PyObject **ptraceback)
.. deprecated:: 3.12
Use :c:func:`PyErr_GetRaisedException` instead.
Retrieve the error indicator into three variables whose addresses are passed.
If the error indicator is not set, set all three variables to ``NULL``. If it is
set, it will be cleared and you own a reference to each object retrieved. The
@ -408,8 +486,10 @@ Querying the error indicator
.. note::
This function is normally only used by code that needs to catch exceptions or
by code that needs to save and restore the error indicator temporarily, e.g.::
This function is normally only used by legacy code that needs to catch
exceptions or save and restore the error indicator temporarily.
For example::
{
PyObject *type, *value, *traceback;
@ -423,8 +503,14 @@ Querying the error indicator
.. c:function:: void PyErr_Restore(PyObject *type, PyObject *value, PyObject *traceback)
Set the error indicator from the three objects. If the error indicator is
already set, it is cleared first. If the objects are ``NULL``, the error
.. deprecated:: 3.12
Use :c:func:`PyErr_SetRaisedException` instead.
Set the error indicator from the three objects,
*type*, *value*, and *traceback*,
clearing the existing exception if one is set.
If the objects are ``NULL``, the error
indicator is cleared. Do not pass a ``NULL`` type and non-``NULL`` value or
traceback. The exception type should be a class. Do not pass an invalid
exception type or value. (Violating these rules will cause subtle problems
@ -435,12 +521,17 @@ Querying the error indicator
.. note::
This function is normally only used by code that needs to save and restore the
error indicator temporarily. Use :c:func:`PyErr_Fetch` to save the current
error indicator.
This function is normally only used by legacy code that needs to
save and restore the error indicator temporarily.
Use :c:func:`PyErr_Fetch` to save the current error indicator.
.. c:function:: void PyErr_NormalizeException(PyObject**exc, PyObject**val, PyObject**tb)
.. c:function:: void PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
.. deprecated:: 3.12
Use :c:func:`PyErr_GetRaisedException` instead,
to avoid any possible de-normalization.
Under certain circumstances, the values returned by :c:func:`PyErr_Fetch` below
can be "unnormalized", meaning that ``*exc`` is a class object but ``*val`` is
@ -450,7 +541,8 @@ Querying the error indicator
.. note::
This function *does not* implicitly set the ``__traceback__``
This function *does not* implicitly set the
:attr:`~BaseException.__traceback__`
attribute on the exception value. If setting the traceback
appropriately is desired, the following additional snippet is needed::
@ -459,12 +551,46 @@ Querying the error indicator
}
.. c:function:: PyObject* PyErr_GetHandledException(void)
Retrieve the active exception instance, as would be returned by :func:`sys.exception`.
This refers to an exception that was *already caught*, not to an exception that was
freshly raised. Returns a new reference to the exception or ``NULL``.
Does not modify the interpreter's exception state.
.. note::
This function is not normally used by code that wants to handle exceptions.
Rather, it can be used when code needs to save and restore the exception
state temporarily. Use :c:func:`PyErr_SetHandledException` to restore or
clear the exception state.
.. versionadded:: 3.11
.. c:function:: void PyErr_SetHandledException(PyObject *exc)
Set the active exception, as known from ``sys.exception()``. This refers
to an exception that was *already caught*, not to an exception that was
freshly raised.
To clear the exception state, pass ``NULL``.
.. note::
This function is not normally used by code that wants to handle exceptions.
Rather, it can be used when code needs to save and restore the exception
state temporarily. Use :c:func:`PyErr_GetHandledException` to get the exception
state.
.. versionadded:: 3.11
.. c:function:: void PyErr_GetExcInfo(PyObject **ptype, PyObject **pvalue, PyObject **ptraceback)
Retrieve the exception info, as known from ``sys.exc_info()``. This refers
to an exception that was *already caught*, not to an exception that was
freshly raised. Returns new references for the three objects, any of which
may be ``NULL``. Does not modify the exception info state.
Retrieve the old-style representation of the exception info, as known from
:func:`sys.exc_info`. This refers to an exception that was *already caught*,
not to an exception that was freshly raised. Returns new references for the
three objects, any of which may be ``NULL``. Does not modify the exception
info state. This function is kept for backwards compatibility. Prefer using
:c:func:`PyErr_GetHandledException`.
.. note::
@ -482,7 +608,8 @@ Querying the error indicator
to an exception that was *already caught*, not to an exception that was
freshly raised. This function steals the references of the arguments.
To clear the exception state, pass ``NULL`` for all three arguments.
For general rules about the three arguments, see :c:func:`PyErr_Restore`.
This function is kept for backwards compatibility. Prefer using
:c:func:`PyErr_SetHandledException`.
.. note::
@ -493,6 +620,12 @@ Querying the error indicator
.. versionadded:: 3.3
.. versionchanged:: 3.11
The ``type`` and ``traceback`` arguments are no longer used and
can be NULL. The interpreter now derives them from the exception
instance (the ``value`` argument). The function still steals
references of all three arguments.
Signal Handling
===============
@ -501,7 +634,7 @@ Signal Handling
.. c:function:: int PyErr_CheckSignals()
.. index::
module: signal
pair: module; signal
single: SIGINT
single: KeyboardInterrupt (built-in exception)
@ -525,18 +658,18 @@ Signal Handling
be interruptible by user requests (such as by pressing Ctrl-C).
.. note::
The default Python signal handler for :const:`SIGINT` raises the
The default Python signal handler for :c:macro:`!SIGINT` raises the
:exc:`KeyboardInterrupt` exception.
.. c:function:: void PyErr_SetInterrupt()
.. index::
module: signal
pair: module; signal
single: SIGINT
single: KeyboardInterrupt (built-in exception)
Simulate the effect of a :const:`SIGINT` signal arriving.
Simulate the effect of a :c:macro:`!SIGINT` signal arriving.
This is equivalent to ``PyErr_SetInterruptEx(SIGINT)``.
.. note::
@ -547,7 +680,7 @@ Signal Handling
.. c:function:: int PyErr_SetInterruptEx(int signum)
.. index::
module: signal
pair: module; signal
single: KeyboardInterrupt (built-in exception)
Simulate the effect of a signal arriving. The next time
@ -560,7 +693,7 @@ Signal Handling
to interrupt an operation).
If the given signal isn't handled by Python (it was set to
:data:`signal.SIG_DFL` or :data:`signal.SIG_IGN`), it will be ignored.
:py:const:`signal.SIG_DFL` or :py:const:`signal.SIG_IGN`), it will be ignored.
If *signum* is outside of the allowed range of signal numbers, ``-1``
is returned. Otherwise, ``0`` is returned. The error indicator is
@ -621,7 +754,8 @@ Exception Objects
.. c:function:: PyObject* PyException_GetTraceback(PyObject *ex)
Return the traceback associated with the exception as a new reference, as
accessible from Python through :attr:`__traceback__`. If there is no
accessible from Python through the :attr:`~BaseException.__traceback__`
attribute. If there is no
traceback associated, this returns ``NULL``.
@ -635,8 +769,8 @@ Exception Objects
Return the context (another exception instance during whose handling *ex* was
raised) associated with the exception as a new reference, as accessible from
Python through :attr:`__context__`. If there is no context associated, this
returns ``NULL``.
Python through the :attr:`~BaseException.__context__` attribute.
If there is no context associated, this returns ``NULL``.
.. c:function:: void PyException_SetContext(PyObject *ex, PyObject *ctx)
@ -648,20 +782,44 @@ Exception Objects
.. c:function:: PyObject* PyException_GetCause(PyObject *ex)
Return the cause (either an exception instance, or :const:`None`,
Return the cause (either an exception instance, or ``None``,
set by ``raise ... from ...``) associated with the exception as a new
reference, as accessible from Python through :attr:`__cause__`.
reference, as accessible from Python through the
:attr:`~BaseException.__cause__` attribute.
.. c:function:: void PyException_SetCause(PyObject *ex, PyObject *cause)
Set the cause associated with the exception to *cause*. Use ``NULL`` to clear
it. There is no type check to make sure that *cause* is either an exception
instance or :const:`None`. This steals a reference to *cause*.
instance or ``None``. This steals a reference to *cause*.
:attr:`__suppress_context__` is implicitly set to ``True`` by this function.
The :attr:`~BaseException.__suppress_context__` attribute is implicitly set
to ``True`` by this function.
.. c:function:: PyObject* PyException_GetArgs(PyObject *ex)
Return :attr:`~BaseException.args` of exception *ex*.
.. c:function:: void PyException_SetArgs(PyObject *ex, PyObject *args)
Set :attr:`~BaseException.args` of exception *ex* to *args*.
.. c:function:: PyObject* PyUnstable_Exc_PrepReraiseStar(PyObject *orig, PyObject *excs)
Implement part of the interpreter's implementation of :keyword:`!except*`.
*orig* is the original exception that was caught, and *excs* is the list of
the exceptions that need to be raised. This list contains the unhandled
part of *orig*, if any, as well as the exceptions that were raised from the
:keyword:`!except*` clauses (so they have a different traceback from *orig*) and
those that were reraised (and have the same traceback as *orig*).
Return the :exc:`ExceptionGroup` that needs to be reraised in the end, or
``None`` if there is nothing to reraise.
.. versionadded:: 3.12
.. _unicodeexceptions:
Unicode Exception Objects
@ -746,7 +904,7 @@ because the :ref:`call protocol <call>` takes care of recursion handling.
Marks a point where a recursive C-level call is about to be performed.
If :const:`USE_STACKCHECK` is defined, this function checks if the OS
If :c:macro:`USE_STACKCHECK` is defined, this function checks if the OS
stack overflowed using :c:func:`PyOS_CheckStack`. In this is the case, it
sets a :exc:`MemoryError` and returns a nonzero value.
@ -759,7 +917,7 @@ because the :ref:`call protocol <call>` takes care of recursion handling.
depth limit.
.. versionchanged:: 3.9
This function is now also available in the limited API.
This function is now also available in the :ref:`limited API <limited-c-api>`.
.. c:function:: void Py_LeaveRecursiveCall(void)
@ -767,7 +925,7 @@ because the :ref:`call protocol <call>` takes care of recursion handling.
*successful* invocation of :c:func:`Py_EnterRecursiveCall`.
.. versionchanged:: 3.9
This function is now also available in the limited API.
This function is now also available in the :ref:`limited API <limited-c-api>`.
Properly implementing :c:member:`~PyTypeObject.tp_repr` for container types requires
special recursion handling. In addition to protecting the stack,
@ -806,7 +964,7 @@ Standard Exceptions
All standard Python exceptions are available as global variables whose names are
``PyExc_`` followed by the Python exception name. These have the type
:c:type:`PyObject*`; they are all class objects. For completeness, here are all
:c:expr:`PyObject*`; they are all class objects. For completeness, here are all
the variables:
.. index::
@ -867,11 +1025,11 @@ the variables:
+-----------------------------------------+---------------------------------+----------+
| C Name | Python Name | Notes |
+=========================================+=================================+==========+
| :c:data:`PyExc_BaseException` | :exc:`BaseException` | \(1) |
| :c:data:`PyExc_BaseException` | :exc:`BaseException` | [1]_ |
+-----------------------------------------+---------------------------------+----------+
| :c:data:`PyExc_Exception` | :exc:`Exception` | \(1) |
| :c:data:`PyExc_Exception` | :exc:`Exception` | [1]_ |
+-----------------------------------------+---------------------------------+----------+
| :c:data:`PyExc_ArithmeticError` | :exc:`ArithmeticError` | \(1) |
| :c:data:`PyExc_ArithmeticError` | :exc:`ArithmeticError` | [1]_ |
+-----------------------------------------+---------------------------------+----------+
| :c:data:`PyExc_AssertionError` | :exc:`AssertionError` | |
+-----------------------------------------+---------------------------------+----------+
@ -917,7 +1075,7 @@ the variables:
+-----------------------------------------+---------------------------------+----------+
| :c:data:`PyExc_KeyboardInterrupt` | :exc:`KeyboardInterrupt` | |
+-----------------------------------------+---------------------------------+----------+
| :c:data:`PyExc_LookupError` | :exc:`LookupError` | \(1) |
| :c:data:`PyExc_LookupError` | :exc:`LookupError` | [1]_ |
+-----------------------------------------+---------------------------------+----------+
| :c:data:`PyExc_MemoryError` | :exc:`MemoryError` | |
+-----------------------------------------+---------------------------------+----------+
@ -929,7 +1087,7 @@ the variables:
+-----------------------------------------+---------------------------------+----------+
| :c:data:`PyExc_NotImplementedError` | :exc:`NotImplementedError` | |
+-----------------------------------------+---------------------------------+----------+
| :c:data:`PyExc_OSError` | :exc:`OSError` | \(1) |
| :c:data:`PyExc_OSError` | :exc:`OSError` | [1]_ |
+-----------------------------------------+---------------------------------+----------+
| :c:data:`PyExc_OverflowError` | :exc:`OverflowError` | |
+-----------------------------------------+---------------------------------+----------+
@ -939,7 +1097,7 @@ the variables:
+-----------------------------------------+---------------------------------+----------+
| :c:data:`PyExc_RecursionError` | :exc:`RecursionError` | |
+-----------------------------------------+---------------------------------+----------+
| :c:data:`PyExc_ReferenceError` | :exc:`ReferenceError` | \(2) |
| :c:data:`PyExc_ReferenceError` | :exc:`ReferenceError` | |
+-----------------------------------------+---------------------------------+----------+
| :c:data:`PyExc_RuntimeError` | :exc:`RuntimeError` | |
+-----------------------------------------+---------------------------------+----------+
@ -1004,7 +1162,7 @@ These are compatibility aliases to :c:data:`PyExc_OSError`:
+-------------------------------------+----------+
| :c:data:`PyExc_IOError` | |
+-------------------------------------+----------+
| :c:data:`PyExc_WindowsError` | \(3) |
| :c:data:`PyExc_WindowsError` | [2]_ |
+-------------------------------------+----------+
.. versionchanged:: 3.3
@ -1012,10 +1170,10 @@ These are compatibility aliases to :c:data:`PyExc_OSError`:
Notes:
(1)
.. [1]
This is a base class for other standard exceptions.
(2)
.. [2]
Only defined on Windows; protect code that uses this by testing that the
preprocessor macro ``MS_WINDOWS`` is defined.
@ -1026,7 +1184,7 @@ Standard Warning Categories
All standard Python warning categories are available as global variables whose
names are ``PyExc_`` followed by the Python exception name. These have the type
:c:type:`PyObject*`; they are all class objects. For completeness, here are all
:c:expr:`PyObject*`; they are all class objects. For completeness, here are all
the variables:
.. index::
@ -1045,7 +1203,7 @@ the variables:
+------------------------------------------+---------------------------------+----------+
| C Name | Python Name | Notes |
+==========================================+=================================+==========+
| :c:data:`PyExc_Warning` | :exc:`Warning` | \(1) |
| :c:data:`PyExc_Warning` | :exc:`Warning` | [3]_ |
+------------------------------------------+---------------------------------+----------+
| :c:data:`PyExc_BytesWarning` | :exc:`BytesWarning` | |
+------------------------------------------+---------------------------------+----------+
@ -1073,5 +1231,5 @@ the variables:
Notes:
(1)
.. [3]
This is a base class for other standard warning categories.

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