Imported Upstream version 3.6.7
authorHyunjee Kim <hj0426.kim@samsung.com>
Wed, 20 Mar 2019 01:58:57 +0000 (10:58 +0900)
committerHyunjee Kim <hj0426.kim@samsung.com>
Wed, 20 Mar 2019 01:58:57 +0000 (10:58 +0900)
492 files changed:
.azure-pipelines/ci.yml [new file with mode: 0644]
.azure-pipelines/docker-steps.yml [new file with mode: 0644]
.azure-pipelines/docs-steps.yml [new file with mode: 0644]
.azure-pipelines/macos-steps.yml [new file with mode: 0644]
.azure-pipelines/posix-deps.sh [new file with mode: 0755]
.azure-pipelines/posix-steps.yml [new file with mode: 0644]
.azure-pipelines/pr.yml [new file with mode: 0644]
.azure-pipelines/prebuild-checks.yml [new file with mode: 0644]
.azure-pipelines/windows-steps.yml [new file with mode: 0644]
.vsts/docs-release.yml [deleted file]
.vsts/docs.yml [deleted file]
.vsts/linux-buildbot.yml [deleted file]
.vsts/linux-coverage.yml [deleted file]
.vsts/linux-deps.yml [deleted file]
.vsts/linux-pr.yml [deleted file]
.vsts/macos-buildbot.yml [deleted file]
.vsts/macos-pr.yml [deleted file]
.vsts/windows-buildbot.yml [deleted file]
.vsts/windows-pr.yml [deleted file]
Doc/README.rst
Doc/c-api/marshal.rst
Doc/c-api/memory.rst
Doc/conf.py
Doc/distutils/builtdist.rst
Doc/distutils/introduction.rst
Doc/faq/design.rst
Doc/faq/programming.rst
Doc/glossary.rst
Doc/howto/functional.rst
Doc/includes/run-func.c
Doc/library/asyncio-protocol.rst
Doc/library/asyncio-stream.rst
Doc/library/collections.rst
Doc/library/configparser.rst
Doc/library/contextlib.rst
Doc/library/ctypes.rst
Doc/library/datetime.rst
Doc/library/depgraph-output.png [deleted file]
Doc/library/dis.rst
Doc/library/email.errors.rst
Doc/library/email.parser.rst
Doc/library/email.rst
Doc/library/enum.rst
Doc/library/exceptions.rst
Doc/library/functions.rst
Doc/library/hashlib.rst
Doc/library/html.rst
Doc/library/importlib.rst
Doc/library/io.rst
Doc/library/json.rst
Doc/library/logging.rst
Doc/library/multiprocessing.rst
Doc/library/optparse.rst
Doc/library/pathlib.rst
Doc/library/platform.rst
Doc/library/profile.rst
Doc/library/re.rst
Doc/library/select.rst
Doc/library/site.rst
Doc/library/smtplib.rst
Doc/library/socket.rst
Doc/library/sqlite3.rst
Doc/library/ssl.rst
Doc/library/statistics.rst
Doc/library/stdtypes.rst
Doc/library/string.rst
Doc/library/subprocess.rst
Doc/library/tempfile.rst
Doc/library/threading.rst
Doc/library/traceback.rst
Doc/library/typing.rst
Doc/library/unittest.mock.rst
Doc/library/unittest.rst
Doc/library/urllib.request.rst
Doc/library/xml.dom.pulldom.rst
Doc/library/xml.rst
Doc/library/xml.sax.rst
Doc/library/xmlrpc.client.rst
Doc/make.bat
Doc/reference/compound_stmts.rst
Doc/reference/expressions.rst
Doc/reference/simple_stmts.rst
Doc/reference/toplevel_components.rst
Doc/tools/extensions/escape4chm.py [new file with mode: 0644]
Doc/tutorial/classes.rst
Doc/tutorial/inputoutput.rst
Doc/tutorial/introduction.rst
Doc/tutorial/modules.rst
Doc/using/windows.rst
Doc/whatsnew/3.3.rst
Doc/whatsnew/3.5.rst
Doc/whatsnew/3.6.rst
Include/patchlevel.h
Include/pyexpat.h
Lib/_pyio.py
Lib/antigravity.py
Lib/asyncio/base_events.py
Lib/asyncio/proactor_events.py
Lib/asyncio/selector_events.py
Lib/asyncio/test_utils.py
Lib/base64.py
Lib/cProfile.py
Lib/concurrent/futures/_base.py
Lib/configparser.py
Lib/ctypes/test/test_as_parameter.py
Lib/ctypes/test/test_win32.py
Lib/datetime.py
Lib/distutils/_msvccompiler.py
Lib/distutils/log.py
Lib/distutils/spawn.py
Lib/distutils/tests/test_bdist.py
Lib/distutils/tests/test_bdist_wininst.py
Lib/distutils/tests/test_log.py
Lib/distutils/tests/test_spawn.py
Lib/email/_encoded_words.py
Lib/email/_header_value_parser.py
Lib/email/errors.py
Lib/enum.py
Lib/functools.py
Lib/hashlib.py
Lib/http/client.py
Lib/http/server.py
Lib/idlelib/NEWS.txt
Lib/idlelib/autocomplete.py
Lib/idlelib/autocomplete_w.py
Lib/idlelib/autoexpand.py
Lib/idlelib/browser.py
Lib/idlelib/calltip.py [new file with mode: 0644]
Lib/idlelib/calltip_w.py
Lib/idlelib/calltips.py [deleted file]
Lib/idlelib/codecontext.py
Lib/idlelib/colorizer.py
Lib/idlelib/config-main.def
Lib/idlelib/config.py
Lib/idlelib/config_key.py
Lib/idlelib/configdialog.py
Lib/idlelib/debugger.py
Lib/idlelib/debugger_r.py
Lib/idlelib/debugobj.py
Lib/idlelib/debugobj_r.py
Lib/idlelib/editor.py
Lib/idlelib/filelist.py
Lib/idlelib/grep.py
Lib/idlelib/help.py
Lib/idlelib/help_about.py
Lib/idlelib/hyperparser.py
Lib/idlelib/idle_test/README.txt
Lib/idlelib/idle_test/htest.py
Lib/idlelib/idle_test/template.py [new file with mode: 0644]
Lib/idlelib/idle_test/test_autocomplete.py
Lib/idlelib/idle_test/test_autocomplete_w.py [new file with mode: 0644]
Lib/idlelib/idle_test/test_autoexpand.py
Lib/idlelib/idle_test/test_browser.py
Lib/idlelib/idle_test/test_calltip.py [new file with mode: 0644]
Lib/idlelib/idle_test/test_calltip_w.py [new file with mode: 0644]
Lib/idlelib/idle_test/test_calltips.py [deleted file]
Lib/idlelib/idle_test/test_codecontext.py
Lib/idlelib/idle_test/test_colorizer.py
Lib/idlelib/idle_test/test_config.py
Lib/idlelib/idle_test/test_config_key.py
Lib/idlelib/idle_test/test_configdialog.py
Lib/idlelib/idle_test/test_debugger.py
Lib/idlelib/idle_test/test_debugger_r.py [new file with mode: 0644]
Lib/idlelib/idle_test/test_debugobj.py [new file with mode: 0644]
Lib/idlelib/idle_test/test_debugobj_r.py [new file with mode: 0644]
Lib/idlelib/idle_test/test_delegator.py
Lib/idlelib/idle_test/test_editor.py
Lib/idlelib/idle_test/test_filelist.py [new file with mode: 0644]
Lib/idlelib/idle_test/test_grep.py
Lib/idlelib/idle_test/test_help.py
Lib/idlelib/idle_test/test_help_about.py
Lib/idlelib/idle_test/test_history.py
Lib/idlelib/idle_test/test_hyperparser.py
Lib/idlelib/idle_test/test_iomenu.py
Lib/idlelib/idle_test/test_macosx.py
Lib/idlelib/idle_test/test_mainmenu.py [new file with mode: 0644]
Lib/idlelib/idle_test/test_multicall.py [new file with mode: 0644]
Lib/idlelib/idle_test/test_outwin.py
Lib/idlelib/idle_test/test_paragraph.py
Lib/idlelib/idle_test/test_parenmatch.py
Lib/idlelib/idle_test/test_pathbrowser.py
Lib/idlelib/idle_test/test_percolator.py
Lib/idlelib/idle_test/test_pyparse.py
Lib/idlelib/idle_test/test_pyshell.py [new file with mode: 0644]
Lib/idlelib/idle_test/test_query.py
Lib/idlelib/idle_test/test_redirector.py
Lib/idlelib/idle_test/test_replace.py
Lib/idlelib/idle_test/test_rpc.py [new file with mode: 0644]
Lib/idlelib/idle_test/test_rstrip.py
Lib/idlelib/idle_test/test_run.py
Lib/idlelib/idle_test/test_runscript.py [new file with mode: 0644]
Lib/idlelib/idle_test/test_scrolledlist.py
Lib/idlelib/idle_test/test_search.py
Lib/idlelib/idle_test/test_searchbase.py
Lib/idlelib/idle_test/test_searchengine.py
Lib/idlelib/idle_test/test_squeezer.py [new file with mode: 0644]
Lib/idlelib/idle_test/test_stackviewer.py [new file with mode: 0644]
Lib/idlelib/idle_test/test_statusbar.py [new file with mode: 0644]
Lib/idlelib/idle_test/test_textview.py
Lib/idlelib/idle_test/test_tooltip.py [new file with mode: 0644]
Lib/idlelib/idle_test/test_tree.py
Lib/idlelib/idle_test/test_undo.py
Lib/idlelib/idle_test/test_warning.py
Lib/idlelib/idle_test/test_window.py [new file with mode: 0644]
Lib/idlelib/idle_test/test_zoomheight.py [new file with mode: 0644]
Lib/idlelib/iomenu.py
Lib/idlelib/macosx.py
Lib/idlelib/mainmenu.py
Lib/idlelib/multicall.py
Lib/idlelib/outwin.py
Lib/idlelib/paragraph.py
Lib/idlelib/parenmatch.py
Lib/idlelib/percolator.py
Lib/idlelib/pyparse.py
Lib/idlelib/pyshell.py
Lib/idlelib/query.py
Lib/idlelib/redirector.py
Lib/idlelib/replace.py
Lib/idlelib/rpc.py
Lib/idlelib/rstrip.py
Lib/idlelib/run.py
Lib/idlelib/runscript.py
Lib/idlelib/scrolledlist.py
Lib/idlelib/search.py
Lib/idlelib/searchbase.py
Lib/idlelib/searchengine.py
Lib/idlelib/squeezer.py [new file with mode: 0644]
Lib/idlelib/stackviewer.py
Lib/idlelib/statusbar.py
Lib/idlelib/textview.py
Lib/idlelib/tooltip.py
Lib/idlelib/tree.py
Lib/idlelib/undo.py
Lib/idlelib/window.py [new file with mode: 0644]
Lib/idlelib/windows.py [deleted file]
Lib/idlelib/zoomheight.py
Lib/imaplib.py
Lib/inspect.py
Lib/logging/__init__.py
Lib/logging/config.py
Lib/multiprocessing/connection.py
Lib/multiprocessing/managers.py
Lib/multiprocessing/pool.py
Lib/multiprocessing/queues.py
Lib/multiprocessing/reduction.py
Lib/multiprocessing/synchronize.py
Lib/ntpath.py
Lib/pathlib.py
Lib/pickletools.py
Lib/platform.py
Lib/pydoc.py
Lib/pydoc_data/topics.py
Lib/random.py
Lib/site.py
Lib/smtplib.py
Lib/ssl.py
Lib/tarfile.py
Lib/test/_test_multiprocessing.py
Lib/test/allsans.pem
Lib/test/capath/b1930218.0
Lib/test/capath/ceff1710.0
Lib/test/datetimetester.py
Lib/test/dh1024.pem [deleted file]
Lib/test/eintrdata/eintr_tester.py
Lib/test/ffdh3072.pem [new file with mode: 0644]
Lib/test/inspect_fodder.py
Lib/test/keycert.passwd.pem
Lib/test/keycert.pem
Lib/test/keycert2.pem
Lib/test/keycert3.pem
Lib/test/keycert4.pem
Lib/test/libregrtest/cmdline.py
Lib/test/libregrtest/main.py
Lib/test/libregrtest/runtest.py
Lib/test/libregrtest/runtest_mp.py
Lib/test/libregrtest/utils.py
Lib/test/lock_tests.py
Lib/test/make_ssl_certs.py
Lib/test/pycacert.pem
Lib/test/pycakey.pem
Lib/test/pythoninfo.py
Lib/test/revocation.crl
Lib/test/ssl_cert.pem
Lib/test/ssl_key.passwd.pem
Lib/test/ssl_key.pem
Lib/test/support/__init__.py
Lib/test/support/testresult.py [new file with mode: 0644]
Lib/test/test_argparse.py
Lib/test/test_asyncio/test_base_events.py
Lib/test/test_asyncio/test_events.py
Lib/test/test_asyncio/test_proactor_events.py
Lib/test/test_asyncio/test_selector_events.py
Lib/test/test_asyncio/test_tasks.py
Lib/test/test_base64.py
Lib/test/test_builtin.py
Lib/test/test_call.py
Lib/test/test_capi.py
Lib/test/test_complex.py
Lib/test/test_concurrent_futures.py
Lib/test/test_dbm_gnu.py
Lib/test/test_deque.py
Lib/test/test_dict.py
Lib/test/test_email/test__encoded_words.py
Lib/test/test_email/test__header_value_parser.py
Lib/test/test_email/test_defect_handling.py
Lib/test/test_enum.py
Lib/test/test_epoll.py
Lib/test/test_file.py
Lib/test/test_float.py
Lib/test/test_flufl.py
Lib/test/test_ftplib.py
Lib/test/test_functools.py
Lib/test/test_gc.py
Lib/test/test_gdb.py
Lib/test/test_genericpath.py
Lib/test/test_getargs2.py
Lib/test/test_gzip.py
Lib/test/test_hashlib.py
Lib/test/test_httplib.py
Lib/test/test_imaplib.py
Lib/test/test_import/__init__.py
Lib/test/test_importlib/test_util.py
Lib/test/test_inspect.py
Lib/test/test_io.py
Lib/test/test_logging.py
Lib/test/test_long.py
Lib/test/test_marshal.py
Lib/test/test_multiprocessing_main_handling.py
Lib/test/test_ntpath.py
Lib/test/test_opcodes.py
Lib/test/test_os.py
Lib/test/test_pkg.py
Lib/test/test_platform.py
Lib/test/test_posix.py
Lib/test/test_posixpath.py
Lib/test/test_pulldom.py
Lib/test/test_random.py
Lib/test/test_regrtest.py
Lib/test/test_resource.py
Lib/test/test_sax.py
Lib/test/test_script_helper.py
Lib/test/test_shutil.py
Lib/test/test_signal.py
Lib/test/test_site.py
Lib/test/test_smtplib.py
Lib/test/test_socket.py
Lib/test/test_spwd.py
Lib/test/test_ssl.py
Lib/test/test_subprocess.py
Lib/test/test_support.py
Lib/test/test_sysconfig.py
Lib/test/test_tcl.py
Lib/test/test_threadsignals.py
Lib/test/test_time.py
Lib/test/test_tokenize.py
Lib/test/test_tools/test_sundry.py
Lib/test/test_traceback.py
Lib/test/test_unicodedata.py
Lib/test/test_urllib2_localnet.py
Lib/test/test_venv.py
Lib/test/test_warnings/__init__.py
Lib/test/test_webbrowser.py
Lib/test/test_xml_etree.py
Lib/test/test_zipfile.py
Lib/test/test_zlib.py
Lib/test/wrongcert.pem [deleted file]
Lib/tkinter/__init__.py
Lib/tkinter/test/support.py
Lib/tkinter/test/test_tkinter/test_widgets.py
Lib/tokenize.py
Lib/traceback.py
Lib/turtledemo/penrose.py
Lib/turtledemo/rosette.py [new file with mode: 0644]
Lib/turtledemo/tree.py
Lib/turtledemo/wikipedia.py [deleted file]
Lib/unittest/test/test_break.py
Lib/webbrowser.py
Lib/xml/sax/expatreader.py
Lib/zipfile.py
Mac/BuildScript/build-installer.py
Misc/ACKS
Misc/HISTORY
Misc/NEWS
Misc/SpecialBuilds.txt
Misc/valgrind-python.supp
Modules/Setup.dist
Modules/_asynciomodule.c
Modules/_blake2/blake2b_impl.c
Modules/_blake2/blake2s_impl.c
Modules/_blake2/clinic/blake2b_impl.c.h
Modules/_blake2/clinic/blake2s_impl.c.h
Modules/_bz2module.c
Modules/_collectionsmodule.c
Modules/_csv.c
Modules/_ctypes/_ctypes_test.c
Modules/_ctypes/callproc.c
Modules/_ctypes/libffi_msvc/ffi.c
Modules/_ctypes/libffi_msvc/ffi.h
Modules/_ctypes/libffi_msvc/prep_cif.c
Modules/_ctypes/libffi_msvc/win32.c
Modules/_datetimemodule.c
Modules/_elementtree.c
Modules/_hashopenssl.c
Modules/_io/iobase.c
Modules/_io/stringio.c
Modules/_io/textio.c
Modules/_io/winconsoleio.c
Modules/_json.c
Modules/_lsprof.c
Modules/_lzmamodule.c
Modules/_pickle.c
Modules/_posixsubprocess.c
Modules/_scproxy.c
Modules/_sha3/clinic/sha3module.c.h
Modules/_sha3/sha3module.c
Modules/_sqlite/connection.c
Modules/_sqlite/cursor.c
Modules/_sqlite/module.c
Modules/_sqlite/module.h
Modules/_sqlite/statement.c
Modules/_ssl.c
Modules/_testbuffer.c
Modules/_testcapimodule.c
Modules/_testmultiphase.c
Modules/_threadmodule.c
Modules/_winapi.c
Modules/clinic/_ssl.c.h
Modules/clinic/_winapi.c.h
Modules/expat/expat.h
Modules/expat/expat_external.h
Modules/expat/internal.h
Modules/expat/loadlibrary.c
Modules/expat/siphash.h
Modules/expat/xmlparse.c
Modules/expat/xmltok.c
Modules/expat/xmltok.h
Modules/expat/xmltok_impl.c
Modules/grpmodule.c
Modules/md5module.c
Modules/mmapmodule.c
Modules/ossaudiodev.c
Modules/posixmodule.c
Modules/pwdmodule.c
Modules/pyexpat.c
Modules/selectmodule.c
Modules/sha1module.c
Modules/sha256module.c
Modules/sha512module.c
Modules/socketmodule.c
Modules/timemodule.c
Modules/unicodedata.c
Objects/abstract.c
Objects/bytesobject.c
Objects/codeobject.c
Objects/dict-common.h
Objects/dictobject.c
Objects/longobject.c
Objects/moduleobject.c
Objects/namespaceobject.c
Objects/object.c
Objects/odictobject.c
Objects/rangeobject.c
Objects/typeobject.c
Objects/unicodeobject.c
PC/_msi.c
PC/launcher.c
PC/pyshellext.cpp
PCbuild/get_externals.bat
PCbuild/python.props
Parser/myreadline.c
Parser/parsetok.c
Python/ast.c
Python/bltinmodule.c
Python/ceval.c
Python/errors.c
Python/fileutils.c
Python/formatter_unicode.c
Python/getargs.c
Python/pystrtod.c
Python/pythonrun.c
Python/symtable.c
Python/traceback.c
README.rst
Tools/gdb/libpython.py
Tools/i18n/msgfmt.py
Tools/msi/README.txt
Tools/msi/distutils.command.bdist_wininst.py
Tools/ssl/multissltests.py
aclocal.m4
configure
configure.ac
pyconfig.h.in

diff --git a/.azure-pipelines/ci.yml b/.azure-pipelines/ci.yml
new file mode 100644 (file)
index 0000000..49a7bb6
--- /dev/null
@@ -0,0 +1,136 @@
+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
diff --git a/.azure-pipelines/docker-steps.yml b/.azure-pipelines/docker-steps.yml
new file mode 100644 (file)
index 0000000..ba4dfd7
--- /dev/null
@@ -0,0 +1,76 @@
+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'))
diff --git a/.azure-pipelines/docs-steps.yml b/.azure-pipelines/docs-steps.yml
new file mode 100644 (file)
index 0000000..c0404ae
--- /dev/null
@@ -0,0 +1,46 @@
+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
diff --git a/.azure-pipelines/macos-steps.yml b/.azure-pipelines/macos-steps.yml
new file mode 100644 (file)
index 0000000..6470816
--- /dev/null
@@ -0,0 +1,25 @@
+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()
diff --git a/.azure-pipelines/posix-deps.sh b/.azure-pipelines/posix-deps.sh
new file mode 100755 (executable)
index 0000000..a572107
--- /dev/null
@@ -0,0 +1,26 @@
+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
diff --git a/.azure-pipelines/posix-steps.yml b/.azure-pipelines/posix-steps.yml
new file mode 100644 (file)
index 0000000..9fec9be
--- /dev/null
@@ -0,0 +1,63 @@
+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()
diff --git a/.azure-pipelines/pr.yml b/.azure-pipelines/pr.yml
new file mode 100644 (file)
index 0000000..2d7fba9
--- /dev/null
@@ -0,0 +1,86 @@
+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)
diff --git a/.azure-pipelines/prebuild-checks.yml b/.azure-pipelines/prebuild-checks.yml
new file mode 100644 (file)
index 0000000..30ff642
--- /dev/null
@@ -0,0 +1,36 @@
+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
diff --git a/.azure-pipelines/windows-steps.yml b/.azure-pipelines/windows-steps.yml
new file mode 100644 (file)
index 0000000..d8d5f17
--- /dev/null
@@ -0,0 +1,32 @@
+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()
diff --git a/.vsts/docs-release.yml b/.vsts/docs-release.yml
deleted file mode 100644 (file)
index e90428a..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-# 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
diff --git a/.vsts/docs.yml b/.vsts/docs.yml
deleted file mode 100644 (file)
index 62f6123..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-# 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
diff --git a/.vsts/linux-buildbot.yml b/.vsts/linux-buildbot.yml
deleted file mode 100644 (file)
index 76222d1..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-# 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'
diff --git a/.vsts/linux-coverage.yml b/.vsts/linux-coverage.yml
deleted file mode 100644 (file)
index d16d9c9..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-# 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'
diff --git a/.vsts/linux-deps.yml b/.vsts/linux-deps.yml
deleted file mode 100644 (file)
index 540b76e..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-# 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'
diff --git a/.vsts/linux-pr.yml b/.vsts/linux-pr.yml
deleted file mode 100644 (file)
index 83df9b4..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-# 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'
diff --git a/.vsts/macos-buildbot.yml b/.vsts/macos-buildbot.yml
deleted file mode 100644 (file)
index 8a4f6ba..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-# 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'
diff --git a/.vsts/macos-pr.yml b/.vsts/macos-pr.yml
deleted file mode 100644 (file)
index 8a4f6ba..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-# 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'
diff --git a/.vsts/windows-buildbot.yml b/.vsts/windows-buildbot.yml
deleted file mode 100644 (file)
index 5ec4522..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-# 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)
diff --git a/.vsts/windows-pr.yml b/.vsts/windows-pr.yml
deleted file mode 100644 (file)
index 5ec4522..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-# 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)
index a29d1f3a708a4360802dae3be22bd1ea0688f495..d7bcc5ba7919bbe4d3306fa3fc0910c3fb32f2aa 100644 (file)
@@ -33,7 +33,7 @@ To get started on UNIX, you can create a virtual environment with the command ::
   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::
 
index c6d1d02a2fa510e99692b8ba4f2e8cd6f18c8050..17ec621610b5e3aded74939f5fc6ad499830e178 100644 (file)
@@ -40,12 +40,6 @@ unmarshalling.  Version 2 uses a binary format for floating point numbers.
 
 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)
 
@@ -53,7 +47,8 @@ written using these routines?
    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)
@@ -62,7 +57,8 @@ written using these routines?
    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)
@@ -70,8 +66,8 @@ written using these routines?
    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)
@@ -84,8 +80,8 @@ written using these routines?
    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)
@@ -93,6 +89,6 @@ written using these routines?
    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*.
 
index 73bec7c95a1df4030785484ffc17decae93987e6..b502b25f708bb5dba633037508281238f2f1b9b2 100644 (file)
@@ -35,7 +35,7 @@ operate within the bounds of the private heap.
 
 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.
index 43826ec01f46634d8c82070e68a4427c0f7dcca6..e2758bcd00b5bb1c16ad8c30ee1b8ab3c651ad19 100644 (file)
@@ -13,7 +13,7 @@ sys.path.append(os.path.abspath('tools/extensions'))
 # ---------------------
 
 extensions = ['sphinx.ext.coverage', 'sphinx.ext.doctest',
-              'pyspecific', 'c_annotations']
+              'pyspecific', 'c_annotations', 'escape4chm']
 
 # General substitutions.
 project = 'Python'
index bbd2a8ce831cee1daeb7dfe286e3b13259a75a0a..5e1a04979dacad0fc11155a50101534d9d09b7b6 100644 (file)
@@ -21,7 +21,7 @@ specialty---writing code and creating source distributions---while an
 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
index a38555910361b85a565a43fe8c205415d74ae997..7721484fe737178988767223f315c8321900c8a7 100644 (file)
@@ -94,7 +94,7 @@ containing your setup script :file:`setup.py`, and your module :file:`foo.py`.
 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 ::
 
index 1bd800b1a81babcf638fa3cf910cb66603525e2e..234dc9c12b5ec9a3ffedf3d8d6a7df82ca8120f2 100644 (file)
@@ -2,6 +2,11 @@
 Design and History FAQ
 ======================
 
+.. only:: html
+
+   .. contents::
+
+
 Why does Python use indentation for grouping of statements?
 -----------------------------------------------------------
 
@@ -210,24 +215,25 @@ objects using the ``for`` statement.  For example, :term:`file objects
 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?
@@ -465,10 +471,10 @@ you can always change a list's elements.  Only immutable elements can be used as
 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.
 
@@ -481,10 +487,10 @@ when the array must be grown, some extra space is allocated so the next few
 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.
 
index 7476ce11f4f141189e241ddb22640d67b1173468..b717ab8f0f81ef2246509639f4b7673e92d57a3e 100644 (file)
@@ -371,8 +371,8 @@ compute, a common technique is to cache the parameters and the resulting value
 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)]
 
index 6dbf0c398ddb0ba94a5dd03f0c3040fc260f4136..cf2ca671f26dd7dc9ce70fd5bd6e3c8ee09e5e26 100644 (file)
@@ -14,8 +14,9 @@ Glossary
 
    ``...``
       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
@@ -122,10 +123,10 @@ Glossary
       :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
@@ -636,7 +637,7 @@ Glossary
    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
@@ -1005,7 +1006,7 @@ Glossary
 
    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
index 40601812a77cb583c8f381ef8b2cba0512be82d8..7e21aa76a3647a79941f4a2be7f79325172aba83 100644 (file)
@@ -198,7 +198,7 @@ for it.
 
 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 ...>
@@ -229,7 +229,7 @@ iterator.  These two statements are equivalent::
 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
@@ -238,10 +238,10 @@ Iterators can be materialized as lists or tuples by using the :func:`list` or
 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
@@ -410,7 +410,7 @@ lengths of all the sequences.  If you have two lists of length 3, the output
 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),
@@ -478,7 +478,7 @@ Here's a sample usage of the ``generate_ints()`` generator:
       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)``
@@ -694,17 +694,17 @@ truth values of an iterable's contents.  :func:`any` returns ``True`` if any ele
 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
 
 
@@ -763,7 +763,7 @@ which defaults to 0, and the interval between numbers, which defaults to 1::
 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
@@ -874,7 +874,7 @@ iterable's results. ::
 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
 
 
@@ -1034,7 +1034,7 @@ first calculation. ::
     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
@@ -1044,9 +1044,9 @@ elements of the iterable.  This case is so common that there's a special
 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
@@ -1056,11 +1056,11 @@ write the obvious :keyword:`for` loop::
 
    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)
@@ -1068,10 +1068,10 @@ 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
 
 
@@ -1155,7 +1155,7 @@ But it would be best of all if I had simply used a ``for`` loop::
 
 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.
 
index ead7bdd23209a3d45eb498731454f427bf4fcb42..9caf1fdb20104af60af4e275acaa5682e180055f 100644 (file)
@@ -3,7 +3,7 @@
 int
 main(int argc, char *argv[])
 {
-    PyObject *pName, *pModule, *pDict, *pFunc;
+    PyObject *pName, *pModule, *pFunc;
     PyObject *pArgs, *pValue;
     int i;
 
index cd84ae76b5d86e0fbd6b7bee880e930cda683c6e..9605261c0a3f46cb32d1ede4f8c48154af08d36d 100644 (file)
@@ -124,11 +124,19 @@ ReadTransport
       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
 --------------
index 491afdd610ca0864867014f4e5ae435531b6e6c5..a510e1e638a73d83124bcd31ea201f3b189b4f5e 100644 (file)
@@ -88,10 +88,12 @@ Stream functions
 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.
index 82ba0573741390ee08fdeba8d5ad13d69b6246ee..25687348d16deef961c4032c41f1198184f89023 100644 (file)
@@ -198,6 +198,7 @@ updates keys found deeper in the chain::
     >>> 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'})
 
 
index ba107274f7bec48916756106a788892d37de950a..4abc6aa756062b901239ff10c4ecf1bd490b093c 100644 (file)
@@ -982,15 +982,16 @@ ConfigParser Objects
 
    .. 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
index dd34c96c8f8d6040289baae4c3bc47b49876a649..49eaba3d01ed95ce02bc7ae2239d8eb0538432d7 100644 (file)
@@ -36,22 +36,28 @@ Functions and classes provided:
    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
index cdcbefa4e8084af95e40d815778c022a13be501a..a7cc0c84df1b1ee1fabfccdbb627f337f48f979a 100644 (file)
@@ -1025,6 +1025,22 @@ As we can easily check, our array is sorted now::
    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
@@ -1575,7 +1591,9 @@ Foreign functions can also be created by instantiating function prototypes.
 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)
index 06141d1c00d92be16ddad250b192c6e6ea32b6ce..88bc328e3a1d4d812f71de68a20639d2bb3a34ac 100644 (file)
@@ -241,7 +241,7 @@ Supported operations:
 +--------------------------------+-----------------------------------------------+
 | ``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,         |
@@ -316,6 +316,11 @@ Notes:
   >>> 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).
@@ -497,8 +502,6 @@ Notes:
    :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)
@@ -507,10 +510,9 @@ Notes:
 
 (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
@@ -930,8 +932,6 @@ Supported operations:
    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
diff --git a/Doc/library/depgraph-output.png b/Doc/library/depgraph-output.png
deleted file mode 100644 (file)
index 960bb1b..0000000
Binary files a/Doc/library/depgraph-output.png and /dev/null differ
index 3f615dbd15ce1f979bf2b2ab3713fa38dfbcea69..d5757c2c6628d6def67dd57dc239b850c70a33de 100644 (file)
@@ -1043,18 +1043,20 @@ All of the following opcodes use their arguments.
 
 .. 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.
@@ -1062,31 +1064,36 @@ All of the following opcodes use their 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
 
@@ -1096,7 +1103,8 @@ All of the following opcodes use their arguments.
    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
@@ -1179,7 +1187,7 @@ instructions:
 
 .. data:: hasconst
 
-   Sequence of bytecodes that have a constant parameter.
+   Sequence of bytecodes that access a constant.
 
 
 .. data:: hasfree
index 5838767b18f742cf68b9b6a1ef10e72c0327b323..511ad16358319796a3940064e504e3668e61bc4d 100644 (file)
@@ -108,3 +108,7 @@ All defect classes are subclassed from :class:`email.errors.MessageDefect`.
 * :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.
index dea409d223da4cf783e50fd131648ce094d49772..e0cab6a69497431cff245b4053b892f5fe0d9111 100644 (file)
@@ -246,7 +246,7 @@ in the top-level :mod:`email` package namespace.
       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
index c4187dd0098d1a6cf257456ba5f05b013abfbb2f..1033d8c130eb756c8eba57d1d4813e07d28d47e8 100644 (file)
@@ -133,7 +133,7 @@ Legacy API:
 .. seealso::
 
    Module :mod:`smtplib`
-      SMTP (Simple Mail Transport Protcol) client
+      SMTP (Simple Mail Transport Protocol) client
 
    Module :mod:`poplib`
       POP (Post Office Protocol) client
index 5c1b226efc757d34dc04b3f8b69d85e7fa77d074..2bf4885d2159661679173199202daf39c457927a 100644 (file)
@@ -4,10 +4,10 @@
 .. 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
 
index a6b20a5ac95b1bb1ef84a0df15a51d0fd120b966..cfa1649d4d1ffb0ad49650de3068c24ec6f51a62 100644 (file)
@@ -524,7 +524,7 @@ The following exceptions are the exceptions that are usually raised.
 
 .. 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`.
 
index 501a3c99d41a9e2c57e55110f48bd77f4375ac0b..b6e52469bd85b52c76d4e76b7a24490c9b9f1a5f 100644 (file)
@@ -98,7 +98,7 @@ are always available.  They are listed here in alphabetical order.
       >>> 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])
@@ -226,8 +226,8 @@ are always available.  They are listed here in alphabetical order.
    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
@@ -420,8 +420,10 @@ are always available.  They are listed here in alphabetical order.
    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
@@ -632,11 +634,11 @@ are always available.  They are listed here in alphabetical order.
    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])
 
@@ -957,6 +959,11 @@ are always available.  They are listed here in alphabetical order.
    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
    ========= ===============================================================
index 9bd39cb4a51b1a5f317c9e7642c2c8e0c983c23c..b4f51763523333cd29000c0fe09862c2b17a0c35 100644 (file)
@@ -101,7 +101,7 @@ More condensed:
 
 .. 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`
@@ -162,10 +162,10 @@ A hash object has the following attributes:
 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)``.
 
@@ -206,7 +206,7 @@ by the SHAKE algorithm.
 .. 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.
 
 
@@ -262,9 +262,10 @@ include a `salt <https://en.wikipedia.org/wiki/Salt_%28cryptography%29>`_.
    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).
@@ -305,11 +306,11 @@ Creating hash objects
 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)
 
@@ -317,8 +318,8 @@ New hash objects are created by calling constructor functions:
 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.
 
@@ -427,7 +428,7 @@ object, and, finally, get the digest out of the object by calling
 
 
 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()
@@ -546,7 +547,7 @@ on the hash function used in digital signatures.
     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
index d0706bcbc0793411981f5532ecb2bc6b1c40a521..c2b01e14ea755569e1c78743e2b3fe21f5ba8272 100644 (file)
@@ -24,7 +24,7 @@ This module defines utilities to manipulate HTML.
 .. function:: unescape(s)
 
    Convert all named and numeric character references (e.g. ``&gt;``,
-   ``&#62;``, ``&x3e;``) in the string *s* to the corresponding unicode
+   ``&#62;``, ``&#x3e;``) 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>`.
index c1cd9485cc7882390a7736f50e9f4d1e58adaf3e..356d1608bf4eed4c685cbe4704195a76daa6afc4 100644 (file)
@@ -243,7 +243,7 @@ ABC hierarchy::
 
    .. 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.
 
@@ -681,7 +681,7 @@ ABC hierarchy::
 
        Concrete implementation of :meth:`Loader.exec_module`.
 
-      .. versionadded:: 3.4
+       .. versionadded:: 3.4
 
     .. method:: load_module(fullname)
 
index 73b3efff0f49a5be79e9708b20cd3b16317e1a3b..28aac923cc375b6a890131d2d905655202db8712 100644 (file)
@@ -790,7 +790,7 @@ Text I/O
 
       .. 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.
index d6dcd5209928650430247ceeac873df2de6142f8..aa9da91303086334a5ef948b435431b6a5cba22e 100644 (file)
@@ -188,6 +188,11 @@ Basic Usage
    .. 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, \
@@ -198,12 +203,6 @@ Basic Usage
    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
index 9ef174ebb44cce21440bc36f395ea4233eebeb52..590d55689d8a7e7f0ca0485c52e5734fa86ef45d 100644 (file)
@@ -1129,52 +1129,54 @@ functions.
    +--------------+---------------------------------------------+
    | 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()
 
index 20d7974e29fd732f2deb62fc97793281a10bfa00..a3cdfd74eadf29d2e149d7e663cb79475b59e327 100644 (file)
@@ -135,7 +135,7 @@ start a *semaphore tracker* process which tracks the unlinked named
 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.)
 
@@ -179,7 +179,7 @@ program. ::
 
 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 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
index 337c7c2994169b07e9e17cde5c0c7ae4a1db40de..e9b82ee2ac13c7108a678209fbe742f5a42dab0a 100644 (file)
@@ -1677,7 +1677,7 @@ The callback function should raise :exc:`OptionValueError` if there are any
 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:
index 34ab3b8edf962b61d6a65ff131007723ce88fcc1..0377027da56fac62535ccd3c07b5109c970feece 100644 (file)
@@ -555,7 +555,8 @@ Pure paths provide the following methods and properties:
 .. 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')
@@ -563,6 +564,9 @@ Pure paths provide the following methods and properties:
       >>> p = PureWindowsPath('README')
       >>> p.with_suffix('.txt')
       PureWindowsPath('README.txt')
+      >>> p = PureWindowsPath('README.txt')
+      >>> p.with_suffix('')
+      PureWindowsPath('README')
 
 
 .. _concrete-paths:
@@ -893,7 +897,8 @@ call fails (for example because the path doesn't exist):
       >>> 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
 
index f5cb52cb4745b4cf2d8049cf20b0e53a2906c50e..7d29dc186b67c7712319f38b15ad101ef05cb3ac 100644 (file)
@@ -270,7 +270,7 @@ Unix Platforms
    .. 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,
index 32d2116e4b149150cf803a59e7b1176b7c1b2816..845065e38133240111f1e9621c7aecd68c45387e 100644 (file)
@@ -290,6 +290,11 @@ functions:
 
       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
index 14360edc31ec33e22bd26f8aa7b1e146a2b8bdfa..82632b9232b321d60849f1cc474f9e0abfdd013b 100644 (file)
@@ -1426,8 +1426,8 @@ Finding all Adverbs
 ^^^^^^^^^^^^^^^^^^^
 
 :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."
@@ -1441,8 +1441,8 @@ Finding all Adverbs and their Positions
 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):
index bd5442c6a27aa0917e20e80d63517fe1254c2a5f..413ec3579a462428212be720c36c9fade3828819 100644 (file)
@@ -57,7 +57,16 @@ The module defines the following:
 
    (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.
index 71ba999f12fb314df0136466d24317dcee107521..dabb4fee514c8d75be5aa2549133340ad1d7b0a0 100644 (file)
@@ -243,7 +243,7 @@ If it is called without arguments, it will print the contents of
 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.
index 86e769e6a1f8dc701f97456a41c074f3ffdf6627..6fb0934218a603ade74d2f5b27f56a525fc7564b 100644 (file)
@@ -271,7 +271,7 @@ An :class:`SMTP` instance has the following methods:
 
 .. 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.
 
@@ -346,7 +346,7 @@ An :class:`SMTP` instance has the following methods:
 
    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
@@ -355,7 +355,7 @@ An :class:`SMTP` instance has the following methods:
    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``,
@@ -379,16 +379,23 @@ An :class:`SMTP` instance has the following methods:
    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.
 
@@ -412,7 +419,7 @@ An :class:`SMTP` instance has the following methods:
       :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
@@ -484,7 +491,7 @@ An :class:`SMTP` instance has the following methods:
 
 
 .. 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
index 512c38e785d22fd60280562133263f7b737e9dc6..f4e5af9d5eb57991e549e8476db37f5647798c9d 100644 (file)
@@ -70,6 +70,13 @@ created.  Socket addresses are represented as follows:
   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
@@ -149,16 +156,25 @@ created.  Socket addresses are represented as follows:
 
   .. 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
@@ -342,6 +358,17 @@ Constants
 
    .. 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
@@ -423,16 +450,16 @@ The following functions all create :ref:`socket objects <socket-objects>`.
 
    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>`.
 
index ef0c0bf64cdadd76c2465da52ccb9b3689e9f0d5..a9048046ae4b1c591049136ee193b843e32280b7 100644 (file)
@@ -229,8 +229,8 @@ Module functions and constants
    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)
@@ -274,7 +274,7 @@ Connection Objects
 
    .. 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.
 
@@ -764,6 +764,20 @@ Exceptions
    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:
 
@@ -932,22 +946,30 @@ timestamp converter.
 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
index 45418c7db1cca7efc8e885ebbde2081e8b6ef9fd..a85be1a744abecea6a6d08f3acd0dcf2f4f6ba26 100644 (file)
@@ -221,7 +221,7 @@ instead.
 
    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
@@ -300,11 +300,6 @@ purposes.
 
      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
 ^^^^^^^^^^^^^^^^^
@@ -821,6 +816,15 @@ Constants
 
    .. 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
@@ -1206,6 +1210,26 @@ SSL sockets also have the following additional methods and attributes:
    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
@@ -1465,7 +1489,7 @@ to speed up repeated connections from the same clients.
 
    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.
@@ -1474,6 +1498,9 @@ to speed up repeated connections from the same clients.
       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
@@ -1686,6 +1713,28 @@ to speed up repeated connections from the same clients.
          >>> 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
@@ -1737,7 +1786,7 @@ message with one of the parts, you can decrypt it with the other part, and
 
 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
index 2aa778c4d06deb94d545ecdb6a4c3513256ad604..652e751366c546140e8cb00c0f6145b510615a71 100644 (file)
@@ -169,6 +169,10 @@ However, for reading convenience, most of the examples show sorted sequences.
    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`
 
 
index d8a1647e8b587d06693e6cb595fe4ab1d746f845..6de7e1a2df5acc2630df5143a1be59b8cbc9f7e7 100644 (file)
@@ -197,8 +197,8 @@ exception.
    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:
 
@@ -382,7 +382,7 @@ modules.
 .. _bitstring-ops:
 
 Bitwise Operations on Integer Types
---------------------------------------
+-----------------------------------
 
 .. index::
    triple: operations on; integer; types
@@ -396,9 +396,9 @@ Bitwise 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
@@ -409,13 +409,13 @@ This table lists the bitwise operations sorted in ascending priority:
 +------------+--------------------------------+----------+
 | 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)   |
@@ -438,6 +438,12 @@ Notes:
    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
 -----------------------------------
@@ -1059,10 +1065,10 @@ accepts integers that meet the value restriction ``0 <= x <= 255``).
 |                              | 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           |                     |
@@ -1365,7 +1371,7 @@ objects that compare equal might have different :attr:`~range.start`,
 .. 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::
@@ -1600,13 +1606,14 @@ expression support in the :mod:`re` module).
    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
@@ -2042,7 +2049,7 @@ expression support in the :mod:`re` module).
 .. 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).
@@ -2305,7 +2312,7 @@ data and are closely related to string objects in a variety of other ways.
    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
@@ -3360,7 +3367,10 @@ Notes:
    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:
index 706d5e1fff3f33e87ba394bced459db5d5b66e20..a87d285e0d2798c0fb9687504a4044e5f0c6fe63 100644 (file)
@@ -231,8 +231,11 @@ attribute using :func:`getattr`, while an expression of the form ``'[index]'``
 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::
 
@@ -461,11 +464,11 @@ The available presentation types for floating point and decimal values are:
    | ``'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   |
index f624adbda4c805ae5b4d325042785bc54e80b3c1..dfb183aba547f4482d14e67034eb1e11a13acd56 100644 (file)
@@ -1199,14 +1199,15 @@ handling consistency are valid for these functions.
       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')
index c59aca1e1890864dc8c21a97bbcbb9b104190901..0d0da4d62e4725fc9d0719127cbda91d758f7a2c 100644 (file)
@@ -253,7 +253,7 @@ to specify the directory and this is the recommended approach.
    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`.
 
index 26e6a35bfba2542a1d9b301c2c47c513a5952763..063d2c0663662673f05e759ccc547349856741ac 100644 (file)
@@ -400,7 +400,8 @@ All methods are executed atomically.
          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()
index 55d331c996a187c343196bf974b86db05022398e..7ac3cacd3d1c9316fc097301476dbe449bb9387d 100644 (file)
@@ -88,14 +88,16 @@ The module defines the following functions:
 
 .. 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)
@@ -107,12 +109,12 @@ The module defines the following functions:
 
 .. 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)
@@ -293,9 +295,9 @@ capture data for later printing in a lightweight fashion.
 
    .. 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()
 
index bd6f3a95fe62c95192d8e7eda3494eba99ab675c..e80cd3f2d75cea955c47eb81df1435929763c1d1 100644 (file)
@@ -169,6 +169,8 @@ It is possible to declare the return type of a callable without specifying
 the call signature by substituting a literal ellipsis
 for the list of arguments in the type hint: ``Callable[..., ReturnType]``.
 
+.. _generics:
+
 Generics
 --------
 
@@ -183,7 +185,7 @@ subscription to denote expected types for container elements.
    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`.
 
 ::
@@ -488,8 +490,9 @@ The module defines the following classes, functions and decorators:
    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]]): ...
 
@@ -992,10 +995,18 @@ The module defines the following classes, functions and decorators:
 
    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
 
index 9d4d36fe005c772d013f166f180a71ffbebc118f..6841ef8ecc2b4174f48ec9776a10793e348d189d 100644 (file)
@@ -1825,12 +1825,12 @@ sentinel
 
 .. 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>`.
@@ -2069,22 +2069,22 @@ mock_open
 
 .. 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.
index f0de85f76157f421368aa4d1227c254bd626629a..dd85e9e33d9c8cc1a213e173d79277209c5c1aac 100644 (file)
@@ -393,7 +393,7 @@ run whether the test method succeeded or not.
 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
@@ -705,7 +705,7 @@ Test cases
 
    .. 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`::
 
@@ -925,7 +925,7 @@ Test cases
    +---------------------------------------------------------+--------------------------------------+------------+
 
    .. 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
@@ -965,7 +965,7 @@ Test cases
 
 
    .. 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
@@ -991,7 +991,7 @@ Test cases
 
 
    .. 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
@@ -1032,7 +1032,7 @@ Test cases
 
 
    .. 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
index 705517a32e33a5d22d0c7ec1b93c0231120c17c3..0890f74ca793f190bfc232622c29b46c08179d5e 100644 (file)
@@ -1125,7 +1125,7 @@ UnknownHandler Objects
 HTTPErrorProcessor Objects
 --------------------------
 
-.. method:: HTTPErrorProcessor.http_response()
+.. method:: HTTPErrorProcessor.http_response(request, response)
 
    Process HTTP error responses.
 
@@ -1137,7 +1137,7 @@ HTTPErrorProcessor Objects
    :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.
 
@@ -1339,9 +1339,9 @@ some point in the future.
 
    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.
index 5c0f469ad7a5cf5e32508480100ef91330cf9134..2504409e7f87cce67a44d3ae46af2471bc896e8d 100644 (file)
@@ -25,6 +25,20 @@ events until either processing is finished or an error condition occurs.
    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::
 
index 63c24f80ac87c41d9524b3a17725ac506816b26c..9b8ba6b17c85314b7e4974aa62250cdf393fc35a 100644 (file)
@@ -65,8 +65,8 @@ kind                       sax              etree             minidom          p
 =========================  ==============   ===============   ==============   ==============   ==============
 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**
 =========================  ==============   ===============   ==============   ==============   ==============
 
@@ -75,6 +75,8 @@ decompression bomb         Safe             Safe              Safe             S
 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
index 78d6633e098ba55cd1262ec9c9db704f7dfbb943..1a8f183a945fa4409a7640654267d1ebf2a31927 100644 (file)
@@ -24,6 +24,14 @@ the SAX API.
    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:
 
index ed2ccaeae07a91fb785526e66d306577e97f45c1..27d92e324722eabdd4d8518d4c1f43a33d4ce1e3 100644 (file)
@@ -145,7 +145,7 @@ between conformable Python objects and XML on the wire.
 
    .. 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.
index 8c6cb9a3b364ecf5e8dcbe40e324f5b3078319a6..2ddb3e23fc1fa0eebaad6e217d5afc5b0c0750b0 100644 (file)
@@ -131,6 +131,9 @@ if exist ..\Misc\NEWS (
 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
index dca9362400455c87bc53fa1b9e93896971d417b2..1f753308e398a3cba26366b865663ecb4b9bdecf 100644 (file)
@@ -91,7 +91,7 @@ The :keyword:`if` statement is used for conditional execution:
 
 .. 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
@@ -203,7 +203,7 @@ returns the list ``[0, 1, 2]``.
       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)
@@ -235,7 +235,7 @@ The :keyword:`try` statement specifies exception handlers and/or cleanup code
 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`]
@@ -383,7 +383,7 @@ This allows common :keyword:`try`...\ :keyword:`except`...\ :keyword:`finally`
 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:
@@ -467,14 +467,15 @@ A function definition defines a user-defined function object (see section
 :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`
@@ -682,7 +683,8 @@ Coroutine function definition
 -----------------------------
 
 .. productionlist::
-   async_funcdef: [`decorators`] "async" "def" `funcname` "(" [`parameter_list`] ")" ["->" `expression`] ":" `suite`
+   async_funcdef: [`decorators`] "async" "def" `funcname` "(" [`parameter_list`] ")"
+                : ["->" `expression`] ":" `suite`
 
 .. index::
    keyword: async
index 57ae639ab6e0ac555a6d9f00dcd1e68056a30134..3f929bf0928736597fe407f158dac5c22b68d121 100644 (file)
@@ -730,7 +730,7 @@ whose value is one of the keys of the mapping, and the subscription selects the
 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
@@ -1013,7 +1013,7 @@ The power operator binds more tightly than unary operators on its left; it binds
 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
@@ -1085,7 +1085,7 @@ operators and one for additive operators:
 
 .. 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`
 
@@ -1097,7 +1097,9 @@ the other must be a sequence. In the former case, the numbers are converted to a
 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.
@@ -1163,7 +1165,7 @@ Shifting operations
 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.
@@ -1228,7 +1230,7 @@ C, expressions like ``a < b < c`` have the interpretation that is conventional
 in mathematics:
 
 .. productionlist::
-   comparison: `or_expr` ( `comp_operator` `or_expr` )*
+   comparison: `or_expr` (`comp_operator` `or_expr`)*
    comp_operator: "<" | ">" | "==" | ">=" | "<=" | "!="
                 : | "is" ["not"] | ["not"] "in"
 
@@ -1592,9 +1594,9 @@ Expression lists
 .. 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
index 8d17383853a3c4ac6e3961d147eec12137aadb38..76630dfc590fdb402767de1989bca34f52a2a4fd 100644 (file)
@@ -708,15 +708,14 @@ The :keyword:`import` statement
    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:
@@ -838,12 +837,11 @@ features on a per-module basis before the release in which the feature becomes
 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 e1687ff04d328683af030149e76c4c202c81b2af..d5ffb37b2e58cde69f65d4ea134b521e2c4edb08 100644 (file)
@@ -48,14 +48,15 @@ a complete program; each statement is executed in the namespace of
 
 .. 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:
diff --git a/Doc/tools/extensions/escape4chm.py b/Doc/tools/extensions/escape4chm.py
new file mode 100644 (file)
index 0000000..6f2e357
--- /dev/null
@@ -0,0 +1,39 @@
+"""
+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}
index 4676ef4b8a6044c18ec008e22bfccdb4c9a66153..f26838cddbfa0dbceb489286fafc1a9b2ad19c76 100644 (file)
@@ -387,8 +387,8 @@ the corresponding function with an argument list that is created by inserting
 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
index d5531029d064c2de66486b5a0db692f2fe18545b..9fd939a20388ac8b322b4a64ff1c05b1d5cc380e 100644 (file)
@@ -289,7 +289,7 @@ automatically fail. ::
    >>> 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:
index 6415ae66ab877477574719c667d25fb815adcb53..2454bf0b0528e38434b557c671e2f8610cfe062e 100644 (file)
@@ -143,12 +143,12 @@ to escape quotes::
    "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
@@ -159,10 +159,10 @@ enclosed in single quotes.  The :func:`print` function produces a more
 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.'
index a4c766efb72d18de1f8fa7329ec94e046e497319..04352cf6e9d2898c9119e22259d744737df3b02b 100644 (file)
@@ -249,7 +249,7 @@ Some tips for experts:
   directory.
 
 * There is more detail on this process, including a flow chart of the
-  decisions, in PEP 3147.
+  decisions, in :pep:`3147`.
 
 
 .. _tut-standardmodules:
index c6624fe446b01aa6b4cfe7ea861027a80d265039..a4294686fafec1cd06c7544d5fd4aa9fbb8f99ab 100644 (file)
@@ -147,7 +147,7 @@ of available options is shown below.
 |                           | ``.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                        |
@@ -210,7 +210,7 @@ The options listed above can also be provided in a file named ``unattend.xml``
 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
 
@@ -610,7 +610,7 @@ Customization via INI files
 
 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)
@@ -816,7 +816,7 @@ following advice will prevent conflicts with other installations:
 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::
index b091507a19d557771c3a0c348b9e18c4166fa771..79b349072cf5824b7126ccf9082d7369b5aeb4a7 100644 (file)
@@ -303,7 +303,7 @@ The launcher can also be used explicitly from the command line as the ``py``
 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
@@ -1414,7 +1414,7 @@ http
 :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.
@@ -2386,7 +2386,7 @@ Porting Python code
   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
index 96f86e6c6142da9781574c02ee95f2be6c939f79..dc6a3eadb5387ae84c7eb405cb8f616066365404 100644 (file)
@@ -2471,7 +2471,7 @@ Changes in the Python API
   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.
index 2c675a5fbb44bf3d09688eb49d224c8ee6289f8c..96a8831cd6fff15b71110f737d7c9e6f00f50968 100644 (file)
@@ -1176,13 +1176,22 @@ Editor code context option revised.  Box displays all context lines up to
 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
@@ -1462,6 +1471,10 @@ Server and client-side specific TLS protocols for :class:`~ssl.SSLContext`
 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
 ----------
@@ -1855,7 +1868,7 @@ Build and C API Changes
   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`.
 
@@ -2051,6 +2064,15 @@ connected to and thus what Python interpreter will be used by the virtual
 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
 -------------------------------------------
 
@@ -2159,7 +2181,7 @@ Changes in the Python 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
@@ -2404,3 +2426,10 @@ Notable changes in Python 3.6.5
 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`.
index f20d080f5b983053f86d71a90bb57cb009885722..ee403a82cc03a39a08add6f930f881cedd65af2a 100644 (file)
 /*--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.
index 44259bf6d716bab70325f7375b70c5d05c7ad3e8..07020b5dc964cb3abeeb7bd14131dce55acc737a 100644 (file)
@@ -3,7 +3,7 @@
 
 /* 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
@@ -48,6 +48,8 @@ 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! */
 };
 
index 2ebfb0576f592bd68cffd07f69b18d3880413350..b577dede5da86053845ca901c05839909cd9e4cb 100644 (file)
@@ -2064,6 +2064,7 @@ class TextIOWrapper(TextIOBase):
         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()
index 9b143680372210efed9dc507a069b1954ab1d54d..c6f174ca6d8736949754519c167fea0182246827 100644 (file)
@@ -11,7 +11,7 @@ def geohash(latitude, longitude, datedow):
     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:]))
index 083f45df2ffdf4b312ab52c5490ea18df84da01e..accd669250cbefb55924bf41c2050406fa38f66b 100644 (file)
@@ -54,6 +54,11 @@ _MIN_CANCELLED_TIMER_HANDLES_FRACTION = 0.5
 _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
@@ -136,7 +141,7 @@ def _ipaddr_info(host, port, family, type, proto):
 
     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]
@@ -152,7 +157,10 @@ def _ipaddr_info(host, port, family, type, proto):
         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
 
@@ -360,10 +368,7 @@ class BaseEventLoop(events.AbstractEventLoop):
     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:
@@ -997,7 +1002,6 @@ class BaseEventLoop(events.AbstractEventLoop):
                 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 = []
@@ -1037,7 +1041,9 @@ class BaseEventLoop(events.AbstractEventLoop):
                     # 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)
@@ -1372,7 +1378,7 @@ class BaseEventLoop(events.AbstractEventLoop):
         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()
index 967a696961a611df944debb1f161c96bf9ace6c6..6f621ef0cc4f188cbaaed1af3671586a732bdce6 100644 (file)
@@ -160,20 +160,16 @@ class _ProactorReadPipeTransport(_ProactorBasePipeTransport,
         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
index 81dfd7651c5ed0a8432a7c175a5e3d238bcc9726..bc7c740cc2af3826dc7fb0c895aaeca557a92b15 100644 (file)
@@ -703,18 +703,16 @@ class _SelectorSocketTransport(_SelectorTransport):
                                  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():
index 8b8c22a74757de5efb0379b855953f7590d4962a..f41720428cecd2ef3d23ddcd56c4a1687c2a75ac 100644 (file)
@@ -335,12 +335,19 @@ class TestLoop(base_events.BaseEventLoop):
             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)
index eb8f258a2d1977408fc23a4cd3eccdb4937b0ba8..2be9c395a96674718fd51d5afe716598e577b8aa 100755 (executable)
@@ -231,23 +231,16 @@ def b32decode(s, casefold=False, map01=None):
             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.
index 1184385ae1f1fe1909f59fc2d79619afcc51e6e4..6ae8512ddd2e4839c4f0b4cbb87a7b7467c804aa 100755 (executable)
@@ -25,11 +25,11 @@ runctx.__doc__ = _pyprofile.runctx.__doc__
 # ____________________________________________________________
 
 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).
     """
index 6bace6c7464121c5869c7fee880ad5dcd02ece02..4c140508c9eaec1f3883b90c9adfb06a2c61dbab 100644 (file)
@@ -212,7 +212,7 @@ def as_completed(fs, timeout=None):
             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)
@@ -231,7 +231,7 @@ def as_completed(fs, timeout=None):
             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' % (
@@ -570,7 +570,7 @@ class Executor(object):
             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)]
 
@@ -585,7 +585,7 @@ class Executor(object):
                     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()
index 230ab2b017eade3c35c9738a53e2a60c0015005f..0e529e9693ab48df8f32b282326d6da5d8f72d2a 100644 (file)
@@ -80,7 +80,7 @@ ConfigParser -- responsible for parsing a list of
         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.
 
@@ -677,13 +677,13 @@ class RawConfigParser(MutableMapping):
         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.
index a2640575a07452e5038a6ea6b798c9c4a21db949..f9d27cb89d341b9b9f06d9b0c2cadde4f31b96cc 100644 (file)
@@ -24,7 +24,7 @@ class BasicWrapTestCase(unittest.TestCase):
         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
index 5d85ad6200b31997ef77f3caf7c9fec58b9b58a0..a2941f3fe0785a3271e40828c2534e1ff348759c 100644 (file)
@@ -54,6 +54,24 @@ class FunctionCallTestCase(unittest.TestCase):
         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):
index b2b1457e376fa1d04bab1b7b40cd5ac2bcd7ddd4..b8782fc8b363ce4d3437c5810a2f935ae712f5b3 100644 (file)
@@ -6,6 +6,7 @@ time zone and DST data sources.
 
 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
@@ -1444,6 +1445,14 @@ class datetime(date):
             # 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)
index c9d3c6c67120a5109d05de9d094b328e29fca544..30b3b4739851bad041e94c4285e7fec82c7038f6 100644 (file)
@@ -252,11 +252,11 @@ class MSVCCompiler(CCompiler) :
 
         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,
index b301a8338c20dbbf7dee4b92b7b7ede449991ef0..8ef6b28ea2ec097ae6ab5d9ac9b2e0d3fc8f4809 100644 (file)
@@ -27,11 +27,13 @@ class Log:
                 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):
index 5dd415a283d1de57af8c01c625d4415d42568cd2..538768809327955d3409d57ffe47462014de9a96 100644 (file)
@@ -173,7 +173,7 @@ def find_executable(executable, path=None):
     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)
index f762f5d98730991abacf3db1b3b0ecc3495e6d83..c80b3edc022088fdafdf56f8ef2bbb4305ca4d38 100644 (file)
@@ -39,6 +39,9 @@ class BuildTestCase(support.TempdirManager,
 
         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)
 
index 5d17ab19a9d89afcbca0a9cd681ff9a160e4a7ae..4c19bbab219baf866cb91348a551bdfaedff0ff7 100644 (file)
@@ -5,6 +5,8 @@ from test.support import run_unittest
 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):
index 0c2ad7a4268d49ab958dff5e312df800f9e8605d..75cf900617be6c52ef52361996a35e29b2ae6137 100644 (file)
@@ -1,35 +1,43 @@
 """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)
index 5edc24a3a10491cbf165bb80284849083340dc15..0d455385d8ace9a21b8dd2acbbccd8c0d13c0269 100644 (file)
@@ -1,9 +1,13 @@
 """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
@@ -51,6 +55,47 @@ class SpawnTestCase(support.TempdirManager,
         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)
 
index 5eaab36ed0a6c35f73abe67a7ea79fca3ddcdf24..b43b18000932036ecdd312b0dba5c835723bd4d1 100644 (file)
@@ -98,30 +98,42 @@ def len_q(bstring):
 #
 
 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')
index 14ffd30ca47194692869a8a1d7ccfeb6bd3b9f8d..de7ab5d12e78bd6e2a0503bb92e79e734a13ad1b 100644 (file)
@@ -1876,7 +1876,7 @@ def get_group(value):
     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'))
index 791239fa6a54cc0a826d1c53df8c42cba5a9619c..d28a6800104babc44734bf4b75f4f94785178bae 100644 (file)
@@ -73,6 +73,9 @@ class InvalidBase64PaddingDefect(MessageDefect):
 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):
index 112523e998f77c369657c577db6a7b3e59462382..8405fa965d063f389f04d78ddfdc9f6a78951864 100644 (file)
@@ -155,9 +155,11 @@ class EnumMeta(type):
         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_ = {}
@@ -217,7 +219,7 @@ class EnumMeta(type):
                 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
index 89f2cf4f5f7d6921b17c81f602da974d6de31038..784628829d8570e3ada9c5babef818ad6a49f5b5 100644 (file)
@@ -800,8 +800,13 @@ def singledispatch(func):
         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
index 053a7add4593d84fa3b1f3a994504ff4b2a4cfe6..98d2d7981a3854020d570f5da9d762e33af342f5 100644 (file)
@@ -25,18 +25,18 @@ Choose your hash function wisely.  Some have known collision weaknesses.
 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
@@ -130,14 +130,15 @@ def __get_openssl_constructor(name):
 
 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.
index 8a82c57eb5d2dbae0f427e7e249adc2dbde78b42..baabfeb2ea8c8f6e8600d39daf01a9f33936b804 100644 (file)
@@ -322,7 +322,7 @@ class HTTPResponse(io.BufferedIOBase):
 
         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")
index e12e45bfc3809577ec861d04e870c38cad320972..60a4dadf033600252f91c217b7a90aa49dea63a2 100644 (file)
@@ -466,7 +466,7 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
             })
             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:
index ada8801d0dad79f27e57341d2bb7e8624343f43f..8ecd85a9ceb69d3c312c47cd11ec92a16c6b53a9 100644 (file)
@@ -1,8 +1,65 @@
-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
@@ -183,7 +240,7 @@ To see the example in action, enable it on options extensions tab.
 
 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
@@ -431,7 +488,7 @@ Released on 2016-12-23
   -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.
@@ -497,7 +554,7 @@ Released on 2016-12-23
 
 - 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.
index edf445f08b586909bdd00910fd08046b65045db4..9caf50d5d0c21c8820be91fea89e5735457e6239 100644 (file)
@@ -226,7 +226,6 @@ class AutoComplete:
 
 AutoComplete.reload()
 
-
 if __name__ == '__main__':
     from unittest import main
     main('idlelib.idle_test.test_autocomplete', verbosity=2)
index 12113f95e63aa68f9b58222a4e1089f2cab4c7f9..9e0d336523d4799fe53450fabd69288e40b4edb6 100644 (file)
@@ -246,7 +246,7 @@ class AutoCompleteWindow:
         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)
@@ -269,7 +269,7 @@ class AutoCompleteWindow:
         # 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)
@@ -458,3 +458,10 @@ class AutoCompleteWindow:
         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
index 42e733a1a9e7358ee9f272c8a0482d9103f1e644..92f5c84eb6f40195c1bfa989002304a6c8d76cad 100644 (file)
@@ -92,5 +92,5 @@ class AutoExpand:
 
 
 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)
index 571dd8fe0e20a32076a8c0a9e4566b3678e053b4..104a92a4c1ae02e015f83777e12fc53999e435f4 100644 (file)
@@ -16,7 +16,7 @@ import sys
 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.
diff --git a/Lib/idlelib/calltip.py b/Lib/idlelib/calltip.py
new file mode 100644 (file)
index 0000000..758569a
--- /dev/null
@@ -0,0 +1,178 @@
+"""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)
index bf967f40b6ab1c10a7a683c20a74d38ab343f79c..7553dfefc55c0bd8a52a0525a752893bf390e020 100644 (file)
-"""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
@@ -112,53 +120,81 @@ class CallTip:
         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)
diff --git a/Lib/idlelib/calltips.py b/Lib/idlelib/calltips.py
deleted file mode 100644 (file)
index ec8f616..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-"""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)
index 8b378bceba250ac581fde73ef10fdd3e4fcee6a1..7c88a4d015e358c54f871932efb646a66428cef1 100644 (file)
@@ -233,6 +233,8 @@ class CodeContext:
 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.
index f450ec2fd4ef5abdba4003cab9fbc56dbab54a9f..f2de9fc455154a4c216b1c64bdfdf874975a6ab4 100644 (file)
@@ -31,11 +31,12 @@ def make_pat():
 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')
@@ -50,6 +51,7 @@ def color_config(text):  # Called from htest, Editor, and Turtle Demo.
         inactiveselectbackground=select_colors['background'],  # new in 8.5
     )
 
+
 class ColorDelegator(Delegator):
 
     def __init__(self):
@@ -285,10 +287,10 @@ def _color_delegator(parent):  # htest #
     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)
index 16f4b0959cf13cc9f198f0426275bb884dff9cae..06e3c5adb0e35b62b0d3808fdec3e0981335fc10 100644 (file)
@@ -66,6 +66,9 @@ font-size= 10
 font-bold= 0
 encoding= none
 
+[PyShell]
+auto-squeeze-min-lines= 50
+
 [Indent]
 use-spaces= 1
 num-spaces= 4
index 94b20832091691af6cef98c9011cf70b16858e65..0eb90fc8dc5fd6718c0b008ec0fc187bbfe1fac1 100644 (file)
@@ -925,7 +925,7 @@ def _dump():  # htest # (not really, but ignore in coverage)
     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?
index 3a865f869a06c4d9f6d78881f354bf402e97919e..abab74265f3ef81f0033c08188a01d5573a565d8 100644 (file)
@@ -235,10 +235,12 @@ class GetKeysDialog(Toplevel):
             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):
@@ -291,8 +293,8 @@ class GetKeysDialog(Toplevel):
 
 
 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)
index 75b917d0e193162ef8ed6d35609e63d4188bfabf..229dc89874332259e8f20791c9ba186f14de6c5b 100644 (file)
@@ -30,10 +30,12 @@ from idlelib.autocomplete import AutoComplete
 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):
@@ -191,6 +193,7 @@ 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):
@@ -1747,9 +1750,9 @@ class KeysPage(Frame):
             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()
@@ -1816,6 +1819,10 @@ class GenPage(Frame):
                 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
@@ -1841,6 +1848,9 @@ class GenPage(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(
@@ -1854,8 +1864,10 @@ class GenPage(Frame):
                                   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')
@@ -1917,6 +1929,13 @@ class GenPage(Frame):
         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)
@@ -1942,6 +1961,7 @@ class GenPage(Frame):
         # 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)
@@ -1982,6 +2002,11 @@ class GenPage(Frame):
         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)
@@ -2017,6 +2042,10 @@ class GenPage(Frame):
         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')
@@ -2210,6 +2239,9 @@ long to highlight if cursor is not moved (0 means forever).
 
 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".
 '''
 }
 
@@ -2269,8 +2301,8 @@ class VerticalScrolledFrame(Frame):
 
 
 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)
index 114d0d128e883e9bfa8e4139f30da0551d12e684..09f912c9af336dd4bd490039b5b20f2179d522a4 100644 (file)
@@ -6,13 +6,13 @@ from tkinter.ttk import Scrollbar
 
 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):
@@ -40,7 +40,7 @@ class Idb(bdb.Bdb):
             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)
 
@@ -63,7 +63,7 @@ class Debugger:
         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
@@ -542,3 +542,9 @@ class NamespaceViewer:
 
     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?
index bc971276de6727cc87b3cc1699e454946a9cc190..01a3bd25998fc04ba1bc4acc7814f5b9d0fbf142 100644 (file)
@@ -386,3 +386,8 @@ def restart_subprocess_debugger(rpcclt):
     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)
index b70b13cec481de62246b92732a3a82d70e4d36cd..5a4c99788420357221cf4ad0372a41e4ccd6a08d 100644 (file)
@@ -71,7 +71,7 @@ class ClassTreeItem(ObjectTreeItem):
 
 class AtomicObjectTreeItem(ObjectTreeItem):
     def IsExpandable(self):
-        return 0
+        return False
 
 class SequenceTreeItem(ObjectTreeItem):
     def IsExpandable(self):
@@ -135,5 +135,8 @@ def _object_browser(parent):  # htest #
     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)
index 8031aaeaf1f25a416edfd5ed61c390cb0e4c382d..75e75ebe5acafcdffcff92fd385f6099c864b973 100644 (file)
@@ -34,3 +34,8 @@ class StubObjectTreeItem:
     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)
index 7c3f215e9f96a8cc604f3c2d973cc8c79d94a185..6689af64c429be123e789b6347f6f2abbcff64a3 100644 (file)
@@ -2,9 +2,7 @@ import importlib.abc
 import importlib.util
 import os
 import platform
-import re
 import string
-import sys
 import tokenize
 import traceback
 import webbrowser
@@ -25,7 +23,7 @@ from idlelib import pyparse
 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
@@ -50,15 +48,15 @@ class EditorWindow(object):
     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
@@ -101,7 +99,7 @@ class EditorWindow(object):
         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
@@ -138,7 +136,7 @@ class EditorWindow(object):
         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
@@ -267,7 +265,7 @@ class EditorWindow(object):
         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:
@@ -276,7 +274,7 @@ class EditorWindow(object):
                 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
@@ -310,15 +308,18 @@ class EditorWindow(object):
         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."""
@@ -410,7 +411,7 @@ class EditorWindow(object):
         ("format", "F_ormat"),
         ("run", "_Run"),
         ("options", "_Options"),
-        ("windows", "_Window"),
+        ("window", "_Window"),
         ("help", "_Help"),
     ]
 
@@ -436,14 +437,14 @@ class EditorWindow(object):
         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."
@@ -457,12 +458,19 @@ class EditorWindow(object):
         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'
 
@@ -1012,7 +1020,7 @@ class EditorWindow(object):
     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
@@ -1701,13 +1709,17 @@ def _editor_window(parent):  # htest #
         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)
index 5e1a3dcd77dc67ba09097a5fe65c7f86680c8055..52628392e6170c3051255374568a3a50a7ac339d 100644 (file)
@@ -1,7 +1,7 @@
-import os
+"idlelib.filelist"
 
-from tkinter import *
-import tkinter.messagebox as tkMessageBox
+import os
+from tkinter import messagebox as tkMessageBox
 
 
 class FileList:
@@ -111,7 +111,8 @@ 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
@@ -120,13 +121,12 @@ def _test():
     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()
index c55c48cf2d69bcc1429c34239eca0ecefd94a6a7..8cc293c380dec67f0fb3bc3819976b8100a5d9d8 100644 (file)
@@ -193,8 +193,8 @@ def _grep_dialog(parent):  # htest #
     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)
index fa6112a339444f976d56af9e0e08f75144668f13..21b5ea5a816e3fc2a642d9bcabcedb7c403a89bf 100644 (file)
@@ -271,5 +271,8 @@ def show_idlehelp(parent):
     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)
index 77b4b18962066ca25a77b7606159c98e16c8fa10..64b13ac2abb3b2eb76fa35d9eee9b2eff0bd70ae 100644 (file)
@@ -195,11 +195,13 @@ class AboutDialog(Toplevel):
 
     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)
index a42665bb632846defbf7052b5f13a5a9a97dbc73..7581fe274b215e8232ddd292178a38a0e051ac72 100644 (file)
@@ -308,5 +308,5 @@ class HyperParser:
 
 
 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)
index 5f3678fc7e1de31c13774389db8e24ab77f3e5c9..566bfd179fdf1b439b6dfe1c492c484233f70d07 100644 (file)
@@ -15,28 +15,27 @@ python -m idlelib.idle_test.htest
 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.
 
 
 
@@ -55,12 +54,14 @@ from test.support import requires
 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):
@@ -75,12 +76,23 @@ deleted BEFORE root is destroyed.  See https://bugs.python.org/issue20567.
         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:
 
index 442f55e283a484e02e411937229d792c61945bb7..8c1c24d070cc8fd8c4b3a9cecd44645a7a859489 100644 (file)
@@ -65,6 +65,7 @@ autocomplete_w.AutoCompleteWindow
 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
@@ -79,11 +80,14 @@ AboutDialog_spec = {
            "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 = {
@@ -159,7 +163,7 @@ _grep_dialog_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."
     }
 
@@ -296,16 +300,6 @@ _stack_viewer_spec = {
            "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': {},
diff --git a/Lib/idlelib/idle_test/template.py b/Lib/idlelib/idle_test/template.py
new file mode 100644 (file)
index 0000000..725a55b
--- /dev/null
@@ -0,0 +1,30 @@
+"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)
index f3f2dea4246df00a6fe4a47e099d9475de0bd0c3..d7ee00af94b4daa82b79f65735851386ff62c938 100644 (file)
@@ -1,7 +1,5 @@
-''' 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
@@ -11,9 +9,6 @@ import idlelib.autocomplete_w as acw
 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):
diff --git a/Lib/idlelib/idle_test/test_autocomplete_w.py b/Lib/idlelib/idle_test/test_autocomplete_w.py
new file mode 100644 (file)
index 0000000..b1bdc6c
--- /dev/null
@@ -0,0 +1,32 @@
+"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)
index ae8186cdc49f7b5abbaacc22996794a94187b0b8..e5f44c468713258c1f2d5ca893d3ace1055eb6ce 100644 (file)
@@ -1,9 +1,9 @@
-"""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:
@@ -15,15 +15,27 @@ class AutoExpandTest(unittest.TestCase):
 
     @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
index 05eb4718887ae7e1405378b3a7242f5c69813ede..35cc3469019411cd12013e698fa9640a574bedac 100644 (file)
@@ -1,20 +1,16 @@
-""" 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
 
diff --git a/Lib/idlelib/idle_test/test_calltip.py b/Lib/idlelib/idle_test/test_calltip.py
new file mode 100644 (file)
index 0000000..b1ee0fe
--- /dev/null
@@ -0,0 +1,216 @@
+"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)
diff --git a/Lib/idlelib/idle_test/test_calltip_w.py b/Lib/idlelib/idle_test/test_calltip_w.py
new file mode 100644 (file)
index 0000000..a5ec76e
--- /dev/null
@@ -0,0 +1,29 @@
+"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)
diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py
deleted file mode 100644 (file)
index f6b7130..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-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)
index 2e59b8501c91166adb2457463865af899f943888..ef8170e3b6964d7987eab200a81d31eed66d5664 100644 (file)
@@ -1,16 +1,12 @@
-"""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
 
 
index 238bc3e1141363ebc34f19742dc4951aba5e000b..1e74bed1f0c0f08bea31c30c5627eec23c327b76 100644 (file)
@@ -1,10 +1,6 @@
-'''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
@@ -36,6 +32,7 @@ class ColorConfigTest(unittest.TestCase):
     def test_colorizer(self):
         colorizer.color_config(self.text)
 
+
 class ColorDelegatorTest(unittest.TestCase):
 
     @classmethod
index abfec7993e0744f0a8547cc4d008a3c2ce09aaa2..8c9197284e07e48539363c2f34704d67262f8b8f 100644 (file)
@@ -1,9 +1,9 @@
-'''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
@@ -12,7 +12,6 @@ from test.support import captured_stderr, findfile
 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.
@@ -256,9 +255,9 @@ class IdleConfTest(unittest.TestCase):
                 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
@@ -357,11 +356,11 @@ class IdleConfTest(unittest.TestCase):
 
         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):
@@ -453,7 +452,7 @@ class IdleConfTest(unittest.TestCase):
 
         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('''
index 9074e23aab35d1859439c6585dfbb8bc91177da0..08471666a4529d3999f4908b161e4ad9d4a0cb00 100644 (file)
@@ -1,7 +1,5 @@
-''' 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
index 26aba32c47e6aba85753079f1967c32716b33e41..dbfcd01c63eac4badeabeb8dc30024f61d9e3691 100644 (file)
@@ -1,7 +1,6 @@
-"""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
@@ -61,6 +60,7 @@ class FontPageTest(unittest.TestCase):
         page = cls.page = dialog.fontpage
         dialog.note.select(page)
         page.set_samples = Func()  # Mask instance method.
+        page.update()
 
     @classmethod
     def tearDownClass(cls):
@@ -211,6 +211,7 @@ class IndentTest(unittest.TestCase):
     @classmethod
     def setUpClass(cls):
         cls.page = dialog.fontpage
+        cls.page.update()
 
     def test_load_tab_cfg(self):
         d = self.page
@@ -241,6 +242,7 @@ class HighPageTest(unittest.TestCase):
         page.paint_theme_sample = Func()
         page.set_highlight_target = Func()
         page.set_color_sample = Func()
+        page.update()
 
     @classmethod
     def tearDownClass(cls):
@@ -1086,6 +1088,7 @@ class GenPageTest(unittest.TestCase):
         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):
index bcba9a45c160a9e2ef1957062a91f533c1ab5f39..35efb3411c73b546d67a30bc1907a7eb912b30d7 100644 (file)
@@ -1,11 +1,9 @@
-''' 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
 
 
@@ -25,5 +23,7 @@ class NameSpaceTest(unittest.TestCase):
         debugger.NamespaceViewer(self.root, 'Test')
 
 
+# Other classes are Idb, Debugger, and StackViewer.
+
 if __name__ == '__main__':
     unittest.main(verbosity=2)
diff --git a/Lib/idlelib/idle_test/test_debugger_r.py b/Lib/idlelib/idle_test/test_debugger_r.py
new file mode 100644 (file)
index 0000000..199f634
--- /dev/null
@@ -0,0 +1,29 @@
+"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)
diff --git a/Lib/idlelib/idle_test/test_debugobj.py b/Lib/idlelib/idle_test/test_debugobj.py
new file mode 100644 (file)
index 0000000..131ce22
--- /dev/null
@@ -0,0 +1,57 @@
+"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)
diff --git a/Lib/idlelib/idle_test/test_debugobj_r.py b/Lib/idlelib/idle_test/test_debugobj_r.py
new file mode 100644 (file)
index 0000000..86e51b6
--- /dev/null
@@ -0,0 +1,22 @@
+"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)
index 85624fbc127c852ec7c64b46c904fbbb6d886315..922416297a42e028bc0db33fb1f5195190b29f6e 100644 (file)
@@ -1,5 +1,8 @@
-import unittest
+"Test delegator, coverage 100%."
+
 from idlelib.delegator import Delegator
+import unittest
+
 
 class DelegatorTest(unittest.TestCase):
 
@@ -36,5 +39,6 @@ class DelegatorTest(unittest.TestCase):
         self.assertEqual(mydel._Delegator__cache, set())
         self.assertIs(mydel.delegate, float)
 
+
 if __name__ == '__main__':
     unittest.main(verbosity=2, exit=2)
index 64a2a88b7e3765602325197e8d6f864d9a523855..12bc8473668334ca22f49eb9f8686eab416a468a 100644 (file)
@@ -1,14 +1,46 @@
+"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)
diff --git a/Lib/idlelib/idle_test/test_filelist.py b/Lib/idlelib/idle_test/test_filelist.py
new file mode 100644 (file)
index 0000000..731f197
--- /dev/null
@@ -0,0 +1,33 @@
+"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)
index 6b54c1313153d1c90b8e0af3555bdecfb977a7d5..ab0d7860f78953a26cf0695720f42d00f2df2664 100644 (file)
@@ -3,14 +3,15 @@ Non-gui unit tests for grep.GrepDialog methods.
 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
@@ -21,6 +22,7 @@ class Dummy_searchengine:
 
 searchengine = Dummy_searchengine()
 
+
 class Dummy_grep:
     # Methods tested
     #default_command = GrepDialog.default_command
@@ -34,6 +36,7 @@ class Dummy_grep:
 
 grep = Dummy_grep()
 
+
 class FindfilesTest(unittest.TestCase):
     # findfiles is really a function, not a method, could be iterator
     # test that filename return filename
@@ -41,6 +44,7 @@ class FindfilesTest(unittest.TestCase):
     # 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
@@ -71,10 +75,12 @@ class Grep_itTest(unittest.TestCase):
         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)
index 2c68e23b328c2426351674a7d56bf7e4b88fda56..b542659981894d3e72919ac314612adfa1176316 100644 (file)
@@ -1,13 +1,12 @@
-'''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):
 
@@ -30,5 +29,6 @@ class HelpFrameTest(unittest.TestCase):
         text = self.frame.text
         self.assertEqual(text.get('1.0', '1.end'), ' IDLE ')
 
+
 if __name__ == '__main__':
     unittest.main(verbosity=2)
index 9c6a834a461baedb3359b7ffbcb621c3f6f16a80..5839b5d045d89e2f53fd32f898dbc6052912b87d 100644 (file)
@@ -1,18 +1,19 @@
-'''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):
index b27801071be64933e620fd64f09a6823f58148f6..675396514447514ff9c6811d095fe054fef589b0 100644 (file)
@@ -1,15 +1,18 @@
+" 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'''
 
@@ -61,6 +64,7 @@ class TextWrapper:
     def bell(self):
         self._bell = True
 
+
 class FetchTest(unittest.TestCase):
     '''Test History.fetch with wrapped tk.Text.
     '''
index 73c8281e430d648fca651f9efa6ceef2f714a23f..8dbfc63779d380699bb09c3bece3db282920127c 100644 (file)
@@ -1,9 +1,10 @@
-"""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):
@@ -270,5 +271,6 @@ class HyperParserTest(unittest.TestCase):
             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)
index 65bf593055956292f34be6c03edce02f1bc06d94..743a05b3c3134eba9444111315022ff6c79ab3d2 100644 (file)
-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__':
index 3d85f3ca72254ca091d3ae1ff28970c197ac69c4..b6bd922e4b99dd47356227c9e9382ac6ecfc974a 100644 (file)
@@ -1,11 +1,9 @@
-'''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
 
diff --git a/Lib/idlelib/idle_test/test_mainmenu.py b/Lib/idlelib/idle_test/test_mainmenu.py
new file mode 100644 (file)
index 0000000..7ec0368
--- /dev/null
@@ -0,0 +1,21 @@
+"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)
diff --git a/Lib/idlelib/idle_test/test_multicall.py b/Lib/idlelib/idle_test/test_multicall.py
new file mode 100644 (file)
index 0000000..68156a7
--- /dev/null
@@ -0,0 +1,40 @@
+"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)
index 231c7bf9cfb620c1c9188516707666f61583d960..cd099ecd841b3c7296a902a0906b6a3b273dd031 100644 (file)
@@ -1,12 +1,11 @@
-""" 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
 
 
index ba350c976534e8bc71183eaebde56b60b21b2f6c..0cb966fb96ca0eadf8ac8436dec7bf6b02f6489d 100644 (file)
@@ -1,9 +1,10 @@
-# 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):
@@ -15,26 +16,26 @@ 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):
@@ -62,7 +63,7 @@ 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):
@@ -161,7 +162,7 @@ class ReformatFunctionTest(unittest.TestCase):
 
     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")
@@ -192,7 +193,7 @@ class ReformatCommentTest(unittest.TestCase):
         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?\"\"\"")
@@ -201,7 +202,7 @@ class ReformatCommentTest(unittest.TestCase):
         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?")
@@ -210,7 +211,7 @@ class ReformatCommentTest(unittest.TestCase):
 
 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)
@@ -269,14 +270,16 @@ class FormatEventTest(unittest.TestCase):
     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
 
index 3caa2754a6d8a2e07e7770e609399afd180dc573..f58819abf1121194a106dacfad4b5bc75c974d08 100644 (file)
@@ -1,8 +1,8 @@
-'''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')
index 74b716a3199327a10e6b2bcf06f1fc56f600b050..13d8b9e1ba9572afeefc20b2bf0f6b7bf3a50716 100644 (file)
@@ -1,19 +1,17 @@
-""" 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
 
 
index 573b9a1e8e69e3905122b905c4f30ee3958b17d7..17668ccd1227b7834cdf374287c812f23f048337 100644 (file)
@@ -1,10 +1,10 @@
-'''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):
index 574b19d9d6f15c07eedc0df7be2592b9e9fdd034..0534301b36102f0024678bfeb0f6b621c78b70c1 100644 (file)
@@ -1,11 +1,8 @@
-"""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):
diff --git a/Lib/idlelib/idle_test/test_pyshell.py b/Lib/idlelib/idle_test/test_pyshell.py
new file mode 100644 (file)
index 0000000..581444c
--- /dev/null
@@ -0,0 +1,42 @@
+"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)
index 953f24f0a5ac82b335fdf19ee3dfa4a5fffaa083..c1c4a25cc50608ba23d0ed416647d885dec9f1a2 100644 (file)
@@ -1,4 +1,4 @@
-"""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
@@ -8,17 +8,15 @@ the subclass definition.
 
 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
index b0385fa78cd9744802b1dbf94243d77643ea34eb..a97b3002afcf12cec74c77a036978e2a22b45598 100644 (file)
@@ -1,12 +1,10 @@
-'''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):
index df76dec3e6276d28aec99c99e3e00ab9e33c4f2e..c3c5d2eeb94998bdfb643eaabdf8e8eec213ce98 100644 (file)
@@ -1,13 +1,14 @@
-"""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
diff --git a/Lib/idlelib/idle_test/test_rpc.py b/Lib/idlelib/idle_test/test_rpc.py
new file mode 100644 (file)
index 0000000..48be65b
--- /dev/null
@@ -0,0 +1,30 @@
+"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)
index 130e6be257fe58cdc0454a82ba23019b7174aa8f..2bc7c6f035e96b0c46374ce726896a1fcfd1c081 100644 (file)
@@ -1,5 +1,7 @@
+"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):
@@ -7,7 +9,7 @@ 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'), '')
@@ -20,12 +22,12 @@ class rstripTest(unittest.TestCase):
 
     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"
@@ -45,5 +47,7 @@ class rstripTest(unittest.TestCase):
         do_rstrip()
         self.assertEqual(text.get('1.0', 'insert'), stripped)
 
+
+
 if __name__ == '__main__':
-    unittest.main(verbosity=2, exit=False)
+    unittest.main(verbosity=2)
index d7e627d23d3841bbf574e5c7ebe540496cd9ddad..46f0235fbfdca171390227363059f11ce5fd94e3 100644 (file)
@@ -1,11 +1,14 @@
+"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):
@@ -20,10 +23,10 @@ class RunTest(unittest.TestCase):
                 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))
@@ -31,5 +34,231 @@ class RunTest(unittest.TestCase):
         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)
diff --git a/Lib/idlelib/idle_test/test_runscript.py b/Lib/idlelib/idle_test/test_runscript.py
new file mode 100644 (file)
index 0000000..5fc6018
--- /dev/null
@@ -0,0 +1,33 @@
+"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)
index 56aabfecf4a9ceff946221d75cb7f0ca8525afa7..2f819fda025ba3d453e081327a05ffc2fd7cf972 100644 (file)
@@ -1,11 +1,9 @@
-''' 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
 
 
@@ -22,7 +20,7 @@ class ScrolledListTest(unittest.TestCase):
 
 
     def test_init(self):
-        scrolledlist.ScrolledList(self.root)
+        ScrolledList(self.root)
 
 
 if __name__ == '__main__':
index 3ab72951efe3fa787ba31212d8477e9dc663ce25..de703c195cd22900b92f3b239018f805bbf373da 100644 (file)
@@ -1,25 +1,23 @@
-"""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):
@@ -27,10 +25,10 @@ class SearchDialogTest(unittest.TestCase):
         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):
index 27b02fbe54602c5cb7b3688b1d7bed0e82eaf073..46c3ad111d179336122f24604553589eb19053de 100644 (file)
@@ -1,8 +1,7 @@
-'''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
@@ -22,6 +21,7 @@ from idlelib.idle_test.mock_idle import Func
 ##    se.BooleanVar = BooleanVar
 ##    se.StringVar = StringVar
 
+
 class SearchDialogBaseTest(unittest.TestCase):
 
     @classmethod
index b3aa8eb81205eeb4e0bdc5737bcbda4ddf483456..3d26d62a95a8730b90933e5a7928852cc3802880 100644 (file)
@@ -1,18 +1,19 @@
-'''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.
@@ -326,4 +327,4 @@ class ForwardBackwardTest(unittest.TestCase):
 
 
 if __name__ == '__main__':
-    unittest.main(verbosity=2, exit=2)
+    unittest.main(verbosity=2)
diff --git a/Lib/idlelib/idle_test/test_squeezer.py b/Lib/idlelib/idle_test/test_squeezer.py
new file mode 100644 (file)
index 0000000..ca8b674
--- /dev/null
@@ -0,0 +1,509 @@
+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)
diff --git a/Lib/idlelib/idle_test/test_stackviewer.py b/Lib/idlelib/idle_test/test_stackviewer.py
new file mode 100644 (file)
index 0000000..98f53f9
--- /dev/null
@@ -0,0 +1,47 @@
+"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)
diff --git a/Lib/idlelib/idle_test/test_statusbar.py b/Lib/idlelib/idle_test/test_statusbar.py
new file mode 100644 (file)
index 0000000..203a57d
--- /dev/null
@@ -0,0 +1,41 @@
+"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)
index dfd4063eb08d1e2dae2664599a0fe250caf60c76..6f0c1930518a51e5c4c9c9819ce927d3f337018a 100644 (file)
@@ -1,17 +1,15 @@
-'''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
@@ -75,7 +73,6 @@ class TextFrameTest(unittest.TestCase):
 
     @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')
@@ -109,7 +106,7 @@ class ViewFunctionTest(unittest.TestCase):
         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)
@@ -128,11 +125,15 @@ class ViewFunctionTest(unittest.TestCase):
     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):
diff --git a/Lib/idlelib/idle_test/test_tooltip.py b/Lib/idlelib/idle_test/test_tooltip.py
new file mode 100644 (file)
index 0000000..44ea111
--- /dev/null
@@ -0,0 +1,146 @@
+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)
index bb597d87ffd104eb2bd5d5bc4ae434d5e2ea479d..9be9abee361f083632626437e483602cdc93c771 100644 (file)
@@ -1,11 +1,9 @@
-''' 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
 
 
index e872927a6c6d99ebe9fc0e14f04d5a85ac6ed638..beb5b582039f8844dd179561c7bb939606184375 100644 (file)
@@ -1,14 +1,13 @@
-"""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
 
 
@@ -131,5 +130,6 @@ class UndoDelegatorTest(unittest.TestCase):
             text.insert('insert', 'foo')
             self.assertLessEqual(len(self.delegator.undolist), max_undo)
 
+
 if __name__ == '__main__':
     unittest.main(verbosity=2, exit=False)
index f3269f195af83160419dd1bc5485da3114c54ead..221068c5885fcbad118283b6c1702a1c55896ec7 100644 (file)
@@ -5,20 +5,18 @@ This file could be expanded to include traceback overrides
 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 = '''
@@ -29,6 +27,7 @@ UserWarning: Test
 '''
 shellmsg = idlemsg + ">>> "
 
+
 class RunWarnTest(unittest.TestCase):
 
     @unittest.skipIf(running_in_idle, "Does not work when run within Idle.")
@@ -46,6 +45,7 @@ class RunWarnTest(unittest.TestCase):
             # 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.")
@@ -70,4 +70,4 @@ class ShellWarnTest(unittest.TestCase):
 
 
 if __name__ == '__main__':
-    unittest.main(verbosity=2, exit=False)
+    unittest.main(verbosity=2)
diff --git a/Lib/idlelib/idle_test/test_window.py b/Lib/idlelib/idle_test/test_window.py
new file mode 100644 (file)
index 0000000..5a2645b
--- /dev/null
@@ -0,0 +1,45 @@
+"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)
diff --git a/Lib/idlelib/idle_test/test_zoomheight.py b/Lib/idlelib/idle_test/test_zoomheight.py
new file mode 100644 (file)
index 0000000..bac86ac
--- /dev/null
@@ -0,0 +1,39 @@
+"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)
index f9b6907b40cecc062de391e7ac3d9380b378dc96..fcd8dcc1393da7ce23282bfd2d9f542df32b0b4c 100644 (file)
@@ -40,7 +40,7 @@ else:
             # 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)
@@ -50,7 +50,7 @@ else:
             # 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)
@@ -567,8 +567,8 @@ def _io_binding(parent):  # htest #
     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)
index d85278a0b765ae2addeb6471c48a61df00b34cdd..d3ae224100cff8b2b51a5bb3b5c9042e7cb7530c 100644 (file)
@@ -128,7 +128,7 @@ def overrideRootMenu(root, flist):
     # menu.
     from tkinter import Menu
     from idlelib import mainmenu
-    from idlelib import windows
+    from idlelib import window
 
     closeItem = mainmenu.menudefs[0][1][-2]
 
@@ -148,7 +148,7 @@ def overrideRootMenu(root, flist):
     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):
@@ -158,8 +158,8 @@ def overrideRootMenu(root, flist):
 
         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."
index 143570d6b11c416abbce33e202c4299525d53f30..9fe6b5229446e3072744db46de8a3001f6adff47 100644 (file)
@@ -36,7 +36,8 @@ menudefs = [
    None,
    ('_Close', '<<close-window>>'),
    ('E_xit', '<<close-all-windows>>'),
-  ]),
+   ]),
+
  ('edit', [
    ('_Undo', '<<undo>>'),
    ('_Redo', '<<redo>>'),
@@ -56,9 +57,9 @@ menudefs = [
    ('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>>'),
@@ -70,30 +71,36 @@ menudefs = [
    ('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,
@@ -106,3 +113,7 @@ if find_spec('turtledemo'):
     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)
index b74fed4c0cd13f59eb2f656a708cbe6180a705fb..dc02001292fc14e812db4b292c14fa427800276a 100644 (file)
@@ -441,5 +441,8 @@ def _multi_call(parent):  # htest #
     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)
index 6c2a792d86b99ae3016c558a6486359e17db90e4..4af9f1afaed5181eae2dd80c7f4b1b0f2335f0b9 100644 (file)
@@ -184,5 +184,5 @@ class OnDemandOutputWindow:
         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)
index 1270115a44ce44be308dc82217845728a892eaf0..81422571fa32f4f0d673d2570e62d04bdeaad327 100644 (file)
@@ -190,6 +190,5 @@ def get_comment_header(line):
 
 
 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)
index 983ca20675af1de3c378fb916a414fe5e14e29a4..3fd7aadb2aea84f10921a321941990cd57ebb6e9 100644 (file)
@@ -179,5 +179,5 @@ ParenMatch.reload()
 
 
 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)
index d18daf05863c183d6a0e6c42b9518541e74f3cd8..db70304f589159108e369564193baa20a8a127d4 100644 (file)
@@ -96,9 +96,8 @@ def _percolator(parent):  # htest #
     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)
index 6196c2b7edc9eaae0d61d479ff15db66deb72d79..1eeb9154d9061049155b5879246608b2b54fd6e7 100644 (file)
@@ -594,6 +594,6 @@ class Parser:
         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)
index ddfb56acdbc44fa01e84a611c5557fcfa8e59d88..5458c59dbd7e0b81398e37573965dfef2d06b255 100755 (executable)
@@ -852,10 +852,14 @@ class PyShell(OutputWindow):
         ("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
@@ -1033,7 +1037,7 @@ class PyShell(OutputWindow):
         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")
index 593506383c41abcfd185309bfcfa8816d3b9c5c8..c2628cceb739781a96cd17d61ada0a8f477e1e61 100644 (file)
@@ -143,6 +143,10 @@ class Query(Toplevel):
         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."
@@ -301,8 +305,8 @@ class HelpSource(Query):
 
 
 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)
index ec681de38d457f69e4ea45f856881343e36d75ae..9ab34c5acfb22c6683882c80954ab503b40d9e47 100644 (file)
@@ -167,9 +167,8 @@ def _widget_redirector(parent):  # htest #
     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)
index abd9e59f4e5d17263211e41f5b5ee03389e8c3c5..83cf98756bdf8127978b8818ffe5cdfc96ea68ed 100644 (file)
@@ -235,9 +235,8 @@ def _replace_dialog(parent):  # htest #
     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)
index 8f57edb836dec8a7c68a53c191a5d94bd730fc79..9962477cc56185c8cb76e7044004ec661bfcfd71 100644 (file)
@@ -43,16 +43,20 @@ import traceback
 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)
@@ -625,3 +629,8 @@ def displayhook(value):
         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,)
index 18c86f9b2c88968c7a9ee9a08046263a24af284d..f93b5e8fc20021182e0da2ca796f447e66f12b82 100644 (file)
@@ -1,6 +1,6 @@
 'Provides "Strip trailing whitespace" under the "Format" menu.'
 
-class RstripExtension:
+class Rstrip:
 
     def __init__(self, editwin):
         self.editwin = editwin
@@ -25,5 +25,5 @@ class RstripExtension:
         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,)
index 176fe3db743bd4513d5a9eacbc5194506197553b..6fa373f2584c271315fcc4156dea4d87d03c1734 100644 (file)
@@ -11,7 +11,7 @@ import warnings
 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
@@ -462,7 +462,7 @@ class Executive(object):
     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):
index 45bf56345825a188b2728450b7de61a2cb6570f5..83433b1cf0a4591bc3fc9c9833987b9aa17f507c 100644 (file)
@@ -193,3 +193,8 @@ class ScriptBinding:
         # 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,)
index cdf658404ab643ac7ef3c9b8c10674f753ad8128..10229b63629293caa246ccc346edea7956a6db26 100644 (file)
@@ -142,6 +142,8 @@ def _scrolled_list(parent):  # htest #
         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)
index 4b9065930822844a7f3d5c9bef8fa0a42e82e62c..6223661c8e080a9b583d8a9fa927dbbf442bfdf6 100644 (file)
@@ -94,9 +94,8 @@ def _search_dialog(parent):  # htest #
     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)
index 5f81785b712c088d6abec74918575ba8e30d88b7..9b03ff64c1e1a6635dbac4a129e2f218d577cad6 100644 (file)
@@ -192,9 +192,10 @@ class _searchbase(SearchDialogBase):  # htest #
 
     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)
index 253f1b0831a6190ac69b03cc96afe544df5c3161..911e7d4691cac11f45cf7f2fd86d641f147ce90c 100644 (file)
@@ -231,6 +231,7 @@ def get_line_col(index):
     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)
diff --git a/Lib/idlelib/squeezer.py b/Lib/idlelib/squeezer.py
new file mode 100644 (file)
index 0000000..f5aac81
--- /dev/null
@@ -0,0 +1,355 @@
+"""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.
index 400fa632a098cf2da9a9cc92971e6f05d20e3994..94ffb4eff4dd26e8e20298100bd886884c534b91 100644 (file)
@@ -8,6 +8,7 @@ from idlelib.debugobj import ObjectTreeItem, make_objecttreeitem
 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)
@@ -134,7 +135,6 @@ def _stack_viewer(parent):  # htest #
         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
@@ -148,5 +148,8 @@ def _stack_viewer(parent):  # htest #
     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)
index 8618528d822130c63800a1a20db251d2d17127e0..c071f898b0f7443e57cbad073d3ff5fefedd827f 100644 (file)
@@ -42,5 +42,8 @@ def _multistatus_bar(parent):  # htest #
     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)
index 66201344061090fca5cedc4d610e5f533f5d82b9..4867a80db1abe6da978e62cad9de801627fa8396 100644 (file)
@@ -1,15 +1,37 @@
 """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
@@ -18,31 +40,40 @@ class TextFrame(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')
@@ -56,7 +87,7 @@ class ViewFrame(Frame):
 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.
 
@@ -66,6 +97,7 @@ class ViewWindow(Toplevel):
         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.
         """
@@ -77,13 +109,14 @@ class ViewWindow(Toplevel):
         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:
@@ -91,23 +124,27 @@ class ViewWindow(Toplevel):
 
     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
@@ -125,12 +162,14 @@ def view_file(parent, title, filename, encoding, modal=True, _utest=False):
                   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)
index 843fb4a7d0b7419884f07a07ad92be6a33b6294e..f54ea36f059d6fa305610dad96bd8447c8cbb5e2 100644 (file)
-# 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)
@@ -83,14 +170,17 @@ def _tooltip(parent):  # htest #
     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)
index 292ce36184c76d92d76a09aa8fca14ee64de0dc4..05f864657fb827903acfaa694bd1d44f881e4e1b 100644 (file)
@@ -462,6 +462,8 @@ def _tree_widget(parent):  # htest #
     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)
index 4332f1099343b451ed097a97170b31546d14980b..f048994b7d15c3a80239155360e415e64775d800 100644 (file)
@@ -359,8 +359,8 @@ def _undo_delegator(parent):  # htest #
     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)
diff --git a/Lib/idlelib/window.py b/Lib/idlelib/window.py
new file mode 100644 (file)
index 0000000..b2488b2
--- /dev/null
@@ -0,0 +1,97 @@
+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)
diff --git a/Lib/idlelib/windows.py b/Lib/idlelib/windows.py
deleted file mode 100644 (file)
index a3f858a..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-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
index 74fbc888a80d3f21363dc29a07bc7912111c64bd..73f1df071bf3bf6aa9e4b43eaed6d2627702f941 100644 (file)
@@ -11,7 +11,7 @@ class ZoomHeight:
     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"
@@ -46,3 +46,10 @@ def zoom_height(top):
     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?
index 1c0b03bff8a3792c2fda3ca566690889daa1b4be..b9a01d636f780ebdeb12d2018754facf49474855 100644 (file)
@@ -79,6 +79,7 @@ Commands = {
         'LOGIN':        ('NONAUTH',),
         'LOGOUT':       ('NONAUTH', 'AUTH', 'SELECTED', 'LOGOUT'),
         'LSUB':         ('AUTH', 'SELECTED'),
+        'MOVE':         ('SELECTED',),
         'NAMESPACE':    ('AUTH', 'SELECTED'),
         'NOOP':         ('NONAUTH', 'AUTH', 'SELECTED', 'LOGOUT'),
         'PARTIAL':      ('SELECTED',),                                  # NB: obsolete
@@ -281,7 +282,11 @@ class IMAP4:
 
 
     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"
index 362ae9abeb6614986c96154c9be90904f8a68285..dd3b784a607e9d95543780d06420aa6470f62a03 100644 (file)
@@ -954,7 +954,12 @@ def getsourcelines(object):
     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
@@ -1968,7 +1973,7 @@ def _signature_fromstr(cls, obj, s, skip_bound_arg=True):
         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)
index e2084f55050891ed6ddbb0a992971c7a0a62be10..386ed17782c056eaa7e1be0acbbd9752ad405e1f 100644 (file)
@@ -431,7 +431,8 @@ class Formatter(object):
     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
index 8a99923bf31ef9990bb2b89bd80ade1aa96e835d..cabddc58cf05500837a9372d8ffb9da59986abd4 100644 (file)
@@ -78,8 +78,8 @@ def fileConfig(fname, defaults=None, disable_existing_loggers=True):
     # 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)
@@ -268,6 +268,14 @@ def _install_loggers(cp, handlers, disable_existing):
     #        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)
 
 
@@ -527,8 +535,7 @@ class DictConfigurator(BaseConfigurator):
             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)
index d49e8f0d32b62a4a4e6149e54b844672d047cde9..d3797503a7551e6c35f4d6bfb2d219dcc05eae8b 100644 (file)
@@ -57,10 +57,10 @@ if sys.platform == 'win32':
 
 
 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
 
 #
 #
@@ -905,7 +905,7 @@ else:
                 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)
@@ -913,7 +913,7 @@ else:
                     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
 
index b9ce84b2d85ddc4d6a561b3ba36d91445a0a27f7..4d74401398ccc8c6df9254aa7b5c39688e737e45 100644 (file)
@@ -18,8 +18,8 @@ import sys
 import threading
 import array
 import queue
+import time
 
-from time import time as _time
 from traceback import format_exc
 
 from . import connection
@@ -1006,13 +1006,13 @@ class ConditionProxy(AcquirerProxy):
         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)
@@ -1095,10 +1095,13 @@ class ListProxy(BaseListProxy):
 
 
 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', (
index a545f3c1a189613b9d95bf9a921c1c2abd80692c..32254d8ea6cfbe130e3dbcfdf389f847371bd193 100644 (file)
@@ -147,8 +147,9 @@ class Pool(object):
     '''
     _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):
@@ -175,13 +176,15 @@ class Pool(object):
 
         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,
@@ -207,43 +210,62 @@ class Pool(object):
             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()
@@ -396,16 +418,20 @@ class Pool(object):
         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
@@ -781,7 +807,7 @@ class ThreadPool(Pool):
     _wrap_exception = False
 
     @staticmethod
-    def Process(*args, **kwds):
+    def Process(ctx, *args, **kwds):
         from .dummy import Process
         return Process(*args, **kwds)
 
index 513807cafecb6dd2e19ec347ef210e9a2c109367..1b3fddb2bfece7b05410232d45baa602f5c7d74b 100644 (file)
@@ -95,12 +95,12 @@ class Queue(object):
             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():
index c043c9a0dc164438c058874b97bb94e585c1875a..f1b9d3ac99ce813a4d8236a6780d548e294d573a 100644 (file)
@@ -150,7 +150,7 @@ else:
         '''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:
index d4bdf0e8b1737f6342b0ff11e38d53faf87f0dbb..364adbe6087856e5ebb0f02c90f3c19a56c297aa 100644 (file)
@@ -15,8 +15,7 @@ import threading
 import sys
 import tempfile
 import _multiprocessing
-
-from time import time as _time
+import time
 
 from . import context
 from . import process
@@ -313,13 +312,13 @@ class Condition(object):
         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)
index a5e79ba66371f89f44b41cddee2455fd16e77572..24113e701d1152a72c370bcb9bb7961fdcf58cbf 100644 (file)
@@ -518,38 +518,36 @@ def normpath(path):
         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
index 44788c02c2f3dc29334608c94d109b1ecd17f38d..5e130110f2e8c2a0ff2903c8ec8a61d54b2d49a3 100644 (file)
@@ -823,8 +823,10 @@ class PurePath(object):
                                        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))
index 5e129b5b56373b8eb13355d7b58caabc1e1282a8..c0415ec46b768f53decb775e382e914fcd1bb967 100644 (file)
@@ -1354,9 +1354,7 @@ opcodes = [
       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',
@@ -1364,9 +1362,7 @@ opcodes = [
       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.
 
index cc2db9870d84b693d140d63c4d769fc48cbda3c5..4205abde038866053046b0ef9e6a2c95849731eb 100755 (executable)
@@ -136,6 +136,35 @@ except AttributeError:
 # 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)'
@@ -144,9 +173,7 @@ _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.
@@ -161,6 +188,7 @@ def libc_ver(executable=sys.executable, lib='', version='',
         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
@@ -169,17 +197,19 @@ def libc_ver(executable=sys.executable, lib='', version='',
     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()]
@@ -189,12 +219,12 @@ def libc_ver(executable=sys.executable, lib='', version='',
                 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
@@ -389,6 +419,7 @@ def popen(cmd, mode='r', bufsize=-1):
     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
index 8c707540030b297aa06ce32df3eb56b8d2e0bf9d..fffa2d50a29c2601a0f13d58f4781d9457c5c7d3 100644 (file)
@@ -1992,14 +1992,15 @@ module "pydoc_data.topics" could not be found.
         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).
index 0c307a11512e64466839bee1400f595344b55be3..9dc4a71620898891707eca0cb8d0e01e3a3d6dc0 100644 (file)
@@ -1,5 +1,5 @@
 # -*- 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'
@@ -985,7 +985,7 @@ topics = {'assert': 'The "assert" statement\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'
@@ -1505,7 +1505,7 @@ topics = {'assert': 'The "assert" statement\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'
@@ -1956,7 +1956,7 @@ topics = {'assert': 'The "assert" statement\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 '
@@ -2065,7 +2065,7 @@ topics = {'assert': 'The "assert" statement\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).  '
+             '  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'
@@ -2361,7 +2361,8 @@ topics = {'assert': 'The "assert" statement\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'
@@ -2626,7 +2627,8 @@ topics = {'assert': 'The "assert" statement\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'
@@ -4063,7 +4065,7 @@ topics = {'assert': 'The "assert" statement\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 '
@@ -4474,10 +4476,10 @@ topics = {'assert': 'The "assert" statement\n'
  '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'
@@ -4591,7 +4593,7 @@ topics = {'assert': 'The "assert" statement\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 '
@@ -4689,7 +4691,13 @@ topics = {'assert': 'The "assert" statement\n'
                   '\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'
@@ -5076,16 +5084,16 @@ topics = {'assert': 'The "assert" statement\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 '
@@ -5312,8 +5320,7 @@ topics = {'assert': 'The "assert" statement\n'
                   '   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"
@@ -5334,7 +5341,8 @@ topics = {'assert': 'The "assert" statement\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'
@@ -5739,7 +5747,7 @@ topics = {'assert': 'The "assert" statement\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 '
@@ -5772,18 +5780,17 @@ topics = {'assert': 'The "assert" statement\n'
  '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'
@@ -5943,14 +5950,13 @@ topics = {'assert': 'The "assert" statement\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'
@@ -6915,7 +6921,7 @@ topics = {'assert': 'The "assert" statement\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'
@@ -7318,7 +7324,7 @@ topics = {'assert': 'The "assert" statement\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'
@@ -9503,20 +9509,21 @@ topics = {'assert': 'The "assert" statement\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'
@@ -10119,7 +10126,7 @@ topics = {'assert': 'The "assert" statement\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” '
@@ -10405,9 +10412,9 @@ topics = {'assert': 'The "assert" statement\n'
                   '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 '
@@ -12375,13 +12382,13 @@ topics = {'assert': 'The "assert" statement\n'
              '|                                | "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'
@@ -12771,7 +12778,7 @@ topics = {'assert': 'The "assert" statement\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'
@@ -12831,12 +12838,12 @@ topics = {'assert': 'The "assert" statement\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'
index 7a2585e01ab3a36f154301dc36fb00809280169f..61e881642cb3f446e0291668c4a7d4294dceba06 100644 (file)
@@ -360,7 +360,9 @@ class Random(_random.Random):
             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  -------------------
 
index 1bd63ccf6a23537594b5fed1b67309913a862fae..86ca2dba61bf3c729eadd4c90bb0b664ae0b4dbd 100644 (file)
@@ -418,7 +418,16 @@ def enablerlcompleter():
                 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
 
index b679875fd2c5399ec470fcc2f724df347a7c27fa..5e1bc0b198ed8947e9e4656e8a44fb479631b8e0 100755 (executable)
@@ -513,7 +513,7 @@ class SMTP:
         """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:
@@ -534,7 +534,7 @@ class SMTP:
         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:
@@ -615,7 +615,7 @@ class SMTP:
 
         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
@@ -785,8 +785,8 @@ class SMTP:
             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:
@@ -890,7 +890,7 @@ class SMTP:
         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
@@ -958,7 +958,7 @@ class SMTP:
             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')
index 1f3a31a9b796879427784fc453ea72e78c8cc469..cd216a15cda8361bebc473c4e8a2db341cc60873 100644 (file)
@@ -576,7 +576,7 @@ class SSLObject:
 
     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.
     """
 
@@ -714,6 +714,9 @@ class SSLObject:
         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
@@ -1054,6 +1057,12 @@ class SSLSocket(socket):
         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)
index 395b846ee2c409b1c138a61c4a63726a99c662c2..62d22150f50da594b34f8004d28cf6ebfe8a0643 100755 (executable)
@@ -534,7 +534,7 @@ class _Stream:
                 if not buf:
                     break
                 t.append(buf)
-            buf = "".join(t)
+            buf = b"".join(t)
         else:
             buf = self._read(size)
         self.pos += len(buf)
@@ -547,6 +547,7 @@ class _Stream:
             return self.__read(size)
 
         c = len(self.dbuf)
+        t = [self.dbuf]
         while c < size:
             buf = self.__read(self.bufsize)
             if not buf:
@@ -555,26 +556,27 @@ class _Stream:
                 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):
index 0a82026f4d21f429309a638249c5193981c8a6de..6667f117857482d2ce806922324b1ee0378d03ae 100644 (file)
@@ -494,13 +494,17 @@ class _TestProcess(BaseTestCase):
         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,))
@@ -878,9 +882,10 @@ class _TestQueue(BaseTestCase):
         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):
@@ -1217,9 +1222,9 @@ class _TestCondition(BaseTestCase):
             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()
 
@@ -1808,6 +1813,16 @@ class _TestContainers(BaseTestCase):
         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)
@@ -1838,6 +1853,19 @@ class _TestContainers(BaseTestCase):
         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)
@@ -2085,10 +2113,10 @@ class _TestPool(BaseTestCase):
         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):
@@ -2257,6 +2285,12 @@ class _TestPool(BaseTestCase):
         # 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")
@@ -2400,7 +2434,9 @@ class _TestMyManager(BaseTestCase):
     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()
index 3ee4f59513abfedd6d61b5115315924e528d8d30..6eebde7a57f15a8f1735bc6792065b1386d20f18 100644 (file)
@@ -1,37 +1,81 @@
 -----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-----
index 373349cae059a4f9ed220d8b6eb3b80335d20952..730e7fd911a55144acbadf3a2c2a1c37dd85fdf0 100644 (file)
@@ -1,21 +1,26 @@
 -----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-----
index 373349cae059a4f9ed220d8b6eb3b80335d20952..730e7fd911a55144acbadf3a2c2a1c37dd85fdf0 100644 (file)
@@ -1,21 +1,26 @@
 -----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-----
index d3fa7530edd4c76cacbdb50dcb669181087c267d..40a457c9c53830ae827efe1c7fff1a1219085fb6 100644 (file)
@@ -69,7 +69,7 @@ class TestModule(unittest.TestCase):
                     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):
@@ -4423,6 +4423,10 @@ class TestLocalTimeDisambiguation(unittest.TestCase):
         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):
diff --git a/Lib/test/dh1024.pem b/Lib/test/dh1024.pem
deleted file mode 100644 (file)
index a391176..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
------BEGIN DH PARAMETERS-----
-MIGHAoGBAIbzw1s9CT8SV5yv6L7esdAdZYZjPi3qWFs61CYTFFQnf2s/d09NYaJt
-rrvJhIzWavqnue71qXCf83/J3nz3FEwUU/L0mGyheVbsSHiI64wUo3u50wK5Igo0
-RNs/LD0irs7m0icZ//hijafTU+JOBiuA8zMI+oZfU7BGuc9XrUprAgEC
------END DH PARAMETERS-----
-
-Generated with: openssl dhparam -out dh1024.pem  1024
index bc308fe107b31172159012278ed1e03878789ebf..1caeafe25d9b72bbbc211272da8b352215e78f60 100644 (file)
@@ -52,7 +52,8 @@ class EINTRBaseTest(unittest.TestCase):
 
         # 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):
diff --git a/Lib/test/ffdh3072.pem b/Lib/test/ffdh3072.pem
new file mode 100644 (file)
index 0000000..ad69bac
--- /dev/null
@@ -0,0 +1,41 @@
+    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-----
index 711badad849211f6b390fb68c8d7c3d9acd157a4..ff3f0e4b73b9ad644fed7ba42951d2850d6d6e8c 100644 (file)
@@ -74,3 +74,9 @@ class FesteringGob(MalodorousPervert, ParrotDroppings):
 
 async def lobbest(grenade):
     pass
+
+currentframe = inspect.currentframe()
+try:
+    raise Exception()
+except:
+    tb = sys.exc_info()[2]
index e90574881db5485cbead413f62be2237a6791f05..cbb3c3bccd2ca551ba8f7f7088a6d2d5bbd92e9e 100644 (file)
@@ -1,33 +1,68 @@
 -----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-----
index 64318aa2e03a6c2f882448d667e1d7592a7f7d2d..0d398633739a51e750d705bc6410fa243a3f5384 100644 (file)
@@ -1,31 +1,66 @@
 -----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-----
index e8a9e082b313a6223d58dbc931f40f2e3d24182b..ed6ae85a4649d9d624ac6cacc8364503c573989a 100644 (file)
@@ -1,31 +1,66 @@
 -----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-----
index 5bfa62c4ca30b2e530da41938e8934e5642fe288..e0a8205a660e891c43fa1ca177b02055d9ba6d3c 100644 (file)
 -----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-----
index 53355c8a50cba21cfac38c4274ace437cf423658..d1ebb82486de2408f42d7a7a06af5fb7216a5b08 100644 (file)
 -----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-----
index dab17c3edf32aef869d39ed3bb7641b78838f4e7..2af839a182dbdb58ccbe86729c45a37ac6cf7033 100644 (file)
@@ -268,6 +268,10 @@ def _create_parser():
                        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
 
 
index 3429b3726abe90a541467506d568545ab4e5b23c..b491a08c2424ef4a74a562338daeb78bb298f4d9 100644 (file)
@@ -100,8 +100,11 @@ class Regrtest:
         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:
@@ -118,6 +121,15 @@ class Regrtest:
         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
@@ -164,6 +176,9 @@ class Regrtest:
                       file=sys.stderr)
                 ns.findleaks = False
 
+        if ns.xmlpath:
+            support.junit_xml_list = self.testsuite_xml = []
+
         # Strip .py extensions.
         removepy(ns.args)
 
@@ -384,7 +399,7 @@ class Regrtest:
                     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)
@@ -462,6 +477,13 @@ class Regrtest:
                    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)
 
@@ -501,6 +523,31 @@ class Regrtest:
         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
 
@@ -526,6 +573,15 @@ class Regrtest:
     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)
@@ -554,6 +610,9 @@ class Regrtest:
             self.rerun_failed_tests()
 
         self.finalize()
+
+        self.save_xml_result()
+
         if self.bad:
             sys.exit(2)
         if self.interrupted:
index 12bf422c902dc1cd77b54f8b2dafd7ee2b1f85e7..4f41080d37b9989fab1ab6d1d2027f5783a8f34f 100644 (file)
@@ -85,8 +85,8 @@ def runtest(ns, test):
     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
@@ -94,6 +94,9 @@ def runtest(ns, test):
         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
@@ -106,22 +109,13 @@ def runtest(ns, test):
         # 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:
@@ -138,12 +132,18 @@ def runtest(ns, test):
         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():
@@ -173,9 +173,10 @@ def runtest_inner(ns, test, display_failure=True):
                     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:
index 108b56d8d22f01125aaadfe9e70d5dae17fcf869..e5e808a6aa53dabe1044f5e961c6f1061c157da3 100644 (file)
@@ -71,7 +71,7 @@ def run_tests_slave(slaveargs):
     try:
         result = runtest(ns, testname)
     except KeyboardInterrupt:
-        result = INTERRUPTED, ''
+        result = INTERRUPTED, '', None
     except BaseException as e:
         traceback.print_exc()
         result = CHILD_ERROR, str(e)
@@ -126,7 +126,7 @@ class MultiprocessThread(threading.Thread):
             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
@@ -137,6 +137,7 @@ class MultiprocessThread(threading.Thread):
             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
@@ -199,12 +200,12 @@ def run_tests_multiprocess(regrtest):
             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)
index 85049cb06b36498147edb126cf13e1bed58380b3..d36bf9196626db5c2230e550f3345e859f1208b9 100644 (file)
@@ -1,19 +1,28 @@
 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):
index 5b1f033c6f806d5d2900afee9152b4093e38b7e8..65fa4d87d4ce38a4cfbf3fbd9158aa6c1e15e0c0 100644 (file)
@@ -405,12 +405,13 @@ class EventTests(BaseTestCase):
         # 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()
index 4d9f01ba6a8e91388f79a68d8a8c125d06e9d525..362276583f500050b62870f4cc9cd169bd7de23e 100644 (file)
@@ -2,14 +2,17 @@
 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]
@@ -18,8 +21,25 @@ req_template = """
     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}
@@ -49,14 +69,13 @@ req_template = """
     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 ]
@@ -87,7 +106,9 @@ req_template = """
 
 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):
@@ -99,7 +120,8 @@ def make_cert_key(hostname, sign=False, extra_san=''):
         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:
@@ -112,8 +134,15 @@ def make_cert_key(hostname, sign=False, extra_san=''):
         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)
 
 
@@ -145,7 +174,7 @@ def make_ca():
         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)
@@ -157,9 +186,21 @@ def make_ca():
             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:
@@ -177,7 +218,7 @@ if __name__ == '__main__':
 
     # 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)
@@ -192,6 +233,13 @@ if __name__ == '__main__':
         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',
@@ -211,6 +259,24 @@ if __name__ == '__main__':
         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')
index 09b1f3e08aee6153552cad67c752bc008bed75f2..73150c960f35814def2c2bc5faf7bdfeb8dab30b 100644 (file)
@@ -1,78 +1,99 @@
 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-----
index fc6effefb21042756394b9376008877a11e9ccbc..c283f89098684d999e5d22c89317c204569e3a08 100644 (file)
@@ -1,28 +1,40 @@
 -----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-----
index 9242a36bedd68b2447d40da3b5f6eec51cf1b1ab..4a563e9baae2922a1493b81055ce7911f241619e 100644 (file)
@@ -142,7 +142,7 @@ def collect_platform(info_add):
     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):
index 6d89b08ebea205560426dbda9d2d96fffd451d0a..c05461ca7f9389288039a776aef4f62cf7eb0e2e 100644 (file)
@@ -1,11 +1,14 @@
 -----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-----
index 47a7d7e37e809f45b0cc8c3dbc07ab8650a364d0..de596717bd855f0eff27140d799747ea776ac294 100644 (file)
@@ -1,15 +1,26 @@
 -----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-----
index 2524672e70d194749fbd52e986ddc8e2cffe6472..e4f1370ab270c85af561d552182ad2da41a3d895 100644 (file)
@@ -1,18 +1,42 @@
 -----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-----
index 3fd3bbd54a34517c7bd77b0b84c66d1ebc9694f8..1ea4578d81ecc4c73bf83bd98fc2b03ce5477f0b 100644 (file)
@@ -1,16 +1,40 @@
 -----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-----
index 20c1edc53c21c2b375f03798a09875006a7a2975..3f1962fe1cd2b55259e7e0874b89e18ea16f6835 100644 (file)
@@ -5,6 +5,7 @@ if __name__ != 'test.support':
 
 import collections.abc
 import contextlib
+import datetime
 import errno
 import faulthandler
 import fnmatch
@@ -12,6 +13,7 @@ import functools
 import gc
 import importlib
 import importlib.util
+import io
 import logging.handlers
 import nntplib
 import os
@@ -31,6 +33,8 @@ import unittest
 import urllib.error
 import warnings
 
+from .testresult import get_test_runner
+
 try:
     import _thread, threading
 except ImportError:
@@ -280,6 +284,7 @@ use_resources = None     # Flag set to [] by regrtest.py
 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.
@@ -1406,6 +1411,9 @@ def transient_internet(resource_name, *, timeout=30.0, errnos=()):
         ('EHOSTUNREACH', 113),
         ('ENETUNREACH', 101),
         ('ETIMEDOUT', 110),
+        # socket.create_connection() fails randomly with
+        # EADDRNOTAVAIL on Travis CI.
+        ('EADDRNOTAVAIL', 99),
     ]
     default_gai_errnos = [
         ('EAI_AGAIN', -3),
@@ -1899,13 +1907,16 @@ def _filter_suite(suite, pred):
 
 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]
diff --git a/Lib/test/support/testresult.py b/Lib/test/support/testresult.py
new file mode 100644 (file)
index 0000000..8988d3d
--- /dev/null
@@ -0,0 +1,201 @@
+'''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()
index 41a7f414581529b3f07e69c3082faf0ad483ca40..1ba899677435a61c1873fa245ad77c75a42496ab 100644 (file)
@@ -1459,6 +1459,16 @@ class TestFileTypeRepr(TestCase):
         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 = {}
@@ -1497,7 +1507,7 @@ class TestFileTypeR(TempDirMixin, ParserTestCase):
         ('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'))),
     ]
 
@@ -1537,7 +1547,7 @@ class TestFileTypeRB(TempDirMixin, ParserTestCase):
         ('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)),
     ]
 
 
@@ -1576,7 +1586,7 @@ class TestFileTypeW(TempDirMixin, ParserTestCase):
         ('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)),
     ]
 
 
@@ -1591,7 +1601,7 @@ class TestFileTypeWB(TempDirMixin, ParserTestCase):
         ('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)),
     ]
 
 
index 42c0707e8f21b1edc8e47eadd542fe12754f5ce6..09f71f2f39002dc7b1a42b59d48f3fc3a583d710 100644 (file)
@@ -101,11 +101,11 @@ class BaseEventTests(test_utils.TestCase):
             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.
@@ -915,6 +915,74 @@ class BaseEventLoopTests(test_utils.TestCase):
         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
@@ -1067,6 +1135,26 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase):
             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:
index 548a4610f7729e8c303d95b3589275e3f77f6670..b024ef4ca007852b2ab952a92a2a4dda366bae22 100644 (file)
@@ -71,17 +71,23 @@ ONLYCERT = data_file('ssl_cert.pem')
 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):
@@ -1187,7 +1193,11 @@ class EventLoopTestsMixin:
                     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):
index edf0461957f8cdd99c5ca234b8b0a15a9f5624ed..ba187c97fed410a733c079437afe18932f385c46 100644 (file)
@@ -334,6 +334,7 @@ class ProactorSocketTransportTests(test_utils.TestCase):
             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)
@@ -341,11 +342,15 @@ class ProactorSocketTransportTests(test_utils.TestCase):
         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()
index c359b458029db292fbe7c9046e367715dfb40eb2..533d2898e7fc5824260a7b5d2e012fdf0235cd45 100644 (file)
@@ -81,6 +81,7 @@ class BaseSelectorEventLoopTests(test_utils.TestCase):
         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)
@@ -884,14 +885,19 @@ class SelectorSocketTransportTests(test_utils.TestCase):
         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()
index e8ec09efd4ad98bd53f87b1a0f1ebb7a65773cce..084846bace3b9164a7401a6ec0ecca6d1ed203ed 100644 (file)
@@ -621,6 +621,42 @@ class BaseTaskTests:
         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():
index 47547396b8cb54bffafcd496bbb5dc536bef045f..2a4cc2acad24b1b32c6d91aca27db9748edeee90 100644 (file)
@@ -343,11 +343,20 @@ class BaseXYTestCase(unittest.TestCase):
             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
index e0dbe78498082966afd85f8e87431a3b1b3e23d0..e885e6d4a49aa63191d2badea369bcaa6cacddd9 100644 (file)
@@ -1841,6 +1841,15 @@ class TestType(unittest.TestCase):
         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
index 2e8819be5dac68cd4c606186f12a81c410396214..e71ede26466b7eb2ba714a6d84d2104f4b17d69e 100644 (file)
@@ -1,3 +1,4 @@
+import collections
 import datetime
 import unittest
 from test.support import cpython_only
@@ -6,6 +7,23 @@ try:
 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
index b36a2ce585ce3ea35a3ec20ab408299f8d1f36dc..ae3bcb92057b639ebeda72fb1490ba54d5fb3125 100644 (file)
@@ -372,258 +372,6 @@ class SubinterpreterTest(unittest.TestCase):
             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.')
@@ -652,12 +400,9 @@ class TestThreadState(unittest.TestCase):
 
 
 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):
index cee49343e268a23c76f37c305d398eb29be423fb..1980fc4092644e8b87ddf0b57a7ff09d89ec8239 100644 (file)
@@ -345,6 +345,9 @@ class ComplexTest(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
index 5ddce09a08bc47569eec9dc961c9662eb81d35d1..1ce0c15512bf19097074897a07d6db2f2082db85 100644 (file)
@@ -79,7 +79,7 @@ class ExecutorMixin:
     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:
@@ -90,10 +90,10 @@ class ExecutorMixin:
         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()
 
index 463d343411558c985e140a29c7ddc814d0d0d241..379601ad86deb283a0c97a5298bb55f096708a77 100644 (file)
@@ -72,9 +72,13 @@ class TestGdbm(unittest.TestCase):
         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.
@@ -82,7 +86,8 @@ class TestGdbm(unittest.TestCase):
 
         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:
index ce517b51d58e94c8a1ee924b12347ea49245869f..ed9ea0251a743dcae921ea1df0a1f5f34d33b203 100644 (file)
@@ -893,6 +893,21 @@ class TestSubclass(unittest.TestCase):
         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):
index 4386eda3ae48fdd4a65d81e545d22a66b1e0384f..7e94ad279364502e1c4c7349a4bf467eee93d5f7 100644 (file)
@@ -1010,7 +1010,7 @@ class DictTest(unittest.TestCase):
             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())
@@ -1176,6 +1176,37 @@ class DictTest(unittest.TestCase):
 
         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):
 
index 900e1d0e64d4341c4ca286c7127a34d0e34dc0af..5a59aebba89be4c7f7fb09364bec7ac82a1807c1 100644 (file)
@@ -33,7 +33,10 @@ class TestDecodeB(TestEmailBase):
         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])
@@ -42,6 +45,9 @@ class TestDecodeB(TestEmailBase):
         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):
 
index 5cdc4bcecad44769c57889b98032ba15568a28ce..676732bb3d026160543c64fc1fdce4babfff649b 100644 (file)
@@ -347,6 +347,15 @@ class TestParser(TestParserMixin, 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?=',
@@ -2143,6 +2152,31 @@ class TestParser(TestParserMixin, TestEmailBase):
         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):
index f36b907573995d774032a6cadd83eff5a08f5488..781f657418220c282ca94dff719db91844071c2a 100644 (file)
@@ -254,6 +254,23 @@ class TestDefectsBase:
         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
index eaea8ee3abdfc92ce4e15965344cc98f572ee93d..3cecee6916262e3a96a0d224191b8bc81ec8cd7e 100644 (file)
@@ -1506,6 +1506,23 @@ class TestEnum(unittest.TestCase):
             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):
index a7aff8a59ef6f07e295714ef01dd6e7716672432..efb54f42deb39ee8a1d661ac9f52ba38f901930a 100644 (file)
@@ -74,9 +74,11 @@ class TestEPoll(unittest.TestCase):
         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)
@@ -86,6 +88,13 @@ class TestEPoll(unittest.TestCase):
         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)
@@ -115,19 +124,19 @@ class TestEPoll(unittest.TestCase):
         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()
 
@@ -158,9 +167,9 @@ class TestEPoll(unittest.TestCase):
 
         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)
index 9890b8c586f380f3bfbdd76328b4c06e2c9fc467..f58d1dae6045f49ff17ae8a852ed6ab8371f92b0 100644 (file)
@@ -241,8 +241,7 @@ class OtherFileTests:
         # 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()
index c5ca50c8f71206d5b3e55a053bacd6f5e90817af..61551e5c99031ba7ea07cdd79576600877e0f971 100644 (file)
@@ -60,6 +60,9 @@ class GeneralFloatCases(unittest.TestCase):
         # 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:
index 98b5bd6fd18ace00d18d70124df7c275d34a511f..33e52e609a761a6bacf6499bb82802c304590a42 100644 (file)
@@ -4,18 +4,29 @@ import unittest
 class FLUFLTests(unittest.TestCase):
 
     def test_barry_as_bdfl(self):
-        code = "from __future__ import barry_as_FLUFL2 {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__':
index 44dd73aecaca92808a1b47195cbe4692d14dee92..4ff2f71afb837de963cca2c68bf9f43f61b1d7c4 100644 (file)
@@ -876,18 +876,23 @@ class TestTLS_FTPClass(TestCase):
         # 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):
index 145440027c910baf2bb52e9615edbdaa45a212a9..af02e8d1d5461955df4cb0ec638bb0b27a009340 100644 (file)
@@ -2078,6 +2078,13 @@ class TestSingleDispatch(unittest.TestCase):
         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()
index e7274998d52656dff92be34de687b3e92cf6666d..7e82b242dab5da59af6073f579bc9244b97281e8 100644 (file)
@@ -1,7 +1,7 @@
 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
@@ -713,6 +713,21 @@ class GCTests(unittest.TestCase):
             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)
index b7554d698c9d6c549716e4871e7d5005f3b0a0ce..b33d007acbdf37767e4fc55bcf203aae5a207a9b 100644 (file)
@@ -60,6 +60,23 @@ checkout_hook_path = os.path.join(os.path.dirname(sys.executable),
 
 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.
 
@@ -168,6 +185,12 @@ class DebuggerTests(unittest.TestCase):
             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']
@@ -212,6 +235,15 @@ class DebuggerTests(unittest.TestCase):
         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)
 
@@ -859,9 +891,17 @@ id(42)
             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 ")
 
index 9ed53902dc12bd108b305db6d3dc14ce7115e8c6..8b291cda689ce1ec55430403348640f6536e9360 100644 (file)
@@ -127,17 +127,20 @@ class GenericTest:
 
     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):
@@ -149,37 +152,45 @@ class GenericTest:
             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
@@ -280,15 +291,25 @@ class TestGenericTest(GenericTest, unittest.TestCase):
     # 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).
@@ -529,5 +550,5 @@ class PathLikeTests(unittest.TestCase):
         self.assertTrue(os.path.samefile(self.file_path, self.file_name))
 
 
-if __name__=="__main__":
+if __name__ == "__main__":
     unittest.main()
index d14a6ee31fd8b120c2292bb48132098c6dcd95d9..cdc4cbf7199921e1935c5fc484cd44a6edae0ba7 100644 (file)
@@ -1,9 +1,10 @@
 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
@@ -954,5 +955,182 @@ class Object_TestCase(unittest.TestCase):
         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()
index 295d4d4a8fdf3fc0b2b502a90cb45ab2c9a71637..b072ce4682c0fed78d7474505785402cbc3c0f39 100644 (file)
@@ -1,14 +1,19 @@
 """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;
@@ -24,6 +29,9 @@ data2 = b"""/* zlibmodule.c -- gzip-compatible data compression */
 """
 
 
+TEMPDIR = os.path.abspath(support.TESTFN) + '-gzdir'
+
+
 class UnseekableIO(io.BytesIO):
     def seekable(self):
         return False
@@ -665,8 +673,87 @@ class TestOpen(BaseTest):
         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)
index 220b5febc2fea429965b87bcf3a469acb23da028..9711856853ded32cafee514a5e183805089f0be6 100644 (file)
@@ -233,6 +233,20 @@ class HashLibTestCase(unittest.TestCase):
                 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()
@@ -571,8 +585,12 @@ class HashLibTestCase(unittest.TestCase):
         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'',
index 64d6e43537b381a60e042e9806d96a9a450fa863..714d521cf0e504625814b2f7cae10eaef28b5bda 100644 (file)
@@ -343,6 +343,21 @@ class HeaderTests(TestCase):
                 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"
index 93ba61a1a99e5df571c27eff1aa0c5ee4660f331..0593a3756b08431902eefc212d9965ecef601468 100644 (file)
@@ -5,6 +5,7 @@ from test import support
 threading = support.import_module('threading')
 
 from contextlib import contextmanager
+import errno
 import imaplib
 import os.path
 import socketserver
@@ -73,6 +74,19 @@ class TestImaplib(unittest.TestCase):
         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):
index b73a96f757005ecf54a9bc8bb5cae214d91ad5a8..6fb7cb0669cc13646dfc93693b25225ceac35e5f 100644 (file)
@@ -779,8 +779,11 @@ class PycacheTests(unittest.TestCase):
         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.
index ac18e5c34b87fae9e084bbabf08ea6229caa7574..43b158cc67f2469aad859b79340eabcd0ece94f1 100644 (file)
@@ -763,7 +763,7 @@ class MagicNumberTests(unittest.TestCase):
     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):
index d64bd453d5408ea2966cfc100d9ce6dff5a5d3b7..b968ae6a17e8fc958f86a49b2d422c0589c02f7e 100644 (file)
@@ -322,7 +322,7 @@ class GetSourceBase(unittest.TestCase):
 
     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),
@@ -497,6 +497,16 @@ class TestRetrievingSourceCode(GetSourceBase):
     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
 
@@ -3747,7 +3757,7 @@ def test_main():
         TestBoundArguments, TestSignaturePrivateHelpers,
         TestSignatureDefinitions,
         TestGetClosureVars, TestUnwrap, TestMain, TestReload,
-        TestGetCoroutineState
+        TestGetCoroutineState, TestGettingSourceOfToplevelFrames
     )
 
 if __name__ == "__main__":
index 0b5b033b5f88a7446c3da077596e0ce28a555d98..f306917ca7da2f5e2bb38b867d81b33094a14c07 100644 (file)
@@ -957,6 +957,16 @@ class IOTest(unittest.TestCase):
                 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):
 
@@ -3348,6 +3358,17 @@ class TextIOWrapperTest(unittest.TestCase):
         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
index d341ef8779bda33d48db07daa2051837069d9197..763a5d1df0e3a40503718bc27508d9f2dcc12eb1 100644 (file)
@@ -959,7 +959,9 @@ if threading:
 
 @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,
@@ -973,7 +975,7 @@ class SMTPHandlerTest(BaseTest):
         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)
@@ -1076,6 +1078,7 @@ class ConfigFileTest(BaseTest):
 
     """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.
@@ -1284,6 +1287,27 @@ class ConfigFileTest(BaseTest):
     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
@@ -1429,6 +1453,29 @@ class ConfigFileTest(BaseTest):
             # 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')
@@ -1977,6 +2024,7 @@ class ConfigDictTest(BaseTest):
 
     """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.
@@ -2851,6 +2899,35 @@ class ConfigDictTest(BaseTest):
             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")
index fd15f04aceca8fc7f15298a8fe0e40d9add08a06..6937284655cdcfcbfe57ba4b55a133079aa5835c 100644 (file)
@@ -373,6 +373,10 @@ class LongTest(unittest.TestCase):
         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):
 
@@ -695,6 +699,9 @@ class LongTest(unittest.TestCase):
         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)]):
index 29dda987d0bb7f28c59e16ccb4769acb469ce00a..64a7aa112de78dbc79a21eac3b11f94bddec81e4 100644 (file)
@@ -192,8 +192,8 @@ class BugsTestCase(unittest.TestCase):
         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):
@@ -204,19 +204,31 @@ class BugsTestCase(unittest.TestCase):
     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.
@@ -304,7 +316,7 @@ class BugsTestCase(unittest.TestCase):
             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])
index 32593dab86da16c9bec3323aa9e73f13eca1a621..e1b8d30f6a4c0653b854982a24777297ae71c372 100644 (file)
@@ -58,11 +58,13 @@ if __name__ == '__main__':
     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)
 """
@@ -86,11 +88,13 @@ set_start_method(start_method)
 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)
 """
index 40761843f34ca32874961fd3f523dcc8e07a0b44..f93d902d32fa93330bbb331b8468ba427bccfdb7 100644 (file)
@@ -303,6 +303,10 @@ class TestNtpath(unittest.TestCase):
         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')
 
index 6806c616cbef3888a2b9ba2b54eef369fb166a81..b2a22861880fa3f960ca9319b830e313cd67db64 100644 (file)
@@ -1,7 +1,7 @@
 # Python test set -- part 2, opcodes
 
 import unittest
-from test import ann_module
+from test import ann_module, support
 
 class OpcodeTest(unittest.TestCase):
 
@@ -42,10 +42,13 @@ 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):
 
index 240b7c432ba92fcb6eae7a9ca1b27348d1e15563..8339f849e84ea644e29915313298f0c0119d0335 100644 (file)
@@ -2540,12 +2540,14 @@ if threading is not None:
             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)
@@ -2627,6 +2629,8 @@ class TestSendfile(unittest.TestCase):
                                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):
@@ -2657,17 +2661,13 @@ class TestSendfile(unittest.TestCase):
             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
@@ -2758,20 +2758,22 @@ class TestSendfile(unittest.TestCase):
     @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()
@@ -2787,12 +2789,30 @@ class TestSendfile(unittest.TestCase):
         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'),
index 532e8fe6d0d88609422c5a59081b2ba7e4161a19..eed0fd1c6b73fa14f58794bc1a2fde7285c597b0 100644 (file)
@@ -5,7 +5,6 @@ import os
 import tempfile
 import textwrap
 import unittest
-from test import support
 
 
 # Helpers to create and destroy hierarchies.
@@ -50,11 +49,13 @@ class TestPkg(unittest.TestCase):
         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)
 
@@ -75,17 +76,17 @@ class TestPkg(unittest.TestCase):
             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]
@@ -138,7 +139,7 @@ class TestPkg(unittest.TestCase):
 
         s = """
             from t2 import *
-            self.assertTrue(dir(), ['self', 'sub'])
+            self.assertEqual(dir(), ['self', 'sub'])
             """
         self.run_code(s)
 
index ea6752b61d8f77f165c16e76c96c88cc3971f6a1..371cf0ad5e4a6aac71d27265d9cbb87feb437eb1 100644 (file)
@@ -3,6 +3,7 @@ import os
 import platform
 import subprocess
 import sys
+import sysconfig
 import tempfile
 import unittest
 import warnings
@@ -16,29 +17,34 @@ class PlatformTest(unittest.TestCase):
     @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)
 
@@ -270,7 +276,6 @@ class PlatformTest(unittest.TestCase):
             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
@@ -279,6 +284,49 @@ class PlatformTest(unittest.TestCase):
             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 (
index eb3ef8494788be13ad193876425aa6605fa32526..2dae473327f1b7076e530cf49cdf054705ce8ebd 100644 (file)
@@ -19,6 +19,21 @@ import warnings
 _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):
@@ -322,6 +337,17 @@ class PosixTester(unittest.TestCase):
         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)
@@ -344,6 +370,19 @@ class PosixTester(unittest.TestCase):
         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):
@@ -1109,7 +1148,7 @@ class PosixTester(unittest.TestCase):
             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_")]
index 96b267cd45fd9ae9f4293cff6384ea8a67a2637e..9476ede5319397ddce5e76ce97a795a13ad2b6ce 100644 (file)
@@ -153,27 +153,20 @@ class PosixPathTest(unittest.TestCase):
     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.
index 3d89e3adda26ce646d3a05eced17aca727e6e779..6dc51e4371d0f630300fa9487f88015e9e28793b 100644 (file)
@@ -3,6 +3,7 @@ import unittest
 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
@@ -159,6 +160,12 @@ class PullDOMTestCase(unittest.TestCase):
             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."""
index 10f431a63eb75b365dacc4c135f2d50dc2b15b13..877adf1ced4029e51638cf01467ebc405c33c717 100644 (file)
@@ -220,6 +220,14 @@ class TestBasicOps:
         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
index e2b52283cd11fc73376f832ba1f1b51860012e6d..0b590ad8f188cfb77166208ac725acdbc9677c9c 100644 (file)
@@ -18,6 +18,7 @@ import textwrap
 import unittest
 from test import libregrtest
 from test import support
+from test.libregrtest import utils
 
 
 Py_DEBUG = hasattr(sys, 'getobjects')
@@ -984,5 +985,29 @@ class ArgsTestCase(BaseTestCase):
                                   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()
index cc9c57024dee8e2ac98de38d454437ad645afe47..b405f0169d6ed6d905b72162f3ad3127b0a95b5d 100644 (file)
@@ -148,9 +148,6 @@ class ResourceTest(unittest.TestCase):
     @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)
index 2eb62905ffa882ba04c181af54a51424e3132d4e..3044960a0ed165466a7a425161ba49e5e50ed98c 100644 (file)
@@ -13,13 +13,14 @@ except SAXReaderNotAvailable:
 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
 
@@ -911,6 +912,18 @@ class ExpatReaderTest(XmlTestBase):
         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()
@@ -927,6 +940,32 @@ class ExpatReaderTest(XmlTestBase):
             [("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:
@@ -936,8 +975,9 @@ class ExpatReaderTest(XmlTestBase):
             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))
@@ -951,6 +991,22 @@ class ExpatReaderTest(XmlTestBase):
         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):
index a7680f886a8d7419572148e162fed945a21f6a29..4ade2cbc0d4b18467be012b511b7ee442d9828f1 100644 (file)
@@ -2,6 +2,7 @@
 
 import subprocess
 import sys
+import os
 from test.support import script_helper
 import unittest
 from unittest import mock
@@ -73,7 +74,7 @@ class TestScriptHelperEnvironment(unittest.TestCase):
 
     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
 
@@ -83,27 +84,41 @@ class TestScriptHelperEnvironment(unittest.TestCase):
 
     @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__':
index 588e7d27941cc1ccdb60f8fa6d6af9b37487ac3d..81457c8f09c972c0a6f2bb310963fe2eea9da7da 100644 (file)
@@ -1127,6 +1127,8 @@ class TestShutil(unittest.TestCase):
                 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))
 
index 8d6386793d4a57cf309f6201c80f92515ea632bc..5565eb745caf12500b8684fe4dd0ee7259200dcb 100644 (file)
@@ -370,7 +370,6 @@ class WakeupSocketSignalTests(unittest.TestCase):
         signal.signal(signum, handler)
 
         read, write = socket.socketpair()
-        read.setblocking(False)
         write.setblocking(False)
         signal.set_wakeup_fd(write.fileno())
 
index dce2aac909de4d4a2dafc5192a911c109c009809..afdcf36f394df58e74c622c2930b719b50b17f73 100644 (file)
@@ -6,7 +6,8 @@ executing have not been removed.
 """
 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
@@ -345,40 +346,47 @@ class ImportSideEffectTests(unittest.TestCase):
         # __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
index 67b3b478f76f2386c35d8ad7e13e2bcc8c83d12c..18110191dc3bf77e67993aa4834ffd68c1b6b45d 100644 (file)
@@ -18,6 +18,11 @@ import textwrap
 
 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
@@ -569,6 +574,33 @@ class NonConnectingTests(unittest.TestCase):
                           "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):
@@ -1068,6 +1100,19 @@ class SMTPSimTests(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
@@ -1213,17 +1258,6 @@ class SMTPUTF8SimTests(unittest.TestCase):
         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='')
 
@@ -1292,18 +1326,5 @@ class SMTPAUTHInitialResponseSimTests(unittest.TestCase):
         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()
index e41ddfd8afd68ac424a8a1e4591a96f6b8802fff..fbbc9f9abfb034b469a76fc7461e4b0f8c1907cd 100644 (file)
@@ -1773,33 +1773,6 @@ class RDSTest(ThreadedRDSSocketTest):
         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):
@@ -2314,9 +2287,18 @@ class SendmsgStreamTests(SendmsgTests):
     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()
 
@@ -2339,8 +2321,10 @@ class SendmsgStreamTests(SendmsgTests):
             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()
 
@@ -2874,10 +2858,11 @@ class SCMRightsTest(SendrecvmsgServerTimeoutBase):
     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
@@ -5490,7 +5475,7 @@ class LinuxKernelCryptoAPI(unittest.TestCase):
                                  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:
index e893f3a847fdf9032ca908f73a5c80adea0c045e..07793c84c8e912c5d09bff0e05884a8dc69a42f6 100644 (file)
@@ -67,8 +67,6 @@ class TestSpwdNonRoot(unittest.TestCase):
                 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__":
index 9785a59a7e49abe51b59d0da0e9e0205c06a19a4..2f0b6a75e96f19808175dbdcde1e4ba664d8e582 100644 (file)
@@ -60,7 +60,6 @@ BYTES_CAPATH = os.fsencode(CAPATH)
 CAFILE_NEURONIO = data_file("capath", "4e1295a3.0")
 CAFILE_CACERT = data_file("capath", "5ed36f99.0")
 
-
 # empty CRL
 CRLFILE = data_file("revocation.crl")
 
@@ -81,7 +80,7 @@ BADKEY = data_file("badkey.pem")
 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
@@ -89,6 +88,7 @@ OP_NO_COMPRESSION = getattr(ssl, "OP_NO_COMPRESSION", 0)
 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):
@@ -181,8 +181,8 @@ class BasicSocketTests(unittest.TestCase):
         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
@@ -251,6 +251,8 @@ class BasicSocketTests(unittest.TestCase):
 
             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
@@ -265,9 +267,9 @@ class BasicSocketTests(unittest.TestCase):
                           (('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'),),
@@ -899,12 +901,13 @@ class ContextTests(unittest.TestCase):
 
     @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)
@@ -1857,11 +1860,23 @@ if _have_threads:
                         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.
                     #
@@ -1961,6 +1976,24 @@ if _have_threads:
                                 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):
@@ -2461,10 +2494,10 @@ if _have_threads:
             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, \
@@ -3042,7 +3075,7 @@ if _have_threads:
                 # 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()
@@ -3050,6 +3083,8 @@ if _have_threads:
             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()
@@ -3073,17 +3108,22 @@ if _have_threads:
                     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])
@@ -3116,9 +3156,9 @@ if _have_threads:
                 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")
@@ -3444,19 +3484,25 @@ if _have_threads:
             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):
@@ -3601,6 +3647,194 @@ if _have_threads:
                                      '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
@@ -3653,6 +3887,7 @@ def test_main(verbose=False):
         thread_info = support.threading_setup()
         if thread_info:
             tests.append(ThreadedTests)
+            tests.append(TestPostHandshakeAuth)
 
     try:
         support.run_unittest(*tests)
index 9ebe3228ac0353ac1b0fca46aaa3e39350f862ad..e1b24778430e5660429843bf67201d687c4e3194 100644 (file)
@@ -2493,6 +2493,36 @@ class POSIXProcessTestCase(BaseTestCase):
         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)"],
index 6e0c122c4fe913609ec4342ef38d0281f39b023c..45cdc94393eb6493c8f966e30ac492e726d51c75 100644 (file)
@@ -247,7 +247,7 @@ class TestSupport(unittest.TestCase):
         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):
index a29ca96d1fc4b2211b8335d796ebeef0bd53d0f3..90e671908d9528b5a6f9f246c6d09958bc6fa774 100644 (file)
@@ -243,21 +243,34 @@ class TestSysConfig(unittest.TestCase):
     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)
 
index db99b75eec6458e277703feadd4ca7900b1d40db..80f1668bcecab876ca2b84821f77f1edc6afcdb8 100644 (file)
@@ -649,6 +649,43 @@ class TclTest(unittest.TestCase):
                 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)
 
index 99b60cd9e6b18ef567359901af7e32dbed459dba..9083e419d1d535774934462673b731f194938729 100644 (file)
@@ -78,6 +78,10 @@ class ThreadSignals(unittest.TestCase):
 
     @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')
@@ -105,6 +109,10 @@ class ThreadSignals(unittest.TestCase):
 
     @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')
index 5b6e58fa55756eb29abf39b7544a0fa006e4c9e4..6e57b6010f77b1cf32284d8dcc67063b8ed5ffcb 100644 (file)
@@ -21,7 +21,7 @@ except ImportError:
 # 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
@@ -603,9 +603,9 @@ class _Test4dYear:
         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):
@@ -614,12 +614,11 @@ class _Test4dYear:
         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):
@@ -772,19 +771,19 @@ class CPyTimeTestCase:
         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
index ef02342244c5ae2bb3f597e938a8c5b783a2f15a..844358aeeffa3ae93731a6bd134b69fc6118d701 100644 (file)
@@ -1,7 +1,8 @@
 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
@@ -11,27 +12,51 @@ import os
 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)
@@ -993,8 +1018,8 @@ class Test_Tokenize(TestCase):
             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")
@@ -1010,8 +1035,8 @@ class Test_Tokenize(TestCase):
             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")
@@ -1311,7 +1336,7 @@ class TestTokenize(TestCase):
             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 = []
@@ -1322,18 +1347,21 @@ class TestTokenize(TestCase):
 
         # 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):
@@ -1484,7 +1512,7 @@ class TestRoundtrip(TestCase):
         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
index 39e541b45bd264fb81cdaf079a27429de3dbbab3..00b8789929a5256bc4ea374bf01cdcfd18492457 100644 (file)
@@ -25,15 +25,25 @@ class TestSundryScripts(unittest.TestCase):
     # 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):
index bffc03e663ff787f29c0bb9c8fcb9ace7586bc09..8a3aa8a8648f86c5aa1d3a42b23db1b3a413ed87 100644 (file)
@@ -373,7 +373,7 @@ class TracebackFormatTests(unittest.TestCase):
             '    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'
@@ -412,7 +412,7 @@ class TracebackFormatTests(unittest.TestCase):
             '    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'
         )
@@ -420,6 +420,63 @@ class TracebackFormatTests(unittest.TestCase):
         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)
 
index 4fc11ec32f2a1b159da6df91615f5bf37db975a2..8a72ca278040fe3cc61ce25b744082474a85b4ab 100644 (file)
@@ -208,6 +208,19 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest):
         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')
index 9d9ec8726d8a6b15f1d49e2f80cb04419abc4d64..ef0091c49300f55ecc7de6eb838c2d1558419bbb 100644 (file)
@@ -308,7 +308,7 @@ class BasicAuthTests(unittest.TestCase):
         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()
index 2569a1fe49ef43f55bad288cac1dc02bd0f9f62c..d1ffb8132d819c7475f996236dfe7179c61f4db6 100644 (file)
@@ -32,6 +32,17 @@ except ImportError:
 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
@@ -139,9 +150,7 @@ class BasicTest(BaseTest):
             ('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':
@@ -264,11 +273,10 @@ class BasicTest(BaseTest):
         """
         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')
@@ -279,17 +287,16 @@ class BasicTest(BaseTest):
         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), 'ϼўТλФЙ')
@@ -297,12 +304,10 @@ class BasicTest(BaseTest):
         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
@@ -311,11 +316,8 @@ class EnsurePipTest(BaseTest):
     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
@@ -392,10 +394,7 @@ class EnsurePipTest(BaseTest):
                     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
@@ -409,11 +408,8 @@ class EnsurePipTest(BaseTest):
         # 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
index ea81d119160c8e1176b35e0378d2717439a36616..3dc88f5e36e31cf165153489fc5198442d224a2a 100644 (file)
@@ -145,10 +145,14 @@ class FilterTests(BaseTest):
             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,
index e46b6fb08938664d6ff2c3a326346cd4e5e2d12e..7cbb8d0a2957de6a8dd798544a195c6bbba17347 100644 (file)
@@ -170,23 +170,23 @@ class OperaCommandTest(CommandTestMixin, unittest.TestCase):
 
     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):
index c14f8397ae7da522a2a9c58b8b9dc9398fedda1c..2b8c5e59865652cbc0bef1f0a29b2ffacaa8a349 100644 (file)
@@ -90,6 +90,12 @@ ENTITY_XML = """\
 <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):
@@ -846,6 +852,13 @@ class ElementTreeTest(unittest.TestCase):
         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.
 
index d09ad96fc8baaa09558abe1b035c48c80210c772..e62b82e1d31dd5d244ef89c45086475013068d26 100644 (file)
@@ -718,6 +718,20 @@ class StoredTestZip64InSmallFiles(AbstractTestZip64InSmallFiles,
         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):
index 5b58c77630b6b47c7717587d0819bcf08f719daa..b7170b4ff525129b7138632fc289709d494673bc 100644 (file)
@@ -435,18 +435,29 @@ class CompressObjectTestCase(BaseCompressTestCase, 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))
diff --git a/Lib/test/wrongcert.pem b/Lib/test/wrongcert.pem
deleted file mode 100644 (file)
index 5f92f9b..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
------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-----
index b78191e2777f450e4af79a32e9822d36b84e5b7a..ff85f837d1d5941c4ae572e64b63ca5140ee5801 100644 (file)
@@ -61,7 +61,7 @@ def _stringify(value):
     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)
@@ -72,7 +72,10 @@ def _stringify(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
index dd155fad0fd0b3c97f8067938de33d878ce770c6..0d9a65a5cc830288e61cb51848b3337363da7bd1 100644 (file)
@@ -1,3 +1,4 @@
+import functools
 import re
 import tkinter
 import unittest
@@ -54,9 +55,20 @@ import _tkinter
 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
index 81b52eafea9a83a7ec6e221c9266d4e688aec725..e4c9d337ba7d2b1652d32281c7cda8fa96449ab4 100644 (file)
@@ -703,7 +703,7 @@ class ListboxTest(AbstractWidgetTest, unittest.TestCase):
         'disabledforeground', 'exportselection',
         'font', 'foreground', 'height',
         'highlightbackground', 'highlightcolor', 'highlightthickness',
-        'listvariable', 'relief',
+        'justify', 'listvariable', 'relief',
         'selectbackground', 'selectborderwidth', 'selectforeground',
         'selectmode', 'setgrid', 'state',
         'takefocus', 'width', 'xscrollcommand', 'yscrollcommand',
@@ -717,6 +717,8 @@ class ListboxTest(AbstractWidgetTest, unittest.TestCase):
         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)
@@ -951,7 +953,9 @@ class PanedWindowTest(AbstractWidgetTest, unittest.TestCase):
     OPTIONS = (
         'background', 'borderwidth', 'cursor',
         'handlepad', 'handlesize', 'height',
-        'opaqueresize', 'orient', 'relief',
+        'opaqueresize', 'orient',
+        'proxybackground', 'proxyborderwidth', 'proxyrelief',
+        'relief',
         'sashcursor', 'sashpad', 'sashrelief', 'sashwidth',
         'showhandle', 'width',
     )
@@ -978,6 +982,23 @@ class PanedWindowTest(AbstractWidgetTest, unittest.TestCase):
         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')
index 825aa90646057e67f67939d46a0633e1c750269f..e131ae66c96a5396f100676442b3c9df4411d374 100644 (file)
@@ -507,8 +507,15 @@ def _tokenize(readline, encoding):
             # 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''
@@ -719,6 +726,9 @@ def _tokenize(readline, encoding):
         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), '')
index 41fefff9c2dcfe420b77e1bf6ed18db6e2843067..1e5190954b95a74651418d3368b13ea34a96361e 100644 (file)
@@ -25,10 +25,12 @@ def print_list(extracted_list, file=None):
         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
@@ -55,15 +57,17 @@ def format_tb(tb, limit=None):
     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)
 
@@ -307,6 +311,8 @@ def walk_tb(tb):
         tb = tb.tb_next
 
 
+_RECURSIVE_CUTOFF = 3 # Also hardcoded in traceback.c.
+
 class StackSummary(list):
     """A stack of frames."""
 
@@ -360,10 +366,9 @@ class StackSummary(list):
 
     @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
@@ -396,18 +401,21 @@ class StackSummary(list):
         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(
@@ -418,8 +426,12 @@ class StackSummary(list):
                 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
 
 
index f73c864b7b40a247028a17474ecec1f2a772aefc..f167ed1f353020ed2d053381b432aae285fb5694 100755 (executable)
@@ -144,9 +144,6 @@ def test(l=200, n=4, fun=sun, startpos=(0,0), th=2):
     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))
diff --git a/Lib/turtledemo/rosette.py b/Lib/turtledemo/rosette.py
new file mode 100644 (file)
index 0000000..0f27442
--- /dev/null
@@ -0,0 +1,65 @@
+"""      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()
index 71fff355c7cf946e8b2db6c12ec6d62f473c44bd..e7f202e69223d2842dde8f11ebad1481d6c26475 100755 (executable)
@@ -49,7 +49,6 @@ def maketree():
     t = tree([p], 200, 65, 0.6375)
     for x in t:
         pass
-    print(len(p.getscreen().turtles()))
 
 def main():
     a=clock()
diff --git a/Lib/turtledemo/wikipedia.py b/Lib/turtledemo/wikipedia.py
deleted file mode 100644 (file)
index 0f27442..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-"""      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()
index 2c7501952c7e48dbf57b3fc081bf1704e2b0e85e..898056fa9989069e039b8f7406c0a530fde4bcd5 100644 (file)
@@ -41,16 +41,13 @@ class TestBreak(unittest.TestCase):
 
     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)
index 6f43b7f1265d1abdbb213b9e634bfa6d55122032..1a553f0e65ac9448da80fb3b9cfee640e57a193d 100755 (executable)
@@ -290,11 +290,10 @@ Chromium = Chrome
 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
 
 
index 421358fa5bc7f02023dd33c5ce1147f7b3a5e114..5066ffc2fa51f029eb7147cd7becbd4e835f823d 100644 (file)
@@ -95,7 +95,7 @@ class ExpatParser(xmlreader.IncrementalParser, xmlreader.Locator):
         self._lex_handler_prop = None
         self._parsing = 0
         self._entity_stack = []
-        self._external_ges = 1
+        self._external_ges = 0
         self._interning = None
 
     # XMLReader methods
index 9164f8ab086a1656a24eca919f9a1684d7b30e59..5bb35870a68970c9b689805295676d63aaa02729 100644 (file)
@@ -164,6 +164,29 @@ _CD64_NUMBER_ENTRIES_TOTAL = 7
 _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):
@@ -1010,8 +1033,8 @@ class _ZipWriteFile(io.BufferedIOBase):
         # 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:
@@ -1710,6 +1733,7 @@ class ZipFile:
             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
index d76b2c096764f5a9ff0ccf02e571a1badf5e709c..b97d55bb0306f030e4085656163f1115f519e23e 100755 (executable)
@@ -162,7 +162,8 @@ def getTargetCompilers():
 
 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]
@@ -210,9 +211,9 @@ def library_recipes():
 
     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,
@@ -607,9 +608,10 @@ def checkEnvironment():
         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):
     """
@@ -822,6 +824,13 @@ def build_universal_openssl(basedir, archList):
         ]
         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")
@@ -1055,9 +1064,14 @@ def buildPythonDocs():
     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)
index 93e65a4bbf2eaa3125a9dcb1e86d45348465ac78..94731b493c51dd0d9befb625abd703a20a4381a9 100644 (file)
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -21,6 +21,7 @@ Ron Adam
 Anton Afanasyev
 Ali Afshar
 Nitika Agarwal
+Pablo S. Blum de Aguiar
 Jim Ahlstrom
 Farhan Ahmad
 Matthew Ahrens
@@ -1418,6 +1419,7 @@ Roger D. Serwy
 Jerry Seutter
 Pete Sevander
 Denis Severson
+Silas Sewell
 Ian Seyer
 Dmitry Shachnev
 Anish Shah
@@ -1727,6 +1729,7 @@ Gordon Worley
 Darren Worrall
 Thomas Wouters
 Daniel Wozniak
+Marcin Niemira
 Wei Wu
 Heiko Wundram
 Doug Wyatt
@@ -1742,6 +1745,7 @@ Jason Yeo
 EungJun Yi
 Bob Yodlowski
 Danny Yoo
+Wonsup Yoon
 Rory Yorke
 George Yoshida
 Kazuhiro Yoshida
index 4ce431f660e1cc8249a85e7ef2c05272775d6be3..76d7b950a2325d2e816415fda5d456fad8ecb2ba 100644 (file)
@@ -629,7 +629,7 @@ Library
 - 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
@@ -677,7 +677,7 @@ Library
 - 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.
@@ -966,7 +966,7 @@ Core and Builtins
   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.
 
@@ -1042,7 +1042,7 @@ Library
 - 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
@@ -9956,7 +9956,7 @@ Library
   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.
 
index c23bcfd619a1fab881e3f736079e8ad288921920..37489cd51f5706debd91db3bfa86c7a9de5af27a 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -2,6 +2,474 @@
 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?
 =================================
 
@@ -77,7 +545,7 @@ Library
   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
@@ -309,7 +777,7 @@ Tools/Demos
 
 - 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
@@ -944,7 +1412,7 @@ Documentation
 -------------
 
 - 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.
@@ -1025,7 +1493,7 @@ IDLE
 - 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.
@@ -1081,9 +1549,6 @@ Tools/Demos
 
 - 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.
 
@@ -1306,7 +1771,7 @@ Library
   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
@@ -1420,13 +1885,13 @@ IDLE
 - 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.
@@ -1632,7 +2097,7 @@ Security
 - 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?
@@ -3240,7 +3705,7 @@ Library
 - 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.
@@ -3613,7 +4078,7 @@ IDLE
   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.
@@ -3875,8 +4340,8 @@ Build
 - 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.
 
@@ -3956,8 +4421,8 @@ Library
   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.
@@ -4098,12 +4563,12 @@ IDLE
 
 - 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.
@@ -5090,7 +5555,7 @@ Library
 - 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,
@@ -5506,7 +5971,7 @@ C API
 
 - 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.
 
 
@@ -5847,7 +6312,7 @@ Library
 - 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.
@@ -6709,7 +7174,7 @@ Library
   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.
@@ -7079,7 +7544,7 @@ Core and Builtins
 - 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
 -------
@@ -8359,7 +8824,7 @@ 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
@@ -8514,7 +8979,7 @@ Library
 
 - 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
@@ -8663,7 +9128,7 @@ Library
 - 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.
@@ -8789,7 +9254,7 @@ Core and Builtins
   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.
@@ -9072,7 +9537,7 @@ Library
 - 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
@@ -9648,7 +10113,7 @@ Library
 - 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
@@ -9698,8 +10163,8 @@ Library
 
 - 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.
 
index 82fa23e1a7ea2159dd5ae67317d65bca1a32ec9f..8099a2d1d8cb9502cbd6636a01a16d1e5f048639 100644 (file)
@@ -218,7 +218,7 @@ Compile in support for Low Level TRACE-ing of the main interpreter loop.
 
 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.
 
index 5bc60fc0a732d71d6c6a836be114f301379fba50..bc8f77f261a805498bc9d36a2e5c4b1e520cb75f 100644 (file)
@@ -11,7 +11,7 @@
 # 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
 ###}
 
 ###
index 735bacb1b4dfbf58c7c411bb4f0dc9256941285a..acf4433cfe6fb60c603ae604de6c25fcd0dc155f 100644 (file)
@@ -366,14 +366,6 @@ _symtable symtablemodule.c
 #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
index 1430097f82dacd81d34305ee65f282c764a7a20a..2a6c16da85b41e3c8c72749fe65a1dd2cb1acea5 100644 (file)
@@ -1221,7 +1221,7 @@ static PyGetSetDef TaskStepMethWrapper_getsetlist[] = {
     {NULL} /* Sentinel */
 };
 
-PyTypeObject TaskStepMethWrapper_Type = {
+static PyTypeObject TaskStepMethWrapper_Type = {
     PyVarObject_HEAD_INIT(NULL, 0)
     "TaskStepMethWrapper",
     .tp_basicsize = sizeof(TaskStepMethWrapper),
@@ -1296,7 +1296,7 @@ TaskWakeupMethWrapper_dealloc(TaskWakeupMethWrapper *o)
     Py_TYPE(o)->tp_free(o);
 }
 
-PyTypeObject TaskWakeupMethWrapper_Type = {
+static PyTypeObject TaskWakeupMethWrapper_Type = {
     PyVarObject_HEAD_INIT(NULL, 0)
     "TaskWakeupMethWrapper",
     .tp_basicsize = sizeof(TaskWakeupMethWrapper),
@@ -2121,14 +2121,19 @@ set_exception:
 
             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;
index 09b200ebe1726c33faea57795ce60c293b66401b..418c0184006d04fe22bdba81365c0ffbb8f45ea6 100644 (file)
@@ -49,10 +49,10 @@ typedef struct {
 #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 *
@@ -70,17 +70,18 @@ new_BLAKE2bObject(PyTypeObject *type)
 
 /*[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
@@ -94,7 +95,7 @@ py_blake2b_new_impl(PyTypeObject *type, PyObject *data, int digest_size,
                     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;
@@ -256,14 +257,14 @@ py_blake2b_new_impl(PyTypeObject *type, PyObject *data, int digest_size,
 }
 
 /*[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;
 
@@ -278,21 +279,21 @@ _blake2b_blake2b_copy_impl(BLAKE2bObject *self)
 }
 
 /*[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)
@@ -317,14 +318,14 @@ _blake2b_blake2b_update(BLAKE2bObject *self, PyObject *obj)
 }
 
 /*[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;
@@ -338,14 +339,14 @@ _blake2b_blake2b_digest_impl(BLAKE2bObject *self)
 }
 
 /*[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;
@@ -359,10 +360,10 @@ _blake2b_blake2b_hexdigest_impl(BLAKE2bObject *self)
 
 
 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}
 };
 
@@ -423,7 +424,7 @@ py_blake2b_dealloc(PyObject *self)
 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           */
index 735b6f08deb6f8bc8bc04a8c4ec854d47b100483..24e529b6596ac2e93f45224dabcfa15af7065728 100644 (file)
@@ -49,10 +49,10 @@ typedef struct {
 #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 *
@@ -70,17 +70,18 @@ new_BLAKE2sObject(PyTypeObject *type)
 
 /*[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
@@ -94,7 +95,7 @@ py_blake2s_new_impl(PyTypeObject *type, PyObject *data, int digest_size,
                     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;
@@ -256,14 +257,14 @@ py_blake2s_new_impl(PyTypeObject *type, PyObject *data, int digest_size,
 }
 
 /*[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;
 
@@ -278,21 +279,21 @@ _blake2s_blake2s_copy_impl(BLAKE2sObject *self)
 }
 
 /*[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)
@@ -317,14 +318,14 @@ _blake2s_blake2s_update(BLAKE2sObject *self, PyObject *obj)
 }
 
 /*[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;
@@ -338,14 +339,14 @@ _blake2s_blake2s_digest_impl(BLAKE2sObject *self)
 }
 
 /*[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;
@@ -359,10 +360,10 @@ _blake2s_blake2s_hexdigest_impl(BLAKE2sObject *self)
 
 
 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}
 };
 
@@ -423,7 +424,7 @@ py_blake2s_dealloc(PyObject *self)
 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           */
index 71c073aa36c6b1f27c446f622b8ef8a434dfa5d4..9b2965eb6b31843c1bf985eb13fac10427e17f19 100644 (file)
@@ -3,10 +3,9 @@ preserve
 [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.");
@@ -22,7 +21,7 @@ static PyObject *
 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;
@@ -60,66 +59,66 @@ exit:
     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]*/
index ca908d393b5bb7b02f7bf4878382844c70ce8503..42b87b7099dfb0c3a703314f3ef81f7e84e5fb90 100644 (file)
@@ -3,10 +3,9 @@ preserve
 [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.");
@@ -22,7 +21,7 @@ static PyObject *
 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;
@@ -60,66 +59,66 @@ exit:
     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]*/
index 9c5a631eff45f347e2f4c3d8bcb6cff5e908af9d..3f555992316dad3cd8da5daa4a6d7373a8bedf30 100644 (file)
@@ -652,11 +652,15 @@ _bz2_BZ2Decompressor___init___impl(BZ2Decompressor *self)
     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;
index d7b344be692c1d6e043abb37497be895552421d1..85037d002703295ce022426a158ef8acc7867c0b 100644 (file)
@@ -514,6 +514,7 @@ deque_inplace_concat(dequeobject *deque, PyObject *other)
 static PyObject *
 deque_copy(PyObject *deque)
 {
+    PyObject *result;
     dequeobject *old_deque = (dequeobject *)deque;
     if (Py_TYPE(deque) == &deque_type) {
         dequeobject *new_deque;
@@ -538,10 +539,19 @@ deque_copy(PyObject *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.");
index c61eae5341aeeb312281f82b49dd98a5b0f17505..5d0044a2377a803e258d65bebac51c9132eb74ee 100644 (file)
@@ -561,25 +561,17 @@ parse_save_field(ReaderObj *self)
 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;
 }
 
@@ -1095,31 +1087,18 @@ join_append_data(WriterObj *self, unsigned int field_kind, void *field_data,
 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;
 }
index f6af49aea3850b7f7622ef11cd8289ff5617ac9b..6ffbeab8bf6329fb15205bd6dd23b5bb05bf71a5 100644 (file)
@@ -662,6 +662,200 @@ EXPORT(void) TwoOutArgs(int a, int *pi, int b, int *pj)
     *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); }
index 8edffabcdf09ffb368285fa7852b4015f1eeebaa..b8c2c746a0feb7cbe46539c5a6c0181be24d061a 100644 (file)
@@ -715,9 +715,9 @@ ffi_type *_ctypes_get_ffi_type(PyObject *obj)
        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
index 91a27dce3f25753676796fd6ae5a9ca9e5f170b3..d202b158b07902abcfa77eec5a21c8f92f3973ba 100644 (file)
@@ -145,6 +145,21 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
   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)
 {
@@ -163,9 +178,9 @@ 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;
index efb14c5f6f3aa11cb28616fe72aa22d979bef0ed..ba74202720a652dd1144cc39c3efa74969dbad45 100644 (file)
@@ -136,6 +136,9 @@ typedef struct _ffi_type
   /*@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;
index b07a2e6db27137b910efaae2ccf3e09ff2c44df6..022435e53fcd118130b5732fa84b15959e459c6c 100644 (file)
@@ -117,7 +117,8 @@ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif,
   /* 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)
@@ -146,7 +147,9 @@ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif,
        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
index d1149a85eb4286fb03dcfeabd4fad6cc72b31045..f44a5fe3697cfaa8dda7fb32ba342d745f650852 100644 (file)
@@ -90,7 +90,7 @@ noclean:
 
 // 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
index 148bd80190e8a28be6b4417f406930c735901c20..64928b1f81c19ec404dcd4cb024ff8678552e7c0 100644 (file)
@@ -4309,7 +4309,22 @@ datetime_from_timet_and_us(PyObject *cls, TM_FUNC f, time_t timet, int us,
     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,
index 707ab2912b3502e232c1e7f8349362ac8ad4302c..53f05f937ffb82fca31296c40d0d2ff646722c44 100644 (file)
@@ -3261,6 +3261,11 @@ _elementtree_XMLParser___init___impl(XMLParserObject *self, PyObject *html,
         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);
index 8f6185ccb73be48209047d9baf01b4408d561a54..9e3a286896085e044984c2bb37bce3cd73730824 100644 (file)
@@ -740,6 +740,10 @@ pbkdf2_hmac(PyObject *self, PyObject *args, PyObject *kwdict)
 #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
 
index c8642040ae426a8e41ca7cd6652cbe954304d226..f5c82c14096c3f482887568859707e49bd43b30c 100644 (file)
@@ -210,16 +210,19 @@ static PyObject *
 _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)
index 8542efd9726a7aab74efa3ba1998de232713184e..bf4f892b48a64a4f53f4d78bee0c5032e0546f2f 100644 (file)
@@ -870,8 +870,10 @@ stringio_getstate(stringio *self)
     }
     else {
         dict = PyDict_Copy(self->dict);
-        if (dict == NULL)
+        if (dict == NULL) {
+            Py_DECREF(initvalue);
             return NULL;
+        }
     }
 
     state = Py_BuildValue("(OOnN)", initvalue,
index 4638b4759701f84887909c6fa38a9af66046e3fe..d582d3fb13407090829ed3ffa2f3069cd6f9617a 100644 (file)
@@ -696,6 +696,9 @@ typedef struct
     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. */
 
@@ -1367,6 +1370,7 @@ _io_TextIOWrapper_write_impl(textio *self, PyObject *text)
         Py_DECREF(ret);
     }
 
+    textiowrapper_set_decoded_chars(self, NULL);
     Py_CLEAR(self->snapshot);
 
     if (self->decoder) {
@@ -1536,11 +1540,16 @@ textiowrapper_read_chunk(textio *self, Py_ssize_t size_hint)
          */
         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);
 
@@ -1602,6 +1611,7 @@ _io_TextIOWrapper_read_impl(textio *self, Py_ssize_t n)
         if (result == NULL)
             goto fail;
 
+        textiowrapper_set_decoded_chars(self, NULL);
         Py_CLEAR(self->snapshot);
         return result;
     }
@@ -2088,6 +2098,7 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence)
     cookie_type cookie;
     PyObject *res;
     int cmp;
+    PyObject *snapshot;
 
     CHECK_ATTACHED(self);
     CHECK_CLOSED(self);
@@ -2222,11 +2233,11 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence)
             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);
@@ -2244,9 +2255,10 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence)
         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) */
index 0d1b0926baeef100e6343cc4c71100f88a18b737..979bcfc49b9b3685d26be35ac50eb7f31cc5600a 100644 (file)
@@ -573,7 +573,8 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) {
     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);
 
@@ -581,6 +582,9 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) {
             err = GetLastError();
             break;
         }
+        if (n == (DWORD)-1 && (err = GetLastError()) == ERROR_OPERATION_ABORTED) {
+            break;
+        }
         if (n == 0) {
             err = GetLastError();
             if (err != ERROR_OPERATION_ABORTED)
index 8f1743bada875394a950de4ce871b0cc603c7999..dad6b01f822fa2d63b5c1082796340877fb4c80a 100644 (file)
@@ -1376,7 +1376,7 @@ _encoded_const(PyObject *obj)
         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) {
@@ -1384,7 +1384,7 @@ _encoded_const(PyObject *obj)
         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) {
@@ -1392,7 +1392,7 @@ _encoded_const(PyObject *obj)
         if (s_false == NULL) {
             s_false = PyUnicode_InternFromString("false");
         }
-        Py_INCREF(s_false);
+        Py_XINCREF(s_false);
         return s_false;
     }
     else {
index 0e7623ddbc966711e8d03e31cf4e022dc06647d4..5f2eeea6dfcc163c8f1b6a34e2a7d6220cab6466 100644 (file)
@@ -791,11 +791,11 @@ static PyMethodDef profiler_methods[] = {
 };
 
 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\
 ");
index b25faff5ac4924a377f6832aa7e4701c1db88e12..c265507ff58ed934d32dc88effb5b13dfa452d00 100644 (file)
@@ -1181,11 +1181,15 @@ _lzma_LZMADecompressor___init___impl(Decompressor *self, int format,
     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;
index 792c7604b59ef29be687b393c62a733cef626c9c..0a7e20e10592e1947b61d2377b5ca4a50fe12ec3 100644 (file)
@@ -596,9 +596,9 @@ typedef struct {
 } 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;
 
@@ -644,8 +644,8 @@ typedef struct UnpicklerObject {
     /* 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
@@ -731,7 +731,6 @@ PyMemoTable_New(void)
 static PyMemoTable *
 PyMemoTable_Copy(PyMemoTable *self)
 {
-    Py_ssize_t i;
     PyMemoTable *new = PyMemoTable_New();
     if (new == NULL)
         return NULL;
@@ -748,7 +747,7 @@ PyMemoTable_Copy(PyMemoTable *self)
         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,
@@ -794,7 +793,7 @@ _PyMemoTable_Lookup(PyMemoTable *self, PyObject *key)
 {
     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;
@@ -816,22 +815,24 @@ _PyMemoTable_Lookup(PyMemoTable *self, PyObject *key)
 
 /* 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);
 
@@ -904,10 +905,12 @@ PyMemoTable_Set(PyMemoTable *self, PyObject *key, Py_ssize_t value)
      * 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
@@ -1352,17 +1355,19 @@ _Unpickler_Readline(UnpicklerObject *self, char **result)
 /* 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;
@@ -1371,9 +1376,9 @@ _Unpickler_ResizeMemoList(UnpicklerObject *self, Py_ssize_t 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];
@@ -1382,7 +1387,7 @@ _Unpickler_MemoGet(UnpicklerObject *self, Py_ssize_t 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;
 
@@ -3347,6 +3352,8 @@ save_global(PicklerObject *self, PyObject *obj, PyObject *name)
             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)
@@ -4324,14 +4331,13 @@ static PyObject *
 _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;
@@ -6195,11 +6201,10 @@ load_mark(UnpicklerObject *self)
             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;
@@ -6708,7 +6713,7 @@ _pickle_Unpickler___init___impl(UnpicklerObject *self, PyObject *file,
 
     self->stack = (Pdata *)Pdata_New();
     if (self->stack == NULL)
-        return 1;
+        return -1;
 
     self->memo_size = 32;
     self->memo = _Unpickler_NewMemo(self->memo_size);
@@ -6761,7 +6766,7 @@ static PyObject *
 _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;
@@ -6912,8 +6917,7 @@ static int
 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,
@@ -6930,7 +6934,7 @@ Unpickler_set_memo(UnpicklerObject *self, PyObject *obj)
         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];
         }
@@ -6978,8 +6982,7 @@ Unpickler_set_memo(UnpicklerObject *self, PyObject *obj)
 
   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);
index ad934dfe7d87613a4d3c2fbebb78f856c482dfb4..fe0e554618aabb4fe35d3b44a70632ba4a6868f1 100644 (file)
@@ -422,10 +422,20 @@ child_exec(char *const exec_array[],
 
     /* 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()
@@ -451,14 +461,8 @@ child_exec(char *const exec_array[],
     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));
index 1ce4b776f3e26908353a9a1f80cb501c3cd28b74..e37515ee6552023c2690d40f0316296b1fdd3191 100644 (file)
@@ -62,7 +62,10 @@ get_proxy_settings(PyObject* mod __attribute__((__unused__)))
     PyObject* v;
     int r;
 
+    Py_BEGIN_ALLOW_THREADS
     proxyDict = SCDynamicStoreCopyProxies(NULL);
+    Py_END_ALLOW_THREADS
+
     if (!proxyDict) {
         Py_INCREF(Py_None);
         return Py_None;
@@ -173,7 +176,10 @@ get_proxies(PyObject* mod __attribute__((__unused__)))
     int r;
     CFDictionaryRef proxyDict = NULL;
 
+    Py_BEGIN_ALLOW_THREADS
     proxyDict = SCDynamicStoreCopyProxies(NULL);
+    Py_END_ALLOW_THREADS
+
     if (proxyDict == NULL) {
         return PyDict_New();
     }
index 7688e7de29f97b077b52d59dc66b7d8552901e37..35f11abca0fceb59fbc094a44e6b3846781bb59b 100644 (file)
@@ -2,33 +2,6 @@
 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"
@@ -51,7 +24,7 @@ PyDoc_STRVAR(_sha3_sha3_224_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 _SHA3_SHA3_224_DIGEST_METHODDEF    \
     {"digest", (PyCFunction)_sha3_sha3_224_digest, METH_NOARGS, _sha3_sha3_224_digest__doc__},
@@ -84,71 +57,29 @@ _sha3_sha3_224_hexdigest(SHA3object *self, PyObject *Py_UNUSED(ignored))
 }
 
 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]*/
index 11aaa1f6b0afd937d344b67d142a3e3bb4b7aee8..2c2b2dbc5c7d41e0e2583d5b689eaa66a95b2b01 100644 (file)
@@ -174,21 +174,20 @@ newSHA3object(PyTypeObject *type)
 }
 
 
-/*[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) {
@@ -302,12 +301,12 @@ _sha3_sha3_224_copy_impl(SHA3object *self)
 /*[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;
@@ -357,20 +356,20 @@ _sha3_sha3_224_hexdigest_impl(SHA3object *self)
 /*[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
@@ -505,7 +504,7 @@ static PyGetSetDef SHA3_getseters[] = {
     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 */ \
@@ -544,44 +543,49 @@ static PyGetSetDef SHA3_getseters[] = {
         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.");
 
@@ -593,13 +597,22 @@ SHA3_TYPE(Keccak_512type, "_sha3.keccak_512", keccak_512__doc__, SHA3_methods);
 
 
 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.
      */
@@ -639,15 +652,15 @@ _SHAKE_digest(SHA3object *self, unsigned long digestlen, int hex)
 /*[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);
 }
@@ -656,15 +669,15 @@ _sha3_shake_128_digest_impl(SHA3object *self, unsigned long length)
 /*[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);
 }
@@ -679,12 +692,12 @@ static PyMethodDef SHAKE_methods[] = {
 };
 
 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.");
 
index 32cd306b372103322f74ceb0a82fe2c31fbe328f..f503288336d08dc6691a670666b66137ec6ed24b 100644 (file)
@@ -613,7 +613,7 @@ void _pysqlite_func_callback(sqlite3_context* context, int argc, sqlite3_value**
         Py_DECREF(py_retval);
     }
     if (!ok) {
-        if (_enable_callback_tracebacks) {
+        if (_pysqlite_enable_callback_tracebacks) {
             PyErr_Print();
         } else {
             PyErr_Clear();
@@ -649,7 +649,7 @@ static void _pysqlite_step_callback(sqlite3_context *context, int argc, sqlite3_
 
         if (PyErr_Occurred()) {
             *aggregate_instance = 0;
-            if (_enable_callback_tracebacks) {
+            if (_pysqlite_enable_callback_tracebacks) {
                 PyErr_Print();
             } else {
                 PyErr_Clear();
@@ -673,7 +673,7 @@ static void _pysqlite_step_callback(sqlite3_context *context, int argc, sqlite3_
     Py_DECREF(args);
 
     if (!function_result) {
-        if (_enable_callback_tracebacks) {
+        if (_pysqlite_enable_callback_tracebacks) {
             PyErr_Print();
         } else {
             PyErr_Clear();
@@ -727,7 +727,7 @@ void _pysqlite_final_callback(sqlite3_context* context)
         Py_DECREF(function_result);
     }
     if (!ok) {
-        if (_enable_callback_tracebacks) {
+        if (_pysqlite_enable_callback_tracebacks) {
             PyErr_Print();
         } else {
             PyErr_Clear();
@@ -894,7 +894,7 @@ static int _authorizer_callback(void* user_arg, int action, const char* arg1, co
     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();
@@ -905,7 +905,7 @@ static int _authorizer_callback(void* user_arg, int action, const char* arg1, co
         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();
@@ -936,7 +936,7 @@ static int _progress_handler(void* user_arg)
     ret = PyObject_CallFunction((PyObject*)user_arg, NULL);
 
     if (!ret) {
-        if (_enable_callback_tracebacks) {
+        if (_pysqlite_enable_callback_tracebacks) {
             PyErr_Print();
         } else {
             PyErr_Clear();
@@ -975,7 +975,7 @@ static void _trace_callback(void* user_arg, const char* statement_string)
     if (ret) {
         Py_DECREF(ret);
     } else {
-        if (_enable_callback_tracebacks) {
+        if (_pysqlite_enable_callback_tracebacks) {
             PyErr_Print();
         } else {
             PyErr_Clear();
index 82373409471a88d029e78e837159e885b516cb3c..098d5a3575d1441371fdc76402bd1146b38b6f53 100644 (file)
@@ -109,7 +109,7 @@ PyObject* _pysqlite_get_converter(PyObject* key)
         return NULL;
     }
 
-    retval = PyDict_GetItem(converters, upcase_key);
+    retval = PyDict_GetItem(_pysqlite_converters, upcase_key);
     Py_DECREF(upcase_key);
 
     return retval;
@@ -564,7 +564,7 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
             } 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();
index cc45331ab55d1650fa585bccad91e81057795270..7af22846736bacf57f1f33c4732df890a2ef01f4 100644 (file)
@@ -39,8 +39,8 @@ PyObject* pysqlite_Error, *pysqlite_Warning, *pysqlite_InterfaceError, *pysqlite
     *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*
@@ -197,7 +197,7 @@ static PyObject* module_register_converter(PyObject* self, PyObject* args)
         goto error;
     }
 
-    if (PyDict_SetItem(converters, name, callable) != 0) {
+    if (PyDict_SetItem(_pysqlite_converters, name, callable) != 0) {
         goto error;
     }
 
@@ -215,7 +215,7 @@ Registers a converter with pysqlite. Non-standard.");
 
 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;
     }
 
@@ -229,12 +229,12 @@ Enable or disable callback functions throwing errors to stderr.");
 
 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[] = {
@@ -448,7 +448,7 @@ PyMODINIT_FUNC PyInit__sqlite3(void)
     /* initialize the default converters */
     converters_init(dict);
 
-    _enable_callback_tracebacks = 0;
+    _pysqlite_enable_callback_tracebacks = 0;
 
     pysqlite_BaseTypeAdapted = 0;
 
index 0fb5a55fa4d640e70797c3e403daae95c78fe0cd..6f90934b325dc097ce8c9c54d121ae3197735cb4 100644 (file)
@@ -38,17 +38,13 @@ extern PyObject* pysqlite_IntegrityError;
 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
index 087375be9b63d888a7f12b46feb18ddf8a17d18d..de265963b084b9702d305c554f261894575a84ed 100644 (file)
@@ -85,10 +85,10 @@ int pysqlite_statement_create(pysqlite_Statement* self, pysqlite_Connection* con
                 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;
     }
 
index 5e007da858bd591940b62e2a0b7d36e406e77b49..b0cfbdc96c073d715eff3f7afe9400e76e932d28 100644 (file)
@@ -78,6 +78,7 @@ static PySocketModule_APIObject PySocketModule;
 #include "openssl/err.h"
 #include "openssl/rand.h"
 #include "openssl/bio.h"
+#include "openssl/dh.h"
 
 /* SSL error object */
 static PyObject *PySSLErrorObject;
@@ -322,8 +323,19 @@ typedef struct {
     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 */
@@ -333,11 +345,7 @@ typedef struct {
     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 {
@@ -357,19 +365,18 @@ static PyTypeObject PySSLSocket_Type;
 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
@@ -536,7 +543,7 @@ PySSL_SetError(PySSLSocket *obj, int ret, const char *filename, int lineno)
 {
     PyObject *type = PySSLErrorObject;
     char *errstr = NULL;
-    int err;
+    _PySSLError err;
     enum py_ssl_error p = PY_SSL_ERROR_NONE;
     unsigned long e = 0;
 
@@ -544,9 +551,9 @@ PySSL_SetError(PySSLSocket *obj, int ret, const char *filename, int lineno)
     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;
@@ -582,11 +589,12 @@ PySSL_SetError(PySSLSocket *obj, int ret, const char *filename, int lineno)
                     /* 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);
@@ -646,6 +654,7 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock,
     PySSLSocket *self;
     SSL_CTX *ctx = sslctx->ctx;
     long mode;
+    _PySSLError err = { 0 };
 
     self = PyObject_New(PySSLSocket, &PySSLSocket_Type);
     if (self == NULL)
@@ -667,11 +676,7 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock,
         }
         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();
@@ -772,7 +777,7 @@ _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self)
 /*[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;
@@ -802,9 +807,9 @@ _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self)
     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;
@@ -812,9 +817,9 @@ _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self)
         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;
@@ -835,7 +840,8 @@ _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self)
         } 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__);
@@ -2049,7 +2055,7 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
 {
     int len;
     int sockstate;
-    int err;
+    _PySSLError err;
     int nonblocking;
     PySocketSockObject *sock = GET_SOCKET(self);
     _PyTime_t timeout, deadline = 0;
@@ -2100,9 +2106,9 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
     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;
@@ -2110,9 +2116,9 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
         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;
@@ -2129,7 +2135,8 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
         } 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)
@@ -2153,11 +2160,14 @@ _ssl__SSLSocket_pending_impl(PySSLSocket *self)
 /*[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
@@ -2184,7 +2194,7 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, int len, int group_right_1,
     char *mem;
     int count;
     int sockstate;
-    int err;
+    _PySSLError err;
     int nonblocking;
     PySocketSockObject *sock = GET_SOCKET(self);
     _PyTime_t timeout, deadline = 0;
@@ -2245,8 +2255,9 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, int len, int group_right_1,
     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;
@@ -2254,12 +2265,11 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, int len, int group_right_1,
         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;
@@ -2275,7 +2285,8 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, int len, int group_right_1,
         } 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__);
@@ -2311,7 +2322,8 @@ static PyObject *
 _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;
@@ -2349,14 +2361,15 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self)
          */
         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 */
@@ -2371,16 +2384,15 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self)
             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
@@ -2398,9 +2410,9 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self)
             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 */
@@ -2447,6 +2459,30 @@ _ssl__SSLSocket_tls_unique_cb_impl(PySSLSocket *self)
     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*
@@ -2623,6 +2659,7 @@ static PyMethodDef PySSLMethods[] = {
     _SSL__SSLSOCKET_COMPRESSION_METHODDEF
     _SSL__SSLSOCKET_SHUTDOWN_METHODDEF
     _SSL__SSLSOCKET_TLS_UNIQUE_CB_METHODDEF
+    _SSL__SSLSOCKET_VERIFY_CLIENT_POST_HANDSHAKE_METHODDEF
     {NULL, NULL}
 };
 
@@ -2666,7 +2703,7 @@ static PyTypeObject PySSLSocket_Type = {
  */
 
 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;
@@ -2686,9 +2723,13 @@ _set_verify_mode(SSL_CTX *ctx, enum py_ssl_cert_requirements n)
                         "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;
 }
 
@@ -2767,13 +2808,13 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version)
     /* 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;
         }
@@ -2862,6 +2903,11 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version)
     }
 #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;
 }
 
@@ -3116,7 +3162,10 @@ _ssl__SSLContext__set_alpn_protocols_impl(PySSLContext *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:
@@ -3141,7 +3190,7 @@ set_verify_mode(PySSLContext *self, PyObject *arg, void *c)
                         "check_hostname is enabled.");
         return -1;
     }
-    return _set_verify_mode(self->ctx, n);
+    return _set_verify_mode(self, n);
 }
 
 static PyObject *
@@ -3238,6 +3287,42 @@ set_check_hostname(PySSLContext *self, PyObject *arg, void *c)
     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;
@@ -4109,6 +4194,13 @@ static PyGetSetDef context_getsetlist[] = {
                        (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,
@@ -5486,6 +5578,10 @@ PyInit__ssl(void)
     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;
index 6b8ab34d931cd3faa728e6821af2af9c7e76eb9a..669794df012c18fdb12dfac7fd21210566a11466 100644 (file)
@@ -8,13 +8,13 @@
 
 
 /* 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)
 
index c2c63e94db3edb9e9b868d99c6034983327a9600..556d49bb3c83998406806b513518300822ee1307 100644 (file)
@@ -2324,7 +2324,8 @@ static int _pending_callback(void *arg)
 /* 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;
index 43f8034e8e9b58bcf25a35d3c42d550047084916..6b18859a4667bc4b763c00090c4616a70c821dfc 100644 (file)
@@ -237,7 +237,7 @@ static int execfunc(PyObject *m)
 
 #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},
 };
@@ -487,7 +487,7 @@ createfunc_null(PyObject *spec, PyModuleDef *def)
     return NULL;
 }
 
-PyModuleDef_Slot slots_create_null[] = {
+static PyModuleDef_Slot slots_create_null[] = {
     {Py_mod_create, createfunc_null},
     {0, NULL},
 };
index 47e84b9e916d9928b28c89fd81d9b327d72cee68..c504b57b064f3bca1905fc6825c202ef6a77224f 100644 (file)
@@ -234,7 +234,7 @@ static PyMethodDef lock_methods[] = {
 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*/
@@ -495,7 +495,7 @@ static PyMethodDef rlock_methods[] = {
 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*/
index b98e7789b7876af57edb30d62640c9cec6d63406..0647f6bedf1b14052b8f68df52cd7c21782aef08 100644 (file)
@@ -1167,7 +1167,7 @@ _winapi_PeekNamedPipe_impl(PyObject *module, HANDLE handle, int size)
         }
         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
@@ -1176,7 +1176,7 @@ _winapi_PeekNamedPipe_impl(PyObject *module, HANDLE handle, int size)
         if (!ret) {
             return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
         }
-        return Py_BuildValue("ii", navail, nleft);
+        return Py_BuildValue("II", navail, nleft);
     }
 }
 
@@ -1184,14 +1184,14 @@ _winapi_PeekNamedPipe_impl(PyObject *module, HANDLE handle, int size)
 _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;
index eabe2aa06686f22230e47881f8a4901e79be342f..c9206a684efd496d395e23ded28f47211e2a225e 100644 (file)
@@ -329,6 +329,24 @@ _ssl__SSLSocket_tls_unique_cb(PySSLSocket *self, PyObject *Py_UNUSED(ignored))
     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);
 
@@ -1168,4 +1186,4 @@ exit:
 #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]*/
index 5bfbaf0d56346c5022d4ffdc1613c70a9a3a2e34..feb98bc797d19acd52d7449eb2b5b72bf765d4b9 100644 (file)
@@ -673,7 +673,7 @@ PyDoc_STRVAR(_winapi_ReadFile__doc__,
     {"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 *
@@ -681,9 +681,9 @@ _winapi_ReadFile(PyObject *module, PyObject **args, Py_ssize_t nargs, 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,
@@ -889,4 +889,4 @@ _winapi_WriteFile(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject
 exit:
     return return_value;
 }
-/*[clinic end generated code: output=46d6382a6662c4a9 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=6c5cf8865d381c70 input=a9049054013a1b77]*/
index d0735bb5c61676935657a83251431eb13503ead5..174c3fafda3f27342f78666ce241abf4519e2464 100644 (file)
@@ -264,7 +264,7 @@ XML_ParserCreate_MM(const XML_Char *encoding,
                     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
@@ -1076,7 +1076,7 @@ XML_GetFeatureList(void);
 */
 #define XML_MAJOR_VERSION 2
 #define XML_MINOR_VERSION 2
-#define XML_MICRO_VERSION 4
+#define XML_MICRO_VERSION 6
 
 #ifdef __cplusplus
 }
index 8110285649696547e305538b2e6933beb7405871..629483a91b27f41a031ee12276cae8d2eda0c70a 100644 (file)
 
 /* 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
@@ -125,33 +121,35 @@ extern "C" {
 #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;
index 3c5d6e913d6db33600620b2915b5bd027fffa536..e33fdcb0238d727c0c5097481a0548d906dca072 100644 (file)
@@ -116,7 +116,7 @@ extern "C" {
 
 
 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
index 452ae92db2673c95e4646afeb894474af7888f2a..35fdf98bce6ceac2e2de490700bd95889710d298 100644 (file)
@@ -84,7 +84,7 @@ HMODULE _Expat_LoadLibrary(LPCTSTR filename)
   /* 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 */
index 581872df7b499247f46ec3c910bb8a929d71caca..4d6786d7839a2c1a99989930afec3dbe8789a2bc 100644 (file)
  * --------------------------------------------------------------------------
  * 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
  *
@@ -151,6 +157,8 @@ static struct sipkey *sip_tokey(struct sipkey *key, const void *src) {
 } /* 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) {
@@ -158,6 +166,8 @@ 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;
@@ -231,12 +241,19 @@ static uint64_t sip24_final(struct siphash *H) {
 
        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;
        }
 
index 0df68830f05e3a9c6e5f2e97af2d5ec6681a6e6f..c4f3ffc215c9ef9b3f385a9fc6e3199236e99b5a 100644 (file)
@@ -1,4 +1,4 @@
-/* 8c6b2be7c6281da65ce05218fc15c339f02a811706340824ab596aa86e1fd51a (2.2.4+)
+/* 19ac4776051591216f1874e34ee99b6a43a3784c8bd7d70efeb9258dd22b906a (2.2.6+)
                             __  __            _
                          ___\ \/ /_ __   __ _| |_
                         / _ \\  /| '_ \ / _` | __|
@@ -161,6 +161,9 @@ typedef char ICHAR;
 /* 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
@@ -470,7 +473,7 @@ setContext(XML_Parser parser, const XML_Char *context);
 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);
@@ -542,7 +545,7 @@ parserInit(XML_Parser parser, const XML_Char *encodingName);
    : ((*((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;
@@ -552,7 +555,7 @@ struct XML_ParserStruct {
   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;
@@ -644,113 +647,10 @@ struct XML_ParserStruct {
   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)
@@ -776,6 +676,9 @@ static const XML_Char implicitContext[] = {
 };
 
 
+/* 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+ */
@@ -841,6 +744,8 @@ writeRandomBytes_dev_urandom(void * target, size_t count) {
 
 #endif  /* ! defined(_WIN32) && defined(XML_DEV_URANDOM) */
 
+#endif  /* ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM) */
+
 
 #if defined(HAVE_ARC4RANDOM)
 
@@ -942,6 +847,8 @@ generate_hash_secret_salt(XML_Parser parser)
 {
   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);
@@ -990,9 +897,9 @@ static XML_Bool  /* only valid for root parser */
 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
       */
@@ -1042,85 +949,85 @@ parserCreate(const XML_Char *encodingName,
   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;
@@ -1129,85 +1036,85 @@ parserCreate(const XML_Char *encodingName,
 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;
   }
 }
 
@@ -1220,36 +1127,36 @@ XML_ParserReset(XML_Parser parser, const XML_Char *encodingName)
   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;
 }
 
@@ -1262,19 +1169,19 @@ XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName)
      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;
@@ -1331,44 +1238,44 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser,
     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)
@@ -1380,9 +1287,9 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser,
      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 {
@@ -1392,62 +1299,62 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser,
   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;
@@ -1461,8 +1368,8 @@ destroyBindings(BINDING *bindings, XML_Parser parser)
     if (!b)
       break;
     bindings = b->nextTagBinding;
-    FREE(b->uri);
-    FREE(b);
+    FREE(parser, b->uri);
+    FREE(parser, b);
   }
 }
 
@@ -1473,70 +1380,70 @@ XML_ParserFree(XML_Parser parser)
   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
@@ -1546,9 +1453,9 @@ XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD)
     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;
@@ -1561,9 +1468,9 @@ XML_SetReturnNSTriplet(XML_Parser parser, int do_nst)
   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
@@ -1571,10 +1478,10 @@ XML_SetUserData(XML_Parser parser, void *p)
 {
   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
@@ -1583,13 +1490,13 @@ XML_SetBase(XML_Parser parser, const XML_Char *p)
   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;
 }
 
@@ -1598,7 +1505,7 @@ XML_GetBase(XML_Parser parser)
 {
   if (parser == NULL)
     return NULL;
-  return curBase;
+  return parser->m_curBase;
 }
 
 int XMLCALL
@@ -1606,7 +1513,7 @@ XML_GetSpecifiedAttributeCount(XML_Parser parser)
 {
   if (parser == NULL)
     return -1;
-  return nSpecifiedAtts;
+  return parser->m_nSpecifiedAtts;
 }
 
 int XMLCALL
@@ -1614,7 +1521,7 @@ XML_GetIdAttributeIndex(XML_Parser parser)
 {
   if (parser == NULL)
     return -1;
-  return idAttIndex;
+  return parser->m_idAttIndex;
 }
 
 #ifdef XML_ATTR_INFO
@@ -1623,7 +1530,7 @@ XML_GetAttributeInfo(XML_Parser parser)
 {
   if (parser == NULL)
     return NULL;
-  return attInfo;
+  return parser->m_attInfo;
 }
 #endif
 
@@ -1634,22 +1541,22 @@ XML_SetElementHandler(XML_Parser parser,
 {
   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
@@ -1657,7 +1564,7 @@ XML_SetCharacterDataHandler(XML_Parser parser,
                             XML_CharacterDataHandler handler)
 {
   if (parser != NULL)
-    characterDataHandler = handler;
+    parser->m_characterDataHandler = handler;
 }
 
 void XMLCALL
@@ -1665,7 +1572,7 @@ XML_SetProcessingInstructionHandler(XML_Parser parser,
                                     XML_ProcessingInstructionHandler handler)
 {
   if (parser != NULL)
-    processingInstructionHandler = handler;
+    parser->m_processingInstructionHandler = handler;
 }
 
 void XMLCALL
@@ -1673,7 +1580,7 @@ XML_SetCommentHandler(XML_Parser parser,
                       XML_CommentHandler handler)
 {
   if (parser != NULL)
-    commentHandler = handler;
+    parser->m_commentHandler = handler;
 }
 
 void XMLCALL
@@ -1683,22 +1590,22 @@ XML_SetCdataSectionHandler(XML_Parser parser,
 {
   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
@@ -1707,8 +1614,8 @@ XML_SetDefaultHandler(XML_Parser parser,
 {
   if (parser == NULL)
     return;
-  defaultHandler = handler;
-  defaultExpandInternalEntities = XML_FALSE;
+  parser->m_defaultHandler = handler;
+  parser->m_defaultExpandInternalEntities = XML_FALSE;
 }
 
 void XMLCALL
@@ -1717,8 +1624,8 @@ XML_SetDefaultHandlerExpand(XML_Parser parser,
 {
   if (parser == NULL)
     return;
-  defaultHandler = handler;
-  defaultExpandInternalEntities = XML_TRUE;
+  parser->m_defaultHandler = handler;
+  parser->m_defaultExpandInternalEntities = XML_TRUE;
 }
 
 void XMLCALL
@@ -1728,22 +1635,22 @@ XML_SetDoctypeDeclHandler(XML_Parser parser,
 {
   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
@@ -1751,7 +1658,7 @@ XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
                                  XML_UnparsedEntityDeclHandler handler)
 {
   if (parser != NULL)
-    unparsedEntityDeclHandler = handler;
+    parser->m_unparsedEntityDeclHandler = handler;
 }
 
 void XMLCALL
@@ -1759,7 +1666,7 @@ XML_SetNotationDeclHandler(XML_Parser parser,
                            XML_NotationDeclHandler handler)
 {
   if (parser != NULL)
-    notationDeclHandler = handler;
+    parser->m_notationDeclHandler = handler;
 }
 
 void XMLCALL
@@ -1769,22 +1676,22 @@ XML_SetNamespaceDeclHandler(XML_Parser parser,
 {
   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
@@ -1792,7 +1699,7 @@ XML_SetNotStandaloneHandler(XML_Parser parser,
                             XML_NotStandaloneHandler handler)
 {
   if (parser != NULL)
-    notStandaloneHandler = handler;
+    parser->m_notStandaloneHandler = handler;
 }
 
 void XMLCALL
@@ -1800,7 +1707,7 @@ XML_SetExternalEntityRefHandler(XML_Parser parser,
                                 XML_ExternalEntityRefHandler handler)
 {
   if (parser != NULL)
-    externalEntityRefHandler = handler;
+    parser->m_externalEntityRefHandler = handler;
 }
 
 void XMLCALL
@@ -1809,9 +1716,9 @@ XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg)
   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
@@ -1819,7 +1726,7 @@ XML_SetSkippedEntityHandler(XML_Parser parser,
                             XML_SkippedEntityHandler handler)
 {
   if (parser != NULL)
-    skippedEntityHandler = handler;
+    parser->m_skippedEntityHandler = handler;
 }
 
 void XMLCALL
@@ -1829,8 +1736,8 @@ XML_SetUnknownEncodingHandler(XML_Parser parser,
 {
   if (parser == NULL)
     return;
-  unknownEncodingHandler = handler;
-  unknownEncodingHandlerData = data;
+  parser->m_unknownEncodingHandler = handler;
+  parser->m_unknownEncodingHandlerData = data;
 }
 
 void XMLCALL
@@ -1838,7 +1745,7 @@ XML_SetElementDeclHandler(XML_Parser parser,
                           XML_ElementDeclHandler eldecl)
 {
   if (parser != NULL)
-    elementDeclHandler = eldecl;
+    parser->m_elementDeclHandler = eldecl;
 }
 
 void XMLCALL
@@ -1846,7 +1753,7 @@ XML_SetAttlistDeclHandler(XML_Parser parser,
                           XML_AttlistDeclHandler attdecl)
 {
   if (parser != NULL)
-    attlistDeclHandler = attdecl;
+    parser->m_attlistDeclHandler = attdecl;
 }
 
 void XMLCALL
@@ -1854,14 +1761,14 @@ XML_SetEntityDeclHandler(XML_Parser parser,
                          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
@@ -1871,10 +1778,10 @@ XML_SetParamEntityParsing(XML_Parser parser,
   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;
@@ -1890,9 +1797,9 @@ XML_SetHashSalt(XML_Parser parser,
   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;
 }
 
@@ -1904,37 +1811,38 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
       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
@@ -1948,54 +1856,54 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
          *
          * 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 */
@@ -2004,35 +1912,33 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
       }
     }
 
-    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 */
@@ -2055,53 +1961,54 @@ XML_ParseBuffer(XML_Parser parser, int len, int isFinal)
 
   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;
 }
 
@@ -2111,52 +2018,59 @@ XML_GetBuffer(XML_Parser parser, int len)
   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 {
@@ -2164,43 +2078,52 @@ XML_GetBuffer(XML_Parser parser, int len)
         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
@@ -2208,29 +2131,29 @@ XML_StopParser(XML_Parser parser, XML_Bool resumable)
 {
   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;
 }
@@ -2242,36 +2165,36 @@ XML_ResumeParser(XML_Parser parser)
 
   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;
 }
 
@@ -2289,7 +2212,7 @@ XML_GetErrorCode(XML_Parser parser)
 {
   if (parser == NULL)
     return XML_ERROR_INVALID_ARGUMENT;
-  return errorCode;
+  return parser->m_errorCode;
 }
 
 XML_Index XMLCALL
@@ -2297,8 +2220,8 @@ XML_GetCurrentByteIndex(XML_Parser parser)
 {
   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;
 }
 
@@ -2307,8 +2230,8 @@ XML_GetCurrentByteCount(XML_Parser parser)
 {
   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;
 }
 
@@ -2318,12 +2241,12 @@ XML_GetInputContext(XML_Parser parser, int *offset, int *size)
 #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;
@@ -2338,11 +2261,11 @@ XML_GetCurrentLineNumber(XML_Parser 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
@@ -2350,18 +2273,18 @@ XML_GetCurrentColumnNumber(XML_Parser 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.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
@@ -2369,7 +2292,7 @@ XML_MemMalloc(XML_Parser parser, size_t size)
 {
   if (parser == NULL)
     return NULL;
-  return MALLOC(size);
+  return MALLOC(parser, size);
 }
 
 void * XMLCALL
@@ -2377,14 +2300,14 @@ XML_MemRealloc(XML_Parser parser, void *ptr, size_t size)
 {
   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
@@ -2392,65 +2315,110 @@ XML_DefaultCurrent(XML_Parser parser)
 {
   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;
 }
 
@@ -2533,12 +2501,12 @@ XML_GetFeatureList(void)
 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.
@@ -2550,7 +2518,7 @@ storeRawNames(XML_Parser parser)
     */
     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
@@ -2581,8 +2549,8 @@ contentProcessor(XML_Parser parser,
                  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;
@@ -2599,7 +2567,7 @@ externalEntityInitProcessor(XML_Parser parser,
   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);
 }
 
@@ -2610,7 +2578,7 @@ externalEntityInitProcessor2(XML_Parser parser,
                              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,
@@ -2618,28 +2586,28 @@ externalEntityInitProcessor2(XML_Parser parser,
        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);
 }
 
@@ -2651,9 +2619,9 @@ externalEntityInitProcessor3(XML_Parser parser,
 {
   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:
@@ -2662,7 +2630,7 @@ externalEntityInitProcessor3(XML_Parser parser,
       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;
@@ -2674,20 +2642,20 @@ externalEntityInitProcessor3(XML_Parser parser,
     }
     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);
 }
 
@@ -2697,8 +2665,8 @@ externalEntityContentProcessor(XML_Parser parser,
                                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;
@@ -2716,17 +2684,17 @@ doContent(XML_Parser parser,
           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;
 
@@ -2741,18 +2709,18 @@ doContent(XML_Parser parser,
         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;
@@ -2762,7 +2730,7 @@ doContent(XML_Parser parser,
         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;
@@ -2791,9 +2759,9 @@ doContent(XML_Parser parser,
                                               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;
         }
@@ -2815,9 +2783,9 @@ doContent(XML_Parser parser,
             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;
         }
@@ -2827,10 +2795,10 @@ doContent(XML_Parser parser,
           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;
           }
@@ -2838,22 +2806,22 @@ doContent(XML_Parser parser,
           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;
       }
@@ -2864,29 +2832,29 @@ doContent(XML_Parser parser,
         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;
@@ -2904,7 +2872,7 @@ doContent(XML_Parser parser,
             }
             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;
@@ -2918,12 +2886,12 @@ doContent(XML_Parser parser,
         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:
@@ -2935,45 +2903,49 @@ doContent(XML_Parser parser,
         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
@@ -2981,13 +2953,13 @@ doContent(XML_Parser parser,
           *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
@@ -2996,26 +2968,26 @@ doContent(XML_Parser parser,
             /* 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;
@@ -3024,29 +2996,29 @@ doContent(XML_Parser parser,
         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
@@ -3060,16 +3032,16 @@ doContent(XML_Parser parser,
            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;
         }
       }
@@ -3079,19 +3051,19 @@ doContent(XML_Parser parser,
         *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?
@@ -3100,7 +3072,7 @@ doContent(XML_Parser parser,
         *eventPP = end;
         return XML_ERROR_NO_ELEMENTS;
       }
-      if (tagLevel != startTagLevel) {
+      if (parser->m_tagLevel != startTagLevel) {
         *eventPP = end;
         return XML_ERROR_ASYNC_ENTITY;
       }
@@ -3108,26 +3080,26 @@ doContent(XML_Parser parser,
       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;
@@ -3147,13 +3119,13 @@ doContent(XML_Parser parser,
        *
        * 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;
@@ -3166,7 +3138,7 @@ doContent(XML_Parser parser,
 }
 
 /* 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
@@ -3175,15 +3147,15 @@ freeBindings(XML_Parser parser, BINDING *bindings)
   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;
   }
 }
@@ -3203,7 +3175,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
           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 */
@@ -3226,43 +3198,43 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
                                          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,
@@ -3271,25 +3243,25 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
     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;
 
@@ -3306,20 +3278,20 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
 
       /* 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) {
@@ -3343,16 +3315,16 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
   }
 
   /* 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++) {
@@ -3386,33 +3358,33 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
   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) {
@@ -3452,7 +3424,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
 
         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;
         }
 
@@ -3464,7 +3436,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
         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++);
 
@@ -3476,40 +3448,40 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
           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;
@@ -3526,7 +3498,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
   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 */
@@ -3545,7 +3517,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
   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 */
   }
@@ -3558,24 +3530,24 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
   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;
@@ -3653,48 +3625,48 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
   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;
 }
@@ -3708,17 +3680,17 @@ cdataSectionProcessor(XML_Parser parser,
                       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);
     }
   }
@@ -3739,14 +3711,14 @@ doCdataSection(XML_Parser parser,
   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;
@@ -3757,51 +3729,51 @@ doCdataSection(XML_Parser parser,
     *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;
@@ -3835,7 +3807,7 @@ doCdataSection(XML_Parser parser,
     }
 
     *eventPP = s = next;
-    switch (ps_parsing) {
+    switch (parser->m_parsingStatus.parsing) {
     case XML_SUSPENDED:
       *nextPtr = next;
       return XML_ERROR_NONE;
@@ -3858,12 +3830,12 @@ ignoreSectionProcessor(XML_Parser parser,
                        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;
@@ -3885,15 +3857,15 @@ doIgnoreSection(XML_Parser parser,
   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.
      *
@@ -3902,8 +3874,8 @@ doIgnoreSection(XML_Parser parser,
      *
      * LCOV_EXCL_START
      */
-    eventPP = &(openInternalEntities->internalEventPtr);
-    eventEndPP = &(openInternalEntities->internalEventEndPtr);
+    eventPP = &(parser->m_openInternalEntities->internalEventPtr);
+    eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr);
     /* LCOV_EXCL_STOP */
   }
   *eventPP = s;
@@ -3912,11 +3884,11 @@ doIgnoreSection(XML_Parser parser,
   *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;
@@ -3960,27 +3932,27 @@ initializeEncoding(XML_Parser parser)
 #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
@@ -3994,13 +3966,13 @@ processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
   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,
@@ -4012,69 +3984,69 @@ processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
       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;
 }
@@ -4082,7 +4054,7 @@ processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
 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++)
@@ -4090,25 +4062,25 @@ handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName)
     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;
       }
     }
@@ -4127,7 +4099,7 @@ prologInitProcessor(XML_Parser parser,
   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);
 }
 
@@ -4145,14 +4117,14 @@ externalParEntInitProcessor(XML_Parser parser,
 
   /* 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);
   }
 }
@@ -4166,13 +4138,13 @@ entityValueInitProcessor(XML_Parser parser,
   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;
       }
@@ -4188,23 +4160,23 @@ entityValueInitProcessor(XML_Parser parser,
         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
@@ -4214,7 +4186,7 @@ entityValueInitProcessor(XML_Parser parser,
        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;
     }
@@ -4227,7 +4199,7 @@ entityValueInitProcessor(XML_Parser parser,
       return XML_ERROR_SYNTAX;
     }
     start = next;
-    eventPtr = start;
+    parser->m_eventPtr = start;
   }
 }
 
@@ -4240,9 +4212,9 @@ externalParEntProcessor(XML_Parser parser,
   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;
     }
@@ -4264,12 +4236,12 @@ externalParEntProcessor(XML_Parser parser,
   */
   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
@@ -4280,13 +4252,13 @@ entityValueProcessor(XML_Parser parser,
 {
   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;
       }
@@ -4317,9 +4289,9 @@ prologProcessor(XML_Parser parser,
                 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
@@ -4356,19 +4328,19 @@ doProlog(XML_Parser parser,
   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 (;;) {
@@ -4395,7 +4367,7 @@ doProlog(XML_Parser parser,
       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;
         }
@@ -4403,8 +4375,8 @@ doProlog(XML_Parser parser,
            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;
@@ -4418,34 +4390,34 @@ doProlog(XML_Parser parser,
         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;
@@ -4455,34 +4427,34 @@ doProlog(XML_Parser parser,
         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;
       }
@@ -4491,7 +4463,7 @@ doProlog(XML_Parser parser,
       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,
@@ -4499,28 +4471,31 @@ doProlog(XML_Parser parser,
         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,
@@ -4533,10 +4508,10 @@ doProlog(XML_Parser parser,
              */
             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,
@@ -4544,22 +4519,22 @@ doProlog(XML_Parser parser,
             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;
@@ -4568,18 +4543,18 @@ doProlog(XML_Parser parser,
       /* 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,
@@ -4587,8 +4562,8 @@ doProlog(XML_Parser parser,
             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
@@ -4600,55 +4575,55 @@ doProlog(XML_Parser parser,
         }
       }
 #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 {
@@ -4656,37 +4631,37 @@ doProlog(XML_Parser parser,
                     ? 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;
         }
       }
@@ -4696,7 +4671,7 @@ doProlog(XML_Parser parser,
       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);
@@ -4705,26 +4680,26 @@ doProlog(XML_Parser parser,
         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;
         }
       }
@@ -4734,18 +4709,18 @@ doProlog(XML_Parser parser,
         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;
           }
         }
@@ -4757,97 +4732,100 @@ doProlog(XML_Parser parser,
       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;
         }
       }
@@ -4855,36 +4833,36 @@ doProlog(XML_Parser parser,
     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;
@@ -4894,90 +4872,90 @@ doProlog(XML_Parser parser,
         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) {
@@ -4994,45 +4972,45 @@ doProlog(XML_Parser parser,
     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)
@@ -5040,37 +5018,37 @@ doProlog(XML_Parser parser,
         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;
@@ -5086,9 +5064,9 @@ doProlog(XML_Parser parser,
            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;
@@ -5119,8 +5097,8 @@ doProlog(XML_Parser parser,
         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;
@@ -5137,10 +5115,10 @@ doProlog(XML_Parser parser,
           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,
@@ -5162,17 +5140,17 @@ doProlog(XML_Parser parser,
       }
 #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;
@@ -5184,8 +5162,8 @@ doProlog(XML_Parser parser,
     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;
@@ -5196,7 +5174,7 @@ doProlog(XML_Parser parser,
                            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;
@@ -5207,7 +5185,7 @@ doProlog(XML_Parser parser,
       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;
@@ -5244,7 +5222,7 @@ doProlog(XML_Parser parser,
         nameLen = 0;
         for (; name[nameLen++]; );
         dtd->contentStringLen +=  nameLen;
-        if (elementDeclHandler)
+        if (parser->m_elementDeclHandler)
           handleDefault = XML_FALSE;
       }
       break;
@@ -5262,7 +5240,7 @@ doProlog(XML_Parser parser,
       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;
@@ -5272,7 +5250,7 @@ doProlog(XML_Parser parser,
             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;
@@ -5299,31 +5277,31 @@ doProlog(XML_Parser parser,
       }
       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;
@@ -5343,18 +5321,18 @@ epilogProcessor(XML_Parser parser,
                 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;
@@ -5363,28 +5341,28 @@ epilogProcessor(XML_Parser parser,
       *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;
       }
@@ -5392,8 +5370,8 @@ epilogProcessor(XML_Parser parser,
     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;
@@ -5413,21 +5391,21 @@ processInternalEntity(XML_Parser parser, ENTITY *entity,
   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;
@@ -5438,26 +5416,26 @@ processInternalEntity(XML_Parser parser, ENTITY *entity,
 
 #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;
@@ -5473,7 +5451,7 @@ internalEntityProcessor(XML_Parser parser,
   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;
 
@@ -5485,44 +5463,44 @@ internalEntityProcessor(XML_Parser parser,
 
 #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);
   }
 }
 
@@ -5532,7 +5510,7 @@ errorProcessor(XML_Parser parser,
                const char *UNUSED_P(end),
                const char **UNUSED_P(nextPtr))
 {
-  return errorCode;
+  return parser->m_errorCode;
 }
 
 static enum XML_Error
@@ -5556,7 +5534,7 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
                      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);
@@ -5564,12 +5542,12 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
     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:
       {
@@ -5577,8 +5555,8 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
         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
@@ -5628,25 +5606,25 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool 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)
@@ -5656,19 +5634,19 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
         }
         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
@@ -5686,25 +5664,25 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
              * 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;
@@ -5725,8 +5703,8 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
        *
        * 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 */
     }
@@ -5741,12 +5719,12 @@ storeEntityValue(XML_Parser parser,
                  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
@@ -5762,10 +5740,10 @@ storeEntityValue(XML_Parser parser,
     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) {
@@ -5773,28 +5751,28 @@ storeEntityValue(XML_Parser parser,
           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,
@@ -5813,7 +5791,7 @@ storeEntityValue(XML_Parser parser,
         else {
           entity->open = XML_TRUE;
           result = storeEntityValue(parser,
-                                    internalEncoding,
+                                    parser->m_internalEncoding,
                                     (char *)entity->textPtr,
                                     (char *)(entity->textPtr
                                              + entity->textLen));
@@ -5826,7 +5804,7 @@ storeEntityValue(XML_Parser parser,
 #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:
@@ -5855,8 +5833,8 @@ storeEntityValue(XML_Parser parser,
         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;
         }
@@ -5880,13 +5858,13 @@ storeEntityValue(XML_Parser parser,
       }
       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:
@@ -5897,8 +5875,8 @@ storeEntityValue(XML_Parser parser,
        *
        * 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 */
@@ -5907,7 +5885,7 @@ storeEntityValue(XML_Parser parser,
   }
 endEntityValue:
 #ifdef XML_DTD
-  prologState.inEntityValue = oldInEntityValue;
+  parser->m_prologState.inEntityValue = oldInEntityValue;
 #endif /* XML_DTD */
   return result;
 }
@@ -5942,25 +5920,25 @@ reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
   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;
 }
 
@@ -5969,20 +5947,20 @@ reportComment(XML_Parser parser, const ENCODING *enc,
               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;
 }
 
@@ -5994,9 +5972,9 @@ reportDefault(XML_Parser parser, const ENCODING *enc,
     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
@@ -6015,20 +5993,20 @@ reportDefault(XML_Parser parser, const ENCODING *enc,
        *
        * 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));
 }
 
 
@@ -6050,16 +6028,18 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata,
   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;
@@ -6079,7 +6059,7 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata,
 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)) {
@@ -6110,7 +6090,7 @@ static ATTRIBUTE_ID *
 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')))
@@ -6127,7 +6107,7 @@ getAttributeId(XML_Parser parser, const ENCODING *enc,
     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)
@@ -6174,20 +6154,20 @@ getAttributeId(XML_Parser parser, const ENCODING *enc,
 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.
          *
@@ -6230,18 +6210,18 @@ getContext(XML_Parser parser)
        */
       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;
   }
@@ -6255,73 +6235,73 @@ getContext(XML_Parser parser)
       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++;
     }
@@ -6686,7 +6666,6 @@ hash(XML_Parser parser, KEY s)
 {
   struct siphash state;
   struct sipkey key;
-  (void)sip_tobin;
   (void)sip24_valid;
   copy_salt_to_sipkey(parser, &key);
   sip24_init(&state, &key);
@@ -7006,8 +6985,8 @@ poolGrow(STRING_POOL *pool)
     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) {
@@ -7085,12 +7064,12 @@ poolGrow(STRING_POOL *pool)
 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;
@@ -7100,13 +7079,13 @@ nextScaffoldPart(XML_Parser parser)
     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;
@@ -7137,7 +7116,7 @@ build_node(XML_Parser parser,
            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) {
@@ -7171,14 +7150,14 @@ build_node(XML_Parser parser,
 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;
 
@@ -7195,7 +7174,7 @@ getElementType(XML_Parser parser,
                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;
 
index 007aed0640a2ef3dd8096804cb9f434c6fd2c991..6b415d83972ca605a97c27eb36f75cdab37165c1 100644 (file)
 */
 
 #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"
@@ -57,7 +66,6 @@
   { PREFIX(prologTok), PREFIX(contentTok), \
     PREFIX(cdataSectionTok) IGNORE_SECTION_TOK_VTABLE }, \
   { PREFIX(attributeValueTok), PREFIX(entityValueTok) }, \
-  PREFIX(sameName), \
   PREFIX(nameMatchesAscii), \
   PREFIX(nameLength), \
   PREFIX(skipS), \
@@ -354,7 +362,7 @@ enum {  /* UTF8_cvalN is value of masked first byte of N byte sequence */
 };
 
 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;
@@ -405,18 +413,22 @@ utf8_toUtf8(const ENCODING *UNUSED_P(enc),
   }
 
   /* 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;
@@ -1452,9 +1464,8 @@ unknown_toUtf8(const ENCODING *enc,
         return XML_CONVERT_OUTPUT_EXHAUSTED;
       (*fromP)++;
     }
-    do {
-      *(*toP)++ = *utf8++;
-    } while (--n != 0);
+    memcpy(*toP, utf8, n);
+    *toP += n;
   }
 }
 
index 6d31879b331d83bc96b857e778f14ca051773c04..50926f38ab323ea24a6f6db451a0061bb743a062 100644 (file)
@@ -167,9 +167,6 @@ enum XML_Convert_Result {
 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 *,
@@ -260,8 +257,6 @@ struct encoding {
 #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))
 
index 93328b841a168bba00f7ec6ec704ed623bb1b238..4d9ae7dc3896b8393f8b41eeb98becdcb3bcaa46 100644 (file)
@@ -74,6 +74,7 @@
       *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); \
@@ -602,7 +604,7 @@ PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end,
           return XML_TOK_INVALID;
         }
       }
-    /* fall through */
+      /* fall through */
     case BT_EQUALS:
       {
         int open;
@@ -1442,6 +1444,7 @@ PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end,
     case BT_NMSTRT:
       if (!(BYTE_TO_ASCII(enc, ptr) & ~0x7f))
         break;
+      /* fall through */
     default:
       switch (BYTE_TO_ASCII(enc, ptr)) {
       case 0x24: /* $ */
@@ -1653,87 +1656,14 @@ PREFIX(predefinedEntityName)(const ENCODING *UNUSED_P(enc), const char *ptr,
   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.
        */
index f577fd3ab4ec3baeabcd09499d62229d457ad273..43e45ef7aad5c1e4bd6786bf608735888e1e81e5 100644 (file)
@@ -156,7 +156,7 @@ grp_getgrnam_impl(PyObject *module, PyObject *name)
         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);
index fe9da7d3af2d804c9ed483b2c3bfa538d66bf3e1..01d2118339e3dd563445816d6eb90ac436279f71 100644 (file)
@@ -466,7 +466,7 @@ static PyGetSetDef MD5_getseters[] = {
 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*/
index ebef501d6749157dd4ce2720e0189adaa174e689..721e5ed32ea2f70433155a356147071c3553d4da 100644 (file)
@@ -1008,7 +1008,7 @@ To map anonymous memory, pass -1 as the fileno (both versions).");
 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 */
index 5f0505c8a7b4b43323edf03ed3617acae41ec05d..da1d1631451fc77a1445d1903f3aa9ab3c6d01b9 100644 (file)
@@ -969,7 +969,7 @@ oss_getattro(oss_audio_t *self, PyObject *nameobj)
 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*/
@@ -1001,7 +1001,7 @@ static PyTypeObject OSSAudioType = {
 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*/
index 9c05acb24f0c9a24a71162adcf1a14acd097a537..af6b9dc4ef037e57d0e356383d378eec7252d01f 100644 (file)
@@ -7924,11 +7924,10 @@ os_read_impl(PyObject *module, int fd, Py_ssize_t length)
 
 #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) {
@@ -7953,11 +7952,9 @@ iov_setup(struct iovec **iov, Py_buffer **buf, PyObject *seq, Py_ssize_t cnt, in
         }
         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);
@@ -8166,12 +8163,20 @@ posix_sendfile(PyObject *self, PyObject *args, PyObject *kwdict)
             }
             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
             }
         }
@@ -8192,13 +8197,9 @@ posix_sendfile(PyObject *self, PyObject *args, PyObject *kwdict)
             }
             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
             }
         }
     }
index bbef2de9c52253287f7dc068d798d33044f674c8..21c2b546f6ddaf68ede187f6b756ebaceb153dca 100644 (file)
@@ -163,7 +163,7 @@ pwd_getpwnam_impl(PyObject *module, PyObject *arg)
         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);
index 47c3e86c209d9c1a1d1d1627610ed6d9585e65a7..aa21d93c115aaf4d3f0b0c7443f384fefbe02270 100644 (file)
@@ -1887,6 +1887,11 @@ MODULE_INITFUNC(void)
     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);
index 7e81f1904c0a6f7e6a35d88d0d357519a86ba93d..5438b697ddcddc7f841e77663382818bbff4710b 100644 (file)
@@ -1302,14 +1302,17 @@ newPyEpoll_Object(PyTypeObject *type, int sizehint, int flags, SOCKET fd)
 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;
     }
 
index d5065ce13490862c1915c3c78fe42cb3c4070a29..cd123586264c8e66025860341d16cd0eedac48bc 100644 (file)
@@ -443,7 +443,7 @@ static PyGetSetDef SHA1_getseters[] = {
 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*/
index 8f067f182c7788ecefd2737220a4ed304b85e407..70c49b5da2ee7c5dfb4dcc0c6d1450b1aeddc0a3 100644 (file)
@@ -530,7 +530,7 @@ static PyMemberDef SHA_members[] = {
 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*/
@@ -564,7 +564,7 @@ static PyTypeObject SHA224type = {
 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*/
index 17775ae57b6cf061b31f2307aa68de01cd9ec321..da0cb5775edbe3afba52c76904238852ddf9c080 100644 (file)
@@ -599,7 +599,7 @@ static PyMemberDef SHA_members[] = {
 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*/
@@ -633,7 +633,7 @@ static PyTypeObject SHA384type = {
 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*/
index ff73a3fbfa2b92bcfba2975a492f3a915ffb1ac9..ed3166740278b487591ca44d65bd99727bf53a6a 100644 (file)
@@ -1834,7 +1834,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
         const char *interfaceName;
         int protoNumber;
         int hatype = 0;
-        int pkttype = 0;
+        int pkttype = PACKET_HOST;
         Py_buffer haddr = {NULL, NULL};
 
         if (!PyTuple_Check(args)) {
@@ -1865,7 +1865,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *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;
         }
@@ -2742,7 +2742,7 @@ PyDoc_STRVAR(bind_doc,
 \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.
index dba3d0452acbb0c92878ad6afdb8601da0bb85a9..f66f098740b29574eb564fd25f21952a9b48ba7c 100644 (file)
@@ -433,6 +433,12 @@ gettmarg(PyObject *args, struct tm *p)
                           &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;
@@ -648,6 +654,7 @@ time_strftime(PyObject *self, PyObject *args)
         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;
         }
     }
index 9e71e018e21590230334c6012876109a16ac74ba..7c9aca9d320125a5fb0db92958bd0e703ac35a22 100644 (file)
@@ -681,15 +681,19 @@ nfc_nfkc(PyObject *self, PyObject *input, int k)
       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++;
           }
index 6c6c86cd44a9bc2f550e0fbe8192e844193c9f30..252572024091c91417cbeab3d6928a3eb1809939 100644 (file)
@@ -1477,7 +1477,7 @@ PySequence_Check(PyObject *s)
 {
     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;
 }
 
index 4950d01a6e4907349ede0a70ad137c5635b6f5b3..04ebe0b701e6e3b20a27b5323b90d6c798d921b2 100644 (file)
@@ -446,7 +446,7 @@ formatfloat(PyObject *v, int flags, int prec, int type,
     result = PyBytes_FromStringAndSize(p, len);
     PyMem_Free(p);
     *p_result = result;
-    return str;
+    return result != NULL ? str : NULL;
 }
 
 static PyObject *
@@ -813,8 +813,8 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len,
                     goto error;
             }
 
-            if (fmtcnt < 0) {
-                /* last writer: disable writer overallocation */
+            if (fmtcnt == 0) {
+                /* last write: disable writer overallocation */
                 writer.overallocate = 0;
             }
 
@@ -1046,7 +1046,7 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len,
 
         /* 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) {
index d1c3abf486158a0ee3d8b9e5f53437257dce7e53..c37563c6a4743e8fa1a66875955a4349ad5ce8b3 100644 (file)
@@ -114,7 +114,7 @@ PyCode_New(int argcount, int kwonlyargcount,
 {
     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 ||
@@ -150,15 +150,29 @@ PyCode_New(int argcount, int kwonlyargcount,
         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++) {
@@ -166,7 +180,12 @@ PyCode_New(int argcount, int kwonlyargcount,
             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;
index ce9edabd8959ebf77a40e96ca71e6571540269d9..d3ae07bfd3f44d17f5469e56972d81d4ed124540 100644 (file)
@@ -59,15 +59,8 @@ struct _dictkeysobject {
        - 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 */
index ddd05826ea5fbae30372f24616329e2047fb1473..b55e49c4c9f78966380a68486f275aeb1b6e33a4 100644 (file)
@@ -237,6 +237,8 @@ static Py_ssize_t lookdict_split(PyDictObject *mp, PyObject *key,
 
 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. */
@@ -300,7 +302,7 @@ PyDict_Fini(void)
             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
@@ -318,21 +320,21 @@ dk_get_index(PyDictKeysObject *keys, Py_ssize_t i)
     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);
@@ -348,23 +350,23 @@ dk_set_index(PyDictKeysObject *keys, Py_ssize_t i, Py_ssize_t ix)
     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;
     }
@@ -424,8 +426,8 @@ static PyDictKeysObject empty_keys_struct = {
         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 };
@@ -533,7 +535,6 @@ static PyDictKeysObject *new_keys_object(Py_ssize_t size)
     }
     else {
         dk = PyObject_MALLOC(sizeof(PyDictKeysObject)
-                             - Py_MEMBER_SIZE(PyDictKeysObject, dk_indices)
                              + es * size
                              + sizeof(PyDictKeyEntry) * usable);
         if (dk == NULL) {
@@ -546,7 +547,7 @@ static PyDictKeysObject *new_keys_object(Py_ssize_t size)
     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;
 }
@@ -2483,7 +2484,7 @@ dict_merge(PyObject *a, PyObject *b, int override)
         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 */
@@ -3086,7 +3087,6 @@ _PyDict_SizeOf(PyDictObject *mp)
        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;
@@ -3096,7 +3096,6 @@ Py_ssize_t
 _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));
 }
index c3c0949189d85106d29aa581ce9a1a733f3a8158..3864cec97a0a0fd42cd6f7d9e4635fd09e57fce7 100644 (file)
@@ -5302,7 +5302,7 @@ long_from_bytes(PyTypeObject *type, PyObject *args, PyObject *kwds)
         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));
     }
index c5979329647bf4ad9fa8d409f1572291c152d0bb..0fba90c43c144e69b0d6b732b9476baa61c800ab 100644 (file)
@@ -34,7 +34,7 @@ bad_traverse_test(PyObject *self, void *arg) {
 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 */
 };
 
@@ -761,7 +761,7 @@ The name must be a string; the optional doc argument can have any type.");
 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 */
index d28c9133b4b700b56fb1a03d4a03d085e473eb9d..6307ee0423dc299e6a65e460b4ce24eea97547d2 100644 (file)
@@ -207,7 +207,7 @@ SimpleNamespace(**kwargs)");
 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 */
index defff5579699e11c79849bca431d8c446ae29c0f..fdd41a61681f6411c608b705e92b16a4a98908de 100644 (file)
@@ -387,8 +387,9 @@ PyObject_Print(PyObject *op, FILE *fp, int flags)
             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);
index 65f90e83434edde74b23c792c2af79069063596b..26f15794418b51daaf0583143d4df043b81298d3 100644 (file)
@@ -67,7 +67,7 @@ Linked-List API
 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:
@@ -444,7 +444,7 @@ Potential Optimizations
   - 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__().
index 8f5fc434bd49550b65393ada5d377c1af71d87ea..2fc70cd8d7b7c5bf791d2c88dd914315d88fe5e4 100644 (file)
@@ -618,11 +618,11 @@ range_repr(rangeobject *r)
     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)
index 69b1878fd8f2c0030cef89aa72963a1f0a098571..ed2d40064adc4f827bec36ca1b41960819ebb9d5 100644 (file)
@@ -2235,6 +2235,9 @@ type_init(PyObject *cls, PyObject *args, PyObject *kwds)
     /* 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;
@@ -2745,6 +2748,15 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
     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)
@@ -2752,8 +2764,6 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
     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;
@@ -2763,8 +2773,6 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
     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) {
@@ -2996,6 +3004,7 @@ type_getattro(PyTypeObject *type, PyObject *name)
     PyTypeObject *metatype = Py_TYPE(type);
     PyObject *meta_attribute, *attribute;
     descrgetfunc meta_get;
+    PyObject* res;
 
     if (!PyUnicode_Check(name)) {
         PyErr_Format(PyExc_TypeError,
@@ -3017,6 +3026,7 @@ type_getattro(PyTypeObject *type, PyObject *name)
     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)) {
@@ -3024,10 +3034,11 @@ type_getattro(PyTypeObject *type, PyObject *name)
              * 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
@@ -3035,6 +3046,7 @@ type_getattro(PyTypeObject *type, PyObject *name)
     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);
@@ -3042,11 +3054,12 @@ type_getattro(PyTypeObject *type, PyObject *name)
         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;
     }
 
index bed7d419b0701f7af0abde9c9325b9babbaf86c0..972423e78da8c41d13e6be988abede495e29c3a7 100644 (file)
@@ -6903,8 +6903,6 @@ unicode_encode_ucs1(PyObject *unicode,
                     str = _PyBytesWriter_WriteBytes(&writer, str,
                                                     PyBytes_AS_STRING(rep),
                                                     PyBytes_GET_SIZE(rep));
-                    if (str == NULL)
-                        goto onError;
                 }
                 else {
                     assert(PyUnicode_Check(rep));
@@ -6940,6 +6938,9 @@ unicode_encode_ucs1(PyObject *unicode,
                         }
                     }
                 }
+                if (str == NULL)
+                    goto onError;
+
                 pos = newpos;
                 Py_CLEAR(rep);
             }
index a7c8fa3d092a6437a1d0c760c7b503c548ca226b..0487743b59aaacd2980b64ab455279bbd3f77c8f 100644 (file)
--- a/PC/_msi.c
+++ b/PC/_msi.c
@@ -340,6 +340,10 @@ msierror(int status)
     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';
     }
@@ -563,6 +567,9 @@ summary_getproperty(msiobj* si, PyObject *args)
         &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);
     }
index d11df437b97eb382852bec22e4a9bdf7e68eb166..56f16eae4043cedfa53e1b714df1359fe1331cf0 100644 (file)
@@ -61,6 +61,7 @@ debug(wchar_t * format, ...)
     if (log_fp != NULL) {
         va_start(va, format);
         vfwprintf_s(log_fp, format, va);
+        va_end(va);
     }
 }
 
@@ -83,6 +84,7 @@ error(int rc, wchar_t * format, ... )
 
     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);
index 04fe61e89618bd78a16353b70654e804f94002a0..019880264bee92946deea391d0a765a29c061f9f 100644 (file)
@@ -172,6 +172,11 @@ private:
             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;
index 4e5cbc6f6cb547a349fed32c8a36b85488044db3..639bf86a83dfc7bf2d60264fdb504b0d00f06126 100644 (file)
@@ -41,7 +41,7 @@ echo.Fetching external libraries...
 \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
index a146e656187d54433d23142a8efa6b9ac4914096..59162fc57e25508c4bfa38ae85145cb44d78befe 100644 (file)
@@ -49,7 +49,7 @@
     <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
index 9f3c2e343c032cf7af9a68149cacee6bbb317e68..476af717451bee33eb0ffe932ff3aa54e58ae641 100644 (file)
@@ -114,15 +114,21 @@ _PyOS_WindowsConsoleReadline(HANDLE hStdIn)
     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();
index 1f467d63c41e24e10e908dd6003dc3f028cfd773..a1580e6751e4c692ee355208f79b91ac3d889fad 100644 (file)
@@ -225,7 +225,7 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret,
         }
         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;
@@ -246,18 +246,19 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret,
             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,
index ede7f4fd990ca73e2cd24e88a39ede3a2450e03c..51175cdb55e6a20f03ee6121efcca2e580267bd2 100644 (file)
@@ -3267,6 +3267,8 @@ alias_for_import_name(struct compiling *c, const node *n, int store)
             break;
         case STAR:
             str = PyUnicode_InternFromString("*");
+            if (!str)
+                return NULL;
             if (PyArena_AddPyObject(c->c_arena, str) < 0) {
                 Py_DECREF(str);
                 return NULL;
index 5ee08e67e7fb80606dcce8a3a29a1e256b3068aa..d7b0bbd331dacc37e5608e59dab54a5b050561d9 100644 (file)
@@ -2343,6 +2343,11 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start)
                 }
             }
             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);
index 646f6a5bea9ca80c4571692a25c5562810d6744e..50834f82c74607c25a9fc3eb3f9c1bf0af025ba8 100644 (file)
@@ -1155,11 +1155,18 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
            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
index 78c0524a1d8a2ad7dbdd8a555ba2d1356ba49a89..a08936dda8732d2f6058eb54a5877b4a3068bf6f 100644 (file)
@@ -97,6 +97,7 @@ PyErr_SetObject(PyObject *exception, PyObject *value)
             fixed_value = _PyErr_CreateException(exception, value);
             Py_XDECREF(value);
             if (fixed_value == NULL) {
+                Py_DECREF(exc_value);
                 return;
             }
 
index b9638d2df513bee4c3dc4f049a6a8716b536c629..b8e489125e3c69ff760e0283a5023e2301e3e528 100644 (file)
@@ -132,7 +132,7 @@ check_force_ascii(void)
     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;
     }
index d3ef650e6ce62f6fa384fd3b89a4bf3b27c350fa..d6772c593877cd9fbbef2382799a6c6183a28883 100644 (file)
@@ -28,16 +28,17 @@ unknown_presentation_type(Py_UCS4 presentation_type,
 }
 
 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
@@ -117,8 +118,8 @@ is_sign_element(Py_UCS4 c)
 /* 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
 };
@@ -314,7 +315,7 @@ parse_internal_render_format_spec(PyObject *format_spec,
             }
             /* fall through */
         default:
-            invalid_comma_type(format->type);
+            invalid_thousands_separator_type(format->thousands_separators, format->type);
             return 0;
         }
     }
index 4d27418a84ba0779efa7fb50bc591b7ee3505eda..594b150deeb1f0d0e637cbf63c8d8debd943ed02 100644 (file)
@@ -2281,7 +2281,9 @@ skipitem(const char **p_format, va_list *p_va, int flags)
                         (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;
index 64d0c52e4879583c2aec5cb806c4723eb04184cc..1c635602340a8554dfc4cf7c689504fa254437f3 100644 (file)
@@ -391,6 +391,8 @@ _Py_string_to_number_with_underscores(
     char *dup, *end;
     PyObject *result;
 
+    assert(s[orig_len] == '\0');
+
     if (strchr(s, '_') == NULL) {
         return innerfunc(s, orig_len, arg);
     }
@@ -1059,8 +1061,6 @@ format_float_short(double d, char format_code,
         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;
index e644e2a6d5710dcc9a93d192ddcb7a39820c4b5d..fa0221e3ee2b1e3e69037521430834f6ce5f83a2 100644 (file)
@@ -408,7 +408,6 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit,
             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 &&
@@ -422,6 +421,7 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit,
     }
     flush_io();
     if (v == NULL) {
+        Py_CLEAR(m);
         PyErr_Print();
         goto done;
     }
@@ -430,7 +430,7 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit,
   done:
     if (set_file_name && PyDict_DelItemString(d, "__file__"))
         PyErr_Clear();
-    Py_DECREF(m);
+    Py_XDECREF(m);
     return ret;
 }
 
@@ -1041,27 +1041,31 @@ run_pyc_file(FILE *fp, const char *filename, PyObject *globals,
         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 *
@@ -1324,7 +1328,7 @@ err_input(perrdetail *err)
     errtype = PyExc_SyntaxError;
     switch (err->error) {
     case E_ERROR:
-        return;
+        goto cleanup;
     case E_SYNTAX:
         errtype = PyExc_IndentationError;
         if (err->expected == INDENT)
@@ -1333,6 +1337,10 @@ err_input(perrdetail *err)
             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";
index 6165cfe162eac0690ad68795f70babf05c0a2397..90b07efa0334cc44f6b7cfe2562f0224ef936c05 100644 (file)
@@ -628,8 +628,10 @@ update_symbols(PyObject *symbols, PyObject *scopes,
         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);
index d9620675f7475ea1f7fde73637c15dec7c0d613d..145d028ba353fd586347d2ef0f921e9151eeca7c 100644 (file)
@@ -413,16 +413,21 @@ tb_displayline(PyObject *f, PyObject *filename, int lineno, PyObject *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;
 }
@@ -446,15 +451,11 @@ tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit)
         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;
@@ -462,7 +463,8 @@ tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit)
             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,
@@ -473,7 +475,7 @@ tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit)
         }
         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;
index 1dab9c80bc8d963403db097cd164588e8cd2b487..698d9db3a9a47ba56d89cab221202f773822698d 100644 (file)
@@ -1,4 +1,4 @@
-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
@@ -9,6 +9,10 @@ This is Python version 3.6.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
@@ -186,6 +190,8 @@ If the failure persists and appears to be a problem with Python rather than
 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
 ----------------------------
index aac9b5c1b8a77bb1ee30853604f0f74ab7e07f2a..6d3d52f397d400fa3573e517ca9642750daa76c8 100755 (executable)
@@ -270,12 +270,13 @@ class PyObjectPtr(object):
 
     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):
@@ -349,7 +350,9 @@ class PyObjectPtr(object):
         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
@@ -617,7 +620,10 @@ class PyCFunctionObjectPtr(PyObjectPtr):
 
     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():
@@ -730,7 +736,7 @@ class PyDictObjectPtr(PyObjectPtr):
         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)
@@ -1340,13 +1346,13 @@ class wrapperobject(PyObjectPtr):
         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):
@@ -1541,6 +1547,7 @@ class Frame(object):
             return False
 
         if caller == 'PyCFunction_Call':
+            arg_name = 'func'
             # Within that frame:
             #   "func" is the local containing the PyObject* of the
             # PyCFunctionObject instance
@@ -1548,24 +1555,35 @@ class Frame(object):
             #   "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
index b0751a1ffc1dcdee9c2302d3ce48b5e64376b18b..63d52d1f46e561438b5375dfd87860d6ae27fd15 100755 (executable)
@@ -89,7 +89,7 @@ def generate():
                          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
@@ -109,7 +109,8 @@ def make(filename, outfile):
         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)
@@ -199,7 +200,8 @@ def make(filename, outfile):
     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)
 
index 7023b6118199b16a1b537df3ce453154a22d2800..741b67c793a50a0a07cc8b6b1fc1809f779511d2 100644 (file)
@@ -66,6 +66,14 @@ Before building the installer, download extra build dependencies using
 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:
 
index d586e34fec822f95d1a56fea3de7e5cbc0584bf8..548fdd0cc432eecf4d15ddbaee03bbeb321e5c77 100644 (file)
@@ -9,6 +9,9 @@ from distutils.errors import DistutilsPlatformError
 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
 
index f3241cd6071c80c11c1eb0180e4ad38ba9c41aee..2264c9331042e540fadeea203fdef8b89d6a0d96 100755 (executable)
@@ -41,30 +41,31 @@ import tarfile
 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',
@@ -76,7 +77,7 @@ parser = argparse.ArgumentParser(
 parser.add_argument(
     '--debug',
     action='store_true',
-    help="Enable debug mode",
+    help="Enable debug logging",
 )
 parser.add_argument(
     '--disable-ancient',
@@ -119,15 +120,32 @@ parser.add_argument(
     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):
@@ -135,21 +153,21 @@ 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)
@@ -258,24 +276,31 @@ class AbstractBuilder(object):
         """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:
@@ -341,6 +366,8 @@ class BuildOpenSSL(AbstractBuilder):
     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):
@@ -379,57 +406,63 @@ def main():
 
     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:
index 5fadcb1e44575ead0491bcbcf351fca7be54837b..5e29449ae2a15342978adda6dfa95d0f930b68a6 100644 (file)
@@ -1,6 +1,6 @@
-# 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,
@@ -12,9 +12,9 @@
 # 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
@@ -288,71 +288,3 @@ AS_VAR_COPY([$1], [pkg_cv_][$1])
 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
-
index 986ab871bd53ec32476440e602fa883c43a70322..bfa4b83cd6c0e2a07ebe34f7e17841c2e070180b 100755 (executable)
--- a/configure
+++ b/configure
@@ -784,6 +784,7 @@ infodir
 docdir
 oldincludedir
 includedir
+runstatedir
 localstatedir
 sharedstatedir
 sysconfdir
@@ -895,6 +896,7 @@ datadir='${datarootdir}'
 sysconfdir='${prefix}/etc'
 sharedstatedir='${prefix}/com'
 localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
 includedir='${prefix}/include'
 oldincludedir='/usr/include'
 docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1147,6 +1149,15 @@ do
   | -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=* \
@@ -1284,7 +1295,7 @@ fi
 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.
@@ -1437,6 +1448,7 @@ Fine tuning of the installation directories:
   --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]
@@ -2746,9 +2758,9 @@ HAS_GIT=no-repository
 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=""
@@ -6618,6 +6630,13 @@ if test "$Py_LTO" = 'true' ; then
       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.
@@ -11343,7 +11362,7 @@ for ac_func in alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
  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>
 "
@@ -15664,77 +15700,6 @@ $as_echo "#define HAVE_BROKEN_POLL 1" >>confdefs.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; }
@@ -16789,7 +16754,6 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 
     #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;
index 338be3b9a6bd4454c7d326a8c9f49366d9849bbd..3f2459ab7100a12bba9e128097feadf089815cf1 100644 (file)
@@ -37,9 +37,9 @@ HAS_GIT=no-repository
 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=""
@@ -1347,6 +1347,13 @@ if test "$Py_LTO" = 'true' ; then
       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.
@@ -3472,7 +3479,7 @@ AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
  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 \
@@ -3488,6 +3495,13 @@ AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
  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.), ,
@@ -4890,11 +4904,6 @@ then
       [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, [
@@ -5444,7 +5453,6 @@ AC_LINK_IFELSE(
   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;
@@ -5456,7 +5464,7 @@ AC_MSG_RESULT($have_stdatomic_h)
 
 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
index 6cef7b37b7b6ca0c937b1254aaf8b7321355af72..2fbbb6d20dd9498ca35d12d40da59259c25a99f1 100644 (file)
 /* 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. */