--- /dev/null
+variables:
+ manylinux: false
+ coverage: false
+
+jobs:
+- job: Prebuild
+ displayName: Pre-build checks
+
+ pool:
+ vmImage: ubuntu-16.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-16.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'))
+
+ variables:
+ testRunTitle: '$(build.sourceBranchName)-macos'
+ testRunPlatform: macos
+
+ pool:
+ vmImage: xcode9-macos10.13
+
+ 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-16.04
+
+ variables:
+ testRunTitle: '$(build.sourceBranchName)-linux'
+ testRunPlatform: linux
+ openssl_version: 1.1.0g
+
+ steps:
+ - template: ./posix-steps.yml
+
+
+- job: ManyLinux1_CI_Tests
+ displayName: ManyLinux1 CI Tests
+ dependsOn: Prebuild
+ condition: |
+ and(
+ and(
+ succeeded(),
+ eq(variables['manylinux'], 'true')
+ ),
+ eq(dependencies.Prebuild.outputs['tests.run'], 'true')
+ )
+
+ pool:
+ vmImage: ubuntu-16.04
+
+ variables:
+ testRunTitle: '$(build.sourceBranchName)-manylinux1'
+ testRunPlatform: manylinux1
+ imageName: 'dockcross/manylinux-x64'
+
+ steps:
+ - template: ./docker-steps.yml
+
+
+- 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-16.04
+
+ variables:
+ testRunTitle: '$(Build.SourceBranchName)-linux-coverage'
+ testRunPlatform: linux-coverage
+ openssl_version: 1.1.0g
+
+ steps:
+ - template: ./posix-steps.yml
+ parameters:
+ coverage: true
+
+
+- job: Windows_CI_Tests
+ displayName: Windows CI Tests
+ dependsOn: Prebuild
+ condition: and(succeeded(), eq(dependencies.Prebuild.outputs['tests.run'], 'true'))
+
+ pool:
+ vmImage: vs2017-win2016
+
+ strategy:
+ matrix:
+ win32:
+ arch: win32
+ buildOpt:
+ testRunTitle: '$(Build.SourceBranchName)-win32'
+ testRunPlatform: win32
+ win64:
+ arch: amd64
+ buildOpt: '-p x64'
+ testRunTitle: '$(Build.SourceBranchName)-win64'
+ testRunPlatform: win64
+ maxParallel: 2
+
+ steps:
+ - template: ./windows-steps.yml
--- /dev/null
+steps:
+- checkout: self
+ clean: true
+ fetchDepth: 5
+
+- ${{ if ne(parameters.targetBranch, '') }}:
+ - script: |
+ git fetch -q origin ${{ parameters.targetbranch }}
+ if ! git diff --name-only HEAD $(git merge-base HEAD FETCH_HEAD) | grep -qvE '(\.rst$|^Doc|^Misc)'
+ then
+ echo "Only docs were updated, stopping build process."
+ echo "##vso[task.setvariable variable=DocOnly]true"
+ exit
+ fi
+ displayName: Detect doc-only changes
+
+- task: docker@0
+ displayName: 'Configure CPython (debug)'
+ inputs:
+ action: 'Run an image'
+ imageName: $(imageName)
+ volumes: |
+ $(build.sourcesDirectory):/src
+ $(build.binariesDirectory):/build
+ workDir: '/src'
+ containerCommand: './configure --with-pydebug'
+ detached: false
+ condition: and(succeeded(), ne(variables['DocOnly'], 'true'))
+
+- task: docker@0
+ displayName: 'Build CPython'
+ inputs:
+ action: 'Run an image'
+ imageName: $(imageName)
+ volumes: |
+ $(build.sourcesDirectory):/src
+ $(build.binariesDirectory):/build
+ workDir: '/src'
+ containerCommand: 'make -s -j4'
+ detached: false
+ condition: and(succeeded(), ne(variables['DocOnly'], 'true'))
+
+- task: docker@0
+ displayName: 'Display build info'
+ inputs:
+ action: 'Run an image'
+ imageName: $(imageName)
+ volumes: |
+ $(build.sourcesDirectory):/src
+ $(build.binariesDirectory):/build
+ workDir: '/src'
+ containerCommand: 'make pythoninfo'
+ detached: false
+ condition: and(succeeded(), ne(variables['DocOnly'], 'true'))
+
+- task: docker@0
+ displayName: 'Tests'
+ inputs:
+ action: 'Run an image'
+ imageName: $(imageName)
+ volumes: |
+ $(build.sourcesDirectory):/src
+ $(build.binariesDirectory):/build
+ workDir: '/src'
+ containerCommand: 'make buildbottest TESTOPTS="-j4 -uall,-cpu --junit-xml=/build/test-results.xml"'
+ detached: false
+ condition: and(succeeded(), ne(variables['DocOnly'], 'true'))
+
+- task: PublishTestResults@2
+ displayName: 'Publish Test Results'
+ inputs:
+ testResultsFiles: '$(build.binariesDirectory)/test-results.xml'
+ mergeTestResults: true
+ testRunTitle: $(testRunTitle)
+ platform: $(testRunPlatform)
+ condition: and(succeededOrFailed(), ne(variables['DocOnly'], 'true'))
--- /dev/null
+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 sphinx~=1.6.1 blurb python-docs-theme
+ displayName: 'Install build dependencies'
+
+- ${{ if ne(parameters.latex, 'true') }}:
+ - script: make check suspicious 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
--- /dev/null
+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 -s -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'
+
+- task: PublishTestResults@2
+ displayName: 'Publish Test Results'
+ inputs:
+ testResultsFiles: '$(build.binariesDirectory)/test-results.xml'
+ mergeTestResults: true
+ testRunTitle: $(testRunTitle)
+ platform: $(testRunPlatform)
+ condition: succeededOrFailed()
--- /dev/null
+sudo apt-get update
+
+sudo apt-get -yq install \
+ build-essential \
+ zlib1g-dev \
+ libbz2-dev \
+ liblzma-dev \
+ libncurses5-dev \
+ libreadline6-dev \
+ libsqlite3-dev \
+ libssl-dev \
+ libgdbm-dev \
+ tk-dev \
+ lzma \
+ lzma-dev \
+ liblzma-dev \
+ libffi-dev \
+ uuid-dev \
+ xvfb
+
+if [ ! -z "$1" ]
+then
+ echo ##vso[task.prependpath]$PWD/multissl/openssl/$1
+ echo ##vso[task.setvariable variable=OPENSSL_DIR]$PWD/multissl/openssl/$1
+ python3 Tools/ssl/multissltests.py --steps=library --base-directory $PWD/multissl --openssl $1 --system Linux
+fi
--- /dev/null
+parameters:
+ coverage: false
+
+steps:
+- checkout: self
+ clean: true
+ fetchDepth: 5
+
+- script: ./.azure-pipelines/posix-deps.sh $(openssl_version)
+ displayName: 'Install dependencies'
+
+- script: ./configure --with-pydebug
+ displayName: 'Configure CPython (debug)'
+
+- script: make -s -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: ./venv/bin/python -m test.pythoninfo
+ displayName: 'Display build info'
+
+ - script: |
+ xvfb-run ./venv/bin/python -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'
+
+ - script: ./venv/bin/python -m coverage xml
+ displayName: 'Generate coverage.xml'
+
+ - script: source ./venv/bin/activate && bash <(curl -s https://codecov.io/bash)
+ displayName: 'Publish code coverage results'
+
+
+- ${{ if ne(parameters.coverage, 'true') }}:
+ - script: make pythoninfo
+ displayName: 'Display build info'
+
+ - script: xvfb-run make buildbottest TESTOPTS="-j4 -uall,-cpu --junit-xml=$(build.binariesDirectory)/test-results.xml"
+ displayName: 'Tests'
+
+
+- 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()
--- /dev/null
+jobs:
+- job: Prebuild
+ displayName: Pre-build checks
+
+ pool:
+ vmImage: ubuntu-16.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-16.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'))
+
+ variables:
+ testRunTitle: '$(system.pullRequest.TargetBranch)-macos'
+ testRunPlatform: macos
+
+ pool:
+ vmImage: xcode9-macos10.13
+
+ steps:
+ - template: ./macos-steps.yml
+ parameters:
+ targetBranch: $(System.PullRequest.TargetBranch)
+
+
+- job: Ubuntu_PR_Tests
+ displayName: Ubuntu PR Tests
+ dependsOn: Prebuild
+ condition: and(succeeded(), eq(dependencies.Prebuild.outputs['tests.run'], 'true'))
+
+ pool:
+ vmImage: ubuntu-16.04
+
+ variables:
+ testRunTitle: '$(system.pullRequest.TargetBranch)-linux'
+ testRunPlatform: linux
+ openssl_version: 1.1.0g
+
+ steps:
+ - template: ./posix-steps.yml
+ parameters:
+ targetBranch: $(System.PullRequest.TargetBranch)
+
+
+- job: Windows_PR_Tests
+ displayName: Windows PR Tests
+ dependsOn: Prebuild
+ condition: and(succeeded(), eq(dependencies.Prebuild.outputs['tests.run'], 'true'))
+
+ pool:
+ vmImage: vs2017-win2016
+
+ strategy:
+ matrix:
+ win32:
+ arch: win32
+ buildOpt:
+ testRunTitle: '$(System.PullRequest.TargetBranch)-win32'
+ testRunPlatform: win32
+ win64:
+ arch: amd64
+ buildOpt: '-p x64'
+ testRunTitle: '$(System.PullRequest.TargetBranch)-win64'
+ testRunPlatform: win64
+ maxParallel: 2
+
+ steps:
+ - template: ./windows-steps.yml
+ parameters:
+ targetBranch: $(System.PullRequest.TargetBranch)
--- /dev/null
+steps:
+- checkout: self
+ fetchDepth: 5
+
+- script: echo "##vso[task.setvariable variable=diffTarget]HEAD~1"
+ displayName: Set default diff target
+
+- script: |
+ git fetch -q origin $(System.PullRequest.TargetBranch)
+ echo "##vso[task.setvariable variable=diffTarget]HEAD \$(git merge-base HEAD FETCH_HEAD)"
+ 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
+ echo "Only docs were updated: tests.run=false"
+ echo "##vso[task.setvariable variable=run;isOutput=true]false"
+ else
+ echo "Code was updated: tests.run=true"
+ echo "##vso[task.setvariable variable=run;isOutput=true]true"
+ fi
+ displayName: Detect source changes
+ name: tests
--- /dev/null
+steps:
+- checkout: self
+ clean: true
+ fetchDepth: 5
+
+- powershell: |
+ # Relocate build outputs outside of source directory to make cleaning faster
+ Write-Host '##vso[task.setvariable variable=Py_IntDir]$(Build.BinariesDirectory)\obj'
+ # UNDONE: Do not build to a different directory because of broken tests
+ Write-Host '##vso[task.setvariable variable=Py_OutDir]$(Build.SourcesDirectory)\PCbuild'
+ Write-Host '##vso[task.setvariable variable=EXTERNAL_DIR]$(Build.BinariesDirectory)\externals'
+ displayName: Update build locations
+
+- script: PCbuild\build.bat -e $(buildOpt)
+ displayName: 'Build CPython'
+
+- script: python.bat -m test.pythoninfo
+ displayName: 'Display build info'
+
+- script: PCbuild\rt.bat -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0 --junit-xml="$(Build.BinariesDirectory)\test-results.xml"
+ displayName: 'Tests'
+ env:
+ PREFIX: $(Py_OutDir)\$(arch)
+
+- task: PublishTestResults@2
+ displayName: 'Publish Test Results'
+ inputs:
+ testResultsFiles: '$(Build.BinariesDirectory)\test-results.xml'
+ mergeTestResults: true
+ testRunTitle: $(testRunTitle)
+ platform: $(testRunPlatform)
+ condition: succeededOrFailed()
+++ /dev/null
-# Current docs for the syntax of this file are at:
-# https://github.com/Microsoft/vsts-agent/blob/master/docs/preview/yamlgettingstarted.md
-
-name: $(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.rr)
-
-queue:
- name: Hosted Linux Preview
-
-#variables:
-
-steps:
-- checkout: self
- clean: true
- fetchDepth: 5
-
-- script: sudo apt-get update && sudo apt-get install -qy --force-yes texlive-full
- displayName: 'Install LaTeX'
-
-- task: UsePythonVersion@0
- displayName: 'Use Python 3.6 or later'
- inputs:
- versionSpec: '>=3.6'
-
-- script: python -m pip install sphinx blurb python-docs-theme
- displayName: 'Install build dependencies'
-
-- script: make dist PYTHON=python SPHINXBUILD='python -m sphinx' BLURB='python -m blurb'
- workingDirectory: '$(build.sourcesDirectory)/Doc'
- displayName: 'Build documentation'
-
-- task: PublishBuildArtifacts@1
- displayName: 'Publish build'
- inputs:
- PathToPublish: '$(build.sourcesDirectory)/Doc/build'
- ArtifactName: build
- publishLocation: Container
-
-- task: PublishBuildArtifacts@1
- displayName: 'Publish dist'
- inputs:
- PathToPublish: '$(build.sourcesDirectory)/Doc/dist'
- ArtifactName: dist
- publishLocation: Container
+++ /dev/null
-# Current docs for the syntax of this file are at:
-# https://github.com/Microsoft/vsts-agent/blob/master/docs/preview/yamlgettingstarted.md
-
-name: $(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.rr)
-
-queue:
- name: Hosted Linux Preview
-
-trigger:
- branches:
- include:
- - master
- - 3.7
- - 3.6
- paths:
- include:
- - Doc/*
-
-#variables:
-
-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 sphinx~=1.6.1 blurb python-docs-theme
- displayName: 'Install build dependencies'
-
-- script: make check suspicious html PYTHON=python
- workingDirectory: '$(build.sourcesDirectory)/Doc'
- displayName: 'Build documentation'
-
-- task: PublishBuildArtifacts@1
- displayName: 'Publish build'
- condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
- inputs:
- PathToPublish: '$(build.sourcesDirectory)/Doc/build'
- ArtifactName: build
- publishLocation: Container
+++ /dev/null
-# Current docs for the syntax of this file are at:
-# https://github.com/Microsoft/vsts-agent/blob/master/docs/preview/yamlgettingstarted.md
-
-name: $(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.rr)
-
-queue:
- name: Hosted Linux Preview
-
-trigger:
- branches:
- include:
- - master
- - 3.7
- - 3.6
- paths:
- exclude:
- - Doc/*
- - Tools/*
-
-#variables:
-
-
-steps:
-- checkout: self
- clean: true
- fetchDepth: 5
-
-#- template: linux-deps.yml
-
-# See https://github.com/Microsoft/vsts-agent/blob/master/docs/preview/yamlgettingstarted-templates.md
-# For now, we copy/paste the steps
-- script: echo "deb-src http://archive.ubuntu.com/ubuntu/ xenial main" > /etc/apt/sources.list.d/python.list && sudo apt-get update
- displayName: 'Update apt-get lists'
-
-- script: >
- sudo apt-get -yq install
- build-essential
- zlib1g-dev
- libbz2-dev
- liblzma-dev
- libncurses5-dev
- libreadline6-dev
- libsqlite3-dev
- libssl-dev
- libgdbm-dev
- tk-dev
- lzma
- lzma-dev
- liblzma-dev
- libffi-dev
- uuid-dev
- displayName: 'Install dependencies'
-
-- script: ./configure --with-pydebug
- displayName: 'Configure CPython (debug)'
-
-- script: make -s -j4
- displayName: 'Build CPython'
-
-- script: make pythoninfo
- displayName: 'Display build info'
-
-- script: make buildbottest TESTOPTS="-j4 -uall,-cpu"
- displayName: 'Tests'
+++ /dev/null
-# Current docs for the syntax of this file are at:
-# https://github.com/Microsoft/vsts-agent/blob/master/docs/preview/yamlgettingstarted.md
-
-name: $(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.rr)
-
-queue:
- name: Hosted Linux Preview
-
-trigger:
- branches:
- include:
- - master
- - 3.7
- - 3.6
- paths:
- exclude:
- - Doc/*
- - Tools/*
-
-#variables:
-
-steps:
-- checkout: self
- clean: true
- fetchDepth: 5
-
-#- template: linux-deps.yml
-
-# See https://github.com/Microsoft/vsts-agent/blob/master/docs/preview/yamlgettingstarted-templates.md
-# For now, we copy/paste the steps
-- script: echo "deb-src http://archive.ubuntu.com/ubuntu/ xenial main" > /etc/apt/sources.list.d/python.list && sudo apt-get update
- displayName: 'Update apt-get lists'
-
-- script: >
- sudo apt-get -yq install
- build-essential
- zlib1g-dev
- libbz2-dev
- liblzma-dev
- libncurses5-dev
- libreadline6-dev
- libsqlite3-dev
- libssl-dev
- libgdbm-dev
- tk-dev
- lzma
- lzma-dev
- liblzma-dev
- libffi-dev
- uuid-dev
- displayName: 'Install dependencies'
-
-
-- script: ./configure --with-pydebug
- displayName: 'Configure CPython (debug)'
-
-- script: make -s -j4
- displayName: 'Build CPython'
-
-- script: ./python -m venv venv && ./venv/bin/python -m pip install -U coverage
- displayName: 'Set up virtual environment'
-
-- script: ./venv/bin/python -m test.pythoninfo
- displayName: 'Display build info'
-
-- script: ./venv/bin/python -m coverage run --pylib -m test -uall,-cpu -x test_multiprocessing_fork -x test_multiprocessing_forkserver -x test_multiprocessing_spawn -x test_concurrent_futures
- displayName: 'Tests with coverage'
-
-- script: source ./venv/bin/activate && bash <(curl -s https://codecov.io/bash)
- displayName: 'Publish code coverage results'
+++ /dev/null
-# Note: this file is not currently used, but when template support comes to VSTS it
-# will be referenced from the other scripts..
-
-# Current docs for the syntax of this file are at:
-# https://github.com/Microsoft/vsts-agent/blob/master/docs/preview/yamlgettingstarted.md
-
-#parameters:
-
-steps:
-- script: echo "deb-src http://archive.ubuntu.com/ubuntu/ xenial main" > /etc/apt/sources.list.d/python.list && sudo apt-get update
- displayName: 'Update apt-get lists'
-
-- script: >
- sudo apt-get -yq install
- build-essential
- zlib1g-dev
- libbz2-dev
- liblzma-dev
- libncurses5-dev
- libreadline6-dev
- libsqlite3-dev
- libssl-dev
- libgdbm-dev
- tk-dev
- lzma
- lzma-dev
- liblzma-dev
- libffi-dev
- uuid-dev
- displayName: 'Install dependencies'
+++ /dev/null
-# Current docs for the syntax of this file are at:
-# https://github.com/Microsoft/vsts-agent/blob/master/docs/preview/yamlgettingstarted.md
-
-name: $(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.rr)
-
-queue:
- name: Hosted Linux Preview
-
-trigger:
- branches:
- include:
- - master
- - 3.7
- - 3.6
- paths:
- exclude:
- - Doc/*
- - Tools/*
-
-#variables:
-
-steps:
-- checkout: self
- clean: true
- fetchDepth: 5
-
-#- template: linux-deps.yml
-
-# See https://github.com/Microsoft/vsts-agent/blob/master/docs/preview/yamlgettingstarted-templates.md
-# For now, we copy/paste the steps
-- script: echo "deb-src http://archive.ubuntu.com/ubuntu/ xenial main" > /etc/apt/sources.list.d/python.list && sudo apt-get update
- displayName: 'Update apt-get lists'
-
-- script: >
- sudo apt-get -yq install
- build-essential
- zlib1g-dev
- libbz2-dev
- liblzma-dev
- libncurses5-dev
- libreadline6-dev
- libsqlite3-dev
- libssl-dev
- libgdbm-dev
- tk-dev
- lzma
- lzma-dev
- liblzma-dev
- libffi-dev
- uuid-dev
- displayName: 'Install dependencies'
-
-
-- script: ./configure --with-pydebug
- displayName: 'Configure CPython (debug)'
-
-- script: make -s -j4
- displayName: 'Build CPython'
-
-- script: make pythoninfo
- displayName: 'Display build info'
-
-# Run patchcheck and fail if anything is discovered
-- script: ./python Tools/scripts/patchcheck.py --travis true
- displayName: 'Run patchcheck.py'
-
-- script: make buildbottest TESTOPTS="-j4 -uall,-cpu"
- displayName: 'Tests'
+++ /dev/null
-# Current docs for the syntax of this file are at:
-# https://github.com/Microsoft/vsts-agent/blob/master/docs/preview/yamlgettingstarted.md
-
-name: $(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.rr)
-
-queue:
- name: Hosted macOS Preview
-
-trigger:
- branches:
- include:
- - master
- - 3.7
- - 3.6
- paths:
- exclude:
- - Doc/*
- - Tools/*
-
-#variables:
-
-steps:
-- checkout: self
- clean: true
- fetchDepth: 5
-
-- script: ./configure --with-pydebug --with-openssl=/usr/local/opt/openssl
- displayName: 'Configure CPython (debug)'
-
-- script: make -s -j4
- displayName: 'Build CPython'
-
-- script: make pythoninfo
- displayName: 'Display build info'
-
-- script: make buildbottest TESTOPTS="-j4 -uall,-cpu"
- displayName: 'Tests'
+++ /dev/null
-# Current docs for the syntax of this file are at:
-# https://github.com/Microsoft/vsts-agent/blob/master/docs/preview/yamlgettingstarted.md
-
-name: $(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.rr)
-
-queue:
- name: Hosted macOS Preview
-
-trigger:
- branches:
- include:
- - master
- - 3.7
- - 3.6
- paths:
- exclude:
- - Doc/*
- - Tools/*
-
-#variables:
-
-steps:
-- checkout: self
- clean: true
- fetchDepth: 5
-
-- script: ./configure --with-pydebug --with-openssl=/usr/local/opt/openssl
- displayName: 'Configure CPython (debug)'
-
-- script: make -s -j4
- displayName: 'Build CPython'
-
-- script: make pythoninfo
- displayName: 'Display build info'
-
-- script: make buildbottest TESTOPTS="-j4 -uall,-cpu"
- displayName: 'Tests'
+++ /dev/null
-# Current docs for the syntax of this file are at:
-# https://github.com/Microsoft/vsts-agent/blob/master/docs/preview/yamlgettingstarted.md
-
-name: $(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.rr)
-
-queue:
- name: Hosted VS2017
- parallel: 2
- matrix:
- amd64:
- buildOpt: -p x64
- outDirSuffix: amd64
- win32:
- buildOpt:
- outDirSuffix: win32
-
-trigger:
- branches:
- include:
- - master
- - 3.7
- - 3.6
- paths:
- exclude:
- - Doc/*
- - Tools/*
-
-variables:
- # Relocate build outputs outside of source directory to make cleaning faster
- Py_IntDir: $(Build.BinariesDirectory)\obj
- # UNDONE: Do not build to a different directory because of broken tests
- Py_OutDir: $(Build.SourcesDirectory)\PCbuild
- EXTERNAL_DIR: $(Build.BinariesDirectory)\externals
-
-steps:
-- checkout: self
- clean: true
- fetchDepth: 5
-
-- script: PCbuild\build.bat -e $(buildOpt)
- displayName: 'Build CPython'
-
-- script: python.bat -m test.pythoninfo
- displayName: 'Display build info'
-
-- script: PCbuild\rt.bat -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0
- displayName: 'Tests'
- env:
- PREFIX: $(Py_OutDir)\$(outDirSuffix)
+++ /dev/null
-# Current docs for the syntax of this file are at:
-# https://github.com/Microsoft/vsts-agent/blob/master/docs/preview/yamlgettingstarted.md
-
-name: $(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.rr)
-
-queue:
- name: Hosted VS2017
- parallel: 2
- matrix:
- amd64:
- buildOpt: -p x64
- outDirSuffix: amd64
- win32:
- buildOpt:
- outDirSuffix: win32
-
-trigger:
- branches:
- include:
- - master
- - 3.7
- - 3.6
- paths:
- exclude:
- - Doc/*
- - Tools/*
-
-variables:
- # Relocate build outputs outside of source directory to make cleaning faster
- Py_IntDir: $(Build.BinariesDirectory)\obj
- # UNDONE: Do not build to a different directory because of broken tests
- Py_OutDir: $(Build.SourcesDirectory)\PCbuild
- EXTERNAL_DIR: $(Build.BinariesDirectory)\externals
-
-steps:
-- checkout: self
- clean: true
- fetchDepth: 5
-
-- script: PCbuild\build.bat -e $(buildOpt)
- displayName: 'Build CPython'
-
-- script: python.bat -m test.pythoninfo
- displayName: 'Display build info'
-
-- script: PCbuild\rt.bat -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0
- displayName: 'Tests'
- env:
- PREFIX: $(Py_OutDir)\$(outDirSuffix)
make venv
That will install all the tools necessary to build the documentation. Assuming
-the virtual environment was created in the ``env`` directory (the default;
+the virtual environment was created in the ``venv`` directory (the default;
configurable with the VENVDIR variable), you can run the following command to
build the HTML output files::
The following functions allow marshalled values to be read back in.
-XXX What about error detection? It appears that reading past the end of the
-file will always result in a negative numeric value (where that's relevant),
-but it's not clear that negative values won't be handled properly when there's
-no error. What's the right way to tell? Should only non-negative values be
-written using these routines?
-
.. c:function:: long PyMarshal_ReadLongFromFile(FILE *file)
for reading. Only a 32-bit value can be read in using this function,
regardless of the native size of :c:type:`long`.
- On error, raise an exception and return ``-1``.
+ On error, sets the appropriate exception (:exc:`EOFError`) and returns
+ ``-1``.
.. c:function:: int PyMarshal_ReadShortFromFile(FILE *file)
for reading. Only a 16-bit value can be read in using this function,
regardless of the native size of :c:type:`short`.
- On error, raise an exception and return ``-1``.
+ On error, sets the appropriate exception (:exc:`EOFError`) and returns
+ ``-1``.
.. c:function:: PyObject* PyMarshal_ReadObjectFromFile(FILE *file)
Return a Python object from the data stream in a :c:type:`FILE\*` opened for
reading.
- On error, sets the appropriate exception (:exc:`EOFError` or
- :exc:`TypeError`) and returns *NULL*.
+ On error, sets the appropriate exception (:exc:`EOFError`, :exc:`ValueError`
+ or :exc:`TypeError`) and returns *NULL*.
.. c:function:: PyObject* PyMarshal_ReadLastObjectFromFile(FILE *file)
file. Only use these variant if you are certain that you won't be reading
anything else from the file.
- On error, sets the appropriate exception (:exc:`EOFError` or
- :exc:`TypeError`) and returns *NULL*.
+ On error, sets the appropriate exception (:exc:`EOFError`, :exc:`ValueError`
+ or :exc:`TypeError`) and returns *NULL*.
.. c:function:: PyObject* PyMarshal_ReadObjectFromString(const char *data, Py_ssize_t len)
Return a Python object from the data stream in a byte buffer
containing *len* bytes pointed to by *data*.
- On error, sets the appropriate exception (:exc:`EOFError` or
- :exc:`TypeError`) and returns *NULL*.
+ On error, sets the appropriate exception (:exc:`EOFError`, :exc:`ValueError`
+ or :exc:`TypeError`) and returns *NULL*.
It is important to understand that the management of the Python heap is
performed by the interpreter itself and that the user has no control over it,
-even if she regularly manipulates object pointers to memory blocks inside that
+even if they regularly manipulate object pointers to memory blocks inside that
heap. The allocation of heap space for Python objects and other internal
buffers is performed on demand by the Python memory manager through the Python/C
API functions listed in this document.
# ---------------------
extensions = ['sphinx.ext.coverage', 'sphinx.ext.doctest',
- 'pyspecific', 'c_annotations']
+ 'pyspecific', 'c_annotations', 'escape4chm']
# General substitutions.
project = 'Python'
intermediary species called *packagers* springs up to turn source distributions
into built distributions for as many platforms as there are packagers.
-Of course, the module developer could be his own packager; or the packager could
+Of course, the module developer could be their own packager; or the packager could
be a volunteer "out there" somewhere who has access to a platform which the
original developer does not; or it could be software periodically grabbing new
source distributions and turning them into built distributions for as many
The archive file will be named :file:`foo-1.0.tar.gz` (or :file:`.zip`), and
will unpack into a directory :file:`foo-1.0`.
-If an end-user wishes to install your :mod:`foo` module, all she has to do is
+If an end-user wishes to install your :mod:`foo` module, all they have to do is
download :file:`foo-1.0.tar.gz` (or :file:`.zip`), unpack it, and---from the
:file:`foo-1.0` directory---run ::
Design and History FAQ
======================
+.. only:: html
+
+ .. contents::
+
+
Why does Python use indentation for grouping of statements?
-----------------------------------------------------------
Why does Python use methods for some functionality (e.g. list.index()) but functions for other (e.g. len(list))?
----------------------------------------------------------------------------------------------------------------
-The major reason is history. Functions were used for those operations that were
-generic for a group of types and which were intended to work even for objects
-that didn't have methods at all (e.g. tuples). It is also convenient to have a
-function that can readily be applied to an amorphous collection of objects when
-you use the functional features of Python (``map()``, ``zip()`` et al).
+As Guido said:
-In fact, implementing ``len()``, ``max()``, ``min()`` as a built-in function is
-actually less code than implementing them as methods for each type. One can
-quibble about individual cases but it's a part of Python, and it's too late to
-make such fundamental changes now. The functions have to remain to avoid massive
-code breakage.
+ (a) For some operations, prefix notation just reads better than
+ postfix -- prefix (and infix!) operations have a long tradition in
+ mathematics which likes notations where the visuals help the
+ mathematician thinking about a problem. Compare the easy with which we
+ rewrite a formula like x*(a+b) into x*a + x*b to the clumsiness of
+ doing the same thing using a raw OO notation.
-.. XXX talk about protocols?
+ (b) When I read code that says len(x) I *know* that it is asking for
+ the length of something. This tells me two things: the result is an
+ integer, and the argument is some kind of container. To the contrary,
+ when I read x.len(), I have to already know that x is some kind of
+ container implementing an interface or inheriting from a class that
+ has a standard len(). Witness the confusion we occasionally have when
+ a class that is not implementing a mapping has a get() or keys()
+ method, or something that isn't a file has a write() method.
-.. note::
-
- For string operations, Python has moved from external functions (the
- ``string`` module) to methods. However, ``len()`` is still a function.
+ -- https://mail.python.org/pipermail/python-3000/2006-November/004643.html
Why is join() a string method instead of a list or tuple method?
dictionary keys, and hence only tuples and not lists can be used as keys.
-How are lists implemented?
---------------------------
+How are lists implemented in CPython?
+-------------------------------------
-Python's lists are really variable-length arrays, not Lisp-style linked lists.
+CPython's lists are really variable-length arrays, not Lisp-style linked lists.
The implementation uses a contiguous array of references to other objects, and
keeps a pointer to this array and the array's length in a list head structure.
times don't require an actual resize.
-How are dictionaries implemented?
----------------------------------
+How are dictionaries implemented in CPython?
+--------------------------------------------
-Python's dictionaries are implemented as resizable hash tables. Compared to
+CPython's dictionaries are implemented as resizable hash tables. Compared to
B-trees, this gives better performance for lookup (the most common operation by
far) under most circumstances, and the implementation is simpler.
of each call to the function, and return the cached value if the same value is
requested again. This is called "memoizing", and can be implemented like this::
- # Callers will never provide a third parameter for this function.
- def expensive(arg1, arg2, _cache={}):
+ # Callers can only provide two parameters and optionally pass _cache by keyword
+ def expensive(arg1, arg2, *, _cache={}):
if (arg1, arg2) in _cache:
return _cache[(arg1, arg2)]
``...``
The default Python prompt of the interactive shell when entering code for
- an indented code block or within a pair of matching left and right
- delimiters (parentheses, square brackets or curly braces).
+ an indented code block, when within a pair of matching left and right
+ delimiters (parentheses, square brackets, curly braces or triple quotes),
+ or after specifying a decorator.
2to3
A tool that tries to convert Python 2.x code to Python 3.x code by
:meth:`__aiter__` method. Introduced by :pep:`492`.
asynchronous iterator
- An object that implements :meth:`__aiter__` and :meth:`__anext__`
+ An object that implements the :meth:`__aiter__` and :meth:`__anext__`
methods. ``__anext__`` must return an :term:`awaitable` object.
- :keyword:`async for` resolves awaitable returned from asynchronous
- iterator's :meth:`__anext__` method until it raises
+ :keyword:`async for` resolves the awaitables returned by an asynchronous
+ iterator's :meth:`__anext__` method until it raises a
:exc:`StopAsyncIteration` exception. Introduced by :pep:`492`.
attribute
list
A built-in Python :term:`sequence`. Despite its name it is more akin
to an array in other languages than to a linked list since access to
- elements are O(1).
+ elements is O(1).
list comprehension
A compact way to process all or part of the elements in a sequence and
struct sequence
A tuple with named elements. Struct sequences expose an interface similar
- to :term:`named tuple` in that elements can either be accessed either by
+ to :term:`named tuple` in that elements can be accessed either by
index or as an attribute. However, they do not have any of the named tuple
methods like :meth:`~collections.somenamedtuple._make` or
:meth:`~collections.somenamedtuple._asdict`. Examples of struct sequences
You can experiment with the iteration interface manually:
- >>> L = [1,2,3]
+ >>> L = [1, 2, 3]
>>> it = iter(L)
>>> it #doctest: +ELLIPSIS
<...iterator object at ...>
Iterators can be materialized as lists or tuples by using the :func:`list` or
:func:`tuple` constructor functions:
- >>> L = [1,2,3]
+ >>> L = [1, 2, 3]
>>> iterator = iter(L)
>>> t = tuple(iterator)
>>> t
Sequence unpacking also supports iterators: if you know an iterator will return
N elements, you can unpack them into an N-tuple:
- >>> L = [1,2,3]
+ >>> L = [1, 2, 3]
>>> iterator = iter(L)
- >>> a,b,c = iterator
- >>> a,b,c
+ >>> a, b, c = iterator
+ >>> a, b, c
(1, 2, 3)
Built-in functions such as :func:`max` and :func:`min` can take a single
list is 9 elements long:
>>> seq1 = 'abc'
- >>> seq2 = (1,2,3)
+ >>> seq2 = (1, 2, 3)
>>> [(x, y) for x in seq1 for y in seq2] #doctest: +NORMALIZE_WHITESPACE
[('a', 1), ('a', 2), ('a', 3),
('b', 1), ('b', 2), ('b', 3),
File "stdin", line 2, in generate_ints
StopIteration
-You could equally write ``for i in generate_ints(5)``, or ``a,b,c =
+You could equally write ``for i in generate_ints(5)``, or ``a, b, c =
generate_ints(3)``.
Inside a generator function, ``return value`` causes ``StopIteration(value)``
in the iterable is a true value, and :func:`all` returns ``True`` if all of the
elements are true values:
- >>> any([0,1,0])
+ >>> any([0, 1, 0])
True
- >>> any([0,0,0])
+ >>> any([0, 0, 0])
False
- >>> any([1,1,1])
+ >>> any([1, 1, 1])
True
- >>> all([0,1,0])
+ >>> all([0, 1, 0])
False
- >>> all([0,0,0])
+ >>> all([0, 0, 0])
False
- >>> all([1,1,1])
+ >>> all([1, 1, 1])
True
a provided iterable and returns a new iterator that returns its elements from
first to last. The new iterator will repeat these elements infinitely. ::
- itertools.cycle([1,2,3,4,5]) =>
+ itertools.cycle([1, 2, 3, 4, 5]) =>
1, 2, 3, 4, 5, 1, 2, 3, 4, 5, ...
:func:`itertools.repeat(elem, [n]) <itertools.repeat>` returns the provided
iterators and returns only those elements of *data* for which the corresponding
element of *selectors* is true, stopping whenever either one is exhausted::
- itertools.compress([1,2,3,4,5], [True, True, False, False, True]) =>
+ itertools.compress([1, 2, 3, 4, 5], [True, True, False, False, True]) =>
1, 2, 5
Traceback (most recent call last):
...
TypeError: reduce() of empty sequence with no initial value
- >>> functools.reduce(operator.mul, [1,2,3], 1)
+ >>> functools.reduce(operator.mul, [1, 2, 3], 1)
6
>>> functools.reduce(operator.mul, [], 1)
1
built-in called :func:`sum` to compute it:
>>> import functools, operator
- >>> functools.reduce(operator.add, [1,2,3,4], 0)
+ >>> functools.reduce(operator.add, [1, 2, 3, 4], 0)
10
- >>> sum([1,2,3,4])
+ >>> sum([1, 2, 3, 4])
10
>>> sum([])
0
import functools
# Instead of:
- product = functools.reduce(operator.mul, [1,2,3], 1)
+ product = functools.reduce(operator.mul, [1, 2, 3], 1)
# You can write:
product = 1
- for i in [1,2,3]:
+ for i in [1, 2, 3]:
product *= i
A related function is :func:`itertools.accumulate(iterable, func=operator.add)
returning only the final result, :func:`accumulate` returns an iterator that
also yields each partial result::
- itertools.accumulate([1,2,3,4,5]) =>
+ itertools.accumulate([1, 2, 3, 4, 5]) =>
1, 3, 6, 10, 15
- itertools.accumulate([1,2,3,4,5], operator.mul) =>
+ itertools.accumulate([1, 2, 3, 4, 5], operator.mul) =>
1, 2, 6, 24, 120
Or the :func:`sum` built-in and a generator expression::
- total = sum(b for a,b in items)
+ total = sum(b for a, b in items)
Many uses of :func:`functools.reduce` are clearer when written as ``for`` loops.
int
main(int argc, char *argv[])
{
- PyObject *pName, *pModule, *pDict, *pFunc;
+ PyObject *pName, *pModule, *pFunc;
PyObject *pArgs, *pValue;
int i;
the protocol's :meth:`data_received` method until :meth:`resume_reading`
is called.
+ .. versionchanged:: 3.6.7
+ The method is idempotent, i.e. it can be called when the
+ transport is already paused or closed.
+
.. method:: resume_reading()
Resume the receiving end. The protocol's :meth:`data_received` method
will be called once again if some data is available for reading.
+ .. versionchanged:: 3.6.7
+ The method is idempotent, i.e. it can be called when the
+ transport is already reading.
+
WriteTransport
--------------
StreamReader
============
-.. class:: StreamReader(limit=None, loop=None)
+.. class:: StreamReader(limit=_DEFAULT_LIMIT, loop=None)
This class is :ref:`not thread safe <asyncio-multithreading>`.
+ The *limit* argument's default value is set to _DEFAULT_LIMIT which is 2**16 (64 KiB)
+
.. method:: exception()
Get the exception.
>>> d['lion'] = 'orange' # update an existing key two levels down
>>> d['snake'] = 'red' # new keys get added to the topmost dict
>>> del d['elephant'] # remove an existing key one level down
+ >>> d # display result
DeepChainMap({'zebra': 'black', 'snake': 'red'}, {}, {'lion': 'orange'})
.. method:: read(filenames, encoding=None)
- Attempt to read and parse a list of filenames, returning a list of
+ Attempt to read and parse an iterable of filenames, returning a list of
filenames which were successfully parsed.
If *filenames* is a string or :term:`path-like object`, it is treated as
a single filename. If a file named in *filenames* cannot be opened, that
- file will be ignored. This is designed so that you can specify a list of
- potential configuration file locations (for example, the current
- directory, the user's home directory, and some system-wide directory),
- and all existing configuration files in the list will be read.
+ file will be ignored. This is designed so that you can specify an
+ iterable of potential configuration file locations (for example, the
+ current directory, the user's home directory, and some system-wide
+ directory), and all existing configuration files in the iterable will be
+ read.
If none of the named files exist, the :class:`ConfigParser`
instance will contain an empty dataset. An application which requires
function for :keyword:`with` statement context managers, without needing to
create a class or separate :meth:`__enter__` and :meth:`__exit__` methods.
- A simple example (this is not recommended as a real way of generating HTML!)::
+ While many objects natively support use in with statements, sometimes a
+ resource needs to be managed that isn't a context manager in its own right,
+ and doesn't implement a ``close()`` method for use with ``contextlib.closing``
+
+ An abstract example would be the following to ensure correct resource
+ management::
from contextlib import contextmanager
@contextmanager
- def tag(name):
- print("<%s>" % name)
- yield
- print("</%s>" % name)
+ def managed_resource(*args, **kwds):
+ # Code to acquire resource, e.g.:
+ resource = acquire_resource(*args, **kwds)
+ try:
+ yield resource
+ finally:
+ # Code to release resource, e.g.:
+ release_resource(resource)
- >>> with tag("h1"):
- ... print("foo")
- ...
- <h1>
- foo
- </h1>
+ >>> with managed_resource(timeout=3600) as resource:
+ ... # Resource is released at the end of this block,
+ ... # even if code in the block raises an exception
The function being decorated must return a :term:`generator`-iterator when
called. This iterator must yield exactly one value, which will be bound to
1 5 7 33 99
>>>
+The function factories can be used as decorator factories, so we may as well
+write::
+
+ >>> @CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
+ ... def py_cmp_func(a, b):
+ ... print("py_cmp_func", a[0], b[0])
+ ... return a[0] - b[0]
+ ...
+ >>> qsort(ia, len(ia), sizeof(c_int), py_cmp_func)
+ py_cmp_func 5 1
+ py_cmp_func 33 99
+ py_cmp_func 7 33
+ py_cmp_func 1 7
+ py_cmp_func 5 7
+ >>>
+
.. note::
Make sure you keep references to :func:`CFUNCTYPE` objects as long as they
Function prototypes are similar to function prototypes in C; they describe a
function (return type, argument types, calling convention) without defining an
implementation. The factory functions must be called with the desired result
-type and the argument types of the function.
+type and the argument types of the function, and can be used as decorator
+factories, and as such, be applied to functions through the ``@wrapper`` syntax.
+See :ref:`ctypes-callback-functions` for examples.
.. function:: CFUNCTYPE(restype, *argtypes, use_errno=False, use_last_error=False)
+--------------------------------+-----------------------------------------------+
| ``t1 = t2 - t3`` | Difference of *t2* and *t3*. Afterwards *t1* |
| | == *t2* - *t3* and *t2* == *t1* + *t3* are |
-| | true. (1) |
+| | true. (1)(6) |
+--------------------------------+-----------------------------------------------+
| ``t1 = t2 * i or t1 = i * t2`` | Delta multiplied by an integer. |
| | Afterwards *t1* // i == *t2* is true, |
>>> print(_)
-1 day, 19:00:00
+(6)
+ The expression ``t2 - t3`` will always be equal to the expression ``t2 + (-t3)`` except
+ when t3 is equal to ``timedelta.max``; in that case the former will produce a result
+ while the latter will overflow.
+
In addition to the operations listed above :class:`timedelta` objects support
certain additions and subtractions with :class:`date` and :class:`.datetime`
objects (see below).
:const:`MINYEAR` or larger than :const:`MAXYEAR`.
(2)
- This isn't quite equivalent to date1 + (-timedelta), because -timedelta in
- isolation can overflow in cases where date1 - timedelta does not.
``timedelta.seconds`` and ``timedelta.microseconds`` are ignored.
(3)
(4)
In other words, ``date1 < date2`` if and only if ``date1.toordinal() <
- date2.toordinal()``. In order to stop comparison from falling back to the
- default scheme of comparing object addresses, date comparison normally raises
- :exc:`TypeError` if the other comparand isn't also a :class:`date` object.
- However, ``NotImplemented`` is returned instead if the other comparand has a
+ date2.toordinal()``. Date comparison raises :exc:`TypeError` if
+ the other comparand isn't also a :class:`date` object. However,
+ ``NotImplemented`` is returned instead if the other comparand has a
:meth:`timetuple` attribute. This hook gives other kinds of date objects a
chance at implementing mixed-type comparison. If not, when a :class:`date`
object is compared to an object of a different type, :exc:`TypeError` is raised
Computes the datetime2 such that datetime2 + timedelta == datetime1. As for
addition, the result has the same :attr:`~.datetime.tzinfo` attribute as the input
datetime, and no time zone adjustments are done even if the input is aware.
- This isn't quite equivalent to datetime1 + (-timedelta), because -timedelta
- in isolation can overflow in cases where datetime1 - timedelta does not.
(3)
Subtraction of a :class:`.datetime` from a :class:`.datetime` is defined only if
.. opcode:: RAISE_VARARGS (argc)
- Raises an exception. *argc* indicates the number of parameters to the raise
+ Raises an exception. *argc* indicates the number of arguments to the raise
statement, ranging from 0 to 3. The handler will find the traceback as TOS2,
the parameter as TOS1, and the exception as TOS.
.. opcode:: CALL_FUNCTION (argc)
- Calls a function. *argc* indicates the number of positional arguments.
- The positional arguments are on the stack, with the right-most argument
- on top. Below the arguments, the function object to call is on the stack.
- Pops all function arguments, and the function itself off the stack, and
- pushes the return value.
+ Calls a callable object with positional arguments.
+ *argc* indicates the number of positional arguments.
+ The top of the stack contains positional arguments, with the right-most
+ argument on top. Below the arguments is a callable object to call.
+ ``CALL_FUNCTION`` pops all arguments and the callable object off the stack,
+ calls the callable object with those arguments, and pushes the return value
+ returned by the callable object.
.. versionchanged:: 3.6
This opcode is used only for calls with positional arguments.
.. opcode:: CALL_FUNCTION_KW (argc)
- Calls a function. *argc* indicates the number of arguments (positional
- and keyword). The top element on the stack contains a tuple of keyword
- argument names. Below the tuple, keyword arguments are on the stack, in
- the order corresponding to the tuple. Below the keyword arguments, the
- positional arguments are on the stack, with the right-most parameter on
- top. Below the arguments, the function object to call is on the stack.
- Pops all function arguments, and the function itself off the stack, and
- pushes the return value.
+ Calls a callable object with positional (if any) and keyword arguments.
+ *argc* indicates the total number of positional and keyword arguments.
+ The top element on the stack contains a tuple of keyword argument names.
+ Below that are keyword arguments in the order corresponding to the tuple.
+ Below that are positional arguments, with the right-most parameter on
+ top. Below the arguments is a callable object to call.
+ ``CALL_FUNCTION_KW`` pops all arguments and the callable object off the stack,
+ calls the callable object with those arguments, and pushes the return value
+ returned by the callable object.
.. versionchanged:: 3.6
Keyword arguments are packed in a tuple instead of a dictionary,
- *argc* indicates the total number of arguments
+ *argc* indicates the total number of arguments.
.. opcode:: CALL_FUNCTION_EX (flags)
- Calls a function. The lowest bit of *flags* indicates whether the
- var-keyword argument is placed at the top of the stack. Below the
- var-keyword argument, the var-positional argument is on the stack.
- Below the arguments, the function object to call is placed.
- Pops all function arguments, and the function itself off the stack, and
- pushes the return value. Note that this opcode pops at most three items
- from the stack. Var-positional and var-keyword arguments are packed
- by :opcode:`BUILD_TUPLE_UNPACK_WITH_CALL` and
- :opcode:`BUILD_MAP_UNPACK_WITH_CALL`.
+ Calls a callable object with variable set of positional and keyword
+ arguments. If the lowest bit of *flags* is set, the top of the stack
+ contains a mapping object containing additional keyword arguments.
+ Below that is an iterable object containing positional arguments and
+ a callable object to call. :opcode:`BUILD_MAP_UNPACK_WITH_CALL` and
+ :opcode:`BUILD_TUPLE_UNPACK_WITH_CALL` can be used for merging multiple
+ mapping objects and iterables containing arguments.
+ Before the callable is called, the mapping object and iterable object
+ are each "unpacked" and their contents passed in as keyword and
+ positional arguments respectively.
+ ``CALL_FUNCTION_EX`` pops all arguments and the callable object off the stack,
+ calls the callable object with those arguments, and pushes the return value
+ returned by the callable object.
.. versionadded:: 3.6
Pushes a new function object on the stack. From bottom to top, the consumed
stack must consist of values if the argument carries a specified flag value
- * ``0x01`` a tuple of default argument objects in positional order
+ * ``0x01`` a tuple of default values for positional-only and
+ positional-or-keyword parameters in positional order
* ``0x02`` a dictionary of keyword-only parameters' default values
* ``0x04`` an annotation dictionary
* ``0x08`` a tuple containing cells for free variables, making a closure
.. data:: hasconst
- Sequence of bytecodes that have a constant parameter.
+ Sequence of bytecodes that access a constant.
.. data:: hasfree
* :class:`InvalidBase64CharactersDefect` -- When decoding a block of base64
encoded bytes, characters outside the base64 alphabet were encountered.
The characters are ignored, but the resulting decoded bytes may be invalid.
+
+* :class:`InvalidBase64LengthDefect` -- When decoding a block of base64 encoded
+ bytes, the number of non-padding base64 characters was invalid (1 more than
+ a multiple of 4). The encoded block was kept as-is.
Removed the *strict* argument. Added the *policy* keyword.
-.. function:: message_from_binary_file(fp, _class=None, *,
+.. function:: message_from_binary_file(fp, _class=None, *, \
policy=policy.compat32)
Return a message object structure tree from an open binary :term:`file
.. seealso::
Module :mod:`smtplib`
- SMTP (Simple Mail Transport Protcol) client
+ SMTP (Simple Mail Transport Protocol) client
Module :mod:`poplib`
POP (Post Office Protocol) client
.. module:: enum
:synopsis: Implementation of an enumeration class.
-.. :moduleauthor:: Ethan Furman <ethan@stoneleaf.us>
-.. :sectionauthor:: Barry Warsaw <barry@python.org>,
-.. :sectionauthor:: Eli Bendersky <eliben@gmail.com>,
-.. :sectionauthor:: Ethan Furman <ethan@stoneleaf.us>
+.. moduleauthor:: Ethan Furman <ethan@stoneleaf.us>
+.. sectionauthor:: Barry Warsaw <barry@python.org>
+.. sectionauthor:: Eli Bendersky <eliben@gmail.com>
+.. sectionauthor:: Ethan Furman <ethan@stoneleaf.us>
.. versionadded:: 3.4
.. exception:: ValueError
- Raised when a built-in operation or function receives an argument that has the
+ Raised when an operation or function receives an argument that has the
right type but an inappropriate value, and the situation is not described by a
more precise exception such as :exc:`IndexError`.
>>> f'{14:#b}', f'{14:b}'
('0b1110', '1110')
- See also :func:`format` for more information.
+ See also :func:`format` for more information.
.. class:: bool([x])
interactive statement (in the latter case, expression statements that
evaluate to something other than ``None`` will be printed).
- The optional arguments *flags* and *dont_inherit* control which future
- statements (see :pep:`236`) affect the compilation of *source*. If neither
+ The optional arguments *flags* and *dont_inherit* control which :ref:`future
+ statements <future>` affect the compilation of *source*. If neither
is present (or both are zero) the code is compiled with those future
statements that are in effect in the code that is calling :func:`compile`. If the
*flags* argument is given and *dont_inherit* is not (or is zero) then the
The *expression* argument is parsed and evaluated as a Python expression
(technically speaking, a condition list) using the *globals* and *locals*
dictionaries as global and local namespace. If the *globals* dictionary is
- present and lacks '__builtins__', the current globals are copied into *globals*
- before *expression* is parsed. This means that *expression* normally has full
+ present and does not contain a value for the key ``__builtins__``, a
+ reference to the dictionary of the built-in module :mod:`builtins` is
+ inserted under that key before *expression* is parsed.
+ This means that *expression* normally has full
access to the standard :mod:`builtins` module and restricted environments are
propagated. If the *locals* dictionary is omitted it defaults to the *globals*
dictionary. If both dictionaries are omitted, the expression is executed in the
dictionary lookup. Numeric values that compare equal have the same hash
value (even if they are of different types, as is the case for 1 and 1.0).
- .. note::
+ .. note::
- For objects with custom :meth:`__hash__` methods, note that :func:`hash`
- truncates the return value based on the bit width of the host machine.
- See :meth:`__hash__` for details.
+ For objects with custom :meth:`__hash__` methods, note that :func:`hash`
+ truncates the return value based on the bit width of the host machine.
+ See :meth:`__hash__` for details.
.. function:: help([object])
encoding. (For reading and writing raw bytes use binary mode and leave
*encoding* unspecified.) The available modes are:
+ .. _filemodes:
+
+ .. index::
+ pair: file; modes
+
========= ===============================================================
Character Meaning
========= ===============================================================
.. function:: new(name[, data])
- Is a generic constructor that takes the string name of the desired
+ Is a generic constructor that takes the string *name* of the desired
algorithm as its first parameter. It also exists to allow access to the
above listed hashes as well as any other algorithms that your OpenSSL
library may offer. The named constructors are much faster than :func:`new`
A hash object has the following methods:
-.. method:: hash.update(arg)
+.. method:: hash.update(data)
- Update the hash object with the object *arg*, which must be interpretable as
- a buffer of bytes. Repeated calls are equivalent to a single call with the
+ Update the hash object with the :term:`bytes-like object`.
+ Repeated calls are equivalent to a single call with the
concatenation of all the arguments: ``m.update(a); m.update(b)`` is
equivalent to ``m.update(a+b)``.
.. method:: shake.digest(length)
Return the digest of the data passed to the :meth:`update` method so far.
- This is a bytes object of size ``length`` which may contain bytes in
+ This is a bytes object of size *length* which may contain bytes in
the whole range from 0 to 255.
The function provides scrypt password-based key derivation function as
defined in :rfc:`7914`.
- *password* and *salt* must be bytes-like objects. Applications and
- libraries should limit *password* to a sensible length (e.g. 1024). *salt*
- should be about 16 or more bytes from a proper source, e.g. :func:`os.urandom`.
+ *password* and *salt* must be :term:`bytes-like objects
+ <bytes-like object>`. Applications and libraries should limit *password*
+ to a sensible length (e.g. 1024). *salt* should be about 16 or more
+ bytes from a proper source, e.g. :func:`os.urandom`.
*n* is the CPU/Memory cost factor, *r* the block size, *p* parallelization
factor and *maxmem* limits memory (OpenSSL 1.1.0 defaults to 32 MB).
New hash objects are created by calling constructor functions:
-.. function:: blake2b(data=b'', digest_size=64, key=b'', salt=b'', \
+.. function:: blake2b(data=b'', *, digest_size=64, key=b'', salt=b'', \
person=b'', fanout=1, depth=1, leaf_size=0, node_offset=0, \
node_depth=0, inner_size=0, last_node=False)
-.. function:: blake2s(data=b'', digest_size=32, key=b'', salt=b'', \
+.. function:: blake2s(data=b'', *, digest_size=32, key=b'', salt=b'', \
person=b'', fanout=1, depth=1, leaf_size=0, node_offset=0, \
node_depth=0, inner_size=0, last_node=False)
These functions return the corresponding hash objects for calculating
BLAKE2b or BLAKE2s. They optionally take these general parameters:
-* *data*: initial chunk of data to hash, which must be interpretable as buffer
- of bytes.
+* *data*: initial chunk of data to hash, which must be
+ :term:`bytes-like object`. It can be passed only as positional argument.
* *digest_size*: size of output digest in bytes.
As a shortcut, you can pass the first chunk of data to update directly to the
-constructor as the first argument (or as *data* keyword argument):
+constructor as the positional argument:
>>> from hashlib import blake2b
>>> blake2b(b'Hello world').hexdigest()
preparer, generates all or part of a message to be signed by a second
party, the message signer. If the message preparer is able to find
cryptographic hash function collisions (i.e., two messages producing the
- same hash value), then she might prepare meaningful versions of the message
+ same hash value), then they might prepare meaningful versions of the message
that would produce the same hash value and digital signature, but with
different results (e.g., transferring $1,000,000 to an account, rather than
$10). Cryptographic hash functions have been designed with collision
.. function:: unescape(s)
Convert all named and numeric character references (e.g. ``>``,
- ``>``, ``&x3e;``) in the string *s* to the corresponding unicode
+ ``>``, ``>``) in the string *s* to the corresponding Unicode
characters. This function uses the rules defined by the HTML 5 standard
for both valid and invalid character references, and the :data:`list of
HTML 5 named character references <html.entities.html5>`.
.. abstractmethod:: find_module(fullname, path=None)
- An abstact method for finding a :term:`loader` for the specified
+ An abstract method for finding a :term:`loader` for the specified
module. Originally specified in :pep:`302`, this method was meant
for use in :data:`sys.meta_path` and in the path-based import subsystem.
Concrete implementation of :meth:`Loader.exec_module`.
- .. versionadded:: 3.4
+ .. versionadded:: 3.4
.. method:: load_module(fullname)
.. versionadded:: 3.1
- .. method:: read(size)
+ .. method:: read(size=-1)
Read and return at most *size* characters from the stream as a single
:class:`str`. If *size* is negative or ``None``, reads until EOF.
.. versionchanged:: 3.6
All optional parameters are now :ref:`keyword-only <keyword-only_parameter>`.
+ .. note::
+
+ Unlike :mod:`pickle` and :mod:`marshal`, JSON is not a framed protocol,
+ so trying to serialize multiple objects with repeated calls to
+ :func:`dump` using the same *fp* will result in an invalid JSON file.
.. function:: dumps(obj, *, skipkeys=False, ensure_ascii=True, \
check_circular=True, allow_nan=True, cls=None, \
table <py-to-json-table>`. The arguments have the same meaning as in
:func:`dump`.
- .. note::
-
- Unlike :mod:`pickle` and :mod:`marshal`, JSON is not a framed protocol,
- so trying to serialize multiple objects with repeated calls to
- :func:`dump` using the same *fp* will result in an invalid JSON file.
-
.. note::
Keys in key/value pairs of JSON are always of the type :class:`str`. When
+--------------+---------------------------------------------+
| Format | Description |
+==============+=============================================+
- | ``filename`` | Specifies that a FileHandler be created, |
+ | *filename* | Specifies that a FileHandler be created, |
| | using the specified filename, rather than a |
| | StreamHandler. |
+--------------+---------------------------------------------+
- | ``filemode`` | Specifies the mode to open the file, if |
- | | filename is specified (if filemode is |
- | | unspecified, it defaults to 'a'). |
+ | *filemode* | If *filename* is specified, open the file |
+ | | in this :ref:`mode <filemodes>`. Defaults |
+ | | to ``'a'``. |
+--------------+---------------------------------------------+
- | ``format`` | Use the specified format string for the |
+ | *format* | Use the specified format string for the |
| | handler. |
+--------------+---------------------------------------------+
- | ``datefmt`` | Use the specified date/time format. |
+ | *datefmt* | Use the specified date/time format, as |
+ | | accepted by :func:`time.strftime`. |
+--------------+---------------------------------------------+
- | ``style`` | If ``format`` is specified, use this style |
- | | for the format string. One of '%', '{' or |
- | | '$' for %-formatting, :meth:`str.format` or |
- | | :class:`string.Template` respectively, and |
- | | defaulting to '%' if not specified. |
+ | *style* | If *format* is specified, use this style |
+ | | for the format string. One of ``'%'``, |
+ | | ``'{'`` or ``'$'`` for :ref:`printf-style |
+ | | <old-string-formatting>`, |
+ | | :meth:`str.format` or |
+ | | :class:`string.Template` respectively. |
+ | | Defaults to ``'%'``. |
+--------------+---------------------------------------------+
- | ``level`` | Set the root logger level to the specified |
- | | level. |
+ | *level* | Set the root logger level to the specified |
+ | | :ref:`level <levels>`. |
+--------------+---------------------------------------------+
- | ``stream`` | Use the specified stream to initialize the |
+ | *stream* | Use the specified stream to initialize the |
| | StreamHandler. Note that this argument is |
- | | incompatible with 'filename' - if both are |
- | | present, a ``ValueError`` is raised. |
+ | | incompatible with *filename* - if both |
+ | | are present, a ``ValueError`` is raised. |
+--------------+---------------------------------------------+
- | ``handlers`` | If specified, this should be an iterable of |
+ | *handlers* | If specified, this should be an iterable of |
| | already created handlers to add to the root |
| | logger. Any handlers which don't already |
| | have a formatter set will be assigned the |
| | default formatter created in this function. |
| | Note that this argument is incompatible |
- | | with 'filename' or 'stream' - if both are |
- | | present, a ``ValueError`` is raised. |
+ | | with *filename* or *stream* - if both |
+ | | are present, a ``ValueError`` is raised. |
+--------------+---------------------------------------------+
.. versionchanged:: 3.2
- The ``style`` argument was added.
+ The *style* argument was added.
.. versionchanged:: 3.3
- The ``handlers`` argument was added. Additional checks were added to
+ The *handlers* argument was added. Additional checks were added to
catch situations where incompatible arguments are specified (e.g.
- ``handlers`` together with ``stream`` or ``filename``, or ``stream``
- together with ``filename``).
-
+ *handlers* together with *stream* or *filename*, or *stream*
+ together with *filename*).
.. function:: shutdown()
semaphores created by processes of the program. When all processes
have exited the semaphore tracker unlinks any remaining semaphores.
Usually there should be none, but if a process was killed by a signal
-there may some "leaked" semaphores. (Unlinking the named semaphores
+there may be some "leaked" semaphores. (Unlinking the named semaphores
is a serious matter since the system allows only a limited number, and
they will not be automatically unlinked until the next reboot.)
Note that objects related to one context may not be compatible with
processes for a different context. In particular, locks created using
-the *fork* context cannot be passed to a processes started using the
+the *fork* context cannot be passed to processes started using the
*spawn* or *forkserver* start methods.
A library which wants to use a particular start method should probably
problems with the option or its argument(s). :mod:`optparse` catches this and
terminates the program, printing the error message you supply to stderr. Your
message should be clear, concise, accurate, and mention the option at fault.
-Otherwise, the user will have a hard time figuring out what he did wrong.
+Otherwise, the user will have a hard time figuring out what they did wrong.
.. _optparse-callback-example-1:
.. method:: PurePath.with_suffix(suffix)
Return a new path with the :attr:`suffix` changed. If the original path
- doesn't have a suffix, the new *suffix* is appended instead::
+ doesn't have a suffix, the new *suffix* is appended instead. If the
+ *suffix* is an empty string, the original suffix is removed::
>>> p = PureWindowsPath('c:/Downloads/pathlib.tar.gz')
>>> p.with_suffix('.bz2')
>>> p = PureWindowsPath('README')
>>> p.with_suffix('.txt')
PureWindowsPath('README.txt')
+ >>> p = PureWindowsPath('README.txt')
+ >>> p.with_suffix('')
+ PureWindowsPath('README')
.. _concrete-paths:
>>> p.read_text()
'Text file contents'
- The optional parameters have the same meaning as in :func:`open`.
+ The file is opened and then closed. The optional parameters have the same
+ meaning as in :func:`open`.
.. versionadded:: 3.5
.. deprecated-removed:: 3.5 3.8
See alternative like the `distro <https://pypi.org/project/distro>`_ package.
-.. function:: libc_ver(executable=sys.executable, lib='', version='', chunksize=2048)
+.. function:: libc_ver(executable=sys.executable, lib='', version='', chunksize=16384)
Tries to determine the libc version against which the file executable (defaults
to the Python interpreter) is linked. Returns a tuple of strings ``(lib,
Profile ``func(*args, **kwargs)``
+Note that profiling will only work if the called command/function actually
+returns. If the interpreter is terminated (e.g. via a :func:`sys.exit` call
+during the called command/function execution) no profiling results will be
+printed.
+
.. _profile-stats:
The :class:`Stats` Class
^^^^^^^^^^^^^^^^^^^
:func:`findall` matches *all* occurrences of a pattern, not just the first
-one as :func:`search` does. For example, if one was a writer and wanted to
-find all of the adverbs in some text, he or she might use :func:`findall` in
+one as :func:`search` does. For example, if a writer wanted to
+find all of the adverbs in some text, they might use :func:`findall` in
the following manner::
>>> text = "He was carefully disguised but captured quickly by police."
If one wants more information about all matches of a pattern than the matched
text, :func:`finditer` is useful as it provides :ref:`match objects
<match-objects>` instead of strings. Continuing with the previous example, if
-one was a writer who wanted to find all of the adverbs *and their positions* in
-some text, he or she would use :func:`finditer` in the following manner::
+a writer wanted to find all of the adverbs *and their positions* in
+some text, they would use :func:`finditer` in the following manner::
>>> text = "He was carefully disguised but captured quickly by police."
>>> for m in re.finditer(r"\w+ly", text):
(Only supported on Linux 2.5.44 and newer.) Return an edge polling object,
which can be used as Edge or Level Triggered interface for I/O
- events. *sizehint* and *flags* are deprecated and completely ignored.
+ events.
+
+ *sizehint* informs epoll about the expected number of events to be
+ registered. It must be positive, or `-1` to use the default. It is only
+ used on older systems where :c:func:`epoll_create1` is not available;
+ otherwise it has no effect (though its value is still checked).
+
+ *flags* is deprecated and completely ignored. However, when supplied, its
+ value must be ``0`` or ``select.EPOLL_CLOEXEC``, otherwise ``OSError`` is
+ raised.
See the :ref:`epoll-objects` section below for the methods supported by
epolling objects.
If both options are given, user base and user site will be printed (always in
this order), separated by :data:`os.pathsep`.
-If any option is given, the script will exit with one of these values: ``O`` if
+If any option is given, the script will exit with one of these values: ``0`` if
the user site-packages directory is enabled, ``1`` if it was disabled by the
user, ``2`` if it is disabled for security reasons or by an administrator, and a
value greater than 2 if there is an error.
.. method:: SMTP.ehlo_or_helo_if_needed()
- This method call :meth:`ehlo` and or :meth:`helo` if there has been no
+ This method calls :meth:`ehlo` and/or :meth:`helo` if there has been no
previous ``EHLO`` or ``HELO`` command this session. It tries ESMTP ``EHLO``
first.
If optional keyword argument *initial_response_ok* is true,
``authobject()`` will be called first with no argument. It can return the
- :rfc:`4954` "initial response" bytes which will be encoded and sent with
+ :rfc:`4954` "initial response" ASCII ``str`` which will be encoded and sent with
the ``AUTH`` command as below. If the ``authobject()`` does not support an
initial response (e.g. because it requires a challenge), it should return
``None`` when called with ``challenge=None``. If *initial_response_ok* is
If the initial response check returns ``None``, or if *initial_response_ok* is
false, ``authobject()`` will be called to process the server's challenge
response; the *challenge* argument it is passed will be a ``bytes``. It
- should return ``bytes`` *data* that will be base64 encoded and sent to the
+ should return ASCII ``str`` *data* that will be base64 encoded and sent to the
server.
The ``SMTP`` class provides ``authobjects`` for the ``CRAM-MD5``, ``PLAIN``,
commands that follow will be encrypted. You should then call :meth:`ehlo`
again.
- If *keyfile* and *certfile* are provided, these are passed to the :mod:`socket`
- module's :func:`ssl` function.
+ If *keyfile* and *certfile* are provided, they are used to create an
+ :class:`ssl.SSLContext`.
- Optional *context* parameter is a :class:`ssl.SSLContext` object; This is
+ Optional *context* parameter is an :class:`ssl.SSLContext` object; This is
an alternative to using a keyfile and a certfile and if specified both
*keyfile* and *certfile* should be ``None``.
If there has been no previous ``EHLO`` or ``HELO`` command this session,
this method tries ESMTP ``EHLO`` first.
+ .. deprecated:: 3.6
+
+ *keyfile* and *certfile* are deprecated in favor of *context*.
+ Please use :meth:`ssl.SSLContext.load_cert_chain` instead, or let
+ :func:`ssl.create_default_context` select the system's trusted CA
+ certificates for you.
+
:exc:`SMTPHeloError`
The server didn't reply properly to the ``HELO`` greeting.
:exc:`SMTPException`.
-.. method:: SMTP.sendmail(from_addr, to_addrs, msg, mail_options=[], rcpt_options=[])
+.. method:: SMTP.sendmail(from_addr, to_addrs, msg, mail_options=(), rcpt_options=())
Send mail. The required arguments are an :rfc:`822` from-address string, a list
of :rfc:`822` to-address strings (a bare string will be treated as a list with 1
.. method:: SMTP.send_message(msg, from_addr=None, to_addrs=None, \
- mail_options=[], rcpt_options=[])
+ mail_options=(), rcpt_options=())
This is a convenience method for calling :meth:`sendmail` with the message
represented by an :class:`email.message.Message` object. The arguments have
notation like ``'daring.cwi.nl'`` or an IPv4 address like ``'100.50.200.5'``,
and *port* is an integer.
+ - For IPv4 addresses, two special forms are accepted instead of a host
+ address: ``''`` represents :const:`INADDR_ANY`, which is used to bind to all
+ interfaces, and the string ``'<broadcast>'`` represents
+ :const:`INADDR_BROADCAST`. This behavior is not compatible with IPv6,
+ therefore, you may want to avoid these if you intend to support IPv6 with your
+ Python programs.
+
- For :const:`AF_INET6` address family, a four-tuple ``(host, port, flowinfo,
scopeid)`` is used, where *flowinfo* and *scopeid* represent the ``sin6_flowinfo``
and ``sin6_scope_id`` members in :const:`struct sockaddr_in6` in C. For
.. versionadded:: 3.6
-- Certain other address families (:const:`AF_PACKET`, :const:`AF_CAN`)
- support specific representations.
-
- .. XXX document them!
-
-For IPv4 addresses, two special forms are accepted instead of a host address:
-the empty string represents :const:`INADDR_ANY`, and the string
-``'<broadcast>'`` represents :const:`INADDR_BROADCAST`. This behavior is not
-compatible with IPv6, therefore, you may want to avoid these if you intend
-to support IPv6 with your Python programs.
+- :const:`AF_PACKET` is a low-level interface directly to network devices.
+ The packets are represented by the tuple
+ ``(ifname, proto[, pkttype[, hatype[, addr]]])`` where:
+
+ - *ifname* - String specifying the device name.
+ - *proto* - An in network-byte-order integer specifying the Ethernet
+ protocol number.
+ - *pkttype* - Optional integer specifying the packet type:
+
+ - ``PACKET_HOST`` (the default) - Packet addressed to the local host.
+ - ``PACKET_BROADCAST`` - Physical-layer broadcast packet.
+ - ``PACKET_MULTIHOST`` - Packet sent to a physical-layer multicast address.
+ - ``PACKET_OTHERHOST`` - Packet to some other host that has been caught by
+ a device driver in promiscuous mode.
+ - ``PACKET_OUTGOING`` - Packet originating from the local host that is
+ looped back to a packet socket.
+ - *hatype* - Optional integer specifying the ARP hardware address type.
+ - *addr* - Optional bytes-like object specifying the hardware physical
+ address, whose interpretation depends on the device.
If you use a hostname in the *host* portion of IPv4/v6 socket address, the
program may show a nondeterministic behavior, as Python uses the first address
.. versionadded:: 3.5
+
+.. data:: AF_PACKET
+ PF_PACKET
+ PACKET_*
+
+ Many constants of these forms, documented in the Linux documentation, are
+ also defined in the socket module.
+
+ Availability: Linux >= 2.2.
+
+
.. data:: AF_RDS
PF_RDS
SOL_RDS
Create a new socket using the given address family, socket type and protocol
number. The address family should be :const:`AF_INET` (the default),
- :const:`AF_INET6`, :const:`AF_UNIX`, :const:`AF_CAN` or :const:`AF_RDS`. The
- socket type should be :const:`SOCK_STREAM` (the default),
- :const:`SOCK_DGRAM`, :const:`SOCK_RAW` or perhaps one of the other ``SOCK_``
- constants. The protocol number is usually zero and may be omitted or in the
- case where the address family is :const:`AF_CAN` the protocol should be one
- of :const:`CAN_RAW` or :const:`CAN_BCM`. If *fileno* is specified, the other
- arguments are ignored, causing the socket with the specified file descriptor
- to return. Unlike :func:`socket.fromfd`, *fileno* will return the same
- socket and not a duplicate. This may help close a detached socket using
- :meth:`socket.close()`.
+ :const:`AF_INET6`, :const:`AF_UNIX`, :const:`AF_CAN`, :const:`AF_PACKET`, or
+ :const:`AF_RDS`. The socket type should be :const:`SOCK_STREAM` (the
+ default), :const:`SOCK_DGRAM`, :const:`SOCK_RAW` or perhaps one of the other
+ ``SOCK_`` constants. The protocol number is usually zero and may be omitted
+ or in the case where the address family is :const:`AF_CAN` the protocol
+ should be one of :const:`CAN_RAW` or :const:`CAN_BCM`. If *fileno* is
+ specified, the other arguments are ignored, causing the socket with the
+ specified file descriptor to return. Unlike :func:`socket.fromfd`, *fileno*
+ will return the same socket and not a duplicate. This may help close a
+ detached socket using :meth:`socket.close()`.
The newly created socket is :ref:`non-inheritable <fd_inheritance>`.
Registers a callable to convert a bytestring from the database into a custom
Python type. The callable will be invoked for all database values that are of
the type *typename*. Confer the parameter *detect_types* of the :func:`connect`
- function for how the type detection works. Note that the case of *typename* and
- the name of the type in your query must match!
+ function for how the type detection works. Note that *typename* and the name of
+ the type in your query are matched in case-insensitive manner.
.. function:: register_adapter(type, callable)
.. attribute:: isolation_level
- Get or set the current isolation level. :const:`None` for autocommit mode or
+ Get or set the current default isolation level. :const:`None` for autocommit mode or
one of "DEFERRED", "IMMEDIATE" or "EXCLUSIVE". See section
:ref:`sqlite3-controlling-transactions` for a more detailed explanation.
exists, syntax error in the SQL statement, wrong number of parameters
specified, etc. It is a subclass of :exc:`DatabaseError`.
+.. exception:: OperationalError
+
+ Exception raised for errors that are related to the database's operation
+ and not necessarily under the control of the programmer, e.g. an unexpected
+ disconnect occurs, the data source name is not found, a transaction could
+ not be processed, etc. It is a subclass of :exc:`DatabaseError`.
+
+.. exception:: NotSupportedError
+
+ Exception raised in case a method or database API was used which is not
+ supported by the database, e.g. calling the :meth:`~Connection.rollback`
+ method on a connection that does not support transaction or has
+ transactions turned off. It is a subclass of :exc:`DatabaseError`.
+
.. _sqlite3-types:
Controlling Transactions
------------------------
-By default, the :mod:`sqlite3` module opens transactions implicitly before a
-Data Modification Language (DML) statement (i.e.
-``INSERT``/``UPDATE``/``DELETE``/``REPLACE``).
+The underlying ``sqlite3`` library operates in ``autocommit`` mode by default,
+but the Python :mod:`sqlite3` module by default does not.
-You can control which kind of ``BEGIN`` statements sqlite3 implicitly executes
-(or none at all) via the *isolation_level* parameter to the :func:`connect`
-call, or via the :attr:`isolation_level` property of connections.
-
-If you want **autocommit mode**, then set :attr:`isolation_level` to ``None``.
+``autocommit`` mode means that statements that modify the database take effect
+immediately. A ``BEGIN`` or ``SAVEPOINT`` statement disables ``autocommit``
+mode, and a ``COMMIT``, a ``ROLLBACK``, or a ``RELEASE`` that ends the
+outermost transaction, turns ``autocommit`` mode back on.
-Otherwise leave it at its default, which will result in a plain "BEGIN"
-statement, or set it to one of SQLite's supported isolation levels: "DEFERRED",
-"IMMEDIATE" or "EXCLUSIVE".
+The Python :mod:`sqlite3` module by default issues a ``BEGIN`` statement
+implicitly before a Data Modification Language (DML) statement (i.e.
+``INSERT``/``UPDATE``/``DELETE``/``REPLACE``).
-The current transaction state is exposed through the
-:attr:`Connection.in_transaction` attribute of the connection object.
+You can control which kind of ``BEGIN`` statements :mod:`sqlite3` implicitly
+executes via the *isolation_level* parameter to the :func:`connect`
+call, or via the :attr:`isolation_level` property of connections.
+If you specify no *isolation_level*, a plain ``BEGIN`` is used, which is
+equivalent to specifying ``DEFERRED``. Other possible values are ``IMMEDIATE``
+and ``EXCLUSIVE``.
+
+You can disable the :mod:`sqlite3` module's implicit transaction management by
+setting :attr:`isolation_level` to ``None``. This will leave the underlying
+``sqlite3`` library operating in ``autocommit`` mode. You can then completely
+control the transaction state by explicitly issuing ``BEGIN``, ``ROLLBACK``,
+``SAVEPOINT``, and ``RELEASE`` statements in your code.
.. versionchanged:: 3.6
:mod:`sqlite3` used to implicitly commit an open transaction before DDL
The *ciphers* parameter sets the available ciphers for this SSL object.
It should be a string in the `OpenSSL cipher list format
- <https://wiki.openssl.org/index.php/Manual:Ciphers(1)#CIPHER_LIST_FORMAT>`_.
+ <https://www.openssl.org/docs/manmaster/man1/ciphers.html>`_.
The parameter ``do_handshake_on_connect`` specifies whether to do the SSL
handshake automatically after doing a :meth:`socket.connect`, or whether the
3DES was dropped from the default cipher string.
- .. versionchanged:: 3.6.3
-
- TLS 1.3 cipher suites TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384,
- and TLS_CHACHA20_POLY1305_SHA256 were added to the default cipher string.
-
Random generation
^^^^^^^^^^^^^^^^^
.. versionadded:: 3.3
+.. data:: OP_ENABLE_MIDDLEBOX_COMPAT
+
+ Send dummy Change Cipher Spec (CCS) messages in TLS 1.3 handshake to make
+ a TLS 1.3 connection look more like a TLS 1.2 connection.
+
+ This option is only available with OpenSSL 1.1.1 and later.
+
+ .. versionadded:: 3.6.7
+
.. data:: OP_NO_COMPRESSION
Disable compression on the SSL channel. This is useful if the application
returned socket should always be used for further communication with the
other side of the connection, rather than the original socket.
+.. method:: SSLSocket.verify_client_post_handshake()
+
+ Requests post-handshake authentication (PHA) from a TLS 1.3 client. PHA
+ can only be initiated for a TLS 1.3 connection from a server-side socket,
+ after the initial TLS handshake and with PHA enabled on both sides, see
+ :attr:`SSLContext.post_handshake_auth`.
+
+ The method does not perform a cert exchange immediately. The server-side
+ sends a CertificateRequest during the next write event and expects the
+ client to respond with a certificate on the next read event.
+
+ If any precondition isn't met (e.g. not TLS 1.3, PHA not enabled), an
+ :exc:`SSLError` is raised.
+
+ .. versionadded:: 3.6.7
+
+ .. note::
+ Only available with OpenSSL 1.1.1 and TLS 1.3 enabled. Without TLS 1.3
+ support, the method raises :exc:`NotImplementedError`.
+
.. method:: SSLSocket.version()
Return the actual SSL protocol version negotiated by the connection
Set the available ciphers for sockets created with this context.
It should be a string in the `OpenSSL cipher list format
- <https://wiki.openssl.org/index.php/Manual:Ciphers(1)#CIPHER_LIST_FORMAT>`_.
+ <https://www.openssl.org/docs/manmaster/man1/ciphers.html>`_.
If no cipher can be selected (because compile-time options or other
configuration forbids use of all the specified ciphers), an
:class:`SSLError` will be raised.
when connected, the :meth:`SSLSocket.cipher` method of SSL sockets will
give the currently selected cipher.
+ OpenSSL 1.1.1 has TLS 1.3 cipher suites enabled by default. The suites
+ cannot be disabled with :meth:`~SSLContext.set_ciphers`.
+
.. method:: SSLContext.set_alpn_protocols(protocols)
Specify which protocols the socket should advertise during the SSL/TLS
>>> ssl.create_default_context().options
<Options.OP_ALL|OP_NO_SSLv3|OP_NO_SSLv2|OP_NO_COMPRESSION: 2197947391>
+.. attribute:: SSLContext.post_handshake_auth
+
+ Enable TLS 1.3 post-handshake client authentication. Post-handshake auth
+ is disabled by default and a server can only request a TLS client
+ certificate during the initial handshake. When enabled, a server may
+ request a TLS client certificate at any time after the handshake.
+
+ When enabled on client-side sockets, the client signals the server that
+ it supports post-handshake authentication.
+
+ When enabled on server-side sockets, :attr:`SSLContext.verify_mode` must
+ be set to :data:`CERT_OPTIONAL` or :data:`CERT_REQUIRED`, too. The
+ actual client cert exchange is delayed until
+ :meth:`SSLSocket.verify_client_post_handshake` is called and some I/O is
+ performed.
+
+ .. versionadded:: 3.6.7
+
+ .. note::
+ Only available with OpenSSL 1.1.1 and TLS 1.3 enabled. Without TLS 1.3
+ support, the property value is None and can't be modified
+
.. attribute:: SSLContext.protocol
The protocol version chosen when constructing the context. This attribute
A certificate contains information about two principals. It contains the name
of a *subject*, and the subject's public key. It also contains a statement by a
-second principal, the *issuer*, that the subject is who he claims to be, and
+second principal, the *issuer*, that the subject is who they claim to be, and
that this is indeed the subject's public key. The issuer's statement is signed
with the issuer's private key, which only the issuer knows. However, anyone can
verify the issuer's statement by finding the issuer's public key, decrypting the
This is suited for when your data is discrete, and you don't mind that the
median may not be an actual data point.
+ If your data is ordinal (supports order operations) but not numeric (doesn't
+ support addition), you should use :func:`median_low` or :func:`median_high`
+ instead.
+
.. seealso:: :func:`median_low`, :func:`median_high`, :func:`median_grouped`
operator: not in
Two more operations with the same syntactic priority, :keyword:`in` and
-:keyword:`not in`, are supported only by sequence types (below).
-
+:keyword:`not in`, are supported by types that are :term:`iterable` or
+implement the :meth:`__contains__` method.
.. _typesnumeric:
.. _bitstring-ops:
Bitwise Operations on Integer Types
---------------------------------------
+-----------------------------------
.. index::
triple: operations on; integer; types
operator: >>
operator: ~
-Bitwise operations only make sense for integers. Negative numbers are treated
-as their 2's complement value (this assumes that there are enough bits so that
-no overflow occurs during the operation).
+Bitwise operations only make sense for integers. The result of bitwise
+operations is calculated as though carried out in two's complement with an
+infinite number of sign bits.
The priorities of the binary bitwise operations are all lower than the numeric
operations and higher than the comparisons; the unary operation ``~`` has the
+------------+--------------------------------+----------+
| Operation | Result | Notes |
+============+================================+==========+
-| ``x | y`` | bitwise :dfn:`or` of *x* and | |
+| ``x | y`` | bitwise :dfn:`or` of *x* and | \(4) |
| | *y* | |
+------------+--------------------------------+----------+
-| ``x ^ y`` | bitwise :dfn:`exclusive or` of | |
+| ``x ^ y`` | bitwise :dfn:`exclusive or` of | \(4) |
| | *x* and *y* | |
+------------+--------------------------------+----------+
-| ``x & y`` | bitwise :dfn:`and` of *x* and | |
+| ``x & y`` | bitwise :dfn:`and` of *x* and | \(4) |
| | *y* | |
+------------+--------------------------------+----------+
| ``x << n`` | *x* shifted left by *n* bits | (1)(2) |
A right shift by *n* bits is equivalent to division by ``pow(2, n)`` without
overflow check.
+(4)
+ Performing these calculations with at least one extra sign extension bit in
+ a finite two's complement representation (a working bit-width of
+ ``1 + max(x.bit_length(), y.bit_length()`` or more) is sufficient to get the
+ same result as if there were an infinite number of sign bits.
+
Additional Methods on Integer Types
-----------------------------------
| | sequence (same as | |
| | ``s[len(s):len(s)] = [x]``) | |
+------------------------------+--------------------------------+---------------------+
-| ``s.clear()`` | removes all items from ``s`` | \(5) |
+| ``s.clear()`` | removes all items from *s* | \(5) |
| | (same as ``del s[:]``) | |
+------------------------------+--------------------------------+---------------------+
-| ``s.copy()`` | creates a shallow copy of ``s``| \(5) |
+| ``s.copy()`` | creates a shallow copy of *s* | \(5) |
| | (same as ``s[:]``) | |
+------------------------------+--------------------------------+---------------------+
| ``s.extend(t)`` or | extends *s* with the | |
.. seealso::
* The `linspace recipe <http://code.activestate.com/recipes/579000/>`_
- shows how to implement a lazy version of range that suitable for floating
+ shows how to implement a lazy version of range suitable for floating
point applications.
.. index::
that can be specified in format strings.
.. note::
- When formatting a number (:class:`int`, :class:`float`, :class:`float`
- and subclasses) with the ``n`` type (ex: ``'{:n}'.format(1234)``), the
- function sets temporarily the ``LC_CTYPE`` locale to the ``LC_NUMERIC``
- locale to decode ``decimal_point`` and ``thousands_sep`` fields of
- :c:func:`localeconv` if they are non-ASCII or longer than 1 byte, and the
- ``LC_NUMERIC`` locale is different than the ``LC_CTYPE`` locale. This
- temporary change affects other threads.
+ When formatting a number (:class:`int`, :class:`float`, :class:`complex`,
+ :class:`decimal.Decimal` and subclasses) with the ``n`` type
+ (ex: ``'{:n}'.format(1234)``), the function temporarily sets the
+ ``LC_CTYPE`` locale to the ``LC_NUMERIC`` locale to decode
+ ``decimal_point`` and ``thousands_sep`` fields of :c:func:`localeconv` if
+ they are non-ASCII or longer than 1 byte, and the ``LC_NUMERIC`` locale is
+ different than the ``LC_CTYPE`` locale. This temporary change affects
+ other threads.
.. versionchanged:: 3.6.5
When formatting a number with the ``n`` type, the function sets
.. method:: str.upper()
Return a copy of the string with all the cased characters [4]_ converted to
- uppercase. Note that ``str.upper().isupper()`` might be ``False`` if ``s``
+ uppercase. Note that ``s.upper().isupper()`` might be ``False`` if ``s``
contains uncased characters or if the Unicode category of the resulting
character(s) is not "Lu" (Letter, uppercase), but e.g. "Lt" (Letter,
titlecase).
While bytes literals and representations are based on ASCII text, bytes
objects actually behave like immutable sequences of integers, with each
value in the sequence restricted such that ``0 <= x < 256`` (attempts to
- violate this restriction will trigger :exc:`ValueError`. This is done
+ violate this restriction will trigger :exc:`ValueError`). This is done
deliberately to emphasise that while many binary formats include ASCII based
elements and can be usefully manipulated with some text-oriented algorithms,
this is not generally the case for arbitrary binary data (blindly applying
The bytearray version of this method does *not* operate in place - it
always produces a new object, even if no changes were made.
-.. seealso:: :pep:`461`.
+.. seealso::
+
+ :pep:`461` - Adding % formatting to bytes and bytearray
+
.. versionadded:: 3.5
.. _typememoryview:
does an index lookup using :func:`__getitem__`.
.. versionchanged:: 3.1
- The positional argument specifiers can be omitted, so ``'{} {}'`` is
- equivalent to ``'{0} {1}'``.
+ The positional argument specifiers can be omitted for :meth:`str.format`,
+ so ``'{} {}'.format(a, b)`` is equivalent to ``'{0} {1}'.format(a, b)``.
+
+.. versionchanged:: 3.4
+ The positional argument specifiers can be omitted for :class:`Formatter`.
Some simple format string examples::
| ``'E'`` | Exponent notation. Same as ``'e'`` except it uses an |
| | upper case 'E' as the separator character. |
+---------+----------------------------------------------------------+
- | ``'f'`` | Fixed point. Displays the number as a fixed-point |
- | | number. The default precision is ``6``. |
+ | ``'f'`` | Fixed-point notation. Displays the number as a |
+ | | fixed-point number. The default precision is ``6``. |
+---------+----------------------------------------------------------+
- | ``'F'`` | Fixed point. Same as ``'f'``, but converts ``nan`` to |
- | | ``NAN`` and ``inf`` to ``INF``. |
+ | ``'F'`` | Fixed-point notation. Same as ``'f'``, but converts |
+ | | ``nan`` to ``NAN`` and ``inf`` to ``INF``. |
+---------+----------------------------------------------------------+
| ``'g'`` | General format. For a given precision ``p >= 1``, |
| | this rounds the number to ``p`` significant digits and |
Windows support was added.
The function now returns (exitcode, output) instead of (status, output)
- as it did in Python 3.3.3 and earlier. See :func:`WEXITSTATUS`.
+ as it did in Python 3.3.3 and earlier. exitcode has the same value as
+ :attr:`~Popen.returncode`.
.. function:: getoutput(cmd)
Return output (stdout and stderr) of executing *cmd* in a shell.
- Like :func:`getstatusoutput`, except the exit status is ignored and the return
+ Like :func:`getstatusoutput`, except the exit code is ignored and the return
value is a string containing the command's output. Example::
>>> subprocess.getoutput('ls /bin/ls')
default value for the *dir* argument to the functions defined in this
module.
- If ``tempdir`` is unset or ``None`` at any call to any of the above
+ If ``tempdir`` is ``None`` (the default) at any call to any of the above
functions except :func:`gettempprefix` it is initialized following the
algorithm described in :func:`gettempdir`.
The *timeout* parameter is new.
.. versionchanged:: 3.2
- Lock acquires can now be interrupted by signals on POSIX.
+ Lock acquisition can now be interrupted by signals on POSIX if the
+ underlying threading implementation supports it.
.. method:: release()
.. function:: extract_tb(tb, limit=None)
- Return a list of "pre-processed" stack trace entries extracted from the
- traceback object *tb*. It is useful for alternate formatting of
- stack traces. The optional *limit* argument has the same meaning as for
- :func:`print_tb`. A "pre-processed" stack trace entry is a 4-tuple
- (*filename*, *line number*, *function name*, *text*) representing the
- information that is usually printed for a stack trace. The *text* is a
- string with leading and trailing whitespace stripped; if the source is
- not available it is ``None``.
+ Return a :class:`StackSummary` object representing a list of "pre-processed"
+ stack trace entries extracted from the traceback object *tb*. It is useful
+ for alternate formatting of stack traces. The optional *limit* argument has
+ the same meaning as for :func:`print_tb`. A "pre-processed" stack trace
+ entry is a :class:`FrameSummary` object containing attributes
+ :attr:`~FrameSummary.filename`, :attr:`~FrameSummary.lineno`,
+ :attr:`~FrameSummary.name`, and :attr:`~FrameSummary.line` representing the
+ information that is usually printed for a stack trace. The
+ :attr:`~FrameSummary.line` is a string with leading and trailing
+ whitespace stripped; if the source is not available it is ``None``.
.. function:: extract_stack(f=None, limit=None)
.. function:: format_list(extracted_list)
- Given a list of tuples as returned by :func:`extract_tb` or
- :func:`extract_stack`, return a list of strings ready for printing. Each
- string in the resulting list corresponds to the item with the same index in
- the argument list. Each string ends in a newline; the strings may contain
- internal newlines as well, for those items whose source text line is not
- ``None``.
+ Given a list of tuples or :class:`FrameSummary` objects as returned by
+ :func:`extract_tb` or :func:`extract_stack`, return a list of strings ready
+ for printing. Each string in the resulting list corresponds to the item with
+ the same index in the argument list. Each string ends in a newline; the
+ strings may contain internal newlines as well, for those items whose source
+ text line is not ``None``.
.. function:: format_exception_only(etype, value)
.. classmethod:: from_list(a_list)
- Construct a :class:`StackSummary` object from a supplied old-style list
- of tuples. Each tuple should be a 4-tuple with filename, lineno, name,
- line as the elements.
+ Construct a :class:`StackSummary` object from a supplied list of
+ :class:`FrameSummary` objects or old-style list of tuples. Each tuple
+ should be a 4-tuple with filename, lineno, name, line as the elements.
.. method:: format()
the call signature by substituting a literal ellipsis
for the list of arguments in the type hint: ``Callable[..., ReturnType]``.
+.. _generics:
+
Generics
--------
def notify_by_email(employees: Sequence[Employee],
overrides: Mapping[str, str]) -> None: ...
-Generics can be parametrized by using a new factory available in typing
+Generics can be parameterized by using a new factory available in typing
called :class:`TypeVar`.
::
required to handle this particular case may change in future revisions of
:pep:`484`.
- The only legal parameters for :class:`Type` are classes, unions of classes, and
- :data:`Any`. For example::
+ The only legal parameters for :class:`Type` are classes, :data:`Any`,
+ :ref:`type variables <generics>`, and unions of any of these types.
+ For example::
def new_non_team_user(user_class: Type[Union[BaseUser, ProUser]]): ...
Note that this is not the same concept as an optional argument,
which is one that has a default. An optional argument with a
- default needn't use the ``Optional`` qualifier on its type
- annotation (although it is inferred if the default is ``None``).
- A mandatory argument may still have an ``Optional`` type if an
- explicit value of ``None`` is allowed.
+ default does not require the ``Optional`` qualifier on its type
+ annotation just because it is optional. For example::
+
+ def foo(arg: int = 0) -> None:
+ ...
+
+ On the other hand, if an explicit value of ``None`` is allowed, the
+ use of ``Optional`` is appropriate, whether the argument is optional
+ or not. For example::
+
+ def foo(arg: Optional[int] = None) -> None:
+ ...
.. data:: Tuple
.. data:: sentinel
- The ``sentinel`` object provides a convenient way of providing unique
- objects for your tests.
+ The ``sentinel`` object provides a convenient way of providing unique
+ objects for your tests.
- Attributes are created on demand when you access them by name. Accessing
- the same attribute will always return the same object. The objects
- returned have a sensible repr so that test failure messages are readable.
+ Attributes are created on demand when you access them by name. Accessing
+ the same attribute will always return the same object. The objects
+ returned have a sensible repr so that test failure messages are readable.
The ``sentinel`` attributes don't preserve their identity when they are
:mod:`copied <copy>` or :mod:`pickled <pickle>`.
.. function:: mock_open(mock=None, read_data=None)
- A helper function to create a mock to replace the use of :func:`open`. It works
- for :func:`open` called directly or used as a context manager.
-
- The *mock* argument is the mock object to configure. If ``None`` (the
- default) then a :class:`MagicMock` will be created for you, with the API limited
- to methods or attributes available on standard file handles.
-
- *read_data* is a string for the :meth:`~io.IOBase.read`,
- :meth:`~io.IOBase.readline`, and :meth:`~io.IOBase.readlines` methods
- of the file handle to return. Calls to those methods will take data from
- *read_data* until it is depleted. The mock of these methods is pretty
- simplistic: every time the *mock* is called, the *read_data* is rewound to
- the start. If you need more control over the data that you are feeding to
- the tested code you will need to customize this mock for yourself. When that
- is insufficient, one of the in-memory filesystem packages on `PyPI
- <https://pypi.org>`_ can offer a realistic filesystem for testing.
+ A helper function to create a mock to replace the use of :func:`open`. It works
+ for :func:`open` called directly or used as a context manager.
+
+ The *mock* argument is the mock object to configure. If ``None`` (the
+ default) then a :class:`MagicMock` will be created for you, with the API limited
+ to methods or attributes available on standard file handles.
+
+ *read_data* is a string for the :meth:`~io.IOBase.read`,
+ :meth:`~io.IOBase.readline`, and :meth:`~io.IOBase.readlines` methods
+ of the file handle to return. Calls to those methods will take data from
+ *read_data* until it is depleted. The mock of these methods is pretty
+ simplistic: every time the *mock* is called, the *read_data* is rewound to
+ the start. If you need more control over the data that you are feeding to
+ the tested code you will need to customize this mock for yourself. When that
+ is insufficient, one of the in-memory filesystem packages on `PyPI
+ <https://pypi.org>`_ can offer a realistic filesystem for testing.
.. versionchanged:: 3.4
Added :meth:`~io.IOBase.readline` and :meth:`~io.IOBase.readlines` support.
Such a working environment for the testing code is called a
:dfn:`test fixture`. A new TestCase instance is created as a unique
test fixture used to execute each individual test method. Thus
-`~TestCase.setUp`, `~TestCase.tearDown`, and `~TestCase.__init__`
+:meth:`~TestCase.setUp`, :meth:`~TestCase.tearDown`, and :meth:`~TestCase.__init__`
will be called once per test.
It is recommended that you use TestCase implementations to group tests together
.. method:: setUpClass()
- A class method called before tests in an individual class run.
+ A class method called before tests in an individual class are run.
``setUpClass`` is called with the class as the only argument
and must be decorated as a :func:`classmethod`::
+---------------------------------------------------------+--------------------------------------+------------+
.. method:: assertRaises(exception, callable, *args, **kwds)
- assertRaises(exception, msg=None)
+ assertRaises(exception, *, msg=None)
Test that an exception is raised when *callable* is called with any
positional or keyword arguments that are also passed to
.. method:: assertRaisesRegex(exception, regex, callable, *args, **kwds)
- assertRaisesRegex(exception, regex, msg=None)
+ assertRaisesRegex(exception, regex, *, msg=None)
Like :meth:`assertRaises` but also tests that *regex* matches
on the string representation of the raised exception. *regex* may be
.. method:: assertWarns(warning, callable, *args, **kwds)
- assertWarns(warning, msg=None)
+ assertWarns(warning, *, msg=None)
Test that a warning is triggered when *callable* is called with any
positional or keyword arguments that are also passed to
.. method:: assertWarnsRegex(warning, regex, callable, *args, **kwds)
- assertWarnsRegex(warning, regex, msg=None)
+ assertWarnsRegex(warning, regex, *, msg=None)
Like :meth:`assertWarns` but also tests that *regex* matches on the
message of the triggered warning. *regex* may be a regular expression
HTTPErrorProcessor Objects
--------------------------
-.. method:: HTTPErrorProcessor.http_response()
+.. method:: HTTPErrorProcessor.http_response(request, response)
Process HTTP error responses.
:exc:`~urllib.error.HTTPError` if no other handler handles the error.
-.. method:: HTTPErrorProcessor.https_response()
+.. method:: HTTPErrorProcessor.https_response(request, response)
Process HTTPS error responses.
The second argument, if present, specifies the file location to copy to (if
absent, the location will be a tempfile with a generated name). The third
- argument, if present, is a hook function that will be called once on
+ argument, if present, is a callable that will be called once on
establishment of the network connection and once after each block read
- thereafter. The hook will be passed three arguments; a count of blocks
+ thereafter. The callable will be passed three arguments; a count of blocks
transferred so far, a block size in bytes, and the total size of the file. The
third argument may be ``-1`` on older FTP servers which do not return a file
size in response to a retrieval request.
maliciously constructed data. If you need to parse untrusted or
unauthenticated data see :ref:`xml-vulnerabilities`.
+.. versionchanged:: 3.6.7
+
+ The SAX parser no longer processes general external entities by default to
+ increase security by default. To enable processing of external entities,
+ pass a custom parser instance in::
+
+ from xml.dom.pulldom import parse
+ from xml.sax import make_parser
+ from xml.sax.handler import feature_external_ges
+
+ parser = make_parser()
+ parser.setFeature(feature_external_ges, True)
+ parse(filename, parser=parser)
+
Example::
========================= ============== =============== ============== ============== ==============
billion laughs **Vulnerable** **Vulnerable** **Vulnerable** **Vulnerable** **Vulnerable**
quadratic blowup **Vulnerable** **Vulnerable** **Vulnerable** **Vulnerable** **Vulnerable**
-external entity expansion **Vulnerable** Safe (1) Safe (2) **Vulnerable** Safe (3)
-`DTD`_ retrieval **Vulnerable** Safe Safe **Vulnerable** Safe
+external entity expansion Safe (4) Safe (1) Safe (2) Safe (4) Safe (3)
+`DTD`_ retrieval Safe (4) Safe Safe Safe (4) Safe
decompression bomb Safe Safe Safe Safe **Vulnerable**
========================= ============== =============== ============== ============== ==============
2. :mod:`xml.dom.minidom` doesn't expand external entities and simply returns
the unexpanded entity verbatim.
3. :mod:`xmlrpclib` doesn't expand external entities and omits them.
+4. Since Python 3.8.0, external general entities are no longer processed by
+ default since Python.
billion laughs / exponential entity expansion
constructed data. If you need to parse untrusted or unauthenticated data see
:ref:`xml-vulnerabilities`.
+.. versionchanged:: 3.6.7
+
+ The SAX parser no longer processes general external entities by default
+ to increase security. Before, the parser created network connections
+ to fetch remote files or loaded local files from the file
+ system for DTD and entities. The feature can be enabled again with method
+ :meth:`~xml.sax.xmlreader.XMLReader.setFeature` on the parser object
+ and argument :data:`~xml.sax.handler.feature_external_ges`.
The convenience functions are:
.. versionchanged:: 3.6
Added support of type tags with prefixes (e.g. ``ex:nil``).
- Added support of unmarsalling additional types used by Apache XML-RPC
+ Added support of unmarshalling additional types used by Apache XML-RPC
implementation for numerics: ``i1``, ``i2``, ``i8``, ``biginteger``,
``float`` and ``bigdecimal``.
See http://ws.apache.org/xmlrpc/types.html for a description.
if NOT "%PAPER%" == "" (\r
set SPHINXOPTS=-D latex_elements.papersize=%PAPER% %SPHINXOPTS%\r
)\r
+if "%1" EQU "htmlhelp" (\r
+ set SPHINXOPTS=-D html_theme_options.body_max_width=none %SPHINXOPTS%\r
+)\r
cmd /S /C "%SPHINXBUILD% %SPHINXOPTS% -b%1 -dbuild\doctrees . "%BUILDDIR%\%1" %2 %3 %4 %5 %6 %7 %8 %9"\r
\r
if "%1" EQU "htmlhelp" (\r
.. productionlist::
if_stmt: "if" `expression` ":" `suite`
- : ( "elif" `expression` ":" `suite` )*
+ : ("elif" `expression` ":" `suite`)*
: ["else" ":" `suite`]
It selects exactly one of the suites by evaluating the expressions one by one
single: mutable sequence; loop over
There is a subtlety when the sequence is being modified by the loop (this can
- only occur for mutable sequences, i.e. lists). An internal counter is used
+ only occur for mutable sequences, e.g. lists). An internal counter is used
to keep track of which item is used next, and this is incremented on each
iteration. When this counter has reached the length of the sequence the loop
terminates. This means that if the suite deletes the current (or a previous)
for a group of statements:
.. productionlist::
- try_stmt: try1_stmt | try2_stmt
+ try_stmt: `try1_stmt` | `try2_stmt`
try1_stmt: "try" ":" `suite`
: ("except" [`expression` ["as" `identifier`]] ":" `suite`)+
: ["else" ":" `suite`]
usage patterns to be encapsulated for convenient reuse.
.. productionlist::
- with_stmt: "with" with_item ("," with_item)* ":" `suite`
+ with_stmt: "with" `with_item` ("," `with_item`)* ":" `suite`
with_item: `expression` ["as" `target`]
The execution of the :keyword:`with` statement with one "item" proceeds as follows:
:ref:`types`):
.. productionlist::
- funcdef: [`decorators`] "def" `funcname` "(" [`parameter_list`] ")" ["->" `expression`] ":" `suite`
+ funcdef: [`decorators`] "def" `funcname` "(" [`parameter_list`] ")"
+ : ["->" `expression`] ":" `suite`
decorators: `decorator`+
decorator: "@" `dotted_name` ["(" [`argument_list` [","]] ")"] NEWLINE
dotted_name: `identifier` ("." `identifier`)*
parameter_list: `defparameter` ("," `defparameter`)* ["," [`parameter_list_starargs`]]
: | `parameter_list_starargs`
parameter_list_starargs: "*" [`parameter`] ("," `defparameter`)* ["," ["**" `parameter` [","]]]
- : | "**" `parameter` [","]
+ : | "**" `parameter` [","]
parameter: `identifier` [":" `expression`]
defparameter: `parameter` ["=" `expression`]
funcname: `identifier`
-----------------------------
.. productionlist::
- async_funcdef: [`decorators`] "async" "def" `funcname` "(" [`parameter_list`] ")" ["->" `expression`] ":" `suite`
+ async_funcdef: [`decorators`] "async" "def" `funcname` "(" [`parameter_list`] ")"
+ : ["->" `expression`] ":" `suite`
.. index::
keyword: async
value in the mapping that corresponds to that key. (The expression list is a
tuple except if it has exactly one item.)
-If the primary is a sequence, the expression (list) must evaluate to an integer
+If the primary is a sequence, the expression list must evaluate to an integer
or a slice (as discussed in the following section).
The formal syntax makes no special provision for negative indices in
less tightly than unary operators on its right. The syntax is:
.. productionlist::
- power: ( `await_expr` | `primary` ) ["**" `u_expr`]
+ power: (`await_expr` | `primary`) ["**" `u_expr`]
Thus, in an unparenthesized sequence of power and unary operators, the operators
are evaluated from right to left (this does not constrain the evaluation order
.. productionlist::
m_expr: `u_expr` | `m_expr` "*" `u_expr` | `m_expr` "@" `m_expr` |
- : `m_expr` "//" `u_expr`| `m_expr` "/" `u_expr` |
+ : `m_expr` "//" `u_expr` | `m_expr` "/" `u_expr` |
: `m_expr` "%" `u_expr`
a_expr: `m_expr` | `a_expr` "+" `m_expr` | `a_expr` "-" `m_expr`
common type and then multiplied together. In the latter case, sequence
repetition is performed; a negative repetition factor yields an empty sequence.
-.. index:: single: matrix multiplication
+.. index::
+ single: matrix multiplication
+ operator: @
The ``@`` (at) operator is intended to be used for matrix multiplication. No
builtin Python types implement this operator.
The shifting operations have lower priority than the arithmetic operations:
.. productionlist::
- shift_expr: `a_expr` | `shift_expr` ( "<<" | ">>" ) `a_expr`
+ shift_expr: `a_expr` | `shift_expr` ("<<" | ">>") `a_expr`
These operators accept integers as arguments. They shift the first argument to
the left or right by the number of bits given by the second argument.
in mathematics:
.. productionlist::
- comparison: `or_expr` ( `comp_operator` `or_expr` )*
+ comparison: `or_expr` (`comp_operator` `or_expr`)*
comp_operator: "<" | ">" | "==" | ">=" | "<=" | "!="
: | "is" ["not"] | ["not"] "in"
.. index:: pair: expression; list
.. productionlist::
- expression_list: `expression` ( "," `expression` )* [","]
- starred_list: `starred_item` ( "," `starred_item` )* [","]
- starred_expression: `expression` | ( `starred_item` "," )* [`starred_item`]
+ expression_list: `expression` ("," `expression`)* [","]
+ starred_list: `starred_item` ("," `starred_item`)* [","]
+ starred_expression: `expression` | (`starred_item` ",")* [`starred_item`]
starred_item: `expression` | "*" `or_expr`
.. index:: object: tuple
keyword: from
.. productionlist::
- import_stmt: "import" `module` ["as" `name`] ( "," `module` ["as" `name`] )*
- : | "from" `relative_module` "import" `identifier` ["as" `name`]
- : ( "," `identifier` ["as" `name`] )*
- : | "from" `relative_module` "import" "(" `identifier` ["as" `name`]
- : ( "," `identifier` ["as" `name`] )* [","] ")"
+ import_stmt: "import" `module` ["as" `identifier`] ("," `module` ["as" `identifier`])*
+ : | "from" `relative_module` "import" `identifier` ["as" `identifier`]
+ : ("," `identifier` ["as" `identifier`])*
+ : | "from" `relative_module` "import" "(" `identifier` ["as" `identifier`]
+ : ("," `identifier` ["as" `identifier`])* [","] ")"
: | "from" `module` "import" "*"
module: (`identifier` ".")* `identifier`
relative_module: "."* `module` | "."+
- name: `identifier`
The basic import statement (no :keyword:`from` clause) is executed in two
steps:
standard.
.. productionlist:: *
- future_statement: "from" "__future__" "import" feature ["as" name]
- : ("," feature ["as" name])*
- : | "from" "__future__" "import" "(" feature ["as" name]
- : ("," feature ["as" name])* [","] ")"
- feature: identifier
- name: identifier
+ future_stmt: "from" "__future__" "import" `feature` ["as" `identifier`]
+ : ("," `feature` ["as" `identifier`])*
+ : | "from" "__future__" "import" "(" `feature` ["as" `identifier`]
+ : ("," `feature` ["as" `identifier`])* [","] ")"
+ feature: `identifier`
A future statement must appear near the top of the module. The only lines that
can appear before a future statement are:
.. index::
single: UNIX
+ single: Windows
single: command line
single: standard input
-Under Unix, a complete program can be passed to the interpreter in three forms:
-with the :option:`-c` *string* command line option, as a file passed as the
-first command line argument, or as standard input. If the file or standard
-input is a tty device, the interpreter enters interactive mode; otherwise, it
-executes the file as a complete program.
+A complete program can be passed to the interpreter
+in three forms: with the :option:`-c` *string* command line option, as a file
+passed as the first command line argument, or as standard input. If the file
+or standard input is a tty device, the interpreter enters interactive mode;
+otherwise, it executes the file as a complete program.
.. _file-input:
--- /dev/null
+"""
+Escape the `body` part of .chm source file to 7-bit ASCII, to fix visual
+effect on some MBCS Windows systems.
+
+https://bugs.python.org/issue32174
+"""
+
+import re
+from html.entities import codepoint2name
+
+# escape the characters which codepoint > 0x7F
+def _process(string):
+ def escape(matchobj):
+ codepoint = ord(matchobj.group(0))
+
+ name = codepoint2name.get(codepoint)
+ if name is None:
+ return '&#%d;' % codepoint
+ else:
+ return '&%s;' % name
+
+ return re.sub(r'[^\x00-\x7F]', escape, string)
+
+def escape_for_chm(app, pagename, templatename, context, doctree):
+ # only works for .chm output
+ if not hasattr(app.builder, 'name') or app.builder.name != 'htmlhelp':
+ return
+
+ # escape the `body` part to 7-bit ASCII
+ body = context.get('body')
+ if body is not None:
+ context['body'] = _process(body)
+
+def setup(app):
+ # `html-page-context` event emitted when the HTML builder has
+ # created a context dictionary to render a template with.
+ app.connect('html-page-context', escape_for_chm)
+
+ return {'version': '1.0', 'parallel_read_safe': True}
the method's instance object before the first argument.
If you still don't understand how methods work, a look at the implementation can
-perhaps clarify matters. When an instance attribute is referenced that isn't a
-data attribute, its class is searched. If the name denotes a valid class
+perhaps clarify matters. When a non-data attribute of an instance is
+referenced, the instance's class is searched. If the name denotes a valid class
attribute that is a function object, a method object is created by packing
(pointers to) the instance object and the function object just found together in
an abstract object: this is the method object. When the method object is called
>>> f.read()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
- ValueError: I/O operation on closed file
+ ValueError: I/O operation on closed file.
.. _tut-filemethods:
"doesn't"
>>> "doesn't" # ...or use double quotes instead
"doesn't"
- >>> '"Yes," he said.'
- '"Yes," he said.'
- >>> "\"Yes,\" he said."
- '"Yes," he said.'
- >>> '"Isn\'t," she said.'
- '"Isn\'t," she said.'
+ >>> '"Yes," they said.'
+ '"Yes," they said.'
+ >>> "\"Yes,\" they said."
+ '"Yes," they said.'
+ >>> '"Isn\'t," they said.'
+ '"Isn\'t," they said.'
In the interactive interpreter, the output string is enclosed in quotes and
special characters are escaped with backslashes. While this might sometimes
readable output, by omitting the enclosing quotes and by printing escaped
and special characters::
- >>> '"Isn\'t," she said.'
- '"Isn\'t," she said.'
- >>> print('"Isn\'t," she said.')
- "Isn't," she said.
+ >>> '"Isn\'t," they said.'
+ '"Isn\'t," they said.'
+ >>> print('"Isn\'t," they said.')
+ "Isn't," they said.
>>> s = 'First line.\nSecond line.' # \n means newline
>>> s # without print(), \n is included in the output
'First line.\nSecond line.'
directory.
* There is more detail on this process, including a flow chart of the
- decisions, in PEP 3147.
+ decisions, in :pep:`3147`.
.. _tut-standardmodules:
| | ``.pyc``. | |
+---------------------------+--------------------------------------+--------------------------+
| PrependPath | Add install and Scripts directories | 0 |
-| | tho :envvar:`PATH` and ``.PY`` to | |
+| | to :envvar:`PATH` and ``.PY`` to | |
| | :envvar:`PATHEXT` | |
+---------------------------+--------------------------------------+--------------------------+
| Shortcuts | Create shortcuts for the interpreter,| 1 |
alongside the executable. This file specifies a list of options and values.
When a value is provided as an attribute, it will be converted to a number if
possible. Values provided as element text are always left as strings. This
-example file sets the same options and the previous example:
+example file sets the same options as the previous example:
.. code-block:: xml
Two .ini files will be searched by the launcher - ``py.ini`` in the current
user's "application data" directory (i.e. the directory returned by calling the
-Windows function SHGetFolderPath with CSIDL_LOCAL_APPDATA) and ``py.ini`` in the
+Windows function ``SHGetFolderPath`` with ``CSIDL_LOCAL_APPDATA``) and ``py.ini`` in the
same directory as the launcher. The same .ini files are used for both the
'console' version of the launcher (i.e. py.exe) and for the 'windows' version
(i.e. pyw.exe)
These will ensure that the files in a system-wide installation will not take
precedence over the copy of the standard library bundled with your application.
Otherwise, your users may experience problems using your application. Note that
-the first suggestion is the best, as the other may still be susceptible to
+the first suggestion is the best, as the others may still be susceptible to
non-standard paths in the registry and user site-packages.
.. versionchanged::
application. Running ``py`` follows the same version selection rules as
implicitly launching scripts, but a more specific version can be selected
by passing appropriate arguments (such as ``-3`` to request Python 3 when
-Python 2 is also installed, or ``-2.6`` to specifclly request an earlier
+Python 2 is also installed, or ``-2.6`` to specifically request an earlier
Python version when a more recent version is installed).
In addition to the launcher, the Windows installer now includes an
:class:`http.server.BaseHTTPRequestHandler` now buffers the headers and writes
them all at once when :meth:`~http.server.BaseHTTPRequestHandler.end_headers` is
called. A new method :meth:`~http.server.BaseHTTPRequestHandler.flush_headers`
-can be used to directly manage when the accumlated headers are sent.
+can be used to directly manage when the accumulated headers are sent.
(Contributed by Andrew Schaaf in :issue:`3709`.)
:class:`http.server` now produces valid ``HTML 4.01 strict`` output.
finder, you will need to remove keys paired with values of ``None`` **and**
:class:`imp.NullImporter` to be backwards-compatible. This will lead to extra
overhead on older versions of Python that re-insert ``None`` into
- :attr:`sys.path_importer_cache` where it repesents the use of implicit
+ :attr:`sys.path_importer_cache` where it represents the use of implicit
finders, but semantically it should not change anything.
* :class:`importlib.abc.Finder` no longer specifies a `find_module()` abstract
parameter to help control the ``opt-`` tag. Because of this, the
*debug_override* parameter of the function is now deprecated. `.pyo` files
are also no longer supported as a file argument to the Python interpreter and
- thus serve no purpose when distributed on their own (i.e. sourcless code
+ thus serve no purpose when distributed on their own (i.e. sourceless code
distribution). Due to the fact that the magic number for bytecode has changed
in Python 3.5, all old `.pyo` files from previous versions of Python are
invalid regardless of this PEP.
maxlines. Clicking on a context line jumps the editor to that line. Context
colors for custom themes is added to Highlights tab of Settings dialog.
(Contributed by Cheryl Sabella and Terry Jan Reedy in :issue:`33642`,
-:issue:`33768`, and :issue:`33679`)
+:issue:`33768`, and :issue:`33679`.)
On Windows, a new API call tells Windows that tk scales for DPI. On Windows
8.1+ or 10, with DPI compatibility properties of the Python binary
unchanged, and a monitor resolution greater than 96 DPI, this should
make text and lines sharper. It should otherwise have no effect.
-(Contributed by Terry Jan Reedy in :issue:`33656`).
+(Contributed by Terry Jan Reedy in :issue:`33656`.)
+
+New in 3.6.7:
+
+Output over N lines (50 by default) is squeezed down to a button.
+N can be changed in the PyShell section of the General page of the
+Settings dialog. Fewer, but possibly extra long, lines can be squeezed by
+right clicking on the output. Squeezed output can be expanded in place
+by double-clicking the button or into the clipboard or a separate window
+by right-clicking the button. (Contributed by Tal Einat in :issue:`1529353`.)
importlib
were added.
(Contributed by Christian Heimes in :issue:`28085`.)
+Added :attr:`SSLContext.post_handshake_auth` to enable and
+:meth:`ssl.SSLSocket.verify_client_post_handshake` to initiate TLS 1.3
+post-handshake authentication.
+(Contributed by Christian Heimes in :issue:`34670`.)
statistics
----------
For more information, see :pep:`7` and :issue:`17884`.
* Cross-compiling CPython with the Android NDK and the Android API level set to
- 21 (Android 5.0 Lollilop) or greater runs successfully. While Android is not
+ 21 (Android 5.0 Lollipop) or greater runs successfully. While Android is not
yet a supported platform, the Python test suite runs on the Android emulator
with only about 16 tests failures. See the Android meta-issue :issue:`26865`.
environment. (Contributed by Brett Cannon in :issue:`25154`.)
+xml
+---
+
+* As mitigation against DTD and external entity retrieval, the
+ :mod:`xml.dom.minidom` and mod:`xml.sax` modules no longer process
+ external entities by default.
+ (Contributed by Christian Heimes in :issue:`17239`.)
+
+
Deprecated functions and types of the C API
-------------------------------------------
* The functions in the :mod:`compileall` module now return booleans instead
of ``1`` or ``0`` to represent success or failure, respectively. Thanks to
- booleans being a subclass of integers, this should only be an issue if you
+ booleans being a subclass of integers, this should only be an issue if you7
were doing identity checks for ``1`` or ``0``. See :issue:`25768`.
* Reading the :attr:`~urllib.parse.SplitResult.port` attribute of
The :func:`locale.localeconv` function now sets temporarily the ``LC_CTYPE``
locale to the ``LC_NUMERIC`` locale in some cases.
(Contributed by Victor Stinner in :issue:`31900`.)
+
+
+Notable changes in Python 3.6.7
+===============================
+
+:mod:`xml.dom.minidom` and mod:`xml.sax` modules no longer process
+external entities by default. See also :issue:`17239`.
/*--start constants--*/
#define PY_MAJOR_VERSION 3
#define PY_MINOR_VERSION 6
-#define PY_MICRO_VERSION 6
+#define PY_MICRO_VERSION 7
#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL
#define PY_RELEASE_SERIAL 0
/* Version as a string */
-#define PY_VERSION "3.6.6"
+#define PY_VERSION "3.6.7"
/*--end constants--*/
/* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2.
/* note: you must import expat.h before importing this module! */
-#define PyExpat_CAPI_MAGIC "pyexpat.expat_CAPI 1.0"
+#define PyExpat_CAPI_MAGIC "pyexpat.expat_CAPI 1.1"
#define PyExpat_CAPSULE_NAME "pyexpat.expat_CAPI"
struct PyExpat_CAPI
enum XML_Status (*SetEncoding)(XML_Parser parser, const XML_Char *encoding);
int (*DefaultUnknownEncodingHandler)(
void *encodingHandlerData, const XML_Char *name, XML_Encoding *info);
+ /* might be none for expat < 2.1.0 */
+ int (*SetHashSalt)(XML_Parser parser, unsigned long hash_salt);
/* always add new stuff to the end! */
};
self.buffer.write(b)
if self._line_buffering and (haslf or "\r" in s):
self.flush()
+ self._set_decoded_chars('')
self._snapshot = None
if self._decoder:
self._decoder.reset()
37.857713 -122.544543
'''
- # http://xkcd.com/426/
+ # https://xkcd.com/426/
h = hashlib.md5(datedow).hexdigest()
p, q = [('%f' % float.fromhex('0.' + x)) for x in (h[:16], h[16:32])]
print('%d%s %d%s' % (latitude, p[1:], longitude, q[1:]))
_FATAL_ERROR_IGNORE = (BrokenPipeError,
ConnectionResetError, ConnectionAbortedError)
+_HAS_IPv6 = hasattr(socket, 'AF_INET6')
+
+# Maximum timeout passed to select to avoid OS limitations
+MAXIMUM_SELECT_TIMEOUT = 24 * 3600
+
def _format_handle(handle):
cb = handle._callback
if family == socket.AF_UNSPEC:
afs = [socket.AF_INET]
- if hasattr(socket, 'AF_INET6'):
+ if _HAS_IPv6:
afs.append(socket.AF_INET6)
else:
afs = [family]
try:
socket.inet_pton(af, host)
# The host has already been resolved.
- return af, type, proto, '', (host, port)
+ if _HAS_IPv6 and af == socket.AF_INET6:
+ return af, type, proto, '', (host, port, 0, 0)
+ else:
+ return af, type, proto, '', (host, port)
except OSError:
pass
def _asyncgen_finalizer_hook(self, agen):
self._asyncgens.discard(agen)
if not self.is_closed():
- self.create_task(agen.aclose())
- # Wake up the loop if the finalizer was called from
- # a different thread.
- self._write_to_self()
+ self.call_soon_threadsafe(self.create_task, agen.aclose())
def _asyncgen_firstiter_hook(self, agen):
if self._asyncgens_shutdown_called:
raise ValueError(
'host/port and sock can not be specified at the same time')
- AF_INET6 = getattr(socket, 'AF_INET6', 0)
if reuse_address is None:
reuse_address = os.name == 'posix' and sys.platform != 'cygwin'
sockets = []
# Disable IPv4/IPv6 dual stack support (enabled by
# default on Linux) which makes a single socket
# listen on both address families.
- if af == AF_INET6 and hasattr(socket, 'IPPROTO_IPV6'):
+ if (_HAS_IPv6 and
+ af == socket.AF_INET6 and
+ hasattr(socket, 'IPPROTO_IPV6')):
sock.setsockopt(socket.IPPROTO_IPV6,
socket.IPV6_V6ONLY,
True)
elif self._scheduled:
# Compute the desired timeout.
when = self._scheduled[0]._when
- timeout = max(0, when - self.time())
+ timeout = min(max(0, when - self.time()), MAXIMUM_SELECT_TIMEOUT)
if self._debug and timeout != 0:
t0 = self.time()
self._loop.call_soon(self._loop_reading)
def pause_reading(self):
- if self._closing:
- raise RuntimeError('Cannot pause_reading() when closing')
- if self._paused:
- raise RuntimeError('Already paused')
+ if self._closing or self._paused:
+ return
self._paused = True
if self._loop.get_debug():
logger.debug("%r pauses reading", self)
def resume_reading(self):
- if not self._paused:
- raise RuntimeError('Not paused')
- self._paused = False
- if self._closing:
+ if self._closing or not self._paused:
return
+ self._paused = False
if self._reschedule_on_resume:
self._loop.call_soon(self._loop_reading, self._read_fut)
self._reschedule_on_resume = False
waiter, None)
def pause_reading(self):
- if self._closing:
- raise RuntimeError('Cannot pause_reading() when closing')
- if self._paused:
- raise RuntimeError('Already paused')
+ if self._closing or self._paused:
+ return
self._paused = True
self._loop._remove_reader(self._sock_fd)
if self._loop.get_debug():
logger.debug("%r pauses reading", self)
def resume_reading(self):
- if not self._paused:
- raise RuntimeError('Not paused')
+ if self._closing or not self._paused:
+ return
self._paused = False
self._add_reader(self._sock_fd, self._read_ready)
if self._loop.get_debug():
return False
def assert_reader(self, fd, callback, *args):
- assert fd in self.readers, 'fd {} is not registered'.format(fd)
+ if fd not in self.readers:
+ raise AssertionError(f'fd {fd} is not registered')
handle = self.readers[fd]
- assert handle._callback == callback, '{!r} != {!r}'.format(
- handle._callback, callback)
- assert handle._args == args, '{!r} != {!r}'.format(
- handle._args, args)
+ if handle._callback != callback:
+ raise AssertionError(
+ f'unexpected callback: {handle._callback} != {callback}')
+ if handle._args != args:
+ raise AssertionError(
+ f'unexpected callback args: {handle._args} != {args}')
+
+ def assert_no_reader(self, fd):
+ if fd in self.readers:
+ raise AssertionError(f'fd {fd} is registered')
def _add_writer(self, fd, callback, *args):
self.writers[fd] = events.Handle(callback, args, self)
raise binascii.Error('Non-base32 digit found') from None
decoded += acc.to_bytes(5, 'big')
# Process the last, partial quanta
- if padchars:
+ if l % 8 or padchars not in {0, 1, 3, 4, 6}:
+ raise binascii.Error('Incorrect padding')
+ if padchars and decoded:
acc <<= 5 * padchars
last = acc.to_bytes(5, 'big')
- if padchars == 1:
- decoded[-5:] = last[:-1]
- elif padchars == 3:
- decoded[-5:] = last[:-2]
- elif padchars == 4:
- decoded[-5:] = last[:-3]
- elif padchars == 6:
- decoded[-5:] = last[:-4]
- else:
- raise binascii.Error('Incorrect padding')
+ leftover = (43 - 5 * padchars) // 8 # 1: 4, 3: 3, 4: 2, 6: 1
+ decoded[-5:] = last[:leftover]
return bytes(decoded)
-
# RFC 3548, Base 16 Alphabet specifies uppercase, but hexlify() returns
# lowercase. The RFC also recommends against accepting input case
# insensitively.
# ____________________________________________________________
class Profile(_lsprof.Profiler):
- """Profile(custom_timer=None, time_unit=None, subcalls=True, builtins=True)
+ """Profile(timer=None, timeunit=None, subcalls=True, builtins=True)
Builds a profiler object using the specified timer function.
The default timer is a fast built-in one based on real time.
- For custom timer functions returning integers, time_unit can
+ For custom timer functions returning integers, timeunit can
be a float specifying a scale (i.e. how long each integer unit
is, in seconds).
"""
before the given timeout.
"""
if timeout is not None:
- end_time = timeout + time.time()
+ end_time = timeout + time.monotonic()
fs = set(fs)
total_futures = len(fs)
if timeout is None:
wait_timeout = None
else:
- wait_timeout = end_time - time.time()
+ wait_timeout = end_time - time.monotonic()
if wait_timeout < 0:
raise TimeoutError(
'%d (of %d) futures unfinished' % (
Exception: If fn(*args) raises for any values.
"""
if timeout is not None:
- end_time = timeout + time.time()
+ end_time = timeout + time.monotonic()
fs = [self.submit(fn, *args) for args in zip(*iterables)]
if timeout is None:
yield fs.pop().result()
else:
- yield fs.pop().result(end_time - time.time())
+ yield fs.pop().result(end_time - time.monotonic())
finally:
for future in fs:
future.cancel()
Return list of configuration options for the named section.
read(filenames, encoding=None)
- Read and parse the list of named configuration files, given by
+ Read and parse the iterable of named configuration files, given by
name. A single filename is also allowed. Non-existing files
are ignored. Return list of successfully read files.
return list(opts.keys())
def read(self, filenames, encoding=None):
- """Read and parse a filename or a list of filenames.
+ """Read and parse a filename or an iterable of filenames.
Files that cannot be opened are silently ignored; this is
- designed so that you can specify a list of potential
+ designed so that you can specify an iterable of potential
configuration file locations (e.g. current directory, user's
home directory, systemwide directory), and all existing
- configuration files in the list will be read. A single
+ configuration files in the iterable will be read. A single
filename may also be given.
Return list of successfully read files.
f.argtypes = [c_byte, c_wchar, c_int, c_long, c_float, c_double]
result = f(self.wrap(1), self.wrap("x"), self.wrap(3), self.wrap(4), self.wrap(5.0), self.wrap(6.0))
self.assertEqual(result, 139)
- self.assertTrue(type(result), int)
+ self.assertIs(type(result), int)
def test_pointers(self):
f = dll._testfunc_p_p
windll.user32.GetDesktopWindow()
+@unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
+class ReturnStructSizesTestCase(unittest.TestCase):
+ def test_sizes(self):
+ dll = CDLL(_ctypes_test.__file__)
+ for i in range(1, 11):
+ fields = [ (f"f{f}", c_char) for f in range(1, i + 1)]
+ class S(Structure):
+ _fields_ = fields
+ f = getattr(dll, f"TestSize{i}")
+ f.restype = S
+ res = f()
+ for i, f in enumerate(fields):
+ value = getattr(res, f[0])
+ expected = bytes([ord('a') + i])
+ self.assertEqual(value, expected)
+
+
+
@unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
class TestWintypes(unittest.TestCase):
def test_HWND(self):
import time as _time
import math as _math
+import sys
def _cmp(x, y):
return 0 if x == y else 1 if x > y else -1
# 23 hours at 1969-09-30 13:00:00 in Kwajalein.
# Let's probe 24 hours in the past to detect a transition:
max_fold_seconds = 24 * 3600
+
+ # On Windows localtime_s throws an OSError for negative values,
+ # thus we can't perform fold detection for values of time less
+ # than the max time fold. See comments in _datetimemodule's
+ # version of this method for more details.
+ if t < max_fold_seconds and sys.platform.startswith("win"):
+ return result
+
y, m, d, hh, mm, ss = converter(t - max_fold_seconds)[:6]
probe1 = cls(y, m, d, hh, mm, ss, us, tz)
trans = result - probe1 - timedelta(0, max_fold_seconds)
for dir in vc_env.get('include', '').split(os.pathsep):
if dir:
- self.add_include_dir(dir)
+ self.add_include_dir(dir.rstrip(os.sep))
for dir in vc_env.get('lib', '').split(os.pathsep):
if dir:
- self.add_library_dir(dir)
+ self.add_library_dir(dir.rstrip(os.sep))
self.preprocess_options = None
# If vcruntime_redist is available, link against it dynamically. Otherwise,
stream = sys.stderr
else:
stream = sys.stdout
- if stream.errors == 'strict':
+ try:
+ stream.write('%s\n' % msg)
+ except UnicodeEncodeError:
# emulate backslashreplace error handler
encoding = stream.encoding
msg = msg.encode(encoding, "backslashreplace").decode(encoding)
- stream.write('%s\n' % msg)
+ stream.write('%s\n' % msg)
stream.flush()
def log(self, level, msg, *args):
os.environ['PATH']. Returns the complete filename or None if not found.
"""
if path is None:
- path = os.environ['PATH']
+ path = os.environ.get('PATH', os.defpath)
paths = path.split(os.pathsep)
base, ext = os.path.splitext(executable)
for name in names:
subcmd = cmd.get_finalized_command(name)
+ if getattr(subcmd, '_unsupported', False):
+ # command is not supported on this build
+ continue
self.assertTrue(subcmd.skip_build,
'%s should take --skip-build from bdist' % name)
from distutils.command.bdist_wininst import bdist_wininst
from distutils.tests import support
+@unittest.skipIf(getattr(bdist_wininst, '_unsupported', False),
+ 'bdist_wininst is not supported in this install')
class BuildWinInstTestCase(support.TempdirManager,
support.LoggingSilencer,
unittest.TestCase):
"""Tests for distutils.log"""
+import io
import sys
import unittest
-from tempfile import NamedTemporaryFile
-from test.support import run_unittest
+from test.support import swap_attr, run_unittest
from distutils import log
class TestLog(unittest.TestCase):
def test_non_ascii(self):
- # Issue #8663: test that non-ASCII text is escaped with
- # backslashreplace error handler (stream use ASCII encoding and strict
- # error handler)
- old_stdout = sys.stdout
- old_stderr = sys.stderr
- old_threshold = log.set_threshold(log.DEBUG)
- try:
- with NamedTemporaryFile(mode="w+", encoding='ascii') as stdout, \
- NamedTemporaryFile(mode="w+", encoding='ascii') as stderr:
- sys.stdout = stdout
- sys.stderr = stderr
- log.debug("debug:\xe9")
- log.fatal("fatal:\xe9")
+ # Issues #8663, #34421: test that non-encodable text is escaped with
+ # backslashreplace error handler and encodable non-ASCII text is
+ # output as is.
+ for errors in ('strict', 'backslashreplace', 'surrogateescape',
+ 'replace', 'ignore'):
+ with self.subTest(errors=errors):
+ stdout = io.TextIOWrapper(io.BytesIO(),
+ encoding='cp437', errors=errors)
+ stderr = io.TextIOWrapper(io.BytesIO(),
+ encoding='cp437', errors=errors)
+ old_threshold = log.set_threshold(log.DEBUG)
+ try:
+ with swap_attr(sys, 'stdout', stdout), \
+ swap_attr(sys, 'stderr', stderr):
+ log.debug('Dεbug\tMėssãge')
+ log.fatal('Fαtal\tÈrrōr')
+ finally:
+ log.set_threshold(old_threshold)
+
stdout.seek(0)
- self.assertEqual(stdout.read().rstrip(), "debug:\\xe9")
+ self.assertEqual(stdout.read().rstrip(),
+ 'Dεbug\tM?ss?ge' if errors == 'replace' else
+ 'Dεbug\tMssge' if errors == 'ignore' else
+ 'Dεbug\tM\\u0117ss\\xe3ge')
stderr.seek(0)
- self.assertEqual(stderr.read().rstrip(), "fatal:\\xe9")
- finally:
- log.set_threshold(old_threshold)
- sys.stdout = old_stdout
- sys.stderr = old_stderr
+ self.assertEqual(stderr.read().rstrip(),
+ 'Fαtal\t?rr?r' if errors == 'replace' else
+ 'Fαtal\trrr' if errors == 'ignore' else
+ 'Fαtal\t\\xc8rr\\u014dr')
def test_suite():
return unittest.makeSuite(TestLog)
"""Tests for distutils.spawn."""
-import unittest
-import sys
import os
+import stat
+import sys
+import unittest
+from unittest import mock
from test.support import run_unittest, unix_shell
+from test import support as test_support
+from distutils.spawn import find_executable
from distutils.spawn import _nt_quote_args
from distutils.spawn import spawn
from distutils.errors import DistutilsExecError
os.chmod(exe, 0o777)
spawn([exe]) # should work without any error
+ def test_find_executable(self):
+ with test_support.temp_dir() as tmp_dir:
+ # use TESTFN to get a pseudo-unique filename
+ program_noeext = test_support.TESTFN
+ # Give the temporary program an ".exe" suffix for all.
+ # It's needed on Windows and not harmful on other platforms.
+ program = program_noeext + ".exe"
+
+ filename = os.path.join(tmp_dir, program)
+ with open(filename, "wb"):
+ pass
+ os.chmod(filename, stat.S_IXUSR)
+
+ # test path parameter
+ rv = find_executable(program, path=tmp_dir)
+ self.assertEqual(rv, filename)
+
+ if sys.platform == 'win32':
+ # test without ".exe" extension
+ rv = find_executable(program_noeext, path=tmp_dir)
+ self.assertEqual(rv, filename)
+
+ # test find in the current directory
+ with test_support.change_cwd(tmp_dir):
+ rv = find_executable(program)
+ self.assertEqual(rv, program)
+
+ # test non-existent program
+ dont_exist_program = "dontexist_" + program
+ rv = find_executable(dont_exist_program , path=tmp_dir)
+ self.assertIsNone(rv)
+
+ # test os.defpath: missing PATH environment variable
+ with test_support.EnvironmentVarGuard() as env:
+ with mock.patch('distutils.spawn.os.defpath', tmp_dir):
+ env.pop('PATH')
+
+ rv = find_executable(program)
+ self.assertEqual(rv, filename)
+
+
def test_suite():
return unittest.makeSuite(SpawnTestCase)
#
def decode_b(encoded):
- defects = []
+ # First try encoding with validate=True, fixing the padding if needed.
+ # This will succeed only if encoded includes no invalid characters.
pad_err = len(encoded) % 4
- if pad_err:
- defects.append(errors.InvalidBase64PaddingDefect())
- padded_encoded = encoded + b'==='[:4-pad_err]
- else:
- padded_encoded = encoded
+ missing_padding = b'==='[:4-pad_err] if pad_err else b''
try:
- return base64.b64decode(padded_encoded, validate=True), defects
+ return (
+ base64.b64decode(encoded + missing_padding, validate=True),
+ [errors.InvalidBase64PaddingDefect()] if pad_err else [],
+ )
except binascii.Error:
- # Since we had correct padding, this must an invalid char error.
- defects = [errors.InvalidBase64CharactersDefect()]
+ # Since we had correct padding, this is likely an invalid char error.
+ #
# The non-alphabet characters are ignored as far as padding
- # goes, but we don't know how many there are. So we'll just
- # try various padding lengths until something works.
- for i in 0, 1, 2, 3:
+ # goes, but we don't know how many there are. So try without adding
+ # padding to see if it works.
+ try:
+ return (
+ base64.b64decode(encoded, validate=False),
+ [errors.InvalidBase64CharactersDefect()],
+ )
+ except binascii.Error:
+ # Add as much padding as could possibly be necessary (extra padding
+ # is ignored).
try:
- return base64.b64decode(encoded+b'='*i, validate=False), defects
+ return (
+ base64.b64decode(encoded + b'==', validate=False),
+ [errors.InvalidBase64CharactersDefect(),
+ errors.InvalidBase64PaddingDefect()],
+ )
except binascii.Error:
- if i==0:
- defects.append(errors.InvalidBase64PaddingDefect())
- else:
- # This should never happen.
- raise AssertionError("unexpected binascii.Error")
+ # This only happens when the encoded string's length is 1 more
+ # than a multiple of 4, which is invalid.
+ #
+ # bpo-27397: Just return the encoded string since there's no
+ # way to decode.
+ return encoded, [errors.InvalidBase64LengthDefect()]
def encode_b(bstring):
return base64.b64encode(bstring).decode('ascii')
if not value:
group.defects.append(errors.InvalidHeaderDefect(
"end of header in group"))
- if value[0] != ';':
+ elif value[0] != ';':
raise errors.HeaderParseError(
"expected ';' at end of group but found {}".format(value))
group.append(ValueTerminal(';', 'group-terminator'))
class InvalidBase64CharactersDefect(MessageDefect):
"""base64 encoded sequence had characters not in base64 alphabet"""
+class InvalidBase64LengthDefect(MessageDefect):
+ """base64 encoded sequence had invalid length (1 mod 4)"""
+
# These errors are specific to header parsing.
class HeaderDefect(MessageDefect):
enum_class._member_map_ = OrderedDict() # name->value map
enum_class._member_type_ = member_type
- # save attributes from super classes so we know if we can take
- # the shortcut of storing members in the class dict
- base_attributes = {a for b in enum_class.mro() for a in b.__dict__}
+ # save DynamicClassAttribute attributes from super classes so we know
+ # if we can take the shortcut of storing members in the class dict
+ dynamic_attributes = {k for c in enum_class.mro()
+ for k, v in c.__dict__.items()
+ if isinstance(v, DynamicClassAttribute)}
# Reverse value->name map for hashable values.
enum_class._value2member_map_ = {}
enum_class._member_names_.append(member_name)
# performance boost for any member that would not shadow
# a DynamicClassAttribute
- if member_name not in base_attributes:
+ if member_name not in dynamic_attributes:
setattr(enum_class, member_name, enum_member)
# now add to _member_map_
enum_class._member_map_[member_name] = enum_member
return func
def wrapper(*args, **kw):
+ if not args:
+ raise TypeError(f'{funcname} requires at least '
+ '1 positional argument')
+
return dispatch(args[0].__class__)(*args, **kw)
+ funcname = getattr(func, '__name__', 'singledispatch function')
registry[object] = func
wrapper.register = register
wrapper.dispatch = dispatch
sha384 and sha512 will be slow on 32 bit platforms.
Hash objects have these methods:
- - update(arg): Update the hash object with the bytes in arg. Repeated calls
- are equivalent to a single call with the concatenation of all
- the arguments.
- - digest(): Return the digest of the bytes passed to the update() method
- so far.
- - hexdigest(): Like digest() except the digest is returned as a unicode
- object of double length, containing only hexadecimal digits.
- - copy(): Return a copy (clone) of the hash object. This can be used to
- efficiently compute the digests of strings that share a common
- initial substring.
-
-For example, to obtain the digest of the string 'Nobody inspects the
+ - update(data): Update the hash object with the bytes in data. Repeated calls
+ are equivalent to a single call with the concatenation of all
+ the arguments.
+ - digest(): Return the digest of the bytes passed to the update() method
+ so far as a bytes object.
+ - hexdigest(): Like digest() except the digest is returned as a string
+ of double length, containing only hexadecimal digits.
+ - copy(): Return a copy (clone) of the hash object. This can be used to
+ efficiently compute the digests of datas that share a common
+ initial substring.
+
+For example, to obtain the digest of the byte string 'Nobody inspects the
spammish repetition':
>>> import hashlib
def __py_new(name, data=b'', **kwargs):
"""new(name, data=b'', **kwargs) - Return a new hashing object using the
- named algorithm; optionally initialized with data (which must be bytes).
+ named algorithm; optionally initialized with data (which must be
+ a bytes-like object).
"""
return __get_builtin_constructor(name)(data, **kwargs)
def __hash_new(name, data=b'', **kwargs):
"""new(name, data=b'') - Return a new hashing object using the named algorithm;
- optionally initialized with data (which must be bytes).
+ optionally initialized with data (which must be a bytes-like object).
"""
if name in {'blake2b', 'blake2s'}:
# Prefer our blake2 implementation.
if self.debuglevel > 0:
for hdr in self.headers:
- print("header:", hdr, end=" ")
+ print("header:", hdr + ":", self.headers.get(hdr))
# are we using the chunked-style of transfer encoding?
tr_enc = self.headers.get("transfer-encoding")
})
body = content.encode('UTF-8', 'replace')
self.send_header("Content-Type", self.error_content_type)
- self.send_header('Content-Length', int(len(body)))
+ self.send_header('Content-Length', str(len(body)))
self.end_headers()
if self.command != 'HEAD' and body:
-What's New in IDLE 3.6.6
-Released on 2018-06-15?
+What's New in IDLE 3.6.7
+Released on 2018-09-24?
======================================
+bpo-1529353: Output over N lines (50 by default) is squeezed down to a button.
+N can be changed in the PyShell section of the General page of the
+Settings dialog. Fewer, but possibly extra long, lines can be squeezed by
+right clicking on the output. Squeezed output can be expanded in place
+by double-clicking the button or into the clipboard or a separate window
+by right-clicking the button.
+
+bpo-34548: Use configured color theme for read-only text views.
+
+bpo-33839: Refactor ToolTip and CallTip classes; add documentation
+and tests.
+
+bpo-34047: Fix mouse wheel scrolling direction on macOS.
+
+bpo-34275: Make calltips always visible on Mac.
+Patch by Kevin Walzer.
+
+bpo-34120: Fix freezing after closing some dialogs on Mac.
+This is one of multiple regressions from using newer tcl/tk.
+
+bpo-33975: Avoid small type when running htests.
+Since part of the purpose of human-viewed tests is to determine that
+widgets look right, it is important that they look the same for
+testing as when running IDLE.
+
+bpo-33905: Add test for idlelib.stackview.StackBrowser.
+
+bpo-33924: Change mainmenu.menudefs key 'windows' to 'window'.
+Every other menudef key is the lowercase version of the
+corresponding main menu entry (in this case, 'Window').
+
+bpo-33906: Rename idlelib.windows as window
+Match Window on the main menu and remove last plural module name.
+Change imports, test, and attribute references to match new name.
+
+bpo-33917: Fix and document idlelib/idle_test/template.py.
+The revised file compiles, runs, and tests OK. idle_test/README.txt
+explains how to use it to create new IDLE test files.
+
+bpo-33904: In rstrip module, rename class RstripExtension as Rstrip.
+
+bpo-33907: For consistency and clarity, rename calltip objects.
+Module calltips and its class CallTips are now calltip and Calltip.
+In module calltip_w, class CallTip is now CalltipWindow.
+
+bpo-33855: Minimally test all IDLE modules.
+Standardize the test file format. Add missing test files that import
+the tested module and perform at least one test. Check and record the
+coverage of each test.
+
+bpo-33856: Add 'help' to Shell's initial welcome message.
+
+
+What's New in IDLE 3.6.6
+Released on 2018-06-27
+======================================
+
bpo-33656: On Windows, add API call saying that tk scales for DPI.
On Windows 8.1+ or 10, with DPI compatibility properties of the Python
binary unchanged, and a monitor resolution greater than 96 DPI, this
bpo-31421: Document how IDLE runs tkinter programs.
IDLE calls tcl/tk update in the background in order to make live
-interaction and experimentatin with tkinter applications much easier.
+interaction and experimentation with tkinter applications much easier.
bpo-31414: Fix tk entry box tests by deleting first.
Adding to an int entry is not the same as deleting and inserting
-w option but without -jn. Fix warning from test_config.
- Issue #27621: Put query response validation error messages in the query
- box itself instead of in a separate massagebox. Redo tests to match.
+ box itself instead of in a separate messagebox. Redo tests to match.
Add Mac OSX refinements. Original patch by Mark Roseman.
- Issue #27620: Escape key now closes Query box as cancelled.
- Issue #27239: idlelib.macosx.isXyzTk functions initialize as needed.
-- Issue #27262: move Aqua unbinding code, which enable context menus, to maxosx.
+- Issue #27262: move Aqua unbinding code, which enable context menus, to macosx.
- Issue #24759: Make clear in idlelib.idle_test.__init__ that the directory
is a private implementation of test.test_idle and tool for maintainers.
AutoComplete.reload()
-
if __name__ == '__main__':
from unittest import main
main('idlelib.idle_test.test_autocomplete', verbosity=2)
acw.wm_geometry("+%d+%d" % (new_x, new_y))
if platform.system().startswith('Windows'):
- # See issue 15786. When on windows platform, Tk will misbehave
+ # See issue 15786. When on Windows platform, Tk will misbehave
# to call winconfig_event multiple times, we need to prevent this,
# otherwise mouse button double click will not be able to used.
acw.unbind(WINCONFIG_SEQUENCE, self.winconfigid)
# mouse click on widget / text area.
if self.is_active():
if event.type == EventType.FocusOut:
- # On windows platform, it will need to delay the check for
+ # On Windows platform, it will need to delay the check for
# acw.focus_get() when click on acw, otherwise it will return
# None and close the window
self.widget.after(1, self._hide_event_check)
self.listbox = None
self.autocompletewindow.destroy()
self.autocompletewindow = None
+
+
+if __name__ == '__main__':
+ from unittest import main
+ main('idlelib.idle_test.test_autocomplete_w', verbosity=2, exit=False)
+
+# TODO: autocomplete/w htest here
if __name__ == '__main__':
- import unittest
- unittest.main('idlelib.idle_test.test_autoexpand', verbosity=2)
+ from unittest import main
+ main('idlelib.idle_test.test_autoexpand', verbosity=2)
from idlelib.config import idleConf
from idlelib import pyshell
from idlelib.tree import TreeNode, TreeItem, ScrolledCanvas
-from idlelib.windows import ListedToplevel
+from idlelib.window import ListedToplevel
file_open = None # Method...Item and Class...Item use this.
--- /dev/null
+"""Pop up a reminder of how to call a function.
+
+Call Tips are floating windows which display function, class, and method
+parameter and docstring information when you type an opening parenthesis, and
+which disappear when you type a closing parenthesis.
+"""
+import inspect
+import re
+import sys
+import textwrap
+import types
+
+from idlelib import calltip_w
+from idlelib.hyperparser import HyperParser
+import __main__
+
+
+class Calltip:
+
+ def __init__(self, editwin=None):
+ if editwin is None: # subprocess and test
+ self.editwin = None
+ else:
+ self.editwin = editwin
+ self.text = editwin.text
+ self.active_calltip = None
+ self._calltip_window = self._make_tk_calltip_window
+
+ def close(self):
+ self._calltip_window = None
+
+ def _make_tk_calltip_window(self):
+ # See __init__ for usage
+ return calltip_w.CalltipWindow(self.text)
+
+ def _remove_calltip_window(self, event=None):
+ if self.active_calltip:
+ self.active_calltip.hidetip()
+ self.active_calltip = None
+
+ def force_open_calltip_event(self, event):
+ "The user selected the menu entry or hotkey, open the tip."
+ self.open_calltip(True)
+ return "break"
+
+ def try_open_calltip_event(self, event):
+ """Happens when it would be nice to open a calltip, but not really
+ necessary, for example after an opening bracket, so function calls
+ won't be made.
+ """
+ self.open_calltip(False)
+
+ def refresh_calltip_event(self, event):
+ if self.active_calltip and self.active_calltip.tipwindow:
+ self.open_calltip(False)
+
+ def open_calltip(self, evalfuncs):
+ self._remove_calltip_window()
+
+ hp = HyperParser(self.editwin, "insert")
+ sur_paren = hp.get_surrounding_brackets('(')
+ if not sur_paren:
+ return
+ hp.set_index(sur_paren[0])
+ expression = hp.get_expression()
+ if not expression:
+ return
+ if not evalfuncs and (expression.find('(') != -1):
+ return
+ argspec = self.fetch_tip(expression)
+ if not argspec:
+ return
+ self.active_calltip = self._calltip_window()
+ self.active_calltip.showtip(argspec, sur_paren[0], sur_paren[1])
+
+ def fetch_tip(self, expression):
+ """Return the argument list and docstring of a function or class.
+
+ If there is a Python subprocess, get the calltip there. Otherwise,
+ either this fetch_tip() is running in the subprocess or it was
+ called in an IDLE running without the subprocess.
+
+ The subprocess environment is that of the most recently run script. If
+ two unrelated modules are being edited some calltips in the current
+ module may be inoperative if the module was not the last to run.
+
+ To find methods, fetch_tip must be fed a fully qualified name.
+
+ """
+ try:
+ rpcclt = self.editwin.flist.pyshell.interp.rpcclt
+ except AttributeError:
+ rpcclt = None
+ if rpcclt:
+ return rpcclt.remotecall("exec", "get_the_calltip",
+ (expression,), {})
+ else:
+ return get_argspec(get_entity(expression))
+
+
+def get_entity(expression):
+ """Return the object corresponding to expression evaluated
+ in a namespace spanning sys.modules and __main.dict__.
+ """
+ if expression:
+ namespace = sys.modules.copy()
+ namespace.update(__main__.__dict__)
+ try:
+ return eval(expression, namespace)
+ except BaseException:
+ # An uncaught exception closes idle, and eval can raise any
+ # exception, especially if user classes are involved.
+ return None
+
+# The following are used in get_argspec and some in tests
+_MAX_COLS = 85
+_MAX_LINES = 5 # enough for bytes
+_INDENT = ' '*4 # for wrapped signatures
+_first_param = re.compile(r'(?<=\()\w*\,?\s*')
+_default_callable_argspec = "See source or doc"
+_invalid_method = "invalid method signature"
+_argument_positional = "\n['/' marks preceding arguments as positional-only]\n"
+
+def get_argspec(ob):
+ '''Return a string describing the signature of a callable object, or ''.
+
+ For Python-coded functions and methods, the first line is introspected.
+ Delete 'self' parameter for classes (.__init__) and bound methods.
+ The next lines are the first lines of the doc string up to the first
+ empty line or _MAX_LINES. For builtins, this typically includes
+ the arguments in addition to the return value.
+ '''
+ argspec = default = ""
+ try:
+ ob_call = ob.__call__
+ except BaseException:
+ return default
+
+ fob = ob_call if isinstance(ob_call, types.MethodType) else ob
+
+ try:
+ argspec = str(inspect.signature(fob))
+ except ValueError as err:
+ msg = str(err)
+ if msg.startswith(_invalid_method):
+ return _invalid_method
+
+ if '/' in argspec:
+ """Using AC's positional argument should add the explain"""
+ argspec += _argument_positional
+ if isinstance(fob, type) and argspec == '()':
+ """fob with no argument, use default callable argspec"""
+ argspec = _default_callable_argspec
+
+ lines = (textwrap.wrap(argspec, _MAX_COLS, subsequent_indent=_INDENT)
+ if len(argspec) > _MAX_COLS else [argspec] if argspec else [])
+
+ if isinstance(ob_call, types.MethodType):
+ doc = ob_call.__doc__
+ else:
+ doc = getattr(ob, "__doc__", "")
+ if doc:
+ for line in doc.split('\n', _MAX_LINES)[:_MAX_LINES]:
+ line = line.strip()
+ if not line:
+ break
+ if len(line) > _MAX_COLS:
+ line = line[: _MAX_COLS - 3] + '...'
+ lines.append(line)
+ argspec = '\n'.join(lines)
+ if not argspec:
+ argspec = _default_callable_argspec
+ return argspec
+
+
+if __name__ == '__main__':
+ from unittest import main
+ main('idlelib.idle_test.test_calltip', verbosity=2)
-"""A CallTip window class for Tkinter/IDLE.
+"""A call-tip window class for Tkinter/IDLE.
-After tooltip.py, which uses ideas gleaned from PySol
-Used by the calltips IDLE extension.
+After tooltip.py, which uses ideas gleaned from PySol.
+Used by calltip.py.
"""
-from tkinter import Toplevel, Label, LEFT, SOLID, TclError
+from tkinter import Label, LEFT, SOLID, TclError
-HIDE_VIRTUAL_EVENT_NAME = "<<calltipwindow-hide>>"
+from idlelib.tooltip import TooltipBase
+
+HIDE_EVENT = "<<calltipwindow-hide>>"
HIDE_SEQUENCES = ("<Key-Escape>", "<FocusOut>")
-CHECKHIDE_VIRTUAL_EVENT_NAME = "<<calltipwindow-checkhide>>"
+CHECKHIDE_EVENT = "<<calltipwindow-checkhide>>"
CHECKHIDE_SEQUENCES = ("<KeyRelease>", "<ButtonRelease>")
-CHECKHIDE_TIME = 100 # milliseconds
+CHECKHIDE_TIME = 100 # milliseconds
MARK_RIGHT = "calltipwindowregion_right"
-class CallTip:
- def __init__(self, widget):
- self.widget = widget
- self.tipwindow = self.label = None
- self.parenline = self.parencol = None
- self.lastline = None
+class CalltipWindow(TooltipBase):
+ """A call-tip widget for tkinter text widgets."""
+
+ def __init__(self, text_widget):
+ """Create a call-tip; shown by showtip().
+
+ text_widget: a Text widget with code for which call-tips are desired
+ """
+ # Note: The Text widget will be accessible as self.anchor_widget
+ super(CalltipWindow, self).__init__(text_widget)
+
+ self.label = self.text = None
+ self.parenline = self.parencol = self.lastline = None
self.hideid = self.checkhideid = None
self.checkhide_after_id = None
- def position_window(self):
- """Check if needs to reposition the window, and if so - do it."""
- curline = int(self.widget.index("insert").split('.')[0])
- if curline == self.lastline:
- return
- self.lastline = curline
- self.widget.see("insert")
+ def get_position(self):
+ """Choose the position of the call-tip."""
+ curline = int(self.anchor_widget.index("insert").split('.')[0])
if curline == self.parenline:
- box = self.widget.bbox("%d.%d" % (self.parenline,
- self.parencol))
+ anchor_index = (self.parenline, self.parencol)
else:
- box = self.widget.bbox("%d.0" % curline)
+ anchor_index = (curline, 0)
+ box = self.anchor_widget.bbox("%d.%d" % anchor_index)
if not box:
- box = list(self.widget.bbox("insert"))
+ box = list(self.anchor_widget.bbox("insert"))
# align to left of window
box[0] = 0
box[2] = 0
- x = box[0] + self.widget.winfo_rootx() + 2
- y = box[1] + box[3] + self.widget.winfo_rooty()
- self.tipwindow.wm_geometry("+%d+%d" % (x, y))
+ return box[0] + 2, box[1] + box[3]
+
+ def position_window(self):
+ "Reposition the window if needed."
+ curline = int(self.anchor_widget.index("insert").split('.')[0])
+ if curline == self.lastline:
+ return
+ self.lastline = curline
+ self.anchor_widget.see("insert")
+ super(CalltipWindow, self).position_window()
def showtip(self, text, parenleft, parenright):
- """Show the calltip, bind events which will close it and reposition it.
+ """Show the call-tip, bind events which will close it and reposition it.
+
+ text: the text to display in the call-tip
+ parenleft: index of the opening parenthesis in the text widget
+ parenright: index of the closing parenthesis in the text widget,
+ or the end of the line if there is no closing parenthesis
"""
- # Only called in CallTips, where lines are truncated
+ # Only called in calltip.Calltip, where lines are truncated
self.text = text
if self.tipwindow or not self.text:
return
- self.widget.mark_set(MARK_RIGHT, parenright)
+ self.anchor_widget.mark_set(MARK_RIGHT, parenright)
self.parenline, self.parencol = map(
- int, self.widget.index(parenleft).split("."))
+ int, self.anchor_widget.index(parenleft).split("."))
- self.tipwindow = tw = Toplevel(self.widget)
- self.position_window()
- # remove border on calltip window
- tw.wm_overrideredirect(1)
- try:
- # This command is only needed and available on Tk >= 8.4.0 for OSX
- # Without it, call tips intrude on the typing process by grabbing
- # the focus.
- tw.tk.call("::tk::unsupported::MacWindowStyle", "style", tw._w,
- "help", "noActivates")
- except TclError:
- pass
- self.label = Label(tw, text=self.text, justify=LEFT,
+ super(CalltipWindow, self).showtip()
+
+ self._bind_events()
+
+ def showcontents(self):
+ """Create the call-tip widget."""
+ self.label = Label(self.tipwindow, text=self.text, justify=LEFT,
background="#ffffe0", relief=SOLID, borderwidth=1,
- font = self.widget['font'])
+ font=self.anchor_widget['font'])
self.label.pack()
- tw.lift() # work around bug in Tk 8.5.18+ (issue #24570)
-
- self.checkhideid = self.widget.bind(CHECKHIDE_VIRTUAL_EVENT_NAME,
- self.checkhide_event)
- for seq in CHECKHIDE_SEQUENCES:
- self.widget.event_add(CHECKHIDE_VIRTUAL_EVENT_NAME, seq)
- self.widget.after(CHECKHIDE_TIME, self.checkhide_event)
- self.hideid = self.widget.bind(HIDE_VIRTUAL_EVENT_NAME,
- self.hide_event)
- for seq in HIDE_SEQUENCES:
- self.widget.event_add(HIDE_VIRTUAL_EVENT_NAME, seq)
def checkhide_event(self, event=None):
+ """Handle CHECK_HIDE_EVENT: call hidetip or reschedule."""
if not self.tipwindow:
- # If the event was triggered by the same event that unbinded
+ # If the event was triggered by the same event that unbound
# this function, the function will be called nevertheless,
# so do nothing in this case.
return None
- curline, curcol = map(int, self.widget.index("insert").split('.'))
+
+ # Hide the call-tip if the insertion cursor moves outside of the
+ # parenthesis.
+ curline, curcol = map(int, self.anchor_widget.index("insert").split('.'))
if curline < self.parenline or \
(curline == self.parenline and curcol <= self.parencol) or \
- self.widget.compare("insert", ">", MARK_RIGHT):
+ self.anchor_widget.compare("insert", ">", MARK_RIGHT):
self.hidetip()
return "break"
- else:
- self.position_window()
- if self.checkhide_after_id is not None:
- self.widget.after_cancel(self.checkhide_after_id)
- self.checkhide_after_id = \
- self.widget.after(CHECKHIDE_TIME, self.checkhide_event)
- return None
+
+ # Not hiding the call-tip.
+
+ self.position_window()
+ # Re-schedule this function to be called again in a short while.
+ if self.checkhide_after_id is not None:
+ self.anchor_widget.after_cancel(self.checkhide_after_id)
+ self.checkhide_after_id = \
+ self.anchor_widget.after(CHECKHIDE_TIME, self.checkhide_event)
+ return None
def hide_event(self, event):
+ """Handle HIDE_EVENT by calling hidetip."""
if not self.tipwindow:
# See the explanation in checkhide_event.
return None
return "break"
def hidetip(self):
+ """Hide the call-tip."""
if not self.tipwindow:
return
- for seq in CHECKHIDE_SEQUENCES:
- self.widget.event_delete(CHECKHIDE_VIRTUAL_EVENT_NAME, seq)
- self.widget.unbind(CHECKHIDE_VIRTUAL_EVENT_NAME, self.checkhideid)
- self.checkhideid = None
- for seq in HIDE_SEQUENCES:
- self.widget.event_delete(HIDE_VIRTUAL_EVENT_NAME, seq)
- self.widget.unbind(HIDE_VIRTUAL_EVENT_NAME, self.hideid)
- self.hideid = None
-
- self.label.destroy()
+ try:
+ self.label.destroy()
+ except TclError:
+ pass
self.label = None
- self.tipwindow.destroy()
- self.tipwindow = None
- self.widget.mark_unset(MARK_RIGHT)
self.parenline = self.parencol = self.lastline = None
+ try:
+ self.anchor_widget.mark_unset(MARK_RIGHT)
+ except TclError:
+ pass
- def is_active(self):
- return bool(self.tipwindow)
+ try:
+ self._unbind_events()
+ except (TclError, ValueError):
+ # ValueError may be raised by MultiCall
+ pass
+
+ super(CalltipWindow, self).hidetip()
+
+ def _bind_events(self):
+ """Bind event handlers."""
+ self.checkhideid = self.anchor_widget.bind(CHECKHIDE_EVENT,
+ self.checkhide_event)
+ for seq in CHECKHIDE_SEQUENCES:
+ self.anchor_widget.event_add(CHECKHIDE_EVENT, seq)
+ self.anchor_widget.after(CHECKHIDE_TIME, self.checkhide_event)
+ self.hideid = self.anchor_widget.bind(HIDE_EVENT,
+ self.hide_event)
+ for seq in HIDE_SEQUENCES:
+ self.anchor_widget.event_add(HIDE_EVENT, seq)
+
+ def _unbind_events(self):
+ """Unbind event handlers."""
+ for seq in CHECKHIDE_SEQUENCES:
+ self.anchor_widget.event_delete(CHECKHIDE_EVENT, seq)
+ self.anchor_widget.unbind(CHECKHIDE_EVENT, self.checkhideid)
+ self.checkhideid = None
+ for seq in HIDE_SEQUENCES:
+ self.anchor_widget.event_delete(HIDE_EVENT, seq)
+ self.anchor_widget.unbind(HIDE_EVENT, self.hideid)
+ self.hideid = None
def _calltip_window(parent): # htest #
from tkinter import Toplevel, Text, LEFT, BOTH
top = Toplevel(parent)
- top.title("Test calltips")
+ top.title("Test call-tips")
x, y = map(int, parent.geometry().split('+')[1:])
- top.geometry("200x100+%d+%d" % (x + 250, y + 175))
+ top.geometry("250x100+%d+%d" % (x + 175, y + 150))
text = Text(top)
text.pack(side=LEFT, fill=BOTH, expand=1)
text.insert("insert", "string.split")
top.update()
- calltip = CallTip(text)
+ calltip = CalltipWindow(text)
def calltip_show(event):
- calltip.showtip("(s=Hello world)", "insert", "end")
+ calltip.showtip("(s='Hello world')", "insert", "end")
def calltip_hide(event):
calltip.hidetip()
text.event_add("<<calltip-show>>", "(")
text.event_add("<<calltip-hide>>", ")")
text.bind("<<calltip-show>>", calltip_show)
text.bind("<<calltip-hide>>", calltip_hide)
+
text.focus_set()
-if __name__=='__main__':
+if __name__ == '__main__':
+ from unittest import main
+ main('idlelib.idle_test.test_calltip_w', verbosity=2, exit=False)
+
from idlelib.idle_test.htest import run
run(_calltip_window)
+++ /dev/null
-"""Pop up a reminder of how to call a function.
-
-Call Tips are floating windows which display function, class, and method
-parameter and docstring information when you type an opening parenthesis, and
-which disappear when you type a closing parenthesis.
-"""
-import inspect
-import re
-import sys
-import textwrap
-import types
-
-from idlelib import calltip_w
-from idlelib.hyperparser import HyperParser
-import __main__
-
-
-class CallTips:
-
- def __init__(self, editwin=None):
- if editwin is None: # subprocess and test
- self.editwin = None
- else:
- self.editwin = editwin
- self.text = editwin.text
- self.active_calltip = None
- self._calltip_window = self._make_tk_calltip_window
-
- def close(self):
- self._calltip_window = None
-
- def _make_tk_calltip_window(self):
- # See __init__ for usage
- return calltip_w.CallTip(self.text)
-
- def _remove_calltip_window(self, event=None):
- if self.active_calltip:
- self.active_calltip.hidetip()
- self.active_calltip = None
-
- def force_open_calltip_event(self, event):
- "The user selected the menu entry or hotkey, open the tip."
- self.open_calltip(True)
- return "break"
-
- def try_open_calltip_event(self, event):
- """Happens when it would be nice to open a CallTip, but not really
- necessary, for example after an opening bracket, so function calls
- won't be made.
- """
- self.open_calltip(False)
-
- def refresh_calltip_event(self, event):
- if self.active_calltip and self.active_calltip.is_active():
- self.open_calltip(False)
-
- def open_calltip(self, evalfuncs):
- self._remove_calltip_window()
-
- hp = HyperParser(self.editwin, "insert")
- sur_paren = hp.get_surrounding_brackets('(')
- if not sur_paren:
- return
- hp.set_index(sur_paren[0])
- expression = hp.get_expression()
- if not expression:
- return
- if not evalfuncs and (expression.find('(') != -1):
- return
- argspec = self.fetch_tip(expression)
- if not argspec:
- return
- self.active_calltip = self._calltip_window()
- self.active_calltip.showtip(argspec, sur_paren[0], sur_paren[1])
-
- def fetch_tip(self, expression):
- """Return the argument list and docstring of a function or class.
-
- If there is a Python subprocess, get the calltip there. Otherwise,
- either this fetch_tip() is running in the subprocess or it was
- called in an IDLE running without the subprocess.
-
- The subprocess environment is that of the most recently run script. If
- two unrelated modules are being edited some calltips in the current
- module may be inoperative if the module was not the last to run.
-
- To find methods, fetch_tip must be fed a fully qualified name.
-
- """
- try:
- rpcclt = self.editwin.flist.pyshell.interp.rpcclt
- except AttributeError:
- rpcclt = None
- if rpcclt:
- return rpcclt.remotecall("exec", "get_the_calltip",
- (expression,), {})
- else:
- return get_argspec(get_entity(expression))
-
-
-def get_entity(expression):
- """Return the object corresponding to expression evaluated
- in a namespace spanning sys.modules and __main.dict__.
- """
- if expression:
- namespace = sys.modules.copy()
- namespace.update(__main__.__dict__)
- try:
- return eval(expression, namespace)
- except BaseException:
- # An uncaught exception closes idle, and eval can raise any
- # exception, especially if user classes are involved.
- return None
-
-# The following are used in get_argspec and some in tests
-_MAX_COLS = 85
-_MAX_LINES = 5 # enough for bytes
-_INDENT = ' '*4 # for wrapped signatures
-_first_param = re.compile(r'(?<=\()\w*\,?\s*')
-_default_callable_argspec = "See source or doc"
-_invalid_method = "invalid method signature"
-_argument_positional = "\n['/' marks preceding arguments as positional-only]\n"
-
-def get_argspec(ob):
- '''Return a string describing the signature of a callable object, or ''.
-
- For Python-coded functions and methods, the first line is introspected.
- Delete 'self' parameter for classes (.__init__) and bound methods.
- The next lines are the first lines of the doc string up to the first
- empty line or _MAX_LINES. For builtins, this typically includes
- the arguments in addition to the return value.
- '''
- argspec = default = ""
- try:
- ob_call = ob.__call__
- except BaseException:
- return default
-
- fob = ob_call if isinstance(ob_call, types.MethodType) else ob
-
- try:
- argspec = str(inspect.signature(fob))
- except ValueError as err:
- msg = str(err)
- if msg.startswith(_invalid_method):
- return _invalid_method
-
- if '/' in argspec:
- """Using AC's positional argument should add the explain"""
- argspec += _argument_positional
- if isinstance(fob, type) and argspec == '()':
- """fob with no argument, use default callable argspec"""
- argspec = _default_callable_argspec
-
- lines = (textwrap.wrap(argspec, _MAX_COLS, subsequent_indent=_INDENT)
- if len(argspec) > _MAX_COLS else [argspec] if argspec else [])
-
- if isinstance(ob_call, types.MethodType):
- doc = ob_call.__doc__
- else:
- doc = getattr(ob, "__doc__", "")
- if doc:
- for line in doc.split('\n', _MAX_LINES)[:_MAX_LINES]:
- line = line.strip()
- if not line:
- break
- if len(line) > _MAX_COLS:
- line = line[: _MAX_COLS - 3] + '...'
- lines.append(line)
- argspec = '\n'.join(lines)
- if not argspec:
- argspec = _default_callable_argspec
- return argspec
-
-
-if __name__ == '__main__':
- from unittest import main
- main('idlelib.idle_test.test_calltips', verbosity=2)
CodeContext.reload()
-if __name__ == "__main__": # pragma: no cover
- import unittest
- unittest.main('idlelib.idle_test.test_codecontext', verbosity=2, exit=False)
+if __name__ == "__main__":
+ from unittest import main
+ main('idlelib.idle_test.test_codecontext', verbosity=2, exit=False)
+
+ # Add htest.
prog = re.compile(make_pat(), re.S)
idprog = re.compile(r"\s+(\w+)", re.S)
-def color_config(text): # Called from htest, Editor, and Turtle Demo.
- '''Set color opitons of Text widget.
+def color_config(text):
+ """Set color options of Text widget.
- Should be called whenever ColorDelegator is called.
- '''
+ If ColorDelegator is used, this should be called first.
+ """
+ # Called from htest, TextFrame, Editor, and Turtledemo.
# Not automatic because ColorDelegator does not know 'text'.
theme = idleConf.CurrentTheme()
normal_colors = idleConf.GetHighlight(theme, 'normal')
inactiveselectbackground=select_colors['background'], # new in 8.5
)
+
class ColorDelegator(Delegator):
def __init__(self):
d = ColorDelegator()
p.insertfilter(d)
+
if __name__ == "__main__":
- import unittest
- unittest.main('idlelib.idle_test.test_colorizer',
- verbosity=2, exit=False)
+ from unittest import main
+ main('idlelib.idle_test.test_colorizer', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(_color_delegator)
font-bold= 0
encoding= none
+[PyShell]
+auto-squeeze-min-lines= 50
+
[Indent]
use-spaces= 1
num-spaces= 4
print('\nlines = ', line, ', crc = ', crc, sep='')
if __name__ == '__main__':
- import unittest
- unittest.main('idlelib.idle_test.test_config',
- verbosity=2, exit=False)
- #_dump()
+ from unittest import main
+ main('idlelib.idle_test.test_config', verbosity=2, exit=False)
+
+ # Run revised _dump() as htest?
return
if (self.advanced or self.KeysOK(keys)) and self.bind_ok(keys):
self.result = keys
+ self.grab_release()
self.destroy()
def Cancel(self, event=None):
self.result=''
+ self.grab_release()
self.destroy()
def KeysOK(self, keys):
if __name__ == '__main__':
- import unittest
- unittest.main('idlelib.idle_test.test_config_key', verbosity=2, exit=False)
+ from unittest import main
+ main('idlelib.idle_test.test_config_key', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(GetKeysDialog)
from idlelib.codecontext import CodeContext
from idlelib.parenmatch import ParenMatch
from idlelib.paragraph import FormatParagraph
+from idlelib.squeezer import Squeezer
changes = ConfigChanges()
# Reload changed options in the following classes.
-reloadables = (AutoComplete, CodeContext, ParenMatch, FormatParagraph)
+reloadables = (AutoComplete, CodeContext, ParenMatch, FormatParagraph,
+ Squeezer)
class ConfigDialog(Toplevel):
def destroy(self):
global font_sample_text
font_sample_text = self.fontpage.font_sample.get('1.0', 'end')
+ self.grab_release()
super().destroy()
def help(self):
self.customlist.SetMenu(item_list, item_list[0])
# Revert to default key set.
self.keyset_source.set(idleConf.defaultCfg['main']
- .Get('Keys', 'default'))
+ .Get('Keys', 'default'))
self.builtin_name.set(idleConf.defaultCfg['main'].Get('Keys', 'name')
- or idleConf.default_keys())
+ or idleConf.default_keys())
# User can't back out of these changes, they must be applied now.
changes.save_all()
self.cd.save_all_changed_extensions()
frame_context: Frame
context_title: Label
(*)context_int: Entry - context_lines
+ frame_shell: LabelFrame
+ frame_auto_squeeze_min_lines: Frame
+ auto_squeeze_min_lines_title: Label
+ (*)auto_squeeze_min_lines_int: Entry - auto_squeeze_min_lines
frame_help: LabelFrame
frame_helplist: Frame
frame_helplist_buttons: Frame
self.paren_bell = tracers.add(
BooleanVar(self), ('extensions', 'ParenMatch', 'bell'))
+ self.auto_squeeze_min_lines = tracers.add(
+ StringVar(self), ('main', 'PyShell', 'auto-squeeze-min-lines'))
+
self.autosave = tracers.add(
IntVar(self), ('main', 'General', 'autosave'))
self.format_width = tracers.add(
text=' Window Preferences')
frame_editor = LabelFrame(self, borderwidth=2, relief=GROOVE,
text=' Editor Preferences')
+ frame_shell = LabelFrame(self, borderwidth=2, relief=GROOVE,
+ text=' Shell Preferences')
frame_help = LabelFrame(self, borderwidth=2, relief=GROOVE,
- text=' Additional Help Sources ')
+ text=' Additional Help Sources ')
# Frame_window.
frame_run = Frame(frame_window, borderwidth=0)
startup_title = Label(frame_run, text='At Startup')
self.context_int = Entry(
frame_context, textvariable=self.context_lines, width=3)
+ # Frame_shell.
+ frame_auto_squeeze_min_lines = Frame(frame_shell, borderwidth=0)
+ auto_squeeze_min_lines_title = Label(frame_auto_squeeze_min_lines,
+ text='Auto-Squeeze Min. Lines:')
+ self.auto_squeeze_min_lines_int = Entry(
+ frame_auto_squeeze_min_lines, width=4,
+ textvariable=self.auto_squeeze_min_lines)
# frame_help.
frame_helplist = Frame(frame_help)
# Body.
frame_window.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
frame_editor.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
+ frame_shell.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
frame_help.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
# frame_run.
frame_run.pack(side=TOP, padx=5, pady=0, fill=X)
context_title.pack(side=LEFT, anchor=W, padx=5, pady=5)
self.context_int.pack(side=TOP, padx=5, pady=5)
+ # frame_auto_squeeze_min_lines
+ frame_auto_squeeze_min_lines.pack(side=TOP, padx=5, pady=0, fill=X)
+ auto_squeeze_min_lines_title.pack(side=LEFT, anchor=W, padx=5, pady=5)
+ self.auto_squeeze_min_lines_int.pack(side=TOP, padx=5, pady=5)
+
# frame_help.
frame_helplist_buttons.pack(side=RIGHT, padx=5, pady=5, fill=Y)
frame_helplist.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
self.context_lines.set(idleConf.GetOption(
'extensions', 'CodeContext', 'maxlines', type='int'))
+ # Set variables for shell windows.
+ self.auto_squeeze_min_lines.set(idleConf.GetOption(
+ 'main', 'PyShell', 'auto-squeeze-min-lines', type='int'))
+
# Set additional help sources.
self.user_helplist = idleConf.GetAllExtraHelpSourcesList()
self.helplist.delete(0, 'end')
CodeContext: Maxlines is the maximum number of code context lines to
display when Code Context is turned on for an editor window.
+
+Shell Preferences: Auto-Squeeze Min. Lines is the minimum number of lines
+of output to automatically "squeeze".
'''
}
if __name__ == '__main__':
- import unittest
- unittest.main('idlelib.idle_test.test_configdialog',
- verbosity=2, exit=False)
+ from unittest import main
+ main('idlelib.idle_test.test_configdialog', verbosity=2, exit=False)
+
from idlelib.idle_test.htest import run
run(ConfigDialog)
from idlelib import macosx
from idlelib.scrolledlist import ScrolledList
-from idlelib.windows import ListedToplevel
+from idlelib.window import ListedToplevel
class Idb(bdb.Bdb):
def __init__(self, gui):
- self.gui = gui
+ self.gui = gui # An instance of Debugger or proxy of remote.
bdb.Bdb.__init__(self)
def user_line(self, frame):
prev_name = prev_frame.f_code.co_filename
if 'idlelib' in prev_name and 'debugger' in prev_name:
# catch both idlelib/debugger.py and idlelib/debugger_r.py
- # on both posix and windows
+ # on both Posix and Windows
return False
return self.in_rpc_code(prev_frame)
if idb is None:
idb = Idb(self)
self.pyshell = pyshell
- self.idb = idb
+ self.idb = idb # If passed, a proxy of remote instance.
self.frame = None
self.make_gui()
self.interacting = 0
def close(self):
self.frame.destroy()
+
+if __name__ == "__main__":
+ from unittest import main
+ main('idlelib.idle_test.test_debugger', verbosity=2, exit=False)
+
+# TODO: htest?
idb_adap_oid_ret = rpcclt.remotecall("exec", "start_the_debugger",\
(gui_adap_oid,), {})
assert idb_adap_oid_ret == idb_adap_oid, 'Idb restarted with different oid'
+
+
+if __name__ == "__main__":
+ from unittest import main
+ main('idlelib.idle_test.test_debugger', verbosity=2, exit=False)
class AtomicObjectTreeItem(ObjectTreeItem):
def IsExpandable(self):
- return 0
+ return False
class SequenceTreeItem(ObjectTreeItem):
def IsExpandable(self):
node.update()
if __name__ == '__main__':
+ from unittest import main
+ main('idlelib.idle_test.test_debugobj', verbosity=2, exit=False)
+
from idlelib.idle_test.htest import run
run(_object_browser)
def _GetSubList(self):
sub_list = self.sockio.remotecall(self.oid, "_GetSubList", (), {})
return [StubObjectTreeItem(self.sockio, oid) for oid in sub_list]
+
+
+if __name__ == '__main__':
+ from unittest import main
+ main('idlelib.idle_test.test_debugobj_r', verbosity=2)
import importlib.util
import os
import platform
-import re
import string
-import sys
import tokenize
import traceback
import webbrowser
from idlelib import query
from idlelib import replace
from idlelib import search
-from idlelib import windows
+from idlelib import window
# The default tab setting for a Text widget, in average-width characters.
TK_TABWIDTH_DEFAULT = 8
from idlelib.undo import UndoDelegator
from idlelib.iomenu import IOBinding, encoding
from idlelib import mainmenu
- from tkinter import Toplevel, EventType
from idlelib.statusbar import MultiStatusBar
from idlelib.autocomplete import AutoComplete
from idlelib.autoexpand import AutoExpand
- from idlelib.calltips import CallTips
+ from idlelib.calltip import Calltip
from idlelib.codecontext import CodeContext
from idlelib.paragraph import FormatParagraph
from idlelib.parenmatch import ParenMatch
- from idlelib.rstrip import RstripExtension
+ from idlelib.rstrip import Rstrip
+ from idlelib.squeezer import Squeezer
from idlelib.zoomheight import ZoomHeight
filesystemencoding = sys.getfilesystemencoding() # for file names
root = root or flist.root
self.root = root
self.menubar = Menu(root)
- self.top = top = windows.ListedToplevel(root, menu=self.menubar)
+ self.top = top = window.ListedToplevel(root, menu=self.menubar)
if flist:
self.tkinter_vars = flist.vars
#self.top.instance_dict makes flist.inversedict available to
self.top.protocol("WM_DELETE_WINDOW", self.close)
self.top.bind("<<close-window>>", self.close_event)
if macosx.isAquaTk():
- # Command-W on editorwindows doesn't work without this.
+ # Command-W on editor windows doesn't work without this.
text.bind('<<close-window>>', self.close_event)
# Some OS X systems have only one mouse button, so use
# control-click for popup context menus there. For two
self.saved_change_hook()
self.update_recent_files_list()
self.load_extensions()
- menu = self.menudict.get('windows')
+ menu = self.menudict.get('window')
if menu:
end = menu.index("end")
if end is None:
menu.add_separator()
end = end + 1
self.wmenu_end = end
- windows.register_callback(self.postwindowsmenu)
+ window.register_callback(self.postwindowsmenu)
# Some abstractions so IDLE extensions are cross-IDE
self.askyesno = tkMessageBox.askyesno
scriptbinding = ScriptBinding(self)
text.bind("<<check-module>>", scriptbinding.check_module_event)
text.bind("<<run-module>>", scriptbinding.run_module_event)
- text.bind("<<do-rstrip>>", self.RstripExtension(self).do_rstrip)
- calltips = self.CallTips(self)
- text.bind("<<try-open-calltip>>", calltips.try_open_calltip_event)
- #refresh-calltips must come after paren-closed to work right
- text.bind("<<refresh-calltip>>", calltips.refresh_calltip_event)
- text.bind("<<force-open-calltip>>", calltips.force_open_calltip_event)
+ text.bind("<<do-rstrip>>", self.Rstrip(self).do_rstrip)
+ ctip = self.Calltip(self)
+ text.bind("<<try-open-calltip>>", ctip.try_open_calltip_event)
+ #refresh-calltip must come after paren-closed to work right
+ text.bind("<<refresh-calltip>>", ctip.refresh_calltip_event)
+ text.bind("<<force-open-calltip>>", ctip.force_open_calltip_event)
text.bind("<<zoom-height>>", self.ZoomHeight(self).zoom_height_event)
text.bind("<<toggle-code-context>>",
self.CodeContext(self).toggle_code_context_event)
+ squeezer = self.Squeezer(self)
+ text.bind("<<squeeze-current-text>>",
+ squeezer.squeeze_current_text_event)
def _filename_to_unicode(self, filename):
"""Return filename as BMP unicode so diplayable in Tk."""
("format", "F_ormat"),
("run", "_Run"),
("options", "_Options"),
- ("windows", "_Window"),
+ ("window", "_Window"),
("help", "_Help"),
]
self.reset_help_menu_entries()
def postwindowsmenu(self):
- # Only called when Windows menu exists
- menu = self.menudict['windows']
+ # Only called when Window menu exists
+ menu = self.menudict['window']
end = menu.index("end")
if end is None:
end = -1
if end > self.wmenu_end:
menu.delete(self.wmenu_end+1, end)
- windows.add_windows_to_menu(menu)
+ window.add_windows_to_menu(menu)
def handle_yview(self, event, *args):
"Handle scrollbar."
return 'break'
def mousescroll(self, event):
- "Handle scroll wheel."
- up = {EventType.MouseWheel: event.delta >= 0 == darwin,
+ """Handle scrollwheel event.
+
+ For wheel up, event.delta = 120*n on Windows, -1*n on darwin,
+ where n can be > 1 if one scrolls fast. Flicking the wheel
+ generates up to maybe 20 events with n up to 10 or more 1.
+ Macs use wheel down (delta = 1*n) to scroll up, so positive
+ delta means to scroll up on both systems.
+
+ X-11 sends Control-Button-4 event instead.
+ """
+ up = {EventType.MouseWheel: event.delta > 0,
EventType.Button: event.num == 4}
- lines = 5
- if up[event.type]:
- lines = -lines
+ lines = -5 if up[event.type] else 5
self.text.yview_scroll(lines, 'units')
return 'break'
def _close(self):
if self.io.filename:
self.update_recent_files_list(new_file=self.io.filename)
- windows.unregister_callback(self.postwindowsmenu)
+ window.unregister_callback(self.postwindowsmenu)
self.unload_extensions()
self.io.close()
self.io = None
filename = None
macosx.setupApp(root, None)
edit = EditorWindow(root=root, filename=filename)
- edit.text.bind("<<close-all-windows>>", edit.close_event)
+ text = edit.text
+ text['height'] = 10
+ for i in range(20):
+ text.insert('insert', ' '*i + str(i) + '\n')
+ # text.bind("<<close-all-windows>>", edit.close_event)
# Does not stop error, neither does following
# edit.text.bind("<<close-window>>", edit.close_event)
if __name__ == '__main__':
- import unittest
- unittest.main('idlelib.idle_test.test_editor', verbosity=2, exit=False)
+ from unittest import main
+ main('idlelib.idle_test.test_editor', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(_editor_window)
-import os
+"idlelib.filelist"
-from tkinter import *
-import tkinter.messagebox as tkMessageBox
+import os
+from tkinter import messagebox as tkMessageBox
class FileList:
return os.path.normpath(filename)
-def _test():
+def _test(): # TODO check and convert to htest
+ from tkinter import Tk
from idlelib.editor import fixwordbreaks
from idlelib.run import fix_scaling
import sys
fixwordbreaks(root)
root.withdraw()
flist = FileList(root)
- if sys.argv[1:]:
- for filename in sys.argv[1:]:
- flist.open(filename)
- else:
- flist.new()
+ flist.new()
if flist.inversedict:
root.mainloop()
if __name__ == '__main__':
- _test()
+ from unittest import main
+ main('idlelib.idle_test.test_filelist', verbosity=2)
+
+# _test()
button.pack()
if __name__ == "__main__":
- import unittest
- unittest.main('idlelib.idle_test.test_grep', verbosity=2, exit=False)
+ from unittest import main
+ main('idlelib.idle_test.test_grep', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(_grep_dialog)
HelpWindow(parent, filename, 'IDLE Help (%s)' % python_version())
if __name__ == '__main__':
+ from unittest import main
+ main('idlelib.idle_test.test_help', verbosity=2, exit=False)
+
from idlelib.idle_test.htest import run
run(show_idlehelp)
def ok(self, event=None):
"Dismiss help_about dialog."
+ self.grab_release()
self.destroy()
if __name__ == '__main__':
- import unittest
- unittest.main('idlelib.idle_test.test_help_about', verbosity=2, exit=False)
+ from unittest import main
+ main('idlelib.idle_test.test_help_about', verbosity=2, exit=False)
+
from idlelib.idle_test.htest import run
run(AboutDialog)
if __name__ == '__main__':
- import unittest
- unittest.main('idlelib.idle_test.test_hyperparser', verbosity=2)
+ from unittest import main
+ main('idlelib.idle_test.test_hyperparser', verbosity=2)
1. Test Files
The idle directory, idlelib, has over 60 xyz.py files. The idle_test
-subdirectory should contain a test_xyz.py for each, where 'xyz' is
-lowercased even if xyz.py is not. Here is a possible template, with the
-blanks after '.' and 'as', and before and after '_' to be filled in.
+subdirectory contains test_xyz.py for each implementation file xyz.py.
+To add a test for abc.py, open idle_test/template.py and immediately
+Save As test_abc.py. Insert 'abc' on the first line, and replace
+'zzdummy' with 'abc.
-import unittest
-from test.support import requires
-import idlelib. as
-
-class _Test(unittest.TestCase):
+Remove the imports of requires and tkinter if not needed. Otherwise,
+add to the tkinter imports as needed.
- def test_(self):
+Add a prefix to 'Test' for the initial test class. The template class
+contains code needed or possibly needed for gui tests. See the next
+section if doing gui tests. If not, and not needed for further classes,
+this code can be removed.
-if __name__ == '__main__':
- unittest.main(verbosity=2)
-
-Add the following at the end of xyy.py, with the appropriate name added
-after 'test_'. Some files already have something like this for htest.
-If so, insert the import and unittest.main lines before the htest lines.
+Add the following at the end of abc.py. If an htest was added first,
+insert the import and main lines before the htest lines.
if __name__ == "__main__":
- import unittest
- unittest.main('idlelib.idle_test.test_', verbosity=2, exit=False)
+ from unittest import main
+ main('idlelib.idle_test.test_abc', verbosity=2, exit=False)
+
+The ', exit=False' is only needed if an htest follows.
requires('gui')
To guard a test class, put "requires('gui')" in its setUpClass function.
+The template.py file does this.
-To avoid interfering with other GUI tests, all GUI objects must be destroyed and
-deleted by the end of the test. The Tk root created in a setUpX function should
-be destroyed in the corresponding tearDownX and the module or class attribute
-deleted. Others widgets should descend from the single root and the attributes
-deleted BEFORE root is destroyed. See https://bugs.python.org/issue20567.
+To avoid interfering with other GUI tests, all GUI objects must be
+destroyed and deleted by the end of the test. The Tk root created in a
+setUpX function should be destroyed in the corresponding tearDownX and
+the module or class attribute deleted. Others widgets should descend
+from the single root and the attributes deleted BEFORE root is
+destroyed. See https://bugs.python.org/issue20567.
@classmethod
def setUpClass(cls):
cls.root.destroy()
del cls.root
-The update_idletasks call is sometimes needed to prevent the following warning
-either when running a test alone or as part of the test suite (#27196).
+The update_idletasks call is sometimes needed to prevent the following
+warning either when running a test alone or as part of the test suite
+(#27196). It should not hurt if not needed.
+
can't invoke "event" command: application has been destroyed
...
"ttk::ThemeChanged"
+If a test creates instance 'e' of EditorWindow, call 'e._close()' before
+or as the first part of teardown. The effect of omitting this depends
+on the later shutdown. Then enable the after_cancel loop in the
+template. This prevents messages like the following.
+
+bgerror failed to handle background error.
+ Original error: invalid command name "106096696timer_event"
+ Error in bgerror: can't invoke "tk" command: application has been destroyed
+
Requires('gui') causes the test(s) it guards to be skipped if any of
these conditions are met:
outwin.OutputWindow (indirectly being tested with grep test)
'''
+import idlelib.pyshell # Set Windows DPI awareness before Tk().
from importlib import import_module
import tkinter as tk
from tkinter.ttk import Scrollbar
"are correctly displayed.\n [Close] to exit.",
}
+# TODO implement ^\; adding '<Control-Key-\\>' to function does not work.
_calltip_window_spec = {
'file': 'calltip_w',
'kwds': {},
'msg': "Typing '(' should display a calltip.\n"
"Typing ') should hide the calltip.\n"
+ "So should moving cursor out of argument area.\n"
+ "Force-open-calltip does not work here.\n"
}
_module_browser_spec = {
'msg': "Click the 'Show GrepDialog' button.\n"
"Test the various 'Find-in-files' functions.\n"
"The results should be displayed in a new '*Output*' window.\n"
- "'Right-click'->'Goto file/line' anywhere in the search results "
+ "'Right-click'->'Go to file/line' anywhere in the search results "
"should open that file \nin a new EditorWindow."
}
"Check that exc_value, exc_tb, and exc_type are correct.\n"
}
-_tabbed_pages_spec = {
- 'file': 'tabbedpages',
- 'kwds': {},
- 'msg': "Toggle between the two tabs 'foo' and 'bar'\n"
- "Add a tab by entering a suitable name for it.\n"
- "Remove an existing tab by entering its name.\n"
- "Remove all existing tabs.\n"
- "<nothing> is an invalid add page and remove page name.\n"
- }
-
_tooltip_spec = {
'file': 'tooltip',
'kwds': {},
--- /dev/null
+"Test , coverage %."
+
+from idlelib import zzdummy
+import unittest
+from test.support import requires
+from tkinter import Tk
+
+
+class Test(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ requires('gui')
+ cls.root = Tk()
+ cls.root.withdraw()
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.root.update_idletasks()
+## for id in cls.root.tk.call('after', 'info'):
+## cls.root.after_cancel(id) # Need for EditorWindow.
+ cls.root.destroy()
+ del cls.root
+
+ def test_init(self):
+ self.assertTrue(True)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
-''' Test autocomplete and autocomple_w
+"Test autocomplete, coverage 57%."
-Coverage of autocomple: 56%
-'''
import unittest
from test.support import requires
from tkinter import Tk, Text
from idlelib.idle_test.mock_idle import Func
from idlelib.idle_test.mock_tk import Event
-class AutoCompleteWindow:
- def complete():
- return
class DummyEditwin:
def __init__(self, root, text):
--- /dev/null
+"Test autocomplete_w, coverage 11%."
+
+import unittest
+from test.support import requires
+from tkinter import Tk, Text
+
+import idlelib.autocomplete_w as acw
+
+
+class AutoCompleteWindowTest(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ requires('gui')
+ cls.root = Tk()
+ cls.root.withdraw()
+ cls.text = Text(cls.root)
+ cls.acw = acw.AutoCompleteWindow(cls.text)
+
+ @classmethod
+ def tearDownClass(cls):
+ del cls.text, cls.acw
+ cls.root.update_idletasks()
+ cls.root.destroy()
+ del cls.root
+
+ def test_init(self):
+ self.assertEqual(self.acw.widget, self.text)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
-"""Unit tests for idlelib.autoexpand"""
+"Test autoexpand, coverage 100%."
+
+from idlelib.autoexpand import AutoExpand
import unittest
from test.support import requires
from tkinter import Text, Tk
-#from idlelib.idle_test.mock_tk import Text
-from idlelib.autoexpand import AutoExpand
class Dummy_Editwin:
@classmethod
def setUpClass(cls):
- if 'tkinter' in str(Text):
- requires('gui')
- cls.tk = Tk()
- cls.text = Text(cls.tk)
- else:
- cls.text = Text()
+ requires('gui')
+ cls.tk = Tk()
+ cls.text = Text(cls.tk)
cls.auto_expand = AutoExpand(Dummy_Editwin(cls.text))
cls.auto_expand.bell = lambda: None
+# If mock_tk.Text._decode understood indexes 'insert' with suffixed 'linestart',
+# 'wordstart', and 'lineend', used by autoexpand, we could use the following
+# to run these test on non-gui machines (but check bell).
+## try:
+## requires('gui')
+## #raise ResourceDenied() # Uncomment to test mock.
+## except ResourceDenied:
+## from idlelib.idle_test.mock_tk import Text
+## cls.text = Text()
+## cls.text.bell = lambda: None
+## else:
+## from tkinter import Tk, Text
+## cls.tk = Tk()
+## cls.text = Text(cls.tk)
+
@classmethod
def tearDownClass(cls):
del cls.text, cls.auto_expand
-""" Test idlelib.browser.
+"Test browser, coverage 90%."
-Coverage: 88%
-(Higher, because should exclude 3 lines that .coveragerc won't exclude.)
-"""
+from idlelib import browser
+from test.support import requires
+import unittest
+from unittest import mock
+from idlelib.idle_test.mock_idle import Func
from collections import deque
import os.path
from idlelib import _pyclbr as pyclbr
from tkinter import Tk
-from test.support import requires
-import unittest
-from unittest import mock
-from idlelib.idle_test.mock_idle import Func
-
-from idlelib import browser
from idlelib import filelist
from idlelib.tree import TreeNode
--- /dev/null
+"Test calltip, coverage 60%"
+
+from idlelib import calltip
+import unittest
+import textwrap
+import types
+
+default_tip = calltip._default_callable_argspec
+
+
+# Test Class TC is used in multiple get_argspec test methods
+class TC():
+ 'doc'
+ tip = "(ai=None, *b)"
+ def __init__(self, ai=None, *b): 'doc'
+ __init__.tip = "(self, ai=None, *b)"
+ def t1(self): 'doc'
+ t1.tip = "(self)"
+ def t2(self, ai, b=None): 'doc'
+ t2.tip = "(self, ai, b=None)"
+ def t3(self, ai, *args): 'doc'
+ t3.tip = "(self, ai, *args)"
+ def t4(self, *args): 'doc'
+ t4.tip = "(self, *args)"
+ def t5(self, ai, b=None, *args, **kw): 'doc'
+ t5.tip = "(self, ai, b=None, *args, **kw)"
+ def t6(no, self): 'doc'
+ t6.tip = "(no, self)"
+ def __call__(self, ci): 'doc'
+ __call__.tip = "(self, ci)"
+ # attaching .tip to wrapped methods does not work
+ @classmethod
+ def cm(cls, a): 'doc'
+ @staticmethod
+ def sm(b): 'doc'
+
+
+tc = TC()
+signature = calltip.get_argspec # 2.7 and 3.x use different functions
+
+
+class Get_signatureTest(unittest.TestCase):
+ # The signature function must return a string, even if blank.
+ # Test a variety of objects to be sure that none cause it to raise
+ # (quite aside from getting as correct an answer as possible).
+ # The tests of builtins may break if inspect or the docstrings change,
+ # but a red buildbot is better than a user crash (as has happened).
+ # For a simple mismatch, change the expected output to the actual.
+
+ def test_builtins(self):
+
+ # Python class that inherits builtin methods
+ class List(list): "List() doc"
+
+ # Simulate builtin with no docstring for default tip test
+ class SB: __call__ = None
+
+ def gtest(obj, out):
+ self.assertEqual(signature(obj), out)
+
+ if List.__doc__ is not None:
+ gtest(List, List.__doc__) # This and append_doc changed in 3.7.
+ gtest(list.__new__,
+ '(*args, **kwargs)\n'
+ 'Create and return a new object.'
+ ' See help(type) for accurate signature.')
+ gtest(list.__init__,
+ '(self, /, *args, **kwargs)'
+ + calltip._argument_positional + '\n' +
+ 'Initialize self. See help(type(self)) for accurate signature.')
+ append_doc = "L.append(object) -> None -- append object to end"
+ gtest(list.append, append_doc)
+ gtest([].append, append_doc)
+ gtest(List.append, append_doc)
+
+ gtest(types.MethodType, "method(function, instance)")
+ gtest(SB(), default_tip)
+ import re
+ p = re.compile('')
+ gtest(re.sub, '''\
+(pattern, repl, string, count=0, flags=0)
+Return the string obtained by replacing the leftmost
+non-overlapping occurrences of the pattern in string by the
+replacement repl. repl can be either a string or a callable;
+if a string, backslash escapes in it are processed. If it is
+a callable, it's passed the match object and must return''')
+ gtest(p.sub, '''\
+(repl, string, count=0)
+Return the string obtained by replacing the leftmost \
+non-overlapping occurrences o...''')
+
+ def test_signature_wrap(self):
+ if textwrap.TextWrapper.__doc__ is not None:
+ self.assertEqual(signature(textwrap.TextWrapper), '''\
+(width=70, initial_indent='', subsequent_indent='', expand_tabs=True,
+ replace_whitespace=True, fix_sentence_endings=False, break_long_words=True,
+ drop_whitespace=True, break_on_hyphens=True, tabsize=8, *, max_lines=None,
+ placeholder=' [...]')''')
+
+ def test_docline_truncation(self):
+ def f(): pass
+ f.__doc__ = 'a'*300
+ self.assertEqual(signature(f), '()\n' + 'a' * (calltip._MAX_COLS-3) + '...')
+
+ def test_multiline_docstring(self):
+ # Test fewer lines than max.
+ self.assertEqual(signature(range),
+ "range(stop) -> range object\n"
+ "range(start, stop[, step]) -> range object")
+
+ # Test max lines
+ self.assertEqual(signature(bytes), '''\
+bytes(iterable_of_ints) -> bytes
+bytes(string, encoding[, errors]) -> bytes
+bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer
+bytes(int) -> bytes object of size given by the parameter initialized with null bytes
+bytes() -> empty bytes object''')
+
+ # Test more than max lines
+ def f(): pass
+ f.__doc__ = 'a\n' * 15
+ self.assertEqual(signature(f), '()' + '\na' * calltip._MAX_LINES)
+
+ def test_functions(self):
+ def t1(): 'doc'
+ t1.tip = "()"
+ def t2(a, b=None): 'doc'
+ t2.tip = "(a, b=None)"
+ def t3(a, *args): 'doc'
+ t3.tip = "(a, *args)"
+ def t4(*args): 'doc'
+ t4.tip = "(*args)"
+ def t5(a, b=None, *args, **kw): 'doc'
+ t5.tip = "(a, b=None, *args, **kw)"
+
+ doc = '\ndoc' if t1.__doc__ is not None else ''
+ for func in (t1, t2, t3, t4, t5, TC):
+ self.assertEqual(signature(func), func.tip + doc)
+
+ def test_methods(self):
+ doc = '\ndoc' if TC.__doc__ is not None else ''
+ for meth in (TC.t1, TC.t2, TC.t3, TC.t4, TC.t5, TC.t6, TC.__call__):
+ self.assertEqual(signature(meth), meth.tip + doc)
+ self.assertEqual(signature(TC.cm), "(a)" + doc)
+ self.assertEqual(signature(TC.sm), "(b)" + doc)
+
+ def test_bound_methods(self):
+ # test that first parameter is correctly removed from argspec
+ doc = '\ndoc' if TC.__doc__ is not None else ''
+ for meth, mtip in ((tc.t1, "()"), (tc.t4, "(*args)"),
+ (tc.t6, "(self)"), (tc.__call__, '(ci)'),
+ (tc, '(ci)'), (TC.cm, "(a)"),):
+ self.assertEqual(signature(meth), mtip + doc)
+
+ def test_starred_parameter(self):
+ # test that starred first parameter is *not* removed from argspec
+ class C:
+ def m1(*args): pass
+ c = C()
+ for meth, mtip in ((C.m1, '(*args)'), (c.m1, "(*args)"),):
+ self.assertEqual(signature(meth), mtip)
+
+ def test_invalid_method_signature(self):
+ class C:
+ def m2(**kwargs): pass
+ class Test:
+ def __call__(*, a): pass
+
+ mtip = calltip._invalid_method
+ self.assertEqual(signature(C().m2), mtip)
+ self.assertEqual(signature(Test()), mtip)
+
+ def test_non_ascii_name(self):
+ # test that re works to delete a first parameter name that
+ # includes non-ascii chars, such as various forms of A.
+ uni = "(A\u0391\u0410\u05d0\u0627\u0905\u1e00\u3042, a)"
+ assert calltip._first_param.sub('', uni) == '(a)'
+
+ def test_no_docstring(self):
+ def nd(s):
+ pass
+ TC.nd = nd
+ self.assertEqual(signature(nd), "(s)")
+ self.assertEqual(signature(TC.nd), "(s)")
+ self.assertEqual(signature(tc.nd), "()")
+
+ def test_attribute_exception(self):
+ class NoCall:
+ def __getattr__(self, name):
+ raise BaseException
+ class CallA(NoCall):
+ def __call__(oui, a, b, c):
+ pass
+ class CallB(NoCall):
+ def __call__(self, ci):
+ pass
+
+ for meth, mtip in ((NoCall, default_tip), (CallA, default_tip),
+ (NoCall(), ''), (CallA(), '(a, b, c)'),
+ (CallB(), '(ci)')):
+ self.assertEqual(signature(meth), mtip)
+
+ def test_non_callables(self):
+ for obj in (0, 0.0, '0', b'0', [], {}):
+ self.assertEqual(signature(obj), '')
+
+
+class Get_entityTest(unittest.TestCase):
+ def test_bad_entity(self):
+ self.assertIsNone(calltip.get_entity('1/0'))
+ def test_good_entity(self):
+ self.assertIs(calltip.get_entity('int'), int)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
--- /dev/null
+"Test calltip_w, coverage 18%."
+
+from idlelib import calltip_w
+import unittest
+from test.support import requires
+from tkinter import Tk, Text
+
+
+class CallTipWindowTest(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ requires('gui')
+ cls.root = Tk()
+ cls.root.withdraw()
+ cls.text = Text(cls.root)
+ cls.calltip = calltip_w.CalltipWindow(cls.text)
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.root.update_idletasks()
+ cls.root.destroy()
+ del cls.text, cls.root
+
+ def test_init(self):
+ self.assertEqual(self.calltip.anchor_widget, self.text)
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
+++ /dev/null
-import unittest
-import idlelib.calltips as ct
-import textwrap
-import types
-
-default_tip = ct._default_callable_argspec
-
-# Test Class TC is used in multiple get_argspec test methods
-class TC():
- 'doc'
- tip = "(ai=None, *b)"
- def __init__(self, ai=None, *b): 'doc'
- __init__.tip = "(self, ai=None, *b)"
- def t1(self): 'doc'
- t1.tip = "(self)"
- def t2(self, ai, b=None): 'doc'
- t2.tip = "(self, ai, b=None)"
- def t3(self, ai, *args): 'doc'
- t3.tip = "(self, ai, *args)"
- def t4(self, *args): 'doc'
- t4.tip = "(self, *args)"
- def t5(self, ai, b=None, *args, **kw): 'doc'
- t5.tip = "(self, ai, b=None, *args, **kw)"
- def t6(no, self): 'doc'
- t6.tip = "(no, self)"
- def __call__(self, ci): 'doc'
- __call__.tip = "(self, ci)"
- # attaching .tip to wrapped methods does not work
- @classmethod
- def cm(cls, a): 'doc'
- @staticmethod
- def sm(b): 'doc'
-
-tc = TC()
-
-signature = ct.get_argspec # 2.7 and 3.x use different functions
-class Get_signatureTest(unittest.TestCase):
- # The signature function must return a string, even if blank.
- # Test a variety of objects to be sure that none cause it to raise
- # (quite aside from getting as correct an answer as possible).
- # The tests of builtins may break if inspect or the docstrings change,
- # but a red buildbot is better than a user crash (as has happened).
- # For a simple mismatch, change the expected output to the actual.
-
- def test_builtins(self):
-
- # Python class that inherits builtin methods
- class List(list): "List() doc"
-
- # Simulate builtin with no docstring for default tip test
- class SB: __call__ = None
-
- def gtest(obj, out):
- self.assertEqual(signature(obj), out)
-
- if List.__doc__ is not None:
- gtest(List, List.__doc__) # This and append_doc changed in 3.7.
- gtest(list.__new__,
- '(*args, **kwargs)\nCreate and return a new object.'
- ' See help(type) for accurate signature.')
- gtest(list.__init__,
- '(self, /, *args, **kwargs)' + ct._argument_positional + '\n' +
- 'Initialize self. See help(type(self)) for accurate signature.')
-
- append_doc = "L.append(object) -> None -- append object to end"
- gtest(list.append, append_doc)
- gtest([].append, append_doc)
- gtest(List.append, append_doc)
-
- gtest(types.MethodType, "method(function, instance)")
- gtest(SB(), default_tip)
- import re
- p = re.compile('')
- gtest(re.sub, '''(pattern, repl, string, count=0, flags=0)\nReturn the string obtained by replacing the leftmost
-non-overlapping occurrences of the pattern in string by the
-replacement repl. repl can be either a string or a callable;
-if a string, backslash escapes in it are processed. If it is
-a callable, it's passed the match object and must return''')
- gtest(p.sub, '''(repl, string, count=0)\nReturn the string obtained by replacing the leftmost non-overlapping occurrences o...''')
-
- def test_signature_wrap(self):
- if textwrap.TextWrapper.__doc__ is not None:
- self.assertEqual(signature(textwrap.TextWrapper), '''\
-(width=70, initial_indent='', subsequent_indent='', expand_tabs=True,
- replace_whitespace=True, fix_sentence_endings=False, break_long_words=True,
- drop_whitespace=True, break_on_hyphens=True, tabsize=8, *, max_lines=None,
- placeholder=' [...]')''')
-
- def test_docline_truncation(self):
- def f(): pass
- f.__doc__ = 'a'*300
- self.assertEqual(signature(f), '()\n' + 'a' * (ct._MAX_COLS-3) + '...')
-
- def test_multiline_docstring(self):
- # Test fewer lines than max.
- self.assertEqual(signature(range),
- "range(stop) -> range object\n"
- "range(start, stop[, step]) -> range object")
-
- # Test max lines
- self.assertEqual(signature(bytes), '''\
-bytes(iterable_of_ints) -> bytes
-bytes(string, encoding[, errors]) -> bytes
-bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer
-bytes(int) -> bytes object of size given by the parameter initialized with null bytes
-bytes() -> empty bytes object''')
-
- # Test more than max lines
- def f(): pass
- f.__doc__ = 'a\n' * 15
- self.assertEqual(signature(f), '()' + '\na' * ct._MAX_LINES)
-
- def test_functions(self):
- def t1(): 'doc'
- t1.tip = "()"
- def t2(a, b=None): 'doc'
- t2.tip = "(a, b=None)"
- def t3(a, *args): 'doc'
- t3.tip = "(a, *args)"
- def t4(*args): 'doc'
- t4.tip = "(*args)"
- def t5(a, b=None, *args, **kw): 'doc'
- t5.tip = "(a, b=None, *args, **kw)"
-
- doc = '\ndoc' if t1.__doc__ is not None else ''
- for func in (t1, t2, t3, t4, t5, TC):
- self.assertEqual(signature(func), func.tip + doc)
-
- def test_methods(self):
- doc = '\ndoc' if TC.__doc__ is not None else ''
- for meth in (TC.t1, TC.t2, TC.t3, TC.t4, TC.t5, TC.t6, TC.__call__):
- self.assertEqual(signature(meth), meth.tip + doc)
- self.assertEqual(signature(TC.cm), "(a)" + doc)
- self.assertEqual(signature(TC.sm), "(b)" + doc)
-
- def test_bound_methods(self):
- # test that first parameter is correctly removed from argspec
- doc = '\ndoc' if TC.__doc__ is not None else ''
- for meth, mtip in ((tc.t1, "()"), (tc.t4, "(*args)"), (tc.t6, "(self)"),
- (tc.__call__, '(ci)'), (tc, '(ci)'), (TC.cm, "(a)"),):
- self.assertEqual(signature(meth), mtip + doc)
-
- def test_starred_parameter(self):
- # test that starred first parameter is *not* removed from argspec
- class C:
- def m1(*args): pass
- c = C()
- for meth, mtip in ((C.m1, '(*args)'), (c.m1, "(*args)"),):
- self.assertEqual(signature(meth), mtip)
-
- def test_invalid_method_signature(self):
- class C:
- def m2(**kwargs): pass
- class Test:
- def __call__(*, a): pass
-
- mtip = ct._invalid_method
- self.assertEqual(signature(C().m2), mtip)
- self.assertEqual(signature(Test()), mtip)
-
- def test_non_ascii_name(self):
- # test that re works to delete a first parameter name that
- # includes non-ascii chars, such as various forms of A.
- uni = "(A\u0391\u0410\u05d0\u0627\u0905\u1e00\u3042, a)"
- assert ct._first_param.sub('', uni) == '(a)'
-
- def test_no_docstring(self):
- def nd(s):
- pass
- TC.nd = nd
- self.assertEqual(signature(nd), "(s)")
- self.assertEqual(signature(TC.nd), "(s)")
- self.assertEqual(signature(tc.nd), "()")
-
- def test_attribute_exception(self):
- class NoCall:
- def __getattr__(self, name):
- raise BaseException
- class CallA(NoCall):
- def __call__(oui, a, b, c):
- pass
- class CallB(NoCall):
- def __call__(self, ci):
- pass
-
- for meth, mtip in ((NoCall, default_tip), (CallA, default_tip),
- (NoCall(), ''), (CallA(), '(a, b, c)'),
- (CallB(), '(ci)')):
- self.assertEqual(signature(meth), mtip)
-
- def test_non_callables(self):
- for obj in (0, 0.0, '0', b'0', [], {}):
- self.assertEqual(signature(obj), '')
-
-
-class Get_entityTest(unittest.TestCase):
- def test_bad_entity(self):
- self.assertIsNone(ct.get_entity('1/0'))
- def test_good_entity(self):
- self.assertIs(ct.get_entity('int'), int)
-
-if __name__ == '__main__':
- unittest.main(verbosity=2, exit=False)
-"""Test idlelib.codecontext.
-
-Coverage: 100%
-"""
-
-import re
+"Test codecontext, coverage 100%"
+from idlelib import codecontext
import unittest
-from unittest import mock
from test.support import requires
from tkinter import Tk, Frame, Text, TclError
-import idlelib.codecontext as codecontext
+from unittest import mock
+import re
from idlelib import config
-'''Test idlelib/colorizer.py
+"Test colorizer, coverage 25%."
-Perform minimal sanity checks that module imports and some things run.
-
-Coverage 22%.
-'''
-from idlelib import colorizer # always test import
+from idlelib import colorizer
from test.support import requires
from tkinter import Tk, Text
import unittest
def test_colorizer(self):
colorizer.color_config(self.text)
+
class ColorDelegatorTest(unittest.TestCase):
@classmethod
-'''Test idlelib.config.
-
-Coverage: 96% (100% for IdleConfParser, IdleUserConfParser*, ConfigChanges).
+"""Test config, coverage 93%.
+(100% for IdleConfParser, IdleUserConfParser*, ConfigChanges).
* Exception is OSError clause in Save method.
Much of IdleConf is also exercised by ConfigDialog and test_configdialog.
-'''
+"""
+from idlelib import config
import copy
import sys
import os
import unittest
from unittest import mock
import idlelib
-from idlelib import config
from idlelib.idle_test.mock_idle import Func
# Tests should not depend on fortuitous user configurations.
with self.assertRaises(FileNotFoundError):
conf.GetUserCfgDir()
- @unittest.skipIf(not sys.platform.startswith('win'), 'this is test for windows system')
+ @unittest.skipIf(not sys.platform.startswith('win'), 'this is test for Windows system')
def test_get_user_cfg_dir_windows(self):
- "Test to get user config directory under windows"
+ "Test to get user config directory under Windows"
conf = self.new_config(_utest=True)
# Check normal way should success
self.assertCountEqual(
conf.GetSectionList('default', 'main'),
- ['General', 'EditorWindow', 'Indent', 'Theme',
+ ['General', 'EditorWindow', 'PyShell', 'Indent', 'Theme',
'Keys', 'History', 'HelpFiles'])
self.assertCountEqual(
conf.GetSectionList('user', 'main'),
- ['General', 'EditorWindow', 'Indent', 'Theme',
+ ['General', 'EditorWindow', 'PyShell', 'Indent', 'Theme',
'Keys', 'History', 'HelpFiles'])
with self.assertRaises(config.InvalidConfigSet):
self.assertCountEqual(
conf.RemoveKeyBindNames(conf.GetSectionList('default', 'extensions')),
- ['AutoComplete', 'CodeContext', 'FormatParagraph', 'ParenMatch','ZzDummy'])
+ ['AutoComplete', 'CodeContext', 'FormatParagraph', 'ParenMatch', 'ZzDummy'])
def test_get_extn_name_for_event(self):
userextn.read_string('''
-''' Test idlelib.config_key.
+"Test config_key, coverage 75%"
-Coverage: 56% from creating and closing dialog.
-'''
from idlelib import config_key
from test.support import requires
import sys
-"""Test idlelib.configdialog.
+"""Test configdialog, coverage 94%.
Half the class creates dialog, half works with user customizations.
-Coverage: 95%.
"""
from idlelib import configdialog
from test.support import requires
page = cls.page = dialog.fontpage
dialog.note.select(page)
page.set_samples = Func() # Mask instance method.
+ page.update()
@classmethod
def tearDownClass(cls):
@classmethod
def setUpClass(cls):
cls.page = dialog.fontpage
+ cls.page.update()
def test_load_tab_cfg(self):
d = self.page
page.paint_theme_sample = Func()
page.set_highlight_target = Func()
page.set_color_sample = Func()
+ page.update()
@classmethod
def tearDownClass(cls):
dialog.note.select(page)
page.set = page.set_add_delete_state = Func()
page.upc = page.update_help_changes = Func()
+ page.update()
@classmethod
def tearDownClass(cls):
-''' Test idlelib.debugger.
+"Test debugger, coverage 19%"
-Coverage: 19%
-'''
from idlelib import debugger
+import unittest
from test.support import requires
requires('gui')
-import unittest
from tkinter import Tk
debugger.NamespaceViewer(self.root, 'Test')
+# Other classes are Idb, Debugger, and StackViewer.
+
if __name__ == '__main__':
unittest.main(verbosity=2)
--- /dev/null
+"Test debugger_r, coverage 30%."
+
+from idlelib import debugger_r
+import unittest
+from test.support import requires
+from tkinter import Tk
+
+
+class Test(unittest.TestCase):
+
+## @classmethod
+## def setUpClass(cls):
+## requires('gui')
+## cls.root = Tk()
+##
+## @classmethod
+## def tearDownClass(cls):
+## cls.root.destroy()
+## del cls.root
+
+ def test_init(self):
+ self.assertTrue(True) # Get coverage of import
+
+
+# Classes GUIProxy, IdbAdapter, FrameProxy, CodeProxy, DictProxy,
+# GUIAdapter, IdbProxy plus 7 module functions.
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
--- /dev/null
+"Test debugobj, coverage 40%."
+
+from idlelib import debugobj
+import unittest
+
+
+class ObjectTreeItemTest(unittest.TestCase):
+
+ def test_init(self):
+ ti = debugobj.ObjectTreeItem('label', 22)
+ self.assertEqual(ti.labeltext, 'label')
+ self.assertEqual(ti.object, 22)
+ self.assertEqual(ti.setfunction, None)
+
+
+class ClassTreeItemTest(unittest.TestCase):
+
+ def test_isexpandable(self):
+ ti = debugobj.ClassTreeItem('label', 0)
+ self.assertTrue(ti.IsExpandable())
+
+
+class AtomicObjectTreeItemTest(unittest.TestCase):
+
+ def test_isexpandable(self):
+ ti = debugobj.AtomicObjectTreeItem('label', 0)
+ self.assertFalse(ti.IsExpandable())
+
+
+class SequenceTreeItemTest(unittest.TestCase):
+
+ def test_isexpandable(self):
+ ti = debugobj.SequenceTreeItem('label', ())
+ self.assertFalse(ti.IsExpandable())
+ ti = debugobj.SequenceTreeItem('label', (1,))
+ self.assertTrue(ti.IsExpandable())
+
+ def test_keys(self):
+ ti = debugobj.SequenceTreeItem('label', 'abc')
+ self.assertEqual(list(ti.keys()), [0, 1, 2])
+
+
+class DictTreeItemTest(unittest.TestCase):
+
+ def test_isexpandable(self):
+ ti = debugobj.DictTreeItem('label', {})
+ self.assertFalse(ti.IsExpandable())
+ ti = debugobj.DictTreeItem('label', {1:1})
+ self.assertTrue(ti.IsExpandable())
+
+ def test_keys(self):
+ ti = debugobj.DictTreeItem('label', {1:1, 0:0, 2:2})
+ self.assertEqual(ti.keys(), [0, 1, 2])
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
--- /dev/null
+"Test debugobj_r, coverage 56%."
+
+from idlelib import debugobj_r
+import unittest
+
+
+class WrappedObjectTreeItemTest(unittest.TestCase):
+
+ def test_getattr(self):
+ ti = debugobj_r.WrappedObjectTreeItem(list)
+ self.assertEqual(ti.append, list.append)
+
+class StubObjectTreeItemTest(unittest.TestCase):
+
+ def test_init(self):
+ ti = debugobj_r.StubObjectTreeItem('socket', 1111)
+ self.assertEqual(ti.sockio, 'socket')
+ self.assertEqual(ti.oid, 1111)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
-import unittest
+"Test delegator, coverage 100%."
+
from idlelib.delegator import Delegator
+import unittest
+
class DelegatorTest(unittest.TestCase):
self.assertEqual(mydel._Delegator__cache, set())
self.assertIs(mydel.delegate, float)
+
if __name__ == '__main__':
unittest.main(verbosity=2, exit=2)
+"Test editor, coverage 35%."
+
+from idlelib import editor
import unittest
-from idlelib.editor import EditorWindow
+from test.support import requires
+from tkinter import Tk
+
+Editor = editor.EditorWindow
+
+
+class EditorWindowTest(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ requires('gui')
+ cls.root = Tk()
+ cls.root.withdraw()
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.root.update_idletasks()
+ for id in cls.root.tk.call('after', 'info'):
+ cls.root.after_cancel(id)
+ cls.root.destroy()
+ del cls.root
+
+ def test_init(self):
+ e = Editor(root=self.root)
+ self.assertEqual(e.root, self.root)
+ e._close()
+
+
+class EditorFunctionTest(unittest.TestCase):
-class Editor_func_test(unittest.TestCase):
def test_filename_to_unicode(self):
- func = EditorWindow._filename_to_unicode
- class dummy(): filesystemencoding = 'utf-8'
+ func = Editor._filename_to_unicode
+ class dummy():
+ filesystemencoding = 'utf-8'
pairs = (('abc', 'abc'), ('a\U00011111c', 'a\ufffdc'),
(b'abc', 'abc'), (b'a\xf0\x91\x84\x91c', 'a\ufffdc'))
for inp, out in pairs:
self.assertEqual(func(dummy, inp), out)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
--- /dev/null
+"Test filelist, coverage 19%."
+
+from idlelib import filelist
+import unittest
+from test.support import requires
+from tkinter import Tk
+
+class FileListTest(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ requires('gui')
+ cls.root = Tk()
+ cls.root.withdraw()
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.root.update_idletasks()
+ for id in cls.root.tk.call('after', 'info'):
+ cls.root.after_cancel(id)
+ cls.root.destroy()
+ del cls.root
+
+ def test_new_empty(self):
+ flist = filelist.FileList(self.root)
+ self.assertEqual(flist.root, self.root)
+ e = flist.new()
+ self.assertEqual(type(e), flist.EditorWindow)
+ e._close()
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
dummy_command calls grep_it calls findfiles.
An exception raised in one method will fail callers.
Otherwise, tests are mostly independent.
-*** Currently only test grep_it.
+Currently only test grep_it, coverage 51%.
"""
+from idlelib.grep import GrepDialog
import unittest
from test.support import captured_stdout
from idlelib.idle_test.mock_tk import Var
-from idlelib.grep import GrepDialog
import re
+
class Dummy_searchengine:
'''GrepDialog.__init__ calls parent SearchDiabolBase which attaches the
passed in SearchEngine instance as attribute 'engine'. Only a few of the
searchengine = Dummy_searchengine()
+
class Dummy_grep:
# Methods tested
#default_command = GrepDialog.default_command
grep = Dummy_grep()
+
class FindfilesTest(unittest.TestCase):
# findfiles is really a function, not a method, could be iterator
# test that filename return filename
# test that recursive flag adds idle_test .py files
pass
+
class Grep_itTest(unittest.TestCase):
# Test captured reports with 0 and some hits.
# Should test file names, but Windows reports have mixed / and \ separators
self.assertIn('2', lines[3]) # hits found 2
self.assertTrue(lines[4].startswith('(Hint:'))
+
class Default_commandTest(unittest.TestCase):
# To write this, move outwin import to top of GrepDialog
# so it can be replaced by captured_stdout in class setup/teardown.
pass
+
if __name__ == '__main__':
- unittest.main(verbosity=2, exit=False)
+ unittest.main(verbosity=2)
-'''Test idlelib.help.
+"Test help, coverage 87%."
-Coverage: 87%
-'''
from idlelib import help
+import unittest
from test.support import requires
requires('gui')
from os.path import abspath, dirname, join
from tkinter import Tk
-import unittest
+
class HelpFrameTest(unittest.TestCase):
text = self.frame.text
self.assertEqual(text.get('1.0', '1.end'), ' IDLE ')
+
if __name__ == '__main__':
unittest.main(verbosity=2)
-'''Test idlelib.help_about.
+"""Test help_about, coverage 100%.
+help_about.build_bits branches on sys.platform='darwin'.
+'100% combines coverage on Mac and others.
+"""
-Coverage: 100%
-'''
+from idlelib import help_about
+import unittest
from test.support import requires, findfile
from tkinter import Tk, TclError
-import unittest
-from unittest import mock
from idlelib.idle_test.mock_idle import Func
from idlelib.idle_test.mock_tk import Mbox_func
-from idlelib.help_about import AboutDialog as About
-from idlelib import help_about
from idlelib import textview
import os.path
-from platform import python_version, architecture
+from platform import python_version
+
+About = help_about.AboutDialog
class LiveDialogTest(unittest.TestCase):
+" Test history, coverage 100%."
+
+from idlelib.history import History
import unittest
from test.support import requires
import tkinter as tk
from tkinter import Text as tkText
from idlelib.idle_test.mock_tk import Text as mkText
-from idlelib.history import History
from idlelib.config import idleConf
line1 = 'a = 7'
line2 = 'b = a'
+
class StoreTest(unittest.TestCase):
'''Tests History.__init__ and History.store with mock Text'''
def bell(self):
self._bell = True
+
class FetchTest(unittest.TestCase):
'''Test History.fetch with wrapped tk.Text.
'''
-"""Unittest for idlelib.hyperparser.py."""
+"Test hyperparser, coverage 98%."
+
+from idlelib.hyperparser import HyperParser
import unittest
from test.support import requires
from tkinter import Tk, Text
from idlelib.editor import EditorWindow
-from idlelib.hyperparser import HyperParser
class DummyEditwin:
def __init__(self, text):
self.assertEqual(eat_id('2' + 'a' * (length - 1), 0, length), 0)
self.assertEqual(eat_id('2' + 'é' * (length - 1), 0, length), 0)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
-import unittest
-import io
-
-from idlelib.run import PseudoInputFile, PseudoOutputFile
-
-
-class S(str):
- def __str__(self):
- return '%s:str' % type(self).__name__
- def __unicode__(self):
- return '%s:unicode' % type(self).__name__
- def __len__(self):
- return 3
- def __iter__(self):
- return iter('abc')
- def __getitem__(self, *args):
- return '%s:item' % type(self).__name__
- def __getslice__(self, *args):
- return '%s:slice' % type(self).__name__
-
-class MockShell:
- def __init__(self):
- self.reset()
-
- def write(self, *args):
- self.written.append(args)
-
- def readline(self):
- return self.lines.pop()
-
- def close(self):
- pass
-
- def reset(self):
- self.written = []
-
- def push(self, lines):
- self.lines = list(lines)[::-1]
-
-
-class PseudeOutputFilesTest(unittest.TestCase):
- def test_misc(self):
- shell = MockShell()
- f = PseudoOutputFile(shell, 'stdout', 'utf-8')
- self.assertIsInstance(f, io.TextIOBase)
- self.assertEqual(f.encoding, 'utf-8')
- self.assertIsNone(f.errors)
- self.assertIsNone(f.newlines)
- self.assertEqual(f.name, '<stdout>')
- self.assertFalse(f.closed)
- self.assertTrue(f.isatty())
- self.assertFalse(f.readable())
- self.assertTrue(f.writable())
- self.assertFalse(f.seekable())
-
- def test_unsupported(self):
- shell = MockShell()
- f = PseudoOutputFile(shell, 'stdout', 'utf-8')
- self.assertRaises(OSError, f.fileno)
- self.assertRaises(OSError, f.tell)
- self.assertRaises(OSError, f.seek, 0)
- self.assertRaises(OSError, f.read, 0)
- self.assertRaises(OSError, f.readline, 0)
-
- def test_write(self):
- shell = MockShell()
- f = PseudoOutputFile(shell, 'stdout', 'utf-8')
- f.write('test')
- self.assertEqual(shell.written, [('test', 'stdout')])
- shell.reset()
- f.write('t\xe8st')
- self.assertEqual(shell.written, [('t\xe8st', 'stdout')])
- shell.reset()
-
- f.write(S('t\xe8st'))
- self.assertEqual(shell.written, [('t\xe8st', 'stdout')])
- self.assertEqual(type(shell.written[0][0]), str)
- shell.reset()
+"Test , coverage 16%."
- self.assertRaises(TypeError, f.write)
- self.assertEqual(shell.written, [])
- self.assertRaises(TypeError, f.write, b'test')
- self.assertRaises(TypeError, f.write, 123)
- self.assertEqual(shell.written, [])
- self.assertRaises(TypeError, f.write, 'test', 'spam')
- self.assertEqual(shell.written, [])
-
- def test_writelines(self):
- shell = MockShell()
- f = PseudoOutputFile(shell, 'stdout', 'utf-8')
- f.writelines([])
- self.assertEqual(shell.written, [])
- shell.reset()
- f.writelines(['one\n', 'two'])
- self.assertEqual(shell.written,
- [('one\n', 'stdout'), ('two', 'stdout')])
- shell.reset()
- f.writelines(['on\xe8\n', 'tw\xf2'])
- self.assertEqual(shell.written,
- [('on\xe8\n', 'stdout'), ('tw\xf2', 'stdout')])
- shell.reset()
-
- f.writelines([S('t\xe8st')])
- self.assertEqual(shell.written, [('t\xe8st', 'stdout')])
- self.assertEqual(type(shell.written[0][0]), str)
- shell.reset()
-
- self.assertRaises(TypeError, f.writelines)
- self.assertEqual(shell.written, [])
- self.assertRaises(TypeError, f.writelines, 123)
- self.assertEqual(shell.written, [])
- self.assertRaises(TypeError, f.writelines, [b'test'])
- self.assertRaises(TypeError, f.writelines, [123])
- self.assertEqual(shell.written, [])
- self.assertRaises(TypeError, f.writelines, [], [])
- self.assertEqual(shell.written, [])
-
- def test_close(self):
- shell = MockShell()
- f = PseudoOutputFile(shell, 'stdout', 'utf-8')
- self.assertFalse(f.closed)
- f.write('test')
- f.close()
- self.assertTrue(f.closed)
- self.assertRaises(ValueError, f.write, 'x')
- self.assertEqual(shell.written, [('test', 'stdout')])
- f.close()
- self.assertRaises(TypeError, f.close, 1)
-
-
-class PseudeInputFilesTest(unittest.TestCase):
- def test_misc(self):
- shell = MockShell()
- f = PseudoInputFile(shell, 'stdin', 'utf-8')
- self.assertIsInstance(f, io.TextIOBase)
- self.assertEqual(f.encoding, 'utf-8')
- self.assertIsNone(f.errors)
- self.assertIsNone(f.newlines)
- self.assertEqual(f.name, '<stdin>')
- self.assertFalse(f.closed)
- self.assertTrue(f.isatty())
- self.assertTrue(f.readable())
- self.assertFalse(f.writable())
- self.assertFalse(f.seekable())
-
- def test_unsupported(self):
- shell = MockShell()
- f = PseudoInputFile(shell, 'stdin', 'utf-8')
- self.assertRaises(OSError, f.fileno)
- self.assertRaises(OSError, f.tell)
- self.assertRaises(OSError, f.seek, 0)
- self.assertRaises(OSError, f.write, 'x')
- self.assertRaises(OSError, f.writelines, ['x'])
-
- def test_read(self):
- shell = MockShell()
- f = PseudoInputFile(shell, 'stdin', 'utf-8')
- shell.push(['one\n', 'two\n', ''])
- self.assertEqual(f.read(), 'one\ntwo\n')
- shell.push(['one\n', 'two\n', ''])
- self.assertEqual(f.read(-1), 'one\ntwo\n')
- shell.push(['one\n', 'two\n', ''])
- self.assertEqual(f.read(None), 'one\ntwo\n')
- shell.push(['one\n', 'two\n', 'three\n', ''])
- self.assertEqual(f.read(2), 'on')
- self.assertEqual(f.read(3), 'e\nt')
- self.assertEqual(f.read(10), 'wo\nthree\n')
-
- shell.push(['one\n', 'two\n'])
- self.assertEqual(f.read(0), '')
- self.assertRaises(TypeError, f.read, 1.5)
- self.assertRaises(TypeError, f.read, '1')
- self.assertRaises(TypeError, f.read, 1, 1)
-
- def test_readline(self):
- shell = MockShell()
- f = PseudoInputFile(shell, 'stdin', 'utf-8')
- shell.push(['one\n', 'two\n', 'three\n', 'four\n'])
- self.assertEqual(f.readline(), 'one\n')
- self.assertEqual(f.readline(-1), 'two\n')
- self.assertEqual(f.readline(None), 'three\n')
- shell.push(['one\ntwo\n'])
- self.assertEqual(f.readline(), 'one\n')
- self.assertEqual(f.readline(), 'two\n')
- shell.push(['one', 'two', 'three'])
- self.assertEqual(f.readline(), 'one')
- self.assertEqual(f.readline(), 'two')
- shell.push(['one\n', 'two\n', 'three\n'])
- self.assertEqual(f.readline(2), 'on')
- self.assertEqual(f.readline(1), 'e')
- self.assertEqual(f.readline(1), '\n')
- self.assertEqual(f.readline(10), 'two\n')
-
- shell.push(['one\n', 'two\n'])
- self.assertEqual(f.readline(0), '')
- self.assertRaises(TypeError, f.readlines, 1.5)
- self.assertRaises(TypeError, f.readlines, '1')
- self.assertRaises(TypeError, f.readlines, 1, 1)
-
- def test_readlines(self):
- shell = MockShell()
- f = PseudoInputFile(shell, 'stdin', 'utf-8')
- shell.push(['one\n', 'two\n', ''])
- self.assertEqual(f.readlines(), ['one\n', 'two\n'])
- shell.push(['one\n', 'two\n', ''])
- self.assertEqual(f.readlines(-1), ['one\n', 'two\n'])
- shell.push(['one\n', 'two\n', ''])
- self.assertEqual(f.readlines(None), ['one\n', 'two\n'])
- shell.push(['one\n', 'two\n', ''])
- self.assertEqual(f.readlines(0), ['one\n', 'two\n'])
- shell.push(['one\n', 'two\n', ''])
- self.assertEqual(f.readlines(3), ['one\n'])
- shell.push(['one\n', 'two\n', ''])
- self.assertEqual(f.readlines(4), ['one\n', 'two\n'])
-
- shell.push(['one\n', 'two\n', ''])
- self.assertRaises(TypeError, f.readlines, 1.5)
- self.assertRaises(TypeError, f.readlines, '1')
- self.assertRaises(TypeError, f.readlines, 1, 1)
-
- def test_close(self):
- shell = MockShell()
- f = PseudoInputFile(shell, 'stdin', 'utf-8')
- shell.push(['one\n', 'two\n', ''])
- self.assertFalse(f.closed)
- self.assertEqual(f.readline(), 'one\n')
- f.close()
- self.assertFalse(f.closed)
- self.assertEqual(f.readline(), 'two\n')
- self.assertRaises(TypeError, f.close, 1)
+from idlelib import iomenu
+import unittest
+from test.support import requires
+from tkinter import Tk
+
+from idlelib.editor import EditorWindow
+
+
+class IOBindigTest(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ requires('gui')
+ cls.root = Tk()
+ cls.root.withdraw()
+ cls.editwin = EditorWindow(root=cls.root)
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.editwin._close()
+ del cls.editwin
+ cls.root.update_idletasks()
+ for id in cls.root.tk.call('after', 'info'):
+ cls.root.after_cancel(id) # Need for EditorWindow.
+ cls.root.destroy()
+ del cls.root
+
+ def test_init(self):
+ io = iomenu.IOBinding(self.editwin)
+ self.assertIs(io.editwin, self.editwin)
+ io.close
if __name__ == '__main__':
-'''Test idlelib.macosx.py.
+"Test macosx, coverage 45% on Windows."
-Coverage: 71% on Windows.
-'''
from idlelib import macosx
+import unittest
from test.support import requires
import tkinter as tk
-import unittest
import unittest.mock as mock
from idlelib.filelist import FileList
--- /dev/null
+"Test mainmenu, coverage 100%."
+# Reported as 88%; mocking turtledemo absence would have no point.
+
+from idlelib import mainmenu
+import unittest
+
+
+class MainMenuTest(unittest.TestCase):
+
+ def test_menudefs(self):
+ actual = [item[0] for item in mainmenu.menudefs]
+ expect = ['file', 'edit', 'format', 'run', 'shell',
+ 'debug', 'options', 'window', 'help']
+ self.assertEqual(actual, expect)
+
+ def test_default_keydefs(self):
+ self.assertGreaterEqual(len(mainmenu.default_keydefs), 50)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
--- /dev/null
+"Test multicall, coverage 33%."
+
+from idlelib import multicall
+import unittest
+from test.support import requires
+from tkinter import Tk, Text
+
+
+class MultiCallTest(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ requires('gui')
+ cls.root = Tk()
+ cls.root.withdraw()
+ cls.mc = multicall.MultiCallCreator(Text)
+
+ @classmethod
+ def tearDownClass(cls):
+ del cls.mc
+ cls.root.update_idletasks()
+## for id in cls.root.tk.call('after', 'info'):
+## cls.root.after_cancel(id) # Need for EditorWindow.
+ cls.root.destroy()
+ del cls.root
+
+ def test_creator(self):
+ mc = self.mc
+ self.assertIs(multicall._multicall_dict[Text], mc)
+ self.assertTrue(issubclass(mc, Text))
+ mc2 = multicall.MultiCallCreator(Text)
+ self.assertIs(mc, mc2)
+
+ def test_init(self):
+ mctext = self.mc(self.root)
+ self.assertIsInstance(mctext._MultiCall__binders, list)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
-""" Test idlelib.outwin.
-"""
+"Test outwin, coverage 76%."
+from idlelib import outwin
import unittest
+from test.support import requires
from tkinter import Tk, Text
from idlelib.idle_test.mock_tk import Mbox_func
from idlelib.idle_test.mock_idle import Func
-from idlelib import outwin
-from test.support import requires
from unittest import mock
-# Test the functions and main class method of paragraph.py
+"Test paragraph, coverage 76%."
+
+from idlelib import paragraph as pg
import unittest
-from idlelib import paragraph as fp
-from idlelib.editor import EditorWindow
-from tkinter import Tk, Text
from test.support import requires
+from tkinter import Tk, Text
+from idlelib.editor import EditorWindow
class Is_Get_Test(unittest.TestCase):
leadingws_nocomment = ' This is not a comment'
def test_is_all_white(self):
- self.assertTrue(fp.is_all_white(''))
- self.assertTrue(fp.is_all_white('\t\n\r\f\v'))
- self.assertFalse(fp.is_all_white(self.test_comment))
+ self.assertTrue(pg.is_all_white(''))
+ self.assertTrue(pg.is_all_white('\t\n\r\f\v'))
+ self.assertFalse(pg.is_all_white(self.test_comment))
def test_get_indent(self):
Equal = self.assertEqual
- Equal(fp.get_indent(self.test_comment), '')
- Equal(fp.get_indent(self.trailingws_comment), '')
- Equal(fp.get_indent(self.leadingws_comment), ' ')
- Equal(fp.get_indent(self.leadingws_nocomment), ' ')
+ Equal(pg.get_indent(self.test_comment), '')
+ Equal(pg.get_indent(self.trailingws_comment), '')
+ Equal(pg.get_indent(self.leadingws_comment), ' ')
+ Equal(pg.get_indent(self.leadingws_nocomment), ' ')
def test_get_comment_header(self):
Equal = self.assertEqual
# Test comment strings
- Equal(fp.get_comment_header(self.test_comment), '#')
- Equal(fp.get_comment_header(self.trailingws_comment), '#')
- Equal(fp.get_comment_header(self.leadingws_comment), ' #')
+ Equal(pg.get_comment_header(self.test_comment), '#')
+ Equal(pg.get_comment_header(self.trailingws_comment), '#')
+ Equal(pg.get_comment_header(self.leadingws_comment), ' #')
# Test non-comment strings
- Equal(fp.get_comment_header(self.leadingws_nocomment), ' ')
- Equal(fp.get_comment_header(self.test_nocomment), '')
+ Equal(pg.get_comment_header(self.leadingws_nocomment), ' ')
+ Equal(pg.get_comment_header(self.test_nocomment), '')
class FindTest(unittest.TestCase):
linelength = int(text.index("%d.end" % line).split('.')[1])
for col in (0, linelength//2, linelength):
tempindex = "%d.%d" % (line, col)
- self.assertEqual(fp.find_paragraph(text, tempindex), expected)
+ self.assertEqual(pg.find_paragraph(text, tempindex), expected)
text.delete('1.0', 'end')
def test_find_comment(self):
def test_reformat_paragraph(self):
Equal = self.assertEqual
- reform = fp.reformat_paragraph
+ reform = pg.reformat_paragraph
hw = "O hello world"
Equal(reform(' ', 1), ' ')
Equal(reform("Hello world", 20), "Hello world")
test_string = (
" \"\"\"this is a test of a reformat for a triple quoted string"
" will it reformat to less than 70 characters for me?\"\"\"")
- result = fp.reformat_comment(test_string, 70, " ")
+ result = pg.reformat_comment(test_string, 70, " ")
expected = (
" \"\"\"this is a test of a reformat for a triple quoted string will it\n"
" reformat to less than 70 characters for me?\"\"\"")
test_comment = (
"# this is a test of a reformat for a triple quoted string will "
"it reformat to less than 70 characters for me?")
- result = fp.reformat_comment(test_comment, 70, "#")
+ result = pg.reformat_comment(test_comment, 70, "#")
expected = (
"# this is a test of a reformat for a triple quoted string will it\n"
"# reformat to less than 70 characters for me?")
class FormatClassTest(unittest.TestCase):
def test_init_close(self):
- instance = fp.FormatParagraph('editor')
+ instance = pg.FormatParagraph('editor')
self.assertEqual(instance.editwin, 'editor')
instance.close()
self.assertEqual(instance.editwin, None)
def setUpClass(cls):
requires('gui')
cls.root = Tk()
+ cls.root.withdraw()
editor = Editor(root=cls.root)
cls.text = editor.text.text # Test code does not need the wrapper.
- cls.formatter = fp.FormatParagraph(editor).format_paragraph_event
+ cls.formatter = pg.FormatParagraph(editor).format_paragraph_event
# Sets the insert mark just after the re-wrapped and inserted text.
@classmethod
def tearDownClass(cls):
del cls.text, cls.formatter
+ cls.root.update_idletasks()
cls.root.destroy()
del cls.root
-'''Test idlelib.parenmatch.
+"""Test parenmatch, coverage 91%.
This must currently be a gui test because ParenMatch methods use
several text methods not defined on idlelib.idle_test.mock_tk.Text.
-'''
+"""
from idlelib.parenmatch import ParenMatch
from test.support import requires
requires('gui')
-""" Test idlelib.pathbrowser.
-"""
+"Test pathbrowser, coverage 95%."
+from idlelib import pathbrowser
+import unittest
+from test.support import requires
+from tkinter import Tk
import os.path
import pyclbr # for _modules
import sys # for sys.path
-from tkinter import Tk
-from test.support import requires
-import unittest
from idlelib.idle_test.mock_idle import Func
-
import idlelib # for __file__
from idlelib import browser
-from idlelib import pathbrowser
from idlelib.tree import TreeNode
-'''Test percolator.py.'''
-from test.support import requires
-requires('gui')
+"Test percolator, coverage 100%."
+from idlelib.percolator import Percolator, Delegator
import unittest
+from test.support import requires
+requires('gui')
from tkinter import Text, Tk, END
-from idlelib.percolator import Percolator, Delegator
class MyFilter(Delegator):
-"""Unittest for idlelib.pyparse.py.
+"Test pyparse, coverage 96%."
-Coverage: 97%
-"""
-
-from collections import namedtuple
-import unittest
from idlelib import pyparse
+import unittest
+from collections import namedtuple
class ParseMapTest(unittest.TestCase):
--- /dev/null
+"Test pyshell, coverage 12%."
+# Plus coverage of test_warning. Was 20% with test_openshell.
+
+from idlelib import pyshell
+import unittest
+from test.support import requires
+from tkinter import Tk
+
+
+class PyShellFileListTest(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ requires('gui')
+ cls.root = Tk()
+ cls.root.withdraw()
+
+ @classmethod
+ def tearDownClass(cls):
+ #cls.root.update_idletasks()
+## for id in cls.root.tk.call('after', 'info'):
+## cls.root.after_cancel(id) # Need for EditorWindow.
+ cls.root.destroy()
+ del cls.root
+
+ def test_init(self):
+ psfl = pyshell.PyShellFileList(self.root)
+ self.assertEqual(psfl.EditorWindow, pyshell.PyShellEditorWindow)
+ self.assertIsNone(psfl.pyshell)
+
+# The following sometimes causes 'invalid command name "109734456recolorize"'.
+# Uncommenting after_cancel above prevents this, but results in
+# TclError: bad window path name ".!listedtoplevel.!frame.text"
+# which is normally prevented by after_cancel.
+## def test_openshell(self):
+## pyshell.use_subprocess = False
+## ps = pyshell.PyShellFileList(self.root).open_shell()
+## self.assertIsInstance(ps, pyshell.PyShell)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
-"""Test idlelib.query.
+"""Test query, coverage 91%).
Non-gui tests for Query, SectionName, ModuleName, and HelpSource use
dummy versions that extract the non-gui methods and add other needed
The appearance of the widgets is checked by the Query and
HelpSource htests. These are run by running query.py.
-
-Coverage: 94% (100% for Query and SectionName).
-6 of 8 missing are ModuleName exceptions I don't know how to trigger.
"""
+from idlelib import query
+import unittest
from test.support import requires
-import sys
from tkinter import Tk
-import unittest
+
+import sys
from unittest import mock
from idlelib.idle_test.mock_tk import Var
-from idlelib import query
# NON-GUI TESTS
-'''Test idlelib.redirector.
+"Test redirector, coverage 100%."
-100% coverage
-'''
-from test.support import requires
+from idlelib.redirector import WidgetRedirector
import unittest
-from idlelib.idle_test.mock_idle import Func
+from test.support import requires
from tkinter import Tk, Text, TclError
-from idlelib.redirector import WidgetRedirector
+from idlelib.idle_test.mock_idle import Func
class InitCloseTest(unittest.TestCase):
-"""Unittest for idlelib.replace.py"""
+"Test replace, coverage 78%."
+
+from idlelib.replace import ReplaceDialog
+import unittest
from test.support import requires
requires('gui')
+from tkinter import Tk, Text
-import unittest
from unittest.mock import Mock
-from tkinter import Tk, Text
from idlelib.idle_test.mock_tk import Mbox
import idlelib.searchengine as se
-from idlelib.replace import ReplaceDialog
orig_mbox = se.tkMessageBox
showerror = Mbox.showerror
--- /dev/null
+"Test rpc, coverage 20%."
+
+from idlelib import rpc
+import unittest
+
+import marshal
+
+
+class CodePicklerTest(unittest.TestCase):
+
+ def test_pickle_unpickle(self):
+ def f(): return a + b + c
+ func, (cbytes,) = rpc.pickle_code(f.__code__)
+ self.assertIs(func, rpc.unpickle_code)
+ self.assertIn(b'test_rpc.py', cbytes)
+ code = rpc.unpickle_code(cbytes)
+ self.assertEqual(code.co_names, ('a', 'b', 'c'))
+
+ def test_code_pickler(self):
+ self.assertIn(type((lambda:None).__code__),
+ rpc.CodePickler.dispatch_table)
+
+ def test_dumps(self):
+ def f(): pass
+ # The main test here is that pickling code does not raise.
+ self.assertIn(b'test_rpc.py', rpc.dumps(f.__code__))
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
+"Test rstrip, coverage 100%."
+
+from idlelib import rstrip
import unittest
-import idlelib.rstrip as rs
from idlelib.idle_test.mock_idle import Editor
class rstripTest(unittest.TestCase):
def test_rstrip_line(self):
editor = Editor()
text = editor.text
- do_rstrip = rs.RstripExtension(editor).do_rstrip
+ do_rstrip = rstrip.Rstrip(editor).do_rstrip
do_rstrip()
self.assertEqual(text.get('1.0', 'insert'), '')
def test_rstrip_multiple(self):
editor = Editor()
- # Uncomment following to verify that test passes with real widgets.
-## from idlelib.editor import EditorWindow as Editor
-## from tkinter import Tk
-## editor = Editor(root=Tk())
+ # Comment above, uncomment 3 below to test with real Editor & Text.
+ #from idlelib.editor import EditorWindow as Editor
+ #from tkinter import Tk
+ #editor = Editor(root=Tk())
text = editor.text
- do_rstrip = rs.RstripExtension(editor).do_rstrip
+ do_rstrip = rstrip.Rstrip(editor).do_rstrip
original = (
"Line with an ending tab \n"
do_rstrip()
self.assertEqual(text.get('1.0', 'insert'), stripped)
+
+
if __name__ == '__main__':
- unittest.main(verbosity=2, exit=False)
+ unittest.main(verbosity=2)
+"Test run, coverage 42%."
+
+from idlelib import run
import unittest
from unittest import mock
-
from test.support import captured_stderr
-import idlelib.run as idlerun
+import io
class RunTest(unittest.TestCase):
+
def test_print_exception_unhashable(self):
class UnhashableException(Exception):
def __eq__(self, other):
raise ex1
except UnhashableException:
with captured_stderr() as output:
- with mock.patch.object(idlerun,
+ with mock.patch.object(run,
'cleanup_traceback') as ct:
ct.side_effect = lambda t, e: t
- idlerun.print_exception()
+ run.print_exception()
tb = output.getvalue().strip().splitlines()
self.assertEqual(11, len(tb))
self.assertIn('UnhashableException: ex1', tb[10])
+# PseudoFile tests.
+
+class S(str):
+ def __str__(self):
+ return '%s:str' % type(self).__name__
+ def __unicode__(self):
+ return '%s:unicode' % type(self).__name__
+ def __len__(self):
+ return 3
+ def __iter__(self):
+ return iter('abc')
+ def __getitem__(self, *args):
+ return '%s:item' % type(self).__name__
+ def __getslice__(self, *args):
+ return '%s:slice' % type(self).__name__
+
+
+class MockShell:
+ def __init__(self):
+ self.reset()
+ def write(self, *args):
+ self.written.append(args)
+ def readline(self):
+ return self.lines.pop()
+ def close(self):
+ pass
+ def reset(self):
+ self.written = []
+ def push(self, lines):
+ self.lines = list(lines)[::-1]
+
+
+class PseudeInputFilesTest(unittest.TestCase):
+
+ def test_misc(self):
+ shell = MockShell()
+ f = run.PseudoInputFile(shell, 'stdin', 'utf-8')
+ self.assertIsInstance(f, io.TextIOBase)
+ self.assertEqual(f.encoding, 'utf-8')
+ self.assertIsNone(f.errors)
+ self.assertIsNone(f.newlines)
+ self.assertEqual(f.name, '<stdin>')
+ self.assertFalse(f.closed)
+ self.assertTrue(f.isatty())
+ self.assertTrue(f.readable())
+ self.assertFalse(f.writable())
+ self.assertFalse(f.seekable())
+
+ def test_unsupported(self):
+ shell = MockShell()
+ f = run.PseudoInputFile(shell, 'stdin', 'utf-8')
+ self.assertRaises(OSError, f.fileno)
+ self.assertRaises(OSError, f.tell)
+ self.assertRaises(OSError, f.seek, 0)
+ self.assertRaises(OSError, f.write, 'x')
+ self.assertRaises(OSError, f.writelines, ['x'])
+
+ def test_read(self):
+ shell = MockShell()
+ f = run.PseudoInputFile(shell, 'stdin', 'utf-8')
+ shell.push(['one\n', 'two\n', ''])
+ self.assertEqual(f.read(), 'one\ntwo\n')
+ shell.push(['one\n', 'two\n', ''])
+ self.assertEqual(f.read(-1), 'one\ntwo\n')
+ shell.push(['one\n', 'two\n', ''])
+ self.assertEqual(f.read(None), 'one\ntwo\n')
+ shell.push(['one\n', 'two\n', 'three\n', ''])
+ self.assertEqual(f.read(2), 'on')
+ self.assertEqual(f.read(3), 'e\nt')
+ self.assertEqual(f.read(10), 'wo\nthree\n')
+
+ shell.push(['one\n', 'two\n'])
+ self.assertEqual(f.read(0), '')
+ self.assertRaises(TypeError, f.read, 1.5)
+ self.assertRaises(TypeError, f.read, '1')
+ self.assertRaises(TypeError, f.read, 1, 1)
+
+ def test_readline(self):
+ shell = MockShell()
+ f = run.PseudoInputFile(shell, 'stdin', 'utf-8')
+ shell.push(['one\n', 'two\n', 'three\n', 'four\n'])
+ self.assertEqual(f.readline(), 'one\n')
+ self.assertEqual(f.readline(-1), 'two\n')
+ self.assertEqual(f.readline(None), 'three\n')
+ shell.push(['one\ntwo\n'])
+ self.assertEqual(f.readline(), 'one\n')
+ self.assertEqual(f.readline(), 'two\n')
+ shell.push(['one', 'two', 'three'])
+ self.assertEqual(f.readline(), 'one')
+ self.assertEqual(f.readline(), 'two')
+ shell.push(['one\n', 'two\n', 'three\n'])
+ self.assertEqual(f.readline(2), 'on')
+ self.assertEqual(f.readline(1), 'e')
+ self.assertEqual(f.readline(1), '\n')
+ self.assertEqual(f.readline(10), 'two\n')
+
+ shell.push(['one\n', 'two\n'])
+ self.assertEqual(f.readline(0), '')
+ self.assertRaises(TypeError, f.readlines, 1.5)
+ self.assertRaises(TypeError, f.readlines, '1')
+ self.assertRaises(TypeError, f.readlines, 1, 1)
+
+ def test_readlines(self):
+ shell = MockShell()
+ f = run.PseudoInputFile(shell, 'stdin', 'utf-8')
+ shell.push(['one\n', 'two\n', ''])
+ self.assertEqual(f.readlines(), ['one\n', 'two\n'])
+ shell.push(['one\n', 'two\n', ''])
+ self.assertEqual(f.readlines(-1), ['one\n', 'two\n'])
+ shell.push(['one\n', 'two\n', ''])
+ self.assertEqual(f.readlines(None), ['one\n', 'two\n'])
+ shell.push(['one\n', 'two\n', ''])
+ self.assertEqual(f.readlines(0), ['one\n', 'two\n'])
+ shell.push(['one\n', 'two\n', ''])
+ self.assertEqual(f.readlines(3), ['one\n'])
+ shell.push(['one\n', 'two\n', ''])
+ self.assertEqual(f.readlines(4), ['one\n', 'two\n'])
+
+ shell.push(['one\n', 'two\n', ''])
+ self.assertRaises(TypeError, f.readlines, 1.5)
+ self.assertRaises(TypeError, f.readlines, '1')
+ self.assertRaises(TypeError, f.readlines, 1, 1)
+
+ def test_close(self):
+ shell = MockShell()
+ f = run.PseudoInputFile(shell, 'stdin', 'utf-8')
+ shell.push(['one\n', 'two\n', ''])
+ self.assertFalse(f.closed)
+ self.assertEqual(f.readline(), 'one\n')
+ f.close()
+ self.assertFalse(f.closed)
+ self.assertEqual(f.readline(), 'two\n')
+ self.assertRaises(TypeError, f.close, 1)
+
+
+class PseudeOutputFilesTest(unittest.TestCase):
+
+ def test_misc(self):
+ shell = MockShell()
+ f = run.PseudoOutputFile(shell, 'stdout', 'utf-8')
+ self.assertIsInstance(f, io.TextIOBase)
+ self.assertEqual(f.encoding, 'utf-8')
+ self.assertIsNone(f.errors)
+ self.assertIsNone(f.newlines)
+ self.assertEqual(f.name, '<stdout>')
+ self.assertFalse(f.closed)
+ self.assertTrue(f.isatty())
+ self.assertFalse(f.readable())
+ self.assertTrue(f.writable())
+ self.assertFalse(f.seekable())
+
+ def test_unsupported(self):
+ shell = MockShell()
+ f = run.PseudoOutputFile(shell, 'stdout', 'utf-8')
+ self.assertRaises(OSError, f.fileno)
+ self.assertRaises(OSError, f.tell)
+ self.assertRaises(OSError, f.seek, 0)
+ self.assertRaises(OSError, f.read, 0)
+ self.assertRaises(OSError, f.readline, 0)
+
+ def test_write(self):
+ shell = MockShell()
+ f = run.PseudoOutputFile(shell, 'stdout', 'utf-8')
+ f.write('test')
+ self.assertEqual(shell.written, [('test', 'stdout')])
+ shell.reset()
+ f.write('t\xe8st')
+ self.assertEqual(shell.written, [('t\xe8st', 'stdout')])
+ shell.reset()
+
+ f.write(S('t\xe8st'))
+ self.assertEqual(shell.written, [('t\xe8st', 'stdout')])
+ self.assertEqual(type(shell.written[0][0]), str)
+ shell.reset()
+
+ self.assertRaises(TypeError, f.write)
+ self.assertEqual(shell.written, [])
+ self.assertRaises(TypeError, f.write, b'test')
+ self.assertRaises(TypeError, f.write, 123)
+ self.assertEqual(shell.written, [])
+ self.assertRaises(TypeError, f.write, 'test', 'spam')
+ self.assertEqual(shell.written, [])
+
+ def test_writelines(self):
+ shell = MockShell()
+ f = run.PseudoOutputFile(shell, 'stdout', 'utf-8')
+ f.writelines([])
+ self.assertEqual(shell.written, [])
+ shell.reset()
+ f.writelines(['one\n', 'two'])
+ self.assertEqual(shell.written,
+ [('one\n', 'stdout'), ('two', 'stdout')])
+ shell.reset()
+ f.writelines(['on\xe8\n', 'tw\xf2'])
+ self.assertEqual(shell.written,
+ [('on\xe8\n', 'stdout'), ('tw\xf2', 'stdout')])
+ shell.reset()
+
+ f.writelines([S('t\xe8st')])
+ self.assertEqual(shell.written, [('t\xe8st', 'stdout')])
+ self.assertEqual(type(shell.written[0][0]), str)
+ shell.reset()
+
+ self.assertRaises(TypeError, f.writelines)
+ self.assertEqual(shell.written, [])
+ self.assertRaises(TypeError, f.writelines, 123)
+ self.assertEqual(shell.written, [])
+ self.assertRaises(TypeError, f.writelines, [b'test'])
+ self.assertRaises(TypeError, f.writelines, [123])
+ self.assertEqual(shell.written, [])
+ self.assertRaises(TypeError, f.writelines, [], [])
+ self.assertEqual(shell.written, [])
+
+ def test_close(self):
+ shell = MockShell()
+ f = run.PseudoOutputFile(shell, 'stdout', 'utf-8')
+ self.assertFalse(f.closed)
+ f.write('test')
+ f.close()
+ self.assertTrue(f.closed)
+ self.assertRaises(ValueError, f.write, 'x')
+ self.assertEqual(shell.written, [('test', 'stdout')])
+ f.close()
+ self.assertRaises(TypeError, f.close, 1)
+
+
if __name__ == '__main__':
unittest.main(verbosity=2)
--- /dev/null
+"Test runscript, coverage 16%."
+
+from idlelib import runscript
+import unittest
+from test.support import requires
+from tkinter import Tk
+from idlelib.editor import EditorWindow
+
+
+class ScriptBindingTest(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ requires('gui')
+ cls.root = Tk()
+ cls.root.withdraw()
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.root.update_idletasks()
+ for id in cls.root.tk.call('after', 'info'):
+ cls.root.after_cancel(id) # Need for EditorWindow.
+ cls.root.destroy()
+ del cls.root
+
+ def test_init(self):
+ ew = EditorWindow(root=self.root)
+ sb = runscript.ScriptBinding(ew)
+ ew._close()
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
-''' Test idlelib.scrolledlist.
+"Test scrolledlist, coverage 38%."
-Coverage: 39%
-'''
-from idlelib import scrolledlist
+from idlelib.scrolledlist import ScrolledList
+import unittest
from test.support import requires
requires('gui')
-import unittest
from tkinter import Tk
def test_init(self):
- scrolledlist.ScrolledList(self.root)
+ ScrolledList(self.root)
if __name__ == '__main__':
-"""Test SearchDialog class in idlelib.search.py"""
+"Test search, coverage 69%."
+
+from idlelib import search
+import unittest
+from test.support import requires
+requires('gui')
+from tkinter import Tk, Text, BooleanVar
+from idlelib import searchengine
# Does not currently test the event handler wrappers.
# A usage test should simulate clicks and check highlighting.
# Tests need to be coordinated with SearchDialogBase tests
# to avoid duplication.
-from test.support import requires
-requires('gui')
-
-import unittest
-import tkinter as tk
-from tkinter import BooleanVar
-import idlelib.searchengine as se
-import idlelib.search as sd
-
class SearchDialogTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
- cls.root = tk.Tk()
+ cls.root = Tk()
@classmethod
def tearDownClass(cls):
del cls.root
def setUp(self):
- self.engine = se.SearchEngine(self.root)
- self.dialog = sd.SearchDialog(self.root, self.engine)
+ self.engine = searchengine.SearchEngine(self.root)
+ self.dialog = search.SearchDialog(self.root, self.engine)
self.dialog.bell = lambda: None
- self.text = tk.Text(self.root)
+ self.text = Text(self.root)
self.text.insert('1.0', 'Hello World!')
def test_find_again(self):
-'''tests idlelib.searchbase.
+"Test searchbase, coverage 98%."
+# The only thing not covered is inconsequential --
+# testing skipping of suite when self.needwrapbutton is false.
-Coverage: 99%. The only thing not covered is inconsequential --
-testing skipping of suite when self.needwrapbutton is false.
-'''
import unittest
from test.support import requires
from tkinter import Tk, Frame ##, BooleanVar, StringVar
## se.BooleanVar = BooleanVar
## se.StringVar = StringVar
+
class SearchDialogBaseTest(unittest.TestCase):
@classmethod
-'''Test functions and SearchEngine class in idlelib.searchengine.py.'''
+"Test searchengine, coverage 99%."
-# With mock replacements, the module does not use any gui widgets.
-# The use of tk.Text is avoided (for now, until mock Text is improved)
-# by patching instances with an index function returning what is needed.
-# This works because mock Text.get does not use .index.
-
-import re
+from idlelib import searchengine as se
import unittest
# from test.support import requires
from tkinter import BooleanVar, StringVar, TclError # ,Tk, Text
import tkinter.messagebox as tkMessageBox
-from idlelib import searchengine as se
from idlelib.idle_test.mock_tk import Var, Mbox
from idlelib.idle_test.mock_tk import Text as mockText
+import re
+
+# With mock replacements, the module does not use any gui widgets.
+# The use of tk.Text is avoided (for now, until mock Text is improved)
+# by patching instances with an index function returning what is needed.
+# This works because mock Text.get does not use .index.
+# The tkinter imports are used to restore searchengine.
def setUpModule():
# Replace s-e module tkinter imports other than non-gui TclError.
if __name__ == '__main__':
- unittest.main(verbosity=2, exit=2)
+ unittest.main(verbosity=2)
--- /dev/null
+from collections import namedtuple
+from tkinter import Text, Tk
+import unittest
+from unittest.mock import Mock, NonCallableMagicMock, patch, sentinel, ANY
+from test.support import requires
+
+from idlelib.config import idleConf
+from idlelib.squeezer import count_lines_with_wrapping, ExpandingButton, \
+ Squeezer
+from idlelib import macosx
+from idlelib.textview import view_text
+from idlelib.tooltip import Hovertip
+from idlelib.pyshell import PyShell
+
+
+SENTINEL_VALUE = sentinel.SENTINEL_VALUE
+
+
+def get_test_tk_root(test_instance):
+ """Helper for tests: Create a root Tk object."""
+ requires('gui')
+ root = Tk()
+ root.withdraw()
+
+ def cleanup_root():
+ root.update_idletasks()
+ root.destroy()
+ test_instance.addCleanup(cleanup_root)
+
+ return root
+
+
+class CountLinesTest(unittest.TestCase):
+ """Tests for the count_lines_with_wrapping function."""
+ def check(self, expected, text, linewidth, tabwidth):
+ return self.assertEqual(
+ expected,
+ count_lines_with_wrapping(text, linewidth, tabwidth),
+ )
+
+ def test_count_empty(self):
+ """Test with an empty string."""
+ self.assertEqual(count_lines_with_wrapping(""), 0)
+
+ def test_count_begins_with_empty_line(self):
+ """Test with a string which begins with a newline."""
+ self.assertEqual(count_lines_with_wrapping("\ntext"), 2)
+
+ def test_count_ends_with_empty_line(self):
+ """Test with a string which ends with a newline."""
+ self.assertEqual(count_lines_with_wrapping("text\n"), 1)
+
+ def test_count_several_lines(self):
+ """Test with several lines of text."""
+ self.assertEqual(count_lines_with_wrapping("1\n2\n3\n"), 3)
+
+ def test_tab_width(self):
+ """Test with various tab widths and line widths."""
+ self.check(expected=1, text='\t' * 1, linewidth=8, tabwidth=4)
+ self.check(expected=1, text='\t' * 2, linewidth=8, tabwidth=4)
+ self.check(expected=2, text='\t' * 3, linewidth=8, tabwidth=4)
+ self.check(expected=2, text='\t' * 4, linewidth=8, tabwidth=4)
+ self.check(expected=3, text='\t' * 5, linewidth=8, tabwidth=4)
+
+ # test longer lines and various tab widths
+ self.check(expected=4, text='\t' * 10, linewidth=12, tabwidth=4)
+ self.check(expected=10, text='\t' * 10, linewidth=12, tabwidth=8)
+ self.check(expected=2, text='\t' * 4, linewidth=10, tabwidth=3)
+
+ # test tabwidth=1
+ self.check(expected=2, text='\t' * 9, linewidth=5, tabwidth=1)
+ self.check(expected=2, text='\t' * 10, linewidth=5, tabwidth=1)
+ self.check(expected=3, text='\t' * 11, linewidth=5, tabwidth=1)
+
+ # test for off-by-one errors
+ self.check(expected=2, text='\t' * 6, linewidth=12, tabwidth=4)
+ self.check(expected=3, text='\t' * 6, linewidth=11, tabwidth=4)
+ self.check(expected=2, text='\t' * 6, linewidth=13, tabwidth=4)
+
+
+class SqueezerTest(unittest.TestCase):
+ """Tests for the Squeezer class."""
+ def make_mock_editor_window(self):
+ """Create a mock EditorWindow instance."""
+ editwin = NonCallableMagicMock()
+ # isinstance(editwin, PyShell) must be true for Squeezer to enable
+ # auto-squeezing; in practice this will always be true
+ editwin.__class__ = PyShell
+ return editwin
+
+ def make_squeezer_instance(self, editor_window=None):
+ """Create an actual Squeezer instance with a mock EditorWindow."""
+ if editor_window is None:
+ editor_window = self.make_mock_editor_window()
+ return Squeezer(editor_window)
+
+ def test_count_lines(self):
+ """Test Squeezer.count_lines() with various inputs.
+
+ This checks that Squeezer.count_lines() calls the
+ count_lines_with_wrapping() function with the appropriate parameters.
+ """
+ for tabwidth, linewidth in [(4, 80), (1, 79), (8, 80), (3, 120)]:
+ self._test_count_lines_helper(linewidth=linewidth,
+ tabwidth=tabwidth)
+
+ def _prepare_mock_editwin_for_count_lines(self, editwin,
+ linewidth, tabwidth):
+ """Prepare a mock EditorWindow object for Squeezer.count_lines."""
+ CHAR_WIDTH = 10
+ BORDER_WIDTH = 2
+ PADDING_WIDTH = 1
+
+ # Prepare all the required functionality on the mock EditorWindow object
+ # so that the calculations in Squeezer.count_lines() can run.
+ editwin.get_tk_tabwidth.return_value = tabwidth
+ editwin.text.winfo_width.return_value = \
+ linewidth * CHAR_WIDTH + 2 * (BORDER_WIDTH + PADDING_WIDTH)
+ text_opts = {
+ 'border': BORDER_WIDTH,
+ 'padx': PADDING_WIDTH,
+ 'font': None,
+ }
+ editwin.text.cget = lambda opt: text_opts[opt]
+
+ # monkey-path tkinter.font.Font with a mock object, so that
+ # Font.measure('0') returns CHAR_WIDTH
+ mock_font = Mock()
+ def measure(char):
+ if char == '0':
+ return CHAR_WIDTH
+ raise ValueError("measure should only be called on '0'!")
+ mock_font.return_value.measure = measure
+ patcher = patch('idlelib.squeezer.Font', mock_font)
+ patcher.start()
+ self.addCleanup(patcher.stop)
+
+ def _test_count_lines_helper(self, linewidth, tabwidth):
+ """Helper for test_count_lines."""
+ editwin = self.make_mock_editor_window()
+ self._prepare_mock_editwin_for_count_lines(editwin, linewidth, tabwidth)
+ squeezer = self.make_squeezer_instance(editwin)
+
+ mock_count_lines = Mock(return_value=SENTINEL_VALUE)
+ text = 'TEXT'
+ with patch('idlelib.squeezer.count_lines_with_wrapping',
+ mock_count_lines):
+ self.assertIs(squeezer.count_lines(text), SENTINEL_VALUE)
+ mock_count_lines.assert_called_with(text, linewidth, tabwidth)
+
+ def test_init(self):
+ """Test the creation of Squeezer instances."""
+ editwin = self.make_mock_editor_window()
+ squeezer = self.make_squeezer_instance(editwin)
+ self.assertIs(squeezer.editwin, editwin)
+ self.assertEqual(squeezer.expandingbuttons, [])
+
+ def test_write_no_tags(self):
+ """Test Squeezer's overriding of the EditorWindow's write() method."""
+ editwin = self.make_mock_editor_window()
+ for text in ['', 'TEXT', 'LONG TEXT' * 1000, 'MANY_LINES\n' * 100]:
+ editwin.write = orig_write = Mock(return_value=SENTINEL_VALUE)
+ squeezer = self.make_squeezer_instance(editwin)
+
+ self.assertEqual(squeezer.editwin.write(text, ()), SENTINEL_VALUE)
+ self.assertEqual(orig_write.call_count, 1)
+ orig_write.assert_called_with(text, ())
+ self.assertEqual(len(squeezer.expandingbuttons), 0)
+
+ def test_write_not_stdout(self):
+ """Test Squeezer's overriding of the EditorWindow's write() method."""
+ for text in ['', 'TEXT', 'LONG TEXT' * 1000, 'MANY_LINES\n' * 100]:
+ editwin = self.make_mock_editor_window()
+ editwin.write.return_value = SENTINEL_VALUE
+ orig_write = editwin.write
+ squeezer = self.make_squeezer_instance(editwin)
+
+ self.assertEqual(squeezer.editwin.write(text, "stderr"),
+ SENTINEL_VALUE)
+ self.assertEqual(orig_write.call_count, 1)
+ orig_write.assert_called_with(text, "stderr")
+ self.assertEqual(len(squeezer.expandingbuttons), 0)
+
+ def test_write_stdout(self):
+ """Test Squeezer's overriding of the EditorWindow's write() method."""
+ editwin = self.make_mock_editor_window()
+ self._prepare_mock_editwin_for_count_lines(editwin,
+ linewidth=80, tabwidth=8)
+
+ for text in ['', 'TEXT']:
+ editwin.write = orig_write = Mock(return_value=SENTINEL_VALUE)
+ squeezer = self.make_squeezer_instance(editwin)
+ squeezer.auto_squeeze_min_lines = 50
+
+ self.assertEqual(squeezer.editwin.write(text, "stdout"),
+ SENTINEL_VALUE)
+ self.assertEqual(orig_write.call_count, 1)
+ orig_write.assert_called_with(text, "stdout")
+ self.assertEqual(len(squeezer.expandingbuttons), 0)
+
+ for text in ['LONG TEXT' * 1000, 'MANY_LINES\n' * 100]:
+ editwin.write = orig_write = Mock(return_value=SENTINEL_VALUE)
+ squeezer = self.make_squeezer_instance(editwin)
+ squeezer.auto_squeeze_min_lines = 50
+
+ self.assertEqual(squeezer.editwin.write(text, "stdout"), None)
+ self.assertEqual(orig_write.call_count, 0)
+ self.assertEqual(len(squeezer.expandingbuttons), 1)
+
+ def test_auto_squeeze(self):
+ """Test that the auto-squeezing creates an ExpandingButton properly."""
+ root = get_test_tk_root(self)
+ text_widget = Text(root)
+ text_widget.mark_set("iomark", "1.0")
+
+ editwin = self.make_mock_editor_window()
+ editwin.text = text_widget
+ squeezer = self.make_squeezer_instance(editwin)
+ squeezer.auto_squeeze_min_lines = 5
+ squeezer.count_lines = Mock(return_value=6)
+
+ editwin.write('TEXT\n'*6, "stdout")
+ self.assertEqual(text_widget.get('1.0', 'end'), '\n')
+ self.assertEqual(len(squeezer.expandingbuttons), 1)
+
+ def test_squeeze_current_text_event(self):
+ """Test the squeeze_current_text event."""
+ root = get_test_tk_root(self)
+
+ # squeezing text should work for both stdout and stderr
+ for tag_name in ["stdout", "stderr"]:
+ text_widget = Text(root)
+ text_widget.mark_set("iomark", "1.0")
+
+ editwin = self.make_mock_editor_window()
+ editwin.text = editwin.per.bottom = text_widget
+ squeezer = self.make_squeezer_instance(editwin)
+ squeezer.count_lines = Mock(return_value=6)
+
+ # prepare some text in the Text widget
+ text_widget.insert("1.0", "SOME\nTEXT\n", tag_name)
+ text_widget.mark_set("insert", "1.0")
+ self.assertEqual(text_widget.get('1.0', 'end'), 'SOME\nTEXT\n\n')
+
+ self.assertEqual(len(squeezer.expandingbuttons), 0)
+
+ # test squeezing the current text
+ retval = squeezer.squeeze_current_text_event(event=Mock())
+ self.assertEqual(retval, "break")
+ self.assertEqual(text_widget.get('1.0', 'end'), '\n\n')
+ self.assertEqual(len(squeezer.expandingbuttons), 1)
+ self.assertEqual(squeezer.expandingbuttons[0].s, 'SOME\nTEXT')
+
+ # test that expanding the squeezed text works and afterwards the
+ # Text widget contains the original text
+ squeezer.expandingbuttons[0].expand(event=Mock())
+ self.assertEqual(text_widget.get('1.0', 'end'), 'SOME\nTEXT\n\n')
+ self.assertEqual(len(squeezer.expandingbuttons), 0)
+
+ def test_squeeze_current_text_event_no_allowed_tags(self):
+ """Test that the event doesn't squeeze text without a relevant tag."""
+ root = get_test_tk_root(self)
+
+ text_widget = Text(root)
+ text_widget.mark_set("iomark", "1.0")
+
+ editwin = self.make_mock_editor_window()
+ editwin.text = editwin.per.bottom = text_widget
+ squeezer = self.make_squeezer_instance(editwin)
+ squeezer.count_lines = Mock(return_value=6)
+
+ # prepare some text in the Text widget
+ text_widget.insert("1.0", "SOME\nTEXT\n", "TAG")
+ text_widget.mark_set("insert", "1.0")
+ self.assertEqual(text_widget.get('1.0', 'end'), 'SOME\nTEXT\n\n')
+
+ self.assertEqual(len(squeezer.expandingbuttons), 0)
+
+ # test squeezing the current text
+ retval = squeezer.squeeze_current_text_event(event=Mock())
+ self.assertEqual(retval, "break")
+ self.assertEqual(text_widget.get('1.0', 'end'), 'SOME\nTEXT\n\n')
+ self.assertEqual(len(squeezer.expandingbuttons), 0)
+
+ def test_squeeze_text_before_existing_squeezed_text(self):
+ """Test squeezing text before existing squeezed text."""
+ root = get_test_tk_root(self)
+
+ text_widget = Text(root)
+ text_widget.mark_set("iomark", "1.0")
+
+ editwin = self.make_mock_editor_window()
+ editwin.text = editwin.per.bottom = text_widget
+ squeezer = self.make_squeezer_instance(editwin)
+ squeezer.count_lines = Mock(return_value=6)
+
+ # prepare some text in the Text widget and squeeze it
+ text_widget.insert("1.0", "SOME\nTEXT\n", "stdout")
+ text_widget.mark_set("insert", "1.0")
+ squeezer.squeeze_current_text_event(event=Mock())
+ self.assertEqual(len(squeezer.expandingbuttons), 1)
+
+ # test squeezing the current text
+ text_widget.insert("1.0", "MORE\nSTUFF\n", "stdout")
+ text_widget.mark_set("insert", "1.0")
+ retval = squeezer.squeeze_current_text_event(event=Mock())
+ self.assertEqual(retval, "break")
+ self.assertEqual(text_widget.get('1.0', 'end'), '\n\n\n')
+ self.assertEqual(len(squeezer.expandingbuttons), 2)
+ self.assertTrue(text_widget.compare(
+ squeezer.expandingbuttons[0],
+ '<',
+ squeezer.expandingbuttons[1],
+ ))
+
+ GetOptionSignature = namedtuple('GetOptionSignature',
+ 'configType section option default type warn_on_default raw')
+ @classmethod
+ def _make_sig(cls, configType, section, option, default=sentinel.NOT_GIVEN,
+ type=sentinel.NOT_GIVEN,
+ warn_on_default=sentinel.NOT_GIVEN,
+ raw=sentinel.NOT_GIVEN):
+ return cls.GetOptionSignature(configType, section, option, default,
+ type, warn_on_default, raw)
+
+ @classmethod
+ def get_GetOption_signature(cls, mock_call_obj):
+ args, kwargs = mock_call_obj[-2:]
+ return cls._make_sig(*args, **kwargs)
+
+ def test_reload(self):
+ """Test the reload() class-method."""
+ self.assertIsInstance(Squeezer.auto_squeeze_min_lines, int)
+ idleConf.SetOption('main', 'PyShell', 'auto-squeeze-min-lines', '42')
+ Squeezer.reload()
+ self.assertEqual(Squeezer.auto_squeeze_min_lines, 42)
+
+
+class ExpandingButtonTest(unittest.TestCase):
+ """Tests for the ExpandingButton class."""
+ # In these tests the squeezer instance is a mock, but actual tkinter
+ # Text and Button instances are created.
+ def make_mock_squeezer(self):
+ """Helper for tests: Create a mock Squeezer object."""
+ root = get_test_tk_root(self)
+ squeezer = Mock()
+ squeezer.editwin.text = Text(root)
+
+ # Set default values for the configuration settings
+ squeezer.auto_squeeze_min_lines = 50
+ return squeezer
+
+ @patch('idlelib.squeezer.Hovertip', autospec=Hovertip)
+ def test_init(self, MockHovertip):
+ """Test the simplest creation of an ExpandingButton."""
+ squeezer = self.make_mock_squeezer()
+ text_widget = squeezer.editwin.text
+
+ expandingbutton = ExpandingButton('TEXT', 'TAGS', 50, squeezer)
+ self.assertEqual(expandingbutton.s, 'TEXT')
+
+ # check that the underlying tkinter.Button is properly configured
+ self.assertEqual(expandingbutton.master, text_widget)
+ self.assertTrue('50 lines' in expandingbutton.cget('text'))
+
+ # check that the text widget still contains no text
+ self.assertEqual(text_widget.get('1.0', 'end'), '\n')
+
+ # check that the mouse events are bound
+ self.assertIn('<Double-Button-1>', expandingbutton.bind())
+ right_button_code = '<Button-%s>' % ('2' if macosx.isAquaTk() else '3')
+ self.assertIn(right_button_code, expandingbutton.bind())
+
+ # check that ToolTip was called once, with appropriate values
+ self.assertEqual(MockHovertip.call_count, 1)
+ MockHovertip.assert_called_with(expandingbutton, ANY, hover_delay=ANY)
+
+ # check that 'right-click' appears in the tooltip text
+ tooltip_text = MockHovertip.call_args[0][1]
+ self.assertIn('right-click', tooltip_text.lower())
+
+ def test_expand(self):
+ """Test the expand event."""
+ squeezer = self.make_mock_squeezer()
+ expandingbutton = ExpandingButton('TEXT', 'TAGS', 50, squeezer)
+
+ # insert the button into the text widget
+ # (this is normally done by the Squeezer class)
+ text_widget = expandingbutton.text
+ text_widget.window_create("1.0", window=expandingbutton)
+
+ # set base_text to the text widget, so that changes are actually made
+ # to it (by ExpandingButton) and we can inspect these changes afterwards
+ expandingbutton.base_text = expandingbutton.text
+
+ # trigger the expand event
+ retval = expandingbutton.expand(event=Mock())
+ self.assertEqual(retval, None)
+
+ # check that the text was inserted into the text widget
+ self.assertEqual(text_widget.get('1.0', 'end'), 'TEXT\n')
+
+ # check that the 'TAGS' tag was set on the inserted text
+ text_end_index = text_widget.index('end-1c')
+ self.assertEqual(text_widget.get('1.0', text_end_index), 'TEXT')
+ self.assertEqual(text_widget.tag_nextrange('TAGS', '1.0'),
+ ('1.0', text_end_index))
+
+ # check that the button removed itself from squeezer.expandingbuttons
+ self.assertEqual(squeezer.expandingbuttons.remove.call_count, 1)
+ squeezer.expandingbuttons.remove.assert_called_with(expandingbutton)
+
+ def test_expand_dangerous_oupput(self):
+ """Test that expanding very long output asks user for confirmation."""
+ squeezer = self.make_mock_squeezer()
+ text = 'a' * 10**5
+ expandingbutton = ExpandingButton(text, 'TAGS', 50, squeezer)
+ expandingbutton.set_is_dangerous()
+ self.assertTrue(expandingbutton.is_dangerous)
+
+ # insert the button into the text widget
+ # (this is normally done by the Squeezer class)
+ text_widget = expandingbutton.text
+ text_widget.window_create("1.0", window=expandingbutton)
+
+ # set base_text to the text widget, so that changes are actually made
+ # to it (by ExpandingButton) and we can inspect these changes afterwards
+ expandingbutton.base_text = expandingbutton.text
+
+ # patch the message box module to always return False
+ with patch('idlelib.squeezer.tkMessageBox') as mock_msgbox:
+ mock_msgbox.askokcancel.return_value = False
+ mock_msgbox.askyesno.return_value = False
+
+ # trigger the expand event
+ retval = expandingbutton.expand(event=Mock())
+
+ # check that the event chain was broken and no text was inserted
+ self.assertEqual(retval, 'break')
+ self.assertEqual(expandingbutton.text.get('1.0', 'end-1c'), '')
+
+ # patch the message box module to always return True
+ with patch('idlelib.squeezer.tkMessageBox') as mock_msgbox:
+ mock_msgbox.askokcancel.return_value = True
+ mock_msgbox.askyesno.return_value = True
+
+ # trigger the expand event
+ retval = expandingbutton.expand(event=Mock())
+
+ # check that the event chain wasn't broken and the text was inserted
+ self.assertEqual(retval, None)
+ self.assertEqual(expandingbutton.text.get('1.0', 'end-1c'), text)
+
+ def test_copy(self):
+ """Test the copy event."""
+ # testing with the actual clipboard proved problematic, so this test
+ # replaces the clipboard manipulation functions with mocks and checks
+ # that they are called appropriately
+ squeezer = self.make_mock_squeezer()
+ expandingbutton = ExpandingButton('TEXT', 'TAGS', 50, squeezer)
+ expandingbutton.clipboard_clear = Mock()
+ expandingbutton.clipboard_append = Mock()
+
+ # trigger the copy event
+ retval = expandingbutton.copy(event=Mock())
+ self.assertEqual(retval, None)
+
+ # check that the expanding button called clipboard_clear() and
+ # clipboard_append('TEXT') once each
+ self.assertEqual(expandingbutton.clipboard_clear.call_count, 1)
+ self.assertEqual(expandingbutton.clipboard_append.call_count, 1)
+ expandingbutton.clipboard_append.assert_called_with('TEXT')
+
+ def test_view(self):
+ """Test the view event."""
+ squeezer = self.make_mock_squeezer()
+ expandingbutton = ExpandingButton('TEXT', 'TAGS', 50, squeezer)
+ expandingbutton.selection_own = Mock()
+
+ with patch('idlelib.squeezer.view_text', autospec=view_text)\
+ as mock_view_text:
+ # trigger the view event
+ expandingbutton.view(event=Mock())
+
+ # check that the expanding button called view_text
+ self.assertEqual(mock_view_text.call_count, 1)
+
+ # check that the proper text was passed
+ self.assertEqual(mock_view_text.call_args[0][2], 'TEXT')
+
+ def test_rmenu(self):
+ """Test the context menu."""
+ squeezer = self.make_mock_squeezer()
+ expandingbutton = ExpandingButton('TEXT', 'TAGS', 50, squeezer)
+ with patch('tkinter.Menu') as mock_Menu:
+ mock_menu = Mock()
+ mock_Menu.return_value = mock_menu
+ mock_event = Mock()
+ mock_event.x = 10
+ mock_event.y = 10
+ expandingbutton.context_menu_event(event=mock_event)
+ self.assertEqual(mock_menu.add_command.call_count,
+ len(expandingbutton.rmenu_specs))
+ for label, *data in expandingbutton.rmenu_specs:
+ mock_menu.add_command.assert_any_call(label=label, command=ANY)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
--- /dev/null
+"Test stackviewer, coverage 63%."
+
+from idlelib import stackviewer
+import unittest
+from test.support import requires
+from tkinter import Tk
+
+from idlelib.tree import TreeNode, ScrolledCanvas
+import sys
+
+
+class StackBrowserTest(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ svs = stackviewer.sys
+ try:
+ abc
+ except NameError:
+ svs.last_type, svs.last_value, svs.last_traceback = (
+ sys.exc_info())
+
+ requires('gui')
+ cls.root = Tk()
+ cls.root.withdraw()
+
+ @classmethod
+ def tearDownClass(cls):
+ svs = stackviewer.sys
+ del svs.last_traceback, svs.last_type, svs.last_value
+
+ cls.root.update_idletasks()
+## for id in cls.root.tk.call('after', 'info'):
+## cls.root.after_cancel(id) # Need for EditorWindow.
+ cls.root.destroy()
+ del cls.root
+
+ def test_init(self):
+ sb = stackviewer.StackBrowser(self.root)
+ isi = self.assertIsInstance
+ isi(stackviewer.sc, ScrolledCanvas)
+ isi(stackviewer.item, stackviewer.StackTreeItem)
+ isi(stackviewer.node, TreeNode)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
--- /dev/null
+"Test statusbar, coverage 100%."
+
+from idlelib import statusbar
+import unittest
+from test.support import requires
+from tkinter import Tk
+
+
+class Test(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ requires('gui')
+ cls.root = Tk()
+ cls.root.withdraw()
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.root.update_idletasks()
+ cls.root.destroy()
+ del cls.root
+
+ def test_init(self):
+ bar = statusbar.MultiStatusBar(self.root)
+ self.assertEqual(bar.labels, {})
+
+ def test_set_label(self):
+ bar = statusbar.MultiStatusBar(self.root)
+ bar.set_label('left', text='sometext', width=10)
+ self.assertIn('left', bar.labels)
+ left = bar.labels['left']
+ self.assertEqual(left['text'], 'sometext')
+ self.assertEqual(left['width'], 10)
+ bar.set_label('left', text='revised text')
+ self.assertEqual(left['text'], 'revised text')
+ bar.set_label('right', text='correct text')
+ self.assertEqual(bar.labels['right']['text'], 'correct text')
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
-'''Test idlelib.textview.
+"""Test textview, coverage 100%.
Since all methods and functions create (or destroy) a ViewWindow, which
is a widget containing a widget, etcetera, all tests must be gui tests.
Using mock Text would not change this. Other mocks are used to retrieve
information about calls.
-
-Coverage: 100%.
-'''
+"""
from idlelib import textview as tv
+import unittest
from test.support import requires
requires('gui')
-import unittest
import os
from tkinter import Tk
from tkinter.ttk import Button
@classmethod
def setUpClass(cls):
- "By itself, this tests that file parsed without exception."
cls.root = root = Tk()
root.withdraw()
cls.frame = tv.TextFrame(root, 'test text')
view = tv.view_text(root, 'Title', 'test text', modal=False)
self.assertIsInstance(view, tv.ViewWindow)
self.assertIsInstance(view.viewframe, tv.ViewFrame)
- view.ok()
+ view.viewframe.ok()
def test_view_file(self):
view = tv.view_file(root, 'Title', __file__, 'ascii', modal=False)
def test_bad_encoding(self):
p = os.path
fn = p.abspath(p.join(p.dirname(__file__), '..', 'CREDITS.txt'))
- tv.showerror.title = None
view = tv.view_file(root, 'Title', fn, 'ascii', modal=False)
self.assertIsNone(view)
self.assertEqual(tv.showerror.title, 'Unicode Decode Error')
+ def test_nowrap(self):
+ view = tv.view_text(root, 'Title', 'test', modal=False, wrap='none')
+ text_widget = view.viewframe.textframe.text
+ self.assertEqual(text_widget.cget('wrap'), 'none')
+
# Call ViewWindow with _utest=True.
class ButtonClickTest(unittest.TestCase):
--- /dev/null
+from idlelib.tooltip import TooltipBase, Hovertip
+from test.support import requires
+requires('gui')
+
+from functools import wraps
+import time
+from tkinter import Button, Tk, Toplevel
+import unittest
+
+
+def setUpModule():
+ global root
+ root = Tk()
+
+def root_update():
+ global root
+ root.update()
+
+def tearDownModule():
+ global root
+ root.update_idletasks()
+ root.destroy()
+ del root
+
+def add_call_counting(func):
+ @wraps(func)
+ def wrapped_func(*args, **kwargs):
+ wrapped_func.call_args_list.append((args, kwargs))
+ return func(*args, **kwargs)
+ wrapped_func.call_args_list = []
+ return wrapped_func
+
+
+def _make_top_and_button(testobj):
+ global root
+ top = Toplevel(root)
+ testobj.addCleanup(top.destroy)
+ top.title("Test tooltip")
+ button = Button(top, text='ToolTip test button')
+ button.pack()
+ testobj.addCleanup(button.destroy)
+ top.lift()
+ return top, button
+
+
+class ToolTipBaseTest(unittest.TestCase):
+ def setUp(self):
+ self.top, self.button = _make_top_and_button(self)
+
+ def test_base_class_is_unusable(self):
+ global root
+ top = Toplevel(root)
+ self.addCleanup(top.destroy)
+
+ button = Button(top, text='ToolTip test button')
+ button.pack()
+ self.addCleanup(button.destroy)
+
+ with self.assertRaises(NotImplementedError):
+ tooltip = TooltipBase(button)
+ tooltip.showtip()
+
+
+class HovertipTest(unittest.TestCase):
+ def setUp(self):
+ self.top, self.button = _make_top_and_button(self)
+
+ def test_showtip(self):
+ tooltip = Hovertip(self.button, 'ToolTip text')
+ self.addCleanup(tooltip.hidetip)
+ self.assertFalse(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+ tooltip.showtip()
+ self.assertTrue(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+
+ def test_showtip_twice(self):
+ tooltip = Hovertip(self.button, 'ToolTip text')
+ self.addCleanup(tooltip.hidetip)
+ self.assertFalse(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+ tooltip.showtip()
+ self.assertTrue(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+ orig_tipwindow = tooltip.tipwindow
+ tooltip.showtip()
+ self.assertTrue(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+ self.assertIs(tooltip.tipwindow, orig_tipwindow)
+
+ def test_hidetip(self):
+ tooltip = Hovertip(self.button, 'ToolTip text')
+ self.addCleanup(tooltip.hidetip)
+ tooltip.showtip()
+ tooltip.hidetip()
+ self.assertFalse(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+
+ def test_showtip_on_mouse_enter_no_delay(self):
+ tooltip = Hovertip(self.button, 'ToolTip text', hover_delay=None)
+ self.addCleanup(tooltip.hidetip)
+ tooltip.showtip = add_call_counting(tooltip.showtip)
+ root_update()
+ self.assertFalse(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+ self.button.event_generate('<Enter>', x=0, y=0)
+ root_update()
+ self.assertTrue(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+ self.assertGreater(len(tooltip.showtip.call_args_list), 0)
+
+ def test_showtip_on_mouse_enter_hover_delay(self):
+ tooltip = Hovertip(self.button, 'ToolTip text', hover_delay=50)
+ self.addCleanup(tooltip.hidetip)
+ tooltip.showtip = add_call_counting(tooltip.showtip)
+ root_update()
+ self.assertFalse(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+ self.button.event_generate('<Enter>', x=0, y=0)
+ root_update()
+ self.assertFalse(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+ time.sleep(0.1)
+ root_update()
+ self.assertTrue(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+ self.assertGreater(len(tooltip.showtip.call_args_list), 0)
+
+ def test_hidetip_on_mouse_leave(self):
+ tooltip = Hovertip(self.button, 'ToolTip text', hover_delay=None)
+ self.addCleanup(tooltip.hidetip)
+ tooltip.showtip = add_call_counting(tooltip.showtip)
+ root_update()
+ self.button.event_generate('<Enter>', x=0, y=0)
+ root_update()
+ self.button.event_generate('<Leave>', x=0, y=0)
+ root_update()
+ self.assertFalse(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+ self.assertGreater(len(tooltip.showtip.call_args_list), 0)
+
+ def test_dont_show_on_mouse_leave_before_delay(self):
+ tooltip = Hovertip(self.button, 'ToolTip text', hover_delay=50)
+ self.addCleanup(tooltip.hidetip)
+ tooltip.showtip = add_call_counting(tooltip.showtip)
+ root_update()
+ self.button.event_generate('<Enter>', x=0, y=0)
+ root_update()
+ self.button.event_generate('<Leave>', x=0, y=0)
+ root_update()
+ time.sleep(0.1)
+ root_update()
+ self.assertFalse(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+ self.assertEqual(tooltip.showtip.call_args_list, [])
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
-''' Test idlelib.tree.
+"Test tree. coverage 56%."
-Coverage: 56%
-'''
from idlelib import tree
+import unittest
from test.support import requires
requires('gui')
-import unittest
from tkinter import Tk
-"""Unittest for UndoDelegator in idlelib.undo.py.
+"Test undo, coverage 77%."
+# Only test UndoDelegator so far.
-Coverage about 80% (retest).
-"""
+from idlelib.undo import UndoDelegator
+import unittest
from test.support import requires
requires('gui')
-import unittest
from unittest.mock import Mock
from tkinter import Text, Tk
-from idlelib.undo import UndoDelegator
from idlelib.percolator import Percolator
text.insert('insert', 'foo')
self.assertLessEqual(len(self.delegator.undolist), max_undo)
+
if __name__ == '__main__':
unittest.main(verbosity=2, exit=False)
Revise if output destination changes (http://bugs.python.org/issue18318).
Make sure warnings module is left unaltered (http://bugs.python.org/issue18081).
'''
-
+from idlelib import run
+from idlelib import pyshell as shell
import unittest
from test.support import captured_stderr
-
import warnings
+
# Try to capture default showwarning before Idle modules are imported.
showwarning = warnings.showwarning
# But if we run this file within idle, we are in the middle of the run.main loop
# and default showwarnings has already been replaced.
running_in_idle = 'idle' in showwarning.__name__
-from idlelib import run
-from idlelib import pyshell as shell
-
# The following was generated from pyshell.idle_formatwarning
# and checked as matching expectation.
idlemsg = '''
'''
shellmsg = idlemsg + ">>> "
+
class RunWarnTest(unittest.TestCase):
@unittest.skipIf(running_in_idle, "Does not work when run within Idle.")
# The following uses .splitlines to erase line-ending differences
self.assertEqual(idlemsg.splitlines(), f.getvalue().splitlines())
+
class ShellWarnTest(unittest.TestCase):
@unittest.skipIf(running_in_idle, "Does not work when run within Idle.")
if __name__ == '__main__':
- unittest.main(verbosity=2, exit=False)
+ unittest.main(verbosity=2)
--- /dev/null
+"Test window, coverage 47%."
+
+from idlelib import window
+import unittest
+from test.support import requires
+from tkinter import Tk
+
+
+class WindowListTest(unittest.TestCase):
+
+ def test_init(self):
+ wl = window.WindowList()
+ self.assertEqual(wl.dict, {})
+ self.assertEqual(wl.callbacks, [])
+
+ # Further tests need mock Window.
+
+
+class ListedToplevelTest(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ window.registry = set()
+ requires('gui')
+ cls.root = Tk()
+ cls.root.withdraw()
+
+ @classmethod
+ def tearDownClass(cls):
+ window.registry = window.WindowList()
+ cls.root.update_idletasks()
+## for id in cls.root.tk.call('after', 'info'):
+## cls.root.after_cancel(id) # Need for EditorWindow.
+ cls.root.destroy()
+ del cls.root
+
+ def test_init(self):
+
+ win = window.ListedToplevel(self.root)
+ self.assertIn(win, window.registry)
+ self.assertEqual(win.focused_widget, win)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
--- /dev/null
+"Test zoomheight, coverage 66%."
+# Some code is system dependent.
+
+from idlelib import zoomheight
+import unittest
+from test.support import requires
+from tkinter import Tk, Text
+from idlelib.editor import EditorWindow
+
+
+class Test(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ requires('gui')
+ cls.root = Tk()
+ cls.root.withdraw()
+ cls.editwin = EditorWindow(root=cls.root)
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.editwin._close()
+ cls.root.update_idletasks()
+ for id in cls.root.tk.call('after', 'info'):
+ cls.root.after_cancel(id) # Need for EditorWindow.
+ cls.root.destroy()
+ del cls.root
+
+ def test_init(self):
+ zoom = zoomheight.ZoomHeight(self.editwin)
+ self.assertIs(zoom.editwin, self.editwin)
+
+ def test_zoom_height_event(self):
+ zoom = zoomheight.ZoomHeight(self.editwin)
+ zoom.zoom_height_event()
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
# resulting codeset may be unknown to Python. We ignore all
# these problems, falling back to ASCII
locale_encoding = locale.nl_langinfo(locale.CODESET)
- if locale_encoding is None or locale_encoding is '':
+ if locale_encoding is None or locale_encoding == '':
# situation occurs on Mac OS X
locale_encoding = 'ascii'
codecs.lookup(locale_encoding)
# bugs that can cause ValueError.
try:
locale_encoding = locale.getdefaultlocale()[1]
- if locale_encoding is None or locale_encoding is '':
+ if locale_encoding is None or locale_encoding == '':
# situation occurs on Mac OS X
locale_encoding = 'ascii'
codecs.lookup(locale_encoding)
IOBinding(editwin)
if __name__ == "__main__":
- import unittest
- unittest.main('idlelib.idle_test.test_iomenu', verbosity=2, exit=False)
+ from unittest import main
+ main('idlelib.idle_test.test_iomenu', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(_io_binding)
# menu.
from tkinter import Menu
from idlelib import mainmenu
- from idlelib import windows
+ from idlelib import window
closeItem = mainmenu.menudefs[0][1][-2]
root.configure(menu=menubar)
menudict = {}
- menudict['windows'] = menu = Menu(menubar, name='windows', tearoff=0)
+ menudict['window'] = menu = Menu(menubar, name='window', tearoff=0)
menubar.add_cascade(label='Window', menu=menu, underline=0)
def postwindowsmenu(menu=menu):
if end > 0:
menu.delete(0, end)
- windows.add_windows_to_menu(menu)
- windows.register_callback(postwindowsmenu)
+ window.add_windows_to_menu(menu)
+ window.register_callback(postwindowsmenu)
def about_dialog(event=None):
"Handle Help 'About IDLE' event."
None,
('_Close', '<<close-window>>'),
('E_xit', '<<close-all-windows>>'),
- ]),
+ ]),
+
('edit', [
('_Undo', '<<undo>>'),
('_Redo', '<<redo>>'),
('E_xpand Word', '<<expand-word>>'),
('Show C_all Tip', '<<force-open-calltip>>'),
('Show Surrounding P_arens', '<<flash-paren>>'),
+ ]),
- ]),
-('format', [
+ ('format', [
('_Indent Region', '<<indent-region>>'),
('_Dedent Region', '<<dedent-region>>'),
('Comment _Out Region', '<<comment-region>>'),
('F_ormat Paragraph', '<<format-paragraph>>'),
('S_trip Trailing Whitespace', '<<do-rstrip>>'),
]),
+
('run', [
('Python Shell', '<<open-python-shell>>'),
('C_heck Module', '<<check-module>>'),
('R_un Module', '<<run-module>>'),
]),
+
('shell', [
('_View Last Restart', '<<view-restart>>'),
('_Restart Shell', '<<restart-shell>>'),
None,
('_Interrupt Execution', '<<interrupt-execution>>'),
]),
+
('debug', [
('_Go to File/Line', '<<goto-file-line>>'),
('!_Debugger', '<<toggle-debugger>>'),
('_Stack Viewer', '<<open-stack-viewer>>'),
('!_Auto-open Stack Viewer', '<<toggle-jit-stack-viewer>>'),
]),
+
('options', [
('Configure _IDLE', '<<open-config-dialog>>'),
('_Code Context', '<<toggle-code-context>>'),
]),
- ('windows', [
+
+ ('window', [
('Zoom Height', '<<zoom-height>>'),
]),
+
('help', [
('_About IDLE', '<<about-idle>>'),
None,
menudefs[-1][1].append(('Turtle Demo', '<<open-turtle-demo>>'))
default_keydefs = idleConf.GetCurrentKeySet()
+
+if __name__ == '__main__':
+ from unittest import main
+ main('idlelib.idle_test.test_mainmenu', verbosity=2)
bindseq("<Leave>")
if __name__ == "__main__":
+ from unittest import main
+ main('idlelib.idle_test.test_mainmenu', verbosity=2, exit=False)
+
from idlelib.idle_test.htest import run
run(_multi_call)
self.write = self.owin.write
if __name__ == '__main__':
- import unittest
- unittest.main('idlelib.idle_test.test_outwin', verbosity=2, exit=False)
+ from unittest import main
+ main('idlelib.idle_test.test_outwin', verbosity=2, exit=False)
if __name__ == "__main__":
- import unittest
- unittest.main('idlelib.idle_test.test_paragraph',
- verbosity=2, exit=False)
+ from unittest import main
+ main('idlelib.idle_test.test_paragraph', verbosity=2, exit=False)
if __name__ == '__main__':
- import unittest
- unittest.main('idlelib.idle_test.test_parenmatch', verbosity=2)
+ from unittest import main
+ main('idlelib.idle_test.test_parenmatch', verbosity=2)
cb2.pack()
if __name__ == "__main__":
- import unittest
- unittest.main('idlelib.idle_test.test_percolator', verbosity=2,
- exit=False)
+ from unittest import main
+ main('idlelib.idle_test.test_percolator', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(_percolator)
return self.stmt_bracketing
-if __name__ == '__main__': #pragma: nocover
- import unittest
- unittest.main('idlelib.idle_test.test_pyparse', verbosity=2)
+if __name__ == '__main__':
+ from unittest import main
+ main('idlelib.idle_test.test_pyparse', verbosity=2)
("edit", "_Edit"),
("debug", "_Debug"),
("options", "_Options"),
- ("windows", "_Window"),
+ ("window", "_Window"),
("help", "_Help"),
]
+ # Extend right-click context menu
+ rmenu_specs = OutputWindow.rmenu_specs + [
+ ("Squeeze", "<<squeeze-current-text>>"),
+ ]
# New classes
from idlelib.history import History
return self.shell_title
COPYRIGHT = \
- 'Type "copyright", "credits" or "license()" for more information.'
+ 'Type "help", "copyright", "credits" or "license()" for more information.'
def begin(self):
self.text.mark_set("iomark", "insert")
self.result = None
self.destroy()
+ def destroy(self):
+ self.grab_release()
+ super().destroy()
+
class SectionName(Query):
"Get a name for a config file section name."
if __name__ == '__main__':
- import unittest
- unittest.main('idlelib.idle_test.test_query', verbosity=2, exit=False)
+ from unittest import main
+ main('idlelib.idle_test.test_query', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(Query, HelpSource)
original_insert = redir.register("insert", my_insert)
if __name__ == "__main__":
- import unittest
- unittest.main('idlelib.idle_test.test_redirector',
- verbosity=2, exit=False)
+ from unittest import main
+ main('idlelib.idle_test.test_redirector', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(_widget_redirector)
button.pack()
if __name__ == '__main__':
- import unittest
- unittest.main('idlelib.idle_test.test_replace',
- verbosity=2, exit=False)
+ from unittest import main
+ main('idlelib.idle_test.test_replace', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(_replace_dialog)
import types
def unpickle_code(ms):
+ "Return code object from marshal string ms."
co = marshal.loads(ms)
assert isinstance(co, types.CodeType)
return co
def pickle_code(co):
+ "Return unpickle function and tuple with marshalled co code object."
assert isinstance(co, types.CodeType)
ms = marshal.dumps(co)
return unpickle_code, (ms,)
def dumps(obj, protocol=None):
+ "Return pickled (or marshalled) string for obj."
+ # IDLE passes 'None' to select pickle.DEFAULT_PROTOCOL.
f = io.BytesIO()
p = CodePickler(f, protocol)
p.dump(obj)
sys.stdout.write(text)
sys.stdout.write("\n")
builtins._ = value
+
+
+if __name__ == '__main__':
+ from unittest import main
+ main('idlelib.idle_test.test_rpc', verbosity=2,)
'Provides "Strip trailing whitespace" under the "Format" menu.'
-class RstripExtension:
+class Rstrip:
def __init__(self, editwin):
self.editwin = editwin
undo.undo_block_stop()
if __name__ == "__main__":
- import unittest
- unittest.main('idlelib.idle_test.test_rstrip', verbosity=2, exit=False)
+ from unittest import main
+ main('idlelib.idle_test.test_rstrip', verbosity=2,)
import tkinter # Tcl, deletions, messagebox if startup fails
from idlelib import autocomplete # AutoComplete, fetch_encodings
-from idlelib import calltips # CallTips
+from idlelib import calltip # Calltip
from idlelib import debugger_r # start_debugger
from idlelib import debugobj_r # remote_object_tree_item
from idlelib import iomenu # encoding
def __init__(self, rpchandler):
self.rpchandler = rpchandler
self.locals = __main__.__dict__
- self.calltip = calltips.CallTips()
+ self.calltip = calltip.Calltip()
self.autocomplete = autocomplete.AutoComplete()
def runcode(self, code):
# XXX This should really be a function of EditorWindow...
tkMessageBox.showerror(title, message, parent=self.editwin.text)
self.editwin.text.focus_set()
+
+
+if __name__ == "__main__":
+ from unittest import main
+ main('idlelib.idle_test.test_runscript', verbosity=2,)
scrolled_list.append("Item %02d" % i)
if __name__ == '__main__':
- # At the moment, test_scrolledlist merely creates instance, like htest.
+ from unittest import main
+ main('idlelib.idle_test.test_scrolledlist', verbosity=2,)
+
from idlelib.idle_test.htest import run
run(_scrolled_list)
button.pack()
if __name__ == '__main__':
- import unittest
- unittest.main('idlelib.idle_test.test_search',
- verbosity=2, exit=False)
+ from unittest import main
+ main('idlelib.idle_test.test_search', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(_search_dialog)
def default_command(self, dummy): pass
+
if __name__ == '__main__':
- import unittest
- unittest.main('idlelib.idle_test.test_searchbase', verbosity=2, exit=False)
+ from unittest import main
+ main('idlelib.idle_test.test_searchbase', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(_searchbase)
line, col = map(int, index.split(".")) # Fails on invalid index
return line, col
+
if __name__ == "__main__":
- import unittest
- unittest.main('idlelib.idle_test.test_searchengine', verbosity=2, exit=False)
+ from unittest import main
+ main('idlelib.idle_test.test_searchengine', verbosity=2)
--- /dev/null
+"""An IDLE extension to avoid having very long texts printed in the shell.
+
+A common problem in IDLE's interactive shell is printing of large amounts of
+text into the shell. This makes looking at the previous history difficult.
+Worse, this can cause IDLE to become very slow, even to the point of being
+completely unusable.
+
+This extension will automatically replace long texts with a small button.
+Double-cliking this button will remove it and insert the original text instead.
+Middle-clicking will copy the text to the clipboard. Right-clicking will open
+the text in a separate viewing window.
+
+Additionally, any output can be manually "squeezed" by the user. This includes
+output written to the standard error stream ("stderr"), such as exception
+messages and their tracebacks.
+"""
+import re
+
+import tkinter as tk
+from tkinter.font import Font
+import tkinter.messagebox as tkMessageBox
+
+from idlelib.config import idleConf
+from idlelib.textview import view_text
+from idlelib.tooltip import Hovertip
+from idlelib import macosx
+
+
+def count_lines_with_wrapping(s, linewidth=80, tabwidth=8):
+ """Count the number of lines in a given string.
+
+ Lines are counted as if the string was wrapped so that lines are never over
+ linewidth characters long.
+
+ Tabs are considered tabwidth characters long.
+ """
+ pos = 0
+ linecount = 1
+ current_column = 0
+
+ for m in re.finditer(r"[\t\n]", s):
+ # process the normal chars up to tab or newline
+ numchars = m.start() - pos
+ pos += numchars
+ current_column += numchars
+
+ # deal with tab or newline
+ if s[pos] == '\n':
+ linecount += 1
+ current_column = 0
+ else:
+ assert s[pos] == '\t'
+ current_column += tabwidth - (current_column % tabwidth)
+
+ # if a tab passes the end of the line, consider the entire tab as
+ # being on the next line
+ if current_column > linewidth:
+ linecount += 1
+ current_column = tabwidth
+
+ pos += 1 # after the tab or newline
+
+ # avoid divmod(-1, linewidth)
+ if current_column > 0:
+ # If the length was exactly linewidth, divmod would give (1,0),
+ # even though a new line hadn't yet been started. The same is true
+ # if length is any exact multiple of linewidth. Therefore, subtract
+ # 1 before doing divmod, and later add 1 to the column to
+ # compensate.
+ lines, column = divmod(current_column - 1, linewidth)
+ linecount += lines
+ current_column = column + 1
+
+ # process remaining chars (no more tabs or newlines)
+ current_column += len(s) - pos
+ # avoid divmod(-1, linewidth)
+ if current_column > 0:
+ linecount += (current_column - 1) // linewidth
+ else:
+ # the text ended with a newline; don't count an extra line after it
+ linecount -= 1
+
+ return linecount
+
+
+class ExpandingButton(tk.Button):
+ """Class for the "squeezed" text buttons used by Squeezer
+
+ These buttons are displayed inside a Tk Text widget in place of text. A
+ user can then use the button to replace it with the original text, copy
+ the original text to the clipboard or view the original text in a separate
+ window.
+
+ Each button is tied to a Squeezer instance, and it knows to update the
+ Squeezer instance when it is expanded (and therefore removed).
+ """
+ def __init__(self, s, tags, numoflines, squeezer):
+ self.s = s
+ self.tags = tags
+ self.numoflines = numoflines
+ self.squeezer = squeezer
+ self.editwin = editwin = squeezer.editwin
+ self.text = text = editwin.text
+
+ # the base Text widget of the PyShell object, used to change text
+ # before the iomark
+ self.base_text = editwin.per.bottom
+
+ button_text = "Squeezed text (%d lines)." % self.numoflines
+ tk.Button.__init__(self, text, text=button_text,
+ background="#FFFFC0", activebackground="#FFFFE0")
+
+ button_tooltip_text = (
+ "Double-click to expand, right-click for more options."
+ )
+ Hovertip(self, button_tooltip_text, hover_delay=80)
+
+ self.bind("<Double-Button-1>", self.expand)
+ if macosx.isAquaTk():
+ # AquaTk defines <2> as the right button, not <3>.
+ self.bind("<Button-2>", self.context_menu_event)
+ else:
+ self.bind("<Button-3>", self.context_menu_event)
+ self.selection_handle(
+ lambda offset, length: s[int(offset):int(offset) + int(length)])
+
+ self.is_dangerous = None
+ self.after_idle(self.set_is_dangerous)
+
+ def set_is_dangerous(self):
+ dangerous_line_len = 50 * self.text.winfo_width()
+ self.is_dangerous = (
+ self.numoflines > 1000 or
+ len(self.s) > 50000 or
+ any(
+ len(line_match.group(0)) >= dangerous_line_len
+ for line_match in re.finditer(r'[^\n]+', self.s)
+ )
+ )
+
+ def expand(self, event=None):
+ """expand event handler
+
+ This inserts the original text in place of the button in the Text
+ widget, removes the button and updates the Squeezer instance.
+
+ If the original text is dangerously long, i.e. expanding it could
+ cause a performance degradation, ask the user for confirmation.
+ """
+ if self.is_dangerous is None:
+ self.set_is_dangerous()
+ if self.is_dangerous:
+ confirm = tkMessageBox.askokcancel(
+ title="Expand huge output?",
+ message="\n\n".join([
+ "The squeezed output is very long: %d lines, %d chars.",
+ "Expanding it could make IDLE slow or unresponsive.",
+ "It is recommended to view or copy the output instead.",
+ "Really expand?"
+ ]) % (self.numoflines, len(self.s)),
+ default=tkMessageBox.CANCEL,
+ parent=self.text)
+ if not confirm:
+ return "break"
+
+ self.base_text.insert(self.text.index(self), self.s, self.tags)
+ self.base_text.delete(self)
+ self.squeezer.expandingbuttons.remove(self)
+
+ def copy(self, event=None):
+ """copy event handler
+
+ Copy the original text to the clipboard.
+ """
+ self.clipboard_clear()
+ self.clipboard_append(self.s)
+
+ def view(self, event=None):
+ """view event handler
+
+ View the original text in a separate text viewer window.
+ """
+ view_text(self.text, "Squeezed Output Viewer", self.s,
+ modal=False, wrap='none')
+
+ rmenu_specs = (
+ # item structure: (label, method_name)
+ ('copy', 'copy'),
+ ('view', 'view'),
+ )
+
+ def context_menu_event(self, event):
+ self.text.mark_set("insert", "@%d,%d" % (event.x, event.y))
+ rmenu = tk.Menu(self.text, tearoff=0)
+ for label, method_name in self.rmenu_specs:
+ rmenu.add_command(label=label, command=getattr(self, method_name))
+ rmenu.tk_popup(event.x_root, event.y_root)
+ return "break"
+
+
+class Squeezer:
+ """Replace long outputs in the shell with a simple button.
+
+ This avoids IDLE's shell slowing down considerably, and even becoming
+ completely unresponsive, when very long outputs are written.
+ """
+ @classmethod
+ def reload(cls):
+ """Load class variables from config."""
+ cls.auto_squeeze_min_lines = idleConf.GetOption(
+ "main", "PyShell", "auto-squeeze-min-lines",
+ type="int", default=50,
+ )
+
+ def __init__(self, editwin):
+ """Initialize settings for Squeezer.
+
+ editwin is the shell's Editor window.
+ self.text is the editor window text widget.
+ self.base_test is the actual editor window Tk text widget, rather than
+ EditorWindow's wrapper.
+ self.expandingbuttons is the list of all buttons representing
+ "squeezed" output.
+ """
+ self.editwin = editwin
+ self.text = text = editwin.text
+
+ # Get the base Text widget of the PyShell object, used to change text
+ # before the iomark. PyShell deliberately disables changing text before
+ # the iomark via its 'text' attribute, which is actually a wrapper for
+ # the actual Text widget. Squeezer, however, needs to make such changes.
+ self.base_text = editwin.per.bottom
+
+ self.expandingbuttons = []
+ from idlelib.pyshell import PyShell # done here to avoid import cycle
+ if isinstance(editwin, PyShell):
+ # If we get a PyShell instance, replace its write method with a
+ # wrapper, which inserts an ExpandingButton instead of a long text.
+ def mywrite(s, tags=(), write=editwin.write):
+ # only auto-squeeze text which has just the "stdout" tag
+ if tags != "stdout":
+ return write(s, tags)
+
+ # only auto-squeeze text with at least the minimum
+ # configured number of lines
+ numoflines = self.count_lines(s)
+ if numoflines < self.auto_squeeze_min_lines:
+ return write(s, tags)
+
+ # create an ExpandingButton instance
+ expandingbutton = ExpandingButton(s, tags, numoflines,
+ self)
+
+ # insert the ExpandingButton into the Text widget
+ text.mark_gravity("iomark", tk.RIGHT)
+ text.window_create("iomark", window=expandingbutton,
+ padx=3, pady=5)
+ text.see("iomark")
+ text.update()
+ text.mark_gravity("iomark", tk.LEFT)
+
+ # add the ExpandingButton to the Squeezer's list
+ self.expandingbuttons.append(expandingbutton)
+
+ editwin.write = mywrite
+
+ def count_lines(self, s):
+ """Count the number of lines in a given text.
+
+ Before calculation, the tab width and line length of the text are
+ fetched, so that up-to-date values are used.
+
+ Lines are counted as if the string was wrapped so that lines are never
+ over linewidth characters long.
+
+ Tabs are considered tabwidth characters long.
+ """
+ # Tab width is configurable
+ tabwidth = self.editwin.get_tk_tabwidth()
+
+ # Get the Text widget's size
+ linewidth = self.editwin.text.winfo_width()
+ # Deduct the border and padding
+ linewidth -= 2*sum([int(self.editwin.text.cget(opt))
+ for opt in ('border', 'padx')])
+
+ # Get the Text widget's font
+ font = Font(self.editwin.text, name=self.editwin.text.cget('font'))
+ # Divide the size of the Text widget by the font's width.
+ # According to Tk8.5 docs, the Text widget's width is set
+ # according to the width of its font's '0' (zero) character,
+ # so we will use this as an approximation.
+ # see: http://www.tcl.tk/man/tcl8.5/TkCmd/text.htm#M-width
+ linewidth //= font.measure('0')
+
+ return count_lines_with_wrapping(s, linewidth, tabwidth)
+
+ def squeeze_current_text_event(self, event):
+ """squeeze-current-text event handler
+
+ Squeeze the block of text inside which contains the "insert" cursor.
+
+ If the insert cursor is not in a squeezable block of text, give the
+ user a small warning and do nothing.
+ """
+ # set tag_name to the first valid tag found on the "insert" cursor
+ tag_names = self.text.tag_names(tk.INSERT)
+ for tag_name in ("stdout", "stderr"):
+ if tag_name in tag_names:
+ break
+ else:
+ # the insert cursor doesn't have a "stdout" or "stderr" tag
+ self.text.bell()
+ return "break"
+
+ # find the range to squeeze
+ start, end = self.text.tag_prevrange(tag_name, tk.INSERT + "+1c")
+ s = self.text.get(start, end)
+
+ # if the last char is a newline, remove it from the range
+ if len(s) > 0 and s[-1] == '\n':
+ end = self.text.index("%s-1c" % end)
+ s = s[:-1]
+
+ # delete the text
+ self.base_text.delete(start, end)
+
+ # prepare an ExpandingButton
+ numoflines = self.count_lines(s)
+ expandingbutton = ExpandingButton(s, tag_name, numoflines, self)
+
+ # insert the ExpandingButton to the Text
+ self.text.window_create(start, window=expandingbutton,
+ padx=3, pady=5)
+
+ # insert the ExpandingButton to the list of ExpandingButtons, while
+ # keeping the list ordered according to the position of the buttons in
+ # the Text widget
+ i = len(self.expandingbuttons)
+ while i > 0 and self.text.compare(self.expandingbuttons[i-1],
+ ">", expandingbutton):
+ i -= 1
+ self.expandingbuttons.insert(i, expandingbutton)
+
+ return "break"
+
+
+Squeezer.reload()
+
+
+if __name__ == "__main__":
+ from unittest import main
+ main('idlelib.idle_test.test_squeezer', verbosity=2, exit=False)
+
+ # Add htest.
from idlelib.tree import TreeNode, TreeItem, ScrolledCanvas
def StackBrowser(root, flist=None, tb=None, top=None):
+ global sc, item, node # For testing.
if top is None:
top = tk.Toplevel(root)
sc = ScrolledCanvas(top, bg="white", highlightthickness=0)
intentional_name_error
except NameError:
exc_type, exc_value, exc_tb = sys.exc_info()
-
# inject stack trace to sys
sys.last_type = exc_type
sys.last_value = exc_value
del sys.last_traceback
if __name__ == '__main__':
+ from unittest import main
+ main('idlelib.idle_test.test_stackviewer', verbosity=2, exit=False)
+
from idlelib.idle_test.htest import run
run(_stack_viewer)
frame.pack()
if __name__ == '__main__':
+ from unittest import main
+ main('idlelib.idle_test.test_statusbar', verbosity=2, exit=False)
+
from idlelib.idle_test.htest import run
run(_multistatus_bar)
"""Simple text browser for IDLE
"""
-from tkinter import Toplevel, Text
+from tkinter import Toplevel, Text, TclError,\
+ HORIZONTAL, VERTICAL, N, S, E, W
from tkinter.ttk import Frame, Scrollbar, Button
from tkinter.messagebox import showerror
+from idlelib.colorizer import color_config
+
+
+class AutoHiddenScrollbar(Scrollbar):
+ """A scrollbar that is automatically hidden when not needed.
+
+ Only the grid geometry manager is supported.
+ """
+ def set(self, lo, hi):
+ if float(lo) > 0.0 or float(hi) < 1.0:
+ self.grid()
+ else:
+ self.grid_remove()
+ super().set(lo, hi)
+
+ def pack(self, **kwargs):
+ raise TclError(f'{self.__class__.__name__} does not support "pack"')
+
+ def place(self, **kwargs):
+ raise TclError(f'{self.__class__.__name__} does not support "place"')
+
class TextFrame(Frame):
"Display text with scrollbar."
- def __init__(self, parent, rawtext):
+ def __init__(self, parent, rawtext, wrap='word'):
"""Create a frame for Textview.
parent - parent widget for this frame
super().__init__(parent)
self['relief'] = 'sunken'
self['height'] = 700
- # TODO: get fg/bg from theme.
- self.bg = '#ffffff'
- self.fg = '#000000'
-
- self.text = text = Text(self, wrap='word', highlightthickness=0,
- fg=self.fg, bg=self.bg)
- self.scroll = scroll = Scrollbar(self, orient='vertical',
- takefocus=False, command=text.yview)
- text['yscrollcommand'] = scroll.set
+
+ self.text = text = Text(self, wrap=wrap, highlightthickness=0)
+ color_config(text)
+ text.grid(row=0, column=0, sticky=N+S+E+W)
+ self.grid_rowconfigure(0, weight=1)
+ self.grid_columnconfigure(0, weight=1)
text.insert(0.0, rawtext)
text['state'] = 'disabled'
text.focus_set()
- scroll.pack(side='right', fill='y')
- text.pack(side='left', expand=True, fill='both')
+ # vertical scrollbar
+ self.yscroll = yscroll = AutoHiddenScrollbar(self, orient=VERTICAL,
+ takefocus=False,
+ command=text.yview)
+ text['yscrollcommand'] = yscroll.set
+ yscroll.grid(row=0, column=1, sticky=N+S)
+
+ if wrap == 'none':
+ # horizontal scrollbar
+ self.xscroll = xscroll = AutoHiddenScrollbar(self, orient=HORIZONTAL,
+ takefocus=False,
+ command=text.xview)
+ text['xscrollcommand'] = xscroll.set
+ xscroll.grid(row=1, column=0, sticky=E+W)
class ViewFrame(Frame):
"Display TextFrame and Close button."
- def __init__(self, parent, text):
+ def __init__(self, parent, text, wrap='word'):
super().__init__(parent)
self.parent = parent
self.bind('<Return>', self.ok)
self.bind('<Escape>', self.ok)
- self.textframe = TextFrame(self, text)
+ self.textframe = TextFrame(self, text, wrap=wrap)
self.button_ok = button_ok = Button(
self, text='Close', command=self.ok, takefocus=False)
self.textframe.pack(side='top', expand=True, fill='both')
class ViewWindow(Toplevel):
"A simple text viewer dialog for IDLE."
- def __init__(self, parent, title, text, modal=True,
+ def __init__(self, parent, title, text, modal=True, wrap='word',
*, _htest=False, _utest=False):
"""Show the given text in a scrollable window with a 'close' button.
parent - parent of this dialog
title - string which is title of popup dialog
text - text to display in dialog
+ wrap - type of text wrapping to use ('word', 'char' or 'none')
_htest - bool; change box location when running htest.
_utest - bool; don't wait_window when running unittest.
"""
self.geometry(f'=750x500+{x}+{y}')
self.title(title)
- self.viewframe = ViewFrame(self, text)
+ self.viewframe = ViewFrame(self, text, wrap=wrap)
self.protocol("WM_DELETE_WINDOW", self.ok)
self.button_ok = button_ok = Button(self, text='Close',
command=self.ok, takefocus=False)
self.viewframe.pack(side='top', expand=True, fill='both')
- if modal:
+ self.is_modal = modal
+ if self.is_modal:
self.transient(parent)
self.grab_set()
if not _utest:
def ok(self, event=None):
"""Dismiss text viewer dialog."""
+ if self.is_modal:
+ self.grab_release()
self.destroy()
-def view_text(parent, title, text, modal=True, _utest=False):
+def view_text(parent, title, text, modal=True, wrap='word', _utest=False):
"""Create text viewer for given text.
parent - parent of this dialog
title - string which is the title of popup dialog
text - text to display in this dialog
+ wrap - type of text wrapping to use ('word', 'char' or 'none')
modal - controls if users can interact with other windows while this
dialog is displayed
_utest - bool; controls wait_window on unittest
"""
- return ViewWindow(parent, title, text, modal, _utest=_utest)
+ return ViewWindow(parent, title, text, modal, wrap=wrap, _utest=_utest)
-def view_file(parent, title, filename, encoding, modal=True, _utest=False):
+def view_file(parent, title, filename, encoding, modal=True, wrap='word',
+ _utest=False):
"""Create text viewer for text in filename.
Return error message if file cannot be read. Otherwise calls view_text
message=str(err),
parent=parent)
else:
- return view_text(parent, title, contents, modal, _utest=_utest)
+ return view_text(parent, title, contents, modal, wrap=wrap,
+ _utest=_utest)
return None
if __name__ == '__main__':
- import unittest
- unittest.main('idlelib.idle_test.test_textview', verbosity=2, exit=False)
+ from unittest import main
+ main('idlelib.idle_test.test_textview', verbosity=2, exit=False)
+
from idlelib.idle_test.htest import run
run(ViewWindow)
-# general purpose 'tooltip' routines - currently unused in idlelib
-# (although the 'calltips' extension is partly based on this code)
-# may be useful for some purposes in (or almost in ;) the current project scope
-# Ideas gleaned from PySol
+"""Tools for displaying tool-tips.
+This includes:
+ * an abstract base-class for different kinds of tooltips
+ * a simple text-only Tooltip class
+"""
from tkinter import *
-class ToolTipBase:
- def __init__(self, button):
- self.button = button
- self.tipwindow = None
- self.id = None
- self.x = self.y = 0
- self._id1 = self.button.bind("<Enter>", self.enter)
- self._id2 = self.button.bind("<Leave>", self.leave)
- self._id3 = self.button.bind("<ButtonPress>", self.leave)
+class TooltipBase(object):
+ """abstract base class for tooltips"""
- def enter(self, event=None):
- self.schedule()
+ def __init__(self, anchor_widget):
+ """Create a tooltip.
- def leave(self, event=None):
- self.unschedule()
- self.hidetip()
+ anchor_widget: the widget next to which the tooltip will be shown
- def schedule(self):
- self.unschedule()
- self.id = self.button.after(1500, self.showtip)
+ Note that a widget will only be shown when showtip() is called.
+ """
+ self.anchor_widget = anchor_widget
+ self.tipwindow = None
- def unschedule(self):
- id = self.id
- self.id = None
- if id:
- self.button.after_cancel(id)
+ def __del__(self):
+ self.hidetip()
def showtip(self):
+ """display the tooltip"""
if self.tipwindow:
return
- # The tip window must be completely outside the button;
+ self.tipwindow = tw = Toplevel(self.anchor_widget)
+ # show no border on the top level window
+ tw.wm_overrideredirect(1)
+ try:
+ # This command is only needed and available on Tk >= 8.4.0 for OSX.
+ # Without it, call tips intrude on the typing process by grabbing
+ # the focus.
+ tw.tk.call("::tk::unsupported::MacWindowStyle", "style", tw._w,
+ "help", "noActivates")
+ except TclError:
+ pass
+
+ self.position_window()
+ self.showcontents()
+ self.tipwindow.update_idletasks() # Needed on MacOS -- see #34275.
+ self.tipwindow.lift() # work around bug in Tk 8.5.18+ (issue #24570)
+
+ def position_window(self):
+ """(re)-set the tooltip's screen position"""
+ x, y = self.get_position()
+ root_x = self.anchor_widget.winfo_rootx() + x
+ root_y = self.anchor_widget.winfo_rooty() + y
+ self.tipwindow.wm_geometry("+%d+%d" % (root_x, root_y))
+
+ def get_position(self):
+ """choose a screen position for the tooltip"""
+ # The tip window must be completely outside the anchor widget;
# otherwise when the mouse enters the tip window we get
# a leave event and it disappears, and then we get an enter
# event and it reappears, and so on forever :-(
- x = self.button.winfo_rootx() + 20
- y = self.button.winfo_rooty() + self.button.winfo_height() + 1
- self.tipwindow = tw = Toplevel(self.button)
- tw.wm_overrideredirect(1)
- tw.wm_geometry("+%d+%d" % (x, y))
- self.showcontents()
+ #
+ # Note: This is a simplistic implementation; sub-classes will likely
+ # want to override this.
+ return 20, self.anchor_widget.winfo_height() + 1
- def showcontents(self, text="Your text here"):
- # Override this in derived class
- label = Label(self.tipwindow, text=text, justify=LEFT,
- background="#ffffe0", relief=SOLID, borderwidth=1)
- label.pack()
+ def showcontents(self):
+ """content display hook for sub-classes"""
+ # See ToolTip for an example
+ raise NotImplementedError
def hidetip(self):
+ """hide the tooltip"""
+ # Note: This is called by __del__, so careful when overriding/extending
tw = self.tipwindow
self.tipwindow = None
if tw:
- tw.destroy()
+ try:
+ tw.destroy()
+ except TclError:
+ pass
+
+
+class OnHoverTooltipBase(TooltipBase):
+ """abstract base class for tooltips, with delayed on-hover display"""
+
+ def __init__(self, anchor_widget, hover_delay=1000):
+ """Create a tooltip with a mouse hover delay.
+
+ anchor_widget: the widget next to which the tooltip will be shown
+ hover_delay: time to delay before showing the tooltip, in milliseconds
-class ToolTip(ToolTipBase):
- def __init__(self, button, text):
- ToolTipBase.__init__(self, button)
+ Note that a widget will only be shown when showtip() is called,
+ e.g. after hovering over the anchor widget with the mouse for enough
+ time.
+ """
+ super(OnHoverTooltipBase, self).__init__(anchor_widget)
+ self.hover_delay = hover_delay
+
+ self._after_id = None
+ self._id1 = self.anchor_widget.bind("<Enter>", self._show_event)
+ self._id2 = self.anchor_widget.bind("<Leave>", self._hide_event)
+ self._id3 = self.anchor_widget.bind("<Button>", self._hide_event)
+
+ def __del__(self):
+ try:
+ self.anchor_widget.unbind("<Enter>", self._id1)
+ self.anchor_widget.unbind("<Leave>", self._id2)
+ self.anchor_widget.unbind("<Button>", self._id3)
+ except TclError:
+ pass
+ super(OnHoverTooltipBase, self).__del__()
+
+ def _show_event(self, event=None):
+ """event handler to display the tooltip"""
+ if self.hover_delay:
+ self.schedule()
+ else:
+ self.showtip()
+
+ def _hide_event(self, event=None):
+ """event handler to hide the tooltip"""
+ self.hidetip()
+
+ def schedule(self):
+ """schedule the future display of the tooltip"""
+ self.unschedule()
+ self._after_id = self.anchor_widget.after(self.hover_delay,
+ self.showtip)
+
+ def unschedule(self):
+ """cancel the future display of the tooltip"""
+ after_id = self._after_id
+ self._after_id = None
+ if after_id:
+ self.anchor_widget.after_cancel(after_id)
+
+ def hidetip(self):
+ """hide the tooltip"""
+ try:
+ self.unschedule()
+ except TclError:
+ pass
+ super(OnHoverTooltipBase, self).hidetip()
+
+
+class Hovertip(OnHoverTooltipBase):
+ "A tooltip that pops up when a mouse hovers over an anchor widget."
+ def __init__(self, anchor_widget, text, hover_delay=1000):
+ """Create a text tooltip with a mouse hover delay.
+
+ anchor_widget: the widget next to which the tooltip will be shown
+ hover_delay: time to delay before showing the tooltip, in milliseconds
+
+ Note that a widget will only be shown when showtip() is called,
+ e.g. after hovering over the anchor widget with the mouse for enough
+ time.
+ """
+ super(Hovertip, self).__init__(anchor_widget, hover_delay=hover_delay)
self.text = text
- def showcontents(self):
- ToolTipBase.showcontents(self, self.text)
-class ListboxToolTip(ToolTipBase):
- def __init__(self, button, items):
- ToolTipBase.__init__(self, button)
- self.items = items
def showcontents(self):
- listbox = Listbox(self.tipwindow, background="#ffffe0")
- listbox.pack()
- for item in self.items:
- listbox.insert(END, item)
+ label = Label(self.tipwindow, text=self.text, justify=LEFT,
+ background="#ffffe0", relief=SOLID, borderwidth=1)
+ label.pack()
+
def _tooltip(parent): # htest #
top = Toplevel(parent)
top.geometry("+%d+%d" % (x, y + 150))
label = Label(top, text="Place your mouse over buttons")
label.pack()
- button1 = Button(top, text="Button 1")
- button2 = Button(top, text="Button 2")
+ button1 = Button(top, text="Button 1 -- 1/2 second hover delay")
button1.pack()
+ Hovertip(button1, "This is tooltip text for button1.", hover_delay=500)
+ button2 = Button(top, text="Button 2 -- no hover delay")
button2.pack()
- ToolTip(button1, "This is tooltip text for button1.")
- ListboxToolTip(button2, ["This is","multiple line",
- "tooltip text","for button2"])
+ Hovertip(button2, "This is tooltip\ntext for button2.", hover_delay=None)
+
if __name__ == '__main__':
+ from unittest import main
+ main('idlelib.idle_test.test_tooltip', verbosity=2, exit=False)
+
from idlelib.idle_test.htest import run
run(_tooltip)
node.expand()
if __name__ == '__main__':
- # test_tree is currently a copy of this
+ from unittest import main
+ main('idlelib.idle_test.test_tree', verbosity=2, exit=False)
+
from idlelib.idle_test.htest import run
run(_tree_widget)
dump.pack(side='left')
if __name__ == "__main__":
- import unittest
- unittest.main('idlelib.idle_test.test_undo', verbosity=2, exit=False)
+ from unittest import main
+ main('idlelib.idle_test.test_undo', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(_undo_delegator)
--- /dev/null
+from tkinter import *
+
+
+class WindowList:
+
+ def __init__(self):
+ self.dict = {}
+ self.callbacks = []
+
+ def add(self, window):
+ window.after_idle(self.call_callbacks)
+ self.dict[str(window)] = window
+
+ def delete(self, window):
+ try:
+ del self.dict[str(window)]
+ except KeyError:
+ # Sometimes, destroy() is called twice
+ pass
+ self.call_callbacks()
+
+ def add_windows_to_menu(self, menu):
+ list = []
+ for key in self.dict:
+ window = self.dict[key]
+ try:
+ title = window.get_title()
+ except TclError:
+ continue
+ list.append((title, key, window))
+ list.sort()
+ for title, key, window in list:
+ menu.add_command(label=title, command=window.wakeup)
+
+ def register_callback(self, callback):
+ self.callbacks.append(callback)
+
+ def unregister_callback(self, callback):
+ try:
+ self.callbacks.remove(callback)
+ except ValueError:
+ pass
+
+ def call_callbacks(self):
+ for callback in self.callbacks:
+ try:
+ callback()
+ except:
+ t, v, tb = sys.exc_info()
+ print("warning: callback failed in WindowList", t, ":", v)
+
+
+registry = WindowList()
+
+add_windows_to_menu = registry.add_windows_to_menu
+register_callback = registry.register_callback
+unregister_callback = registry.unregister_callback
+
+
+class ListedToplevel(Toplevel):
+
+ def __init__(self, master, **kw):
+ Toplevel.__init__(self, master, kw)
+ registry.add(self)
+ self.focused_widget = self
+
+ def destroy(self):
+ registry.delete(self)
+ Toplevel.destroy(self)
+ # If this is Idle's last window then quit the mainloop
+ # (Needed for clean exit on Windows 98)
+ if not registry.dict:
+ self.quit()
+
+ def update_windowlist_registry(self, window):
+ registry.call_callbacks()
+
+ def get_title(self):
+ # Subclass can override
+ return self.wm_title()
+
+ def wakeup(self):
+ try:
+ if self.wm_state() == "iconic":
+ self.wm_withdraw()
+ self.wm_deiconify()
+ self.tkraise()
+ self.focused_widget.focus_set()
+ except TclError:
+ # This can happen when the Window menu was torn off.
+ # Simply ignore it.
+ pass
+
+
+if __name__ == "__main__":
+ from unittest import main
+ main('idlelib.idle_test.test_window', verbosity=2)
+++ /dev/null
-from tkinter import *
-
-
-class WindowList:
-
- def __init__(self):
- self.dict = {}
- self.callbacks = []
-
- def add(self, window):
- window.after_idle(self.call_callbacks)
- self.dict[str(window)] = window
-
- def delete(self, window):
- try:
- del self.dict[str(window)]
- except KeyError:
- # Sometimes, destroy() is called twice
- pass
- self.call_callbacks()
-
- def add_windows_to_menu(self, menu):
- list = []
- for key in self.dict:
- window = self.dict[key]
- try:
- title = window.get_title()
- except TclError:
- continue
- list.append((title, key, window))
- list.sort()
- for title, key, window in list:
- menu.add_command(label=title, command=window.wakeup)
-
- def register_callback(self, callback):
- self.callbacks.append(callback)
-
- def unregister_callback(self, callback):
- try:
- self.callbacks.remove(callback)
- except ValueError:
- pass
-
- def call_callbacks(self):
- for callback in self.callbacks:
- try:
- callback()
- except:
- t, v, tb = sys.exc_info()
- print("warning: callback failed in WindowList", t, ":", v)
-
-
-registry = WindowList()
-
-add_windows_to_menu = registry.add_windows_to_menu
-register_callback = registry.register_callback
-unregister_callback = registry.unregister_callback
-
-
-class ListedToplevel(Toplevel):
-
- def __init__(self, master, **kw):
- Toplevel.__init__(self, master, kw)
- registry.add(self)
- self.focused_widget = self
-
- def destroy(self):
- registry.delete(self)
- Toplevel.destroy(self)
- # If this is Idle's last window then quit the mainloop
- # (Needed for clean exit on Windows 98)
- if not registry.dict:
- self.quit()
-
- def update_windowlist_registry(self, window):
- registry.call_callbacks()
-
- def get_title(self):
- # Subclass can override
- return self.wm_title()
-
- def wakeup(self):
- try:
- if self.wm_state() == "iconic":
- self.wm_withdraw()
- self.wm_deiconify()
- self.tkraise()
- self.focused_widget.focus_set()
- except TclError:
- # This can happen when the window menu was torn off.
- # Simply ignore it.
- pass
def __init__(self, editwin):
self.editwin = editwin
- def zoom_height_event(self, event):
+ def zoom_height_event(self, event=None):
top = self.editwin.top
zoom_height(top)
return "break"
else:
newgeom = "%dx%d+%d+%d" % (width, newheight, x, newy)
top.wm_geometry(newgeom)
+
+
+if __name__ == "__main__":
+ from unittest import main
+ main('idlelib.idle_test.test_zoomheight', verbosity=2, exit=False)
+
+ # Add htest?
'LOGIN': ('NONAUTH',),
'LOGOUT': ('NONAUTH', 'AUTH', 'SELECTED', 'LOGOUT'),
'LSUB': ('AUTH', 'SELECTED'),
+ 'MOVE': ('SELECTED',),
'NAMESPACE': ('AUTH', 'SELECTED'),
'NOOP': ('NONAUTH', 'AUTH', 'SELECTED', 'LOGOUT'),
'PARTIAL': ('SELECTED',), # NB: obsolete
def _create_socket(self):
- return socket.create_connection((self.host, self.port))
+ # Default value of IMAP4.host is '', but socket.getaddrinfo()
+ # (which is used by socket.create_connection()) expects None
+ # as a default value for host.
+ host = None if not self.host else self.host
+ return socket.create_connection((host, self.port))
def open(self, host = '', port = IMAP4_PORT):
"""Setup connection to remote server on "host:port"
object = unwrap(object)
lines, lnum = findsource(object)
- if ismodule(object):
+ if istraceback(object):
+ object = object.tb_frame
+
+ # for module or frame that corresponds to module, return all source lines
+ if (ismodule(object) or
+ (isframe(object) and object.f_code.co_name == "<module>")):
return lines, 0
else:
return getblock(lines[lnum:]), lnum + 1
module = sys.modules.get(module_name, None)
if module:
module_dict = module.__dict__
- sys_module_dict = sys.modules
+ sys_module_dict = sys.modules.copy()
def parse_name(node):
assert isinstance(node, ast.arg)
responsible for converting a LogRecord to (usually) a string which can
be interpreted by either a human or an external system. The base Formatter
allows a formatting string to be specified. If none is supplied, the
- default value of "%s(message)" is used.
+ the style-dependent default value, "%(message)s", "{message}", or
+ "${message}", is used.
The Formatter can be initialized with a format string which makes use of
knowledge of the LogRecord attributes - e.g. the default value mentioned
# critical section
logging._acquireLock()
try:
- logging._handlers.clear()
- del logging._handlerList[:]
+ _clearExistingHandlers()
+
# Handlers add themselves to logging._handlers
handlers = _install_handlers(cp, formatters)
_install_loggers(cp, handlers, disable_existing_loggers)
# logger.disabled = 1
_handle_existing_loggers(existing, child_loggers, disable_existing)
+
+def _clearExistingHandlers():
+ """Clear and close existing handlers"""
+ logging._handlers.clear()
+ logging.shutdown(logging._handlerList[:])
+ del logging._handlerList[:]
+
+
IDENTIFIER = re.compile('^[a-z_][a-z0-9_]*$', re.I)
else:
disable_existing = config.pop('disable_existing_loggers', True)
- logging._handlers.clear()
- del logging._handlerList[:]
+ _clearExistingHandlers()
# Do formatters first - they don't refer to anything else
formatters = config.get('formatters', EMPTY_DICT)
def _init_timeout(timeout=CONNECTION_TIMEOUT):
- return time.time() + timeout
+ return time.monotonic() + timeout
def _check_timeout(t):
- return time.time() > t
+ return time.monotonic() > t
#
#
selector.register(obj, selectors.EVENT_READ)
if timeout is not None:
- deadline = time.time() + timeout
+ deadline = time.monotonic() + timeout
while True:
ready = selector.select(timeout)
return [key.fileobj for (key, events) in ready]
else:
if timeout is not None:
- timeout = deadline - time.time()
+ timeout = deadline - time.monotonic()
if timeout < 0:
return ready
import threading
import array
import queue
+import time
-from time import time as _time
from traceback import format_exc
from . import connection
if result:
return result
if timeout is not None:
- endtime = _time() + timeout
+ endtime = time.monotonic() + timeout
else:
endtime = None
waittime = None
while not result:
if endtime is not None:
- waittime = endtime - _time()
+ waittime = endtime - time.monotonic()
if waittime <= 0:
break
self.wait(waittime)
DictProxy = MakeProxyType('DictProxy', (
- '__contains__', '__delitem__', '__getitem__', '__len__',
+ '__contains__', '__delitem__', '__getitem__', '__iter__', '__len__',
'__setitem__', 'clear', 'copy', 'get', 'has_key', 'items',
'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'
))
+DictProxy._method_to_typeid_ = {
+ '__iter__': 'Iterator',
+ }
ArrayProxy = MakeProxyType('ArrayProxy', (
'''
_wrap_exception = True
- def Process(self, *args, **kwds):
- return self._ctx.Process(*args, **kwds)
+ @staticmethod
+ def Process(ctx, *args, **kwds):
+ return ctx.Process(*args, **kwds)
def __init__(self, processes=None, initializer=None, initargs=(),
maxtasksperchild=None, context=None):
self._worker_handler = threading.Thread(
target=Pool._handle_workers,
- args=(self, )
+ args=(self._cache, self._taskqueue, self._ctx, self.Process,
+ self._processes, self._pool, self._inqueue, self._outqueue,
+ self._initializer, self._initargs, self._maxtasksperchild,
+ self._wrap_exception)
)
self._worker_handler.daemon = True
self._worker_handler._state = RUN
self._worker_handler.start()
-
self._task_handler = threading.Thread(
target=Pool._handle_tasks,
args=(self._taskqueue, self._quick_put, self._outqueue,
exitpriority=15
)
- def _join_exited_workers(self):
+ @staticmethod
+ def _join_exited_workers(pool):
"""Cleanup after any worker processes which have exited due to reaching
their specified lifetime. Returns True if any workers were cleaned up.
"""
cleaned = False
- for i in reversed(range(len(self._pool))):
- worker = self._pool[i]
+ for i in reversed(range(len(pool))):
+ worker = pool[i]
if worker.exitcode is not None:
# worker exited
util.debug('cleaning up worker %d' % i)
worker.join()
cleaned = True
- del self._pool[i]
+ del pool[i]
return cleaned
def _repopulate_pool(self):
+ return self._repopulate_pool_static(self._ctx, self.Process,
+ self._processes,
+ self._pool, self._inqueue,
+ self._outqueue, self._initializer,
+ self._initargs,
+ self._maxtasksperchild,
+ self._wrap_exception)
+
+ @staticmethod
+ def _repopulate_pool_static(ctx, Process, processes, pool, inqueue,
+ outqueue, initializer, initargs,
+ maxtasksperchild, wrap_exception):
"""Bring the number of pool processes up to the specified number,
for use after reaping workers which have exited.
"""
- for i in range(self._processes - len(self._pool)):
- w = self.Process(target=worker,
- args=(self._inqueue, self._outqueue,
- self._initializer,
- self._initargs, self._maxtasksperchild,
- self._wrap_exception)
- )
- self._pool.append(w)
+ for i in range(processes - len(pool)):
+ w = Process(ctx, target=worker,
+ args=(inqueue, outqueue,
+ initializer,
+ initargs, maxtasksperchild,
+ wrap_exception)
+ )
+ pool.append(w)
w.name = w.name.replace('Process', 'PoolWorker')
w.daemon = True
w.start()
util.debug('added worker')
- def _maintain_pool(self):
+ @staticmethod
+ def _maintain_pool(ctx, Process, processes, pool, inqueue, outqueue,
+ initializer, initargs, maxtasksperchild,
+ wrap_exception):
"""Clean up any exited workers and start replacements for them.
"""
- if self._join_exited_workers():
- self._repopulate_pool()
+ if Pool._join_exited_workers(pool):
+ Pool._repopulate_pool_static(ctx, Process, processes, pool,
+ inqueue, outqueue, initializer,
+ initargs, maxtasksperchild,
+ wrap_exception)
def _setup_queues(self):
self._inqueue = self._ctx.SimpleQueue()
return result
@staticmethod
- def _handle_workers(pool):
+ def _handle_workers(cache, taskqueue, ctx, Process, processes, pool,
+ inqueue, outqueue, initializer, initargs,
+ maxtasksperchild, wrap_exception):
thread = threading.current_thread()
# Keep maintaining workers until the cache gets drained, unless the pool
# is terminated.
- while thread._state == RUN or (pool._cache and thread._state != TERMINATE):
- pool._maintain_pool()
+ while thread._state == RUN or (cache and thread._state != TERMINATE):
+ Pool._maintain_pool(ctx, Process, processes, pool, inqueue,
+ outqueue, initializer, initargs,
+ maxtasksperchild, wrap_exception)
time.sleep(0.1)
# send sentinel to stop workers
- pool._taskqueue.put(None)
+ taskqueue.put(None)
util.debug('worker handler exiting')
@staticmethod
_wrap_exception = False
@staticmethod
- def Process(*args, **kwds):
+ def Process(ctx, *args, **kwds):
from .dummy import Process
return Process(*args, **kwds)
self._sem.release()
else:
if block:
- deadline = time.time() + timeout
+ deadline = time.monotonic() + timeout
if not self._rlock.acquire(block, timeout):
raise Empty
try:
if block:
- timeout = deadline - time.time()
+ timeout = deadline - time.monotonic()
if not self._poll(timeout):
raise Empty
elif not self._poll():
'''Receive an array of fds over an AF_UNIX socket.'''
a = array.array('i')
bytes_size = a.itemsize * size
- msg, ancdata, flags, addr = sock.recvmsg(1, socket.CMSG_LEN(bytes_size))
+ msg, ancdata, flags, addr = sock.recvmsg(1, socket.CMSG_SPACE(bytes_size))
if not msg and not ancdata:
raise EOFError
try:
import sys
import tempfile
import _multiprocessing
-
-from time import time as _time
+import time
from . import context
from . import process
if result:
return result
if timeout is not None:
- endtime = _time() + timeout
+ endtime = time.monotonic() + timeout
else:
endtime = None
waittime = None
while not result:
if endtime is not None:
- waittime = endtime - _time()
+ waittime = endtime - time.monotonic()
if waittime <= 0:
break
self.wait(waittime)
comps.append(curdir)
return prefix + sep.join(comps)
+def _abspath_fallback(path):
+ """Return the absolute version of a path as a fallback function in case
+ `nt._getfullpathname` is not available or raises OSError. See bpo-31047 for
+ more.
+
+ """
+
+ path = os.fspath(path)
+ if not isabs(path):
+ if isinstance(path, bytes):
+ cwd = os.getcwdb()
+ else:
+ cwd = os.getcwd()
+ path = join(cwd, path)
+ return normpath(path)
# Return an absolute path.
try:
from nt import _getfullpathname
except ImportError: # not running on Windows - mock up something sensible
- def abspath(path):
- """Return the absolute version of a path."""
- path = os.fspath(path)
- if not isabs(path):
- if isinstance(path, bytes):
- cwd = os.getcwdb()
- else:
- cwd = os.getcwd()
- path = join(cwd, path)
- return normpath(path)
+ abspath = _abspath_fallback
else: # use native Windows method on Windows
def abspath(path):
"""Return the absolute version of a path."""
-
- if path: # Empty path must return current working directory.
- path = os.fspath(path)
- try:
- path = _getfullpathname(path)
- except OSError:
- pass # Bad path - return unchanged.
- elif isinstance(path, bytes):
- path = os.getcwdb()
- else:
- path = os.getcwd()
- return normpath(path)
+ try:
+ return _getfullpathname(path)
+ except OSError:
+ return _abspath_fallback(path)
# realpath is a no-op on systems without islink support
realpath = abspath
self._parts[:-1] + [name])
def with_suffix(self, suffix):
- """Return a new path with the file suffix changed (or added, if none)."""
- # XXX if suffix is None, should the current suffix be removed?
+ """Return a new path with the file suffix changed. If the path
+ has no suffix, add given suffix. If the given suffix is an empty
+ string, remove the suffix from the path.
+ """
f = self._flavour
if f.sep in suffix or f.altsep and f.altsep in suffix:
raise ValueError("Invalid suffix %r" % (suffix))
stack_before=[],
stack_after=[pybool],
proto=2,
- doc="""True.
-
- Push True onto the stack."""),
+ doc="Push True onto the stack."),
I(name='NEWFALSE',
code='\x89',
stack_before=[],
stack_after=[pybool],
proto=2,
- doc="""True.
-
- Push False onto the stack."""),
+ doc="Push False onto the stack."),
# Ways to spell Unicode strings.
# Constant used by test_platform to test linux_distribution().
_UNIXCONFDIR = '/etc'
+# Helper for comparing two version number strings.
+# Based on the description of the PHP's version_compare():
+# http://php.net/manual/en/function.version-compare.php
+
+_ver_stages = {
+ # any string not found in this dict, will get 0 assigned
+ 'dev': 10,
+ 'alpha': 20, 'a': 20,
+ 'beta': 30, 'b': 30,
+ 'c': 40,
+ 'RC': 50, 'rc': 50,
+ # number, will get 100 assigned
+ 'pl': 200, 'p': 200,
+}
+
+_component_re = re.compile(r'([0-9]+|[._+-])')
+
+def _comparable_version(version):
+ result = []
+ for v in _component_re.split(version):
+ if v not in '._+-':
+ try:
+ v = int(v, 10)
+ t = 100
+ except ValueError:
+ t = _ver_stages.get(v, 0)
+ result.extend((t, v))
+ return result
+
### Platform specific APIs
_libc_search = re.compile(b'(__libc_init)'
b'|'
br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
-def libc_ver(executable=sys.executable, lib='', version='',
-
- chunksize=16384):
+def libc_ver(executable=sys.executable, lib='', version='', chunksize=16384):
""" Tries to determine the libc version that the file executable
(which defaults to the Python interpreter) is linked against.
The file is read and scanned in chunks of chunksize bytes.
"""
+ V = _comparable_version
if hasattr(os.path, 'realpath'):
# Python 2.2 introduced os.path.realpath(); it is used
# here to work around problems with Cygwin not being
with open(executable, 'rb') as f:
binary = f.read(chunksize)
pos = 0
- while 1:
+ while pos < len(binary):
if b'libc' in binary or b'GLIBC' in binary:
m = _libc_search.search(binary, pos)
else:
m = None
- if not m:
- binary = f.read(chunksize)
- if not binary:
+ if not m or m.end() == len(binary):
+ chunk = f.read(chunksize)
+ if chunk:
+ binary = binary[max(pos, len(binary) - 1000):] + chunk
+ pos = 0
+ continue
+ if not m:
break
- pos = 0
- continue
libcinit, glibc, glibcversion, so, threads, soversion = [
s.decode('latin1') if s is not None else s
for s in m.groups()]
if lib != 'glibc':
lib = 'glibc'
version = glibcversion
- elif glibcversion > version:
+ elif V(glibcversion) > V(version):
version = glibcversion
elif so:
if lib != 'glibc':
lib = 'libc'
- if soversion and soversion > version:
+ if soversion and (not version or V(soversion) > V(version)):
version = soversion
if threads and version[-len(threads):] != threads:
version = version + threads
warnings.warn('use os.popen instead', DeprecationWarning, stacklevel=2)
return os.popen(cmd, mode, bufsize)
+
def _norm_version(version, build=''):
""" Normalize the version and build strings and return a single
except KeyError:
self.output.write('no documentation found for %s\n' % repr(topic))
return
- pager(doc.strip() + '\n')
+ doc = doc.strip() + '\n'
if more_xrefs:
xrefs = (xrefs or '') + ' ' + more_xrefs
if xrefs:
import textwrap
text = 'Related help topics: ' + ', '.join(xrefs.split()) + '\n'
wrapped_text = textwrap.wrap(text, 72)
- self.output.write('\n%s\n' % ''.join(wrapped_text))
+ doc += '\n%s\n' % '\n'.join(wrapped_text)
+ pager(doc)
def _gettopic(self, topic, more_xrefs=''):
"""Return unbuffered tuple of (topic, xrefs).
# -*- coding: utf-8 -*-
-# Autogenerated by Sphinx on Tue Jun 12 00:16:23 2018
+# Autogenerated by Sphinx on Sat Oct 20 01:13:41 2018
topics = {'assert': 'The "assert" statement\n'
'**********************\n'
'\n'
'operators:\n'
'\n'
' m_expr ::= u_expr | m_expr "*" u_expr | m_expr "@" m_expr |\n'
- ' m_expr "//" u_expr| m_expr "/" u_expr |\n'
+ ' m_expr "//" u_expr | m_expr "/" u_expr |\n'
' m_expr "%" u_expr\n'
' a_expr ::= m_expr | a_expr "+" m_expr | a_expr "-" m_expr\n'
'\n'
'the\n'
'interpretation that is conventional in mathematics:\n'
'\n'
- ' comparison ::= or_expr ( comp_operator or_expr )*\n'
+ ' comparison ::= or_expr (comp_operator or_expr)*\n'
' comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n'
' | "is" ["not"] | ["not"] "in"\n'
'\n'
'The "if" statement is used for conditional execution:\n'
'\n'
' if_stmt ::= "if" expression ":" suite\n'
- ' ( "elif" expression ":" suite )*\n'
+ ' ("elif" expression ":" suite)*\n'
' ["else" ":" suite]\n'
'\n'
'It selects exactly one of the suites by evaluating the '
'\n'
'Note: There is a subtlety when the sequence is being modified by '
'the\n'
- ' loop (this can only occur for mutable sequences, i.e. lists). '
+ ' loop (this can only occur for mutable sequences, e.g. lists). '
'An\n'
' internal counter is used to keep track of which item is used '
'next,\n'
'section The standard type hierarchy):\n'
'\n'
' funcdef ::= [decorators] "def" funcname "(" '
- '[parameter_list] ")" ["->" expression] ":" suite\n'
+ '[parameter_list] ")"\n'
+ ' ["->" expression] ":" suite\n'
' decorators ::= decorator+\n'
' decorator ::= "@" dotted_name ["(" '
'[argument_list [","]] ")"] NEWLINE\n'
'-----------------------------\n'
'\n'
' async_funcdef ::= [decorators] "async" "def" funcname "(" '
- '[parameter_list] ")" ["->" expression] ":" suite\n'
+ '[parameter_list] ")"\n'
+ ' ["->" expression] ":" suite\n'
'\n'
'Execution of Python coroutines can be suspended and resumed at '
'many\n'
'The "if" statement is used for conditional execution:\n'
'\n'
' if_stmt ::= "if" expression ":" suite\n'
- ' ( "elif" expression ":" suite )*\n'
+ ' ("elif" expression ":" suite)*\n'
' ["else" ":" suite]\n'
'\n'
'It selects exactly one of the suites by evaluating the expressions '
'exprlists': 'Expression lists\n'
'****************\n'
'\n'
- ' expression_list ::= expression ( "," expression )* [","]\n'
- ' starred_list ::= starred_item ( "," starred_item )* '
+ ' expression_list ::= expression ("," expression)* [","]\n'
+ ' starred_list ::= starred_item ("," starred_item)* '
'[","]\n'
- ' starred_expression ::= expression | ( starred_item "," )* '
+ ' starred_expression ::= expression | (starred_item ",")* '
'[starred_item]\n'
' starred_item ::= expression | "*" or_expr\n'
'\n'
':= a to b do"; e.g., "list(range(3))" returns the list "[0, 1, 2]".\n'
'\n'
'Note: There is a subtlety when the sequence is being modified by the\n'
- ' loop (this can only occur for mutable sequences, i.e. lists). An\n'
+ ' loop (this can only occur for mutable sequences, e.g. lists). An\n'
' internal counter is used to keep track of which item is used next,\n'
' and this is incremented on each iteration. When this counter has\n'
' reached the length of the sequence the loop terminates. This '
'\n'
'Changed in version 3.1: The positional argument specifiers '
'can be\n'
- 'omitted, so "\'{} {}\'" is equivalent to "\'{0} {1}\'".\n'
+ 'omitted for "str.format()", so "\'{} {}\'.format(a, b)" is '
+ 'equivalent to\n'
+ '"\'{0} {1}\'.format(a, b)".\n'
+ '\n'
+ 'Changed in version 3.4: The positional argument specifiers '
+ 'can be\n'
+ 'omitted for "Formatter".\n'
'\n'
'Some simple format string examples:\n'
'\n'
'character. |\n'
' '
'+-----------+------------------------------------------------------------+\n'
- ' | "\'f\'" | Fixed point. Displays the number as a '
- 'fixed-point number. |\n'
- ' | | The default precision is '
- '"6". |\n'
+ ' | "\'f\'" | Fixed-point notation. Displays the '
+ 'number as a fixed-point |\n'
+ ' | | number. The default precision is '
+ '"6". |\n'
' '
'+-----------+------------------------------------------------------------+\n'
- ' | "\'F\'" | Fixed point. Same as "\'f\'", but '
- 'converts "nan" to "NAN" |\n'
- ' | | and "inf" to '
- '"INF". |\n'
+ ' | "\'F\'" | Fixed-point notation. Same as "\'f\'", '
+ 'but converts "nan" to |\n'
+ ' | | "NAN" and "inf" to '
+ '"INF". |\n'
' '
'+-----------+------------------------------------------------------------+\n'
' | "\'g\'" | General format. For a given precision '
' 3232235521\n'
' >>>\n'
' >>> width = 5\n'
- ' >>> for num in range(5,12): #doctest: '
- '+NORMALIZE_WHITESPACE\n'
+ ' >>> for num in range(5,12): \n'
" ... for base in 'dXob':\n"
" ... print('{0:{width}{base}}'.format(num, "
"base=base, width=width), end=' ')\n"
'section The standard type hierarchy):\n'
'\n'
' funcdef ::= [decorators] "def" funcname "(" '
- '[parameter_list] ")" ["->" expression] ":" suite\n'
+ '[parameter_list] ")"\n'
+ ' ["->" expression] ":" suite\n'
' decorators ::= decorator+\n'
' decorator ::= "@" dotted_name ["(" '
'[argument_list [","]] ")"] NEWLINE\n'
'The "if" statement is used for conditional execution:\n'
'\n'
' if_stmt ::= "if" expression ":" suite\n'
- ' ( "elif" expression ":" suite )*\n'
+ ' ("elif" expression ":" suite)*\n'
' ["else" ":" suite]\n'
'\n'
'It selects exactly one of the suites by evaluating the expressions '
'import': 'The "import" statement\n'
'**********************\n'
'\n'
- ' import_stmt ::= "import" module ["as" name] ( "," module '
- '["as" name] )*\n'
+ ' import_stmt ::= "import" module ["as" identifier] ("," '
+ 'module ["as" identifier])*\n'
' | "from" relative_module "import" identifier '
- '["as" name]\n'
- ' ( "," identifier ["as" name] )*\n'
+ '["as" identifier]\n'
+ ' ("," identifier ["as" identifier])*\n'
' | "from" relative_module "import" "(" '
- 'identifier ["as" name]\n'
- ' ( "," identifier ["as" name] )* [","] ")"\n'
+ 'identifier ["as" identifier]\n'
+ ' ("," identifier ["as" identifier])* [","] ")"\n'
' | "from" module "import" "*"\n'
' module ::= (identifier ".")* identifier\n'
' relative_module ::= "."* module | "."+\n'
- ' name ::= identifier\n'
'\n'
'The basic import statement (no "from" clause) is executed in two\n'
'steps:\n'
'allows use of the new features on a per-module basis before the\n'
'release in which the feature becomes standard.\n'
'\n'
- ' future_statement ::= "from" "__future__" "import" feature ["as" '
- 'name]\n'
- ' ("," feature ["as" name])*\n'
- ' | "from" "__future__" "import" "(" feature '
- '["as" name]\n'
- ' ("," feature ["as" name])* [","] ")"\n'
- ' feature ::= identifier\n'
- ' name ::= identifier\n'
+ ' future_stmt ::= "from" "__future__" "import" feature ["as" '
+ 'identifier]\n'
+ ' ("," feature ["as" identifier])*\n'
+ ' | "from" "__future__" "import" "(" feature '
+ '["as" identifier]\n'
+ ' ("," feature ["as" identifier])* [","] ")"\n'
+ ' feature ::= identifier\n'
'\n'
'A future statement must appear near the top of the module. The '
'only\n'
'The\n'
'syntax is:\n'
'\n'
- ' power ::= ( await_expr | primary ) ["**" u_expr]\n'
+ ' power ::= (await_expr | primary) ["**" u_expr]\n'
'\n'
'Thus, in an unparenthesized sequence of power and unary operators, '
'the\n'
'The shifting operations have lower priority than the arithmetic\n'
'operations:\n'
'\n'
- ' shift_expr ::= a_expr | shift_expr ( "<<" | ">>" ) a_expr\n'
+ ' shift_expr ::= a_expr | shift_expr ("<<" | ">>") a_expr\n'
'\n'
'These operators accept integers as arguments. They shift the '
'first\n'
' formatting options that can be specified in format '
'strings.\n'
'\n'
- ' Note: When formatting a number ("int", "float", "float" '
- 'and\n'
- ' subclasses) with the "n" type (ex: '
- '"\'{:n}\'.format(1234)"), the\n'
- ' function sets temporarily the "LC_CTYPE" locale to '
- 'the\n'
- ' "LC_NUMERIC" locale to decode "decimal_point" and '
- '"thousands_sep"\n'
- ' fields of "localeconv()" if they are non-ASCII or '
- 'longer than 1\n'
- ' byte, and the "LC_NUMERIC" locale is different than '
- 'the\n'
- ' "LC_CTYPE" locale. This temporary change affects '
- 'other threads.\n'
+ ' Note: When formatting a number ("int", "float", '
+ '"complex",\n'
+ ' "decimal.Decimal" and subclasses) with the "n" type '
+ '(ex:\n'
+ ' "\'{:n}\'.format(1234)"), the function temporarily '
+ 'sets the\n'
+ ' "LC_CTYPE" locale to the "LC_NUMERIC" locale to '
+ 'decode\n'
+ ' "decimal_point" and "thousands_sep" fields of '
+ '"localeconv()" if\n'
+ ' they are non-ASCII or longer than 1 byte, and the '
+ '"LC_NUMERIC"\n'
+ ' locale is different than the "LC_CTYPE" locale. This '
+ 'temporary\n'
+ ' change affects other threads.\n'
'\n'
' Changed in version 3.6.5: When formatting a number with '
'the "n"\n'
' Return a copy of the string with all the cased '
'characters [4]\n'
' converted to uppercase. Note that '
- '"str.upper().isupper()" might be\n'
+ '"s.upper().isupper()" might be\n'
' "False" if "s" contains uncased characters or if the '
'Unicode\n'
' category of the resulting character(s) is not “Lu” '
'exactly one\n'
'item.)\n'
'\n'
- 'If the primary is a sequence, the expression (list) must '
- 'evaluate to\n'
- 'an integer or a slice (as discussed in the following '
+ 'If the primary is a sequence, the expression list must '
+ 'evaluate to an\n'
+ 'integer or a slice (as discussed in the following '
'section).\n'
'\n'
'The formal syntax makes no special provision for negative '
'| | "s[len(s):len(s)] = '
'[x]") | |\n'
'+--------------------------------+----------------------------------+-----------------------+\n'
- '| "s.clear()" | removes all items from "s" '
+ '| "s.clear()" | removes all items from *s* '
'(same | (5) |\n'
'| | as "del '
's[:]") | |\n'
'+--------------------------------+----------------------------------+-----------------------+\n'
'| "s.copy()" | creates a shallow copy of '
- '"s" | (5) |\n'
+ '*s* | (5) |\n'
'| | (same as '
'"s[:]") | |\n'
'+--------------------------------+----------------------------------+-----------------------+\n'
'\n'
' * The linspace recipe shows how to implement a lazy version '
'of\n'
- ' range that suitable for floating point applications.\n',
+ ' range suitable for floating point applications.\n',
'typesseq-mutable': 'Mutable Sequence Types\n'
'**********************\n'
'\n'
'[x]") | |\n'
'+--------------------------------+----------------------------------+-----------------------+\n'
'| "s.clear()" | removes all items '
- 'from "s" (same | (5) |\n'
+ 'from *s* (same | (5) |\n'
'| | as "del '
's[:]") | |\n'
'+--------------------------------+----------------------------------+-----------------------+\n'
'| "s.copy()" | creates a shallow '
- 'copy of "s" | (5) |\n'
+ 'copy of *s* | (5) |\n'
'| | (same as '
'"s[:]") | |\n'
'+--------------------------------+----------------------------------+-----------------------+\n'
raise ValueError('The number of weights does not match the population')
bisect = _bisect.bisect
total = cum_weights[-1]
- return [population[bisect(cum_weights, random() * total)] for i in range(k)]
+ hi = len(cum_weights) - 1
+ return [population[bisect(cum_weights, random() * total, 0, hi)]
+ for i in range(k)]
## -------------------- real-valued distributions -------------------
readline.read_history_file(history)
except IOError:
pass
- atexit.register(readline.write_history_file, history)
+
+ def write_history():
+ try:
+ readline.write_history_file(history)
+ except (FileNotFoundError, PermissionError):
+ # home directory does not exist or is not writable
+ # https://bugs.python.org/issue19891
+ pass
+
+ atexit.register(write_history)
sys.__interactivehook__ = register_readline
"""SMTP 'noop' command -- doesn't do anything :>"""
return self.docmd("noop")
- def mail(self, sender, options=[]):
+ def mail(self, sender, options=()):
"""SMTP 'mail' command -- begins mail xfer session.
This method may raise the following exceptions:
self.putcmd("mail", "FROM:%s%s" % (quoteaddr(sender), optionlist))
return self.getreply()
- def rcpt(self, recip, options=[]):
+ def rcpt(self, recip, options=()):
"""SMTP 'rcpt' command -- indicates 1 recipient for this mail."""
optionlist = ''
if options and self.does_esmtp:
It will be called to process the server's challenge response; the
challenge argument it is passed will be a bytes. It should return
- bytes data that will be base64 encoded and sent to the server.
+ an ASCII string that will be base64 encoded and sent to the server.
Keyword arguments:
- initial_response_ok: Allow sending the RFC 4954 initial-response
raise SMTPResponseException(resp, reply)
return (resp, reply)
- def sendmail(self, from_addr, to_addrs, msg, mail_options=[],
- rcpt_options=[]):
+ def sendmail(self, from_addr, to_addrs, msg, mail_options=(),
+ rcpt_options=()):
"""This command performs an entire mail transaction.
The arguments are:
return senderrs
def send_message(self, msg, from_addr=None, to_addrs=None,
- mail_options=[], rcpt_options={}):
+ mail_options=(), rcpt_options=()):
"""Converts message to a bytestring and passes it to sendmail.
The arguments are as for sendmail, except that msg is an
if international:
g = email.generator.BytesGenerator(
bytesmsg, policy=msg.policy.clone(utf8=True))
- mail_options += ['SMTPUTF8', 'BODY=8BITMIME']
+ mail_options = (*mail_options, 'SMTPUTF8', 'BODY=8BITMIME')
else:
g = email.generator.BytesGenerator(bytesmsg)
g.flatten(msg_copy, linesep='\r\n')
When compared to ``SSLSocket``, this object lacks the following features:
- * Any form of network IO incluging methods such as ``recv`` and ``send``.
+ * Any form of network IO, including methods such as ``recv`` and ``send``.
* The ``do_handshake_on_connect`` and ``suppress_ragged_eofs`` machinery.
"""
current SSL channel. """
return self._sslobj.version()
+ def verify_client_post_handshake(self):
+ return self._sslobj.verify_client_post_handshake()
+
class SSLSocket(socket):
"""This class implements a subtype of socket.socket that wraps
else:
raise ValueError("No SSL wrapper around " + str(self))
+ def verify_client_post_handshake(self):
+ if self._sslobj:
+ return self._sslobj.verify_client_post_handshake()
+ else:
+ raise ValueError("No SSL wrapper around " + str(self))
+
def _real_close(self):
self._sslobj = None
socket._real_close(self)
if not buf:
break
t.append(buf)
- buf = "".join(t)
+ buf = b"".join(t)
else:
buf = self._read(size)
self.pos += len(buf)
return self.__read(size)
c = len(self.dbuf)
+ t = [self.dbuf]
while c < size:
buf = self.__read(self.bufsize)
if not buf:
buf = self.cmp.decompress(buf)
except self.exception:
raise ReadError("invalid compressed data")
- self.dbuf += buf
+ t.append(buf)
c += len(buf)
- buf = self.dbuf[:size]
- self.dbuf = self.dbuf[size:]
- return buf
+ t = b"".join(t)
+ self.dbuf = t[size:]
+ return t[:size]
def __read(self, size):
"""Return size bytes from stream. If internal buffer is empty,
read another block from the stream.
"""
c = len(self.buf)
+ t = [self.buf]
while c < size:
buf = self.fileobj.read(self.bufsize)
if not buf:
break
- self.buf += buf
+ t.append(buf)
c += len(buf)
- buf = self.buf[:size]
- self.buf = self.buf[size:]
- return buf
+ t = b"".join(t)
+ self.buf = t[size:]
+ return t[:size]
# class _Stream
class _StreamProxy(object):
from multiprocessing.forkserver import _forkserver
_forkserver.ensure_running()
+ # First process sleeps 500 ms
+ delay = 0.5
+
evt = self.Event()
- proc = self.Process(target=self._sleep_and_set_event, args=(evt, 1.0))
+ proc = self.Process(target=self._sleep_and_set_event, args=(evt, delay))
proc.start()
pid = _forkserver._forkserver_pid
os.kill(pid, signum)
- time.sleep(1.0) # give it time to die
+ # give time to the fork server to die and time to proc to complete
+ time.sleep(delay * 2.0)
evt2 = self.Event()
proc2 = self.Process(target=self._sleep_and_set_event, args=(evt2,))
start = time.time()
self.assertRaises(pyqueue.Empty, q.get, True, 0.200)
delta = time.time() - start
- # Tolerate a delta of 30 ms because of the bad clock resolution on
- # Windows (usually 15.6 ms)
- self.assertGreaterEqual(delta, 0.170)
+ # bpo-30317: Tolerate a delta of 100 ms because of the bad clock
+ # resolution on Windows (usually 15.6 ms). x86 Windows7 3.x once
+ # failed because the delta was only 135.8 ms.
+ self.assertGreaterEqual(delta, 0.100)
close_queue(q)
def test_queue_feeder_donot_stop_onexc(self):
p = self.Process(target=self._test_wait_result, args=(c, pid))
p.start()
- self.assertTrue(c.wait(10))
+ self.assertTrue(c.wait(60))
if pid is not None:
- self.assertRaises(KeyboardInterrupt, c.wait, 10)
+ self.assertRaises(KeyboardInterrupt, c.wait, 60)
p.join()
a.append('hello')
self.assertEqual(f[0][:], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'hello'])
+ def test_list_iter(self):
+ a = self.list(list(range(10)))
+ it = iter(a)
+ self.assertEqual(list(it), list(range(10)))
+ self.assertEqual(list(it), []) # exhausted
+ # list modified during iteration
+ it = iter(a)
+ a[0] = 100
+ self.assertEqual(next(it), 100)
+
def test_list_proxy_in_list(self):
a = self.list([self.list(range(3)) for _i in range(3)])
self.assertEqual([inner[:] for inner in a], [[0, 1, 2]] * 3)
self.assertEqual(sorted(d.values()), [chr(i) for i in indices])
self.assertEqual(sorted(d.items()), [(i, chr(i)) for i in indices])
+ def test_dict_iter(self):
+ d = self.dict()
+ indices = list(range(65, 70))
+ for i in indices:
+ d[i] = chr(i)
+ it = iter(d)
+ self.assertEqual(list(it), indices)
+ self.assertEqual(list(it), []) # exhausted
+ # dictionary changed size during iteration
+ it = iter(d)
+ d.clear()
+ self.assertRaises(RuntimeError, next, it)
+
def test_dict_proxy_nested(self):
pets = self.dict(ferrets=2, hamsters=4)
supplies = self.dict(water=10, feed=3)
self.assertRaises(SayWhenError, it.__next__)
def test_imap_unordered(self):
- it = self.pool.imap_unordered(sqr, list(range(1000)))
- self.assertEqual(sorted(it), list(map(sqr, list(range(1000)))))
+ it = self.pool.imap_unordered(sqr, list(range(10)))
+ self.assertEqual(sorted(it), list(map(sqr, list(range(10)))))
- it = self.pool.imap_unordered(sqr, list(range(1000)), chunksize=53)
+ it = self.pool.imap_unordered(sqr, list(range(1000)), chunksize=100)
self.assertEqual(sorted(it), list(map(sqr, list(range(1000)))))
def test_imap_unordered_handle_iterable_exception(self):
# they were released too.
self.assertEqual(CountedObject.n_instances, 0)
+ def test_del_pool(self):
+ p = self.Pool(1)
+ wr = weakref.ref(p)
+ del p
+ gc.collect()
+ self.assertIsNone(wr())
def raising():
raise KeyError("key")
def test_mymanager_context(self):
with MyManager() as manager:
self.common(manager)
- self.assertEqual(manager._process.exitcode, 0)
+ # bpo-30356: BaseManager._finalize_manager() sends SIGTERM
+ # to the manager process if it takes longer than 1 second to stop.
+ self.assertIn(manager._process.exitcode, (0, -signal.SIGTERM))
def test_mymanager_context_prestarted(self):
manager = MyManager()
-----BEGIN PRIVATE KEY-----
-MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAOoy7/QOtTjQ0niE
-6uDcTwtkC0R2Tvy1AjVnXohCntZfdzbTGDoYTgXSOLsP8A697jUiJ8VCePGH50xG
-Z4DKnAF3a9O3a9nr2pLXb0iY3XOMv+YEBii7CfI+3oxFYgCl0sMgHzDD2ZTVYAsm
-DWgLUVsE2gHEccRwrM2tPf2EgR+FAgMBAAECgYEA3qyfyYVSeTrTYxO93x6ZaVMu
-A2IZp9zSxMQL9bKiI2GRj+cV2ebSCGbg2btFnD6qBor7FWsmYz+8g6FNN/9sY4az
-61rMqMtQvLBe+7L8w70FeTze4qQ4Y1oQri0qD6tBWhDVlpnbI5Py9bkZKD67yVUk
-elcEA/5x4PrYXkuqsAECQQD80NjT0mDvaY0JOOaQFSEpMv6QiUA8GGX8Xli7IoKb
-tAolPG8rQBa+qSpcWfDMTrWw/aWHuMEEQoP/bVDH9W4FAkEA7SYQbBAKnojZ5A3G
-kOHdV7aeivRQxQk/JN8Fb8oKB9Csvpv/BsuGxPKXHdhFa6CBTTsNRtHQw/szPo4l
-xMIjgQJAPoMxqibR+0EBM6+TKzteSL6oPXsCnBl4Vk/J5vPgkbmR7KUl4+7j8N8J
-b2554TrxKEN/w7CGYZRE6UrRd7ATNQJAWD7Yz41sli+wfPdPU2xo1BHljyl4wMk/
-EPZYbI/PCbdyAH/F935WyQTIjNeEhZc1Zkq6FwdOWw8ns3hrv3rKgQJAHXv1BqUa
-czGPIFxX2TNoqtcl6/En4vrxVB1wzsfzkkDAg98kBl7qsF+S3qujSzKikjeaVbI2
-/CyWR2P3yLtOmA==
+MIIG/QIBADANBgkqhkiG9w0BAQEFAASCBucwggbjAgEAAoIBgQCg/pM6dP7BTFNc
+qe6wIJIBB7HjwL42bp0vjcCVl4Z3MRWFswYpfxy+o+8+PguMp4K6zndA5fwNkK/H
+3HmtanncUfPqnV0usN0NHQGh/f9xRoNmB1q2L7kTuO99o0KLQgvonRT2snf8rq9n
+tPRzhHUGYhog7zzNxetYV309PHpPr19BcKepDtM5RMk2aBnoN5vtItorjXiDosFm
+6o5wQHrcupcVydszba6P75BEbc1XIWvq2Fv8muaw4pCe81QYINyLqgcPNO/nF3Os
+5EI4HKjCNRSCOhOcWqYctXLXN9lBdMBBvQc3zDmYzh1eIZewzZXPVEQT33xPkhxz
+HNmhcIctpWX4LTRF6FulkcbeuZDga3gkZYJf/M6IpU1WYXr6q8sNxbgmRRX/NuHo
+V9oDwBzLG07rKUiqRHfjGqoCRmmVeVYpryvXUNjHGH0nlVzz/8lTUxAnJorO3Fdc
+I+6zKLUPICdAlvz51AH6yopgPFhrdgA0pVzPO6L5G8SRQCxKhAUCAwEAAQKCAYAa
+2jtOTcNMFGH3G7TfFZ+kolbuaPCQ/aQkEV2k1dAswzgWw8RsWXI+7fLyi8C7Zhks
+9VD4tyNyU8at7D0zSoYm1Fh9sl+fcQp9rG/gSBA6IYu7EdD0gEM7YeY4K2nm9k4s
+Lz8W4q+WqsBA6PK47cfjF6vKAH1AyRk28+jEtPiln9egf5zHWtyqOanh9D0V+Wh9
+hgmjqAYI1rWxZ7/4Qxj7Bfg7Px7blhi+kzOZ5kKQnNd2JT46hM+jgzah/G3zVE+R
+FFW6ksmJgZ+dCuSbE7HEJmKms1CWq/1Cll0A3uy4JTDZOrK4KcZQ9UjjWJWvlXQm
+uNXSSAp1k287DLVUm9c22SDeXpb9PyKmzyvJvVmMqqBx6QzHZ/L7WPzpUWAoLcU+
+ZHT7vggDymkIO+fcRbUzv8s5R7RnLbcBga51/5OCUvAWDoJXNw0qwYZOIbfTnQgs
+8xbCmbMzllyYM/dK3GxQAwfn8Hzk+DbS/NObMjHLCWLfYeUvutXJSNly6Ny+ZcEC
+gcEAzo5Y1UFOfBX4MZLIZ69LfgaXj9URobMwqlEwKil8pWQMa951ga3moLt91nOe
+SAQz3meFTBX/VAb2ZHLeIf3FoNkiIx48PkxsR/hhLHpvl26zEg3yXs3tv0IFBx2R
+EEnLNpQaAQFR9S1yDOaG2rsb17ZDKyp9isDpAENHAmEnT/XJn+Dc0SOH1EVDjUeM
+JqToAF/fjIx/RF4oUJCAgOPBMlRy5ywLQk8uDi6ft0NCzzCi0eCuk1Ty3KzWFGwx
+7cYRAoHBAMeIPCzHG3No4JGUFunslVwo5TuC7maO6qYKbq0OyvwWfL4b7gjrMBR9
+d5WyZlp/Vf40O463dg8x8qPNOFWp49f3hxTvvfnt2/m3+CQuDOLfqBbHufZApP1J
+U9MubUNnDFHHeJ9l0tg2nhiLw24GHeMARZhA/BimMQPY0OpZPpLVxAUArM2EB7hI
+glQpYCtdXhqwl1pl0u3TZ08y3BXYNg9BycdpGRMWSsAwsApJRgNuI/dfDKu0uMYF
+/pUhXVPatQKBwGgLpAun3dT7bA3sli5ESo6s22OEPGFrVbQ1OUHDrBnTj742TJKJ
++oY0a2q+ypgUJdx94NM2sWquJybqBaKxpf8j4OI3tLjc3h5SqwAwnE13YZRSmifP
+K1cP9mBjMFM4GLjhWUfwVkxeG/kLlhpP7fJ2yNbRjHN8QOH1AavdLGRGts1mA1UF
+xMHUMfbUd3Bv2L13ja/KhcD2fPA4GcLS9tpXV5nCwdkg8V4LdkBmDR04rotx1f44
+6Czokt2usmfHQQKBwFkufxbUd2SB/72Rnxw27hse/DY5My0Lu70y9HzNG9TIiEDA
+YwgBdp/x5D04W58fQuQ3nFcRkOcBwB2OYBuJr5ibvfiRnyvSMHvQykwBeSj+Jjbo
+VinGgvfiimDdY2C48jyrFzLHZBHXd5oo/dRzT3Bicri2cvbhcQ7zHY1hDiK7AL3r
+q1DALmMjpXzQcXdwZ9suCrgQwtIhpw8zAEOTO7ZeBT3nr5lkYUy9djFixrRJyjGK
+fjNQtzVrAHrPStNr8QKBwQDCC0zhsCnTv4sAJmW7LL6Ayd5rbWhUZ6px1xY0yHMA
+hehj+xbaiC6cfVr5Rg0ncvaa8AExu4kXpVsupTyNwvC4NgzLHtfBw6WUdOnd1awE
+kSrDtDReBt2wByAcQwttQsrJ1/Pt6zcNJJI4Z9s8G4NTcQWJwUhU20N55JQKR//l
+OQJqhq9NVhte/ctDjVwOHs/OhDNvxsAWxdjnf/O2up0os+M2bFkmHuaVW0vQbqTQ
+mw7Vbzk2Ff5oT6E3kbC8Ur4=
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
-MIIDcjCCAtugAwIBAgIJAN5dc9TOWjB7MA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV
+MIIHMDCCBZigAwIBAgIJALVVA6v9zJS5MA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV
BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
-IFNvZnR3YXJlIEZvdW5kYXRpb24xEDAOBgNVBAMMB2FsbHNhbnMwHhcNMTYwODA1
-MTAyMTExWhcNMjYwODAzMTAyMTExWjBdMQswCQYDVQQGEwJYWTEXMBUGA1UEBwwO
+IFNvZnR3YXJlIEZvdW5kYXRpb24xEDAOBgNVBAMMB2FsbHNhbnMwHhcNMTgwODI5
+MTQyMzE3WhcNMjgwODI2MTQyMzE3WjBdMQswCQYDVQQGEwJYWTEXMBUGA1UEBwwO
Q2FzdGxlIEFudGhyYXgxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0
-aW9uMRAwDgYDVQQDDAdhbGxzYW5zMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
-gQDqMu/0DrU40NJ4hOrg3E8LZAtEdk78tQI1Z16IQp7WX3c20xg6GE4F0ji7D/AO
-ve41IifFQnjxh+dMRmeAypwBd2vTt2vZ69qS129ImN1zjL/mBAYouwnyPt6MRWIA
-pdLDIB8ww9mU1WALJg1oC1FbBNoBxHHEcKzNrT39hIEfhQIDAQABo4IBODCCATQw
-ggEwBgNVHREEggEnMIIBI4IHYWxsc2Fuc6AeBgMqAwSgFwwVc29tZSBvdGhlciBp
-ZGVudGlmaWVyoDUGBisGAQUCAqArMCmgEBsOS0VSQkVST1MuUkVBTE2hFTAToAMC
-AQGhDDAKGwh1c2VybmFtZYEQdXNlckBleGFtcGxlLm9yZ4IPd3d3LmV4YW1wbGUu
-b3JnpGcwZTELMAkGA1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMw
-IQYDVQQKDBpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjEYMBYGA1UEAwwPZGly
-bmFtZSBleGFtcGxlhhdodHRwczovL3d3dy5weXRob24ub3JnL4cEfwAAAYcQAAAA
-AAAAAAAAAAAAAAAAAYgEKgMEBTANBgkqhkiG9w0BAQsFAAOBgQAy16h+F+nOmeiT
-VWR0fc8F/j6FcadbLseAUaogcC15OGxCl4UYpLV88HBkABOoGCpP155qwWTwOrdG
-iYPGJSusf1OnJEbvzFejZf6u078bPd9/ZL4VWLjv+FPGkjd+N+/OaqMvgj8Lu99f
-3Y/C4S7YbHxxwff6C6l2Xli+q6gnuQ==
+aW9uMRAwDgYDVQQDDAdhbGxzYW5zMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIB
+igKCAYEAoP6TOnT+wUxTXKnusCCSAQex48C+Nm6dL43AlZeGdzEVhbMGKX8cvqPv
+Pj4LjKeCus53QOX8DZCvx9x5rWp53FHz6p1dLrDdDR0Bof3/cUaDZgdati+5E7jv
+faNCi0IL6J0U9rJ3/K6vZ7T0c4R1BmIaIO88zcXrWFd9PTx6T69fQXCnqQ7TOUTJ
+NmgZ6Deb7SLaK414g6LBZuqOcEB63LqXFcnbM22uj++QRG3NVyFr6thb/JrmsOKQ
+nvNUGCDci6oHDzTv5xdzrORCOByowjUUgjoTnFqmHLVy1zfZQXTAQb0HN8w5mM4d
+XiGXsM2Vz1REE998T5IccxzZoXCHLaVl+C00RehbpZHG3rmQ4Gt4JGWCX/zOiKVN
+VmF6+qvLDcW4JkUV/zbh6FfaA8AcyxtO6ylIqkR34xqqAkZplXlWKa8r11DYxxh9
+J5Vc8//JU1MQJyaKztxXXCPusyi1DyAnQJb8+dQB+sqKYDxYa3YANKVczzui+RvE
+kUAsSoQFAgMBAAGjggLxMIIC7TCCATAGA1UdEQSCAScwggEjggdhbGxzYW5zoB4G
+AyoDBKAXDBVzb21lIG90aGVyIGlkZW50aWZpZXKgNQYGKwYBBQICoCswKaAQGw5L
+RVJCRVJPUy5SRUFMTaEVMBOgAwIBAaEMMAobCHVzZXJuYW1lgRB1c2VyQGV4YW1w
+bGUub3Jngg93d3cuZXhhbXBsZS5vcmekZzBlMQswCQYDVQQGEwJYWTEXMBUGA1UE
+BwwOQ2FzdGxlIEFudGhyYXgxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3Vu
+ZGF0aW9uMRgwFgYDVQQDDA9kaXJuYW1lIGV4YW1wbGWGF2h0dHBzOi8vd3d3LnB5
+dGhvbi5vcmcvhwR/AAABhxAAAAAAAAAAAAAAAAAAAAABiAQqAwQFMA4GA1UdDwEB
+/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/
+BAIwADAdBgNVHQ4EFgQUoLHAHNTWrHkSCUYkhn5NH0S40CAwgY8GA1UdIwSBhzCB
+hIAUoLHAHNTWrHkSCUYkhn5NH0S40CChYaRfMF0xCzAJBgNVBAYTAlhZMRcwFQYD
+VQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZv
+dW5kYXRpb24xEDAOBgNVBAMMB2FsbHNhbnOCCQC1VQOr/cyUuTCBgwYIKwYBBQUH
+AQEEdzB1MDwGCCsGAQUFBzAChjBodHRwOi8vdGVzdGNhLnB5dGhvbnRlc3QubmV0
+L3Rlc3RjYS9weWNhY2VydC5jZXIwNQYIKwYBBQUHMAGGKWh0dHA6Ly90ZXN0Y2Eu
+cHl0aG9udGVzdC5uZXQvdGVzdGNhL29jc3AvMEMGA1UdHwQ8MDowOKA2oDSGMmh0
+dHA6Ly90ZXN0Y2EucHl0aG9udGVzdC5uZXQvdGVzdGNhL3Jldm9jYXRpb24uY3Js
+MA0GCSqGSIb3DQEBCwUAA4IBgQAeKJKycO2DES98gyR2e/GzPYEw87cCS0cEpiiP
+3CEUgzfEbF0X89GDKEey4H3Irvosbvt2hEcf2RNpahLUL/fUv53bDmHNmL8qJg5E
+UJVMOHvOpSOjqoqeRuSyG0GnnAuUwcxdrZY6UzLdslhuq9F8UjgHr6KSMx56G9uK
+LmTy5njMab0in2xL/YRX/0nogK3BHqpUHrfCdEYZkciRxtAa+OPpWn4dcZi+Fpf7
+ZYSgPLNt+djtFDMIAk5Bo+XDaQdW3dhF0w44enrGAOV0xPE+/jOuenNhKBafjuNb
+lkeSr45+QZsi1rd18ny8z3uuaGqIAziFgmllZOH2D8giTn6+5jZcCNZCoGKUkPI9
+l/GMWwxg4HQYYlZcsZzTCem9Rb2XcrasAbmhFapMtR+QAwSed5vKE7ZdtQhj74kB
+7Q0E7Lkgpp6BaObb2As8/f0K/UlSVSvrYk+i3JT9wK/qqkRGxsTFEF7N9t0rKu8y
+4JdQDtZCI552MsFvYW6m+IOYgxg=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDbTCCAlWgAwIBAgIJALCSZLHy2iHQMA0GCSqGSIb3DQEBBQUAME0xCzAJBgNV
+MIIEbTCCAtWgAwIBAgIJAMstgJlaaVJbMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV
BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW
-MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xMzAxMDQxOTQ3MDdaFw0yMzAxMDIx
-OTQ3MDdaME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUg
-Rm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNhLXNlcnZlcjCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBAOfe6eMMnwC2of0rW5bSb8zgvoa5IF7sA3pV
-q+qk6flJhdJm1e3HeupWji2P50LiYiipn9Ybjuu1tJyfFKvf5pSLdh0+bSRh7Qy/
-AIphDN9cyDZzFgDNR7ptpKR0iIMjChn8Cac8SkvT5x0t5OpMVCHzJtuJNxjUArtA
-Ml+k/y0c99S77I7PXIKs5nwIbEiFYQd/JeBc4Lw0X+C5BEd1yEcLjbzWyGhfM4Ni
-0iBENbGtgRqKzbw1sFyLR9YY6ZwYl8wBPCnM6B7k5MG43ufCERiHWpM02KYl9xRx
-6+QhotIPLi7UYgA109bvXGBLTKkU4t0VWEY3Mya35y5d7ULkxU0CAwEAAaNQME4w
-HQYDVR0OBBYEFLzdYtl22hvSVGvP4GabHh57VgwLMB8GA1UdIwQYMBaAFLzdYtl2
-2hvSVGvP4GabHh57VgwLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB
-AH0K9cuN0129mY74Kw+668LZpidPLnsvDmTYHDVQTu78kLmNbajFxgawr/Mtvzu4
-QgfdGH1tlVRXhRhgRy/reBv56Bf9Wg2HFyisTGrmvCn09FVwKULeheqrbCMGZDB1
-Ao5TvF4BMzfMHs24pP3K5F9lO4MchvFVAqA6j9uRt0AUtOeN0u5zuuPlNC28lG9O
-JAb3X4sOp45r3l519DKaULFEM5rQBeJ4gv/b2opj66nd0b+gYa3jnookXWIO50yR
-f+/fNDY7L131hLIvxG2TlhpvMCjx2hKaZLRAMx293itTqOq+1rxOlvVE+zIYrtUf
-9mmvtk57HVjsO6lTo15YyJ4=
+MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xODA4MjkxNDIzMTZaFw0yODA4MjYx
+NDIzMTZaME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUg
+Rm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNhLXNlcnZlcjCCAaIwDQYJKoZI
+hvcNAQEBBQADggGPADCCAYoCggGBAJftVUG6NheV23Ec0+FhrFhz48aWzysfuAj1
+nUtLxzD2uAuzUnKgu8lNO47fIo4BV4HJknPMAMbscLA6F0DB3/KMNkzEp4HntiRo
+4qB+NQcvoFv5RUb3HvBGEf7KGjxQ8SapX5winPhB4d9PEpUZL1yQARdufj59z+kJ
+ryX4+EJ3LW1fNvJ4Hn1Kh2hjbAZxG436Jf7U0/WlF7Hv6hfLVMgnmYDLPEXxLFIc
+3R9RRSBQHl6rV3MbQXiW3oSket2PMIU2WHl2oNJhyBuplJljxu74FL+0UlYxl/rr
+rFOelc5MxFpKt8oDJ1s1V84C3OzKafiKWjnLFiAVAyRhbPR6/LZI5VkQXEnQI5/7
+cV466WifNHKAJ7Y/TLHZ22N/Z2hKbhH46MD0WhY5Uwto3nf6Ref4kc14zSiUl3FU
++8/wN97JJsXcG56JbQmsyERxy23xlzHVTCAzv3VKoODcaRHtKrRkEBEwiw6wpxDY
+isWqG8gmiiXnZp+lahovfF+DxnhPHwIDAQABo1AwTjAdBgNVHQ4EFgQU3b/K2ubR
+NLo3dSHKb5oIKPI1tkgwHwYDVR0jBBgwFoAU3b/K2ubRNLo3dSHKb5oIKPI1tkgw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAYEAM2pU02vA1wFfnfQFwZNm
+kFDQtxjpsB5KoLbadpOvhNutFVQxFRPk3n5ODNUJHDQ1tuVM1m9lfTJf6/ypawf3
+SYLlgX4HgJpj+CzDQLyP1CraPtHuCLdNp4TK9D+hmEW+sQVp59/Xmasb7oswzPf8
+59QLF66Xv+R7/Q+ntIV541niFoe/HylFLCOTdr7Ahx3e7CtCauW7yPQKSggKjFzY
+fU3RuL/V9yntktGUBOg1Bld/LCOXh6U1jSbTGkfyFtfZxtQfI0PTJpk5yiD0cSNv
+DEp2dvd2H7P+v0ew/CpWgeHS3e4I2PT/WtwlYYqRArmGHPJQc3YlNfy2JSYVy+vE
+K2EMHOfuLxeb7PDUoYTn0q/e5BskFKcBh+OrKVhGoNnACuCN11nTG/hUID54paXI
+T4sDxJaf7PtHz3YtjWU0J7/6rgEFivOSCt2JbJehx+dgUees60t9LLhlyf5dakhV
+juTH+WpA4bhkRem1WSmlX899WH1keeWkCawedmU9lMRo
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDbTCCAlWgAwIBAgIJALCSZLHy2iHQMA0GCSqGSIb3DQEBBQUAME0xCzAJBgNV
+MIIEbTCCAtWgAwIBAgIJAMstgJlaaVJbMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV
BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW
-MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xMzAxMDQxOTQ3MDdaFw0yMzAxMDIx
-OTQ3MDdaME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUg
-Rm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNhLXNlcnZlcjCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBAOfe6eMMnwC2of0rW5bSb8zgvoa5IF7sA3pV
-q+qk6flJhdJm1e3HeupWji2P50LiYiipn9Ybjuu1tJyfFKvf5pSLdh0+bSRh7Qy/
-AIphDN9cyDZzFgDNR7ptpKR0iIMjChn8Cac8SkvT5x0t5OpMVCHzJtuJNxjUArtA
-Ml+k/y0c99S77I7PXIKs5nwIbEiFYQd/JeBc4Lw0X+C5BEd1yEcLjbzWyGhfM4Ni
-0iBENbGtgRqKzbw1sFyLR9YY6ZwYl8wBPCnM6B7k5MG43ufCERiHWpM02KYl9xRx
-6+QhotIPLi7UYgA109bvXGBLTKkU4t0VWEY3Mya35y5d7ULkxU0CAwEAAaNQME4w
-HQYDVR0OBBYEFLzdYtl22hvSVGvP4GabHh57VgwLMB8GA1UdIwQYMBaAFLzdYtl2
-2hvSVGvP4GabHh57VgwLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB
-AH0K9cuN0129mY74Kw+668LZpidPLnsvDmTYHDVQTu78kLmNbajFxgawr/Mtvzu4
-QgfdGH1tlVRXhRhgRy/reBv56Bf9Wg2HFyisTGrmvCn09FVwKULeheqrbCMGZDB1
-Ao5TvF4BMzfMHs24pP3K5F9lO4MchvFVAqA6j9uRt0AUtOeN0u5zuuPlNC28lG9O
-JAb3X4sOp45r3l519DKaULFEM5rQBeJ4gv/b2opj66nd0b+gYa3jnookXWIO50yR
-f+/fNDY7L131hLIvxG2TlhpvMCjx2hKaZLRAMx293itTqOq+1rxOlvVE+zIYrtUf
-9mmvtk57HVjsO6lTo15YyJ4=
+MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xODA4MjkxNDIzMTZaFw0yODA4MjYx
+NDIzMTZaME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUg
+Rm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNhLXNlcnZlcjCCAaIwDQYJKoZI
+hvcNAQEBBQADggGPADCCAYoCggGBAJftVUG6NheV23Ec0+FhrFhz48aWzysfuAj1
+nUtLxzD2uAuzUnKgu8lNO47fIo4BV4HJknPMAMbscLA6F0DB3/KMNkzEp4HntiRo
+4qB+NQcvoFv5RUb3HvBGEf7KGjxQ8SapX5winPhB4d9PEpUZL1yQARdufj59z+kJ
+ryX4+EJ3LW1fNvJ4Hn1Kh2hjbAZxG436Jf7U0/WlF7Hv6hfLVMgnmYDLPEXxLFIc
+3R9RRSBQHl6rV3MbQXiW3oSket2PMIU2WHl2oNJhyBuplJljxu74FL+0UlYxl/rr
+rFOelc5MxFpKt8oDJ1s1V84C3OzKafiKWjnLFiAVAyRhbPR6/LZI5VkQXEnQI5/7
+cV466WifNHKAJ7Y/TLHZ22N/Z2hKbhH46MD0WhY5Uwto3nf6Ref4kc14zSiUl3FU
++8/wN97JJsXcG56JbQmsyERxy23xlzHVTCAzv3VKoODcaRHtKrRkEBEwiw6wpxDY
+isWqG8gmiiXnZp+lahovfF+DxnhPHwIDAQABo1AwTjAdBgNVHQ4EFgQU3b/K2ubR
+NLo3dSHKb5oIKPI1tkgwHwYDVR0jBBgwFoAU3b/K2ubRNLo3dSHKb5oIKPI1tkgw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAYEAM2pU02vA1wFfnfQFwZNm
+kFDQtxjpsB5KoLbadpOvhNutFVQxFRPk3n5ODNUJHDQ1tuVM1m9lfTJf6/ypawf3
+SYLlgX4HgJpj+CzDQLyP1CraPtHuCLdNp4TK9D+hmEW+sQVp59/Xmasb7oswzPf8
+59QLF66Xv+R7/Q+ntIV541niFoe/HylFLCOTdr7Ahx3e7CtCauW7yPQKSggKjFzY
+fU3RuL/V9yntktGUBOg1Bld/LCOXh6U1jSbTGkfyFtfZxtQfI0PTJpk5yiD0cSNv
+DEp2dvd2H7P+v0ew/CpWgeHS3e4I2PT/WtwlYYqRArmGHPJQc3YlNfy2JSYVy+vE
+K2EMHOfuLxeb7PDUoYTn0q/e5BskFKcBh+OrKVhGoNnACuCN11nTG/hUID54paXI
+T4sDxJaf7PtHz3YtjWU0J7/6rgEFivOSCt2JbJehx+dgUees60t9LLhlyf5dakhV
+juTH+WpA4bhkRem1WSmlX899WH1keeWkCawedmU9lMRo
-----END CERTIFICATE-----
if not name.startswith('__') and not name.endswith('__'))
allowed = set(['MAXYEAR', 'MINYEAR', 'date', 'datetime',
'datetime_CAPI', 'time', 'timedelta', 'timezone',
- 'tzinfo'])
+ 'tzinfo', 'sys'])
self.assertEqual(names - allowed, set([]))
def test_divide_and_round(self):
self.assertEqual(t0.fold, 0)
self.assertEqual(t1.fold, 1)
+ def test_fromtimestamp_low_fold_detection(self):
+ # Ensure that fold detection doesn't cause an
+ # OSError for really low values, see bpo-29097
+ self.assertEqual(datetime.fromtimestamp(0).fold, 0)
@support.run_with_tz('EST+05EDT,M3.2.0,M11.1.0')
def test_timestamp(self):
+++ /dev/null
------BEGIN DH PARAMETERS-----
-MIGHAoGBAIbzw1s9CT8SV5yv6L7esdAdZYZjPi3qWFs61CYTFFQnf2s/d09NYaJt
-rrvJhIzWavqnue71qXCf83/J3nz3FEwUU/L0mGyheVbsSHiI64wUo3u50wK5Igo0
-RNs/LD0irs7m0icZ//hijafTU+JOBiuA8zMI+oZfU7BGuc9XrUprAgEC
------END DH PARAMETERS-----
-
-Generated with: openssl dhparam -out dh1024.pem 1024
# Issue #25277: Use faulthandler to try to debug a hang on FreeBSD
if hasattr(faulthandler, 'dump_traceback_later'):
- faulthandler.dump_traceback_later(10 * 60, exit=True)
+ faulthandler.dump_traceback_later(10 * 60, exit=True,
+ file=sys.__stderr__)
@classmethod
def stop_alarm(cls):
--- /dev/null
+ DH Parameters: (3072 bit)
+ prime:
+ 00:ff:ff:ff:ff:ff:ff:ff:ff:ad:f8:54:58:a2:bb:
+ 4a:9a:af:dc:56:20:27:3d:3c:f1:d8:b9:c5:83:ce:
+ 2d:36:95:a9:e1:36:41:14:64:33:fb:cc:93:9d:ce:
+ 24:9b:3e:f9:7d:2f:e3:63:63:0c:75:d8:f6:81:b2:
+ 02:ae:c4:61:7a:d3:df:1e:d5:d5:fd:65:61:24:33:
+ f5:1f:5f:06:6e:d0:85:63:65:55:3d:ed:1a:f3:b5:
+ 57:13:5e:7f:57:c9:35:98:4f:0c:70:e0:e6:8b:77:
+ e2:a6:89:da:f3:ef:e8:72:1d:f1:58:a1:36:ad:e7:
+ 35:30:ac:ca:4f:48:3a:79:7a:bc:0a:b1:82:b3:24:
+ fb:61:d1:08:a9:4b:b2:c8:e3:fb:b9:6a:da:b7:60:
+ d7:f4:68:1d:4f:42:a3:de:39:4d:f4:ae:56:ed:e7:
+ 63:72:bb:19:0b:07:a7:c8:ee:0a:6d:70:9e:02:fc:
+ e1:cd:f7:e2:ec:c0:34:04:cd:28:34:2f:61:91:72:
+ fe:9c:e9:85:83:ff:8e:4f:12:32:ee:f2:81:83:c3:
+ fe:3b:1b:4c:6f:ad:73:3b:b5:fc:bc:2e:c2:20:05:
+ c5:8e:f1:83:7d:16:83:b2:c6:f3:4a:26:c1:b2:ef:
+ fa:88:6b:42:38:61:1f:cf:dc:de:35:5b:3b:65:19:
+ 03:5b:bc:34:f4:de:f9:9c:02:38:61:b4:6f:c9:d6:
+ e6:c9:07:7a:d9:1d:26:91:f7:f7:ee:59:8c:b0:fa:
+ c1:86:d9:1c:ae:fe:13:09:85:13:92:70:b4:13:0c:
+ 93:bc:43:79:44:f4:fd:44:52:e2:d7:4d:d3:64:f2:
+ e2:1e:71:f5:4b:ff:5c:ae:82:ab:9c:9d:f6:9e:e8:
+ 6d:2b:c5:22:36:3a:0d:ab:c5:21:97:9b:0d:ea:da:
+ 1d:bf:9a:42:d5:c4:48:4e:0a:bc:d0:6b:fa:53:dd:
+ ef:3c:1b:20:ee:3f:d5:9d:7c:25:e4:1d:2b:66:c6:
+ 2e:37:ff:ff:ff:ff:ff:ff:ff:ff
+ generator: 2 (0x2)
+ recommended-private-length: 276 bits
+-----BEGIN DH PARAMETERS-----
+MIIBjAKCAYEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
++8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
+87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
+YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
+7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
+ssbzSibBsu/6iGtCOGEfz9zeNVs7ZRkDW7w09N75nAI4YbRvydbmyQd62R0mkff3
+7lmMsPrBhtkcrv4TCYUTknC0EwyTvEN5RPT9RFLi103TZPLiHnH1S/9croKrnJ32
+nuhtK8UiNjoNq8Uhl5sN6todv5pC1cRITgq80Gv6U93vPBsg7j/VnXwl5B0rZsYu
+N///////////AgECAgIBFA==
+-----END DH PARAMETERS-----
async def lobbest(grenade):
pass
+
+currentframe = inspect.currentframe()
+try:
+ raise Exception()
+except:
+ tb = sys.exc_info()[2]
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
-DEK-Info: DES-EDE3-CBC,1A8D9D2A02EC698A
+DEK-Info: DES-EDE3-CBC,D134E931C96D9DEC
-kJYbfZ8L0sfe9Oty3gw0aloNnY5E8fegRfQLZlNoxTl6jNt0nIwI8kDJ36CZgR9c
-u3FDJm/KqrfUoz8vW+qEnWhSG7QPX2wWGPHd4K94Yz/FgrRzZ0DoK7XxXq9gOtVA
-AVGQhnz32p+6WhfGsCr9ArXEwRZrTk/FvzEPaU5fHcoSkrNVAGX8IpSVkSDwEDQr
-Gv17+cfk99UV1OCza6yKHoFkTtrC+PZU71LomBabivS2Oc4B9hYuSR2hF01wTHP+
-YlWNagZOOVtNz4oKK9x9eNQpmfQXQvPPTfusexKIbKfZrMvJoxcm1gfcZ0H/wK6P
-6wmXSG35qMOOztCZNtperjs1wzEBXznyK8QmLcAJBjkfarABJX9vBEzZV0OUKhy+
-noORFwHTllphbmydLhu6ehLUZMHPhzAS5UN7srtpSN81eerDMy0RMUAwA7/PofX1
-94Me85Q8jP0PC9ETdsJcPqLzAPETEYu0ELewKRcrdyWi+tlLFrpE5KT/s5ecbl9l
-7B61U4Kfd1PIXc/siINhU3A3bYK+845YyUArUOnKf1kEox7p1RpD7yFqVT04lRTo
-cibNKATBusXSuBrp2G6GNuhWEOSafWCKJQAzgCYIp6ZTV2khhMUGppc/2H3CF6cO
-zX0KtlPVZC7hLkB6HT8SxYUwF1zqWY7+/XPPdc37MeEZ87Q3UuZwqORLY+Z0hpgt
-L5JXBCoklZhCAaN2GqwFLXtGiRSRFGY7xXIhbDTlE65Wv1WGGgDLMKGE1gOz3yAo
-2jjG1+yAHJUdE69XTFHSqSkvaloA1W03LdMXZ9VuQJ/ySXCie6ABAQ==
+nuGFEej7vIjkYWSMz5OJeVTNntDRQi6ZM4DBm3g8T7i/0odr3WFqGMMKZcIhLYQf
+rgRq7RSKtrJ1y5taVucMV+EuCjyfzDo0TsYt+ZrXv/D08eZhjRmkhoHnGVF0TqQm
+nQEXM/ERT4J2RM78dnG+homMkI76qOqxgGbRqQqJo6AiVRcAZ45y8s96bru2TAB8
++pWjO/v0Je7AFVdwSU52N8OOY6uoSAygW+0UY1WVxbVGJF2XfRsNpPX+YQHYl6e+
+3xM5XBVCgr6kmdAyub5qUJ38X3TpdVGoR0i+CVS9GTr2pSRib1zURAeeHnlqiUZM
+4m0Gn9s72nJevU1wxED8pwOhR8fnHEmMKGD2HPhKoOCbzDhwwBZO27TNa1uWeM3f
+M5oixKDi2PqMn3y2cDx1NjJtP661688EcJ5a2Ih9BgO9xpnhSyzBWEKcAn0tJB0H
+/56M0FW6cdOOIzMveGGL7sHW5E+iOdI1n5e7C6KJUzew78Y9qJnhS53EdI6qTz9R
+wsIsj1i070Fk6RbPo6zpLlF6w7Zj8GlZaZA7OZZv9wo5VEV/0ST8gmiiBOBc4C6Y
+u9hyLIIu4dFEBKyQHRvBnQSLNpKx6or1OGFDVBay2In9Yh2BHh1+vOj/OIz/wq48
+EHOIV27fRJxLu4jeK5LIGDhuPnMJ8AJYQ0bQOUP6fd7p+TxWkAQZPB/Dx/cs3hxr
+nFEdzx+eO+IAsObx/b1EGZyEJyETBslu4GwYX7/KK3HsJhDJ1bdZ//28jOCaoir6
+ZOMT72GRwmVoQTJ0XpccfjHfKJDRLT7C1xvzo4Eibth0hpTZkA75IUYUp6qK/PuJ
+kH/qdiC7QIkRKtsrawW4vEDna3YtxIYhQqz9+KwO6u/0gzooZtv1RU4U3ifMDB5u
+5P5GAzACRqlY8QYBkM869lvWqzQPHvybC4ak9Yx6/heMO9ddjdIW9BaK8BLxvN/6
+UCD936Y4fWltt09jHZIoxWFykouBwmd7bXooNYXmDRNmjTdVhKJuOEOQw8hDzx7e
+pWFJ9Z/V4Qm1tvXbCD7QFqMCDoY3qFvVG8DBqXpmxe1yPfz21FWrT7IuqDXAD3ns
+vxfN/2a+Cy04U9FBNVCvWqWIs5AgNpdCMJC2FlXKTy+H3/7rIjNyFyvbX0vxIXtK
+liOVNXiyVM++KZXqktqMUDlsJENmIHV9B046luqbgW018fHkyEYlL3iRZGbYegwr
+XO9VVIKVPw1BEvJ8VNdGFGuZGepd8qX2ezfYADrNR+4t85HDm8inbjTobSjWuljs
+ftUNkOeCHqAvWCFQTLCfdykvV08EJfVY79y7yFPtfRV2gxYokXFifjo3su9sVQr1
+UiIS5ZAsIC1hBXWeXoBN7QVTkFi7Yto6E1q2k10LiT3obpUUUQ/oclhrJOCJVjrS
+oRcj2QBy8OT4T9slJr5maTWdgd7Lt6+I6cGQXPaDvjGOJl0eBYM14vhx4rRQWytJ
+k07hhHFO4+9CGCuHS8AAy2gR6acYFWt2ZiiNZ0z/iPIHNK4YEyy9aLf6uZH/KQjE
+jmHToo7XD6QvCAEC5qTHby3o3LfHIhyZi/4L+AhS4FKUHF6M0peeyYt4z3HaK2d2
+N6mHLPdjwNjra7GOmcns4gzcrdfoF+R293KpPal4PjknvR3dZL4kKP/ougTAM5zv
+qDIvRbkHzjP8ChTpoLcJsNVXykNcNkjcSi0GHtIpYjh6QX6P2uvR/S4+Bbb9p9rn
+hIy/ovu9tWN2hiPxGPe6torF6BulAxsTYlDercC204AyzsrdA0pr6HBgJH9C6ML1
+TchwodbFJqn9rSv91i1liusAGoOvE81AGBdrXY7LxfSNhYY1IK6yR/POJPTd53sA
+uX2/j6Rtoksd/2BHPM6AUnI/2B9slhuzWX2aCtWLeuwvXDS6rYuTigaQmLkzTRfM
+dlMI3s9KLXxgi5YVumUZleJWXwBNP7KiKajd+VTSD+7WAhyhM5FIG5wVOaxmy4G2
+TyqZ/Ax9d2VEjTQHWvQlLPQ4Mp0EIz0aEl94K/S8CK8bJRH6+PRkar+dJi1xqlL+
+BYb42At9mEJ8odLlFikvNi1+t7jqXk5jRi5C0xFKx3nTtzoH2zNUeuA3R6vSocVK
+45jnze9IkKmxMlJ4loR5sgszdpDCD3kXqjtCcbMTmcrGyzJek3HSOTpiEORoTFOe
+Rhg6jH5lm+QcC263oipojS0qEQcnsWJP2CylNYMYHR9O/9NQxT3o2lsRHqZTMELV
+uQa/SFH+paQNbZOj8MRwPSqqiIxJFuLswKte1R+W7LKn1yBSM7Pp39lNbzGvJD2E
+YRfnCwFpJ54voVAuQ4jXJvigCW2qeCjXlxeD6K2j4eGJEEOmIjIW1wjubyBY6OI3
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
-MIICVDCCAb2gAwIBAgIJANfHOBkZr8JOMA0GCSqGSIb3DQEBBQUAMF8xCzAJBgNV
-BAYTAlhZMRcwFQYDVQQHEw5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9u
-IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xMDEw
-MDgyMzAxNTZaFw0yMDEwMDUyMzAxNTZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH
-Ew5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9uIFNvZnR3YXJlIEZvdW5k
-YXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
-gYkCgYEA21vT5isq7F68amYuuNpSFlKDPrMUCa4YWYqZRt2OZ+/3NKaZ2xAiSwr7
-6MrQF70t5nLbSPpqE5+5VrS58SY+g/sXLiFd6AplH1wJZwh78DofbFYXUggktFMt
-pTyiX8jtP66bkcPkDADA089RI1TQR6Ca+n7HFa7c1fabVV6i3zkCAwEAAaMYMBYw
-FAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBBQUAA4GBAHPctQBEQ4wd
-BJ6+JcpIraopLn8BGhbjNWj40mmRqWB/NAWF6M5ne7KpGAu7tLeG4hb1zLaldK8G
-lxy2GPSRF6LFS48dpEj2HbMv2nvv6xxalDMJ9+DicWgAKTQ6bcX2j3GUkCR0g/T1
-CRlNBAAlvhKzO7Clpf9l0YKBEfraJByX
+MIIEWTCCAsGgAwIBAgIJAJinz4jHSjLtMA0GCSqGSIb3DQEBCwUAMF8xCzAJBgNV
+BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
+IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xODA4
+MjkxNDIzMTVaFw0yODA4MjYxNDIzMTVaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH
+DA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5k
+YXRpb24xEjAQBgNVBAMMCWxvY2FsaG9zdDCCAaIwDQYJKoZIhvcNAQEBBQADggGP
+ADCCAYoCggGBALKUqUtopT6E68kN+uJNEt34i2EbmG/bwjcD8IaMsgJPSsMO2Bpd
+3S6qWgkCeOyCfmAwBxK2kNbxGb63ouysEv7l8GCTJTWv3hG/HQcejJpnAEGi6K1U
+fDbyE/db6yZ12SoHVTGkadN4vYGCPd1Wj9ZO1F877SHQ8rDWX3xgTWkxN2ojBw44
+T8RHSDiG8D/CvG4uEy+VUszL+Uvny5y2poNSqvI3J56sptWSrh8nIIbkPZPBdUne
+LYMOHTFK3ZjXSmhlXgziTxK71nnzM3Y9K9gxPnRqoXbvu/wFo55hQCkETiRkYgmm
+jXcBMZ0TClQVnQWuLjMthRnWFZs4Lfmwqjs7FZD/61581R2BYehvpWbLvvuOJhwv
+DFzexL2sXcAl7SsxbzeQKRHqGbIDfbnQTXfs3/VC6Ye5P82P2ucj+XC32N9piRmO
+gCBP8L3ub+YzzdxikZN2gZXXE2jsb3QyE/R2LkWdWyshpKe+RsZP1SBRbHShUyOh
+yJ90baoiEwj2mwIDAQABoxgwFjAUBgNVHREEDTALgglsb2NhbGhvc3QwDQYJKoZI
+hvcNAQELBQADggGBAHRUO/UIHl3jXQENewYayHxkIx8t7nu40iO2DXbicSijz5bo
+5//xAB6RxhBAlsDBehgQP1uoZg+WJW+nHu3CIVOU3qZNZRaozxiCl2UFKcNqLOmx
+R3NKpo1jYf4REQIeG8Yw9+hSWLRbshNteP6bKUUf+vanhg9+axyOEOH/iOQvgk/m
+b8wA8wNa4ujWljPbTQnj7ry8RqhTM0GcAN5LSdSvcKcpzLcs3aYwh+Z8e30sQWna
+F40sa5u7izgBTOrwpcDm/w5kC46vpRQ5fnbshVw6pne2by0mdMECASid/p25N103
+jMqTFlmO7kpf/jpCSmamp3/JSEE1BJKHwQ6Ql4nzRA2N1mnvWH7Zxcv043gkHeAu
+0x8evpvwuhdIyproejNFlBpKmW8OX7yKTCPPMC/VkX8Q1rVkxU0DQ6hmvwZlhoKa
+9Wc2uXpw9xF8itV4Uvcdr3dwqByvIqn7iI/gB+4l41e0u8OmH2MKOx4Nxlly5TNW
+HcVKQHyOeyvnINuBAQ==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANtb0+YrKuxevGpm
-LrjaUhZSgz6zFAmuGFmKmUbdjmfv9zSmmdsQIksK++jK0Be9LeZy20j6ahOfuVa0
-ufEmPoP7Fy4hXegKZR9cCWcIe/A6H2xWF1IIJLRTLaU8ol/I7T+um5HD5AwAwNPP
-USNU0Eegmvp+xxWu3NX2m1Veot85AgMBAAECgYA3ZdZ673X0oexFlq7AAmrutkHt
-CL7LvwrpOiaBjhyTxTeSNWzvtQBkIU8DOI0bIazA4UreAFffwtvEuPmonDb3F+Iq
-SMAu42XcGyVZEl+gHlTPU9XRX7nTOXVt+MlRRRxL6t9GkGfUAXI3XxJDXW3c0vBK
-UL9xqD8cORXOfE06rQJBAP8mEX1ERkR64Ptsoe4281vjTlNfIbs7NMPkUnrn9N/Y
-BLhjNIfQ3HFZG8BTMLfX7kCS9D593DW5tV4Z9BP/c6cCQQDcFzCcVArNh2JSywOQ
-ZfTfRbJg/Z5Lt9Fkngv1meeGNPgIMLN8Sg679pAOOWmzdMO3V706rNPzSVMME7E5
-oPIfAkEA8pDddarP5tCvTTgUpmTFbakm0KoTZm2+FzHcnA4jRh+XNTjTOv98Y6Ik
-eO5d1ZnKXseWvkZncQgxfdnMqqpj5wJAcNq/RVne1DbYlwWchT2Si65MYmmJ8t+F
-0mcsULqjOnEMwf5e+ptq5LzwbyrHZYq5FNk7ocufPv/ZQrcSSC+cFwJBAKvOJByS
-x56qyGeZLOQlWS2JS3KJo59XuLFGqcbgN9Om9xFa41Yb4N9NvplFivsvZdw3m1Q/
-SPIXQuT8RMPDVNQ=
+MIIG/wIBADANBgkqhkiG9w0BAQEFAASCBukwggblAgEAAoIBgQCylKlLaKU+hOvJ
+DfriTRLd+IthG5hv28I3A/CGjLICT0rDDtgaXd0uqloJAnjsgn5gMAcStpDW8Rm+
+t6LsrBL+5fBgkyU1r94Rvx0HHoyaZwBBouitVHw28hP3W+smddkqB1UxpGnTeL2B
+gj3dVo/WTtRfO+0h0PKw1l98YE1pMTdqIwcOOE/ER0g4hvA/wrxuLhMvlVLMy/lL
+58uctqaDUqryNyeerKbVkq4fJyCG5D2TwXVJ3i2DDh0xSt2Y10poZV4M4k8Su9Z5
+8zN2PSvYMT50aqF277v8BaOeYUApBE4kZGIJpo13ATGdEwpUFZ0Fri4zLYUZ1hWb
+OC35sKo7OxWQ/+tefNUdgWHob6Vmy777jiYcLwxc3sS9rF3AJe0rMW83kCkR6hmy
+A3250E137N/1QumHuT/Nj9rnI/lwt9jfaYkZjoAgT/C97m/mM83cYpGTdoGV1xNo
+7G90MhP0di5FnVsrIaSnvkbGT9UgUWx0oVMjocifdG2qIhMI9psCAwEAAQKCAYBT
+sHmaPmNaZj59jZCqp0YVQlpHWwBYQ5vD3pPE6oCttm0p9nXt/VkfenQRTthOtmT1
+POzDp00/feP7zeGLmqSYUjgRekPw4gdnN7Ip2PY5kdW77NWwDSzdLxuOS8Rq1MW9
+/Yu+ZPe3RBlDbT8C0IM+Atlh/BqIQ3zIxN4g0pzUlF0M33d6AYfYSzOcUhibOO7H
+j84r+YXBNkIRgYKZYbutRXuZYaGuqejRpBj3voVu0d3Ntdb6lCWuClpB9HzfGN0c
+RTv8g6UYO4sK3qyFn90ibIR/1GB9watvtoWVZqggiWeBzSWVWRsGEf9O+Cx4oJw1
+IphglhmhbgNksbj7bD24on/icldSOiVkoUemUOFmHWhCm4PnB1GmbD8YMfEdSbks
+qDr1Ps1zg4mGOinVD/4cY7vuPFO/HCH07wfeaUGzRt4g0/yLr+XjVofOA3oowyxv
+JAzr+niHA3lg5ecj4r7M68efwzN1OCyjMrVJw2RAzwvGxE+rm5NiT08SWlKQZnkC
+gcEA4wvyLpIur/UB84nV3XVJ89UMNBLm++aTFzld047BLJtMaOhvNqx6Cl5c8VuW
+l261KHjiVzpfNM3/A2LBQJcYkhX7avkqEXlj57cl+dCWAVwUzKmLJTPjfaTTZnYJ
+xeN3dMYjJz2z2WtgvfvDoJLukVwIMmhTY8wtqqYyQBJ/l06pBsfw5TNvmVIOQHds
+8ASOiFt+WRLk2bl9xrGGayqt3VV93KVRzF27cpjOgEcG74F3c0ZW9snERN7vIYwB
+JfrlAoHBAMlahPwMP2TYylG8OzHe7EiehTekSO26LGh0Cq3wTGXYsK/q8hQCzL14
+kWW638vpwXL6L9ntvrd7hjzWRO3vX/VxnYEA6f0bpqHq1tZi6lzix5CTUN5McpDg
+QnjenSJNrNjS1zEF8WeY9iLEuDI/M/iUW4y9R6s3WpgQhPDXpSvd2g3gMGRUYhxQ
+Xna8auiJeYFq0oNaOxvJj+VeOfJ3ZMJttd+Y7gTOYZcbg3SdRb/kdxYki0RMD2hF
+4ZvjJ6CTfwKBwQDiMqiZFTJGQwYqp4vWEmAW+I4r4xkUpWatoI2Fk5eI5T9+1PLX
+uYXsho56NxEU1UrOg4Cb/p+TcBc8PErkGqR0BkpxDMOInTOXSrQe6lxIBoECVXc3
+HTbrmiay0a5y5GfCgxPKqIJhfcToAceoVjovv0y7S4yoxGZKuUEe7E8JY2iqRNAO
+yOvKCCICv/hcN235E44RF+2/rDlOltagNej5tY6rIFkaDdgOF4bD7f9O5eEni1Bg
+litfoesDtQP/3rECgcEAkQfvQ7D6tIPmbqsbJBfCr6fmoqZllT4FIJN84b50+OL0
+mTGsfjdqC4tdhx3sdu7/VPbaIqm5NmX10bowWgWSY7MbVME4yQPyqSwC5NbIonEC
+d6N0mzoLR0kQ+Ai4u+2g82gicgAq2oj1uSNi3WZi48jQjHYFulCbo246o1NgeFFK
+77WshYe2R1ioQfQDOU1URKCR0uTaMHClgfu112yiGd12JAD+aF3TM0kxDXz+sXI5
+SKy311DFxECZeXRLpcC3AoHBAJkNMJWTyPYbeVu+CTQkec8Uun233EkXa2kUNZc/
+5DuXDaK+A3DMgYRufTKSPpDHGaCZ1SYPInX1Uoe2dgVjWssRL2uitR4ENabDoAOA
+ICVYXYYNagqQu5wwirF0QeaMXo1fjhuuHQh8GsMdXZvYEaAITZ9/NG5x/oY08+8H
+kr78SMBOPy3XQn964uKG+e3JwpOG14GKABdAlrHKFXNWchu/6dgcYXB87mrC/GhO
+zNwzC+QhFTZoOomFoqMgFWujng==
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
-MIICVDCCAb2gAwIBAgIJANfHOBkZr8JOMA0GCSqGSIb3DQEBBQUAMF8xCzAJBgNV
-BAYTAlhZMRcwFQYDVQQHEw5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9u
-IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xMDEw
-MDgyMzAxNTZaFw0yMDEwMDUyMzAxNTZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH
-Ew5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9uIFNvZnR3YXJlIEZvdW5k
-YXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
-gYkCgYEA21vT5isq7F68amYuuNpSFlKDPrMUCa4YWYqZRt2OZ+/3NKaZ2xAiSwr7
-6MrQF70t5nLbSPpqE5+5VrS58SY+g/sXLiFd6AplH1wJZwh78DofbFYXUggktFMt
-pTyiX8jtP66bkcPkDADA089RI1TQR6Ca+n7HFa7c1fabVV6i3zkCAwEAAaMYMBYw
-FAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBBQUAA4GBAHPctQBEQ4wd
-BJ6+JcpIraopLn8BGhbjNWj40mmRqWB/NAWF6M5ne7KpGAu7tLeG4hb1zLaldK8G
-lxy2GPSRF6LFS48dpEj2HbMv2nvv6xxalDMJ9+DicWgAKTQ6bcX2j3GUkCR0g/T1
-CRlNBAAlvhKzO7Clpf9l0YKBEfraJByX
+MIIEWTCCAsGgAwIBAgIJAJinz4jHSjLtMA0GCSqGSIb3DQEBCwUAMF8xCzAJBgNV
+BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
+IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xODA4
+MjkxNDIzMTVaFw0yODA4MjYxNDIzMTVaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH
+DA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5k
+YXRpb24xEjAQBgNVBAMMCWxvY2FsaG9zdDCCAaIwDQYJKoZIhvcNAQEBBQADggGP
+ADCCAYoCggGBALKUqUtopT6E68kN+uJNEt34i2EbmG/bwjcD8IaMsgJPSsMO2Bpd
+3S6qWgkCeOyCfmAwBxK2kNbxGb63ouysEv7l8GCTJTWv3hG/HQcejJpnAEGi6K1U
+fDbyE/db6yZ12SoHVTGkadN4vYGCPd1Wj9ZO1F877SHQ8rDWX3xgTWkxN2ojBw44
+T8RHSDiG8D/CvG4uEy+VUszL+Uvny5y2poNSqvI3J56sptWSrh8nIIbkPZPBdUne
+LYMOHTFK3ZjXSmhlXgziTxK71nnzM3Y9K9gxPnRqoXbvu/wFo55hQCkETiRkYgmm
+jXcBMZ0TClQVnQWuLjMthRnWFZs4Lfmwqjs7FZD/61581R2BYehvpWbLvvuOJhwv
+DFzexL2sXcAl7SsxbzeQKRHqGbIDfbnQTXfs3/VC6Ye5P82P2ucj+XC32N9piRmO
+gCBP8L3ub+YzzdxikZN2gZXXE2jsb3QyE/R2LkWdWyshpKe+RsZP1SBRbHShUyOh
+yJ90baoiEwj2mwIDAQABoxgwFjAUBgNVHREEDTALgglsb2NhbGhvc3QwDQYJKoZI
+hvcNAQELBQADggGBAHRUO/UIHl3jXQENewYayHxkIx8t7nu40iO2DXbicSijz5bo
+5//xAB6RxhBAlsDBehgQP1uoZg+WJW+nHu3CIVOU3qZNZRaozxiCl2UFKcNqLOmx
+R3NKpo1jYf4REQIeG8Yw9+hSWLRbshNteP6bKUUf+vanhg9+axyOEOH/iOQvgk/m
+b8wA8wNa4ujWljPbTQnj7ry8RqhTM0GcAN5LSdSvcKcpzLcs3aYwh+Z8e30sQWna
+F40sa5u7izgBTOrwpcDm/w5kC46vpRQ5fnbshVw6pne2by0mdMECASid/p25N103
+jMqTFlmO7kpf/jpCSmamp3/JSEE1BJKHwQ6Ql4nzRA2N1mnvWH7Zxcv043gkHeAu
+0x8evpvwuhdIyproejNFlBpKmW8OX7yKTCPPMC/VkX8Q1rVkxU0DQ6hmvwZlhoKa
+9Wc2uXpw9xF8itV4Uvcdr3dwqByvIqn7iI/gB+4l41e0u8OmH2MKOx4Nxlly5TNW
+HcVKQHyOeyvnINuBAQ==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAJnsJZVrppL+W5I9
-zGQrrawWwE5QJpBK9nWw17mXrZ03R1cD9BamLGivVISbPlRlAVnZBEyh1ATpsB7d
-CUQ+WHEvALquvx4+Yw5l+fXeiYRjrLRBYZuVy8yNtXzU3iWcGObcYRkUdiXdOyP7
-sLF2YZHRvQZpzgDBKkrraeQ81w21AgMBAAECgYBEm7n07FMHWlE+0kT0sXNsLYfy
-YE+QKZnJw9WkaDN+zFEEPELkhZVt5BjsMraJr6v2fIEqF0gGGJPkbenffVq2B5dC
-lWUOxvJHufMK4sM3Cp6s/gOp3LP+QkzVnvJSfAyZU6l+4PGX5pLdUsXYjPxgzjzL
-S36tF7/2Uv1WePyLUQJBAMsPhYzUXOPRgmbhcJiqi9A9c3GO8kvSDYTCKt3VMnqz
-HBn6MQ4VQasCD1F+7jWTI0FU/3vdw8non/Fj8hhYqZcCQQDCDRdvmZqDiZnpMqDq
-L6ZSrLTVtMvZXZbgwForaAD9uHj51TME7+eYT7EG2YCgJTXJ4YvRJEnPNyskwdKt
-vTSTAkEAtaaN/vyemEJ82BIGStwONNw0ILsSr5cZ9tBHzqiA/tipY+e36HRFiXhP
-QcU9zXlxyWkDH8iz9DSAmE2jbfoqwwJANlMJ65E543cjIlitGcKLMnvtCCLcKpb7
-xSG0XJB6Lo11OKPJ66jp0gcFTSCY1Lx2CXVd+gfJrfwI1Pp562+bhwJBAJ9IfDPU
-R8OpO9v1SGd8x33Owm7uXOpB9d63/T70AD1QOXjKUC4eXYbt0WWfWuny/RNPRuyh
-w7DXSfUF+kPKolU=
+MIIG/QIBADANBgkqhkiG9w0BAQEFAASCBucwggbjAgEAAoIBgQDKjrjWZlfOs1Ch
+qt1RoyLfqyXbHVXIAW0fTzAxfJnxvFOiWqAAKgC2qVQM8Y080kRUuRaXP/w9ywXT
++MzX6tByy5VbTYJYyTjHOH46EWLNdcqEJs4+FCVqOIYrQPQ6pGAhCXmgBy4Vb42J
+ABLwb+Kt+y2Dk15tggVcAHP2Khri+lRXWvda+kZAe2F1IojmuWyCTy3FEYHic5qN
+BsXcf6u1oyFV8MybOuz1zGj3vd2C+dEKO4Ohw9rRwnvHSatjM+CfwiXf8kTXzDBF
+Z/8W3+6yA49pHxRbG7FE3K1TAPhkrp+BVTIUOcdI74wEA6UEkWFF5sQcmmAth59M
+EQrl2CXorftEPhsKZE59dUP1+nYAPvR/mTySNCSw7/rvdf+csRSZ5ollMu/lxsht
+ulJYJI03+IiDTn47FI5D+IF25REK7d4LzGIo6T73ktsT+qpSXHuTWC+IABm8AMF9
+7ljxHSwMRU/z+O5uiONRItDAgKH/OItFG54PtY2vAhaO0YiZrZcCAwEAAQKCAYB2
+hTo8IVghlySH5B1p5kXCkDcvVaPaypLaLhCp9Blzq9lX9yUF043lU4Ddrf0RaIsY
+88/3IjZqxb+cP0lE0Z20fdDfwqORZfQ2BaU+PuwMAm9EEhy9kDYwR/ChoHkHUyT4
+T7392BWr70Dmt8ddLmp5mK4R/gnTk6+lHJK9p/dhdk4haxWvAyBWHJty2Yk3T6nh
+OYkzdUIFidUVza+6jG2hc1lPGv3tmnYKgNeulkblm10oWphz79C6ycx5WG7TNgef
+CQ3z7//Nn89YTiaUBjLvoLvxRTMwO96r7E/FaslSl/fWnF3HP3lut26Z/mNfhiwj
+qn7AhUwpSNPV0qcxFWXr/rXUjdk745wv8wOODK8atjjE/vt/MRBK0rAOIPSm3ecx
+37PKNtR4i+sNeDEcY1IyTHE6wFvJSy5y8AFpn5y8tbqYfhlEVWZ4pcnlrKxhWm7j
+oBkB/4GBjKQgbQ7ttym9eNG1wIbZ8v9N06+yeLs/NCc4bFZEgcWjFqBH1bLtAYEC
+gcEA8tt8iYNqbsDH2ognjEmbbBxrDBmyYcEKRpg1i1SUopcZl8i93IHpG7EgJIaj
+l7aWSbASAxjnK02t0VZ3nNS60acibzRwY/+e8OrSqlQdMXlAB2ggBA86drDJpfBl
+WGJG8TJVY9bc1TU2uuwtZR1LAMSsRHVp+3IvKLpHrne5exPd3x6KGYcuaM+Uk/rE
+u6tLsFNwaCdh+iBFFDT2bnYIw7jAsokJUkwxMVxSC0/21s2blhO/q5LsN1gFC1kN
+TbpXAoHBANWE7TmG2szPvujPwrK18v6iJlHCA2n50AgAQXrsetj2JcF3HYHYdHnq
+z36MQ6FpBKOiQumozWvb32WTjEwdG2kix7GEfam4DAUBdqYuCHzPcR12K5Tc8hsX
+NG7JXUAeS8ZJEiOdu95X59JHyBxUQtNfte5rcbaV17SVw6K6bsWVJnj60YjtJrpa
+xHvv1ZRnT2WEzJGpA+ii1h3I52N7ipGBiw172qcW+bKJukMi8eHxx5CC9e5tBpnu
+C+Ou/eYewQKBwHxNa0jXQrq9YY2w8s0TP8HuKbxfyrXOIHxRm9ZczFcMD8VosgUT
+WUUbO+B2KXWVtwawYAfFz0ySzcy//SkAmT6F1VIl/QCx7aBSENGti+Ous98WpIxv
+XvUxN4T/rl+2raj2ok4fw5g9TG4QRIvkmmciQyonDr/sicbG0bmy/fTJDl8NOpIm
+ZtKurNWxHNERtAPkMTyeK7/ilHjrQtb3AzVqcvbuvR6qcONa5YN0wlrfkisWoJwo
+707EdpCAXBbUsQKBwQCnpzcpu2Sj+t9ZKIElF87T93gFLETH+ppJHgJMRdDz+NqO
+fTwTD2XtsNz57aLQ44f8AFVv6NZbQYq41FEOFrDGLcQE9BZDpDrz10FVnMGXVr7n
+tjjkK1SCxwapkr0AsoknCYsPojO4kud46loLPHI4TGeq7HyeNCvqJMo3RRHjXIiX
+58GNNUD6hHjRI/FdFH14Jf0GxmJGUU20l2Jwb7nPJJuNm9mE53pqoNA7FP4+Pj1H
+kD0Q2FSdmxeE0IuWHEECgcBgw6ogJ/FRRGLcym+aApqP9BChK+W8FDfDc9Mi4p/J
+g+XmetWNFGCGTlOefGqUDIkwSG+QVOEN3hxziXbsjnvfpGApqoaulAI5oRvrwIcj
+QIvD2mt0PB52k5ZL9QL2K9sgBa43BJDyCKooMAlTy2XMM+NyXVxQKmzf3r3jQ5sl
+Rptk7ro38a9G8Rs99RFDyOmP1haOM0KXZvPksN4nsXuTlE01cnwnI29XKAlEZaoA
+pQPLXD8W/KK4mwDbmokYXmo=
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
-MIICXTCCAcagAwIBAgIJAIO3upAG445fMA0GCSqGSIb3DQEBBQUAMGIxCzAJBgNV
-BAYTAlhZMRcwFQYDVQQHEw5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9u
-IFNvZnR3YXJlIEZvdW5kYXRpb24xFTATBgNVBAMTDGZha2Vob3N0bmFtZTAeFw0x
-MDEwMDkxNTAxMDBaFw0yMDEwMDYxNTAxMDBaMGIxCzAJBgNVBAYTAlhZMRcwFQYD
-VQQHEw5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9uIFNvZnR3YXJlIEZv
-dW5kYXRpb24xFTATBgNVBAMTDGZha2Vob3N0bmFtZTCBnzANBgkqhkiG9w0BAQEF
-AAOBjQAwgYkCgYEAmewllWumkv5bkj3MZCutrBbATlAmkEr2dbDXuZetnTdHVwP0
-FqYsaK9UhJs+VGUBWdkETKHUBOmwHt0JRD5YcS8Auq6/Hj5jDmX59d6JhGOstEFh
-m5XLzI21fNTeJZwY5txhGRR2Jd07I/uwsXZhkdG9BmnOAMEqSutp5DzXDbUCAwEA
-AaMbMBkwFwYDVR0RBBAwDoIMZmFrZWhvc3RuYW1lMA0GCSqGSIb3DQEBBQUAA4GB
-AH+iMClLLGSaKWgwXsmdVo4FhTZZHo8Uprrtg3N9FxEeE50btpDVQysgRt5ias3K
-m+bME9zbKwvbVWD5zZdjus4pDgzwF/iHyccL8JyYhxOvS/9zmvAtFXj/APIIbZFp
-IT75d9f88ScIGEtknZQejnrdhB64tYki/EqluiuKBqKD
+MIIEYjCCAsqgAwIBAgIJAJm2YulYpr+6MA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNV
+BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
+IFNvZnR3YXJlIEZvdW5kYXRpb24xFTATBgNVBAMMDGZha2Vob3N0bmFtZTAeFw0x
+ODA4MjkxNDIzMTZaFw0yODA4MjYxNDIzMTZaMGIxCzAJBgNVBAYTAlhZMRcwFQYD
+VQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZv
+dW5kYXRpb24xFTATBgNVBAMMDGZha2Vob3N0bmFtZTCCAaIwDQYJKoZIhvcNAQEB
+BQADggGPADCCAYoCggGBAMqOuNZmV86zUKGq3VGjIt+rJdsdVcgBbR9PMDF8mfG8
+U6JaoAAqALapVAzxjTzSRFS5Fpc//D3LBdP4zNfq0HLLlVtNgljJOMc4fjoRYs11
+yoQmzj4UJWo4hitA9DqkYCEJeaAHLhVvjYkAEvBv4q37LYOTXm2CBVwAc/YqGuL6
+VFda91r6RkB7YXUiiOa5bIJPLcURgeJzmo0Gxdx/q7WjIVXwzJs67PXMaPe93YL5
+0Qo7g6HD2tHCe8dJq2Mz4J/CJd/yRNfMMEVn/xbf7rIDj2kfFFsbsUTcrVMA+GSu
+n4FVMhQ5x0jvjAQDpQSRYUXmxByaYC2Hn0wRCuXYJeit+0Q+GwpkTn11Q/X6dgA+
+9H+ZPJI0JLDv+u91/5yxFJnmiWUy7+XGyG26UlgkjTf4iINOfjsUjkP4gXblEQrt
+3gvMYijpPveS2xP6qlJce5NYL4gAGbwAwX3uWPEdLAxFT/P47m6I41Ei0MCAof84
+i0Ubng+1ja8CFo7RiJmtlwIDAQABoxswGTAXBgNVHREEEDAOggxmYWtlaG9zdG5h
+bWUwDQYJKoZIhvcNAQELBQADggGBAMIVLp6e6saH2NQSg8iFg8Ewg/K/etI++jHo
+gCJ697AY02wtfrBox1XtljlmI2xpJtVAYZWHhrNqwrEG43aB7YEV6RqTcG6QUVqa
+NbD8iNCnMKm7fP89hZizmqA1l4aHnieI3ucOqpgooM7FQwLX6qk+rSue6lD5N/5f
+avsublnj8rNKyDfHpQ3AWduLoj8QqctpzI3CqoDZNLNzaDnzVWpxT1SKDQ88q7VI
+W5zb+lndpdQlCu3v5HM4w5UpwL/k1htl/z6PnPseS2UdlXv6A8KITnCLg5PLP4tz
+2oTAg9gjOtRP/0uwkhvicwoFzFJNVT813lzTLE1jlobMPiZhsS1mjaJGPD9GQZDK
+ny3j8ogrIRGjnI4xpOMNNDVphcvwtV8fRbvURSHCj9Y4kCLpD5ODuoyEyLYicJIv
+GZP456GP0iSCK5GKO0ij/YzGCkPWD5zA+mYFpMMGZPTwajenMw7TVaPXcc9CZBtr
+oOjwwiLEqdkpxUj13mJYTlt5wsS/Kw==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMLgD0kAKDb5cFyP
-jbwNfR5CtewdXC+kMXAWD8DLxiTTvhMW7qVnlwOm36mZlszHKvsRf05lT4pegiFM
-9z2j1OlaN+ci/X7NU22TNN6crYSiN77FjYJP464j876ndSxyD+rzys386T+1r1aZ
-aggEdkj1TsSsv1zWIYKlPIjlvhuxAgMBAAECgYA0aH+T2Vf3WOPv8KdkcJg6gCRe
-yJKXOWgWRcicx/CUzOEsTxmFIDPLxqAWA3k7v0B+3vjGw5Y9lycV/5XqXNoQI14j
-y09iNsumds13u5AKkGdTJnZhQ7UKdoVHfuP44ZdOv/rJ5/VD6F4zWywpe90pcbK+
-AWDVtusgGQBSieEl1QJBAOyVrUG5l2yoUBtd2zr/kiGm/DYyXlIthQO/A3/LngDW
-5/ydGxVsT7lAVOgCsoT+0L4efTh90PjzW8LPQrPBWVMCQQDS3h/FtYYd5lfz+FNL
-9CEe1F1w9l8P749uNUD0g317zv1tatIqVCsQWHfVHNdVvfQ+vSFw38OORO00Xqs9
-1GJrAkBkoXXEkxCZoy4PteheO/8IWWLGGr6L7di6MzFl1lIqwT6D8L9oaV2vynFT
-DnKop0pa09Unhjyw57KMNmSE2SUJAkEArloTEzpgRmCq4IK2/NpCeGdHS5uqRlbh
-1VIa/xGps7EWQl5Mn8swQDel/YP3WGHTjfx7pgSegQfkyaRtGpZ9OQJAa9Vumj8m
-JAAtI0Bnga8hgQx7BhTQY4CadDxyiRGOGYhwUzYVCqkb2sbVRH9HnwUaJT7cWBY3
-RnJdHOMXWem7/w==
+MIIG/QIBADANBgkqhkiG9w0BAQEFAASCBucwggbjAgEAAoIBgQCfKC83Qe9/ZGMW
+YhbpARRiKco6mJI9CNNeaf7A89TE+w5Y3GSwS8uzqp5C6QebZzPNueg8HYoTwN85
+Z3xM036/Qw9KhQVth+XDAqM+19e5KHkYcxg3d3ZI1HgY170eakaLBvMDN5ULoFOw
+Is2PtwM2o9cjd5mfSuWttI6+fCqop8/l8cerG9iX2GH39p3iWwWoTZuYndAA9qYv
+07YWajuQ1ESWKPjHYGTnMvu4xIzibC1mXd2M6u/IjNO6g426SKFaRDWQkx01gIV/
+CyKs9DgZoeMHkKZuPqZVOxOK+A/NrmrqHFsPIsrs5wk7QAVju5/X1skpn/UGQlmM
+RwBaQULOs1FagA+54RXU6qUPW0YmhJ4xOB4gHHD1vjAKEsRZ7/6zcxMyOm+M1DbK
+RTH4NWjVWpnY8XaVGdRhtTpH9MjycpKhF+D2Zdy2tQXtqu2GdcMnUedt13fn9xDu
+P4PophE0ip/IMgn+kb4m9e+S+K9lldQl0B+4BcGWAqHelh2KuU0CAwEAAQKCAYEA
+lKiWIYjmyRjdLKUGPTES9vWNvNmRjozV0RQ0LcoSbMMLDZkeO0UwyWqOVHUQ8+ib
+jIcfEjeNJxI57oZopeHOO5vJhpNlFH+g7ltiW2qERqA1K88lSXm99Bzw6FNqhCRE
+K8ub5N9fyfJA+P4o/xm0WK8EXk5yIUV17p/9zJJxzgKgv2jsVTi3QG2OZGvn4Oug
+ByomMZEGHkBDzdxz8c/cP1Tlk1RFuwSgews178k2xq7AYSM/s0YmHi7b/RSvptX6
+1v8P8kXNUe4AwTaNyrlvF2lwIadZ8h1hA7tCE2n44b7a7KfhAkwcbr1T59ioYh6P
+zxsyPT678uD51dbtD/DXJCcoeeFOb8uzkR2KNcrnQzZpCJnRq4Gp5ybxwsxxuzpr
+gz0gbNlhuWtE7EoSzmIK9t+WTS7IM2CvZymd6/OAh1Fuw6AQhSp64XRp3OfMMAAC
+Ie2EPtKj4islWGT8VoUjuRYGmdRh4duAH1dkiAXOWA3R7y5a1/y/iE8KE8BtxocB
+AoHBAM8aiURgpu1Fs0Oqz6izec7KSLL3l8hmW+MKUOfk/Ybng6FrTFsL5YtzR+Ap
+wW4wwWnnIKEc1JLiZ7g8agRETK8hr5PwFXUn/GSWC0SMsazLJToySQS5LOV0tLzK
+kJ3jtNU7tnlDGNkCHTHSoVL2T/8t+IkZI/h5Z6wjlYPvU2Iu0nVIXtiG+alv4A6M
+Hrh9l5or4mjB6rGnVXeYohLkCm6s/W97ahVxLMcEdbsBo1prm2JqGnSoiR/tEFC/
+QHQnbQKBwQDEu7kW0Yg9sZ89QtYtVQ1YpixFZORaUeRIRLnpEs1w7L1mCbOZ2Lj9
+JHxsH05cYAc7HJfPwwxv3+3aGAIC/dfu4VSwEFtatAzUpzlhzKS5+HQCWB4JUNNU
+MQ3+FwK2xQX4Ph8t+OzrFiYcK2g0An5UxWMa2HWIAWUOhnTOydAVsoH6yP31cVm4
+0hxoABCwflaNLNGjRUyfBpLTAcNu/YtcE+KREy7YAAgXXrhRSO4XpLsSXwLnLT7/
+YOkoBWDcTWECgcBPWnSUDZCIQ3efithMZJBciqd2Y2X19Dpq8O31HImD4jtOY0V7
+cUB/wSkeHAGwjd/eCyA2e0x8B2IEdqmMfvr+86JJxekC3dJYXCFvH5WIhsH53YCa
+3bT1KlWCLP9ib/g+58VQC0R/Cc9T4sfLePNH7D5ZkZd1wlbV30CPr+i8KwKay6MD
+xhvtLx+jk07GE+E9wmjbCMo7TclyrLoVEOlqZMAqshgApT+p9eyCPetwXuDHwa3n
+WxhHclcZCV7R4rUCgcAkdGSnxcvpIrDPOUNWwxvmAWTStw9ZbTNP8OxCNCm9cyDl
+d4bAS1h8D/a+Uk7C70hnu7Sl2w7C7Eu2zhwRUdhhe3+l4GINPK/j99i6NqGPlGpq
+xMlMEJ4YS768BqeKFpg0l85PRoEgTsphDeoROSUPsEPdBZ9BxIBlYKTkbKESZDGR
+twzYHljx1n1NCDYPflmrb1KpXn4EOcObNghw2KqqNUUWfOeBPwBA1FxzM4BrAStp
+DBINpGS4Dc0mjViVegECgcA3hTtm82XdxQXj9LQmb/E3lKx/7H87XIOeNMmvjYuZ
+iS9wKrkF+u42vyoDxcKMCnxP5056wpdST4p56r+SBwVTHcc3lGBSGcMTIfwRXrj3
+thOA2our2n4ouNIsYyTlcsQSzifwmpRmVMRPxl9fYVdEWUgB83FgHT0D9avvZnF9
+t9OccnGJXShAIZIBADhVj/JwG4FbaX42NijD5PNpVLk1Y17OV0I576T9SfaQoBjJ
+aH1M/zC4aVaS0DYB/Gxq7v8=
-----END PRIVATE KEY-----
Certificate:
Data:
- Version: 1 (0x0)
- Serial Number: 12723342612721443281 (0xb09264b1f2da21d1)
- Signature Algorithm: sha1WithRSAEncryption
+ Version: 3 (0x2)
+ Serial Number:
+ cb:2d:80:99:5a:69:52:5c
+ Signature Algorithm: sha256WithRSAEncryption
Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server
Validity
- Not Before: Jan 4 19:47:07 2013 GMT
- Not After : Nov 13 19:47:07 2022 GMT
+ Not Before: Aug 29 14:23:16 2018 GMT
+ Not After : Jul 7 14:23:16 2028 GMT
Subject: C=XY, L=Castle Anthrax, O=Python Software Foundation, CN=localhost
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
- Public-Key: (1024 bit)
+ Public-Key: (3072 bit)
Modulus:
- 00:c2:e0:0f:49:00:28:36:f9:70:5c:8f:8d:bc:0d:
- 7d:1e:42:b5:ec:1d:5c:2f:a4:31:70:16:0f:c0:cb:
- c6:24:d3:be:13:16:ee:a5:67:97:03:a6:df:a9:99:
- 96:cc:c7:2a:fb:11:7f:4e:65:4f:8a:5e:82:21:4c:
- f7:3d:a3:d4:e9:5a:37:e7:22:fd:7e:cd:53:6d:93:
- 34:de:9c:ad:84:a2:37:be:c5:8d:82:4f:e3:ae:23:
- f3:be:a7:75:2c:72:0f:ea:f3:ca:cd:fc:e9:3f:b5:
- af:56:99:6a:08:04:76:48:f5:4e:c4:ac:bf:5c:d6:
- 21:82:a5:3c:88:e5:be:1b:b1
+ 00:9f:28:2f:37:41:ef:7f:64:63:16:62:16:e9:01:
+ 14:62:29:ca:3a:98:92:3d:08:d3:5e:69:fe:c0:f3:
+ d4:c4:fb:0e:58:dc:64:b0:4b:cb:b3:aa:9e:42:e9:
+ 07:9b:67:33:cd:b9:e8:3c:1d:8a:13:c0:df:39:67:
+ 7c:4c:d3:7e:bf:43:0f:4a:85:05:6d:87:e5:c3:02:
+ a3:3e:d7:d7:b9:28:79:18:73:18:37:77:76:48:d4:
+ 78:18:d7:bd:1e:6a:46:8b:06:f3:03:37:95:0b:a0:
+ 53:b0:22:cd:8f:b7:03:36:a3:d7:23:77:99:9f:4a:
+ e5:ad:b4:8e:be:7c:2a:a8:a7:cf:e5:f1:c7:ab:1b:
+ d8:97:d8:61:f7:f6:9d:e2:5b:05:a8:4d:9b:98:9d:
+ d0:00:f6:a6:2f:d3:b6:16:6a:3b:90:d4:44:96:28:
+ f8:c7:60:64:e7:32:fb:b8:c4:8c:e2:6c:2d:66:5d:
+ dd:8c:ea:ef:c8:8c:d3:ba:83:8d:ba:48:a1:5a:44:
+ 35:90:93:1d:35:80:85:7f:0b:22:ac:f4:38:19:a1:
+ e3:07:90:a6:6e:3e:a6:55:3b:13:8a:f8:0f:cd:ae:
+ 6a:ea:1c:5b:0f:22:ca:ec:e7:09:3b:40:05:63:bb:
+ 9f:d7:d6:c9:29:9f:f5:06:42:59:8c:47:00:5a:41:
+ 42:ce:b3:51:5a:80:0f:b9:e1:15:d4:ea:a5:0f:5b:
+ 46:26:84:9e:31:38:1e:20:1c:70:f5:be:30:0a:12:
+ c4:59:ef:fe:b3:73:13:32:3a:6f:8c:d4:36:ca:45:
+ 31:f8:35:68:d5:5a:99:d8:f1:76:95:19:d4:61:b5:
+ 3a:47:f4:c8:f2:72:92:a1:17:e0:f6:65:dc:b6:b5:
+ 05:ed:aa:ed:86:75:c3:27:51:e7:6d:d7:77:e7:f7:
+ 10:ee:3f:83:e8:a6:11:34:8a:9f:c8:32:09:fe:91:
+ be:26:f5:ef:92:f8:af:65:95:d4:25:d0:1f:b8:05:
+ c1:96:02:a1:de:96:1d:8a:b9:4d
Exponent: 65537 (0x10001)
- Signature Algorithm: sha1WithRSAEncryption
- 2f:42:5f:a3:09:2c:fa:51:88:c7:37:7f:ea:0e:63:f0:a2:9a:
- e5:5a:e2:c8:20:f0:3f:60:bc:c8:0f:b6:c6:76:ce:db:83:93:
- f5:a3:33:67:01:8e:04:cd:00:9a:73:fd:f3:35:86:fa:d7:13:
- e2:46:c6:9d:c0:29:53:d4:a9:90:b8:77:4b:e6:83:76:e4:92:
- d6:9c:50:cf:43:d0:c6:01:77:61:9a:de:9b:70:f7:72:cd:59:
- 00:31:69:d9:b4:ca:06:9c:6d:c3:c7:80:8c:68:e6:b5:a2:f8:
- ef:1d:bb:16:9f:77:77:ef:87:62:22:9b:4d:69:a4:3a:1a:f1:
- 21:5e:8c:32:ac:92:fd:15:6b:18:c2:7f:15:0d:98:30:ca:75:
- 8f:1a:71:df:da:1d:b2:ef:9a:e8:2d:2e:02:fd:4a:3c:aa:96:
- 0b:06:5d:35:b3:3d:24:87:4b:e0:b0:58:60:2f:45:ac:2e:48:
- 8a:b0:99:10:65:27:ff:cc:b1:d8:fd:bd:26:6b:b9:0c:05:2a:
- f4:45:63:35:51:07:ed:83:85:fe:6f:69:cb:bb:40:a8:ae:b6:
- 3b:56:4a:2d:a4:ed:6d:11:2c:4d:ed:17:24:fd:47:bc:d3:41:
- a2:d3:06:fe:0c:90:d8:d8:94:26:c4:ff:cc:a1:d8:42:77:eb:
- fc:a9:94:71
+ X509v3 extensions:
+ X509v3 Subject Alternative Name:
+ DNS:localhost
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ X509v3 Basic Constraints: critical
+ CA:FALSE
+ X509v3 Subject Key Identifier:
+ 8F:EA:1D:E3:33:5C:00:16:B3:8B:6F:6B:6F:D3:4C:CB:B5:CB:7C:55
+ X509v3 Authority Key Identifier:
+ keyid:DD:BF:CA:DA:E6:D1:34:BA:37:75:21:CA:6F:9A:08:28:F2:35:B6:48
+ DirName:/C=XY/O=Python Software Foundation CA/CN=our-ca-server
+ serial:CB:2D:80:99:5A:69:52:5B
+
+ Authority Information Access:
+ CA Issuers - URI:http://testca.pythontest.net/testca/pycacert.cer
+ OCSP - URI:http://testca.pythontest.net/testca/ocsp/
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://testca.pythontest.net/testca/revocation.crl
+
+ Signature Algorithm: sha256WithRSAEncryption
+ 27:f5:8c:59:10:f4:c6:e7:28:00:bf:ba:8d:7b:13:03:f1:1c:
+ a6:5f:b3:06:55:a4:22:b9:db:b2:d5:46:bd:f7:0c:dd:43:6e:
+ b4:79:65:67:21:0c:2a:55:ee:40:8e:85:9f:9f:47:bb:0a:2a:
+ 4d:b6:64:74:98:a0:7f:ae:dc:f1:2e:db:42:77:18:e0:75:8b:
+ 26:35:68:c3:41:ed:6b:c8:77:72:6f:6a:9a:5d:55:69:02:fd:
+ 5a:54:c8:57:cb:b0:65:03:16:e2:0f:00:39:99:66:a0:9b:88:
+ 93:17:e2:5a:2d:79:35:5f:97:57:78:c4:af:f5:99:5e:86:ab:
+ d3:11:ad:1a:a2:0d:fa:52:10:b9:fe:bf:9d:ce:33:d9:86:b2:
+ 9c:16:f8:d6:75:08:8a:db:0a:e5:b4:2b:16:7f:b4:f9:2a:9f:
+ c3:d2:77:d7:cd:65:1e:f4:6c:1e:eb:59:b9:f0:ae:5f:a4:1f:
+ cc:4a:c4:b9:7a:a9:d9:6b:32:68:3b:e1:65:b0:84:b7:90:c4:
+ ae:fe:f4:37:4f:21:a0:de:9f:3a:b1:e5:cc:16:04:66:3f:0b:
+ 41:dc:42:3d:20:3e:ec:b7:95:2b:35:57:fa:be:7f:b6:3a:ba:
+ ca:4f:58:fe:75:3e:08:89:2c:8c:b0:5d:2e:f9:89:10:2b:f9:
+ 41:46:4f:3c:00:b7:27:d3:65:24:28:17:23:26:31:42:ea:7e:
+ 4e:93:e4:7b:68:54:ca:9f:46:f3:ef:2b:e9:85:0c:b5:84:b2:
+ d5:35:34:80:75:2b:f0:91:23:b8:08:01:8e:b9:0a:54:d4:fb:
+ 34:52:fe:d9:45:f0:80:3b:b6:c1:6f:82:d1:1f:f2:3b:08:f6:
+ 46:a6:96:27:61:4b:58:32:7a:0e:1d:59:c5:44:ad:5e:1a:79:
+ 33:c1:d4:05:2f:4a:d3:d8:42:42:8d:33:e3:63:ca:d5:87:97:
+ 9b:4d:b8:1a:03:34:bb:1c:d2:02:3f:59:23:e2:23:80:88:63:
+ c2:f0:a2:63:a8:8b
-----BEGIN CERTIFICATE-----
-MIICpDCCAYwCCQCwkmSx8toh0TANBgkqhkiG9w0BAQUFADBNMQswCQYDVQQGEwJY
-WTEmMCQGA1UECgwdUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24gQ0ExFjAUBgNV
-BAMMDW91ci1jYS1zZXJ2ZXIwHhcNMTMwMTA0MTk0NzA3WhcNMjIxMTEzMTk0NzA3
-WjBfMQswCQYDVQQGEwJYWTEXMBUGA1UEBxMOQ2FzdGxlIEFudGhyYXgxIzAhBgNV
-BAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMRIwEAYDVQQDEwlsb2NhbGhv
-c3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMLgD0kAKDb5cFyPjbwNfR5C
-tewdXC+kMXAWD8DLxiTTvhMW7qVnlwOm36mZlszHKvsRf05lT4pegiFM9z2j1Ola
-N+ci/X7NU22TNN6crYSiN77FjYJP464j876ndSxyD+rzys386T+1r1aZaggEdkj1
-TsSsv1zWIYKlPIjlvhuxAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAC9CX6MJLPpR
-iMc3f+oOY/CimuVa4sgg8D9gvMgPtsZ2ztuDk/WjM2cBjgTNAJpz/fM1hvrXE+JG
-xp3AKVPUqZC4d0vmg3bkktacUM9D0MYBd2Ga3ptw93LNWQAxadm0ygacbcPHgIxo
-5rWi+O8duxafd3fvh2Iim01ppDoa8SFejDKskv0VaxjCfxUNmDDKdY8acd/aHbLv
-mugtLgL9SjyqlgsGXTWzPSSHS+CwWGAvRawuSIqwmRBlJ//Msdj9vSZruQwFKvRF
-YzVRB+2Dhf5vacu7QKiutjtWSi2k7W0RLE3tFyT9R7zTQaLTBv4MkNjYlCbE/8yh
-2EJ36/yplHE=
+MIIF8TCCBFmgAwIBAgIJAMstgJlaaVJcMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV
+BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW
+MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xODA4MjkxNDIzMTZaFw0yODA3MDcx
+NDIzMTZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEj
+MCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMMCWxv
+Y2FsaG9zdDCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAJ8oLzdB739k
+YxZiFukBFGIpyjqYkj0I015p/sDz1MT7DljcZLBLy7OqnkLpB5tnM8256DwdihPA
+3zlnfEzTfr9DD0qFBW2H5cMCoz7X17koeRhzGDd3dkjUeBjXvR5qRosG8wM3lQug
+U7AizY+3Azaj1yN3mZ9K5a20jr58Kqinz+Xxx6sb2JfYYff2neJbBahNm5id0AD2
+pi/TthZqO5DURJYo+MdgZOcy+7jEjOJsLWZd3Yzq78iM07qDjbpIoVpENZCTHTWA
+hX8LIqz0OBmh4weQpm4+plU7E4r4D82uauocWw8iyuznCTtABWO7n9fWySmf9QZC
+WYxHAFpBQs6zUVqAD7nhFdTqpQ9bRiaEnjE4HiAccPW+MAoSxFnv/rNzEzI6b4zU
+NspFMfg1aNVamdjxdpUZ1GG1Okf0yPJykqEX4PZl3La1Be2q7YZ1wydR523Xd+f3
+EO4/g+imETSKn8gyCf6Rvib175L4r2WV1CXQH7gFwZYCod6WHYq5TQIDAQABo4IB
+wDCCAbwwFAYDVR0RBA0wC4IJbG9jYWxob3N0MA4GA1UdDwEB/wQEAwIFoDAdBgNV
+HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4E
+FgQUj+od4zNcABazi29rb9NMy7XLfFUwfQYDVR0jBHYwdIAU3b/K2ubRNLo3dSHK
+b5oIKPI1tkihUaRPME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29m
+dHdhcmUgRm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNhLXNlcnZlcoIJAMst
+gJlaaVJbMIGDBggrBgEFBQcBAQR3MHUwPAYIKwYBBQUHMAKGMGh0dHA6Ly90ZXN0
+Y2EucHl0aG9udGVzdC5uZXQvdGVzdGNhL3B5Y2FjZXJ0LmNlcjA1BggrBgEFBQcw
+AYYpaHR0cDovL3Rlc3RjYS5weXRob250ZXN0Lm5ldC90ZXN0Y2Evb2NzcC8wQwYD
+VR0fBDwwOjA4oDagNIYyaHR0cDovL3Rlc3RjYS5weXRob250ZXN0Lm5ldC90ZXN0
+Y2EvcmV2b2NhdGlvbi5jcmwwDQYJKoZIhvcNAQELBQADggGBACf1jFkQ9MbnKAC/
+uo17EwPxHKZfswZVpCK527LVRr33DN1DbrR5ZWchDCpV7kCOhZ+fR7sKKk22ZHSY
+oH+u3PEu20J3GOB1iyY1aMNB7WvId3JvappdVWkC/VpUyFfLsGUDFuIPADmZZqCb
+iJMX4loteTVfl1d4xK/1mV6Gq9MRrRqiDfpSELn+v53OM9mGspwW+NZ1CIrbCuW0
+KxZ/tPkqn8PSd9fNZR70bB7rWbnwrl+kH8xKxLl6qdlrMmg74WWwhLeQxK7+9DdP
+IaDenzqx5cwWBGY/C0HcQj0gPuy3lSs1V/q+f7Y6uspPWP51PgiJLIywXS75iRAr
++UFGTzwAtyfTZSQoFyMmMULqfk6T5HtoVMqfRvPvK+mFDLWEstU1NIB1K/CRI7gI
+AY65ClTU+zRS/tlF8IA7tsFvgtEf8jsI9kamlidhS1gyeg4dWcVErV4aeTPB1AUv
+StPYQkKNM+NjytWHl5tNuBoDNLsc0gI/WSPiI4CIY8LwomOoiw==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAK5UQiMI5VkNs2Qv
-L7gUaiDdFevNUXRjU4DHAe3ZzzYLZNE69h9gO9VCSS16tJ5fT5VEu0EZyGr0e3V2
-NkX0ZoU0Hc/UaY4qx7LHmn5SYZpIxhJnkf7SyHJK1zUaGlU0/LxYqIuGCtF5dqx1
-L2OQhEx1GM6RydHdgX69G64LXcY5AgMBAAECgYAhsRMfJkb9ERLMl/oG/5sLQu9L
-pWDKt6+ZwdxzlZbggQ85CMYshjLKIod2DLL/sLf2x1PRXyRG131M1E3k8zkkz6de
-R1uDrIN/x91iuYzfLQZGh8bMY7Yjd2eoroa6R/7DjpElGejLxOAaDWO0ST2IFQy9
-myTGS2jSM97wcXfsSQJBANP3jelJoS5X6BRjTSneY21wcocxVuQh8pXpErALVNsT
-drrFTeaBuZp7KvbtnIM5g2WRNvaxLZlAY/hXPJvi6ncCQQDSix1cebml6EmPlEZS
-Mm8gwI2F9ufUunwJmBJcz826Do0ZNGByWDAM/JQZH4FX4GfAFNuj8PUb+GQfadkx
-i1DPAkEA0lVsNHojvuDsIo8HGuzarNZQT2beWjJ1jdxh9t7HrTx7LIps6rb/fhOK
-Zs0R6gVAJaEbcWAPZ2tFyECInAdnsQJAUjaeXXjuxFkjOFym5PvqpvhpivEx78Bu
-JPTr3rAKXmfGMxxfuOa0xK1wSyshP6ZR/RBn/+lcXPKubhHQDOegwwJAJF1DBQnN
-+/tLmOPULtDwfP4Zixn+/8GmGOahFoRcu6VIGHmRilJTn6MOButw7Glv2YdeC6l/
-e83Gq6ffLVfKNQ==
+MIIG/QIBADANBgkqhkiG9w0BAQEFAASCBucwggbjAgEAAoIBgQDGjpiHzq7ghxhM
+ZzrnRsGBC/cmw8EREIdbqlrz/l8BFaWeipvO5Hb/MyU8xs2zLUrqIr2JNf+Eii8Y
+m4bYmZclFra4jomaiSlxTZOe3dMV8m4vAq4eT2mSfZZC1+XAutqdz7WhHxhMVEm3
+AyTWvTC3qCbnlbX5VIoQUwFrsSWqDiHyaGdK3rrOTKFUKM8YPiq/BZkm6A4eiFci
+5wd/SPD+w0pIscZbQW1MUr5bs54uylWaUmtfI8KJt6BDZQ/uA06c6i863sSCEI6L
+gq+wyikeJGNMxZMfgu3dzfv4BiZBQX0ZhiRvqseDSdPcuVa2Ifb6CFlg298neweY
+4EAIE1O+uqo5h8FF1aUOMZpQEZuzsp9R/TAMBHX1YmVjG/kRdBeaHe3whzB1Pfue
+PIX2ZTMmLNYbYbfnmxhk1nn8aAvoT98pNw8y3/2k2KNsu24n9uSkkxAoqJ19WKwm
+mL8MpJKAzLv45tRvhN+QLtnRdu+LJ9m29npQHFmYLbdqRfmidnMCAwEAAQKCAYBd
+w1C8MRnb5W/QBJ+IP515NxFLOP2e9VM2MkgpGGH8vSAssf/Jv5GCCcD35lmU1zqd
+PjKK7PjwueBrmmYfOshpN0Sp+oV4eHUdkCi5yL65inYFtRpMLewIxU2D2zgfvx0l
+kMSQhYKP6O22gsGOtmCfGcTlb4kzaHyaINh25nyGxY26TxsX+/3zFbTJbUv+grzk
+39vmx4aDXJbpYHfl36gOZmJZ2bl1tnvKovhJjZSRO/MYoPsbPmPLbO89ZCgVmXFc
+GVkb5Cram6i3iyutSDjxWN7Fb8uy8pFLPGAXZgF7pQoXPSEHZe8GEWBnWSC9KaDa
+uM9Ir847/Muy1ceCmxKcI2WrSjoH2AhPcmHgvbPE9Mynr6+uzReSP3q7Wh9PHm23
+oFx3DwdCfmjysnpAMBawNmJdWyxVDbZ6eyrhp17ADpsMaDTynZ+fJjgMr+MmWtbU
+YSRD0wWtl/DrzsaePZsOjCpKYJyulC+rh9/Zz1aiwrGWPbgEAzDrD6Q1Zp0mUCEC
+gcEA+XskmGIB9rRPy+YQmRgzQ555PsjLWsnQsNktP6KBhlQjFKJZXRZ0DxDTS7h8
+NrJrUDBmwfsgzggVbeO55VP5FGwD6DNeO/Bz++Fdevh8uKQFHDfk4sbIUPS91qw4
+s7OW7PR7C7Jf7Dnjmsn42o2lO4FsbcEn2F+PHOvoLl/OrSx73lS/RkdOEItW8d8/
+ExRohylnba/I2vCE9bNZd4DGjMW87j/THKPadDZWEqWggcrjY8x6ibSQGm2n2Tka
+8B+vAoHBAMu+zl8kqFlYDG24dGfVpMaOYj5Osj0cV5f7O2pZ15sCevjiqoKGHH7G
+O8EiI5pRBZ893+Fsx6YWmcKue88lfGvaoQjV0LUbfMfX/FoD39w/ZLx31yKEiFuc
+KvMiRV5mO3kQiHBVX9vamzr5NeaErccXY9LnhaKOMX9blgiDQZH7fc3RhodcFWrC
+9yfX6ryfidpPnRvK7Ops7hVnFKyyS4FaAarnzH1B2WcVcD4lYYxhMc8VXeU3eKOh
+j1fI/F5ifQKBwQDpCjB670HqUzAexL9IYqSwSz3yedoK6m24ZIWx5XicI8fJJIXZ
+QHoVAKB/IMtWxH8dnri+Bnj0O/TYe1pQb4pBm0xjAGjMEKYm6LNLhQXr67qiS0vQ
+0eKYTKVv+9vTcLRQj2bI3Exh+wkys+tzK9DmrtS8CSvRICIs3+g4OWJzvRPP8NXj
+LgQrzBzhPqpKhkvFxdVJTmSOrxFj+a5exLmzEZqT6qanIB+VYpQwQuqVkxGpTX5B
+V5ssNLYPYRpapx0CgcByCtQixzcAA1u5knR9pkT76ris3YnA0Ptqk3I3XiBjoGjK
+pL0CICUVBMpvmTdKai12a8DDwgqiOaZJJTchxH63NAHNGzkeFkuq5IdYrzB/bHBr
+WbzukjZs6KXVv4oKg7ioVAu6rN7iBaO7x8BWzk8i0EHMzFCto1+rRM1e6HEsUBOj
+v7LIU0+dmZGUGLRIbhhQPR3Yb6ZatSwyiKc23vmKZqHmUqbQOaqBm6te7beDRugF
+XJVY9sqs9IJyhYpVHlUCgcAPoslwYKeAXagsxdQrH3D9VJDXVOHWKMBqQZDio5dB
+Q80uWpuxtt6nhZkQO1JIWnYb6v+zbDbcgjByBIDuxCdBW9d+QQnanKmVyrXguK91
+C3OcHHOmSduFdWC3/zYW1mW97Tz1sXyam2hly1u3L5kW+GnE1hr9VVPjQNrO9+Ge
+qW0coaJqKY78q3Rm2dtyZeJSFFI1o/DQ3blyItsFpg/QrR+a5XrS6Nw2ZLIL4Azo
+J1CTgMwjhwlMNCI4t4dkHd0=
-----END PRIVATE KEY-----
Certificate:
Data:
- Version: 1 (0x0)
- Serial Number: 12723342612721443282 (0xb09264b1f2da21d2)
- Signature Algorithm: sha1WithRSAEncryption
+ Version: 3 (0x2)
+ Serial Number:
+ cb:2d:80:99:5a:69:52:5d
+ Signature Algorithm: sha256WithRSAEncryption
Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server
Validity
- Not Before: Jan 4 19:47:07 2013 GMT
- Not After : Nov 13 19:47:07 2022 GMT
+ Not Before: Aug 29 14:23:16 2018 GMT
+ Not After : Jul 7 14:23:16 2028 GMT
Subject: C=XY, L=Castle Anthrax, O=Python Software Foundation, CN=fakehostname
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
- Public-Key: (1024 bit)
+ Public-Key: (3072 bit)
Modulus:
- 00:ae:54:42:23:08:e5:59:0d:b3:64:2f:2f:b8:14:
- 6a:20:dd:15:eb:cd:51:74:63:53:80:c7:01:ed:d9:
- cf:36:0b:64:d1:3a:f6:1f:60:3b:d5:42:49:2d:7a:
- b4:9e:5f:4f:95:44:bb:41:19:c8:6a:f4:7b:75:76:
- 36:45:f4:66:85:34:1d:cf:d4:69:8e:2a:c7:b2:c7:
- 9a:7e:52:61:9a:48:c6:12:67:91:fe:d2:c8:72:4a:
- d7:35:1a:1a:55:34:fc:bc:58:a8:8b:86:0a:d1:79:
- 76:ac:75:2f:63:90:84:4c:75:18:ce:91:c9:d1:dd:
- 81:7e:bd:1b:ae:0b:5d:c6:39
+ 00:c6:8e:98:87:ce:ae:e0:87:18:4c:67:3a:e7:46:
+ c1:81:0b:f7:26:c3:c1:11:10:87:5b:aa:5a:f3:fe:
+ 5f:01:15:a5:9e:8a:9b:ce:e4:76:ff:33:25:3c:c6:
+ cd:b3:2d:4a:ea:22:bd:89:35:ff:84:8a:2f:18:9b:
+ 86:d8:99:97:25:16:b6:b8:8e:89:9a:89:29:71:4d:
+ 93:9e:dd:d3:15:f2:6e:2f:02:ae:1e:4f:69:92:7d:
+ 96:42:d7:e5:c0:ba:da:9d:cf:b5:a1:1f:18:4c:54:
+ 49:b7:03:24:d6:bd:30:b7:a8:26:e7:95:b5:f9:54:
+ 8a:10:53:01:6b:b1:25:aa:0e:21:f2:68:67:4a:de:
+ ba:ce:4c:a1:54:28:cf:18:3e:2a:bf:05:99:26:e8:
+ 0e:1e:88:57:22:e7:07:7f:48:f0:fe:c3:4a:48:b1:
+ c6:5b:41:6d:4c:52:be:5b:b3:9e:2e:ca:55:9a:52:
+ 6b:5f:23:c2:89:b7:a0:43:65:0f:ee:03:4e:9c:ea:
+ 2f:3a:de:c4:82:10:8e:8b:82:af:b0:ca:29:1e:24:
+ 63:4c:c5:93:1f:82:ed:dd:cd:fb:f8:06:26:41:41:
+ 7d:19:86:24:6f:aa:c7:83:49:d3:dc:b9:56:b6:21:
+ f6:fa:08:59:60:db:df:27:7b:07:98:e0:40:08:13:
+ 53:be:ba:aa:39:87:c1:45:d5:a5:0e:31:9a:50:11:
+ 9b:b3:b2:9f:51:fd:30:0c:04:75:f5:62:65:63:1b:
+ f9:11:74:17:9a:1d:ed:f0:87:30:75:3d:fb:9e:3c:
+ 85:f6:65:33:26:2c:d6:1b:61:b7:e7:9b:18:64:d6:
+ 79:fc:68:0b:e8:4f:df:29:37:0f:32:df:fd:a4:d8:
+ a3:6c:bb:6e:27:f6:e4:a4:93:10:28:a8:9d:7d:58:
+ ac:26:98:bf:0c:a4:92:80:cc:bb:f8:e6:d4:6f:84:
+ df:90:2e:d9:d1:76:ef:8b:27:d9:b6:f6:7a:50:1c:
+ 59:98:2d:b7:6a:45:f9:a2:76:73
Exponent: 65537 (0x10001)
- Signature Algorithm: sha1WithRSAEncryption
- ad:45:8a:8e:ef:c6:ef:04:41:5c:2c:4a:84:dc:02:76:0c:d0:
- 66:0f:f0:16:04:58:4d:fd:68:b7:b8:d3:a8:41:a5:5c:3c:6f:
- 65:3c:d1:f8:ce:43:35:e7:41:5f:53:3d:c9:2c:c3:7d:fc:56:
- 4a:fa:47:77:38:9d:bb:97:28:0a:3b:91:19:7f:bc:74:ae:15:
- 6b:bd:20:36:67:45:a5:1e:79:d7:75:e6:89:5c:6d:54:84:d1:
- 95:d7:a7:b4:33:3c:af:37:c4:79:8f:5e:75:dc:75:c2:18:fb:
- 61:6f:2d:dc:38:65:5b:ba:67:28:d0:88:d7:8d:b9:23:5a:8e:
- e8:c6:bb:db:ce:d5:b8:41:2a:ce:93:08:b6:95:ad:34:20:18:
- d5:3b:37:52:74:50:0b:07:2c:b0:6d:a4:4c:7b:f4:e0:fd:d1:
- af:17:aa:20:cd:62:e3:f0:9d:37:69:db:41:bd:d4:1c:fb:53:
- 20:da:88:9d:76:26:67:ce:01:90:a7:80:1d:a9:5b:39:73:68:
- 54:0a:d1:2a:03:1b:8f:3c:43:5d:5d:c4:51:f1:a7:e7:11:da:
- 31:2c:49:06:af:04:f4:b8:3c:99:c4:20:b9:06:36:a2:00:92:
- 61:1d:0c:6d:24:05:e2:82:e1:47:db:a0:5f:ba:b9:fb:ba:fa:
- 49:12:1e:ce
+ X509v3 extensions:
+ X509v3 Subject Alternative Name:
+ DNS:fakehostname
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ X509v3 Basic Constraints: critical
+ CA:FALSE
+ X509v3 Subject Key Identifier:
+ 52:E0:93:AA:52:55:B7:BB:E7:A8:E0:8C:DE:41:2E:F4:07:F0:36:FB
+ X509v3 Authority Key Identifier:
+ keyid:DD:BF:CA:DA:E6:D1:34:BA:37:75:21:CA:6F:9A:08:28:F2:35:B6:48
+ DirName:/C=XY/O=Python Software Foundation CA/CN=our-ca-server
+ serial:CB:2D:80:99:5A:69:52:5B
+
+ Authority Information Access:
+ CA Issuers - URI:http://testca.pythontest.net/testca/pycacert.cer
+ OCSP - URI:http://testca.pythontest.net/testca/ocsp/
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://testca.pythontest.net/testca/revocation.crl
+
+ Signature Algorithm: sha256WithRSAEncryption
+ 29:d2:3f:82:3f:c1:38:35:a6:bd:81:10:fe:64:ec:ff:7e:e1:
+ c6:6f:7f:86:65:f9:31:6f:fb:ef:32:4e:2f:87:c8:42:de:6c:
+ 8d:b8:06:08:8f:37:70:95:7d:e1:40:d4:82:2b:8d:b3:4a:fd:
+ 34:c5:9e:df:ff:01:53:4a:4f:08:f4:58:e1:74:fc:78:e3:3e:
+ 71:a7:5e:66:07:ea:d2:04:31:e2:75:a8:4c:80:17:86:92:20:
+ d2:32:a7:9a:65:8b:1a:5f:f1:4c:c8:50:6d:00:fc:99:bf:69:
+ b3:48:f3:45:5a:ee:35:50:14:b8:f3:92:92:c6:9f:0e:5d:eb:
+ 0d:e8:ec:f2:a4:09:6b:dc:66:2b:fc:df:4c:fc:65:a1:ae:d3:
+ b5:88:6a:a4:e7:08:1c:94:49:e0:b8:c1:04:8c:21:09:6c:55:
+ 4b:2c:97:10:f1:8c:6c:d0:bb:ba:8d:93:e8:47:8b:4d:8e:7d:
+ 7d:85:53:18:c8:f8:f4:8f:67:3a:b1:aa:3e:18:34:6c:3a:e6:
+ a6:c7:2f:be:83:38:f5:d5:e5:d2:17:28:61:6c:b6:49:99:21:
+ 69:a4:a8:b6:94:76:fd:18:ad:35:52:45:64:fb:f1:5d:8e:bb:
+ c0:21:2e:59:55:24:af:bb:8f:b2:0a:7b:17:f0:34:97:8e:68:
+ a9:f2:d0:3e:f6:73:82:f8:7c:4e:9a:70:7d:d6:b3:8c:cc:85:
+ 04:5c:02:8f:74:da:88:3a:20:a8:7e:c2:9e:b0:dd:56:1f:ce:
+ cd:42:16:c6:14:91:ad:30:e0:dc:76:f2:2c:56:ea:38:45:d8:
+ c0:3e:b8:90:fa:f3:38:99:ec:44:07:35:8f:69:62:0c:f9:ef:
+ b7:9d:e5:15:42:6e:fb:fe:4c:ff:e8:94:5a:1a:b0:80:b2:0e:
+ 17:3d:e1:87:a8:08:84:93:74:68:8d:29:df:ca:0b:6a:44:32:
+ 8a:51:3b:d6:38:db:bd:e3:2a:1b:5e:20:48:81:82:19:91:c6:
+ 87:8c:0f:cd:51:ea
-----BEGIN CERTIFICATE-----
-MIICpzCCAY8CCQCwkmSx8toh0jANBgkqhkiG9w0BAQUFADBNMQswCQYDVQQGEwJY
-WTEmMCQGA1UECgwdUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24gQ0ExFjAUBgNV
-BAMMDW91ci1jYS1zZXJ2ZXIwHhcNMTMwMTA0MTk0NzA3WhcNMjIxMTEzMTk0NzA3
-WjBiMQswCQYDVQQGEwJYWTEXMBUGA1UEBxMOQ2FzdGxlIEFudGhyYXgxIzAhBgNV
-BAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMRUwEwYDVQQDEwxmYWtlaG9z
-dG5hbWUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAK5UQiMI5VkNs2QvL7gU
-aiDdFevNUXRjU4DHAe3ZzzYLZNE69h9gO9VCSS16tJ5fT5VEu0EZyGr0e3V2NkX0
-ZoU0Hc/UaY4qx7LHmn5SYZpIxhJnkf7SyHJK1zUaGlU0/LxYqIuGCtF5dqx1L2OQ
-hEx1GM6RydHdgX69G64LXcY5AgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAK1Fio7v
-xu8EQVwsSoTcAnYM0GYP8BYEWE39aLe406hBpVw8b2U80fjOQzXnQV9TPcksw338
-Vkr6R3c4nbuXKAo7kRl/vHSuFWu9IDZnRaUeedd15olcbVSE0ZXXp7QzPK83xHmP
-XnXcdcIY+2FvLdw4ZVu6ZyjQiNeNuSNajujGu9vO1bhBKs6TCLaVrTQgGNU7N1J0
-UAsHLLBtpEx79OD90a8XqiDNYuPwnTdp20G91Bz7UyDaiJ12JmfOAZCngB2pWzlz
-aFQK0SoDG488Q11dxFHxp+cR2jEsSQavBPS4PJnEILkGNqIAkmEdDG0kBeKC4Ufb
-oF+6ufu6+kkSHs4=
+MIIF9zCCBF+gAwIBAgIJAMstgJlaaVJdMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV
+BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW
+MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xODA4MjkxNDIzMTZaFw0yODA3MDcx
+NDIzMTZaMGIxCzAJBgNVBAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEj
+MCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24xFTATBgNVBAMMDGZh
+a2Vob3N0bmFtZTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAMaOmIfO
+ruCHGExnOudGwYEL9ybDwREQh1uqWvP+XwEVpZ6Km87kdv8zJTzGzbMtSuoivYk1
+/4SKLxibhtiZlyUWtriOiZqJKXFNk57d0xXybi8Crh5PaZJ9lkLX5cC62p3PtaEf
+GExUSbcDJNa9MLeoJueVtflUihBTAWuxJaoOIfJoZ0reus5MoVQozxg+Kr8FmSbo
+Dh6IVyLnB39I8P7DSkixxltBbUxSvluzni7KVZpSa18jwom3oENlD+4DTpzqLzre
+xIIQjouCr7DKKR4kY0zFkx+C7d3N+/gGJkFBfRmGJG+qx4NJ09y5VrYh9voIWWDb
+3yd7B5jgQAgTU766qjmHwUXVpQ4xmlARm7Oyn1H9MAwEdfViZWMb+RF0F5od7fCH
+MHU9+548hfZlMyYs1htht+ebGGTWefxoC+hP3yk3DzLf/aTYo2y7bif25KSTECio
+nX1YrCaYvwykkoDMu/jm1G+E35Au2dF274sn2bb2elAcWZgtt2pF+aJ2cwIDAQAB
+o4IBwzCCAb8wFwYDVR0RBBAwDoIMZmFrZWhvc3RuYW1lMA4GA1UdDwEB/wQEAwIF
+oDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAd
+BgNVHQ4EFgQUUuCTqlJVt7vnqOCM3kEu9AfwNvswfQYDVR0jBHYwdIAU3b/K2ubR
+NLo3dSHKb5oIKPI1tkihUaRPME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQKDB1QeXRo
+b24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNhLXNlcnZl
+coIJAMstgJlaaVJbMIGDBggrBgEFBQcBAQR3MHUwPAYIKwYBBQUHMAKGMGh0dHA6
+Ly90ZXN0Y2EucHl0aG9udGVzdC5uZXQvdGVzdGNhL3B5Y2FjZXJ0LmNlcjA1Bggr
+BgEFBQcwAYYpaHR0cDovL3Rlc3RjYS5weXRob250ZXN0Lm5ldC90ZXN0Y2Evb2Nz
+cC8wQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL3Rlc3RjYS5weXRob250ZXN0Lm5l
+dC90ZXN0Y2EvcmV2b2NhdGlvbi5jcmwwDQYJKoZIhvcNAQELBQADggGBACnSP4I/
+wTg1pr2BEP5k7P9+4cZvf4Zl+TFv++8yTi+HyELebI24BgiPN3CVfeFA1IIrjbNK
+/TTFnt//AVNKTwj0WOF0/HjjPnGnXmYH6tIEMeJ1qEyAF4aSINIyp5plixpf8UzI
+UG0A/Jm/abNI80Va7jVQFLjzkpLGnw5d6w3o7PKkCWvcZiv830z8ZaGu07WIaqTn
+CByUSeC4wQSMIQlsVUsslxDxjGzQu7qNk+hHi02OfX2FUxjI+PSPZzqxqj4YNGw6
+5qbHL76DOPXV5dIXKGFstkmZIWmkqLaUdv0YrTVSRWT78V2Ou8AhLllVJK+7j7IK
+exfwNJeOaKny0D72c4L4fE6acH3Ws4zMhQRcAo902og6IKh+wp6w3VYfzs1CFsYU
+ka0w4Nx28ixW6jhF2MA+uJD68ziZ7EQHNY9pYgz577ed5RVCbvv+TP/olFoasICy
+Dhc94YeoCISTdGiNKd/KC2pEMopRO9Y4273jKhteIEiBghmRxoeMD81R6g==
-----END CERTIFICATE-----
help='if a test file alters the environment, mark '
'the test as failed')
+ group.add_argument('--junit-xml', dest='xmlpath', metavar='FILENAME',
+ help='writes JUnit-style XML results to the specified '
+ 'file')
+
return parser
self.next_single_test = None
self.next_single_filename = None
+ # used by --junit-xml
+ self.testsuite_xml = None
+
def accumulate_result(self, test, result):
- ok, test_time = result
+ ok, test_time, xml_data = result
if ok not in (CHILD_ERROR, INTERRUPTED):
self.test_times.append((test_time, test))
if ok == PASSED:
elif ok != INTERRUPTED:
raise ValueError("invalid test result: %r" % ok)
+ if xml_data:
+ import xml.etree.ElementTree as ET
+ for e in xml_data:
+ try:
+ self.testsuite_xml.append(ET.fromstring(e))
+ except ET.ParseError:
+ print(xml_data, file=sys.__stderr__)
+ raise
+
def display_progress(self, test_index, test):
if self.ns.quiet:
return
file=sys.stderr)
ns.findleaks = False
+ if ns.xmlpath:
+ support.junit_xml_list = self.testsuite_xml = []
+
# Strip .py extensions.
removepy(ns.args)
result = runtest(self.ns, test)
except KeyboardInterrupt:
self.interrupted = True
- self.accumulate_result(test, (INTERRUPTED, None))
+ self.accumulate_result(test, (INTERRUPTED, None, None))
break
else:
self.accumulate_result(test, result)
or self.tests or self.ns.args)):
self.display_header()
+ if self.ns.huntrleaks:
+ warmup, repetitions, _ = self.ns.huntrleaks
+ if warmup < 3:
+ msg = ("WARNING: Running tests with --huntrleaks/-R and less than "
+ "3 warmup repetitions can give false positives!")
+ print(msg, file=sys.stdout, flush=True)
+
if self.ns.randomize:
print("Using random seed", self.ns.random_seed)
if self.ns.runleaks:
os.system("leaks %d" % os.getpid())
+ def save_xml_result(self):
+ if not self.ns.xmlpath and not self.testsuite_xml:
+ return
+
+ import xml.etree.ElementTree as ET
+ root = ET.Element("testsuites")
+
+ # Manually count the totals for the overall summary
+ totals = {'tests': 0, 'errors': 0, 'failures': 0}
+ for suite in self.testsuite_xml:
+ root.append(suite)
+ for k in totals:
+ try:
+ totals[k] += int(suite.get(k, 0))
+ except ValueError:
+ pass
+
+ for k, v in totals.items():
+ root.set(k, str(v))
+
+ xmlpath = os.path.join(support.SAVEDCWD, self.ns.xmlpath)
+ with open(xmlpath, 'wb') as f:
+ for s in ET.tostringlist(root):
+ f.write(s)
+
def main(self, tests=None, **kwargs):
global TEMPDIR
def _main(self, tests, kwargs):
self.ns = self.parse_args(kwargs)
+ if self.ns.huntrleaks:
+ warmup, repetitions, _ = self.ns.huntrleaks
+ if warmup < 1 or repetitions < 1:
+ msg = ("Invalid values for the --huntrleaks/-R parameters. The "
+ "number of warmups and repetitions must be at least 1 "
+ "each (1:1).")
+ print(msg, file=sys.stderr, flush=True)
+ sys.exit(2)
+
if self.ns.slaveargs is not None:
from test.libregrtest.runtest_mp import run_tests_slave
run_tests_slave(self.ns.slaveargs)
self.rerun_failed_tests()
self.finalize()
+
+ self.save_xml_result()
+
if self.bad:
sys.exit(2)
if self.interrupted:
ns -- regrtest namespace of options
test -- the name of the test
- Returns the tuple (result, test_time), where result is one of the
- constants:
+ Returns the tuple (result, test_time, xml_data), where result is one
+ of the constants:
INTERRUPTED KeyboardInterrupt when run under -j
RESOURCE_DENIED test skipped because resource denied
ENV_CHANGED test failed because it changed the execution environment
FAILED test failed
PASSED test passed
+
+ If ns.xmlpath is not None, xml_data is a list containing each
+ generated testsuite element.
"""
output_on_failure = ns.verbose3
# reset the environment_altered flag to detect if a test altered
# the environment
support.environment_altered = False
+ support.junit_xml_list = xml_list = [] if ns.xmlpath else None
if ns.failfast:
support.failfast = True
if output_on_failure:
support.verbose = True
- # Reuse the same instance to all calls to runtest(). Some
- # tests keep a reference to sys.stdout or sys.stderr
- # (eg. test_argparse).
- if runtest.stringio is None:
- stream = io.StringIO()
- runtest.stringio = stream
- else:
- stream = runtest.stringio
- stream.seek(0)
- stream.truncate()
-
+ stream = io.StringIO()
orig_stdout = sys.stdout
orig_stderr = sys.stderr
try:
else:
support.verbose = ns.verbose # Tell tests to be moderately quiet
result = runtest_inner(ns, test, display_failure=not ns.verbose)
- return result
+
+ if xml_list:
+ import xml.etree.ElementTree as ET
+ xml_data = [ET.tostring(x).decode('us-ascii') for x in xml_list]
+ else:
+ xml_data = None
+ return result + (xml_data,)
finally:
if use_timeout:
faulthandler.cancel_dump_traceback_later()
cleanup_test_droppings(test, ns.verbose)
-runtest.stringio = None
+ support.junit_xml_list = None
def post_test_cleanup():
if loader.errors:
raise Exception("errors while loading tests")
support.run_unittest(tests)
- test_runner()
if ns.huntrleaks:
refleak = dash_R(the_module, test, test_runner, ns.huntrleaks)
+ else:
+ test_runner()
test_time = time.time() - start_time
post_test_cleanup()
except support.ResourceDenied as msg:
try:
result = runtest(ns, testname)
except KeyboardInterrupt:
- result = INTERRUPTED, ''
+ result = INTERRUPTED, '', None
except BaseException as e:
traceback.print_exc()
result = CHILD_ERROR, str(e)
self.current_test = None
if retcode != 0:
- result = (CHILD_ERROR, "Exit code %s" % retcode)
+ result = (CHILD_ERROR, "Exit code %s" % retcode, None)
self.output.put((test, stdout.rstrip(), stderr.rstrip(),
result))
return False
return True
result = json.loads(result)
+ assert len(result) == 3, f"Invalid result tuple: {result!r}"
self.output.put((test, stdout.rstrip(), stderr.rstrip(),
result))
return False
regrtest.accumulate_result(test, result)
# Display progress
- ok, test_time = result
+ ok, test_time, xml_data = result
text = format_test_result(test, ok)
if (ok not in (CHILD_ERROR, INTERRUPTED)
and test_time >= PROGRESS_MIN_TIME
and not regrtest.ns.pgo):
- text += ' (%.0f sec)' % test_time
+ text += ' (%s)' % format_duration(test_time)
elif ok == CHILD_ERROR:
text = '%s (%s)' % (text, test_time)
running = get_running(workers)
import os.path
+import math
import textwrap
def format_duration(seconds):
- if seconds < 1.0:
- return '%.0f ms' % (seconds * 1e3)
- if seconds < 60.0:
- return '%.0f sec' % seconds
+ ms = math.ceil(seconds * 1e3)
+ seconds, ms = divmod(ms, 1000)
+ minutes, seconds = divmod(seconds, 60)
+ hours, minutes = divmod(minutes, 60)
- minutes, seconds = divmod(seconds, 60.0)
- hours, minutes = divmod(minutes, 60.0)
+ parts = []
if hours:
- return '%.0f hour %.0f min' % (hours, minutes)
- else:
- return '%.0f min %.0f sec' % (minutes, seconds)
+ parts.append('%s hour' % hours)
+ if minutes:
+ parts.append('%s min' % minutes)
+ if seconds:
+ parts.append('%s sec' % seconds)
+ if ms:
+ parts.append('%s ms' % ms)
+ if not parts:
+ return '0 ms'
+
+ parts = parts[:2]
+ return ' '.join(parts)
def removepy(names):
# cleared before the waiting thread is woken up.
evt = self.eventtype()
results = []
+ timeout = 0.250
N = 5
def f():
- results.append(evt.wait(1))
+ results.append(evt.wait(timeout * 4))
b = Bunch(f, N)
b.wait_for_started()
- time.sleep(0.5)
+ time.sleep(timeout)
evt.set()
evt.clear()
b.wait_for_finished()
and friends."""
import os
+import pprint
import shutil
import tempfile
from subprocess import *
req_template = """
+ [ default ]
+ base_url = http://testca.pythontest.net/testca
+
[req]
distinguished_name = req_distinguished_name
- x509_extensions = req_x509_extensions
prompt = no
[req_distinguished_name]
O = Python Software Foundation
CN = {hostname}
- [req_x509_extensions]
+ [req_x509_extensions_simple]
+ subjectAltName = @san
+
+ [req_x509_extensions_full]
subjectAltName = @san
+ keyUsage = critical,keyEncipherment,digitalSignature
+ extendedKeyUsage = serverAuth,clientAuth
+ basicConstraints = critical,CA:false
+ subjectKeyIdentifier = hash
+ authorityKeyIdentifier = keyid:always,issuer:always
+ authorityInfoAccess = @issuer_ocsp_info
+ crlDistributionPoints = @crl_info
+
+ [ issuer_ocsp_info ]
+ caIssuers;URI.0 = $base_url/pycacert.cer
+ OCSP;URI.0 = $base_url/ocsp/
+
+ [ crl_info ]
+ URI.0 = $base_url/revocation.crl
[san]
DNS.1 = {hostname}
dir = cadir
database = $dir/index.txt
crlnumber = $dir/crl.txt
- default_md = sha1
+ default_md = sha256
default_days = 3600
default_crl_days = 3600
certificate = pycacert.pem
private_key = pycakey.pem
serial = $dir/serial
RANDFILE = $dir/.rand
-
policy = policy_match
[ policy_match ]
here = os.path.abspath(os.path.dirname(__file__))
-def make_cert_key(hostname, sign=False, extra_san=''):
+
+def make_cert_key(hostname, sign=False, extra_san='',
+ ext='req_x509_extensions_full', key='rsa:3072'):
print("creating cert for " + hostname)
tempnames = []
for i in range(3):
with open(req_file, 'w') as f:
f.write(req)
args = ['req', '-new', '-days', '3650', '-nodes',
- '-newkey', 'rsa:1024', '-keyout', key_file,
+ '-newkey', key, '-keyout', key_file,
+ '-extensions', ext,
'-config', req_file]
if sign:
with tempfile.NamedTemporaryFile(delete=False) as f:
check_call(['openssl'] + args)
if sign:
- args = ['ca', '-config', req_file, '-out', cert_file, '-outdir', 'cadir',
- '-policy', 'policy_anything', '-batch', '-infiles', reqfile ]
+ args = [
+ 'ca',
+ '-config', req_file,
+ '-extensions', ext,
+ '-out', cert_file,
+ '-outdir', 'cadir',
+ '-policy', 'policy_anything',
+ '-batch', '-infiles', reqfile
+ ]
check_call(['openssl'] + args)
t.flush()
with tempfile.NamedTemporaryFile() as f:
args = ['req', '-new', '-days', '3650', '-extensions', 'v3_ca', '-nodes',
- '-newkey', 'rsa:2048', '-keyout', 'pycakey.pem',
+ '-newkey', 'rsa:3072', '-keyout', 'pycakey.pem',
'-out', f.name,
'-subj', '/C=XY/L=Castle Anthrax/O=Python Software Foundation CA/CN=our-ca-server']
check_call(['openssl'] + args)
args = ['ca', '-config', t.name, '-gencrl', '-out', 'revocation.crl']
check_call(['openssl'] + args)
+ # capath hashes depend on subject!
+ check_call([
+ 'openssl', 'x509', '-in', 'pycacert.pem', '-out', 'capath/ceff1710.0'
+ ])
+ shutil.copy('capath/ceff1710.0', 'capath/b1930218.0')
+
+
+def print_cert(path):
+ import _ssl
+ pprint.pprint(_ssl._test_decode_cert(path))
+
+
if __name__ == '__main__':
os.chdir(here)
- cert, key = make_cert_key('localhost')
+ cert, key = make_cert_key('localhost', ext='req_x509_extensions_simple')
with open('ssl_cert.pem', 'w') as f:
f.write(cert)
with open('ssl_key.pem', 'w') as f:
# For certificate matching tests
make_ca()
- cert, key = make_cert_key('fakehostname')
+ cert, key = make_cert_key('fakehostname', ext='req_x509_extensions_simple')
with open('keycert2.pem', 'w') as f:
f.write(key)
f.write(cert)
f.write(key)
f.write(cert)
+ cert, key = make_cert_key(
+ 'localhost-ecc', True, key='param:secp384r1.pem'
+ )
+ with open('keycertecc.pem', 'w') as f:
+ f.write(key)
+ f.write(cert)
+
extra_san = [
'otherName.1 = 1.2.3.4;UTF8:some other identifier',
'otherName.2 = 1.3.6.1.5.2.2;SEQUENCE:princ_name',
f.write(key)
f.write(cert)
+ extra_san = [
+ # könig (king)
+ 'DNS.2 = xn--knig-5qa.idn.pythontest.net',
+ # königsgäßchen (king's alleyway)
+ 'DNS.3 = xn--knigsgsschen-lcb0w.idna2003.pythontest.net',
+ 'DNS.4 = xn--knigsgchen-b4a3dun.idna2008.pythontest.net',
+ # βόλοσ (marble)
+ 'DNS.5 = xn--nxasmq6b.idna2003.pythontest.net',
+ 'DNS.6 = xn--nxasmm1c.idna2008.pythontest.net',
+ ]
+
+ # IDN SANS, signed
+ cert, key = make_cert_key('idnsans', True, extra_san='\n'.join(extra_san))
+ with open('idnsans.pem', 'w') as f:
+ f.write(key)
+ f.write(cert)
+
unmake_ca()
- print("\n\nPlease change the values in test_ssl.py, test_parse_cert function related to notAfter,notBefore and serialNumber")
- check_call(['openssl','x509','-in','keycert.pem','-dates','-serial','-noout'])
+ print("update Lib/test/test_ssl.py and Lib/test/test_asyncio/util.py")
+ print_cert('keycert.pem')
+ print_cert('keycert3.pem')
Certificate:
Data:
Version: 3 (0x2)
- Serial Number: 12723342612721443280 (0xb09264b1f2da21d0)
- Signature Algorithm: sha1WithRSAEncryption
+ Serial Number:
+ cb:2d:80:99:5a:69:52:5b
+ Signature Algorithm: sha256WithRSAEncryption
Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server
Validity
- Not Before: Jan 4 19:47:07 2013 GMT
- Not After : Jan 2 19:47:07 2023 GMT
+ Not Before: Aug 29 14:23:16 2018 GMT
+ Not After : Aug 26 14:23:16 2028 GMT
Subject: C=XY, O=Python Software Foundation CA, CN=our-ca-server
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
+ Public-Key: (3072 bit)
Modulus:
- 00:e7:de:e9:e3:0c:9f:00:b6:a1:fd:2b:5b:96:d2:
- 6f:cc:e0:be:86:b9:20:5e:ec:03:7a:55:ab:ea:a4:
- e9:f9:49:85:d2:66:d5:ed:c7:7a:ea:56:8e:2d:8f:
- e7:42:e2:62:28:a9:9f:d6:1b:8e:eb:b5:b4:9c:9f:
- 14:ab:df:e6:94:8b:76:1d:3e:6d:24:61:ed:0c:bf:
- 00:8a:61:0c:df:5c:c8:36:73:16:00:cd:47:ba:6d:
- a4:a4:74:88:83:23:0a:19:fc:09:a7:3c:4a:4b:d3:
- e7:1d:2d:e4:ea:4c:54:21:f3:26:db:89:37:18:d4:
- 02:bb:40:32:5f:a4:ff:2d:1c:f7:d4:bb:ec:8e:cf:
- 5c:82:ac:e6:7c:08:6c:48:85:61:07:7f:25:e0:5c:
- e0:bc:34:5f:e0:b9:04:47:75:c8:47:0b:8d:bc:d6:
- c8:68:5f:33:83:62:d2:20:44:35:b1:ad:81:1a:8a:
- cd:bc:35:b0:5c:8b:47:d6:18:e9:9c:18:97:cc:01:
- 3c:29:cc:e8:1e:e4:e4:c1:b8:de:e7:c2:11:18:87:
- 5a:93:34:d8:a6:25:f7:14:71:eb:e4:21:a2:d2:0f:
- 2e:2e:d4:62:00:35:d3:d6:ef:5c:60:4b:4c:a9:14:
- e2:dd:15:58:46:37:33:26:b7:e7:2e:5d:ed:42:e4:
- c5:4d
+ 00:97:ed:55:41:ba:36:17:95:db:71:1c:d3:e1:61:
+ ac:58:73:e3:c6:96:cf:2b:1f:b8:08:f5:9d:4b:4b:
+ c7:30:f6:b8:0b:b3:52:72:a0:bb:c9:4d:3b:8e:df:
+ 22:8e:01:57:81:c9:92:73:cc:00:c6:ec:70:b0:3a:
+ 17:40:c1:df:f2:8c:36:4c:c4:a7:81:e7:b6:24:68:
+ e2:a0:7e:35:07:2f:a0:5b:f9:45:46:f7:1e:f0:46:
+ 11:fe:ca:1a:3c:50:f1:26:a9:5f:9c:22:9c:f8:41:
+ e1:df:4f:12:95:19:2f:5c:90:01:17:6e:7e:3e:7d:
+ cf:e9:09:af:25:f8:f8:42:77:2d:6d:5f:36:f2:78:
+ 1e:7d:4a:87:68:63:6c:06:71:1b:8d:fa:25:fe:d4:
+ d3:f5:a5:17:b1:ef:ea:17:cb:54:c8:27:99:80:cb:
+ 3c:45:f1:2c:52:1c:dd:1f:51:45:20:50:1e:5e:ab:
+ 57:73:1b:41:78:96:de:84:a4:7a:dd:8f:30:85:36:
+ 58:79:76:a0:d2:61:c8:1b:a9:94:99:63:c6:ee:f8:
+ 14:bf:b4:52:56:31:97:fa:eb:ac:53:9e:95:ce:4c:
+ c4:5a:4a:b7:ca:03:27:5b:35:57:ce:02:dc:ec:ca:
+ 69:f8:8a:5a:39:cb:16:20:15:03:24:61:6c:f4:7a:
+ fc:b6:48:e5:59:10:5c:49:d0:23:9f:fb:71:5e:3a:
+ e9:68:9f:34:72:80:27:b6:3f:4c:b1:d9:db:63:7f:
+ 67:68:4a:6e:11:f8:e8:c0:f4:5a:16:39:53:0b:68:
+ de:77:fa:45:e7:f8:91:cd:78:cd:28:94:97:71:54:
+ fb:cf:f0:37:de:c9:26:c5:dc:1b:9e:89:6d:09:ac:
+ c8:44:71:cb:6d:f1:97:31:d5:4c:20:33:bf:75:4a:
+ a0:e0:dc:69:11:ed:2a:b4:64:10:11:30:8b:0e:b0:
+ a7:10:d8:8a:c5:aa:1b:c8:26:8a:25:e7:66:9f:a5:
+ 6a:1a:2f:7c:5f:83:c6:78:4f:1f
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- BC:DD:62:D9:76:DA:1B:D2:54:6B:CF:E0:66:9B:1E:1E:7B:56:0C:0B
+ DD:BF:CA:DA:E6:D1:34:BA:37:75:21:CA:6F:9A:08:28:F2:35:B6:48
X509v3 Authority Key Identifier:
- keyid:BC:DD:62:D9:76:DA:1B:D2:54:6B:CF:E0:66:9B:1E:1E:7B:56:0C:0B
+ keyid:DD:BF:CA:DA:E6:D1:34:BA:37:75:21:CA:6F:9A:08:28:F2:35:B6:48
X509v3 Basic Constraints:
CA:TRUE
- Signature Algorithm: sha1WithRSAEncryption
- 7d:0a:f5:cb:8d:d3:5d:bd:99:8e:f8:2b:0f:ba:eb:c2:d9:a6:
- 27:4f:2e:7b:2f:0e:64:d8:1c:35:50:4e:ee:fc:90:b9:8d:6d:
- a8:c5:c6:06:b0:af:f3:2d:bf:3b:b8:42:07:dd:18:7d:6d:95:
- 54:57:85:18:60:47:2f:eb:78:1b:f9:e8:17:fd:5a:0d:87:17:
- 28:ac:4c:6a:e6:bc:29:f4:f4:55:70:29:42:de:85:ea:ab:6c:
- 23:06:64:30:75:02:8e:53:bc:5e:01:33:37:cc:1e:cd:b8:a4:
- fd:ca:e4:5f:65:3b:83:1c:86:f1:55:02:a0:3a:8f:db:91:b7:
- 40:14:b4:e7:8d:d2:ee:73:ba:e3:e5:34:2d:bc:94:6f:4e:24:
- 06:f7:5f:8b:0e:a7:8e:6b:de:5e:75:f4:32:9a:50:b1:44:33:
- 9a:d0:05:e2:78:82:ff:db:da:8a:63:eb:a9:dd:d1:bf:a0:61:
- ad:e3:9e:8a:24:5d:62:0e:e7:4c:91:7f:ef:df:34:36:3b:2f:
- 5d:f5:84:b2:2f:c4:6d:93:96:1a:6f:30:28:f1:da:12:9a:64:
- b4:40:33:1d:bd:de:2b:53:a8:ea:be:d6:bc:4e:96:f5:44:fb:
- 32:18:ae:d5:1f:f6:69:af:b6:4e:7b:1d:58:ec:3b:a9:53:a3:
- 5e:58:c8:9e
+ Signature Algorithm: sha256WithRSAEncryption
+ 33:6a:54:d3:6b:c0:d7:01:5f:9d:f4:05:c1:93:66:90:50:d0:
+ b7:18:e9:b0:1e:4a:a0:b6:da:76:93:af:84:db:ad:15:54:31:
+ 15:13:e4:de:7e:4e:0c:d5:09:1c:34:35:b6:e5:4c:d6:6f:65:
+ 7d:32:5f:eb:fc:a9:6b:07:f7:49:82:e5:81:7e:07:80:9a:63:
+ f8:2c:c3:40:bc:8f:d4:2a:da:3e:d1:ee:08:b7:4d:a7:84:ca:
+ f4:3f:a1:98:45:be:b1:05:69:e7:df:d7:99:ab:1b:ee:8b:30:
+ cc:f7:fc:e7:d4:0b:17:ae:97:bf:e4:7b:fd:0f:a7:b4:85:79:
+ e3:59:e2:16:87:bf:1f:29:45:2c:23:93:76:be:c0:87:1d:de:
+ ec:2b:42:6a:e5:bb:c8:f4:0a:4a:08:0a:8c:5c:d8:7d:4d:d1:
+ b8:bf:d5:f7:29:ed:92:d1:94:04:e8:35:06:57:7f:2c:23:97:
+ 87:a5:35:8d:26:d3:1a:47:f2:16:d7:d9:c6:d4:1f:23:43:d3:
+ 26:99:39:ca:20:f4:71:23:6f:0c:4a:76:76:f7:76:1f:b3:fe:
+ bf:47:b0:fc:2a:56:81:e1:d2:dd:ee:08:d8:f4:ff:5a:dc:25:
+ 61:8a:91:02:b9:86:1c:f2:50:73:76:25:35:fc:b6:25:26:15:
+ cb:eb:c4:2b:61:0c:1c:e7:ee:2f:17:9b:ec:f0:d4:a1:84:e7:
+ d2:af:de:e4:1b:24:14:a7:01:87:e3:ab:29:58:46:a0:d9:c0:
+ 0a:e0:8d:d7:59:d3:1b:f8:54:20:3e:78:a5:a5:c8:4f:8b:03:
+ c4:96:9f:ec:fb:47:cf:76:2d:8d:65:34:27:bf:fa:ae:01:05:
+ 8a:f3:92:0a:dd:89:6c:97:a1:c7:e7:60:51:e7:ac:eb:4b:7d:
+ 2c:b8:65:c9:fe:5d:6a:48:55:8e:e4:c7:f9:6a:40:e1:b8:64:
+ 45:e9:b5:59:29:a5:5f:cf:7d:58:7d:64:79:e5:a4:09:ac:1e:
+ 76:65:3d:94:c4:68
-----BEGIN CERTIFICATE-----
-MIIDbTCCAlWgAwIBAgIJALCSZLHy2iHQMA0GCSqGSIb3DQEBBQUAME0xCzAJBgNV
+MIIEbTCCAtWgAwIBAgIJAMstgJlaaVJbMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV
BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW
-MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xMzAxMDQxOTQ3MDdaFw0yMzAxMDIx
-OTQ3MDdaME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUg
-Rm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNhLXNlcnZlcjCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBAOfe6eMMnwC2of0rW5bSb8zgvoa5IF7sA3pV
-q+qk6flJhdJm1e3HeupWji2P50LiYiipn9Ybjuu1tJyfFKvf5pSLdh0+bSRh7Qy/
-AIphDN9cyDZzFgDNR7ptpKR0iIMjChn8Cac8SkvT5x0t5OpMVCHzJtuJNxjUArtA
-Ml+k/y0c99S77I7PXIKs5nwIbEiFYQd/JeBc4Lw0X+C5BEd1yEcLjbzWyGhfM4Ni
-0iBENbGtgRqKzbw1sFyLR9YY6ZwYl8wBPCnM6B7k5MG43ufCERiHWpM02KYl9xRx
-6+QhotIPLi7UYgA109bvXGBLTKkU4t0VWEY3Mya35y5d7ULkxU0CAwEAAaNQME4w
-HQYDVR0OBBYEFLzdYtl22hvSVGvP4GabHh57VgwLMB8GA1UdIwQYMBaAFLzdYtl2
-2hvSVGvP4GabHh57VgwLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB
-AH0K9cuN0129mY74Kw+668LZpidPLnsvDmTYHDVQTu78kLmNbajFxgawr/Mtvzu4
-QgfdGH1tlVRXhRhgRy/reBv56Bf9Wg2HFyisTGrmvCn09FVwKULeheqrbCMGZDB1
-Ao5TvF4BMzfMHs24pP3K5F9lO4MchvFVAqA6j9uRt0AUtOeN0u5zuuPlNC28lG9O
-JAb3X4sOp45r3l519DKaULFEM5rQBeJ4gv/b2opj66nd0b+gYa3jnookXWIO50yR
-f+/fNDY7L131hLIvxG2TlhpvMCjx2hKaZLRAMx293itTqOq+1rxOlvVE+zIYrtUf
-9mmvtk57HVjsO6lTo15YyJ4=
+MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xODA4MjkxNDIzMTZaFw0yODA4MjYx
+NDIzMTZaME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUg
+Rm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNhLXNlcnZlcjCCAaIwDQYJKoZI
+hvcNAQEBBQADggGPADCCAYoCggGBAJftVUG6NheV23Ec0+FhrFhz48aWzysfuAj1
+nUtLxzD2uAuzUnKgu8lNO47fIo4BV4HJknPMAMbscLA6F0DB3/KMNkzEp4HntiRo
+4qB+NQcvoFv5RUb3HvBGEf7KGjxQ8SapX5winPhB4d9PEpUZL1yQARdufj59z+kJ
+ryX4+EJ3LW1fNvJ4Hn1Kh2hjbAZxG436Jf7U0/WlF7Hv6hfLVMgnmYDLPEXxLFIc
+3R9RRSBQHl6rV3MbQXiW3oSket2PMIU2WHl2oNJhyBuplJljxu74FL+0UlYxl/rr
+rFOelc5MxFpKt8oDJ1s1V84C3OzKafiKWjnLFiAVAyRhbPR6/LZI5VkQXEnQI5/7
+cV466WifNHKAJ7Y/TLHZ22N/Z2hKbhH46MD0WhY5Uwto3nf6Ref4kc14zSiUl3FU
++8/wN97JJsXcG56JbQmsyERxy23xlzHVTCAzv3VKoODcaRHtKrRkEBEwiw6wpxDY
+isWqG8gmiiXnZp+lahovfF+DxnhPHwIDAQABo1AwTjAdBgNVHQ4EFgQU3b/K2ubR
+NLo3dSHKb5oIKPI1tkgwHwYDVR0jBBgwFoAU3b/K2ubRNLo3dSHKb5oIKPI1tkgw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAYEAM2pU02vA1wFfnfQFwZNm
+kFDQtxjpsB5KoLbadpOvhNutFVQxFRPk3n5ODNUJHDQ1tuVM1m9lfTJf6/ypawf3
+SYLlgX4HgJpj+CzDQLyP1CraPtHuCLdNp4TK9D+hmEW+sQVp59/Xmasb7oswzPf8
+59QLF66Xv+R7/Q+ntIV541niFoe/HylFLCOTdr7Ahx3e7CtCauW7yPQKSggKjFzY
+fU3RuL/V9yntktGUBOg1Bld/LCOXh6U1jSbTGkfyFtfZxtQfI0PTJpk5yiD0cSNv
+DEp2dvd2H7P+v0ew/CpWgeHS3e4I2PT/WtwlYYqRArmGHPJQc3YlNfy2JSYVy+vE
+K2EMHOfuLxeb7PDUoYTn0q/e5BskFKcBh+OrKVhGoNnACuCN11nTG/hUID54paXI
+T4sDxJaf7PtHz3YtjWU0J7/6rgEFivOSCt2JbJehx+dgUees60t9LLhlyf5dakhV
+juTH+WpA4bhkRem1WSmlX899WH1keeWkCawedmU9lMRo
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDn3unjDJ8AtqH9
-K1uW0m/M4L6GuSBe7AN6VavqpOn5SYXSZtXtx3rqVo4tj+dC4mIoqZ/WG47rtbSc
-nxSr3+aUi3YdPm0kYe0MvwCKYQzfXMg2cxYAzUe6baSkdIiDIwoZ/AmnPEpL0+cd
-LeTqTFQh8ybbiTcY1AK7QDJfpP8tHPfUu+yOz1yCrOZ8CGxIhWEHfyXgXOC8NF/g
-uQRHdchHC4281shoXzODYtIgRDWxrYEais28NbBci0fWGOmcGJfMATwpzOge5OTB
-uN7nwhEYh1qTNNimJfcUcevkIaLSDy4u1GIANdPW71xgS0ypFOLdFVhGNzMmt+cu
-Xe1C5MVNAgMBAAECggEBAJPM7QuUrPn4cLN/Ysd15lwTWn9oHDFFgkYFvCs66gXE
-ju/6Kx2BjWE4wTJby09AHM/MqB0DvguT7Mf1Q2j3tPQ1HZowg8OwRDleuwp6KIls
-jBbhL0Jdl/5HC67ktWvZ9wNvO/wFG1rQfT6FVajf9LUbWEaSZbOG2SLhHfsHorzu
-xjTJaI3bQ/0+79B1exwk5ruwhzFRd/XpY8hls7D/RfPIuHDlBghkW3N59KFWrf5h
-6bNEh2THm0+IyGcGqs0FD+QCOXyvsjwSUswqrr2ctLREOeDcd5ReUjSxYgjcJRrm
-J7ceIY/+uwDJxw/OlnmBvF6pQMkKwYW2gFztu+g2t4UCgYEA/9yo01Exz4crxXsy
-tAlnDJM++nZcm07rtFjTKHUfKY/cCgNTa8udM0svnfwlid/dpgLsI38gx04HHC1i
-EZ4acz+ToIWedLxM0nq73//xeRWEazOvCz1mMTZaMldahTWAyzN8qVK2B/625Yy4
-wNYWyweBBwEB8MzaCs73spksXOsCgYEA5/7wvhiofYGFAfMuANeJIwDL2OtBnoOv
-mVNfCmi3GC38fzwyi5ZpskWDiS2woJ+LQfs9Qu4EcZbUFLd7gbeOvb5gmFUtYope
-LitUUKunIR18MkQ+mQDBpQPQPhk4QJP5reCbWkrfTu7b5o/iS41s6fBTFmuzhLcT
-C71vFdCyeKcCgYAiCCqYeOtELDmBOeLDmaCQRqGQ1N96dOPbCBmF/xYXBCCDYG/f
-HaUaJnz96YTgstsbcrYP/p/Qgqtlbw/lQf9IpwMuzbcG1ejt8g89OyDWNyt2ytgU
-iaUnFJCos3/Byh0Iah/BsdOueo2/OJl2ZMOBW80orlSgv86cs2y037TL4wKBgQDm
-OOyW+MlbowhnIvfoBfwlLEkefnej4nKD6WRLZBcue5Qyf355X06Mhsc9foXlH+6G
-D9h/bswiHNdhp6N82rdgPGiHQx/CxiUoE/+b/nvgNO5mw6qLE2EXbG1e8pAMJcyE
-bHw+YkawggDfELI036fRj5gki8SeUz8nS1nNgElbyQKBgCRDX9Jh+MwSLu4QBWdt
-/fi+lv3K6kun/fI7EOV1vCV/j871tICu7pu5BrOLxAHqoVfU9AUX299/2KjCb5pv
-kjogiUK6qWCWBlfuqDNWGCoUGt1rhznUva0nNjSMy5rinBhhjpROZC2pw48lOluP
-UuvXsaPph7GTqPuy4Kab12YC
+MIIG/AIBADANBgkqhkiG9w0BAQEFAASCBuYwggbiAgEAAoIBgQCX7VVBujYXldtx
+HNPhYaxYc+PGls8rH7gI9Z1LS8cw9rgLs1JyoLvJTTuO3yKOAVeByZJzzADG7HCw
+OhdAwd/yjDZMxKeB57YkaOKgfjUHL6Bb+UVG9x7wRhH+yho8UPEmqV+cIpz4QeHf
+TxKVGS9ckAEXbn4+fc/pCa8l+PhCdy1tXzbyeB59SodoY2wGcRuN+iX+1NP1pRex
+7+oXy1TIJ5mAyzxF8SxSHN0fUUUgUB5eq1dzG0F4lt6EpHrdjzCFNlh5dqDSYcgb
+qZSZY8bu+BS/tFJWMZf666xTnpXOTMRaSrfKAydbNVfOAtzsymn4ilo5yxYgFQMk
+YWz0evy2SOVZEFxJ0COf+3FeOulonzRygCe2P0yx2dtjf2doSm4R+OjA9FoWOVML
+aN53+kXn+JHNeM0olJdxVPvP8DfeySbF3BueiW0JrMhEcctt8Zcx1UwgM791SqDg
+3GkR7Sq0ZBARMIsOsKcQ2IrFqhvIJool52afpWoaL3xfg8Z4Tx8CAwEAAQKCAYB6
+1g1kwyYRE70FS4WUaOBr8+dqHW0LNO4bcFrpEi/PSuurqiUzQPoT3DoXXhoWLseN
+zGh476yBKZJDKfS7CwYCmZMdprK4uZvu/E6f7Or7EGrbckOtCQkew8iw9L8ZnWgd
+FjyThPjdUIdLgidIHcDJWjVHuLKh3B9KD+ZpEU/IjYtRLvbCPJSKQMQShrBE1Rau
+SF6IF5P4vK7X0162NlQqMLpQBAKLml93VJcERzVY1u53JJnkG1loIrNvE32zvZ0C
+ZnGVpWwamixVrO9K66F+Ml3Y3bkguF8aPUitc+l+yPmUSXmcDcKmhw9DZA0k5t39
+FxVYGn1uJlvHll8QvV9aZtzuTSkAN8VWNufGwivLLsoRlRb1LtGWqHY583FlUWtz
+99ABCBehZ2EpAP+MrRj+pyKuMrkQH61bbOhjqifBM8MhHdn9uNmMpvnKyGPMIdRY
+cLH4i2S5aQVvmsQbOa98DLOFGXdf+z5HuwdxHtG1S3J7jkT+FkIyYDehJA3X8UEC
+gcEAyCpD8rMFfR5qLwrajhy8vbV7TIkNfFHEkm9tCWDBHwuOJqA0DFuMDAKl7cMv
+Uo7Z6R2Fqe2OyWvxYkOi/CSjvtT+PTiA0ux1tXUZcxcRSIsLqQZV+elsKcv+QJPy
+vf02vNvHjaMaRwl+NYtqpfr1s/3EdJnWCNC3nV1dD+mWVJoO3kGAK5grLAPM1/uP
+stARN5Tnh3Doh8e1Yl4V4UKcVqyVqDykX1OLSmPqNH86T4Um0B4h+jf4UBBdDBz1
+rD3JAoHBAMJOZ3M7LqX+F2haSrF/hnG1y9qAqDWGsvy+8YgjFwPFWu7LvqLuXLuz
+S3+5GGhplMuM0itqA9PyPotlgtG5O9hAU8SyMitrx1uTW+Q2U3iYPZQ9O327l1cO
+F2jKljq0aJrXp+5iWUq8t/FG6DAqYYUCY/X1SheqEXCgCh4ldRhXig3TBYbVZNs9
+7azN0lk408AO/Hx7WYreFQVS7A/EJhk/M1yyIqnJESuxkDefjV4hTVkRXhh+MrCe
+vF/jHqh5pwKBwHxXPQRbzvINXbrBTEjxcxGJ1gESNg1fIfQxQZOMxgrJ+9DkvdBb
+YiDn2DldgV0Qni8ghrKrfoKDClyXVXy6KfnWh+Rx4BymhOxmxJto3fSpY2HpLKll
+JirErLli7my1CjbBdDH4+s7cB8mtRF+9CLp5znr8QSgSt60KnU/QM/F0Df5kxADQ
+syjRZ4NXoslaVQeo+TZ6nggSuAtWFNNstH9nEESE/zq0RBe+/3MDAa76MMUhosuz
+zw21TIfEyZvoeQKBwDpszNpvPzWWU3+DNtZsXAaw/Vz0Np/xorwwxfuDYZY2r4MC
+LI5dUfD2losPIvGyXZVfAIshU4lVW80adt2M7xu1K/sHAeLgg49bndPfKfYnAM0k
+JFFIKNd6WzudPtLkEFgO5GXfmK3KVRztjz98XtpZv6jjWqYG8zuEQ8aQyMbK+63w
+d8b1P2BVHLRLJybA2Zr0ZqMfi+sfn/570pNjDXml8VG8FoQq+0jCGXVAOofFR7ay
+bDK9L4zADjBe4IcUHQKBwFwj8TEVlWxtG+IWO5d+vyuP0OPjSYOmYq4dCMyZ2+Xy
+Y+XDYEhlgGTVxafRMTwt57VV3hJTtRxUZziDA++atr8+gPio+QHBYg1JgCKsqKYL
+TGoSVrM1jTfdl1orwkpgQmq2q5j7ExpNA3Spsm5kyCaJ1S/8Ivusqaod8S4t7UhW
+BRec3gQ+UYv/V3Pc9hS1Zdzf5+G+PDOYoNmveY16hcu0DKc/PlqGtJuBoQjjH7ir
+1YVK9GAgLk0VqJvePnF57A==
-----END PRIVATE KEY-----
info_add('platform.python_implementation',
platform.python_implementation())
info_add('platform.platform',
- platform.platform(aliased=True))
+ platform.platform(aliased=True, terse=True))
def collect_locale(info_add):
-----BEGIN X509 CRL-----
-MIIBpjCBjwIBATANBgkqhkiG9w0BAQUFADBNMQswCQYDVQQGEwJYWTEmMCQGA1UE
+MIICJjCBjwIBATANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQGEwJYWTEmMCQGA1UE
CgwdUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24gQ0ExFjAUBgNVBAMMDW91ci1j
-YS1zZXJ2ZXIXDTEzMTEyMTE3MDg0N1oXDTIzMDkzMDE3MDg0N1qgDjAMMAoGA1Ud
-FAQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQCNJXC2mVKauEeN3LlQ3ZtM5gkH3ExH
-+i4bmJjtJn497WwvvoIeUdrmVXgJQR93RtV37hZwN0SXMLlNmUZPH4rHhihayw4m
-unCzVj/OhCCY7/TPjKuJ1O/0XhaLBpBVjQN7R/1ujoRKbSia/CD3vcn7Fqxzw7LK
-fSRCKRGTj1CZiuxrphtFchwALXSiFDy9mr2ZKhImcyq1PydfgEzU78APpOkMQsIC
-UNJ/cf3c9emzf+dUtcMEcejQ3mynBo4eIGg1EW42bz4q4hSjzQlKcBV0muw5qXhc
-HOxH2iTFhQ7SrvVuK/dM14rYM4B5mSX3nRC1kNmXpS9j3wJDhuwmjHed
+YS1zZXJ2ZXIXDTE4MDgyOTE0MjMxNloXDTI4MDcwNzE0MjMxNlqgDjAMMAoGA1Ud
+FAQDAgEAMA0GCSqGSIb3DQEBCwUAA4IBgQCPhrtGSbuvxPAI3YWQFDB4iOWdBnVk
+ugW1lsifmCsE86FfID0EwUut1SRHlksltMtcoULMEIdu8yMLWci++4ve22EEuMKT
+HUc3T/wBIuQUhA7U4deFG8CZPAxRpNoK470y7dkD4OVf0Gxa6WYDl9z8mXKmWCB9
+hvzqVfLWNSLTAVPsHtkD5PXdi5yRkQr6wYD7poWaIvkpsn7EKCY6Tw5V3rsbRuZq
+AGVCq5TH3mctcmwLloCJ4Xr/1q0DsRrYxeeLYxE+UpvvCbVBKgtjBK7zINS7AbcJ
+CYCYKUwGWv1fYKJ+KQQHf75mT3jQ9lWuzOj/YWK4k1EBnYmVGuKKt73lLFxC6h3y
+MUnaBZc1KZSyJj0IxfHg/o6qx8NgKOl9XRIQ5g5B30cwpPOskGhEhodbTTY3bPtm
+RQ36JvQZngzmkhyhr+MDEV5yUTOShfUiclzQOx26CmLmLHWxOZgXtFZob/oKrvbm
+Gen/+7K7YTw6hfY52U7J2FuQRGOyzBXfBYQ=
-----END X509 CRL-----
-----BEGIN CERTIFICATE-----
-MIICVDCCAb2gAwIBAgIJANfHOBkZr8JOMA0GCSqGSIb3DQEBBQUAMF8xCzAJBgNV
-BAYTAlhZMRcwFQYDVQQHEw5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9u
-IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xMDEw
-MDgyMzAxNTZaFw0yMDEwMDUyMzAxNTZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH
-Ew5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9uIFNvZnR3YXJlIEZvdW5k
-YXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
-gYkCgYEA21vT5isq7F68amYuuNpSFlKDPrMUCa4YWYqZRt2OZ+/3NKaZ2xAiSwr7
-6MrQF70t5nLbSPpqE5+5VrS58SY+g/sXLiFd6AplH1wJZwh78DofbFYXUggktFMt
-pTyiX8jtP66bkcPkDADA089RI1TQR6Ca+n7HFa7c1fabVV6i3zkCAwEAAaMYMBYw
-FAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBBQUAA4GBAHPctQBEQ4wd
-BJ6+JcpIraopLn8BGhbjNWj40mmRqWB/NAWF6M5ne7KpGAu7tLeG4hb1zLaldK8G
-lxy2GPSRF6LFS48dpEj2HbMv2nvv6xxalDMJ9+DicWgAKTQ6bcX2j3GUkCR0g/T1
-CRlNBAAlvhKzO7Clpf9l0YKBEfraJByX
+MIIEWTCCAsGgAwIBAgIJAJinz4jHSjLtMA0GCSqGSIb3DQEBCwUAMF8xCzAJBgNV
+BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
+IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xODA4
+MjkxNDIzMTVaFw0yODA4MjYxNDIzMTVaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH
+DA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5k
+YXRpb24xEjAQBgNVBAMMCWxvY2FsaG9zdDCCAaIwDQYJKoZIhvcNAQEBBQADggGP
+ADCCAYoCggGBALKUqUtopT6E68kN+uJNEt34i2EbmG/bwjcD8IaMsgJPSsMO2Bpd
+3S6qWgkCeOyCfmAwBxK2kNbxGb63ouysEv7l8GCTJTWv3hG/HQcejJpnAEGi6K1U
+fDbyE/db6yZ12SoHVTGkadN4vYGCPd1Wj9ZO1F877SHQ8rDWX3xgTWkxN2ojBw44
+T8RHSDiG8D/CvG4uEy+VUszL+Uvny5y2poNSqvI3J56sptWSrh8nIIbkPZPBdUne
+LYMOHTFK3ZjXSmhlXgziTxK71nnzM3Y9K9gxPnRqoXbvu/wFo55hQCkETiRkYgmm
+jXcBMZ0TClQVnQWuLjMthRnWFZs4Lfmwqjs7FZD/61581R2BYehvpWbLvvuOJhwv
+DFzexL2sXcAl7SsxbzeQKRHqGbIDfbnQTXfs3/VC6Ye5P82P2ucj+XC32N9piRmO
+gCBP8L3ub+YzzdxikZN2gZXXE2jsb3QyE/R2LkWdWyshpKe+RsZP1SBRbHShUyOh
+yJ90baoiEwj2mwIDAQABoxgwFjAUBgNVHREEDTALgglsb2NhbGhvc3QwDQYJKoZI
+hvcNAQELBQADggGBAHRUO/UIHl3jXQENewYayHxkIx8t7nu40iO2DXbicSijz5bo
+5//xAB6RxhBAlsDBehgQP1uoZg+WJW+nHu3CIVOU3qZNZRaozxiCl2UFKcNqLOmx
+R3NKpo1jYf4REQIeG8Yw9+hSWLRbshNteP6bKUUf+vanhg9+axyOEOH/iOQvgk/m
+b8wA8wNa4ujWljPbTQnj7ry8RqhTM0GcAN5LSdSvcKcpzLcs3aYwh+Z8e30sQWna
+F40sa5u7izgBTOrwpcDm/w5kC46vpRQ5fnbshVw6pne2by0mdMECASid/p25N103
+jMqTFlmO7kpf/jpCSmamp3/JSEE1BJKHwQ6Ql4nzRA2N1mnvWH7Zxcv043gkHeAu
+0x8evpvwuhdIyproejNFlBpKmW8OX7yKTCPPMC/VkX8Q1rVkxU0DQ6hmvwZlhoKa
+9Wc2uXpw9xF8itV4Uvcdr3dwqByvIqn7iI/gB+4l41e0u8OmH2MKOx4Nxlly5TNW
+HcVKQHyOeyvnINuBAQ==
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
-DEK-Info: DES-EDE3-CBC,1A8D9D2A02EC698A
+DEK-Info: DES-EDE3-CBC,8064BE1494B24B13
-kJYbfZ8L0sfe9Oty3gw0aloNnY5E8fegRfQLZlNoxTl6jNt0nIwI8kDJ36CZgR9c
-u3FDJm/KqrfUoz8vW+qEnWhSG7QPX2wWGPHd4K94Yz/FgrRzZ0DoK7XxXq9gOtVA
-AVGQhnz32p+6WhfGsCr9ArXEwRZrTk/FvzEPaU5fHcoSkrNVAGX8IpSVkSDwEDQr
-Gv17+cfk99UV1OCza6yKHoFkTtrC+PZU71LomBabivS2Oc4B9hYuSR2hF01wTHP+
-YlWNagZOOVtNz4oKK9x9eNQpmfQXQvPPTfusexKIbKfZrMvJoxcm1gfcZ0H/wK6P
-6wmXSG35qMOOztCZNtperjs1wzEBXznyK8QmLcAJBjkfarABJX9vBEzZV0OUKhy+
-noORFwHTllphbmydLhu6ehLUZMHPhzAS5UN7srtpSN81eerDMy0RMUAwA7/PofX1
-94Me85Q8jP0PC9ETdsJcPqLzAPETEYu0ELewKRcrdyWi+tlLFrpE5KT/s5ecbl9l
-7B61U4Kfd1PIXc/siINhU3A3bYK+845YyUArUOnKf1kEox7p1RpD7yFqVT04lRTo
-cibNKATBusXSuBrp2G6GNuhWEOSafWCKJQAzgCYIp6ZTV2khhMUGppc/2H3CF6cO
-zX0KtlPVZC7hLkB6HT8SxYUwF1zqWY7+/XPPdc37MeEZ87Q3UuZwqORLY+Z0hpgt
-L5JXBCoklZhCAaN2GqwFLXtGiRSRFGY7xXIhbDTlE65Wv1WGGgDLMKGE1gOz3yAo
-2jjG1+yAHJUdE69XTFHSqSkvaloA1W03LdMXZ9VuQJ/ySXCie6ABAQ==
+KJrffOMbo8M0I3PzcYxRZGMpKD1yB3Ii4+bT5XoanxjIJ+4fdx6LfZ0Rsx+riyzs
+tymsQu/iYY9j+4rCvN9+eetsL1X6iZpiimKsLexcid9M3fb0vxED5Sgw0dvunCUA
+xhqjLIKR92MKbODHf6KrDKCpsiPbjq4gZ7P+uCGXAMHL3MXIJSC0hW9rK7Ce6oyO
+CjpIcgB8x+GUWZZZhAFdlzIHMZrteNP2P5HK6QcaT71P034Dz1hhqoj4Q0t+Fta2
+4tfsM/bnTR/l6hwlhPa1e3Uj322tDTDWBScgWANn5+sEWldLmozMaWhZsn22pfk2
+KjRMGXG024JVheV882nbdOBvG7oq+lxkZ/ZP+vvqJqnvYtf7WtM8UivzYpe5Hz5b
+kVvWzPjBLUSZ9whM9rDLqSSqMPyPvDTuEmLkuq+xm7pYJmsLqIMP2klZLqRxLX6K
+uqwplb8UG440qauxgnQ905PId1l2fJEnRtV+7vXprA0L0QotgXLVHBhLmTFM+3PH
+9H3onf31dionUAPrn3nfVE36HhvVgRyvDBnBzJSIMighgq21Qx/d1dk0DRYi1hUI
+nCHl0YJPXheVcXR7JiSF2XQCAaFuS1Mr7NCXfWZOZQC/0dkvmHnl9DUAhuqq9BNZ
+1cKhZXcKHadg2/r0Zup/oDzmHPUEfTAXT0xbqoWlhkdwbF2veWQ96A/ncx3ISTb4
+PkXBlX9rdia8nmtyQDQRn4NuvchbaGkj4WKFC8pF8Hn7naHqwjpHaDUimBc0CoQW
+edNJqruKWwtSVLuwKHCC2gZFX9AXSKJXJz/QRSUlhFGOhuF/J6yKaXj6n5lxWNiQ
+54J+OP/hz2aS95CD2+Zf1SKpxdWiLZSIQqESpmmUrXROixNJZ/Z7gI74Dd9dSJOH
+W+3AU03vrrFZVrJVZhjcINHoH1Skh6JKscH18L6x4U868nSr4SrRLX8BhHllOQyD
+bmU+PZAjF8ZBIaCtTGulDXD29F73MeAZeTSsgQjFu0iKLj1wPiphbx8i/SUtR4YP
+X6PVA04g66r1NBw+3RQASVorZ3g1MSFvITHXcbKkBDeJH2z1+c6t/VVyTONnQhM5
+lLgRSk6HCbetvT9PKxWrWutA12pdBYEHdZhMHVf2+xclky7l09w8hg2/qqcdGRGe
+oAOZ72t0l5ObNyaruDKUS6f4AjOyWq/Xj5xuFtf1n3tQHyslSyCTPcAbQhDfTHUx
+vixb/V9qvYPt7OCn8py7v1M69NH42QVFAvwveDIFjZdqfIKBoJK2V4qPoevJI6uj
+Q5ByMt8OXOjSXNpHXpYQWUiWeCwOEBXJX8rzCHdMtg37jJ0zCmeErR1NTdg+EujM
+TWYgd06jlT67tURST0aB2kg4ijKgUJefD313LW1zC6gVsTbjSZxYyRbPfSP6flQB
+yCi1C19E2OsgleqbkBVC5GlYUzaJT7SGjCRmGx1eqtbrALu+LVH24Wceexlpjydl
++s2nf/DZlKun/tlPh6YioifPCJjByZMQOCEfIox6BkemZETz8uYA4TTWimG13Z03
+gyDGC2jdpEW414J2qcQDvrdUgJ+HlhrAAHaWpMQDbXYxBGoZ+3+ORvQV4kAsCwL8
+k3EIrVpePdik+1xgOWsyLj6QxFXlTMvL6Wc5pnArFPORsgHEolJvxSPTf9aAHNPn
+V2WBvxiLBtYpGrujAUM40Syx/aN2RPtcXYPAusHUBw+S8/p+/8Kg8GZmnIXG3F89
+45Eepl2quZYIrou7a1fwIpIIZ0hFiBQ1mlHVMFtxwVHS1bQb3SU2GeO+JcGjdVXc
+04qeGuQ5M164eQ5C0T7ZQ1ULiUlFWKD30m+cjqmZzt3d7Q0mKpMKuESIuZJo/wpD
+Nas432aLKUhcNx/pOYLkKJRpGZKOupQoD5iUj/j44o8JoFkDK33v2S57XB5QGz28
+9Zuhx49b3W8mbM6EBanlQKLWJGCxXqc/jhYhFWn+b0MhidynFgA0oeWvf6ZDyt6H
+Yi5Etxsar09xp0Do3NxtQXLuSUu0ji2pQzSIKuoqQWKqldm6VrpwojiqJhy4WQBQ
+aVVyFeWBC7G3Zj76dO+yp2sfJ0itJUQ8AIB9Cg0f34rEZu+r9luPmqBoUeL95Tk7
+YvCOU3Jl8Iqysv8aNpVXT8sa8rrSbruWCByEePZ37RIdHLMVBwVY0eVaFQjrjU7E
+mXmM9eaoYLfXOllsQ+M2+qPFUITr/GU3Qig13DhK/+yC1R6V2a0l0WRhMltIPYKW
+Ztvvr4hK5LcYCeS113BLiMbDIMMZZYGDZGMdC8DnnVbT2loF0Rfmp80Af31KmMQ4
+6XvMatW9UDjBoY5a/YMpdm7SRwm+MgV2KNPpc2kST87/yi9oprGAb8qiarHiHTM0
-----END RSA PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
-MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANtb0+YrKuxevGpm
-LrjaUhZSgz6zFAmuGFmKmUbdjmfv9zSmmdsQIksK++jK0Be9LeZy20j6ahOfuVa0
-ufEmPoP7Fy4hXegKZR9cCWcIe/A6H2xWF1IIJLRTLaU8ol/I7T+um5HD5AwAwNPP
-USNU0Eegmvp+xxWu3NX2m1Veot85AgMBAAECgYA3ZdZ673X0oexFlq7AAmrutkHt
-CL7LvwrpOiaBjhyTxTeSNWzvtQBkIU8DOI0bIazA4UreAFffwtvEuPmonDb3F+Iq
-SMAu42XcGyVZEl+gHlTPU9XRX7nTOXVt+MlRRRxL6t9GkGfUAXI3XxJDXW3c0vBK
-UL9xqD8cORXOfE06rQJBAP8mEX1ERkR64Ptsoe4281vjTlNfIbs7NMPkUnrn9N/Y
-BLhjNIfQ3HFZG8BTMLfX7kCS9D593DW5tV4Z9BP/c6cCQQDcFzCcVArNh2JSywOQ
-ZfTfRbJg/Z5Lt9Fkngv1meeGNPgIMLN8Sg679pAOOWmzdMO3V706rNPzSVMME7E5
-oPIfAkEA8pDddarP5tCvTTgUpmTFbakm0KoTZm2+FzHcnA4jRh+XNTjTOv98Y6Ik
-eO5d1ZnKXseWvkZncQgxfdnMqqpj5wJAcNq/RVne1DbYlwWchT2Si65MYmmJ8t+F
-0mcsULqjOnEMwf5e+ptq5LzwbyrHZYq5FNk7ocufPv/ZQrcSSC+cFwJBAKvOJByS
-x56qyGeZLOQlWS2JS3KJo59XuLFGqcbgN9Om9xFa41Yb4N9NvplFivsvZdw3m1Q/
-SPIXQuT8RMPDVNQ=
+MIIG/wIBADANBgkqhkiG9w0BAQEFAASCBukwggblAgEAAoIBgQCylKlLaKU+hOvJ
+DfriTRLd+IthG5hv28I3A/CGjLICT0rDDtgaXd0uqloJAnjsgn5gMAcStpDW8Rm+
+t6LsrBL+5fBgkyU1r94Rvx0HHoyaZwBBouitVHw28hP3W+smddkqB1UxpGnTeL2B
+gj3dVo/WTtRfO+0h0PKw1l98YE1pMTdqIwcOOE/ER0g4hvA/wrxuLhMvlVLMy/lL
+58uctqaDUqryNyeerKbVkq4fJyCG5D2TwXVJ3i2DDh0xSt2Y10poZV4M4k8Su9Z5
+8zN2PSvYMT50aqF277v8BaOeYUApBE4kZGIJpo13ATGdEwpUFZ0Fri4zLYUZ1hWb
+OC35sKo7OxWQ/+tefNUdgWHob6Vmy777jiYcLwxc3sS9rF3AJe0rMW83kCkR6hmy
+A3250E137N/1QumHuT/Nj9rnI/lwt9jfaYkZjoAgT/C97m/mM83cYpGTdoGV1xNo
+7G90MhP0di5FnVsrIaSnvkbGT9UgUWx0oVMjocifdG2qIhMI9psCAwEAAQKCAYBT
+sHmaPmNaZj59jZCqp0YVQlpHWwBYQ5vD3pPE6oCttm0p9nXt/VkfenQRTthOtmT1
+POzDp00/feP7zeGLmqSYUjgRekPw4gdnN7Ip2PY5kdW77NWwDSzdLxuOS8Rq1MW9
+/Yu+ZPe3RBlDbT8C0IM+Atlh/BqIQ3zIxN4g0pzUlF0M33d6AYfYSzOcUhibOO7H
+j84r+YXBNkIRgYKZYbutRXuZYaGuqejRpBj3voVu0d3Ntdb6lCWuClpB9HzfGN0c
+RTv8g6UYO4sK3qyFn90ibIR/1GB9watvtoWVZqggiWeBzSWVWRsGEf9O+Cx4oJw1
+IphglhmhbgNksbj7bD24on/icldSOiVkoUemUOFmHWhCm4PnB1GmbD8YMfEdSbks
+qDr1Ps1zg4mGOinVD/4cY7vuPFO/HCH07wfeaUGzRt4g0/yLr+XjVofOA3oowyxv
+JAzr+niHA3lg5ecj4r7M68efwzN1OCyjMrVJw2RAzwvGxE+rm5NiT08SWlKQZnkC
+gcEA4wvyLpIur/UB84nV3XVJ89UMNBLm++aTFzld047BLJtMaOhvNqx6Cl5c8VuW
+l261KHjiVzpfNM3/A2LBQJcYkhX7avkqEXlj57cl+dCWAVwUzKmLJTPjfaTTZnYJ
+xeN3dMYjJz2z2WtgvfvDoJLukVwIMmhTY8wtqqYyQBJ/l06pBsfw5TNvmVIOQHds
+8ASOiFt+WRLk2bl9xrGGayqt3VV93KVRzF27cpjOgEcG74F3c0ZW9snERN7vIYwB
+JfrlAoHBAMlahPwMP2TYylG8OzHe7EiehTekSO26LGh0Cq3wTGXYsK/q8hQCzL14
+kWW638vpwXL6L9ntvrd7hjzWRO3vX/VxnYEA6f0bpqHq1tZi6lzix5CTUN5McpDg
+QnjenSJNrNjS1zEF8WeY9iLEuDI/M/iUW4y9R6s3WpgQhPDXpSvd2g3gMGRUYhxQ
+Xna8auiJeYFq0oNaOxvJj+VeOfJ3ZMJttd+Y7gTOYZcbg3SdRb/kdxYki0RMD2hF
+4ZvjJ6CTfwKBwQDiMqiZFTJGQwYqp4vWEmAW+I4r4xkUpWatoI2Fk5eI5T9+1PLX
+uYXsho56NxEU1UrOg4Cb/p+TcBc8PErkGqR0BkpxDMOInTOXSrQe6lxIBoECVXc3
+HTbrmiay0a5y5GfCgxPKqIJhfcToAceoVjovv0y7S4yoxGZKuUEe7E8JY2iqRNAO
+yOvKCCICv/hcN235E44RF+2/rDlOltagNej5tY6rIFkaDdgOF4bD7f9O5eEni1Bg
+litfoesDtQP/3rECgcEAkQfvQ7D6tIPmbqsbJBfCr6fmoqZllT4FIJN84b50+OL0
+mTGsfjdqC4tdhx3sdu7/VPbaIqm5NmX10bowWgWSY7MbVME4yQPyqSwC5NbIonEC
+d6N0mzoLR0kQ+Ai4u+2g82gicgAq2oj1uSNi3WZi48jQjHYFulCbo246o1NgeFFK
+77WshYe2R1ioQfQDOU1URKCR0uTaMHClgfu112yiGd12JAD+aF3TM0kxDXz+sXI5
+SKy311DFxECZeXRLpcC3AoHBAJkNMJWTyPYbeVu+CTQkec8Uun233EkXa2kUNZc/
+5DuXDaK+A3DMgYRufTKSPpDHGaCZ1SYPInX1Uoe2dgVjWssRL2uitR4ENabDoAOA
+ICVYXYYNagqQu5wwirF0QeaMXo1fjhuuHQh8GsMdXZvYEaAITZ9/NG5x/oY08+8H
+kr78SMBOPy3XQn964uKG+e3JwpOG14GKABdAlrHKFXNWchu/6dgcYXB87mrC/GhO
+zNwzC+QhFTZoOomFoqMgFWujng==
-----END PRIVATE KEY-----
import collections.abc
import contextlib
+import datetime
import errno
import faulthandler
import fnmatch
import gc
import importlib
import importlib.util
+import io
import logging.handlers
import nntplib
import os
import urllib.error
import warnings
+from .testresult import get_test_runner
+
try:
import _thread, threading
except ImportError:
max_memuse = 0 # Disable bigmem tests (they will still be run with
# small sizes, to make sure they work.)
real_max_memuse = 0
+junit_xml_list = None # list of testsuite XML elements
failfast = False
# _original_stdout is meant to hold stdout at the time regrtest began.
('EHOSTUNREACH', 113),
('ENETUNREACH', 101),
('ETIMEDOUT', 110),
+ # socket.create_connection() fails randomly with
+ # EADDRNOTAVAIL on Travis CI.
+ ('EADDRNOTAVAIL', 99),
]
default_gai_errnos = [
('EAI_AGAIN', -3),
def _run_suite(suite):
"""Run tests from a unittest.TestSuite-derived class."""
- if verbose:
- runner = unittest.TextTestRunner(sys.stdout, verbosity=2,
- failfast=failfast)
- else:
- runner = BasicTestRunner()
+ runner = get_test_runner(sys.stdout, verbosity=verbose)
+
+ # TODO: Remove this before merging (here for easy comparison with old impl)
+ #runner = unittest.TextTestRunner(sys.stdout, verbosity=2, failfast=failfast)
result = runner.run(suite)
+
+ if junit_xml_list is not None:
+ junit_xml_list.append(result.get_xml_element())
+
if not result.wasSuccessful():
if len(result.errors) == 1 and not result.failures:
err = result.errors[0][1]
--- /dev/null
+'''Test runner and result class for the regression test suite.
+
+'''
+
+import functools
+import io
+import sys
+import time
+import traceback
+import unittest
+
+import xml.etree.ElementTree as ET
+
+from datetime import datetime
+
+class RegressionTestResult(unittest.TextTestResult):
+ separator1 = '=' * 70 + '\n'
+ separator2 = '-' * 70 + '\n'
+
+ def __init__(self, stream, descriptions, verbosity):
+ super().__init__(stream=stream, descriptions=descriptions, verbosity=0)
+ self.buffer = True
+ self.__suite = ET.Element('testsuite')
+ self.__suite.set('start', datetime.utcnow().isoformat(' '))
+
+ self.__e = None
+ self.__start_time = None
+ self.__results = []
+ self.__verbose = bool(verbosity)
+
+ @classmethod
+ def __getId(cls, test):
+ try:
+ test_id = test.id
+ except AttributeError:
+ return str(test)
+ try:
+ return test_id()
+ except TypeError:
+ return str(test_id)
+ return repr(test)
+
+ def startTest(self, test):
+ super().startTest(test)
+ self.__e = e = ET.SubElement(self.__suite, 'testcase')
+ self.__start_time = time.perf_counter()
+ if self.__verbose:
+ self.stream.write(f'{self.getDescription(test)} ... ')
+ self.stream.flush()
+
+ def _add_result(self, test, capture=False, **args):
+ e = self.__e
+ self.__e = None
+ if e is None:
+ return
+ e.set('name', args.pop('name', self.__getId(test)))
+ e.set('status', args.pop('status', 'run'))
+ e.set('result', args.pop('result', 'completed'))
+ if self.__start_time:
+ e.set('time', f'{time.perf_counter() - self.__start_time:0.6f}')
+
+ if capture:
+ stdout = self._stdout_buffer.getvalue().rstrip()
+ ET.SubElement(e, 'system-out').text = stdout
+ stderr = self._stderr_buffer.getvalue().rstrip()
+ ET.SubElement(e, 'system-err').text = stderr
+
+ for k, v in args.items():
+ if not k or not v:
+ continue
+ e2 = ET.SubElement(e, k)
+ if hasattr(v, 'items'):
+ for k2, v2 in v.items():
+ if k2:
+ e2.set(k2, str(v2))
+ else:
+ e2.text = str(v2)
+ else:
+ e2.text = str(v)
+
+ def __write(self, c, word):
+ if self.__verbose:
+ self.stream.write(f'{word}\n')
+
+ @classmethod
+ def __makeErrorDict(cls, err_type, err_value, err_tb):
+ if isinstance(err_type, type):
+ if err_type.__module__ == 'builtins':
+ typename = err_type.__name__
+ else:
+ typename = f'{err_type.__module__}.{err_type.__name__}'
+ else:
+ typename = repr(err_type)
+
+ msg = traceback.format_exception(err_type, err_value, None)
+ tb = traceback.format_exception(err_type, err_value, err_tb)
+
+ return {
+ 'type': typename,
+ 'message': ''.join(msg),
+ '': ''.join(tb),
+ }
+
+ def addError(self, test, err):
+ self._add_result(test, True, error=self.__makeErrorDict(*err))
+ super().addError(test, err)
+ self.__write('E', 'ERROR')
+
+ def addExpectedFailure(self, test, err):
+ self._add_result(test, True, output=self.__makeErrorDict(*err))
+ super().addExpectedFailure(test, err)
+ self.__write('x', 'expected failure')
+
+ def addFailure(self, test, err):
+ self._add_result(test, True, failure=self.__makeErrorDict(*err))
+ super().addFailure(test, err)
+ self.__write('F', 'FAIL')
+
+ def addSkip(self, test, reason):
+ self._add_result(test, skipped=reason)
+ super().addSkip(test, reason)
+ self.__write('S', f'skipped {reason!r}')
+
+ def addSuccess(self, test):
+ self._add_result(test)
+ super().addSuccess(test)
+ self.__write('.', 'ok')
+
+ def addUnexpectedSuccess(self, test):
+ self._add_result(test, outcome='UNEXPECTED_SUCCESS')
+ super().addUnexpectedSuccess(test)
+ self.__write('u', 'unexpected success')
+
+ def printErrors(self):
+ if self.__verbose:
+ self.stream.write('\n')
+ self.printErrorList('ERROR', self.errors)
+ self.printErrorList('FAIL', self.failures)
+
+ def printErrorList(self, flavor, errors):
+ for test, err in errors:
+ self.stream.write(self.separator1)
+ self.stream.write(f'{flavor}: {self.getDescription(test)}\n')
+ self.stream.write(self.separator2)
+ self.stream.write('%s\n' % err)
+
+ def get_xml_element(self):
+ e = self.__suite
+ e.set('tests', str(self.testsRun))
+ e.set('errors', str(len(self.errors)))
+ e.set('failures', str(len(self.failures)))
+ return e
+
+class QuietRegressionTestRunner:
+ def __init__(self, stream):
+ self.result = RegressionTestResult(stream, None, 0)
+
+ def run(self, test):
+ test(self.result)
+ return self.result
+
+def get_test_runner_class(verbosity):
+ if verbosity:
+ return functools.partial(unittest.TextTestRunner,
+ resultclass=RegressionTestResult,
+ buffer=True,
+ verbosity=verbosity)
+ return QuietRegressionTestRunner
+
+def get_test_runner(stream, verbosity):
+ return get_test_runner_class(verbosity)(stream)
+
+if __name__ == '__main__':
+ class TestTests(unittest.TestCase):
+ def test_pass(self):
+ pass
+
+ def test_pass_slow(self):
+ time.sleep(1.0)
+
+ def test_fail(self):
+ print('stdout', file=sys.stdout)
+ print('stderr', file=sys.stderr)
+ self.fail('failure message')
+
+ def test_error(self):
+ print('stdout', file=sys.stdout)
+ print('stderr', file=sys.stderr)
+ raise RuntimeError('error message')
+
+ suite = unittest.TestSuite()
+ suite.addTest(unittest.makeSuite(TestTests))
+ stream = io.StringIO()
+ runner_cls = get_test_runner_class(sum(a == '-v' for a in sys.argv))
+ runner = runner_cls(sys.stdout)
+ result = runner.run(suite)
+ print('Output:', stream.getvalue())
+ print('XML: ', end='')
+ for s in ET.tostringlist(result.get_xml_element()):
+ print(s.decode(), end='')
+ print()
type = argparse.FileType('r', 1, errors='replace')
self.assertEqual("FileType('r', 1, errors='replace')", repr(type))
+class StdStreamComparer:
+ def __init__(self, attr):
+ self.attr = attr
+
+ def __eq__(self, other):
+ return other == getattr(sys, self.attr)
+
+eq_stdin = StdStreamComparer('stdin')
+eq_stdout = StdStreamComparer('stdout')
+eq_stderr = StdStreamComparer('stderr')
class RFile(object):
seen = {}
('foo', NS(x=None, spam=RFile('foo'))),
('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
- ('-x - -', NS(x=sys.stdin, spam=sys.stdin)),
+ ('-x - -', NS(x=eq_stdin, spam=eq_stdin)),
('readonly', NS(x=None, spam=RFile('readonly'))),
]
('foo', NS(x=None, spam=RFile('foo'))),
('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
- ('-x - -', NS(x=sys.stdin, spam=sys.stdin)),
+ ('-x - -', NS(x=eq_stdin, spam=eq_stdin)),
]
('foo', NS(x=None, spam=WFile('foo'))),
('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
- ('-x - -', NS(x=sys.stdout, spam=sys.stdout)),
+ ('-x - -', NS(x=eq_stdout, spam=eq_stdout)),
]
('foo', NS(x=None, spam=WFile('foo'))),
('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
- ('-x - -', NS(x=sys.stdout, spam=sys.stdout)),
+ ('-x - -', NS(x=eq_stdout, spam=eq_stdout)),
]
base_events._ipaddr_info('1.2.3.4', 1, INET6, STREAM, TCP))
self.assertEqual(
- (INET6, STREAM, TCP, '', ('::3', 1)),
+ (INET6, STREAM, TCP, '', ('::3', 1, 0, 0)),
base_events._ipaddr_info('::3', 1, INET6, STREAM, TCP))
self.assertEqual(
- (INET6, STREAM, TCP, '', ('::3', 1)),
+ (INET6, STREAM, TCP, '', ('::3', 1, 0, 0)),
base_events._ipaddr_info('::3', 1, UNSPEC, STREAM, TCP))
# IPv6 address with family IPv4.
self.loop.run_forever()
self.loop._selector.select.assert_called_once_with(0)
+ async def leave_unfinalized_asyncgen(self):
+ # Create an async generator, iterate it partially, and leave it
+ # to be garbage collected.
+ # Used in async generator finalization tests.
+ # Depends on implementation details of garbage collector. Changes
+ # in gc may break this function.
+ status = {'started': False,
+ 'stopped': False,
+ 'finalized': False}
+
+ async def agen():
+ status['started'] = True
+ try:
+ for item in ['ZERO', 'ONE', 'TWO', 'THREE', 'FOUR']:
+ yield item
+ finally:
+ status['finalized'] = True
+
+ ag = agen()
+ ai = ag.__aiter__()
+
+ async def iter_one():
+ try:
+ item = await ai.__anext__()
+ except StopAsyncIteration:
+ return
+ if item == 'THREE':
+ status['stopped'] = True
+ return
+ self.loop.create_task(iter_one())
+
+ self.loop.create_task(iter_one())
+ return status
+
+ def test_asyncgen_finalization_by_gc(self):
+ # Async generators should be finalized when garbage collected.
+ self.loop._process_events = mock.Mock()
+ self.loop._write_to_self = mock.Mock()
+ with support.disable_gc():
+ status = self.loop.run_until_complete(self.leave_unfinalized_asyncgen())
+ while not status['stopped']:
+ test_utils.run_briefly(self.loop)
+ self.assertTrue(status['started'])
+ self.assertTrue(status['stopped'])
+ self.assertFalse(status['finalized'])
+ support.gc_collect()
+ test_utils.run_briefly(self.loop)
+ self.assertTrue(status['finalized'])
+
+ def test_asyncgen_finalization_by_gc_in_other_thread(self):
+ # Python issue 34769: If garbage collector runs in another
+ # thread, async generators will not finalize in debug
+ # mode.
+ self.loop._process_events = mock.Mock()
+ self.loop._write_to_self = mock.Mock()
+ self.loop.set_debug(True)
+ with support.disable_gc():
+ status = self.loop.run_until_complete(self.leave_unfinalized_asyncgen())
+ while not status['stopped']:
+ test_utils.run_briefly(self.loop)
+ self.assertTrue(status['started'])
+ self.assertTrue(status['stopped'])
+ self.assertFalse(status['finalized'])
+ self.loop.run_until_complete(
+ self.loop.run_in_executor(None, support.gc_collect))
+ test_utils.run_briefly(self.loop)
+ self.assertTrue(status['finalized'])
+
class MyProto(asyncio.Protocol):
done = None
srv.close()
self.loop.run_until_complete(srv.wait_closed())
+ @unittest.skipUnless(hasattr(socket, 'AF_INET6'), 'no IPv6 support')
+ def test_create_server_ipv6(self):
+ async def main():
+ srv = await asyncio.start_server(
+ lambda: None, '::1', 0, loop=self.loop)
+ try:
+ self.assertGreater(len(srv.sockets), 0)
+ finally:
+ srv.close()
+ await srv.wait_closed()
+
+ try:
+ self.loop.run_until_complete(main())
+ except OSError as ex:
+ if (hasattr(errno, 'EADDRNOTAVAIL') and
+ ex.errno == errno.EADDRNOTAVAIL):
+ self.skipTest('failed to bind to ::1')
+ else:
+ raise
+
def test_create_datagram_endpoint_wrong_sock(self):
sock = socket.socket(socket.AF_INET)
with sock:
ONLYKEY = data_file('ssl_key.pem')
SIGNED_CERTFILE = data_file('keycert3.pem')
SIGNING_CA = data_file('pycacert.pem')
-PEERCERT = {'serialNumber': 'B09264B1F2DA21D1',
- 'version': 1,
- 'subject': ((('countryName', 'XY'),),
- (('localityName', 'Castle Anthrax'),),
- (('organizationName', 'Python Software Foundation'),),
- (('commonName', 'localhost'),)),
- 'issuer': ((('countryName', 'XY'),),
- (('organizationName', 'Python Software Foundation CA'),),
- (('commonName', 'our-ca-server'),)),
- 'notAfter': 'Nov 13 19:47:07 2022 GMT',
- 'notBefore': 'Jan 4 19:47:07 2013 GMT'}
+PEERCERT = {
+ 'OCSP': ('http://testca.pythontest.net/testca/ocsp/',),
+ 'caIssuers': ('http://testca.pythontest.net/testca/pycacert.cer',),
+ 'crlDistributionPoints': ('http://testca.pythontest.net/testca/revocation.crl',),
+ 'issuer': ((('countryName', 'XY'),),
+ (('organizationName', 'Python Software Foundation CA'),),
+ (('commonName', 'our-ca-server'),)),
+ 'notAfter': 'Jul 7 14:23:16 2028 GMT',
+ 'notBefore': 'Aug 29 14:23:16 2018 GMT',
+ 'serialNumber': 'CB2D80995A69525C',
+ 'subject': ((('countryName', 'XY'),),
+ (('localityName', 'Castle Anthrax'),),
+ (('organizationName', 'Python Software Foundation'),),
+ (('commonName', 'localhost'),)),
+ 'subjectAltName': (('DNS', 'localhost'),),
+ 'version': 3
+}
class MyBaseProto(asyncio.Protocol):
self.loop.run_until_complete(f_c)
# close connection
- proto.transport.close()
+ # transport may be None with TLS 1.3, because connection is
+ # interrupted, server is unable to send session tickets, and
+ # transport is closed.
+ if proto.transport is not None:
+ proto.transport.close()
server.close()
def test_legacy_create_server_ssl_match_failed(self):
f = asyncio.Future(loop=self.loop)
f.set_result(msg)
futures.append(f)
+
self.loop._proactor.recv.side_effect = futures
self.loop._run_once()
self.assertFalse(tr._paused)
self.protocol.data_received.assert_called_with(b'data1')
self.loop._run_once()
self.protocol.data_received.assert_called_with(b'data2')
+
+ tr.pause_reading()
tr.pause_reading()
self.assertTrue(tr._paused)
for i in range(10):
self.loop._run_once()
self.protocol.data_received.assert_called_with(b'data2')
+
+ tr.resume_reading()
tr.resume_reading()
self.assertFalse(tr._paused)
self.loop._run_once()
with test_utils.disable_logger():
transport = self.loop._make_ssl_transport(
m, asyncio.Protocol(), m, waiter)
+
# execute the handshake while the logger is disabled
# to ignore SSL handshake failure
test_utils.run_briefly(self.loop)
test_utils.run_briefly(self.loop)
self.assertFalse(tr._paused)
self.loop.assert_reader(7, tr._read_ready)
+
+ tr.pause_reading()
tr.pause_reading()
self.assertTrue(tr._paused)
- self.assertFalse(7 in self.loop.readers)
+ self.loop.assert_no_reader(7)
+
+ tr.resume_reading()
tr.resume_reading()
self.assertFalse(tr._paused)
self.loop.assert_reader(7, tr._read_ready)
- with self.assertRaises(RuntimeError):
- tr.resume_reading()
+
+ tr.close()
+ self.loop.assert_no_reader(7)
def test_read_ready(self):
transport = self.socket_transport()
self.assertFalse(t._must_cancel) # White-box test.
self.assertFalse(t.cancel())
+ def test_cancel_awaited_task(self):
+ # This tests for a relatively rare condition when
+ # a task cancellation is requested for a task which is not
+ # currently blocked, such as a task cancelling itself.
+ # In this situation we must ensure that whatever next future
+ # or task the cancelled task blocks on is cancelled correctly
+ # as well. See also bpo-34872.
+ loop = asyncio.new_event_loop()
+ self.addCleanup(lambda: loop.close())
+
+ task = nested_task = None
+ fut = self.new_future(loop)
+
+ async def nested():
+ await fut
+
+ async def coro():
+ nonlocal nested_task
+ # Create a sub-task and wait for it to run.
+ nested_task = self.new_task(loop, nested())
+ await asyncio.sleep(0)
+
+ # Request the current task to be cancelled.
+ task.cancel()
+ # Block on the nested task, which should be immediately
+ # cancelled.
+ await nested_task
+
+ task = self.new_task(loop, coro())
+ with self.assertRaises(asyncio.CancelledError):
+ loop.run_until_complete(task)
+
+ self.assertTrue(task.cancelled())
+ self.assertTrue(nested_task.cancelled())
+ self.assertTrue(fut.cancelled())
+
def test_stop_while_run_in_complete(self):
def gen():
self.assertRaises(binascii.Error, base64.b32decode, data_str)
def test_b32decode_error(self):
- for data in [b'abc', b'ABCDEF==', b'==ABCDEF']:
- with self.assertRaises(binascii.Error):
- base64.b32decode(data)
- with self.assertRaises(binascii.Error):
- base64.b32decode(data.decode('ascii'))
+ tests = [b'abc', b'ABCDEF==', b'==ABCDEF']
+ prefixes = [b'M', b'ME', b'MFRA', b'MFRGG', b'MFRGGZA', b'MFRGGZDF']
+ for i in range(0, 17):
+ if i:
+ tests.append(b'='*i)
+ for prefix in prefixes:
+ if len(prefix) + i != 8:
+ tests.append(prefix + b'='*i)
+ for data in tests:
+ with self.subTest(data=data):
+ with self.assertRaises(binascii.Error):
+ base64.b32decode(data)
+ with self.assertRaises(binascii.Error):
+ base64.b32decode(data.decode('ascii'))
def test_b16encode(self):
eq = self.assertEqual
with self.assertRaises(TypeError):
type('A', (B,), {'__slots__': '__weakref__'})
+ def test_namespace_order(self):
+ # bpo-34320: namespace should preserve order
+ od = collections.OrderedDict([('a', 1), ('b', 2)])
+ od.move_to_end('a')
+ expected = list(od.items())
+
+ C = type('C', (), od)
+ self.assertEqual(list(C.__dict__.items())[:2], [('b', 2), ('a', 1)])
+
def load_tests(loader, tests, pattern):
from doctest import DocTestSuite
+import collections
import datetime
import unittest
from test.support import cpython_only
except ImportError:
_testcapi = None
+
+class FunctionCalls(unittest.TestCase):
+
+ def test_kwargs_order(self):
+ # bpo-34320: **kwargs should preserve order of passed OrderedDict
+ od = collections.OrderedDict([('a', 1), ('b', 2)])
+ od.move_to_end('a')
+ expected = list(od.items())
+
+ def fn(**kw):
+ return kw
+
+ res = fn(**od)
+ self.assertIsInstance(res, dict)
+ self.assertEqual(list(res.items()), expected)
+
+
# The test cases here cover several paths through the function calling
# code. They depend on the METH_XXX flag that is used to define a C
# function, which can't be verified from Python. If the METH_XXX decl
self.assertNotEqual(pickle.load(f), id(builtins))
-# Bug #6012
-class Test6012(unittest.TestCase):
- def test(self):
- self.assertEqual(_testcapi.argparsing("Hello", "World"), 1)
-
-
-class EmbeddingTests(unittest.TestCase):
- def setUp(self):
- here = os.path.abspath(__file__)
- basepath = os.path.dirname(os.path.dirname(os.path.dirname(here)))
- exename = "_testembed"
- if sys.platform.startswith("win"):
- ext = ("_d" if "_d" in sys.executable else "") + ".exe"
- exename += ext
- exepath = os.path.dirname(sys.executable)
- else:
- exepath = os.path.join(basepath, "Programs")
- self.test_exe = exe = os.path.join(exepath, exename)
- if not os.path.exists(exe):
- self.skipTest("%r doesn't exist" % exe)
- # This is needed otherwise we get a fatal error:
- # "Py_Initialize: Unable to get the locale encoding
- # LookupError: no codec search functions registered: can't find encoding"
- self.oldcwd = os.getcwd()
- os.chdir(basepath)
-
- def tearDown(self):
- os.chdir(self.oldcwd)
-
- def run_embedded_interpreter(self, *args, env=None):
- """Runs a test in the embedded interpreter"""
- cmd = [self.test_exe]
- cmd.extend(args)
- if env is not None and sys.platform == 'win32':
- # Windows requires at least the SYSTEMROOT environment variable to
- # start Python.
- env = env.copy()
- env['SYSTEMROOT'] = os.environ['SYSTEMROOT']
-
- p = subprocess.Popen(cmd,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- universal_newlines=True,
- env=env)
- (out, err) = p.communicate()
- self.assertEqual(p.returncode, 0,
- "bad returncode %d, stderr is %r" %
- (p.returncode, err))
- return out, err
-
- def test_repeated_init_and_subinterpreters(self):
- # This is just a "don't crash" test
- out, err = self.run_embedded_interpreter('repeated_init_and_subinterpreters')
- if support.verbose:
- print()
- print(out)
- print(err)
-
- @staticmethod
- def _get_default_pipe_encoding():
- rp, wp = os.pipe()
- try:
- with os.fdopen(wp, 'w') as w:
- default_pipe_encoding = w.encoding
- finally:
- os.close(rp)
- return default_pipe_encoding
-
- def test_forced_io_encoding(self):
- # Checks forced configuration of embedded interpreter IO streams
- env = dict(os.environ, PYTHONIOENCODING="utf-8:surrogateescape")
- out, err = self.run_embedded_interpreter("forced_io_encoding", env=env)
- if support.verbose:
- print()
- print(out)
- print(err)
- expected_stream_encoding = "utf-8"
- expected_errors = "surrogateescape"
- expected_pipe_encoding = self._get_default_pipe_encoding()
- expected_output = '\n'.join([
- "--- Use defaults ---",
- "Expected encoding: default",
- "Expected errors: default",
- "stdin: {in_encoding}:{errors}",
- "stdout: {out_encoding}:{errors}",
- "stderr: {out_encoding}:backslashreplace",
- "--- Set errors only ---",
- "Expected encoding: default",
- "Expected errors: ignore",
- "stdin: {in_encoding}:ignore",
- "stdout: {out_encoding}:ignore",
- "stderr: {out_encoding}:backslashreplace",
- "--- Set encoding only ---",
- "Expected encoding: latin-1",
- "Expected errors: default",
- "stdin: latin-1:{errors}",
- "stdout: latin-1:{errors}",
- "stderr: latin-1:backslashreplace",
- "--- Set encoding and errors ---",
- "Expected encoding: latin-1",
- "Expected errors: replace",
- "stdin: latin-1:replace",
- "stdout: latin-1:replace",
- "stderr: latin-1:backslashreplace"])
- expected_output = expected_output.format(
- in_encoding=expected_stream_encoding,
- out_encoding=expected_stream_encoding,
- errors=expected_errors)
- # This is useful if we ever trip over odd platform behaviour
- self.maxDiff = None
- self.assertEqual(out.strip(), expected_output)
-
- def test_pre_initialization_api(self):
- """
- Checks the few parts of the C-API that work before the runtine
- is initialized (via Py_Initialize()).
- """
- env = dict(os.environ, PYTHONPATH=os.pathsep.join(sys.path))
- out, err = self.run_embedded_interpreter("pre_initialization_api", env=env)
- self.assertEqual(out, '')
- self.assertEqual(err, '')
-
-
-class SkipitemTest(unittest.TestCase):
-
- def test_skipitem(self):
- """
- If this test failed, you probably added a new "format unit"
- in Python/getargs.c, but neglected to update our poor friend
- skipitem() in the same file. (If so, shame on you!)
-
- With a few exceptions**, this function brute-force tests all
- printable ASCII*** characters (32 to 126 inclusive) as format units,
- checking to see that PyArg_ParseTupleAndKeywords() return consistent
- errors both when the unit is attempted to be used and when it is
- skipped. If the format unit doesn't exist, we'll get one of two
- specific error messages (one for used, one for skipped); if it does
- exist we *won't* get that error--we'll get either no error or some
- other error. If we get the specific "does not exist" error for one
- test and not for the other, there's a mismatch, and the test fails.
-
- ** Some format units have special funny semantics and it would
- be difficult to accommodate them here. Since these are all
- well-established and properly skipped in skipitem() we can
- get away with not testing them--this test is really intended
- to catch *new* format units.
-
- *** Python C source files must be ASCII. Therefore it's impossible
- to have non-ASCII format units.
-
- """
- empty_tuple = ()
- tuple_1 = (0,)
- dict_b = {'b':1}
- keywords = ["a", "b"]
-
- for i in range(32, 127):
- c = chr(i)
-
- # skip parentheses, the error reporting is inconsistent about them
- # skip 'e', it's always a two-character code
- # skip '|' and '$', they don't represent arguments anyway
- if c in '()e|$':
- continue
-
- # test the format unit when not skipped
- format = c + "i"
- try:
- _testcapi.parse_tuple_and_keywords(tuple_1, dict_b,
- format, keywords)
- when_not_skipped = False
- except SystemError as e:
- s = "argument 1 (impossible<bad format char>)"
- when_not_skipped = (str(e) == s)
- except TypeError:
- when_not_skipped = False
-
- # test the format unit when skipped
- optional_format = "|" + format
- try:
- _testcapi.parse_tuple_and_keywords(empty_tuple, dict_b,
- optional_format, keywords)
- when_skipped = False
- except SystemError as e:
- s = "impossible<bad format char>: '{}'".format(format)
- when_skipped = (str(e) == s)
-
- message = ("test_skipitem_parity: "
- "detected mismatch between convertsimple and skipitem "
- "for format unit '{}' ({}), not skipped {}, skipped {}".format(
- c, i, when_skipped, when_not_skipped))
- self.assertIs(when_skipped, when_not_skipped, message)
-
- def test_parse_tuple_and_keywords(self):
- # Test handling errors in the parse_tuple_and_keywords helper itself
- self.assertRaises(TypeError, _testcapi.parse_tuple_and_keywords,
- (), {}, 42, [])
- self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords,
- (), {}, '', 42)
- self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords,
- (), {}, '', [''] * 42)
- self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords,
- (), {}, '', [42])
-
- def test_bad_use(self):
- # Test handling invalid format and keywords in
- # PyArg_ParseTupleAndKeywords()
- self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
- (1,), {}, '||O', ['a'])
- self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
- (1, 2), {}, '|O|O', ['a', 'b'])
- self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
- (), {'a': 1}, '$$O', ['a'])
- self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
- (), {'a': 1, 'b': 2}, '$O$O', ['a', 'b'])
- self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
- (), {'a': 1}, '$|O', ['a'])
- self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
- (), {'a': 1, 'b': 2}, '$O|O', ['a', 'b'])
- self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
- (1,), {}, '|O', ['a', 'b'])
- self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
- (1,), {}, '|OO', ['a'])
- self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
- (), {}, '|$O', [''])
- self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
- (), {}, '|OO', ['a', ''])
-
- def test_positional_only(self):
- parse = _testcapi.parse_tuple_and_keywords
-
- parse((1, 2, 3), {}, 'OOO', ['', '', 'a'])
- parse((1, 2), {'a': 3}, 'OOO', ['', '', 'a'])
- with self.assertRaisesRegex(TypeError,
- r'Function takes at least 2 positional arguments \(1 given\)'):
- parse((1,), {'a': 3}, 'OOO', ['', '', 'a'])
- parse((1,), {}, 'O|OO', ['', '', 'a'])
- with self.assertRaisesRegex(TypeError,
- r'Function takes at least 1 positional arguments \(0 given\)'):
- parse((), {}, 'O|OO', ['', '', 'a'])
- parse((1, 2), {'a': 3}, 'OO$O', ['', '', 'a'])
- with self.assertRaisesRegex(TypeError,
- r'Function takes exactly 2 positional arguments \(1 given\)'):
- parse((1,), {'a': 3}, 'OO$O', ['', '', 'a'])
- parse((1,), {}, 'O|O$O', ['', '', 'a'])
- with self.assertRaisesRegex(TypeError,
- r'Function takes at least 1 positional arguments \(0 given\)'):
- parse((), {}, 'O|O$O', ['', '', 'a'])
- with self.assertRaisesRegex(SystemError, r'Empty parameter name after \$'):
- parse((1,), {}, 'O|$OO', ['', '', 'a'])
- with self.assertRaisesRegex(SystemError, 'Empty keyword'):
- parse((1,), {}, 'O|OO', ['', 'a', ''])
@unittest.skipUnless(threading, 'Threading required for this test.')
class Test_testcapi(unittest.TestCase):
- def test__testcapi(self):
- for name in dir(_testcapi):
- if name.startswith('test_'):
- with self.subTest("internal", name=name):
- test = getattr(_testcapi, name)
- test()
+ locals().update((name, getattr(_testcapi, name))
+ for name in dir(_testcapi)
+ if name.startswith('test_') and not name.endswith('_code'))
class PyMemDebugTests(unittest.TestCase):
self.assertEqual(type(complex("1"*500)), complex)
# check whitespace processing
self.assertEqual(complex('\N{EM SPACE}(\N{EN SPACE}1+1j ) '), 1+1j)
+ # Invalid unicode string
+ # See bpo-34087
+ self.assertRaises(ValueError, complex, '\u3053\u3093\u306b\u3061\u306f')
class EvilExc(Exception):
pass
def setUp(self):
super().setUp()
- self.t1 = time.time()
+ self.t1 = time.monotonic()
try:
self.executor = self.executor_type(max_workers=self.worker_count)
except NotImplementedError as e:
self.executor.shutdown(wait=True)
self.executor = None
- dt = time.time() - self.t1
+ dt = time.monotonic() - self.t1
if test.support.verbose:
print("%.2fs" % dt, end=' ')
- self.assertLess(dt, 60, "synchronization issue: test lasted too long")
+ self.assertLess(dt, 300, "synchronization issue: test lasted too long")
super().tearDown()
self.g = gdbm.open(filename, 'c')
size0 = os.path.getsize(filename)
- self.g['x'] = 'x' * 10000
+ # bpo-33901: on macOS with gdbm 1.15, an empty database uses 16 MiB
+ # and adding an entry of 10,000 B has no effect on the file size.
+ # Add size0 bytes to make sure that the file size changes.
+ value_size = max(size0, 10000)
+ self.g['x'] = 'x' * value_size
size1 = os.path.getsize(filename)
- self.assertTrue(size0 < size1)
+ self.assertGreater(size1, size0)
del self.g['x']
# 'size' is supposed to be the same even after deleting an entry.
self.g.reorganize()
size2 = os.path.getsize(filename)
- self.assertTrue(size1 > size2 >= size0)
+ self.assertLess(size2, size1)
+ self.assertGreaterEqual(size2, size0)
def test_context_manager(self):
with gdbm.open(filename, 'c') as db:
d1 == d2 # not clear if this is supposed to be True or False,
# but it used to give a SystemError
+ @support.cpython_only
+ def test_bug_31608(self):
+ # The interpreter used to crash in specific cases where a deque
+ # subclass returned a non-deque.
+ class X(deque):
+ pass
+ d = X()
+ def bad___new__(cls, *args, **kwargs):
+ return [42]
+ X.__new__ = bad___new__
+ with self.assertRaises(TypeError):
+ d * 42 # shouldn't crash
+ with self.assertRaises(TypeError):
+ d + deque([1, 2, 3]) # shouldn't crash
+
class SubclassWithKwargs(deque):
def __init__(self, newarg=1):
self.assertEqual(dict(it), data)
def test_valuesiterator_pickling(self):
- for proto in range(pickle.HIGHEST_PROTOCOL):
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
data = {1:"a", 2:"b", 3:"c"}
# data.values() isn't picklable, only its iterator
it = iter(data.values())
self.assertRaises(RuntimeError, iter_and_mutate)
+ @support.cpython_only
+ def test_dict_copy_order(self):
+ # bpo-34320
+ od = collections.OrderedDict([('a', 1), ('b', 2)])
+ od.move_to_end('a')
+ expected = list(od.items())
+
+ copy = dict(od)
+ self.assertEqual(list(copy.items()), expected)
+
+ # dict subclass doesn't override __iter__
+ class CustomDict(dict):
+ pass
+
+ pairs = [('a', 1), ('b', 2), ('c', 3)]
+
+ d = CustomDict(pairs)
+ self.assertEqual(pairs, list(dict(d).items()))
+
+ class CustomReversedDict(dict):
+ def keys(self):
+ return reversed(list(dict.keys(self)))
+
+ __iter__ = keys
+
+ def items(self):
+ return reversed(dict.items(self))
+
+ d = CustomReversedDict(pairs)
+ self.assertEqual(pairs[::-1], list(dict(d).items()))
+
class CAPITest(unittest.TestCase):
self._test(b'Zm9v', b'foo')
def test_missing_padding(self):
+ # 1 missing padding character
self._test(b'dmk', b'vi', [errors.InvalidBase64PaddingDefect])
+ # 2 missing padding characters
+ self._test(b'dg', b'v', [errors.InvalidBase64PaddingDefect])
def test_invalid_character(self):
self._test(b'dm\x01k===', b'vi', [errors.InvalidBase64CharactersDefect])
self._test(b'dm\x01k', b'vi', [errors.InvalidBase64CharactersDefect,
errors.InvalidBase64PaddingDefect])
+ def test_invalid_length(self):
+ self._test(b'abcde', b'abcde', [errors.InvalidBase64LengthDefect])
+
class TestDecode(TestEmailBase):
errors.InvalidBase64PaddingDefect],
'')
+ def test_get_unstructured_invalid_base64_length(self):
+ # bpo-27397: Return the encoded string since there's no way to decode.
+ self._test_get_x(self._get_unst,
+ '=?utf-8?b?abcde?=',
+ 'abcde',
+ 'abcde',
+ [errors.InvalidBase64LengthDefect],
+ '')
+
def test_get_unstructured_no_whitespace_between_ews(self):
self._test_get_x(self._get_unst,
'=?utf-8?q?foo?==?utf-8?q?bar?=',
self.assertEqual(group.mailboxes[1].local_part, 'x')
self.assertIsNone(group.all_mailboxes[1].display_name)
+ def test_get_group_missing_final_semicol(self):
+ group = self._test_get_x(parser.get_group,
+ ('Monty Python:"Fred A. Bear" <dinsdale@example.com>,'
+ 'eric@where.test,John <jdoe@test>'),
+ ('Monty Python:"Fred A. Bear" <dinsdale@example.com>,'
+ 'eric@where.test,John <jdoe@test>;'),
+ ('Monty Python:"Fred A. Bear" <dinsdale@example.com>,'
+ 'eric@where.test,John <jdoe@test>;'),
+ [errors.InvalidHeaderDefect],
+ '')
+ self.assertEqual(group.token_type, 'group')
+ self.assertEqual(group.display_name, 'Monty Python')
+ self.assertEqual(len(group.mailboxes), 3)
+ self.assertEqual(group.mailboxes,
+ group.all_mailboxes)
+ self.assertEqual(group.mailboxes[0].addr_spec,
+ 'dinsdale@example.com')
+ self.assertEqual(group.mailboxes[0].display_name,
+ 'Fred A. Bear')
+ self.assertEqual(group.mailboxes[1].addr_spec,
+ 'eric@where.test')
+ self.assertEqual(group.mailboxes[2].display_name,
+ 'John')
+ self.assertEqual(group.mailboxes[2].addr_spec,
+ 'jdoe@test')
# get_address
def test_get_address_simple(self):
self.assertDefectsEqual(self.get_defects(msg),
[errors.InvalidBase64CharactersDefect])
+ def test_invalid_length_of_base64_payload(self):
+ source = textwrap.dedent("""\
+ Subject: test
+ MIME-Version: 1.0
+ Content-Type: text/plain; charset="utf-8"
+ Content-Transfer-Encoding: base64
+
+ abcde
+ """)
+ msg = self._str_msg(source)
+ with self._raise_point(errors.InvalidBase64LengthDefect):
+ payload = msg.get_payload(decode=True)
+ if self.raise_expected: return
+ self.assertEqual(payload, b'abcde')
+ self.assertDefectsEqual(self.get_defects(msg),
+ [errors.InvalidBase64LengthDefect])
+
def test_missing_ending_boundary(self):
source = textwrap.dedent("""\
To: 1@harrydomain4.com
yellow = 6
self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
+ def test_subclass_duplicate_name(self):
+ class Base(Enum):
+ def test(self):
+ pass
+ class Test(Base):
+ test = 1
+ self.assertIs(type(Test.test), Test)
+
+ def test_subclass_duplicate_name_dynamic(self):
+ from types import DynamicClassAttribute
+ class Base(Enum):
+ @DynamicClassAttribute
+ def test(self):
+ return 'dynamic'
+ class Test(Base):
+ test = 1
+ self.assertEqual(Test.test.test, 'dynamic')
def test_no_duplicates(self):
class UniqueEnum(Enum):
ep.close()
self.assertTrue(ep.closed)
self.assertRaises(ValueError, ep.fileno)
+
if hasattr(select, "EPOLL_CLOEXEC"):
- select.epoll(select.EPOLL_CLOEXEC).close()
- self.assertRaises(OSError, select.epoll, flags=12356)
+ select.epoll(-1, select.EPOLL_CLOEXEC).close()
+ select.epoll(flags=select.EPOLL_CLOEXEC).close()
+ select.epoll(flags=0).close()
def test_badcreate(self):
self.assertRaises(TypeError, select.epoll, 1, 2, 3)
self.assertRaises(TypeError, select.epoll, ['foo'])
self.assertRaises(TypeError, select.epoll, {})
+ self.assertRaises(ValueError, select.epoll, 0)
+ self.assertRaises(ValueError, select.epoll, -2)
+ self.assertRaises(ValueError, select.epoll, sizehint=-2)
+
+ if hasattr(select, "EPOLL_CLOEXEC"):
+ self.assertRaises(OSError, select.epoll, flags=12356)
+
def test_context_manager(self):
with select.epoll(16) as ep:
self.assertGreater(ep.fileno(), 0)
try:
# TypeError: argument must be an int, or have a fileno() method.
self.assertRaises(TypeError, ep.register, object(),
- select.EPOLLIN | select.EPOLLOUT)
+ select.EPOLLIN | select.EPOLLOUT)
self.assertRaises(TypeError, ep.register, None,
- select.EPOLLIN | select.EPOLLOUT)
+ select.EPOLLIN | select.EPOLLOUT)
# ValueError: file descriptor cannot be a negative integer (-1)
self.assertRaises(ValueError, ep.register, -1,
- select.EPOLLIN | select.EPOLLOUT)
+ select.EPOLLIN | select.EPOLLOUT)
# OSError: [Errno 9] Bad file descriptor
self.assertRaises(OSError, ep.register, 10000,
- select.EPOLLIN | select.EPOLLOUT)
+ select.EPOLLIN | select.EPOLLOUT)
# registering twice also raises an exception
ep.register(server, select.EPOLLIN | select.EPOLLOUT)
self.assertRaises(OSError, ep.register, server,
- select.EPOLLIN | select.EPOLLOUT)
+ select.EPOLLIN | select.EPOLLOUT)
finally:
ep.close()
ep = select.epoll(16)
ep.register(server.fileno(),
- select.EPOLLIN | select.EPOLLOUT | select.EPOLLET)
+ select.EPOLLIN | select.EPOLLOUT | select.EPOLLET)
ep.register(client.fileno(),
- select.EPOLLIN | select.EPOLLOUT | select.EPOLLET)
+ select.EPOLLIN | select.EPOLLOUT | select.EPOLLET)
now = time.monotonic()
events = ep.poll(1, 4)
# Test for appropriate errors mixing read* and iteration
for methodname, args in methods:
f = self.open(TESTFN, 'rb')
- if next(f) != filler:
- self.fail, "Broken testfile"
+ self.assertEqual(next(f), filler)
meth = getattr(f, methodname)
meth(*args) # This simply shouldn't fail
f.close()
# extra long strings should not be a problem
float(b'.' + b'1'*1000)
float('.' + '1'*1000)
+ # Invalid unicode string
+ # See bpo-34087
+ self.assertRaises(ValueError, float, '\u3053\u3093\u306b\u3061\u306f')
def test_underscores(self):
for lit in VALID_UNDERSCORE_LITERALS:
class FLUFLTests(unittest.TestCase):
def test_barry_as_bdfl(self):
- code = "from __future__ import barry_as_FLUFL; 2 {0} 3"
+ code = "from __future__ import barry_as_FLUFL\n2 {0} 3"
compile(code.format('<>'), '<BDFL test>', 'exec',
__future__.CO_FUTURE_BARRY_AS_BDFL)
- self.assertRaises(SyntaxError, compile, code.format('!='),
- '<FLUFL test>', 'exec',
- __future__.CO_FUTURE_BARRY_AS_BDFL)
+ with self.assertRaises(SyntaxError) as cm:
+ compile(code.format('!='), '<FLUFL test>', 'exec',
+ __future__.CO_FUTURE_BARRY_AS_BDFL)
+ self.assertRegex(str(cm.exception),
+ "with Barry as BDFL, use '<>' instead of '!='")
+ self.assertEqual(cm.exception.text, '2 != 3\n')
+ self.assertEqual(cm.exception.filename, '<FLUFL test>')
+ self.assertEqual(cm.exception.lineno, 2)
+ self.assertEqual(cm.exception.offset, 4)
def test_guido_as_bdfl(self):
code = '2 {0} 3'
compile(code.format('!='), '<BDFL test>', 'exec')
- self.assertRaises(SyntaxError, compile, code.format('<>'),
- '<FLUFL test>', 'exec')
+ with self.assertRaises(SyntaxError) as cm:
+ compile(code.format('<>'), '<FLUFL test>', 'exec')
+ self.assertRegex(str(cm.exception), "invalid syntax")
+ self.assertEqual(cm.exception.text, '2 <> 3\n')
+ self.assertEqual(cm.exception.filename, '<FLUFL test>')
+ self.assertEqual(cm.exception.lineno, 1)
+ self.assertEqual(cm.exception.offset, 4)
if __name__ == '__main__':
# clear text
with self.client.transfercmd('list') as sock:
self.assertNotIsInstance(sock, ssl.SSLSocket)
+ self.assertEqual(sock.recv(1024), LIST_DATA.encode('ascii'))
self.assertEqual(self.client.voidresp(), "226 transfer complete")
# secured, after PROT P
self.client.prot_p()
with self.client.transfercmd('list') as sock:
self.assertIsInstance(sock, ssl.SSLSocket)
+ # consume from SSL socket to finalize handshake and avoid
+ # "SSLError [SSL] shutdown while in init"
+ self.assertEqual(sock.recv(1024), LIST_DATA.encode('ascii'))
self.assertEqual(self.client.voidresp(), "226 transfer complete")
# PROT C is issued, the connection must be in cleartext again
self.client.prot_c()
with self.client.transfercmd('list') as sock:
self.assertNotIsInstance(sock, ssl.SSLSocket)
+ self.assertEqual(sock.recv(1024), LIST_DATA.encode('ascii'))
self.assertEqual(self.client.voidresp(), "226 transfer complete")
def test_login(self):
self.assertEqual(len(td), 0)
functools.WeakKeyDictionary = _orig_wkd
+ def test_invalid_positional_argument(self):
+ @functools.singledispatch
+ def f(*args):
+ pass
+ msg = 'f requires at least 1 positional argument'
+ with self.assertRaisesRegex(TypeError, msg):
+ f()
if __name__ == '__main__':
unittest.main()
import unittest
from test.support import (verbose, refcount_test, run_unittest,
strip_python_stderr, cpython_only, start_threads,
- temp_dir, requires_type_collecting)
+ temp_dir, requires_type_collecting, TESTFN, unlink)
from test.support.script_helper import assert_python_ok, make_script
import sys
rc, out, err = assert_python_ok('-c', code)
self.assertEqual(out.strip(), b'__del__ called')
+ @requires_type_collecting
+ def test_global_del_SystemExit(self):
+ code = """if 1:
+ class ClassWithDel:
+ def __del__(self):
+ print('__del__ called')
+ a = ClassWithDel()
+ a.link = a
+ raise SystemExit(0)"""
+ self.addCleanup(unlink, TESTFN)
+ with open(TESTFN, 'w') as script:
+ script.write(code)
+ rc, out, err = assert_python_ok(TESTFN)
+ self.assertEqual(out.strip(), b'__del__ called')
+
def test_get_stats(self):
stats = gc.get_stats()
self.assertEqual(len(stats), 3)
PYTHONHASHSEED = '123'
+
+def cet_protection():
+ cflags = sysconfig.get_config_var('CFLAGS')
+ if not cflags:
+ return False
+ flags = cflags.split()
+ # True if "-mcet -fcf-protection" options are found, but false
+ # if "-fcf-protection=none" or "-fcf-protection=return" is found.
+ return (('-mcet' in flags)
+ and any((flag.startswith('-fcf-protection')
+ and not flag.endswith(("=none", "=return")))
+ for flag in flags))
+
+# Control-flow enforcement technology
+CET_PROTECTION = cet_protection()
+
+
def run_gdb(*args, **env_vars):
"""Runs gdb in --batch mode with the additional arguments given by *args.
commands += ['set print entry-values no']
if cmds_after_breakpoint:
+ if CET_PROTECTION:
+ # bpo-32962: When Python is compiled with -mcet
+ # -fcf-protection, function arguments are unusable before
+ # running the first instruction of the function entry point.
+ # The 'next' command makes the required first step.
+ commands += ['next']
commands += cmds_after_breakpoint
else:
commands += ['backtrace']
for line in errlines:
if not line:
continue
+ # bpo34007: Sometimes some versions of the shared libraries that
+ # are part of the traceback are compiled in optimised mode and the
+ # Program Counter (PC) is not present, not allowing gdb to walk the
+ # frames back. When this happens, the Python bindings of gdb raise
+ # an exception, making the test impossible to succeed.
+ if "PC not saved" in line:
+ raise unittest.SkipTest("gdb cannot walk the frame object"
+ " because the Program Counter is"
+ " not present")
if not line.startswith(ignore_patterns):
unexpected_errlines.append(line)
id("first break point")
l = MyList()
''')
+ cmds_after_breakpoint = ['break wrapper_call', 'continue']
+ if CET_PROTECTION:
+ # bpo-32962: same case as in get_stack_trace():
+ # we need an additional 'next' command in order to read
+ # arguments of the innermost function of the call stack.
+ cmds_after_breakpoint.append('next')
+ cmds_after_breakpoint.append('py-bt')
+
# Verify with "py-bt":
gdb_output = self.get_stack_trace(cmd,
- cmds_after_breakpoint=['break wrapper_call', 'continue', 'py-bt'])
+ cmds_after_breakpoint=cmds_after_breakpoint)
self.assertRegex(gdb_output,
r"<method-wrapper u?'__init__' of MyList object at ")
def test_exists(self):
filename = support.TESTFN
+ bfilename = os.fsencode(filename)
self.addCleanup(support.unlink, filename)
self.assertIs(self.pathmodule.exists(filename), False)
+ self.assertIs(self.pathmodule.exists(bfilename), False)
- with open(filename, "xb") as f:
- f.write(b"foo")
+ create_file(filename)
self.assertIs(self.pathmodule.exists(filename), True)
+ self.assertIs(self.pathmodule.exists(bfilename), True)
- if not self.pathmodule == genericpath:
+ if self.pathmodule is not genericpath:
self.assertIs(self.pathmodule.lexists(filename), True)
+ self.assertIs(self.pathmodule.lexists(bfilename), True)
@unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()")
def test_exists_fd(self):
os.close(w)
self.assertFalse(self.pathmodule.exists(r))
- def test_isdir_file(self):
+ def test_isdir(self):
filename = support.TESTFN
- self.addCleanup(support.unlink, filename)
- self.assertIs(self.pathmodule.isdir(filename), False)
-
- create_file(filename)
+ bfilename = os.fsencode(filename)
self.assertIs(self.pathmodule.isdir(filename), False)
+ self.assertIs(self.pathmodule.isdir(bfilename), False)
- def test_isdir_dir(self):
- filename = support.TESTFN
- self.addCleanup(support.rmdir, filename)
- self.assertIs(self.pathmodule.isdir(filename), False)
+ try:
+ create_file(filename)
+ self.assertIs(self.pathmodule.isdir(filename), False)
+ self.assertIs(self.pathmodule.isdir(bfilename), False)
+ finally:
+ support.unlink(filename)
- os.mkdir(filename)
- self.assertIs(self.pathmodule.isdir(filename), True)
+ try:
+ os.mkdir(filename)
+ self.assertIs(self.pathmodule.isdir(filename), True)
+ self.assertIs(self.pathmodule.isdir(bfilename), True)
+ finally:
+ support.rmdir(filename)
- def test_isfile_file(self):
+ def test_isfile(self):
filename = support.TESTFN
- self.addCleanup(support.unlink, filename)
+ bfilename = os.fsencode(filename)
self.assertIs(self.pathmodule.isfile(filename), False)
+ self.assertIs(self.pathmodule.isfile(bfilename), False)
- create_file(filename)
- self.assertIs(self.pathmodule.isfile(filename), True)
-
- def test_isfile_dir(self):
- filename = support.TESTFN
- self.addCleanup(support.rmdir, filename)
- self.assertIs(self.pathmodule.isfile(filename), False)
+ try:
+ create_file(filename)
+ self.assertIs(self.pathmodule.isfile(filename), True)
+ self.assertIs(self.pathmodule.isfile(bfilename), True)
+ finally:
+ support.unlink(filename)
- os.mkdir(filename)
- self.assertIs(self.pathmodule.isfile(filename), False)
+ try:
+ os.mkdir(filename)
+ self.assertIs(self.pathmodule.isfile(filename), False)
+ self.assertIs(self.pathmodule.isfile(bfilename), False)
+ finally:
+ support.rmdir(filename)
def test_samefile(self):
file1 = support.TESTFN
# and is only meant to be inherited by others.
pathmodule = genericpath
- def test_null_bytes(self):
+ def test_invalid_paths(self):
for attr in GenericTest.common_attributes:
# os.path.commonprefix doesn't raise ValueError
if attr == 'commonprefix':
continue
+ func = getattr(self.pathmodule, attr)
with self.subTest(attr=attr):
- with self.assertRaises(ValueError) as cm:
- getattr(self.pathmodule, attr)('/tmp\x00abcds')
- self.assertIn('embedded null', str(cm.exception))
+ try:
+ func('/tmp\udfffabcds')
+ except (OSError, UnicodeEncodeError):
+ pass
+ try:
+ func(b'/tmp\xffabcds')
+ except (OSError, UnicodeDecodeError):
+ pass
+ with self.assertRaisesRegex(ValueError, 'embedded null'):
+ func('/tmp\x00abcds')
+ with self.assertRaisesRegex(ValueError, 'embedded null'):
+ func(b'/tmp\x00abcds')
# Following TestCase is not supposed to be run from test_genericpath.
# It is inherited by other test modules (macpath, ntpath, posixpath).
self.assertTrue(os.path.samefile(self.file_path, self.file_name))
-if __name__=="__main__":
+if __name__ == "__main__":
unittest.main()
import unittest
import math
+import string
import sys
from test import support
# Skip this test if the _testcapi module isn't available.
-support.import_module('_testcapi')
+_testcapi = support.import_module('_testcapi')
from _testcapi import getargs_keywords, getargs_keyword_only
# > How about the following counterproposal. This also changes some of
self.assertRaises(TypeError, getargs_U, None)
+# Bug #6012
+class Test6012(unittest.TestCase):
+ def test(self):
+ self.assertEqual(_testcapi.argparsing("Hello", "World"), 1)
+
+
+class SkipitemTest(unittest.TestCase):
+
+ def test_skipitem(self):
+ """
+ If this test failed, you probably added a new "format unit"
+ in Python/getargs.c, but neglected to update our poor friend
+ skipitem() in the same file. (If so, shame on you!)
+
+ With a few exceptions**, this function brute-force tests all
+ printable ASCII*** characters (32 to 126 inclusive) as format units,
+ checking to see that PyArg_ParseTupleAndKeywords() return consistent
+ errors both when the unit is attempted to be used and when it is
+ skipped. If the format unit doesn't exist, we'll get one of two
+ specific error messages (one for used, one for skipped); if it does
+ exist we *won't* get that error--we'll get either no error or some
+ other error. If we get the specific "does not exist" error for one
+ test and not for the other, there's a mismatch, and the test fails.
+
+ ** Some format units have special funny semantics and it would
+ be difficult to accommodate them here. Since these are all
+ well-established and properly skipped in skipitem() we can
+ get away with not testing them--this test is really intended
+ to catch *new* format units.
+
+ *** Python C source files must be ASCII. Therefore it's impossible
+ to have non-ASCII format units.
+
+ """
+ empty_tuple = ()
+ tuple_1 = (0,)
+ dict_b = {'b':1}
+ keywords = ["a", "b"]
+
+ for i in range(32, 127):
+ c = chr(i)
+
+ # skip parentheses, the error reporting is inconsistent about them
+ # skip 'e', it's always a two-character code
+ # skip '|' and '$', they don't represent arguments anyway
+ if c in '()e|$':
+ continue
+
+ # test the format unit when not skipped
+ format = c + "i"
+ try:
+ _testcapi.parse_tuple_and_keywords(tuple_1, dict_b,
+ format, keywords)
+ when_not_skipped = False
+ except SystemError as e:
+ s = "argument 1 (impossible<bad format char>)"
+ when_not_skipped = (str(e) == s)
+ except TypeError:
+ when_not_skipped = False
+
+ # test the format unit when skipped
+ optional_format = "|" + format
+ try:
+ _testcapi.parse_tuple_and_keywords(empty_tuple, dict_b,
+ optional_format, keywords)
+ when_skipped = False
+ except SystemError as e:
+ s = "impossible<bad format char>: '{}'".format(format)
+ when_skipped = (str(e) == s)
+
+ message = ("test_skipitem_parity: "
+ "detected mismatch between convertsimple and skipitem "
+ "for format unit '{}' ({}), not skipped {}, skipped {}".format(
+ c, i, when_skipped, when_not_skipped))
+ self.assertIs(when_skipped, when_not_skipped, message)
+
+ def test_skipitem_with_suffix(self):
+ parse = _testcapi.parse_tuple_and_keywords
+ empty_tuple = ()
+ tuple_1 = (0,)
+ dict_b = {'b':1}
+ keywords = ["a", "b"]
+
+ supported = ('s#', 's*', 'z#', 'z*', 'u#', 'Z#', 'y#', 'y*', 'w#', 'w*')
+ for c in string.ascii_letters:
+ for c2 in '#*':
+ f = c + c2
+ with self.subTest(format=f):
+ optional_format = "|" + f + "i"
+ if f in supported:
+ parse(empty_tuple, dict_b, optional_format, keywords)
+ else:
+ with self.assertRaisesRegex(SystemError,
+ 'impossible<bad format char>'):
+ parse(empty_tuple, dict_b, optional_format, keywords)
+
+ for c in map(chr, range(32, 128)):
+ f = 'e' + c
+ optional_format = "|" + f + "i"
+ with self.subTest(format=f):
+ if c in 'st':
+ parse(empty_tuple, dict_b, optional_format, keywords)
+ else:
+ with self.assertRaisesRegex(SystemError,
+ 'impossible<bad format char>'):
+ parse(empty_tuple, dict_b, optional_format, keywords)
+
+
+class ParseTupleAndKeywords_Test(unittest.TestCase):
+
+ def test_parse_tuple_and_keywords(self):
+ # Test handling errors in the parse_tuple_and_keywords helper itself
+ self.assertRaises(TypeError, _testcapi.parse_tuple_and_keywords,
+ (), {}, 42, [])
+ self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords,
+ (), {}, '', 42)
+ self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords,
+ (), {}, '', [''] * 42)
+ self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords,
+ (), {}, '', [42])
+
+ def test_bad_use(self):
+ # Test handling invalid format and keywords in
+ # PyArg_ParseTupleAndKeywords()
+ self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
+ (1,), {}, '||O', ['a'])
+ self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
+ (1, 2), {}, '|O|O', ['a', 'b'])
+ self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
+ (), {'a': 1}, '$$O', ['a'])
+ self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
+ (), {'a': 1, 'b': 2}, '$O$O', ['a', 'b'])
+ self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
+ (), {'a': 1}, '$|O', ['a'])
+ self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
+ (), {'a': 1, 'b': 2}, '$O|O', ['a', 'b'])
+ self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
+ (1,), {}, '|O', ['a', 'b'])
+ self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
+ (1,), {}, '|OO', ['a'])
+ self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
+ (), {}, '|$O', [''])
+ self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
+ (), {}, '|OO', ['a', ''])
+
+ def test_positional_only(self):
+ parse = _testcapi.parse_tuple_and_keywords
+
+ parse((1, 2, 3), {}, 'OOO', ['', '', 'a'])
+ parse((1, 2), {'a': 3}, 'OOO', ['', '', 'a'])
+ with self.assertRaisesRegex(TypeError,
+ r'Function takes at least 2 positional arguments \(1 given\)'):
+ parse((1,), {'a': 3}, 'OOO', ['', '', 'a'])
+ parse((1,), {}, 'O|OO', ['', '', 'a'])
+ with self.assertRaisesRegex(TypeError,
+ r'Function takes at least 1 positional arguments \(0 given\)'):
+ parse((), {}, 'O|OO', ['', '', 'a'])
+ parse((1, 2), {'a': 3}, 'OO$O', ['', '', 'a'])
+ with self.assertRaisesRegex(TypeError,
+ r'Function takes exactly 2 positional arguments \(1 given\)'):
+ parse((1,), {'a': 3}, 'OO$O', ['', '', 'a'])
+ parse((1,), {}, 'O|O$O', ['', '', 'a'])
+ with self.assertRaisesRegex(TypeError,
+ r'Function takes at least 1 positional arguments \(0 given\)'):
+ parse((), {}, 'O|O$O', ['', '', 'a'])
+ with self.assertRaisesRegex(SystemError, r'Empty parameter name after \$'):
+ parse((1,), {}, 'O|$OO', ['', '', 'a'])
+ with self.assertRaisesRegex(SystemError, 'Empty keyword'):
+ parse((1,), {}, 'O|OO', ['', 'a', ''])
+
+
+class Test_testcapi(unittest.TestCase):
+ locals().update((name, getattr(_testcapi, name))
+ for name in dir(_testcapi)
+ if name.startswith('test_') and name.endswith('_code'))
+
+
if __name__ == "__main__":
unittest.main()
"""Test script for the gzip module.
"""
-import unittest
-from test import support
-from test.support import bigmemtest, _4G
+import array
+import functools
+import io
import os
import pathlib
-import io
import struct
-import array
+import sys
+import unittest
+from subprocess import PIPE, Popen
+from test import support
+from test.support import _4G, bigmemtest
+from test.support.script_helper import assert_python_ok
+
gzip = support.import_module('gzip')
data1 = b""" int length=DEFAULTALLOC, err = Z_OK;
"""
+TEMPDIR = os.path.abspath(support.TESTFN) + '-gzdir'
+
+
class UnseekableIO(io.BytesIO):
def seekable(self):
return False
with gzip.open(self.filename, "rt", newline="\r") as f:
self.assertEqual(f.readlines(), [uncompressed])
+
+def create_and_remove_directory(directory):
+ def decorator(function):
+ @functools.wraps(function)
+ def wrapper(*args, **kwargs):
+ os.makedirs(directory)
+ try:
+ return function(*args, **kwargs)
+ finally:
+ support.rmtree(directory)
+ return wrapper
+ return decorator
+
+
+class TestCommandLine(unittest.TestCase):
+ data = b'This is a simple test with gzip'
+
+ def test_decompress_stdin_stdout(self):
+ with io.BytesIO() as bytes_io:
+ with gzip.GzipFile(fileobj=bytes_io, mode='wb') as gzip_file:
+ gzip_file.write(self.data)
+
+ args = sys.executable, '-m', 'gzip', '-d'
+ with Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) as proc:
+ out, err = proc.communicate(bytes_io.getvalue())
+
+ self.assertEqual(err, b'')
+ self.assertEqual(out, self.data)
+
+ @create_and_remove_directory(TEMPDIR)
+ def test_decompress_infile_outfile(self):
+ gzipname = os.path.join(TEMPDIR, 'testgzip.gz')
+ self.assertFalse(os.path.exists(gzipname))
+
+ with gzip.open(gzipname, mode='wb') as fp:
+ fp.write(self.data)
+ rc, out, err = assert_python_ok('-m', 'gzip', '-d', gzipname)
+
+ with open(os.path.join(TEMPDIR, "testgzip"), "rb") as gunziped:
+ self.assertEqual(gunziped.read(), self.data)
+
+ self.assertTrue(os.path.exists(gzipname))
+ self.assertEqual(rc, 0)
+ self.assertEqual(out, b'')
+ self.assertEqual(err, b'')
+
+ def test_decompress_infile_outfile_error(self):
+ rc, out, err = assert_python_ok('-m', 'gzip', '-d', 'thisisatest.out')
+ self.assertIn(b"filename doesn't end in .gz:", out)
+ self.assertEqual(rc, 0)
+ self.assertEqual(err, b'')
+
+ @create_and_remove_directory(TEMPDIR)
+ def test_compress_stdin_outfile(self):
+ args = sys.executable, '-m', 'gzip'
+ with Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) as proc:
+ out, err = proc.communicate(self.data)
+
+ self.assertEqual(err, b'')
+ self.assertEqual(out[:2], b"\x1f\x8b")
+
+ @create_and_remove_directory(TEMPDIR)
+ def test_compress_infile_outfile(self):
+ local_testgzip = os.path.join(TEMPDIR, 'testgzip')
+ gzipname = local_testgzip + '.gz'
+ self.assertFalse(os.path.exists(gzipname))
+
+ with open(local_testgzip, 'wb') as fp:
+ fp.write(self.data)
+
+ rc, out, err = assert_python_ok('-m', 'gzip', local_testgzip)
+
+ self.assertTrue(os.path.exists(gzipname))
+ self.assertEqual(rc, 0)
+ self.assertEqual(out, b'')
+ self.assertEqual(err, b'')
+
+
def test_main(verbose=None):
- support.run_unittest(TestGzip, TestOpen)
+ support.run_unittest(TestGzip, TestOpen, TestCommandLine)
+
if __name__ == "__main__":
test_main(verbose=True)
self.assertIsInstance(h.digest(), bytes)
self.assertEqual(hexstr(h.digest()), h.hexdigest())
+ def test_digest_length_overflow(self):
+ # See issue #34922
+ large_sizes = (2**29, 2**32-10, 2**32+10, 2**61, 2**64-10, 2**64+10)
+ for cons in self.hash_constructors:
+ h = cons()
+ if h.name not in self.shakes:
+ continue
+ for digest in h.digest, h.hexdigest:
+ with self.assertRaises((ValueError, OverflowError)):
+ digest(-10)
+ for length in large_sizes:
+ with self.assertRaises((ValueError, OverflowError)):
+ digest(length)
+
def test_name_attribute(self):
for cons in self.hash_constructors:
h = cons()
self.assertRaises(OverflowError, constructor, node_offset=-1)
self.assertRaises(OverflowError, constructor, node_offset=max_offset+1)
+ self.assertRaises(TypeError, constructor, data=b'')
+ self.assertRaises(TypeError, constructor, string=b'')
+ self.assertRaises(TypeError, constructor, '')
+
constructor(
- string=b'',
+ b'',
key=b'',
salt=b'',
person=b'',
with self.assertRaisesRegex(ValueError, 'Invalid header'):
conn.putheader(name, value)
+ def test_headers_debuglevel(self):
+ body = (
+ b'HTTP/1.1 200 OK\r\n'
+ b'First: val\r\n'
+ b'Second: val\r\n'
+ )
+ sock = FakeSocket(body)
+ resp = client.HTTPResponse(sock, debuglevel=1)
+ with support.captured_stdout() as output:
+ resp.begin()
+ lines = output.getvalue().splitlines()
+ self.assertEqual(lines[0], "reply: 'HTTP/1.1 200 OK\\r\\n'")
+ self.assertEqual(lines[1], "header: First: val")
+ self.assertEqual(lines[2], "header: Second: val")
+
class TransferEncodingTest(TestCase):
expected_body = b"It's just a flesh wound"
threading = support.import_module('threading')
from contextlib import contextmanager
+import errno
import imaplib
import os.path
import socketserver
for t in self.timevalues():
imaplib.Time2Internaldate(t)
+ def test_imap4_host_default_value(self):
+ expected_errnos = [
+ # This is the exception that should be raised.
+ errno.ECONNREFUSED,
+ ]
+ if hasattr(errno, 'EADDRNOTAVAIL'):
+ # socket.create_connection() fails randomly with
+ # EADDRNOTAVAIL on Travis CI.
+ expected_errnos.append(errno.EADDRNOTAVAIL)
+ with self.assertRaises(OSError) as cm:
+ imaplib.IMAP4()
+ self.assertIn(cm.exception.errno, expected_errnos)
+
if ssl:
class SecureTCPServer(socketserver.TCPServer):
unload(TESTFN)
importlib.invalidate_caches()
m = __import__(TESTFN)
- self.assertEqual(m.__file__,
- os.path.join(os.curdir, os.path.relpath(pyc_file)))
+ try:
+ self.assertEqual(m.__file__,
+ os.path.join(os.curdir, os.path.relpath(pyc_file)))
+ finally:
+ os.remove(pyc_file)
def test___cached__(self):
# Modules now also have an __cached__ that points to the pyc file.
Test release compatibility issues relating to importlib
"""
@unittest.skipUnless(
- sys.version_info.releaselevel in ('final', 'release'),
+ sys.version_info.releaselevel in ('candidate', 'final'),
'only applies to candidate or final python release levels'
)
def test_magic_number(self):
def sourcerange(self, top, bottom):
lines = self.source.split("\n")
- return "\n".join(lines[top-1:bottom]) + "\n"
+ return "\n".join(lines[top-1:bottom]) + ("\n" if bottom else "")
def assertSourceEqual(self, obj, top, bottom):
self.assertEqual(inspect.getsource(obj),
def test_getsource_on_code_object(self):
self.assertSourceEqual(mod.eggs.__code__, 12, 18)
+class TestGettingSourceOfToplevelFrames(GetSourceBase):
+ fodderModule = mod
+
+ def test_range_toplevel_frame(self):
+ self.maxDiff = None
+ self.assertSourceEqual(mod.currentframe, 1, None)
+
+ def test_range_traceback_toplevel_frame(self):
+ self.assertSourceEqual(mod.tb, 1, None)
+
class TestDecorators(GetSourceBase):
fodderModule = mod2
TestBoundArguments, TestSignaturePrivateHelpers,
TestSignatureDefinitions,
TestGetClosureVars, TestUnwrap, TestMain, TestReload,
- TestGetCoroutineState
+ TestGetCoroutineState, TestGettingSourceOfToplevelFrames
)
if __name__ == "__main__":
self.assertSequenceEqual(buffer[result:], unused)
self.assertEqual(len(reader.avail), avail - result)
+ def test_close_assert(self):
+ class R(self.IOBase):
+ def __setattr__(self, name, value):
+ pass
+ def flush(self):
+ raise OSError()
+ f = R()
+ # This would cause an assertion failure.
+ self.assertRaises(OSError, f.close)
+
class CIOTest(IOTest):
F.tell = lambda x: 0
t = self.TextIOWrapper(F(), encoding='utf-8')
+ def test_issue25862(self):
+ # Assertion failures occurred in tell() after read() and write().
+ t = self.TextIOWrapper(self.BytesIO(b'test'), encoding='ascii')
+ t.read(1)
+ t.read()
+ t.tell()
+ t = self.TextIOWrapper(self.BytesIO(b'test'), encoding='ascii')
+ t.read(1)
+ t.write('x')
+ t.tell()
+
class MemviewBytesIO(io.BytesIO):
'''A BytesIO object whose read method returns memoryviews
@unittest.skipUnless(threading, 'Threading required for this test.')
class SMTPHandlerTest(BaseTest):
- TIMEOUT = 8.0
+ # bpo-14314, bpo-19665, bpo-34092: don't wait forever, timeout of 1 minute
+ TIMEOUT = 60.0
+
def test_basic(self):
sockmap = {}
server = TestSMTPServer((support.HOST, 0), self.process_message, 0.001,
r = logging.makeLogRecord({'msg': 'Hello \u2713'})
self.handled = threading.Event()
h.handle(r)
- self.handled.wait(self.TIMEOUT) # 14314: don't wait forever
+ self.handled.wait(self.TIMEOUT)
server.stop()
self.assertTrue(self.handled.is_set())
self.assertEqual(len(self.messages), 1)
"""Reading logging config from a .ini-style config file."""
+ check_no_resource_warning = support.check_no_resource_warning
expected_log_pat = r"^(\w+) \+\+ (\w+)$"
# config0 is a standard configuration.
datefmt=
"""
+ # config 8, check for resource warning
+ config8 = r"""
+ [loggers]
+ keys=root
+
+ [handlers]
+ keys=file
+
+ [formatters]
+ keys=
+
+ [logger_root]
+ level=DEBUG
+ handlers=file
+
+ [handler_file]
+ class=FileHandler
+ level=DEBUG
+ args=("{tempfile}",)
+ """
+
disable_test = """
[loggers]
keys=root
# Original logger output is empty.
self.assert_log_lines([])
+ def test_config8_ok(self):
+
+ def cleanup(h1, fn):
+ h1.close()
+ os.remove(fn)
+
+ with self.check_no_resource_warning():
+ fd, fn = tempfile.mkstemp(".log", "test_logging-X-")
+ os.close(fd)
+
+ # Replace single backslash with double backslash in windows
+ # to avoid unicode error during string formatting
+ if os.name == "nt":
+ fn = fn.replace("\\", "\\\\")
+
+ config8 = self.config8.format(tempfile=fn)
+
+ self.apply_config(config8)
+ self.apply_config(config8)
+
+ handler = logging.root.handlers[0]
+ self.addCleanup(cleanup, handler, fn)
+
def test_logger_disabling(self):
self.apply_config(self.disable_test)
logger = logging.getLogger('some_pristine_logger')
"""Reading logging config from a dictionary."""
+ check_no_resource_warning = support.check_no_resource_warning
expected_log_pat = r"^(\w+) \+\+ (\w+)$"
# config0 is a standard configuration.
logging.warning('Exclamation')
self.assertTrue(output.getvalue().endswith('Exclamation!\n'))
+ def test_config15_ok(self):
+
+ def cleanup(h1, fn):
+ h1.close()
+ os.remove(fn)
+
+ with self.check_no_resource_warning():
+ fd, fn = tempfile.mkstemp(".log", "test_logging-X-")
+ os.close(fd)
+
+ config = {
+ "version": 1,
+ "handlers": {
+ "file": {
+ "class": "logging.FileHandler",
+ "filename": fn
+ }
+ },
+ "root": {
+ "handlers": ["file"]
+ }
+ }
+
+ self.apply_config(config)
+ self.apply_config(config)
+
+ handler = logging.root.handlers[0]
+ self.addCleanup(cleanup, handler, fn)
+
@unittest.skipUnless(threading, 'listen() needs threading to work')
def setup_via_listener(self, text, verify=None):
text = text.encode("utf-8")
for base in invalid_bases:
self.assertRaises(ValueError, int, '42', base)
+ # Invalid unicode string
+ # See bpo-34087
+ self.assertRaises(ValueError, int, '\u3053\u3093\u306b\u3061\u306f')
+
def test_conversion(self):
self.assertRaisesRegex(ValueError, 'Cannot specify both', format, 3, '_,d')
self.assertRaisesRegex(ValueError, 'Cannot specify both', format, 3, ',_d')
+ self.assertRaisesRegex(ValueError, "Cannot specify ',' with 's'", format, 3, ',s')
+ self.assertRaisesRegex(ValueError, "Cannot specify '_' with 's'", format, 3, '_s')
+
# ensure that only int and float type specifiers work
for format_spec in ([chr(x) for x in range(ord('a'), ord('z')+1)] +
[chr(x) for x in range(ord('A'), ord('Z')+1)]):
marshal.dumps([128] * 1000)
def test_patch_873224(self):
- self.assertRaises(Exception, marshal.loads, '0')
- self.assertRaises(Exception, marshal.loads, 'f')
+ self.assertRaises(Exception, marshal.loads, b'0')
+ self.assertRaises(Exception, marshal.loads, b'f')
self.assertRaises(Exception, marshal.loads, marshal.dumps(2**65)[:-1])
def test_version_argument(self):
def test_fuzz(self):
# simple test that it's at least not *totally* trivial to
# crash from bad marshal data
- for c in [chr(i) for i in range(256)]:
+ for i in range(256):
+ c = bytes([i])
try:
marshal.loads(c)
except Exception:
pass
- def test_loads_2x_code(self):
- s = b'c' + (b'X' * 4*4) + b'{' * 2**20
- self.assertRaises(ValueError, marshal.loads, s)
-
def test_loads_recursion(self):
- s = b'c' + (b'X' * 4*5) + b'{' * 2**20
- self.assertRaises(ValueError, marshal.loads, s)
+ def run_tests(N, check):
+ # (((...None...),),)
+ check(b')\x01' * N + b'N')
+ check(b'(\x01\x00\x00\x00' * N + b'N')
+ # [[[...None...]]]
+ check(b'[\x01\x00\x00\x00' * N + b'N')
+ # {None: {None: {None: ...None...}}}
+ check(b'{N' * N + b'N' + b'0' * N)
+ # frozenset([frozenset([frozenset([...None...])])])
+ check(b'>\x01\x00\x00\x00' * N + b'N')
+ # Check that the generated marshal data is valid and marshal.loads()
+ # works for moderately deep nesting
+ run_tests(100, marshal.loads)
+ # Very deeply nested structure shouldn't blow the stack
+ def check(s):
+ self.assertRaises(ValueError, marshal.loads, s)
+ run_tests(2**20, check)
def test_recursion_limit(self):
# Create a deeply nested structure.
self.assertRaises(ValueError, marshal.load,
BadReader(marshal.dumps(value)))
- def _test_eof(self):
+ def test_eof(self):
data = marshal.dumps(("hello", "dolly", None))
for i in range(len(data)):
self.assertRaises(EOFError, marshal.loads, data[0: i])
p = Pool(5)
results = []
p.map_async(f, [1, 2, 3], callback=results.extend)
- deadline = time.time() + 10 # up to 10 s to report the results
+ start_time = time.monotonic()
while not results:
time.sleep(0.05)
- if time.time() > deadline:
- raise RuntimeError("Timed out waiting for results")
+ # up to 1 min to report the results
+ dt = time.monotonic() - start_time
+ if dt > 60.0:
+ raise RuntimeError("Timed out waiting for results (%.1f sec)" % dt)
results.sort()
print(start_method, "->", results)
"""
p = Pool(5)
results = []
p.map_async(int, [1, 4, 9], callback=results.extend)
-deadline = time.time() + 10 # up to 10 s to report the results
+start_time = time.monotonic()
while not results:
time.sleep(0.05)
- if time.time() > deadline:
- raise RuntimeError("Timed out waiting for results")
+ # up to 1 min to report the results
+ dt = time.monotonic() - start_time
+ if dt > 60.0:
+ raise RuntimeError("Timed out waiting for results (%.1f sec)" % dt)
results.sort()
print(start_method, "->", results)
"""
try:
import nt
tester('ntpath.abspath("C:\\")', "C:\\")
+ with support.temp_cwd(support.TESTFN) as cwd_dir: # bpo-31047
+ tester('ntpath.abspath("")', cwd_dir)
+ tester('ntpath.abspath(" ")', cwd_dir + "\\ ")
+ tester('ntpath.abspath("?")', cwd_dir + "\\?")
except ImportError:
self.skipTest('nt module not available')
# Python test set -- part 2, opcodes
import unittest
-from test import ann_module
+from test import ann_module, support
class OpcodeTest(unittest.TestCase):
self.assertEqual(ns['__annotations__'], {'x': int, 1: 2})
def test_do_not_recreate_annotations(self):
- class C:
- del __annotations__
- with self.assertRaises(NameError):
- x: int
+ # Don't rely on the existence of the '__annotations__' global.
+ with support.swap_item(globals(), '__annotations__', {}):
+ del globals()['__annotations__']
+ class C:
+ del __annotations__
+ with self.assertRaises(NameError):
+ x: int
def test_raise_class_exceptions(self):
def __init__(self, conn):
asynchat.async_chat.__init__(self, conn)
self.in_buffer = []
+ self.accumulate = True
self.closed = False
self.push(b"220 ready\r\n")
def handle_read(self):
data = self.recv(4096)
- self.in_buffer.append(data)
+ if self.accumulate:
+ self.in_buffer.append(data)
def get_data(self):
return b''.join(self.in_buffer)
not sys.platform.startswith("sunos")
requires_headers_trailers = unittest.skipUnless(SUPPORT_HEADERS_TRAILERS,
'requires headers and trailers support')
+ requires_32b = unittest.skipUnless(sys.maxsize < 2**32,
+ 'test is only meaningful on 32-bit builds')
@classmethod
def setUpClass(cls):
self.server.stop()
self.server = None
- def sendfile_wrapper(self, sock, file, offset, nbytes, headers=[], trailers=[]):
+ def sendfile_wrapper(self, *args, **kwargs):
"""A higher level wrapper representing how an application is
supposed to use sendfile().
"""
- while 1:
+ while True:
try:
- if self.SUPPORT_HEADERS_TRAILERS:
- return os.sendfile(sock, file, offset, nbytes, headers,
- trailers)
- else:
- return os.sendfile(sock, file, offset, nbytes)
+ return os.sendfile(*args, **kwargs)
except OSError as err:
if err.errno == errno.ECONNRESET:
# disconnected
@requires_headers_trailers
def test_headers(self):
total_sent = 0
+ expected_data = b"x" * 512 + b"y" * 256 + self.DATA[:-1]
sent = os.sendfile(self.sockno, self.fileno, 0, 4096,
- headers=[b"x" * 512])
+ headers=[b"x" * 512, b"y" * 256])
+ self.assertLessEqual(sent, 512 + 256 + 4096)
total_sent += sent
offset = 4096
- nbytes = 4096
- while 1:
+ while total_sent < len(expected_data):
+ nbytes = min(len(expected_data) - total_sent, 4096)
sent = self.sendfile_wrapper(self.sockno, self.fileno,
offset, nbytes)
if sent == 0:
break
+ self.assertLessEqual(sent, nbytes)
total_sent += sent
offset += sent
- expected_data = b"x" * 512 + self.DATA
self.assertEqual(total_sent, len(expected_data))
self.client.close()
self.server.wait()
create_file(TESTFN2, file_data)
with open(TESTFN2, 'rb') as f:
- os.sendfile(self.sockno, f.fileno(), 0, len(file_data),
- trailers=[b"1234"])
+ os.sendfile(self.sockno, f.fileno(), 0, 5,
+ trailers=[b"123456", b"789"])
self.client.close()
self.server.wait()
data = self.server.handler_instance.get_data()
- self.assertEqual(data, b"abcdef1234")
+ self.assertEqual(data, b"abcde123456789")
+
+ @requires_headers_trailers
+ @requires_32b
+ def test_headers_overflow_32bits(self):
+ self.server.handler_instance.accumulate = False
+ with self.assertRaises(OSError) as cm:
+ os.sendfile(self.sockno, self.fileno, 0, 0,
+ headers=[b"x" * 2**16] * 2**15)
+ self.assertEqual(cm.exception.errno, errno.EINVAL)
+
+ @requires_headers_trailers
+ @requires_32b
+ def test_trailers_overflow_32bits(self):
+ self.server.handler_instance.accumulate = False
+ with self.assertRaises(OSError) as cm:
+ os.sendfile(self.sockno, self.fileno, 0, 0,
+ trailers=[b"x" * 2**16] * 2**15)
+ self.assertEqual(cm.exception.errno, errno.EINVAL)
@requires_headers_trailers
@unittest.skipUnless(hasattr(os, 'SF_NODISKIO'),
import tempfile
import textwrap
import unittest
-from test import support
# Helpers to create and destroy hierarchies.
self.root = None
self.pkgname = None
self.syspath = list(sys.path)
- self.modules_before = support.modules_setup()
+ self.modules_to_cleanup = set() # Populated by mkhier().
def tearDown(self):
sys.path[:] = self.syspath
- support.modules_cleanup(*self.modules_before)
+ for modulename in self.modules_to_cleanup:
+ if modulename in sys.modules:
+ del sys.modules[modulename]
if self.root: # Only clean if the test was actually run
cleanout(self.root)
os.mkdir(root)
for name, contents in descr:
comps = name.split()
+ self.modules_to_cleanup.add('.'.join(comps))
fullname = root
for c in comps:
fullname = os.path.join(fullname, c)
if contents is None:
os.mkdir(fullname)
else:
- f = open(fullname, "w")
- f.write(contents)
- if contents and contents[-1] != '\n':
- f.write('\n')
- f.close()
+ with open(fullname, "w") as f:
+ f.write(contents)
+ if not contents.endswith('\n'):
+ f.write('\n')
self.root = root
# package name is the name of the first item
self.pkgname = descr[0][0]
s = """
from t2 import *
- self.assertTrue(dir(), ['self', 'sub'])
+ self.assertEqual(dir(), ['self', 'sub'])
"""
self.run_code(s)
import platform
import subprocess
import sys
+import sysconfig
import tempfile
import unittest
import warnings
@support.skip_unless_symlink
def test_architecture_via_symlink(self): # issue3762
# On Windows, the EXE needs to know where pythonXY.dll and *.pyd is at
- # so we add the directory to the path and PYTHONPATH.
+ # so we add the directory to the path, PYTHONHOME and PYTHONPATH.
+ env = None
if sys.platform == "win32":
- def restore_environ(old_env):
- os.environ.clear()
- os.environ.update(old_env)
-
- self.addCleanup(restore_environ, dict(os.environ))
-
- os.environ["Path"] = "{};{}".format(
- os.path.dirname(sys.executable), os.environ["Path"])
- os.environ["PYTHONPATH"] = os.path.dirname(sys.executable)
-
- def get(python):
+ env = {k.upper(): os.environ[k] for k in os.environ}
+ env["PATH"] = "{};{}".format(
+ os.path.dirname(sys.executable), env.get("PATH", ""))
+ env["PYTHONHOME"] = os.path.dirname(sys.executable)
+ if sysconfig.is_python_build(True):
+ env["PYTHONPATH"] = os.path.dirname(os.__file__)
+
+ def get(python, env=None):
cmd = [python, '-c',
'import platform; print(platform.architecture())']
- p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
- return p.communicate()
+ p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, env=env)
+ r = p.communicate()
+ if p.returncode:
+ print(repr(r[0]))
+ print(repr(r[1]), file=sys.stderr)
+ self.fail('unexpected return code: {0} (0x{0:08X})'
+ .format(p.returncode))
+ return r
real = os.path.realpath(sys.executable)
link = os.path.abspath(support.TESTFN)
os.symlink(real, link)
try:
- self.assertEqual(get(real), get(link))
+ self.assertEqual(get(real), get(link, env=env))
finally:
os.remove(link)
res = platform.dist()
def test_libc_ver(self):
- import os
if os.path.isdir(sys.executable) and \
os.path.exists(sys.executable+'.exe'):
# Cygwin horror
executable = sys.executable
res = platform.libc_ver(executable)
+ self.addCleanup(support.unlink, support.TESTFN)
+ with open(support.TESTFN, 'wb') as f:
+ f.write(b'x'*(16384-10))
+ f.write(b'GLIBC_1.23.4\0GLIBC_1.9\0GLIBC_1.21\0')
+ self.assertEqual(platform.libc_ver(support.TESTFN),
+ ('glibc', '1.23.4'))
+
+ @support.cpython_only
+ def test__comparable_version(self):
+ from platform import _comparable_version as V
+ self.assertEqual(V('1.2.3'), V('1.2.3'))
+ self.assertLess(V('1.2.3'), V('1.2.10'))
+ self.assertEqual(V('1.2.3.4'), V('1_2-3+4'))
+ self.assertLess(V('1.2spam'), V('1.2dev'))
+ self.assertLess(V('1.2dev'), V('1.2alpha'))
+ self.assertLess(V('1.2dev'), V('1.2a'))
+ self.assertLess(V('1.2alpha'), V('1.2beta'))
+ self.assertLess(V('1.2a'), V('1.2b'))
+ self.assertLess(V('1.2beta'), V('1.2c'))
+ self.assertLess(V('1.2b'), V('1.2c'))
+ self.assertLess(V('1.2c'), V('1.2RC'))
+ self.assertLess(V('1.2c'), V('1.2rc'))
+ self.assertLess(V('1.2RC'), V('1.2.0'))
+ self.assertLess(V('1.2rc'), V('1.2.0'))
+ self.assertLess(V('1.2.0'), V('1.2pl'))
+ self.assertLess(V('1.2.0'), V('1.2p'))
+
+ self.assertLess(V('1.5.1'), V('1.5.2b2'))
+ self.assertLess(V('3.10a'), V('161'))
+ self.assertEqual(V('8.02'), V('8.02'))
+ self.assertLess(V('3.4j'), V('1996.07.12'))
+ self.assertLess(V('3.1.1.6'), V('3.2.pl0'))
+ self.assertLess(V('2g6'), V('11g'))
+ self.assertLess(V('0.9'), V('2.2'))
+ self.assertLess(V('1.2'), V('1.2.1'))
+ self.assertLess(V('1.1'), V('1.2.2'))
+ self.assertLess(V('1.1'), V('1.2'))
+ self.assertLess(V('1.2.1'), V('1.2.2'))
+ self.assertLess(V('1.2'), V('1.2.2'))
+ self.assertLess(V('0.4'), V('0.4.0'))
+ self.assertLess(V('1.13++'), V('5.5.kw'))
+ self.assertLess(V('0.960923'), V('2.2beta29'))
+
def test_parse_release_file(self):
for input, output in (
_DUMMY_SYMLINK = os.path.join(tempfile.gettempdir(),
support.TESTFN + '-dummy-symlink')
+requires_32b = unittest.skipUnless(sys.maxsize < 2**32,
+ 'test is only meaningful on 32-bit builds')
+
+def _supports_sched():
+ if not hasattr(posix, 'sched_getscheduler'):
+ return False
+ try:
+ posix.sched_getscheduler(0)
+ except OSError as e:
+ if e.errno == errno.ENOSYS:
+ return False
+ return True
+
+requires_sched = unittest.skipUnless(_supports_sched(), 'requires POSIX scheduler API')
+
class PosixTester(unittest.TestCase):
def setUp(self):
finally:
os.close(fd)
+ @unittest.skipUnless(hasattr(posix, 'writev'), "test needs posix.writev()")
+ @requires_32b
+ def test_writev_overflow_32bits(self):
+ fd = os.open(support.TESTFN, os.O_RDWR | os.O_CREAT)
+ try:
+ with self.assertRaises(OSError) as cm:
+ os.writev(fd, [b"x" * 2**16] * 2**15)
+ self.assertEqual(cm.exception.errno, errno.EINVAL)
+ finally:
+ os.close(fd)
+
@unittest.skipUnless(hasattr(posix, 'readv'), "test needs posix.readv()")
def test_readv(self):
fd = os.open(support.TESTFN, os.O_RDWR | os.O_CREAT)
finally:
os.close(fd)
+ @unittest.skipUnless(hasattr(posix, 'readv'), "test needs posix.readv()")
+ @requires_32b
+ def test_readv_overflow_32bits(self):
+ fd = os.open(support.TESTFN, os.O_RDWR | os.O_CREAT)
+ try:
+ buf = [bytearray(2**16)] * 2**15
+ with self.assertRaises(OSError) as cm:
+ os.readv(fd, buf)
+ self.assertEqual(cm.exception.errno, errno.EINVAL)
+ self.assertEqual(bytes(buf[0]), b'\0'* 2**16)
+ finally:
+ os.close(fd)
+
@unittest.skipUnless(hasattr(posix, 'dup'),
'test needs posix.dup()')
def test_dup(self):
self.assertRaises(OSError, posix.sched_get_priority_min, -23)
self.assertRaises(OSError, posix.sched_get_priority_max, -23)
- @unittest.skipUnless(hasattr(posix, 'sched_setscheduler'), "can't change scheduler")
+ @requires_sched
def test_get_and_set_scheduler_and_param(self):
possible_schedulers = [sched for name, sched in posix.__dict__.items()
if name.startswith("SCHED_")]
def test_islink(self):
self.assertIs(posixpath.islink(support.TESTFN + "1"), False)
self.assertIs(posixpath.lexists(support.TESTFN + "2"), False)
- f = open(support.TESTFN + "1", "wb")
- try:
+ with open(support.TESTFN + "1", "wb") as f:
f.write(b"foo")
- f.close()
- self.assertIs(posixpath.islink(support.TESTFN + "1"), False)
- if support.can_symlink():
- os.symlink(support.TESTFN + "1", support.TESTFN + "2")
- self.assertIs(posixpath.islink(support.TESTFN + "2"), True)
- os.remove(support.TESTFN + "1")
- self.assertIs(posixpath.islink(support.TESTFN + "2"), True)
- self.assertIs(posixpath.exists(support.TESTFN + "2"), False)
- self.assertIs(posixpath.lexists(support.TESTFN + "2"), True)
- finally:
- if not f.close():
- f.close()
+ self.assertIs(posixpath.islink(support.TESTFN + "1"), False)
+ if support.can_symlink():
+ os.symlink(support.TESTFN + "1", support.TESTFN + "2")
+ self.assertIs(posixpath.islink(support.TESTFN + "2"), True)
+ os.remove(support.TESTFN + "1")
+ self.assertIs(posixpath.islink(support.TESTFN + "2"), True)
+ self.assertIs(posixpath.exists(support.TESTFN + "2"), False)
+ self.assertIs(posixpath.lexists(support.TESTFN + "2"), True)
def test_ismount(self):
self.assertIs(posixpath.ismount("/"), True)
- with warnings.catch_warnings():
- warnings.simplefilter("ignore", DeprecationWarning)
- self.assertIs(posixpath.ismount(b"/"), True)
+ self.assertIs(posixpath.ismount(b"/"), True)
def test_ismount_non_existent(self):
# Non-existent mountpoint.
import xml.sax
from xml.sax.xmlreader import AttributesImpl
+from xml.sax.handler import feature_external_ges
from xml.dom import pulldom
from test.support import findfile
self.fail(
"Ran out of events, but should have received END_DOCUMENT")
+ def test_external_ges_default(self):
+ parser = pulldom.parseString(SMALL_SAMPLE)
+ saxparser = parser.parser
+ ges = saxparser.getFeature(feature_external_ges)
+ self.assertEqual(ges, False)
+
class ThoroughTestCase(unittest.TestCase):
"""Test the hard-to-reach parts of pulldom."""
with self.assertRaises(IndexError):
choices([], cum_weights=[], k=5)
+ def test_choices_subnormal(self):
+ # Subnormal weights would occassionally trigger an IndexError
+ # in choices() when the value returned by random() was large
+ # enough to make `random() * total` round up to the total.
+ # See https://bugs.python.org/msg275594 for more detail.
+ choices = self.gen.choices
+ choices(population=[1, 2], weights=[1e-323, 1e-323], k=5000)
+
def test_gauss(self):
# Ensure that the seed() method initializes all the hidden state. In
# particular, through 2.2.1 it failed to reset a piece of state used
import unittest
from test import libregrtest
from test import support
+from test.libregrtest import utils
Py_DEBUG = hasattr(sys, 'getobjects')
failed=testname, rerun=testname)
+class TestUtils(unittest.TestCase):
+ def test_format_duration(self):
+ self.assertEqual(utils.format_duration(0),
+ '0 ms')
+ self.assertEqual(utils.format_duration(1e-9),
+ '1 ms')
+ self.assertEqual(utils.format_duration(10e-3),
+ '10 ms')
+ self.assertEqual(utils.format_duration(1.5),
+ '1 sec 500 ms')
+ self.assertEqual(utils.format_duration(1),
+ '1 sec')
+ self.assertEqual(utils.format_duration(2 * 60),
+ '2 min')
+ self.assertEqual(utils.format_duration(2 * 60 + 1),
+ '2 min 1 sec')
+ self.assertEqual(utils.format_duration(3 * 3600),
+ '3 hour')
+ self.assertEqual(utils.format_duration(3 * 3600 + 2 * 60 + 1),
+ '3 hour 2 min')
+ self.assertEqual(utils.format_duration(3 * 3600 + 1),
+ '3 hour 1 sec')
+
+
if __name__ == '__main__':
unittest.main()
@support.requires_linux_version(2, 6, 36)
def test_prlimit(self):
self.assertRaises(TypeError, resource.prlimit)
- if os.geteuid() != 0:
- self.assertRaises(PermissionError, resource.prlimit,
- 1, resource.RLIMIT_AS)
self.assertRaises(ProcessLookupError, resource.prlimit,
-1, resource.RLIMIT_AS)
limit = resource.getrlimit(resource.RLIMIT_AS)
from xml.sax.saxutils import XMLGenerator, escape, unescape, quoteattr, \
XMLFilterBase, prepare_input_source
from xml.sax.expatreader import create_parser
-from xml.sax.handler import feature_namespaces
+from xml.sax.handler import feature_namespaces, feature_external_ges
from xml.sax.xmlreader import InputSource, AttributesImpl, AttributesNSImpl
from io import BytesIO, StringIO
import codecs
import gc
import os.path
import shutil
+from urllib.error import URLError
from test import support
from test.support import findfile, run_unittest, TESTFN
def unparsedEntityDecl(self, name, publicId, systemId, ndata):
self._entities.append((name, publicId, systemId, ndata))
+
+ class TestEntityRecorder:
+ def __init__(self):
+ self.entities = []
+
+ def resolveEntity(self, publicId, systemId):
+ self.entities.append((publicId, systemId))
+ source = InputSource()
+ source.setPublicId(publicId)
+ source.setSystemId(systemId)
+ return source
+
def test_expat_dtdhandler(self):
parser = create_parser()
handler = self.TestDTDHandler()
[("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)])
self.assertEqual(handler._entities, [("img", None, "expat.gif", "GIF")])
+ def test_expat_external_dtd_enabled(self):
+ parser = create_parser()
+ parser.setFeature(feature_external_ges, True)
+ resolver = self.TestEntityRecorder()
+ parser.setEntityResolver(resolver)
+
+ with self.assertRaises(URLError):
+ parser.feed(
+ '<!DOCTYPE external SYSTEM "unsupported://non-existing">\n'
+ )
+ self.assertEqual(
+ resolver.entities, [(None, 'unsupported://non-existing')]
+ )
+
+ def test_expat_external_dtd_default(self):
+ parser = create_parser()
+ resolver = self.TestEntityRecorder()
+ parser.setEntityResolver(resolver)
+
+ parser.feed(
+ '<!DOCTYPE external SYSTEM "unsupported://non-existing">\n'
+ )
+ parser.feed('<doc />')
+ parser.close()
+ self.assertEqual(resolver.entities, [])
+
# ===== EntityResolver support
class TestEntityResolver:
inpsrc.setByteStream(BytesIO(b"<entity/>"))
return inpsrc
- def test_expat_entityresolver(self):
+ def test_expat_entityresolver_enabled(self):
parser = create_parser()
+ parser.setFeature(feature_external_ges, True)
parser.setEntityResolver(self.TestEntityResolver())
result = BytesIO()
parser.setContentHandler(XMLGenerator(result))
self.assertEqual(result.getvalue(), start +
b"<doc><entity></entity></doc>")
+ def test_expat_entityresolver_default(self):
+ parser = create_parser()
+ self.assertEqual(parser.getFeature(feature_external_ges), False)
+ parser.setEntityResolver(self.TestEntityResolver())
+ result = BytesIO()
+ parser.setContentHandler(XMLGenerator(result))
+
+ parser.feed('<!DOCTYPE doc [\n')
+ parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
+ parser.feed(']>\n')
+ parser.feed('<doc>&test;</doc>')
+ parser.close()
+
+ self.assertEqual(result.getvalue(), start +
+ b"<doc></doc>")
+
# ===== Attributes support
class AttrGatherer(ContentHandler):
import subprocess
import sys
+import os
from test.support import script_helper
import unittest
from unittest import mock
def setUp(self):
self.assertTrue(
- hasattr(script_helper, '__cached_interp_requires_environment'))
+ hasattr(script_helper, '__cached_interp_requires_environment'))
# Reset the private cached state.
script_helper.__dict__['__cached_interp_requires_environment'] = None
@mock.patch('subprocess.check_call')
def test_interpreter_requires_environment_true(self, mock_check_call):
- mock_check_call.side_effect = subprocess.CalledProcessError('', '')
- self.assertTrue(script_helper.interpreter_requires_environment())
- self.assertTrue(script_helper.interpreter_requires_environment())
- self.assertEqual(1, mock_check_call.call_count)
+ with mock.patch.dict(os.environ):
+ os.environ.pop('PYTHONHOME', None)
+ mock_check_call.side_effect = subprocess.CalledProcessError('', '')
+ self.assertTrue(script_helper.interpreter_requires_environment())
+ self.assertTrue(script_helper.interpreter_requires_environment())
+ self.assertEqual(1, mock_check_call.call_count)
@mock.patch('subprocess.check_call')
def test_interpreter_requires_environment_false(self, mock_check_call):
- # The mocked subprocess.check_call fakes a no-error process.
- script_helper.interpreter_requires_environment()
- self.assertFalse(script_helper.interpreter_requires_environment())
- self.assertEqual(1, mock_check_call.call_count)
+ with mock.patch.dict(os.environ):
+ os.environ.pop('PYTHONHOME', None)
+ # The mocked subprocess.check_call fakes a no-error process.
+ script_helper.interpreter_requires_environment()
+ self.assertFalse(script_helper.interpreter_requires_environment())
+ self.assertEqual(1, mock_check_call.call_count)
@mock.patch('subprocess.check_call')
def test_interpreter_requires_environment_details(self, mock_check_call):
- script_helper.interpreter_requires_environment()
- self.assertFalse(script_helper.interpreter_requires_environment())
- self.assertFalse(script_helper.interpreter_requires_environment())
- self.assertEqual(1, mock_check_call.call_count)
- check_call_command = mock_check_call.call_args[0][0]
- self.assertEqual(sys.executable, check_call_command[0])
- self.assertIn('-E', check_call_command)
+ with mock.patch.dict(os.environ):
+ os.environ.pop('PYTHONHOME', None)
+ script_helper.interpreter_requires_environment()
+ self.assertFalse(script_helper.interpreter_requires_environment())
+ self.assertFalse(script_helper.interpreter_requires_environment())
+ self.assertEqual(1, mock_check_call.call_count)
+ check_call_command = mock_check_call.call_args[0][0]
+ self.assertEqual(sys.executable, check_call_command[0])
+ self.assertIn('-E', check_call_command)
+
+ @mock.patch('subprocess.check_call')
+ def test_interpreter_requires_environment_with_pythonhome(self, mock_check_call):
+ with mock.patch.dict(os.environ):
+ os.environ['PYTHONHOME'] = 'MockedHome'
+ self.assertTrue(script_helper.interpreter_requires_environment())
+ self.assertTrue(script_helper.interpreter_requires_environment())
+ self.assertEqual(0, mock_check_call.call_count)
if __name__ == '__main__':
subprocess.check_output(zip_cmd, stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as exc:
details = exc.output.decode(errors="replace")
+ if 'unrecognized option: t' in details:
+ self.skipTest("unzip doesn't support -t")
msg = "{}\n\n**Unzip Output**\n{}"
self.fail(msg.format(exc, details))
signal.signal(signum, handler)
read, write = socket.socketpair()
- read.setblocking(False)
write.setblocking(False)
signal.set_wakeup_fd(write.fileno())
"""
import unittest
import test.support
-from test.support import captured_stderr, TESTFN, EnvironmentVarGuard
+from test.support import (captured_stderr, TESTFN, EnvironmentVarGuard,
+ change_cwd)
import builtins
import os
import sys
# __file__ if abs_paths() does not get run. sys and builtins (the
# only other modules imported before site.py runs) do not have
# __file__ or __cached__ because they are built-in.
- parent = os.path.relpath(os.path.dirname(os.__file__))
- env = os.environ.copy()
- env['PYTHONPATH'] = parent
- code = ('import os, sys',
- # use ASCII to avoid locale issues with non-ASCII directories
- 'os_file = os.__file__.encode("ascii", "backslashreplace")',
- r'sys.stdout.buffer.write(os_file + b"\n")',
- 'os_cached = os.__cached__.encode("ascii", "backslashreplace")',
- r'sys.stdout.buffer.write(os_cached + b"\n")')
- command = '\n'.join(code)
- # First, prove that with -S (no 'import site'), the paths are
- # relative.
- proc = subprocess.Popen([sys.executable, '-S', '-c', command],
- env=env,
- stdout=subprocess.PIPE)
- stdout, stderr = proc.communicate()
-
- self.assertEqual(proc.returncode, 0)
- os__file__, os__cached__ = stdout.splitlines()[:2]
- self.assertFalse(os.path.isabs(os__file__))
- self.assertFalse(os.path.isabs(os__cached__))
- # Now, with 'import site', it works.
- proc = subprocess.Popen([sys.executable, '-c', command],
- env=env,
- stdout=subprocess.PIPE)
- stdout, stderr = proc.communicate()
- self.assertEqual(proc.returncode, 0)
- os__file__, os__cached__ = stdout.splitlines()[:2]
- self.assertTrue(os.path.isabs(os__file__),
- "expected absolute path, got {}"
- .format(os__file__.decode('ascii')))
- self.assertTrue(os.path.isabs(os__cached__),
- "expected absolute path, got {}"
- .format(os__cached__.decode('ascii')))
+ try:
+ parent = os.path.relpath(os.path.dirname(os.__file__))
+ cwd = os.getcwd()
+ except ValueError:
+ # Failure to get relpath probably means we need to chdir
+ # to the same drive.
+ cwd, parent = os.path.split(os.path.dirname(os.__file__))
+ with change_cwd(cwd):
+ env = os.environ.copy()
+ env['PYTHONPATH'] = parent
+ code = ('import os, sys',
+ # use ASCII to avoid locale issues with non-ASCII directories
+ 'os_file = os.__file__.encode("ascii", "backslashreplace")',
+ r'sys.stdout.buffer.write(os_file + b"\n")',
+ 'os_cached = os.__cached__.encode("ascii", "backslashreplace")',
+ r'sys.stdout.buffer.write(os_cached + b"\n")')
+ command = '\n'.join(code)
+ # First, prove that with -S (no 'import site'), the paths are
+ # relative.
+ proc = subprocess.Popen([sys.executable, '-S', '-c', command],
+ env=env,
+ stdout=subprocess.PIPE)
+ stdout, stderr = proc.communicate()
+
+ self.assertEqual(proc.returncode, 0)
+ os__file__, os__cached__ = stdout.splitlines()[:2]
+ self.assertFalse(os.path.isabs(os__file__))
+ self.assertFalse(os.path.isabs(os__cached__))
+ # Now, with 'import site', it works.
+ proc = subprocess.Popen([sys.executable, '-c', command],
+ env=env,
+ stdout=subprocess.PIPE)
+ stdout, stderr = proc.communicate()
+ self.assertEqual(proc.returncode, 0)
+ os__file__, os__cached__ = stdout.splitlines()[:2]
+ self.assertTrue(os.path.isabs(os__file__),
+ "expected absolute path, got {}"
+ .format(os__file__.decode('ascii')))
+ self.assertTrue(os.path.isabs(os__cached__),
+ "expected absolute path, got {}"
+ .format(os__cached__.decode('ascii')))
def test_no_duplicate_paths(self):
# No duplicate paths should exist in sys.path
import unittest
from test import support, mock_socket
+from unittest.mock import Mock
+
+HOST = "localhost"
+HOSTv4 = "127.0.0.1"
+HOSTv6 = "::1"
try:
import threading
"localhost:bogus")
+class DefaultArgumentsTests(unittest.TestCase):
+
+ def setUp(self):
+ self.msg = EmailMessage()
+ self.msg['From'] = 'Páolo <főo@bar.com>'
+ self.smtp = smtplib.SMTP()
+ self.smtp.ehlo = Mock(return_value=(200, 'OK'))
+ self.smtp.has_extn, self.smtp.sendmail = Mock(), Mock()
+
+ def testSendMessage(self):
+ expected_mail_options = ('SMTPUTF8', 'BODY=8BITMIME')
+ self.smtp.send_message(self.msg)
+ self.smtp.send_message(self.msg)
+ self.assertEqual(self.smtp.sendmail.call_args_list[0][0][3],
+ expected_mail_options)
+ self.assertEqual(self.smtp.sendmail.call_args_list[1][0][3],
+ expected_mail_options)
+
+ def testSendMessageWithMailOptions(self):
+ mail_options = ['STARTTLS']
+ expected_mail_options = ('STARTTLS', 'SMTPUTF8', 'BODY=8BITMIME')
+ self.smtp.send_message(self.msg, None, None, mail_options)
+ self.assertEqual(mail_options, ['STARTTLS'])
+ self.assertEqual(self.smtp.sendmail.call_args_list[0][0][3],
+ expected_mail_options)
+
+
# test response of client to a non-successful HELO message
@unittest.skipUnless(threading, 'Threading required for this test.')
class BadHELOServerTests(unittest.TestCase):
self.assertRaises(UnicodeEncodeError, smtp.sendmail, 'Alice', 'Böb', '')
self.assertRaises(UnicodeEncodeError, smtp.mail, 'Älice')
+ def test_send_message_error_on_non_ascii_addrs_if_no_smtputf8(self):
+ # This test is located here and not in the SMTPUTF8SimTests
+ # class because it needs a "regular" SMTP server to work
+ msg = EmailMessage()
+ msg['From'] = "Páolo <főo@bar.com>"
+ msg['To'] = 'Dinsdale'
+ msg['Subject'] = 'Nudge nudge, wink, wink \u1F609'
+ smtp = smtplib.SMTP(
+ HOST, self.port, local_hostname='localhost', timeout=3)
+ self.addCleanup(smtp.close)
+ with self.assertRaises(smtplib.SMTPNotSupportedError):
+ smtp.send_message(msg)
+
def test_name_field_not_included_in_envelop_addresses(self):
smtp = smtplib.SMTP(
HOST, self.port, local_hostname='localhost', timeout=3
self.assertIn('SMTPUTF8', self.serv.last_mail_options)
self.assertEqual(self.serv.last_rcpt_options, [])
- def test_send_message_error_on_non_ascii_addrs_if_no_smtputf8(self):
- msg = EmailMessage()
- msg['From'] = "Páolo <főo@bar.com>"
- msg['To'] = 'Dinsdale'
- msg['Subject'] = 'Nudge nudge, wink, wink \u1F609'
- smtp = smtplib.SMTP(
- HOST, self.port, local_hostname='localhost', timeout=3)
- self.addCleanup(smtp.close)
- self.assertRaises(smtplib.SMTPNotSupportedError,
- smtp.send_message(msg))
-
EXPECTED_RESPONSE = encode_base64(b'\0psu\0doesnotexist', eol='')
self.assertEqual(code, 235)
-@support.reap_threads
-def test_main(verbose=None):
- support.run_unittest(
- BadHELOServerTests,
- DebuggingServerTests,
- GeneralTests,
- NonConnectingTests,
- SMTPAUTHInitialResponseSimTests,
- SMTPSimTests,
- TooLongLineTests,
- )
-
-
if __name__ == '__main__':
- test_main()
+ unittest.main()
self.data = b'select'
self.cli.sendto(self.data, 0, (HOST, self.port))
- def testCongestion(self):
- # wait until the sender is done
- self.evt.wait()
-
- def _testCongestion(self):
- # test the behavior in case of congestion
- self.data = b'fill'
- self.cli.setblocking(False)
- try:
- # try to lower the receiver's socket buffer size
- self.cli.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 16384)
- except OSError:
- pass
- with self.assertRaises(OSError) as cm:
- try:
- # fill the receiver's socket buffer
- while True:
- self.cli.sendto(self.data, 0, (HOST, self.port))
- finally:
- # signal the receiver we're done
- self.evt.set()
- # sendto() should have failed with ENOBUFS
- self.assertEqual(cm.exception.errno, errno.ENOBUFS)
- # and we should have received a congestion notification through poll
- r, w, x = select.select([self.serv], [], [], 3.0)
- self.assertIn(self.serv, r)
-
@unittest.skipUnless(thread, 'Threading required for this test.')
class BasicTCPTest(SocketConnectedTest):
def _testSendmsgTimeout(self):
try:
self.cli_sock.settimeout(0.03)
- with self.assertRaises(socket.timeout):
+ try:
while True:
self.sendmsgToServer([b"a"*512])
+ except socket.timeout:
+ pass
+ except OSError as exc:
+ if exc.errno != errno.ENOMEM:
+ raise
+ # bpo-33937 the test randomly fails on Travis CI with
+ # "OSError: [Errno 12] Cannot allocate memory"
+ else:
+ self.fail("socket.timeout not raised")
finally:
self.misc_event.set()
with self.assertRaises(OSError) as cm:
while True:
self.sendmsgToServer([b"a"*512], [], socket.MSG_DONTWAIT)
+ # bpo-33937: catch also ENOMEM, the test randomly fails on Travis CI
+ # with "OSError: [Errno 12] Cannot allocate memory"
self.assertIn(cm.exception.errno,
- (errno.EAGAIN, errno.EWOULDBLOCK))
+ (errno.EAGAIN, errno.EWOULDBLOCK, errno.ENOMEM))
finally:
self.misc_event.set()
def testFDPassSeparateMinSpace(self):
# Pass two FDs in two separate arrays, receiving them into the
# minimum space for two arrays.
- self.checkRecvmsgFDs(2,
+ num_fds = 2
+ self.checkRecvmsgFDs(num_fds,
self.doRecvmsg(self.serv_sock, len(MSG),
socket.CMSG_SPACE(SIZEOF_INT) +
- socket.CMSG_LEN(SIZEOF_INT)),
+ socket.CMSG_LEN(SIZEOF_INT * num_fds)),
maxcmsgs=2, ignoreflags=socket.MSG_CTRUNC)
@testFDPassSeparateMinSpace.client_skip
op=socket.ALG_OP_ENCRYPT, iv=iv)
enc = op.recv(msglen * multiplier)
self.assertEqual(len(enc), msglen * multiplier)
- self.assertTrue(enc[:msglen], ciphertext)
+ self.assertEqual(enc[:msglen], ciphertext)
op, _ = algo.accept()
with op:
spwd.getspnam(name)
except KeyError as exc:
self.skipTest("spwd entry %r doesn't exist: %s" % (name, exc))
- else:
- self.assertEqual(str(cm.exception), '[Errno 13] Permission denied')
if __name__ == "__main__":
CAFILE_NEURONIO = data_file("capath", "4e1295a3.0")
CAFILE_CACERT = data_file("capath", "5ed36f99.0")
-
# empty CRL
CRLFILE = data_file("revocation.crl")
NOKIACERT = data_file("nokia.pem")
NULLBYTECERT = data_file("nullbytecert.pem")
-DHFILE = data_file("dh1024.pem")
+DHFILE = data_file("ffdh3072.pem")
BYTES_DHFILE = os.fsencode(DHFILE)
# Not defined in all versions of OpenSSL
OP_SINGLE_DH_USE = getattr(ssl, "OP_SINGLE_DH_USE", 0)
OP_SINGLE_ECDH_USE = getattr(ssl, "OP_SINGLE_ECDH_USE", 0)
OP_CIPHER_SERVER_PREFERENCE = getattr(ssl, "OP_CIPHER_SERVER_PREFERENCE", 0)
+OP_ENABLE_MIDDLEBOX_COMPAT = getattr(ssl, "OP_ENABLE_MIDDLEBOX_COMPAT", 0)
def handle_error(prefix):
ssl.OP_NO_TLSv1
ssl.OP_NO_TLSv1_3
if ssl.OPENSSL_VERSION_INFO >= (1, 0, 1):
- ssl.OP_NO_TLSv1_1
- ssl.OP_NO_TLSv1_2
+ ssl.OP_NO_TLSv1_1
+ ssl.OP_NO_TLSv1_2
def test_str_for_enums(self):
# Make sure that the PROTOCOL_* constants have enum-like string
self.assertNotEqual(child_random, parent_random)
+ maxDiff = None
+
def test_parse_cert(self):
# note that this uses an 'unofficial' function in _ssl.c,
# provided solely for this test, to exercise the certificate
(('commonName', 'localhost'),))
)
# Note the next three asserts will fail if the keys are regenerated
- self.assertEqual(p['notAfter'], asn1time('Oct 5 23:01:56 2020 GMT'))
- self.assertEqual(p['notBefore'], asn1time('Oct 8 23:01:56 2010 GMT'))
- self.assertEqual(p['serialNumber'], 'D7C7381919AFC24E')
+ self.assertEqual(p['notAfter'], asn1time('Aug 26 14:23:15 2028 GMT'))
+ self.assertEqual(p['notBefore'], asn1time('Aug 29 14:23:15 2018 GMT'))
+ self.assertEqual(p['serialNumber'], '98A7CF88C74A32ED')
self.assertEqual(p['subject'],
((('countryName', 'XY'),),
(('localityName', 'Castle Anthrax'),),
@skip_if_broken_ubuntu_ssl
def test_options(self):
- ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
# OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 is the default value
default = (ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
# SSLContext also enables these by default
default |= (OP_NO_COMPRESSION | OP_CIPHER_SERVER_PREFERENCE |
- OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE)
+ OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE |
+ OP_ENABLE_MIDDLEBOX_COMPAT)
self.assertEqual(default, ctx.options)
ctx.options |= ssl.OP_NO_TLSv1
self.assertEqual(default | ssl.OP_NO_TLSv1, ctx.options)
self.sock, server_side=True)
self.server.selected_npn_protocols.append(self.sslconn.selected_npn_protocol())
self.server.selected_alpn_protocols.append(self.sslconn.selected_alpn_protocol())
- except (ssl.SSLError, ConnectionResetError, OSError) as e:
+ except (ConnectionResetError, BrokenPipeError) as e:
# We treat ConnectionResetError as though it were an
# SSLError - OpenSSL on Ubuntu abruptly closes the
# connection when asked to use an unsupported protocol.
#
+ # BrokenPipeError is raised in TLS 1.3 mode, when OpenSSL
+ # tries to send session tickets after handshake.
+ # https://github.com/openssl/openssl/issues/6342
+ self.server.conn_errors.append(str(e))
+ if self.server.chatty:
+ handle_error(
+ "\n server: bad connection attempt from " + repr(
+ self.addr) + ":\n")
+ self.running = False
+ self.close()
+ return False
+ except (ssl.SSLError, OSError) as e:
# OSError may occur with wrong protocols, e.g. both
# sides use PROTOCOL_TLS_SERVER.
#
sys.stdout.write(" server: read CB tls-unique from client, sending our CB data...\n")
data = self.sslconn.get_channel_binding("tls-unique")
self.write(repr(data).encode("us-ascii") + b"\n")
+ elif stripped == b'PHA':
+ if support.verbose and self.server.connectionchatty:
+ sys.stdout.write(
+ " server: initiating post handshake auth\n")
+ try:
+ self.sslconn.verify_client_post_handshake()
+ except ssl.SSLError as e:
+ self.write(repr(e).encode("us-ascii") + b"\n")
+ else:
+ self.write(b"OK\n")
+ elif stripped == b'HASCERT':
+ if self.sslconn.getpeercert() is not None:
+ self.write(b'TRUE\n')
+ else:
+ self.write(b'FALSE\n')
+ elif stripped == b'GETCERT':
+ cert = self.sslconn.getpeercert()
+ self.write(repr(cert).encode("us-ascii") + b"\n")
else:
if (support.verbose and
self.server.connectionchatty):
connect to it with a wrong client certificate fails.
"""
certfile = os.path.join(os.path.dirname(__file__) or os.curdir,
- "wrongcert.pem")
- server = ThreadedEchoServer(CERTFILE,
+ "keycert.pem")
+ server = ThreadedEchoServer(SIGNED_CERTFILE,
certreqs=ssl.CERT_REQUIRED,
- cacerts=CERTFILE, chatty=False,
+ cacerts=SIGNING_CA, chatty=False,
connectionchatty=False)
with server, \
socket.socket() as sock, \
# Block on the accept and wait on the connection to close.
evt.set()
remote, peer = server.accept()
- remote.recv(1)
+ remote.send(remote.recv(4))
t = threading.Thread(target=serve)
t.start()
evt.wait()
client = context.wrap_socket(socket.socket())
client.connect((host, port))
+ client.send(b'data')
+ client.recv()
client_addr = client.getsockname()
client.close()
t.join()
sock.do_handshake()
self.assertEqual(cm.exception.errno, errno.ENOTCONN)
- def test_default_ciphers(self):
- context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
- try:
- # Force a set of weak ciphers on our client context
- context.set_ciphers("DES")
- except ssl.SSLError:
- self.skipTest("no DES cipher available")
- with ThreadedEchoServer(CERTFILE,
- ssl_version=ssl.PROTOCOL_SSLv23,
- chatty=False) as server:
- with context.wrap_socket(socket.socket()) as s:
+ def test_no_shared_ciphers(self):
+ server_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
+ server_context.load_cert_chain(SIGNED_CERTFILE)
+ client_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
+ client_context.verify_mode = ssl.CERT_REQUIRED
+ client_context.check_hostname = True
+
+ # OpenSSL enables all TLS 1.3 ciphers, enforce TLS 1.2 for test
+ client_context.options |= ssl.OP_NO_TLSv1_3
+ # Force different suites on client and master
+ client_context.set_ciphers("AES128")
+ server_context.set_ciphers("AES256")
+ with ThreadedEchoServer(context=server_context) as server:
+ with client_context.wrap_socket(
+ socket.socket(),
+ server_hostname="localhost") as s:
with self.assertRaises(OSError):
s.connect((HOST, server.port))
self.assertIn("no shared cipher", server.conn_errors[0])
with context.wrap_socket(socket.socket()) as s:
s.connect((HOST, server.port))
self.assertIn(s.cipher()[0], [
- 'TLS13-AES-256-GCM-SHA384',
- 'TLS13-CHACHA20-POLY1305-SHA256',
- 'TLS13-AES-128-GCM-SHA256',
+ 'TLS_AES_256_GCM_SHA384',
+ 'TLS_CHACHA20_POLY1305_SHA256',
+ 'TLS_AES_128_GCM_SHA256',
])
@unittest.skipUnless(ssl.HAS_ECDH, "test requires ECDH-enabled OpenSSL")
if ssl.OPENSSL_VERSION_INFO >= (1, 0, 2):
client_context.set_ciphers("AES128:AES256")
server_context.set_ciphers("AES256")
- alg1 = "AES256"
- alg2 = "AES-256"
+ expected_algs = [
+ "AES256", "AES-256"
+ ]
else:
client_context.set_ciphers("AES:3DES")
server_context.set_ciphers("3DES")
- alg1 = "3DES"
- alg2 = "DES-CBC3"
+ expected_algs = [
+ "3DES", "DES-CBC3"
+ ]
+
+ if ssl.HAS_TLSv1_3:
+ # TLS 1.3 ciphers are always enabled
+ expected_algs.extend(["TLS_CHACHA20", "TLS_AES"])
stats = server_params_test(client_context, server_context)
ciphers = stats['server_shared_ciphers'][0]
self.assertGreater(len(ciphers), 0)
for name, tls_version, bits in ciphers:
- if not alg1 in name.split("-") and alg2 not in name:
+ if not any(alg in name for alg in expected_algs):
self.fail(name)
def test_read_write_after_close_raises_valuerror(self):
'Session refers to a different SSLContext.')
+def testing_context():
+ """Create context
+
+ client_context, server_context, hostname = testing_context()
+ """
+ client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
+ client_context.load_verify_locations(SIGNING_CA)
+
+ server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
+ server_context.load_cert_chain(SIGNED_CERTFILE)
+ server_context.load_verify_locations(SIGNING_CA)
+
+ return client_context, server_context, 'localhost'
+
+
+@unittest.skipUnless(ssl.HAS_TLSv1_3, "Test needs TLS 1.3")
+class TestPostHandshakeAuth(unittest.TestCase):
+ def test_pha_setter(self):
+ protocols = [
+ ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLS_SERVER, ssl.PROTOCOL_TLS_CLIENT
+ ]
+ for protocol in protocols:
+ ctx = ssl.SSLContext(protocol)
+ self.assertEqual(ctx.post_handshake_auth, False)
+
+ ctx.post_handshake_auth = True
+ self.assertEqual(ctx.post_handshake_auth, True)
+
+ ctx.verify_mode = ssl.CERT_REQUIRED
+ self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
+ self.assertEqual(ctx.post_handshake_auth, True)
+
+ ctx.post_handshake_auth = False
+ self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
+ self.assertEqual(ctx.post_handshake_auth, False)
+
+ ctx.verify_mode = ssl.CERT_OPTIONAL
+ ctx.post_handshake_auth = True
+ self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
+ self.assertEqual(ctx.post_handshake_auth, True)
+
+ def test_pha_required(self):
+ client_context, server_context, hostname = testing_context()
+ server_context.post_handshake_auth = True
+ server_context.verify_mode = ssl.CERT_REQUIRED
+ client_context.post_handshake_auth = True
+ client_context.load_cert_chain(SIGNED_CERTFILE)
+
+ server = ThreadedEchoServer(context=server_context, chatty=False)
+ with server:
+ with client_context.wrap_socket(socket.socket(),
+ server_hostname=hostname) as s:
+ s.connect((HOST, server.port))
+ s.write(b'HASCERT')
+ self.assertEqual(s.recv(1024), b'FALSE\n')
+ s.write(b'PHA')
+ self.assertEqual(s.recv(1024), b'OK\n')
+ s.write(b'HASCERT')
+ self.assertEqual(s.recv(1024), b'TRUE\n')
+ # PHA method just returns true when cert is already available
+ s.write(b'PHA')
+ self.assertEqual(s.recv(1024), b'OK\n')
+ s.write(b'GETCERT')
+ cert_text = s.recv(4096).decode('us-ascii')
+ self.assertIn('Python Software Foundation CA', cert_text)
+
+ def test_pha_required_nocert(self):
+ client_context, server_context, hostname = testing_context()
+ server_context.post_handshake_auth = True
+ server_context.verify_mode = ssl.CERT_REQUIRED
+ client_context.post_handshake_auth = True
+
+ server = ThreadedEchoServer(context=server_context, chatty=False)
+ with server:
+ with client_context.wrap_socket(socket.socket(),
+ server_hostname=hostname) as s:
+ s.connect((HOST, server.port))
+ s.write(b'PHA')
+ # receive CertificateRequest
+ self.assertEqual(s.recv(1024), b'OK\n')
+ # send empty Certificate + Finish
+ s.write(b'HASCERT')
+ # receive alert
+ with self.assertRaisesRegex(
+ ssl.SSLError,
+ 'tlsv13 alert certificate required'):
+ s.recv(1024)
+
+ def test_pha_optional(self):
+ if support.verbose:
+ sys.stdout.write("\n")
+
+ client_context, server_context, hostname = testing_context()
+ server_context.post_handshake_auth = True
+ server_context.verify_mode = ssl.CERT_REQUIRED
+ client_context.post_handshake_auth = True
+ client_context.load_cert_chain(SIGNED_CERTFILE)
+
+ # check CERT_OPTIONAL
+ server_context.verify_mode = ssl.CERT_OPTIONAL
+ server = ThreadedEchoServer(context=server_context, chatty=False)
+ with server:
+ with client_context.wrap_socket(socket.socket(),
+ server_hostname=hostname) as s:
+ s.connect((HOST, server.port))
+ s.write(b'HASCERT')
+ self.assertEqual(s.recv(1024), b'FALSE\n')
+ s.write(b'PHA')
+ self.assertEqual(s.recv(1024), b'OK\n')
+ s.write(b'HASCERT')
+ self.assertEqual(s.recv(1024), b'TRUE\n')
+
+ def test_pha_optional_nocert(self):
+ if support.verbose:
+ sys.stdout.write("\n")
+
+ client_context, server_context, hostname = testing_context()
+ server_context.post_handshake_auth = True
+ server_context.verify_mode = ssl.CERT_OPTIONAL
+ client_context.post_handshake_auth = True
+
+ server = ThreadedEchoServer(context=server_context, chatty=False)
+ with server:
+ with client_context.wrap_socket(socket.socket(),
+ server_hostname=hostname) as s:
+ s.connect((HOST, server.port))
+ s.write(b'HASCERT')
+ self.assertEqual(s.recv(1024), b'FALSE\n')
+ s.write(b'PHA')
+ self.assertEqual(s.recv(1024), b'OK\n')
+ # optional doens't fail when client does not have a cert
+ s.write(b'HASCERT')
+ self.assertEqual(s.recv(1024), b'FALSE\n')
+
+ def test_pha_no_pha_client(self):
+ client_context, server_context, hostname = testing_context()
+ server_context.post_handshake_auth = True
+ server_context.verify_mode = ssl.CERT_REQUIRED
+ client_context.load_cert_chain(SIGNED_CERTFILE)
+
+ server = ThreadedEchoServer(context=server_context, chatty=False)
+ with server:
+ with client_context.wrap_socket(socket.socket(),
+ server_hostname=hostname) as s:
+ s.connect((HOST, server.port))
+ with self.assertRaisesRegex(ssl.SSLError, 'not server'):
+ s.verify_client_post_handshake()
+ s.write(b'PHA')
+ self.assertIn(b'extension not received', s.recv(1024))
+
+ def test_pha_no_pha_server(self):
+ # server doesn't have PHA enabled, cert is requested in handshake
+ client_context, server_context, hostname = testing_context()
+ server_context.verify_mode = ssl.CERT_REQUIRED
+ client_context.post_handshake_auth = True
+ client_context.load_cert_chain(SIGNED_CERTFILE)
+
+ server = ThreadedEchoServer(context=server_context, chatty=False)
+ with server:
+ with client_context.wrap_socket(socket.socket(),
+ server_hostname=hostname) as s:
+ s.connect((HOST, server.port))
+ s.write(b'HASCERT')
+ self.assertEqual(s.recv(1024), b'TRUE\n')
+ # PHA doesn't fail if there is already a cert
+ s.write(b'PHA')
+ self.assertEqual(s.recv(1024), b'OK\n')
+ s.write(b'HASCERT')
+ self.assertEqual(s.recv(1024), b'TRUE\n')
+
+ def test_pha_not_tls13(self):
+ # TLS 1.2
+ client_context, server_context, hostname = testing_context()
+ server_context.verify_mode = ssl.CERT_REQUIRED
+ client_context.options |= ssl.OP_NO_TLSv1_3
+ client_context.post_handshake_auth = True
+ client_context.load_cert_chain(SIGNED_CERTFILE)
+
+ server = ThreadedEchoServer(context=server_context, chatty=False)
+ with server:
+ with client_context.wrap_socket(socket.socket(),
+ server_hostname=hostname) as s:
+ s.connect((HOST, server.port))
+ # PHA fails for TLS != 1.3
+ s.write(b'PHA')
+ self.assertIn(b'WRONG_SSL_VERSION', s.recv(1024))
+
+
def test_main(verbose=False):
if support.verbose:
import warnings
thread_info = support.threading_setup()
if thread_info:
tests.append(ThreadedTests)
+ tests.append(TestPostHandshakeAuth)
try:
support.run_unittest(*tests)
self.assertEqual(os.get_inheritable(inheritable), True)
self.assertEqual(os.get_inheritable(non_inheritable), False)
+
+ # bpo-32270: Ensure that descriptors specified in pass_fds
+ # are inherited even if they are used in redirections.
+ # Contributed by @izbyshev.
+ def test_pass_fds_redirected(self):
+ """Regression test for https://bugs.python.org/issue32270."""
+ fd_status = support.findfile("fd_status.py", subdir="subprocessdata")
+ pass_fds = []
+ for _ in range(2):
+ fd = os.open(os.devnull, os.O_RDWR)
+ self.addCleanup(os.close, fd)
+ pass_fds.append(fd)
+
+ stdout_r, stdout_w = os.pipe()
+ self.addCleanup(os.close, stdout_r)
+ self.addCleanup(os.close, stdout_w)
+ pass_fds.insert(1, stdout_w)
+
+ with subprocess.Popen([sys.executable, fd_status],
+ stdin=pass_fds[0],
+ stdout=pass_fds[1],
+ stderr=pass_fds[2],
+ close_fds=True,
+ pass_fds=pass_fds):
+ output = os.read(stdout_r, 1024)
+ fds = {int(num) for num in output.split(b',')}
+
+ self.assertEqual(fds, {0, 1, 2} | frozenset(pass_fds), f"output={output!a}")
+
+
def test_stdout_stdin_are_single_inout_fd(self):
with io.open(os.devnull, "r+") as inout:
p = subprocess.Popen([sys.executable, "-c", "import sys; sys.exit(0)"],
with support.temp_cwd(name=TESTFN):
self.assertEqual(os.path.basename(os.getcwd()), TESTFN)
self.assertFalse(os.path.exists(TESTFN))
- self.assertTrue(os.path.basename(os.getcwd()), here)
+ self.assertEqual(os.getcwd(), here)
def test_temp_cwd__name_none(self):
def test_symlink(self):
# On Windows, the EXE needs to know where pythonXY.dll is at so we have
# to add the directory to the path.
+ env = None
if sys.platform == "win32":
- os.environ["PATH"] = "{};{}".format(
- os.path.dirname(sys.executable), os.environ["PATH"])
+ env = {k.upper(): os.environ[k] for k in os.environ}
+ env["PATH"] = "{};{}".format(
+ os.path.dirname(sys.executable), env.get("PATH", ""))
+ # Requires PYTHONHOME as well since we locate stdlib from the
+ # EXE path and not the DLL path (which should be fixed)
+ env["PYTHONHOME"] = os.path.dirname(sys.executable)
+ if sysconfig.is_python_build(True):
+ env["PYTHONPATH"] = os.path.dirname(os.__file__)
# Issue 7880
- def get(python):
+ def get(python, env=None):
cmd = [python, '-c',
'import sysconfig; print(sysconfig.get_platform())']
- p = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=os.environ)
- return p.communicate()
+ p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, env=env)
+ out, err = p.communicate()
+ if p.returncode:
+ print((out, err))
+ self.fail('Non-zero return code {0} (0x{0:08X})'
+ .format(p.returncode))
+ return out, err
real = os.path.realpath(sys.executable)
link = os.path.abspath(TESTFN)
os.symlink(real, link)
try:
- self.assertEqual(get(real), get(link))
+ self.assertEqual(get(real), get(link, env))
finally:
unlink(link)
expected = {'a': (1, 2, 3), 'something': 'foo', 'status': ''}
self.assertEqual(splitdict(tcl, arg), expected)
+ def test_join(self):
+ join = tkinter._join
+ tcl = self.interp.tk
+ def unpack(s):
+ return tcl.call('lindex', s, 0)
+ def check(value):
+ self.assertEqual(unpack(join([value])), value)
+ self.assertEqual(unpack(join([value, 0])), value)
+ self.assertEqual(unpack(unpack(join([[value]]))), value)
+ self.assertEqual(unpack(unpack(join([[value, 0]]))), value)
+ self.assertEqual(unpack(unpack(join([[value], 0]))), value)
+ self.assertEqual(unpack(unpack(join([[value, 0], 0]))), value)
+ check('')
+ check('spam')
+ check('sp am')
+ check('sp\tam')
+ check('sp\nam')
+ check(' \t\n')
+ check('{spam}')
+ check('{sp am}')
+ check('"spam"')
+ check('"sp am"')
+ check('{"spam"}')
+ check('"{spam}"')
+ check('sp\\am')
+ check('"sp\\am"')
+ check('"{}" "{}"')
+ check('"\\')
+ check('"{')
+ check('"}')
+ check('\n\\')
+ check('\n{')
+ check('\n}')
+ check('\\\n')
+ check('{\n')
+ check('}\n')
+
def test_new_tcl_obj(self):
self.assertRaises(TypeError, _tkinter.Tcl_Obj)
@unittest.skipIf(USING_PTHREAD_COND,
'POSIX condition variables cannot be interrupted')
+ @unittest.skipIf(sys.platform.startswith('linux') and
+ not sys.thread_info.version,
+ 'Issue 34004: musl does not allow interruption of locks '
+ 'by signals.')
# Issue #20564: sem_timedwait() cannot be interrupted on OpenBSD
@unittest.skipIf(sys.platform.startswith('openbsd'),
'lock cannot be interrupted on OpenBSD')
@unittest.skipIf(USING_PTHREAD_COND,
'POSIX condition variables cannot be interrupted')
+ @unittest.skipIf(sys.platform.startswith('linux') and
+ not sys.thread_info.version,
+ 'Issue 34004: musl does not allow interruption of locks '
+ 'by signals.')
# Issue #20564: sem_timedwait() cannot be interrupted on OpenBSD
@unittest.skipIf(sys.platform.startswith('openbsd'),
'lock cannot be interrupted on OpenBSD')
# Max year is only limited by the size of C int.
SIZEOF_INT = sysconfig.get_config_var('SIZEOF_INT') or 4
TIME_MAXYEAR = (1 << 8 * SIZEOF_INT - 1) - 1
-TIME_MINYEAR = -TIME_MAXYEAR - 1
+TIME_MINYEAR = -TIME_MAXYEAR - 1 + 1900
SEC_TO_US = 10 ** 6
US_TO_NS = 10 ** 3
self.assertEqual(func(9999), fmt % 9999)
def test_large_year(self):
- self.assertEqual(self.yearstr(12345), '12345')
- self.assertEqual(self.yearstr(123456789), '123456789')
- self.assertEqual(self.yearstr(TIME_MAXYEAR), str(TIME_MAXYEAR))
+ self.assertEqual(self.yearstr(12345).lstrip('+'), '12345')
+ self.assertEqual(self.yearstr(123456789).lstrip('+'), '123456789')
+ self.assertEqual(self.yearstr(TIME_MAXYEAR).lstrip('+'), str(TIME_MAXYEAR))
self.assertRaises(OverflowError, self.yearstr, TIME_MAXYEAR + 1)
def test_negative(self):
self.assertEqual(self.yearstr(-123456), '-123456')
self.assertEqual(self.yearstr(-123456789), str(-123456789))
self.assertEqual(self.yearstr(-1234567890), str(-1234567890))
- self.assertEqual(self.yearstr(TIME_MINYEAR + 1900), str(TIME_MINYEAR + 1900))
- # Issue #13312: it may return wrong value for year < TIME_MINYEAR + 1900
- # Skip the value test, but check that no error is raised
- self.yearstr(TIME_MINYEAR)
- # self.assertEqual(self.yearstr(TIME_MINYEAR), str(TIME_MINYEAR))
+ self.assertEqual(self.yearstr(TIME_MINYEAR), str(TIME_MINYEAR))
+ # Modules/timemodule.c checks for underflow
self.assertRaises(OverflowError, self.yearstr, TIME_MINYEAR - 1)
+ with self.assertRaises(OverflowError):
+ self.yearstr(-TIME_MAXYEAR - 1)
class TestAsctime4dyear(_TestAsctimeYear, _Test4dYear, unittest.TestCase):
ns_timestamps = self._rounding_values(use_float)
valid_values = convert_values(ns_timestamps)
for time_rnd, decimal_rnd in ROUNDING_MODES :
- context = decimal.getcontext()
- context.rounding = decimal_rnd
-
- for value in valid_values:
- debug_info = {'value': value, 'rounding': decimal_rnd}
- try:
- result = pytime_converter(value, time_rnd)
- expected = expected_func(value)
- except Exception as exc:
- self.fail("Error on timestamp conversion: %s" % debug_info)
- self.assertEqual(result,
- expected,
- debug_info)
+ with decimal.localcontext() as context:
+ context.rounding = decimal_rnd
+
+ for value in valid_values:
+ debug_info = {'value': value, 'rounding': decimal_rnd}
+ try:
+ result = pytime_converter(value, time_rnd)
+ expected = expected_func(value)
+ except Exception as exc:
+ self.fail("Error on timestamp conversion: %s" % debug_info)
+ self.assertEqual(result,
+ expected,
+ debug_info)
# test overflow
ns = self.OVERFLOW_SECONDS * SEC_TO_NS
from test import support
from tokenize import (tokenize, _tokenize, untokenize, NUMBER, NAME, OP,
STRING, ENDMARKER, ENCODING, tok_name, detect_encoding,
- open as tokenize_open, Untokenizer)
+ open as tokenize_open, Untokenizer, generate_tokens,
+ NEWLINE)
from io import BytesIO
import unittest
from unittest import TestCase, mock
import token
+# Converts a source string into a list of textual representation
+# of the tokens such as:
+# ` NAME 'if' (1, 0) (1, 2)`
+# to make writing tests easier.
+def stringify_tokens_from_source(token_generator, source_string):
+ result = []
+ num_lines = len(source_string.splitlines())
+ missing_trailing_nl = source_string[-1] not in '\r\n'
+
+ for type, token, start, end, line in token_generator:
+ if type == ENDMARKER:
+ break
+ # Ignore the new line on the last line if the input lacks one
+ if missing_trailing_nl and type == NEWLINE and end[0] == num_lines:
+ continue
+ type = tok_name[type]
+ result.append(f" {type:10} {token!r:13} {start} {end}")
+
+ return result
+
class TokenizeTest(TestCase):
# Tests for the tokenize module.
# The tests can be really simple. Given a small fragment of source
- # code, print out a table with tokens. The ENDMARKER is omitted for
- # brevity.
+ # code, print out a table with tokens. The ENDMARKER, ENCODING and
+ # final NEWLINE are omitted for brevity.
def check_tokenize(self, s, expected):
# Format the tokens in s in a table format.
- # The ENDMARKER is omitted.
- result = []
+ # The ENDMARKER and final NEWLINE are omitted.
f = BytesIO(s.encode('utf-8'))
- for type, token, start, end, line in tokenize(f.readline):
- if type == ENDMARKER:
- break
- type = tok_name[type]
- result.append(f" {type:10} {token!r:13} {start} {end}")
+ result = stringify_tokens_from_source(tokenize(f.readline), s)
+
self.assertEqual(result,
[" ENCODING 'utf-8' (0, 0) (0, 0)"] +
expected.rstrip().splitlines())
+ def test_implicit_newline(self):
+ # Make sure that the tokenizer puts in an implicit NEWLINE
+ # when the input lacks a trailing new line.
+ f = BytesIO("x".encode('utf-8'))
+ tokens = list(tokenize(f.readline))
+ self.assertEqual(tokens[-2].type, NEWLINE)
+ self.assertEqual(tokens[-1].type, ENDMARKER)
+
def test_basic(self):
self.check_tokenize("1 + 1", """\
NUMBER '1' (1, 0) (1, 1)
else:
return b''
- # skip the initial encoding token and the end token
- tokens = list(_tokenize(readline, encoding='utf-8'))[1:-1]
+ # skip the initial encoding token and the end tokens
+ tokens = list(_tokenize(readline, encoding='utf-8'))[1:-2]
expected_tokens = [(3, '"ЉЊЈЁЂ"', (1, 0), (1, 7), '"ЉЊЈЁЂ"')]
self.assertEqual(tokens, expected_tokens,
"bytes not decoded with encoding")
else:
return b''
- # skip the end token
- tokens = list(_tokenize(readline, encoding=None))[:-1]
+ # skip the end tokens
+ tokens = list(_tokenize(readline, encoding=None))[:-2]
expected_tokens = [(3, '"ЉЊЈЁЂ"', (1, 0), (1, 7), '"ЉЊЈЁЂ"')]
self.assertEqual(tokens, expected_tokens,
"string not tokenized when encoding is None")
tokenize_module.detect_encoding = orig_detect_encoding
tokenize_module._tokenize = orig__tokenize
- self.assertTrue(encoding_used, encoding)
+ self.assertEqual(encoding_used, encoding)
def test_oneline_defs(self):
buf = []
# Test that 500 consequent, one-line defs is OK
toks = list(tokenize(BytesIO(buf.encode('utf-8')).readline))
- self.assertEqual(toks[-2].string, 'OK') # [-1] is always ENDMARKER
+ self.assertEqual(toks[-3].string, 'OK') # [-1] is always ENDMARKER
+ # [-2] is always NEWLINE
def assertExactTypeEqual(self, opstr, *optypes):
tokens = list(tokenize(BytesIO(opstr.encode('utf-8')).readline))
num_optypes = len(optypes)
- self.assertEqual(len(tokens), 2 + num_optypes)
+ self.assertEqual(len(tokens), 3 + num_optypes)
self.assertEqual(token.tok_name[tokens[0].exact_type],
token.tok_name[ENCODING])
for i in range(num_optypes):
self.assertEqual(token.tok_name[tokens[i + 1].exact_type],
token.tok_name[optypes[i]])
self.assertEqual(token.tok_name[tokens[1 + num_optypes].exact_type],
+ token.tok_name[token.NEWLINE])
+ self.assertEqual(token.tok_name[tokens[2 + num_optypes].exact_type],
token.tok_name[token.ENDMARKER])
def test_exact_type(self):
self.check_roundtrip("if x == 1:\n"
" print(x)\n")
self.check_roundtrip("# This is a comment\n"
- "# This also")
+ "# This also\n")
# Some people use different formatting conventions, which makes
# untokenize a little trickier. Note that this test involves trailing
# scripts that use windows-only modules
windows_only = ['win_add2path']
# blacklisted for other reasons
- other = ['analyze_dxp']
+ other = ['analyze_dxp', '2to3']
skiplist = blacklist + whitelist + windows_only + other
def test_sundry(self):
- for fn in os.listdir(scriptsdir):
- name = fn[:-3]
- if fn.endswith('.py') and name not in self.skiplist:
+ old_modules = support.modules_setup()
+ try:
+ for fn in os.listdir(scriptsdir):
+ if not fn.endswith('.py'):
+ continue
+
+ name = fn[:-3]
+ if name in self.skiplist:
+ continue
+
import_tool(name)
+ finally:
+ # Unload all modules loaded in this test
+ support.modules_cleanup(*old_modules)
@unittest.skipIf(sys.platform != "win32", "Windows-only test")
def test_sundry_windows(self):
' return g(count-1)\n'
f' File "{__file__}", line {lineno_g+2}, in g\n'
' return g(count-1)\n'
- ' [Previous line repeated 6 more times]\n'
+ ' [Previous line repeated 7 more times]\n'
f' File "{__file__}", line {lineno_g+3}, in g\n'
' raise ValueError\n'
'ValueError\n'
' return h(count-1)\n'
f' File "{__file__}", line {lineno_h+2}, in h\n'
' return h(count-1)\n'
- ' [Previous line repeated 6 more times]\n'
+ ' [Previous line repeated 7 more times]\n'
f' File "{__file__}", line {lineno_h+3}, in h\n'
' g()\n'
)
actual = stderr_h.getvalue().splitlines()
self.assertEqual(actual, expected)
+ # Check the boundary conditions. First, test just below the cutoff.
+ with captured_output("stderr") as stderr_g:
+ try:
+ g(traceback._RECURSIVE_CUTOFF)
+ except ValueError as exc:
+ render_exc()
+ else:
+ self.fail("no error raised")
+ result_g = (
+ f' File "{__file__}", line {lineno_g+2}, in g\n'
+ ' return g(count-1)\n'
+ f' File "{__file__}", line {lineno_g+2}, in g\n'
+ ' return g(count-1)\n'
+ f' File "{__file__}", line {lineno_g+2}, in g\n'
+ ' return g(count-1)\n'
+ f' File "{__file__}", line {lineno_g+3}, in g\n'
+ ' raise ValueError\n'
+ 'ValueError\n'
+ )
+ tb_line = (
+ 'Traceback (most recent call last):\n'
+ f' File "{__file__}", line {lineno_g+71}, in _check_recursive_traceback_display\n'
+ ' g(traceback._RECURSIVE_CUTOFF)\n'
+ )
+ expected = (tb_line + result_g).splitlines()
+ actual = stderr_g.getvalue().splitlines()
+ self.assertEqual(actual, expected)
+
+ # Second, test just above the cutoff.
+ with captured_output("stderr") as stderr_g:
+ try:
+ g(traceback._RECURSIVE_CUTOFF + 1)
+ except ValueError as exc:
+ render_exc()
+ else:
+ self.fail("no error raised")
+ result_g = (
+ f' File "{__file__}", line {lineno_g+2}, in g\n'
+ ' return g(count-1)\n'
+ f' File "{__file__}", line {lineno_g+2}, in g\n'
+ ' return g(count-1)\n'
+ f' File "{__file__}", line {lineno_g+2}, in g\n'
+ ' return g(count-1)\n'
+ ' [Previous line repeated 1 more time]\n'
+ f' File "{__file__}", line {lineno_g+3}, in g\n'
+ ' raise ValueError\n'
+ 'ValueError\n'
+ )
+ tb_line = (
+ 'Traceback (most recent call last):\n'
+ f' File "{__file__}", line {lineno_g+99}, in _check_recursive_traceback_display\n'
+ ' g(traceback._RECURSIVE_CUTOFF + 1)\n'
+ )
+ expected = (tb_line + result_g).splitlines()
+ actual = stderr_g.getvalue().splitlines()
+ self.assertEqual(actual, expected)
+
def test_recursive_traceback_python(self):
self._check_recursive_traceback_display(traceback.print_exc)
b = 'C\u0338' * 20 + '\xC7'
self.assertEqual(self.db.normalize('NFC', a), b)
+ def test_issue29456(self):
+ # Fix #29456
+ u1176_str_a = '\u1100\u1176\u11a8'
+ u1176_str_b = '\u1100\u1176\u11a8'
+ u11a7_str_a = '\u1100\u1175\u11a7'
+ u11a7_str_b = '\uae30\u11a7'
+ u11c3_str_a = '\u1100\u1175\u11c3'
+ u11c3_str_b = '\uae30\u11c3'
+ self.assertEqual(self.db.normalize('NFC', u1176_str_a), u1176_str_b)
+ self.assertEqual(self.db.normalize('NFC', u11a7_str_a), u11a7_str_b)
+ self.assertEqual(self.db.normalize('NFC', u11c3_str_a), u11c3_str_b)
+
+
def test_east_asian_width(self):
eaw = self.db.east_asian_width
self.assertRaises(TypeError, eaw, b'a')
try:
self.assertTrue(urllib.request.urlopen(self.server_url))
except urllib.error.HTTPError:
- self.fail("Basic auth failed for the url: %s", self.server_url)
+ self.fail("Basic auth failed for the url: %s" % self.server_url)
def test_basic_auth_httperror(self):
ah = urllib.request.HTTPBasicAuthHandler()
skipInVenv = unittest.skipIf(sys.prefix != sys.base_prefix,
'Test not appropriate in a venv')
+def check_output(cmd, encoding=None):
+ p = subprocess.Popen(cmd,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ encoding=encoding)
+ out, err = p.communicate()
+ if p.returncode:
+ raise subprocess.CalledProcessError(
+ p.returncode, cmd, None, out, err)
+ return out, err
+
class BaseTest(unittest.TestCase):
"""Base class for venv tests."""
maxDiff = 80 * 50
('base_prefix', sys.prefix),
('base_exec_prefix', sys.exec_prefix)):
cmd[2] = 'import sys; print(sys.%s)' % prefix
- p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- out, err = p.communicate()
+ out, err = check_output(cmd)
self.assertEqual(out.strip(), expected.encode())
if sys.platform == 'win32':
"""
rmtree(self.env_dir)
self.run_with_capture(venv.create, self.env_dir)
- envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe)
- cmd = [envpy, '-c', 'import sys; print(sys.executable)']
- p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- out, err = p.communicate()
+ envpy = os.path.join(os.path.realpath(self.env_dir),
+ self.bindir, self.exe)
+ out, err = check_output([envpy, '-c',
+ 'import sys; print(sys.executable)'])
self.assertEqual(out.strip(), envpy.encode())
@unittest.skipUnless(can_symlink(), 'Needs symlinks')
rmtree(self.env_dir)
builder = venv.EnvBuilder(clear=True, symlinks=True)
builder.create(self.env_dir)
- envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe)
- cmd = [envpy, '-c', 'import sys; print(sys.executable)']
- p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- out, err = p.communicate()
+ envpy = os.path.join(os.path.realpath(self.env_dir),
+ self.bindir, self.exe)
+ out, err = check_output([envpy, '-c',
+ 'import sys; print(sys.executable)'])
self.assertEqual(out.strip(), envpy.encode())
@unittest.skipUnless(os.name == 'nt', 'only relevant on Windows')
def test_unicode_in_batch_file(self):
"""
- Test isolation from system site-packages
+ Test handling of Unicode paths
"""
rmtree(self.env_dir)
env_dir = os.path.join(os.path.realpath(self.env_dir), 'ϼўТλФЙ')
builder.create(env_dir)
activate = os.path.join(env_dir, self.bindir, 'activate.bat')
envpy = os.path.join(env_dir, self.bindir, self.exe)
- cmd = [activate, '&', self.exe, '-c', 'print(0)']
- p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE, encoding='oem',
- shell=True)
- out, err = p.communicate()
- print(err)
+ out, err = check_output(
+ [activate, '&', self.exe, '-c', 'print(0)'],
+ encoding='oem',
+ )
self.assertEqual(out.strip(), '0')
@skipInVenv
def assert_pip_not_installed(self):
envpy = os.path.join(os.path.realpath(self.env_dir),
self.bindir, self.exe)
- try_import = 'try:\n import pip\nexcept ImportError:\n print("OK")'
- cmd = [envpy, '-c', try_import]
- p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- out, err = p.communicate()
+ out, err = check_output([envpy, '-c',
+ 'try:\n import pip\nexcept ImportError:\n print("OK")'])
# We force everything to text, so unittest gives the detailed diff
# if we get unexpected results
err = err.decode("latin-1") # Force to text, prevent decoding errors
self.fail(msg.format(exc, details))
# Ensure pip is available in the virtual environment
envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe)
- cmd = [envpy, '-Im', 'pip', '--version']
- p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- out, err = p.communicate()
+ out, err = check_output([envpy, '-Im', 'pip', '--version'])
# We force everything to text, so unittest gives the detailed diff
# if we get unexpected results
err = err.decode("latin-1") # Force to text, prevent decoding errors
# http://bugs.python.org/issue19728
# Check the private uninstall command provided for the Windows
# installers works (at least in a virtual environment)
- cmd = [envpy, '-Im', 'ensurepip._uninstall']
with EnvironmentVarGuard() as envvars:
- p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- out, err = p.communicate()
+ out, err = check_output([envpy, '-Im', 'ensurepip._uninstall'])
# We force everything to text, so unittest gives the detailed diff
# if we get unexpected results
err = err.decode("latin-1") # Force to text, prevent decoding errors
self.module.resetwarnings()
self.module.filterwarnings("always", category=UserWarning)
message = "FilterTests.test_always"
- self.module.warn(message, UserWarning)
- self.assertTrue(message, w[-1].message)
- self.module.warn(message, UserWarning)
- self.assertTrue(w[-1].message, message)
+ def f():
+ self.module.warn(message, UserWarning)
+ f()
+ self.assertEqual(len(w), 1)
+ self.assertEqual(w[-1].message.args[0], message)
+ f()
+ self.assertEqual(len(w), 2)
+ self.assertEqual(w[-1].message.args[0], message)
def test_always_after_default(self):
with original_warnings.catch_warnings(record=True,
def test_open(self):
self._test('open',
- options=['-remote'],
- arguments=['openURL({})'.format(URL)])
+ options=[],
+ arguments=[URL])
def test_open_with_autoraise_false(self):
self._test('open', kw=dict(autoraise=False),
- options=['-remote', '-noraise'],
- arguments=['openURL({})'.format(URL)])
+ options=[],
+ arguments=[URL])
def test_open_new(self):
self._test('open_new',
- options=['-remote'],
- arguments=['openURL({},new-window)'.format(URL)])
+ options=['--new-window'],
+ arguments=[URL])
def test_open_new_tab(self):
self._test('open_new_tab',
- options=['-remote'],
- arguments=['openURL({},new-page)'.format(URL)])
+ options=[],
+ arguments=[URL])
class ELinksCommandTest(CommandTestMixin, unittest.TestCase):
<document>&entity;</document>
"""
+EXTERNAL_ENTITY_XML = """\
+<!DOCTYPE points [
+<!ENTITY entity SYSTEM "file:///non-existing-file.xml">
+]>
+<document>&entity;</document>
+"""
class ModuleTest(unittest.TestCase):
def test_sanity(self):
root = parser.close()
self.serialize_check(root, '<document>text</document>')
+ # 4) external (SYSTEM) entity
+
+ with self.assertRaises(ET.ParseError) as cm:
+ ET.XML(EXTERNAL_ENTITY_XML)
+ self.assertEqual(str(cm.exception),
+ 'undefined entity &entity;: line 4, column 10')
+
def test_namespace(self):
# Test namespace issues.
with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) as zipfp:
self.assertEqual(zipfp.namelist(), ["absolute"])
+ def test_append(self):
+ # Test that appending to the Zip64 archive doesn't change
+ # extra fields of existing entries.
+ with zipfile.ZipFile(TESTFN2, "w", allowZip64=True) as zipfp:
+ zipfp.writestr("strfile", self.data)
+ with zipfile.ZipFile(TESTFN2, "r", allowZip64=True) as zipfp:
+ zinfo = zipfp.getinfo("strfile")
+ extra = zinfo.extra
+ with zipfile.ZipFile(TESTFN2, "a", allowZip64=True) as zipfp:
+ zipfp.writestr("strfile2", self.data)
+ with zipfile.ZipFile(TESTFN2, "r", allowZip64=True) as zipfp:
+ zinfo = zipfp.getinfo("strfile")
+ self.assertEqual(zinfo.extra, extra)
+
@requires_zlib
class DeflateTestZip64InSmallFiles(AbstractTestZip64InSmallFiles,
unittest.TestCase):
# Test flush() with the various options, using all the
# different levels in order to provide more variations.
sync_opt = ['Z_NO_FLUSH', 'Z_SYNC_FLUSH', 'Z_FULL_FLUSH',
- 'Z_PARTIAL_FLUSH', 'Z_BLOCK']
+ 'Z_PARTIAL_FLUSH']
+
+ ver = tuple(int(v) for v in zlib.ZLIB_RUNTIME_VERSION.split('.'))
+ # Z_BLOCK has a known failure prior to 1.2.5.3
+ if ver >= (1, 2, 5, 3):
+ sync_opt.append('Z_BLOCK')
+
sync_opt = [getattr(zlib, opt) for opt in sync_opt
if hasattr(zlib, opt)]
data = HAMLET_SCENE * 8
for sync in sync_opt:
for level in range(10):
- obj = zlib.compressobj( level )
- a = obj.compress( data[:3000] )
- b = obj.flush( sync )
- c = obj.compress( data[3000:] )
- d = obj.flush()
+ try:
+ obj = zlib.compressobj( level )
+ a = obj.compress( data[:3000] )
+ b = obj.flush( sync )
+ c = obj.compress( data[3000:] )
+ d = obj.flush()
+ except:
+ print("Error for flush mode={}, level={}"
+ .format(sync, level))
+ raise
self.assertEqual(zlib.decompress(b''.join([a,b,c,d])),
data, ("Decompress failed: flush "
"mode=%i, level=%i") % (sync, level))
+++ /dev/null
------BEGIN RSA PRIVATE KEY-----
-MIICXAIBAAKBgQC89ZNxjTgWgq7Z1g0tJ65w+k7lNAj5IgjLb155UkUrz0XsHDnH
-FlbsVUg2Xtk6+bo2UEYIzN7cIm5ImpmyW/2z0J1IDVDlvR2xJ659xrE0v5c2cB6T
-f9lnNTwpSoeK24Nd7Jwq4j9vk95fLrdqsBq0/KVlsCXeixS/CaqqduXfvwIDAQAB
-AoGAQFko4uyCgzfxr4Ezb4Mp5pN3Npqny5+Jey3r8EjSAX9Ogn+CNYgoBcdtFgbq
-1yif/0sK7ohGBJU9FUCAwrqNBI9ZHB6rcy7dx+gULOmRBGckln1o5S1+smVdmOsW
-7zUVLBVByKuNWqTYFlzfVd6s4iiXtAE2iHn3GCyYdlICwrECQQDhMQVxHd3EFbzg
-SFmJBTARlZ2GKA3c1g/h9/XbkEPQ9/RwI3vnjJ2RaSnjlfoLl8TOcf0uOGbOEyFe
-19RvCLXjAkEA1s+UE5ziF+YVkW3WolDCQ2kQ5WG9+ccfNebfh6b67B7Ln5iG0Sbg
-ky9cjsO3jbMJQtlzAQnH1850oRD5Gi51dQJAIbHCDLDZU9Ok1TI+I2BhVuA6F666
-lEZ7TeZaJSYq34OaUYUdrwG9OdqwZ9sy9LUav4ESzu2lhEQchCJrKMn23QJAReqs
-ZLHUeTjfXkVk7dHhWPWSlUZ6AhmIlA/AQ7Payg2/8wM/JkZEJEPvGVykms9iPUrv
-frADRr+hAGe43IewnQJBAJWKZllPgKuEBPwoEldHNS8nRu61D7HzxEzQ2xnfj+Nk
-2fgf1MAzzTRsikfGENhVsVWeqOcijWb6g5gsyCmlRpc=
------END RSA PRIVATE KEY-----
------BEGIN CERTIFICATE-----
-MIICsDCCAhmgAwIBAgIJAOqYOYFJfEEoMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
-BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
-aWRnaXRzIFB0eSBMdGQwHhcNMDgwNjI2MTgxNTUyWhcNMDkwNjI2MTgxNTUyWjBF
-MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
-ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
-gQC89ZNxjTgWgq7Z1g0tJ65w+k7lNAj5IgjLb155UkUrz0XsHDnHFlbsVUg2Xtk6
-+bo2UEYIzN7cIm5ImpmyW/2z0J1IDVDlvR2xJ659xrE0v5c2cB6Tf9lnNTwpSoeK
-24Nd7Jwq4j9vk95fLrdqsBq0/KVlsCXeixS/CaqqduXfvwIDAQABo4GnMIGkMB0G
-A1UdDgQWBBTctMtI3EO9OjLI0x9Zo2ifkwIiNjB1BgNVHSMEbjBsgBTctMtI3EO9
-OjLI0x9Zo2ifkwIiNqFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUt
-U3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAOqYOYFJ
-fEEoMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAQwa7jya/DfhaDn7E
-usPkpgIX8WCL2B1SqnRTXEZfBPPVq/cUmFGyEVRVATySRuMwi8PXbVcOhXXuocA+
-43W+iIsD9pXapCZhhOerCq18TC1dWK98vLUsoK8PMjB6e5H/O8bqojv0EeC+fyCw
-eSHj5jpC8iZKjCHBn+mAi4cQ514=
------END CERTIFICATE-----
if isinstance(value, (list, tuple)):
if len(value) == 1:
value = _stringify(value[0])
- if value[0] == '{':
+ if _magic_re.search(value):
value = '{%s}' % value
else:
value = '{%s}' % _join(value)
elif _magic_re.search(value):
# add '\' before special characters and spaces
value = _magic_re.sub(r'\\\1', value)
+ value = value.replace('\n', r'\n')
value = _space_re.sub(r'\\\1', value)
+ if value[0] == '"':
+ value = '\\' + value
elif value[0] == '"' or _space_re.search(value):
value = '{%s}' % value
return value
+import functools
import re
import tkinter
import unittest
tcl_version = tuple(map(int, _tkinter.TCL_VERSION.split('.')))
def requires_tcl(*version):
- return unittest.skipUnless(tcl_version >= version,
+ if len(version) <= 2:
+ return unittest.skipUnless(tcl_version >= version,
'requires Tcl version >= ' + '.'.join(map(str, version)))
+ def deco(test):
+ @functools.wraps(test)
+ def newtest(self):
+ if get_tk_patchlevel() < (8, 6, 5):
+ self.skipTest('requires Tcl version >= ' +
+ '.'.join(map(str, get_tk_patchlevel())))
+ test(self)
+ return newtest
+ return deco
+
_tk_patchlevel = None
def get_tk_patchlevel():
global _tk_patchlevel
'disabledforeground', 'exportselection',
'font', 'foreground', 'height',
'highlightbackground', 'highlightcolor', 'highlightthickness',
- 'listvariable', 'relief',
+ 'justify', 'listvariable', 'relief',
'selectbackground', 'selectborderwidth', 'selectforeground',
'selectmode', 'setgrid', 'state',
'takefocus', 'width', 'xscrollcommand', 'yscrollcommand',
self.checkEnumParam(widget, 'activestyle',
'dotbox', 'none', 'underline')
+ test_justify = requires_tcl(8, 6, 5)(StandardOptionsTests.test_justify)
+
def test_listvariable(self):
widget = self.create()
var = tkinter.DoubleVar(self.root)
OPTIONS = (
'background', 'borderwidth', 'cursor',
'handlepad', 'handlesize', 'height',
- 'opaqueresize', 'orient', 'relief',
+ 'opaqueresize', 'orient',
+ 'proxybackground', 'proxyborderwidth', 'proxyrelief',
+ 'relief',
'sashcursor', 'sashpad', 'sashrelief', 'sashwidth',
'showhandle', 'width',
)
widget = self.create()
self.checkBooleanParam(widget, 'opaqueresize')
+ @requires_tcl(8, 6, 5)
+ def test_proxybackground(self):
+ widget = self.create()
+ self.checkColorParam(widget, 'proxybackground')
+
+ @requires_tcl(8, 6, 5)
+ def test_proxyborderwidth(self):
+ widget = self.create()
+ self.checkPixelsParam(widget, 'proxyborderwidth',
+ 0, 1.3, 2.9, 6, -2, '10p',
+ conv=noconv)
+
+ @requires_tcl(8, 6, 5)
+ def test_proxyrelief(self):
+ widget = self.create()
+ self.checkReliefParam(widget, 'proxyrelief')
+
def test_sashcursor(self):
widget = self.create()
self.checkCursorParam(widget, 'sashcursor')
# BOM will already have been stripped.
encoding = "utf-8"
yield TokenInfo(ENCODING, encoding, (0, 0), (0, 0), '')
- while True: # loop over lines in stream
+ last_line = b''
+ line = b''
+ while True: # loop over lines in stream
try:
+ # We capture the value of the line variable here because
+ # readline uses the empty string '' to signal end of input,
+ # hence `line` itself will always be overwritten at the end
+ # of this loop.
+ last_line = line
line = readline()
except StopIteration:
line = b''
yield stashed
stashed = None
+ # Add an implicit NEWLINE if the input doesn't end in one
+ if last_line and last_line[-1] not in '\r\n':
+ yield TokenInfo(NEWLINE, '', (lnum - 1, len(last_line)), (lnum - 1, len(last_line) + 1), '')
for indent in indents[1:]: # pop remaining indent levels
yield TokenInfo(DEDENT, '', (lnum, 0), (lnum, 0), '')
yield TokenInfo(ENDMARKER, '', (lnum, 0), (lnum, 0), '')
print(item, file=file, end="")
def format_list(extracted_list):
- """Format a list of traceback entry tuples for printing.
+ """Format a list of tuples or FrameSummary objects for printing.
+
+ Given a list of tuples or FrameSummary objects as returned by
+ extract_tb() or extract_stack(), return a list of strings ready
+ for printing.
- Given a list of tuples as returned by extract_tb() or
- extract_stack(), return a list of strings ready for printing.
Each string in the resulting list corresponds to the item with the
same index in the argument list. Each string ends in a newline;
the strings may contain internal newlines as well, for those items
return extract_tb(tb, limit=limit).format()
def extract_tb(tb, limit=None):
- """Return list of up to limit pre-processed entries from traceback.
+ """
+ Return a StackSummary object representing a list of
+ pre-processed entries from traceback.
This is useful for alternate formatting of stack traces. If
'limit' is omitted or None, all entries are extracted. A
- pre-processed stack trace entry is a quadruple (filename, line
- number, function name, text) representing the information that is
- usually printed for a stack trace. The text is a string with
- leading and trailing whitespace stripped; if the source is not
- available it is None.
+ pre-processed stack trace entry is a FrameSummary object
+ containing attributes filename, lineno, name, and line
+ representing the information that is usually printed for a stack
+ trace. The line is a string with leading and trailing
+ whitespace stripped; if the source is not available it is None.
"""
return StackSummary.extract(walk_tb(tb), limit=limit)
tb = tb.tb_next
+_RECURSIVE_CUTOFF = 3 # Also hardcoded in traceback.c.
+
class StackSummary(list):
"""A stack of frames."""
@classmethod
def from_list(klass, a_list):
- """Create a StackSummary from a simple list of tuples.
-
- This method supports the older Python API. Each tuple should be a
- 4-tuple with (filename, lineno, name, line) elements.
+ """
+ Create a StackSummary object from a supplied list of
+ FrameSummary objects or old-style list of tuples.
"""
# While doing a fast-path check for isinstance(a_list, StackSummary) is
# appealing, idlelib.run.cleanup_traceback and other similar code may
last_name = None
count = 0
for frame in self:
- if (last_file is not None and last_file == frame.filename and
- last_line is not None and last_line == frame.lineno and
- last_name is not None and last_name == frame.name):
- count += 1
- else:
- if count > 3:
- result.append(f' [Previous line repeated {count-3} more times]\n')
+ if (last_file is None or last_file != frame.filename or
+ last_line is None or last_line != frame.lineno or
+ last_name is None or last_name != frame.name):
+ if count > _RECURSIVE_CUTOFF:
+ count -= _RECURSIVE_CUTOFF
+ result.append(
+ f' [Previous line repeated {count} more '
+ f'time{"s" if count > 1 else ""}]\n'
+ )
last_file = frame.filename
last_line = frame.lineno
last_name = frame.name
count = 0
- if count >= 3:
+ count += 1
+ if count > _RECURSIVE_CUTOFF:
continue
row = []
row.append(' File "{}", line {}, in {}\n'.format(
for name, value in sorted(frame.locals.items()):
row.append(' {name} = {value}\n'.format(name=name, value=value))
result.append(''.join(row))
- if count > 3:
- result.append(f' [Previous line repeated {count-3} more times]\n')
+ if count > _RECURSIVE_CUTOFF:
+ count -= _RECURSIVE_CUTOFF
+ result.append(
+ f' [Previous line repeated {count} more '
+ f'time{"s" if count > 1 else ""}]\n'
+ )
return result
draw(l, n, th)
tracer(1)
c = clock()
- print("Calculation: %7.4f s" % (b - a))
- print("Drawing: %7.4f s" % (c - b))
- print("Together: %7.4f s" % (c - a))
nk = len([x for x in tiledict if tiledict[x]])
nd = len([x for x in tiledict if not tiledict[x]])
print("%d kites and %d darts = %d pieces." % (nk, nd, nk+nd))
--- /dev/null
+""" turtle-example-suite:
+
+ tdemo_wikipedia3.py
+
+This example is
+inspired by the Wikipedia article on turtle
+graphics. (See example wikipedia1 for URLs)
+
+First we create (ne-1) (i.e. 35 in this
+example) copies of our first turtle p.
+Then we let them perform their steps in
+parallel.
+
+Followed by a complete undo().
+"""
+from turtle import Screen, Turtle, mainloop
+from time import clock, sleep
+
+def mn_eck(p, ne,sz):
+ turtlelist = [p]
+ #create ne-1 additional turtles
+ for i in range(1,ne):
+ q = p.clone()
+ q.rt(360.0/ne)
+ turtlelist.append(q)
+ p = q
+ for i in range(ne):
+ c = abs(ne/2.0-i)/(ne*.7)
+ # let those ne turtles make a step
+ # in parallel:
+ for t in turtlelist:
+ t.rt(360./ne)
+ t.pencolor(1-c,0,c)
+ t.fd(sz)
+
+def main():
+ s = Screen()
+ s.bgcolor("black")
+ p=Turtle()
+ p.speed(0)
+ p.hideturtle()
+ p.pencolor("red")
+ p.pensize(3)
+
+ s.tracer(36,0)
+
+ at = clock()
+ mn_eck(p, 36, 19)
+ et = clock()
+ z1 = et-at
+
+ sleep(1)
+
+ at = clock()
+ while any([t.undobufferentries() for t in s.turtles()]):
+ for t in s.turtles():
+ t.undo()
+ et = clock()
+ return "runtime: %.3f sec" % (z1+et-at)
+
+
+if __name__ == '__main__':
+ msg = main()
+ print(msg)
+ mainloop()
t = tree([p], 200, 65, 0.6375)
for x in t:
pass
- print(len(p.getscreen().turtles()))
def main():
a=clock()
+++ /dev/null
-""" turtle-example-suite:
-
- tdemo_wikipedia3.py
-
-This example is
-inspired by the Wikipedia article on turtle
-graphics. (See example wikipedia1 for URLs)
-
-First we create (ne-1) (i.e. 35 in this
-example) copies of our first turtle p.
-Then we let them perform their steps in
-parallel.
-
-Followed by a complete undo().
-"""
-from turtle import Screen, Turtle, mainloop
-from time import clock, sleep
-
-def mn_eck(p, ne,sz):
- turtlelist = [p]
- #create ne-1 additional turtles
- for i in range(1,ne):
- q = p.clone()
- q.rt(360.0/ne)
- turtlelist.append(q)
- p = q
- for i in range(ne):
- c = abs(ne/2.0-i)/(ne*.7)
- # let those ne turtles make a step
- # in parallel:
- for t in turtlelist:
- t.rt(360./ne)
- t.pencolor(1-c,0,c)
- t.fd(sz)
-
-def main():
- s = Screen()
- s.bgcolor("black")
- p=Turtle()
- p.speed(0)
- p.hideturtle()
- p.pencolor("red")
- p.pensize(3)
-
- s.tracer(36,0)
-
- at = clock()
- mn_eck(p, 36, 19)
- et = clock()
- z1 = et-at
-
- sleep(1)
-
- at = clock()
- while any([t.undobufferentries() for t in s.turtles()]):
- for t in s.turtles():
- t.undo()
- et = clock()
- return "runtime: %.3f sec" % (z1+et-at)
-
-
-if __name__ == '__main__':
- msg = main()
- print(msg)
- mainloop()
def testRegisterResult(self):
result = unittest.TestResult()
- unittest.registerResult(result)
-
- for ref in unittest.signals._results:
- if ref is result:
- break
- elif ref is not result:
- self.fail("odd object in result set")
- else:
- self.fail("result not found")
+ self.assertNotIn(result, unittest.signals._results)
+ unittest.registerResult(result)
+ try:
+ self.assertIn(result, unittest.signals._results)
+ finally:
+ unittest.removeResult(result)
def testInterruptCaught(self):
default_handler = signal.getsignal(signal.SIGINT)
class Opera(UnixBrowser):
"Launcher class for Opera browser."
- raise_opts = ["-noraise", ""]
- remote_args = ['-remote', 'openURL(%s%action)']
+ remote_args = ['%action', '%s']
remote_action = ""
- remote_action_newwin = ",new-window"
- remote_action_newtab = ",new-page"
+ remote_action_newwin = "--new-window"
+ remote_action_newtab = ""
background = True
self._lex_handler_prop = None
self._parsing = 0
self._entity_stack = []
- self._external_ges = 1
+ self._external_ges = 0
self._interning = None
# XMLReader methods
_CD64_DIRECTORY_SIZE = 8
_CD64_OFFSET_START_CENTDIR = 9
+_DD_SIGNATURE = 0x08074b50
+
+_EXTRA_FIELD_STRUCT = struct.Struct('<HH')
+
+def _strip_extra(extra, xids):
+ # Remove Extra Fields with specified IDs.
+ unpack = _EXTRA_FIELD_STRUCT.unpack
+ modified = False
+ buffer = []
+ start = i = 0
+ while i + 4 <= len(extra):
+ xid, xlen = unpack(extra[i : i + 4])
+ j = i + 4 + xlen
+ if xid in xids:
+ if i != start:
+ buffer.append(extra[start : i])
+ start = j
+ modified = True
+ i = j
+ if not modified:
+ return extra
+ return b''.join(buffer)
+
def _check_zipfile(fp):
try:
if _EndRecData(fp):
# Write updated header info
if self._zinfo.flag_bits & 0x08:
# Write CRC and file sizes after the file data
- fmt = '<LQQ' if self._zip64 else '<LLL'
- self._fileobj.write(struct.pack(fmt, self._zinfo.CRC,
+ fmt = '<LLQQ' if self._zip64 else '<LLLL'
+ self._fileobj.write(struct.pack(fmt, _DD_SIGNATURE, self._zinfo.CRC,
self._zinfo.compress_size, self._zinfo.file_size))
self._zipfile.start_dir = self._fileobj.tell()
else:
min_version = 0
if extra:
# Append a ZIP64 field to the extra's
+ extra_data = _strip_extra(extra_data, (1,))
extra_data = struct.pack(
'<HH' + 'Q'*len(extra),
1, 8*len(extra), *extra) + extra_data
CC, CXX = getTargetCompilers()
-PYTHON_3 = getVersionMajorMinor() >= (3, 0)
+PYTHON_2 = getVersionMajorMinor()[0] == 2
+PYTHON_3 = getVersionMajorMinor()[0] == 3
USAGE = textwrap.dedent("""\
Usage: build_python [options]
result.extend([
dict(
- name="OpenSSL 1.0.2o",
- url="https://www.openssl.org/source/openssl-1.0.2o.tar.gz",
- checksum='44279b8557c3247cbe324e2322ecd114',
+ name="OpenSSL 1.0.2p",
+ url="https://www.openssl.org/source/openssl-1.0.2p.tar.gz",
+ checksum='ac5eb30bf5798aa14b1ae6d0e7da58df',
buildrecipe=build_universal_openssl,
configure=None,
install=None,
base_path = base_path + ':' + OLD_DEVELOPER_TOOLS
os.environ['PATH'] = base_path
print("Setting default PATH: %s"%(os.environ['PATH']))
- # Ensure we have access to sphinx-build.
- # You may have to create a link in /usr/bin for it.
- runCommand('sphinx-build --version')
+ if PYTHON_2:
+ # Ensure we have access to sphinx-build.
+ # You may have to define SDK_TOOLS_BIN and link to it there,
+ runCommand('sphinx-build --version')
def parseOptions(args=None):
"""
]
if no_asm:
configure_opts.append("no-asm")
+ # OpenSSL 1.0.2o broke the Configure test for whether the compiler
+ # in use supports dependency rule generation (cc -M) with gcc-4.2
+ # used for the 10.6+ installer builds. Patch Configure here to
+ # force use of "cc -M" rather than "makedepend".
+ runCommand(
+ """sed -i "" 's|my $cc_as_makedepend = 0|my $cc_as_makedepend = 1|g' Configure""")
+
runCommand(" ".join(["perl", "Configure"]
+ arch_opts[arch] + configure_opts))
runCommand("make depend")
curDir = os.getcwd()
os.chdir(buildDir)
runCommand('make clean')
- # Create virtual environment for docs builds with blurb and sphinx
- runCommand('make venv')
- runCommand('make html PYTHON=venv/bin/python')
+ if PYTHON_2:
+ # Python 2 doc builds do not use blurb nor do they have a venv target.
+ # Assume sphinx-build is on our PATH, checked in checkEnvironment
+ runCommand('make html')
+ else:
+ # Create virtual environment for docs builds with blurb and sphinx
+ runCommand('make venv')
+ runCommand('make html PYTHON=venv/bin/python')
os.chdir(curDir)
if not os.path.exists(docdir):
os.mkdir(docdir)
Anton Afanasyev
Ali Afshar
Nitika Agarwal
+Pablo S. Blum de Aguiar
Jim Ahlstrom
Farhan Ahmad
Matthew Ahrens
Jerry Seutter
Pete Sevander
Denis Severson
+Silas Sewell
Ian Seyer
Dmitry Shachnev
Anish Shah
Darren Worrall
Thomas Wouters
Daniel Wozniak
+Marcin Niemira
Wei Wu
Heiko Wundram
Doug Wyatt
EungJun Yi
Bob Yodlowski
Danny Yoo
+Wonsup Yoon
Rory Yorke
George Yoshida
Kazuhiro Yoshida
- Issue #21560: An attempt to write a data of wrong type no longer cause
GzipFile corruption. Original patch by Wolfgang Maier.
-- Issue #23647: Increase impalib's MAXLINE to accommodate modern mailbox sizes.
+- Issue #23647: Increase imaplib's MAXLINE to accommodate modern mailbox sizes.
- Issue #23539: If body is None, http.client.HTTPConnection.request now sets
Content-Length to 0 for PUT, POST, and PATCH headers to avoid 411 errors from
- Issue #23521: Corrected pure python implementation of timedelta division.
* Eliminated OverflowError from timedelta * float for some floats;
- * Corrected rounding in timedlta true division.
+ * Corrected rounding in timedelta true division.
- Issue #21619: Popen objects no longer leave a zombie after exit in the with
statement if the pipe was broken. Patch by Martin Panter.
returned NotImplemented. Original patch by Martin Panter.
- Issue #23321: Fixed a crash in str.decode() when error handler returned
- replacment string longer than mailformed input data.
+ replacement string longer than malformed input data.
- Issue #23048: Fix jumping out of an infinite while loop in the pdb.
- Issue #23250: In the http.cookies module, capitalize "HttpOnly" and "Secure"
as they are written in the standard.
-- Issue #23063: In the disutils' check command, fix parsing of reST with code or
+- Issue #23063: In the distutils' check command, fix parsing of reST with code or
code-block directives.
- Issue #23209, #23225: selectors.BaseSelector.close() now clears its internal
ensure that it will be found regardless of the shell PATH. This ensures
that multiprocessing.cpu_count works on default installs of MacOSX.
-- Issue #11501: disutils.archive_utils.make_zipfile no longer fails if zlib is
+- Issue #11501: distutils.archive_utils.make_zipfile no longer fails if zlib is
not installed. Instead, the zipfile.ZIP_STORED compression is used to create
the ZipFile. Patch by Natalia B. Bidart.
Python News
+++++++++++
+What's New in Python 3.6.7 final?
+=================================
+
+*Release date: 2018-10-20*
+
+There were no new changes in version 3.6.7.
+
+
+
+What's New in Python 3.6.7 release candidate 2?
+===============================================
+
+*Release date: 2018-10-13*
+
+Core and Builtins
+-----------------
+
+- bpo-34879: Fix a possible null pointer dereference in bytesobject.c.
+ Patch by Zackery Spytz.
+
+- bpo-34320: Fix ``dict(od)`` didn't copy iteration order of OrderedDict.
+
+Library
+-------
+
+- bpo-34769: Fix for async generators not finalizing when event loop is in
+ debug mode and garbage collector runs in another thread.
+
+- bpo-34922: Fixed integer overflow in the :meth:`~hashlib.shake.digest()`
+ and :meth:`~hashlib.shake.hexdigest()` methods for the SHAKE algorithm in
+ the :mod:`hashlib` module.
+
+- bpo-34871: Fix inspect module polluted ``sys.modules`` when parsing
+ ``__text_signature__`` of callable.
+
+- bpo-34872: Fix self-cancellation in C implementation of asyncio.Task
+
+- bpo-34819: Use a monotonic clock to compute timeouts in
+ :meth:`Executor.map` and :func:`as_completed`, in order to prevent
+ timeouts from deviating when the system clock is adjusted.
+
+- bpo-34521: Use :func:`socket.CMSG_SPACE` to calculate ancillary data size
+ instead of :func:`socket.CMSG_LEN` in
+ :func:`multiprocessing.reduction.recvfds` as :rfc:`3542` requires the use
+ of the former for portable applications.
+
+- bpo-34282: Fix enum members getting shadowed by parent attributes.
+
+- bpo-34172: Fix a reference issue inside multiprocessing.Pool that caused
+ the pool to remain alive if it was deleted without being closed or
+ terminated explicitly.
+
+- bpo-33729: Fixed issues with arguments parsing in :mod:`hashlib`.
+
+Documentation
+-------------
+
+- bpo-32174: chm document displays non-ASCII charaters properly on some MBCS
+ Windows systems.
+
+Tests
+-----
+
+- bpo-32962: Fixed test_gdb when Python is compiled with flags -mcet
+ -fcf-protection -O0.
+
+macOS
+-----
+
+- bpo-34370: Revert to using the released Tk 8.6.8 with macOS installers
+ instead of the Tk 8.6.x development snapshot used with 3.7.1rc1 and
+ 3.6.7rc1. The snapshot introduced at least one significant regression
+ (bpo-34927).
+
+C API
+-----
+
+- bpo-34910: Ensure that :c:func:`PyObject_Print` always returns ``-1`` on
+ error. Patch by Zackery Spytz.
+
+
+What's New in Python 3.6.7 release candidate 1?
+===============================================
+
+*Release date: 2018-09-26*
+
+Security
+--------
+
+- bpo-17239: The xml.sax and xml.dom.minidom parsers no longer processes
+ external entities by default. External DTD and ENTITY declarations no
+ longer load files or create network connections.
+
+- bpo-34623: CVE-2018-14647: The C accelerated _elementtree module now
+ initializes hash randomization salt from _Py_HashSecret instead of
+ libexpat's default CSPRNG.
+
+- bpo-34405: Updated to OpenSSL 1.0.2p for Windows builds.
+
+- bpo-33871: Fixed sending the part of the file in :func:`os.sendfile` on
+ macOS. Using the *trailers* argument could cause sending more bytes from
+ the input file than was specified.
+
+- bpo-32533: Fixed thread-safety of error handling in _ssl.
+
+Core and Builtins
+-----------------
+
+- bpo-34735: Fix a memory leak in Modules/timemodule.c. Patch by Zackery
+ Spytz.
+
+- bpo-34588: Fix an off-by-one in the recursive call pruning feature of
+ traceback formatting.
+
+- bpo-34527: On FreeBSD, Py_DecodeLocale() and Py_EncodeLocale() now also
+ forces the ASCII encoding if the LC_CTYPE locale is "POSIX", not only if
+ the LC_CTYPE locale is "C".
+
+- bpo-34400: Fix undefined behavior in parsetok.c. Patch by Zackery Spytz.
+
+- bpo-34377: Update valgrind suppression list to use
+ ``_PyObject_Free``/``_PyObject_Realloc`` instead of
+ ``PyObject_Free``/``PyObject_Realloc``.
+
+- bpo-24618: Fixed reading invalid memory when create the code object with
+ too small varnames tuple or too large argument counts.
+
+- bpo-34068: In :meth:`io.IOBase.close`, ensure that the
+ :attr:`~io.IOBase.closed` attribute is not set with a live exception.
+ Patch by Zackery Spytz and Serhiy Storchaka.
+
+- bpo-34080: Fixed a memory leak in the compiler when it raised some
+ uncommon errors during tokenizing.
+
+- bpo-34066: Disabled interruption by Ctrl-C between calling ``open()`` and
+ entering a **with** block in ``with open()``.
+
+- bpo-33956: Update vendored Expat library copy to version 2.2.5.
+
+- bpo-24596: Decref the module object in :c:func:`PyRun_SimpleFileExFlags`
+ before calling :c:func:`PyErr_Print()`. Patch by Zackery Spytz.
+
+- bpo-33451: Close directly executed pyc files before calling
+ ``PyEval_EvalCode()``.
+
+- bpo-33312: Fixed clang ubsan (undefined behavior sanitizer) warnings in
+ dictobject.c by adjusting how the internal struct _dictkeysobject shared
+ keys structure is declared.
+
+- bpo-25750: Fix rare Python crash due to bad refcounting in
+ ``type_getattro()`` if a descriptor deletes itself from the class. Patch
+ by Jeroen Demeyer.
+
+- bpo-25862: Fix assertion failures in the ``tell()`` method of
+ ``io.TextIOWrapper``. Patch by Zackery Spytz.
+
+Library
+-------
+
+- bpo-34670: Add SSLContext.post_handshake_auth and
+ SSLSocket.verify_client_post_handshake for TLS 1.3's post handshake
+ authentication feature.
+
+- bpo-34652: Ensure :func:`os.lchmod` is never defined on Linux.
+
+- bpo-34625: Update vendorized expat library version to 2.2.6.
+
+- bpo-32270: The subprocess module no longer mistakenly closes redirected
+ fds even when they were in pass_fds when outside of the default {0, 1, 2}
+ set.
+
+- bpo-34610: Fixed iterator of :class:`multiprocessing.managers.DictProxy`.
+
+- bpo-34421: Fix distutils logging for non-ASCII strings. This caused
+ installation issues on Windows.
+
+- bpo-34604: Fix possible mojibake in the error message of `pwd.getpwnam`
+ and `grp.getgrnam`. Patch by William Grzybowski.
+
+- bpo-34530: ``distutils.spawn.find_executable()`` now falls back on
+ :data:`os.defpath` if the ``PATH`` environment variable is not set.
+
+- bpo-34563: On Windows, fix multiprocessing.Connection for very large read:
+ fix _winapi.PeekNamedPipe() and _winapi.ReadFile() for read larger than
+ INT_MAX (usually 2^31-1).
+
+- bpo-13312: Avoids a possible integer underflow (undefined behavior) in the
+ time module's year handling code when passed a very low negative year
+ value.
+
+- bpo-34472: Improved compatibility for streamed files in :mod:`zipfile`.
+ Previously an optional signature was not being written and certain ZIP
+ applications were not supported. Patch by Silas Sewell.
+
+- bpo-6700: Fix inspect.getsourcelines for module level frames/tracebacks.
+ Patch by Vladimir Matveev.
+
+- bpo-32947: Add OP_ENABLE_MIDDLEBOX_COMPAT and test workaround for TLSv1.3
+ for future compatibility with OpenSSL 1.1.1.
+
+- bpo-34341: Appending to the ZIP archive with the ZIP64 extension no longer
+ grows the size of extra fields of existing entries.
+
+- bpo-18540: The :class:`imaplib.IMAP4` and :class:`imaplib.IMAP4_SSL`
+ classes now resolve to the local host IP correctly when the default value
+ of *host* parameter (``''``) is used.
+
+- bpo-34246: :meth:`smtplib.SMTP.send_message` no longer modifies the
+ content of the *mail_options* argument. Patch by Pablo S. Blum de Aguiar.
+
+- bpo-31047: Fix ``ntpath.abspath`` for invalid paths on windows. Patch by
+ Franz Woellert.
+
+- bpo-34263: asyncio's event loop will not pass timeouts longer than one day
+ to epoll/select etc.
+
+- bpo-32215: Fix performance regression in :mod:`sqlite3` when a DML
+ statement appeared in a different line than the rest of the SQL query.
+
+- bpo-19891: Ignore errors caused by missing / non-writable homedir while
+ writing history during exit of an interactive session. Patch by Anthony
+ Sottile.
+
+- bpo-940286: pydoc's ``Helper.showtopic()`` method now prints the cross
+ references of a topic correctly.
+
+- bpo-34164: :func:`base64.b32decode` could raise UnboundLocalError or
+ OverflowError for incorrect padding. Now it always raises
+ :exc:`base64.Error` in these cases.
+
+- bpo-33967: functools.singledispatch now raises TypeError instead of
+ IndexError when no positional arguments are passed.
+
+- bpo-34054: The multiprocessing module now uses the monotonic clock
+ :func:`time.monotonic` instead of the system clock :func:`time.time` to
+ implement timeout.
+
+- bpo-34010: Fixed a performance regression for reading streams with
+ tarfile. The buffered read should use a list, instead of appending to a
+ bytes object.
+
+- bpo-34019: webbrowser: Correct the arguments passed to Opera Browser when
+ opening a new URL using the ``webbrowser`` module. Patch by Bumsik Kim.
+
+- bpo-33978: Closed existing logging handlers before reconfiguration via
+ fileConfig and dictConfig. Patch by Karthikeyan Singaravelan.
+
+- bpo-14117: Make minor tweaks to turtledemo. The 'wikipedia' example is now
+ 'rosette', decribing what it draws. The 'penrose' print output is
+ reduced. The'1024' output of 'tree' is eliminated.
+
+- bpo-33974: Fixed passing lists and tuples of strings containing special
+ characters ``"``, ``\``, ``{``, ``}`` and ``\n`` as options to
+ :mod:`~tkinter.ttk` widgets.
+
+- bpo-27500: Fix getaddrinfo to resolve IPv6 addresses correctly.
+
+- bpo-24567: Improve random.choices() to handle subnormal input weights that
+ could occasionally trigger an IndexError.
+
+- bpo-33871: Fixed integer overflow in :func:`os.readv` and
+ :func:`os.writev` and in :func:`os.sendfile` with *headers* or *trailers*
+ arguments (on BSD-based OSes and macOS).
+
+- bpo-33899: Tokenize module now implicitly emits a NEWLINE when provided
+ with input that does not have a trailing new line. This behavior now
+ matches what the C tokenizer does internally. Contributed by Ammar Askar.
+
+- bpo-33916: bz2 and lzma: When Decompressor.__init__() is called twice,
+ free the old lock to not leak memory.
+
+- bpo-32568: Make select.epoll() and its documentation consistent regarding
+ *sizehint* and *flags*.
+
+- bpo-33663: Convert content length to string before putting to header.
+
+- bpo-26544: Fixed implementation of :func:`platform.libc_ver`. It almost
+ always returned version '2.9' for glibc.
+
+- bpo-27397: Make email module properly handle invalid-length base64
+ strings.
+
+- bpo-33476: Fix _header_value_parser.py when address group is missing final
+ ';'. Contributed by Enrique Perez-Terron
+
+- bpo-33570: Change TLS 1.3 cipher suite settings for compatibility with
+ OpenSSL 1.1.1-pre6 and newer. OpenSSL 1.1.1 will have TLS 1.3 cipers
+ enabled by default.
+
+- bpo-33365: Print the header values besides the header keys instead just
+ the header keys if *debuglevel* is set to >0 in :mod:`http.client`. Patch
+ by Marco Strigl.
+
+- bpo-33336: ``imaplib`` now allows ``MOVE`` command in ``IMAP4.uid()`` (RFC
+ 6851: IMAP MOVE Extension) and potentially as a name of supported method
+ of ``IMAP4`` object.
+
+- bpo-32356: asyncio.transport.resume_reading() and pause_reading() are now
+ idempotent.
+
+- bpo-31608: Raise a ``TypeError`` instead of crashing if a
+ ``collections.deque`` subclass returns a non-deque from ``__new__``. Patch
+ by Oren Milman.
+
+- bpo-29456: Fix bugs in hangul normalization: u1176, u11a7 and u11c3
+
+Documentation
+-------------
+
+- bpo-28617: Fixed info in the stdtypes docs concerning the types that
+ support membership tests.
+
+- bpo-34065: Fix wrongly written basicConfig documentation markup syntax
+
+- bpo-33847: Add '@' operator entry to index.
+
+- bpo-25041: Document ``AF_PACKET`` in the :mod:`socket` module.
+
+Tests
+-----
+
+- bpo-34587: test_socket: Remove RDSTest.testCongestion(). The test tries to
+ fill the receiver's socket buffer and expects an error. But the RDS
+ protocol doesn't require that. Moreover, the Linux implementation of RDS
+ expects that the producer of the messages reduces its rate, it's not the
+ role of the receiver to trigger an error. The test fails on Fedora 28 by
+ design, so just remove it.
+
+- bpo-34661: Fix test_shutil if unzip doesn't support -t.
+
+- bpo-34200: Fixed non-deterministic flakiness of test_pkg by not using the
+ scary test.support.module_cleanup() logic to save and restore sys.modules
+ contents between test cases.
+
+- bpo-34594: Fix usage of hardcoded ``errno`` values in the tests.
+
+- bpo-34542: Use 3072 RSA keys and SHA-256 signature for test certs and
+ keys.
+
+- bpo-34391: Fix ftplib test for TLS 1.3 by reading from data socket.
+
+- bpo-34399: Update all RSA keys and DH params to use at least 2048 bits.
+
+- bpo-33746: Fix test_unittest when run in verbose mode.
+
+- bpo-33901: Fix test_dbm_gnu on macOS with gdbm 1.15: add a larger value to
+ make sure that the file size changes.
+
+- bpo-33873: Fix a bug in ``regrtest`` that caused an extra test to run if
+ --huntrleaks/-R was used. Exit with error in case that invalid parameters
+ are specified to --huntrleaks/-R (at least one warmup run and one
+ repetition must be used).
+
+- bpo-32663: Making sure the `SMTPUTF8SimTests` class of tests gets run in
+ test_smtplib.py.
+
+Build
+-----
+
+- bpo-34710: Fixed SSL module build with OpenSSL & pedantic CFLAGS.
+
+- bpo-34582: Add JUnit XML output for regression tests and update Azure
+ DevOps builds.
+
+- bpo-34121: Fix detection of C11 atomic support on clang.
+
+- bpo-30345: Add -g to LDFLAGS when compiling with LTO to get debug symbols.
+
+Windows
+-------
+
+- bpo-34770: Fix a possible null pointer dereference in pyshellext.cpp.
+
+- bpo-34603: Fix returning structs from functions produced by MSVC
+
+- bpo-34225: Ensure INCLUDE and LIB directories do not end with a backslash.
+
+- bpo-34006: Revert line length limit for Windows help docs. The line-length
+ limit is not needed because the pages appear in a separate app rather than
+ on a browser tab. It can also interact badly with the DPI setting.
+
+- bpo-31546: Restore running PyOS_InputHook while waiting for user input at
+ the prompt. The restores integration of interactive GUI windows (such as
+ Matplotlib figures) with the prompt on Windows.
+
+- bpo-30237: Output error when ReadConsole is canceled by
+ CancelSynchronousIo instead of crashing.
+
+- bpo-29097: Fix bug where :meth:`datetime.fromtimestamp` erronously throws
+ an :exc:`OSError` on Windows for values between 0 and 86400. Patch by
+ Ammar Askar.
+
+macOS
+-----
+
+- bpo-34370: Have macOS 10.9+ installer builds for 3.7.1rc and 3.6.7rc use a
+ development snapshot of Tk 8.6 (post-8.6.8) to mitigate certain scroller
+ issues seen with IDLE and tkinter apps.
+
+- bpo-34405: Update to OpenSSL 1.0.2p for macOS installer builds.
+
+- bpo-31903: In :mod:`_scproxy`, drop the GIL when calling into
+ ``SystemConfiguration`` to avoid deadlocks.
+
+IDLE
+----
+
+- bpo-34548: Use configured color theme for read-only text views.
+
+- bpo-1529353: Enable "squeezing" of long outputs in the shell, to avoid
+ performance degradation and to clean up the history without losing it.
+ Squeezed outputs may be copied, viewed in a separate window, and
+ "unsqueezed".
+
+- bpo-34047: Fixed mousewheel scrolling direction on macOS.
+
+- bpo-34275: Make IDLE calltips always visible on Mac. Some MacOS-tk
+ combinations need .update_idletasks(). Patch by Kevin Walzer.
+
+- bpo-34120: Fix unresponsiveness after closing certain windows and dialogs.
+
+- bpo-33975: Avoid small type when running htests. Since part of the purpose
+ of human- viewed tests is to determine that widgets look right, it is
+ important that they look the same for testing as when running IDLE.
+
+- bpo-33905: Add test for idlelib.stackview.StackBrowser.
+
+- bpo-33924: Change mainmenu.menudefs key 'windows' to 'window'. Every other
+ menudef key is lowercase version of main menu entry.
+
+- bpo-33906: Rename idlelib.windows as window Match Window on the main menu
+ and remove last plural module name.
+
+- bpo-33917: Fix and document idlelib/idle_test/template.py. The revised
+ file compiles, runs, and tests OK. idle_test/README.txt explains how to
+ use it to create new IDLE test files.
+
+- bpo-33904: IDLE: In rstrip, rename class RstripExtension as Rstrip
+
+- bpo-33907: For consistency and clarity, rename an IDLE module and classes.
+ Module calltips and its class CallTips are now calltip and Calltip. In
+ module calltip_w, class CallTip is now CalltipWindow.
+
+- bpo-33856: Add "help" in the welcome message of IDLE
+
+- bpo-33839: IDLE: refactor ToolTip and CallTip and add documentation and
+ tests
+
+- bpo-33855: Minimally test all IDLE modules. Add missing files, import
+ module, instantiate classes, and check coverage. Check existing files.
+
+Tools/Demos
+-----------
+
+- bpo-32962: python-gdb now catchs ``UnicodeDecodeError`` exceptions when
+ calling ``string()``.
+
+- bpo-32962: python-gdb now catchs ValueError on read_var(): when Python has
+ no debug symbols for example.
+
+C API
+-----
+
+- bpo-23927: Fixed :exc:`SystemError` in
+ :c:func:`PyArg_ParseTupleAndKeywords` when the ``w*`` format unit is used
+ for optional parameter.
+
+
What's New in Python 3.6.6 final?
=================================
call_soon(). Previously, data_received() could be called before the
handshake started, causing the handshake to hang or fail.
-- bpo-31467: Fixed bug where calling write_eof() on a
+- bpo-31647: Fixed bug where calling write_eof() on a
_SelectorSocketTransport after it's already closed raises AttributeError.
- bpo-33672: Fix Task.__repr__ crash with Cython's bogus coroutines
- bpo-29673: Fix pystackv and pystack gdbinit macros.
-- bpo-32885: Add an ``-n`` flag for ``Tools/scripts/pathfix.py`` to disbale
+- bpo-32885: Add an ``-n`` flag for ``Tools/scripts/pathfix.py`` to disable
automatic backup creation (files with ``~`` suffix).
- bpo-31583: Fix 2to3 for using with --add-suffix option but without
-------------
- bpo-32105: Added asyncio.BaseEventLoop.connect_accepted_socket
- versionaddded marker.
+ versionadded marker.
- bpo-31537: Fix incorrect usage of ``get_history_length`` in readline
documentation example code. Patch by Brad Smith.
- bpo-32100: IDLE: Fix old and new bugs in pathbrowser; improve tests. Patch
mostly by Cheryl Sabella.
-- bpo-31858: IDLE -- Restrict shell prompt manipulaton to the shell. Editor
+- bpo-31858: IDLE -- Restrict shell prompt manipulation to the shell. Editor
and output windows only see an empty last prompt line. This simplifies
the code and fixes a minor bug when newline is inserted. Sys.ps1, if
present, is read on Shell start-up, but is not set or changed.
- bpo-30722: Make redemo work with Python 3.6 and newer versions.
- In Python 3.6, flags like re.DOTALL became members of an enum.IntFlag so
- usages like ``getattr(re, 'DOTALL')`` are invalid.
-
Also, remove the ``LOCALE`` option since it doesn't work with string
patterns in Python 3.
contains CR or LF. Patch by Dong-hee Na.
- bpo-30595: multiprocessing.Queue.get() with a timeout now polls its reader
- in non-blocking mode if it succeeded to aquire the lock but the acquire
+ in non-blocking mode if it succeeded to acquire the lock but the acquire
took longer than the timeout.
- bpo-29403: Fix ``unittest.mock``'s autospec to not fail on method-bound
- bpo-31421: Document how IDLE runs tkinter programs. IDLE calls tcl/tk
update in the background in order to make live
- interaction and experimentatin with tkinter applications much easier.
+ interaction and experimentation with tkinter applications much easier.
- bpo-31414: IDLE -- fix tk entry box tests by deleting first. Adding to an
int entry is not the same as deleting and inserting because int('') will
fail.
-- bpo-31051: Rearrange IDLE condigdialog GenPage into Window, Editor, and
+- bpo-31051: Rearrange IDLE configdialog GenPage into Window, Editor, and
Help sections.
- bpo-30617: IDLE - Add docstrings and tests for outwin subclass of editor.
- bpo-30500: Fix urllib.parse.splithost() to correctly parse fragments. For
example, ``splithost('//127.0.0.1#@evil.com/')`` now correctly returns the
``127.0.0.1`` host, instead of treating ``@evil.com`` as the host in an
- authentification (``login@host``).
+ authentication (``login@host``).
What's New in Python 3.6.2 release candidate 1?
- bpo-27850: Remove 3DES from ssl module's default cipher list to counter
measure sweet32 attack (CVE-2016-2183).
-- bpo-27766: Add ChaCha20 Poly1305 to ssl module's default ciper list.
+- bpo-27766: Add ChaCha20 Poly1305 to ssl module's default cipher list.
(Required OpenSSL 1.1.0 or LibreSSL).
- bpo-25387: Check return value of winsound.MessageBeep.
option but without -jn. Fix warning from test_config.
- bpo-27621: Put query response validation error messages in the query box
- itself instead of in a separate massagebox. Redo tests to match. Add Mac
+ itself instead of in a separate messagebox. Redo tests to match. Add Mac
OSX refinements. Original patch by Mark Roseman.
- bpo-27620: Escape key now closes Query box as cancelled.
- bpo-23968: Rename the platform directory from plat-$(MACHDEP) to
plat-$(PLATFORM_TRIPLET). Rename the config directory (LIBPL) from
config-$(LDVERSION) to config-$(LDVERSION)-$(PLATFORM_TRIPLET). Install
- the platform specifc _sysconfigdata module into the platform directory and
- rename it to include the ABIFLAGS.
+ the platform specific _sysconfigdata module into the platform directory
+ and rename it to include the ABIFLAGS.
- Don't use largefile support for GNU/Hurd.
exposed on the API which are not implemented on GNU/Hurd. They would not
work at runtime anyway.
-- bpo-27025: Generated names for Tkinter widgets are now more meanful and
- recognizirable.
+- bpo-27025: Generated names for Tkinter widgets are now more meaningful and
+ recognizable.
- bpo-25455: Fixed crashes in repr of recursive ElementTree.Element and
functools.partial objects.
- bpo-24759: IDLE requires tk 8.5 and availability ttk widgets. Delete now
unneeded tk version tests and code for older versions. Add test for IDLE
- syntax colorizoer.
+ syntax colorizer.
- bpo-27239: idlelib.macosx.isXyzTk functions initialize as needed.
- bpo-27262: move Aqua unbinding code, which enable context menus, to
- maxosx.
+ macosx.
- bpo-24759: Make clear in idlelib.idle_test.__init__ that the directory is
a private implementation of test.test_idle and tool for maintainers.
- bpo-25382: pickletools.dis() now outputs implicit memo index for the
MEMOIZE opcode.
-- bpo-25357: Add an optional newline paramer to binascii.b2a_base64().
+- bpo-25357: Add an optional newline parameter to binascii.b2a_base64().
base64.b64encode() uses it to avoid a memory copy.
- bpo-24164: Objects that need calling ``__new__`` with keyword arguments,
- bpo-26198: ValueError is now raised instead of TypeError on buffer
overflow in parsing "es#" and "et#" format units. SystemError is now
- raised instead of TypeError on programmical error in parsing format
+ raised instead of TypeError on programmatical error in parsing format
string.
- bpo-27850: Remove 3DES from ssl module's default cipher list to counter
measure sweet32 attack (CVE-2016-2183).
-- bpo-27766: Add ChaCha20 Poly1305 to ssl module's default ciper list.
+- bpo-27766: Add ChaCha20 Poly1305 to ssl module's default cipher list.
(Required OpenSSL 1.1.0 or LibreSSL).
- bpo-26470: Port ssl and hashlib module to OpenSSL 1.1.0.
attribute (restores backward compatibility).
- bpo-25447: Copying the lru_cache() wrapper object now always works,
- independedly from the type of the wrapped object (by returning the
+ independently from the type of the wrapped object (by returning the
original object unchanged).
- bpo-24103: Fixed possible use after free in ElementTree.XMLPullParser.
- bpo-25150: Hide the private _Py_atomic_xxx symbols from the public
Python.h header to fix a compilation error with OpenMP.
PyThreadState_GET() becomes an alias to PyThreadState_Get() to avoid ABI
- incompatibilies.
+ incompatibilities.
Library
-------
- bpo-13583: sqlite3.Row now supports slice indexing.
- bpo-18473: Fixed 2to3 and 3to2 compatible pickle mappings. Fixed
- ambigious reverse mappings. Added many new mappings. Import mapping is
+ ambiguous reverse mappings. Added many new mappings. Import mapping is
no longer applied to modules already mapped with full name mapping.
- bpo-23485: select.select() is now retried automatically with the
- bpo-23252: Added support for writing ZIP files to unseekable streams.
-- bpo-23647: Increase impalib's MAXLINE to accommodate modern mailbox sizes.
+- bpo-23647: Increase imaplib's MAXLINE to accommodate modern mailbox sizes.
- bpo-23539: If body is None, http.client.HTTPConnection.request now sets
Content-Length to 0 for PUT, POST, and PATCH headers to avoid 411 errors
- bpo-23521: Corrected pure python implementation of timedelta division.
Eliminated OverflowError from ``timedelta * float`` for some floats;
- Corrected rounding in timedlta true division.
+ Corrected rounding in timedelta true division.
- bpo-21619: Popen objects no longer leave a zombie after exit in the with
statement if the pipe was broken. Patch by Martin Panter.
returned NotImplemented. Original patch by Martin Panter.
- bpo-23321: Fixed a crash in str.decode() when error handler returned
- replacment string longer than mailformed input data.
+ replacement string longer than malformed input data.
- bpo-22286: The "backslashreplace" error handlers now works with decoding
and translating.
- bpo-23250: In the http.cookies module, capitalize "HttpOnly" and "Secure"
as they are written in the standard.
-- bpo-23063: In the disutils' check command, fix parsing of reST with code
+- bpo-23063: In the distutils' check command, fix parsing of reST with code
or code-block directives.
- bpo-23209: selectors.BaseSelector.get_key() now raises a RuntimeError if
- Fix repr(_socket.socket) on Windows 64-bit: don't fail with OverflowError
on closed socket. repr(socket.socket) already works fine.
-- bpo-22033: Reprs of most Python implemened classes now contain actual
+- bpo-22033: Reprs of most Python implemented classes now contain actual
class name instead of hardcoded one.
- bpo-21947: The dis module can now disassemble generator-iterator objects
- bpo-21932: os.read() now uses a :c:func:`Py_ssize_t` type instead of
:c:type:`int` for the size to support reading more than 2 GB at once. On
- Windows, the size is truncted to INT_MAX. As any call to os.read(), the OS
- may read less bytes than the number of requested bytes.
+ Windows, the size is truncated to INT_MAX. As any call to os.read(), the
+ OS may read less bytes than the number of requested bytes.
- bpo-21942: Fixed source file viewing in pydoc's server mode on Windows.
When this preprocessor symbol is defined, before PyEval_EvalFrame executes a
frame's code it checks the frame's global namespace for a variable
-"__lltrace__". If such a variable is found, mounds of information about what
+"__ltrace__". If such a variable is found, mounds of information about what
the interpreter is doing are sprayed to stdout, such as every opcode and opcode
argument and values pushed onto and popped off the value stack.
# to use the preferred suppressions with address_in_range.
#
# If you do not want to recompile Python, you can uncomment
-# suppressions for PyObject_Free and PyObject_Realloc.
+# suppressions for _PyObject_Free and _PyObject_Realloc.
#
# See Misc/README.valgrind for more information.
###{
### ADDRESS_IN_RANGE/Invalid read of size 4
### Memcheck:Addr4
-### fun:PyObject_Free
+### fun:_PyObject_Free
###}
###
###{
### ADDRESS_IN_RANGE/Invalid read of size 4
### Memcheck:Value4
-### fun:PyObject_Free
+### fun:_PyObject_Free
###}
###
###{
### ADDRESS_IN_RANGE/Use of uninitialised value of size 8
### Memcheck:Addr8
-### fun:PyObject_Free
+### fun:_PyObject_Free
###}
###
###{
### ADDRESS_IN_RANGE/Use of uninitialised value of size 8
### Memcheck:Value8
-### fun:PyObject_Free
+### fun:_PyObject_Free
###}
###
###{
### ADDRESS_IN_RANGE/Conditional jump or move depends on uninitialised value
### Memcheck:Cond
-### fun:PyObject_Free
+### fun:_PyObject_Free
###}
###{
### ADDRESS_IN_RANGE/Invalid read of size 4
### Memcheck:Addr4
-### fun:PyObject_Realloc
+### fun:_PyObject_Realloc
###}
###
###{
### ADDRESS_IN_RANGE/Invalid read of size 4
### Memcheck:Value4
-### fun:PyObject_Realloc
+### fun:_PyObject_Realloc
###}
###
###{
### ADDRESS_IN_RANGE/Use of uninitialised value of size 8
### Memcheck:Addr8
-### fun:PyObject_Realloc
+### fun:_PyObject_Realloc
###}
###
###{
### ADDRESS_IN_RANGE/Use of uninitialised value of size 8
### Memcheck:Value8
-### fun:PyObject_Realloc
+### fun:_PyObject_Realloc
###}
###
###{
### ADDRESS_IN_RANGE/Conditional jump or move depends on uninitialised value
### Memcheck:Cond
-### fun:PyObject_Realloc
+### fun:_PyObject_Realloc
###}
###
#zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib -lz
# Interface to the Expat XML parser
-#
-# Expat was written by James Clark and is now maintained by a group of
-# developers on SourceForge; see www.libexpat.org for more
-# information. The pyexpat module was written by Paul Prescod after a
-# prototype by Jack Jansen. Source of Expat 1.95.2 is included in
-# Modules/expat/. Usage of a system shared libexpat.so/expat.dll is
-# not advised.
-#
# More information on Expat can be found at www.libexpat.org.
#
#pyexpat expat/xmlparse.c expat/xmlrole.c expat/xmltok.c pyexpat.c -I$(srcdir)/Modules/expat -DHAVE_EXPAT_CONFIG_H -DUSE_PYEXPAT_CAPI
{NULL} /* Sentinel */
};
-PyTypeObject TaskStepMethWrapper_Type = {
+static PyTypeObject TaskStepMethWrapper_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"TaskStepMethWrapper",
.tp_basicsize = sizeof(TaskStepMethWrapper),
Py_TYPE(o)->tp_free(o);
}
-PyTypeObject TaskWakeupMethWrapper_Type = {
+static PyTypeObject TaskWakeupMethWrapper_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"TaskWakeupMethWrapper",
.tp_basicsize = sizeof(TaskWakeupMethWrapper),
if (task->task_must_cancel) {
PyObject *r;
- r = future_cancel(fut);
+ int is_true;
+ r = _PyObject_CallMethodId(result, &PyId_cancel, NULL);
if (r == NULL) {
return NULL;
}
- if (r == Py_True) {
+ is_true = PyObject_IsTrue(r);
+ Py_DECREF(r);
+ if (is_true < 0) {
+ return NULL;
+ }
+ else if (is_true) {
task->task_must_cancel = 0;
}
- Py_DECREF(r);
}
Py_RETURN_NONE;
#include "clinic/blake2b_impl.c.h"
/*[clinic input]
-module _blake2b
-class _blake2b.blake2b "BLAKE2bObject *" "&PyBlake2_BLAKE2bType"
+module _blake2
+class _blake2.blake2b "BLAKE2bObject *" "&PyBlake2_BLAKE2bType"
[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6893358c6622aecf]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=d47b0527b39c673f]*/
static BLAKE2bObject *
/*[clinic input]
@classmethod
-_blake2b.blake2b.__new__ as py_blake2b_new
- string as data: object = NULL
+_blake2.blake2b.__new__ as py_blake2b_new
+ data: object(c_default="NULL") = b''
+ /
*
- digest_size: int(c_default="BLAKE2B_OUTBYTES") = _blake2b.blake2b.MAX_DIGEST_SIZE
- key: Py_buffer = None
- salt: Py_buffer = None
- person: Py_buffer = None
+ digest_size: int(c_default="BLAKE2B_OUTBYTES") = _blake2.blake2b.MAX_DIGEST_SIZE
+ key: Py_buffer(c_default="NULL", py_default="b''") = None
+ salt: Py_buffer(c_default="NULL", py_default="b''") = None
+ person: Py_buffer(c_default="NULL", py_default="b''") = None
fanout: int = 1
depth: int = 1
- leaf_size as leaf_size_obj: object = NULL
- node_offset as node_offset_obj: object = NULL
+ leaf_size as leaf_size_obj: object(c_default="NULL") = 0
+ node_offset as node_offset_obj: object(c_default="NULL") = 0
node_depth: int = 0
inner_size: int = 0
last_node: bool = False
int fanout, int depth, PyObject *leaf_size_obj,
PyObject *node_offset_obj, int node_depth,
int inner_size, int last_node)
-/*[clinic end generated code: output=7506d8d890e5f13b input=e41548dfa0866031]*/
+/*[clinic end generated code: output=7506d8d890e5f13b input=aca35b33c5612b4b]*/
{
BLAKE2bObject *self = NULL;
Py_buffer buf;
}
/*[clinic input]
-_blake2b.blake2b.copy
+_blake2.blake2b.copy
Return a copy of the hash object.
[clinic start generated code]*/
static PyObject *
-_blake2b_blake2b_copy_impl(BLAKE2bObject *self)
-/*[clinic end generated code: output=c89cd33550ab1543 input=4c9c319f18f10747]*/
+_blake2_blake2b_copy_impl(BLAKE2bObject *self)
+/*[clinic end generated code: output=ff6acee5f93656ae input=e383c2d199fd8a2e]*/
{
BLAKE2bObject *cpy;
}
/*[clinic input]
-_blake2b.blake2b.update
+_blake2.blake2b.update
- obj: object
+ data: object
/
-Update this hash object's state with the provided string.
+Update this hash object's state with the provided bytes-like object.
[clinic start generated code]*/
static PyObject *
-_blake2b_blake2b_update(BLAKE2bObject *self, PyObject *obj)
-/*[clinic end generated code: output=a888f07c4cddbe94 input=3ecb8c13ee4260f2]*/
+_blake2_blake2b_update(BLAKE2bObject *self, PyObject *data)
+/*[clinic end generated code: output=010dfcbe22654359 input=ffc4aa6a6a225d31]*/
{
Py_buffer buf;
- GET_BUFFER_VIEW_OR_ERROUT(obj, &buf);
+ GET_BUFFER_VIEW_OR_ERROUT(data, &buf);
#ifdef WITH_THREAD
if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE)
}
/*[clinic input]
-_blake2b.blake2b.digest
+_blake2.blake2b.digest
-Return the digest value as a string of binary data.
+Return the digest value as a bytes object.
[clinic start generated code]*/
static PyObject *
-_blake2b_blake2b_digest_impl(BLAKE2bObject *self)
-/*[clinic end generated code: output=b13a79360d984740 input=ac2fa462ebb1b9c7]*/
+_blake2_blake2b_digest_impl(BLAKE2bObject *self)
+/*[clinic end generated code: output=a5864660f4bfc61a input=7d21659e9c5fff02]*/
{
uint8_t digest[BLAKE2B_OUTBYTES];
blake2b_state state_cpy;
}
/*[clinic input]
-_blake2b.blake2b.hexdigest
+_blake2.blake2b.hexdigest
Return the digest value as a string of hexadecimal digits.
[clinic start generated code]*/
static PyObject *
-_blake2b_blake2b_hexdigest_impl(BLAKE2bObject *self)
-/*[clinic end generated code: output=6a503611715b24bd input=d58f0b2f37812e33]*/
+_blake2_blake2b_hexdigest_impl(BLAKE2bObject *self)
+/*[clinic end generated code: output=b5598a87d8794a60 input=76930f6946351f56]*/
{
uint8_t digest[BLAKE2B_OUTBYTES];
blake2b_state state_cpy;
static PyMethodDef py_blake2b_methods[] = {
- _BLAKE2B_BLAKE2B_COPY_METHODDEF
- _BLAKE2B_BLAKE2B_DIGEST_METHODDEF
- _BLAKE2B_BLAKE2B_HEXDIGEST_METHODDEF
- _BLAKE2B_BLAKE2B_UPDATE_METHODDEF
+ _BLAKE2_BLAKE2B_COPY_METHODDEF
+ _BLAKE2_BLAKE2B_DIGEST_METHODDEF
+ _BLAKE2_BLAKE2B_HEXDIGEST_METHODDEF
+ _BLAKE2_BLAKE2B_UPDATE_METHODDEF
{NULL, NULL}
};
PyTypeObject PyBlake2_BLAKE2bType = {
PyVarObject_HEAD_INIT(NULL, 0)
"_blake2.blake2b", /* tp_name */
- sizeof(BLAKE2bObject), /* tp_size */
+ sizeof(BLAKE2bObject), /* tp_basicsize */
0, /* tp_itemsize */
py_blake2b_dealloc, /* tp_dealloc */
0, /* tp_print */
#include "clinic/blake2s_impl.c.h"
/*[clinic input]
-module _blake2s
-class _blake2s.blake2s "BLAKE2sObject *" "&PyBlake2_BLAKE2sType"
+module _blake2
+class _blake2.blake2s "BLAKE2sObject *" "&PyBlake2_BLAKE2sType"
[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=edbfcf7557a685a7]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=4b79d7ffe07286ce]*/
static BLAKE2sObject *
/*[clinic input]
@classmethod
-_blake2s.blake2s.__new__ as py_blake2s_new
- string as data: object = NULL
+_blake2.blake2s.__new__ as py_blake2s_new
+ data: object(c_default="NULL") = b''
+ /
*
- digest_size: int(c_default="BLAKE2S_OUTBYTES") = _blake2s.blake2s.MAX_DIGEST_SIZE
- key: Py_buffer = None
- salt: Py_buffer = None
- person: Py_buffer = None
+ digest_size: int(c_default="BLAKE2S_OUTBYTES") = _blake2.blake2s.MAX_DIGEST_SIZE
+ key: Py_buffer(c_default="NULL", py_default="b''") = None
+ salt: Py_buffer(c_default="NULL", py_default="b''") = None
+ person: Py_buffer(c_default="NULL", py_default="b''") = None
fanout: int = 1
depth: int = 1
- leaf_size as leaf_size_obj: object = NULL
- node_offset as node_offset_obj: object = NULL
+ leaf_size as leaf_size_obj: object(c_default="NULL") = 0
+ node_offset as node_offset_obj: object(c_default="NULL") = 0
node_depth: int = 0
inner_size: int = 0
last_node: bool = False
int fanout, int depth, PyObject *leaf_size_obj,
PyObject *node_offset_obj, int node_depth,
int inner_size, int last_node)
-/*[clinic end generated code: output=fe060b258a8cbfc6 input=458cfdcb3d0d47ff]*/
+/*[clinic end generated code: output=fe060b258a8cbfc6 input=3abfaabe7f5f62cc]*/
{
BLAKE2sObject *self = NULL;
Py_buffer buf;
}
/*[clinic input]
-_blake2s.blake2s.copy
+_blake2.blake2s.copy
Return a copy of the hash object.
[clinic start generated code]*/
static PyObject *
-_blake2s_blake2s_copy_impl(BLAKE2sObject *self)
-/*[clinic end generated code: output=6c5bada404b7aed7 input=c8858e887ae4a07a]*/
+_blake2_blake2s_copy_impl(BLAKE2sObject *self)
+/*[clinic end generated code: output=5b90131c4eae275e input=0b9d44942f0fe4b2]*/
{
BLAKE2sObject *cpy;
}
/*[clinic input]
-_blake2s.blake2s.update
+_blake2.blake2s.update
- obj: object
+ data: object
/
-Update this hash object's state with the provided string.
+Update this hash object's state with the provided bytes-like object.
[clinic start generated code]*/
static PyObject *
-_blake2s_blake2s_update(BLAKE2sObject *self, PyObject *obj)
-/*[clinic end generated code: output=fe8438a1d3cede87 input=47a408b9a3cc05c5]*/
+_blake2_blake2s_update(BLAKE2sObject *self, PyObject *data)
+/*[clinic end generated code: output=757dc087fec37815 input=97500db2f9de4aaa]*/
{
Py_buffer buf;
- GET_BUFFER_VIEW_OR_ERROUT(obj, &buf);
+ GET_BUFFER_VIEW_OR_ERROUT(data, &buf);
#ifdef WITH_THREAD
if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE)
}
/*[clinic input]
-_blake2s.blake2s.digest
+_blake2.blake2s.digest
-Return the digest value as a string of binary data.
+Return the digest value as a bytes object.
[clinic start generated code]*/
static PyObject *
-_blake2s_blake2s_digest_impl(BLAKE2sObject *self)
-/*[clinic end generated code: output=80e81a48c6f79cf9 input=feb9a220135bdeba]*/
+_blake2_blake2s_digest_impl(BLAKE2sObject *self)
+/*[clinic end generated code: output=40c566ca4bc6bc51 input=f41e0b8d6d937454]*/
{
uint8_t digest[BLAKE2S_OUTBYTES];
blake2s_state state_cpy;
}
/*[clinic input]
-_blake2s.blake2s.hexdigest
+_blake2.blake2s.hexdigest
Return the digest value as a string of hexadecimal digits.
[clinic start generated code]*/
static PyObject *
-_blake2s_blake2s_hexdigest_impl(BLAKE2sObject *self)
-/*[clinic end generated code: output=db6c5028c0a3c2e5 input=4e4877b8bd7aea91]*/
+_blake2_blake2s_hexdigest_impl(BLAKE2sObject *self)
+/*[clinic end generated code: output=15153eb5e59c52eb input=c77a1321567e8952]*/
{
uint8_t digest[BLAKE2S_OUTBYTES];
blake2s_state state_cpy;
static PyMethodDef py_blake2s_methods[] = {
- _BLAKE2S_BLAKE2S_COPY_METHODDEF
- _BLAKE2S_BLAKE2S_DIGEST_METHODDEF
- _BLAKE2S_BLAKE2S_HEXDIGEST_METHODDEF
- _BLAKE2S_BLAKE2S_UPDATE_METHODDEF
+ _BLAKE2_BLAKE2S_COPY_METHODDEF
+ _BLAKE2_BLAKE2S_DIGEST_METHODDEF
+ _BLAKE2_BLAKE2S_HEXDIGEST_METHODDEF
+ _BLAKE2_BLAKE2S_UPDATE_METHODDEF
{NULL, NULL}
};
PyTypeObject PyBlake2_BLAKE2sType = {
PyVarObject_HEAD_INIT(NULL, 0)
"_blake2.blake2s", /* tp_name */
- sizeof(BLAKE2sObject), /* tp_size */
+ sizeof(BLAKE2sObject), /* tp_basicsize */
0, /* tp_itemsize */
py_blake2s_dealloc, /* tp_dealloc */
0, /* tp_print */
[clinic start generated code]*/
PyDoc_STRVAR(py_blake2b_new__doc__,
-"blake2b(string=None, *, digest_size=_blake2b.blake2b.MAX_DIGEST_SIZE,\n"
-" key=None, salt=None, person=None, fanout=1, depth=1,\n"
-" leaf_size=None, node_offset=None, node_depth=0, inner_size=0,\n"
-" last_node=False)\n"
+"blake2b(data=b\'\', /, *, digest_size=_blake2.blake2b.MAX_DIGEST_SIZE,\n"
+" key=b\'\', salt=b\'\', person=b\'\', fanout=1, depth=1, leaf_size=0,\n"
+" node_offset=0, node_depth=0, inner_size=0, last_node=False)\n"
"--\n"
"\n"
"Return a new BLAKE2b hash object.");
py_blake2b_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
PyObject *return_value = NULL;
- static const char * const _keywords[] = {"string", "digest_size", "key", "salt", "person", "fanout", "depth", "leaf_size", "node_offset", "node_depth", "inner_size", "last_node", NULL};
+ static const char * const _keywords[] = {"", "digest_size", "key", "salt", "person", "fanout", "depth", "leaf_size", "node_offset", "node_depth", "inner_size", "last_node", NULL};
static _PyArg_Parser _parser = {"|O$iy*y*y*iiOOiip:blake2b", _keywords, 0};
PyObject *data = NULL;
int digest_size = BLAKE2B_OUTBYTES;
return return_value;
}
-PyDoc_STRVAR(_blake2b_blake2b_copy__doc__,
+PyDoc_STRVAR(_blake2_blake2b_copy__doc__,
"copy($self, /)\n"
"--\n"
"\n"
"Return a copy of the hash object.");
-#define _BLAKE2B_BLAKE2B_COPY_METHODDEF \
- {"copy", (PyCFunction)_blake2b_blake2b_copy, METH_NOARGS, _blake2b_blake2b_copy__doc__},
+#define _BLAKE2_BLAKE2B_COPY_METHODDEF \
+ {"copy", (PyCFunction)_blake2_blake2b_copy, METH_NOARGS, _blake2_blake2b_copy__doc__},
static PyObject *
-_blake2b_blake2b_copy_impl(BLAKE2bObject *self);
+_blake2_blake2b_copy_impl(BLAKE2bObject *self);
static PyObject *
-_blake2b_blake2b_copy(BLAKE2bObject *self, PyObject *Py_UNUSED(ignored))
+_blake2_blake2b_copy(BLAKE2bObject *self, PyObject *Py_UNUSED(ignored))
{
- return _blake2b_blake2b_copy_impl(self);
+ return _blake2_blake2b_copy_impl(self);
}
-PyDoc_STRVAR(_blake2b_blake2b_update__doc__,
-"update($self, obj, /)\n"
+PyDoc_STRVAR(_blake2_blake2b_update__doc__,
+"update($self, data, /)\n"
"--\n"
"\n"
-"Update this hash object\'s state with the provided string.");
+"Update this hash object\'s state with the provided bytes-like object.");
-#define _BLAKE2B_BLAKE2B_UPDATE_METHODDEF \
- {"update", (PyCFunction)_blake2b_blake2b_update, METH_O, _blake2b_blake2b_update__doc__},
+#define _BLAKE2_BLAKE2B_UPDATE_METHODDEF \
+ {"update", (PyCFunction)_blake2_blake2b_update, METH_O, _blake2_blake2b_update__doc__},
-PyDoc_STRVAR(_blake2b_blake2b_digest__doc__,
+PyDoc_STRVAR(_blake2_blake2b_digest__doc__,
"digest($self, /)\n"
"--\n"
"\n"
-"Return the digest value as a string of binary data.");
+"Return the digest value as a bytes object.");
-#define _BLAKE2B_BLAKE2B_DIGEST_METHODDEF \
- {"digest", (PyCFunction)_blake2b_blake2b_digest, METH_NOARGS, _blake2b_blake2b_digest__doc__},
+#define _BLAKE2_BLAKE2B_DIGEST_METHODDEF \
+ {"digest", (PyCFunction)_blake2_blake2b_digest, METH_NOARGS, _blake2_blake2b_digest__doc__},
static PyObject *
-_blake2b_blake2b_digest_impl(BLAKE2bObject *self);
+_blake2_blake2b_digest_impl(BLAKE2bObject *self);
static PyObject *
-_blake2b_blake2b_digest(BLAKE2bObject *self, PyObject *Py_UNUSED(ignored))
+_blake2_blake2b_digest(BLAKE2bObject *self, PyObject *Py_UNUSED(ignored))
{
- return _blake2b_blake2b_digest_impl(self);
+ return _blake2_blake2b_digest_impl(self);
}
-PyDoc_STRVAR(_blake2b_blake2b_hexdigest__doc__,
+PyDoc_STRVAR(_blake2_blake2b_hexdigest__doc__,
"hexdigest($self, /)\n"
"--\n"
"\n"
"Return the digest value as a string of hexadecimal digits.");
-#define _BLAKE2B_BLAKE2B_HEXDIGEST_METHODDEF \
- {"hexdigest", (PyCFunction)_blake2b_blake2b_hexdigest, METH_NOARGS, _blake2b_blake2b_hexdigest__doc__},
+#define _BLAKE2_BLAKE2B_HEXDIGEST_METHODDEF \
+ {"hexdigest", (PyCFunction)_blake2_blake2b_hexdigest, METH_NOARGS, _blake2_blake2b_hexdigest__doc__},
static PyObject *
-_blake2b_blake2b_hexdigest_impl(BLAKE2bObject *self);
+_blake2_blake2b_hexdigest_impl(BLAKE2bObject *self);
static PyObject *
-_blake2b_blake2b_hexdigest(BLAKE2bObject *self, PyObject *Py_UNUSED(ignored))
+_blake2_blake2b_hexdigest(BLAKE2bObject *self, PyObject *Py_UNUSED(ignored))
{
- return _blake2b_blake2b_hexdigest_impl(self);
+ return _blake2_blake2b_hexdigest_impl(self);
}
-/*[clinic end generated code: output=535a54852c98e51c input=a9049054013a1b77]*/
+/*[clinic end generated code: output=0eb559f418fc0a21 input=a9049054013a1b77]*/
[clinic start generated code]*/
PyDoc_STRVAR(py_blake2s_new__doc__,
-"blake2s(string=None, *, digest_size=_blake2s.blake2s.MAX_DIGEST_SIZE,\n"
-" key=None, salt=None, person=None, fanout=1, depth=1,\n"
-" leaf_size=None, node_offset=None, node_depth=0, inner_size=0,\n"
-" last_node=False)\n"
+"blake2s(data=b\'\', /, *, digest_size=_blake2.blake2s.MAX_DIGEST_SIZE,\n"
+" key=b\'\', salt=b\'\', person=b\'\', fanout=1, depth=1, leaf_size=0,\n"
+" node_offset=0, node_depth=0, inner_size=0, last_node=False)\n"
"--\n"
"\n"
"Return a new BLAKE2s hash object.");
py_blake2s_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
PyObject *return_value = NULL;
- static const char * const _keywords[] = {"string", "digest_size", "key", "salt", "person", "fanout", "depth", "leaf_size", "node_offset", "node_depth", "inner_size", "last_node", NULL};
+ static const char * const _keywords[] = {"", "digest_size", "key", "salt", "person", "fanout", "depth", "leaf_size", "node_offset", "node_depth", "inner_size", "last_node", NULL};
static _PyArg_Parser _parser = {"|O$iy*y*y*iiOOiip:blake2s", _keywords, 0};
PyObject *data = NULL;
int digest_size = BLAKE2S_OUTBYTES;
return return_value;
}
-PyDoc_STRVAR(_blake2s_blake2s_copy__doc__,
+PyDoc_STRVAR(_blake2_blake2s_copy__doc__,
"copy($self, /)\n"
"--\n"
"\n"
"Return a copy of the hash object.");
-#define _BLAKE2S_BLAKE2S_COPY_METHODDEF \
- {"copy", (PyCFunction)_blake2s_blake2s_copy, METH_NOARGS, _blake2s_blake2s_copy__doc__},
+#define _BLAKE2_BLAKE2S_COPY_METHODDEF \
+ {"copy", (PyCFunction)_blake2_blake2s_copy, METH_NOARGS, _blake2_blake2s_copy__doc__},
static PyObject *
-_blake2s_blake2s_copy_impl(BLAKE2sObject *self);
+_blake2_blake2s_copy_impl(BLAKE2sObject *self);
static PyObject *
-_blake2s_blake2s_copy(BLAKE2sObject *self, PyObject *Py_UNUSED(ignored))
+_blake2_blake2s_copy(BLAKE2sObject *self, PyObject *Py_UNUSED(ignored))
{
- return _blake2s_blake2s_copy_impl(self);
+ return _blake2_blake2s_copy_impl(self);
}
-PyDoc_STRVAR(_blake2s_blake2s_update__doc__,
-"update($self, obj, /)\n"
+PyDoc_STRVAR(_blake2_blake2s_update__doc__,
+"update($self, data, /)\n"
"--\n"
"\n"
-"Update this hash object\'s state with the provided string.");
+"Update this hash object\'s state with the provided bytes-like object.");
-#define _BLAKE2S_BLAKE2S_UPDATE_METHODDEF \
- {"update", (PyCFunction)_blake2s_blake2s_update, METH_O, _blake2s_blake2s_update__doc__},
+#define _BLAKE2_BLAKE2S_UPDATE_METHODDEF \
+ {"update", (PyCFunction)_blake2_blake2s_update, METH_O, _blake2_blake2s_update__doc__},
-PyDoc_STRVAR(_blake2s_blake2s_digest__doc__,
+PyDoc_STRVAR(_blake2_blake2s_digest__doc__,
"digest($self, /)\n"
"--\n"
"\n"
-"Return the digest value as a string of binary data.");
+"Return the digest value as a bytes object.");
-#define _BLAKE2S_BLAKE2S_DIGEST_METHODDEF \
- {"digest", (PyCFunction)_blake2s_blake2s_digest, METH_NOARGS, _blake2s_blake2s_digest__doc__},
+#define _BLAKE2_BLAKE2S_DIGEST_METHODDEF \
+ {"digest", (PyCFunction)_blake2_blake2s_digest, METH_NOARGS, _blake2_blake2s_digest__doc__},
static PyObject *
-_blake2s_blake2s_digest_impl(BLAKE2sObject *self);
+_blake2_blake2s_digest_impl(BLAKE2sObject *self);
static PyObject *
-_blake2s_blake2s_digest(BLAKE2sObject *self, PyObject *Py_UNUSED(ignored))
+_blake2_blake2s_digest(BLAKE2sObject *self, PyObject *Py_UNUSED(ignored))
{
- return _blake2s_blake2s_digest_impl(self);
+ return _blake2_blake2s_digest_impl(self);
}
-PyDoc_STRVAR(_blake2s_blake2s_hexdigest__doc__,
+PyDoc_STRVAR(_blake2_blake2s_hexdigest__doc__,
"hexdigest($self, /)\n"
"--\n"
"\n"
"Return the digest value as a string of hexadecimal digits.");
-#define _BLAKE2S_BLAKE2S_HEXDIGEST_METHODDEF \
- {"hexdigest", (PyCFunction)_blake2s_blake2s_hexdigest, METH_NOARGS, _blake2s_blake2s_hexdigest__doc__},
+#define _BLAKE2_BLAKE2S_HEXDIGEST_METHODDEF \
+ {"hexdigest", (PyCFunction)_blake2_blake2s_hexdigest, METH_NOARGS, _blake2_blake2s_hexdigest__doc__},
static PyObject *
-_blake2s_blake2s_hexdigest_impl(BLAKE2sObject *self);
+_blake2_blake2s_hexdigest_impl(BLAKE2sObject *self);
static PyObject *
-_blake2s_blake2s_hexdigest(BLAKE2sObject *self, PyObject *Py_UNUSED(ignored))
+_blake2_blake2s_hexdigest(BLAKE2sObject *self, PyObject *Py_UNUSED(ignored))
{
- return _blake2s_blake2s_hexdigest_impl(self);
+ return _blake2_blake2s_hexdigest_impl(self);
}
-/*[clinic end generated code: output=535ea7903f9ccf76 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=13d4b08ea9ee2d62 input=a9049054013a1b77]*/
int bzerror;
#ifdef WITH_THREAD
- self->lock = PyThread_allocate_lock();
- if (self->lock == NULL) {
+ PyThread_type_lock lock = PyThread_allocate_lock();
+ if (lock == NULL) {
PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
return -1;
}
+ if (self->lock != NULL) {
+ PyThread_free_lock(self->lock);
+ }
+ self->lock = lock;
#endif
self->needs_input = 1;
static PyObject *
deque_copy(PyObject *deque)
{
+ PyObject *result;
dequeobject *old_deque = (dequeobject *)deque;
if (Py_TYPE(deque) == &deque_type) {
dequeobject *new_deque;
return NULL;
}
if (old_deque->maxlen < 0)
- return PyObject_CallFunction((PyObject *)(Py_TYPE(deque)), "O", deque, NULL);
+ result = PyObject_CallFunctionObjArgs((PyObject *)(Py_TYPE(deque)),
+ deque, NULL);
else
- return PyObject_CallFunction((PyObject *)(Py_TYPE(deque)), "Oi",
- deque, old_deque->maxlen, NULL);
+ result = PyObject_CallFunction((PyObject *)(Py_TYPE(deque)), "Oi",
+ deque, old_deque->maxlen, NULL);
+ if (result != NULL && !PyObject_TypeCheck(result, &deque_type)) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s() must return a deque, not %.200s",
+ Py_TYPE(deque)->tp_name, Py_TYPE(result)->tp_name);
+ Py_DECREF(result);
+ return NULL;
+ }
+ return result;
}
PyDoc_STRVAR(copy_doc, "Return a shallow copy of a deque.");
static int
parse_grow_buff(ReaderObj *self)
{
- if (self->field_size == 0) {
- self->field_size = 4096;
- if (self->field != NULL)
- PyMem_Free(self->field);
- self->field = PyMem_New(Py_UCS4, self->field_size);
- }
- else {
- Py_UCS4 *field = self->field;
- if (self->field_size > PY_SSIZE_T_MAX / 2) {
- PyErr_NoMemory();
- return 0;
- }
- self->field_size *= 2;
- self->field = PyMem_Resize(field, Py_UCS4, self->field_size);
- }
- if (self->field == NULL) {
+ assert((size_t)self->field_size <= PY_SSIZE_T_MAX / sizeof(Py_UCS4));
+
+ Py_ssize_t field_size_new = self->field_size ? 2 * self->field_size : 4096;
+ Py_UCS4 *field_new = self->field;
+ PyMem_Resize(field_new, Py_UCS4, field_size_new);
+ if (field_new == NULL) {
PyErr_NoMemory();
return 0;
}
+ self->field = field_new;
+ self->field_size = field_size_new;
return 1;
}
static int
join_check_rec_size(WriterObj *self, Py_ssize_t rec_len)
{
-
- if (rec_len < 0 || rec_len > PY_SSIZE_T_MAX - MEM_INCR) {
- PyErr_NoMemory();
- return 0;
- }
+ assert(rec_len >= 0);
if (rec_len > self->rec_size) {
- if (self->rec_size == 0) {
- self->rec_size = (rec_len / MEM_INCR + 1) * MEM_INCR;
- if (self->rec != NULL)
- PyMem_Free(self->rec);
- self->rec = PyMem_New(Py_UCS4, self->rec_size);
- }
- else {
- Py_UCS4* old_rec = self->rec;
-
- self->rec_size = (rec_len / MEM_INCR + 1) * MEM_INCR;
- self->rec = PyMem_Resize(old_rec, Py_UCS4, self->rec_size);
- if (self->rec == NULL)
- PyMem_Free(old_rec);
- }
- if (self->rec == NULL) {
+ size_t rec_size_new = (size_t)(rec_len / MEM_INCR + 1) * MEM_INCR;
+ Py_UCS4 *rec_new = self->rec;
+ PyMem_Resize(rec_new, Py_UCS4, rec_size_new);
+ if (rec_new == NULL) {
PyErr_NoMemory();
return 0;
}
+ self->rec = rec_new;
+ self->rec_size = (Py_ssize_t)rec_size_new;
}
return 1;
}
*pj += b;
}
+#ifdef MS_WIN32
+
+typedef struct {
+ char f1;
+} Size1;
+
+typedef struct {
+ char f1;
+ char f2;
+} Size2;
+
+typedef struct {
+ char f1;
+ char f2;
+ char f3;
+} Size3;
+
+typedef struct {
+ char f1;
+ char f2;
+ char f3;
+ char f4;
+} Size4;
+
+typedef struct {
+ char f1;
+ char f2;
+ char f3;
+ char f4;
+ char f5;
+} Size5;
+
+typedef struct {
+ char f1;
+ char f2;
+ char f3;
+ char f4;
+ char f5;
+ char f6;
+} Size6;
+
+typedef struct {
+ char f1;
+ char f2;
+ char f3;
+ char f4;
+ char f5;
+ char f6;
+ char f7;
+} Size7;
+
+typedef struct {
+ char f1;
+ char f2;
+ char f3;
+ char f4;
+ char f5;
+ char f6;
+ char f7;
+ char f8;
+} Size8;
+
+typedef struct {
+ char f1;
+ char f2;
+ char f3;
+ char f4;
+ char f5;
+ char f6;
+ char f7;
+ char f8;
+ char f9;
+} Size9;
+
+typedef struct {
+ char f1;
+ char f2;
+ char f3;
+ char f4;
+ char f5;
+ char f6;
+ char f7;
+ char f8;
+ char f9;
+ char f10;
+} Size10;
+
+EXPORT(Size1) TestSize1() {
+ Size1 f;
+ f.f1 = 'a';
+ return f;
+}
+
+EXPORT(Size2) TestSize2() {
+ Size2 f;
+ f.f1 = 'a';
+ f.f2 = 'b';
+ return f;
+}
+
+EXPORT(Size3) TestSize3() {
+ Size3 f;
+ f.f1 = 'a';
+ f.f2 = 'b';
+ f.f3 = 'c';
+ return f;
+}
+
+EXPORT(Size4) TestSize4() {
+ Size4 f;
+ f.f1 = 'a';
+ f.f2 = 'b';
+ f.f3 = 'c';
+ f.f4 = 'd';
+ return f;
+}
+
+EXPORT(Size5) TestSize5() {
+ Size5 f;
+ f.f1 = 'a';
+ f.f2 = 'b';
+ f.f3 = 'c';
+ f.f4 = 'd';
+ f.f5 = 'e';
+ return f;
+}
+
+EXPORT(Size6) TestSize6() {
+ Size6 f;
+ f.f1 = 'a';
+ f.f2 = 'b';
+ f.f3 = 'c';
+ f.f4 = 'd';
+ f.f5 = 'e';
+ f.f6 = 'f';
+ return f;
+}
+
+EXPORT(Size7) TestSize7() {
+ Size7 f;
+ f.f1 = 'a';
+ f.f2 = 'b';
+ f.f3 = 'c';
+ f.f4 = 'd';
+ f.f5 = 'e';
+ f.f6 = 'f';
+ f.f7 = 'g';
+ return f;
+}
+
+EXPORT(Size8) TestSize8() {
+ Size8 f;
+ f.f1 = 'a';
+ f.f2 = 'b';
+ f.f3 = 'c';
+ f.f4 = 'd';
+ f.f5 = 'e';
+ f.f6 = 'f';
+ f.f7 = 'g';
+ f.f8 = 'h';
+ return f;
+}
+
+EXPORT(Size9) TestSize9() {
+ Size9 f;
+ f.f1 = 'a';
+ f.f2 = 'b';
+ f.f3 = 'c';
+ f.f4 = 'd';
+ f.f5 = 'e';
+ f.f6 = 'f';
+ f.f7 = 'g';
+ f.f8 = 'h';
+ f.f9 = 'i';
+ return f;
+}
+
+EXPORT(Size10) TestSize10() {
+ Size10 f;
+ f.f1 = 'a';
+ f.f2 = 'b';
+ f.f3 = 'c';
+ f.f4 = 'd';
+ f.f5 = 'e';
+ f.f6 = 'f';
+ f.f7 = 'g';
+ f.f8 = 'h';
+ f.f9 = 'i';
+ f.f10 = 'j';
+ return f;
+}
+
+#endif
+
#ifdef MS_WIN32
EXPORT(S2H) __stdcall s_ret_2h_func(S2H inp) { return ret_2h_func(inp); }
EXPORT(S8I) __stdcall s_ret_8i_func(S8I inp) { return ret_8i_func(inp); }
It returns small structures in registers
*/
if (dict->ffi_type_pointer.type == FFI_TYPE_STRUCT) {
- if (dict->ffi_type_pointer.size <= 4)
+ if (can_return_struct_as_int(dict->ffi_type_pointer.size))
return &ffi_type_sint32;
- else if (dict->ffi_type_pointer.size <= 8)
+ else if (can_return_struct_as_sint64 (dict->ffi_type_pointer.size))
return &ffi_type_sint64;
}
#endif
return;
}
+/*
+Per: https://msdn.microsoft.com/en-us/library/7572ztz4.aspx
+To be returned by value in RAX, user-defined types must have a length
+of 1, 2, 4, 8, 16, 32, or 64 bits
+*/
+int can_return_struct_as_int(size_t s)
+{
+ return s == 1 || s == 2 || s == 4;
+}
+
+int can_return_struct_as_sint64(size_t s)
+{
+ return s == 8;
+}
+
/* Perform machine dependent cif processing */
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
{
/* MSVC returns small structures in registers. Put in cif->flags
the value FFI_TYPE_STRUCT only if the structure is big enough;
otherwise, put the 4- or 8-bytes integer type. */
- if (cif->rtype->size <= 4)
+ if (can_return_struct_as_int(cif->rtype->size))
cif->flags = FFI_TYPE_INT;
- else if (cif->rtype->size <= 8)
+ else if (can_return_struct_as_sint64(cif->rtype->size))
cif->flags = FFI_TYPE_SINT64;
else
cif->flags = FFI_TYPE_STRUCT;
/*@null@*/ struct _ffi_type **elements;
} ffi_type;
+int can_return_struct_as_int(size_t);
+int can_return_struct_as_sint64(size_t);
+
/* These are defined in types.c */
extern ffi_type ffi_type_void;
extern ffi_type ffi_type_uint8;
/* Make space for the return structure pointer */
if (cif->rtype->type == FFI_TYPE_STRUCT
#ifdef _WIN32
- && (cif->rtype->size > 8) /* MSVC returns small structs in registers */
+ && !can_return_struct_as_int(cif->rtype->size) /* MSVC returns small structs in registers */
+ && !can_return_struct_as_sint64(cif->rtype->size)
#endif
#ifdef SPARC
&& (cif->abi != FFI_V9 || cif->rtype->size > 32)
bytes += sizeof(void*);
else
#elif defined (_WIN64)
- if ((*ptr)->type == FFI_TYPE_STRUCT && ((*ptr)->size > 8))
+ if ((*ptr)->type == FFI_TYPE_STRUCT &&
+ !can_return_struct_as_int((*ptr)->size) &&
+ !can_return_struct_as_sint64((*ptr)->size))
bytes += sizeof(void*);
else
#endif
// If the return value pointer is NULL, assume no return value.
/*
- Intel asm is weird. We have to explicitely specify 'DWORD PTR' in the nexr instruction,
+ Intel asm is weird. We have to explicitly specify 'DWORD PTR' in the next instruction,
otherwise only one BYTE will be compared (instead of a DWORD)!
*/
cmp DWORD PTR [ebp + 24], 0
second = Py_MIN(59, tm.tm_sec);
/* local timezone requires to compute fold */
- if (tzinfo == Py_None && f == _PyTime_localtime) {
+ if (tzinfo == Py_None && f == _PyTime_localtime
+ /* On Windows, passing a negative value to local results
+ * in an OSError because localtime_s on Windows does
+ * not support negative timestamps. Unfortunately this
+ * means that fold detection for time values between
+ * 0 and max_fold_seconds will result in an identical
+ * error since we subtract max_fold_seconds to detect a
+ * fold. However, since we know there haven't been any
+ * folds in the interval [0, max_fold_seconds) in any
+ * timezone, we can hackily just forego fold detection
+ * for this time range.
+ */
+#ifdef MS_WINDOWS
+ && (timet - max_fold_seconds > 0)
+#endif
+ ) {
long long probe_seconds, result_seconds, transition;
result_seconds = utc_to_seconds(year, month, day,
PyErr_NoMemory();
return -1;
}
+ /* expat < 2.1.0 has no XML_SetHashSalt() */
+ if (EXPAT(SetHashSalt) != NULL) {
+ EXPAT(SetHashSalt)(self->parser,
+ (unsigned long)_Py_HashSecret.expat.hashsalt);
+ }
if (target) {
Py_INCREF(target);
#if OPENSSL_VERSION_NUMBER > 0x10100000L && !defined(OPENSSL_NO_SCRYPT) && !defined(LIBRESSL_VERSION_NUMBER)
#define PY_SCRYPT 1
+/* XXX: Parameters salt, n, r and p should be required keyword-only parameters.
+ They are optional in the Argument Clinic declaration only due to a
+ limitation of PyArg_ParseTupleAndKeywords. */
+
/*[clinic input]
_hashlib.scrypt
_io__IOBase_close_impl(PyObject *self)
/*[clinic end generated code: output=63c6a6f57d783d6d input=f4494d5c31dbc6b7]*/
{
- PyObject *res;
+ PyObject *res, *exc, *val, *tb;
+ int rc;
if (IS_CLOSED(self))
Py_RETURN_NONE;
res = PyObject_CallMethodObjArgs(self, _PyIO_str_flush, NULL);
- if (_PyObject_SetAttrId(self, &PyId___IOBase_closed, Py_True) < 0) {
- Py_XDECREF(res);
- return NULL;
+ PyErr_Fetch(&exc, &val, &tb);
+ rc = _PyObject_SetAttrId(self, &PyId___IOBase_closed, Py_True);
+ _PyErr_ChainExceptions(exc, val, tb);
+ if (rc < 0) {
+ Py_CLEAR(res);
}
if (res == NULL)
}
else {
dict = PyDict_Copy(self->dict);
- if (dict == NULL)
+ if (dict == NULL) {
+ Py_DECREF(initvalue);
return NULL;
+ }
}
state = Py_BuildValue("(OOnN)", initvalue,
PyObject *dict;
} textio;
+static void
+textiowrapper_set_decoded_chars(textio *self, PyObject *chars);
+
/* A couple of specialized cases in order to bypass the slow incremental
encoding methods for the most popular encodings. */
Py_DECREF(ret);
}
+ textiowrapper_set_decoded_chars(self, NULL);
Py_CLEAR(self->snapshot);
if (self->decoder) {
*/
PyObject *next_input = dec_buffer;
PyBytes_Concat(&next_input, input_chunk);
+ dec_buffer = NULL; /* Reference lost to PyBytes_Concat */
if (next_input == NULL) {
- dec_buffer = NULL; /* Reference lost to PyBytes_Concat */
goto fail;
}
- Py_XSETREF(self->snapshot, Py_BuildValue("NN", dec_flags, next_input));
+ PyObject *snapshot = Py_BuildValue("NN", dec_flags, next_input);
+ if (snapshot == NULL) {
+ dec_flags = NULL;
+ goto fail;
+ }
+ Py_XSETREF(self->snapshot, snapshot);
}
Py_DECREF(input_chunk);
if (result == NULL)
goto fail;
+ textiowrapper_set_decoded_chars(self, NULL);
Py_CLEAR(self->snapshot);
return result;
}
cookie_type cookie;
PyObject *res;
int cmp;
+ PyObject *snapshot;
CHECK_ATTACHED(self);
CHECK_CLOSED(self);
goto fail;
}
- self->snapshot = Py_BuildValue("iN", cookie.dec_flags, input_chunk);
- if (self->snapshot == NULL) {
- Py_DECREF(input_chunk);
+ snapshot = Py_BuildValue("iN", cookie.dec_flags, input_chunk);
+ if (snapshot == NULL) {
goto fail;
}
+ Py_XSETREF(self->snapshot, snapshot);
decoded = _PyObject_CallMethodId(self->decoder, &PyId_decode,
"Oi", input_chunk, (int)cookie.need_eof);
self->decoded_chars_used = cookie.chars_to_skip;
}
else {
- self->snapshot = Py_BuildValue("iy", cookie.dec_flags, "");
- if (self->snapshot == NULL)
+ snapshot = Py_BuildValue("iy", cookie.dec_flags, "");
+ if (snapshot == NULL)
goto fail;
+ Py_XSETREF(self->snapshot, snapshot);
}
/* Finally, reset the encoder (merely useful for proper BOM handling) */
Py_BEGIN_ALLOW_THREADS
DWORD off = 0;
while (off < maxlen) {
- DWORD n, len = min(maxlen - off, BUFSIZ);
+ DWORD n = (DWORD)-1;
+ DWORD len = min(maxlen - off, BUFSIZ);
SetLastError(0);
BOOL res = ReadConsoleW(handle, &buf[off], len, &n, NULL);
err = GetLastError();
break;
}
+ if (n == (DWORD)-1 && (err = GetLastError()) == ERROR_OPERATION_ABORTED) {
+ break;
+ }
if (n == 0) {
err = GetLastError();
if (err != ERROR_OPERATION_ABORTED)
if (s_null == NULL) {
s_null = PyUnicode_InternFromString("null");
}
- Py_INCREF(s_null);
+ Py_XINCREF(s_null);
return s_null;
}
else if (obj == Py_True) {
if (s_true == NULL) {
s_true = PyUnicode_InternFromString("true");
}
- Py_INCREF(s_true);
+ Py_XINCREF(s_true);
return s_true;
}
else if (obj == Py_False) {
if (s_false == NULL) {
s_false = PyUnicode_InternFromString("false");
}
- Py_INCREF(s_false);
+ Py_XINCREF(s_false);
return s_false;
}
else {
};
PyDoc_STRVAR(profiler_doc, "\
-Profiler(custom_timer=None, time_unit=None, subcalls=True, builtins=True)\n\
+Profiler(timer=None, timeunit=None, subcalls=True, builtins=True)\n\
\n\
Builds a profiler object using the specified timer function.\n\
The default timer is a fast built-in one based on real time.\n\
- For custom timer functions returning integers, time_unit can\n\
+ For custom timer functions returning integers, timeunit can\n\
be a float specifying a scale (i.e. how long each integer unit\n\
is, in seconds).\n\
");
self->lzs.next_in = NULL;
#ifdef WITH_THREAD
- self->lock = PyThread_allocate_lock();
- if (self->lock == NULL) {
+ PyThread_type_lock lock = PyThread_allocate_lock();
+ if (lock == NULL) {
PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
return -1;
}
+ if (self->lock != NULL) {
+ PyThread_free_lock(self->lock);
+ }
+ self->lock = lock;
#endif
self->check = LZMA_CHECK_UNKNOWN;
} PyMemoEntry;
typedef struct {
- Py_ssize_t mt_mask;
- Py_ssize_t mt_used;
- Py_ssize_t mt_allocated;
+ size_t mt_mask;
+ size_t mt_used;
+ size_t mt_allocated;
PyMemoEntry *mt_table;
} PyMemoTable;
/* The unpickler memo is just an array of PyObject *s. Using a dict
is unnecessary, since the keys are contiguous ints. */
PyObject **memo;
- Py_ssize_t memo_size; /* Capacity of the memo array */
- Py_ssize_t memo_len; /* Number of objects in the memo */
+ size_t memo_size; /* Capacity of the memo array */
+ size_t memo_len; /* Number of objects in the memo */
PyObject *pers_func; /* persistent_load() method, can be NULL. */
PyObject *pers_func_self; /* borrowed reference to self if pers_func
static PyMemoTable *
PyMemoTable_Copy(PyMemoTable *self)
{
- Py_ssize_t i;
PyMemoTable *new = PyMemoTable_New();
if (new == NULL)
return NULL;
PyErr_NoMemory();
return NULL;
}
- for (i = 0; i < self->mt_allocated; i++) {
+ for (size_t i = 0; i < self->mt_allocated; i++) {
Py_XINCREF(self->mt_table[i].me_key);
}
memcpy(new->mt_table, self->mt_table,
{
size_t i;
size_t perturb;
- size_t mask = (size_t)self->mt_mask;
+ size_t mask = self->mt_mask;
PyMemoEntry *table = self->mt_table;
PyMemoEntry *entry;
Py_hash_t hash = (Py_hash_t)key >> 3;
/* Returns -1 on failure, 0 on success. */
static int
-_PyMemoTable_ResizeTable(PyMemoTable *self, Py_ssize_t min_size)
+_PyMemoTable_ResizeTable(PyMemoTable *self, size_t min_size)
{
PyMemoEntry *oldtable = NULL;
PyMemoEntry *oldentry, *newentry;
- Py_ssize_t new_size = MT_MINSIZE;
- Py_ssize_t to_process;
+ size_t new_size = MT_MINSIZE;
+ size_t to_process;
assert(min_size > 0);
- /* Find the smallest valid table size >= min_size. */
- while (new_size < min_size && new_size > 0)
- new_size <<= 1;
- if (new_size <= 0) {
+ if (min_size > PY_SSIZE_T_MAX) {
PyErr_NoMemory();
return -1;
}
+
+ /* Find the smallest valid table size >= min_size. */
+ while (new_size < min_size) {
+ new_size <<= 1;
+ }
/* new_size needs to be a power of two. */
assert((new_size & (new_size - 1)) == 0);
* Very large memo tables (over 50K items) use doubling instead.
* This may help applications with severe memory constraints.
*/
- if (!(self->mt_used * 3 >= (self->mt_mask + 1) * 2))
+ if (SIZE_MAX / 3 >= self->mt_used && self->mt_used * 3 < self->mt_allocated * 2) {
return 0;
- return _PyMemoTable_ResizeTable(self,
- (self->mt_used > 50000 ? 2 : 4) * self->mt_used);
+ }
+ // self->mt_used is always < PY_SSIZE_T_MAX, so this can't overflow.
+ size_t desired_size = (self->mt_used > 50000 ? 2 : 4) * self->mt_used;
+ return _PyMemoTable_ResizeTable(self, desired_size);
}
#undef MT_MINSIZE
/* Returns -1 (with an exception set) on failure, 0 on success. The memo array
will be modified in place. */
static int
-_Unpickler_ResizeMemoList(UnpicklerObject *self, Py_ssize_t new_size)
+_Unpickler_ResizeMemoList(UnpicklerObject *self, size_t new_size)
{
- Py_ssize_t i;
+ size_t i;
assert(new_size > self->memo_size);
- PyMem_RESIZE(self->memo, PyObject *, new_size);
- if (self->memo == NULL) {
+ PyObject **memo_new = self->memo;
+ PyMem_RESIZE(memo_new, PyObject *, new_size);
+ if (memo_new == NULL) {
PyErr_NoMemory();
return -1;
}
+ self->memo = memo_new;
for (i = self->memo_size; i < new_size; i++)
self->memo[i] = NULL;
self->memo_size = new_size;
/* Returns NULL if idx is out of bounds. */
static PyObject *
-_Unpickler_MemoGet(UnpicklerObject *self, Py_ssize_t idx)
+_Unpickler_MemoGet(UnpicklerObject *self, size_t idx)
{
- if (idx < 0 || idx >= self->memo_size)
+ if (idx >= self->memo_size)
return NULL;
return self->memo[idx];
/* Returns -1 (with an exception set) on failure, 0 on success.
This takes its own reference to `value`. */
static int
-_Unpickler_MemoPut(UnpicklerObject *self, Py_ssize_t idx, PyObject *value)
+_Unpickler_MemoPut(UnpicklerObject *self, size_t idx, PyObject *value)
{
PyObject *old_item;
PickleState *st = _Pickle_GetGlobalState();
PyObject *reduce_value = Py_BuildValue("(O(OO))",
st->getattr, parent, lastname);
+ if (reduce_value == NULL)
+ goto error;
status = save_reduce(self, reduce_value, NULL);
Py_DECREF(reduce_value);
if (status < 0)
_pickle_PicklerMemoProxy_copy_impl(PicklerMemoProxyObject *self)
/*[clinic end generated code: output=bb83a919d29225ef input=b73043485ac30b36]*/
{
- Py_ssize_t i;
PyMemoTable *memo;
PyObject *new_memo = PyDict_New();
if (new_memo == NULL)
return NULL;
memo = self->pickler->memo;
- for (i = 0; i < memo->mt_allocated; ++i) {
+ for (size_t i = 0; i < memo->mt_allocated; ++i) {
PyMemoEntry entry = memo->mt_table[i];
if (entry.me_key != NULL) {
int status;
return -1;
}
- if (self->marks == NULL)
- self->marks = PyMem_NEW(Py_ssize_t, alloc);
- else
- PyMem_RESIZE(self->marks, Py_ssize_t, alloc);
+ Py_ssize_t *marks_old = self->marks;
+ PyMem_RESIZE(self->marks, Py_ssize_t, alloc);
if (self->marks == NULL) {
+ PyMem_FREE(marks_old);
self->marks_size = 0;
PyErr_NoMemory();
return -1;
self->stack = (Pdata *)Pdata_New();
if (self->stack == NULL)
- return 1;
+ return -1;
self->memo_size = 32;
self->memo = _Unpickler_NewMemo(self->memo_size);
_pickle_UnpicklerMemoProxy_copy_impl(UnpicklerMemoProxyObject *self)
/*[clinic end generated code: output=e12af7e9bc1e4c77 input=97769247ce032c1d]*/
{
- Py_ssize_t i;
+ size_t i;
PyObject *new_memo = PyDict_New();
if (new_memo == NULL)
return NULL;
Unpickler_set_memo(UnpicklerObject *self, PyObject *obj)
{
PyObject **new_memo;
- Py_ssize_t new_memo_size = 0;
- Py_ssize_t i;
+ size_t new_memo_size = 0;
if (obj == NULL) {
PyErr_SetString(PyExc_TypeError,
if (new_memo == NULL)
return -1;
- for (i = 0; i < new_memo_size; i++) {
+ for (size_t i = 0; i < new_memo_size; i++) {
Py_XINCREF(unpickler->memo[i]);
new_memo[i] = unpickler->memo[i];
}
error:
if (new_memo_size) {
- i = new_memo_size;
- while (--i >= 0) {
+ for (size_t i = new_memo_size - 1; i != SIZE_MAX; i--) {
Py_XDECREF(new_memo[i]);
}
PyMem_FREE(new_memo);
/* When duping fds, if there arises a situation where one of the fds is
either 0, 1 or 2, it is possible that it is overwritten (#12607). */
- if (c2pwrite == 0)
+ if (c2pwrite == 0) {
POSIX_CALL(c2pwrite = dup(c2pwrite));
- while (errwrite == 0 || errwrite == 1)
+ /* issue32270 */
+ if (_Py_set_inheritable_async_safe(c2pwrite, 0, NULL) < 0) {
+ goto error;
+ }
+ }
+ while (errwrite == 0 || errwrite == 1) {
POSIX_CALL(errwrite = dup(errwrite));
+ /* issue32270 */
+ if (_Py_set_inheritable_async_safe(errwrite, 0, NULL) < 0) {
+ goto error;
+ }
+ }
/* Dup fds for child.
dup2() removes the CLOEXEC flag but we must do it ourselves if dup2()
else if (errwrite != -1)
POSIX_CALL(dup2(errwrite, 2)); /* stderr */
- /* Close pipe fds. Make sure we don't close the same fd more than */
- /* once, or standard fds. */
- if (p2cread > 2)
- POSIX_CALL(close(p2cread));
- if (c2pwrite > 2 && c2pwrite != p2cread)
- POSIX_CALL(close(c2pwrite));
- if (errwrite != c2pwrite && errwrite != p2cread && errwrite > 2)
- POSIX_CALL(close(errwrite));
+ /* We no longer manually close p2cread, c2pwrite, and errwrite here as
+ * _close_open_fds takes care when it is not already non-inheritable. */
if (cwd)
POSIX_CALL(chdir(cwd));
PyObject* v;
int r;
+ Py_BEGIN_ALLOW_THREADS
proxyDict = SCDynamicStoreCopyProxies(NULL);
+ Py_END_ALLOW_THREADS
+
if (!proxyDict) {
Py_INCREF(Py_None);
return Py_None;
int r;
CFDictionaryRef proxyDict = NULL;
+ Py_BEGIN_ALLOW_THREADS
proxyDict = SCDynamicStoreCopyProxies(NULL);
+ Py_END_ALLOW_THREADS
+
if (proxyDict == NULL) {
return PyDict_New();
}
preserve
[clinic start generated code]*/
-PyDoc_STRVAR(py_sha3_new__doc__,
-"sha3_224(string=None)\n"
-"--\n"
-"\n"
-"Return a new SHA3 hash object with a hashbit length of 28 bytes.");
-
-static PyObject *
-py_sha3_new_impl(PyTypeObject *type, PyObject *data);
-
-static PyObject *
-py_sha3_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
-{
- PyObject *return_value = NULL;
- static const char * const _keywords[] = {"string", NULL};
- static _PyArg_Parser _parser = {"|O:sha3_224", _keywords, 0};
- PyObject *data = NULL;
-
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser,
- &data)) {
- goto exit;
- }
- return_value = py_sha3_new_impl(type, data);
-
-exit:
- return return_value;
-}
-
PyDoc_STRVAR(_sha3_sha3_224_copy__doc__,
"copy($self, /)\n"
"--\n"
"digest($self, /)\n"
"--\n"
"\n"
-"Return the digest value as a string of binary data.");
+"Return the digest value as a bytes object.");
#define _SHA3_SHA3_224_DIGEST_METHODDEF \
{"digest", (PyCFunction)_sha3_sha3_224_digest, METH_NOARGS, _sha3_sha3_224_digest__doc__},
}
PyDoc_STRVAR(_sha3_sha3_224_update__doc__,
-"update($self, obj, /)\n"
+"update($self, data, /)\n"
"--\n"
"\n"
-"Update this hash object\'s state with the provided string.");
+"Update this hash object\'s state with the provided bytes-like object.");
#define _SHA3_SHA3_224_UPDATE_METHODDEF \
{"update", (PyCFunction)_sha3_sha3_224_update, METH_O, _sha3_sha3_224_update__doc__},
PyDoc_STRVAR(_sha3_shake_128_digest__doc__,
-"digest($self, /, length)\n"
+"digest($self, length, /)\n"
"--\n"
"\n"
-"Return the digest value as a string of binary data.");
+"Return the digest value as a bytes object.");
#define _SHA3_SHAKE_128_DIGEST_METHODDEF \
- {"digest", (PyCFunction)_sha3_shake_128_digest, METH_FASTCALL, _sha3_shake_128_digest__doc__},
-
-static PyObject *
-_sha3_shake_128_digest_impl(SHA3object *self, unsigned long length);
-
-static PyObject *
-_sha3_shake_128_digest(SHA3object *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
-{
- PyObject *return_value = NULL;
- static const char * const _keywords[] = {"length", NULL};
- static _PyArg_Parser _parser = {"k:digest", _keywords, 0};
- unsigned long length;
-
- if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
- &length)) {
- goto exit;
- }
- return_value = _sha3_shake_128_digest_impl(self, length);
-
-exit:
- return return_value;
-}
+ {"digest", (PyCFunction)_sha3_shake_128_digest, METH_O, _sha3_shake_128_digest__doc__},
PyDoc_STRVAR(_sha3_shake_128_hexdigest__doc__,
-"hexdigest($self, /, length)\n"
+"hexdigest($self, length, /)\n"
"--\n"
"\n"
"Return the digest value as a string of hexadecimal digits.");
#define _SHA3_SHAKE_128_HEXDIGEST_METHODDEF \
- {"hexdigest", (PyCFunction)_sha3_shake_128_hexdigest, METH_FASTCALL, _sha3_shake_128_hexdigest__doc__},
-
-static PyObject *
-_sha3_shake_128_hexdigest_impl(SHA3object *self, unsigned long length);
-
-static PyObject *
-_sha3_shake_128_hexdigest(SHA3object *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
-{
- PyObject *return_value = NULL;
- static const char * const _keywords[] = {"length", NULL};
- static _PyArg_Parser _parser = {"k:hexdigest", _keywords, 0};
- unsigned long length;
-
- if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
- &length)) {
- goto exit;
- }
- return_value = _sha3_shake_128_hexdigest_impl(self, length);
-
-exit:
- return return_value;
-}
-/*[clinic end generated code: output=9888beab45136a56 input=a9049054013a1b77]*/
+ {"hexdigest", (PyCFunction)_sha3_shake_128_hexdigest, METH_O, _sha3_shake_128_hexdigest__doc__},
+/*[clinic end generated code: output=826b6b5a7c3406eb input=a9049054013a1b77]*/
}
-/*[clinic input]
-@classmethod
-_sha3.sha3_224.__new__ as py_sha3_new
- string as data: object = NULL
-
-Return a new SHA3 hash object with a hashbit length of 28 bytes.
-[clinic start generated code]*/
-
static PyObject *
-py_sha3_new_impl(PyTypeObject *type, PyObject *data)
-/*[clinic end generated code: output=8d5c34279e69bf09 input=d7c582b950a858b6]*/
+py_sha3_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
SHA3object *self = NULL;
Py_buffer buf = {NULL, NULL};
HashReturn res;
+ PyObject *data = NULL;
+
+ if (!_PyArg_NoKeywords(type->tp_name, kwargs)) {
+ return NULL;
+ }
+ if (!PyArg_UnpackTuple(args, type->tp_name, 0, 1, &data)) {
+ return NULL;
+ }
self = newSHA3object(type);
if (self == NULL) {
/*[clinic input]
_sha3.sha3_224.digest
-Return the digest value as a string of binary data.
+Return the digest value as a bytes object.
[clinic start generated code]*/
static PyObject *
_sha3_sha3_224_digest_impl(SHA3object *self)
-/*[clinic end generated code: output=fd531842e20b2d5b input=a5807917d219b30e]*/
+/*[clinic end generated code: output=fd531842e20b2d5b input=5b2a659536bbd248]*/
{
unsigned char digest[SHA3_MAX_DIGESTSIZE + SHA3_LANESIZE];
SHA3_state temp;
/*[clinic input]
_sha3.sha3_224.update
- obj: object
+ data: object
/
-Update this hash object's state with the provided string.
+Update this hash object's state with the provided bytes-like object.
[clinic start generated code]*/
static PyObject *
-_sha3_sha3_224_update(SHA3object *self, PyObject *obj)
-/*[clinic end generated code: output=06721d55b483e0af input=be44bf0d1c279791]*/
+_sha3_sha3_224_update(SHA3object *self, PyObject *data)
+/*[clinic end generated code: output=d3223352286ed357 input=a887f54dcc4ae227]*/
{
Py_buffer buf;
HashReturn res;
- GET_BUFFER_VIEW_OR_ERROUT(obj, &buf);
+ GET_BUFFER_VIEW_OR_ERROUT(data, &buf);
/* add new data, the function takes the length in bits not bytes */
#ifdef WITH_THREAD
static PyTypeObject type_obj = { \
PyVarObject_HEAD_INIT(NULL, 0) \
type_name, /* tp_name */ \
- sizeof(SHA3object), /* tp_size */ \
+ sizeof(SHA3object), /* tp_basicsize */ \
0, /* tp_itemsize */ \
/* methods */ \
(destructor)SHA3_dealloc, /* tp_dealloc */ \
py_sha3_new, /* tp_new */ \
}
+PyDoc_STRVAR(sha3_224__doc__,
+"sha3_224([data]) -> SHA3 object\n\
+\n\
+Return a new SHA3 hash object with a hashbit length of 28 bytes.");
+
PyDoc_STRVAR(sha3_256__doc__,
-"sha3_256([string]) -> SHA3 object\n\
+"sha3_256([data]) -> SHA3 object\n\
\n\
Return a new SHA3 hash object with a hashbit length of 32 bytes.");
PyDoc_STRVAR(sha3_384__doc__,
-"sha3_384([string]) -> SHA3 object\n\
+"sha3_384([data]) -> SHA3 object\n\
\n\
Return a new SHA3 hash object with a hashbit length of 48 bytes.");
PyDoc_STRVAR(sha3_512__doc__,
-"sha3_512([string]) -> SHA3 object\n\
+"sha3_512([data]) -> SHA3 object\n\
\n\
Return a new SHA3 hash object with a hashbit length of 64 bytes.");
-SHA3_TYPE(SHA3_224type, "_sha3.sha3_224", py_sha3_new__doc__, SHA3_methods);
+SHA3_TYPE(SHA3_224type, "_sha3.sha3_224", sha3_224__doc__, SHA3_methods);
SHA3_TYPE(SHA3_256type, "_sha3.sha3_256", sha3_256__doc__, SHA3_methods);
SHA3_TYPE(SHA3_384type, "_sha3.sha3_384", sha3_384__doc__, SHA3_methods);
SHA3_TYPE(SHA3_512type, "_sha3.sha3_512", sha3_512__doc__, SHA3_methods);
#ifdef PY_WITH_KECCAK
PyDoc_STRVAR(keccak_224__doc__,
-"keccak_224([string]) -> Keccak object\n\
+"keccak_224([data]) -> Keccak object\n\
\n\
Return a new Keccak hash object with a hashbit length of 28 bytes.");
PyDoc_STRVAR(keccak_256__doc__,
-"keccak_256([string]) -> Keccak object\n\
+"keccak_256([data]) -> Keccak object\n\
\n\
Return a new Keccak hash object with a hashbit length of 32 bytes.");
PyDoc_STRVAR(keccak_384__doc__,
-"keccak_384([string]) -> Keccak object\n\
+"keccak_384([data]) -> Keccak object\n\
\n\
Return a new Keccak hash object with a hashbit length of 48 bytes.");
PyDoc_STRVAR(keccak_512__doc__,
-"keccak_512([string]) -> Keccak object\n\
+"keccak_512([data]) -> Keccak object\n\
\n\
Return a new Keccak hash object with a hashbit length of 64 bytes.");
static PyObject *
-_SHAKE_digest(SHA3object *self, unsigned long digestlen, int hex)
+_SHAKE_digest(SHA3object *self, PyObject *digestlen_obj, int hex)
{
+ unsigned long digestlen;
unsigned char *digest = NULL;
SHA3_state temp;
int res;
PyObject *result = NULL;
+ digestlen = PyLong_AsUnsignedLong(digestlen_obj);
+ if (digestlen == (unsigned long) -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+ if (digestlen >= (1 << 29)) {
+ PyErr_SetString(PyExc_ValueError, "length is too large");
+ return NULL;
+ }
/* ExtractLane needs at least SHA3_MAX_DIGESTSIZE + SHA3_LANESIZE and
* SHA3_LANESIZE extra space.
*/
/*[clinic input]
_sha3.shake_128.digest
- length: unsigned_long(bitwise=True)
- \
+ length: object
+ /
-Return the digest value as a string of binary data.
+Return the digest value as a bytes object.
[clinic start generated code]*/
static PyObject *
-_sha3_shake_128_digest_impl(SHA3object *self, unsigned long length)
-/*[clinic end generated code: output=2313605e2f87bb8f input=608c8ca80ae9d115]*/
+_sha3_shake_128_digest(SHA3object *self, PyObject *length)
+/*[clinic end generated code: output=eaa80b6299142396 input=c579eb109f6227d2]*/
{
return _SHAKE_digest(self, length, 0);
}
/*[clinic input]
_sha3.shake_128.hexdigest
- length: unsigned_long(bitwise=True)
- \
+ length: object
+ /
Return the digest value as a string of hexadecimal digits.
[clinic start generated code]*/
static PyObject *
-_sha3_shake_128_hexdigest_impl(SHA3object *self, unsigned long length)
-/*[clinic end generated code: output=bf8e2f1e490944a8 input=64e56b4760db4573]*/
+_sha3_shake_128_hexdigest(SHA3object *self, PyObject *length)
+/*[clinic end generated code: output=4752f90e53c8bf2a input=a82694ea83865f5a]*/
{
return _SHAKE_digest(self, length, 1);
}
};
PyDoc_STRVAR(shake_128__doc__,
-"shake_128([string]) -> SHAKE object\n\
+"shake_128([data]) -> SHAKE object\n\
\n\
Return a new SHAKE hash object.");
PyDoc_STRVAR(shake_256__doc__,
-"shake_256([string]) -> SHAKE object\n\
+"shake_256([data]) -> SHAKE object\n\
\n\
Return a new SHAKE hash object.");
Py_DECREF(py_retval);
}
if (!ok) {
- if (_enable_callback_tracebacks) {
+ if (_pysqlite_enable_callback_tracebacks) {
PyErr_Print();
} else {
PyErr_Clear();
if (PyErr_Occurred()) {
*aggregate_instance = 0;
- if (_enable_callback_tracebacks) {
+ if (_pysqlite_enable_callback_tracebacks) {
PyErr_Print();
} else {
PyErr_Clear();
Py_DECREF(args);
if (!function_result) {
- if (_enable_callback_tracebacks) {
+ if (_pysqlite_enable_callback_tracebacks) {
PyErr_Print();
} else {
PyErr_Clear();
Py_DECREF(function_result);
}
if (!ok) {
- if (_enable_callback_tracebacks) {
+ if (_pysqlite_enable_callback_tracebacks) {
PyErr_Print();
} else {
PyErr_Clear();
ret = PyObject_CallFunction((PyObject*)user_arg, "issss", action, arg1, arg2, dbname, access_attempt_source);
if (ret == NULL) {
- if (_enable_callback_tracebacks)
+ if (_pysqlite_enable_callback_tracebacks)
PyErr_Print();
else
PyErr_Clear();
if (PyLong_Check(ret)) {
rc = _PyLong_AsInt(ret);
if (rc == -1 && PyErr_Occurred()) {
- if (_enable_callback_tracebacks)
+ if (_pysqlite_enable_callback_tracebacks)
PyErr_Print();
else
PyErr_Clear();
ret = PyObject_CallFunction((PyObject*)user_arg, NULL);
if (!ret) {
- if (_enable_callback_tracebacks) {
+ if (_pysqlite_enable_callback_tracebacks) {
PyErr_Print();
} else {
PyErr_Clear();
if (ret) {
Py_DECREF(ret);
} else {
- if (_enable_callback_tracebacks) {
+ if (_pysqlite_enable_callback_tracebacks) {
PyErr_Print();
} else {
PyErr_Clear();
return NULL;
}
- retval = PyDict_GetItem(converters, upcase_key);
+ retval = PyDict_GetItem(_pysqlite_converters, upcase_key);
Py_DECREF(upcase_key);
return retval;
} else {
if (PyErr_Occurred()) {
/* there was an error that occurred in a user-defined callback */
- if (_enable_callback_tracebacks) {
+ if (_pysqlite_enable_callback_tracebacks) {
PyErr_Print();
} else {
PyErr_Clear();
*pysqlite_InternalError, *pysqlite_OperationalError, *pysqlite_ProgrammingError,
*pysqlite_IntegrityError, *pysqlite_DataError, *pysqlite_NotSupportedError;
-PyObject* converters;
-int _enable_callback_tracebacks;
+PyObject* _pysqlite_converters;
+int _pysqlite_enable_callback_tracebacks;
int pysqlite_BaseTypeAdapted;
static PyObject* module_connect(PyObject* self, PyObject* args, PyObject*
goto error;
}
- if (PyDict_SetItem(converters, name, callable) != 0) {
+ if (PyDict_SetItem(_pysqlite_converters, name, callable) != 0) {
goto error;
}
static PyObject* enable_callback_tracebacks(PyObject* self, PyObject* args)
{
- if (!PyArg_ParseTuple(args, "i", &_enable_callback_tracebacks)) {
+ if (!PyArg_ParseTuple(args, "i", &_pysqlite_enable_callback_tracebacks)) {
return NULL;
}
static void converters_init(PyObject* dict)
{
- converters = PyDict_New();
- if (!converters) {
+ _pysqlite_converters = PyDict_New();
+ if (!_pysqlite_converters) {
return;
}
- PyDict_SetItemString(dict, "converters", converters);
+ PyDict_SetItemString(dict, "converters", _pysqlite_converters);
}
static PyMethodDef module_methods[] = {
/* initialize the default converters */
converters_init(dict);
- _enable_callback_tracebacks = 0;
+ _pysqlite_enable_callback_tracebacks = 0;
pysqlite_BaseTypeAdapted = 0;
extern PyObject* pysqlite_DataError;
extern PyObject* pysqlite_NotSupportedError;
-/* the functions time.time() and time.sleep() */
-extern PyObject* time_time;
-extern PyObject* time_sleep;
-
/* A dictionary, mapping column types (INTEGER, VARCHAR, etc.) to converter
* functions, that convert the SQL value to the appropriate Python value.
* The key is uppercase.
*/
-extern PyObject* converters;
+extern PyObject* _pysqlite_converters;
-extern int _enable_callback_tracebacks;
+extern int _pysqlite_enable_callback_tracebacks;
extern int pysqlite_BaseTypeAdapted;
#define PARSE_DECLTYPES 1
continue;
}
- self->is_dml = (PyOS_strnicmp(p, "insert ", 7) == 0)
- || (PyOS_strnicmp(p, "update ", 7) == 0)
- || (PyOS_strnicmp(p, "delete ", 7) == 0)
- || (PyOS_strnicmp(p, "replace ", 8) == 0);
+ self->is_dml = (PyOS_strnicmp(p, "insert", 6) == 0)
+ || (PyOS_strnicmp(p, "update", 6) == 0)
+ || (PyOS_strnicmp(p, "delete", 6) == 0)
+ || (PyOS_strnicmp(p, "replace", 7) == 0);
break;
}
#include "openssl/err.h"
#include "openssl/rand.h"
#include "openssl/bio.h"
+#include "openssl/dh.h"
/* SSL error object */
static PyObject *PySSLErrorObject;
PyObject *set_hostname;
#endif
int check_hostname;
+#ifdef TLS1_3_VERSION
+ int post_handshake_auth;
+#endif
} PySSLContext;
+typedef struct {
+ int ssl; /* last seen error from SSL */
+ int c; /* last seen error from libc */
+#ifdef MS_WINDOWS
+ int ws; /* last seen error from winsock */
+#endif
+} _PySSLError;
+
typedef struct {
PyObject_HEAD
PyObject *Socket; /* weakref to socket on which we're layered */
enum py_ssl_server_or_client socket_type;
PyObject *owner; /* Python level "owner" passed to servername callback */
PyObject *server_hostname;
- int ssl_errno; /* last seen error from SSL */
- int c_errno; /* last seen error from libc */
-#ifdef MS_WINDOWS
- int ws_errno; /* last seen error from winsock */
-#endif
+ _PySSLError err; /* last seen error from various sources */
} PySSLSocket;
typedef struct {
static PyTypeObject PySSLMemoryBIO_Type;
static PyTypeObject PySSLSession_Type;
+static inline _PySSLError _PySSL_errno(int failed, const SSL *ssl, int retcode)
+{
+ _PySSLError err = { 0 };
+ if (failed) {
#ifdef MS_WINDOWS
-#define _PySSL_UPDATE_ERRNO_IF(cond, sock, retcode) if (cond) { \
- (sock)->ws_errno = WSAGetLastError(); \
- (sock)->c_errno = errno; \
- (sock)->ssl_errno = SSL_get_error((sock->ssl), (retcode)); \
- } else { sock->ws_errno = 0; sock->c_errno = 0; sock->ssl_errno = 0; }
-#else
-#define _PySSL_UPDATE_ERRNO_IF(cond, sock, retcode) if (cond) { \
- (sock)->c_errno = errno; \
- (sock)->ssl_errno = SSL_get_error((sock->ssl), (retcode)); \
- } else { (sock)->c_errno = 0; (sock)->ssl_errno = 0; }
+ err.ws = WSAGetLastError();
#endif
-#define _PySSL_UPDATE_ERRNO(sock, retcode) _PySSL_UPDATE_ERRNO_IF(1, (sock), (retcode))
+ err.c = errno;
+ err.ssl = SSL_get_error(ssl, retcode);
+ }
+ return err;
+}
/*[clinic input]
module _ssl
{
PyObject *type = PySSLErrorObject;
char *errstr = NULL;
- int err;
+ _PySSLError err;
enum py_ssl_error p = PY_SSL_ERROR_NONE;
unsigned long e = 0;
e = ERR_peek_last_error();
if (obj->ssl != NULL) {
- err = obj->ssl_errno;
+ err = obj->err;
- switch (err) {
+ switch (err.ssl) {
case SSL_ERROR_ZERO_RETURN:
errstr = "TLS/SSL connection has been closed (EOF)";
type = PySSLZeroReturnErrorObject;
/* underlying BIO reported an I/O error */
ERR_clear_error();
#ifdef MS_WINDOWS
- if (obj->ws_errno)
- return PyErr_SetFromWindowsErr(obj->ws_errno);
+ if (err.ws) {
+ return PyErr_SetFromWindowsErr(err.ws);
+ }
#endif
- if (obj->c_errno) {
- errno = obj->c_errno;
+ if (err.c) {
+ errno = err.c;
return PyErr_SetFromErrno(PyExc_OSError);
}
Py_INCREF(s);
PySSLSocket *self;
SSL_CTX *ctx = sslctx->ctx;
long mode;
+ _PySSLError err = { 0 };
self = PyObject_New(PySSLSocket, &PySSLSocket_Type);
if (self == NULL)
}
self->server_hostname = hostname;
}
- self->ssl_errno = 0;
- self->c_errno = 0;
-#ifdef MS_WINDOWS
- self->ws_errno = 0;
-#endif
+ self->err = err;
/* Make sure the SSL error state is initialized */
(void) ERR_get_state();
/*[clinic end generated code: output=6c0898a8936548f6 input=d2d737de3df018c8]*/
{
int ret;
- int err;
+ _PySSLError err;
int sockstate, nonblocking;
PySocketSockObject *sock = GET_SOCKET(self);
_PyTime_t timeout, deadline = 0;
do {
PySSL_BEGIN_ALLOW_THREADS
ret = SSL_do_handshake(self->ssl);
- _PySSL_UPDATE_ERRNO_IF(ret < 1, self, ret);
+ err = _PySSL_errno(ret < 1, self->ssl, ret);
PySSL_END_ALLOW_THREADS
- err = self->ssl_errno;
+ self->err = err;
if (PyErr_CheckSignals())
goto error;
if (has_timeout)
timeout = deadline - _PyTime_GetMonotonicClock();
- if (err == SSL_ERROR_WANT_READ) {
+ if (err.ssl == SSL_ERROR_WANT_READ) {
sockstate = PySSL_select(sock, 0, timeout);
- } else if (err == SSL_ERROR_WANT_WRITE) {
+ } else if (err.ssl == SSL_ERROR_WANT_WRITE) {
sockstate = PySSL_select(sock, 1, timeout);
} else {
sockstate = SOCKET_OPERATION_OK;
} else if (sockstate == SOCKET_IS_NONBLOCKING) {
break;
}
- } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE);
+ } while (err.ssl == SSL_ERROR_WANT_READ ||
+ err.ssl == SSL_ERROR_WANT_WRITE);
Py_XDECREF(sock);
if (ret < 1)
return PySSL_SetError(self, ret, __FILE__, __LINE__);
{
int len;
int sockstate;
- int err;
+ _PySSLError err;
int nonblocking;
PySocketSockObject *sock = GET_SOCKET(self);
_PyTime_t timeout, deadline = 0;
do {
PySSL_BEGIN_ALLOW_THREADS
len = SSL_write(self->ssl, b->buf, (int)b->len);
- _PySSL_UPDATE_ERRNO_IF(len <= 0, self, len);
+ err = _PySSL_errno(len <= 0, self->ssl, len);
PySSL_END_ALLOW_THREADS
- err = self->ssl_errno;
+ self->err = err;
if (PyErr_CheckSignals())
goto error;
if (has_timeout)
timeout = deadline - _PyTime_GetMonotonicClock();
- if (err == SSL_ERROR_WANT_READ) {
+ if (err.ssl == SSL_ERROR_WANT_READ) {
sockstate = PySSL_select(sock, 0, timeout);
- } else if (err == SSL_ERROR_WANT_WRITE) {
+ } else if (err.ssl == SSL_ERROR_WANT_WRITE) {
sockstate = PySSL_select(sock, 1, timeout);
} else {
sockstate = SOCKET_OPERATION_OK;
} else if (sockstate == SOCKET_IS_NONBLOCKING) {
break;
}
- } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE);
+ } while (err.ssl == SSL_ERROR_WANT_READ ||
+ err.ssl == SSL_ERROR_WANT_WRITE);
Py_XDECREF(sock);
if (len > 0)
/*[clinic end generated code: output=983d9fecdc308a83 input=2b77487d6dfd597f]*/
{
int count = 0;
+ _PySSLError err;
PySSL_BEGIN_ALLOW_THREADS
count = SSL_pending(self->ssl);
- _PySSL_UPDATE_ERRNO_IF(count < 0, self, count);
+ err = _PySSL_errno(count < 0, self->ssl, count);
PySSL_END_ALLOW_THREADS
+ self->err = err;
+
if (count < 0)
return PySSL_SetError(self, count, __FILE__, __LINE__);
else
char *mem;
int count;
int sockstate;
- int err;
+ _PySSLError err;
int nonblocking;
PySocketSockObject *sock = GET_SOCKET(self);
_PyTime_t timeout, deadline = 0;
do {
PySSL_BEGIN_ALLOW_THREADS
count = SSL_read(self->ssl, mem, len);
- _PySSL_UPDATE_ERRNO_IF(count <= 0, self, count);
+ err = _PySSL_errno(count <= 0, self->ssl, count);
PySSL_END_ALLOW_THREADS
+ self->err = err;
if (PyErr_CheckSignals())
goto error;
if (has_timeout)
timeout = deadline - _PyTime_GetMonotonicClock();
- err = self->ssl_errno;
- if (err == SSL_ERROR_WANT_READ) {
+ if (err.ssl == SSL_ERROR_WANT_READ) {
sockstate = PySSL_select(sock, 0, timeout);
- } else if (err == SSL_ERROR_WANT_WRITE) {
+ } else if (err.ssl == SSL_ERROR_WANT_WRITE) {
sockstate = PySSL_select(sock, 1, timeout);
- } else if (err == SSL_ERROR_ZERO_RETURN &&
+ } else if (err.ssl == SSL_ERROR_ZERO_RETURN &&
SSL_get_shutdown(self->ssl) == SSL_RECEIVED_SHUTDOWN)
{
count = 0;
} else if (sockstate == SOCKET_IS_NONBLOCKING) {
break;
}
- } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE);
+ } while (err.ssl == SSL_ERROR_WANT_READ ||
+ err.ssl == SSL_ERROR_WANT_WRITE);
if (count <= 0) {
PySSL_SetError(self, count, __FILE__, __LINE__);
_ssl__SSLSocket_shutdown_impl(PySSLSocket *self)
/*[clinic end generated code: output=ca1aa7ed9d25ca42 input=ede2cc1a2ddf0ee4]*/
{
- int err, sockstate, nonblocking;
+ _PySSLError err;
+ int sockstate, nonblocking, ret;
int zeros = 0;
PySocketSockObject *sock = GET_SOCKET(self);
_PyTime_t timeout, deadline = 0;
*/
if (self->shutdown_seen_zero)
SSL_set_read_ahead(self->ssl, 0);
- err = SSL_shutdown(self->ssl);
- _PySSL_UPDATE_ERRNO_IF(err < 0, self, err);
+ ret = SSL_shutdown(self->ssl);
+ err = _PySSL_errno(ret < 0, self->ssl, ret);
PySSL_END_ALLOW_THREADS
+ self->err = err;
/* If err == 1, a secure shutdown with SSL_shutdown() is complete */
- if (err > 0)
+ if (ret > 0)
break;
- if (err == 0) {
+ if (ret == 0) {
/* Don't loop endlessly; instead preserve legacy
behaviour of trying SSL_shutdown() only twice.
This looks necessary for OpenSSL < 0.9.8m */
timeout = deadline - _PyTime_GetMonotonicClock();
/* Possibly retry shutdown until timeout or failure */
- _PySSL_UPDATE_ERRNO(self, err);
- if (self->ssl_errno == SSL_ERROR_WANT_READ)
+ if (err.ssl == SSL_ERROR_WANT_READ)
sockstate = PySSL_select(sock, 0, timeout);
- else if (self->ssl_errno == SSL_ERROR_WANT_WRITE)
+ else if (err.ssl == SSL_ERROR_WANT_WRITE)
sockstate = PySSL_select(sock, 1, timeout);
else
break;
if (sockstate == SOCKET_HAS_TIMED_OUT) {
- if (self->ssl_errno == SSL_ERROR_WANT_READ)
+ if (err.ssl == SSL_ERROR_WANT_READ)
PyErr_SetString(PySocketModule.timeout_error,
"The read operation timed out");
else
break;
}
- if (err < 0) {
+ if (ret < 0) {
Py_XDECREF(sock);
- return PySSL_SetError(self, err, __FILE__, __LINE__);
+ return PySSL_SetError(self, ret, __FILE__, __LINE__);
}
if (sock)
/* It's already INCREF'ed */
return retval;
}
+/*[clinic input]
+_ssl._SSLSocket.verify_client_post_handshake
+
+Initiate TLS 1.3 post-handshake authentication
+[clinic start generated code]*/
+
+static PyObject *
+_ssl__SSLSocket_verify_client_post_handshake_impl(PySSLSocket *self)
+/*[clinic end generated code: output=532147f3b1341425 input=6bfa874810a3d889]*/
+{
+#ifdef TLS1_3_VERSION
+ int err = SSL_verify_client_post_handshake(self->ssl);
+ if (err == 0)
+ return _setSSLError(NULL, 0, __FILE__, __LINE__);
+ else
+ Py_RETURN_NONE;
+#else
+ PyErr_SetString(PyExc_NotImplementedError,
+ "Post-handshake auth is not supported by your "
+ "OpenSSL version.");
+ return NULL;
+#endif
+}
+
#ifdef OPENSSL_VERSION_1_1
static SSL_SESSION*
_SSL__SSLSOCKET_COMPRESSION_METHODDEF
_SSL__SSLSOCKET_SHUTDOWN_METHODDEF
_SSL__SSLSOCKET_TLS_UNIQUE_CB_METHODDEF
+ _SSL__SSLSOCKET_VERIFY_CLIENT_POST_HANDSHAKE_METHODDEF
{NULL, NULL}
};
*/
static int
-_set_verify_mode(SSL_CTX *ctx, enum py_ssl_cert_requirements n)
+_set_verify_mode(PySSLContext *self, enum py_ssl_cert_requirements n)
{
int mode;
int (*verify_cb)(int, X509_STORE_CTX *) = NULL;
"invalid value for verify_mode");
return -1;
}
+#ifdef TLS1_3_VERSION
+ if (self->post_handshake_auth)
+ mode |= SSL_VERIFY_POST_HANDSHAKE;
+#endif
/* keep current verify cb */
- verify_cb = SSL_CTX_get_verify_callback(ctx);
- SSL_CTX_set_verify(ctx, mode, verify_cb);
+ verify_cb = SSL_CTX_get_verify_callback(self->ctx);
+ SSL_CTX_set_verify(self->ctx, mode, verify_cb);
return 0;
}
/* Don't check host name by default */
if (proto_version == PY_SSL_VERSION_TLS_CLIENT) {
self->check_hostname = 1;
- if (_set_verify_mode(self->ctx, PY_SSL_CERT_REQUIRED) == -1) {
+ if (_set_verify_mode(self, PY_SSL_CERT_REQUIRED) == -1) {
Py_DECREF(self);
return NULL;
}
} else {
self->check_hostname = 0;
- if (_set_verify_mode(self->ctx, PY_SSL_CERT_NONE) == -1) {
+ if (_set_verify_mode(self, PY_SSL_CERT_NONE) == -1) {
Py_DECREF(self);
return NULL;
}
}
#endif
+#ifdef TLS1_3_VERSION
+ self->post_handshake_auth = 0;
+ SSL_CTX_set_post_handshake_auth(self->ctx, self->post_handshake_auth);
+#endif
+
return (PyObject *)self;
}
static PyObject *
get_verify_mode(PySSLContext *self, void *c)
{
- switch (SSL_CTX_get_verify_mode(self->ctx)) {
+ /* ignore SSL_VERIFY_CLIENT_ONCE and SSL_VERIFY_POST_HANDSHAKE */
+ int mask = (SSL_VERIFY_NONE | SSL_VERIFY_PEER |
+ SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
+ switch (SSL_CTX_get_verify_mode(self->ctx) & mask) {
case SSL_VERIFY_NONE:
return PyLong_FromLong(PY_SSL_CERT_NONE);
case SSL_VERIFY_PEER:
"check_hostname is enabled.");
return -1;
}
- return _set_verify_mode(self->ctx, n);
+ return _set_verify_mode(self, n);
}
static PyObject *
return 0;
}
+static PyObject *
+get_post_handshake_auth(PySSLContext *self, void *c) {
+#if TLS1_3_VERSION
+ return PyBool_FromLong(self->post_handshake_auth);
+#else
+ Py_RETURN_NONE;
+#endif
+}
+
+#if TLS1_3_VERSION
+static int
+set_post_handshake_auth(PySSLContext *self, PyObject *arg, void *c) {
+ int (*verify_cb)(int, X509_STORE_CTX *) = NULL;
+ int mode = SSL_CTX_get_verify_mode(self->ctx);
+ int pha = PyObject_IsTrue(arg);
+
+ if (pha == -1) {
+ return -1;
+ }
+ self->post_handshake_auth = pha;
+
+ /* client-side socket setting, ignored by server-side */
+ SSL_CTX_set_post_handshake_auth(self->ctx, pha);
+
+ /* server-side socket setting, ignored by client-side */
+ verify_cb = SSL_CTX_get_verify_callback(self->ctx);
+ if (pha) {
+ mode |= SSL_VERIFY_POST_HANDSHAKE;
+ } else {
+ mode ^= SSL_VERIFY_POST_HANDSHAKE;
+ }
+ SSL_CTX_set_verify(self->ctx, mode, verify_cb);
+
+ return 0;
+}
+#endif
typedef struct {
PyThreadState *thread_state;
(setter) set_check_hostname, NULL},
{"options", (getter) get_options,
(setter) set_options, NULL},
+ {"post_handshake_auth", (getter) get_post_handshake_auth,
+#ifdef TLS1_3_VERSION
+ (setter) set_post_handshake_auth,
+#else
+ NULL,
+#endif
+ NULL},
{"verify_flags", (getter) get_verify_flags,
(setter) set_verify_flags, NULL},
{"verify_mode", (getter) get_verify_mode,
PyModule_AddIntConstant(m, "OP_NO_COMPRESSION",
SSL_OP_NO_COMPRESSION);
#endif
+#ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT
+ PyModule_AddIntConstant(m, "OP_ENABLE_MIDDLEBOX_COMPAT",
+ SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
+#endif
#if HAVE_SNI
r = Py_True;
/* struct module */
-PyObject *structmodule = NULL;
-PyObject *Struct = NULL;
-PyObject *calcsize = NULL;
+static PyObject *structmodule = NULL;
+static PyObject *Struct = NULL;
+static PyObject *calcsize = NULL;
/* cache simple format string */
static const char *simple_fmt = "B";
-PyObject *simple_format = NULL;
+static PyObject *simple_format = NULL;
#define SIMPLE_FORMAT(fmt) (fmt == NULL || strcmp(fmt, "B") == 0)
#define FIX_FORMAT(fmt) (fmt == NULL ? "B" : fmt)
/* The following requests n callbacks to _pending_callback. It can be
* run from any python thread.
*/
-PyObject *pending_threadfunc(PyObject *self, PyObject *arg)
+static PyObject *
+pending_threadfunc(PyObject *self, PyObject *arg)
{
PyObject *callable;
int r;
#define TEST_MODULE_DEF(name, slots, methods) TEST_MODULE_DEF_EX(name, slots, methods, 0, NULL)
-PyModuleDef_Slot main_slots[] = {
+static PyModuleDef_Slot main_slots[] = {
{Py_mod_exec, execfunc},
{0, NULL},
};
return NULL;
}
-PyModuleDef_Slot slots_create_null[] = {
+static PyModuleDef_Slot slots_create_null[] = {
{Py_mod_create, createfunc_null},
{0, NULL},
};
static PyTypeObject Locktype = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"_thread.lock", /*tp_name*/
- sizeof(lockobject), /*tp_size*/
+ sizeof(lockobject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)lock_dealloc, /*tp_dealloc*/
static PyTypeObject RLocktype = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"_thread.RLock", /*tp_name*/
- sizeof(rlockobject), /*tp_size*/
+ sizeof(rlockobject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)rlock_dealloc, /*tp_dealloc*/
}
if (_PyBytes_Resize(&buf, nread))
return NULL;
- return Py_BuildValue("Nii", buf, navail, nleft);
+ return Py_BuildValue("NII", buf, navail, nleft);
}
else {
Py_BEGIN_ALLOW_THREADS
if (!ret) {
return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
}
- return Py_BuildValue("ii", navail, nleft);
+ return Py_BuildValue("II", navail, nleft);
}
}
_winapi.ReadFile
handle: HANDLE
- size: int
+ size: DWORD
overlapped as use_overlapped: int(c_default='0') = False
[clinic start generated code]*/
static PyObject *
-_winapi_ReadFile_impl(PyObject *module, HANDLE handle, int size,
+_winapi_ReadFile_impl(PyObject *module, HANDLE handle, DWORD size,
int use_overlapped)
-/*[clinic end generated code: output=492029ca98161d84 input=8dd810194e86ac7d]*/
+/*[clinic end generated code: output=d3d5b44a8201b944 input=1b7d0ed0de1e50bc]*/
{
DWORD nread;
PyObject *buf;
return _ssl__SSLSocket_tls_unique_cb_impl(self);
}
+PyDoc_STRVAR(_ssl__SSLSocket_verify_client_post_handshake__doc__,
+"verify_client_post_handshake($self, /)\n"
+"--\n"
+"\n"
+"Initiate TLS 1.3 post-handshake authentication");
+
+#define _SSL__SSLSOCKET_VERIFY_CLIENT_POST_HANDSHAKE_METHODDEF \
+ {"verify_client_post_handshake", (PyCFunction)_ssl__SSLSocket_verify_client_post_handshake, METH_NOARGS, _ssl__SSLSocket_verify_client_post_handshake__doc__},
+
+static PyObject *
+_ssl__SSLSocket_verify_client_post_handshake_impl(PySSLSocket *self);
+
+static PyObject *
+_ssl__SSLSocket_verify_client_post_handshake(PySSLSocket *self, PyObject *Py_UNUSED(ignored))
+{
+ return _ssl__SSLSocket_verify_client_post_handshake_impl(self);
+}
+
static PyObject *
_ssl__SSLContext_impl(PyTypeObject *type, int proto_version);
#ifndef _SSL_ENUM_CRLS_METHODDEF
#define _SSL_ENUM_CRLS_METHODDEF
#endif /* !defined(_SSL_ENUM_CRLS_METHODDEF) */
-/*[clinic end generated code: output=c79fb0dfd3c90784 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=a832758678f4d934 input=a9049054013a1b77]*/
{"ReadFile", (PyCFunction)_winapi_ReadFile, METH_FASTCALL, _winapi_ReadFile__doc__},
static PyObject *
-_winapi_ReadFile_impl(PyObject *module, HANDLE handle, int size,
+_winapi_ReadFile_impl(PyObject *module, HANDLE handle, DWORD size,
int use_overlapped);
static PyObject *
{
PyObject *return_value = NULL;
static const char * const _keywords[] = {"handle", "size", "overlapped", NULL};
- static _PyArg_Parser _parser = {"" F_HANDLE "i|i:ReadFile", _keywords, 0};
+ static _PyArg_Parser _parser = {"" F_HANDLE "k|i:ReadFile", _keywords, 0};
HANDLE handle;
- int size;
+ DWORD size;
int use_overlapped = 0;
if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
exit:
return return_value;
}
-/*[clinic end generated code: output=46d6382a6662c4a9 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=6c5cf8865d381c70 input=a9049054013a1b77]*/
const XML_Char *namespaceSeparator);
/* Prepare a parser object to be re-used. This is particularly
- valuable when memory allocation overhead is disproportionatly high,
+ valuable when memory allocation overhead is disproportionately high,
such as when a large number of small documnents need to be parsed.
All handlers are cleared from the parser, except for the
unknownEncodingHandler. The parser's external state is re-initialized
*/
#define XML_MAJOR_VERSION 2
#define XML_MINOR_VERSION 2
-#define XML_MICRO_VERSION 4
+#define XML_MICRO_VERSION 6
#ifdef __cplusplus
}
/* External API definitions */
-/* Namespace external symbols to allow multiple libexpat version to
- co-exist. */
-#include "pyexpatns.h"
-
#if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__)
-#define XML_USE_MSC_EXTENSIONS 1
+# define XML_USE_MSC_EXTENSIONS 1
#endif
/* Expat tries very hard to make the API boundary very specifically
system headers may assume the cdecl convention.
*/
#ifndef XMLCALL
-#if defined(_MSC_VER)
-#define XMLCALL __cdecl
-#elif defined(__GNUC__) && defined(__i386) && !defined(__INTEL_COMPILER)
-#define XMLCALL __attribute__((cdecl))
-#else
+# if defined(_MSC_VER)
+# define XMLCALL __cdecl
+# elif defined(__GNUC__) && defined(__i386) && !defined(__INTEL_COMPILER)
+# define XMLCALL __attribute__((cdecl))
+# else
/* For any platform which uses this definition and supports more than
one calling convention, we need to extend this definition to
declare the convention used on that platform, if it's possible to
pre-processor and how to specify the same calling convention as the
platform's malloc() implementation.
*/
-#define XMLCALL
-#endif
+# define XMLCALL
+# endif
#endif /* not defined XMLCALL */
#if !defined(XML_STATIC) && !defined(XMLIMPORT)
-#ifndef XML_BUILDING_EXPAT
+# ifndef XML_BUILDING_EXPAT
/* using Expat from an application */
-#ifdef XML_USE_MSC_EXTENSIONS
-#define XMLIMPORT __declspec(dllimport)
-#endif
+# ifdef XML_USE_MSC_EXTENSIONS
+# define XMLIMPORT __declspec(dllimport)
+# endif
-#endif
+# endif
#endif /* not defined XML_STATIC */
#if !defined(XMLIMPORT) && defined(__GNUC__) && (__GNUC__ >= 4)
-#define XMLIMPORT __attribute__ ((visibility ("default")))
+# define XMLIMPORT __attribute__ ((visibility ("default")))
#endif
/* If we didn't define it above, define it away: */
#ifndef XMLIMPORT
-#define XMLIMPORT
+# define XMLIMPORT
#endif
#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96))
-#define XML_ATTR_MALLOC __attribute__((__malloc__))
+# define XML_ATTR_MALLOC __attribute__((__malloc__))
#else
-#define XML_ATTR_MALLOC
+# define XML_ATTR_MALLOC
#endif
#if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
-#define XML_ATTR_ALLOC_SIZE(x) __attribute__((__alloc_size__(x)))
+# define XML_ATTR_ALLOC_SIZE(x) __attribute__((__alloc_size__(x)))
#else
-#define XML_ATTR_ALLOC_SIZE(x)
+# define XML_ATTR_ALLOC_SIZE(x)
#endif
#define XMLPARSEAPI(type) XMLIMPORT type XMLCALL
#endif
#ifdef XML_UNICODE_WCHAR_T
-# define XML_UNICODE
+# ifndef XML_UNICODE
+# define XML_UNICODE
+# endif
# if defined(__SIZEOF_WCHAR_T__) && (__SIZEOF_WCHAR_T__ != 2)
# error "sizeof(wchar_t) != 2; Need -fshort-wchar for both Expat and libc"
# endif
#endif
#ifdef XML_UNICODE /* Information is UTF-16 encoded. */
-#ifdef XML_UNICODE_WCHAR_T
+# ifdef XML_UNICODE_WCHAR_T
typedef wchar_t XML_Char;
typedef wchar_t XML_LChar;
-#else
+# else
typedef unsigned short XML_Char;
typedef char XML_LChar;
-#endif /* XML_UNICODE_WCHAR_T */
+# endif /* XML_UNICODE_WCHAR_T */
#else /* Information is UTF-8 encoded. */
typedef char XML_Char;
typedef char XML_LChar;
#endif /* XML_UNICODE */
#ifdef XML_LARGE_SIZE /* Use large integers for file/stream positions. */
-#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
+# if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
typedef __int64 XML_Index;
typedef unsigned __int64 XML_Size;
-#else
+# else
typedef long long XML_Index;
typedef unsigned long long XML_Size;
-#endif
+# endif
#else
typedef long XML_Index;
typedef unsigned long XML_Size;
void
-align_limit_to_full_utf8_characters(const char * from, const char ** fromLimRef);
+_INTERNAL_trim_to_complete_utf8_characters(const char * from, const char ** fromLimRef);
#ifdef __cplusplus
/* Get a handle to kernel32 so we can access it's functions at runtime */
HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32"));
if(!hKernel32)
- return NULL;
+ return NULL; /* LCOV_EXCL_LINE */
/* Attempt to find LoadLibraryEx() which is only available on Windows 2000
and above */
* --------------------------------------------------------------------------
* HISTORY:
*
+ * 2018-07-08 (Anton Maklakov)
+ * - Add "fall through" markers for GCC's -Wimplicit-fallthrough
+ *
+ * 2017-11-03 (Sebastian Pipping)
+ * - Hide sip_tobin and sip_binof unless SIPHASH_TOBIN macro is defined
+ *
* 2017-07-25 (Vadim Zeitlin)
* - Fix use of SIPHASH_MAIN macro
*
} /* sip_tokey() */
+#ifdef SIPHASH_TOBIN
+
#define sip_binof(v) sip_tobin((unsigned char[8]){ 0 }, (v))
static void *sip_tobin(void *dst, uint64_t u64) {
return dst;
} /* sip_tobin() */
+#endif /* SIPHASH_TOBIN */
+
static void sip_round(struct siphash *H, const int rounds) {
int i;
switch (left) {
case 7: b |= (uint64_t)H->buf[6] << 48;
+ /* fall through */
case 6: b |= (uint64_t)H->buf[5] << 40;
+ /* fall through */
case 5: b |= (uint64_t)H->buf[4] << 32;
+ /* fall through */
case 4: b |= (uint64_t)H->buf[3] << 24;
+ /* fall through */
case 3: b |= (uint64_t)H->buf[2] << 16;
+ /* fall through */
case 2: b |= (uint64_t)H->buf[1] << 8;
+ /* fall through */
case 1: b |= (uint64_t)H->buf[0] << 0;
+ /* fall through */
case 0: break;
}
-/* 8c6b2be7c6281da65ce05218fc15c339f02a811706340824ab596aa86e1fd51a (2.2.4+)
+/* 19ac4776051591216f1874e34ee99b6a43a3784c8bd7d70efeb9258dd22b906a (2.2.6+)
__ __ _
___\ \/ /_ __ __ _| |_
/ _ \\ /| '_ \ / _` | __|
/* Round up n to be a multiple of sz, where sz is a power of 2. */
#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1))
+/* Do safe (NULL-aware) pointer arithmetic */
+#define EXPAT_SAFE_PTR_DIFF(p, q) (((p) && (q)) ? ((p) - (q)) : 0)
+
/* Handle the case where memmove() doesn't exist. */
#ifndef HAVE_MEMMOVE
#ifdef HAVE_BCOPY
static void FASTCALL normalizePublicId(XML_Char *s);
static DTD * dtdCreate(const XML_Memory_Handling_Suite *ms);
-/* do not call if parentParser != NULL */
+/* do not call if m_parentParser != NULL */
static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms);
static void
dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms);
: ((*((pool)->ptr)++ = c), 1))
struct XML_ParserStruct {
- /* The first member must be userData so that the XML_GetUserData
+ /* The first member must be m_userData so that the XML_GetUserData
macro works. */
void *m_userData;
void *m_handlerArg;
const char *m_bufferPtr;
/* past last character to be parsed */
char *m_bufferEnd;
- /* allocated end of buffer */
+ /* allocated end of m_buffer */
const char *m_bufferLim;
XML_Index m_parseEndByteIndex;
const char *m_parseEndPtr;
unsigned long m_hash_secret_salt;
};
-#define MALLOC(s) (parser->m_mem.malloc_fcn((s)))
-#define REALLOC(p,s) (parser->m_mem.realloc_fcn((p),(s)))
-#define FREE(p) (parser->m_mem.free_fcn((p)))
-
-#define userData (parser->m_userData)
-#define handlerArg (parser->m_handlerArg)
-#define startElementHandler (parser->m_startElementHandler)
-#define endElementHandler (parser->m_endElementHandler)
-#define characterDataHandler (parser->m_characterDataHandler)
-#define processingInstructionHandler \
- (parser->m_processingInstructionHandler)
-#define commentHandler (parser->m_commentHandler)
-#define startCdataSectionHandler \
- (parser->m_startCdataSectionHandler)
-#define endCdataSectionHandler (parser->m_endCdataSectionHandler)
-#define defaultHandler (parser->m_defaultHandler)
-#define startDoctypeDeclHandler (parser->m_startDoctypeDeclHandler)
-#define endDoctypeDeclHandler (parser->m_endDoctypeDeclHandler)
-#define unparsedEntityDeclHandler \
- (parser->m_unparsedEntityDeclHandler)
-#define notationDeclHandler (parser->m_notationDeclHandler)
-#define startNamespaceDeclHandler \
- (parser->m_startNamespaceDeclHandler)
-#define endNamespaceDeclHandler (parser->m_endNamespaceDeclHandler)
-#define notStandaloneHandler (parser->m_notStandaloneHandler)
-#define externalEntityRefHandler \
- (parser->m_externalEntityRefHandler)
-#define externalEntityRefHandlerArg \
- (parser->m_externalEntityRefHandlerArg)
-#define internalEntityRefHandler \
- (parser->m_internalEntityRefHandler)
-#define skippedEntityHandler (parser->m_skippedEntityHandler)
-#define unknownEncodingHandler (parser->m_unknownEncodingHandler)
-#define elementDeclHandler (parser->m_elementDeclHandler)
-#define attlistDeclHandler (parser->m_attlistDeclHandler)
-#define entityDeclHandler (parser->m_entityDeclHandler)
-#define xmlDeclHandler (parser->m_xmlDeclHandler)
-#define encoding (parser->m_encoding)
-#define initEncoding (parser->m_initEncoding)
-#define internalEncoding (parser->m_internalEncoding)
-#define unknownEncodingMem (parser->m_unknownEncodingMem)
-#define unknownEncodingData (parser->m_unknownEncodingData)
-#define unknownEncodingHandlerData \
- (parser->m_unknownEncodingHandlerData)
-#define unknownEncodingRelease (parser->m_unknownEncodingRelease)
-#define protocolEncodingName (parser->m_protocolEncodingName)
-#define ns (parser->m_ns)
-#define ns_triplets (parser->m_ns_triplets)
-#define prologState (parser->m_prologState)
-#define processor (parser->m_processor)
-#define errorCode (parser->m_errorCode)
-#define eventPtr (parser->m_eventPtr)
-#define eventEndPtr (parser->m_eventEndPtr)
-#define positionPtr (parser->m_positionPtr)
-#define position (parser->m_position)
-#define openInternalEntities (parser->m_openInternalEntities)
-#define freeInternalEntities (parser->m_freeInternalEntities)
-#define defaultExpandInternalEntities \
- (parser->m_defaultExpandInternalEntities)
-#define tagLevel (parser->m_tagLevel)
-#define buffer (parser->m_buffer)
-#define bufferPtr (parser->m_bufferPtr)
-#define bufferEnd (parser->m_bufferEnd)
-#define parseEndByteIndex (parser->m_parseEndByteIndex)
-#define parseEndPtr (parser->m_parseEndPtr)
-#define bufferLim (parser->m_bufferLim)
-#define dataBuf (parser->m_dataBuf)
-#define dataBufEnd (parser->m_dataBufEnd)
-#define _dtd (parser->m_dtd)
-#define curBase (parser->m_curBase)
-#define declEntity (parser->m_declEntity)
-#define doctypeName (parser->m_doctypeName)
-#define doctypeSysid (parser->m_doctypeSysid)
-#define doctypePubid (parser->m_doctypePubid)
-#define declAttributeType (parser->m_declAttributeType)
-#define declNotationName (parser->m_declNotationName)
-#define declNotationPublicId (parser->m_declNotationPublicId)
-#define declElementType (parser->m_declElementType)
-#define declAttributeId (parser->m_declAttributeId)
-#define declAttributeIsCdata (parser->m_declAttributeIsCdata)
-#define declAttributeIsId (parser->m_declAttributeIsId)
-#define freeTagList (parser->m_freeTagList)
-#define freeBindingList (parser->m_freeBindingList)
-#define inheritedBindings (parser->m_inheritedBindings)
-#define tagStack (parser->m_tagStack)
-#define atts (parser->m_atts)
-#define attsSize (parser->m_attsSize)
-#define nSpecifiedAtts (parser->m_nSpecifiedAtts)
-#define idAttIndex (parser->m_idAttIndex)
-#define nsAtts (parser->m_nsAtts)
-#define nsAttsVersion (parser->m_nsAttsVersion)
-#define nsAttsPower (parser->m_nsAttsPower)
-#define attInfo (parser->m_attInfo)
-#define tempPool (parser->m_tempPool)
-#define temp2Pool (parser->m_temp2Pool)
-#define groupConnector (parser->m_groupConnector)
-#define groupSize (parser->m_groupSize)
-#define namespaceSeparator (parser->m_namespaceSeparator)
-#define parentParser (parser->m_parentParser)
-#define ps_parsing (parser->m_parsingStatus.parsing)
-#define ps_finalBuffer (parser->m_parsingStatus.finalBuffer)
-#ifdef XML_DTD
-#define isParamEntity (parser->m_isParamEntity)
-#define useForeignDTD (parser->m_useForeignDTD)
-#define paramEntityParsing (parser->m_paramEntityParsing)
-#endif /* XML_DTD */
-#define hash_secret_salt (parser->m_hash_secret_salt)
+#define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s)))
+#define REALLOC(parser, p, s) (parser->m_mem.realloc_fcn((p),(s)))
+#define FREE(parser, p) (parser->m_mem.free_fcn((p)))
+
XML_Parser XMLCALL
XML_ParserCreate(const XML_Char *encodingName)
};
+/* To avoid warnings about unused functions: */
+#if ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM)
+
#if defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM)
/* Obtain entropy on Linux 3.17+ */
#endif /* ! defined(_WIN32) && defined(XML_DEV_URANDOM) */
+#endif /* ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM) */
+
#if defined(HAVE_ARC4RANDOM)
{
unsigned long entropy;
(void)parser;
+
+ /* "Failproof" high quality providers: */
#if defined(HAVE_ARC4RANDOM_BUF)
arc4random_buf(&entropy, sizeof(entropy));
return ENTROPY_DEBUG("arc4random_buf", entropy);
startParsing(XML_Parser parser)
{
/* hash functions must be initialized before setContext() is called */
- if (hash_secret_salt == 0)
- hash_secret_salt = generate_hash_secret_salt(parser);
- if (ns) {
+ if (parser->m_hash_secret_salt == 0)
+ parser->m_hash_secret_salt = generate_hash_secret_salt(parser);
+ if (parser->m_ns) {
/* implicit context only set for root parser, since child
parsers (i.e. external entity parsers) will inherit it
*/
if (!parser)
return parser;
- buffer = NULL;
- bufferLim = NULL;
+ parser->m_buffer = NULL;
+ parser->m_bufferLim = NULL;
- attsSize = INIT_ATTS_SIZE;
- atts = (ATTRIBUTE *)MALLOC(attsSize * sizeof(ATTRIBUTE));
- if (atts == NULL) {
- FREE(parser);
+ parser->m_attsSize = INIT_ATTS_SIZE;
+ parser->m_atts = (ATTRIBUTE *)MALLOC(parser, parser->m_attsSize * sizeof(ATTRIBUTE));
+ if (parser->m_atts == NULL) {
+ FREE(parser, parser);
return NULL;
}
#ifdef XML_ATTR_INFO
- attInfo = (XML_AttrInfo*)MALLOC(attsSize * sizeof(XML_AttrInfo));
- if (attInfo == NULL) {
- FREE(atts);
- FREE(parser);
+ parser->m_attInfo = (XML_AttrInfo*)MALLOC(parser, parser->m_attsSize * sizeof(XML_AttrInfo));
+ if (parser->m_attInfo == NULL) {
+ FREE(parser, parser->m_atts);
+ FREE(parser, parser);
return NULL;
}
#endif
- dataBuf = (XML_Char *)MALLOC(INIT_DATA_BUF_SIZE * sizeof(XML_Char));
- if (dataBuf == NULL) {
- FREE(atts);
+ parser->m_dataBuf = (XML_Char *)MALLOC(parser, INIT_DATA_BUF_SIZE * sizeof(XML_Char));
+ if (parser->m_dataBuf == NULL) {
+ FREE(parser, parser->m_atts);
#ifdef XML_ATTR_INFO
- FREE(attInfo);
+ FREE(parser, parser->m_attInfo);
#endif
- FREE(parser);
+ FREE(parser, parser);
return NULL;
}
- dataBufEnd = dataBuf + INIT_DATA_BUF_SIZE;
+ parser->m_dataBufEnd = parser->m_dataBuf + INIT_DATA_BUF_SIZE;
if (dtd)
- _dtd = dtd;
+ parser->m_dtd = dtd;
else {
- _dtd = dtdCreate(&parser->m_mem);
- if (_dtd == NULL) {
- FREE(dataBuf);
- FREE(atts);
+ parser->m_dtd = dtdCreate(&parser->m_mem);
+ if (parser->m_dtd == NULL) {
+ FREE(parser, parser->m_dataBuf);
+ FREE(parser, parser->m_atts);
#ifdef XML_ATTR_INFO
- FREE(attInfo);
+ FREE(parser, parser->m_attInfo);
#endif
- FREE(parser);
+ FREE(parser, parser);
return NULL;
}
}
- freeBindingList = NULL;
- freeTagList = NULL;
- freeInternalEntities = NULL;
+ parser->m_freeBindingList = NULL;
+ parser->m_freeTagList = NULL;
+ parser->m_freeInternalEntities = NULL;
- groupSize = 0;
- groupConnector = NULL;
+ parser->m_groupSize = 0;
+ parser->m_groupConnector = NULL;
- unknownEncodingHandler = NULL;
- unknownEncodingHandlerData = NULL;
+ parser->m_unknownEncodingHandler = NULL;
+ parser->m_unknownEncodingHandlerData = NULL;
- namespaceSeparator = ASCII_EXCL;
- ns = XML_FALSE;
- ns_triplets = XML_FALSE;
+ parser->m_namespaceSeparator = ASCII_EXCL;
+ parser->m_ns = XML_FALSE;
+ parser->m_ns_triplets = XML_FALSE;
- nsAtts = NULL;
- nsAttsVersion = 0;
- nsAttsPower = 0;
+ parser->m_nsAtts = NULL;
+ parser->m_nsAttsVersion = 0;
+ parser->m_nsAttsPower = 0;
- protocolEncodingName = NULL;
+ parser->m_protocolEncodingName = NULL;
- poolInit(&tempPool, &(parser->m_mem));
- poolInit(&temp2Pool, &(parser->m_mem));
+ poolInit(&parser->m_tempPool, &(parser->m_mem));
+ poolInit(&parser->m_temp2Pool, &(parser->m_mem));
parserInit(parser, encodingName);
- if (encodingName && !protocolEncodingName) {
+ if (encodingName && !parser->m_protocolEncodingName) {
XML_ParserFree(parser);
return NULL;
}
if (nameSep) {
- ns = XML_TRUE;
- internalEncoding = XmlGetInternalEncodingNS();
- namespaceSeparator = *nameSep;
+ parser->m_ns = XML_TRUE;
+ parser->m_internalEncoding = XmlGetInternalEncodingNS();
+ parser->m_namespaceSeparator = *nameSep;
}
else {
- internalEncoding = XmlGetInternalEncoding();
+ parser->m_internalEncoding = XmlGetInternalEncoding();
}
return parser;
static void
parserInit(XML_Parser parser, const XML_Char *encodingName)
{
- processor = prologInitProcessor;
- XmlPrologStateInit(&prologState);
+ parser->m_processor = prologInitProcessor;
+ XmlPrologStateInit(&parser->m_prologState);
if (encodingName != NULL) {
- protocolEncodingName = copyString(encodingName, &(parser->m_mem));
- }
- curBase = NULL;
- XmlInitEncoding(&initEncoding, &encoding, 0);
- userData = NULL;
- handlerArg = NULL;
- startElementHandler = NULL;
- endElementHandler = NULL;
- characterDataHandler = NULL;
- processingInstructionHandler = NULL;
- commentHandler = NULL;
- startCdataSectionHandler = NULL;
- endCdataSectionHandler = NULL;
- defaultHandler = NULL;
- startDoctypeDeclHandler = NULL;
- endDoctypeDeclHandler = NULL;
- unparsedEntityDeclHandler = NULL;
- notationDeclHandler = NULL;
- startNamespaceDeclHandler = NULL;
- endNamespaceDeclHandler = NULL;
- notStandaloneHandler = NULL;
- externalEntityRefHandler = NULL;
- externalEntityRefHandlerArg = parser;
- skippedEntityHandler = NULL;
- elementDeclHandler = NULL;
- attlistDeclHandler = NULL;
- entityDeclHandler = NULL;
- xmlDeclHandler = NULL;
- bufferPtr = buffer;
- bufferEnd = buffer;
- parseEndByteIndex = 0;
- parseEndPtr = NULL;
- declElementType = NULL;
- declAttributeId = NULL;
- declEntity = NULL;
- doctypeName = NULL;
- doctypeSysid = NULL;
- doctypePubid = NULL;
- declAttributeType = NULL;
- declNotationName = NULL;
- declNotationPublicId = NULL;
- declAttributeIsCdata = XML_FALSE;
- declAttributeIsId = XML_FALSE;
- memset(&position, 0, sizeof(POSITION));
- errorCode = XML_ERROR_NONE;
- eventPtr = NULL;
- eventEndPtr = NULL;
- positionPtr = NULL;
- openInternalEntities = NULL;
- defaultExpandInternalEntities = XML_TRUE;
- tagLevel = 0;
- tagStack = NULL;
- inheritedBindings = NULL;
- nSpecifiedAtts = 0;
- unknownEncodingMem = NULL;
- unknownEncodingRelease = NULL;
- unknownEncodingData = NULL;
- parentParser = NULL;
- ps_parsing = XML_INITIALIZED;
+ parser->m_protocolEncodingName = copyString(encodingName, &(parser->m_mem));
+ }
+ parser->m_curBase = NULL;
+ XmlInitEncoding(&parser->m_initEncoding, &parser->m_encoding, 0);
+ parser->m_userData = NULL;
+ parser->m_handlerArg = NULL;
+ parser->m_startElementHandler = NULL;
+ parser->m_endElementHandler = NULL;
+ parser->m_characterDataHandler = NULL;
+ parser->m_processingInstructionHandler = NULL;
+ parser->m_commentHandler = NULL;
+ parser->m_startCdataSectionHandler = NULL;
+ parser->m_endCdataSectionHandler = NULL;
+ parser->m_defaultHandler = NULL;
+ parser->m_startDoctypeDeclHandler = NULL;
+ parser->m_endDoctypeDeclHandler = NULL;
+ parser->m_unparsedEntityDeclHandler = NULL;
+ parser->m_notationDeclHandler = NULL;
+ parser->m_startNamespaceDeclHandler = NULL;
+ parser->m_endNamespaceDeclHandler = NULL;
+ parser->m_notStandaloneHandler = NULL;
+ parser->m_externalEntityRefHandler = NULL;
+ parser->m_externalEntityRefHandlerArg = parser;
+ parser->m_skippedEntityHandler = NULL;
+ parser->m_elementDeclHandler = NULL;
+ parser->m_attlistDeclHandler = NULL;
+ parser->m_entityDeclHandler = NULL;
+ parser->m_xmlDeclHandler = NULL;
+ parser->m_bufferPtr = parser->m_buffer;
+ parser->m_bufferEnd = parser->m_buffer;
+ parser->m_parseEndByteIndex = 0;
+ parser->m_parseEndPtr = NULL;
+ parser->m_declElementType = NULL;
+ parser->m_declAttributeId = NULL;
+ parser->m_declEntity = NULL;
+ parser->m_doctypeName = NULL;
+ parser->m_doctypeSysid = NULL;
+ parser->m_doctypePubid = NULL;
+ parser->m_declAttributeType = NULL;
+ parser->m_declNotationName = NULL;
+ parser->m_declNotationPublicId = NULL;
+ parser->m_declAttributeIsCdata = XML_FALSE;
+ parser->m_declAttributeIsId = XML_FALSE;
+ memset(&parser->m_position, 0, sizeof(POSITION));
+ parser->m_errorCode = XML_ERROR_NONE;
+ parser->m_eventPtr = NULL;
+ parser->m_eventEndPtr = NULL;
+ parser->m_positionPtr = NULL;
+ parser->m_openInternalEntities = NULL;
+ parser->m_defaultExpandInternalEntities = XML_TRUE;
+ parser->m_tagLevel = 0;
+ parser->m_tagStack = NULL;
+ parser->m_inheritedBindings = NULL;
+ parser->m_nSpecifiedAtts = 0;
+ parser->m_unknownEncodingMem = NULL;
+ parser->m_unknownEncodingRelease = NULL;
+ parser->m_unknownEncodingData = NULL;
+ parser->m_parentParser = NULL;
+ parser->m_parsingStatus.parsing = XML_INITIALIZED;
#ifdef XML_DTD
- isParamEntity = XML_FALSE;
- useForeignDTD = XML_FALSE;
- paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
+ parser->m_isParamEntity = XML_FALSE;
+ parser->m_useForeignDTD = XML_FALSE;
+ parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
#endif
- hash_secret_salt = 0;
+ parser->m_hash_secret_salt = 0;
}
-/* moves list of bindings to freeBindingList */
+/* moves list of bindings to m_freeBindingList */
static void FASTCALL
moveToFreeBindingList(XML_Parser parser, BINDING *bindings)
{
while (bindings) {
BINDING *b = bindings;
bindings = bindings->nextTagBinding;
- b->nextTagBinding = freeBindingList;
- freeBindingList = b;
+ b->nextTagBinding = parser->m_freeBindingList;
+ parser->m_freeBindingList = b;
}
}
if (parser == NULL)
return XML_FALSE;
- if (parentParser)
+ if (parser->m_parentParser)
return XML_FALSE;
- /* move tagStack to freeTagList */
- tStk = tagStack;
+ /* move m_tagStack to m_freeTagList */
+ tStk = parser->m_tagStack;
while (tStk) {
TAG *tag = tStk;
tStk = tStk->parent;
- tag->parent = freeTagList;
+ tag->parent = parser->m_freeTagList;
moveToFreeBindingList(parser, tag->bindings);
tag->bindings = NULL;
- freeTagList = tag;
+ parser->m_freeTagList = tag;
}
- /* move openInternalEntities to freeInternalEntities */
- openEntityList = openInternalEntities;
+ /* move m_openInternalEntities to m_freeInternalEntities */
+ openEntityList = parser->m_openInternalEntities;
while (openEntityList) {
OPEN_INTERNAL_ENTITY *openEntity = openEntityList;
openEntityList = openEntity->next;
- openEntity->next = freeInternalEntities;
- freeInternalEntities = openEntity;
- }
- moveToFreeBindingList(parser, inheritedBindings);
- FREE(unknownEncodingMem);
- if (unknownEncodingRelease)
- unknownEncodingRelease(unknownEncodingData);
- poolClear(&tempPool);
- poolClear(&temp2Pool);
- FREE((void *)protocolEncodingName);
- protocolEncodingName = NULL;
+ openEntity->next = parser->m_freeInternalEntities;
+ parser->m_freeInternalEntities = openEntity;
+ }
+ moveToFreeBindingList(parser, parser->m_inheritedBindings);
+ FREE(parser, parser->m_unknownEncodingMem);
+ if (parser->m_unknownEncodingRelease)
+ parser->m_unknownEncodingRelease(parser->m_unknownEncodingData);
+ poolClear(&parser->m_tempPool);
+ poolClear(&parser->m_temp2Pool);
+ FREE(parser, (void *)parser->m_protocolEncodingName);
+ parser->m_protocolEncodingName = NULL;
parserInit(parser, encodingName);
- dtdReset(_dtd, &parser->m_mem);
+ dtdReset(parser->m_dtd, &parser->m_mem);
return XML_TRUE;
}
XXX There's no way for the caller to determine which of the
XXX possible error cases caused the XML_STATUS_ERROR return.
*/
- if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ if (parser->m_parsingStatus.parsing == XML_PARSING || parser->m_parsingStatus.parsing == XML_SUSPENDED)
return XML_STATUS_ERROR;
/* Get rid of any previous encoding name */
- FREE((void *)protocolEncodingName);
+ FREE(parser, (void *)parser->m_protocolEncodingName);
if (encodingName == NULL)
/* No new encoding name */
- protocolEncodingName = NULL;
+ parser->m_protocolEncodingName = NULL;
else {
/* Copy the new encoding name into allocated memory */
- protocolEncodingName = copyString(encodingName, &(parser->m_mem));
- if (!protocolEncodingName)
+ parser->m_protocolEncodingName = copyString(encodingName, &(parser->m_mem));
+ if (!parser->m_protocolEncodingName)
return XML_STATUS_ERROR;
}
return XML_STATUS_OK;
return NULL;
/* Stash the original parser contents on the stack */
- oldDtd = _dtd;
- oldStartElementHandler = startElementHandler;
- oldEndElementHandler = endElementHandler;
- oldCharacterDataHandler = characterDataHandler;
- oldProcessingInstructionHandler = processingInstructionHandler;
- oldCommentHandler = commentHandler;
- oldStartCdataSectionHandler = startCdataSectionHandler;
- oldEndCdataSectionHandler = endCdataSectionHandler;
- oldDefaultHandler = defaultHandler;
- oldUnparsedEntityDeclHandler = unparsedEntityDeclHandler;
- oldNotationDeclHandler = notationDeclHandler;
- oldStartNamespaceDeclHandler = startNamespaceDeclHandler;
- oldEndNamespaceDeclHandler = endNamespaceDeclHandler;
- oldNotStandaloneHandler = notStandaloneHandler;
- oldExternalEntityRefHandler = externalEntityRefHandler;
- oldSkippedEntityHandler = skippedEntityHandler;
- oldUnknownEncodingHandler = unknownEncodingHandler;
- oldElementDeclHandler = elementDeclHandler;
- oldAttlistDeclHandler = attlistDeclHandler;
- oldEntityDeclHandler = entityDeclHandler;
- oldXmlDeclHandler = xmlDeclHandler;
- oldDeclElementType = declElementType;
-
- oldUserData = userData;
- oldHandlerArg = handlerArg;
- oldDefaultExpandInternalEntities = defaultExpandInternalEntities;
- oldExternalEntityRefHandlerArg = externalEntityRefHandlerArg;
+ oldDtd = parser->m_dtd;
+ oldStartElementHandler = parser->m_startElementHandler;
+ oldEndElementHandler = parser->m_endElementHandler;
+ oldCharacterDataHandler = parser->m_characterDataHandler;
+ oldProcessingInstructionHandler = parser->m_processingInstructionHandler;
+ oldCommentHandler = parser->m_commentHandler;
+ oldStartCdataSectionHandler = parser->m_startCdataSectionHandler;
+ oldEndCdataSectionHandler = parser->m_endCdataSectionHandler;
+ oldDefaultHandler = parser->m_defaultHandler;
+ oldUnparsedEntityDeclHandler = parser->m_unparsedEntityDeclHandler;
+ oldNotationDeclHandler = parser->m_notationDeclHandler;
+ oldStartNamespaceDeclHandler = parser->m_startNamespaceDeclHandler;
+ oldEndNamespaceDeclHandler = parser->m_endNamespaceDeclHandler;
+ oldNotStandaloneHandler = parser->m_notStandaloneHandler;
+ oldExternalEntityRefHandler = parser->m_externalEntityRefHandler;
+ oldSkippedEntityHandler = parser->m_skippedEntityHandler;
+ oldUnknownEncodingHandler = parser->m_unknownEncodingHandler;
+ oldElementDeclHandler = parser->m_elementDeclHandler;
+ oldAttlistDeclHandler = parser->m_attlistDeclHandler;
+ oldEntityDeclHandler = parser->m_entityDeclHandler;
+ oldXmlDeclHandler = parser->m_xmlDeclHandler;
+ oldDeclElementType = parser->m_declElementType;
+
+ oldUserData = parser->m_userData;
+ oldHandlerArg = parser->m_handlerArg;
+ oldDefaultExpandInternalEntities = parser->m_defaultExpandInternalEntities;
+ oldExternalEntityRefHandlerArg = parser->m_externalEntityRefHandlerArg;
#ifdef XML_DTD
- oldParamEntityParsing = paramEntityParsing;
- oldInEntityValue = prologState.inEntityValue;
+ oldParamEntityParsing = parser->m_paramEntityParsing;
+ oldInEntityValue = parser->m_prologState.inEntityValue;
#endif
- oldns_triplets = ns_triplets;
+ oldns_triplets = parser->m_ns_triplets;
/* Note that the new parser shares the same hash secret as the old
parser, so that dtdCopy and copyEntityTable can lookup values
from hash tables associated with either parser without us having
to worry which hash secrets each table has.
*/
- oldhash_secret_salt = hash_secret_salt;
+ oldhash_secret_salt = parser->m_hash_secret_salt;
#ifdef XML_DTD
if (!context)
here. This makes this function more painful to follow than it
would be otherwise.
*/
- if (ns) {
+ if (parser->m_ns) {
XML_Char tmp[2];
- *tmp = namespaceSeparator;
+ *tmp = parser->m_namespaceSeparator;
parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd);
}
else {
if (!parser)
return NULL;
- startElementHandler = oldStartElementHandler;
- endElementHandler = oldEndElementHandler;
- characterDataHandler = oldCharacterDataHandler;
- processingInstructionHandler = oldProcessingInstructionHandler;
- commentHandler = oldCommentHandler;
- startCdataSectionHandler = oldStartCdataSectionHandler;
- endCdataSectionHandler = oldEndCdataSectionHandler;
- defaultHandler = oldDefaultHandler;
- unparsedEntityDeclHandler = oldUnparsedEntityDeclHandler;
- notationDeclHandler = oldNotationDeclHandler;
- startNamespaceDeclHandler = oldStartNamespaceDeclHandler;
- endNamespaceDeclHandler = oldEndNamespaceDeclHandler;
- notStandaloneHandler = oldNotStandaloneHandler;
- externalEntityRefHandler = oldExternalEntityRefHandler;
- skippedEntityHandler = oldSkippedEntityHandler;
- unknownEncodingHandler = oldUnknownEncodingHandler;
- elementDeclHandler = oldElementDeclHandler;
- attlistDeclHandler = oldAttlistDeclHandler;
- entityDeclHandler = oldEntityDeclHandler;
- xmlDeclHandler = oldXmlDeclHandler;
- declElementType = oldDeclElementType;
- userData = oldUserData;
+ parser->m_startElementHandler = oldStartElementHandler;
+ parser->m_endElementHandler = oldEndElementHandler;
+ parser->m_characterDataHandler = oldCharacterDataHandler;
+ parser->m_processingInstructionHandler = oldProcessingInstructionHandler;
+ parser->m_commentHandler = oldCommentHandler;
+ parser->m_startCdataSectionHandler = oldStartCdataSectionHandler;
+ parser->m_endCdataSectionHandler = oldEndCdataSectionHandler;
+ parser->m_defaultHandler = oldDefaultHandler;
+ parser->m_unparsedEntityDeclHandler = oldUnparsedEntityDeclHandler;
+ parser->m_notationDeclHandler = oldNotationDeclHandler;
+ parser->m_startNamespaceDeclHandler = oldStartNamespaceDeclHandler;
+ parser->m_endNamespaceDeclHandler = oldEndNamespaceDeclHandler;
+ parser->m_notStandaloneHandler = oldNotStandaloneHandler;
+ parser->m_externalEntityRefHandler = oldExternalEntityRefHandler;
+ parser->m_skippedEntityHandler = oldSkippedEntityHandler;
+ parser->m_unknownEncodingHandler = oldUnknownEncodingHandler;
+ parser->m_elementDeclHandler = oldElementDeclHandler;
+ parser->m_attlistDeclHandler = oldAttlistDeclHandler;
+ parser->m_entityDeclHandler = oldEntityDeclHandler;
+ parser->m_xmlDeclHandler = oldXmlDeclHandler;
+ parser->m_declElementType = oldDeclElementType;
+ parser->m_userData = oldUserData;
if (oldUserData == oldHandlerArg)
- handlerArg = userData;
+ parser->m_handlerArg = parser->m_userData;
else
- handlerArg = parser;
+ parser->m_handlerArg = parser;
if (oldExternalEntityRefHandlerArg != oldParser)
- externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg;
- defaultExpandInternalEntities = oldDefaultExpandInternalEntities;
- ns_triplets = oldns_triplets;
- hash_secret_salt = oldhash_secret_salt;
- parentParser = oldParser;
+ parser->m_externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg;
+ parser->m_defaultExpandInternalEntities = oldDefaultExpandInternalEntities;
+ parser->m_ns_triplets = oldns_triplets;
+ parser->m_hash_secret_salt = oldhash_secret_salt;
+ parser->m_parentParser = oldParser;
#ifdef XML_DTD
- paramEntityParsing = oldParamEntityParsing;
- prologState.inEntityValue = oldInEntityValue;
+ parser->m_paramEntityParsing = oldParamEntityParsing;
+ parser->m_prologState.inEntityValue = oldInEntityValue;
if (context) {
#endif /* XML_DTD */
- if (!dtdCopy(oldParser, _dtd, oldDtd, &parser->m_mem)
+ if (!dtdCopy(oldParser, parser->m_dtd, oldDtd, &parser->m_mem)
|| !setContext(parser, context)) {
XML_ParserFree(parser);
return NULL;
}
- processor = externalEntityInitProcessor;
+ parser->m_processor = externalEntityInitProcessor;
#ifdef XML_DTD
}
else {
- /* The DTD instance referenced by _dtd is shared between the document's
+ /* The DTD instance referenced by parser->m_dtd is shared between the document's
root parser and external PE parsers, therefore one does not need to
call setContext. In addition, one also *must* not call setContext,
because this would overwrite existing prefix->binding pointers in
- _dtd with ones that get destroyed with the external PE parser.
+ parser->m_dtd with ones that get destroyed with the external PE parser.
This would leave those prefixes with dangling pointers.
*/
- isParamEntity = XML_TRUE;
- XmlPrologStateInitExternalEntity(&prologState);
- processor = externalParEntInitProcessor;
+ parser->m_isParamEntity = XML_TRUE;
+ XmlPrologStateInitExternalEntity(&parser->m_prologState);
+ parser->m_processor = externalParEntInitProcessor;
}
#endif /* XML_DTD */
return parser;
if (!b)
break;
bindings = b->nextTagBinding;
- FREE(b->uri);
- FREE(b);
+ FREE(parser, b->uri);
+ FREE(parser, b);
}
}
OPEN_INTERNAL_ENTITY *entityList;
if (parser == NULL)
return;
- /* free tagStack and freeTagList */
- tagList = tagStack;
+ /* free m_tagStack and m_freeTagList */
+ tagList = parser->m_tagStack;
for (;;) {
TAG *p;
if (tagList == NULL) {
- if (freeTagList == NULL)
+ if (parser->m_freeTagList == NULL)
break;
- tagList = freeTagList;
- freeTagList = NULL;
+ tagList = parser->m_freeTagList;
+ parser->m_freeTagList = NULL;
}
p = tagList;
tagList = tagList->parent;
- FREE(p->buf);
+ FREE(parser, p->buf);
destroyBindings(p->bindings, parser);
- FREE(p);
+ FREE(parser, p);
}
- /* free openInternalEntities and freeInternalEntities */
- entityList = openInternalEntities;
+ /* free m_openInternalEntities and m_freeInternalEntities */
+ entityList = parser->m_openInternalEntities;
for (;;) {
OPEN_INTERNAL_ENTITY *openEntity;
if (entityList == NULL) {
- if (freeInternalEntities == NULL)
+ if (parser->m_freeInternalEntities == NULL)
break;
- entityList = freeInternalEntities;
- freeInternalEntities = NULL;
+ entityList = parser->m_freeInternalEntities;
+ parser->m_freeInternalEntities = NULL;
}
openEntity = entityList;
entityList = entityList->next;
- FREE(openEntity);
+ FREE(parser, openEntity);
}
- destroyBindings(freeBindingList, parser);
- destroyBindings(inheritedBindings, parser);
- poolDestroy(&tempPool);
- poolDestroy(&temp2Pool);
- FREE((void *)protocolEncodingName);
+ destroyBindings(parser->m_freeBindingList, parser);
+ destroyBindings(parser->m_inheritedBindings, parser);
+ poolDestroy(&parser->m_tempPool);
+ poolDestroy(&parser->m_temp2Pool);
+ FREE(parser, (void *)parser->m_protocolEncodingName);
#ifdef XML_DTD
/* external parameter entity parsers share the DTD structure
parser->m_dtd with the root parser, so we must not destroy it
*/
- if (!isParamEntity && _dtd)
+ if (!parser->m_isParamEntity && parser->m_dtd)
#else
- if (_dtd)
+ if (parser->m_dtd)
#endif /* XML_DTD */
- dtdDestroy(_dtd, (XML_Bool)!parentParser, &parser->m_mem);
- FREE((void *)atts);
+ dtdDestroy(parser->m_dtd, (XML_Bool)!parser->m_parentParser, &parser->m_mem);
+ FREE(parser, (void *)parser->m_atts);
#ifdef XML_ATTR_INFO
- FREE((void *)attInfo);
+ FREE(parser, (void *)parser->m_attInfo);
#endif
- FREE(groupConnector);
- FREE(buffer);
- FREE(dataBuf);
- FREE(nsAtts);
- FREE(unknownEncodingMem);
- if (unknownEncodingRelease)
- unknownEncodingRelease(unknownEncodingData);
- FREE(parser);
+ FREE(parser, parser->m_groupConnector);
+ FREE(parser, parser->m_buffer);
+ FREE(parser, parser->m_dataBuf);
+ FREE(parser, parser->m_nsAtts);
+ FREE(parser, parser->m_unknownEncodingMem);
+ if (parser->m_unknownEncodingRelease)
+ parser->m_unknownEncodingRelease(parser->m_unknownEncodingData);
+ FREE(parser, parser);
}
void XMLCALL
XML_UseParserAsHandlerArg(XML_Parser parser)
{
if (parser != NULL)
- handlerArg = parser;
+ parser->m_handlerArg = parser;
}
enum XML_Error XMLCALL
return XML_ERROR_INVALID_ARGUMENT;
#ifdef XML_DTD
/* block after XML_Parse()/XML_ParseBuffer() has been called */
- if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ if (parser->m_parsingStatus.parsing == XML_PARSING || parser->m_parsingStatus.parsing == XML_SUSPENDED)
return XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING;
- useForeignDTD = useDTD;
+ parser->m_useForeignDTD = useDTD;
return XML_ERROR_NONE;
#else
return XML_ERROR_FEATURE_REQUIRES_XML_DTD;
if (parser == NULL)
return;
/* block after XML_Parse()/XML_ParseBuffer() has been called */
- if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ if (parser->m_parsingStatus.parsing == XML_PARSING || parser->m_parsingStatus.parsing == XML_SUSPENDED)
return;
- ns_triplets = do_nst ? XML_TRUE : XML_FALSE;
+ parser->m_ns_triplets = do_nst ? XML_TRUE : XML_FALSE;
}
void XMLCALL
{
if (parser == NULL)
return;
- if (handlerArg == userData)
- handlerArg = userData = p;
+ if (parser->m_handlerArg == parser->m_userData)
+ parser->m_handlerArg = parser->m_userData = p;
else
- userData = p;
+ parser->m_userData = p;
}
enum XML_Status XMLCALL
if (parser == NULL)
return XML_STATUS_ERROR;
if (p) {
- p = poolCopyString(&_dtd->pool, p);
+ p = poolCopyString(&parser->m_dtd->pool, p);
if (!p)
return XML_STATUS_ERROR;
- curBase = p;
+ parser->m_curBase = p;
}
else
- curBase = NULL;
+ parser->m_curBase = NULL;
return XML_STATUS_OK;
}
{
if (parser == NULL)
return NULL;
- return curBase;
+ return parser->m_curBase;
}
int XMLCALL
{
if (parser == NULL)
return -1;
- return nSpecifiedAtts;
+ return parser->m_nSpecifiedAtts;
}
int XMLCALL
{
if (parser == NULL)
return -1;
- return idAttIndex;
+ return parser->m_idAttIndex;
}
#ifdef XML_ATTR_INFO
{
if (parser == NULL)
return NULL;
- return attInfo;
+ return parser->m_attInfo;
}
#endif
{
if (parser == NULL)
return;
- startElementHandler = start;
- endElementHandler = end;
+ parser->m_startElementHandler = start;
+ parser->m_endElementHandler = end;
}
void XMLCALL
XML_SetStartElementHandler(XML_Parser parser,
XML_StartElementHandler start) {
if (parser != NULL)
- startElementHandler = start;
+ parser->m_startElementHandler = start;
}
void XMLCALL
XML_SetEndElementHandler(XML_Parser parser,
XML_EndElementHandler end) {
if (parser != NULL)
- endElementHandler = end;
+ parser->m_endElementHandler = end;
}
void XMLCALL
XML_CharacterDataHandler handler)
{
if (parser != NULL)
- characterDataHandler = handler;
+ parser->m_characterDataHandler = handler;
}
void XMLCALL
XML_ProcessingInstructionHandler handler)
{
if (parser != NULL)
- processingInstructionHandler = handler;
+ parser->m_processingInstructionHandler = handler;
}
void XMLCALL
XML_CommentHandler handler)
{
if (parser != NULL)
- commentHandler = handler;
+ parser->m_commentHandler = handler;
}
void XMLCALL
{
if (parser == NULL)
return;
- startCdataSectionHandler = start;
- endCdataSectionHandler = end;
+ parser->m_startCdataSectionHandler = start;
+ parser->m_endCdataSectionHandler = end;
}
void XMLCALL
XML_SetStartCdataSectionHandler(XML_Parser parser,
XML_StartCdataSectionHandler start) {
if (parser != NULL)
- startCdataSectionHandler = start;
+ parser->m_startCdataSectionHandler = start;
}
void XMLCALL
XML_SetEndCdataSectionHandler(XML_Parser parser,
XML_EndCdataSectionHandler end) {
if (parser != NULL)
- endCdataSectionHandler = end;
+ parser->m_endCdataSectionHandler = end;
}
void XMLCALL
{
if (parser == NULL)
return;
- defaultHandler = handler;
- defaultExpandInternalEntities = XML_FALSE;
+ parser->m_defaultHandler = handler;
+ parser->m_defaultExpandInternalEntities = XML_FALSE;
}
void XMLCALL
{
if (parser == NULL)
return;
- defaultHandler = handler;
- defaultExpandInternalEntities = XML_TRUE;
+ parser->m_defaultHandler = handler;
+ parser->m_defaultExpandInternalEntities = XML_TRUE;
}
void XMLCALL
{
if (parser == NULL)
return;
- startDoctypeDeclHandler = start;
- endDoctypeDeclHandler = end;
+ parser->m_startDoctypeDeclHandler = start;
+ parser->m_endDoctypeDeclHandler = end;
}
void XMLCALL
XML_SetStartDoctypeDeclHandler(XML_Parser parser,
XML_StartDoctypeDeclHandler start) {
if (parser != NULL)
- startDoctypeDeclHandler = start;
+ parser->m_startDoctypeDeclHandler = start;
}
void XMLCALL
XML_SetEndDoctypeDeclHandler(XML_Parser parser,
XML_EndDoctypeDeclHandler end) {
if (parser != NULL)
- endDoctypeDeclHandler = end;
+ parser->m_endDoctypeDeclHandler = end;
}
void XMLCALL
XML_UnparsedEntityDeclHandler handler)
{
if (parser != NULL)
- unparsedEntityDeclHandler = handler;
+ parser->m_unparsedEntityDeclHandler = handler;
}
void XMLCALL
XML_NotationDeclHandler handler)
{
if (parser != NULL)
- notationDeclHandler = handler;
+ parser->m_notationDeclHandler = handler;
}
void XMLCALL
{
if (parser == NULL)
return;
- startNamespaceDeclHandler = start;
- endNamespaceDeclHandler = end;
+ parser->m_startNamespaceDeclHandler = start;
+ parser->m_endNamespaceDeclHandler = end;
}
void XMLCALL
XML_SetStartNamespaceDeclHandler(XML_Parser parser,
XML_StartNamespaceDeclHandler start) {
if (parser != NULL)
- startNamespaceDeclHandler = start;
+ parser->m_startNamespaceDeclHandler = start;
}
void XMLCALL
XML_SetEndNamespaceDeclHandler(XML_Parser parser,
XML_EndNamespaceDeclHandler end) {
if (parser != NULL)
- endNamespaceDeclHandler = end;
+ parser->m_endNamespaceDeclHandler = end;
}
void XMLCALL
XML_NotStandaloneHandler handler)
{
if (parser != NULL)
- notStandaloneHandler = handler;
+ parser->m_notStandaloneHandler = handler;
}
void XMLCALL
XML_ExternalEntityRefHandler handler)
{
if (parser != NULL)
- externalEntityRefHandler = handler;
+ parser->m_externalEntityRefHandler = handler;
}
void XMLCALL
if (parser == NULL)
return;
if (arg)
- externalEntityRefHandlerArg = (XML_Parser)arg;
+ parser->m_externalEntityRefHandlerArg = (XML_Parser)arg;
else
- externalEntityRefHandlerArg = parser;
+ parser->m_externalEntityRefHandlerArg = parser;
}
void XMLCALL
XML_SkippedEntityHandler handler)
{
if (parser != NULL)
- skippedEntityHandler = handler;
+ parser->m_skippedEntityHandler = handler;
}
void XMLCALL
{
if (parser == NULL)
return;
- unknownEncodingHandler = handler;
- unknownEncodingHandlerData = data;
+ parser->m_unknownEncodingHandler = handler;
+ parser->m_unknownEncodingHandlerData = data;
}
void XMLCALL
XML_ElementDeclHandler eldecl)
{
if (parser != NULL)
- elementDeclHandler = eldecl;
+ parser->m_elementDeclHandler = eldecl;
}
void XMLCALL
XML_AttlistDeclHandler attdecl)
{
if (parser != NULL)
- attlistDeclHandler = attdecl;
+ parser->m_attlistDeclHandler = attdecl;
}
void XMLCALL
XML_EntityDeclHandler handler)
{
if (parser != NULL)
- entityDeclHandler = handler;
+ parser->m_entityDeclHandler = handler;
}
void XMLCALL
XML_SetXmlDeclHandler(XML_Parser parser,
XML_XmlDeclHandler handler) {
if (parser != NULL)
- xmlDeclHandler = handler;
+ parser->m_xmlDeclHandler = handler;
}
int XMLCALL
if (parser == NULL)
return 0;
/* block after XML_Parse()/XML_ParseBuffer() has been called */
- if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ if (parser->m_parsingStatus.parsing == XML_PARSING || parser->m_parsingStatus.parsing == XML_SUSPENDED)
return 0;
#ifdef XML_DTD
- paramEntityParsing = peParsing;
+ parser->m_paramEntityParsing = peParsing;
return 1;
#else
return peParsing == XML_PARAM_ENTITY_PARSING_NEVER;
if (parser->m_parentParser)
return XML_SetHashSalt(parser->m_parentParser, hash_salt);
/* block after XML_Parse()/XML_ParseBuffer() has been called */
- if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ if (parser->m_parsingStatus.parsing == XML_PARSING || parser->m_parsingStatus.parsing == XML_SUSPENDED)
return 0;
- hash_secret_salt = hash_salt;
+ parser->m_hash_secret_salt = hash_salt;
return 1;
}
parser->m_errorCode = XML_ERROR_INVALID_ARGUMENT;
return XML_STATUS_ERROR;
}
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
- errorCode = XML_ERROR_SUSPENDED;
+ parser->m_errorCode = XML_ERROR_SUSPENDED;
return XML_STATUS_ERROR;
case XML_FINISHED:
- errorCode = XML_ERROR_FINISHED;
+ parser->m_errorCode = XML_ERROR_FINISHED;
return XML_STATUS_ERROR;
case XML_INITIALIZED:
- if (parentParser == NULL && !startParsing(parser)) {
- errorCode = XML_ERROR_NO_MEMORY;
+ if (parser->m_parentParser == NULL && !startParsing(parser)) {
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
return XML_STATUS_ERROR;
}
+ /* fall through */
default:
- ps_parsing = XML_PARSING;
+ parser->m_parsingStatus.parsing = XML_PARSING;
}
if (len == 0) {
- ps_finalBuffer = (XML_Bool)isFinal;
+ parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal;
if (!isFinal)
return XML_STATUS_OK;
- positionPtr = bufferPtr;
- parseEndPtr = bufferEnd;
+ parser->m_positionPtr = parser->m_bufferPtr;
+ parser->m_parseEndPtr = parser->m_bufferEnd;
/* If data are left over from last buffer, and we now know that these
data are the final chunk of input, then we have to check them again
to detect errors based on that fact.
*/
- errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr);
+ parser->m_errorCode = parser->m_processor(parser, parser->m_bufferPtr, parser->m_parseEndPtr, &parser->m_bufferPtr);
- if (errorCode == XML_ERROR_NONE) {
- switch (ps_parsing) {
+ if (parser->m_errorCode == XML_ERROR_NONE) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
/* It is hard to be certain, but it seems that this case
* cannot occur. This code is cleaning up a previous parse
*
* LCOV_EXCL_START
*/
- XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
- positionPtr = bufferPtr;
+ XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr, parser->m_bufferPtr, &parser->m_position);
+ parser->m_positionPtr = parser->m_bufferPtr;
return XML_STATUS_SUSPENDED;
/* LCOV_EXCL_STOP */
case XML_INITIALIZED:
case XML_PARSING:
- ps_parsing = XML_FINISHED;
+ parser->m_parsingStatus.parsing = XML_FINISHED;
/* fall through */
default:
return XML_STATUS_OK;
}
}
- eventEndPtr = eventPtr;
- processor = errorProcessor;
+ parser->m_eventEndPtr = parser->m_eventPtr;
+ parser->m_processor = errorProcessor;
return XML_STATUS_ERROR;
}
#ifndef XML_CONTEXT_BYTES
- else if (bufferPtr == bufferEnd) {
+ else if (parser->m_bufferPtr == parser->m_bufferEnd) {
const char *end;
int nLeftOver;
enum XML_Status result;
/* Detect overflow (a+b > MAX <==> b > MAX-a) */
- if (len > ((XML_Size)-1) / 2 - parseEndByteIndex) {
- errorCode = XML_ERROR_NO_MEMORY;
- eventPtr = eventEndPtr = NULL;
- processor = errorProcessor;
+ if (len > ((XML_Size)-1) / 2 - parser->m_parseEndByteIndex) {
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
+ parser->m_eventPtr = parser->m_eventEndPtr = NULL;
+ parser->m_processor = errorProcessor;
return XML_STATUS_ERROR;
}
- parseEndByteIndex += len;
- positionPtr = s;
- ps_finalBuffer = (XML_Bool)isFinal;
+ parser->m_parseEndByteIndex += len;
+ parser->m_positionPtr = s;
+ parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal;
- errorCode = processor(parser, s, parseEndPtr = s + len, &end);
+ parser->m_errorCode = parser->m_processor(parser, s, parser->m_parseEndPtr = s + len, &end);
- if (errorCode != XML_ERROR_NONE) {
- eventEndPtr = eventPtr;
- processor = errorProcessor;
+ if (parser->m_errorCode != XML_ERROR_NONE) {
+ parser->m_eventEndPtr = parser->m_eventPtr;
+ parser->m_processor = errorProcessor;
return XML_STATUS_ERROR;
}
else {
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
result = XML_STATUS_SUSPENDED;
break;
case XML_INITIALIZED:
case XML_PARSING:
if (isFinal) {
- ps_parsing = XML_FINISHED;
+ parser->m_parsingStatus.parsing = XML_FINISHED;
return XML_STATUS_OK;
}
/* fall through */
}
}
- XmlUpdatePosition(encoding, positionPtr, end, &position);
+ XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr, end, &parser->m_position);
nLeftOver = s + len - end;
if (nLeftOver) {
- if (buffer == NULL || nLeftOver > bufferLim - buffer) {
+ if (parser->m_buffer == NULL || nLeftOver > parser->m_bufferLim - parser->m_buffer) {
/* avoid _signed_ integer overflow */
char *temp = NULL;
const int bytesToAllocate = (int)((unsigned)len * 2U);
if (bytesToAllocate > 0) {
- temp = (buffer == NULL
- ? (char *)MALLOC(bytesToAllocate)
- : (char *)REALLOC(buffer, bytesToAllocate));
+ temp = (char *)REALLOC(parser, parser->m_buffer, bytesToAllocate);
}
if (temp == NULL) {
- errorCode = XML_ERROR_NO_MEMORY;
- eventPtr = eventEndPtr = NULL;
- processor = errorProcessor;
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
+ parser->m_eventPtr = parser->m_eventEndPtr = NULL;
+ parser->m_processor = errorProcessor;
return XML_STATUS_ERROR;
}
- buffer = temp;
- bufferLim = buffer + bytesToAllocate;
+ parser->m_buffer = temp;
+ parser->m_bufferLim = parser->m_buffer + bytesToAllocate;
}
- memcpy(buffer, end, nLeftOver);
+ memcpy(parser->m_buffer, end, nLeftOver);
}
- bufferPtr = buffer;
- bufferEnd = buffer + nLeftOver;
- positionPtr = bufferPtr;
- parseEndPtr = bufferEnd;
- eventPtr = bufferPtr;
- eventEndPtr = bufferPtr;
+ parser->m_bufferPtr = parser->m_buffer;
+ parser->m_bufferEnd = parser->m_buffer + nLeftOver;
+ parser->m_positionPtr = parser->m_bufferPtr;
+ parser->m_parseEndPtr = parser->m_bufferEnd;
+ parser->m_eventPtr = parser->m_bufferPtr;
+ parser->m_eventEndPtr = parser->m_bufferPtr;
return result;
}
#endif /* not defined XML_CONTEXT_BYTES */
if (parser == NULL)
return XML_STATUS_ERROR;
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
- errorCode = XML_ERROR_SUSPENDED;
+ parser->m_errorCode = XML_ERROR_SUSPENDED;
return XML_STATUS_ERROR;
case XML_FINISHED:
- errorCode = XML_ERROR_FINISHED;
+ parser->m_errorCode = XML_ERROR_FINISHED;
return XML_STATUS_ERROR;
case XML_INITIALIZED:
- if (parentParser == NULL && !startParsing(parser)) {
- errorCode = XML_ERROR_NO_MEMORY;
+ if (parser->m_parentParser == NULL && !startParsing(parser)) {
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
return XML_STATUS_ERROR;
}
+ /* fall through */
default:
- ps_parsing = XML_PARSING;
+ parser->m_parsingStatus.parsing = XML_PARSING;
}
- start = bufferPtr;
- positionPtr = start;
- bufferEnd += len;
- parseEndPtr = bufferEnd;
- parseEndByteIndex += len;
- ps_finalBuffer = (XML_Bool)isFinal;
+ start = parser->m_bufferPtr;
+ parser->m_positionPtr = start;
+ parser->m_bufferEnd += len;
+ parser->m_parseEndPtr = parser->m_bufferEnd;
+ parser->m_parseEndByteIndex += len;
+ parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal;
- errorCode = processor(parser, start, parseEndPtr, &bufferPtr);
+ parser->m_errorCode = parser->m_processor(parser, start, parser->m_parseEndPtr, &parser->m_bufferPtr);
- if (errorCode != XML_ERROR_NONE) {
- eventEndPtr = eventPtr;
- processor = errorProcessor;
+ if (parser->m_errorCode != XML_ERROR_NONE) {
+ parser->m_eventEndPtr = parser->m_eventPtr;
+ parser->m_processor = errorProcessor;
return XML_STATUS_ERROR;
}
else {
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
result = XML_STATUS_SUSPENDED;
break;
case XML_INITIALIZED:
case XML_PARSING:
if (isFinal) {
- ps_parsing = XML_FINISHED;
+ parser->m_parsingStatus.parsing = XML_FINISHED;
return result;
}
default: ; /* should not happen */
}
}
- XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
- positionPtr = bufferPtr;
+ XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr, parser->m_bufferPtr, &parser->m_position);
+ parser->m_positionPtr = parser->m_bufferPtr;
return result;
}
if (parser == NULL)
return NULL;
if (len < 0) {
- errorCode = XML_ERROR_NO_MEMORY;
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
return NULL;
}
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
- errorCode = XML_ERROR_SUSPENDED;
+ parser->m_errorCode = XML_ERROR_SUSPENDED;
return NULL;
case XML_FINISHED:
- errorCode = XML_ERROR_FINISHED;
+ parser->m_errorCode = XML_ERROR_FINISHED;
return NULL;
default: ;
}
- if (len > bufferLim - bufferEnd) {
+ if (len > EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferEnd)) {
#ifdef XML_CONTEXT_BYTES
int keep;
#endif /* defined XML_CONTEXT_BYTES */
/* Do not invoke signed arithmetic overflow: */
- int neededSize = (int) ((unsigned)len + (unsigned)(bufferEnd - bufferPtr));
+ int neededSize = (int) ((unsigned)len +
+ (unsigned)EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd,
+ parser->m_bufferPtr));
if (neededSize < 0) {
- errorCode = XML_ERROR_NO_MEMORY;
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
return NULL;
}
#ifdef XML_CONTEXT_BYTES
- keep = (int)(bufferPtr - buffer);
+ keep = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer);
if (keep > XML_CONTEXT_BYTES)
keep = XML_CONTEXT_BYTES;
neededSize += keep;
#endif /* defined XML_CONTEXT_BYTES */
- if (neededSize <= bufferLim - buffer) {
+ if (neededSize <= EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_buffer)) {
#ifdef XML_CONTEXT_BYTES
- if (keep < bufferPtr - buffer) {
- int offset = (int)(bufferPtr - buffer) - keep;
- memmove(buffer, &buffer[offset], bufferEnd - bufferPtr + keep);
- bufferEnd -= offset;
- bufferPtr -= offset;
+ if (keep < EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer)) {
+ int offset = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer) - keep;
+ /* The buffer pointers cannot be NULL here; we have at least some bytes in the buffer */
+ memmove(parser->m_buffer, &parser->m_buffer[offset], parser->m_bufferEnd - parser->m_bufferPtr + keep);
+ parser->m_bufferEnd -= offset;
+ parser->m_bufferPtr -= offset;
}
#else
- memmove(buffer, bufferPtr, bufferEnd - bufferPtr);
- bufferEnd = buffer + (bufferEnd - bufferPtr);
- bufferPtr = buffer;
+ if (parser->m_buffer && parser->m_bufferPtr) {
+ memmove(parser->m_buffer, parser->m_bufferPtr,
+ EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr));
+ parser->m_bufferEnd = parser->m_buffer +
+ EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr);
+ parser->m_bufferPtr = parser->m_buffer;
+ }
#endif /* not defined XML_CONTEXT_BYTES */
}
else {
char *newBuf;
- int bufferSize = (int)(bufferLim - bufferPtr);
+ int bufferSize = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferPtr);
if (bufferSize == 0)
bufferSize = INIT_BUFFER_SIZE;
do {
bufferSize = (int) (2U * (unsigned) bufferSize);
} while (bufferSize < neededSize && bufferSize > 0);
if (bufferSize <= 0) {
- errorCode = XML_ERROR_NO_MEMORY;
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
return NULL;
}
- newBuf = (char *)MALLOC(bufferSize);
+ newBuf = (char *)MALLOC(parser, bufferSize);
if (newBuf == 0) {
- errorCode = XML_ERROR_NO_MEMORY;
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
return NULL;
}
- bufferLim = newBuf + bufferSize;
+ parser->m_bufferLim = newBuf + bufferSize;
#ifdef XML_CONTEXT_BYTES
- if (bufferPtr) {
- int keep = (int)(bufferPtr - buffer);
+ if (parser->m_bufferPtr) {
+ int keep = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer);
if (keep > XML_CONTEXT_BYTES)
keep = XML_CONTEXT_BYTES;
- memcpy(newBuf, &bufferPtr[-keep], bufferEnd - bufferPtr + keep);
- FREE(buffer);
- buffer = newBuf;
- bufferEnd = buffer + (bufferEnd - bufferPtr) + keep;
- bufferPtr = buffer + keep;
+ memcpy(newBuf, &parser->m_bufferPtr[-keep],
+ EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr) + keep);
+ FREE(parser, parser->m_buffer);
+ parser->m_buffer = newBuf;
+ parser->m_bufferEnd = parser->m_buffer +
+ EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr) + keep;
+ parser->m_bufferPtr = parser->m_buffer + keep;
}
else {
- bufferEnd = newBuf + (bufferEnd - bufferPtr);
- bufferPtr = buffer = newBuf;
+ /* This must be a brand new buffer with no data in it yet */
+ parser->m_bufferEnd = newBuf;
+ parser->m_bufferPtr = parser->m_buffer = newBuf;
}
#else
- if (bufferPtr) {
- memcpy(newBuf, bufferPtr, bufferEnd - bufferPtr);
- FREE(buffer);
+ if (parser->m_bufferPtr) {
+ memcpy(newBuf, parser->m_bufferPtr,
+ EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr));
+ FREE(parser, parser->m_buffer);
+ parser->m_bufferEnd = newBuf +
+ EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr);
+ }
+ else {
+ /* This must be a brand new buffer with no data in it yet */
+ parser->m_bufferEnd = newBuf;
}
- bufferEnd = newBuf + (bufferEnd - bufferPtr);
- bufferPtr = buffer = newBuf;
+ parser->m_bufferPtr = parser->m_buffer = newBuf;
#endif /* not defined XML_CONTEXT_BYTES */
}
- eventPtr = eventEndPtr = NULL;
- positionPtr = NULL;
+ parser->m_eventPtr = parser->m_eventEndPtr = NULL;
+ parser->m_positionPtr = NULL;
}
- return bufferEnd;
+ return parser->m_bufferEnd;
}
enum XML_Status XMLCALL
{
if (parser == NULL)
return XML_STATUS_ERROR;
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
if (resumable) {
- errorCode = XML_ERROR_SUSPENDED;
+ parser->m_errorCode = XML_ERROR_SUSPENDED;
return XML_STATUS_ERROR;
}
- ps_parsing = XML_FINISHED;
+ parser->m_parsingStatus.parsing = XML_FINISHED;
break;
case XML_FINISHED:
- errorCode = XML_ERROR_FINISHED;
+ parser->m_errorCode = XML_ERROR_FINISHED;
return XML_STATUS_ERROR;
default:
if (resumable) {
#ifdef XML_DTD
- if (isParamEntity) {
- errorCode = XML_ERROR_SUSPEND_PE;
+ if (parser->m_isParamEntity) {
+ parser->m_errorCode = XML_ERROR_SUSPEND_PE;
return XML_STATUS_ERROR;
}
#endif
- ps_parsing = XML_SUSPENDED;
+ parser->m_parsingStatus.parsing = XML_SUSPENDED;
}
else
- ps_parsing = XML_FINISHED;
+ parser->m_parsingStatus.parsing = XML_FINISHED;
}
return XML_STATUS_OK;
}
if (parser == NULL)
return XML_STATUS_ERROR;
- if (ps_parsing != XML_SUSPENDED) {
- errorCode = XML_ERROR_NOT_SUSPENDED;
+ if (parser->m_parsingStatus.parsing != XML_SUSPENDED) {
+ parser->m_errorCode = XML_ERROR_NOT_SUSPENDED;
return XML_STATUS_ERROR;
}
- ps_parsing = XML_PARSING;
+ parser->m_parsingStatus.parsing = XML_PARSING;
- errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr);
+ parser->m_errorCode = parser->m_processor(parser, parser->m_bufferPtr, parser->m_parseEndPtr, &parser->m_bufferPtr);
- if (errorCode != XML_ERROR_NONE) {
- eventEndPtr = eventPtr;
- processor = errorProcessor;
+ if (parser->m_errorCode != XML_ERROR_NONE) {
+ parser->m_eventEndPtr = parser->m_eventPtr;
+ parser->m_processor = errorProcessor;
return XML_STATUS_ERROR;
}
else {
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
result = XML_STATUS_SUSPENDED;
break;
case XML_INITIALIZED:
case XML_PARSING:
- if (ps_finalBuffer) {
- ps_parsing = XML_FINISHED;
+ if (parser->m_parsingStatus.finalBuffer) {
+ parser->m_parsingStatus.parsing = XML_FINISHED;
return result;
}
default: ;
}
}
- XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
- positionPtr = bufferPtr;
+ XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr, parser->m_bufferPtr, &parser->m_position);
+ parser->m_positionPtr = parser->m_bufferPtr;
return result;
}
{
if (parser == NULL)
return XML_ERROR_INVALID_ARGUMENT;
- return errorCode;
+ return parser->m_errorCode;
}
XML_Index XMLCALL
{
if (parser == NULL)
return -1;
- if (eventPtr)
- return (XML_Index)(parseEndByteIndex - (parseEndPtr - eventPtr));
+ if (parser->m_eventPtr)
+ return (XML_Index)(parser->m_parseEndByteIndex - (parser->m_parseEndPtr - parser->m_eventPtr));
return -1;
}
{
if (parser == NULL)
return 0;
- if (eventEndPtr && eventPtr)
- return (int)(eventEndPtr - eventPtr);
+ if (parser->m_eventEndPtr && parser->m_eventPtr)
+ return (int)(parser->m_eventEndPtr - parser->m_eventPtr);
return 0;
}
#ifdef XML_CONTEXT_BYTES
if (parser == NULL)
return NULL;
- if (eventPtr && buffer) {
+ if (parser->m_eventPtr && parser->m_buffer) {
if (offset != NULL)
- *offset = (int)(eventPtr - buffer);
+ *offset = (int)(parser->m_eventPtr - parser->m_buffer);
if (size != NULL)
- *size = (int)(bufferEnd - buffer);
- return buffer;
+ *size = (int)(parser->m_bufferEnd - parser->m_buffer);
+ return parser->m_buffer;
}
#else
(void)parser;
{
if (parser == NULL)
return 0;
- if (eventPtr && eventPtr >= positionPtr) {
- XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
- positionPtr = eventPtr;
+ if (parser->m_eventPtr && parser->m_eventPtr >= parser->m_positionPtr) {
+ XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr, parser->m_eventPtr, &parser->m_position);
+ parser->m_positionPtr = parser->m_eventPtr;
}
- return position.lineNumber + 1;
+ return parser->m_position.lineNumber + 1;
}
XML_Size XMLCALL
{
if (parser == NULL)
return 0;
- if (eventPtr && eventPtr >= positionPtr) {
- XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
- positionPtr = eventPtr;
+ if (parser->m_eventPtr && parser->m_eventPtr >= parser->m_positionPtr) {
+ XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr, parser->m_eventPtr, &parser->m_position);
+ parser->m_positionPtr = parser->m_eventPtr;
}
- return position.columnNumber;
+ return parser->m_position.columnNumber;
}
void XMLCALL
XML_FreeContentModel(XML_Parser parser, XML_Content *model)
{
if (parser != NULL)
- FREE(model);
+ FREE(parser, model);
}
void * XMLCALL
{
if (parser == NULL)
return NULL;
- return MALLOC(size);
+ return MALLOC(parser, size);
}
void * XMLCALL
{
if (parser == NULL)
return NULL;
- return REALLOC(ptr, size);
+ return REALLOC(parser, ptr, size);
}
void XMLCALL
XML_MemFree(XML_Parser parser, void *ptr)
{
if (parser != NULL)
- FREE(ptr);
+ FREE(parser, ptr);
}
void XMLCALL
{
if (parser == NULL)
return;
- if (defaultHandler) {
- if (openInternalEntities)
+ if (parser->m_defaultHandler) {
+ if (parser->m_openInternalEntities)
reportDefault(parser,
- internalEncoding,
- openInternalEntities->internalEventPtr,
- openInternalEntities->internalEventEndPtr);
+ parser->m_internalEncoding,
+ parser->m_openInternalEntities->internalEventPtr,
+ parser->m_openInternalEntities->internalEventEndPtr);
else
- reportDefault(parser, encoding, eventPtr, eventEndPtr);
+ reportDefault(parser, parser->m_encoding, parser->m_eventPtr, parser->m_eventEndPtr);
}
}
const XML_LChar * XMLCALL
XML_ErrorString(enum XML_Error code)
{
- static const XML_LChar* const message[] = {
- 0,
- XML_L("out of memory"),
- XML_L("syntax error"),
- XML_L("no element found"),
- XML_L("not well-formed (invalid token)"),
- XML_L("unclosed token"),
- XML_L("partial character"),
- XML_L("mismatched tag"),
- XML_L("duplicate attribute"),
- XML_L("junk after document element"),
- XML_L("illegal parameter entity reference"),
- XML_L("undefined entity"),
- XML_L("recursive entity reference"),
- XML_L("asynchronous entity"),
- XML_L("reference to invalid character number"),
- XML_L("reference to binary entity"),
- XML_L("reference to external entity in attribute"),
- XML_L("XML or text declaration not at start of entity"),
- XML_L("unknown encoding"),
- XML_L("encoding specified in XML declaration is incorrect"),
- XML_L("unclosed CDATA section"),
- XML_L("error in processing external entity reference"),
- XML_L("document is not standalone"),
- XML_L("unexpected parser state - please send a bug report"),
- XML_L("entity declared in parameter entity"),
- XML_L("requested feature requires XML_DTD support in Expat"),
- XML_L("cannot change setting once parsing has begun"),
- XML_L("unbound prefix"),
- XML_L("must not undeclare prefix"),
- XML_L("incomplete markup in parameter entity"),
- XML_L("XML declaration not well-formed"),
- XML_L("text declaration not well-formed"),
- XML_L("illegal character(s) in public id"),
- XML_L("parser suspended"),
- XML_L("parser not suspended"),
- XML_L("parsing aborted"),
- XML_L("parsing finished"),
- XML_L("cannot suspend in external parameter entity"),
- XML_L("reserved prefix (xml) must not be undeclared or bound to another namespace name"),
- XML_L("reserved prefix (xmlns) must not be declared or undeclared"),
- XML_L("prefix must not be bound to one of the reserved namespace names")
- };
- if (code > 0 && code < sizeof(message)/sizeof(message[0]))
- return message[code];
+ switch (code) {
+ case XML_ERROR_NONE:
+ return NULL;
+ case XML_ERROR_NO_MEMORY:
+ return XML_L("out of memory");
+ case XML_ERROR_SYNTAX:
+ return XML_L("syntax error");
+ case XML_ERROR_NO_ELEMENTS:
+ return XML_L("no element found");
+ case XML_ERROR_INVALID_TOKEN:
+ return XML_L("not well-formed (invalid token)");
+ case XML_ERROR_UNCLOSED_TOKEN:
+ return XML_L("unclosed token");
+ case XML_ERROR_PARTIAL_CHAR:
+ return XML_L("partial character");
+ case XML_ERROR_TAG_MISMATCH:
+ return XML_L("mismatched tag");
+ case XML_ERROR_DUPLICATE_ATTRIBUTE:
+ return XML_L("duplicate attribute");
+ case XML_ERROR_JUNK_AFTER_DOC_ELEMENT:
+ return XML_L("junk after document element");
+ case XML_ERROR_PARAM_ENTITY_REF:
+ return XML_L("illegal parameter entity reference");
+ case XML_ERROR_UNDEFINED_ENTITY:
+ return XML_L("undefined entity");
+ case XML_ERROR_RECURSIVE_ENTITY_REF:
+ return XML_L("recursive entity reference");
+ case XML_ERROR_ASYNC_ENTITY:
+ return XML_L("asynchronous entity");
+ case XML_ERROR_BAD_CHAR_REF:
+ return XML_L("reference to invalid character number");
+ case XML_ERROR_BINARY_ENTITY_REF:
+ return XML_L("reference to binary entity");
+ case XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF:
+ return XML_L("reference to external entity in attribute");
+ case XML_ERROR_MISPLACED_XML_PI:
+ return XML_L("XML or text declaration not at start of entity");
+ case XML_ERROR_UNKNOWN_ENCODING:
+ return XML_L("unknown encoding");
+ case XML_ERROR_INCORRECT_ENCODING:
+ return XML_L("encoding specified in XML declaration is incorrect");
+ case XML_ERROR_UNCLOSED_CDATA_SECTION:
+ return XML_L("unclosed CDATA section");
+ case XML_ERROR_EXTERNAL_ENTITY_HANDLING:
+ return XML_L("error in processing external entity reference");
+ case XML_ERROR_NOT_STANDALONE:
+ return XML_L("document is not standalone");
+ case XML_ERROR_UNEXPECTED_STATE:
+ return XML_L("unexpected parser state - please send a bug report");
+ case XML_ERROR_ENTITY_DECLARED_IN_PE:
+ return XML_L("entity declared in parameter entity");
+ case XML_ERROR_FEATURE_REQUIRES_XML_DTD:
+ return XML_L("requested feature requires XML_DTD support in Expat");
+ case XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING:
+ return XML_L("cannot change setting once parsing has begun");
+ /* Added in 1.95.7. */
+ case XML_ERROR_UNBOUND_PREFIX:
+ return XML_L("unbound prefix");
+ /* Added in 1.95.8. */
+ case XML_ERROR_UNDECLARING_PREFIX:
+ return XML_L("must not undeclare prefix");
+ case XML_ERROR_INCOMPLETE_PE:
+ return XML_L("incomplete markup in parameter entity");
+ case XML_ERROR_XML_DECL:
+ return XML_L("XML declaration not well-formed");
+ case XML_ERROR_TEXT_DECL:
+ return XML_L("text declaration not well-formed");
+ case XML_ERROR_PUBLICID:
+ return XML_L("illegal character(s) in public id");
+ case XML_ERROR_SUSPENDED:
+ return XML_L("parser suspended");
+ case XML_ERROR_NOT_SUSPENDED:
+ return XML_L("parser not suspended");
+ case XML_ERROR_ABORTED:
+ return XML_L("parsing aborted");
+ case XML_ERROR_FINISHED:
+ return XML_L("parsing finished");
+ case XML_ERROR_SUSPEND_PE:
+ return XML_L("cannot suspend in external parameter entity");
+ /* Added in 2.0.0. */
+ case XML_ERROR_RESERVED_PREFIX_XML:
+ return XML_L("reserved prefix (xml) must not be undeclared or bound to another namespace name");
+ case XML_ERROR_RESERVED_PREFIX_XMLNS:
+ return XML_L("reserved prefix (xmlns) must not be declared or undeclared");
+ case XML_ERROR_RESERVED_NAMESPACE_URI:
+ return XML_L("prefix must not be bound to one of the reserved namespace names");
+ /* Added in 2.2.5. */
+ case XML_ERROR_INVALID_ARGUMENT: /* Constant added in 2.2.1, already */
+ return XML_L("invalid argument");
+ }
return NULL;
}
static XML_Bool
storeRawNames(XML_Parser parser)
{
- TAG *tag = tagStack;
+ TAG *tag = parser->m_tagStack;
while (tag) {
int bufSize;
int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1);
char *rawNameBuf = tag->buf + nameLen;
- /* Stop if already stored. Since tagStack is a stack, we can stop
+ /* Stop if already stored. Since m_tagStack is a stack, we can stop
at the first entry that has already been copied; everything
below it in the stack is already been accounted for in a
previous call to this function.
*/
bufSize = nameLen + ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
if (bufSize > tag->bufEnd - tag->buf) {
- char *temp = (char *)REALLOC(tag->buf, bufSize);
+ char *temp = (char *)REALLOC(parser, tag->buf, bufSize);
if (temp == NULL)
return XML_FALSE;
/* if tag->name.str points to tag->buf (only when namespace
const char *end,
const char **endPtr)
{
- enum XML_Error result = doContent(parser, 0, encoding, start, end,
- endPtr, (XML_Bool)!ps_finalBuffer);
+ enum XML_Error result = doContent(parser, 0, parser->m_encoding, start, end,
+ endPtr, (XML_Bool)!parser->m_parsingStatus.finalBuffer);
if (result == XML_ERROR_NONE) {
if (!storeRawNames(parser))
return XML_ERROR_NO_MEMORY;
enum XML_Error result = initializeEncoding(parser);
if (result != XML_ERROR_NONE)
return result;
- processor = externalEntityInitProcessor2;
+ parser->m_processor = externalEntityInitProcessor2;
return externalEntityInitProcessor2(parser, start, end, endPtr);
}
const char **endPtr)
{
const char *next = start; /* XmlContentTok doesn't always set the last arg */
- int tok = XmlContentTok(encoding, start, end, &next);
+ int tok = XmlContentTok(parser->m_encoding, start, end, &next);
switch (tok) {
case XML_TOK_BOM:
/* If we are at the end of the buffer, this would cause the next stage,
doContent (by detecting XML_TOK_NONE) without processing any xml text
declaration - causing the error XML_ERROR_MISPLACED_XML_PI in doContent.
*/
- if (next == end && !ps_finalBuffer) {
+ if (next == end && !parser->m_parsingStatus.finalBuffer) {
*endPtr = next;
return XML_ERROR_NONE;
}
start = next;
break;
case XML_TOK_PARTIAL:
- if (!ps_finalBuffer) {
+ if (!parser->m_parsingStatus.finalBuffer) {
*endPtr = start;
return XML_ERROR_NONE;
}
- eventPtr = start;
+ parser->m_eventPtr = start;
return XML_ERROR_UNCLOSED_TOKEN;
case XML_TOK_PARTIAL_CHAR:
- if (!ps_finalBuffer) {
+ if (!parser->m_parsingStatus.finalBuffer) {
*endPtr = start;
return XML_ERROR_NONE;
}
- eventPtr = start;
+ parser->m_eventPtr = start;
return XML_ERROR_PARTIAL_CHAR;
}
- processor = externalEntityInitProcessor3;
+ parser->m_processor = externalEntityInitProcessor3;
return externalEntityInitProcessor3(parser, start, end, endPtr);
}
{
int tok;
const char *next = start; /* XmlContentTok doesn't always set the last arg */
- eventPtr = start;
- tok = XmlContentTok(encoding, start, end, &next);
- eventEndPtr = next;
+ parser->m_eventPtr = start;
+ tok = XmlContentTok(parser->m_encoding, start, end, &next);
+ parser->m_eventEndPtr = next;
switch (tok) {
case XML_TOK_XML_DECL:
result = processXmlDecl(parser, 1, start, next);
if (result != XML_ERROR_NONE)
return result;
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
*endPtr = next;
return XML_ERROR_NONE;
}
break;
case XML_TOK_PARTIAL:
- if (!ps_finalBuffer) {
+ if (!parser->m_parsingStatus.finalBuffer) {
*endPtr = start;
return XML_ERROR_NONE;
}
return XML_ERROR_UNCLOSED_TOKEN;
case XML_TOK_PARTIAL_CHAR:
- if (!ps_finalBuffer) {
+ if (!parser->m_parsingStatus.finalBuffer) {
*endPtr = start;
return XML_ERROR_NONE;
}
return XML_ERROR_PARTIAL_CHAR;
}
- processor = externalEntityContentProcessor;
- tagLevel = 1;
+ parser->m_processor = externalEntityContentProcessor;
+ parser->m_tagLevel = 1;
return externalEntityContentProcessor(parser, start, end, endPtr);
}
const char *end,
const char **endPtr)
{
- enum XML_Error result = doContent(parser, 1, encoding, start, end,
- endPtr, (XML_Bool)!ps_finalBuffer);
+ enum XML_Error result = doContent(parser, 1, parser->m_encoding, start, end,
+ endPtr, (XML_Bool)!parser->m_parsingStatus.finalBuffer);
if (result == XML_ERROR_NONE) {
if (!storeRawNames(parser))
return XML_ERROR_NO_MEMORY;
XML_Bool haveMore)
{
/* save one level of indirection */
- DTD * const dtd = _dtd;
+ DTD * const dtd = parser->m_dtd;
const char **eventPP;
const char **eventEndPP;
- if (enc == encoding) {
- eventPP = &eventPtr;
- eventEndPP = &eventEndPtr;
+ if (enc == parser->m_encoding) {
+ eventPP = &parser->m_eventPtr;
+ eventEndPP = &parser->m_eventEndPtr;
}
else {
- eventPP = &(openInternalEntities->internalEventPtr);
- eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ eventPP = &(parser->m_openInternalEntities->internalEventPtr);
+ eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr);
}
*eventPP = s;
return XML_ERROR_NONE;
}
*eventEndPP = end;
- if (characterDataHandler) {
+ if (parser->m_characterDataHandler) {
XML_Char c = 0xA;
- characterDataHandler(handlerArg, &c, 1);
+ parser->m_characterDataHandler(parser->m_handlerArg, &c, 1);
}
- else if (defaultHandler)
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, end);
/* We are at the end of the final buffer, should we check for
XML_SUSPENDED, XML_FINISHED?
*/
if (startTagLevel == 0)
return XML_ERROR_NO_ELEMENTS;
- if (tagLevel != startTagLevel)
+ if (parser->m_tagLevel != startTagLevel)
return XML_ERROR_ASYNC_ENTITY;
*nextPtr = end;
return XML_ERROR_NONE;
return XML_ERROR_NONE;
}
if (startTagLevel > 0) {
- if (tagLevel != startTagLevel)
+ if (parser->m_tagLevel != startTagLevel)
return XML_ERROR_ASYNC_ENTITY;
*nextPtr = s;
return XML_ERROR_NONE;
s + enc->minBytesPerChar,
next - enc->minBytesPerChar);
if (ch) {
- if (characterDataHandler)
- characterDataHandler(handlerArg, &ch, 1);
- else if (defaultHandler)
+ if (parser->m_characterDataHandler)
+ parser->m_characterDataHandler(parser->m_handlerArg, &ch, 1);
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
break;
}
return XML_ERROR_ENTITY_DECLARED_IN_PE;
}
else if (!entity) {
- if (skippedEntityHandler)
- skippedEntityHandler(handlerArg, name, 0);
- else if (defaultHandler)
+ if (parser->m_skippedEntityHandler)
+ parser->m_skippedEntityHandler(parser->m_handlerArg, name, 0);
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
break;
}
return XML_ERROR_BINARY_ENTITY_REF;
if (entity->textPtr) {
enum XML_Error result;
- if (!defaultExpandInternalEntities) {
- if (skippedEntityHandler)
- skippedEntityHandler(handlerArg, entity->name, 0);
- else if (defaultHandler)
+ if (!parser->m_defaultExpandInternalEntities) {
+ if (parser->m_skippedEntityHandler)
+ parser->m_skippedEntityHandler(parser->m_handlerArg, entity->name, 0);
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
break;
}
if (result != XML_ERROR_NONE)
return result;
}
- else if (externalEntityRefHandler) {
+ else if (parser->m_externalEntityRefHandler) {
const XML_Char *context;
entity->open = XML_TRUE;
context = getContext(parser);
entity->open = XML_FALSE;
if (!context)
return XML_ERROR_NO_MEMORY;
- if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ if (!parser->m_externalEntityRefHandler(parser->m_externalEntityRefHandlerArg,
context,
entity->base,
entity->systemId,
entity->publicId))
return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
- poolDiscard(&tempPool);
+ poolDiscard(&parser->m_tempPool);
}
- else if (defaultHandler)
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
break;
}
TAG *tag;
enum XML_Error result;
XML_Char *toPtr;
- if (freeTagList) {
- tag = freeTagList;
- freeTagList = freeTagList->parent;
+ if (parser->m_freeTagList) {
+ tag = parser->m_freeTagList;
+ parser->m_freeTagList = parser->m_freeTagList->parent;
}
else {
- tag = (TAG *)MALLOC(sizeof(TAG));
+ tag = (TAG *)MALLOC(parser, sizeof(TAG));
if (!tag)
return XML_ERROR_NO_MEMORY;
- tag->buf = (char *)MALLOC(INIT_TAG_BUF_SIZE);
+ tag->buf = (char *)MALLOC(parser, INIT_TAG_BUF_SIZE);
if (!tag->buf) {
- FREE(tag);
+ FREE(parser, tag);
return XML_ERROR_NO_MEMORY;
}
tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE;
}
tag->bindings = NULL;
- tag->parent = tagStack;
- tagStack = tag;
+ tag->parent = parser->m_tagStack;
+ parser->m_tagStack = tag;
tag->name.localPart = NULL;
tag->name.prefix = NULL;
tag->rawName = s + enc->minBytesPerChar;
tag->rawNameLength = XmlNameLength(enc, tag->rawName);
- ++tagLevel;
+ ++parser->m_tagLevel;
{
const char *rawNameEnd = tag->rawName + tag->rawNameLength;
const char *fromPtr = tag->rawName;
}
bufSize = (int)(tag->bufEnd - tag->buf) << 1;
{
- char *temp = (char *)REALLOC(tag->buf, bufSize);
+ char *temp = (char *)REALLOC(parser, tag->buf, bufSize);
if (temp == NULL)
return XML_ERROR_NO_MEMORY;
tag->buf = temp;
result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings));
if (result)
return result;
- if (startElementHandler)
- startElementHandler(handlerArg, tag->name.str,
- (const XML_Char **)atts);
- else if (defaultHandler)
+ if (parser->m_startElementHandler)
+ parser->m_startElementHandler(parser->m_handlerArg, tag->name.str,
+ (const XML_Char **)parser->m_atts);
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
- poolClear(&tempPool);
+ poolClear(&parser->m_tempPool);
break;
}
case XML_TOK_EMPTY_ELEMENT_NO_ATTS:
BINDING *bindings = NULL;
XML_Bool noElmHandlers = XML_TRUE;
TAG_NAME name;
- name.str = poolStoreString(&tempPool, enc, rawName,
+ name.str = poolStoreString(&parser->m_tempPool, enc, rawName,
rawName + XmlNameLength(enc, rawName));
if (!name.str)
return XML_ERROR_NO_MEMORY;
- poolFinish(&tempPool);
+ poolFinish(&parser->m_tempPool);
result = storeAtts(parser, enc, s, &name, &bindings);
if (result != XML_ERROR_NONE) {
freeBindings(parser, bindings);
return result;
}
- poolFinish(&tempPool);
- if (startElementHandler) {
- startElementHandler(handlerArg, name.str, (const XML_Char **)atts);
+ poolFinish(&parser->m_tempPool);
+ if (parser->m_startElementHandler) {
+ parser->m_startElementHandler(parser->m_handlerArg, name.str, (const XML_Char **)parser->m_atts);
noElmHandlers = XML_FALSE;
}
- if (endElementHandler) {
- if (startElementHandler)
+ if (parser->m_endElementHandler) {
+ if (parser->m_startElementHandler)
*eventPP = *eventEndPP;
- endElementHandler(handlerArg, name.str);
+ parser->m_endElementHandler(parser->m_handlerArg, name.str);
noElmHandlers = XML_FALSE;
}
- if (noElmHandlers && defaultHandler)
+ if (noElmHandlers && parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
- poolClear(&tempPool);
+ poolClear(&parser->m_tempPool);
freeBindings(parser, bindings);
}
- if (tagLevel == 0)
- return epilogProcessor(parser, next, end, nextPtr);
+ if ((parser->m_tagLevel == 0) && (parser->m_parsingStatus.parsing != XML_FINISHED)) {
+ if (parser->m_parsingStatus.parsing == XML_SUSPENDED)
+ parser->m_processor = epilogProcessor;
+ else
+ return epilogProcessor(parser, next, end, nextPtr);
+ }
break;
case XML_TOK_END_TAG:
- if (tagLevel == startTagLevel)
+ if (parser->m_tagLevel == startTagLevel)
return XML_ERROR_ASYNC_ENTITY;
else {
int len;
const char *rawName;
- TAG *tag = tagStack;
- tagStack = tag->parent;
- tag->parent = freeTagList;
- freeTagList = tag;
+ TAG *tag = parser->m_tagStack;
+ parser->m_tagStack = tag->parent;
+ tag->parent = parser->m_freeTagList;
+ parser->m_freeTagList = tag;
rawName = s + enc->minBytesPerChar*2;
len = XmlNameLength(enc, rawName);
if (len != tag->rawNameLength
*eventPP = rawName;
return XML_ERROR_TAG_MISMATCH;
}
- --tagLevel;
- if (endElementHandler) {
+ --parser->m_tagLevel;
+ if (parser->m_endElementHandler) {
const XML_Char *localPart;
const XML_Char *prefix;
XML_Char *uri;
localPart = tag->name.localPart;
- if (ns && localPart) {
+ if (parser->m_ns && localPart) {
/* localPart and prefix may have been overwritten in
tag->name.str, since this points to the binding->uri
buffer which gets re-used; so we have to add them again
/* don't need to check for space - already done in storeAtts() */
while (*localPart) *uri++ = *localPart++;
prefix = (XML_Char *)tag->name.prefix;
- if (ns_triplets && prefix) {
- *uri++ = namespaceSeparator;
+ if (parser->m_ns_triplets && prefix) {
+ *uri++ = parser->m_namespaceSeparator;
while (*prefix) *uri++ = *prefix++;
}
*uri = XML_T('\0');
}
- endElementHandler(handlerArg, tag->name.str);
+ parser->m_endElementHandler(parser->m_handlerArg, tag->name.str);
}
- else if (defaultHandler)
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
while (tag->bindings) {
BINDING *b = tag->bindings;
- if (endNamespaceDeclHandler)
- endNamespaceDeclHandler(handlerArg, b->prefix->name);
+ if (parser->m_endNamespaceDeclHandler)
+ parser->m_endNamespaceDeclHandler(parser->m_handlerArg, b->prefix->name);
tag->bindings = tag->bindings->nextTagBinding;
- b->nextTagBinding = freeBindingList;
- freeBindingList = b;
+ b->nextTagBinding = parser->m_freeBindingList;
+ parser->m_freeBindingList = b;
b->prefix->binding = b->prevPrefixBinding;
}
- if (tagLevel == 0)
+ if (parser->m_tagLevel == 0)
return epilogProcessor(parser, next, end, nextPtr);
}
break;
int n = XmlCharRefNumber(enc, s);
if (n < 0)
return XML_ERROR_BAD_CHAR_REF;
- if (characterDataHandler) {
+ if (parser->m_characterDataHandler) {
XML_Char buf[XML_ENCODE_MAX];
- characterDataHandler(handlerArg, buf, XmlEncode(n, (ICHAR *)buf));
+ parser->m_characterDataHandler(parser->m_handlerArg, buf, XmlEncode(n, (ICHAR *)buf));
}
- else if (defaultHandler)
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
}
break;
case XML_TOK_XML_DECL:
return XML_ERROR_MISPLACED_XML_PI;
case XML_TOK_DATA_NEWLINE:
- if (characterDataHandler) {
+ if (parser->m_characterDataHandler) {
XML_Char c = 0xA;
- characterDataHandler(handlerArg, &c, 1);
+ parser->m_characterDataHandler(parser->m_handlerArg, &c, 1);
}
- else if (defaultHandler)
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
break;
case XML_TOK_CDATA_SECT_OPEN:
{
enum XML_Error result;
- if (startCdataSectionHandler)
- startCdataSectionHandler(handlerArg);
+ if (parser->m_startCdataSectionHandler)
+ parser->m_startCdataSectionHandler(parser->m_handlerArg);
#if 0
/* Suppose you doing a transformation on a document that involves
changing only the character data. You set up a defaultHandler
However, now we have a start/endCdataSectionHandler, so it seems
easier to let the user deal with this.
*/
- else if (characterDataHandler)
- characterDataHandler(handlerArg, dataBuf, 0);
+ else if (parser->m_characterDataHandler)
+ parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf, 0);
#endif
- else if (defaultHandler)
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
result = doCdataSection(parser, enc, &next, end, nextPtr, haveMore);
if (result != XML_ERROR_NONE)
return result;
else if (!next) {
- processor = cdataSectionProcessor;
+ parser->m_processor = cdataSectionProcessor;
return result;
}
}
*nextPtr = s;
return XML_ERROR_NONE;
}
- if (characterDataHandler) {
+ if (parser->m_characterDataHandler) {
if (MUST_CONVERT(enc, s)) {
- ICHAR *dataPtr = (ICHAR *)dataBuf;
- XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
- characterDataHandler(handlerArg, dataBuf,
- (int)(dataPtr - (ICHAR *)dataBuf));
+ ICHAR *dataPtr = (ICHAR *)parser->m_dataBuf;
+ XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)parser->m_dataBufEnd);
+ parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf,
+ (int)(dataPtr - (ICHAR *)parser->m_dataBuf));
}
else
- characterDataHandler(handlerArg,
+ parser->m_characterDataHandler(parser->m_handlerArg,
(XML_Char *)s,
(int)((XML_Char *)end - (XML_Char *)s));
}
- else if (defaultHandler)
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, end);
/* We are at the end of the final buffer, should we check for
XML_SUSPENDED, XML_FINISHED?
*eventPP = end;
return XML_ERROR_NO_ELEMENTS;
}
- if (tagLevel != startTagLevel) {
+ if (parser->m_tagLevel != startTagLevel) {
*eventPP = end;
return XML_ERROR_ASYNC_ENTITY;
}
return XML_ERROR_NONE;
case XML_TOK_DATA_CHARS:
{
- XML_CharacterDataHandler charDataHandler = characterDataHandler;
+ XML_CharacterDataHandler charDataHandler = parser->m_characterDataHandler;
if (charDataHandler) {
if (MUST_CONVERT(enc, s)) {
for (;;) {
- ICHAR *dataPtr = (ICHAR *)dataBuf;
- const enum XML_Convert_Result convert_res = XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
+ ICHAR *dataPtr = (ICHAR *)parser->m_dataBuf;
+ const enum XML_Convert_Result convert_res = XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)parser->m_dataBufEnd);
*eventEndPP = s;
- charDataHandler(handlerArg, dataBuf,
- (int)(dataPtr - (ICHAR *)dataBuf));
+ charDataHandler(parser->m_handlerArg, parser->m_dataBuf,
+ (int)(dataPtr - (ICHAR *)parser->m_dataBuf));
if ((convert_res == XML_CONVERT_COMPLETED) || (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
break;
*eventPP = s;
}
}
else
- charDataHandler(handlerArg,
+ charDataHandler(parser->m_handlerArg,
(XML_Char *)s,
(int)((XML_Char *)next - (XML_Char *)s));
}
- else if (defaultHandler)
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
}
break;
*
* LCOV_EXCL_START
*/
- if (defaultHandler)
+ if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
break;
/* LCOV_EXCL_STOP */
}
*eventPP = s = next;
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
*nextPtr = next;
return XML_ERROR_NONE;
}
/* This function does not call free() on the allocated memory, merely
- * moving it to the parser's freeBindingList where it can be freed or
+ * moving it to the parser's m_freeBindingList where it can be freed or
* reused as appropriate.
*/
static void
while (bindings) {
BINDING *b = bindings;
- /* startNamespaceDeclHandler will have been called for this
+ /* m_startNamespaceDeclHandler will have been called for this
* binding in addBindings(), so call the end handler now.
*/
- if (endNamespaceDeclHandler)
- endNamespaceDeclHandler(handlerArg, b->prefix->name);
+ if (parser->m_endNamespaceDeclHandler)
+ parser->m_endNamespaceDeclHandler(parser->m_handlerArg, b->prefix->name);
bindings = bindings->nextTagBinding;
- b->nextTagBinding = freeBindingList;
- freeBindingList = b;
+ b->nextTagBinding = parser->m_freeBindingList;
+ parser->m_freeBindingList = b;
b->prefix->binding = b->prevPrefixBinding;
}
}
const char *attStr, TAG_NAME *tagNamePtr,
BINDING **bindingsPtr)
{
- DTD * const dtd = _dtd; /* save one level of indirection */
+ DTD * const dtd = parser->m_dtd; /* save one level of indirection */
ELEMENT_TYPE *elementType;
int nDefaultAtts;
const XML_Char **appAtts; /* the attribute list for the application */
sizeof(ELEMENT_TYPE));
if (!elementType)
return XML_ERROR_NO_MEMORY;
- if (ns && !setElementTypePrefix(parser, elementType))
+ if (parser->m_ns && !setElementTypePrefix(parser, elementType))
return XML_ERROR_NO_MEMORY;
}
nDefaultAtts = elementType->nDefaultAtts;
/* get the attributes from the tokenizer */
- n = XmlGetAttributes(enc, attStr, attsSize, atts);
- if (n + nDefaultAtts > attsSize) {
- int oldAttsSize = attsSize;
+ n = XmlGetAttributes(enc, attStr, parser->m_attsSize, parser->m_atts);
+ if (n + nDefaultAtts > parser->m_attsSize) {
+ int oldAttsSize = parser->m_attsSize;
ATTRIBUTE *temp;
#ifdef XML_ATTR_INFO
XML_AttrInfo *temp2;
#endif
- attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
- temp = (ATTRIBUTE *)REALLOC((void *)atts, attsSize * sizeof(ATTRIBUTE));
+ parser->m_attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
+ temp = (ATTRIBUTE *)REALLOC(parser, (void *)parser->m_atts, parser->m_attsSize * sizeof(ATTRIBUTE));
if (temp == NULL) {
- attsSize = oldAttsSize;
+ parser->m_attsSize = oldAttsSize;
return XML_ERROR_NO_MEMORY;
}
- atts = temp;
+ parser->m_atts = temp;
#ifdef XML_ATTR_INFO
- temp2 = (XML_AttrInfo *)REALLOC((void *)attInfo, attsSize * sizeof(XML_AttrInfo));
+ temp2 = (XML_AttrInfo *)REALLOC(parser, (void *)parser->m_attInfo, parser->m_attsSize * sizeof(XML_AttrInfo));
if (temp2 == NULL) {
- attsSize = oldAttsSize;
+ parser->m_attsSize = oldAttsSize;
return XML_ERROR_NO_MEMORY;
}
- attInfo = temp2;
+ parser->m_attInfo = temp2;
#endif
if (n > oldAttsSize)
- XmlGetAttributes(enc, attStr, n, atts);
+ XmlGetAttributes(enc, attStr, n, parser->m_atts);
}
- appAtts = (const XML_Char **)atts;
+ appAtts = (const XML_Char **)parser->m_atts;
for (i = 0; i < n; i++) {
- ATTRIBUTE *currAtt = &atts[i];
+ ATTRIBUTE *currAtt = &parser->m_atts[i];
#ifdef XML_ATTR_INFO
- XML_AttrInfo *currAttInfo = &attInfo[i];
+ XML_AttrInfo *currAttInfo = &parser->m_attInfo[i];
#endif
/* add the name and value to the attribute list */
ATTRIBUTE_ID *attId = getAttributeId(parser, enc, currAtt->name,
if (!attId)
return XML_ERROR_NO_MEMORY;
#ifdef XML_ATTR_INFO
- currAttInfo->nameStart = parseEndByteIndex - (parseEndPtr - currAtt->name);
+ currAttInfo->nameStart = parser->m_parseEndByteIndex - (parser->m_parseEndPtr - currAtt->name);
currAttInfo->nameEnd = currAttInfo->nameStart +
XmlNameLength(enc, currAtt->name);
- currAttInfo->valueStart = parseEndByteIndex -
- (parseEndPtr - currAtt->valuePtr);
- currAttInfo->valueEnd = parseEndByteIndex - (parseEndPtr - currAtt->valueEnd);
+ currAttInfo->valueStart = parser->m_parseEndByteIndex -
+ (parser->m_parseEndPtr - currAtt->valuePtr);
+ currAttInfo->valueEnd = parser->m_parseEndByteIndex - (parser->m_parseEndPtr - currAtt->valueEnd);
#endif
/* Detect duplicate attributes by their QNames. This does not work when
namespace processing is turned on and different prefixes for the same
namespace are used. For this case we have a check further down.
*/
if ((attId->name)[-1]) {
- if (enc == encoding)
- eventPtr = atts[i].name;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = parser->m_atts[i].name;
return XML_ERROR_DUPLICATE_ATTRIBUTE;
}
(attId->name)[-1] = 1;
appAtts[attIndex++] = attId->name;
- if (!atts[i].normalized) {
+ if (!parser->m_atts[i].normalized) {
enum XML_Error result;
XML_Bool isCdata = XML_TRUE;
/* normalize the attribute value */
result = storeAttributeValue(parser, enc, isCdata,
- atts[i].valuePtr, atts[i].valueEnd,
- &tempPool);
+ parser->m_atts[i].valuePtr, parser->m_atts[i].valueEnd,
+ &parser->m_tempPool);
if (result)
return result;
- appAtts[attIndex] = poolStart(&tempPool);
- poolFinish(&tempPool);
+ appAtts[attIndex] = poolStart(&parser->m_tempPool);
+ poolFinish(&parser->m_tempPool);
}
else {
/* the value did not need normalizing */
- appAtts[attIndex] = poolStoreString(&tempPool, enc, atts[i].valuePtr,
- atts[i].valueEnd);
+ appAtts[attIndex] = poolStoreString(&parser->m_tempPool, enc, parser->m_atts[i].valuePtr,
+ parser->m_atts[i].valueEnd);
if (appAtts[attIndex] == 0)
return XML_ERROR_NO_MEMORY;
- poolFinish(&tempPool);
+ poolFinish(&parser->m_tempPool);
}
/* handle prefixed attribute names */
if (attId->prefix) {
}
/* set-up for XML_GetSpecifiedAttributeCount and XML_GetIdAttributeIndex */
- nSpecifiedAtts = attIndex;
+ parser->m_nSpecifiedAtts = attIndex;
if (elementType->idAtt && (elementType->idAtt->name)[-1]) {
for (i = 0; i < attIndex; i += 2)
if (appAtts[i] == elementType->idAtt->name) {
- idAttIndex = i;
+ parser->m_idAttIndex = i;
break;
}
}
else
- idAttIndex = -1;
+ parser->m_idAttIndex = -1;
/* do attribute defaulting */
for (i = 0; i < nDefaultAtts; i++) {
i = 0;
if (nPrefixes) {
int j; /* hash table index */
- unsigned long version = nsAttsVersion;
- int nsAttsSize = (int)1 << nsAttsPower;
- unsigned char oldNsAttsPower = nsAttsPower;
+ unsigned long version = parser->m_nsAttsVersion;
+ int nsAttsSize = (int)1 << parser->m_nsAttsPower;
+ unsigned char oldNsAttsPower = parser->m_nsAttsPower;
/* size of hash table must be at least 2 * (# of prefixed attributes) */
- if ((nPrefixes << 1) >> nsAttsPower) { /* true for nsAttsPower = 0 */
+ if ((nPrefixes << 1) >> parser->m_nsAttsPower) { /* true for m_nsAttsPower = 0 */
NS_ATT *temp;
/* hash table size must also be a power of 2 and >= 8 */
- while (nPrefixes >> nsAttsPower++);
- if (nsAttsPower < 3)
- nsAttsPower = 3;
- nsAttsSize = (int)1 << nsAttsPower;
- temp = (NS_ATT *)REALLOC(nsAtts, nsAttsSize * sizeof(NS_ATT));
+ while (nPrefixes >> parser->m_nsAttsPower++);
+ if (parser->m_nsAttsPower < 3)
+ parser->m_nsAttsPower = 3;
+ nsAttsSize = (int)1 << parser->m_nsAttsPower;
+ temp = (NS_ATT *)REALLOC(parser, parser->m_nsAtts, nsAttsSize * sizeof(NS_ATT));
if (!temp) {
- /* Restore actual size of memory in nsAtts */
- nsAttsPower = oldNsAttsPower;
+ /* Restore actual size of memory in m_nsAtts */
+ parser->m_nsAttsPower = oldNsAttsPower;
return XML_ERROR_NO_MEMORY;
}
- nsAtts = temp;
- version = 0; /* force re-initialization of nsAtts hash table */
+ parser->m_nsAtts = temp;
+ version = 0; /* force re-initialization of m_nsAtts hash table */
}
- /* using a version flag saves us from initializing nsAtts every time */
+ /* using a version flag saves us from initializing m_nsAtts every time */
if (!version) { /* initialize version flags when version wraps around */
version = INIT_ATTS_VERSION;
for (j = nsAttsSize; j != 0; )
- nsAtts[--j].version = version;
+ parser->m_nsAtts[--j].version = version;
}
- nsAttsVersion = --version;
+ parser->m_nsAttsVersion = --version;
/* expand prefixed names and check for duplicates */
for (; i < attIndex; i += 2) {
for (j = 0; j < b->uriLen; j++) {
const XML_Char c = b->uri[j];
- if (!poolAppendChar(&tempPool, c))
+ if (!poolAppendChar(&parser->m_tempPool, c))
return XML_ERROR_NO_MEMORY;
}
sip24_update(&sip_state, s, keylen(s) * sizeof(XML_Char));
do { /* copies null terminator */
- if (!poolAppendChar(&tempPool, *s))
+ if (!poolAppendChar(&parser->m_tempPool, *s))
return XML_ERROR_NO_MEMORY;
} while (*s++);
unsigned char step = 0;
unsigned long mask = nsAttsSize - 1;
j = uriHash & mask; /* index into hash table */
- while (nsAtts[j].version == version) {
+ while (parser->m_nsAtts[j].version == version) {
/* for speed we compare stored hash values first */
- if (uriHash == nsAtts[j].hash) {
- const XML_Char *s1 = poolStart(&tempPool);
- const XML_Char *s2 = nsAtts[j].uriName;
+ if (uriHash == parser->m_nsAtts[j].hash) {
+ const XML_Char *s1 = poolStart(&parser->m_tempPool);
+ const XML_Char *s2 = parser->m_nsAtts[j].uriName;
/* s1 is null terminated, but not s2 */
for (; *s1 == *s2 && *s1 != 0; s1++, s2++);
if (*s1 == 0)
return XML_ERROR_DUPLICATE_ATTRIBUTE;
}
if (!step)
- step = PROBE_STEP(uriHash, mask, nsAttsPower);
+ step = PROBE_STEP(uriHash, mask, parser->m_nsAttsPower);
j < step ? (j += nsAttsSize - step) : (j -= step);
}
}
- if (ns_triplets) { /* append namespace separator and prefix */
- tempPool.ptr[-1] = namespaceSeparator;
+ if (parser->m_ns_triplets) { /* append namespace separator and prefix */
+ parser->m_tempPool.ptr[-1] = parser->m_namespaceSeparator;
s = b->prefix->name;
do {
- if (!poolAppendChar(&tempPool, *s))
+ if (!poolAppendChar(&parser->m_tempPool, *s))
return XML_ERROR_NO_MEMORY;
} while (*s++);
}
/* store expanded name in attribute list */
- s = poolStart(&tempPool);
- poolFinish(&tempPool);
+ s = poolStart(&parser->m_tempPool);
+ poolFinish(&parser->m_tempPool);
appAtts[i] = s;
/* fill empty slot with new version, uriName and hash value */
- nsAtts[j].version = version;
- nsAtts[j].hash = uriHash;
- nsAtts[j].uriName = s;
+ parser->m_nsAtts[j].version = version;
+ parser->m_nsAtts[j].hash = uriHash;
+ parser->m_nsAtts[j].uriName = s;
if (!--nPrefixes) {
i += 2;
for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding)
binding->attId->name[-1] = 0;
- if (!ns)
+ if (!parser->m_ns)
return XML_ERROR_NONE;
/* expand the element type name */
else
return XML_ERROR_NONE;
prefixLen = 0;
- if (ns_triplets && binding->prefix->name) {
+ if (parser->m_ns_triplets && binding->prefix->name) {
for (; binding->prefix->name[prefixLen++];)
; /* prefixLen includes null terminator */
}
n = i + binding->uriLen + prefixLen;
if (n > binding->uriAlloc) {
TAG *p;
- uri = (XML_Char *)MALLOC((n + EXPAND_SPARE) * sizeof(XML_Char));
+ uri = (XML_Char *)MALLOC(parser, (n + EXPAND_SPARE) * sizeof(XML_Char));
if (!uri)
return XML_ERROR_NO_MEMORY;
binding->uriAlloc = n + EXPAND_SPARE;
memcpy(uri, binding->uri, binding->uriLen * sizeof(XML_Char));
- for (p = tagStack; p; p = p->parent)
+ for (p = parser->m_tagStack; p; p = p->parent)
if (p->name.str == binding->uri)
p->name.str = uri;
- FREE(binding->uri);
+ FREE(parser, binding->uri);
binding->uri = uri;
}
- /* if namespaceSeparator != '\0' then uri includes it already */
+ /* if m_namespaceSeparator != '\0' then uri includes it already */
uri = binding->uri + binding->uriLen;
memcpy(uri, localPart, i * sizeof(XML_Char));
/* we always have a namespace separator between localPart and prefix */
if (prefixLen) {
uri += i - 1;
- *uri = namespaceSeparator; /* replace null terminator */
+ *uri = parser->m_namespaceSeparator; /* replace null terminator */
memcpy(uri + 1, binding->prefix->name, prefixLen * sizeof(XML_Char));
}
tagNamePtr->str = binding->uri;
if (isXMLNS)
return XML_ERROR_RESERVED_NAMESPACE_URI;
- if (namespaceSeparator)
+ if (parser->m_namespaceSeparator)
len++;
- if (freeBindingList) {
- b = freeBindingList;
+ if (parser->m_freeBindingList) {
+ b = parser->m_freeBindingList;
if (len > b->uriAlloc) {
- XML_Char *temp = (XML_Char *)REALLOC(b->uri,
+ XML_Char *temp = (XML_Char *)REALLOC(parser, b->uri,
sizeof(XML_Char) * (len + EXPAND_SPARE));
if (temp == NULL)
return XML_ERROR_NO_MEMORY;
b->uri = temp;
b->uriAlloc = len + EXPAND_SPARE;
}
- freeBindingList = b->nextTagBinding;
+ parser->m_freeBindingList = b->nextTagBinding;
}
else {
- b = (BINDING *)MALLOC(sizeof(BINDING));
+ b = (BINDING *)MALLOC(parser, sizeof(BINDING));
if (!b)
return XML_ERROR_NO_MEMORY;
- b->uri = (XML_Char *)MALLOC(sizeof(XML_Char) * (len + EXPAND_SPARE));
+ b->uri = (XML_Char *)MALLOC(parser, sizeof(XML_Char) * (len + EXPAND_SPARE));
if (!b->uri) {
- FREE(b);
+ FREE(parser, b);
return XML_ERROR_NO_MEMORY;
}
b->uriAlloc = len + EXPAND_SPARE;
}
b->uriLen = len;
memcpy(b->uri, uri, len * sizeof(XML_Char));
- if (namespaceSeparator)
- b->uri[len - 1] = namespaceSeparator;
+ if (parser->m_namespaceSeparator)
+ b->uri[len - 1] = parser->m_namespaceSeparator;
b->prefix = prefix;
b->attId = attId;
b->prevPrefixBinding = prefix->binding;
/* NULL binding when default namespace undeclared */
- if (*uri == XML_T('\0') && prefix == &_dtd->defaultPrefix)
+ if (*uri == XML_T('\0') && prefix == &parser->m_dtd->defaultPrefix)
prefix->binding = NULL;
else
prefix->binding = b;
b->nextTagBinding = *bindingsPtr;
*bindingsPtr = b;
/* if attId == NULL then we are not starting a namespace scope */
- if (attId && startNamespaceDeclHandler)
- startNamespaceDeclHandler(handlerArg, prefix->name,
+ if (attId && parser->m_startNamespaceDeclHandler)
+ parser->m_startNamespaceDeclHandler(parser->m_handlerArg, prefix->name,
prefix->binding ? uri : 0);
return XML_ERROR_NONE;
}
const char *end,
const char **endPtr)
{
- enum XML_Error result = doCdataSection(parser, encoding, &start, end,
- endPtr, (XML_Bool)!ps_finalBuffer);
+ enum XML_Error result = doCdataSection(parser, parser->m_encoding, &start, end,
+ endPtr, (XML_Bool)!parser->m_parsingStatus.finalBuffer);
if (result != XML_ERROR_NONE)
return result;
if (start) {
- if (parentParser) { /* we are parsing an external entity */
- processor = externalEntityContentProcessor;
+ if (parser->m_parentParser) { /* we are parsing an external entity */
+ parser->m_processor = externalEntityContentProcessor;
return externalEntityContentProcessor(parser, start, end, endPtr);
}
else {
- processor = contentProcessor;
+ parser->m_processor = contentProcessor;
return contentProcessor(parser, start, end, endPtr);
}
}
const char *s = *startPtr;
const char **eventPP;
const char **eventEndPP;
- if (enc == encoding) {
- eventPP = &eventPtr;
+ if (enc == parser->m_encoding) {
+ eventPP = &parser->m_eventPtr;
*eventPP = s;
- eventEndPP = &eventEndPtr;
+ eventEndPP = &parser->m_eventEndPtr;
}
else {
- eventPP = &(openInternalEntities->internalEventPtr);
- eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ eventPP = &(parser->m_openInternalEntities->internalEventPtr);
+ eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr);
}
*eventPP = s;
*startPtr = NULL;
*eventEndPP = next;
switch (tok) {
case XML_TOK_CDATA_SECT_CLOSE:
- if (endCdataSectionHandler)
- endCdataSectionHandler(handlerArg);
+ if (parser->m_endCdataSectionHandler)
+ parser->m_endCdataSectionHandler(parser->m_handlerArg);
#if 0
/* see comment under XML_TOK_CDATA_SECT_OPEN */
- else if (characterDataHandler)
- characterDataHandler(handlerArg, dataBuf, 0);
+ else if (parser->m_characterDataHandler)
+ parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf, 0);
#endif
- else if (defaultHandler)
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
*startPtr = next;
*nextPtr = next;
- if (ps_parsing == XML_FINISHED)
+ if (parser->m_parsingStatus.parsing == XML_FINISHED)
return XML_ERROR_ABORTED;
else
return XML_ERROR_NONE;
case XML_TOK_DATA_NEWLINE:
- if (characterDataHandler) {
+ if (parser->m_characterDataHandler) {
XML_Char c = 0xA;
- characterDataHandler(handlerArg, &c, 1);
+ parser->m_characterDataHandler(parser->m_handlerArg, &c, 1);
}
- else if (defaultHandler)
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
break;
case XML_TOK_DATA_CHARS:
{
- XML_CharacterDataHandler charDataHandler = characterDataHandler;
+ XML_CharacterDataHandler charDataHandler = parser->m_characterDataHandler;
if (charDataHandler) {
if (MUST_CONVERT(enc, s)) {
for (;;) {
- ICHAR *dataPtr = (ICHAR *)dataBuf;
- const enum XML_Convert_Result convert_res = XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
+ ICHAR *dataPtr = (ICHAR *)parser->m_dataBuf;
+ const enum XML_Convert_Result convert_res = XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)parser->m_dataBufEnd);
*eventEndPP = next;
- charDataHandler(handlerArg, dataBuf,
- (int)(dataPtr - (ICHAR *)dataBuf));
+ charDataHandler(parser->m_handlerArg, parser->m_dataBuf,
+ (int)(dataPtr - (ICHAR *)parser->m_dataBuf));
if ((convert_res == XML_CONVERT_COMPLETED) || (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
break;
*eventPP = s;
}
}
else
- charDataHandler(handlerArg,
+ charDataHandler(parser->m_handlerArg,
(XML_Char *)s,
(int)((XML_Char *)next - (XML_Char *)s));
}
- else if (defaultHandler)
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
}
break;
}
*eventPP = s = next;
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
*nextPtr = next;
return XML_ERROR_NONE;
const char *end,
const char **endPtr)
{
- enum XML_Error result = doIgnoreSection(parser, encoding, &start, end,
- endPtr, (XML_Bool)!ps_finalBuffer);
+ enum XML_Error result = doIgnoreSection(parser, parser->m_encoding, &start, end,
+ endPtr, (XML_Bool)!parser->m_parsingStatus.finalBuffer);
if (result != XML_ERROR_NONE)
return result;
if (start) {
- processor = prologProcessor;
+ parser->m_processor = prologProcessor;
return prologProcessor(parser, start, end, endPtr);
}
return result;
const char *s = *startPtr;
const char **eventPP;
const char **eventEndPP;
- if (enc == encoding) {
- eventPP = &eventPtr;
+ if (enc == parser->m_encoding) {
+ eventPP = &parser->m_eventPtr;
*eventPP = s;
- eventEndPP = &eventEndPtr;
+ eventEndPP = &parser->m_eventEndPtr;
}
else {
/* It's not entirely clear, but it seems the following two lines
* of code cannot be executed. The only occasions on which 'enc'
- * is not 'parser->m_encoding' are when this function is called
+ * is not 'encoding' are when this function is called
* from the internal entity processing, and IGNORE sections are an
* error in internal entities.
*
*
* LCOV_EXCL_START
*/
- eventPP = &(openInternalEntities->internalEventPtr);
- eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ eventPP = &(parser->m_openInternalEntities->internalEventPtr);
+ eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr);
/* LCOV_EXCL_STOP */
}
*eventPP = s;
*eventEndPP = next;
switch (tok) {
case XML_TOK_IGNORE_SECT:
- if (defaultHandler)
+ if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
*startPtr = next;
*nextPtr = next;
- if (ps_parsing == XML_FINISHED)
+ if (parser->m_parsingStatus.parsing == XML_FINISHED)
return XML_ERROR_ABORTED;
else
return XML_ERROR_NONE;
#ifdef XML_UNICODE
char encodingBuf[128];
/* See comments abount `protoclEncodingName` in parserInit() */
- if (!protocolEncodingName)
+ if (!parser->m_protocolEncodingName)
s = NULL;
else {
int i;
- for (i = 0; protocolEncodingName[i]; i++) {
+ for (i = 0; parser->m_protocolEncodingName[i]; i++) {
if (i == sizeof(encodingBuf) - 1
- || (protocolEncodingName[i] & ~0x7f) != 0) {
+ || (parser->m_protocolEncodingName[i] & ~0x7f) != 0) {
encodingBuf[0] = '\0';
break;
}
- encodingBuf[i] = (char)protocolEncodingName[i];
+ encodingBuf[i] = (char)parser->m_protocolEncodingName[i];
}
encodingBuf[i] = '\0';
s = encodingBuf;
}
#else
- s = protocolEncodingName;
+ s = parser->m_protocolEncodingName;
#endif
- if ((ns ? XmlInitEncodingNS : XmlInitEncoding)(&initEncoding, &encoding, s))
+ if ((parser->m_ns ? XmlInitEncodingNS : XmlInitEncoding)(&parser->m_initEncoding, &parser->m_encoding, s))
return XML_ERROR_NONE;
- return handleUnknownEncoding(parser, protocolEncodingName);
+ return handleUnknownEncoding(parser, parser->m_protocolEncodingName);
}
static enum XML_Error
const char *versionend;
const XML_Char *storedversion = NULL;
int standalone = -1;
- if (!(ns
+ if (!(parser->m_ns
? XmlParseXmlDeclNS
: XmlParseXmlDecl)(isGeneralTextEntity,
- encoding,
+ parser->m_encoding,
s,
next,
- &eventPtr,
+ &parser->m_eventPtr,
&version,
&versionend,
&encodingName,
return XML_ERROR_XML_DECL;
}
if (!isGeneralTextEntity && standalone == 1) {
- _dtd->standalone = XML_TRUE;
+ parser->m_dtd->standalone = XML_TRUE;
#ifdef XML_DTD
- if (paramEntityParsing == XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE)
- paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
+ if (parser->m_paramEntityParsing == XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE)
+ parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
#endif /* XML_DTD */
}
- if (xmlDeclHandler) {
+ if (parser->m_xmlDeclHandler) {
if (encodingName != NULL) {
- storedEncName = poolStoreString(&temp2Pool,
- encoding,
+ storedEncName = poolStoreString(&parser->m_temp2Pool,
+ parser->m_encoding,
encodingName,
encodingName
- + XmlNameLength(encoding, encodingName));
+ + XmlNameLength(parser->m_encoding, encodingName));
if (!storedEncName)
return XML_ERROR_NO_MEMORY;
- poolFinish(&temp2Pool);
+ poolFinish(&parser->m_temp2Pool);
}
if (version) {
- storedversion = poolStoreString(&temp2Pool,
- encoding,
+ storedversion = poolStoreString(&parser->m_temp2Pool,
+ parser->m_encoding,
version,
- versionend - encoding->minBytesPerChar);
+ versionend - parser->m_encoding->minBytesPerChar);
if (!storedversion)
return XML_ERROR_NO_MEMORY;
}
- xmlDeclHandler(handlerArg, storedversion, storedEncName, standalone);
+ parser->m_xmlDeclHandler(parser->m_handlerArg, storedversion, storedEncName, standalone);
}
- else if (defaultHandler)
- reportDefault(parser, encoding, s, next);
- if (protocolEncodingName == NULL) {
+ else if (parser->m_defaultHandler)
+ reportDefault(parser, parser->m_encoding, s, next);
+ if (parser->m_protocolEncodingName == NULL) {
if (newEncoding) {
/* Check that the specified encoding does not conflict with what
* the parser has already deduced. Do we have the same number
* of bytes in the smallest representation of a character? If
* this is UTF-16, is it the same endianness?
*/
- if (newEncoding->minBytesPerChar != encoding->minBytesPerChar
+ if (newEncoding->minBytesPerChar != parser->m_encoding->minBytesPerChar
|| (newEncoding->minBytesPerChar == 2 &&
- newEncoding != encoding)) {
- eventPtr = encodingName;
+ newEncoding != parser->m_encoding)) {
+ parser->m_eventPtr = encodingName;
return XML_ERROR_INCORRECT_ENCODING;
}
- encoding = newEncoding;
+ parser->m_encoding = newEncoding;
}
else if (encodingName) {
enum XML_Error result;
if (!storedEncName) {
storedEncName = poolStoreString(
- &temp2Pool, encoding, encodingName,
- encodingName + XmlNameLength(encoding, encodingName));
+ &parser->m_temp2Pool, parser->m_encoding, encodingName,
+ encodingName + XmlNameLength(parser->m_encoding, encodingName));
if (!storedEncName)
return XML_ERROR_NO_MEMORY;
}
result = handleUnknownEncoding(parser, storedEncName);
- poolClear(&temp2Pool);
+ poolClear(&parser->m_temp2Pool);
if (result == XML_ERROR_UNKNOWN_ENCODING)
- eventPtr = encodingName;
+ parser->m_eventPtr = encodingName;
return result;
}
}
if (storedEncName || storedversion)
- poolClear(&temp2Pool);
+ poolClear(&parser->m_temp2Pool);
return XML_ERROR_NONE;
}
static enum XML_Error
handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName)
{
- if (unknownEncodingHandler) {
+ if (parser->m_unknownEncodingHandler) {
XML_Encoding info;
int i;
for (i = 0; i < 256; i++)
info.convert = NULL;
info.data = NULL;
info.release = NULL;
- if (unknownEncodingHandler(unknownEncodingHandlerData, encodingName,
+ if (parser->m_unknownEncodingHandler(parser->m_unknownEncodingHandlerData, encodingName,
&info)) {
ENCODING *enc;
- unknownEncodingMem = MALLOC(XmlSizeOfUnknownEncoding());
- if (!unknownEncodingMem) {
+ parser->m_unknownEncodingMem = MALLOC(parser, XmlSizeOfUnknownEncoding());
+ if (!parser->m_unknownEncodingMem) {
if (info.release)
info.release(info.data);
return XML_ERROR_NO_MEMORY;
}
- enc = (ns
+ enc = (parser->m_ns
? XmlInitUnknownEncodingNS
- : XmlInitUnknownEncoding)(unknownEncodingMem,
+ : XmlInitUnknownEncoding)(parser->m_unknownEncodingMem,
info.map,
info.convert,
info.data);
if (enc) {
- unknownEncodingData = info.data;
- unknownEncodingRelease = info.release;
- encoding = enc;
+ parser->m_unknownEncodingData = info.data;
+ parser->m_unknownEncodingRelease = info.release;
+ parser->m_encoding = enc;
return XML_ERROR_NONE;
}
}
enum XML_Error result = initializeEncoding(parser);
if (result != XML_ERROR_NONE)
return result;
- processor = prologProcessor;
+ parser->m_processor = prologProcessor;
return prologProcessor(parser, s, end, nextPtr);
}
/* we know now that XML_Parse(Buffer) has been called,
so we consider the external parameter entity read */
- _dtd->paramEntityRead = XML_TRUE;
+ parser->m_dtd->paramEntityRead = XML_TRUE;
- if (prologState.inEntityValue) {
- processor = entityValueInitProcessor;
+ if (parser->m_prologState.inEntityValue) {
+ parser->m_processor = entityValueInitProcessor;
return entityValueInitProcessor(parser, s, end, nextPtr);
}
else {
- processor = externalParEntProcessor;
+ parser->m_processor = externalParEntProcessor;
return externalParEntProcessor(parser, s, end, nextPtr);
}
}
int tok;
const char *start = s;
const char *next = start;
- eventPtr = start;
+ parser->m_eventPtr = start;
for (;;) {
- tok = XmlPrologTok(encoding, start, end, &next);
- eventEndPtr = next;
+ tok = XmlPrologTok(parser->m_encoding, start, end, &next);
+ parser->m_eventEndPtr = next;
if (tok <= 0) {
- if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
+ if (!parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
*nextPtr = s;
return XML_ERROR_NONE;
}
break;
}
/* found end of entity value - can store it now */
- return storeEntityValue(parser, encoding, s, end);
+ return storeEntityValue(parser, parser->m_encoding, s, end);
}
else if (tok == XML_TOK_XML_DECL) {
enum XML_Error result;
result = processXmlDecl(parser, 0, start, next);
if (result != XML_ERROR_NONE)
return result;
- /* At this point, ps_parsing cannot be XML_SUSPENDED. For that
+ /* At this point, m_parsingStatus.parsing cannot be XML_SUSPENDED. For that
* to happen, a parameter entity parsing handler must have
* attempted to suspend the parser, which fails and raises an
* error. The parser can be aborted, but can't be suspended.
*/
- if (ps_parsing == XML_FINISHED)
+ if (parser->m_parsingStatus.parsing == XML_FINISHED)
return XML_ERROR_ABORTED;
*nextPtr = next;
/* stop scanning for text declaration - we found one */
- processor = entityValueProcessor;
+ parser->m_processor = entityValueProcessor;
return entityValueProcessor(parser, next, end, nextPtr);
}
/* If we are at the end of the buffer, this would cause XmlPrologTok to
then, when this routine is entered the next time, XmlPrologTok will
return XML_TOK_INVALID, since the BOM is still in the buffer
*/
- else if (tok == XML_TOK_BOM && next == end && !ps_finalBuffer) {
+ else if (tok == XML_TOK_BOM && next == end && !parser->m_parsingStatus.finalBuffer) {
*nextPtr = next;
return XML_ERROR_NONE;
}
return XML_ERROR_SYNTAX;
}
start = next;
- eventPtr = start;
+ parser->m_eventPtr = start;
}
}
const char *next = s;
int tok;
- tok = XmlPrologTok(encoding, s, end, &next);
+ tok = XmlPrologTok(parser->m_encoding, s, end, &next);
if (tok <= 0) {
- if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
+ if (!parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
*nextPtr = s;
return XML_ERROR_NONE;
}
*/
else if (tok == XML_TOK_BOM) {
s = next;
- tok = XmlPrologTok(encoding, s, end, &next);
+ tok = XmlPrologTok(parser->m_encoding, s, end, &next);
}
- processor = prologProcessor;
- return doProlog(parser, encoding, s, end, tok, next,
- nextPtr, (XML_Bool)!ps_finalBuffer);
+ parser->m_processor = prologProcessor;
+ return doProlog(parser, parser->m_encoding, s, end, tok, next,
+ nextPtr, (XML_Bool)!parser->m_parsingStatus.finalBuffer);
}
static enum XML_Error PTRCALL
{
const char *start = s;
const char *next = s;
- const ENCODING *enc = encoding;
+ const ENCODING *enc = parser->m_encoding;
int tok;
for (;;) {
tok = XmlPrologTok(enc, start, end, &next);
if (tok <= 0) {
- if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
+ if (!parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
*nextPtr = s;
return XML_ERROR_NONE;
}
const char **nextPtr)
{
const char *next = s;
- int tok = XmlPrologTok(encoding, s, end, &next);
- return doProlog(parser, encoding, s, end, tok, next,
- nextPtr, (XML_Bool)!ps_finalBuffer);
+ int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+ return doProlog(parser, parser->m_encoding, s, end, tok, next,
+ nextPtr, (XML_Bool)!parser->m_parsingStatus.finalBuffer);
}
static enum XML_Error
static const XML_Char enumValueStart[] = { ASCII_LPAREN, '\0' };
/* save one level of indirection */
- DTD * const dtd = _dtd;
+ DTD * const dtd = parser->m_dtd;
const char **eventPP;
const char **eventEndPP;
enum XML_Content_Quant quant;
- if (enc == encoding) {
- eventPP = &eventPtr;
- eventEndPP = &eventEndPtr;
+ if (enc == parser->m_encoding) {
+ eventPP = &parser->m_eventPtr;
+ eventEndPP = &parser->m_eventEndPtr;
}
else {
- eventPP = &(openInternalEntities->internalEventPtr);
- eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ eventPP = &(parser->m_openInternalEntities->internalEventPtr);
+ eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr);
}
for (;;) {
case XML_TOK_NONE:
#ifdef XML_DTD
/* for internal PE NOT referenced between declarations */
- if (enc != encoding && !openInternalEntities->betweenDecl) {
+ if (enc != parser->m_encoding && !parser->m_openInternalEntities->betweenDecl) {
*nextPtr = s;
return XML_ERROR_NONE;
}
complete markup, not only for external PEs, but also for
internal PEs if the reference occurs between declarations.
*/
- if (isParamEntity || enc != encoding) {
- if (XmlTokenRole(&prologState, XML_TOK_NONE, end, end, enc)
+ if (parser->m_isParamEntity || enc != parser->m_encoding) {
+ if (XmlTokenRole(&parser->m_prologState, XML_TOK_NONE, end, end, enc)
== XML_ROLE_ERROR)
return XML_ERROR_INCOMPLETE_PE;
*nextPtr = s;
break;
}
}
- role = XmlTokenRole(&prologState, tok, s, next, enc);
+ role = XmlTokenRole(&parser->m_prologState, tok, s, next, enc);
switch (role) {
case XML_ROLE_XML_DECL:
{
enum XML_Error result = processXmlDecl(parser, 0, s, next);
if (result != XML_ERROR_NONE)
return result;
- enc = encoding;
+ enc = parser->m_encoding;
handleDefault = XML_FALSE;
}
break;
case XML_ROLE_DOCTYPE_NAME:
- if (startDoctypeDeclHandler) {
- doctypeName = poolStoreString(&tempPool, enc, s, next);
- if (!doctypeName)
+ if (parser->m_startDoctypeDeclHandler) {
+ parser->m_doctypeName = poolStoreString(&parser->m_tempPool, enc, s, next);
+ if (!parser->m_doctypeName)
return XML_ERROR_NO_MEMORY;
- poolFinish(&tempPool);
- doctypePubid = NULL;
+ poolFinish(&parser->m_tempPool);
+ parser->m_doctypePubid = NULL;
handleDefault = XML_FALSE;
}
- doctypeSysid = NULL; /* always initialize to NULL */
+ parser->m_doctypeSysid = NULL; /* always initialize to NULL */
break;
case XML_ROLE_DOCTYPE_INTERNAL_SUBSET:
- if (startDoctypeDeclHandler) {
- startDoctypeDeclHandler(handlerArg, doctypeName, doctypeSysid,
- doctypePubid, 1);
- doctypeName = NULL;
- poolClear(&tempPool);
+ if (parser->m_startDoctypeDeclHandler) {
+ parser->m_startDoctypeDeclHandler(parser->m_handlerArg, parser->m_doctypeName, parser->m_doctypeSysid,
+ parser->m_doctypePubid, 1);
+ parser->m_doctypeName = NULL;
+ poolClear(&parser->m_tempPool);
handleDefault = XML_FALSE;
}
break;
enum XML_Error result = processXmlDecl(parser, 1, s, next);
if (result != XML_ERROR_NONE)
return result;
- enc = encoding;
+ enc = parser->m_encoding;
handleDefault = XML_FALSE;
}
break;
#endif /* XML_DTD */
case XML_ROLE_DOCTYPE_PUBLIC_ID:
#ifdef XML_DTD
- useForeignDTD = XML_FALSE;
- declEntity = (ENTITY *)lookup(parser,
+ parser->m_useForeignDTD = XML_FALSE;
+ parser->m_declEntity = (ENTITY *)lookup(parser,
&dtd->paramEntities,
externalSubsetName,
sizeof(ENTITY));
- if (!declEntity)
+ if (!parser->m_declEntity)
return XML_ERROR_NO_MEMORY;
#endif /* XML_DTD */
dtd->hasParamEntityRefs = XML_TRUE;
- if (startDoctypeDeclHandler) {
+ if (parser->m_startDoctypeDeclHandler) {
XML_Char *pubId;
if (!XmlIsPublicId(enc, s, next, eventPP))
return XML_ERROR_PUBLICID;
- pubId = poolStoreString(&tempPool, enc,
+ pubId = poolStoreString(&parser->m_tempPool, enc,
s + enc->minBytesPerChar,
next - enc->minBytesPerChar);
if (!pubId)
return XML_ERROR_NO_MEMORY;
normalizePublicId(pubId);
- poolFinish(&tempPool);
- doctypePubid = pubId;
+ poolFinish(&parser->m_tempPool);
+ parser->m_doctypePubid = pubId;
handleDefault = XML_FALSE;
goto alreadyChecked;
}
if (!XmlIsPublicId(enc, s, next, eventPP))
return XML_ERROR_PUBLICID;
alreadyChecked:
- if (dtd->keepProcessing && declEntity) {
+ if (dtd->keepProcessing && parser->m_declEntity) {
XML_Char *tem = poolStoreString(&dtd->pool,
enc,
s + enc->minBytesPerChar,
if (!tem)
return XML_ERROR_NO_MEMORY;
normalizePublicId(tem);
- declEntity->publicId = tem;
+ parser->m_declEntity->publicId = tem;
poolFinish(&dtd->pool);
- if (entityDeclHandler)
+ /* Don't suppress the default handler if we fell through from
+ * the XML_ROLE_DOCTYPE_PUBLIC_ID case.
+ */
+ if (parser->m_entityDeclHandler && role == XML_ROLE_ENTITY_PUBLIC_ID)
handleDefault = XML_FALSE;
}
break;
case XML_ROLE_DOCTYPE_CLOSE:
- if (doctypeName) {
- startDoctypeDeclHandler(handlerArg, doctypeName,
- doctypeSysid, doctypePubid, 0);
- poolClear(&tempPool);
+ if (parser->m_doctypeName) {
+ parser->m_startDoctypeDeclHandler(parser->m_handlerArg, parser->m_doctypeName,
+ parser->m_doctypeSysid, parser->m_doctypePubid, 0);
+ poolClear(&parser->m_tempPool);
handleDefault = XML_FALSE;
}
- /* doctypeSysid will be non-NULL in the case of a previous
- XML_ROLE_DOCTYPE_SYSTEM_ID, even if startDoctypeDeclHandler
+ /* parser->m_doctypeSysid will be non-NULL in the case of a previous
+ XML_ROLE_DOCTYPE_SYSTEM_ID, even if parser->m_startDoctypeDeclHandler
was not set, indicating an external subset
*/
#ifdef XML_DTD
- if (doctypeSysid || useForeignDTD) {
+ if (parser->m_doctypeSysid || parser->m_useForeignDTD) {
XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs;
dtd->hasParamEntityRefs = XML_TRUE;
- if (paramEntityParsing && externalEntityRefHandler) {
+ if (parser->m_paramEntityParsing && parser->m_externalEntityRefHandler) {
ENTITY *entity = (ENTITY *)lookup(parser,
&dtd->paramEntities,
externalSubsetName,
*/
return XML_ERROR_NO_MEMORY; /* LCOV_EXCL_LINE */
}
- if (useForeignDTD)
- entity->base = curBase;
+ if (parser->m_useForeignDTD)
+ entity->base = parser->m_curBase;
dtd->paramEntityRead = XML_FALSE;
- if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ if (!parser->m_externalEntityRefHandler(parser->m_externalEntityRefHandlerArg,
0,
entity->base,
entity->systemId,
return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
if (dtd->paramEntityRead) {
if (!dtd->standalone &&
- notStandaloneHandler &&
- !notStandaloneHandler(handlerArg))
+ parser->m_notStandaloneHandler &&
+ !parser->m_notStandaloneHandler(parser->m_handlerArg))
return XML_ERROR_NOT_STANDALONE;
}
/* if we didn't read the foreign DTD then this means that there
is no external subset and we must reset dtd->hasParamEntityRefs
*/
- else if (!doctypeSysid)
+ else if (!parser->m_doctypeSysid)
dtd->hasParamEntityRefs = hadParamEntityRefs;
/* end of DTD - no need to update dtd->keepProcessing */
}
- useForeignDTD = XML_FALSE;
+ parser->m_useForeignDTD = XML_FALSE;
}
#endif /* XML_DTD */
- if (endDoctypeDeclHandler) {
- endDoctypeDeclHandler(handlerArg);
+ if (parser->m_endDoctypeDeclHandler) {
+ parser->m_endDoctypeDeclHandler(parser->m_handlerArg);
handleDefault = XML_FALSE;
}
break;
/* if there is no DOCTYPE declaration then now is the
last chance to read the foreign DTD
*/
- if (useForeignDTD) {
+ if (parser->m_useForeignDTD) {
XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs;
dtd->hasParamEntityRefs = XML_TRUE;
- if (paramEntityParsing && externalEntityRefHandler) {
+ if (parser->m_paramEntityParsing && parser->m_externalEntityRefHandler) {
ENTITY *entity = (ENTITY *)lookup(parser, &dtd->paramEntities,
externalSubsetName,
sizeof(ENTITY));
if (!entity)
return XML_ERROR_NO_MEMORY;
- entity->base = curBase;
+ entity->base = parser->m_curBase;
dtd->paramEntityRead = XML_FALSE;
- if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ if (!parser->m_externalEntityRefHandler(parser->m_externalEntityRefHandlerArg,
0,
entity->base,
entity->systemId,
return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
if (dtd->paramEntityRead) {
if (!dtd->standalone &&
- notStandaloneHandler &&
- !notStandaloneHandler(handlerArg))
+ parser->m_notStandaloneHandler &&
+ !parser->m_notStandaloneHandler(parser->m_handlerArg))
return XML_ERROR_NOT_STANDALONE;
}
/* if we didn't read the foreign DTD then this means that there
}
}
#endif /* XML_DTD */
- processor = contentProcessor;
+ parser->m_processor = contentProcessor;
return contentProcessor(parser, s, end, nextPtr);
case XML_ROLE_ATTLIST_ELEMENT_NAME:
- declElementType = getElementType(parser, enc, s, next);
- if (!declElementType)
+ parser->m_declElementType = getElementType(parser, enc, s, next);
+ if (!parser->m_declElementType)
return XML_ERROR_NO_MEMORY;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_NAME:
- declAttributeId = getAttributeId(parser, enc, s, next);
- if (!declAttributeId)
+ parser->m_declAttributeId = getAttributeId(parser, enc, s, next);
+ if (!parser->m_declAttributeId)
return XML_ERROR_NO_MEMORY;
- declAttributeIsCdata = XML_FALSE;
- declAttributeType = NULL;
- declAttributeIsId = XML_FALSE;
+ parser->m_declAttributeIsCdata = XML_FALSE;
+ parser->m_declAttributeType = NULL;
+ parser->m_declAttributeIsId = XML_FALSE;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_TYPE_CDATA:
- declAttributeIsCdata = XML_TRUE;
- declAttributeType = atypeCDATA;
+ parser->m_declAttributeIsCdata = XML_TRUE;
+ parser->m_declAttributeType = atypeCDATA;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_TYPE_ID:
- declAttributeIsId = XML_TRUE;
- declAttributeType = atypeID;
+ parser->m_declAttributeIsId = XML_TRUE;
+ parser->m_declAttributeType = atypeID;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_TYPE_IDREF:
- declAttributeType = atypeIDREF;
+ parser->m_declAttributeType = atypeIDREF;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_TYPE_IDREFS:
- declAttributeType = atypeIDREFS;
+ parser->m_declAttributeType = atypeIDREFS;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_TYPE_ENTITY:
- declAttributeType = atypeENTITY;
+ parser->m_declAttributeType = atypeENTITY;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_TYPE_ENTITIES:
- declAttributeType = atypeENTITIES;
+ parser->m_declAttributeType = atypeENTITIES;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN:
- declAttributeType = atypeNMTOKEN;
+ parser->m_declAttributeType = atypeNMTOKEN;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS:
- declAttributeType = atypeNMTOKENS;
+ parser->m_declAttributeType = atypeNMTOKENS;
checkAttListDeclHandler:
- if (dtd->keepProcessing && attlistDeclHandler)
+ if (dtd->keepProcessing && parser->m_attlistDeclHandler)
handleDefault = XML_FALSE;
break;
case XML_ROLE_ATTRIBUTE_ENUM_VALUE:
case XML_ROLE_ATTRIBUTE_NOTATION_VALUE:
- if (dtd->keepProcessing && attlistDeclHandler) {
+ if (dtd->keepProcessing && parser->m_attlistDeclHandler) {
const XML_Char *prefix;
- if (declAttributeType) {
+ if (parser->m_declAttributeType) {
prefix = enumValueSep;
}
else {
? notationPrefix
: enumValueStart);
}
- if (!poolAppendString(&tempPool, prefix))
+ if (!poolAppendString(&parser->m_tempPool, prefix))
return XML_ERROR_NO_MEMORY;
- if (!poolAppend(&tempPool, enc, s, next))
+ if (!poolAppend(&parser->m_tempPool, enc, s, next))
return XML_ERROR_NO_MEMORY;
- declAttributeType = tempPool.start;
+ parser->m_declAttributeType = parser->m_tempPool.start;
handleDefault = XML_FALSE;
}
break;
case XML_ROLE_IMPLIED_ATTRIBUTE_VALUE:
case XML_ROLE_REQUIRED_ATTRIBUTE_VALUE:
if (dtd->keepProcessing) {
- if (!defineAttribute(declElementType, declAttributeId,
- declAttributeIsCdata, declAttributeIsId,
+ if (!defineAttribute(parser->m_declElementType, parser->m_declAttributeId,
+ parser->m_declAttributeIsCdata, parser->m_declAttributeIsId,
0, parser))
return XML_ERROR_NO_MEMORY;
- if (attlistDeclHandler && declAttributeType) {
- if (*declAttributeType == XML_T(ASCII_LPAREN)
- || (*declAttributeType == XML_T(ASCII_N)
- && declAttributeType[1] == XML_T(ASCII_O))) {
+ if (parser->m_attlistDeclHandler && parser->m_declAttributeType) {
+ if (*parser->m_declAttributeType == XML_T(ASCII_LPAREN)
+ || (*parser->m_declAttributeType == XML_T(ASCII_N)
+ && parser->m_declAttributeType[1] == XML_T(ASCII_O))) {
/* Enumerated or Notation type */
- if (!poolAppendChar(&tempPool, XML_T(ASCII_RPAREN))
- || !poolAppendChar(&tempPool, XML_T('\0')))
+ if (!poolAppendChar(&parser->m_tempPool, XML_T(ASCII_RPAREN))
+ || !poolAppendChar(&parser->m_tempPool, XML_T('\0')))
return XML_ERROR_NO_MEMORY;
- declAttributeType = tempPool.start;
- poolFinish(&tempPool);
+ parser->m_declAttributeType = parser->m_tempPool.start;
+ poolFinish(&parser->m_tempPool);
}
*eventEndPP = s;
- attlistDeclHandler(handlerArg, declElementType->name,
- declAttributeId->name, declAttributeType,
+ parser->m_attlistDeclHandler(parser->m_handlerArg, parser->m_declElementType->name,
+ parser->m_declAttributeId->name, parser->m_declAttributeType,
0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE);
- poolClear(&tempPool);
+ poolClear(&parser->m_tempPool);
handleDefault = XML_FALSE;
}
}
if (dtd->keepProcessing) {
const XML_Char *attVal;
enum XML_Error result =
- storeAttributeValue(parser, enc, declAttributeIsCdata,
+ storeAttributeValue(parser, enc, parser->m_declAttributeIsCdata,
s + enc->minBytesPerChar,
next - enc->minBytesPerChar,
&dtd->pool);
attVal = poolStart(&dtd->pool);
poolFinish(&dtd->pool);
/* ID attributes aren't allowed to have a default */
- if (!defineAttribute(declElementType, declAttributeId,
- declAttributeIsCdata, XML_FALSE, attVal, parser))
+ if (!defineAttribute(parser->m_declElementType, parser->m_declAttributeId,
+ parser->m_declAttributeIsCdata, XML_FALSE, attVal, parser))
return XML_ERROR_NO_MEMORY;
- if (attlistDeclHandler && declAttributeType) {
- if (*declAttributeType == XML_T(ASCII_LPAREN)
- || (*declAttributeType == XML_T(ASCII_N)
- && declAttributeType[1] == XML_T(ASCII_O))) {
+ if (parser->m_attlistDeclHandler && parser->m_declAttributeType) {
+ if (*parser->m_declAttributeType == XML_T(ASCII_LPAREN)
+ || (*parser->m_declAttributeType == XML_T(ASCII_N)
+ && parser->m_declAttributeType[1] == XML_T(ASCII_O))) {
/* Enumerated or Notation type */
- if (!poolAppendChar(&tempPool, XML_T(ASCII_RPAREN))
- || !poolAppendChar(&tempPool, XML_T('\0')))
+ if (!poolAppendChar(&parser->m_tempPool, XML_T(ASCII_RPAREN))
+ || !poolAppendChar(&parser->m_tempPool, XML_T('\0')))
return XML_ERROR_NO_MEMORY;
- declAttributeType = tempPool.start;
- poolFinish(&tempPool);
+ parser->m_declAttributeType = parser->m_tempPool.start;
+ poolFinish(&parser->m_tempPool);
}
*eventEndPP = s;
- attlistDeclHandler(handlerArg, declElementType->name,
- declAttributeId->name, declAttributeType,
+ parser->m_attlistDeclHandler(parser->m_handlerArg, parser->m_declElementType->name,
+ parser->m_declAttributeId->name, parser->m_declAttributeType,
attVal,
role == XML_ROLE_FIXED_ATTRIBUTE_VALUE);
- poolClear(&tempPool);
+ poolClear(&parser->m_tempPool);
handleDefault = XML_FALSE;
}
}
enum XML_Error result = storeEntityValue(parser, enc,
s + enc->minBytesPerChar,
next - enc->minBytesPerChar);
- if (declEntity) {
- declEntity->textPtr = poolStart(&dtd->entityValuePool);
- declEntity->textLen = (int)(poolLength(&dtd->entityValuePool));
+ if (parser->m_declEntity) {
+ parser->m_declEntity->textPtr = poolStart(&dtd->entityValuePool);
+ parser->m_declEntity->textLen = (int)(poolLength(&dtd->entityValuePool));
poolFinish(&dtd->entityValuePool);
- if (entityDeclHandler) {
+ if (parser->m_entityDeclHandler) {
*eventEndPP = s;
- entityDeclHandler(handlerArg,
- declEntity->name,
- declEntity->is_param,
- declEntity->textPtr,
- declEntity->textLen,
- curBase, 0, 0, 0);
+ parser->m_entityDeclHandler(parser->m_handlerArg,
+ parser->m_declEntity->name,
+ parser->m_declEntity->is_param,
+ parser->m_declEntity->textPtr,
+ parser->m_declEntity->textLen,
+ parser->m_curBase, 0, 0, 0);
handleDefault = XML_FALSE;
}
}
break;
case XML_ROLE_DOCTYPE_SYSTEM_ID:
#ifdef XML_DTD
- useForeignDTD = XML_FALSE;
+ parser->m_useForeignDTD = XML_FALSE;
#endif /* XML_DTD */
dtd->hasParamEntityRefs = XML_TRUE;
- if (startDoctypeDeclHandler) {
- doctypeSysid = poolStoreString(&tempPool, enc,
+ if (parser->m_startDoctypeDeclHandler) {
+ parser->m_doctypeSysid = poolStoreString(&parser->m_tempPool, enc,
s + enc->minBytesPerChar,
next - enc->minBytesPerChar);
- if (doctypeSysid == NULL)
+ if (parser->m_doctypeSysid == NULL)
return XML_ERROR_NO_MEMORY;
- poolFinish(&tempPool);
+ poolFinish(&parser->m_tempPool);
handleDefault = XML_FALSE;
}
#ifdef XML_DTD
else
- /* use externalSubsetName to make doctypeSysid non-NULL
- for the case where no startDoctypeDeclHandler is set */
- doctypeSysid = externalSubsetName;
+ /* use externalSubsetName to make parser->m_doctypeSysid non-NULL
+ for the case where no parser->m_startDoctypeDeclHandler is set */
+ parser->m_doctypeSysid = externalSubsetName;
#endif /* XML_DTD */
if (!dtd->standalone
#ifdef XML_DTD
- && !paramEntityParsing
+ && !parser->m_paramEntityParsing
#endif /* XML_DTD */
- && notStandaloneHandler
- && !notStandaloneHandler(handlerArg))
+ && parser->m_notStandaloneHandler
+ && !parser->m_notStandaloneHandler(parser->m_handlerArg))
return XML_ERROR_NOT_STANDALONE;
#ifndef XML_DTD
break;
#else /* XML_DTD */
- if (!declEntity) {
- declEntity = (ENTITY *)lookup(parser,
+ if (!parser->m_declEntity) {
+ parser->m_declEntity = (ENTITY *)lookup(parser,
&dtd->paramEntities,
externalSubsetName,
sizeof(ENTITY));
- if (!declEntity)
+ if (!parser->m_declEntity)
return XML_ERROR_NO_MEMORY;
- declEntity->publicId = NULL;
+ parser->m_declEntity->publicId = NULL;
}
- /* fall through */
#endif /* XML_DTD */
+ /* fall through */
case XML_ROLE_ENTITY_SYSTEM_ID:
- if (dtd->keepProcessing && declEntity) {
- declEntity->systemId = poolStoreString(&dtd->pool, enc,
+ if (dtd->keepProcessing && parser->m_declEntity) {
+ parser->m_declEntity->systemId = poolStoreString(&dtd->pool, enc,
s + enc->minBytesPerChar,
next - enc->minBytesPerChar);
- if (!declEntity->systemId)
+ if (!parser->m_declEntity->systemId)
return XML_ERROR_NO_MEMORY;
- declEntity->base = curBase;
+ parser->m_declEntity->base = parser->m_curBase;
poolFinish(&dtd->pool);
- if (entityDeclHandler)
+ /* Don't suppress the default handler if we fell through from
+ * the XML_ROLE_DOCTYPE_SYSTEM_ID case.
+ */
+ if (parser->m_entityDeclHandler && role == XML_ROLE_ENTITY_SYSTEM_ID)
handleDefault = XML_FALSE;
}
break;
case XML_ROLE_ENTITY_COMPLETE:
- if (dtd->keepProcessing && declEntity && entityDeclHandler) {
+ if (dtd->keepProcessing && parser->m_declEntity && parser->m_entityDeclHandler) {
*eventEndPP = s;
- entityDeclHandler(handlerArg,
- declEntity->name,
- declEntity->is_param,
+ parser->m_entityDeclHandler(parser->m_handlerArg,
+ parser->m_declEntity->name,
+ parser->m_declEntity->is_param,
0,0,
- declEntity->base,
- declEntity->systemId,
- declEntity->publicId,
+ parser->m_declEntity->base,
+ parser->m_declEntity->systemId,
+ parser->m_declEntity->publicId,
0);
handleDefault = XML_FALSE;
}
break;
case XML_ROLE_ENTITY_NOTATION_NAME:
- if (dtd->keepProcessing && declEntity) {
- declEntity->notation = poolStoreString(&dtd->pool, enc, s, next);
- if (!declEntity->notation)
+ if (dtd->keepProcessing && parser->m_declEntity) {
+ parser->m_declEntity->notation = poolStoreString(&dtd->pool, enc, s, next);
+ if (!parser->m_declEntity->notation)
return XML_ERROR_NO_MEMORY;
poolFinish(&dtd->pool);
- if (unparsedEntityDeclHandler) {
+ if (parser->m_unparsedEntityDeclHandler) {
*eventEndPP = s;
- unparsedEntityDeclHandler(handlerArg,
- declEntity->name,
- declEntity->base,
- declEntity->systemId,
- declEntity->publicId,
- declEntity->notation);
+ parser->m_unparsedEntityDeclHandler(parser->m_handlerArg,
+ parser->m_declEntity->name,
+ parser->m_declEntity->base,
+ parser->m_declEntity->systemId,
+ parser->m_declEntity->publicId,
+ parser->m_declEntity->notation);
handleDefault = XML_FALSE;
}
- else if (entityDeclHandler) {
+ else if (parser->m_entityDeclHandler) {
*eventEndPP = s;
- entityDeclHandler(handlerArg,
- declEntity->name,
+ parser->m_entityDeclHandler(parser->m_handlerArg,
+ parser->m_declEntity->name,
0,0,0,
- declEntity->base,
- declEntity->systemId,
- declEntity->publicId,
- declEntity->notation);
+ parser->m_declEntity->base,
+ parser->m_declEntity->systemId,
+ parser->m_declEntity->publicId,
+ parser->m_declEntity->notation);
handleDefault = XML_FALSE;
}
}
case XML_ROLE_GENERAL_ENTITY_NAME:
{
if (XmlPredefinedEntityName(enc, s, next)) {
- declEntity = NULL;
+ parser->m_declEntity = NULL;
break;
}
if (dtd->keepProcessing) {
const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
if (!name)
return XML_ERROR_NO_MEMORY;
- declEntity = (ENTITY *)lookup(parser, &dtd->generalEntities, name,
+ parser->m_declEntity = (ENTITY *)lookup(parser, &dtd->generalEntities, name,
sizeof(ENTITY));
- if (!declEntity)
+ if (!parser->m_declEntity)
return XML_ERROR_NO_MEMORY;
- if (declEntity->name != name) {
+ if (parser->m_declEntity->name != name) {
poolDiscard(&dtd->pool);
- declEntity = NULL;
+ parser->m_declEntity = NULL;
}
else {
poolFinish(&dtd->pool);
- declEntity->publicId = NULL;
- declEntity->is_param = XML_FALSE;
+ parser->m_declEntity->publicId = NULL;
+ parser->m_declEntity->is_param = XML_FALSE;
/* if we have a parent parser or are reading an internal parameter
entity, then the entity declaration is not considered "internal"
*/
- declEntity->is_internal = !(parentParser || openInternalEntities);
- if (entityDeclHandler)
+ parser->m_declEntity->is_internal = !(parser->m_parentParser || parser->m_openInternalEntities);
+ if (parser->m_entityDeclHandler)
handleDefault = XML_FALSE;
}
}
else {
poolDiscard(&dtd->pool);
- declEntity = NULL;
+ parser->m_declEntity = NULL;
}
}
break;
const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
if (!name)
return XML_ERROR_NO_MEMORY;
- declEntity = (ENTITY *)lookup(parser, &dtd->paramEntities,
+ parser->m_declEntity = (ENTITY *)lookup(parser, &dtd->paramEntities,
name, sizeof(ENTITY));
- if (!declEntity)
+ if (!parser->m_declEntity)
return XML_ERROR_NO_MEMORY;
- if (declEntity->name != name) {
+ if (parser->m_declEntity->name != name) {
poolDiscard(&dtd->pool);
- declEntity = NULL;
+ parser->m_declEntity = NULL;
}
else {
poolFinish(&dtd->pool);
- declEntity->publicId = NULL;
- declEntity->is_param = XML_TRUE;
+ parser->m_declEntity->publicId = NULL;
+ parser->m_declEntity->is_param = XML_TRUE;
/* if we have a parent parser or are reading an internal parameter
entity, then the entity declaration is not considered "internal"
*/
- declEntity->is_internal = !(parentParser || openInternalEntities);
- if (entityDeclHandler)
+ parser->m_declEntity->is_internal = !(parser->m_parentParser || parser->m_openInternalEntities);
+ if (parser->m_entityDeclHandler)
handleDefault = XML_FALSE;
}
}
else {
poolDiscard(&dtd->pool);
- declEntity = NULL;
+ parser->m_declEntity = NULL;
}
#else /* not XML_DTD */
- declEntity = NULL;
+ parser->m_declEntity = NULL;
#endif /* XML_DTD */
break;
case XML_ROLE_NOTATION_NAME:
- declNotationPublicId = NULL;
- declNotationName = NULL;
- if (notationDeclHandler) {
- declNotationName = poolStoreString(&tempPool, enc, s, next);
- if (!declNotationName)
+ parser->m_declNotationPublicId = NULL;
+ parser->m_declNotationName = NULL;
+ if (parser->m_notationDeclHandler) {
+ parser->m_declNotationName = poolStoreString(&parser->m_tempPool, enc, s, next);
+ if (!parser->m_declNotationName)
return XML_ERROR_NO_MEMORY;
- poolFinish(&tempPool);
+ poolFinish(&parser->m_tempPool);
handleDefault = XML_FALSE;
}
break;
case XML_ROLE_NOTATION_PUBLIC_ID:
if (!XmlIsPublicId(enc, s, next, eventPP))
return XML_ERROR_PUBLICID;
- if (declNotationName) { /* means notationDeclHandler != NULL */
- XML_Char *tem = poolStoreString(&tempPool,
+ if (parser->m_declNotationName) { /* means m_notationDeclHandler != NULL */
+ XML_Char *tem = poolStoreString(&parser->m_tempPool,
enc,
s + enc->minBytesPerChar,
next - enc->minBytesPerChar);
if (!tem)
return XML_ERROR_NO_MEMORY;
normalizePublicId(tem);
- declNotationPublicId = tem;
- poolFinish(&tempPool);
+ parser->m_declNotationPublicId = tem;
+ poolFinish(&parser->m_tempPool);
handleDefault = XML_FALSE;
}
break;
case XML_ROLE_NOTATION_SYSTEM_ID:
- if (declNotationName && notationDeclHandler) {
+ if (parser->m_declNotationName && parser->m_notationDeclHandler) {
const XML_Char *systemId
- = poolStoreString(&tempPool, enc,
+ = poolStoreString(&parser->m_tempPool, enc,
s + enc->minBytesPerChar,
next - enc->minBytesPerChar);
if (!systemId)
return XML_ERROR_NO_MEMORY;
*eventEndPP = s;
- notationDeclHandler(handlerArg,
- declNotationName,
- curBase,
+ parser->m_notationDeclHandler(parser->m_handlerArg,
+ parser->m_declNotationName,
+ parser->m_curBase,
systemId,
- declNotationPublicId);
+ parser->m_declNotationPublicId);
handleDefault = XML_FALSE;
}
- poolClear(&tempPool);
+ poolClear(&parser->m_tempPool);
break;
case XML_ROLE_NOTATION_NO_SYSTEM_ID:
- if (declNotationPublicId && notationDeclHandler) {
+ if (parser->m_declNotationPublicId && parser->m_notationDeclHandler) {
*eventEndPP = s;
- notationDeclHandler(handlerArg,
- declNotationName,
- curBase,
+ parser->m_notationDeclHandler(parser->m_handlerArg,
+ parser->m_declNotationName,
+ parser->m_curBase,
0,
- declNotationPublicId);
+ parser->m_declNotationPublicId);
handleDefault = XML_FALSE;
}
- poolClear(&tempPool);
+ poolClear(&parser->m_tempPool);
break;
case XML_ROLE_ERROR:
switch (tok) {
case XML_ROLE_IGNORE_SECT:
{
enum XML_Error result;
- if (defaultHandler)
+ if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
handleDefault = XML_FALSE;
result = doIgnoreSection(parser, enc, &next, end, nextPtr, haveMore);
if (result != XML_ERROR_NONE)
return result;
else if (!next) {
- processor = ignoreSectionProcessor;
+ parser->m_processor = ignoreSectionProcessor;
return result;
}
}
break;
#endif /* XML_DTD */
case XML_ROLE_GROUP_OPEN:
- if (prologState.level >= groupSize) {
- if (groupSize) {
- char *temp = (char *)REALLOC(groupConnector, groupSize *= 2);
+ if (parser->m_prologState.level >= parser->m_groupSize) {
+ if (parser->m_groupSize) {
+ char *temp = (char *)REALLOC(parser, parser->m_groupConnector, parser->m_groupSize *= 2);
if (temp == NULL) {
- groupSize /= 2;
+ parser->m_groupSize /= 2;
return XML_ERROR_NO_MEMORY;
}
- groupConnector = temp;
+ parser->m_groupConnector = temp;
if (dtd->scaffIndex) {
- int *temp = (int *)REALLOC(dtd->scaffIndex,
- groupSize * sizeof(int));
+ int *temp = (int *)REALLOC(parser, dtd->scaffIndex,
+ parser->m_groupSize * sizeof(int));
if (temp == NULL)
return XML_ERROR_NO_MEMORY;
dtd->scaffIndex = temp;
}
}
else {
- groupConnector = (char *)MALLOC(groupSize = 32);
- if (!groupConnector) {
- groupSize = 0;
+ parser->m_groupConnector = (char *)MALLOC(parser, parser->m_groupSize = 32);
+ if (!parser->m_groupConnector) {
+ parser->m_groupSize = 0;
return XML_ERROR_NO_MEMORY;
}
}
}
- groupConnector[prologState.level] = 0;
+ parser->m_groupConnector[parser->m_prologState.level] = 0;
if (dtd->in_eldecl) {
int myindex = nextScaffoldPart(parser);
if (myindex < 0)
dtd->scaffIndex[dtd->scaffLevel] = myindex;
dtd->scaffLevel++;
dtd->scaffold[myindex].type = XML_CTYPE_SEQ;
- if (elementDeclHandler)
+ if (parser->m_elementDeclHandler)
handleDefault = XML_FALSE;
}
break;
case XML_ROLE_GROUP_SEQUENCE:
- if (groupConnector[prologState.level] == ASCII_PIPE)
+ if (parser->m_groupConnector[parser->m_prologState.level] == ASCII_PIPE)
return XML_ERROR_SYNTAX;
- groupConnector[prologState.level] = ASCII_COMMA;
- if (dtd->in_eldecl && elementDeclHandler)
+ parser->m_groupConnector[parser->m_prologState.level] = ASCII_COMMA;
+ if (dtd->in_eldecl && parser->m_elementDeclHandler)
handleDefault = XML_FALSE;
break;
case XML_ROLE_GROUP_CHOICE:
- if (groupConnector[prologState.level] == ASCII_COMMA)
+ if (parser->m_groupConnector[parser->m_prologState.level] == ASCII_COMMA)
return XML_ERROR_SYNTAX;
if (dtd->in_eldecl
- && !groupConnector[prologState.level]
+ && !parser->m_groupConnector[parser->m_prologState.level]
&& (dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
!= XML_CTYPE_MIXED)
) {
dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
= XML_CTYPE_CHOICE;
- if (elementDeclHandler)
+ if (parser->m_elementDeclHandler)
handleDefault = XML_FALSE;
}
- groupConnector[prologState.level] = ASCII_PIPE;
+ parser->m_groupConnector[parser->m_prologState.level] = ASCII_PIPE;
break;
case XML_ROLE_PARAM_ENTITY_REF:
#ifdef XML_DTD
case XML_ROLE_INNER_PARAM_ENTITY_REF:
dtd->hasParamEntityRefs = XML_TRUE;
- if (!paramEntityParsing)
+ if (!parser->m_paramEntityParsing)
dtd->keepProcessing = dtd->standalone;
else {
const XML_Char *name;
if yes, check that the entity exists, and that it is internal,
otherwise call the skipped entity handler
*/
- if (prologState.documentEntity &&
+ if (parser->m_prologState.documentEntity &&
(dtd->standalone
- ? !openInternalEntities
+ ? !parser->m_openInternalEntities
: !dtd->hasParamEntityRefs)) {
if (!entity)
return XML_ERROR_UNDEFINED_ENTITY;
else if (!entity) {
dtd->keepProcessing = dtd->standalone;
/* cannot report skipped entities in declarations */
- if ((role == XML_ROLE_PARAM_ENTITY_REF) && skippedEntityHandler) {
- skippedEntityHandler(handlerArg, name, 1);
+ if ((role == XML_ROLE_PARAM_ENTITY_REF) && parser->m_skippedEntityHandler) {
+ parser->m_skippedEntityHandler(parser->m_handlerArg, name, 1);
handleDefault = XML_FALSE;
}
break;
handleDefault = XML_FALSE;
break;
}
- if (externalEntityRefHandler) {
+ if (parser->m_externalEntityRefHandler) {
dtd->paramEntityRead = XML_FALSE;
entity->open = XML_TRUE;
- if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ if (!parser->m_externalEntityRefHandler(parser->m_externalEntityRefHandlerArg,
0,
entity->base,
entity->systemId,
}
#endif /* XML_DTD */
if (!dtd->standalone &&
- notStandaloneHandler &&
- !notStandaloneHandler(handlerArg))
+ parser->m_notStandaloneHandler &&
+ !parser->m_notStandaloneHandler(parser->m_handlerArg))
return XML_ERROR_NOT_STANDALONE;
break;
/* Element declaration stuff */
case XML_ROLE_ELEMENT_NAME:
- if (elementDeclHandler) {
- declElementType = getElementType(parser, enc, s, next);
- if (!declElementType)
+ if (parser->m_elementDeclHandler) {
+ parser->m_declElementType = getElementType(parser, enc, s, next);
+ if (!parser->m_declElementType)
return XML_ERROR_NO_MEMORY;
dtd->scaffLevel = 0;
dtd->scaffCount = 0;
case XML_ROLE_CONTENT_ANY:
case XML_ROLE_CONTENT_EMPTY:
if (dtd->in_eldecl) {
- if (elementDeclHandler) {
- XML_Content * content = (XML_Content *) MALLOC(sizeof(XML_Content));
+ if (parser->m_elementDeclHandler) {
+ XML_Content * content = (XML_Content *) MALLOC(parser, sizeof(XML_Content));
if (!content)
return XML_ERROR_NO_MEMORY;
content->quant = XML_CQUANT_NONE;
XML_CTYPE_ANY :
XML_CTYPE_EMPTY);
*eventEndPP = s;
- elementDeclHandler(handlerArg, declElementType->name, content);
+ parser->m_elementDeclHandler(parser->m_handlerArg, parser->m_declElementType->name, content);
handleDefault = XML_FALSE;
}
dtd->in_eldecl = XML_FALSE;
if (dtd->in_eldecl) {
dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
= XML_CTYPE_MIXED;
- if (elementDeclHandler)
+ if (parser->m_elementDeclHandler)
handleDefault = XML_FALSE;
}
break;
nameLen = 0;
for (; name[nameLen++]; );
dtd->contentStringLen += nameLen;
- if (elementDeclHandler)
+ if (parser->m_elementDeclHandler)
handleDefault = XML_FALSE;
}
break;
quant = XML_CQUANT_PLUS;
closeGroup:
if (dtd->in_eldecl) {
- if (elementDeclHandler)
+ if (parser->m_elementDeclHandler)
handleDefault = XML_FALSE;
dtd->scaffLevel--;
dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel]].quant = quant;
if (!model)
return XML_ERROR_NO_MEMORY;
*eventEndPP = s;
- elementDeclHandler(handlerArg, declElementType->name, model);
+ parser->m_elementDeclHandler(parser->m_handlerArg, parser->m_declElementType->name, model);
}
dtd->in_eldecl = XML_FALSE;
dtd->contentStringLen = 0;
}
break;
case XML_ROLE_DOCTYPE_NONE:
- if (startDoctypeDeclHandler)
+ if (parser->m_startDoctypeDeclHandler)
handleDefault = XML_FALSE;
break;
case XML_ROLE_ENTITY_NONE:
- if (dtd->keepProcessing && entityDeclHandler)
+ if (dtd->keepProcessing && parser->m_entityDeclHandler)
handleDefault = XML_FALSE;
break;
case XML_ROLE_NOTATION_NONE:
- if (notationDeclHandler)
+ if (parser->m_notationDeclHandler)
handleDefault = XML_FALSE;
break;
case XML_ROLE_ATTLIST_NONE:
- if (dtd->keepProcessing && attlistDeclHandler)
+ if (dtd->keepProcessing && parser->m_attlistDeclHandler)
handleDefault = XML_FALSE;
break;
case XML_ROLE_ELEMENT_NONE:
- if (elementDeclHandler)
+ if (parser->m_elementDeclHandler)
handleDefault = XML_FALSE;
break;
} /* end of big switch */
- if (handleDefault && defaultHandler)
+ if (handleDefault && parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
*nextPtr = next;
return XML_ERROR_NONE;
const char *end,
const char **nextPtr)
{
- processor = epilogProcessor;
- eventPtr = s;
+ parser->m_processor = epilogProcessor;
+ parser->m_eventPtr = s;
for (;;) {
const char *next = NULL;
- int tok = XmlPrologTok(encoding, s, end, &next);
- eventEndPtr = next;
+ int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+ parser->m_eventEndPtr = next;
switch (tok) {
/* report partial linebreak - it might be the last token */
case -XML_TOK_PROLOG_S:
- if (defaultHandler) {
- reportDefault(parser, encoding, s, next);
- if (ps_parsing == XML_FINISHED)
+ if (parser->m_defaultHandler) {
+ reportDefault(parser, parser->m_encoding, s, next);
+ if (parser->m_parsingStatus.parsing == XML_FINISHED)
return XML_ERROR_ABORTED;
}
*nextPtr = next;
*nextPtr = s;
return XML_ERROR_NONE;
case XML_TOK_PROLOG_S:
- if (defaultHandler)
- reportDefault(parser, encoding, s, next);
+ if (parser->m_defaultHandler)
+ reportDefault(parser, parser->m_encoding, s, next);
break;
case XML_TOK_PI:
- if (!reportProcessingInstruction(parser, encoding, s, next))
+ if (!reportProcessingInstruction(parser, parser->m_encoding, s, next))
return XML_ERROR_NO_MEMORY;
break;
case XML_TOK_COMMENT:
- if (!reportComment(parser, encoding, s, next))
+ if (!reportComment(parser, parser->m_encoding, s, next))
return XML_ERROR_NO_MEMORY;
break;
case XML_TOK_INVALID:
- eventPtr = next;
+ parser->m_eventPtr = next;
return XML_ERROR_INVALID_TOKEN;
case XML_TOK_PARTIAL:
- if (!ps_finalBuffer) {
+ if (!parser->m_parsingStatus.finalBuffer) {
*nextPtr = s;
return XML_ERROR_NONE;
}
return XML_ERROR_UNCLOSED_TOKEN;
case XML_TOK_PARTIAL_CHAR:
- if (!ps_finalBuffer) {
+ if (!parser->m_parsingStatus.finalBuffer) {
*nextPtr = s;
return XML_ERROR_NONE;
}
default:
return XML_ERROR_JUNK_AFTER_DOC_ELEMENT;
}
- eventPtr = s = next;
- switch (ps_parsing) {
+ parser->m_eventPtr = s = next;
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
*nextPtr = next;
return XML_ERROR_NONE;
enum XML_Error result;
OPEN_INTERNAL_ENTITY *openEntity;
- if (freeInternalEntities) {
- openEntity = freeInternalEntities;
- freeInternalEntities = openEntity->next;
+ if (parser->m_freeInternalEntities) {
+ openEntity = parser->m_freeInternalEntities;
+ parser->m_freeInternalEntities = openEntity->next;
}
else {
- openEntity = (OPEN_INTERNAL_ENTITY *)MALLOC(sizeof(OPEN_INTERNAL_ENTITY));
+ openEntity = (OPEN_INTERNAL_ENTITY *)MALLOC(parser, sizeof(OPEN_INTERNAL_ENTITY));
if (!openEntity)
return XML_ERROR_NO_MEMORY;
}
entity->open = XML_TRUE;
entity->processed = 0;
- openEntity->next = openInternalEntities;
- openInternalEntities = openEntity;
+ openEntity->next = parser->m_openInternalEntities;
+ parser->m_openInternalEntities = openEntity;
openEntity->entity = entity;
- openEntity->startTagLevel = tagLevel;
+ openEntity->startTagLevel = parser->m_tagLevel;
openEntity->betweenDecl = betweenDecl;
openEntity->internalEventPtr = NULL;
openEntity->internalEventEndPtr = NULL;
#ifdef XML_DTD
if (entity->is_param) {
- int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next);
- result = doProlog(parser, internalEncoding, textStart, textEnd, tok,
+ int tok = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
+ result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd, tok,
next, &next, XML_FALSE);
}
else
#endif /* XML_DTD */
- result = doContent(parser, tagLevel, internalEncoding, textStart,
+ result = doContent(parser, parser->m_tagLevel, parser->m_internalEncoding, textStart,
textEnd, &next, XML_FALSE);
if (result == XML_ERROR_NONE) {
- if (textEnd != next && ps_parsing == XML_SUSPENDED) {
+ if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
entity->processed = (int)(next - textStart);
- processor = internalEntityProcessor;
+ parser->m_processor = internalEntityProcessor;
}
else {
entity->open = XML_FALSE;
- openInternalEntities = openEntity->next;
+ parser->m_openInternalEntities = openEntity->next;
/* put openEntity back in list of free instances */
- openEntity->next = freeInternalEntities;
- freeInternalEntities = openEntity;
+ openEntity->next = parser->m_freeInternalEntities;
+ parser->m_freeInternalEntities = openEntity;
}
}
return result;
const char *textStart, *textEnd;
const char *next;
enum XML_Error result;
- OPEN_INTERNAL_ENTITY *openEntity = openInternalEntities;
+ OPEN_INTERNAL_ENTITY *openEntity = parser->m_openInternalEntities;
if (!openEntity)
return XML_ERROR_UNEXPECTED_STATE;
#ifdef XML_DTD
if (entity->is_param) {
- int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next);
- result = doProlog(parser, internalEncoding, textStart, textEnd, tok,
+ int tok = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
+ result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd, tok,
next, &next, XML_FALSE);
}
else
#endif /* XML_DTD */
- result = doContent(parser, openEntity->startTagLevel, internalEncoding,
+ result = doContent(parser, openEntity->startTagLevel, parser->m_internalEncoding,
textStart, textEnd, &next, XML_FALSE);
if (result != XML_ERROR_NONE)
return result;
- else if (textEnd != next && ps_parsing == XML_SUSPENDED) {
+ else if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
entity->processed = (int)(next - (char *)entity->textPtr);
return result;
}
else {
entity->open = XML_FALSE;
- openInternalEntities = openEntity->next;
+ parser->m_openInternalEntities = openEntity->next;
/* put openEntity back in list of free instances */
- openEntity->next = freeInternalEntities;
- freeInternalEntities = openEntity;
+ openEntity->next = parser->m_freeInternalEntities;
+ parser->m_freeInternalEntities = openEntity;
}
#ifdef XML_DTD
if (entity->is_param) {
int tok;
- processor = prologProcessor;
- tok = XmlPrologTok(encoding, s, end, &next);
- return doProlog(parser, encoding, s, end, tok, next, nextPtr,
- (XML_Bool)!ps_finalBuffer);
+ parser->m_processor = prologProcessor;
+ tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+ return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
+ (XML_Bool)!parser->m_parsingStatus.finalBuffer);
}
else
#endif /* XML_DTD */
{
- processor = contentProcessor;
+ parser->m_processor = contentProcessor;
/* see externalEntityContentProcessor vs contentProcessor */
- return doContent(parser, parentParser ? 1 : 0, encoding, s, end,
- nextPtr, (XML_Bool)!ps_finalBuffer);
+ return doContent(parser, parser->m_parentParser ? 1 : 0, parser->m_encoding, s, end,
+ nextPtr, (XML_Bool)!parser->m_parsingStatus.finalBuffer);
}
}
const char *UNUSED_P(end),
const char **UNUSED_P(nextPtr))
{
- return errorCode;
+ return parser->m_errorCode;
}
static enum XML_Error
const char *ptr, const char *end,
STRING_POOL *pool)
{
- DTD * const dtd = _dtd; /* save one level of indirection */
+ DTD * const dtd = parser->m_dtd; /* save one level of indirection */
for (;;) {
const char *next;
int tok = XmlAttributeValueTok(enc, ptr, end, &next);
case XML_TOK_NONE:
return XML_ERROR_NONE;
case XML_TOK_INVALID:
- if (enc == encoding)
- eventPtr = next;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = next;
return XML_ERROR_INVALID_TOKEN;
case XML_TOK_PARTIAL:
- if (enc == encoding)
- eventPtr = ptr;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = ptr;
return XML_ERROR_INVALID_TOKEN;
case XML_TOK_CHAR_REF:
{
int i;
int n = XmlCharRefNumber(enc, ptr);
if (n < 0) {
- if (enc == encoding)
- eventPtr = ptr;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = ptr;
return XML_ERROR_BAD_CHAR_REF;
}
if (!isCdata
return XML_ERROR_NO_MEMORY;
break;
}
- name = poolStoreString(&temp2Pool, enc,
+ name = poolStoreString(&parser->m_temp2Pool, enc,
ptr + enc->minBytesPerChar,
next - enc->minBytesPerChar);
if (!name)
return XML_ERROR_NO_MEMORY;
entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0);
- poolDiscard(&temp2Pool);
+ poolDiscard(&parser->m_temp2Pool);
/* First, determine if a check for an existing declaration is needed;
if yes, check that the entity exists, and that it is internal.
*/
if (pool == &dtd->pool) /* are we called from prolog? */
checkEntityDecl =
#ifdef XML_DTD
- prologState.documentEntity &&
+ parser->m_prologState.documentEntity &&
#endif /* XML_DTD */
(dtd->standalone
- ? !openInternalEntities
+ ? !parser->m_openInternalEntities
: !dtd->hasParamEntityRefs);
- else /* if (pool == &tempPool): we are called from content */
+ else /* if (pool == &parser->m_tempPool): we are called from content */
checkEntityDecl = !dtd->hasParamEntityRefs || dtd->standalone;
if (checkEntityDecl) {
if (!entity)
}
else if (!entity) {
/* Cannot report skipped entity here - see comments on
- skippedEntityHandler.
- if (skippedEntityHandler)
- skippedEntityHandler(handlerArg, name, 0);
+ parser->m_skippedEntityHandler.
+ if (parser->m_skippedEntityHandler)
+ parser->m_skippedEntityHandler(parser->m_handlerArg, name, 0);
*/
/* Cannot call the default handler because this would be
out of sync with the call to the startElementHandler.
- if ((pool == &tempPool) && defaultHandler)
+ if ((pool == &parser->m_tempPool) && parser->m_defaultHandler)
reportDefault(parser, enc, ptr, next);
*/
break;
}
if (entity->open) {
- if (enc == encoding) {
+ if (enc == parser->m_encoding) {
/* It does not appear that this line can be executed.
*
* The "if (entity->open)" check catches recursive entity
* we keep the line and merely exclude it from coverage
* tests.
*/
- eventPtr = ptr; /* LCOV_EXCL_LINE */
+ parser->m_eventPtr = ptr; /* LCOV_EXCL_LINE */
}
return XML_ERROR_RECURSIVE_ENTITY_REF;
}
if (entity->notation) {
- if (enc == encoding)
- eventPtr = ptr;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = ptr;
return XML_ERROR_BINARY_ENTITY_REF;
}
if (!entity->textPtr) {
- if (enc == encoding)
- eventPtr = ptr;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = ptr;
return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF;
}
else {
enum XML_Error result;
const XML_Char *textEnd = entity->textPtr + entity->textLen;
entity->open = XML_TRUE;
- result = appendAttributeValue(parser, internalEncoding, isCdata,
+ result = appendAttributeValue(parser, parser->m_internalEncoding, isCdata,
(char *)entity->textPtr,
(char *)textEnd, pool);
entity->open = XML_FALSE;
*
* LCOV_EXCL_START
*/
- if (enc == encoding)
- eventPtr = ptr;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = ptr;
return XML_ERROR_UNEXPECTED_STATE;
/* LCOV_EXCL_STOP */
}
const char *entityTextPtr,
const char *entityTextEnd)
{
- DTD * const dtd = _dtd; /* save one level of indirection */
+ DTD * const dtd = parser->m_dtd; /* save one level of indirection */
STRING_POOL *pool = &(dtd->entityValuePool);
enum XML_Error result = XML_ERROR_NONE;
#ifdef XML_DTD
- int oldInEntityValue = prologState.inEntityValue;
- prologState.inEntityValue = 1;
+ int oldInEntityValue = parser->m_prologState.inEntityValue;
+ parser->m_prologState.inEntityValue = 1;
#endif /* XML_DTD */
/* never return Null for the value argument in EntityDeclHandler,
since this would indicate an external entity; therefore we
switch (tok) {
case XML_TOK_PARAM_ENTITY_REF:
#ifdef XML_DTD
- if (isParamEntity || enc != encoding) {
+ if (parser->m_isParamEntity || enc != parser->m_encoding) {
const XML_Char *name;
ENTITY *entity;
- name = poolStoreString(&tempPool, enc,
+ name = poolStoreString(&parser->m_tempPool, enc,
entityTextPtr + enc->minBytesPerChar,
next - enc->minBytesPerChar);
if (!name) {
goto endEntityValue;
}
entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0);
- poolDiscard(&tempPool);
+ poolDiscard(&parser->m_tempPool);
if (!entity) {
/* not a well-formedness error - see XML 1.0: WFC Entity Declared */
/* cannot report skipped entity here - see comments on
- skippedEntityHandler
- if (skippedEntityHandler)
- skippedEntityHandler(handlerArg, name, 0);
+ parser->m_skippedEntityHandler
+ if (parser->m_skippedEntityHandler)
+ parser->m_skippedEntityHandler(parser->m_handlerArg, name, 0);
*/
dtd->keepProcessing = dtd->standalone;
goto endEntityValue;
}
if (entity->open) {
- if (enc == encoding)
- eventPtr = entityTextPtr;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = entityTextPtr;
result = XML_ERROR_RECURSIVE_ENTITY_REF;
goto endEntityValue;
}
if (entity->systemId) {
- if (externalEntityRefHandler) {
+ if (parser->m_externalEntityRefHandler) {
dtd->paramEntityRead = XML_FALSE;
entity->open = XML_TRUE;
- if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ if (!parser->m_externalEntityRefHandler(parser->m_externalEntityRefHandlerArg,
0,
entity->base,
entity->systemId,
else {
entity->open = XML_TRUE;
result = storeEntityValue(parser,
- internalEncoding,
+ parser->m_internalEncoding,
(char *)entity->textPtr,
(char *)(entity->textPtr
+ entity->textLen));
#endif /* XML_DTD */
/* In the internal subset, PE references are not legal
within markup declarations, e.g entity values in this case. */
- eventPtr = entityTextPtr;
+ parser->m_eventPtr = entityTextPtr;
result = XML_ERROR_PARAM_ENTITY_REF;
goto endEntityValue;
case XML_TOK_NONE:
int i;
int n = XmlCharRefNumber(enc, entityTextPtr);
if (n < 0) {
- if (enc == encoding)
- eventPtr = entityTextPtr;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = entityTextPtr;
result = XML_ERROR_BAD_CHAR_REF;
goto endEntityValue;
}
}
break;
case XML_TOK_PARTIAL:
- if (enc == encoding)
- eventPtr = entityTextPtr;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = entityTextPtr;
result = XML_ERROR_INVALID_TOKEN;
goto endEntityValue;
case XML_TOK_INVALID:
- if (enc == encoding)
- eventPtr = next;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = next;
result = XML_ERROR_INVALID_TOKEN;
goto endEntityValue;
default:
*
* LCOV_EXCL_START
*/
- if (enc == encoding)
- eventPtr = entityTextPtr;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = entityTextPtr;
result = XML_ERROR_UNEXPECTED_STATE;
goto endEntityValue;
/* LCOV_EXCL_STOP */
}
endEntityValue:
#ifdef XML_DTD
- prologState.inEntityValue = oldInEntityValue;
+ parser->m_prologState.inEntityValue = oldInEntityValue;
#endif /* XML_DTD */
return result;
}
const XML_Char *target;
XML_Char *data;
const char *tem;
- if (!processingInstructionHandler) {
- if (defaultHandler)
+ if (!parser->m_processingInstructionHandler) {
+ if (parser->m_defaultHandler)
reportDefault(parser, enc, start, end);
return 1;
}
start += enc->minBytesPerChar * 2;
tem = start + XmlNameLength(enc, start);
- target = poolStoreString(&tempPool, enc, start, tem);
+ target = poolStoreString(&parser->m_tempPool, enc, start, tem);
if (!target)
return 0;
- poolFinish(&tempPool);
- data = poolStoreString(&tempPool, enc,
+ poolFinish(&parser->m_tempPool);
+ data = poolStoreString(&parser->m_tempPool, enc,
XmlSkipS(enc, tem),
end - enc->minBytesPerChar*2);
if (!data)
return 0;
normalizeLines(data);
- processingInstructionHandler(handlerArg, target, data);
- poolClear(&tempPool);
+ parser->m_processingInstructionHandler(parser->m_handlerArg, target, data);
+ poolClear(&parser->m_tempPool);
return 1;
}
const char *start, const char *end)
{
XML_Char *data;
- if (!commentHandler) {
- if (defaultHandler)
+ if (!parser->m_commentHandler) {
+ if (parser->m_defaultHandler)
reportDefault(parser, enc, start, end);
return 1;
}
- data = poolStoreString(&tempPool,
+ data = poolStoreString(&parser->m_tempPool,
enc,
start + enc->minBytesPerChar * 4,
end - enc->minBytesPerChar * 3);
if (!data)
return 0;
normalizeLines(data);
- commentHandler(handlerArg, data);
- poolClear(&tempPool);
+ parser->m_commentHandler(parser->m_handlerArg, data);
+ poolClear(&parser->m_tempPool);
return 1;
}
enum XML_Convert_Result convert_res;
const char **eventPP;
const char **eventEndPP;
- if (enc == encoding) {
- eventPP = &eventPtr;
- eventEndPP = &eventEndPtr;
+ if (enc == parser->m_encoding) {
+ eventPP = &parser->m_eventPtr;
+ eventEndPP = &parser->m_eventEndPtr;
}
else {
/* To get here, two things must be true; the parser must be
*
* LCOV_EXCL_START
*/
- eventPP = &(openInternalEntities->internalEventPtr);
- eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ eventPP = &(parser->m_openInternalEntities->internalEventPtr);
+ eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr);
/* LCOV_EXCL_STOP */
}
do {
- ICHAR *dataPtr = (ICHAR *)dataBuf;
- convert_res = XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
+ ICHAR *dataPtr = (ICHAR *)parser->m_dataBuf;
+ convert_res = XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)parser->m_dataBufEnd);
*eventEndPP = s;
- defaultHandler(handlerArg, dataBuf, (int)(dataPtr - (ICHAR *)dataBuf));
+ parser->m_defaultHandler(parser->m_handlerArg, parser->m_dataBuf, (int)(dataPtr - (ICHAR *)parser->m_dataBuf));
*eventPP = s;
} while ((convert_res != XML_CONVERT_COMPLETED) && (convert_res != XML_CONVERT_INPUT_INCOMPLETE));
}
else
- defaultHandler(handlerArg, (XML_Char *)s, (int)((XML_Char *)end - (XML_Char *)s));
+ parser->m_defaultHandler(parser->m_handlerArg, (XML_Char *)s, (int)((XML_Char *)end - (XML_Char *)s));
}
if (type->nDefaultAtts == type->allocDefaultAtts) {
if (type->allocDefaultAtts == 0) {
type->allocDefaultAtts = 8;
- type->defaultAtts = (DEFAULT_ATTRIBUTE *)MALLOC(type->allocDefaultAtts
+ type->defaultAtts = (DEFAULT_ATTRIBUTE *)MALLOC(parser, type->allocDefaultAtts
* sizeof(DEFAULT_ATTRIBUTE));
- if (!type->defaultAtts)
+ if (!type->defaultAtts) {
+ type->allocDefaultAtts = 0;
return 0;
+ }
}
else {
DEFAULT_ATTRIBUTE *temp;
int count = type->allocDefaultAtts * 2;
temp = (DEFAULT_ATTRIBUTE *)
- REALLOC(type->defaultAtts, (count * sizeof(DEFAULT_ATTRIBUTE)));
+ REALLOC(parser, type->defaultAtts, (count * sizeof(DEFAULT_ATTRIBUTE)));
if (temp == NULL)
return 0;
type->allocDefaultAtts = count;
static int
setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType)
{
- DTD * const dtd = _dtd; /* save one level of indirection */
+ DTD * const dtd = parser->m_dtd; /* save one level of indirection */
const XML_Char *name;
for (name = elementType->name; *name; name++) {
if (*name == XML_T(ASCII_COLON)) {
getAttributeId(XML_Parser parser, const ENCODING *enc,
const char *start, const char *end)
{
- DTD * const dtd = _dtd; /* save one level of indirection */
+ DTD * const dtd = parser->m_dtd; /* save one level of indirection */
ATTRIBUTE_ID *id;
const XML_Char *name;
if (!poolAppendChar(&dtd->pool, XML_T('\0')))
poolDiscard(&dtd->pool);
else {
poolFinish(&dtd->pool);
- if (!ns)
+ if (!parser->m_ns)
;
else if (name[0] == XML_T(ASCII_x)
&& name[1] == XML_T(ASCII_m)
static const XML_Char *
getContext(XML_Parser parser)
{
- DTD * const dtd = _dtd; /* save one level of indirection */
+ DTD * const dtd = parser->m_dtd; /* save one level of indirection */
HASH_TABLE_ITER iter;
XML_Bool needSep = XML_FALSE;
if (dtd->defaultPrefix.binding) {
int i;
int len;
- if (!poolAppendChar(&tempPool, XML_T(ASCII_EQUALS)))
+ if (!poolAppendChar(&parser->m_tempPool, XML_T(ASCII_EQUALS)))
return NULL;
len = dtd->defaultPrefix.binding->uriLen;
- if (namespaceSeparator)
+ if (parser->m_namespaceSeparator)
len--;
for (i = 0; i < len; i++) {
- if (!poolAppendChar(&tempPool, dtd->defaultPrefix.binding->uri[i])) {
+ if (!poolAppendChar(&parser->m_tempPool, dtd->defaultPrefix.binding->uri[i])) {
/* Because of memory caching, I don't believe this line can be
* executed.
*
*/
continue; /* LCOV_EXCL_LINE */
}
- if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP))
+ if (needSep && !poolAppendChar(&parser->m_tempPool, CONTEXT_SEP))
return NULL;
for (s = prefix->name; *s; s++)
- if (!poolAppendChar(&tempPool, *s))
+ if (!poolAppendChar(&parser->m_tempPool, *s))
return NULL;
- if (!poolAppendChar(&tempPool, XML_T(ASCII_EQUALS)))
+ if (!poolAppendChar(&parser->m_tempPool, XML_T(ASCII_EQUALS)))
return NULL;
len = prefix->binding->uriLen;
- if (namespaceSeparator)
+ if (parser->m_namespaceSeparator)
len--;
for (i = 0; i < len; i++)
- if (!poolAppendChar(&tempPool, prefix->binding->uri[i]))
+ if (!poolAppendChar(&parser->m_tempPool, prefix->binding->uri[i]))
return NULL;
needSep = XML_TRUE;
}
break;
if (!e->open)
continue;
- if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP))
+ if (needSep && !poolAppendChar(&parser->m_tempPool, CONTEXT_SEP))
return NULL;
for (s = e->name; *s; s++)
- if (!poolAppendChar(&tempPool, *s))
+ if (!poolAppendChar(&parser->m_tempPool, *s))
return 0;
needSep = XML_TRUE;
}
- if (!poolAppendChar(&tempPool, XML_T('\0')))
+ if (!poolAppendChar(&parser->m_tempPool, XML_T('\0')))
return NULL;
- return tempPool.start;
+ return parser->m_tempPool.start;
}
static XML_Bool
setContext(XML_Parser parser, const XML_Char *context)
{
- DTD * const dtd = _dtd; /* save one level of indirection */
+ DTD * const dtd = parser->m_dtd; /* save one level of indirection */
const XML_Char *s = context;
while (*context != XML_T('\0')) {
if (*s == CONTEXT_SEP || *s == XML_T('\0')) {
ENTITY *e;
- if (!poolAppendChar(&tempPool, XML_T('\0')))
+ if (!poolAppendChar(&parser->m_tempPool, XML_T('\0')))
return XML_FALSE;
- e = (ENTITY *)lookup(parser, &dtd->generalEntities, poolStart(&tempPool), 0);
+ e = (ENTITY *)lookup(parser, &dtd->generalEntities, poolStart(&parser->m_tempPool), 0);
if (e)
e->open = XML_TRUE;
if (*s != XML_T('\0'))
s++;
context = s;
- poolDiscard(&tempPool);
+ poolDiscard(&parser->m_tempPool);
}
else if (*s == XML_T(ASCII_EQUALS)) {
PREFIX *prefix;
- if (poolLength(&tempPool) == 0)
+ if (poolLength(&parser->m_tempPool) == 0)
prefix = &dtd->defaultPrefix;
else {
- if (!poolAppendChar(&tempPool, XML_T('\0')))
+ if (!poolAppendChar(&parser->m_tempPool, XML_T('\0')))
return XML_FALSE;
- prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&tempPool),
+ prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&parser->m_tempPool),
sizeof(PREFIX));
if (!prefix)
return XML_FALSE;
- if (prefix->name == poolStart(&tempPool)) {
+ if (prefix->name == poolStart(&parser->m_tempPool)) {
prefix->name = poolCopyString(&dtd->pool, prefix->name);
if (!prefix->name)
return XML_FALSE;
}
- poolDiscard(&tempPool);
+ poolDiscard(&parser->m_tempPool);
}
for (context = s + 1;
*context != CONTEXT_SEP && *context != XML_T('\0');
context++)
- if (!poolAppendChar(&tempPool, *context))
+ if (!poolAppendChar(&parser->m_tempPool, *context))
return XML_FALSE;
- if (!poolAppendChar(&tempPool, XML_T('\0')))
+ if (!poolAppendChar(&parser->m_tempPool, XML_T('\0')))
return XML_FALSE;
- if (addBinding(parser, prefix, NULL, poolStart(&tempPool),
- &inheritedBindings) != XML_ERROR_NONE)
+ if (addBinding(parser, prefix, NULL, poolStart(&parser->m_tempPool),
+ &parser->m_inheritedBindings) != XML_ERROR_NONE)
return XML_FALSE;
- poolDiscard(&tempPool);
+ poolDiscard(&parser->m_tempPool);
if (*context != XML_T('\0'))
++context;
s = context;
}
else {
- if (!poolAppendChar(&tempPool, *s))
+ if (!poolAppendChar(&parser->m_tempPool, *s))
return XML_FALSE;
s++;
}
{
struct siphash state;
struct sipkey key;
- (void)sip_tobin;
(void)sip24_valid;
copy_salt_to_sipkey(parser, &key);
sip24_init(&state, &key);
int blockSize = (int)((unsigned)(pool->end - pool->start)*2U);
size_t bytesToAllocate;
- // NOTE: Needs to be calculated prior to calling `realloc`
- // to avoid dangling pointers:
+ /* NOTE: Needs to be calculated prior to calling `realloc`
+ to avoid dangling pointers: */
const ptrdiff_t offsetInsideBlock = pool->ptr - pool->start;
if (blockSize < 0) {
static int FASTCALL
nextScaffoldPart(XML_Parser parser)
{
- DTD * const dtd = _dtd; /* save one level of indirection */
+ DTD * const dtd = parser->m_dtd; /* save one level of indirection */
CONTENT_SCAFFOLD * me;
int next;
if (!dtd->scaffIndex) {
- dtd->scaffIndex = (int *)MALLOC(groupSize * sizeof(int));
+ dtd->scaffIndex = (int *)MALLOC(parser, parser->m_groupSize * sizeof(int));
if (!dtd->scaffIndex)
return -1;
dtd->scaffIndex[0] = 0;
CONTENT_SCAFFOLD *temp;
if (dtd->scaffold) {
temp = (CONTENT_SCAFFOLD *)
- REALLOC(dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD));
+ REALLOC(parser, dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD));
if (temp == NULL)
return -1;
dtd->scaffSize *= 2;
}
else {
- temp = (CONTENT_SCAFFOLD *)MALLOC(INIT_SCAFFOLD_ELEMENTS
+ temp = (CONTENT_SCAFFOLD *)MALLOC(parser, INIT_SCAFFOLD_ELEMENTS
* sizeof(CONTENT_SCAFFOLD));
if (temp == NULL)
return -1;
XML_Content **contpos,
XML_Char **strpos)
{
- DTD * const dtd = _dtd; /* save one level of indirection */
+ DTD * const dtd = parser->m_dtd; /* save one level of indirection */
dest->type = dtd->scaffold[src_node].type;
dest->quant = dtd->scaffold[src_node].quant;
if (dest->type == XML_CTYPE_NAME) {
static XML_Content *
build_model (XML_Parser parser)
{
- DTD * const dtd = _dtd; /* save one level of indirection */
+ DTD * const dtd = parser->m_dtd; /* save one level of indirection */
XML_Content *ret;
XML_Content *cpos;
XML_Char * str;
int allocsize = (dtd->scaffCount * sizeof(XML_Content)
+ (dtd->contentStringLen * sizeof(XML_Char)));
- ret = (XML_Content *)MALLOC(allocsize);
+ ret = (XML_Content *)MALLOC(parser, allocsize);
if (!ret)
return NULL;
const char *ptr,
const char *end)
{
- DTD * const dtd = _dtd; /* save one level of indirection */
+ DTD * const dtd = parser->m_dtd; /* save one level of indirection */
const XML_Char *name = poolStoreString(&dtd->pool, enc, ptr, end);
ELEMENT_TYPE *ret;
*/
#include <stddef.h>
-#include <stdbool.h>
-#include <string.h> // memcpy
+#include <string.h> /* memcpy */
+
+#if defined(_MSC_VER) && (_MSC_VER <= 1700)
+ /* for vs2012/11.0/1700 and earlier Visual Studio compilers */
+# define bool int
+# define false 0
+# define true 1
+#else
+# include <stdbool.h>
+#endif
+
#ifdef _WIN32
#include "winconfig.h"
{ PREFIX(prologTok), PREFIX(contentTok), \
PREFIX(cdataSectionTok) IGNORE_SECTION_TOK_VTABLE }, \
{ PREFIX(attributeValueTok), PREFIX(entityValueTok) }, \
- PREFIX(sameName), \
PREFIX(nameMatchesAscii), \
PREFIX(nameLength), \
PREFIX(skipS), \
};
void
-align_limit_to_full_utf8_characters(const char * from, const char ** fromLimRef)
+_INTERNAL_trim_to_complete_utf8_characters(const char * from, const char ** fromLimRef)
{
const char * fromLim = *fromLimRef;
size_t walked = 0;
}
/* Avoid copying partial characters (from incomplete input). */
- const char * const fromLimBefore = fromLim;
- align_limit_to_full_utf8_characters(*fromP, &fromLim);
- if (fromLim < fromLimBefore) {
- input_incomplete = true;
+ {
+ const char * const fromLimBefore = fromLim;
+ _INTERNAL_trim_to_complete_utf8_characters(*fromP, &fromLim);
+ if (fromLim < fromLimBefore) {
+ input_incomplete = true;
+ }
}
- const ptrdiff_t bytesToCopy = fromLim - *fromP;
- memcpy((void *)*toP, (const void *)*fromP, (size_t)bytesToCopy);
- *fromP += bytesToCopy;
- *toP += bytesToCopy;
+ {
+ const ptrdiff_t bytesToCopy = fromLim - *fromP;
+ memcpy(*toP, *fromP, bytesToCopy);
+ *fromP += bytesToCopy;
+ *toP += bytesToCopy;
+ }
- if (output_exhausted) // needs to go first
+ if (output_exhausted) /* needs to go first */
return XML_CONVERT_OUTPUT_EXHAUSTED;
else if (input_incomplete)
return XML_CONVERT_INPUT_INCOMPLETE;
return XML_CONVERT_OUTPUT_EXHAUSTED;
(*fromP)++;
}
- do {
- *(*toP)++ = *utf8++;
- } while (--n != 0);
+ memcpy(*toP, utf8, n);
+ *toP += n;
}
}
struct encoding {
SCANNER scanners[XML_N_STATES];
SCANNER literalScanners[XML_N_LITERAL_TYPES];
- int (PTRCALL *sameName)(const ENCODING *,
- const char *,
- const char *);
int (PTRCALL *nameMatchesAscii)(const ENCODING *,
const char *,
const char *,
#define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \
XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr)
-#define XmlSameName(enc, ptr1, ptr2) (((enc)->sameName)(enc, ptr1, ptr2))
-
#define XmlNameMatchesAscii(enc, ptr1, end1, ptr2) \
(((enc)->nameMatchesAscii)(enc, ptr1, end1, ptr2))
*nextTokPtr = ptr; \
return XML_TOK_INVALID; \
} \
+ /* fall through */ \
case BT_NMSTRT: \
case BT_HEX: \
case BT_DIGIT: \
*nextTokPtr = ptr; \
return XML_TOK_INVALID; \
} \
+ /* fall through */ \
case BT_NMSTRT: \
case BT_HEX: \
ptr += MINBPC(enc); \
return XML_TOK_INVALID;
}
}
- /* fall through */
+ /* fall through */
case BT_EQUALS:
{
int open;
case BT_NMSTRT:
if (!(BYTE_TO_ASCII(enc, ptr) & ~0x7f))
break;
+ /* fall through */
default:
switch (BYTE_TO_ASCII(enc, ptr)) {
case 0x24: /* $ */
return 0;
}
-/* This function does not appear to be called from anywhere within the
- * library code. It is used via the macro XmlSameName(), which is
- * defined but never used. Since it appears in the encoding function
- * table, removing it is not a thing to be undertaken lightly. For
- * the moment, we simply exclude it from coverage tests.
- *
- * LCOV_EXCL_START
- */
-static int PTRCALL
-PREFIX(sameName)(const ENCODING *enc, const char *ptr1, const char *ptr2)
-{
- for (;;) {
- switch (BYTE_TYPE(enc, ptr1)) {
-#define LEAD_CASE(n) \
- case BT_LEAD ## n: \
- if (*ptr1++ != *ptr2++) \
- return 0;
- LEAD_CASE(4) LEAD_CASE(3) LEAD_CASE(2)
-#undef LEAD_CASE
- /* fall through */
- if (*ptr1++ != *ptr2++)
- return 0;
- break;
- case BT_NONASCII:
- case BT_NMSTRT:
-#ifdef XML_NS
- case BT_COLON:
-#endif
- case BT_HEX:
- case BT_DIGIT:
- case BT_NAME:
- case BT_MINUS:
- if (*ptr2++ != *ptr1++)
- return 0;
- if (MINBPC(enc) > 1) {
- if (*ptr2++ != *ptr1++)
- return 0;
- if (MINBPC(enc) > 2) {
- if (*ptr2++ != *ptr1++)
- return 0;
- if (MINBPC(enc) > 3) {
- if (*ptr2++ != *ptr1++)
- return 0;
- }
- }
- }
- break;
- default:
- if (MINBPC(enc) == 1 && *ptr1 == *ptr2)
- return 1;
- switch (BYTE_TYPE(enc, ptr2)) {
- case BT_LEAD2:
- case BT_LEAD3:
- case BT_LEAD4:
- case BT_NONASCII:
- case BT_NMSTRT:
-#ifdef XML_NS
- case BT_COLON:
-#endif
- case BT_HEX:
- case BT_DIGIT:
- case BT_NAME:
- case BT_MINUS:
- return 0;
- default:
- return 1;
- }
- }
- }
- /* not reached */
-}
-/* LCOV_EXCL_STOP */
-
static int PTRCALL
PREFIX(nameMatchesAscii)(const ENCODING *UNUSED_P(enc), const char *ptr1,
const char *end1, const char *ptr2)
{
for (; *ptr2; ptr1 += MINBPC(enc), ptr2++) {
if (end1 - ptr1 < MINBPC(enc)) {
- /* This line cannot be executed. THe incoming data has already
- * been tokenized once, so imcomplete characters like this have
+ /* This line cannot be executed. The incoming data has already
+ * been tokenized once, so incomplete characters like this have
* already been eliminated from the input. Retaining the
* paranoia check is still valuable, however.
*/
goto out;
if ((p = getgrnam(name_chars)) == NULL) {
- PyErr_Format(PyExc_KeyError, "getgrnam(): name not found: %s", name_chars);
+ PyErr_Format(PyExc_KeyError, "getgrnam(): name not found: %S", name);
goto out;
}
retval = mkgrent(p);
static PyTypeObject MD5type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_md5.md5", /*tp_name*/
- sizeof(MD5object), /*tp_size*/
+ sizeof(MD5object), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
MD5_dealloc, /*tp_dealloc*/
static PyTypeObject mmap_object_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"mmap.mmap", /* tp_name */
- sizeof(mmap_object), /* tp_size */
+ sizeof(mmap_object), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
(destructor) mmap_object_dealloc, /* tp_dealloc */
static PyTypeObject OSSAudioType = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"ossaudiodev.oss_audio_device", /*tp_name*/
- sizeof(oss_audio_t), /*tp_size*/
+ sizeof(oss_audio_t), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)oss_dealloc, /*tp_dealloc*/
static PyTypeObject OSSMixerType = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"ossaudiodev.oss_mixer_device", /*tp_name*/
- sizeof(oss_mixer_t), /*tp_size*/
+ sizeof(oss_mixer_t), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)oss_mixer_dealloc, /*tp_dealloc*/
#if (defined(HAVE_SENDFILE) && (defined(__FreeBSD__) || defined(__DragonFly__) \
|| defined(__APPLE__))) || defined(HAVE_READV) || defined(HAVE_WRITEV)
-static Py_ssize_t
+static int
iov_setup(struct iovec **iov, Py_buffer **buf, PyObject *seq, Py_ssize_t cnt, int type)
{
Py_ssize_t i, j;
- Py_ssize_t blen, total = 0;
*iov = PyMem_New(struct iovec, cnt);
if (*iov == NULL) {
}
Py_DECREF(item);
(*iov)[i].iov_base = (*buf)[i].buf;
- blen = (*buf)[i].len;
- (*iov)[i].iov_len = blen;
- total += blen;
+ (*iov)[i].iov_len = (*buf)[i].len;
}
- return total;
+ return 0;
fail:
PyMem_Del(*iov);
}
if (i > 0) {
sf.hdr_cnt = (int)i;
- i = iov_setup(&(sf.headers), &hbuf,
- headers, sf.hdr_cnt, PyBUF_SIMPLE);
- if (i < 0)
+ if (iov_setup(&(sf.headers), &hbuf,
+ headers, sf.hdr_cnt, PyBUF_SIMPLE) < 0)
return NULL;
#ifdef __APPLE__
- sbytes += i;
+ for (i = 0; i < sf.hdr_cnt; i++) {
+ Py_ssize_t blen = sf.headers[i].iov_len;
+# define OFF_T_MAX 0x7fffffffffffffff
+ if (sbytes >= OFF_T_MAX - blen) {
+ PyErr_SetString(PyExc_OverflowError,
+ "sendfile() header is too large");
+ return NULL;
+ }
+ sbytes += blen;
+ }
#endif
}
}
}
if (i > 0) {
sf.trl_cnt = (int)i;
- i = iov_setup(&(sf.trailers), &tbuf,
- trailers, sf.trl_cnt, PyBUF_SIMPLE);
- if (i < 0)
+ if (iov_setup(&(sf.trailers), &tbuf,
+ trailers, sf.trl_cnt, PyBUF_SIMPLE) < 0)
return NULL;
-#ifdef __APPLE__
- sbytes += i;
-#endif
}
}
}
goto out;
if ((p = getpwnam(name)) == NULL) {
PyErr_Format(PyExc_KeyError,
- "getpwnam(): name not found: %s", name);
+ "getpwnam(): name not found: %S", arg);
goto out;
}
retval = mkpwent(p);
capi.SetStartDoctypeDeclHandler = XML_SetStartDoctypeDeclHandler;
capi.SetEncoding = XML_SetEncoding;
capi.DefaultUnknownEncodingHandler = PyUnknownEncodingHandler;
+#if XML_COMBINED_VERSION >= 20100
+ capi.SetHashSalt = XML_SetHashSalt;
+#else
+ capi.SetHashSalt = NULL;
+#endif
/* export using capsule */
capi_object = PyCapsule_New(&capi, PyExpat_CAPSULE_NAME, NULL);
static PyObject *
pyepoll_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
- int flags = 0, sizehint = FD_SETSIZE - 1;
+ int flags = 0, sizehint = -1;
static char *kwlist[] = {"sizehint", "flags", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:epoll", kwlist,
&sizehint, &flags))
return NULL;
- if (sizehint < 0) {
- PyErr_SetString(PyExc_ValueError, "negative sizehint");
+ if (sizehint == -1) {
+ sizehint = FD_SETSIZE - 1;
+ }
+ else if (sizehint <= 0) {
+ PyErr_SetString(PyExc_ValueError, "sizehint must be positive or -1");
return NULL;
}
static PyTypeObject SHA1type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_sha1.sha1", /*tp_name*/
- sizeof(SHA1object), /*tp_size*/
+ sizeof(SHA1object), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
SHA1_dealloc, /*tp_dealloc*/
static PyTypeObject SHA224type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_sha256.sha224", /*tp_name*/
- sizeof(SHAobject), /*tp_size*/
+ sizeof(SHAobject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
SHA_dealloc, /*tp_dealloc*/
static PyTypeObject SHA256type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_sha256.sha256", /*tp_name*/
- sizeof(SHAobject), /*tp_size*/
+ sizeof(SHAobject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
SHA_dealloc, /*tp_dealloc*/
static PyTypeObject SHA384type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_sha512.sha384", /*tp_name*/
- sizeof(SHAobject), /*tp_size*/
+ sizeof(SHAobject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
SHA512_dealloc, /*tp_dealloc*/
static PyTypeObject SHA512type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_sha512.sha512", /*tp_name*/
- sizeof(SHAobject), /*tp_size*/
+ sizeof(SHAobject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
SHA512_dealloc, /*tp_dealloc*/
const char *interfaceName;
int protoNumber;
int hatype = 0;
- int pkttype = 0;
+ int pkttype = PACKET_HOST;
Py_buffer haddr = {NULL, NULL};
if (!PyTuple_Check(args)) {
if (protoNumber < 0 || protoNumber > 0xffff) {
PyErr_SetString(
PyExc_OverflowError,
- "getsockaddrarg: protoNumber must be 0-65535.");
+ "getsockaddrarg: proto must be 0-65535.");
PyBuffer_Release(&haddr);
return 0;
}
\n\
Bind the socket to a local address. For IP sockets, the address is a\n\
pair (host, port); the host must refer to the local host. For raw packet\n\
-sockets the address is a tuple (ifname, proto [,pkttype [,hatype]])");
+sockets the address is a tuple (ifname, proto [,pkttype [,hatype [,addr]]])");
/* s.close() method.
&p->tm_hour, &p->tm_min, &p->tm_sec,
&p->tm_wday, &p->tm_yday, &p->tm_isdst))
return 0;
+
+ if (y < INT_MIN + 1900) {
+ PyErr_SetString(PyExc_OverflowError, "year out of range");
+ return 0;
+ }
+
p->tm_year = y - 1900;
p->tm_mon--;
p->tm_wday = (p->tm_wday + 1) % 7;
if (outbuf[1] == L'y' && buf.tm_year < 0) {
PyErr_SetString(PyExc_ValueError,
"format %y requires year >= 1900 on AIX");
+ PyMem_Free(format);
return NULL;
}
}
if (LBase <= code && code < (LBase+LCount) &&
i + 1 < len &&
VBase <= PyUnicode_READ(kind, data, i+1) &&
- PyUnicode_READ(kind, data, i+1) <= (VBase+VCount)) {
+ PyUnicode_READ(kind, data, i+1) < (VBase+VCount)) {
+ /* check L character is a modern leading consonant (0x1100 ~ 0x1112)
+ and V character is a modern vowel (0x1161 ~ 0x1175). */
int LIndex, VIndex;
LIndex = code - LBase;
VIndex = PyUnicode_READ(kind, data, i+1) - VBase;
code = SBase + (LIndex*VCount+VIndex)*TCount;
i+=2;
if (i < len &&
- TBase <= PyUnicode_READ(kind, data, i) &&
- PyUnicode_READ(kind, data, i) <= (TBase+TCount)) {
+ TBase < PyUnicode_READ(kind, data, i) &&
+ PyUnicode_READ(kind, data, i) < (TBase+TCount)) {
+ /* check T character is a modern trailing consonant
+ (0x11A8 ~ 0x11C2). */
code += PyUnicode_READ(kind, data, i)-TBase;
i++;
}
{
if (PyDict_Check(s))
return 0;
- return s != NULL && s->ob_type->tp_as_sequence &&
+ return s->ob_type->tp_as_sequence &&
s->ob_type->tp_as_sequence->sq_item != NULL;
}
result = PyBytes_FromStringAndSize(p, len);
PyMem_Free(p);
*p_result = result;
- return str;
+ return result != NULL ? str : NULL;
}
static PyObject *
goto error;
}
- if (fmtcnt < 0) {
- /* last writer: disable writer overallocation */
+ if (fmtcnt == 0) {
+ /* last write: disable writer overallocation */
writer.overallocate = 0;
}
/* If overallocation was disabled, ensure that it was the last
write. Otherwise, we missed an optimization */
- assert(writer.overallocate || fmtcnt < 0 || use_bytearray);
+ assert(writer.overallocate || fmtcnt == 0 || use_bytearray);
} /* until end */
if (argidx < arglen && !dict) {
{
PyCodeObject *co;
unsigned char *cell2arg = NULL;
- Py_ssize_t i, n_cellvars;
+ Py_ssize_t i, n_cellvars, n_varnames, total_args;
/* Check argument types */
if (argcount < 0 || kwonlyargcount < 0 || nlocals < 0 ||
flags &= ~CO_NOFREE;
}
+ n_varnames = PyTuple_GET_SIZE(varnames);
+ if (argcount <= n_varnames && kwonlyargcount <= n_varnames) {
+ /* Never overflows. */
+ total_args = (Py_ssize_t)argcount + (Py_ssize_t)kwonlyargcount +
+ ((flags & CO_VARARGS) != 0) + ((flags & CO_VARKEYWORDS) != 0);
+ }
+ else {
+ total_args = n_varnames + 1;
+ }
+ if (total_args > n_varnames) {
+ PyErr_SetString(PyExc_ValueError, "code: varnames is too small");
+ return NULL;
+ }
+
/* Create mapping between cells and arguments if needed. */
if (n_cellvars) {
- Py_ssize_t total_args = argcount + kwonlyargcount +
- ((flags & CO_VARARGS) != 0) + ((flags & CO_VARKEYWORDS) != 0);
Py_ssize_t alloc_size = sizeof(unsigned char) * n_cellvars;
bool used_cell2arg = false;
cell2arg = PyMem_MALLOC(alloc_size);
- if (cell2arg == NULL)
+ if (cell2arg == NULL) {
+ PyErr_NoMemory();
return NULL;
+ }
memset(cell2arg, CO_CELL_NOT_AN_ARG, alloc_size);
/* Find cells which are also arguments. */
for (i = 0; i < n_cellvars; i++) {
PyObject *cell = PyTuple_GET_ITEM(cellvars, i);
for (j = 0; j < total_args; j++) {
PyObject *arg = PyTuple_GET_ITEM(varnames, j);
- if (!PyUnicode_Compare(cell, arg)) {
+ int cmp = PyUnicode_Compare(cell, arg);
+ if (cmp == -1 && PyErr_Occurred()) {
+ PyMem_FREE(cell2arg);
+ return NULL;
+ }
+ if (cmp == 0) {
cell2arg[i] = j;
used_cell2arg = true;
break;
- 4 bytes if dk_size <= 0xffffffff (int32_t*)
- 8 bytes otherwise (int64_t*)
- Dynamically sized, 8 is minimum. */
- union {
- int8_t as_1[8];
- int16_t as_2[4];
- int32_t as_4[2];
-#if SIZEOF_VOID_P > 4
- int64_t as_8[1];
-#endif
- } dk_indices;
+ Dynamically sized, SIZEOF_VOID_P is minimum. */
+ char dk_indices[]; /* char is required to avoid strict aliasing. */
/* "PyDictKeyEntry dk_entries[dk_usable];" array follows:
see the DK_ENTRIES() macro */
static int dictresize(PyDictObject *mp, Py_ssize_t minused);
+static PyObject* dict_iter(PyDictObject *dict);
+
/*Global counter used to set ma_version_tag field of dictionary.
* It is incremented each time that a dictionary is created and each
* time that a dictionary is modified. */
2 : sizeof(int32_t))
#endif
#define DK_ENTRIES(dk) \
- ((PyDictKeyEntry*)(&(dk)->dk_indices.as_1[DK_SIZE(dk) * DK_IXSIZE(dk)]))
+ ((PyDictKeyEntry*)(&((int8_t*)((dk)->dk_indices))[DK_SIZE(dk) * DK_IXSIZE(dk)]))
#define DK_DEBUG_INCREF _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA
#define DK_DEBUG_DECREF _Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA
Py_ssize_t ix;
if (s <= 0xff) {
- int8_t *indices = keys->dk_indices.as_1;
+ int8_t *indices = (int8_t*)(keys->dk_indices);
ix = indices[i];
}
else if (s <= 0xffff) {
- int16_t *indices = keys->dk_indices.as_2;
+ int16_t *indices = (int16_t*)(keys->dk_indices);
ix = indices[i];
}
#if SIZEOF_VOID_P > 4
else if (s > 0xffffffff) {
- int64_t *indices = keys->dk_indices.as_8;
+ int64_t *indices = (int64_t*)(keys->dk_indices);
ix = indices[i];
}
#endif
else {
- int32_t *indices = keys->dk_indices.as_4;
+ int32_t *indices = (int32_t*)(keys->dk_indices);
ix = indices[i];
}
assert(ix >= DKIX_DUMMY);
assert(ix >= DKIX_DUMMY);
if (s <= 0xff) {
- int8_t *indices = keys->dk_indices.as_1;
+ int8_t *indices = (int8_t*)(keys->dk_indices);
assert(ix <= 0x7f);
indices[i] = (char)ix;
}
else if (s <= 0xffff) {
- int16_t *indices = keys->dk_indices.as_2;
+ int16_t *indices = (int16_t*)(keys->dk_indices);
assert(ix <= 0x7fff);
indices[i] = (int16_t)ix;
}
#if SIZEOF_VOID_P > 4
else if (s > 0xffffffff) {
- int64_t *indices = keys->dk_indices.as_8;
+ int64_t *indices = (int64_t*)(keys->dk_indices);
indices[i] = ix;
}
#endif
else {
- int32_t *indices = keys->dk_indices.as_4;
+ int32_t *indices = (int32_t*)(keys->dk_indices);
assert(ix <= 0x7fffffff);
indices[i] = (int32_t)ix;
}
lookdict_split, /* dk_lookup */
0, /* dk_usable (immutable) */
0, /* dk_nentries */
- .dk_indices = { .as_1 = {DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY,
- DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY}},
+ {DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY,
+ DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY}, /* dk_indices */
};
static PyObject *empty_values[1] = { NULL };
}
else {
dk = PyObject_MALLOC(sizeof(PyDictKeysObject)
- - Py_MEMBER_SIZE(PyDictKeysObject, dk_indices)
+ es * size
+ sizeof(PyDictKeyEntry) * usable);
if (dk == NULL) {
dk->dk_usable = usable;
dk->dk_lookup = lookdict_unicode_nodummy;
dk->dk_nentries = 0;
- memset(&dk->dk_indices.as_1[0], 0xff, es * size);
+ memset(&dk->dk_indices[0], 0xff, es * size);
memset(DK_ENTRIES(dk), 0, sizeof(PyDictKeyEntry) * usable);
return dk;
}
return -1;
}
mp = (PyDictObject*)a;
- if (PyDict_Check(b)) {
+ if (PyDict_Check(b) && (Py_TYPE(b)->tp_iter == (getiterfunc)dict_iter)) {
other = (PyDictObject*)b;
if (other == mp || other->ma_used == 0)
/* a.update(a) or a.update({}); nothing to do */
in the type object. */
if (mp->ma_keys->dk_refcnt == 1)
res += (sizeof(PyDictKeysObject)
- - Py_MEMBER_SIZE(PyDictKeysObject, dk_indices)
+ DK_IXSIZE(mp->ma_keys) * size
+ sizeof(PyDictKeyEntry) * usable);
return res;
_PyDict_KeysSize(PyDictKeysObject *keys)
{
return (sizeof(PyDictKeysObject)
- - Py_MEMBER_SIZE(PyDictKeysObject, dk_indices)
+ DK_IXSIZE(keys) * DK_SIZE(keys)
+ USABLE_FRACTION(DK_SIZE(keys)) * sizeof(PyDictKeyEntry));
}
little_endian, is_signed);
Py_DECREF(bytes);
- if (type != &PyLong_Type) {
+ if (long_obj != NULL && type != &PyLong_Type) {
Py_SETREF(long_obj, PyObject_CallFunctionObjArgs((PyObject *)type,
long_obj, NULL));
}
PyTypeObject PyModuleDef_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"moduledef", /* tp_name */
- sizeof(struct PyModuleDef), /* tp_size */
+ sizeof(struct PyModuleDef), /* tp_basicsize */
0, /* tp_itemsize */
};
PyTypeObject PyModule_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"module", /* tp_name */
- sizeof(PyModuleObject), /* tp_size */
+ sizeof(PyModuleObject), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)module_dealloc, /* tp_dealloc */
0, /* tp_print */
PyTypeObject _PyNamespace_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"types.SimpleNamespace", /* tp_name */
- sizeof(_PyNamespaceObject), /* tp_size */
+ sizeof(_PyNamespaceObject), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)namespace_dealloc, /* tp_dealloc */
0, /* tp_print */
else if (PyUnicode_Check(s)) {
PyObject *t;
t = PyUnicode_AsEncodedString(s, "utf-8", "backslashreplace");
- if (t == NULL)
- ret = 0;
+ if (t == NULL) {
+ ret = -1;
+ }
else {
fwrite(PyBytes_AS_STRING(t), 1,
PyBytes_GET_SIZE(t), fp);
As noted, the linked-list implemented here does not have all the bells and
whistles. However, we recognize that the implementation may need to
change to accommodate performance improvements or extra functionality. To
-that end, We use a simple API to interact with the linked-list. Here's a
+that end, we use a simple API to interact with the linked-list. Here's a
summary of the methods/macros:
Node info:
- Set node->key to NULL to indicate the node is not-in-use.
- Add _odict_EXISTS()?
- How to maintain consistency across resizes? Existing node pointers
- would be invalidate after a resize, which is particularly problematic
+ would be invalidated after a resize, which is particularly problematic
for the iterators.
* Use a more stream-lined implementation of update() and, likely indirectly,
__init__().
Py_ssize_t istep;
/* Check for special case values for printing. We don't always
- need the step value. We don't care about errors
- (it means overflow), so clear the errors. */
+ need the step value. We don't care about overflow. */
istep = PyNumber_AsSsize_t(r->step, NULL);
- if (istep != 1 || (istep == -1 && PyErr_Occurred())) {
- PyErr_Clear();
+ if (istep == -1 && PyErr_Occurred()) {
+ assert(!PyErr_ExceptionMatches(PyExc_OverflowError));
+ return NULL;
}
if (istep == 1)
/* Call object.__init__(self) now. */
/* XXX Could call super(type, cls).__init__() but what's the point? */
args = PyTuple_GetSlice(args, 0, 0);
+ if (args == NULL) {
+ return -1;
+ }
res = object_init(cls, args, NULL);
Py_DECREF(args);
return res;
char *res_start = (char*)res;
PyType_Slot *slot;
+ if (res == NULL)
+ return NULL;
+
+ if (spec->name == NULL) {
+ PyErr_SetString(PyExc_SystemError,
+ "Type spec does not define the name field.");
+ goto fail;
+ }
+
/* Set the type name and qualname */
s = strrchr(spec->name, '.');
if (s == NULL)
else
s++;
- if (res == NULL)
- return NULL;
type = &res->ht_type;
/* The flags must be initialized early, before the GC traverses us */
type->tp_flags = spec->flags | Py_TPFLAGS_HEAPTYPE;
res->ht_qualname = res->ht_name;
Py_INCREF(res->ht_qualname);
type->tp_name = spec->name;
- if (!type->tp_name)
- goto fail;
/* Adjust for empty tuple bases */
if (!bases) {
PyTypeObject *metatype = Py_TYPE(type);
PyObject *meta_attribute, *attribute;
descrgetfunc meta_get;
+ PyObject* res;
if (!PyUnicode_Check(name)) {
PyErr_Format(PyExc_TypeError,
meta_attribute = _PyType_Lookup(metatype, name);
if (meta_attribute != NULL) {
+ Py_INCREF(meta_attribute);
meta_get = Py_TYPE(meta_attribute)->tp_descr_get;
if (meta_get != NULL && PyDescr_IsData(meta_attribute)) {
* writes. Assume the attribute is not overridden in
* type's tp_dict (and bases): call the descriptor now.
*/
- return meta_get(meta_attribute, (PyObject *)type,
- (PyObject *)metatype);
+ res = meta_get(meta_attribute, (PyObject *)type,
+ (PyObject *)metatype);
+ Py_DECREF(meta_attribute);
+ return res;
}
- Py_INCREF(meta_attribute);
}
/* No data descriptor found on metatype. Look in tp_dict of this
attribute = _PyType_Lookup(type, name);
if (attribute != NULL) {
/* Implement descriptor functionality, if any */
+ Py_INCREF(attribute);
descrgetfunc local_get = Py_TYPE(attribute)->tp_descr_get;
Py_XDECREF(meta_attribute);
if (local_get != NULL) {
/* NULL 2nd argument indicates the descriptor was
* found on the target object itself (or a base) */
- return local_get(attribute, (PyObject *)NULL,
- (PyObject *)type);
+ res = local_get(attribute, (PyObject *)NULL,
+ (PyObject *)type);
+ Py_DECREF(attribute);
+ return res;
}
- Py_INCREF(attribute);
return attribute;
}
str = _PyBytesWriter_WriteBytes(&writer, str,
PyBytes_AS_STRING(rep),
PyBytes_GET_SIZE(rep));
- if (str == NULL)
- goto onError;
}
else {
assert(PyUnicode_Check(rep));
}
}
}
+ if (str == NULL)
+ goto onError;
+
pos = newpos;
Py_CLEAR(rep);
}
code = MsiRecordGetInteger(err, 1); /* XXX code */
if (MsiFormatRecord(0, err, res, &size) == ERROR_MORE_DATA) {
res = malloc(size+1);
+ if (res == NULL) {
+ MsiCloseHandle(err);
+ return PyErr_NoMemory();
+ }
MsiFormatRecord(0, err, res, &size);
res[size]='\0';
}
&fval, sval, &ssize);
if (status == ERROR_MORE_DATA) {
sval = malloc(ssize);
+ if (sval == NULL) {
+ return PyErr_NoMemory();
+ }
status = MsiSummaryInfoGetProperty(si->h, field, &type, &ival,
&fval, sval, &ssize);
}
if (log_fp != NULL) {
va_start(va, format);
vfwprintf_s(log_fp, format, va);
+ va_end(va);
}
}
va_start(va, format);
len = _vsnwprintf_s(message, MSGSIZE, _TRUNCATE, format, va);
+ va_end(va);
if (rc == 0) { /* a Windows error */
winerror(GetLastError(), win_message, MSGSIZE);
return E_FAIL;
}
auto dd = (DROPDESCRIPTION*)GlobalLock(medium.hGlobal);
+ if (!dd) {
+ OutputDebugString(L"PyShellExt::UpdateDropDescription - failed to lock DROPDESCRIPTION hGlobal");
+ ReleaseStgMedium(&medium);
+ return E_FAIL;
+ }
StringCchCopy(dd->szMessage, sizeof(dd->szMessage) / sizeof(dd->szMessage[0]), DRAG_MESSAGE);
StringCchCopy(dd->szInsert, sizeof(dd->szInsert) / sizeof(dd->szInsert[0]), PathFindFileNameW(target));
dd->type = DROPIMAGE_MOVE;
\r
set libraries=\r
set libraries=%libraries% bzip2-1.0.6\r
-if NOT "%IncludeSSL%"=="false" set libraries=%libraries% openssl-1.0.2o\r
+if NOT "%IncludeSSL%"=="false" set libraries=%libraries% openssl-1.0.2p\r
set libraries=%libraries% sqlite-3.21.0.0\r
if NOT "%IncludeTkinter%"=="false" set libraries=%libraries% tcl-core-8.6.6.0\r
if NOT "%IncludeTkinter%"=="false" set libraries=%libraries% tk-8.6.6.0\r
<sqlite3Dir>$(ExternalsDir)sqlite-3.21.0.0\</sqlite3Dir>\r
<bz2Dir>$(ExternalsDir)bzip2-1.0.6\</bz2Dir>\r
<lzmaDir>$(ExternalsDir)xz-5.2.2\</lzmaDir>\r
- <opensslDir>$(ExternalsDir)openssl-1.0.2o\</opensslDir>\r
+ <opensslDir>$(ExternalsDir)openssl-1.0.2p\</opensslDir>\r
<opensslIncludeDir>$(opensslDir)include32</opensslIncludeDir>\r
<opensslIncludeDir Condition="'$(ArchName)' == 'amd64'">$(opensslDir)include64</opensslIncludeDir>\r
<nasmDir>$(ExternalsDir)\nasm-2.11.06\</nasmDir>\r
char *buf = NULL;
int err = 0;
- n_read = 0;
+ n_read = (DWORD)-1;
total_read = 0;
wbuf = wbuf_local;
wbuflen = sizeof(wbuf_local) / sizeof(wbuf_local[0]) - 1;
while (1) {
+ if (PyOS_InputHook != NULL) {
+ (void)(PyOS_InputHook)();
+ }
if (!ReadConsoleW(hStdIn, &wbuf[total_read], wbuflen - total_read, &n_read, NULL)) {
err = GetLastError();
goto exit;
}
+ if (n_read == (DWORD)-1 && (err = GetLastError()) == ERROR_OPERATION_ABORTED) {
+ break;
+ }
if (n_read == 0) {
int s;
err = GetLastError();
}
else
started = 1;
- len = b - a; /* XXX this may compute NULL - NULL */
+ len = (a != NULL && b != NULL) ? b - a : 0;
str = (char *) PyObject_MALLOC(len + 1);
if (str == NULL) {
err_ret->error = E_NOMEM;
else if ((ps->p_flags & CO_FUTURE_BARRY_AS_BDFL) &&
strcmp(str, "<>")) {
PyObject_FREE(str);
- err_ret->text = "with Barry as BDFL, use '<>' "
- "instead of '!='";
+ err_ret->expected = NOTEQUAL;
err_ret->error = E_SYNTAX;
break;
}
}
#endif
- if (a >= tok->line_start)
+ if (a != NULL && a >= tok->line_start) {
col_offset = Py_SAFE_DOWNCAST(a - tok->line_start,
intptr_t, int);
- else
+ }
+ else {
col_offset = -1;
+ }
if ((err_ret->error =
PyParser_AddToken(ps, (int)type, str,
break;
case STAR:
str = PyUnicode_InternFromString("*");
+ if (!str)
+ return NULL;
if (PyArena_AddPyObject(c->c_arena, str) < 0) {
Py_DECREF(str);
return NULL;
}
}
result = PyFloat_FromDouble(f_result);
+ if (result == NULL) {
+ Py_DECREF(item);
+ Py_DECREF(iter);
+ return NULL;
+ }
temp = PyNumber_Add(result, item);
Py_DECREF(result);
Py_DECREF(item);
Py_MakePendingCalls() above. */
if (_Py_atomic_load_relaxed(&eval_breaker)) {
- if (_Py_OPCODE(*next_instr) == SETUP_FINALLY ||
- _Py_OPCODE(*next_instr) == YIELD_FROM) {
- /* Two cases where we skip running signal handlers and other
+ opcode = _Py_OPCODE(*next_instr);
+ if (opcode == SETUP_FINALLY ||
+ opcode == SETUP_WITH ||
+ opcode == BEFORE_ASYNC_WITH ||
+ opcode == YIELD_FROM) {
+ /* Few cases where we skip running signal handlers and other
pending calls:
- - If we're about to enter the try: of a try/finally (not
+ - If we're about to enter the 'with:'. It will prevent
+ emitting a resource warning in the common idiom
+ 'with open(path) as file:'.
+ - If we're about to enter the 'async with:'.
+ - If we're about to enter the 'try:' of a try/finally (not
*very* useful, but might help in some cases and it's
traditional)
- If we're resuming a chain of nested 'yield from' or
fixed_value = _PyErr_CreateException(exception, value);
Py_XDECREF(value);
if (fixed_value == NULL) {
+ Py_DECREF(exc_value);
return;
}
loc = setlocale(LC_CTYPE, NULL);
if (loc == NULL)
goto error;
- if (strcmp(loc, "C") != 0) {
+ if (strcmp(loc, "C") != 0 && strcmp(loc, "POSIX") != 0) {
/* the LC_CTYPE locale is different than C */
return 0;
}
}
static void
-invalid_comma_type(Py_UCS4 presentation_type)
+invalid_thousands_separator_type(char specifier, Py_UCS4 presentation_type)
{
+ assert(specifier == ',' || specifier == '_');
if (presentation_type > 32 && presentation_type < 128)
PyErr_Format(PyExc_ValueError,
- "Cannot specify ',' with '%c'.",
- (char)presentation_type);
+ "Cannot specify '%c' with '%c'.",
+ specifier, (char)presentation_type);
else
PyErr_Format(PyExc_ValueError,
- "Cannot specify ',' with '\\x%x'.",
- (unsigned int)presentation_type);
+ "Cannot specify '%c' with '\\x%x'.",
+ specifier, (unsigned int)presentation_type);
}
static void
/* Locale type codes. LT_NO_LOCALE must be zero. */
enum LocaleType {
LT_NO_LOCALE = 0,
- LT_DEFAULT_LOCALE,
- LT_UNDERSCORE_LOCALE,
+ LT_DEFAULT_LOCALE = ',',
+ LT_UNDERSCORE_LOCALE = '_',
LT_UNDER_FOUR_LOCALE,
LT_CURRENT_LOCALE
};
}
/* fall through */
default:
- invalid_comma_type(format->type);
+ invalid_thousands_separator_type(format->thousands_separators, format->type);
return 0;
}
}
(void) va_arg(*p_va, int *);
}
format++;
- } else if ((c == 's' || c == 'z' || c == 'y') && *format == '*') {
+ } else if ((c == 's' || c == 'z' || c == 'y' || c == 'w')
+ && *format == '*')
+ {
format++;
}
break;
char *dup, *end;
PyObject *result;
+ assert(s[orig_len] == '\0');
+
if (strchr(s, '_') == NULL) {
return innerfunc(s, orig_len, arg);
}
else {
/* shouldn't get here: Gay's code should always return
something starting with a digit, an 'I', or 'N' */
- strncpy(p, "ERR", 3);
- /* p += 3; */
assert(0);
}
goto exit;
goto done;
}
v = run_pyc_file(pyc_fp, filename, d, d, flags);
- fclose(pyc_fp);
} else {
/* When running from stdin, leave __main__.__loader__ alone */
if (strcmp(filename, "<stdin>") != 0 &&
}
flush_io();
if (v == NULL) {
+ Py_CLEAR(m);
PyErr_Print();
goto done;
}
done:
if (set_file_name && PyDict_DelItemString(d, "__file__"))
PyErr_Clear();
- Py_DECREF(m);
+ Py_XDECREF(m);
return ret;
}
if (!PyErr_Occurred())
PyErr_SetString(PyExc_RuntimeError,
"Bad magic number in .pyc file");
- return NULL;
+ goto error;
}
/* Skip mtime and size */
(void) PyMarshal_ReadLongFromFile(fp);
(void) PyMarshal_ReadLongFromFile(fp);
- if (PyErr_Occurred())
- return NULL;
-
+ if (PyErr_Occurred()) {
+ goto error;
+ }
v = PyMarshal_ReadLastObjectFromFile(fp);
if (v == NULL || !PyCode_Check(v)) {
Py_XDECREF(v);
PyErr_SetString(PyExc_RuntimeError,
"Bad code object in .pyc file");
- return NULL;
+ goto error;
}
+ fclose(fp);
co = (PyCodeObject *)v;
v = PyEval_EvalCode((PyObject*)co, globals, locals);
if (v && flags)
flags->cf_flags |= (co->co_flags & PyCF_MASK);
Py_DECREF(co);
return v;
+error:
+ fclose(fp);
+ return NULL;
}
PyObject *
errtype = PyExc_SyntaxError;
switch (err->error) {
case E_ERROR:
- return;
+ goto cleanup;
case E_SYNTAX:
errtype = PyExc_IndentationError;
if (err->expected == INDENT)
msg = "unexpected indent";
else if (err->token == DEDENT)
msg = "unexpected unindent";
+ else if (err->expected == NOTEQUAL) {
+ errtype = PyExc_SyntaxError;
+ msg = "with Barry as BDFL, use '<>' instead of '!='";
+ }
else {
errtype = PyExc_SyntaxError;
msg = "invalid syntax";
return 0;
itr = PyObject_GetIter(free);
- if (!itr)
- goto error;
+ if (itr == NULL) {
+ Py_DECREF(v_free);
+ return 0;
+ }
while ((name = PyIter_Next(itr))) {
v = PyDict_GetItem(symbols, name);
return err;
}
+static const int TB_RECURSIVE_CUTOFF = 3; // Also hardcoded in traceback.py.
+
static int
tb_print_line_repeated(PyObject *f, long cnt)
{
- int err;
+ cnt -= TB_RECURSIVE_CUTOFF;
PyObject *line = PyUnicode_FromFormat(
- " [Previous line repeated %ld more times]\n", cnt-3);
+ (cnt > 1)
+ ? " [Previous line repeated %ld more times]\n"
+ : " [Previous line repeated %ld more time]\n",
+ cnt);
if (line == NULL) {
return -1;
}
- err = PyFile_WriteObject(line, f, Py_PRINT_RAW);
+ int err = PyFile_WriteObject(line, f, Py_PRINT_RAW);
Py_DECREF(line);
return err;
}
tb = tb->tb_next;
}
while (tb != NULL && err == 0) {
- if (last_file != NULL &&
- tb->tb_frame->f_code->co_filename == last_file &&
- last_line != -1 && tb->tb_lineno == last_line &&
- last_name != NULL && tb->tb_frame->f_code->co_name == last_name)
- {
- cnt++;
- }
- else {
- if (cnt > 3) {
+ if (last_file == NULL ||
+ tb->tb_frame->f_code->co_filename != last_file ||
+ last_line == -1 || tb->tb_lineno != last_line ||
+ last_name == NULL || tb->tb_frame->f_code->co_name != last_name) {
+ if (cnt > TB_RECURSIVE_CUTOFF) {
err = tb_print_line_repeated(f, cnt);
}
last_file = tb->tb_frame->f_code->co_filename;
last_name = tb->tb_frame->f_code->co_name;
cnt = 0;
}
- if (err == 0 && cnt < 3) {
+ cnt++;
+ if (err == 0 && cnt <= TB_RECURSIVE_CUTOFF) {
err = tb_displayline(f,
tb->tb_frame->f_code->co_filename,
tb->tb_lineno,
}
tb = tb->tb_next;
}
- if (err == 0 && cnt > 3) {
+ if (err == 0 && cnt > TB_RECURSIVE_CUTOFF) {
err = tb_print_line_repeated(f, cnt);
}
return err;
-This is Python version 3.6.6
+This is Python version 3.6.7
============================
.. image:: https://travis-ci.org/python/cpython.svg?branch=3.6
:alt: CPython build status on Appveyor
:target: https://ci.appveyor.com/project/python/cpython/branch/3.6
+.. image:: https://dev.azure.com/python/cpython/_apis/build/status/Azure%20Pipelines%20CI?branchName=3.6
+ :alt: CPython build status on Azure Pipelines
+ :target: https://dev.azure.com/python/cpython/_build/latest?definitionId=4&branchName=3.6
+
.. image:: https://codecov.io/gh/python/cpython/branch/3.6/graph/badge.svg
:alt: CPython code coverage on Codecov
:target: https://codecov.io/gh/python/cpython
your environment, you can `file a bug report <https://bugs.python.org>`_ and
include relevant output from that command to show the issue.
+See `Running & Writing Tests <https://devguide.python.org/runtests/>`_
+for more on running tests.
Installing multiple versions
----------------------------
def safe_tp_name(self):
try:
- return self.type().field('tp_name').string()
- except NullPyObjectPtr:
- # NULL tp_name?
- return 'unknown'
- except RuntimeError:
- # Can't even read the object at all?
+ ob_type = self.type()
+ tp_name = ob_type.field('tp_name')
+ return tp_name.string()
+ # NullPyObjectPtr: NULL tp_name?
+ # RuntimeError: Can't even read the object at all?
+ # UnicodeDecodeError: Failed to decode tp_name bytestring
+ except (NullPyObjectPtr, RuntimeError, UnicodeDecodeError):
return 'unknown'
def proxyval(self, visited):
try:
tp_name = t.field('tp_name').string()
tp_flags = int(t.field('tp_flags'))
- except RuntimeError:
+ # RuntimeError: NULL pointers
+ # UnicodeDecodeError: string() fails to decode the bytestring
+ except (RuntimeError, UnicodeDecodeError):
# Handle any kind of error e.g. NULL ptrs by simply using the base
# class
return cls
def proxyval(self, visited):
m_ml = self.field('m_ml') # m_ml is a (PyMethodDef*)
- ml_name = m_ml['ml_name'].string()
+ try:
+ ml_name = m_ml['ml_name'].string()
+ except UnicodeDecodeError:
+ ml_name = '<ml_name:UnicodeDecodeError>'
pyop_m_self = self.pyop_field('m_self')
if pyop_m_self.is_null():
else:
offset = 8 * dk_size
- ent_addr = keys['dk_indices']['as_1'].address
+ ent_addr = keys['dk_indices'].address
ent_addr = ent_addr.cast(_type_unsigned_char_ptr()) + offset
ent_ptr_t = gdb.lookup_type('PyDictKeyEntry').pointer()
ent_addr = ent_addr.cast(ent_ptr_t)
try:
name = self.field('descr')['d_base']['name'].string()
return repr(name)
- except (NullPyObjectPtr, RuntimeError):
+ except (NullPyObjectPtr, RuntimeError, UnicodeDecodeError):
return '<unknown name>'
def safe_tp_name(self):
try:
return self.field('self')['ob_type']['tp_name'].string()
- except (NullPyObjectPtr, RuntimeError):
+ except (NullPyObjectPtr, RuntimeError, UnicodeDecodeError):
return '<unknown tp_name>'
def safe_self_addresss(self):
return False
if caller == 'PyCFunction_Call':
+ arg_name = 'func'
# Within that frame:
# "func" is the local containing the PyObject* of the
# PyCFunctionObject instance
# "self" is the (PyObject*) of the 'self'
try:
# Use the prettyprinter for the func:
- func = frame.read_var('func')
+ func = frame.read_var(arg_name)
return str(func)
+ except ValueError:
+ return ('PyCFunction invocation (unable to read %s: '
+ 'missing debuginfos?)' % arg_name)
except RuntimeError:
- return 'PyCFunction invocation (unable to read "func")'
+ return 'PyCFunction invocation (unable to read %s)' % arg_name
elif caller == '_PyCFunction_FastCallDict':
+ arg_name = 'func_obj'
try:
- func = frame.read_var('func_obj')
+ func = frame.read_var(arg_name)
return str(func)
+ except ValueError:
+ return ('PyCFunction invocation (unable to read %s: '
+ 'missing debuginfos?)' % arg_name)
except RuntimeError:
- return 'PyCFunction invocation (unable to read "func_obj")'
+ return 'PyCFunction invocation (unable to read %s)' % arg_name
if caller == 'wrapper_call':
+ arg_name = 'wp'
try:
- func = frame.read_var('wp')
+ func = frame.read_var(arg_name)
return str(func)
+ except ValueError:
+ return ('<wrapper_call invocation (unable to read %s: '
+ 'missing debuginfos?)>' % arg_name)
except RuntimeError:
- return '<wrapper_call invocation>'
+ return '<wrapper_call invocation (unable to read %s)>' % arg_name
# This frame isn't worth reporting:
return False
7*4, # start of key index
7*4+len(keys)*8, # start of value index
0, 0) # size and offset of hash table
- output += array.array("i", offsets).tostring()
+ output += array.array("i", offsets).tobytes()
output += ids
output += strs
return output
outfile = os.path.splitext(infile)[0] + '.mo'
try:
- lines = open(infile, 'rb').readlines()
+ with open(infile, 'rb') as f:
+ lines = f.readlines()
except IOError as msg:
print(msg, file=sys.stderr)
sys.exit(1)
output = generate()
try:
- open(outfile,"wb").write(output)
+ with open(outfile,"wb") as f:
+ f.write(output)
except IOError as msg:
print(msg, file=sys.stderr)
Tools\msi\get_externals.bat. (Note that this is in addition to the
similarly named file in PCBuild.)
+One of the dependencies used in builds is WiX, a toolset that lets developers
+create installers for Windows Installer, the Windows installation engine. WiX
+has a dependency on the Microsoft .NET Framework Version 3.5 (which may not be
+configured on recent versions of Windows, such as Windows 10). If you are
+building on a recent Windows version, use the Control Panel (Programs | Programs
+and Features | Turn Windows Features on or off) and ensure that the entry
+".NET Framework 3.5 (includes .NET 2.0 and 3.0)" is enabled.
+
For testing, the installer should be built with the Tools/msi/build.bat
script:
class bdist_wininst(Command):
description = "create an executable installer for MS Windows"
+ # Marker for tests that we have the unsupported bdist_wininst
+ _unsupported = True
+
def initialize_options(self):
pass
log = logging.getLogger("multissl")
OPENSSL_OLD_VERSIONS = [
- "0.9.8zh",
- "1.0.1u",
+ "0.9.8zh",
+ "1.0.1u",
+ "1.0.2",
]
OPENSSL_RECENT_VERSIONS = [
- "1.0.2",
- "1.0.2m",
- "1.1.0g",
+ "1.0.2p",
+ "1.1.0i",
+ "1.1.1",
]
LIBRESSL_OLD_VERSIONS = [
- "2.3.10",
- "2.4.5",
+ "2.5.5",
+ "2.6.4",
]
LIBRESSL_RECENT_VERSIONS = [
- "2.5.5",
- "2.6.4",
- "2.7.1",
+ "2.7.4",
]
# store files in ../multissl
-HERE = os.path.abspath(os.getcwd())
-MULTISSL_DIR = os.path.abspath(os.path.join(HERE, '..', 'multissl'))
+HERE = os.path.dirname(os.path.abspath(__file__))
+PYTHONROOT = os.path.abspath(os.path.join(HERE, '..', '..'))
+MULTISSL_DIR = os.path.abspath(os.path.join(PYTHONROOT, '..', 'multissl'))
+
parser = argparse.ArgumentParser(
prog='multissl',
parser.add_argument(
'--debug',
action='store_true',
- help="Enable debug mode",
+ help="Enable debug logging",
)
parser.add_argument(
'--disable-ancient',
help="Disable network tests."
)
parser.add_argument(
- '--compile-only',
- action='store_true',
- help="Don't run tests, only compile _ssl.c and _hashopenssl.c."
+ '--steps',
+ choices=['library', 'modules', 'tests'],
+ default='tests',
+ help=(
+ "Which steps to perform. 'library' downloads and compiles OpenSSL "
+ "or LibreSSL. 'module' also compiles Python modules. 'tests' builds "
+ "all and runs the test suite."
+ )
)
parser.add_argument(
'--system',
default='',
help="Override the automatic system type detection."
)
+parser.add_argument(
+ '--force',
+ action='store_true',
+ dest='force',
+ help="Force build and installation."
+)
+parser.add_argument(
+ '--keep-sources',
+ action='store_true',
+ dest='keep_sources',
+ help="Keep original sources for debugging."
+)
class AbstractBuilder(object):
url_template = None
src_template = None
build_template = None
+ install_target = 'install'
module_files = ("Modules/_ssl.c",
"Modules/_hashopenssl.c")
module_libs = ("_ssl", "_hashlib")
- def __init__(self, version, compile_args=(),
- basedir=MULTISSL_DIR):
+ def __init__(self, version, args):
self.version = version
- self.compile_args = compile_args
+ self.args = args
# installation directory
self.install_dir = os.path.join(
- os.path.join(basedir, self.library.lower()), version
+ os.path.join(args.base_directory, self.library.lower()), version
)
# source file
- self.src_dir = os.path.join(basedir, 'src')
+ self.src_dir = os.path.join(args.base_directory, 'src')
self.src_file = os.path.join(
self.src_dir, self.src_template.format(version))
# build directory (removed after install)
"""Now build openssl"""
log.info("Running build in {}".format(self.build_dir))
cwd = self.build_dir
- cmd = ["./config", "shared", "--prefix={}".format(self.install_dir)]
- cmd.extend(self.compile_args)
- env = None
+ cmd = [
+ "./config",
+ "shared", "--debug",
+ "--prefix={}".format(self.install_dir)
+ ]
+ env = os.environ.copy()
+ # set rpath
+ env["LD_RUN_PATH"] = self.lib_dir
if self.system:
- env = os.environ.copy()
env['SYSTEM'] = self.system
self._subprocess_call(cmd, cwd=cwd, env=env)
# Old OpenSSL versions do not support parallel builds.
self._subprocess_call(["make", "-j1"], cwd=cwd, env=env)
- def _make_install(self, remove=True):
- self._subprocess_call(["make", "-j1", "install"], cwd=self.build_dir)
- if remove:
+ def _make_install(self):
+ self._subprocess_call(
+ ["make", "-j1", self.install_target],
+ cwd=self.build_dir
+ )
+ if not self.args.keep_sources:
shutil.rmtree(self.build_dir)
def install(self):
log.info(self.openssl_cli)
- if not self.has_openssl:
+ if not self.has_openssl or self.args.force:
if not self.has_src:
self._download_src()
else:
url_template = "https://www.openssl.org/source/openssl-{}.tar.gz"
src_template = "openssl-{}.tar.gz"
build_template = "openssl-{}"
+ # only install software, skip docs
+ install_target = 'install_sw'
class BuildLibreSSL(AbstractBuilder):
start = datetime.now()
- for name in ['python', 'setup.py', 'Modules/_ssl.c']:
- if not os.path.isfile(name):
+ if args.steps in {'modules', 'tests'}:
+ for name in ['setup.py', 'Modules/_ssl.c']:
+ if not os.path.isfile(os.path.join(PYTHONROOT, name)):
+ parser.error(
+ "Must be executed from CPython build dir"
+ )
+ if not os.path.samefile('python', sys.executable):
parser.error(
- "Must be executed from CPython build dir"
+ "Must be executed with ./python from CPython build dir"
)
- if not os.path.samefile('python', sys.executable):
- parser.error(
- "Must be executed with ./python from CPython build dir"
- )
-
- # check for configure and run make
- configure_make()
+ # check for configure and run make
+ configure_make()
# download and register builder
builds = []
for version in args.openssl:
- build = BuildOpenSSL(version)
+ build = BuildOpenSSL(
+ version,
+ args
+ )
build.install()
builds.append(build)
for version in args.libressl:
- build = BuildLibreSSL(version)
+ build = BuildLibreSSL(
+ version,
+ args
+ )
build.install()
builds.append(build)
- for build in builds:
- try:
- build.recompile_pymods()
- build.check_pyssl()
- if not args.compile_only:
- build.run_python_tests(
- tests=args.tests,
- network=args.network,
- )
- except Exception as e:
- log.exception("%s failed", build)
- print("{} failed: {}".format(build, e), file=sys.stderr)
- sys.exit(2)
-
- print("\n{} finished in {}".format(
- "Tests" if not args.compile_only else "Builds",
- datetime.now() - start
- ))
+ if args.steps in {'modules', 'tests'}:
+ for build in builds:
+ try:
+ build.recompile_pymods()
+ build.check_pyssl()
+ if args.steps == 'tests':
+ build.run_python_tests(
+ tests=args.tests,
+ network=args.network,
+ )
+ except Exception as e:
+ log.exception("%s failed", build)
+ print("{} failed: {}".format(build, e), file=sys.stderr)
+ sys.exit(2)
+
+ log.info("\n{} finished in {}".format(
+ args.steps.capitalize(),
+ datetime.now() - start
+ ))
print('Python: ', sys.version)
- if args.compile_only:
- print('Build only')
- elif args.tests:
- print('Executed Tests:', ' '.join(args.tests))
- else:
- print('Executed all SSL tests.')
+ if args.steps == 'tests':
+ if args.tests:
+ print('Executed Tests:', ' '.join(args.tests))
+ else:
+ print('Executed all SSL tests.')
print('OpenSSL / LibreSSL versions:')
for build in builds:
-# generated automatically by aclocal 1.15 -*- Autoconf -*-
+# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# PARTICULAR PURPOSE.
m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
-# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
-# serial 11 (pkg-config-0.29.1)
-
+dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
+dnl serial 11 (pkg-config-0.29.1)
+dnl
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
dnl
AS_VAR_IF([$1], [""], [$5], [$4])dnl
])dnl PKG_CHECK_VAR
-dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES,
-dnl [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND],
-dnl [DESCRIPTION], [DEFAULT])
-dnl ------------------------------------------
-dnl
-dnl Prepare a "--with-" configure option using the lowercase
-dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and
-dnl PKG_CHECK_MODULES in a single macro.
-AC_DEFUN([PKG_WITH_MODULES],
-[
-m4_pushdef([with_arg], m4_tolower([$1]))
-
-m4_pushdef([description],
- [m4_default([$5], [build with ]with_arg[ support])])
-
-m4_pushdef([def_arg], [m4_default([$6], [auto])])
-m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes])
-m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no])
-
-m4_case(def_arg,
- [yes],[m4_pushdef([with_without], [--without-]with_arg)],
- [m4_pushdef([with_without],[--with-]with_arg)])
-
-AC_ARG_WITH(with_arg,
- AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),,
- [AS_TR_SH([with_]with_arg)=def_arg])
-
-AS_CASE([$AS_TR_SH([with_]with_arg)],
- [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)],
- [auto],[PKG_CHECK_MODULES([$1],[$2],
- [m4_n([def_action_if_found]) $3],
- [m4_n([def_action_if_not_found]) $4])])
-
-m4_popdef([with_arg])
-m4_popdef([description])
-m4_popdef([def_arg])
-
-])dnl PKG_WITH_MODULES
-
-dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES,
-dnl [DESCRIPTION], [DEFAULT])
-dnl -----------------------------------------------
-dnl
-dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES
-dnl check._[VARIABLE-PREFIX] is exported as make variable.
-AC_DEFUN([PKG_HAVE_WITH_MODULES],
-[
-PKG_WITH_MODULES([$1],[$2],,,[$3],[$4])
-
-AM_CONDITIONAL([HAVE_][$1],
- [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"])
-])dnl PKG_HAVE_WITH_MODULES
-
-dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES,
-dnl [DESCRIPTION], [DEFAULT])
-dnl ------------------------------------------------------
-dnl
-dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after
-dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make
-dnl and preprocessor variable.
-AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES],
-[
-PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4])
-
-AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"],
- [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])])
-])dnl PKG_HAVE_DEFINE_WITH_MODULES
-
docdir
oldincludedir
includedir
+runstatedir
localstatedir
sharedstatedir
sysconfdir
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
- libdir localedir mandir
+ libdir localedir mandir runstatedir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
fi
if test $HAS_GIT = found
then
- GITVERSION="git -C \$(srcdir) rev-parse --short HEAD"
- GITTAG="git -C \$(srcdir) describe --all --always --dirty"
- GITBRANCH="git -C \$(srcdir) name-rev --name-only HEAD"
+ GITVERSION="git --git-dir \$(srcdir)/.git rev-parse --short HEAD"
+ GITTAG="git --git-dir \$(srcdir)/.git describe --all --always --dirty"
+ GITBRANCH="git --git-dir \$(srcdir)/.git name-rev --name-only HEAD"
else
GITVERSION=""
GITTAG=""
esac
;;
esac
+
+ if test "$ac_cv_prog_cc_g" = "yes"
+ then
+ # bpo-30345: Add -g to LDFLAGS when compiling with LTO
+ # to get debug symbols.
+ LTOFLAGS="$LTOFLAGS -g"
+ fi
fi
# Enable PGO flags.
futimens futimes gai_strerror getentropy \
getgrouplist getgroups getlogin getloadavg getpeername getpgid getpid \
getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \
- initgroups kill killpg lchmod lchown linkat lstat lutimes mmap \
+ initgroups kill killpg lchown linkat lstat lutimes mmap \
memrchr mbrtowc mkdirat mkfifo \
mkfifoat mknod mknodat mktime mremap nice openat pathconf pause pipe2 plock poll \
posix_fallocate posix_fadvise pread \
done
+# Force lchmod off for Linux. Linux disallows changing the mode of symbolic
+# links. Some libc implementations have a stub lchmod implementation that always
+# returns an error.
+if test "$MACHDEP" != linux; then
+ for ac_func in lchmod
+do :
+ ac_fn_c_check_func "$LINENO" "lchmod" "ac_cv_func_lchmod"
+if test "x$ac_cv_func_lchmod" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LCHMOD 1
+_ACEOF
+
+fi
+done
+
+fi
+
ac_fn_c_check_decl "$LINENO" "dirfd" "ac_cv_have_decl_dirfd" "#include <sys/types.h>
#include <dirent.h>
"
fi
-# Before we can test tzset, we need to check if struct tm has a tm_zone
-# (which is not required by ISO C or UNIX spec) and/or if we support
-# tzname[]
-ac_fn_c_check_member "$LINENO" "struct tm" "tm_zone" "ac_cv_member_struct_tm_tm_zone" "#include <sys/types.h>
-#include <$ac_cv_struct_tm>
-
-"
-if test "x$ac_cv_member_struct_tm_tm_zone" = xyes; then :
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_STRUCT_TM_TM_ZONE 1
-_ACEOF
-
-
-fi
-
-if test "$ac_cv_member_struct_tm_tm_zone" = yes; then
-
-$as_echo "#define HAVE_TM_ZONE 1" >>confdefs.h
-
-else
- ac_fn_c_check_decl "$LINENO" "tzname" "ac_cv_have_decl_tzname" "#include <time.h>
-"
-if test "x$ac_cv_have_decl_tzname" = xyes; then :
- ac_have_decl=1
-else
- ac_have_decl=0
-fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_TZNAME $ac_have_decl
-_ACEOF
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tzname" >&5
-$as_echo_n "checking for tzname... " >&6; }
-if ${ac_cv_var_tzname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <time.h>
-#if !HAVE_DECL_TZNAME
-extern char *tzname[];
-#endif
-
-int
-main ()
-{
-return tzname[0][0];
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_var_tzname=yes
-else
- ac_cv_var_tzname=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_var_tzname" >&5
-$as_echo "$ac_cv_var_tzname" >&6; }
- if test $ac_cv_var_tzname = yes; then
-
-$as_echo "#define HAVE_TZNAME 1" >>confdefs.h
-
- fi
-fi
-
-
# check tzset(3) exists and works like we expect it to
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working tzset()" >&5
$as_echo_n "checking for working tzset()... " >&6; }
#include <stdatomic.h>
atomic_int value = ATOMIC_VAR_INIT(1);
- _Atomic void *py_atomic_address = (void*) &value;
int main() {
int loaded_value = atomic_load(&value);
return 0;
fi
if test $HAS_GIT = found
then
- GITVERSION="git -C \$(srcdir) rev-parse --short HEAD"
- GITTAG="git -C \$(srcdir) describe --all --always --dirty"
- GITBRANCH="git -C \$(srcdir) name-rev --name-only HEAD"
+ GITVERSION="git --git-dir \$(srcdir)/.git rev-parse --short HEAD"
+ GITTAG="git --git-dir \$(srcdir)/.git describe --all --always --dirty"
+ GITBRANCH="git --git-dir \$(srcdir)/.git name-rev --name-only HEAD"
else
GITVERSION=""
GITTAG=""
esac
;;
esac
+
+ if test "$ac_cv_prog_cc_g" = "yes"
+ then
+ # bpo-30345: Add -g to LDFLAGS when compiling with LTO
+ # to get debug symbols.
+ LTOFLAGS="$LTOFLAGS -g"
+ fi
fi
# Enable PGO flags.
futimens futimes gai_strerror getentropy \
getgrouplist getgroups getlogin getloadavg getpeername getpgid getpid \
getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \
- initgroups kill killpg lchmod lchown linkat lstat lutimes mmap \
+ initgroups kill killpg lchown linkat lstat lutimes mmap \
memrchr mbrtowc mkdirat mkfifo \
mkfifoat mknod mknodat mktime mremap nice openat pathconf pause pipe2 plock poll \
posix_fallocate posix_fadvise pread \
truncate uname unlinkat unsetenv utimensat utimes waitid waitpid wait3 wait4 \
wcscoll wcsftime wcsxfrm wmemcmp writev _getpty)
+# Force lchmod off for Linux. Linux disallows changing the mode of symbolic
+# links. Some libc implementations have a stub lchmod implementation that always
+# returns an error.
+if test "$MACHDEP" != linux; then
+ AC_CHECK_FUNCS(lchmod)
+fi
+
AC_CHECK_DECL(dirfd,
AC_DEFINE(HAVE_DIRFD, 1,
Define if you have the 'dirfd' function or macro.), ,
[Define if poll() sets errno on invalid file descriptors.])
fi
-# Before we can test tzset, we need to check if struct tm has a tm_zone
-# (which is not required by ISO C or UNIX spec) and/or if we support
-# tzname[]
-AC_STRUCT_TIMEZONE
-
# check tzset(3) exists and works like we expect it to
AC_MSG_CHECKING(for working tzset())
AC_CACHE_VAL(ac_cv_working_tzset, [
AC_LANG_SOURCE([[
#include <stdatomic.h>
atomic_int value = ATOMIC_VAR_INIT(1);
- _Atomic void *py_atomic_address = (void*) &value;
int main() {
int loaded_value = atomic_load(&value);
return 0;
if test "$have_stdatomic_h" = yes; then
AC_DEFINE(HAVE_STD_ATOMIC, 1,
- [Has stdatomic.h, atomic_int and _Atomic void* types work])
+ [Has stdatomic.h with atomic_int])
fi
# Check for GCC >= 4.7 __atomic builtins
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
-/* Has stdatomic.h, atomic_int and _Atomic void* types work */
+/* Has stdatomic.h with atomic_int */
#undef HAVE_STD_ATOMIC
/* Define to 1 if you have the `strdup' function. */