diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 663a1189..0bc0ebf4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,15 +1,23 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.3.4 + rev: v0.6.7 hooks: - id: ruff - name: Run Ruff on Lib/test/ + name: Run Ruff (lint) on Doc/ + args: [--exit-non-zero-on-fix] + files: ^Doc/ + - id: ruff + name: Run Ruff (lint) on Lib/test/ args: [--exit-non-zero-on-fix] files: ^Lib/test/ - id: ruff - name: Run Ruff on Argument Clinic + name: Run Ruff (lint) on Argument Clinic args: [--exit-non-zero-on-fix, --config=Tools/clinic/.ruff.toml] files: ^Tools/clinic/|Lib/test/test_clinic.py + - id: ruff-format + name: Run Ruff (format) on Doc/ + args: [--check] + files: ^Doc/ - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.5.0 diff --git a/.readthedocs.yml b/.readthedocs.yml index 898a9ae8..250d7ea0 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -8,11 +8,14 @@ sphinx: configuration: Doc/conf.py build: - os: ubuntu-22.04 + os: ubuntu-24.04 tools: python: "3" commands: + - asdf plugin add uv + - asdf install uv latest + - asdf global uv latest - make -C Doc venv html - mkdir _readthedocs - mv Doc/build/html _readthedocs/html diff --git a/Doc/.ruff.toml b/Doc/.ruff.toml new file mode 100644 index 00000000..111ce03b --- /dev/null +++ b/Doc/.ruff.toml @@ -0,0 +1,42 @@ +target-version = "py312" # Align with the version in oldest_supported_sphinx +fix = true +output-format = "full" +line-length = 79 +extend-exclude = [ + "includes/*", + # Temporary exclusions: + "tools/extensions/pyspecific.py", +] + +[lint] +preview = true +select = [ + "C4", # flake8-comprehensions + "B", # flake8-bugbear + "E", # pycodestyle + "F", # pyflakes + "FA", # flake8-future-annotations + "FLY", # flynt + "FURB", # refurb + "G", # flake8-logging-format + "I", # isort + "LOG", # flake8-logging + "N", # pep8-naming + "PERF", # perflint + "PGH", # pygrep-hooks + "PT", # flake8-pytest-style + "TCH", # flake8-type-checking + "UP", # pyupgrade + "W", # pycodestyle +] +ignore = [ + "E501", # Ignore line length errors (we use auto-formatting) +] + +[format] +preview = true +quote-style = "preserve" +docstring-code-format = true +exclude = [ + "tools/extensions/lexers/*", +] diff --git a/Doc/Makefile b/Doc/Makefile index 1cbfc722..4a704ad5 100644 --- a/Doc/Makefile +++ b/Doc/Makefile @@ -6,6 +6,7 @@ # You can set these variables from the command line. PYTHON = python3 VENVDIR = ./venv +UV = uv SPHINXBUILD = PATH=$(VENVDIR)/bin:$$PATH sphinx-build BLURB = PATH=$(VENVDIR)/bin:$$PATH blurb JOBS = auto @@ -143,21 +144,17 @@ pydoc-topics: build .PHONY: gettext gettext: BUILDER = gettext -gettext: SPHINXOPTS += '-d build/doctrees-gettext' +gettext: override SPHINXOPTS := -d build/doctrees-gettext $(SPHINXOPTS) gettext: build .PHONY: htmlview htmlview: html $(PYTHON) -c "import os, webbrowser; webbrowser.open('file://' + os.path.realpath('build/html/index.html'))" -.PHONY: ensure-sphinx-autobuild -ensure-sphinx-autobuild: venv - $(VENVDIR)/bin/sphinx-autobuild --version > /dev/null || $(VENVDIR)/bin/python3 -m pip install sphinx-autobuild - .PHONY: htmllive -htmllive: SPHINXBUILD = $(VENVDIR)/bin/sphinx-autobuild +htmllive: SPHINXBUILD = PATH=$(VENVDIR)/bin:$$PATH sphinx-autobuild htmllive: SPHINXOPTS = --re-ignore="/venv/" --open-browser --delay 0 -htmllive: ensure-sphinx-autobuild html +htmllive: _ensure-sphinx-autobuild html .PHONY: clean clean: clean-venv @@ -174,75 +171,130 @@ venv: echo "To recreate it, remove it first with \`make clean-venv'."; \ else \ echo "Creating venv in $(VENVDIR)"; \ - $(PYTHON) -m venv $(VENVDIR); \ - $(VENVDIR)/bin/python3 -m pip install --upgrade pip; \ - $(VENVDIR)/bin/python3 -m pip install -r $(REQUIREMENTS); \ + if $(UV) --version >/dev/null 2>&1; then \ + $(UV) venv $(VENVDIR); \ + VIRTUAL_ENV=$(VENVDIR) $(UV) pip install -r $(REQUIREMENTS); \ + else \ + $(PYTHON) -m venv $(VENVDIR); \ + $(VENVDIR)/bin/python3 -m pip install --upgrade pip; \ + $(VENVDIR)/bin/python3 -m pip install -r $(REQUIREMENTS); \ + fi; \ echo "The venv has been created in the $(VENVDIR) directory"; \ fi +.PHONY: dist-no-html +dist-no-html: dist-text dist-pdf dist-epub dist-texinfo + .PHONY: dist dist: rm -rf dist mkdir -p dist - + $(MAKE) dist-html + $(MAKE) dist-text + $(MAKE) dist-pdf + $(MAKE) dist-epub + $(MAKE) dist-texinfo + +.PHONY: dist-html +dist-html: # archive the HTML - make html + @echo "Building HTML..." + mkdir -p dist + rm -rf build/html + find dist -name 'python-$(DISTVERSION)-docs-html*' -exec rm -rf {} \; + $(MAKE) html cp -pPR build/html dist/python-$(DISTVERSION)-docs-html tar -C dist -cf dist/python-$(DISTVERSION)-docs-html.tar python-$(DISTVERSION)-docs-html bzip2 -9 -k dist/python-$(DISTVERSION)-docs-html.tar (cd dist; zip -q -r -9 python-$(DISTVERSION)-docs-html.zip python-$(DISTVERSION)-docs-html) rm -r dist/python-$(DISTVERSION)-docs-html rm dist/python-$(DISTVERSION)-docs-html.tar + @echo "Build finished and archived!" +.PHONY: dist-text +dist-text: # archive the text build - make text + @echo "Building text..." + mkdir -p dist + rm -rf build/text + find dist -name 'python-$(DISTVERSION)-docs-text*' -exec rm -rf {} \; + $(MAKE) text cp -pPR build/text dist/python-$(DISTVERSION)-docs-text tar -C dist -cf dist/python-$(DISTVERSION)-docs-text.tar python-$(DISTVERSION)-docs-text bzip2 -9 -k dist/python-$(DISTVERSION)-docs-text.tar (cd dist; zip -q -r -9 python-$(DISTVERSION)-docs-text.zip python-$(DISTVERSION)-docs-text) rm -r dist/python-$(DISTVERSION)-docs-text rm dist/python-$(DISTVERSION)-docs-text.tar + @echo "Build finished and archived!" +.PHONY: dist-pdf +dist-pdf: # archive the A4 latex + @echo "Building LaTeX (A4 paper)..." + mkdir -p dist rm -rf build/latex - make latex PAPER=a4 - -sed -i 's/makeindex/makeindex -q/' build/latex/Makefile - (cd build/latex; make clean && make all-pdf && make FMT=pdf zip bz2) + find dist -name 'python-$(DISTVERSION)-docs-pdf*' -exec rm -rf {} \; + $(MAKE) latex PAPER=a4 + # remove zip & bz2 dependency on all-pdf, + # as otherwise the full latexmk process is run twice. + # ($$ is needed to escape the $; https://www.gnu.org/software/make/manual/make.html#Basics-of-Variable-References) + -sed -i 's/: all-$$(FMT)/:/' build/latex/Makefile + (cd build/latex; $(MAKE) clean && $(MAKE) --jobs=$$((`nproc`+1)) --output-sync LATEXMKOPTS='-quiet' all-pdf && $(MAKE) FMT=pdf zip bz2) cp build/latex/docs-pdf.zip dist/python-$(DISTVERSION)-docs-pdf-a4.zip cp build/latex/docs-pdf.tar.bz2 dist/python-$(DISTVERSION)-docs-pdf-a4.tar.bz2 + @echo "Build finished and archived!" - # archive the letter latex - rm -rf build/latex - make latex PAPER=letter - -sed -i 's/makeindex/makeindex -q/' build/latex/Makefile - (cd build/latex; make clean && make all-pdf && make FMT=pdf zip bz2) - cp build/latex/docs-pdf.zip dist/python-$(DISTVERSION)-docs-pdf-letter.zip - cp build/latex/docs-pdf.tar.bz2 dist/python-$(DISTVERSION)-docs-pdf-letter.tar.bz2 - +.PHONY: dist-epub +dist-epub: # copy the epub build + @echo "Building EPUB..." + mkdir -p dist rm -rf build/epub - make epub + rm -f dist/python-$(DISTVERSION)-docs.epub + $(MAKE) epub cp -pPR build/epub/Python.epub dist/python-$(DISTVERSION)-docs.epub + @echo "Build finished and archived!" +.PHONY: dist-texinfo +dist-texinfo: # archive the texinfo build + @echo "Building Texinfo..." + mkdir -p dist rm -rf build/texinfo - make texinfo - make info --directory=build/texinfo + find dist -name 'python-$(DISTVERSION)-docs-texinfo*' -exec rm -rf {} \; + $(MAKE) texinfo + $(MAKE) info --directory=build/texinfo cp -pPR build/texinfo dist/python-$(DISTVERSION)-docs-texinfo tar -C dist -cf dist/python-$(DISTVERSION)-docs-texinfo.tar python-$(DISTVERSION)-docs-texinfo bzip2 -9 -k dist/python-$(DISTVERSION)-docs-texinfo.tar (cd dist; zip -q -r -9 python-$(DISTVERSION)-docs-texinfo.zip python-$(DISTVERSION)-docs-texinfo) rm -r dist/python-$(DISTVERSION)-docs-texinfo rm dist/python-$(DISTVERSION)-docs-texinfo.tar + @echo "Build finished and archived!" + +.PHONY: _ensure-package +_ensure-package: venv + if $(UV) --version >/dev/null 2>&1; then \ + VIRTUAL_ENV=$(VENVDIR) $(UV) pip install $(PACKAGE); \ + else \ + $(VENVDIR)/bin/python3 -m pip install $(PACKAGE); \ + fi + +.PHONY: _ensure-pre-commit +_ensure-pre-commit: + $(MAKE) _ensure-package PACKAGE=pre-commit + +.PHONY: _ensure-sphinx-autobuild +_ensure-sphinx-autobuild: + $(MAKE) _ensure-package PACKAGE=sphinx-autobuild .PHONY: check -check: venv - $(VENVDIR)/bin/python3 -m pre_commit --version > /dev/null || $(VENVDIR)/bin/python3 -m pip install pre-commit +check: _ensure-pre-commit $(VENVDIR)/bin/python3 -m pre_commit run --all-files .PHONY: serve serve: - @echo "The serve target was removed, use htmlview instead (see bpo-36329)" + @echo "The serve target was removed, use htmllive instead (see gh-80510)" # Targets for daily automated doc build # By default, Sphinx only rebuilds pages where the page content has changed. @@ -253,13 +305,15 @@ serve: # for development releases: always build .PHONY: autobuild-dev +autobuild-dev: DISTVERSION = $(shell $(PYTHON) tools/extensions/patchlevel.py --short) autobuild-dev: - make dist SPHINXOPTS='$(SPHINXOPTS) -Ea -A daily=1' + $(MAKE) dist-no-html SPHINXOPTS='$(SPHINXOPTS) -Ea -A daily=1' DISTVERSION=$(DISTVERSION) -# for quick rebuilds (HTML only) +# for HTML-only rebuilds .PHONY: autobuild-dev-html +autobuild-dev-html: DISTVERSION = $(shell $(PYTHON) tools/extensions/patchlevel.py --short) autobuild-dev-html: - make html SPHINXOPTS='$(SPHINXOPTS) -Ea -A daily=1' + $(MAKE) dist-html SPHINXOPTS='$(SPHINXOPTS) -Ea -A daily=1' DISTVERSION=$(DISTVERSION) # for stable releases: only build if not in pre-release stage (alpha, beta) # release candidate downloads are okay, since the stable tree can be in that stage @@ -269,7 +323,7 @@ autobuild-stable: echo "Not building; $(DISTVERSION) is not a release version."; \ exit 1;; \ esac - @make autobuild-dev + @$(MAKE) autobuild-dev .PHONY: autobuild-stable-html autobuild-stable-html: @@ -277,4 +331,4 @@ autobuild-stable-html: echo "Not building; $(DISTVERSION) is not a release version."; \ exit 1;; \ esac - @make autobuild-dev-html + @$(MAKE) autobuild-dev-html diff --git a/Doc/README.rst b/Doc/README.rst index a3bb5fa5..2d114875 100644 --- a/Doc/README.rst +++ b/Doc/README.rst @@ -28,7 +28,7 @@ install the tools into there. Using make ---------- -To get started on UNIX, you can create a virtual environment and build +To get started on Unix, you can create a virtual environment and build documentation with the commands:: make venv @@ -40,13 +40,13 @@ If you'd like to create the virtual environment in a different location, you can specify it using the ``VENVDIR`` variable. You can also skip creating the virtual environment altogether, in which case -the Makefile will look for instances of ``sphinx-build`` and ``blurb`` +the ``Makefile`` will look for instances of ``sphinx-build`` and ``blurb`` installed on your process ``PATH`` (configurable with the ``SPHINXBUILD`` and ``BLURB`` variables). -On Windows, we try to emulate the Makefile as closely as possible with a +On Windows, we try to emulate the ``Makefile`` as closely as possible with a ``make.bat`` file. If you need to specify the Python interpreter to use, -set the PYTHON environment variable. +set the ``PYTHON`` environment variable. Available make targets are: @@ -62,15 +62,19 @@ Available make targets are: * "htmlview", which re-uses the "html" builder, but then opens the main page in your default web browser. +* "htmllive", which re-uses the "html" builder, rebuilds the docs, + starts a local server, and automatically reloads the page in your browser + when you make changes to reST files (Unix only). + * "htmlhelp", which builds HTML files and a HTML Help project file usable to convert them into a single Compiled HTML (.chm) file -- these are popular under Microsoft Windows, but very handy on every platform. To create the CHM file, you need to run the Microsoft HTML Help Workshop - over the generated project (.hhp) file. The make.bat script does this for + over the generated project (.hhp) file. The ``make.bat`` script does this for you on Windows. -* "latex", which builds LaTeX source files as input to "pdflatex" to produce +* "latex", which builds LaTeX source files as input to ``pdflatex`` to produce PDF documents. * "text", which builds a plain text file for each source file. @@ -95,8 +99,6 @@ Available make targets are: * "check", which checks for frequent markup errors. -* "serve", which serves the build/html directory on port 8000. - * "dist", (Unix only) which creates distributable archives of HTML, text, PDF, and EPUB builds. @@ -131,8 +133,5 @@ Bugs in the content should be reported to the Bugs in the toolset should be reported to the tools themselves. -You can also send a mail to the Python Documentation Team at docs@python.org, -and we will process your request as soon as possible. - -If you want to help the Documentation Team, you are always welcome. Just send -a mail to docs@python.org. +To help with the documentation, or report any problems, please leave a message +on `discuss.python.org `_. diff --git a/Doc/c-api/allocation.rst b/Doc/c-api/allocation.rst index b3609c23..e6ff40ab 100644 --- a/Doc/c-api/allocation.rst +++ b/Doc/c-api/allocation.rst @@ -15,10 +15,8 @@ Allocating Objects on the Heap .. c:function:: PyObject* PyObject_Init(PyObject *op, PyTypeObject *type) Initialize a newly allocated object *op* with its type and initial - reference. Returns the initialized object. If *type* indicates that the - object participates in the cyclic garbage detector, it is added to the - detector's set of observed objects. Other fields of the object are not - affected. + reference. Returns the initialized object. Other fields of the object are + not affected. .. c:function:: PyVarObject* PyObject_InitVar(PyVarObject *op, PyTypeObject *type, Py_ssize_t size) diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index 657b10d3..b8af24f5 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -280,10 +280,10 @@ Numbers length 1, to a C :c:expr:`int`. ``f`` (:class:`float`) [float] - Convert a Python floating point number to a C :c:expr:`float`. + Convert a Python floating-point number to a C :c:expr:`float`. ``d`` (:class:`float`) [double] - Convert a Python floating point number to a C :c:expr:`double`. + Convert a Python floating-point number to a C :c:expr:`double`. ``D`` (:class:`complex`) [Py_complex] Convert a Python complex number to a C :c:type:`Py_complex` structure. @@ -607,10 +607,10 @@ Building values object of length 1. ``d`` (:class:`float`) [double] - Convert a C :c:expr:`double` to a Python floating point number. + Convert a C :c:expr:`double` to a Python floating-point number. ``f`` (:class:`float`) [float] - Convert a C :c:expr:`float` to a Python floating point number. + Convert a C :c:expr:`float` to a Python floating-point number. ``D`` (:class:`complex`) [Py_complex \*] Convert a C :c:type:`Py_complex` structure to a Python complex number. diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst index 9500fe46..dc43a3d5 100644 --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -244,7 +244,6 @@ The following fields are not influenced by *flags* and must always be filled in with the correct values: :c:member:`~Py_buffer.obj`, :c:member:`~Py_buffer.buf`, :c:member:`~Py_buffer.len`, :c:member:`~Py_buffer.itemsize`, :c:member:`~Py_buffer.ndim`. - readonly, format ~~~~~~~~~~~~~~~~ @@ -253,7 +252,8 @@ readonly, format Controls the :c:member:`~Py_buffer.readonly` field. If set, the exporter MUST provide a writable buffer or else report failure. Otherwise, the exporter MAY provide either a read-only or writable buffer, but the choice - MUST be consistent for all consumers. + MUST be consistent for all consumers. For example, :c:expr:`PyBUF_SIMPLE | PyBUF_WRITABLE` + can be used to request a simple writable buffer. .. c:macro:: PyBUF_FORMAT @@ -265,8 +265,9 @@ readonly, format Since :c:macro:`PyBUF_SIMPLE` is defined as 0, :c:macro:`PyBUF_WRITABLE` can be used as a stand-alone flag to request a simple writable buffer. -:c:macro:`PyBUF_FORMAT` can be \|'d to any of the flags except :c:macro:`PyBUF_SIMPLE`. -The latter already implies format ``B`` (unsigned bytes). +:c:macro:`PyBUF_FORMAT` must be \|'d to any of the flags except :c:macro:`PyBUF_SIMPLE`, because +the latter already implies format ``B`` (unsigned bytes). :c:macro:`!PyBUF_FORMAT` cannot be +used on its own. shape, strides, suboffsets diff --git a/Doc/c-api/bytearray.rst b/Doc/c-api/bytearray.rst index 456f7d89..9045689a 100644 --- a/Doc/c-api/bytearray.rst +++ b/Doc/c-api/bytearray.rst @@ -42,17 +42,22 @@ Direct API functions Return a new bytearray object from any object, *o*, that implements the :ref:`buffer protocol `. + On failure, return ``NULL`` with an exception set. + .. c:function:: PyObject* PyByteArray_FromStringAndSize(const char *string, Py_ssize_t len) - Create a new bytearray object from *string* and its length, *len*. On - failure, ``NULL`` is returned. + Create a new bytearray object from *string* and its length, *len*. + + On failure, return ``NULL`` with an exception set. .. c:function:: PyObject* PyByteArray_Concat(PyObject *a, PyObject *b) Concat bytearrays *a* and *b* and return a new bytearray with the result. + On failure, return ``NULL`` with an exception set. + .. c:function:: Py_ssize_t PyByteArray_Size(PyObject *bytearray) diff --git a/Doc/c-api/cell.rst b/Doc/c-api/cell.rst index f8cd0344..61eb994c 100644 --- a/Doc/c-api/cell.rst +++ b/Doc/c-api/cell.rst @@ -39,7 +39,8 @@ Cell objects are not likely to be useful elsewhere. .. c:function:: PyObject* PyCell_Get(PyObject *cell) - Return the contents of the cell *cell*. + Return the contents of the cell *cell*, which can be ``NULL``. + If *cell* is not a cell object, returns ``NULL`` with an exception set. .. c:function:: PyObject* PyCell_GET(PyObject *cell) @@ -52,8 +53,10 @@ Cell objects are not likely to be useful elsewhere. Set the contents of the cell object *cell* to *value*. This releases the reference to any current content of the cell. *value* may be ``NULL``. *cell* - must be non-``NULL``; if it is not a cell object, ``-1`` will be returned. On - success, ``0`` will be returned. + must be non-``NULL``. + + On success, return ``0``. + If *cell* is not a cell object, set an exception and return ``-1``. .. c:function:: void PyCell_SET(PyObject *cell, PyObject *value) diff --git a/Doc/c-api/code.rst b/Doc/c-api/code.rst index f6fdd757..d7e89b73 100644 --- a/Doc/c-api/code.rst +++ b/Doc/c-api/code.rst @@ -90,8 +90,8 @@ bound into a function. Return the line number of the instruction that occurs on or before ``byte_offset`` and ends after it. If you just need the line number of a frame, use :c:func:`PyFrame_GetLineNumber` instead. - For efficiently iterating over the line numbers in a code object, use `the API described in PEP 626 - `_. + For efficiently iterating over the line numbers in a code object, use :pep:`the API described in PEP 626 + <0626#out-of-process-debuggers-and-profilers>`. .. c:function:: int PyCode_Addr2Location(PyObject *co, int byte_offset, int *start_line, int *start_column, int *end_line, int *end_column) diff --git a/Doc/c-api/complex.rst b/Doc/c-api/complex.rst index e3fd001c..77cb67d8 100644 --- a/Doc/c-api/complex.rst +++ b/Doc/c-api/complex.rst @@ -25,12 +25,16 @@ pointers. This is consistent throughout the API. The C structure which corresponds to the value portion of a Python complex number object. Most of the functions for dealing with complex number objects - use structures of this type as input or output values, as appropriate. It is - defined as:: + use structures of this type as input or output values, as appropriate. + + .. c:member:: double real + double imag + + The structure is defined as:: typedef struct { - double real; - double imag; + double real; + double imag; } Py_complex; @@ -106,17 +110,22 @@ Complex Numbers as Python Objects .. c:function:: PyObject* PyComplex_FromCComplex(Py_complex v) Create a new Python complex number object from a C :c:type:`Py_complex` value. + Return ``NULL`` with an exception set on error. .. c:function:: PyObject* PyComplex_FromDoubles(double real, double imag) Return a new :c:type:`PyComplexObject` object from *real* and *imag*. + Return ``NULL`` with an exception set on error. .. c:function:: double PyComplex_RealAsDouble(PyObject *op) Return the real part of *op* as a C :c:expr:`double`. + Upon failure, this method returns ``-1.0`` with an exception set, so one + should call :c:func:`PyErr_Occurred` to check for errors. + .. c:function:: double PyComplex_ImagAsDouble(PyObject *op) @@ -131,8 +140,11 @@ Complex Numbers as Python Objects method, this method will first be called to convert *op* to a Python complex number object. If :meth:`!__complex__` is not defined then it falls back to :meth:`~object.__float__`. If :meth:`!__float__` is not defined then it falls back - to :meth:`~object.__index__`. Upon failure, this method returns ``-1.0`` as a real - value. + to :meth:`~object.__index__`. + + Upon failure, this method returns :c:type:`Py_complex` + with :c:member:`~Py_complex.real` set to ``-1.0`` and with an exception set, so one + should call :c:func:`PyErr_Occurred` to check for errors. .. versionchanged:: 3.8 Use :meth:`~object.__index__` if available. diff --git a/Doc/c-api/datetime.rst b/Doc/c-api/datetime.rst index 97522da7..d2d4d530 100644 --- a/Doc/c-api/datetime.rst +++ b/Doc/c-api/datetime.rst @@ -318,10 +318,10 @@ Macros for the convenience of modules implementing the DB API: .. c:function:: PyObject* PyDateTime_FromTimestamp(PyObject *args) Create and return a new :class:`datetime.datetime` object given an argument - tuple suitable for passing to :meth:`datetime.datetime.fromtimestamp()`. + tuple suitable for passing to :meth:`datetime.datetime.fromtimestamp`. .. c:function:: PyObject* PyDate_FromTimestamp(PyObject *args) Create and return a new :class:`datetime.date` object given an argument - tuple suitable for passing to :meth:`datetime.date.fromtimestamp()`. + tuple suitable for passing to :meth:`datetime.date.fromtimestamp`. diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 7ddecb24..e1fb8c89 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -34,7 +34,7 @@ propagated, additional calls into the Python/C API may not behave as intended and may fail in mysterious ways. .. note:: - The error indicator is **not** the result of :func:`sys.exc_info()`. + The error indicator is **not** the result of :func:`sys.exc_info`. The former corresponds to an exception that is not yet caught (and is therefore still propagating), while the latter returns an exception after it is caught (and has therefore stopped propagating). @@ -720,7 +720,7 @@ Exception Classes This creates a class object derived from :exc:`Exception` (accessible in C as :c:data:`PyExc_Exception`). - The :attr:`!__module__` attribute of the new class is set to the first part (up + The :attr:`~type.__module__` attribute of the new class is set to the first part (up to the last dot) of the *name* argument, and the class name is set to the last part (after the last dot). The *base* argument can be used to specify alternate base classes; it can either be only one class or a tuple of classes. The *dict* diff --git a/Doc/c-api/file.rst b/Doc/c-api/file.rst index c4f53592..e9019a0d 100644 --- a/Doc/c-api/file.rst +++ b/Doc/c-api/file.rst @@ -65,9 +65,10 @@ the :mod:`io` APIs instead. Overrides the normal behavior of :func:`io.open_code` to pass its parameter through the provided handler. - The handler is a function of type: + The *handler* is a function of type: - .. c:type:: Py_OpenCodeHookFunction + .. c:namespace:: NULL + .. c:type:: PyObject * (*Py_OpenCodeHookFunction)(PyObject *, void *) Equivalent of :c:expr:`PyObject *(\*)(PyObject *path, void *userData)`, where *path* is guaranteed to be diff --git a/Doc/c-api/float.rst b/Doc/c-api/float.rst index 4f6ac0d8..1da37a5b 100644 --- a/Doc/c-api/float.rst +++ b/Doc/c-api/float.rst @@ -2,20 +2,20 @@ .. _floatobjects: -Floating Point Objects +Floating-Point Objects ====================== -.. index:: pair: object; floating point +.. index:: pair: object; floating-point .. c:type:: PyFloatObject - This subtype of :c:type:`PyObject` represents a Python floating point object. + This subtype of :c:type:`PyObject` represents a Python floating-point object. .. c:var:: PyTypeObject PyFloat_Type - This instance of :c:type:`PyTypeObject` represents the Python floating point + This instance of :c:type:`PyTypeObject` represents the Python floating-point type. This is the same object as :class:`float` in the Python layer. @@ -45,7 +45,7 @@ Floating Point Objects .. c:function:: double PyFloat_AsDouble(PyObject *pyfloat) Return a C :c:expr:`double` representation of the contents of *pyfloat*. If - *pyfloat* is not a Python floating point object but has a :meth:`~object.__float__` + *pyfloat* is not a Python floating-point object but has a :meth:`~object.__float__` method, this method will first be called to convert *pyfloat* into a float. If :meth:`!__float__` is not defined then it falls back to :meth:`~object.__index__`. This method returns ``-1.0`` upon failure, so one should call diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst index 380465b8..d6370bc9 100644 --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -120,14 +120,14 @@ Importing Modules such modules have no way to know that the module object is an unknown (and probably damaged with respect to the module author's intents) state. - The module's :attr:`__spec__` and :attr:`__loader__` will be set, if - not set already, with the appropriate values. The spec's loader will - be set to the module's ``__loader__`` (if set) and to an instance of - :class:`~importlib.machinery.SourceFileLoader` otherwise. + The module's :attr:`~module.__spec__` and :attr:`~module.__loader__` will be + set, if not set already, with the appropriate values. The spec's loader + will be set to the module's :attr:`!__loader__` (if set) and to an instance + of :class:`~importlib.machinery.SourceFileLoader` otherwise. - The module's :attr:`__file__` attribute will be set to the code object's - :attr:`~codeobject.co_filename`. If applicable, :attr:`__cached__` will also - be set. + The module's :attr:`~module.__file__` attribute will be set to the code + object's :attr:`~codeobject.co_filename`. If applicable, + :attr:`~module.__cached__` will also be set. This function will reload the module if it was already imported. See :c:func:`PyImport_ReloadModule` for the intended way to reload a module. @@ -139,29 +139,29 @@ Importing Modules :c:func:`PyImport_ExecCodeModuleWithPathnames`. .. versionchanged:: 3.12 - The setting of :attr:`__cached__` and :attr:`__loader__` is - deprecated. See :class:`~importlib.machinery.ModuleSpec` for + The setting of :attr:`~module.__cached__` and :attr:`~module.__loader__` + is deprecated. See :class:`~importlib.machinery.ModuleSpec` for alternatives. .. c:function:: PyObject* PyImport_ExecCodeModuleEx(const char *name, PyObject *co, const char *pathname) - Like :c:func:`PyImport_ExecCodeModule`, but the :attr:`__file__` attribute of - the module object is set to *pathname* if it is non-``NULL``. + Like :c:func:`PyImport_ExecCodeModule`, but the :attr:`~module.__file__` + attribute of the module object is set to *pathname* if it is non-``NULL``. See also :c:func:`PyImport_ExecCodeModuleWithPathnames`. .. c:function:: PyObject* PyImport_ExecCodeModuleObject(PyObject *name, PyObject *co, PyObject *pathname, PyObject *cpathname) - Like :c:func:`PyImport_ExecCodeModuleEx`, but the :attr:`__cached__` + Like :c:func:`PyImport_ExecCodeModuleEx`, but the :attr:`~module.__cached__` attribute of the module object is set to *cpathname* if it is non-``NULL``. Of the three functions, this is the preferred one to use. .. versionadded:: 3.3 .. versionchanged:: 3.12 - Setting :attr:`__cached__` is deprecated. See + Setting :attr:`~module.__cached__` is deprecated. See :class:`~importlib.machinery.ModuleSpec` for alternatives. @@ -174,7 +174,7 @@ Importing Modules .. versionadded:: 3.2 .. versionchanged:: 3.3 - Uses :func:`!imp.source_from_cache()` in calculating the source path if + Uses :func:`!imp.source_from_cache` in calculating the source path if only the bytecode path is provided. .. versionchanged:: 3.12 No longer uses the removed :mod:`!imp` module. diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index a51f1da6..aacbab0b 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -388,9 +388,16 @@ Initializing and finalizing the interpreter :c:func:`Py_NewInterpreter` below) that were created and not yet destroyed since the last call to :c:func:`Py_Initialize`. Ideally, this frees all memory allocated by the Python interpreter. This is a no-op when called for a second - time (without calling :c:func:`Py_Initialize` again first). Normally the - return value is ``0``. If there were errors during finalization - (flushing buffered data), ``-1`` is returned. + time (without calling :c:func:`Py_Initialize` again first). + + Since this is the reverse of :c:func:`Py_Initialize`, it should be called + in the same thread with the same interpreter active. That means + the main thread and the main interpreter. + This should never be called while :c:func:`Py_RunMain` is running. + + Normally the return value is ``0``. + If there were errors during finalization (flushing buffered data), + ``-1`` is returned. This function is provided for a number of reasons. An embedding application might want to restart Python without having to restart the application itself. @@ -1262,7 +1269,7 @@ All of the following functions must be called after :c:func:`Py_Initialize`. .. c:function:: void PyThreadState_DeleteCurrent(void) Destroy the current thread state and release the global interpreter lock. - Like :c:func:`PyThreadState_Delete`, the global interpreter lock need not + Like :c:func:`PyThreadState_Delete`, the global interpreter lock must be held. The thread state must have been reset with a previous call to :c:func:`PyThreadState_Clear`. @@ -1637,7 +1644,11 @@ function. You can create and destroy them using the following functions: .check_multi_interp_extensions = 1, .gil = PyInterpreterConfig_OWN_GIL, }; - PyThreadState *tstate = Py_NewInterpreterFromConfig(&config); + PyThreadState *tstate = NULL; + PyStatus status = Py_NewInterpreterFromConfig(&tstate, &config); + if (PyStatus_Exception(status)) { + Py_ExitStatusException(status); + } Note that the config is used only briefly and does not get modified. During initialization the config's values are converted into various diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst index 7c5465b5..c586cfb3 100644 --- a/Doc/c-api/init_config.rst +++ b/Doc/c-api/init_config.rst @@ -311,7 +311,7 @@ PyPreConfig * Set :c:member:`PyConfig.filesystem_encoding` to ``"mbcs"``, * Set :c:member:`PyConfig.filesystem_errors` to ``"replace"``. - Initialized the from :envvar:`PYTHONLEGACYWINDOWSFSENCODING` environment + Initialized from the :envvar:`PYTHONLEGACYWINDOWSFSENCODING` environment variable value. Only available on Windows. ``#ifdef MS_WINDOWS`` macro can be used for @@ -499,7 +499,7 @@ PyConfig The :c:func:`PyConfig_Read` function only parses :c:member:`PyConfig.argv` arguments once: :c:member:`PyConfig.parse_argv` is set to ``2`` after arguments are parsed. Since Python arguments are - strippped from :c:member:`PyConfig.argv`, parsing arguments twice would + stripped from :c:member:`PyConfig.argv`, parsing arguments twice would parse the application options as Python options. :ref:`Preinitialize Python ` if needed. @@ -1000,7 +1000,7 @@ PyConfig The :c:func:`PyConfig_Read` function only parses :c:member:`PyConfig.argv` arguments once: :c:member:`PyConfig.parse_argv` is set to ``2`` after arguments are parsed. Since Python arguments are - strippped from :c:member:`PyConfig.argv`, parsing arguments twice would + stripped from :c:member:`PyConfig.argv`, parsing arguments twice would parse the application options as Python options. Default: ``1`` in Python mode, ``0`` in isolated mode. diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index 76ac8032..972d69a5 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -324,6 +324,17 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Returns ``NULL`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. +.. c:function:: PyObject* PyLong_GetInfo(void) + + On success, return a read only :term:`named tuple`, that holds + information about Python's internal representation of integers. + See :data:`sys.int_info` for description of individual fields. + + On failure, return ``NULL`` with an exception set. + + .. versionadded:: 3.1 + + .. c:function:: int PyUnstable_Long_IsCompact(const PyLongObject* op) Return 1 if *op* is compact, 0 otherwise. @@ -339,6 +350,9 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Exactly what values are considered compact is an implementation detail and is subject to change. + .. versionadded:: 3.12 + + .. c:function:: Py_ssize_t PyUnstable_Long_CompactValue(const PyLongObject* op) If *op* is compact, as determined by :c:func:`PyUnstable_Long_IsCompact`, @@ -346,3 +360,5 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Otherwise, the return value is undefined. + .. versionadded:: 3.12 + diff --git a/Doc/c-api/marshal.rst b/Doc/c-api/marshal.rst index 489f1580..b9085ad3 100644 --- a/Doc/c-api/marshal.rst +++ b/Doc/c-api/marshal.rst @@ -15,7 +15,7 @@ Numeric values are stored with the least significant byte first. The module supports two versions of the data format: version 0 is the historical version, version 1 shares interned strings in the file, and upon -unmarshalling. Version 2 uses a binary format for floating point numbers. +unmarshalling. Version 2 uses a binary format for floating-point numbers. ``Py_MARSHAL_VERSION`` indicates the current file format (currently 2). diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index f941f0c7..cfa6a1a9 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -37,16 +37,19 @@ Module Objects single: __package__ (module attribute) single: __loader__ (module attribute) - Return a new module object with the :attr:`__name__` attribute set to *name*. - The module's :attr:`__name__`, :attr:`__doc__`, :attr:`__package__`, and - :attr:`__loader__` attributes are filled in (all but :attr:`__name__` are set - to ``None``); the caller is responsible for providing a :attr:`__file__` - attribute. + Return a new module object with :attr:`module.__name__` set to *name*. + The module's :attr:`!__name__`, :attr:`~module.__doc__`, + :attr:`~module.__package__` and :attr:`~module.__loader__` attributes are + filled in (all but :attr:`!__name__` are set to ``None``). The caller is + responsible for setting a :attr:`~module.__file__` attribute. + + Return ``NULL`` with an exception set on error. .. versionadded:: 3.3 .. versionchanged:: 3.4 - :attr:`__package__` and :attr:`__loader__` are set to ``None``. + :attr:`~module.__package__` and :attr:`~module.__loader__` are now set to + ``None``. .. c:function:: PyObject* PyModule_New(const char *name) @@ -75,8 +78,9 @@ Module Objects single: __name__ (module attribute) single: SystemError (built-in exception) - Return *module*'s :attr:`__name__` value. If the module does not provide one, - or if it is not a string, :exc:`SystemError` is raised and ``NULL`` is returned. + Return *module*'s :attr:`~module.__name__` value. If the module does not + provide one, or if it is not a string, :exc:`SystemError` is raised and + ``NULL`` is returned. .. versionadded:: 3.3 @@ -106,8 +110,8 @@ Module Objects single: SystemError (built-in exception) Return the name of the file from which *module* was loaded using *module*'s - :attr:`__file__` attribute. If this is not defined, or if it is not a - unicode string, raise :exc:`SystemError` and return ``NULL``; otherwise return + :attr:`~module.__file__` attribute. If this is not defined, or if it is not a + string, raise :exc:`SystemError` and return ``NULL``; otherwise return a reference to a Unicode object. .. versionadded:: 3.2 @@ -265,6 +269,8 @@ of the following two module creation functions: API version *module_api_version*. If that version does not match the version of the running interpreter, a :exc:`RuntimeWarning` is emitted. + Return ``NULL`` with an exception set on error. + .. note:: Most uses of this function should be using :c:func:`PyModule_Create` @@ -338,7 +344,8 @@ The available slot types are: The *value* pointer of this slot must point to a function of the signature: .. c:function:: PyObject* create_module(PyObject *spec, PyModuleDef *def) - :noindex: + :no-index-entry: + :no-contents-entry: The function receives a :py:class:`~importlib.machinery.ModuleSpec` instance, as defined in :PEP:`451`, and the module definition. @@ -373,7 +380,8 @@ The available slot types are: The signature of the function is: .. c:function:: int exec_module(PyObject* module) - :noindex: + :no-index-entry: + :no-contents-entry: If multiple ``Py_mod_exec`` slots are specified, they are processed in the order they appear in the *m_slots* array. @@ -436,6 +444,8 @@ objects dynamically. Note that both ``PyModule_FromDefAndSpec`` and If that version does not match the version of the running interpreter, a :exc:`RuntimeWarning` is emitted. + Return ``NULL`` with an exception set on error. + .. note:: Most uses of this function should be using :c:func:`PyModule_FromDefAndSpec` @@ -486,7 +496,7 @@ state: On success, return ``0``. On error, raise an exception and return ``-1``. - Return ``NULL`` if *value* is ``NULL``. It must be called with an exception + Return ``-1`` if *value* is ``NULL``. It must be called with an exception raised in this case. Example usage:: @@ -518,6 +528,14 @@ state: Note that ``Py_XDECREF()`` should be used instead of ``Py_DECREF()`` in this case, since *obj* can be ``NULL``. + The number of different *name* strings passed to this function + should be kept small, usually by only using statically allocated strings + as *name*. + For names that aren't known at compile time, prefer calling + :c:func:`PyUnicode_FromString` and :c:func:`PyObject_SetAttr` directly. + For more details, see :c:func:`PyUnicode_InternFromString`, which may be + used internally to create a key object. + .. versionadded:: 3.10 @@ -579,15 +597,23 @@ state: .. c:function:: int PyModule_AddIntConstant(PyObject *module, const char *name, long value) Add an integer constant to *module* as *name*. This convenience function can be - used from the module's initialization function. Return ``-1`` on error, ``0`` on - success. + used from the module's initialization function. + Return ``-1`` with an exception set on error, ``0`` on success. + + This is a convenience function that calls :c:func:`PyLong_FromLong` and + :c:func:`PyModule_AddObjectRef`; see their documentation for details. .. c:function:: int PyModule_AddStringConstant(PyObject *module, const char *name, const char *value) Add a string constant to *module* as *name*. This convenience function can be used from the module's initialization function. The string *value* must be - ``NULL``-terminated. Return ``-1`` on error, ``0`` on success. + ``NULL``-terminated. + Return ``-1`` with an exception set on error, ``0`` on success. + + This is a convenience function that calls + :c:func:`PyUnicode_InternFromString` and :c:func:`PyModule_AddObjectRef`; + see their documentation for details. .. c:macro:: PyModule_AddIntMacro(module, macro) @@ -595,7 +621,7 @@ state: Add an int constant to *module*. The name and the value are taken from *macro*. For example ``PyModule_AddIntMacro(module, AF_INET)`` adds the int constant *AF_INET* with the value of *AF_INET* to *module*. - Return ``-1`` on error, ``0`` on success. + Return ``-1`` with an exception set on error, ``0`` on success. .. c:macro:: PyModule_AddStringMacro(module, macro) @@ -608,7 +634,7 @@ state: The type object is finalized by calling internally :c:func:`PyType_Ready`. The name of the type object is taken from the last component of :c:member:`~PyTypeObject.tp_name` after dot. - Return ``-1`` on error, ``0`` on success. + Return ``-1`` with an exception set on error, ``0`` on success. .. versionadded:: 3.9 @@ -647,14 +673,14 @@ since multiple such modules can be created from a single definition. The caller must hold the GIL. - Return 0 on success or -1 on failure. + Return ``-1`` with an exception set on error, ``0`` on success. .. versionadded:: 3.3 .. c:function:: int PyState_RemoveModule(PyModuleDef *def) Removes the module object created from *def* from the interpreter state. - Return 0 on success or -1 on failure. + Return ``-1`` with an exception set on error, ``0`` on success. The caller must hold the GIL. diff --git a/Doc/c-api/number.rst b/Doc/c-api/number.rst index 13d3c5af..ad8b5935 100644 --- a/Doc/c-api/number.rst +++ b/Doc/c-api/number.rst @@ -51,8 +51,8 @@ Number Protocol Return a reasonable approximation for the mathematical value of *o1* divided by *o2*, or ``NULL`` on failure. The return value is "approximate" because binary - floating point numbers are approximate; it is not possible to represent all real - numbers in base two. This function can return a floating point value when + floating-point numbers are approximate; it is not possible to represent all real + numbers in base two. This function can return a floating-point value when passed two integers. This is the equivalent of the Python expression ``o1 / o2``. @@ -177,8 +177,8 @@ Number Protocol Return a reasonable approximation for the mathematical value of *o1* divided by *o2*, or ``NULL`` on failure. The return value is "approximate" because binary - floating point numbers are approximate; it is not possible to represent all real - numbers in base two. This function can return a floating point value when + floating-point numbers are approximate; it is not possible to represent all real + numbers in base two. This function can return a floating-point value when passed two integers. The operation is done *in-place* when *o1* supports it. This is the equivalent of the Python statement ``o1 /= o2``. diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst index 3cb65400..2109b12b 100644 --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -107,6 +107,13 @@ Object Protocol If *v* is ``NULL``, the attribute is deleted, but this feature is deprecated in favour of using :c:func:`PyObject_DelAttrString`. + The number of different attribute names passed to this function + should be kept small, usually by using a statically allocated string + as *attr_name*. + For attribute names that aren't known at compile time, prefer calling + :c:func:`PyUnicode_FromString` and :c:func:`PyObject_SetAttr` directly. + For more details, see :c:func:`PyUnicode_InternFromString`, which may be + used internally to create a key object. .. c:function:: int PyObject_GenericSetAttr(PyObject *o, PyObject *name, PyObject *value) @@ -132,6 +139,14 @@ Object Protocol specified as a :c:expr:`const char*` UTF-8 encoded bytes string, rather than a :c:expr:`PyObject*`. + The number of different attribute names passed to this function + should be kept small, usually by using a statically allocated string + as *attr_name*. + For attribute names that aren't known at compile time, prefer calling + :c:func:`PyUnicode_FromString` and :c:func:`PyObject_DelAttr` directly. + For more details, see :c:func:`PyUnicode_InternFromString`, which may be + used internally to create a key object for lookup. + .. c:function:: PyObject* PyObject_GenericGetDict(PyObject *o, void *context) @@ -253,14 +268,14 @@ Object Protocol The result will be ``1`` when at least one of the checks returns ``1``, otherwise it will be ``0``. - If *cls* has a :meth:`~class.__subclasscheck__` method, it will be called to + If *cls* has a :meth:`~type.__subclasscheck__` method, it will be called to determine the subclass status as described in :pep:`3119`. Otherwise, *derived* is a subclass of *cls* if it is a direct or indirect subclass, - i.e. contained in ``cls.__mro__``. + i.e. contained in :attr:`cls.__mro__ `. Normally only class objects, i.e. instances of :class:`type` or a derived class, are considered classes. However, objects can override this by having - a :attr:`~class.__bases__` attribute (which must be a tuple of base classes). + a :attr:`~type.__bases__` attribute (which must be a tuple of base classes). .. c:function:: int PyObject_IsInstance(PyObject *inst, PyObject *cls) @@ -272,15 +287,15 @@ Object Protocol The result will be ``1`` when at least one of the checks returns ``1``, otherwise it will be ``0``. - If *cls* has a :meth:`~class.__instancecheck__` method, it will be called to + If *cls* has a :meth:`~type.__instancecheck__` method, it will be called to determine the subclass status as described in :pep:`3119`. Otherwise, *inst* is an instance of *cls* if its class is a subclass of *cls*. An instance *inst* can override what is considered its class by having a - :attr:`~instance.__class__` attribute. + :attr:`~object.__class__` attribute. An object *cls* can override if it is considered a class, and what its base - classes are, by having a :attr:`~class.__bases__` attribute (which must be a tuple + classes are, by having a :attr:`~type.__bases__` attribute (which must be a tuple of base classes). diff --git a/Doc/c-api/refcounting.rst b/Doc/c-api/refcounting.rst index a484fa44..158aa737 100644 --- a/Doc/c-api/refcounting.rst +++ b/Doc/c-api/refcounting.rst @@ -59,7 +59,7 @@ of Python objects. ``NULL``, use :c:func:`Py_XINCREF`. Do not expect this function to actually modify *o* in any way. - For at least `some objects `_, + For at least :pep:`some objects <0683>`, this function has no effect. .. versionchanged:: 3.12 @@ -125,7 +125,7 @@ of Python objects. use :c:func:`Py_XDECREF`. Do not expect this function to actually modify *o* in any way. - For at least `some objects `_, + For at least :pep:`some objects <683>`, this function has no effect. .. warning:: diff --git a/Doc/c-api/slice.rst b/Doc/c-api/slice.rst index 9e880c6b..819929a0 100644 --- a/Doc/c-api/slice.rst +++ b/Doc/c-api/slice.rst @@ -23,7 +23,9 @@ Slice Objects Return a new slice object with the given values. The *start*, *stop*, and *step* parameters are used as the values of the slice object attributes of the same names. Any of the values may be ``NULL``, in which case the - ``None`` will be used for the corresponding attribute. Return ``NULL`` if + ``None`` will be used for the corresponding attribute. + + Return ``NULL`` with an exception set if the new object could not be allocated. @@ -52,7 +54,7 @@ Slice Objects of bounds indices are clipped in a manner consistent with the handling of normal slices. - Returns ``0`` on success and ``-1`` on error with exception set. + Return ``0`` on success and ``-1`` on error with an exception set. .. note:: This function is considered not safe for resizable sequences. @@ -95,7 +97,7 @@ Slice Objects ``PY_SSIZE_T_MIN`` to ``PY_SSIZE_T_MIN``, and silently boost the step values less than ``-PY_SSIZE_T_MAX`` to ``-PY_SSIZE_T_MAX``. - Return ``-1`` on error, ``0`` on success. + Return ``-1`` with an exception set on error, ``0`` on success. .. versionadded:: 3.6.1 diff --git a/Doc/c-api/stable.rst b/Doc/c-api/stable.rst index 5b9e4387..124e58cf 100644 --- a/Doc/c-api/stable.rst +++ b/Doc/c-api/stable.rst @@ -66,7 +66,7 @@ Limited C API Python 3.2 introduced the *Limited API*, a subset of Python's C API. Extensions that only use the Limited API can be -compiled once and work with multiple versions of Python. +compiled once and be loaded on multiple versions of Python. Contents of the Limited API are :ref:`listed below `. .. c:macro:: Py_LIMITED_API @@ -76,7 +76,7 @@ Contents of the Limited API are :ref:`listed below `. Define ``Py_LIMITED_API`` to the value of :c:macro:`PY_VERSION_HEX` corresponding to the lowest Python version your extension supports. - The extension will work without recompilation with all Python 3 releases + The extension will be ABI-compatible with all Python 3 releases from the specified one onward, and can use Limited API introduced up to that version. @@ -94,7 +94,15 @@ Stable ABI ---------- To enable this, Python provides a *Stable ABI*: a set of symbols that will -remain compatible across Python 3.x versions. +remain ABI-compatible across Python 3.x versions. + +.. note:: + + The Stable ABI prevents ABI issues, like linker errors due to missing + symbols or data corruption due to changes in structure layouts or function + signatures. + However, other changes in Python can change the *behavior* of extensions. + See Python's Backwards Compatibility Policy (:pep:`387`) for details. The Stable ABI contains symbols exposed in the :ref:`Limited API `, but also other ones – for example, functions necessary to diff --git a/Doc/c-api/tuple.rst b/Doc/c-api/tuple.rst index e0186c1f..e20c5a66 100644 --- a/Doc/c-api/tuple.rst +++ b/Doc/c-api/tuple.rst @@ -33,12 +33,14 @@ Tuple Objects .. c:function:: PyObject* PyTuple_New(Py_ssize_t len) - Return a new tuple object of size *len*, or ``NULL`` on failure. + Return a new tuple object of size *len*, + or ``NULL`` with an exception set on failure. .. c:function:: PyObject* PyTuple_Pack(Py_ssize_t n, ...) - Return a new tuple object of size *n*, or ``NULL`` on failure. The tuple values + Return a new tuple object of size *n*, + or ``NULL`` with an exception set on failure. The tuple values are initialized to the subsequent *n* C arguments pointing to Python objects. ``PyTuple_Pack(2, a, b)`` is equivalent to ``Py_BuildValue("(OO)", a, b)``. @@ -46,12 +48,12 @@ Tuple Objects .. c:function:: Py_ssize_t PyTuple_Size(PyObject *p) Take a pointer to a tuple object, and return the size of that tuple. + On error, return ``-1`` and with an exception set. .. c:function:: Py_ssize_t PyTuple_GET_SIZE(PyObject *p) - Return the size of the tuple *p*, which must be non-``NULL`` and point to a tuple; - no error checking is performed. + Like :c:func:`PyTuple_Size`, but without error checking. .. c:function:: PyObject* PyTuple_GetItem(PyObject *p, Py_ssize_t pos) @@ -74,8 +76,10 @@ Tuple Objects .. c:function:: PyObject* PyTuple_GetSlice(PyObject *p, Py_ssize_t low, Py_ssize_t high) Return the slice of the tuple pointed to by *p* between *low* and *high*, - or ``NULL`` on failure. This is the equivalent of the Python expression - ``p[low:high]``. Indexing from the end of the tuple is not supported. + or ``NULL`` with an exception set on failure. + + This is the equivalent of the Python expression ``p[low:high]``. + Indexing from the end of the tuple is not supported. .. c:function:: int PyTuple_SetItem(PyObject *p, Py_ssize_t pos, PyObject *o) @@ -132,6 +136,8 @@ type. Create a new struct sequence type from the data in *desc*, described below. Instances of the resulting type can be created with :c:func:`PyStructSequence_New`. + Return ``NULL`` with an exception set on failure. + .. c:function:: void PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc) @@ -140,8 +146,8 @@ type. .. c:function:: int PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc) - The same as ``PyStructSequence_InitType``, but returns ``0`` on success and ``-1`` on - failure. + Like :c:func:`PyStructSequence_InitType`, but returns ``0`` on success + and ``-1`` with an exception set on failure. .. versionadded:: 3.4 @@ -152,7 +158,8 @@ type. .. c:member:: const char *name - Name of the struct sequence type. + Fully qualified name of the type; null-terminated UTF-8 encoded. + The name must contain the module name. .. c:member:: const char *doc @@ -198,6 +205,8 @@ type. Creates an instance of *type*, which must have been created with :c:func:`PyStructSequence_NewType`. + Return ``NULL`` with an exception set on failure. + .. c:function:: PyObject* PyStructSequence_GetItem(PyObject *p, Py_ssize_t pos) diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index 5aaa8147..1564fa94 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -53,7 +53,8 @@ Type Objects .. c:function:: PyObject* PyType_GetDict(PyTypeObject* type) Return the type object's internal namespace, which is otherwise only - exposed via a read-only proxy (``cls.__dict__``). This is a + exposed via a read-only proxy (:attr:`cls.__dict__ `). + This is a replacement for accessing :c:member:`~PyTypeObject.tp_dict` directly. The returned dictionary must be treated as read-only. @@ -140,7 +141,7 @@ Type Objects Return true if *a* is a subtype of *b*. This function only checks for actual subtypes, which means that - :meth:`~class.__subclasscheck__` is not called on *b*. Call + :meth:`~type.__subclasscheck__` is not called on *b*. Call :c:func:`PyObject_IsSubclass` to do the same check that :func:`issubclass` would do. @@ -174,14 +175,15 @@ Type Objects .. c:function:: PyObject* PyType_GetName(PyTypeObject *type) - Return the type's name. Equivalent to getting the type's ``__name__`` attribute. + Return the type's name. Equivalent to getting the type's + :attr:`~type.__name__` attribute. .. versionadded:: 3.11 .. c:function:: PyObject* PyType_GetQualName(PyTypeObject *type) Return the type's qualified name. Equivalent to getting the - type's ``__qualname__`` attribute. + type's :attr:`~type.__qualname__` attribute. .. versionadded:: 3.11 @@ -463,19 +465,19 @@ The following functions and structs are used to create The following “offset” fields cannot be set using :c:type:`PyType_Slot`: - * :c:member:`~PyTypeObject.tp_weaklistoffset` - (use :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` instead if possible) - * :c:member:`~PyTypeObject.tp_dictoffset` - (use :c:macro:`Py_TPFLAGS_MANAGED_DICT` instead if possible) - * :c:member:`~PyTypeObject.tp_vectorcall_offset` - (use ``"__vectorcalloffset__"`` in - :ref:`PyMemberDef `) + * :c:member:`~PyTypeObject.tp_weaklistoffset` + (use :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` instead if possible) + * :c:member:`~PyTypeObject.tp_dictoffset` + (use :c:macro:`Py_TPFLAGS_MANAGED_DICT` instead if possible) + * :c:member:`~PyTypeObject.tp_vectorcall_offset` + (use ``"__vectorcalloffset__"`` in + :ref:`PyMemberDef `) - If it is not possible to switch to a ``MANAGED`` flag (for example, - for vectorcall or to support Python older than 3.12), specify the - offset in :c:member:`Py_tp_members `. - See :ref:`PyMemberDef documentation ` - for details. + If it is not possible to switch to a ``MANAGED`` flag (for example, + for vectorcall or to support Python older than 3.12), specify the + offset in :c:member:`Py_tp_members `. + See :ref:`PyMemberDef documentation ` + for details. The following fields cannot be set at all when creating a heap type: @@ -495,14 +497,13 @@ The following functions and structs are used to create To avoid issues, use the *bases* argument of :c:func:`PyType_FromSpecWithBases` instead. - .. versionchanged:: 3.9 + .. versionchanged:: 3.9 + Slots in :c:type:`PyBufferProcs` may be set in the unlimited API. - Slots in :c:type:`PyBufferProcs` may be set in the unlimited API. - - .. versionchanged:: 3.11 - :c:member:`~PyBufferProcs.bf_getbuffer` and - :c:member:`~PyBufferProcs.bf_releasebuffer` are now available - under the :ref:`limited API `. + .. versionchanged:: 3.11 + :c:member:`~PyBufferProcs.bf_getbuffer` and + :c:member:`~PyBufferProcs.bf_releasebuffer` are now available + under the :ref:`limited API `. .. c:member:: void *pfunc diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index f6d865f2..9fc3d358 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -589,12 +589,12 @@ and :c:data:`PyType_Type` effectively act as defaults.) For :ref:`statically allocated type objects `, the *tp_name* field should contain a dot. - Everything before the last dot is made accessible as the :attr:`__module__` + Everything before the last dot is made accessible as the :attr:`~type.__module__` attribute, and everything after the last dot is made accessible as the - :attr:`~definition.__name__` attribute. + :attr:`~type.__name__` attribute. If no dot is present, the entire :c:member:`~PyTypeObject.tp_name` field is made accessible as the - :attr:`~definition.__name__` attribute, and the :attr:`__module__` attribute is undefined + :attr:`~type.__name__` attribute, and the :attr:`~type.__module__` attribute is undefined (unless explicitly set in the dictionary, as explained above). This means your type will be impossible to pickle. Additionally, it will not be listed in module documentations created with pydoc. @@ -704,6 +704,19 @@ and :c:data:`PyType_Type` effectively act as defaults.) Py_DECREF(tp); } + .. warning:: + + In a garbage collected Python, :c:member:`!tp_dealloc` may be called from + any Python thread, not just the thread which created the object (if the + object becomes part of a refcount cycle, that cycle might be collected by + a garbage collection on any thread). This is not a problem for Python + API calls, since the thread on which :c:member:`!tp_dealloc` is called + will own the Global Interpreter Lock (GIL). However, if the object being + destroyed in turn destroys objects from some other C or C++ library, care + should be taken to ensure that destroying those objects on the thread + which called :c:member:`!tp_dealloc` will not violate any assumptions of + the library. + **Inheritance:** @@ -1149,7 +1162,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:macro:: Py_TPFLAGS_MANAGED_DICT - This bit indicates that instances of the class have a ``__dict__`` + This bit indicates that instances of the class have a `~object.__dict__` attribute, and that the space for the dictionary is managed by the VM. If this flag is set, :c:macro:`Py_TPFLAGS_HAVE_GC` should also be set. @@ -1350,8 +1363,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: const char* PyTypeObject.tp_doc An optional pointer to a NUL-terminated C string giving the docstring for this - type object. This is exposed as the :attr:`__doc__` attribute on the type and - instances of the type. + type object. This is exposed as the :attr:`~type.__doc__` attribute on the + type and instances of the type. **Inheritance:** @@ -1584,7 +1597,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) weak references to the type object itself. It is an error to set both the :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` bit and - :c:member:`~PyTypeObject.tp_weaklist`. + :c:member:`~PyTypeObject.tp_weaklistoffset`. **Inheritance:** @@ -1596,7 +1609,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) **Default:** If the :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` bit is set in the - :c:member:`~PyTypeObject.tp_dict` field, then + :c:member:`~PyTypeObject.tp_flags` field, then :c:member:`~PyTypeObject.tp_weaklistoffset` will be set to a negative value, to indicate that it is unsafe to use this field. @@ -2028,7 +2041,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) A collection of subclasses. Internal use only. May be an invalid pointer. To get a list of subclasses, call the Python method - :py:meth:`~class.__subclasses__`. + :py:meth:`~type.__subclasses__`. .. versionchanged:: 3.12 @@ -2101,17 +2114,6 @@ and :c:data:`PyType_Type` effectively act as defaults.) PyErr_Restore(error_type, error_value, error_traceback); } - Also, note that, in a garbage collected Python, - :c:member:`~PyTypeObject.tp_dealloc` may be called from - any Python thread, not just the thread which created the object (if the object - becomes part of a refcount cycle, that cycle might be collected by a garbage - collection on any thread). This is not a problem for Python API calls, since - the thread on which tp_dealloc is called will own the Global Interpreter Lock - (GIL). However, if the object being destroyed in turn destroys objects from some - other C or C++ library, care should be taken to ensure that destroying those - objects on the thread which called tp_dealloc will not violate any assumptions - of the library. - **Inheritance:** This field is inherited by subtypes. @@ -2191,7 +2193,7 @@ This is done by filling a :c:type:`PyType_Spec` structure and calling .. _number-structs: Number Object Structures -======================== +------------------------ .. sectionauthor:: Amaury Forgeot d'Arc @@ -2305,7 +2307,7 @@ Number Object Structures .. _mapping-structs: Mapping Object Structures -========================= +------------------------- .. sectionauthor:: Amaury Forgeot d'Arc @@ -2342,7 +2344,7 @@ Mapping Object Structures .. _sequence-structs: Sequence Object Structures -========================== +-------------------------- .. sectionauthor:: Amaury Forgeot d'Arc @@ -2422,7 +2424,7 @@ Sequence Object Structures .. _buffer-structs: Buffer Object Structures -======================== +------------------------ .. sectionauthor:: Greg J. Stein .. sectionauthor:: Benjamin Peterson @@ -2517,7 +2519,7 @@ Buffer Object Structures Async Object Structures -======================= +----------------------- .. sectionauthor:: Yury Selivanov @@ -2585,7 +2587,7 @@ Async Object Structures .. _slot-typedefs: Slot Type typedefs -================== +------------------ .. c:type:: PyObject *(*allocfunc)(PyTypeObject *cls, Py_ssize_t nitems) @@ -2694,7 +2696,7 @@ Slot Type typedefs .. _typedef-examples: Examples -======== +-------- The following are simple examples of Python type definitions. They include common usage you may encounter. Some demonstrate tricky corner diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index 54a006c0..4d9f9ce0 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -345,6 +345,8 @@ APIs: This is the recommended way to allocate a new Unicode object. Objects created using this function are not resizable. + On error, set an exception and return ``NULL``. + .. versionadded:: 3.3 @@ -598,6 +600,8 @@ APIs: Return the length of the Unicode object, in code points. + On error, set an exception and return ``-1``. + .. versionadded:: 3.3 @@ -641,6 +645,8 @@ APIs: not out of bounds, and that the object can be modified safely (i.e. that it its reference count is one). + Return ``0`` on success, ``-1`` on error with an exception set. + .. versionadded:: 3.3 @@ -650,6 +656,8 @@ APIs: Unicode object and the index is not out of bounds, in contrast to :c:func:`PyUnicode_READ_CHAR`, which performs no error checking. + Return character on success, ``-1`` on error with an exception set. + .. versionadded:: 3.3 @@ -658,6 +666,7 @@ APIs: Return a substring of *unicode*, from character index *start* (included) to character index *end* (excluded). Negative indices are not supported. + On error, set an exception and return ``NULL``. .. versionadded:: 3.3 @@ -1452,15 +1461,35 @@ They all return ``NULL`` or ``-1`` if an exception occurs. existing interned string that is the same as :c:expr:`*p_unicode`, it sets :c:expr:`*p_unicode` to it (releasing the reference to the old string object and creating a new :term:`strong reference` to the interned string object), otherwise it leaves - :c:expr:`*p_unicode` alone and interns it (creating a new :term:`strong reference`). + :c:expr:`*p_unicode` alone and interns it. + (Clarification: even though there is a lot of talk about references, think - of this function as reference-neutral; you own the object after the call - if and only if you owned it before the call.) + of this function as reference-neutral. You must own the object you pass in; + after the call you no longer own the passed-in reference, but you newly own + the result.) + + This function never raises an exception. + On error, it leaves its argument unchanged without interning it. + + Instances of subclasses of :py:class:`str` may not be interned, that is, + :c:expr:`PyUnicode_CheckExact(*p_unicode)` must be true. If it is not, + then -- as with any other error -- the argument is left unchanged. + + Note that interned strings are not “immortal”. + You must keep a reference to the result to benefit from interning. .. c:function:: PyObject* PyUnicode_InternFromString(const char *str) A combination of :c:func:`PyUnicode_FromString` and - :c:func:`PyUnicode_InternInPlace`, returning either a new Unicode string - object that has been interned, or a new ("owned") reference to an earlier - interned string object with the same value. + :c:func:`PyUnicode_InternInPlace`, meant for statically allocated strings. + + Return a new ("owned") reference to either a new Unicode string object + that has been interned, or an earlier interned string object with the + same value. + + Python may keep a reference to the result, or + prevent it from being garbage-collected promptly. + For interning an unbounded number of different strings, such as ones coming + from user input, prefer calling :c:func:`PyUnicode_FromString` and + :c:func:`PyUnicode_InternInPlace` directly. diff --git a/Doc/conf.py b/Doc/conf.py index e292bdd5..4e76c21f 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -6,23 +6,30 @@ # The contents of this file are pickled, so don't put values in the namespace # that aren't pickleable (module imports are okay, they're removed automatically). +import importlib import os import sys import time + +import sphinx + +# Make our custom extensions available to Sphinx sys.path.append(os.path.abspath('tools/extensions')) sys.path.append(os.path.abspath('includes')) +# Python specific content from Doc/Tools/extensions/pyspecific.py from pyspecific import SOURCE_URI # General configuration # --------------------- +# Our custom Sphinx extensions are found in Doc/Tools/extensions/ extensions = [ - 'asdl_highlight', + 'audit_events', + 'availability', 'c_annotations', - 'escape4chm', 'glossary_search', - 'peg_highlight', + 'lexers', 'pyspecific', 'sphinx.ext.coverage', 'sphinx.ext.doctest', @@ -31,7 +38,7 @@ # Skip if downstream redistributors haven't installed it try: - import sphinxext.opengraph + import sphinxext.opengraph # noqa: F401 except ImportError: pass else: @@ -44,7 +51,7 @@ except ImportError: _tkinter = None # Treat warnings as errors, done here to prevent warnings in Sphinx code from -# causing spurious test failures. +# causing spurious CPython test failures. import warnings warnings.simplefilter('error') del warnings @@ -54,35 +61,40 @@ # General substitutions. project = 'Python' -copyright = f"2001-{time.strftime('%Y')}, Python Software Foundation" +if sphinx.version_info[:2] >= (8, 1): + copyright = "2001-%Y, Python Software Foundation" +else: + copyright = f"2001-{time.strftime('%Y')}, Python Software Foundation" # We look for the Include/patchlevel.h file in the current Python source tree # and replace the values accordingly. -import patchlevel -version, release = patchlevel.get_version_info() +# See Doc/tools/extensions/patchlevel.py +version, release = importlib.import_module('patchlevel').get_version_info() rst_epilog = f""" .. |python_version_literal| replace:: ``Python {version}`` """ -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: +# There are two options for replacing |today|. Either, you set today to some +# non-false value and use it. today = '' -# Else, today_fmt is used as the format for a strftime call. +# Or else, today_fmt is used as the format for a strftime call. today_fmt = '%B %d, %Y' # By default, highlight as Python 3. highlight_language = 'python3' # Minimum version of sphinx required -needs_sphinx = '4.2' +needs_sphinx = '7.2.6' # Create table of contents entries for domain objects (e.g. functions, classes, # attributes, etc.). Default is True. -toc_object_entries = False +toc_object_entries = True +# Hide parents to tidy up long entries in sidebar +toc_object_entries_show_parents = 'hide' # Ignore any .rst files in the includes/ directory; -# they're embedded in pages but not rendered individually. +# they're embedded in pages but not rendered as individual pages. # Ignore any .rst files in the venv/ directory. exclude_patterns = ['includes/*.rst', 'venv/*', 'README.rst'] venvdir = os.getenv('VENVDIR') @@ -166,6 +178,7 @@ ('envvar', 'LC_TIME'), ('envvar', 'LINES'), ('envvar', 'LOGNAME'), + ('envvar', 'MANPAGER'), ('envvar', 'PAGER'), ('envvar', 'PATH'), ('envvar', 'PATHEXT'), @@ -256,6 +269,9 @@ ('c:data', 'PyExc_UnicodeWarning'), ('c:data', 'PyExc_UserWarning'), ('c:data', 'PyExc_Warning'), + # Undocumented public C macros + ('c:macro', 'Py_BUILD_ASSERT'), + ('c:macro', 'Py_BUILD_ASSERT_EXPR'), # Do not error nit-picky mode builds when _SubParsersAction.add_parser cannot # be resolved, as the method is currently undocumented. For context, see # https://github.com/python/cpython/pull/103289. @@ -280,7 +296,8 @@ # Disable Docutils smartquotes for several translations smartquotes_excludes = { - 'languages': ['ja', 'fr', 'zh_TW', 'zh_CN'], 'builders': ['man', 'text'], + 'languages': ['ja', 'fr', 'zh_TW', 'zh_CN'], + 'builders': ['man', 'text'], } # Avoid a warning with Sphinx >= 4.0 @@ -289,23 +306,27 @@ # Allow translation of index directives gettext_additional_targets = [ 'index', + 'literal-block', ] # Options for HTML output # ----------------------- -# Use our custom theme. +# Use our custom theme: https://github.com/python/python-docs-theme html_theme = 'python_docs_theme' +# Location of overrides for theme templates and static files html_theme_path = ['tools'] html_theme_options = { 'collapsiblesidebar': True, 'issues_url': '/bugs.html', 'license_url': '/license.html', - 'root_include_title': False # We use the version switcher instead. + 'root_include_title': False, # We use the version switcher instead. } if os.getenv("READTHEDOCS"): - html_theme_options["hosted_on"] = 'Read the Docs' + html_theme_options["hosted_on"] = ( + 'Read the Docs' + ) # Override stylesheet fingerprinting for Windows CHM htmlhelp to fix GH-91207 # https://github.com/python/cpython/issues/91207 @@ -319,17 +340,27 @@ # Deployment preview information # (See .readthedocs.yml and https://docs.readthedocs.io/en/stable/reference/environment-variables.html) -repository_url = os.getenv("READTHEDOCS_GIT_CLONE_URL") +is_deployment_preview = os.getenv("READTHEDOCS_VERSION_TYPE") == "external" +repository_url = os.getenv("READTHEDOCS_GIT_CLONE_URL", "") +repository_url = repository_url.removesuffix(".git") html_context = { - "is_deployment_preview": os.getenv("READTHEDOCS_VERSION_TYPE") == "external", - "repository_url": repository_url.removesuffix(".git") if repository_url else None, - "pr_id": os.getenv("READTHEDOCS_VERSION") + "is_deployment_preview": is_deployment_preview, + "repository_url": repository_url or None, + "pr_id": os.getenv("READTHEDOCS_VERSION"), + "enable_analytics": os.getenv("PYTHON_DOCS_ENABLE_ANALYTICS"), } # This 'Last updated on:' timestamp is inserted at the bottom of every page. -html_last_updated_fmt = time.strftime('%b %d, %Y (%H:%M UTC)', time.gmtime()) +html_last_updated_fmt = '%b %d, %Y (%H:%M UTC)' +if sphinx.version_info[:2] >= (8, 1): + html_last_updated_use_utc = True +else: + html_time = int(os.environ.get('SOURCE_DATE_EPOCH', time.time())) + html_last_updated_fmt = time.strftime( + html_last_updated_fmt, time.gmtime(html_time) + ) -# Path to find HTML templates. +# Path to find HTML templates to override theme templates_path = ['tools/templates'] # Custom sidebar templates, filenames relative to this file. @@ -377,8 +408,8 @@ \let\endVerbatim=\endOriginalVerbatim \setcounter{tocdepth}{2} ''', - # The paper size ('letter' or 'a4'). - 'papersize': 'a4', + # The paper size ('letterpaper' or 'a4paper'). + 'papersize': 'a4paper', # The font size ('10pt', '11pt' or '12pt'). 'pointsize': '10pt', } @@ -387,30 +418,70 @@ # (source start file, target name, title, author, document class [howto/manual]). _stdauthor = 'Guido van Rossum and the Python development team' latex_documents = [ - ('c-api/index', 'c-api.tex', - 'The Python/C API', _stdauthor, 'manual'), - ('extending/index', 'extending.tex', - 'Extending and Embedding Python', _stdauthor, 'manual'), - ('installing/index', 'installing.tex', - 'Installing Python Modules', _stdauthor, 'manual'), - ('library/index', 'library.tex', - 'The Python Library Reference', _stdauthor, 'manual'), - ('reference/index', 'reference.tex', - 'The Python Language Reference', _stdauthor, 'manual'), - ('tutorial/index', 'tutorial.tex', - 'Python Tutorial', _stdauthor, 'manual'), - ('using/index', 'using.tex', - 'Python Setup and Usage', _stdauthor, 'manual'), - ('faq/index', 'faq.tex', - 'Python Frequently Asked Questions', _stdauthor, 'manual'), - ('whatsnew/' + version, 'whatsnew.tex', - 'What\'s New in Python', 'A. M. Kuchling', 'howto'), + ('c-api/index', 'c-api.tex', 'The Python/C API', _stdauthor, 'manual'), + ( + 'extending/index', + 'extending.tex', + 'Extending and Embedding Python', + _stdauthor, + 'manual', + ), + ( + 'installing/index', + 'installing.tex', + 'Installing Python Modules', + _stdauthor, + 'manual', + ), + ( + 'library/index', + 'library.tex', + 'The Python Library Reference', + _stdauthor, + 'manual', + ), + ( + 'reference/index', + 'reference.tex', + 'The Python Language Reference', + _stdauthor, + 'manual', + ), + ( + 'tutorial/index', + 'tutorial.tex', + 'Python Tutorial', + _stdauthor, + 'manual', + ), + ( + 'using/index', + 'using.tex', + 'Python Setup and Usage', + _stdauthor, + 'manual', + ), + ( + 'faq/index', + 'faq.tex', + 'Python Frequently Asked Questions', + _stdauthor, + 'manual', + ), + ( + 'whatsnew/' + version, + 'whatsnew.tex', + 'What\'s New in Python', + 'A. M. Kuchling', + 'howto', + ), ] # Collect all HOWTOs individually -latex_documents.extend(('howto/' + fn[:-4], 'howto-' + fn[:-4] + '.tex', - '', _stdauthor, 'howto') - for fn in os.listdir('howto') - if fn.endswith('.rst') and fn != 'index.rst') +latex_documents.extend( + ('howto/' + fn[:-4], 'howto-' + fn[:-4] + '.tex', '', _stdauthor, 'howto') + for fn in os.listdir('howto') + if fn.endswith('.rst') and fn != 'index.rst' +) # Documents to append as an appendix to all manuals. latex_appendices = ['glossary', 'about', 'license', 'copyright'] @@ -439,8 +510,7 @@ 'test($|_)', ] -coverage_ignore_classes = [ -] +coverage_ignore_classes = [] # Glob patterns for C source files for C API coverage, relative to this directory. coverage_c_path = [ @@ -457,7 +527,7 @@ # The coverage checker will ignore all C items whose names match these regexes # (using re.match) -- the keys must be the same as in coverage_c_regexes. coverage_ignore_c_items = { -# 'cfunction': [...] + # 'cfunction': [...] } @@ -479,9 +549,15 @@ r'https://msdn.microsoft.com/.*': 'https://learn.microsoft.com/.*', r'https://docs.microsoft.com/.*': 'https://learn.microsoft.com/.*', r'https://go.microsoft.com/fwlink/\?LinkID=\d+': 'https://learn.microsoft.com/.*', + # Debian's man page redirects to its current stable version + r'https://manpages.debian.org/\w+\(\d(\w+)?\)': r'https://manpages.debian.org/\w+/[\w/\-\.]*\.\d(\w+)?\.en\.html', # Language redirects r'https://toml.io': 'https://toml.io/en/', r'https://www.redhat.com': 'https://www.redhat.com/en', + # pypi.org project name normalization (upper to lowercase, underscore to hyphen) + r'https://pypi.org/project/[A-Za-z\d_\-\.]+/': r'https://pypi.org/project/[a-z\d\-\.]+/', + # Discourse title name expansion (text changes when title is edited) + r'https://discuss\.python\.org/t/\d+': r'https://discuss\.python\.org/t/.*/\d+', # Other redirects r'https://www.boost.org/libs/.+': r'https://www.boost.org/doc/libs/\d_\d+_\d/.+', r'https://support.microsoft.com/en-us/help/\d+': 'https://support.microsoft.com/en-us/topic/.+', @@ -515,21 +591,31 @@ # mapping unique short aliases to a base URL and a prefix. # https://www.sphinx-doc.org/en/master/usage/extensions/extlinks.html extlinks = { - "cve": ("https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-%s", "CVE-%s"), - "cwe": ("https://cwe.mitre.org/data/definitions/%s.html", "CWE-%s"), "pypi": ("https://pypi.org/project/%s/", "%s"), "source": (SOURCE_URI, "%s"), } extlinks_detect_hardcoded_links = True -# Options for extensions -# ---------------------- +if sphinx.version_info[:2] < (8, 1): + # Sphinx 8.1 has in-built CVE and CWE roles. + extlinks |= { + "cve": ( + "https://www.cve.org/CVERecord?id=CVE-%s", + "CVE-%s", + ), + "cwe": ("https://cwe.mitre.org/data/definitions/%s.html", "CWE-%s"), + } + +# Options for c_annotations extension +# ----------------------------------- # Relative filename of the data files refcount_file = 'data/refcounts.dat' stable_abi_file = 'data/stable_abi.dat' -# sphinxext-opengraph config +# Options for sphinxext-opengraph +# ------------------------------- + ogp_site_url = 'https://docs.python.org/3/' ogp_site_name = 'Python documentation' ogp_image = '_static/og-image.png' diff --git a/Doc/constraints.txt b/Doc/constraints.txt index 16b735ea..26ac1862 100644 --- a/Doc/constraints.txt +++ b/Doc/constraints.txt @@ -7,18 +7,20 @@ # Direct dependencies of Sphinx babel<3 colorama<0.5 -imagesize<1.5 -Jinja2<3.2 -packaging<24 -Pygments>=2.16.1,<3 +imagesize<2 +Jinja2<4 +packaging<25 +Pygments<3 requests<3 snowballstemmer<3 -sphinxcontrib-applehelp<1.0.5 -sphinxcontrib-devhelp<1.0.6 -sphinxcontrib-htmlhelp<2.0.5 -sphinxcontrib-jsmath<1.1 -sphinxcontrib-qthelp<1.0.7 -sphinxcontrib-serializinghtml<1.1.10 +# keep lower-bounds until Sphinx 8.1 is released +# https://github.com/sphinx-doc/sphinx/pull/12756 +sphinxcontrib-applehelp>=1.0.7,<3 +sphinxcontrib-devhelp>=1.0.6,<3 +sphinxcontrib-htmlhelp>=2.0.6,<3 +sphinxcontrib-jsmath>=1.0.1,<2 +sphinxcontrib-qthelp>=1.0.6,<3 +sphinxcontrib-serializinghtml>=1.1.9,<3 # Direct dependencies of Jinja2 (Jinja is a dependency of Sphinx, see above) -MarkupSafe<2.2 +MarkupSafe<3 diff --git a/Doc/contents.rst b/Doc/contents.rst index 24ceacb0..b57f4b09 100644 --- a/Doc/contents.rst +++ b/Doc/contents.rst @@ -14,6 +14,7 @@ installing/index.rst howto/index.rst faq/index.rst + deprecations/index.rst glossary.rst about.rst diff --git a/Doc/data/python3.12.abi b/Doc/data/python3.12.abi index 95dfe64a..875e875a 100644 --- a/Doc/data/python3.12.abi +++ b/Doc/data/python3.12.abi @@ -1,26571 +1,23619 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat index b5d95324..28532620 100644 --- a/Doc/data/refcounts.dat +++ b/Doc/data/refcounts.dat @@ -180,7 +180,7 @@ PyCapsule_IsValid:const char*:name:: PyCapsule_New:PyObject*::+1: PyCapsule_New:void*:pointer:: PyCapsule_New:const char *:name:: -PyCapsule_New::void (* destructor)(PyObject* ):: +PyCapsule_New:void (*)(PyObject *):destructor:: PyCapsule_SetContext:int::: PyCapsule_SetContext:PyObject*:self:0: @@ -349,11 +349,11 @@ PyComplex_CheckExact:int::: PyComplex_CheckExact:PyObject*:p:0: PyComplex_FromCComplex:PyObject*::+1: -PyComplex_FromCComplex::Py_complex v:: +PyComplex_FromCComplex:Py_complex:v:: PyComplex_FromDoubles:PyObject*::+1: -PyComplex_FromDoubles::double real:: -PyComplex_FromDoubles::double imag:: +PyComplex_FromDoubles:double:real:: +PyComplex_FromDoubles:double:imag:: PyComplex_ImagAsDouble:double::: PyComplex_ImagAsDouble:PyObject*:op:0: @@ -622,7 +622,9 @@ PyErr_GetExcInfo:PyObject**:pvalue:+1: PyErr_GetExcInfo:PyObject**:ptraceback:+1: PyErr_GetRaisedException:PyObject*::+1: -PyErr_SetRaisedException:::: + +PyErr_SetRaisedException:void::: +PyErr_SetRaisedException:PyObject *:exc:0:stolen PyErr_GivenExceptionMatches:int::: PyErr_GivenExceptionMatches:PyObject*:given:0: @@ -642,9 +644,9 @@ PyErr_NewExceptionWithDoc:PyObject*:dict:0: PyErr_NoMemory:PyObject*::null: PyErr_NormalizeException:void::: -PyErr_NormalizeException:PyObject**:exc::??? -PyErr_NormalizeException:PyObject**:val::??? -PyErr_NormalizeException:PyObject**:tb::??? +PyErr_NormalizeException:PyObject**:exc:+1:??? +PyErr_NormalizeException:PyObject**:val:+1:??? +PyErr_NormalizeException:PyObject**:tb:+1:??? PyErr_Occurred:PyObject*::0: @@ -1268,7 +1270,7 @@ PyMapping_GetItemString:const char*:key:: PyMapping_HasKey:int::: PyMapping_HasKey:PyObject*:o:0: -PyMapping_HasKey:PyObject*:key:: +PyMapping_HasKey:PyObject*:key:0: PyMapping_HasKeyString:int::: PyMapping_HasKeyString:PyObject*:o:0: @@ -1428,7 +1430,7 @@ PyModule_GetState:void*::: PyModule_GetState:PyObject*:module:0: PyModule_New:PyObject*::+1: -PyModule_New::char* name:: +PyModule_New:char*:name:: PyModule_NewObject:PyObject*::+1: PyModule_NewObject:PyObject*:name:+1: @@ -1438,7 +1440,7 @@ PyModule_SetDocString:PyObject*:module:0: PyModule_SetDocString:const char*:docstring:: PyModuleDef_Init:PyObject*::0: -PyModuleDef_Init:PyModuleDef*:def:0: +PyModuleDef_Init:PyModuleDef*:def:: PyNumber_Absolute:PyObject*::+1: PyNumber_Absolute:PyObject*:o:0: @@ -1950,10 +1952,10 @@ PyRun_StringFlags:PyObject*:locals:0: PyRun_StringFlags:PyCompilerFlags*:flags:: PySeqIter_Check:int::: -PySeqIter_Check::op:: +PySeqIter_Check:PyObject *:op:0: PySeqIter_New:PyObject*::+1: -PySeqIter_New:PyObject*:seq:: +PySeqIter_New:PyObject*:seq:0: PySequence_Check:int::: PySequence_Check:PyObject*:o:0: @@ -2393,7 +2395,7 @@ PyUnicode_GET_DATA_SIZE:PyObject*:o:0: PyUnicode_KIND:int::: PyUnicode_KIND:PyObject*:o:0: -PyUnicode_MAX_CHAR_VALUE:::: +PyUnicode_MAX_CHAR_VALUE:Py_UCS4::: PyUnicode_MAX_CHAR_VALUE:PyObject*:o:0: PyUnicode_AS_UNICODE:Py_UNICODE*::: @@ -2480,7 +2482,7 @@ PyUnicode_FromWideChar:const wchar_t*:w:: PyUnicode_FromWideChar:Py_ssize_t:size:: PyUnicode_AsWideChar:Py_ssize_t::: -PyUnicode_AsWideChar:PyObject*:*unicode:0: +PyUnicode_AsWideChar:PyObject*:unicode:0: PyUnicode_AsWideChar:wchar_t*:w:: PyUnicode_AsWideChar:Py_ssize_t:size:: @@ -2533,7 +2535,7 @@ PyUnicode_AsUTF8String:PyObject*:unicode:0: PyUnicode_AsUTF8AndSize:const char*::: PyUnicode_AsUTF8AndSize:PyObject*:unicode:0: -PyUnicode_AsUTF8AndSize:Py_ssize_t*:size:0: +PyUnicode_AsUTF8AndSize:Py_ssize_t*:size:: PyUnicode_AsUTF8:const char*::: PyUnicode_AsUTF8:PyObject*:unicode:0: @@ -2856,13 +2858,13 @@ PyUnicodeDecodeError_SetStart:PyObject*:exc:0: PyUnicodeDecodeError_SetStart:Py_ssize_t:start:: PyWeakref_Check:int::: -PyWeakref_Check:PyObject*:ob:: +PyWeakref_Check:PyObject*:ob:0: PyWeakref_CheckProxy:int::: -PyWeakref_CheckProxy:PyObject*:ob:: +PyWeakref_CheckProxy:PyObject*:ob:0: PyWeakref_CheckRef:int::: -PyWeakref_CheckRef:PyObject*:ob:: +PyWeakref_CheckRef:PyObject*:ob:0: PyWeakref_GET_OBJECT:PyObject*::0: PyWeakref_GET_OBJECT:PyObject*:ref:0: diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index f112d268..4aa2b351 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -1,868 +1,868 @@ role,name,added,ifdef_note,struct_abi_kind macro,PY_VECTORCALL_ARGUMENTS_OFFSET,3.12,, -function,PyAIter_Check,3.10,, -function,PyArg_Parse,3.2,, -function,PyArg_ParseTuple,3.2,, -function,PyArg_ParseTupleAndKeywords,3.2,, -function,PyArg_UnpackTuple,3.2,, -function,PyArg_VaParse,3.2,, -function,PyArg_VaParseTupleAndKeywords,3.2,, -function,PyArg_ValidateKeywordArguments,3.2,, -var,PyBaseObject_Type,3.2,, -function,PyBool_FromLong,3.2,, -var,PyBool_Type,3.2,, -function,PyBuffer_FillContiguousStrides,3.11,, -function,PyBuffer_FillInfo,3.11,, -function,PyBuffer_FromContiguous,3.11,, -function,PyBuffer_GetPointer,3.11,, -function,PyBuffer_IsContiguous,3.11,, -function,PyBuffer_Release,3.11,, -function,PyBuffer_SizeFromFormat,3.11,, -function,PyBuffer_ToContiguous,3.11,, -var,PyByteArrayIter_Type,3.2,, -function,PyByteArray_AsString,3.2,, -function,PyByteArray_Concat,3.2,, -function,PyByteArray_FromObject,3.2,, -function,PyByteArray_FromStringAndSize,3.2,, -function,PyByteArray_Resize,3.2,, -function,PyByteArray_Size,3.2,, -var,PyByteArray_Type,3.2,, -var,PyBytesIter_Type,3.2,, -function,PyBytes_AsString,3.2,, -function,PyBytes_AsStringAndSize,3.2,, -function,PyBytes_Concat,3.2,, -function,PyBytes_ConcatAndDel,3.2,, -function,PyBytes_DecodeEscape,3.2,, -function,PyBytes_FromFormat,3.2,, -function,PyBytes_FromFormatV,3.2,, -function,PyBytes_FromObject,3.2,, -function,PyBytes_FromString,3.2,, -function,PyBytes_FromStringAndSize,3.2,, -function,PyBytes_Repr,3.2,, -function,PyBytes_Size,3.2,, -var,PyBytes_Type,3.2,, +func,PyAIter_Check,3.10,, +func,PyArg_Parse,3.2,, +func,PyArg_ParseTuple,3.2,, +func,PyArg_ParseTupleAndKeywords,3.2,, +func,PyArg_UnpackTuple,3.2,, +func,PyArg_VaParse,3.2,, +func,PyArg_VaParseTupleAndKeywords,3.2,, +func,PyArg_ValidateKeywordArguments,3.2,, +data,PyBaseObject_Type,3.2,, +func,PyBool_FromLong,3.2,, +data,PyBool_Type,3.2,, +func,PyBuffer_FillContiguousStrides,3.11,, +func,PyBuffer_FillInfo,3.11,, +func,PyBuffer_FromContiguous,3.11,, +func,PyBuffer_GetPointer,3.11,, +func,PyBuffer_IsContiguous,3.11,, +func,PyBuffer_Release,3.11,, +func,PyBuffer_SizeFromFormat,3.11,, +func,PyBuffer_ToContiguous,3.11,, +data,PyByteArrayIter_Type,3.2,, +func,PyByteArray_AsString,3.2,, +func,PyByteArray_Concat,3.2,, +func,PyByteArray_FromObject,3.2,, +func,PyByteArray_FromStringAndSize,3.2,, +func,PyByteArray_Resize,3.2,, +func,PyByteArray_Size,3.2,, +data,PyByteArray_Type,3.2,, +data,PyBytesIter_Type,3.2,, +func,PyBytes_AsString,3.2,, +func,PyBytes_AsStringAndSize,3.2,, +func,PyBytes_Concat,3.2,, +func,PyBytes_ConcatAndDel,3.2,, +func,PyBytes_DecodeEscape,3.2,, +func,PyBytes_FromFormat,3.2,, +func,PyBytes_FromFormatV,3.2,, +func,PyBytes_FromObject,3.2,, +func,PyBytes_FromString,3.2,, +func,PyBytes_FromStringAndSize,3.2,, +func,PyBytes_Repr,3.2,, +func,PyBytes_Size,3.2,, +data,PyBytes_Type,3.2,, type,PyCFunction,3.2,, type,PyCFunctionWithKeywords,3.2,, -function,PyCFunction_Call,3.2,, -function,PyCFunction_GetFlags,3.2,, -function,PyCFunction_GetFunction,3.2,, -function,PyCFunction_GetSelf,3.2,, -function,PyCFunction_New,3.4,, -function,PyCFunction_NewEx,3.2,, -var,PyCFunction_Type,3.2,, -function,PyCMethod_New,3.9,, -function,PyCallIter_New,3.2,, -var,PyCallIter_Type,3.2,, -function,PyCallable_Check,3.2,, +func,PyCFunction_Call,3.2,, +func,PyCFunction_GetFlags,3.2,, +func,PyCFunction_GetFunction,3.2,, +func,PyCFunction_GetSelf,3.2,, +func,PyCFunction_New,3.4,, +func,PyCFunction_NewEx,3.2,, +data,PyCFunction_Type,3.2,, +func,PyCMethod_New,3.9,, +func,PyCallIter_New,3.2,, +data,PyCallIter_Type,3.2,, +func,PyCallable_Check,3.2,, type,PyCapsule_Destructor,3.2,, -function,PyCapsule_GetContext,3.2,, -function,PyCapsule_GetDestructor,3.2,, -function,PyCapsule_GetName,3.2,, -function,PyCapsule_GetPointer,3.2,, -function,PyCapsule_Import,3.2,, -function,PyCapsule_IsValid,3.2,, -function,PyCapsule_New,3.2,, -function,PyCapsule_SetContext,3.2,, -function,PyCapsule_SetDestructor,3.2,, -function,PyCapsule_SetName,3.2,, -function,PyCapsule_SetPointer,3.2,, -var,PyCapsule_Type,3.2,, -var,PyClassMethodDescr_Type,3.2,, -function,PyCodec_BackslashReplaceErrors,3.2,, -function,PyCodec_Decode,3.2,, -function,PyCodec_Decoder,3.2,, -function,PyCodec_Encode,3.2,, -function,PyCodec_Encoder,3.2,, -function,PyCodec_IgnoreErrors,3.2,, -function,PyCodec_IncrementalDecoder,3.2,, -function,PyCodec_IncrementalEncoder,3.2,, -function,PyCodec_KnownEncoding,3.2,, -function,PyCodec_LookupError,3.2,, -function,PyCodec_NameReplaceErrors,3.7,, -function,PyCodec_Register,3.2,, -function,PyCodec_RegisterError,3.2,, -function,PyCodec_ReplaceErrors,3.2,, -function,PyCodec_StreamReader,3.2,, -function,PyCodec_StreamWriter,3.2,, -function,PyCodec_StrictErrors,3.2,, -function,PyCodec_Unregister,3.10,, -function,PyCodec_XMLCharRefReplaceErrors,3.2,, -function,PyComplex_FromDoubles,3.2,, -function,PyComplex_ImagAsDouble,3.2,, -function,PyComplex_RealAsDouble,3.2,, -var,PyComplex_Type,3.2,, -function,PyDescr_NewClassMethod,3.2,, -function,PyDescr_NewGetSet,3.2,, -function,PyDescr_NewMember,3.2,, -function,PyDescr_NewMethod,3.2,, -var,PyDictItems_Type,3.2,, -var,PyDictIterItem_Type,3.2,, -var,PyDictIterKey_Type,3.2,, -var,PyDictIterValue_Type,3.2,, -var,PyDictKeys_Type,3.2,, -function,PyDictProxy_New,3.2,, -var,PyDictProxy_Type,3.2,, -var,PyDictRevIterItem_Type,3.8,, -var,PyDictRevIterKey_Type,3.8,, -var,PyDictRevIterValue_Type,3.8,, -var,PyDictValues_Type,3.2,, -function,PyDict_Clear,3.2,, -function,PyDict_Contains,3.2,, -function,PyDict_Copy,3.2,, -function,PyDict_DelItem,3.2,, -function,PyDict_DelItemString,3.2,, -function,PyDict_GetItem,3.2,, -function,PyDict_GetItemString,3.2,, -function,PyDict_GetItemWithError,3.2,, -function,PyDict_Items,3.2,, -function,PyDict_Keys,3.2,, -function,PyDict_Merge,3.2,, -function,PyDict_MergeFromSeq2,3.2,, -function,PyDict_New,3.2,, -function,PyDict_Next,3.2,, -function,PyDict_SetItem,3.2,, -function,PyDict_SetItemString,3.2,, -function,PyDict_Size,3.2,, -var,PyDict_Type,3.2,, -function,PyDict_Update,3.2,, -function,PyDict_Values,3.2,, -var,PyEllipsis_Type,3.2,, -var,PyEnum_Type,3.2,, -function,PyErr_BadArgument,3.2,, -function,PyErr_BadInternalCall,3.2,, -function,PyErr_CheckSignals,3.2,, -function,PyErr_Clear,3.2,, -function,PyErr_Display,3.2,, -function,PyErr_DisplayException,3.12,, -function,PyErr_ExceptionMatches,3.2,, -function,PyErr_Fetch,3.2,, -function,PyErr_Format,3.2,, -function,PyErr_FormatV,3.5,, -function,PyErr_GetExcInfo,3.7,, -function,PyErr_GetHandledException,3.11,, -function,PyErr_GetRaisedException,3.12,, -function,PyErr_GivenExceptionMatches,3.2,, -function,PyErr_NewException,3.2,, -function,PyErr_NewExceptionWithDoc,3.2,, -function,PyErr_NoMemory,3.2,, -function,PyErr_NormalizeException,3.2,, -function,PyErr_Occurred,3.2,, -function,PyErr_Print,3.2,, -function,PyErr_PrintEx,3.2,, -function,PyErr_ProgramText,3.2,, -function,PyErr_ResourceWarning,3.6,, -function,PyErr_Restore,3.2,, -function,PyErr_SetExcFromWindowsErr,3.7,on Windows, -function,PyErr_SetExcFromWindowsErrWithFilename,3.7,on Windows, -function,PyErr_SetExcFromWindowsErrWithFilenameObject,3.7,on Windows, -function,PyErr_SetExcFromWindowsErrWithFilenameObjects,3.7,on Windows, -function,PyErr_SetExcInfo,3.7,, -function,PyErr_SetFromErrno,3.2,, -function,PyErr_SetFromErrnoWithFilename,3.2,, -function,PyErr_SetFromErrnoWithFilenameObject,3.2,, -function,PyErr_SetFromErrnoWithFilenameObjects,3.7,, -function,PyErr_SetFromWindowsErr,3.7,on Windows, -function,PyErr_SetFromWindowsErrWithFilename,3.7,on Windows, -function,PyErr_SetHandledException,3.11,, -function,PyErr_SetImportError,3.7,, -function,PyErr_SetImportErrorSubclass,3.6,, -function,PyErr_SetInterrupt,3.2,, -function,PyErr_SetInterruptEx,3.10,, -function,PyErr_SetNone,3.2,, -function,PyErr_SetObject,3.2,, -function,PyErr_SetRaisedException,3.12,, -function,PyErr_SetString,3.2,, -function,PyErr_SyntaxLocation,3.2,, -function,PyErr_SyntaxLocationEx,3.7,, -function,PyErr_WarnEx,3.2,, -function,PyErr_WarnExplicit,3.2,, -function,PyErr_WarnFormat,3.2,, -function,PyErr_WriteUnraisable,3.2,, -function,PyEval_AcquireLock,3.2,, -function,PyEval_AcquireThread,3.2,, -function,PyEval_CallFunction,3.2,, -function,PyEval_CallMethod,3.2,, -function,PyEval_CallObjectWithKeywords,3.2,, -function,PyEval_EvalCode,3.2,, -function,PyEval_EvalCodeEx,3.2,, -function,PyEval_EvalFrame,3.2,, -function,PyEval_EvalFrameEx,3.2,, -function,PyEval_GetBuiltins,3.2,, -function,PyEval_GetFrame,3.2,, -function,PyEval_GetFuncDesc,3.2,, -function,PyEval_GetFuncName,3.2,, -function,PyEval_GetGlobals,3.2,, -function,PyEval_GetLocals,3.2,, -function,PyEval_InitThreads,3.2,, -function,PyEval_ReleaseLock,3.2,, -function,PyEval_ReleaseThread,3.2,, -function,PyEval_RestoreThread,3.2,, -function,PyEval_SaveThread,3.2,, -function,PyEval_ThreadsInitialized,3.2,, -var,PyExc_ArithmeticError,3.2,, -var,PyExc_AssertionError,3.2,, -var,PyExc_AttributeError,3.2,, -var,PyExc_BaseException,3.2,, -var,PyExc_BaseExceptionGroup,3.11,, -var,PyExc_BlockingIOError,3.7,, -var,PyExc_BrokenPipeError,3.7,, -var,PyExc_BufferError,3.2,, -var,PyExc_BytesWarning,3.2,, -var,PyExc_ChildProcessError,3.7,, -var,PyExc_ConnectionAbortedError,3.7,, -var,PyExc_ConnectionError,3.7,, -var,PyExc_ConnectionRefusedError,3.7,, -var,PyExc_ConnectionResetError,3.7,, -var,PyExc_DeprecationWarning,3.2,, -var,PyExc_EOFError,3.2,, -var,PyExc_EncodingWarning,3.10,, -var,PyExc_EnvironmentError,3.2,, -var,PyExc_Exception,3.2,, -var,PyExc_FileExistsError,3.7,, -var,PyExc_FileNotFoundError,3.7,, -var,PyExc_FloatingPointError,3.2,, -var,PyExc_FutureWarning,3.2,, -var,PyExc_GeneratorExit,3.2,, -var,PyExc_IOError,3.2,, -var,PyExc_ImportError,3.2,, -var,PyExc_ImportWarning,3.2,, -var,PyExc_IndentationError,3.2,, -var,PyExc_IndexError,3.2,, -var,PyExc_InterruptedError,3.7,, -var,PyExc_IsADirectoryError,3.7,, -var,PyExc_KeyError,3.2,, -var,PyExc_KeyboardInterrupt,3.2,, -var,PyExc_LookupError,3.2,, -var,PyExc_MemoryError,3.2,, -var,PyExc_ModuleNotFoundError,3.6,, -var,PyExc_NameError,3.2,, -var,PyExc_NotADirectoryError,3.7,, -var,PyExc_NotImplementedError,3.2,, -var,PyExc_OSError,3.2,, -var,PyExc_OverflowError,3.2,, -var,PyExc_PendingDeprecationWarning,3.2,, -var,PyExc_PermissionError,3.7,, -var,PyExc_ProcessLookupError,3.7,, -var,PyExc_RecursionError,3.7,, -var,PyExc_ReferenceError,3.2,, -var,PyExc_ResourceWarning,3.7,, -var,PyExc_RuntimeError,3.2,, -var,PyExc_RuntimeWarning,3.2,, -var,PyExc_StopAsyncIteration,3.7,, -var,PyExc_StopIteration,3.2,, -var,PyExc_SyntaxError,3.2,, -var,PyExc_SyntaxWarning,3.2,, -var,PyExc_SystemError,3.2,, -var,PyExc_SystemExit,3.2,, -var,PyExc_TabError,3.2,, -var,PyExc_TimeoutError,3.7,, -var,PyExc_TypeError,3.2,, -var,PyExc_UnboundLocalError,3.2,, -var,PyExc_UnicodeDecodeError,3.2,, -var,PyExc_UnicodeEncodeError,3.2,, -var,PyExc_UnicodeError,3.2,, -var,PyExc_UnicodeTranslateError,3.2,, -var,PyExc_UnicodeWarning,3.2,, -var,PyExc_UserWarning,3.2,, -var,PyExc_ValueError,3.2,, -var,PyExc_Warning,3.2,, -var,PyExc_WindowsError,3.7,on Windows, -var,PyExc_ZeroDivisionError,3.2,, -function,PyExceptionClass_Name,3.8,, -function,PyException_GetArgs,3.12,, -function,PyException_GetCause,3.2,, -function,PyException_GetContext,3.2,, -function,PyException_GetTraceback,3.2,, -function,PyException_SetArgs,3.12,, -function,PyException_SetCause,3.2,, -function,PyException_SetContext,3.2,, -function,PyException_SetTraceback,3.2,, -function,PyFile_FromFd,3.2,, -function,PyFile_GetLine,3.2,, -function,PyFile_WriteObject,3.2,, -function,PyFile_WriteString,3.2,, -var,PyFilter_Type,3.2,, -function,PyFloat_AsDouble,3.2,, -function,PyFloat_FromDouble,3.2,, -function,PyFloat_FromString,3.2,, -function,PyFloat_GetInfo,3.2,, -function,PyFloat_GetMax,3.2,, -function,PyFloat_GetMin,3.2,, -var,PyFloat_Type,3.2,, +func,PyCapsule_GetContext,3.2,, +func,PyCapsule_GetDestructor,3.2,, +func,PyCapsule_GetName,3.2,, +func,PyCapsule_GetPointer,3.2,, +func,PyCapsule_Import,3.2,, +func,PyCapsule_IsValid,3.2,, +func,PyCapsule_New,3.2,, +func,PyCapsule_SetContext,3.2,, +func,PyCapsule_SetDestructor,3.2,, +func,PyCapsule_SetName,3.2,, +func,PyCapsule_SetPointer,3.2,, +data,PyCapsule_Type,3.2,, +data,PyClassMethodDescr_Type,3.2,, +func,PyCodec_BackslashReplaceErrors,3.2,, +func,PyCodec_Decode,3.2,, +func,PyCodec_Decoder,3.2,, +func,PyCodec_Encode,3.2,, +func,PyCodec_Encoder,3.2,, +func,PyCodec_IgnoreErrors,3.2,, +func,PyCodec_IncrementalDecoder,3.2,, +func,PyCodec_IncrementalEncoder,3.2,, +func,PyCodec_KnownEncoding,3.2,, +func,PyCodec_LookupError,3.2,, +func,PyCodec_NameReplaceErrors,3.7,, +func,PyCodec_Register,3.2,, +func,PyCodec_RegisterError,3.2,, +func,PyCodec_ReplaceErrors,3.2,, +func,PyCodec_StreamReader,3.2,, +func,PyCodec_StreamWriter,3.2,, +func,PyCodec_StrictErrors,3.2,, +func,PyCodec_Unregister,3.10,, +func,PyCodec_XMLCharRefReplaceErrors,3.2,, +func,PyComplex_FromDoubles,3.2,, +func,PyComplex_ImagAsDouble,3.2,, +func,PyComplex_RealAsDouble,3.2,, +data,PyComplex_Type,3.2,, +func,PyDescr_NewClassMethod,3.2,, +func,PyDescr_NewGetSet,3.2,, +func,PyDescr_NewMember,3.2,, +func,PyDescr_NewMethod,3.2,, +data,PyDictItems_Type,3.2,, +data,PyDictIterItem_Type,3.2,, +data,PyDictIterKey_Type,3.2,, +data,PyDictIterValue_Type,3.2,, +data,PyDictKeys_Type,3.2,, +func,PyDictProxy_New,3.2,, +data,PyDictProxy_Type,3.2,, +data,PyDictRevIterItem_Type,3.8,, +data,PyDictRevIterKey_Type,3.8,, +data,PyDictRevIterValue_Type,3.8,, +data,PyDictValues_Type,3.2,, +func,PyDict_Clear,3.2,, +func,PyDict_Contains,3.2,, +func,PyDict_Copy,3.2,, +func,PyDict_DelItem,3.2,, +func,PyDict_DelItemString,3.2,, +func,PyDict_GetItem,3.2,, +func,PyDict_GetItemString,3.2,, +func,PyDict_GetItemWithError,3.2,, +func,PyDict_Items,3.2,, +func,PyDict_Keys,3.2,, +func,PyDict_Merge,3.2,, +func,PyDict_MergeFromSeq2,3.2,, +func,PyDict_New,3.2,, +func,PyDict_Next,3.2,, +func,PyDict_SetItem,3.2,, +func,PyDict_SetItemString,3.2,, +func,PyDict_Size,3.2,, +data,PyDict_Type,3.2,, +func,PyDict_Update,3.2,, +func,PyDict_Values,3.2,, +data,PyEllipsis_Type,3.2,, +data,PyEnum_Type,3.2,, +func,PyErr_BadArgument,3.2,, +func,PyErr_BadInternalCall,3.2,, +func,PyErr_CheckSignals,3.2,, +func,PyErr_Clear,3.2,, +func,PyErr_Display,3.2,, +func,PyErr_DisplayException,3.12,, +func,PyErr_ExceptionMatches,3.2,, +func,PyErr_Fetch,3.2,, +func,PyErr_Format,3.2,, +func,PyErr_FormatV,3.5,, +func,PyErr_GetExcInfo,3.7,, +func,PyErr_GetHandledException,3.11,, +func,PyErr_GetRaisedException,3.12,, +func,PyErr_GivenExceptionMatches,3.2,, +func,PyErr_NewException,3.2,, +func,PyErr_NewExceptionWithDoc,3.2,, +func,PyErr_NoMemory,3.2,, +func,PyErr_NormalizeException,3.2,, +func,PyErr_Occurred,3.2,, +func,PyErr_Print,3.2,, +func,PyErr_PrintEx,3.2,, +func,PyErr_ProgramText,3.2,, +func,PyErr_ResourceWarning,3.6,, +func,PyErr_Restore,3.2,, +func,PyErr_SetExcFromWindowsErr,3.7,on Windows, +func,PyErr_SetExcFromWindowsErrWithFilename,3.7,on Windows, +func,PyErr_SetExcFromWindowsErrWithFilenameObject,3.7,on Windows, +func,PyErr_SetExcFromWindowsErrWithFilenameObjects,3.7,on Windows, +func,PyErr_SetExcInfo,3.7,, +func,PyErr_SetFromErrno,3.2,, +func,PyErr_SetFromErrnoWithFilename,3.2,, +func,PyErr_SetFromErrnoWithFilenameObject,3.2,, +func,PyErr_SetFromErrnoWithFilenameObjects,3.7,, +func,PyErr_SetFromWindowsErr,3.7,on Windows, +func,PyErr_SetFromWindowsErrWithFilename,3.7,on Windows, +func,PyErr_SetHandledException,3.11,, +func,PyErr_SetImportError,3.7,, +func,PyErr_SetImportErrorSubclass,3.6,, +func,PyErr_SetInterrupt,3.2,, +func,PyErr_SetInterruptEx,3.10,, +func,PyErr_SetNone,3.2,, +func,PyErr_SetObject,3.2,, +func,PyErr_SetRaisedException,3.12,, +func,PyErr_SetString,3.2,, +func,PyErr_SyntaxLocation,3.2,, +func,PyErr_SyntaxLocationEx,3.7,, +func,PyErr_WarnEx,3.2,, +func,PyErr_WarnExplicit,3.2,, +func,PyErr_WarnFormat,3.2,, +func,PyErr_WriteUnraisable,3.2,, +func,PyEval_AcquireLock,3.2,, +func,PyEval_AcquireThread,3.2,, +func,PyEval_CallFunction,3.2,, +func,PyEval_CallMethod,3.2,, +func,PyEval_CallObjectWithKeywords,3.2,, +func,PyEval_EvalCode,3.2,, +func,PyEval_EvalCodeEx,3.2,, +func,PyEval_EvalFrame,3.2,, +func,PyEval_EvalFrameEx,3.2,, +func,PyEval_GetBuiltins,3.2,, +func,PyEval_GetFrame,3.2,, +func,PyEval_GetFuncDesc,3.2,, +func,PyEval_GetFuncName,3.2,, +func,PyEval_GetGlobals,3.2,, +func,PyEval_GetLocals,3.2,, +func,PyEval_InitThreads,3.2,, +func,PyEval_ReleaseLock,3.2,, +func,PyEval_ReleaseThread,3.2,, +func,PyEval_RestoreThread,3.2,, +func,PyEval_SaveThread,3.2,, +func,PyEval_ThreadsInitialized,3.2,, +data,PyExc_ArithmeticError,3.2,, +data,PyExc_AssertionError,3.2,, +data,PyExc_AttributeError,3.2,, +data,PyExc_BaseException,3.2,, +data,PyExc_BaseExceptionGroup,3.11,, +data,PyExc_BlockingIOError,3.7,, +data,PyExc_BrokenPipeError,3.7,, +data,PyExc_BufferError,3.2,, +data,PyExc_BytesWarning,3.2,, +data,PyExc_ChildProcessError,3.7,, +data,PyExc_ConnectionAbortedError,3.7,, +data,PyExc_ConnectionError,3.7,, +data,PyExc_ConnectionRefusedError,3.7,, +data,PyExc_ConnectionResetError,3.7,, +data,PyExc_DeprecationWarning,3.2,, +data,PyExc_EOFError,3.2,, +data,PyExc_EncodingWarning,3.10,, +data,PyExc_EnvironmentError,3.2,, +data,PyExc_Exception,3.2,, +data,PyExc_FileExistsError,3.7,, +data,PyExc_FileNotFoundError,3.7,, +data,PyExc_FloatingPointError,3.2,, +data,PyExc_FutureWarning,3.2,, +data,PyExc_GeneratorExit,3.2,, +data,PyExc_IOError,3.2,, +data,PyExc_ImportError,3.2,, +data,PyExc_ImportWarning,3.2,, +data,PyExc_IndentationError,3.2,, +data,PyExc_IndexError,3.2,, +data,PyExc_InterruptedError,3.7,, +data,PyExc_IsADirectoryError,3.7,, +data,PyExc_KeyError,3.2,, +data,PyExc_KeyboardInterrupt,3.2,, +data,PyExc_LookupError,3.2,, +data,PyExc_MemoryError,3.2,, +data,PyExc_ModuleNotFoundError,3.6,, +data,PyExc_NameError,3.2,, +data,PyExc_NotADirectoryError,3.7,, +data,PyExc_NotImplementedError,3.2,, +data,PyExc_OSError,3.2,, +data,PyExc_OverflowError,3.2,, +data,PyExc_PendingDeprecationWarning,3.2,, +data,PyExc_PermissionError,3.7,, +data,PyExc_ProcessLookupError,3.7,, +data,PyExc_RecursionError,3.7,, +data,PyExc_ReferenceError,3.2,, +data,PyExc_ResourceWarning,3.7,, +data,PyExc_RuntimeError,3.2,, +data,PyExc_RuntimeWarning,3.2,, +data,PyExc_StopAsyncIteration,3.7,, +data,PyExc_StopIteration,3.2,, +data,PyExc_SyntaxError,3.2,, +data,PyExc_SyntaxWarning,3.2,, +data,PyExc_SystemError,3.2,, +data,PyExc_SystemExit,3.2,, +data,PyExc_TabError,3.2,, +data,PyExc_TimeoutError,3.7,, +data,PyExc_TypeError,3.2,, +data,PyExc_UnboundLocalError,3.2,, +data,PyExc_UnicodeDecodeError,3.2,, +data,PyExc_UnicodeEncodeError,3.2,, +data,PyExc_UnicodeError,3.2,, +data,PyExc_UnicodeTranslateError,3.2,, +data,PyExc_UnicodeWarning,3.2,, +data,PyExc_UserWarning,3.2,, +data,PyExc_ValueError,3.2,, +data,PyExc_Warning,3.2,, +data,PyExc_WindowsError,3.7,on Windows, +data,PyExc_ZeroDivisionError,3.2,, +func,PyExceptionClass_Name,3.8,, +func,PyException_GetArgs,3.12,, +func,PyException_GetCause,3.2,, +func,PyException_GetContext,3.2,, +func,PyException_GetTraceback,3.2,, +func,PyException_SetArgs,3.12,, +func,PyException_SetCause,3.2,, +func,PyException_SetContext,3.2,, +func,PyException_SetTraceback,3.2,, +func,PyFile_FromFd,3.2,, +func,PyFile_GetLine,3.2,, +func,PyFile_WriteObject,3.2,, +func,PyFile_WriteString,3.2,, +data,PyFilter_Type,3.2,, +func,PyFloat_AsDouble,3.2,, +func,PyFloat_FromDouble,3.2,, +func,PyFloat_FromString,3.2,, +func,PyFloat_GetInfo,3.2,, +func,PyFloat_GetMax,3.2,, +func,PyFloat_GetMin,3.2,, +data,PyFloat_Type,3.2,, type,PyFrameObject,3.2,,opaque -function,PyFrame_GetCode,3.10,, -function,PyFrame_GetLineNumber,3.10,, -function,PyFrozenSet_New,3.2,, -var,PyFrozenSet_Type,3.2,, -function,PyGC_Collect,3.2,, -function,PyGC_Disable,3.10,, -function,PyGC_Enable,3.10,, -function,PyGC_IsEnabled,3.10,, -function,PyGILState_Ensure,3.2,, -function,PyGILState_GetThisThreadState,3.2,, -function,PyGILState_Release,3.2,, +func,PyFrame_GetCode,3.10,, +func,PyFrame_GetLineNumber,3.10,, +func,PyFrozenSet_New,3.2,, +data,PyFrozenSet_Type,3.2,, +func,PyGC_Collect,3.2,, +func,PyGC_Disable,3.10,, +func,PyGC_Enable,3.10,, +func,PyGC_IsEnabled,3.10,, +func,PyGILState_Ensure,3.2,, +func,PyGILState_GetThisThreadState,3.2,, +func,PyGILState_Release,3.2,, type,PyGILState_STATE,3.2,, type,PyGetSetDef,3.2,,full-abi -var,PyGetSetDescr_Type,3.2,, -function,PyImport_AddModule,3.2,, -function,PyImport_AddModuleObject,3.7,, -function,PyImport_AppendInittab,3.2,, -function,PyImport_ExecCodeModule,3.2,, -function,PyImport_ExecCodeModuleEx,3.2,, -function,PyImport_ExecCodeModuleObject,3.7,, -function,PyImport_ExecCodeModuleWithPathnames,3.2,, -function,PyImport_GetImporter,3.2,, -function,PyImport_GetMagicNumber,3.2,, -function,PyImport_GetMagicTag,3.2,, -function,PyImport_GetModule,3.8,, -function,PyImport_GetModuleDict,3.2,, -function,PyImport_Import,3.2,, -function,PyImport_ImportFrozenModule,3.2,, -function,PyImport_ImportFrozenModuleObject,3.7,, -function,PyImport_ImportModule,3.2,, -function,PyImport_ImportModuleLevel,3.2,, -function,PyImport_ImportModuleLevelObject,3.7,, -function,PyImport_ImportModuleNoBlock,3.2,, -function,PyImport_ReloadModule,3.2,, -function,PyIndex_Check,3.8,, +data,PyGetSetDescr_Type,3.2,, +func,PyImport_AddModule,3.2,, +func,PyImport_AddModuleObject,3.7,, +func,PyImport_AppendInittab,3.2,, +func,PyImport_ExecCodeModule,3.2,, +func,PyImport_ExecCodeModuleEx,3.2,, +func,PyImport_ExecCodeModuleObject,3.7,, +func,PyImport_ExecCodeModuleWithPathnames,3.2,, +func,PyImport_GetImporter,3.2,, +func,PyImport_GetMagicNumber,3.2,, +func,PyImport_GetMagicTag,3.2,, +func,PyImport_GetModule,3.8,, +func,PyImport_GetModuleDict,3.2,, +func,PyImport_Import,3.2,, +func,PyImport_ImportFrozenModule,3.2,, +func,PyImport_ImportFrozenModuleObject,3.7,, +func,PyImport_ImportModule,3.2,, +func,PyImport_ImportModuleLevel,3.2,, +func,PyImport_ImportModuleLevelObject,3.7,, +func,PyImport_ImportModuleNoBlock,3.2,, +func,PyImport_ReloadModule,3.2,, +func,PyIndex_Check,3.8,, type,PyInterpreterState,3.2,,opaque -function,PyInterpreterState_Clear,3.2,, -function,PyInterpreterState_Delete,3.2,, -function,PyInterpreterState_Get,3.9,, -function,PyInterpreterState_GetDict,3.8,, -function,PyInterpreterState_GetID,3.7,, -function,PyInterpreterState_New,3.2,, -function,PyIter_Check,3.8,, -function,PyIter_Next,3.2,, -function,PyIter_Send,3.10,, -var,PyListIter_Type,3.2,, -var,PyListRevIter_Type,3.2,, -function,PyList_Append,3.2,, -function,PyList_AsTuple,3.2,, -function,PyList_GetItem,3.2,, -function,PyList_GetSlice,3.2,, -function,PyList_Insert,3.2,, -function,PyList_New,3.2,, -function,PyList_Reverse,3.2,, -function,PyList_SetItem,3.2,, -function,PyList_SetSlice,3.2,, -function,PyList_Size,3.2,, -function,PyList_Sort,3.2,, -var,PyList_Type,3.2,, +func,PyInterpreterState_Clear,3.2,, +func,PyInterpreterState_Delete,3.2,, +func,PyInterpreterState_Get,3.9,, +func,PyInterpreterState_GetDict,3.8,, +func,PyInterpreterState_GetID,3.7,, +func,PyInterpreterState_New,3.2,, +func,PyIter_Check,3.8,, +func,PyIter_Next,3.2,, +func,PyIter_Send,3.10,, +data,PyListIter_Type,3.2,, +data,PyListRevIter_Type,3.2,, +func,PyList_Append,3.2,, +func,PyList_AsTuple,3.2,, +func,PyList_GetItem,3.2,, +func,PyList_GetSlice,3.2,, +func,PyList_Insert,3.2,, +func,PyList_New,3.2,, +func,PyList_Reverse,3.2,, +func,PyList_SetItem,3.2,, +func,PyList_SetSlice,3.2,, +func,PyList_Size,3.2,, +func,PyList_Sort,3.2,, +data,PyList_Type,3.2,, type,PyLongObject,3.2,,opaque -var,PyLongRangeIter_Type,3.2,, -function,PyLong_AsDouble,3.2,, -function,PyLong_AsLong,3.2,, -function,PyLong_AsLongAndOverflow,3.2,, -function,PyLong_AsLongLong,3.2,, -function,PyLong_AsLongLongAndOverflow,3.2,, -function,PyLong_AsSize_t,3.2,, -function,PyLong_AsSsize_t,3.2,, -function,PyLong_AsUnsignedLong,3.2,, -function,PyLong_AsUnsignedLongLong,3.2,, -function,PyLong_AsUnsignedLongLongMask,3.2,, -function,PyLong_AsUnsignedLongMask,3.2,, -function,PyLong_AsVoidPtr,3.2,, -function,PyLong_FromDouble,3.2,, -function,PyLong_FromLong,3.2,, -function,PyLong_FromLongLong,3.2,, -function,PyLong_FromSize_t,3.2,, -function,PyLong_FromSsize_t,3.2,, -function,PyLong_FromString,3.2,, -function,PyLong_FromUnsignedLong,3.2,, -function,PyLong_FromUnsignedLongLong,3.2,, -function,PyLong_FromVoidPtr,3.2,, -function,PyLong_GetInfo,3.2,, -var,PyLong_Type,3.2,, -var,PyMap_Type,3.2,, -function,PyMapping_Check,3.2,, -function,PyMapping_GetItemString,3.2,, -function,PyMapping_HasKey,3.2,, -function,PyMapping_HasKeyString,3.2,, -function,PyMapping_Items,3.2,, -function,PyMapping_Keys,3.2,, -function,PyMapping_Length,3.2,, -function,PyMapping_SetItemString,3.2,, -function,PyMapping_Size,3.2,, -function,PyMapping_Values,3.2,, -function,PyMem_Calloc,3.7,, -function,PyMem_Free,3.2,, -function,PyMem_Malloc,3.2,, -function,PyMem_Realloc,3.2,, +data,PyLongRangeIter_Type,3.2,, +func,PyLong_AsDouble,3.2,, +func,PyLong_AsLong,3.2,, +func,PyLong_AsLongAndOverflow,3.2,, +func,PyLong_AsLongLong,3.2,, +func,PyLong_AsLongLongAndOverflow,3.2,, +func,PyLong_AsSize_t,3.2,, +func,PyLong_AsSsize_t,3.2,, +func,PyLong_AsUnsignedLong,3.2,, +func,PyLong_AsUnsignedLongLong,3.2,, +func,PyLong_AsUnsignedLongLongMask,3.2,, +func,PyLong_AsUnsignedLongMask,3.2,, +func,PyLong_AsVoidPtr,3.2,, +func,PyLong_FromDouble,3.2,, +func,PyLong_FromLong,3.2,, +func,PyLong_FromLongLong,3.2,, +func,PyLong_FromSize_t,3.2,, +func,PyLong_FromSsize_t,3.2,, +func,PyLong_FromString,3.2,, +func,PyLong_FromUnsignedLong,3.2,, +func,PyLong_FromUnsignedLongLong,3.2,, +func,PyLong_FromVoidPtr,3.2,, +func,PyLong_GetInfo,3.2,, +data,PyLong_Type,3.2,, +data,PyMap_Type,3.2,, +func,PyMapping_Check,3.2,, +func,PyMapping_GetItemString,3.2,, +func,PyMapping_HasKey,3.2,, +func,PyMapping_HasKeyString,3.2,, +func,PyMapping_Items,3.2,, +func,PyMapping_Keys,3.2,, +func,PyMapping_Length,3.2,, +func,PyMapping_SetItemString,3.2,, +func,PyMapping_Size,3.2,, +func,PyMapping_Values,3.2,, +func,PyMem_Calloc,3.7,, +func,PyMem_Free,3.2,, +func,PyMem_Malloc,3.2,, +func,PyMem_Realloc,3.2,, type,PyMemberDef,3.2,,full-abi -var,PyMemberDescr_Type,3.2,, -function,PyMember_GetOne,3.2,, -function,PyMember_SetOne,3.2,, -function,PyMemoryView_FromBuffer,3.11,, -function,PyMemoryView_FromMemory,3.7,, -function,PyMemoryView_FromObject,3.2,, -function,PyMemoryView_GetContiguous,3.2,, -var,PyMemoryView_Type,3.2,, +data,PyMemberDescr_Type,3.2,, +func,PyMember_GetOne,3.2,, +func,PyMember_SetOne,3.2,, +func,PyMemoryView_FromBuffer,3.11,, +func,PyMemoryView_FromMemory,3.7,, +func,PyMemoryView_FromObject,3.2,, +func,PyMemoryView_GetContiguous,3.2,, +data,PyMemoryView_Type,3.2,, type,PyMethodDef,3.2,,full-abi -var,PyMethodDescr_Type,3.2,, +data,PyMethodDescr_Type,3.2,, type,PyModuleDef,3.2,,full-abi type,PyModuleDef_Base,3.2,,full-abi -function,PyModuleDef_Init,3.5,, -var,PyModuleDef_Type,3.5,, -function,PyModule_AddFunctions,3.7,, -function,PyModule_AddIntConstant,3.2,, -function,PyModule_AddObject,3.2,, -function,PyModule_AddObjectRef,3.10,, -function,PyModule_AddStringConstant,3.2,, -function,PyModule_AddType,3.10,, -function,PyModule_Create2,3.2,, -function,PyModule_ExecDef,3.7,, -function,PyModule_FromDefAndSpec2,3.7,, -function,PyModule_GetDef,3.2,, -function,PyModule_GetDict,3.2,, -function,PyModule_GetFilename,3.2,, -function,PyModule_GetFilenameObject,3.2,, -function,PyModule_GetName,3.2,, -function,PyModule_GetNameObject,3.7,, -function,PyModule_GetState,3.2,, -function,PyModule_New,3.2,, -function,PyModule_NewObject,3.7,, -function,PyModule_SetDocString,3.7,, -var,PyModule_Type,3.2,, -function,PyNumber_Absolute,3.2,, -function,PyNumber_Add,3.2,, -function,PyNumber_And,3.2,, -function,PyNumber_AsSsize_t,3.2,, -function,PyNumber_Check,3.2,, -function,PyNumber_Divmod,3.2,, -function,PyNumber_Float,3.2,, -function,PyNumber_FloorDivide,3.2,, -function,PyNumber_InPlaceAdd,3.2,, -function,PyNumber_InPlaceAnd,3.2,, -function,PyNumber_InPlaceFloorDivide,3.2,, -function,PyNumber_InPlaceLshift,3.2,, -function,PyNumber_InPlaceMatrixMultiply,3.7,, -function,PyNumber_InPlaceMultiply,3.2,, -function,PyNumber_InPlaceOr,3.2,, -function,PyNumber_InPlacePower,3.2,, -function,PyNumber_InPlaceRemainder,3.2,, -function,PyNumber_InPlaceRshift,3.2,, -function,PyNumber_InPlaceSubtract,3.2,, -function,PyNumber_InPlaceTrueDivide,3.2,, -function,PyNumber_InPlaceXor,3.2,, -function,PyNumber_Index,3.2,, -function,PyNumber_Invert,3.2,, -function,PyNumber_Long,3.2,, -function,PyNumber_Lshift,3.2,, -function,PyNumber_MatrixMultiply,3.7,, -function,PyNumber_Multiply,3.2,, -function,PyNumber_Negative,3.2,, -function,PyNumber_Or,3.2,, -function,PyNumber_Positive,3.2,, -function,PyNumber_Power,3.2,, -function,PyNumber_Remainder,3.2,, -function,PyNumber_Rshift,3.2,, -function,PyNumber_Subtract,3.2,, -function,PyNumber_ToBase,3.2,, -function,PyNumber_TrueDivide,3.2,, -function,PyNumber_Xor,3.2,, -function,PyOS_AfterFork,3.2,on platforms with fork(), -function,PyOS_AfterFork_Child,3.7,on platforms with fork(), -function,PyOS_AfterFork_Parent,3.7,on platforms with fork(), -function,PyOS_BeforeFork,3.7,on platforms with fork(), -function,PyOS_CheckStack,3.7,on platforms with USE_STACKCHECK, -function,PyOS_FSPath,3.6,, -var,PyOS_InputHook,3.2,, -function,PyOS_InterruptOccurred,3.2,, -function,PyOS_double_to_string,3.2,, -function,PyOS_getsig,3.2,, -function,PyOS_mystricmp,3.2,, -function,PyOS_mystrnicmp,3.2,, -function,PyOS_setsig,3.2,, +func,PyModuleDef_Init,3.5,, +data,PyModuleDef_Type,3.5,, +func,PyModule_AddFunctions,3.7,, +func,PyModule_AddIntConstant,3.2,, +func,PyModule_AddObject,3.2,, +func,PyModule_AddObjectRef,3.10,, +func,PyModule_AddStringConstant,3.2,, +func,PyModule_AddType,3.10,, +func,PyModule_Create2,3.2,, +func,PyModule_ExecDef,3.7,, +func,PyModule_FromDefAndSpec2,3.7,, +func,PyModule_GetDef,3.2,, +func,PyModule_GetDict,3.2,, +func,PyModule_GetFilename,3.2,, +func,PyModule_GetFilenameObject,3.2,, +func,PyModule_GetName,3.2,, +func,PyModule_GetNameObject,3.7,, +func,PyModule_GetState,3.2,, +func,PyModule_New,3.2,, +func,PyModule_NewObject,3.7,, +func,PyModule_SetDocString,3.7,, +data,PyModule_Type,3.2,, +func,PyNumber_Absolute,3.2,, +func,PyNumber_Add,3.2,, +func,PyNumber_And,3.2,, +func,PyNumber_AsSsize_t,3.2,, +func,PyNumber_Check,3.2,, +func,PyNumber_Divmod,3.2,, +func,PyNumber_Float,3.2,, +func,PyNumber_FloorDivide,3.2,, +func,PyNumber_InPlaceAdd,3.2,, +func,PyNumber_InPlaceAnd,3.2,, +func,PyNumber_InPlaceFloorDivide,3.2,, +func,PyNumber_InPlaceLshift,3.2,, +func,PyNumber_InPlaceMatrixMultiply,3.7,, +func,PyNumber_InPlaceMultiply,3.2,, +func,PyNumber_InPlaceOr,3.2,, +func,PyNumber_InPlacePower,3.2,, +func,PyNumber_InPlaceRemainder,3.2,, +func,PyNumber_InPlaceRshift,3.2,, +func,PyNumber_InPlaceSubtract,3.2,, +func,PyNumber_InPlaceTrueDivide,3.2,, +func,PyNumber_InPlaceXor,3.2,, +func,PyNumber_Index,3.2,, +func,PyNumber_Invert,3.2,, +func,PyNumber_Long,3.2,, +func,PyNumber_Lshift,3.2,, +func,PyNumber_MatrixMultiply,3.7,, +func,PyNumber_Multiply,3.2,, +func,PyNumber_Negative,3.2,, +func,PyNumber_Or,3.2,, +func,PyNumber_Positive,3.2,, +func,PyNumber_Power,3.2,, +func,PyNumber_Remainder,3.2,, +func,PyNumber_Rshift,3.2,, +func,PyNumber_Subtract,3.2,, +func,PyNumber_ToBase,3.2,, +func,PyNumber_TrueDivide,3.2,, +func,PyNumber_Xor,3.2,, +func,PyOS_AfterFork,3.2,on platforms with fork(), +func,PyOS_AfterFork_Child,3.7,on platforms with fork(), +func,PyOS_AfterFork_Parent,3.7,on platforms with fork(), +func,PyOS_BeforeFork,3.7,on platforms with fork(), +func,PyOS_CheckStack,3.7,on platforms with USE_STACKCHECK, +func,PyOS_FSPath,3.6,, +data,PyOS_InputHook,3.2,, +func,PyOS_InterruptOccurred,3.2,, +func,PyOS_double_to_string,3.2,, +func,PyOS_getsig,3.2,, +func,PyOS_mystricmp,3.2,, +func,PyOS_mystrnicmp,3.2,, +func,PyOS_setsig,3.2,, type,PyOS_sighandler_t,3.2,, -function,PyOS_snprintf,3.2,, -function,PyOS_string_to_double,3.2,, -function,PyOS_strtol,3.2,, -function,PyOS_strtoul,3.2,, -function,PyOS_vsnprintf,3.2,, +func,PyOS_snprintf,3.2,, +func,PyOS_string_to_double,3.2,, +func,PyOS_strtol,3.2,, +func,PyOS_strtoul,3.2,, +func,PyOS_vsnprintf,3.2,, type,PyObject,3.2,,members member,PyObject.ob_refcnt,3.2,, member,PyObject.ob_type,3.2,, -function,PyObject_ASCII,3.2,, -function,PyObject_AsCharBuffer,3.2,, -function,PyObject_AsFileDescriptor,3.2,, -function,PyObject_AsReadBuffer,3.2,, -function,PyObject_AsWriteBuffer,3.2,, -function,PyObject_Bytes,3.2,, -function,PyObject_Call,3.2,, -function,PyObject_CallFunction,3.2,, -function,PyObject_CallFunctionObjArgs,3.2,, -function,PyObject_CallMethod,3.2,, -function,PyObject_CallMethodObjArgs,3.2,, -function,PyObject_CallNoArgs,3.10,, -function,PyObject_CallObject,3.2,, -function,PyObject_Calloc,3.7,, -function,PyObject_CheckBuffer,3.11,, -function,PyObject_CheckReadBuffer,3.2,, -function,PyObject_ClearWeakRefs,3.2,, -function,PyObject_CopyData,3.11,, -function,PyObject_DelItem,3.2,, -function,PyObject_DelItemString,3.2,, -function,PyObject_Dir,3.2,, -function,PyObject_Format,3.2,, -function,PyObject_Free,3.2,, -function,PyObject_GC_Del,3.2,, -function,PyObject_GC_IsFinalized,3.9,, -function,PyObject_GC_IsTracked,3.9,, -function,PyObject_GC_Track,3.2,, -function,PyObject_GC_UnTrack,3.2,, -function,PyObject_GenericGetAttr,3.2,, -function,PyObject_GenericGetDict,3.10,, -function,PyObject_GenericSetAttr,3.2,, -function,PyObject_GenericSetDict,3.7,, -function,PyObject_GetAIter,3.10,, -function,PyObject_GetAttr,3.2,, -function,PyObject_GetAttrString,3.2,, -function,PyObject_GetBuffer,3.11,, -function,PyObject_GetItem,3.2,, -function,PyObject_GetIter,3.2,, -function,PyObject_GetTypeData,3.12,, -function,PyObject_HasAttr,3.2,, -function,PyObject_HasAttrString,3.2,, -function,PyObject_Hash,3.2,, -function,PyObject_HashNotImplemented,3.2,, -function,PyObject_Init,3.2,, -function,PyObject_InitVar,3.2,, -function,PyObject_IsInstance,3.2,, -function,PyObject_IsSubclass,3.2,, -function,PyObject_IsTrue,3.2,, -function,PyObject_Length,3.2,, -function,PyObject_Malloc,3.2,, -function,PyObject_Not,3.2,, -function,PyObject_Realloc,3.2,, -function,PyObject_Repr,3.2,, -function,PyObject_RichCompare,3.2,, -function,PyObject_RichCompareBool,3.2,, -function,PyObject_SelfIter,3.2,, -function,PyObject_SetAttr,3.2,, -function,PyObject_SetAttrString,3.2,, -function,PyObject_SetItem,3.2,, -function,PyObject_Size,3.2,, -function,PyObject_Str,3.2,, -function,PyObject_Type,3.2,, -function,PyObject_Vectorcall,3.12,, -function,PyObject_VectorcallMethod,3.12,, -var,PyProperty_Type,3.2,, -var,PyRangeIter_Type,3.2,, -var,PyRange_Type,3.2,, -var,PyReversed_Type,3.2,, -function,PySeqIter_New,3.2,, -var,PySeqIter_Type,3.2,, -function,PySequence_Check,3.2,, -function,PySequence_Concat,3.2,, -function,PySequence_Contains,3.2,, -function,PySequence_Count,3.2,, -function,PySequence_DelItem,3.2,, -function,PySequence_DelSlice,3.2,, -function,PySequence_Fast,3.2,, -function,PySequence_GetItem,3.2,, -function,PySequence_GetSlice,3.2,, -function,PySequence_In,3.2,, -function,PySequence_InPlaceConcat,3.2,, -function,PySequence_InPlaceRepeat,3.2,, -function,PySequence_Index,3.2,, -function,PySequence_Length,3.2,, -function,PySequence_List,3.2,, -function,PySequence_Repeat,3.2,, -function,PySequence_SetItem,3.2,, -function,PySequence_SetSlice,3.2,, -function,PySequence_Size,3.2,, -function,PySequence_Tuple,3.2,, -var,PySetIter_Type,3.2,, -function,PySet_Add,3.2,, -function,PySet_Clear,3.2,, -function,PySet_Contains,3.2,, -function,PySet_Discard,3.2,, -function,PySet_New,3.2,, -function,PySet_Pop,3.2,, -function,PySet_Size,3.2,, -var,PySet_Type,3.2,, -function,PySlice_AdjustIndices,3.7,, -function,PySlice_GetIndices,3.2,, -function,PySlice_GetIndicesEx,3.2,, -function,PySlice_New,3.2,, -var,PySlice_Type,3.2,, -function,PySlice_Unpack,3.7,, -function,PyState_AddModule,3.3,, -function,PyState_FindModule,3.2,, -function,PyState_RemoveModule,3.3,, +func,PyObject_ASCII,3.2,, +func,PyObject_AsCharBuffer,3.2,, +func,PyObject_AsFileDescriptor,3.2,, +func,PyObject_AsReadBuffer,3.2,, +func,PyObject_AsWriteBuffer,3.2,, +func,PyObject_Bytes,3.2,, +func,PyObject_Call,3.2,, +func,PyObject_CallFunction,3.2,, +func,PyObject_CallFunctionObjArgs,3.2,, +func,PyObject_CallMethod,3.2,, +func,PyObject_CallMethodObjArgs,3.2,, +func,PyObject_CallNoArgs,3.10,, +func,PyObject_CallObject,3.2,, +func,PyObject_Calloc,3.7,, +func,PyObject_CheckBuffer,3.11,, +func,PyObject_CheckReadBuffer,3.2,, +func,PyObject_ClearWeakRefs,3.2,, +func,PyObject_CopyData,3.11,, +func,PyObject_DelItem,3.2,, +func,PyObject_DelItemString,3.2,, +func,PyObject_Dir,3.2,, +func,PyObject_Format,3.2,, +func,PyObject_Free,3.2,, +func,PyObject_GC_Del,3.2,, +func,PyObject_GC_IsFinalized,3.9,, +func,PyObject_GC_IsTracked,3.9,, +func,PyObject_GC_Track,3.2,, +func,PyObject_GC_UnTrack,3.2,, +func,PyObject_GenericGetAttr,3.2,, +func,PyObject_GenericGetDict,3.10,, +func,PyObject_GenericSetAttr,3.2,, +func,PyObject_GenericSetDict,3.7,, +func,PyObject_GetAIter,3.10,, +func,PyObject_GetAttr,3.2,, +func,PyObject_GetAttrString,3.2,, +func,PyObject_GetBuffer,3.11,, +func,PyObject_GetItem,3.2,, +func,PyObject_GetIter,3.2,, +func,PyObject_GetTypeData,3.12,, +func,PyObject_HasAttr,3.2,, +func,PyObject_HasAttrString,3.2,, +func,PyObject_Hash,3.2,, +func,PyObject_HashNotImplemented,3.2,, +func,PyObject_Init,3.2,, +func,PyObject_InitVar,3.2,, +func,PyObject_IsInstance,3.2,, +func,PyObject_IsSubclass,3.2,, +func,PyObject_IsTrue,3.2,, +func,PyObject_Length,3.2,, +func,PyObject_Malloc,3.2,, +func,PyObject_Not,3.2,, +func,PyObject_Realloc,3.2,, +func,PyObject_Repr,3.2,, +func,PyObject_RichCompare,3.2,, +func,PyObject_RichCompareBool,3.2,, +func,PyObject_SelfIter,3.2,, +func,PyObject_SetAttr,3.2,, +func,PyObject_SetAttrString,3.2,, +func,PyObject_SetItem,3.2,, +func,PyObject_Size,3.2,, +func,PyObject_Str,3.2,, +func,PyObject_Type,3.2,, +func,PyObject_Vectorcall,3.12,, +func,PyObject_VectorcallMethod,3.12,, +data,PyProperty_Type,3.2,, +data,PyRangeIter_Type,3.2,, +data,PyRange_Type,3.2,, +data,PyReversed_Type,3.2,, +func,PySeqIter_New,3.2,, +data,PySeqIter_Type,3.2,, +func,PySequence_Check,3.2,, +func,PySequence_Concat,3.2,, +func,PySequence_Contains,3.2,, +func,PySequence_Count,3.2,, +func,PySequence_DelItem,3.2,, +func,PySequence_DelSlice,3.2,, +func,PySequence_Fast,3.2,, +func,PySequence_GetItem,3.2,, +func,PySequence_GetSlice,3.2,, +func,PySequence_In,3.2,, +func,PySequence_InPlaceConcat,3.2,, +func,PySequence_InPlaceRepeat,3.2,, +func,PySequence_Index,3.2,, +func,PySequence_Length,3.2,, +func,PySequence_List,3.2,, +func,PySequence_Repeat,3.2,, +func,PySequence_SetItem,3.2,, +func,PySequence_SetSlice,3.2,, +func,PySequence_Size,3.2,, +func,PySequence_Tuple,3.2,, +data,PySetIter_Type,3.2,, +func,PySet_Add,3.2,, +func,PySet_Clear,3.2,, +func,PySet_Contains,3.2,, +func,PySet_Discard,3.2,, +func,PySet_New,3.2,, +func,PySet_Pop,3.2,, +func,PySet_Size,3.2,, +data,PySet_Type,3.2,, +func,PySlice_AdjustIndices,3.7,, +func,PySlice_GetIndices,3.2,, +func,PySlice_GetIndicesEx,3.2,, +func,PySlice_New,3.2,, +data,PySlice_Type,3.2,, +func,PySlice_Unpack,3.7,, +func,PyState_AddModule,3.3,, +func,PyState_FindModule,3.2,, +func,PyState_RemoveModule,3.3,, type,PyStructSequence_Desc,3.2,,full-abi type,PyStructSequence_Field,3.2,,full-abi -function,PyStructSequence_GetItem,3.2,, -function,PyStructSequence_New,3.2,, -function,PyStructSequence_NewType,3.2,, -function,PyStructSequence_SetItem,3.2,, -var,PyStructSequence_UnnamedField,3.11,, -var,PySuper_Type,3.2,, -function,PySys_AddWarnOption,3.2,, -function,PySys_AddWarnOptionUnicode,3.2,, -function,PySys_AddXOption,3.7,, -function,PySys_FormatStderr,3.2,, -function,PySys_FormatStdout,3.2,, -function,PySys_GetObject,3.2,, -function,PySys_GetXOptions,3.7,, -function,PySys_HasWarnOptions,3.2,, -function,PySys_ResetWarnOptions,3.2,, -function,PySys_SetArgv,3.2,, -function,PySys_SetArgvEx,3.2,, -function,PySys_SetObject,3.2,, -function,PySys_SetPath,3.2,, -function,PySys_WriteStderr,3.2,, -function,PySys_WriteStdout,3.2,, +func,PyStructSequence_GetItem,3.2,, +func,PyStructSequence_New,3.2,, +func,PyStructSequence_NewType,3.2,, +func,PyStructSequence_SetItem,3.2,, +data,PyStructSequence_UnnamedField,3.11,, +data,PySuper_Type,3.2,, +func,PySys_AddWarnOption,3.2,, +func,PySys_AddWarnOptionUnicode,3.2,, +func,PySys_AddXOption,3.7,, +func,PySys_FormatStderr,3.2,, +func,PySys_FormatStdout,3.2,, +func,PySys_GetObject,3.2,, +func,PySys_GetXOptions,3.7,, +func,PySys_HasWarnOptions,3.2,, +func,PySys_ResetWarnOptions,3.2,, +func,PySys_SetArgv,3.2,, +func,PySys_SetArgvEx,3.2,, +func,PySys_SetObject,3.2,, +func,PySys_SetPath,3.2,, +func,PySys_WriteStderr,3.2,, +func,PySys_WriteStdout,3.2,, type,PyThreadState,3.2,,opaque -function,PyThreadState_Clear,3.2,, -function,PyThreadState_Delete,3.2,, -function,PyThreadState_Get,3.2,, -function,PyThreadState_GetDict,3.2,, -function,PyThreadState_GetFrame,3.10,, -function,PyThreadState_GetID,3.10,, -function,PyThreadState_GetInterpreter,3.10,, -function,PyThreadState_New,3.2,, -function,PyThreadState_SetAsyncExc,3.2,, -function,PyThreadState_Swap,3.2,, -function,PyThread_GetInfo,3.3,, -function,PyThread_ReInitTLS,3.2,, -function,PyThread_acquire_lock,3.2,, -function,PyThread_acquire_lock_timed,3.2,, -function,PyThread_allocate_lock,3.2,, -function,PyThread_create_key,3.2,, -function,PyThread_delete_key,3.2,, -function,PyThread_delete_key_value,3.2,, -function,PyThread_exit_thread,3.2,, -function,PyThread_free_lock,3.2,, -function,PyThread_get_key_value,3.2,, -function,PyThread_get_stacksize,3.2,, -function,PyThread_get_thread_ident,3.2,, -function,PyThread_get_thread_native_id,3.2,on platforms with native thread IDs, -function,PyThread_init_thread,3.2,, -function,PyThread_release_lock,3.2,, -function,PyThread_set_key_value,3.2,, -function,PyThread_set_stacksize,3.2,, -function,PyThread_start_new_thread,3.2,, -function,PyThread_tss_alloc,3.7,, -function,PyThread_tss_create,3.7,, -function,PyThread_tss_delete,3.7,, -function,PyThread_tss_free,3.7,, -function,PyThread_tss_get,3.7,, -function,PyThread_tss_is_created,3.7,, -function,PyThread_tss_set,3.7,, -function,PyTraceBack_Here,3.2,, -function,PyTraceBack_Print,3.2,, -var,PyTraceBack_Type,3.2,, -var,PyTupleIter_Type,3.2,, -function,PyTuple_GetItem,3.2,, -function,PyTuple_GetSlice,3.2,, -function,PyTuple_New,3.2,, -function,PyTuple_Pack,3.2,, -function,PyTuple_SetItem,3.2,, -function,PyTuple_Size,3.2,, -var,PyTuple_Type,3.2,, +func,PyThreadState_Clear,3.2,, +func,PyThreadState_Delete,3.2,, +func,PyThreadState_Get,3.2,, +func,PyThreadState_GetDict,3.2,, +func,PyThreadState_GetFrame,3.10,, +func,PyThreadState_GetID,3.10,, +func,PyThreadState_GetInterpreter,3.10,, +func,PyThreadState_New,3.2,, +func,PyThreadState_SetAsyncExc,3.2,, +func,PyThreadState_Swap,3.2,, +func,PyThread_GetInfo,3.3,, +func,PyThread_ReInitTLS,3.2,, +func,PyThread_acquire_lock,3.2,, +func,PyThread_acquire_lock_timed,3.2,, +func,PyThread_allocate_lock,3.2,, +func,PyThread_create_key,3.2,, +func,PyThread_delete_key,3.2,, +func,PyThread_delete_key_value,3.2,, +func,PyThread_exit_thread,3.2,, +func,PyThread_free_lock,3.2,, +func,PyThread_get_key_value,3.2,, +func,PyThread_get_stacksize,3.2,, +func,PyThread_get_thread_ident,3.2,, +func,PyThread_get_thread_native_id,3.2,on platforms with native thread IDs, +func,PyThread_init_thread,3.2,, +func,PyThread_release_lock,3.2,, +func,PyThread_set_key_value,3.2,, +func,PyThread_set_stacksize,3.2,, +func,PyThread_start_new_thread,3.2,, +func,PyThread_tss_alloc,3.7,, +func,PyThread_tss_create,3.7,, +func,PyThread_tss_delete,3.7,, +func,PyThread_tss_free,3.7,, +func,PyThread_tss_get,3.7,, +func,PyThread_tss_is_created,3.7,, +func,PyThread_tss_set,3.7,, +func,PyTraceBack_Here,3.2,, +func,PyTraceBack_Print,3.2,, +data,PyTraceBack_Type,3.2,, +data,PyTupleIter_Type,3.2,, +func,PyTuple_GetItem,3.2,, +func,PyTuple_GetSlice,3.2,, +func,PyTuple_New,3.2,, +func,PyTuple_Pack,3.2,, +func,PyTuple_SetItem,3.2,, +func,PyTuple_Size,3.2,, +data,PyTuple_Type,3.2,, type,PyTypeObject,3.2,,opaque -function,PyType_ClearCache,3.2,, -function,PyType_FromMetaclass,3.12,, -function,PyType_FromModuleAndSpec,3.10,, -function,PyType_FromSpec,3.2,, -function,PyType_FromSpecWithBases,3.3,, -function,PyType_GenericAlloc,3.2,, -function,PyType_GenericNew,3.2,, -function,PyType_GetFlags,3.2,, -function,PyType_GetModule,3.10,, -function,PyType_GetModuleState,3.10,, -function,PyType_GetName,3.11,, -function,PyType_GetQualName,3.11,, -function,PyType_GetSlot,3.4,, -function,PyType_GetTypeDataSize,3.12,, -function,PyType_IsSubtype,3.2,, -function,PyType_Modified,3.2,, -function,PyType_Ready,3.2,, +func,PyType_ClearCache,3.2,, +func,PyType_FromMetaclass,3.12,, +func,PyType_FromModuleAndSpec,3.10,, +func,PyType_FromSpec,3.2,, +func,PyType_FromSpecWithBases,3.3,, +func,PyType_GenericAlloc,3.2,, +func,PyType_GenericNew,3.2,, +func,PyType_GetFlags,3.2,, +func,PyType_GetModule,3.10,, +func,PyType_GetModuleState,3.10,, +func,PyType_GetName,3.11,, +func,PyType_GetQualName,3.11,, +func,PyType_GetSlot,3.4,, +func,PyType_GetTypeDataSize,3.12,, +func,PyType_IsSubtype,3.2,, +func,PyType_Modified,3.2,, +func,PyType_Ready,3.2,, type,PyType_Slot,3.2,,full-abi type,PyType_Spec,3.2,,full-abi -var,PyType_Type,3.2,, -function,PyUnicodeDecodeError_Create,3.2,, -function,PyUnicodeDecodeError_GetEncoding,3.2,, -function,PyUnicodeDecodeError_GetEnd,3.2,, -function,PyUnicodeDecodeError_GetObject,3.2,, -function,PyUnicodeDecodeError_GetReason,3.2,, -function,PyUnicodeDecodeError_GetStart,3.2,, -function,PyUnicodeDecodeError_SetEnd,3.2,, -function,PyUnicodeDecodeError_SetReason,3.2,, -function,PyUnicodeDecodeError_SetStart,3.2,, -function,PyUnicodeEncodeError_GetEncoding,3.2,, -function,PyUnicodeEncodeError_GetEnd,3.2,, -function,PyUnicodeEncodeError_GetObject,3.2,, -function,PyUnicodeEncodeError_GetReason,3.2,, -function,PyUnicodeEncodeError_GetStart,3.2,, -function,PyUnicodeEncodeError_SetEnd,3.2,, -function,PyUnicodeEncodeError_SetReason,3.2,, -function,PyUnicodeEncodeError_SetStart,3.2,, -var,PyUnicodeIter_Type,3.2,, -function,PyUnicodeTranslateError_GetEnd,3.2,, -function,PyUnicodeTranslateError_GetObject,3.2,, -function,PyUnicodeTranslateError_GetReason,3.2,, -function,PyUnicodeTranslateError_GetStart,3.2,, -function,PyUnicodeTranslateError_SetEnd,3.2,, -function,PyUnicodeTranslateError_SetReason,3.2,, -function,PyUnicodeTranslateError_SetStart,3.2,, -function,PyUnicode_Append,3.2,, -function,PyUnicode_AppendAndDel,3.2,, -function,PyUnicode_AsASCIIString,3.2,, -function,PyUnicode_AsCharmapString,3.2,, -function,PyUnicode_AsDecodedObject,3.2,, -function,PyUnicode_AsDecodedUnicode,3.2,, -function,PyUnicode_AsEncodedObject,3.2,, -function,PyUnicode_AsEncodedString,3.2,, -function,PyUnicode_AsEncodedUnicode,3.2,, -function,PyUnicode_AsLatin1String,3.2,, -function,PyUnicode_AsMBCSString,3.7,on Windows, -function,PyUnicode_AsRawUnicodeEscapeString,3.2,, -function,PyUnicode_AsUCS4,3.7,, -function,PyUnicode_AsUCS4Copy,3.7,, -function,PyUnicode_AsUTF16String,3.2,, -function,PyUnicode_AsUTF32String,3.2,, -function,PyUnicode_AsUTF8AndSize,3.10,, -function,PyUnicode_AsUTF8String,3.2,, -function,PyUnicode_AsUnicodeEscapeString,3.2,, -function,PyUnicode_AsWideChar,3.2,, -function,PyUnicode_AsWideCharString,3.7,, -function,PyUnicode_BuildEncodingMap,3.2,, -function,PyUnicode_Compare,3.2,, -function,PyUnicode_CompareWithASCIIString,3.2,, -function,PyUnicode_Concat,3.2,, -function,PyUnicode_Contains,3.2,, -function,PyUnicode_Count,3.2,, -function,PyUnicode_Decode,3.2,, -function,PyUnicode_DecodeASCII,3.2,, -function,PyUnicode_DecodeCharmap,3.2,, -function,PyUnicode_DecodeCodePageStateful,3.7,on Windows, -function,PyUnicode_DecodeFSDefault,3.2,, -function,PyUnicode_DecodeFSDefaultAndSize,3.2,, -function,PyUnicode_DecodeLatin1,3.2,, -function,PyUnicode_DecodeLocale,3.7,, -function,PyUnicode_DecodeLocaleAndSize,3.7,, -function,PyUnicode_DecodeMBCS,3.7,on Windows, -function,PyUnicode_DecodeMBCSStateful,3.7,on Windows, -function,PyUnicode_DecodeRawUnicodeEscape,3.2,, -function,PyUnicode_DecodeUTF16,3.2,, -function,PyUnicode_DecodeUTF16Stateful,3.2,, -function,PyUnicode_DecodeUTF32,3.2,, -function,PyUnicode_DecodeUTF32Stateful,3.2,, -function,PyUnicode_DecodeUTF7,3.2,, -function,PyUnicode_DecodeUTF7Stateful,3.2,, -function,PyUnicode_DecodeUTF8,3.2,, -function,PyUnicode_DecodeUTF8Stateful,3.2,, -function,PyUnicode_DecodeUnicodeEscape,3.2,, -function,PyUnicode_EncodeCodePage,3.7,on Windows, -function,PyUnicode_EncodeFSDefault,3.2,, -function,PyUnicode_EncodeLocale,3.7,, -function,PyUnicode_FSConverter,3.2,, -function,PyUnicode_FSDecoder,3.2,, -function,PyUnicode_Find,3.2,, -function,PyUnicode_FindChar,3.7,, -function,PyUnicode_Format,3.2,, -function,PyUnicode_FromEncodedObject,3.2,, -function,PyUnicode_FromFormat,3.2,, -function,PyUnicode_FromFormatV,3.2,, -function,PyUnicode_FromObject,3.2,, -function,PyUnicode_FromOrdinal,3.2,, -function,PyUnicode_FromString,3.2,, -function,PyUnicode_FromStringAndSize,3.2,, -function,PyUnicode_FromWideChar,3.2,, -function,PyUnicode_GetDefaultEncoding,3.2,, -function,PyUnicode_GetLength,3.7,, -function,PyUnicode_InternFromString,3.2,, -function,PyUnicode_InternInPlace,3.2,, -function,PyUnicode_IsIdentifier,3.2,, -function,PyUnicode_Join,3.2,, -function,PyUnicode_Partition,3.2,, -function,PyUnicode_RPartition,3.2,, -function,PyUnicode_RSplit,3.2,, -function,PyUnicode_ReadChar,3.7,, -function,PyUnicode_Replace,3.2,, -function,PyUnicode_Resize,3.2,, -function,PyUnicode_RichCompare,3.2,, -function,PyUnicode_Split,3.2,, -function,PyUnicode_Splitlines,3.2,, -function,PyUnicode_Substring,3.7,, -function,PyUnicode_Tailmatch,3.2,, -function,PyUnicode_Translate,3.2,, -var,PyUnicode_Type,3.2,, -function,PyUnicode_WriteChar,3.7,, +data,PyType_Type,3.2,, +func,PyUnicodeDecodeError_Create,3.2,, +func,PyUnicodeDecodeError_GetEncoding,3.2,, +func,PyUnicodeDecodeError_GetEnd,3.2,, +func,PyUnicodeDecodeError_GetObject,3.2,, +func,PyUnicodeDecodeError_GetReason,3.2,, +func,PyUnicodeDecodeError_GetStart,3.2,, +func,PyUnicodeDecodeError_SetEnd,3.2,, +func,PyUnicodeDecodeError_SetReason,3.2,, +func,PyUnicodeDecodeError_SetStart,3.2,, +func,PyUnicodeEncodeError_GetEncoding,3.2,, +func,PyUnicodeEncodeError_GetEnd,3.2,, +func,PyUnicodeEncodeError_GetObject,3.2,, +func,PyUnicodeEncodeError_GetReason,3.2,, +func,PyUnicodeEncodeError_GetStart,3.2,, +func,PyUnicodeEncodeError_SetEnd,3.2,, +func,PyUnicodeEncodeError_SetReason,3.2,, +func,PyUnicodeEncodeError_SetStart,3.2,, +data,PyUnicodeIter_Type,3.2,, +func,PyUnicodeTranslateError_GetEnd,3.2,, +func,PyUnicodeTranslateError_GetObject,3.2,, +func,PyUnicodeTranslateError_GetReason,3.2,, +func,PyUnicodeTranslateError_GetStart,3.2,, +func,PyUnicodeTranslateError_SetEnd,3.2,, +func,PyUnicodeTranslateError_SetReason,3.2,, +func,PyUnicodeTranslateError_SetStart,3.2,, +func,PyUnicode_Append,3.2,, +func,PyUnicode_AppendAndDel,3.2,, +func,PyUnicode_AsASCIIString,3.2,, +func,PyUnicode_AsCharmapString,3.2,, +func,PyUnicode_AsDecodedObject,3.2,, +func,PyUnicode_AsDecodedUnicode,3.2,, +func,PyUnicode_AsEncodedObject,3.2,, +func,PyUnicode_AsEncodedString,3.2,, +func,PyUnicode_AsEncodedUnicode,3.2,, +func,PyUnicode_AsLatin1String,3.2,, +func,PyUnicode_AsMBCSString,3.7,on Windows, +func,PyUnicode_AsRawUnicodeEscapeString,3.2,, +func,PyUnicode_AsUCS4,3.7,, +func,PyUnicode_AsUCS4Copy,3.7,, +func,PyUnicode_AsUTF16String,3.2,, +func,PyUnicode_AsUTF32String,3.2,, +func,PyUnicode_AsUTF8AndSize,3.10,, +func,PyUnicode_AsUTF8String,3.2,, +func,PyUnicode_AsUnicodeEscapeString,3.2,, +func,PyUnicode_AsWideChar,3.2,, +func,PyUnicode_AsWideCharString,3.7,, +func,PyUnicode_BuildEncodingMap,3.2,, +func,PyUnicode_Compare,3.2,, +func,PyUnicode_CompareWithASCIIString,3.2,, +func,PyUnicode_Concat,3.2,, +func,PyUnicode_Contains,3.2,, +func,PyUnicode_Count,3.2,, +func,PyUnicode_Decode,3.2,, +func,PyUnicode_DecodeASCII,3.2,, +func,PyUnicode_DecodeCharmap,3.2,, +func,PyUnicode_DecodeCodePageStateful,3.7,on Windows, +func,PyUnicode_DecodeFSDefault,3.2,, +func,PyUnicode_DecodeFSDefaultAndSize,3.2,, +func,PyUnicode_DecodeLatin1,3.2,, +func,PyUnicode_DecodeLocale,3.7,, +func,PyUnicode_DecodeLocaleAndSize,3.7,, +func,PyUnicode_DecodeMBCS,3.7,on Windows, +func,PyUnicode_DecodeMBCSStateful,3.7,on Windows, +func,PyUnicode_DecodeRawUnicodeEscape,3.2,, +func,PyUnicode_DecodeUTF16,3.2,, +func,PyUnicode_DecodeUTF16Stateful,3.2,, +func,PyUnicode_DecodeUTF32,3.2,, +func,PyUnicode_DecodeUTF32Stateful,3.2,, +func,PyUnicode_DecodeUTF7,3.2,, +func,PyUnicode_DecodeUTF7Stateful,3.2,, +func,PyUnicode_DecodeUTF8,3.2,, +func,PyUnicode_DecodeUTF8Stateful,3.2,, +func,PyUnicode_DecodeUnicodeEscape,3.2,, +func,PyUnicode_EncodeCodePage,3.7,on Windows, +func,PyUnicode_EncodeFSDefault,3.2,, +func,PyUnicode_EncodeLocale,3.7,, +func,PyUnicode_FSConverter,3.2,, +func,PyUnicode_FSDecoder,3.2,, +func,PyUnicode_Find,3.2,, +func,PyUnicode_FindChar,3.7,, +func,PyUnicode_Format,3.2,, +func,PyUnicode_FromEncodedObject,3.2,, +func,PyUnicode_FromFormat,3.2,, +func,PyUnicode_FromFormatV,3.2,, +func,PyUnicode_FromObject,3.2,, +func,PyUnicode_FromOrdinal,3.2,, +func,PyUnicode_FromString,3.2,, +func,PyUnicode_FromStringAndSize,3.2,, +func,PyUnicode_FromWideChar,3.2,, +func,PyUnicode_GetDefaultEncoding,3.2,, +func,PyUnicode_GetLength,3.7,, +func,PyUnicode_InternFromString,3.2,, +func,PyUnicode_InternInPlace,3.2,, +func,PyUnicode_IsIdentifier,3.2,, +func,PyUnicode_Join,3.2,, +func,PyUnicode_Partition,3.2,, +func,PyUnicode_RPartition,3.2,, +func,PyUnicode_RSplit,3.2,, +func,PyUnicode_ReadChar,3.7,, +func,PyUnicode_Replace,3.2,, +func,PyUnicode_Resize,3.2,, +func,PyUnicode_RichCompare,3.2,, +func,PyUnicode_Split,3.2,, +func,PyUnicode_Splitlines,3.2,, +func,PyUnicode_Substring,3.7,, +func,PyUnicode_Tailmatch,3.2,, +func,PyUnicode_Translate,3.2,, +data,PyUnicode_Type,3.2,, +func,PyUnicode_WriteChar,3.7,, type,PyVarObject,3.2,,members member,PyVarObject.ob_base,3.2,, member,PyVarObject.ob_size,3.2,, -function,PyVectorcall_Call,3.12,, -function,PyVectorcall_NARGS,3.12,, +func,PyVectorcall_Call,3.12,, +func,PyVectorcall_NARGS,3.12,, type,PyWeakReference,3.2,,opaque -function,PyWeakref_GetObject,3.2,, -function,PyWeakref_NewProxy,3.2,, -function,PyWeakref_NewRef,3.2,, -var,PyWrapperDescr_Type,3.2,, -function,PyWrapper_New,3.2,, -var,PyZip_Type,3.2,, -function,Py_AddPendingCall,3.2,, -function,Py_AtExit,3.2,, +func,PyWeakref_GetObject,3.2,, +func,PyWeakref_NewProxy,3.2,, +func,PyWeakref_NewRef,3.2,, +data,PyWrapperDescr_Type,3.2,, +func,PyWrapper_New,3.2,, +data,PyZip_Type,3.2,, +func,Py_AddPendingCall,3.2,, +func,Py_AtExit,3.2,, macro,Py_BEGIN_ALLOW_THREADS,3.2,, macro,Py_BLOCK_THREADS,3.2,, -function,Py_BuildValue,3.2,, -function,Py_BytesMain,3.8,, -function,Py_CompileString,3.2,, -function,Py_DecRef,3.2,, -function,Py_DecodeLocale,3.7,, +func,Py_BuildValue,3.2,, +func,Py_BytesMain,3.8,, +func,Py_CompileString,3.2,, +func,Py_DecRef,3.2,, +func,Py_DecodeLocale,3.7,, macro,Py_END_ALLOW_THREADS,3.2,, -function,Py_EncodeLocale,3.7,, -function,Py_EndInterpreter,3.2,, -function,Py_EnterRecursiveCall,3.9,, -function,Py_Exit,3.2,, -function,Py_FatalError,3.2,, -var,Py_FileSystemDefaultEncodeErrors,3.10,, -var,Py_FileSystemDefaultEncoding,3.2,, -function,Py_Finalize,3.2,, -function,Py_FinalizeEx,3.6,, -function,Py_GenericAlias,3.9,, -var,Py_GenericAliasType,3.9,, -function,Py_GetBuildInfo,3.2,, -function,Py_GetCompiler,3.2,, -function,Py_GetCopyright,3.2,, -function,Py_GetExecPrefix,3.2,, -function,Py_GetPath,3.2,, -function,Py_GetPlatform,3.2,, -function,Py_GetPrefix,3.2,, -function,Py_GetProgramFullPath,3.2,, -function,Py_GetProgramName,3.2,, -function,Py_GetPythonHome,3.2,, -function,Py_GetRecursionLimit,3.2,, -function,Py_GetVersion,3.2,, -var,Py_HasFileSystemDefaultEncoding,3.2,, -function,Py_IncRef,3.2,, -function,Py_Initialize,3.2,, -function,Py_InitializeEx,3.2,, -function,Py_Is,3.10,, -function,Py_IsFalse,3.10,, -function,Py_IsInitialized,3.2,, -function,Py_IsNone,3.10,, -function,Py_IsTrue,3.10,, -function,Py_LeaveRecursiveCall,3.9,, -function,Py_Main,3.2,, -function,Py_MakePendingCalls,3.2,, -function,Py_NewInterpreter,3.2,, -function,Py_NewRef,3.10,, -function,Py_ReprEnter,3.2,, -function,Py_ReprLeave,3.2,, -function,Py_SetPath,3.7,, -function,Py_SetProgramName,3.2,, -function,Py_SetPythonHome,3.2,, -function,Py_SetRecursionLimit,3.2,, +func,Py_EncodeLocale,3.7,, +func,Py_EndInterpreter,3.2,, +func,Py_EnterRecursiveCall,3.9,, +func,Py_Exit,3.2,, +func,Py_FatalError,3.2,, +data,Py_FileSystemDefaultEncodeErrors,3.10,, +data,Py_FileSystemDefaultEncoding,3.2,, +func,Py_Finalize,3.2,, +func,Py_FinalizeEx,3.6,, +func,Py_GenericAlias,3.9,, +data,Py_GenericAliasType,3.9,, +func,Py_GetBuildInfo,3.2,, +func,Py_GetCompiler,3.2,, +func,Py_GetCopyright,3.2,, +func,Py_GetExecPrefix,3.2,, +func,Py_GetPath,3.2,, +func,Py_GetPlatform,3.2,, +func,Py_GetPrefix,3.2,, +func,Py_GetProgramFullPath,3.2,, +func,Py_GetProgramName,3.2,, +func,Py_GetPythonHome,3.2,, +func,Py_GetRecursionLimit,3.2,, +func,Py_GetVersion,3.2,, +data,Py_HasFileSystemDefaultEncoding,3.2,, +func,Py_IncRef,3.2,, +func,Py_Initialize,3.2,, +func,Py_InitializeEx,3.2,, +func,Py_Is,3.10,, +func,Py_IsFalse,3.10,, +func,Py_IsInitialized,3.2,, +func,Py_IsNone,3.10,, +func,Py_IsTrue,3.10,, +func,Py_LeaveRecursiveCall,3.9,, +func,Py_Main,3.2,, +func,Py_MakePendingCalls,3.2,, +func,Py_NewInterpreter,3.2,, +func,Py_NewRef,3.10,, +func,Py_ReprEnter,3.2,, +func,Py_ReprLeave,3.2,, +func,Py_SetPath,3.7,, +func,Py_SetProgramName,3.2,, +func,Py_SetPythonHome,3.2,, +func,Py_SetRecursionLimit,3.2,, type,Py_UCS4,3.2,, macro,Py_UNBLOCK_THREADS,3.2,, -var,Py_UTF8Mode,3.8,, -function,Py_VaBuildValue,3.2,, -var,Py_Version,3.11,, -function,Py_XNewRef,3.10,, +data,Py_UTF8Mode,3.8,, +func,Py_VaBuildValue,3.2,, +data,Py_Version,3.11,, +func,Py_XNewRef,3.10,, type,Py_buffer,3.11,,full-abi type,Py_intptr_t,3.2,, type,Py_ssize_t,3.2,, diff --git a/Doc/deprecations/c-api-pending-removal-in-3.14.rst b/Doc/deprecations/c-api-pending-removal-in-3.14.rst new file mode 100644 index 00000000..d16da66c --- /dev/null +++ b/Doc/deprecations/c-api-pending-removal-in-3.14.rst @@ -0,0 +1,72 @@ +Pending Removal in Python 3.14 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* The ``ma_version_tag`` field in :c:type:`PyDictObject` for extension modules + (:pep:`699`; :gh:`101193`). + +* Creating :c:data:`immutable types ` with mutable + bases (:gh:`95388`). + +* Functions to configure Python's initialization, deprecated in Python 3.11: + + * :c:func:`!PySys_SetArgvEx()`: + Set :c:member:`PyConfig.argv` instead. + * :c:func:`!PySys_SetArgv()`: + Set :c:member:`PyConfig.argv` instead. + * :c:func:`!Py_SetProgramName()`: + Set :c:member:`PyConfig.program_name` instead. + * :c:func:`!Py_SetPythonHome()`: + Set :c:member:`PyConfig.home` instead. + + The :c:func:`Py_InitializeFromConfig` API should be used with + :c:type:`PyConfig` instead. + +* Global configuration variables: + + * :c:var:`Py_DebugFlag`: + Use :c:member:`PyConfig.parser_debug` instead. + * :c:var:`Py_VerboseFlag`: + Use :c:member:`PyConfig.verbose` instead. + * :c:var:`Py_QuietFlag`: + Use :c:member:`PyConfig.quiet` instead. + * :c:var:`Py_InteractiveFlag`: + Use :c:member:`PyConfig.interactive` instead. + * :c:var:`Py_InspectFlag`: + Use :c:member:`PyConfig.inspect` instead. + * :c:var:`Py_OptimizeFlag`: + Use :c:member:`PyConfig.optimization_level` instead. + * :c:var:`Py_NoSiteFlag`: + Use :c:member:`PyConfig.site_import` instead. + * :c:var:`Py_BytesWarningFlag`: + Use :c:member:`PyConfig.bytes_warning` instead. + * :c:var:`Py_FrozenFlag`: + Use :c:member:`PyConfig.pathconfig_warnings` instead. + * :c:var:`Py_IgnoreEnvironmentFlag`: + Use :c:member:`PyConfig.use_environment` instead. + * :c:var:`Py_DontWriteBytecodeFlag`: + Use :c:member:`PyConfig.write_bytecode` instead. + * :c:var:`Py_NoUserSiteDirectory`: + Use :c:member:`PyConfig.user_site_directory` instead. + * :c:var:`Py_UnbufferedStdioFlag`: + Use :c:member:`PyConfig.buffered_stdio` instead. + * :c:var:`Py_HashRandomizationFlag`: + Use :c:member:`PyConfig.use_hash_seed` + and :c:member:`PyConfig.hash_seed` instead. + * :c:var:`Py_IsolatedFlag`: + Use :c:member:`PyConfig.isolated` instead. + * :c:var:`Py_LegacyWindowsFSEncodingFlag`: + Use :c:member:`PyPreConfig.legacy_windows_fs_encoding` instead. + * :c:var:`Py_LegacyWindowsStdioFlag`: + Use :c:member:`PyConfig.legacy_windows_stdio` instead. + * :c:var:`!Py_FileSystemDefaultEncoding`: + Use :c:member:`PyConfig.filesystem_encoding` instead. + * :c:var:`!Py_HasFileSystemDefaultEncoding`: + Use :c:member:`PyConfig.filesystem_encoding` instead. + * :c:var:`!Py_FileSystemDefaultEncodeErrors`: + Use :c:member:`PyConfig.filesystem_errors` instead. + * :c:var:`!Py_UTF8Mode`: + Use :c:member:`PyPreConfig.utf8_mode` instead. + (see :c:func:`Py_PreInitialize`) + + The :c:func:`Py_InitializeFromConfig` API should be used with + :c:type:`PyConfig` instead. diff --git a/Doc/deprecations/c-api-pending-removal-in-3.15.rst b/Doc/deprecations/c-api-pending-removal-in-3.15.rst new file mode 100644 index 00000000..cdfcb2f9 --- /dev/null +++ b/Doc/deprecations/c-api-pending-removal-in-3.15.rst @@ -0,0 +1,27 @@ +Pending Removal in Python 3.15 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* The bundled copy of ``libmpdecimal``. +* The :c:func:`PyImport_ImportModuleNoBlock`: + Use :c:func:`PyImport_ImportModule` instead. +* :c:func:`PyWeakref_GetObject` and :c:func:`PyWeakref_GET_OBJECT`: + Use :c:func:`!PyWeakref_GetRef` instead. +* :c:type:`Py_UNICODE` type and the :c:macro:`!Py_UNICODE_WIDE` macro: + Use :c:type:`wchar_t` instead. +* Python initialization functions: + + * :c:func:`PySys_ResetWarnOptions`: + Clear :data:`sys.warnoptions` and :data:`!warnings.filters` instead. + * :c:func:`Py_GetExecPrefix`: + Get :data:`sys.exec_prefix` instead. + * :c:func:`Py_GetPath`: + Get :data:`sys.path` instead. + * :c:func:`Py_GetPrefix`: + Get :data:`sys.prefix` instead. + * :c:func:`Py_GetProgramFullPath`: + Get :data:`sys.executable` instead. + * :c:func:`Py_GetProgramName`: + Get :data:`sys.executable` instead. + * :c:func:`Py_GetPythonHome`: + Get :c:member:`PyConfig.home` + or the :envvar:`PYTHONHOME` environment variable instead. diff --git a/Doc/deprecations/c-api-pending-removal-in-future.rst b/Doc/deprecations/c-api-pending-removal-in-future.rst new file mode 100644 index 00000000..0c3ae52b --- /dev/null +++ b/Doc/deprecations/c-api-pending-removal-in-future.rst @@ -0,0 +1,51 @@ +Pending Removal in Future Versions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following APIs are deprecated and will be removed, +although there is currently no date scheduled for their removal. + +* :c:macro:`Py_TPFLAGS_HAVE_FINALIZE`: + Unneeded since Python 3.8. +* :c:func:`PyErr_Fetch`: + Use :c:func:`PyErr_GetRaisedException` instead. +* :c:func:`PyErr_NormalizeException`: + Use :c:func:`PyErr_GetRaisedException` instead. +* :c:func:`PyErr_Restore`: + Use :c:func:`PyErr_SetRaisedException` instead. +* :c:func:`PyModule_GetFilename`: + Use :c:func:`PyModule_GetFilenameObject` instead. +* :c:func:`PyOS_AfterFork`: + Use :c:func:`PyOS_AfterFork_Child` instead. +* :c:func:`PySlice_GetIndicesEx`: + Use :c:func:`PySlice_Unpack` and :c:func:`PySlice_AdjustIndices` instead. +* :c:func:`!PyUnicode_AsDecodedObject`: + Use :c:func:`PyCodec_Decode` instead. +* :c:func:`!PyUnicode_AsDecodedUnicode`: + Use :c:func:`PyCodec_Decode` instead. +* :c:func:`!PyUnicode_AsEncodedObject`: + Use :c:func:`PyCodec_Encode` instead. +* :c:func:`!PyUnicode_AsEncodedUnicode`: + Use :c:func:`PyCodec_Encode` instead. +* :c:func:`PyUnicode_READY`: + Unneeded since Python 3.12 +* :c:func:`!PyErr_Display`: + Use :c:func:`PyErr_DisplayException` instead. +* :c:func:`!_PyErr_ChainExceptions`: + Use :c:func:`!_PyErr_ChainExceptions1` instead. +* :c:member:`!PyBytesObject.ob_shash` member: + call :c:func:`PyObject_Hash` instead. +* :c:member:`!PyDictObject.ma_version_tag` member. +* Thread Local Storage (TLS) API: + + * :c:func:`PyThread_create_key`: + Use :c:func:`PyThread_tss_alloc` instead. + * :c:func:`PyThread_delete_key`: + Use :c:func:`PyThread_tss_free` instead. + * :c:func:`PyThread_set_key_value`: + Use :c:func:`PyThread_tss_set` instead. + * :c:func:`PyThread_get_key_value`: + Use :c:func:`PyThread_tss_get` instead. + * :c:func:`PyThread_delete_key_value`: + Use :c:func:`PyThread_tss_delete` instead. + * :c:func:`PyThread_ReInitTLS`: + Unneeded since Python 3.7. diff --git a/Doc/deprecations/index.rst b/Doc/deprecations/index.rst new file mode 100644 index 00000000..aedea375 --- /dev/null +++ b/Doc/deprecations/index.rst @@ -0,0 +1,21 @@ +Deprecations +============ + +.. include:: pending-removal-in-3.13.rst + +.. include:: pending-removal-in-3.14.rst + +.. include:: pending-removal-in-3.15.rst + +.. include:: pending-removal-in-3.16.rst + +.. include:: pending-removal-in-future.rst + +C API Deprecations +------------------ + +.. include:: c-api-pending-removal-in-3.14.rst + +.. include:: c-api-pending-removal-in-3.15.rst + +.. include:: c-api-pending-removal-in-future.rst diff --git a/Doc/deprecations/pending-removal-in-3.13.rst b/Doc/deprecations/pending-removal-in-3.13.rst new file mode 100644 index 00000000..1c24b5b6 --- /dev/null +++ b/Doc/deprecations/pending-removal-in-3.13.rst @@ -0,0 +1,52 @@ +Pending Removal in Python 3.13 +------------------------------ + +Modules (see :pep:`594`): + +* :mod:`aifc` +* :mod:`audioop` +* :mod:`cgi` +* :mod:`cgitb` +* :mod:`chunk` +* :mod:`crypt` +* :mod:`imghdr` +* :mod:`mailcap` +* :mod:`msilib` +* :mod:`nis` +* :mod:`nntplib` +* :mod:`ossaudiodev` +* :mod:`pipes` +* :mod:`sndhdr` +* :mod:`spwd` +* :mod:`sunau` +* :mod:`telnetlib` +* :mod:`uu` +* :mod:`xdrlib` + +Other modules: + +* :mod:`!lib2to3`, and the :program:`2to3` program (:gh:`84540`) + +APIs: + +* :class:`!configparser.LegacyInterpolation` (:gh:`90765`) +* ``locale.resetlocale()`` (:gh:`90817`) +* :meth:`!turtle.RawTurtle.settiltangle` (:gh:`50096`) +* :func:`!unittest.findTestCases` (:gh:`50096`) +* :func:`!unittest.getTestCaseNames` (:gh:`50096`) +* :func:`!unittest.makeSuite` (:gh:`50096`) +* :meth:`!unittest.TestProgram.usageExit` (:gh:`67048`) +* :class:`!webbrowser.MacOSX` (:gh:`86421`) +* :class:`classmethod` descriptor chaining (:gh:`89519`) +* :mod:`importlib.resources` deprecated methods: + + * ``contents()`` + * ``is_resource()`` + * ``open_binary()`` + * ``open_text()`` + * ``path()`` + * ``read_binary()`` + * ``read_text()`` + + Use :func:`importlib.resources.files` instead. Refer to `importlib-resources: Migrating from Legacy + `_ (:gh:`106531`) diff --git a/Doc/deprecations/pending-removal-in-3.14.rst b/Doc/deprecations/pending-removal-in-3.14.rst new file mode 100644 index 00000000..b506b0f0 --- /dev/null +++ b/Doc/deprecations/pending-removal-in-3.14.rst @@ -0,0 +1,108 @@ +Pending Removal in Python 3.14 +------------------------------ + +* :mod:`argparse`: The *type*, *choices*, and *metavar* parameters + of :class:`!argparse.BooleanOptionalAction` are deprecated + and will be removed in 3.14. + (Contributed by Nikita Sobolev in :gh:`92248`.) + +* :mod:`ast`: The following features have been deprecated in documentation + since Python 3.8, now cause a :exc:`DeprecationWarning` to be emitted at + runtime when they are accessed or used, and will be removed in Python 3.14: + + * :class:`!ast.Num` + * :class:`!ast.Str` + * :class:`!ast.Bytes` + * :class:`!ast.NameConstant` + * :class:`!ast.Ellipsis` + + Use :class:`ast.Constant` instead. + (Contributed by Serhiy Storchaka in :gh:`90953`.) + +* :mod:`asyncio`: + + * The child watcher classes :class:`~asyncio.MultiLoopChildWatcher`, + :class:`~asyncio.FastChildWatcher`, :class:`~asyncio.AbstractChildWatcher` + and :class:`~asyncio.SafeChildWatcher` are deprecated and + will be removed in Python 3.14. + (Contributed by Kumar Aditya in :gh:`94597`.) + + * :func:`asyncio.set_child_watcher`, :func:`asyncio.get_child_watcher`, + :meth:`asyncio.AbstractEventLoopPolicy.set_child_watcher` and + :meth:`asyncio.AbstractEventLoopPolicy.get_child_watcher` are deprecated + and will be removed in Python 3.14. + (Contributed by Kumar Aditya in :gh:`94597`.) + + * The :meth:`~asyncio.get_event_loop` method of the + default event loop policy now emits a :exc:`DeprecationWarning` if there + is no current event loop set and it decides to create one. + (Contributed by Serhiy Storchaka and Guido van Rossum in :gh:`100160`.) + +* :mod:`collections.abc`: Deprecated :class:`~collections.abc.ByteString`. + Prefer :class:`!Sequence` or :class:`~collections.abc.Buffer`. + For use in typing, prefer a union, like ``bytes | bytearray``, + or :class:`collections.abc.Buffer`. + (Contributed by Shantanu Jain in :gh:`91896`.) + +* :mod:`email`: Deprecated the *isdst* parameter in :func:`email.utils.localtime`. + (Contributed by Alan Williams in :gh:`72346`.) + +* :mod:`importlib`: ``__package__`` and ``__cached__`` will cease to be set or + taken into consideration by the import system (:gh:`97879`). + +* :mod:`importlib.abc` deprecated classes: + + * :class:`!importlib.abc.ResourceReader` + * :class:`!importlib.abc.Traversable` + * :class:`!importlib.abc.TraversableResources` + + Use :mod:`importlib.resources.abc` classes instead: + + * :class:`importlib.resources.abc.Traversable` + * :class:`importlib.resources.abc.TraversableResources` + + (Contributed by Jason R. Coombs and Hugo van Kemenade in :gh:`93963`.) + +* :mod:`itertools` had undocumented, inefficient, historically buggy, + and inconsistent support for copy, deepcopy, and pickle operations. + This will be removed in 3.14 for a significant reduction in code + volume and maintenance burden. + (Contributed by Raymond Hettinger in :gh:`101588`.) + +* :mod:`multiprocessing`: The default start method will change to a safer one on + Linux, BSDs, and other non-macOS POSIX platforms where ``'fork'`` is currently + the default (:gh:`84559`). Adding a runtime warning about this was deemed too + disruptive as the majority of code is not expected to care. Use the + :func:`~multiprocessing.get_context` or + :func:`~multiprocessing.set_start_method` APIs to explicitly specify when + your code *requires* ``'fork'``. See :ref:`multiprocessing-start-methods`. + +* :mod:`pathlib`: :meth:`~pathlib.PurePath.is_relative_to` and + :meth:`~pathlib.PurePath.relative_to`: passing additional arguments is + deprecated. + +* :mod:`pkgutil`: :func:`~pkgutil.find_loader` and :func:`~pkgutil.get_loader` + now raise :exc:`DeprecationWarning`; + use :func:`importlib.util.find_spec` instead. + (Contributed by Nikita Sobolev in :gh:`97850`.) + +* :mod:`pty`: + + * ``master_open()``: use :func:`pty.openpty`. + * ``slave_open()``: use :func:`pty.openpty`. + +* :mod:`sqlite3`: + + * :data:`~sqlite3.version` and :data:`~sqlite3.version_info`. + + * :meth:`~sqlite3.Cursor.execute` and :meth:`~sqlite3.Cursor.executemany` + if :ref:`named placeholders ` are used and + *parameters* is a sequence instead of a :class:`dict`. + +* :mod:`typing`: :class:`~typing.ByteString`, deprecated since Python 3.9, + now causes a :exc:`DeprecationWarning` to be emitted when it is used. + +* :mod:`urllib`: + :class:`!urllib.parse.Quoter` is deprecated: it was not intended to be a + public API. + (Contributed by Gregory P. Smith in :gh:`88168`.) diff --git a/Doc/deprecations/pending-removal-in-3.15.rst b/Doc/deprecations/pending-removal-in-3.15.rst new file mode 100644 index 00000000..182a72b2 --- /dev/null +++ b/Doc/deprecations/pending-removal-in-3.15.rst @@ -0,0 +1,68 @@ +Pending Removal in Python 3.15 +------------------------------ + +* :class:`http.server.CGIHTTPRequestHandler` will be removed along with its + related ``--cgi`` flag to ``python -m http.server``. It was obsolete and + rarely used. No direct replacement exists. *Anything* is better than CGI + to interface a web server with a request handler. + +* :class:`locale`: :func:`locale.getdefaultlocale` was deprecated in Python 3.11 + and originally planned for removal in Python 3.13 (:gh:`90817`), + but removal has been postponed to Python 3.15. + Use :func:`locale.setlocale`, :func:`locale.getencoding` and + :func:`locale.getlocale` instead. + (Contributed by Hugo van Kemenade in :gh:`111187`.) + +* :mod:`pathlib`: + :meth:`pathlib.PurePath.is_reserved` is deprecated and scheduled for + removal in Python 3.15. From Python 3.13 onwards, use ``os.path.isreserved`` + to detect reserved paths on Windows. + +* :mod:`platform`: + :func:`~platform.java_ver` is deprecated and will be removed in 3.15. + It was largely untested, had a confusing API, + and was only useful for Jython support. + (Contributed by Nikita Sobolev in :gh:`116349`.) + +* :mod:`threading`: + Passing any arguments to :func:`threading.RLock` is now deprecated. + C version allows any numbers of args and kwargs, + but they are just ignored. Python version does not allow any arguments. + All arguments will be removed from :func:`threading.RLock` in Python 3.15. + (Contributed by Nikita Sobolev in :gh:`102029`.) + +* :class:`typing.NamedTuple`: + + * The undocumented keyword argument syntax for creating :class:`!NamedTuple` classes + (``NT = NamedTuple("NT", x=int)``) is deprecated, and will be disallowed in + 3.15. Use the class-based syntax or the functional syntax instead. + +* :mod:`types`: + + * :class:`types.CodeType`: Accessing :attr:`~codeobject.co_lnotab` was + deprecated in :pep:`626` + since 3.10 and was planned to be removed in 3.12, + but it only got a proper :exc:`DeprecationWarning` in 3.12. + May be removed in 3.15. + (Contributed by Nikita Sobolev in :gh:`101866`.) + +* :mod:`typing`: + + * When using the functional syntax to create a :class:`!NamedTuple` class, failing to + pass a value to the *fields* parameter (``NT = NamedTuple("NT")``) is + deprecated. Passing ``None`` to the *fields* parameter + (``NT = NamedTuple("NT", None)``) is also deprecated. Both will be + disallowed in Python 3.15. To create a :class:`!NamedTuple` class with 0 fields, use + ``class NT(NamedTuple): pass`` or ``NT = NamedTuple("NT", [])``. + +* :class:`typing.TypedDict`: When using the functional syntax to create a + :class:`!TypedDict` class, failing to pass a value to the *fields* parameter (``TD = + TypedDict("TD")``) is deprecated. Passing ``None`` to the *fields* parameter + (``TD = TypedDict("TD", None)``) is also deprecated. Both will be disallowed + in Python 3.15. To create a :class:`!TypedDict` class with 0 fields, use ``class + TD(TypedDict): pass`` or ``TD = TypedDict("TD", {})``. + +* :mod:`wave`: Deprecate the ``getmark()``, ``setmark()`` and ``getmarkers()`` + methods of the :class:`wave.Wave_read` and :class:`wave.Wave_write` classes. + They will be removed in Python 3.15. + (Contributed by Victor Stinner in :gh:`105096`.) diff --git a/Doc/deprecations/pending-removal-in-3.16.rst b/Doc/deprecations/pending-removal-in-3.16.rst new file mode 100644 index 00000000..f59a4037 --- /dev/null +++ b/Doc/deprecations/pending-removal-in-3.16.rst @@ -0,0 +1,20 @@ +Pending Removal in Python 3.16 +------------------------------ + +* The import system: + + * Setting :attr:`~module.__loader__` on a module while + failing to set :attr:`__spec__.loader ` + is deprecated. In Python 3.16, :attr:`!__loader__` will cease to be set or + taken into consideration by the import system or the standard library. + +* :mod:`array`: + :class:`array.array` ``'u'`` type (:c:type:`wchar_t`): + use the ``'w'`` type instead (``Py_UCS4``). + +* :mod:`builtins`: + ``~bool``, bitwise inversion on bool. + +* :mod:`symtable`: + Deprecate :meth:`symtable.Class.get_methods` due to the lack of interest. + (Contributed by Bénédikt Tran in :gh:`119698`.) diff --git a/Doc/deprecations/pending-removal-in-future.rst b/Doc/deprecations/pending-removal-in-future.rst new file mode 100644 index 00000000..c5981593 --- /dev/null +++ b/Doc/deprecations/pending-removal-in-future.rst @@ -0,0 +1,152 @@ +Pending Removal in Future Versions +---------------------------------- + +The following APIs will be removed in the future, +although there is currently no date scheduled for their removal. + +* :mod:`argparse`: Nesting argument groups and nesting mutually exclusive + groups are deprecated. + +* :mod:`array`'s ``'u'`` format code (:gh:`57281`) + +* :mod:`builtins`: + + * ``bool(NotImplemented)``. + * Generators: ``throw(type, exc, tb)`` and ``athrow(type, exc, tb)`` + signature is deprecated: use ``throw(exc)`` and ``athrow(exc)`` instead, + the single argument signature. + * Currently Python accepts numeric literals immediately followed by keywords, + for example ``0in x``, ``1or x``, ``0if 1else 2``. It allows confusing and + ambiguous expressions like ``[0x1for x in y]`` (which can be interpreted as + ``[0x1 for x in y]`` or ``[0x1f or x in y]``). A syntax warning is raised + if the numeric literal is immediately followed by one of keywords + :keyword:`and`, :keyword:`else`, :keyword:`for`, :keyword:`if`, + :keyword:`in`, :keyword:`is` and :keyword:`or`. In a future release it + will be changed to a syntax error. (:gh:`87999`) + * Support for ``__index__()`` and ``__int__()`` method returning non-int type: + these methods will be required to return an instance of a strict subclass of + :class:`int`. + * Support for ``__float__()`` method returning a strict subclass of + :class:`float`: these methods will be required to return an instance of + :class:`float`. + * Support for ``__complex__()`` method returning a strict subclass of + :class:`complex`: these methods will be required to return an instance of + :class:`complex`. + * Delegation of ``int()`` to ``__trunc__()`` method. + * Passing a complex number as the *real* or *imag* argument in the + :func:`complex` constructor is now deprecated; it should only be passed + as a single positional argument. + (Contributed by Serhiy Storchaka in :gh:`109218`.) + +* :mod:`calendar`: ``calendar.January`` and ``calendar.February`` constants are + deprecated and replaced by :data:`calendar.JANUARY` and + :data:`calendar.FEBRUARY`. + (Contributed by Prince Roshan in :gh:`103636`.) + +* :attr:`codeobject.co_lnotab`: use the :meth:`codeobject.co_lines` method + instead. + +* :mod:`datetime`: + + * :meth:`~datetime.datetime.utcnow`: + use ``datetime.datetime.now(tz=datetime.UTC)``. + * :meth:`~datetime.datetime.utcfromtimestamp`: + use ``datetime.datetime.fromtimestamp(timestamp, tz=datetime.UTC)``. + +* :mod:`gettext`: Plural value must be an integer. + +* :mod:`importlib`: + + * ``load_module()`` method: use ``exec_module()`` instead. + * :func:`~importlib.util.cache_from_source` *debug_override* parameter is + deprecated: use the *optimization* parameter instead. + +* :mod:`importlib.metadata`: + + * ``EntryPoints`` tuple interface. + * Implicit ``None`` on return values. + +* :mod:`mailbox`: Use of StringIO input and text mode is deprecated, use + BytesIO and binary mode instead. + +* :mod:`os`: Calling :func:`os.register_at_fork` in multi-threaded process. + +* :class:`!pydoc.ErrorDuringImport`: A tuple value for *exc_info* parameter is + deprecated, use an exception instance. + +* :mod:`re`: More strict rules are now applied for numerical group references + and group names in regular expressions. Only sequence of ASCII digits is now + accepted as a numerical reference. The group name in bytes patterns and + replacement strings can now only contain ASCII letters and digits and + underscore. + (Contributed by Serhiy Storchaka in :gh:`91760`.) + +* :mod:`!sre_compile`, :mod:`!sre_constants` and :mod:`!sre_parse` modules. + +* :mod:`shutil`: :func:`~shutil.rmtree`'s *onerror* parameter is deprecated in + Python 3.12; use the *onexc* parameter instead. + +* :mod:`ssl` options and protocols: + + * :class:`ssl.SSLContext` without protocol argument is deprecated. + * :class:`ssl.SSLContext`: :meth:`~ssl.SSLContext.set_npn_protocols` and + :meth:`!selected_npn_protocol` are deprecated: use ALPN + instead. + * ``ssl.OP_NO_SSL*`` options + * ``ssl.OP_NO_TLS*`` options + * ``ssl.PROTOCOL_SSLv3`` + * ``ssl.PROTOCOL_TLS`` + * ``ssl.PROTOCOL_TLSv1`` + * ``ssl.PROTOCOL_TLSv1_1`` + * ``ssl.PROTOCOL_TLSv1_2`` + * ``ssl.TLSVersion.SSLv3`` + * ``ssl.TLSVersion.TLSv1`` + * ``ssl.TLSVersion.TLSv1_1`` + +* :func:`sysconfig.is_python_build` *check_home* parameter is deprecated and + ignored. + +* :mod:`threading` methods: + + * :meth:`!threading.Condition.notifyAll`: use :meth:`~threading.Condition.notify_all`. + * :meth:`!threading.Event.isSet`: use :meth:`~threading.Event.is_set`. + * :meth:`!threading.Thread.isDaemon`, :meth:`threading.Thread.setDaemon`: + use :attr:`threading.Thread.daemon` attribute. + * :meth:`!threading.Thread.getName`, :meth:`threading.Thread.setName`: + use :attr:`threading.Thread.name` attribute. + * :meth:`!threading.currentThread`: use :meth:`threading.current_thread`. + * :meth:`!threading.activeCount`: use :meth:`threading.active_count`. + +* :class:`typing.Text` (:gh:`92332`). + +* :class:`unittest.IsolatedAsyncioTestCase`: it is deprecated to return a value + that is not ``None`` from a test case. + +* :mod:`urllib.parse` deprecated functions: :func:`~urllib.parse.urlparse` instead + + * ``splitattr()`` + * ``splithost()`` + * ``splitnport()`` + * ``splitpasswd()`` + * ``splitport()`` + * ``splitquery()`` + * ``splittag()`` + * ``splittype()`` + * ``splituser()`` + * ``splitvalue()`` + * ``to_bytes()`` + +* :mod:`urllib.request`: :class:`~urllib.request.URLopener` and + :class:`~urllib.request.FancyURLopener` style of invoking requests is + deprecated. Use newer :func:`~urllib.request.urlopen` functions and methods. + +* :mod:`wsgiref`: ``SimpleHandler.stdout.write()`` should not do partial + writes. + +* :mod:`xml.etree.ElementTree`: Testing the truth value of an + :class:`~xml.etree.ElementTree.Element` is deprecated. In a future release it + will always return ``True``. Prefer explicit ``len(elem)`` or + ``elem is not None`` tests instead. + +* :meth:`zipimport.zipimporter.load_module` is deprecated: + use :meth:`~zipimport.zipimporter.exec_module` instead. diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst index cb553cc2..4ee78d28 100644 --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -296,7 +296,7 @@ An interesting advantage of using the :c:member:`~PyTypeObject.tp_members` table descriptors that are used at runtime is that any attribute defined this way can have an associated doc string simply by providing the text in the table. An application can use the introspection API to retrieve the descriptor from the -class object, and get the doc string using its :attr:`!__doc__` attribute. +class object, and get the doc string using its :attr:`~type.__doc__` attribute. As with the :c:member:`~PyTypeObject.tp_methods` table, a sentinel entry with a :c:member:`~PyMethodDef.ml_name` value of ``NULL`` is required. diff --git a/Doc/extending/newtypes_tutorial.rst b/Doc/extending/newtypes_tutorial.rst index c2bc5f69..c5ef1e55 100644 --- a/Doc/extending/newtypes_tutorial.rst +++ b/Doc/extending/newtypes_tutorial.rst @@ -144,7 +144,7 @@ only used for variable-sized objects and should otherwise be zero. If you want your type to be subclassable from Python, and your type has the same :c:member:`~PyTypeObject.tp_basicsize` as its base type, you may have problems with multiple inheritance. A Python subclass of your type will have to list your type first - in its :attr:`~class.__bases__`, or else it will not be able to call your type's + in its :attr:`~type.__bases__`, or else it will not be able to call your type's :meth:`~object.__new__` method without getting an error. You can avoid this problem by ensuring that your type has a larger value for :c:member:`~PyTypeObject.tp_basicsize` than its base type does. Most of the time, this will be true anyway, because either your @@ -449,7 +449,7 @@ Further, the attributes can be deleted, setting the C pointers to ``NULL``. Eve though we can make sure the members are initialized to non-``NULL`` values, the members can be set to ``NULL`` if the attributes are deleted. -We define a single method, :meth:`!Custom.name()`, that outputs the objects name as the +We define a single method, :meth:`!Custom.name`, that outputs the objects name as the concatenation of the first and last names. :: static PyObject * diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst index c8beb64e..e2710fab 100644 --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -70,7 +70,7 @@ operations. This means that as far as floating-point operations are concerned, Python behaves like many popular languages including C and Java. Many numbers that can be written easily in decimal notation cannot be expressed -exactly in binary floating-point. For example, after:: +exactly in binary floating point. For example, after:: >>> x = 1.2 @@ -87,7 +87,7 @@ which is exactly:: The typical precision of 53 bits provides Python floats with 15--16 decimal digits of accuracy. -For a fuller explanation, please see the :ref:`floating point arithmetic +For a fuller explanation, please see the :ref:`floating-point arithmetic ` chapter in the Python tutorial. @@ -328,7 +328,7 @@ Can Python be compiled to machine code, C or some other language? ----------------------------------------------------------------- `Cython `_ compiles a modified version of Python with -optional annotations into C extensions. `Nuitka `_ is +optional annotations into C extensions. `Nuitka `_ is an up-and-coming compiler of Python into C++ code, aiming to support the full Python language. @@ -345,7 +345,7 @@ to perform a garbage collection, obtain debugging statistics, and tune the collector's parameters. Other implementations (such as `Jython `_ or -`PyPy `_), however, can rely on a different mechanism +`PyPy `_), however, can rely on a different mechanism such as a full-blown garbage collector. This difference can cause some subtle porting problems if your Python code depends on the behavior of the reference counting implementation. diff --git a/Doc/faq/extending.rst b/Doc/faq/extending.rst index 1cff2c40..3147fda7 100644 --- a/Doc/faq/extending.rst +++ b/Doc/faq/extending.rst @@ -246,13 +246,12 @@ Then, when you run GDB: I want to compile a Python module on my Linux system, but some files are missing. Why? -------------------------------------------------------------------------------------- -Most packaged versions of Python don't include the -:file:`/usr/lib/python2.{x}/config/` directory, which contains various files +Most packaged versions of Python omit some files required for compiling Python extensions. -For Red Hat, install the python-devel RPM to get the necessary files. +For Red Hat, install the python3-devel RPM to get the necessary files. -For Debian, run ``apt-get install python-dev``. +For Debian, run ``apt-get install python3-dev``. How do I tell "incomplete input" from "invalid input"? ------------------------------------------------------ diff --git a/Doc/faq/general.rst b/Doc/faq/general.rst index eb859c5d..578777d7 100644 --- a/Doc/faq/general.rst +++ b/Doc/faq/general.rst @@ -309,10 +309,9 @@ guaranteed that interfaces will remain the same throughout a series of bugfix releases. The latest stable releases can always be found on the `Python download page -`_. There are two production-ready versions -of Python: 2.x and 3.x. The recommended version is 3.x, which is supported by -most widely used libraries. Although 2.x is still widely used, `it is not -maintained anymore `_. +`_. +Python 3.x is the recommended version and supported by most widely used libraries. +Python 2.x :pep:`is not maintained anymore <373>`. How many people are using Python? --------------------------------- diff --git a/Doc/faq/library.rst b/Doc/faq/library.rst index ac10a04d..45fd7eb1 100644 --- a/Doc/faq/library.rst +++ b/Doc/faq/library.rst @@ -825,12 +825,12 @@ is simple:: import random random.random() -This returns a random floating point number in the range [0, 1). +This returns a random floating-point number in the range [0, 1). There are also many other specialized generators in this module, such as: * ``randrange(a, b)`` chooses an integer in the range [a, b). -* ``uniform(a, b)`` chooses a floating point number in the range [a, b). +* ``uniform(a, b)`` chooses a floating-point number in the range [a, b). * ``normalvariate(mean, sdev)`` samples the normal (Gaussian) distribution. Some higher-level functions operate on sequences directly, such as: diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst index f43f69b8..7a867011 100644 --- a/Doc/faq/programming.rst +++ b/Doc/faq/programming.rst @@ -869,7 +869,7 @@ How do I convert a string to a number? -------------------------------------- For integers, use the built-in :func:`int` type constructor, e.g. ``int('144') -== 144``. Similarly, :func:`float` converts to floating-point, +== 144``. Similarly, :func:`float` converts to a floating-point number, e.g. ``float('144') == 144.0``. By default, these interpret the number as decimal, so that ``int('0144') == @@ -1013,7 +1013,7 @@ Not as such. For simple input parsing, the easiest approach is usually to split the line into whitespace-delimited words using the :meth:`~str.split` method of string objects and then convert decimal strings to numeric values using :func:`int` or -:func:`float`. :meth:`!split()` supports an optional "sep" parameter which is useful +:func:`float`. :meth:`!split` supports an optional "sep" parameter which is useful if the line uses something other than whitespace as a separator. For more complicated input parsing, regular expressions are more powerful @@ -1613,9 +1613,16 @@ method too, and it must do so carefully. The basic implementation of self.__dict__[name] = value ... -Most :meth:`!__setattr__` implementations must modify -:meth:`self.__dict__ ` to store -local state for self without causing an infinite recursion. +Many :meth:`~object.__setattr__` implementations call :meth:`!object.__setattr__` to set +an attribute on self without causing infinite recursion:: + + class X: + def __setattr__(self, name, value): + # Custom logic here... + object.__setattr__(self, name, value) + +Alternatively, it is possible to set attributes by inserting +entries into :attr:`self.__dict__ ` directly. How do I call a method defined in a base class from a derived class that extends it? @@ -1741,11 +1748,31 @@ but effective way to define class private variables. Any identifier of the form is textually replaced with ``_classname__spam``, where ``classname`` is the current class name with any leading underscores stripped. -This doesn't guarantee privacy: an outside user can still deliberately access -the "_classname__spam" attribute, and private values are visible in the object's -``__dict__``. Many Python programmers never bother to use private variable -names at all. +The identifier can be used unchanged within the class, but to access it outside +the class, the mangled name must be used: + +.. code-block:: python + + class A: + def __one(self): + return 1 + def two(self): + return 2 * self.__one() + + class B(A): + def three(self): + return 3 * self._A__one() + + four = 4 * A()._A__one() + +In particular, this does not guarantee privacy since an outside user can still +deliberately access the private attribute; many Python programmers never bother +to use private variable names at all. + +.. seealso:: + The :ref:`private name mangling specifications ` + for details and special cases. My class defines __del__ but it is not called when I delete the object. ----------------------------------------------------------------------- diff --git a/Doc/glossary.rst b/Doc/glossary.rst index d1745bf5..9b29699e 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -350,7 +350,7 @@ Glossary docstring A string literal which appears as the first expression in a class, function or module. While ignored when the suite is executed, it is - recognized by the compiler and put into the :attr:`!__doc__` attribute + recognized by the compiler and put into the :attr:`~definition.__doc__` attribute of the enclosing class, function or module. Since it is available via introspection, it is the canonical place for documentation of the object. @@ -437,7 +437,7 @@ Glossary ` for use with :data:`sys.meta_path`, and :term:`path entry finders ` for use with :data:`sys.path_hooks`. - See :ref:`importsystem` and :mod:`importlib` for much more detail. + See :ref:`finders-and-loaders` and :mod:`importlib` for much more detail. floor division Mathematical division that rounds down to nearest integer. The floor @@ -591,6 +591,14 @@ Glossary :ref:`idle` is a basic editor and interpreter environment which ships with the standard distribution of Python. + immortal + *Immortal objects* are a CPython implementation detail introduced + in :pep:`683`. + + If an object is immortal, its :term:`reference count` is never modified, + and therefore it is never deallocated while the interpreter is running. + For example, :const:`True` and :const:`None` are immortal in CPython. + immutable An object with a fixed value. Immutable objects include numbers, strings and tuples. Such an object cannot be altered. A new object has to @@ -742,8 +750,11 @@ Glossary loader An object that loads a module. It must define a method named :meth:`load_module`. A loader is typically returned by a - :term:`finder`. See :pep:`302` for details and - :class:`importlib.abc.Loader` for an :term:`abstract base class`. + :term:`finder`. See also: + + * :ref:`finders-and-loaders` + * :class:`importlib.abc.Loader` + * :pep:`302` locale encoding On Unix, it is the encoding of the LC_CTYPE locale. It can be set with @@ -813,6 +824,8 @@ Glossary A namespace containing the import-related information used to load a module. An instance of :class:`importlib.machinery.ModuleSpec`. + See also :ref:`module-specs`. + MRO See :term:`method resolution order`. @@ -1098,7 +1111,7 @@ Glossary :class:`tuple`, and :class:`bytes`. Note that :class:`dict` also supports :meth:`~object.__getitem__` and :meth:`!__len__`, but is considered a mapping rather than a sequence because the lookups use arbitrary - :term:`immutable` keys rather than integers. + :term:`hashable` keys rather than integers. The :class:`collections.abc.Sequence` abstract base class defines a much richer interface that goes beyond just @@ -1126,6 +1139,17 @@ Glossary when several are given, such as in ``variable_name[1:3:5]``. The bracket (subscript) notation uses :class:`slice` objects internally. + soft deprecated + A soft deprecated API should not be used in new code, + but it is safe for already existing code to use it. + The API remains documented and tested, but will not be enhanced further. + + Soft deprecation, unlike normal deprecation, does not plan on removing the API + and will not emit warnings. + + See `PEP 387: Soft Deprecation + `_. + special method .. index:: pair: special; method @@ -1193,7 +1217,7 @@ Glossary type The type of a Python object determines what kind of object it is; every object has a type. An object's type is accessible as its - :attr:`~instance.__class__` attribute or can be retrieved with + :attr:`~object.__class__` attribute or can be retrieved with ``type(obj)``. type alias diff --git a/Doc/howto/annotations.rst b/Doc/howto/annotations.rst index be8c7e6c..174078b8 100644 --- a/Doc/howto/annotations.rst +++ b/Doc/howto/annotations.rst @@ -102,9 +102,9 @@ Your code will have to have a separate code path if the object you're examining is a class (``isinstance(o, type)``). In that case, best practice relies on an implementation detail of Python 3.9 and before: if a class has annotations defined, -they are stored in the class's ``__dict__`` dictionary. Since +they are stored in the class's :attr:`~type.__dict__` dictionary. Since the class may or may not have annotations defined, best practice -is to call the ``get`` method on the class dict. +is to call the :meth:`~dict.get` method on the class dict. To put it all together, here is some sample code that safely accesses the ``__annotations__`` attribute on an arbitrary @@ -121,8 +121,8 @@ the type of ``ann`` using :func:`isinstance` before further examination. Note that some exotic or malformed type objects may not have -a ``__dict__`` attribute, so for extra safety you may also wish -to use :func:`getattr` to access ``__dict__``. +a :attr:`~type.__dict__` attribute, so for extra safety you may also wish +to use :func:`getattr` to access :attr:`!__dict__`. Manually Un-Stringizing Stringized Annotations diff --git a/Doc/howto/argparse-optparse.rst b/Doc/howto/argparse-optparse.rst new file mode 100644 index 00000000..cef2d893 --- /dev/null +++ b/Doc/howto/argparse-optparse.rst @@ -0,0 +1,55 @@ +.. currentmodule:: argparse + +.. _upgrading-optparse-code: + +========================== +Upgrading optparse code +========================== + +Originally, the :mod:`argparse` module had attempted to maintain compatibility +with :mod:`optparse`. However, :mod:`optparse` was difficult to extend +transparently, particularly with the changes required to support +``nargs=`` specifiers and better usage messages. When most everything in +:mod:`optparse` had either been copy-pasted over or monkey-patched, it no +longer seemed practical to try to maintain the backwards compatibility. + +The :mod:`argparse` module improves on the :mod:`optparse` +module in a number of ways including: + +* Handling positional arguments. +* Supporting subcommands. +* Allowing alternative option prefixes like ``+`` and ``/``. +* Handling zero-or-more and one-or-more style arguments. +* Producing more informative usage messages. +* Providing a much simpler interface for custom ``type`` and ``action``. + +A partial upgrade path from :mod:`optparse` to :mod:`argparse`: + +* Replace all :meth:`optparse.OptionParser.add_option` calls with + :meth:`ArgumentParser.add_argument` calls. + +* Replace ``(options, args) = parser.parse_args()`` with ``args = + parser.parse_args()`` and add additional :meth:`ArgumentParser.add_argument` + calls for the positional arguments. Keep in mind that what was previously + called ``options``, now in the :mod:`argparse` context is called ``args``. + +* Replace :meth:`optparse.OptionParser.disable_interspersed_args` + by using :meth:`~ArgumentParser.parse_intermixed_args` instead of + :meth:`~ArgumentParser.parse_args`. + +* Replace callback actions and the ``callback_*`` keyword arguments with + ``type`` or ``action`` arguments. + +* Replace string names for ``type`` keyword arguments with the corresponding + type objects (e.g. int, float, complex, etc). + +* Replace :class:`optparse.Values` with :class:`Namespace` and + :exc:`optparse.OptionError` and :exc:`optparse.OptionValueError` with + :exc:`ArgumentError`. + +* Replace strings with implicit arguments such as ``%default`` or ``%prog`` with + the standard Python syntax to use dictionaries to format strings, that is, + ``%(default)s`` and ``%(prog)s``. + +* Replace the OptionParser constructor ``version`` argument with a call to + ``parser.add_argument('--version', action='version', version='')``. diff --git a/Doc/howto/argparse.rst b/Doc/howto/argparse.rst index ae5bab90..ac2a0465 100644 --- a/Doc/howto/argparse.rst +++ b/Doc/howto/argparse.rst @@ -841,6 +841,53 @@ translated messages. To translate your own strings in the :mod:`argparse` output, use :mod:`gettext`. +Custom type converters +====================== + +The :mod:`argparse` module allows you to specify custom type converters for +your command-line arguments. This allows you to modify user input before it's +stored in the :class:`argparse.Namespace`. This can be useful when you need to +pre-process the input before it is used in your program. + +When using a custom type converter, you can use any callable that takes a +single string argument (the argument value) and returns the converted value. +However, if you need to handle more complex scenarios, you can use a custom +action class with the **action** parameter instead. + +For example, let's say you want to handle arguments with different prefixes and +process them accordingly:: + + import argparse + + parser = argparse.ArgumentParser(prefix_chars='-+') + + parser.add_argument('-a', metavar='', action='append', + type=lambda x: ('-', x)) + parser.add_argument('+a', metavar='', action='append', + type=lambda x: ('+', x)) + + args = parser.parse_args() + print(args) + +Output: + +.. code-block:: shell-session + + $ python prog.py -a value1 +a value2 + Namespace(a=[('-', 'value1'), ('+', 'value2')]) + +In this example, we: + +* Created a parser with custom prefix characters using the ``prefix_chars`` + parameter. + +* Defined two arguments, ``-a`` and ``+a``, which used the ``type`` parameter to + create custom type converters to store the value in a tuple with the prefix. + +Without the custom type converters, the arguments would have treated the ``-a`` +and ``+a`` as the same argument, which would have been undesirable. By using custom +type converters, we were able to differentiate between the two arguments. + Conclusion ========== diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst index 330402d1..ac73fcb3 100644 --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -42,7 +42,7 @@ add new capabilities one by one. Simple example: A descriptor that returns a constant ---------------------------------------------------- -The :class:`Ten` class is a descriptor whose :meth:`__get__` method always +The :class:`!Ten` class is a descriptor whose :meth:`~object.__get__` method always returns the constant ``10``: .. testcode:: @@ -120,10 +120,10 @@ different, updated answers each time:: 2 Besides showing how descriptors can run computations, this example also -reveals the purpose of the parameters to :meth:`__get__`. The *self* +reveals the purpose of the parameters to :meth:`~object.__get__`. The *self* parameter is *size*, an instance of *DirectorySize*. The *obj* parameter is either *g* or *s*, an instance of *Directory*. It is the *obj* parameter that -lets the :meth:`__get__` method learn the target directory. The *objtype* +lets the :meth:`~object.__get__` method learn the target directory. The *objtype* parameter is the class *Directory*. @@ -133,7 +133,7 @@ Managed attributes A popular use for descriptors is managing access to instance data. The descriptor is assigned to a public attribute in the class dictionary while the actual data is stored as a private attribute in the instance dictionary. The -descriptor's :meth:`__get__` and :meth:`__set__` methods are triggered when +descriptor's :meth:`~object.__get__` and :meth:`~object.__set__` methods are triggered when the public attribute is accessed. In the following example, *age* is the public attribute and *_age* is the @@ -215,9 +215,9 @@ Customized names When a class uses descriptors, it can inform each descriptor about which variable name was used. -In this example, the :class:`Person` class has two descriptor instances, -*name* and *age*. When the :class:`Person` class is defined, it makes a -callback to :meth:`__set_name__` in *LoggedAccess* so that the field names can +In this example, the :class:`!Person` class has two descriptor instances, +*name* and *age*. When the :class:`!Person` class is defined, it makes a +callback to :meth:`~object.__set_name__` in *LoggedAccess* so that the field names can be recorded, giving each descriptor its own *public_name* and *private_name*: .. testcode:: @@ -253,8 +253,8 @@ be recorded, giving each descriptor its own *public_name* and *private_name*: def birthday(self): self.age += 1 -An interactive session shows that the :class:`Person` class has called -:meth:`__set_name__` so that the field names would be recorded. Here +An interactive session shows that the :class:`!Person` class has called +:meth:`~object.__set_name__` so that the field names would be recorded. Here we call :func:`vars` to look up the descriptor without triggering it: .. doctest:: @@ -294,10 +294,10 @@ The two *Person* instances contain only the private names: Closing thoughts ---------------- -A :term:`descriptor` is what we call any object that defines :meth:`__get__`, -:meth:`__set__`, or :meth:`__delete__`. +A :term:`descriptor` is what we call any object that defines :meth:`~object.__get__`, +:meth:`~object.__set__`, or :meth:`~object.__delete__`. -Optionally, descriptors can have a :meth:`__set_name__` method. This is only +Optionally, descriptors can have a :meth:`~object.__set_name__` method. This is only used in cases where a descriptor needs to know either the class where it was created or the name of class variable it was assigned to. (This method, if present, is called even if the class is not a descriptor.) @@ -337,7 +337,7 @@ any data, it verifies that the new value meets various type and range restrictions. If those restrictions aren't met, it raises an exception to prevent data corruption at its source. -This :class:`Validator` class is both an :term:`abstract base class` and a +This :class:`!Validator` class is both an :term:`abstract base class` and a managed attribute descriptor: .. testcode:: @@ -360,8 +360,8 @@ managed attribute descriptor: def validate(self, value): pass -Custom validators need to inherit from :class:`Validator` and must supply a -:meth:`validate` method to test various restrictions as needed. +Custom validators need to inherit from :class:`!Validator` and must supply a +:meth:`!validate` method to test various restrictions as needed. Custom validators @@ -369,13 +369,13 @@ Custom validators Here are three practical data validation utilities: -1) :class:`OneOf` verifies that a value is one of a restricted set of options. +1) :class:`!OneOf` verifies that a value is one of a restricted set of options. -2) :class:`Number` verifies that a value is either an :class:`int` or +2) :class:`!Number` verifies that a value is either an :class:`int` or :class:`float`. Optionally, it verifies that a value is between a given minimum or maximum. -3) :class:`String` verifies that a value is a :class:`str`. Optionally, it +3) :class:`!String` verifies that a value is a :class:`str`. Optionally, it validates a given minimum or maximum length. It can validate a user-defined `predicate `_ as well. @@ -498,8 +498,8 @@ Definition and introduction --------------------------- In general, a descriptor is an attribute value that has one of the methods in -the descriptor protocol. Those methods are :meth:`__get__`, :meth:`__set__`, -and :meth:`__delete__`. If any of those methods are defined for an +the descriptor protocol. Those methods are :meth:`~object.__get__`, :meth:`~object.__set__`, +and :meth:`~object.__delete__`. If any of those methods are defined for an attribute, it is said to be a :term:`descriptor`. The default behavior for attribute access is to get, set, or delete the @@ -513,7 +513,7 @@ were defined. Descriptors are a powerful, general purpose protocol. They are the mechanism behind properties, methods, static methods, class methods, and -:func:`super()`. They are used throughout Python itself. Descriptors +:func:`super`. They are used throughout Python itself. Descriptors simplify the underlying C code and offer a flexible set of new tools for everyday Python programs. @@ -531,8 +531,8 @@ That is all there is to it. Define any of these methods and an object is considered a descriptor and can override default behavior upon being looked up as an attribute. -If an object defines :meth:`__set__` or :meth:`__delete__`, it is considered -a data descriptor. Descriptors that only define :meth:`__get__` are called +If an object defines :meth:`~object.__set__` or :meth:`~object.__delete__`, it is considered +a data descriptor. Descriptors that only define :meth:`~object.__get__` are called non-data descriptors (they are often used for methods but other uses are possible). @@ -542,9 +542,9 @@ has an entry with the same name as a data descriptor, the data descriptor takes precedence. If an instance's dictionary has an entry with the same name as a non-data descriptor, the dictionary entry takes precedence. -To make a read-only data descriptor, define both :meth:`__get__` and -:meth:`__set__` with the :meth:`__set__` raising an :exc:`AttributeError` when -called. Defining the :meth:`__set__` method with an exception raising +To make a read-only data descriptor, define both :meth:`~object.__get__` and +:meth:`~object.__set__` with the :meth:`~object.__set__` raising an :exc:`AttributeError` when +called. Defining the :meth:`~object.__set__` method with an exception raising placeholder is enough to make it a data descriptor. @@ -559,8 +559,8 @@ attribute access. The expression ``obj.x`` looks up the attribute ``x`` in the chain of namespaces for ``obj``. If the search finds a descriptor outside of the -instance ``__dict__``, its :meth:`__get__` method is invoked according to the -precedence rules listed below. +instance :attr:`~object.__dict__`, its :meth:`~object.__get__` method is +invoked according to the precedence rules listed below. The details of invocation depend on whether ``obj`` is an object, class, or instance of super. @@ -571,7 +571,7 @@ Invocation from an instance Instance lookup scans through a chain of namespaces giving data descriptors the highest priority, followed by instance variables, then non-data -descriptors, then class variables, and lastly :meth:`__getattr__` if it is +descriptors, then class variables, and lastly :meth:`~object.__getattr__` if it is provided. If a descriptor is found for ``a.x``, then it is invoked with: @@ -716,12 +716,12 @@ a pure Python equivalent: >>> object_getattribute(u2, 'x') == u2.x == (D1, u2, U2) True -Note, there is no :meth:`__getattr__` hook in the :meth:`__getattribute__` -code. That is why calling :meth:`__getattribute__` directly or with -``super().__getattribute__`` will bypass :meth:`__getattr__` entirely. +Note, there is no :meth:`~object.__getattr__` hook in the :meth:`~object.__getattribute__` +code. That is why calling :meth:`~object.__getattribute__` directly or with +``super().__getattribute__`` will bypass :meth:`~object.__getattr__` entirely. Instead, it is the dot operator and the :func:`getattr` function that are -responsible for invoking :meth:`__getattr__` whenever :meth:`__getattribute__` +responsible for invoking :meth:`~object.__getattr__` whenever :meth:`~object.__getattribute__` raises an :exc:`AttributeError`. Their logic is encapsulated in a helper function: @@ -773,8 +773,8 @@ Invocation from a class ----------------------- The logic for a dotted lookup such as ``A.x`` is in -:meth:`type.__getattribute__`. The steps are similar to those for -:meth:`object.__getattribute__` but the instance dictionary lookup is replaced +:meth:`!type.__getattribute__`. The steps are similar to those for +:meth:`!object.__getattribute__` but the instance dictionary lookup is replaced by a search through the class's :term:`method resolution order`. If a descriptor is found, it is invoked with ``desc.__get__(None, A)``. @@ -786,8 +786,8 @@ The full C implementation can be found in :c:func:`!type_getattro` and Invocation from super --------------------- -The logic for super's dotted lookup is in the :meth:`__getattribute__` method for -object returned by :class:`super()`. +The logic for super's dotted lookup is in the :meth:`~object.__getattribute__` method for +object returned by :func:`super`. A dotted lookup such as ``super(A, obj).m`` searches ``obj.__class__.__mro__`` for the base class ``B`` immediately following ``A`` and then returns @@ -803,21 +803,21 @@ The full C implementation can be found in :c:func:`!super_getattro` in Summary of invocation logic --------------------------- -The mechanism for descriptors is embedded in the :meth:`__getattribute__()` +The mechanism for descriptors is embedded in the :meth:`~object.__getattribute__` methods for :class:`object`, :class:`type`, and :func:`super`. The important points to remember are: -* Descriptors are invoked by the :meth:`__getattribute__` method. +* Descriptors are invoked by the :meth:`~object.__getattribute__` method. * Classes inherit this machinery from :class:`object`, :class:`type`, or :func:`super`. -* Overriding :meth:`__getattribute__` prevents automatic descriptor calls +* Overriding :meth:`~object.__getattribute__` prevents automatic descriptor calls because all the descriptor logic is in that method. -* :meth:`object.__getattribute__` and :meth:`type.__getattribute__` make - different calls to :meth:`__get__`. The first includes the instance and may +* :meth:`!object.__getattribute__` and :meth:`!type.__getattribute__` make + different calls to :meth:`~object.__get__`. The first includes the instance and may include the class. The second puts in ``None`` for the instance and always includes the class. @@ -832,16 +832,16 @@ Automatic name notification Sometimes it is desirable for a descriptor to know what class variable name it was assigned to. When a new class is created, the :class:`type` metaclass scans the dictionary of the new class. If any of the entries are descriptors -and if they define :meth:`__set_name__`, that method is called with two +and if they define :meth:`~object.__set_name__`, that method is called with two arguments. The *owner* is the class where the descriptor is used, and the *name* is the class variable the descriptor was assigned to. The implementation details are in :c:func:`!type_new` and :c:func:`!set_names` in :source:`Objects/typeobject.c`. -Since the update logic is in :meth:`type.__new__`, notifications only take +Since the update logic is in :meth:`!type.__new__`, notifications only take place at the time of class creation. If descriptors are added to the class -afterwards, :meth:`__set_name__` will need to be called manually. +afterwards, :meth:`~object.__set_name__` will need to be called manually. ORM example @@ -870,7 +870,7 @@ care of lookups or updates: conn.execute(self.store, [value, obj.key]) conn.commit() -We can use the :class:`Field` class to define `models +We can use the :class:`!Field` class to define `models `_ that describe the schema for each table in a database: @@ -1150,7 +1150,7 @@ to wrap access to the value attribute in a property data descriptor: self.recalc() return self._value -Either the built-in :func:`property` or our :func:`Property` equivalent would +Either the built-in :func:`property` or our :func:`!Property` equivalent would work in this example. @@ -1183,7 +1183,7 @@ roughly equivalent to: return func(obj, *args, **kwargs) To support automatic creation of methods, functions include the -:meth:`__get__` method for binding methods during attribute access. This +:meth:`~object.__get__` method for binding methods during attribute access. This means that functions are non-data descriptors that return bound methods during dotted lookup from an instance. Here's how it works: @@ -1215,19 +1215,19 @@ The function has a :term:`qualified name` attribute to support introspection: 'D.f' Accessing the function through the class dictionary does not invoke -:meth:`__get__`. Instead, it just returns the underlying function object:: +:meth:`~object.__get__`. Instead, it just returns the underlying function object:: >>> D.__dict__['f'] -Dotted access from a class calls :meth:`__get__` which just returns the +Dotted access from a class calls :meth:`~object.__get__` which just returns the underlying function unchanged:: >>> D.f The interesting behavior occurs during dotted access from an instance. The -dotted lookup calls :meth:`__get__` which returns a bound method object:: +dotted lookup calls :meth:`~object.__get__` which returns a bound method object:: >>> d = D() >>> d.f @@ -1252,7 +1252,7 @@ Kinds of methods Non-data descriptors provide a simple mechanism for variations on the usual patterns of binding functions into methods. -To recap, functions have a :meth:`__get__` method so that they can be converted +To recap, functions have a :meth:`~object.__get__` method so that they can be converted to a method when accessed as attributes. The non-data descriptor transforms an ``obj.f(*args)`` call into ``f(obj, *args)``. Calling ``cls.f(*args)`` becomes ``f(*args)``. @@ -1682,7 +1682,7 @@ by member descriptors: 'Emulate member_repr() in Objects/descrobject.c' return f'' -The :meth:`type.__new__` method takes care of adding member objects to class +The :meth:`!type.__new__` method takes care of adding member objects to class variables: .. testcode:: @@ -1733,7 +1733,7 @@ Python: ) super().__delattr__(name) -To use the simulation in a real class, just inherit from :class:`Object` and +To use the simulation in a real class, just inherit from :class:`!Object` and set the :term:`metaclass` to :class:`Type`: .. testcode:: diff --git a/Doc/howto/enum.rst b/Doc/howto/enum.rst index ffdafb74..9b6bb613 100644 --- a/Doc/howto/enum.rst +++ b/Doc/howto/enum.rst @@ -7,7 +7,7 @@ Enum HOWTO .. currentmodule:: enum An :class:`Enum` is a set of symbolic names bound to unique values. They are -similar to global variables, but they offer a more useful :func:`repr()`, +similar to global variables, but they offer a more useful :func:`repr`, grouping, type-safety, and a few other features. They are most useful when you have a variable that can take one of a limited @@ -62,12 +62,12 @@ The *type* of an enumeration member is the enum it belongs to:: >>> isinstance(Weekday.FRIDAY, Weekday) True -Enum members have an attribute that contains just their :attr:`name`:: +Enum members have an attribute that contains just their :attr:`!name`:: >>> print(Weekday.TUESDAY.name) TUESDAY -Likewise, they have an attribute for their :attr:`value`:: +Likewise, they have an attribute for their :attr:`!value`:: >>> Weekday.WEDNESDAY.value @@ -75,17 +75,18 @@ Likewise, they have an attribute for their :attr:`value`:: Unlike many languages that treat enumerations solely as name/value pairs, Python Enums can have behavior added. For example, :class:`datetime.date` -has two methods for returning the weekday: :meth:`weekday` and :meth:`isoweekday`. +has two methods for returning the weekday: +:meth:`~datetime.date.weekday` and :meth:`~datetime.date.isoweekday`. The difference is that one of them counts from 0-6 and the other from 1-7. -Rather than keep track of that ourselves we can add a method to the :class:`Weekday` -enum to extract the day from the :class:`date` instance and return the matching +Rather than keep track of that ourselves we can add a method to the :class:`!Weekday` +enum to extract the day from the :class:`~datetime.date` instance and return the matching enum member:: @classmethod def from_date(cls, date): return cls(date.isoweekday()) -The complete :class:`Weekday` enum now looks like this:: +The complete :class:`!Weekday` enum now looks like this:: >>> class Weekday(Enum): ... MONDAY = 1 @@ -108,7 +109,7 @@ Now we can find out what today is! Observe:: Of course, if you're reading this on some other day, you'll see that day instead. -This :class:`Weekday` enum is great if our variable only needs one day, but +This :class:`!Weekday` enum is great if our variable only needs one day, but what if we need several? Maybe we're writing a function to plot chores during a week, and don't want to use a :class:`list` -- we could use a different type of :class:`Enum`:: @@ -126,7 +127,7 @@ of :class:`Enum`:: We've changed two things: we're inherited from :class:`Flag`, and the values are all powers of 2. -Just like the original :class:`Weekday` enum above, we can have a single selection:: +Just like the original :class:`!Weekday` enum above, we can have a single selection:: >>> first_week_day = Weekday.MONDAY >>> first_week_day @@ -165,7 +166,7 @@ And a function to display the chores for a given day:: answer SO questions In cases where the actual values of the members do not matter, you can save -yourself some work and use :func:`auto()` for the values:: +yourself some work and use :func:`auto` for the values:: >>> from enum import auto >>> class Weekday(Flag): @@ -201,7 +202,7 @@ If you want to access enum members by *name*, use item access:: >>> Color['GREEN'] -If you have an enum member and need its :attr:`name` or :attr:`value`:: +If you have an enum member and need its :attr:`!name` or :attr:`!value`:: >>> member = Color.RED >>> member.name @@ -282,7 +283,7 @@ If the exact value is unimportant you can use :class:`auto`:: >>> [member.value for member in Color] [1, 2, 3] -The values are chosen by :func:`_generate_next_value_`, which can be +The values are chosen by :func:`~Enum._generate_next_value_`, which can be overridden:: >>> class AutoName(Enum): @@ -301,7 +302,7 @@ overridden:: .. note:: - The :meth:`_generate_next_value_` method must be defined before any members. + The :meth:`~Enum._generate_next_value_` method must be defined before any members. Iteration --------- @@ -422,18 +423,18 @@ Then:: The rules for what is allowed are as follows: names that start and end with a single underscore are reserved by enum and cannot be used; all other attributes defined within an enumeration will become members of this -enumeration, with the exception of special methods (:meth:`__str__`, -:meth:`__add__`, etc.), descriptors (methods are also descriptors), and -variable names listed in :attr:`_ignore_`. +enumeration, with the exception of special methods (:meth:`~object.__str__`, +:meth:`~object.__add__`, etc.), descriptors (methods are also descriptors), and +variable names listed in :attr:`~Enum._ignore_`. -Note: if your enumeration defines :meth:`__new__` and/or :meth:`__init__`, +Note: if your enumeration defines :meth:`~object.__new__` and/or :meth:`~object.__init__`, any value(s) given to the enum member will be passed into those methods. See `Planet`_ for an example. .. note:: - The :meth:`__new__` method, if defined, is used during creation of the Enum - members; it is then replaced by Enum's :meth:`__new__` which is used after + The :meth:`~object.__new__` method, if defined, is used during creation of the Enum + members; it is then replaced by Enum's :meth:`~object.__new__` which is used after class creation for lookup of existing members. See :ref:`new-vs-init` for more details. @@ -525,7 +526,7 @@ from that module. nested in other classes. It is possible to modify how enum members are pickled/unpickled by defining -:meth:`__reduce_ex__` in the enumeration class. The default method is by-value, +:meth:`~object.__reduce_ex__` in the enumeration class. The default method is by-value, but enums with complicated values may want to use by-name:: >>> import enum @@ -561,7 +562,7 @@ values. The last two options enable assigning arbitrary values to enumerations; the others auto-assign increasing integers starting with 1 (use the ``start`` parameter to specify a different starting value). A new class derived from :class:`Enum` is returned. In other words, the above -assignment to :class:`Animal` is equivalent to:: +assignment to :class:`!Animal` is equivalent to:: >>> class Animal(Enum): ... ANT = 1 @@ -589,7 +590,7 @@ The solution is to specify the module name explicitly as follows:: the source, pickling will be disabled. The new pickle protocol 4 also, in some circumstances, relies on -:attr:`~definition.__qualname__` being set to the location where pickle will be able +:attr:`~type.__qualname__` being set to the location where pickle will be able to find the class. For example, if the class was made available in class SomeData in the global scope:: @@ -872,7 +873,7 @@ simple to implement independently:: pass This demonstrates how similar derived enumerations can be defined; for example -a :class:`FloatEnum` that mixes in :class:`float` instead of :class:`int`. +a :class:`!FloatEnum` that mixes in :class:`float` instead of :class:`int`. Some rules: @@ -886,32 +887,32 @@ Some rules: additional type, all the members must have values of that type, e.g. :class:`int` above. This restriction does not apply to mix-ins which only add methods and don't specify another type. -4. When another data type is mixed in, the :attr:`value` attribute is *not the +4. When another data type is mixed in, the :attr:`~Enum.value` attribute is *not the same* as the enum member itself, although it is equivalent and will compare equal. -5. A ``data type`` is a mixin that defines :meth:`__new__`, or a +5. A ``data type`` is a mixin that defines :meth:`~object.__new__`, or a :class:`~dataclasses.dataclass` 6. %-style formatting: ``%s`` and ``%r`` call the :class:`Enum` class's - :meth:`__str__` and :meth:`__repr__` respectively; other codes (such as + :meth:`~object.__str__` and :meth:`~object.__repr__` respectively; other codes (such as ``%i`` or ``%h`` for IntEnum) treat the enum member as its mixed-in type. 7. :ref:`Formatted string literals `, :meth:`str.format`, - and :func:`format` will use the enum's :meth:`__str__` method. + and :func:`format` will use the enum's :meth:`~object.__str__` method. .. note:: Because :class:`IntEnum`, :class:`IntFlag`, and :class:`StrEnum` are designed to be drop-in replacements for existing constants, their - :meth:`__str__` method has been reset to their data types' - :meth:`__str__` method. + :meth:`~object.__str__` method has been reset to their data types' + :meth:`~object.__str__` method. .. _new-vs-init: -When to use :meth:`__new__` vs. :meth:`__init__` ------------------------------------------------- +When to use :meth:`~object.__new__` vs. :meth:`~object.__init__` +---------------------------------------------------------------- -:meth:`__new__` must be used whenever you want to customize the actual value of +:meth:`~object.__new__` must be used whenever you want to customize the actual value of the :class:`Enum` member. Any other modifications may go in either -:meth:`__new__` or :meth:`__init__`, with :meth:`__init__` being preferred. +:meth:`~object.__new__` or :meth:`~object.__init__`, with :meth:`~object.__init__` being preferred. For example, if you want to pass several items to the constructor, but only want one of them to be the value:: @@ -950,28 +951,28 @@ Finer Points Supported ``__dunder__`` names """""""""""""""""""""""""""""" -:attr:`__members__` is a read-only ordered mapping of ``member_name``:``member`` +:attr:`~enum.EnumType.__members__` is a read-only ordered mapping of ``member_name``:``member`` items. It is only available on the class. -:meth:`__new__`, if specified, must create and return the enum members; it is -also a very good idea to set the member's :attr:`_value_` appropriately. Once +:meth:`~object.__new__`, if specified, must create and return the enum members; it is +also a very good idea to set the member's :attr:`~Enum._value_` appropriately. Once all the members are created it is no longer used. Supported ``_sunder_`` names """""""""""""""""""""""""""" -- ``_name_`` -- name of the member -- ``_value_`` -- value of the member; can be set / modified in ``__new__`` +- :attr:`~Enum._name_` -- name of the member +- :attr:`~Enum._value_` -- value of the member; can be set / modified in ``__new__`` -- ``_missing_`` -- a lookup function used when a value is not found; may be +- :meth:`~Enum._missing_` -- a lookup function used when a value is not found; may be overridden -- ``_ignore_`` -- a list of names, either as a :class:`list` or a :class:`str`, +- :attr:`~Enum._ignore_` -- a list of names, either as a :class:`list` or a :class:`str`, that will not be transformed into members, and will be removed from the final class -- ``_order_`` -- used in Python 2/3 code to ensure member order is consistent +- :attr:`~Enum._order_` -- used in Python 2/3 code to ensure member order is consistent (class attribute, removed during class creation) -- ``_generate_next_value_`` -- used by the `Functional API`_ and by +- :meth:`~Enum._generate_next_value_` -- used by the `Functional API`_ and by :class:`auto` to get an appropriate value for an enum member; may be overridden @@ -986,7 +987,7 @@ Supported ``_sunder_`` names .. versionadded:: 3.6 ``_missing_``, ``_order_``, ``_generate_next_value_`` .. versionadded:: 3.7 ``_ignore_`` -To help keep Python 2 / Python 3 code in sync an :attr:`_order_` attribute can +To help keep Python 2 / Python 3 code in sync an :attr:`~Enum._order_` attribute can be provided. It will be checked against the actual order of the enumeration and raise an error if the two do not match:: @@ -1004,7 +1005,7 @@ and raise an error if the two do not match:: .. note:: - In Python 2 code the :attr:`_order_` attribute is necessary as definition + In Python 2 code the :attr:`~Enum._order_` attribute is necessary as definition order is lost before it can be recorded. @@ -1129,6 +1130,14 @@ the following are true: >>> (Color.RED | Color.GREEN).name 'RED|GREEN' + >>> class Perm(IntFlag): + ... R = 4 + ... W = 2 + ... X = 1 + ... + >>> (Perm.R & Perm.W).name is None # effectively Perm(0) + True + - multi-bit flags, aka aliases, can be returned from operations:: >>> Color.RED | Color.BLUE @@ -1185,12 +1194,12 @@ Enum Classes ^^^^^^^^^^^^ The :class:`EnumType` metaclass is responsible for providing the -:meth:`__contains__`, :meth:`__dir__`, :meth:`__iter__` and other methods that +:meth:`~object.__contains__`, :meth:`~object.__dir__`, :meth:`~object.__iter__` and other methods that allow one to do things with an :class:`Enum` class that fail on a typical class, such as ``list(Color)`` or ``some_enum_var in Color``. :class:`EnumType` is responsible for ensuring that various other methods on the final :class:`Enum` -class are correct (such as :meth:`__new__`, :meth:`__getnewargs__`, -:meth:`__str__` and :meth:`__repr__`). +class are correct (such as :meth:`~object.__new__`, :meth:`~object.__getnewargs__`, +:meth:`~object.__str__` and :meth:`~object.__repr__`). Flag Classes ^^^^^^^^^^^^ @@ -1205,7 +1214,7 @@ Enum Members (aka instances) The most interesting thing about enum members is that they are singletons. :class:`EnumType` creates them all while it is creating the enum class itself, -and then puts a custom :meth:`__new__` in place to ensure that no new ones are +and then puts a custom :meth:`~object.__new__` in place to ensure that no new ones are ever instantiated by returning only the existing member instances. Flag Members @@ -1253,7 +1262,7 @@ is. There are several ways to define this type of simple enumeration: - use instances of :class:`auto` for the value - use instances of :class:`object` as the value - use a descriptive string as the value -- use a tuple as the value and a custom :meth:`__new__` to replace the +- use a tuple as the value and a custom :meth:`~object.__new__` to replace the tuple with an :class:`int` value Using any of these methods signifies to the user that these values are not @@ -1289,7 +1298,7 @@ Using :class:`object` would look like:: > This is also a good example of why you might want to write your own -:meth:`__repr__`:: +:meth:`~object.__repr__`:: >>> class Color(Enum): ... RED = object() @@ -1317,10 +1326,10 @@ Using a string as the value would look like:: -Using a custom :meth:`__new__` -"""""""""""""""""""""""""""""" +Using a custom :meth:`~object.__new__` +"""""""""""""""""""""""""""""""""""""" -Using an auto-numbering :meth:`__new__` would look like:: +Using an auto-numbering :meth:`~object.__new__` would look like:: >>> class AutoNumber(Enum): ... def __new__(cls): @@ -1366,8 +1375,8 @@ to handle any extra arguments:: .. note:: - The :meth:`__new__` method, if defined, is used during creation of the Enum - members; it is then replaced by Enum's :meth:`__new__` which is used after + The :meth:`~object.__new__` method, if defined, is used during creation of the Enum + members; it is then replaced by Enum's :meth:`~object.__new__` which is used after class creation for lookup of existing members. .. warning:: @@ -1450,7 +1459,7 @@ alias:: Planet ^^^^^^ -If :meth:`__new__` or :meth:`__init__` is defined, the value of the enum member +If :meth:`~object.__new__` or :meth:`~object.__init__` is defined, the value of the enum member will be passed to those methods:: >>> class Planet(Enum): @@ -1481,7 +1490,7 @@ will be passed to those methods:: TimePeriod ^^^^^^^^^^ -An example to show the :attr:`_ignore_` attribute in use:: +An example to show the :attr:`~Enum._ignore_` attribute in use:: >>> from datetime import timedelta >>> class Period(timedelta, Enum): diff --git a/Doc/howto/instrumentation.rst b/Doc/howto/instrumentation.rst index 9c99fcec..6e03ef20 100644 --- a/Doc/howto/instrumentation.rst +++ b/Doc/howto/instrumentation.rst @@ -307,7 +307,7 @@ Available static markers .. object:: gc__start(int generation) Fires when the Python interpreter starts a garbage collection cycle. - ``arg0`` is the generation to scan, like :func:`gc.collect()`. + ``arg0`` is the generation to scan, like :func:`gc.collect`. .. object:: gc__done(long collected) diff --git a/Doc/howto/isolating-extensions.rst b/Doc/howto/isolating-extensions.rst index e35855de..a636e06b 100644 --- a/Doc/howto/isolating-extensions.rst +++ b/Doc/howto/isolating-extensions.rst @@ -339,7 +339,7 @@ That is, heap types should: - Define a traverse function using ``Py_tp_traverse``, which visits the type (e.g. using ``Py_VISIT(Py_TYPE(self))``). -Please refer to the the documentation of +Please refer to the documentation of :c:macro:`Py_TPFLAGS_HAVE_GC` and :c:member:`~PyTypeObject.tp_traverse` for additional considerations. diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index 06a1ec18..c7b463d1 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -4022,7 +4022,7 @@ As you can see, this output isn't ideal. That's because the underlying code which writes to ``sys.stderr`` makes multiple writes, each of which results in a separate logged line (for example, the last three lines above). To get around this problem, you need to buffer things and only output log lines when newlines -are seen. Let's use a slghtly better implementation of ``LoggerWriter``: +are seen. Let's use a slightly better implementation of ``LoggerWriter``: .. code-block:: python diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst index 877cb243..5a392f94 100644 --- a/Doc/howto/logging.rst +++ b/Doc/howto/logging.rst @@ -381,8 +381,52 @@ Logging Flow The flow of log event information in loggers and handlers is illustrated in the following diagram. -.. image:: logging_flow.png - :class: invert-in-dark-mode +.. only:: not html + + .. image:: logging_flow.* + +.. raw:: html + :file: logging_flow.svg + +.. raw:: html + + Loggers ^^^^^^^ diff --git a/Doc/howto/logging_flow.png b/Doc/howto/logging_flow.png index d65e597f..d60ed7c0 100644 Binary files a/Doc/howto/logging_flow.png and b/Doc/howto/logging_flow.png differ diff --git a/Doc/howto/logging_flow.svg b/Doc/howto/logging_flow.svg new file mode 100644 index 00000000..4974994a --- /dev/null +++ b/Doc/howto/logging_flow.svg @@ -0,0 +1,327 @@ + + + + + + + + + + + Logger flow + + + + + Create + LogRecord + + + + + + + + + + + + Logging call in user + code, e.g. + + + logger.info(...) + + + + + + + + + Stop + + + + + + Does a filter attached + to logger reject the + record? + + + + + + + + + + Pass record to + handlers of + current logger + + + + + + Is propagate true for + current logger? + + + + + + Is there a parent + logger? + + + + + + Set current + logger to parent + + + + + + At least one handler + in hierarchy? + + + + + + Use + lastResort + handler + + + + + + Handler enabled for + level of record? + + + + + + Does a filter attached + to handler reject the + record? + + + + + + Stop + + + + + + Emit (includes formatting) + + + + Handler flow + + + + + Logger enabled for + level of call? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No + + + Yes + + + Yes + + + No + + + No + + + Yes + + + Yes + + + No + + + No + + + Yes + + + + + + No + + + + + + + + + Yes + + + No + + + + + + Yes + + + Record passed + to handler + + + + + + + + diff --git a/Doc/howto/mro.rst b/Doc/howto/mro.rst index f44b4f98..46db516e 100644 --- a/Doc/howto/mro.rst +++ b/Doc/howto/mro.rst @@ -335,7 +335,7 @@ E is more specialized than C, even if it is in a higher level. A lazy programmer can obtain the MRO directly from Python 2.2, since in this case it coincides with the Python 2.3 linearization. It is enough -to invoke the .mro() method of class A: +to invoke the :meth:`~type.mro` method of class A: >>> A.mro() # doctest: +NORMALIZE_WHITESPACE [, , , diff --git a/Doc/library/__main__.rst b/Doc/library/__main__.rst index 6232e173..647ff9da 100644 --- a/Doc/library/__main__.rst +++ b/Doc/library/__main__.rst @@ -251,9 +251,9 @@ attribute will include the package's path if imported:: >>> asyncio.__main__.__name__ 'asyncio.__main__' -This won't work for ``__main__.py`` files in the root directory of a .zip file -though. Hence, for consistency, minimal ``__main__.py`` like the :mod:`venv` -one mentioned below are preferred. +This won't work for ``__main__.py`` files in the root directory of a +``.zip`` file though. Hence, for consistency, a minimal ``__main__.py`` +without a ``__name__`` check is preferred. .. seealso:: diff --git a/Doc/library/_thread.rst b/Doc/library/_thread.rst index 35053702..e5cbff0b 100644 --- a/Doc/library/_thread.rst +++ b/Doc/library/_thread.rst @@ -210,23 +210,20 @@ In addition to these methods, lock objects can also be used via the .. index:: pair: module; signal -* Threads interact strangely with interrupts: the :exc:`KeyboardInterrupt` - exception will be received by an arbitrary thread. (When the :mod:`signal` - module is available, interrupts always go to the main thread.) +* Interrupts always go to the main thread (the :exc:`KeyboardInterrupt` + exception will be received by that thread.) * Calling :func:`sys.exit` or raising the :exc:`SystemExit` exception is equivalent to calling :func:`_thread.exit`. -* It is not possible to interrupt the :meth:`~threading.Lock.acquire` method on - a lock --- the :exc:`KeyboardInterrupt` exception will happen after the lock - has been acquired. +* It is platform-dependent whether the :meth:`~threading.Lock.acquire` method + on a lock can be interrupted (so that the :exc:`KeyboardInterrupt` exception + will happen immediately, rather than only after the lock has been acquired or + the operation has timed out). It can be interrupted on POSIX, but not on + Windows. * When the main thread exits, it is system defined whether the other threads survive. On most systems, they are killed without executing :keyword:`try` ... :keyword:`finally` clauses or executing object destructors. -* When the main thread exits, it does not do any of its usual cleanup (except - that :keyword:`try` ... :keyword:`finally` clauses are honored), and the - standard I/O files are not flushed. - diff --git a/Doc/library/abc.rst b/Doc/library/abc.rst index 168ef3ec..38d744e9 100644 --- a/Doc/library/abc.rst +++ b/Doc/library/abc.rst @@ -99,7 +99,7 @@ a helper class :class:`ABC` to alternatively define ABCs through inheritance: that you can customize the behavior of :func:`issubclass` further without the need to call :meth:`register` on every class you want to consider a subclass of the ABC. (This class method is called from the - :meth:`~class.__subclasscheck__` method of the ABC.) + :meth:`~type.__subclasscheck__` method of the ABC.) This method should return ``True``, ``False`` or :data:`NotImplemented`. If it returns ``True``, the *subclass* is considered a subclass of this ABC. @@ -149,7 +149,7 @@ a helper class :class:`ABC` to alternatively define ABCs through inheritance: The :meth:`__subclasshook__` class method defined here says that any class that has an :meth:`~iterator.__iter__` method in its :attr:`~object.__dict__` (or in that of one of its base classes, accessed - via the :attr:`~class.__mro__` list) is considered a ``MyIterable`` too. + via the :attr:`~type.__mro__` list) is considered a ``MyIterable`` too. Finally, the last line makes ``Foo`` a virtual subclass of ``MyIterable``, even though it does not define an :meth:`~iterator.__iter__` method (it uses diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index b7ed3f5e..00d7c384 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1,4 +1,4 @@ -:mod:`!argparse` --- Parser for command-line options, arguments and sub-commands +:mod:`!argparse` --- Parser for command-line options, arguments and subcommands ================================================================================ .. module:: argparse @@ -19,17 +19,13 @@ introduction to Python command-line parsing, have a look at the :ref:`argparse tutorial `. -The :mod:`argparse` module makes it easy to write user-friendly command-line -interfaces. The program defines what arguments it requires, and :mod:`argparse` -will figure out how to parse those out of :data:`sys.argv`. The :mod:`argparse` +The :mod:`!argparse` module makes it easy to write user-friendly command-line +interfaces. The program defines what arguments it requires, and :mod:`!argparse` +will figure out how to parse those out of :data:`sys.argv`. The :mod:`!argparse` module also automatically generates help and usage messages. The module will also issue errors when users give the program invalid arguments. - -Core Functionality ------------------- - -The :mod:`argparse` module's support for command-line interfaces is built +The :mod:`!argparse` module's support for command-line interfaces is built around an instance of :class:`argparse.ArgumentParser`. It is a container for argument specifications and has options that apply to the parser as whole:: @@ -53,133 +49,9 @@ the extracted data in a :class:`argparse.Namespace` object:: args = parser.parse_args() print(args.filename, args.count, args.verbose) - -Quick Links for add_argument() ------------------------------- - -============================ =========================================================== ========================================================================================================================== -Name Description Values -============================ =========================================================== ========================================================================================================================== -action_ Specify how an argument should be handled ``'store'``, ``'store_const'``, ``'store_true'``, ``'append'``, ``'append_const'``, ``'count'``, ``'help'``, ``'version'`` -choices_ Limit values to a specific set of choices ``['foo', 'bar']``, ``range(1, 10)``, or :class:`~collections.abc.Container` instance -const_ Store a constant value -default_ Default value used when an argument is not provided Defaults to ``None`` -dest_ Specify the attribute name used in the result namespace -help_ Help message for an argument -metavar_ Alternate display name for the argument as shown in help -nargs_ Number of times the argument can be used :class:`int`, ``'?'``, ``'*'``, or ``'+'`` -required_ Indicate whether an argument is required or optional ``True`` or ``False`` -:ref:`type ` Automatically convert an argument to the given type :class:`int`, :class:`float`, ``argparse.FileType('w')``, or callable function -============================ =========================================================== ========================================================================================================================== - - -Example -------- - -The following code is a Python program that takes a list of integers and -produces either the sum or the max:: - - import argparse - - parser = argparse.ArgumentParser(description='Process some integers.') - parser.add_argument('integers', metavar='N', type=int, nargs='+', - help='an integer for the accumulator') - parser.add_argument('--sum', dest='accumulate', action='store_const', - const=sum, default=max, - help='sum the integers (default: find the max)') - - args = parser.parse_args() - print(args.accumulate(args.integers)) - -Assuming the above Python code is saved into a file called ``prog.py``, it can -be run at the command line and it provides useful help messages: - -.. code-block:: shell-session - - $ python prog.py -h - usage: prog.py [-h] [--sum] N [N ...] - - Process some integers. - - positional arguments: - N an integer for the accumulator - - options: - -h, --help show this help message and exit - --sum sum the integers (default: find the max) - -When run with the appropriate arguments, it prints either the sum or the max of -the command-line integers: - -.. code-block:: shell-session - - $ python prog.py 1 2 3 4 - 4 - - $ python prog.py 1 2 3 4 --sum - 10 - -If invalid arguments are passed in, an error will be displayed: - -.. code-block:: shell-session - - $ python prog.py a b c - usage: prog.py [-h] [--sum] N [N ...] - prog.py: error: argument N: invalid int value: 'a' - -The following sections walk you through this example. - - -Creating a parser -^^^^^^^^^^^^^^^^^ - -The first step in using the :mod:`argparse` is creating an -:class:`ArgumentParser` object:: - - >>> parser = argparse.ArgumentParser(description='Process some integers.') - -The :class:`ArgumentParser` object will hold all the information necessary to -parse the command line into Python data types. - - -Adding arguments -^^^^^^^^^^^^^^^^ - -Filling an :class:`ArgumentParser` with information about program arguments is -done by making calls to the :meth:`~ArgumentParser.add_argument` method. -Generally, these calls tell the :class:`ArgumentParser` how to take the strings -on the command line and turn them into objects. This information is stored and -used when :meth:`~ArgumentParser.parse_args` is called. For example:: - - >>> parser.add_argument('integers', metavar='N', type=int, nargs='+', - ... help='an integer for the accumulator') - >>> parser.add_argument('--sum', dest='accumulate', action='store_const', - ... const=sum, default=max, - ... help='sum the integers (default: find the max)') - -Later, calling :meth:`~ArgumentParser.parse_args` will return an object with -two attributes, ``integers`` and ``accumulate``. The ``integers`` attribute -will be a list of one or more integers, and the ``accumulate`` attribute will be -either the :func:`sum` function, if ``--sum`` was specified at the command line, -or the :func:`max` function if it was not. - - -Parsing arguments -^^^^^^^^^^^^^^^^^ - -:class:`ArgumentParser` parses arguments through the -:meth:`~ArgumentParser.parse_args` method. This will inspect the command line, -convert each argument to the appropriate type and then invoke the appropriate action. -In most cases, this means a simple :class:`Namespace` object will be built up from -attributes parsed out of the command line:: - - >>> parser.parse_args(['--sum', '7', '-1', '42']) - Namespace(accumulate=, integers=[7, -1, 42]) - -In a script, :meth:`~ArgumentParser.parse_args` will typically be called with no -arguments, and the :class:`ArgumentParser` will automatically determine the -command-line arguments from :data:`sys.argv`. - +.. note:: + If you're looking for a guide about how to upgrade :mod:`optparse` code + to :mod:`!argparse`, see :ref:`Upgrading Optparse Code `. ArgumentParser objects ---------------------- @@ -228,7 +100,7 @@ ArgumentParser objects * allow_abbrev_ - Allows long options to be abbreviated if the abbreviation is unambiguous. (default: ``True``) - * exit_on_error_ - Determines whether or not ArgumentParser exits with + * exit_on_error_ - Determines whether or not :class:`!ArgumentParser` exits with error info when an error occurs. (default: ``True``) .. versionchanged:: 3.5 @@ -249,38 +121,21 @@ The following sections describe how each of these are used. prog ^^^^ -By default, :class:`ArgumentParser` objects use ``sys.argv[0]`` to determine -how to display the name of the program in help messages. This default is almost -always desirable because it will make the help messages match how the program was -invoked on the command line. For example, consider a file named -``myprogram.py`` with the following code:: - import argparse - parser = argparse.ArgumentParser() - parser.add_argument('--foo', help='foo help') - args = parser.parse_args() - -The help for this program will display ``myprogram.py`` as the program name -(regardless of where the program was invoked from): - -.. code-block:: shell-session +By default, :class:`ArgumentParser` calculates the name of the program +to display in help messages depending on the way the Python interpreter was run: - $ python myprogram.py --help - usage: myprogram.py [-h] [--foo FOO] +* The :func:`base name ` of ``sys.argv[0]`` if a file was + passed as argument. +* The Python interpreter name followed by ``sys.argv[0]`` if a directory or + a zipfile was passed as argument. +* The Python interpreter name followed by ``-m`` followed by the + module or package name if the :option:`-m` option was used. - options: - -h, --help show this help message and exit - --foo FOO foo help - $ cd .. - $ python subdir/myprogram.py --help - usage: myprogram.py [-h] [--foo FOO] - - options: - -h, --help show this help message and exit - --foo FOO foo help - -To change this default behavior, another value can be supplied using the -``prog=`` argument to :class:`ArgumentParser`:: +This default is almost always desirable because it will make the help messages +match the string that was used to invoke the program on the command line. +However, to change this default behavior, another value can be supplied using +the ``prog=`` argument to :class:`ArgumentParser`:: >>> parser = argparse.ArgumentParser(prog='myprogram') >>> parser.print_help() @@ -309,22 +164,8 @@ usage ^^^^^ By default, :class:`ArgumentParser` calculates the usage message from the -arguments it contains:: - - >>> parser = argparse.ArgumentParser(prog='PROG') - >>> parser.add_argument('--foo', nargs='?', help='foo help') - >>> parser.add_argument('bar', nargs='+', help='bar help') - >>> parser.print_help() - usage: PROG [-h] [--foo [FOO]] bar [bar ...] - - positional arguments: - bar bar help - - options: - -h, --help show this help message and exit - --foo [FOO] foo help - -The default message can be overridden with the ``usage=`` keyword argument:: +arguments it contains. The default message can be overridden with the +``usage=`` keyword argument:: >>> parser = argparse.ArgumentParser(prog='PROG', usage='%(prog)s [options]') >>> parser.add_argument('--foo', nargs='?', help='foo help') @@ -352,16 +193,7 @@ Most calls to the :class:`ArgumentParser` constructor will use the ``description=`` keyword argument. This argument gives a brief description of what the program does and how it works. In help messages, the description is displayed between the command-line usage string and the help messages for the -various arguments:: - - >>> parser = argparse.ArgumentParser(description='A foo that bars') - >>> parser.print_help() - usage: argparse.py [-h] - - A foo that bars - - options: - -h, --help show this help message and exit +various arguments. By default, the description will be line-wrapped so that it fits within the given space. To change this behavior, see the formatter_class_ argument. @@ -491,7 +323,7 @@ should not be line-wrapped:: -h, --help show this help message and exit :class:`RawTextHelpFormatter` maintains whitespace for all sorts of help text, -including argument descriptions. However, multiple new lines are replaced with +including argument descriptions. However, multiple newlines are replaced with one. If you wish to preserve multiple blank lines, add spaces between the newlines. @@ -540,7 +372,7 @@ Most command-line options will use ``-`` as the prefix, e.g. ``-f/--foo``. Parsers that need to support different or additional prefix characters, e.g. for options like ``+f`` or ``/foo``, may specify them using the ``prefix_chars=`` argument -to the ArgumentParser constructor:: +to the :class:`ArgumentParser` constructor:: >>> parser = argparse.ArgumentParser(prog='PROG', prefix_chars='-+') >>> parser.add_argument('+f') @@ -585,8 +417,8 @@ arguments will never be treated as file references. .. versionchanged:: 3.12 :class:`ArgumentParser` changed encoding and errors to read arguments files - from default (e.g. :func:`locale.getpreferredencoding(False) ` and - ``"strict"``) to :term:`filesystem encoding and error handler`. + from default (e.g. :func:`locale.getpreferredencoding(False) ` + and ``"strict"``) to the :term:`filesystem encoding and error handler`. Arguments file should be encoded in UTF-8 instead of ANSI Codepage on Windows. @@ -671,26 +503,9 @@ string was overridden. add_help ^^^^^^^^ -By default, ArgumentParser objects add an option which simply displays -the parser's help message. For example, consider a file named -``myprogram.py`` containing the following code:: - - import argparse - parser = argparse.ArgumentParser() - parser.add_argument('--foo', help='foo help') - args = parser.parse_args() - -If ``-h`` or ``--help`` is supplied at the command line, the ArgumentParser -help will be printed: - -.. code-block:: shell-session - - $ python myprogram.py --help - usage: myprogram.py [-h] [--foo FOO] - - options: - -h, --help show this help message and exit - --foo FOO foo help +By default, :class:`ArgumentParser` objects add an option which simply displays +the parser's help message. If ``-h`` or ``--help`` is supplied at the command +line, the :class:`!ArgumentParser` help will be printed. Occasionally, it may be useful to disable the addition of this help option. This can be achieved by passing ``False`` as the ``add_help=`` argument to @@ -722,7 +537,8 @@ exit_on_error ^^^^^^^^^^^^^ Normally, when you pass an invalid argument list to the :meth:`~ArgumentParser.parse_args` -method of an :class:`ArgumentParser`, it will exit with error info. +method of an :class:`ArgumentParser`, it will print a *message* to :data:`sys.stderr` and exit with a status +code of 2. If the user would like to catch errors manually, the feature can be enabled by setting ``exit_on_error`` to ``False``:: @@ -743,15 +559,15 @@ If the user would like to catch errors manually, the feature can be enabled by s The add_argument() method ------------------------- -.. method:: ArgumentParser.add_argument(name or flags..., [action], [nargs], \ +.. method:: ArgumentParser.add_argument(name or flags..., *, [action], [nargs], \ [const], [default], [type], [choices], [required], \ [help], [metavar], [dest]) Define how a single command-line argument should be parsed. Each parameter has its own more detailed description below, but in short they are: - * `name or flags`_ - Either a name or a list of option strings, e.g. ``foo`` - or ``-f, --foo``. + * `name or flags`_ - Either a name or a list of option strings, e.g. ``'foo'`` + or ``'-f', '--foo'``. * action_ - The basic type of action to be taken when this argument is encountered at the command line. @@ -780,7 +596,7 @@ The add_argument() method The following sections describe how each of these are used. -.. _name_or_flags: +.. _`name or flags`: name or flags ^^^^^^^^^^^^^ @@ -827,12 +643,7 @@ them, though most actions simply add an attribute to the object returned by how the command-line arguments should be handled. The supplied actions are: * ``'store'`` - This just stores the argument's value. This is the default - action. For example:: - - >>> parser = argparse.ArgumentParser() - >>> parser.add_argument('--foo') - >>> parser.parse_args('--foo 1'.split()) - Namespace(foo='1') + action. * ``'store_const'`` - This stores the value specified by the const_ keyword argument; note that the const_ keyword argument defaults to ``None``. The @@ -847,7 +658,7 @@ how the command-line arguments should be handled. The supplied actions are: * ``'store_true'`` and ``'store_false'`` - These are special cases of ``'store_const'`` used for storing the values ``True`` and ``False`` respectively. In addition, they create default values of ``False`` and - ``True`` respectively. For example:: + ``True`` respectively:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('--foo', action='store_true') @@ -879,6 +690,21 @@ how the command-line arguments should be handled. The supplied actions are: >>> parser.parse_args('--str --int'.split()) Namespace(types=[, ]) +* ``'extend'`` - This stores a list and appends each item from the multi-value + argument list to it. + The ``'extend'`` action is typically used with the nargs_ keyword argument + value ``'+'`` or ``'*'``. + Note that when nargs_ is ``None`` (the default) or ``'?'``, each + character of the argument string will be appended to the list. + Example usage:: + + >>> parser = argparse.ArgumentParser() + >>> parser.add_argument("--foo", action="extend", nargs="+", type=str) + >>> parser.parse_args(["--foo", "f1", "--foo", "f2", "f3", "f4"]) + Namespace(foo=['f1', 'f2', 'f3', 'f4']) + + .. versionadded:: 3.8 + * ``'count'`` - This counts the number of times a keyword argument occurs. For example, this is useful for increasing verbosity levels:: @@ -904,33 +730,28 @@ how the command-line arguments should be handled. The supplied actions are: >>> parser.parse_args(['--version']) PROG 2.0 -* ``'extend'`` - This stores a list, and extends each argument value to the - list. - Example usage:: +Only actions that consume command-line arguments (e.g. ``'store'``, +``'append'`` or ``'extend'``) can be used with positional arguments. - >>> parser = argparse.ArgumentParser() - >>> parser.add_argument("--foo", action="extend", nargs="+", type=str) - >>> parser.parse_args(["--foo", "f1", "--foo", "f2", "f3", "f4"]) - Namespace(foo=['f1', 'f2', 'f3', 'f4']) +.. class:: BooleanOptionalAction - .. versionadded:: 3.8 + You may also specify an arbitrary action by passing an :class:`Action` subclass or + other object that implements the same interface. The :class:`!BooleanOptionalAction` + is available in :mod:`!argparse` and adds support for boolean actions such as + ``--foo`` and ``--no-foo``:: -You may also specify an arbitrary action by passing an Action subclass or -other object that implements the same interface. The ``BooleanOptionalAction`` -is available in ``argparse`` and adds support for boolean actions such as -``--foo`` and ``--no-foo``:: + >>> import argparse + >>> parser = argparse.ArgumentParser() + >>> parser.add_argument('--foo', action=argparse.BooleanOptionalAction) + >>> parser.parse_args(['--no-foo']) + Namespace(foo=False) - >>> import argparse - >>> parser = argparse.ArgumentParser() - >>> parser.add_argument('--foo', action=argparse.BooleanOptionalAction) - >>> parser.parse_args(['--no-foo']) - Namespace(foo=False) - -.. versionadded:: 3.9 + .. versionadded:: 3.9 The recommended way to create a custom action is to extend :class:`Action`, -overriding the ``__call__`` method and optionally the ``__init__`` and -``format_usage`` methods. +overriding the :meth:`!__call__` method and optionally the :meth:`!__init__` and +:meth:`!format_usage` methods. You can also register custom actions using the +:meth:`~ArgumentParser.register` method and reference them by their registered name. An example of a custom action:: @@ -960,7 +781,7 @@ For more details, see :class:`Action`. nargs ^^^^^ -ArgumentParser objects usually associate a single command-line argument with a +:class:`ArgumentParser` objects usually associate a single command-line argument with a single action to be taken. The ``nargs`` keyword argument associates a different number of command-line arguments with a single action. See also :ref:`specifying-ambiguous-arguments`. The supported values are: @@ -1042,6 +863,8 @@ See also :ref:`specifying-ambiguous-arguments`. The supported values are: If the ``nargs`` keyword argument is not provided, the number of arguments consumed is determined by the action_. Generally this means a single command-line argument will be consumed and a single item (not a list) will be produced. +Actions that do not consume command-line arguments (e.g. +``'store_const'``) set ``nargs=0``. .. _const: @@ -1092,7 +915,7 @@ was not present at the command line:: Namespace(foo=42) If the target namespace already has an attribute set, the action *default* -will not over write it:: +will not overwrite it:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('--foo', default=42) @@ -1120,6 +943,9 @@ is used when no command-line argument was present:: >>> parser.parse_args([]) Namespace(foo=42) +For required_ arguments, the ``default`` value is ignored. For example, this +applies to positional arguments with nargs_ values other than ``?`` or ``*``, +or optional arguments marked as ``required=True``. Providing ``default=argparse.SUPPRESS`` causes no attribute to be added if the command-line argument was not present:: @@ -1146,10 +972,11 @@ necessary type-checking and type conversions to be performed. If the type_ keyword is used with the default_ keyword, the type converter is only applied if the default is a string. -The argument to ``type`` can be any callable that accepts a single string. +The argument to ``type`` can be a callable that accepts a single string or +the name of a registered type (see :meth:`~ArgumentParser.register`) If the function raises :exc:`ArgumentTypeError`, :exc:`TypeError`, or :exc:`ValueError`, the exception is caught and a nicely formatted error -message is displayed. No other exception types are handled. +message is displayed. Other exception types are not handled. Common built-in types and functions can be used as type converters: @@ -1163,7 +990,6 @@ Common built-in types and functions can be used as type converters: parser.add_argument('distance', type=float) parser.add_argument('street', type=ascii) parser.add_argument('code_point', type=ord) - parser.add_argument('source_file', type=open) parser.add_argument('dest_file', type=argparse.FileType('w', encoding='latin-1')) parser.add_argument('datapath', type=pathlib.Path) @@ -1194,10 +1020,11 @@ better reporting than can be given by the ``type`` keyword. A :exc:`FileNotFoundError` exception would not be handled at all. Even :class:`~argparse.FileType` has its limitations for use with the ``type`` -keyword. If one argument uses *FileType* and then a subsequent argument fails, -an error is reported but the file is not automatically closed. In this case, it -would be better to wait until after the parser has run and then use the -:keyword:`with`-statement to manage the files. +keyword. If one argument uses :class:`~argparse.FileType` and then a +subsequent argument fails, an error is reported but the file is not +automatically closed. In this case, it would be better to wait until after +the parser has run and then use the :keyword:`with`-statement to manage the +files. For type checkers that simply check against a fixed set of values, consider using the choices_ keyword instead. @@ -1225,15 +1052,7 @@ if the argument was not one of the acceptable values:: Note that inclusion in the *choices* sequence is checked after any type_ conversions have been performed, so the type of the objects in the *choices* -sequence should match the type_ specified:: - - >>> parser = argparse.ArgumentParser(prog='doors.py') - >>> parser.add_argument('door', type=int, choices=range(1, 4)) - >>> print(parser.parse_args(['3'])) - Namespace(door=3) - >>> parser.parse_args(['4']) - usage: doors.py [-h] {1,2,3} - doors.py: error: argument door: invalid choice: 4 (choose from 1, 2, 3) +sequence should match the type_ specified. Any sequence can be passed as the *choices* value, so :class:`list` objects, :class:`tuple` objects, and custom sequences are all supported. @@ -1252,7 +1071,7 @@ many choices), just specify an explicit metavar_. required ^^^^^^^^ -In general, the :mod:`argparse` module assumes that flags like ``-f`` and ``--bar`` +In general, the :mod:`!argparse` module assumes that flags like ``-f`` and ``--bar`` indicate *optional* arguments, which can always be omitted at the command line. To make an option *required*, ``True`` can be specified for the ``required=`` keyword argument to :meth:`~ArgumentParser.add_argument`:: @@ -1283,22 +1102,7 @@ help The ``help`` value is a string containing a brief description of the argument. When a user requests help (usually by using ``-h`` or ``--help`` at the command line), these ``help`` descriptions will be displayed with each -argument:: - - >>> parser = argparse.ArgumentParser(prog='frobble') - >>> parser.add_argument('--foo', action='store_true', - ... help='foo the bars before frobbling') - >>> parser.add_argument('bar', nargs='+', - ... help='one of the bars to be frobbled') - >>> parser.parse_args(['-h']) - usage: frobble [-h] [--foo] bar [bar ...] - - positional arguments: - bar one of the bars to be frobbled - - options: - -h, --help show this help message and exit - --foo foo the bars before frobbling +argument. The ``help`` strings can include various format specifiers to avoid repetition of things like the program name or the argument default_. The available @@ -1320,7 +1124,7 @@ specifiers include the program name, ``%(prog)s`` and most keyword arguments to As the help string supports %-formatting, if you want a literal ``%`` to appear in the help string, you must escape it as ``%%``. -:mod:`argparse` supports silencing the help entry for certain options, by +:mod:`!argparse` supports silencing the help entry for certain options, by setting the ``help`` value to ``argparse.SUPPRESS``:: >>> parser = argparse.ArgumentParser(prog='frobble') @@ -1338,7 +1142,7 @@ metavar ^^^^^^^ When :class:`ArgumentParser` generates help messages, it needs some way to refer -to each expected argument. By default, ArgumentParser objects use the dest_ +to each expected argument. By default, :class:`!ArgumentParser` objects use the dest_ value as the "name" of each object. By default, for positional argument actions, the dest_ value is used directly, and for optional argument actions, the dest_ value is uppercased. So, a single positional argument with @@ -1442,7 +1246,7 @@ behavior:: Action classes ^^^^^^^^^^^^^^ -Action classes implement the Action API, a callable which returns a callable +:class:`!Action` classes implement the Action API, a callable which returns a callable which processes arguments from the command-line. Any object which follows this API may be passed as the ``action`` parameter to :meth:`~ArgumentParser.add_argument`. @@ -1451,40 +1255,46 @@ this API may be passed as the ``action`` parameter to type=None, choices=None, required=False, help=None, \ metavar=None) -Action objects are used by an ArgumentParser to represent the information -needed to parse a single argument from one or more strings from the -command line. The Action class must accept the two positional arguments -plus any keyword arguments passed to :meth:`ArgumentParser.add_argument` -except for the ``action`` itself. + :class:`!Action` objects are used by an :class:`ArgumentParser` to represent the information + needed to parse a single argument from one or more strings from the + command line. The :class:`!Action` class must accept the two positional arguments + plus any keyword arguments passed to :meth:`ArgumentParser.add_argument` + except for the ``action`` itself. + + Instances of :class:`!Action` (or return value of any callable to the + ``action`` parameter) should have attributes :attr:`!dest`, + :attr:`!option_strings`, :attr:`!default`, :attr:`!type`, :attr:`!required`, + :attr:`!help`, etc. defined. The easiest way to ensure these attributes + are defined is to call :meth:`!Action.__init__`. -Instances of Action (or return value of any callable to the ``action`` -parameter) should have attributes "dest", "option_strings", "default", "type", -"required", "help", etc. defined. The easiest way to ensure these attributes -are defined is to call ``Action.__init__``. + .. method:: __call__(parser, namespace, values, option_string=None) -Action instances should be callable, so subclasses must override the -``__call__`` method, which should accept four parameters: + :class:`!Action` instances should be callable, so subclasses must override the + :meth:`!__call__` method, which should accept four parameters: -* ``parser`` - The ArgumentParser object which contains this action. + * *parser* - The :class:`ArgumentParser` object which contains this action. -* ``namespace`` - The :class:`Namespace` object that will be returned by - :meth:`~ArgumentParser.parse_args`. Most actions add an attribute to this - object using :func:`setattr`. + * *namespace* - The :class:`Namespace` object that will be returned by + :meth:`~ArgumentParser.parse_args`. Most actions add an attribute to this + object using :func:`setattr`. -* ``values`` - The associated command-line arguments, with any type conversions - applied. Type conversions are specified with the type_ keyword argument to - :meth:`~ArgumentParser.add_argument`. + * *values* - The associated command-line arguments, with any type conversions + applied. Type conversions are specified with the type_ keyword argument to + :meth:`~ArgumentParser.add_argument`. -* ``option_string`` - The option string that was used to invoke this action. - The ``option_string`` argument is optional, and will be absent if the action - is associated with a positional argument. + * *option_string* - The option string that was used to invoke this action. + The ``option_string`` argument is optional, and will be absent if the action + is associated with a positional argument. -The ``__call__`` method may perform arbitrary actions, but will typically set -attributes on the ``namespace`` based on ``dest`` and ``values``. + The :meth:`!__call__` method may perform arbitrary actions, but will typically set + attributes on the ``namespace`` based on ``dest`` and ``values``. + + .. method:: format_usage() + + :class:`!Action` subclasses can define a :meth:`!format_usage` method that takes no argument + and return a string which will be used when printing the usage of the program. + If such method is not provided, a sensible default will be used. -Action subclasses can define a ``format_usage`` method that takes no argument -and return a string which will be used when printing the usage of the program. -If such method is not provided, a sensible default will be used. The parse_args() method ----------------------- @@ -1496,7 +1306,7 @@ The parse_args() method Previous calls to :meth:`add_argument` determine exactly what objects are created and how they are assigned. See the documentation for - :meth:`add_argument` for details. + :meth:`!add_argument` for details. * args_ - List of strings to parse. The default is taken from :data:`sys.argv`. @@ -1652,7 +1462,7 @@ This feature can be disabled by setting :ref:`allow_abbrev` to ``False``. Beyond ``sys.argv`` ^^^^^^^^^^^^^^^^^^^ -Sometimes it may be useful to have an ArgumentParser parse arguments other than those +Sometimes it may be useful to have an :class:`ArgumentParser` parse arguments other than those of :data:`sys.argv`. This can be accomplished by passing a list of strings to :meth:`~ArgumentParser.parse_args`. This is useful for testing at the interactive prompt:: @@ -1679,29 +1489,29 @@ The Namespace object Simple class used by default by :meth:`~ArgumentParser.parse_args` to create an object holding attributes and return it. -This class is deliberately simple, just an :class:`object` subclass with a -readable string representation. If you prefer to have dict-like view of the -attributes, you can use the standard Python idiom, :func:`vars`:: - - >>> parser = argparse.ArgumentParser() - >>> parser.add_argument('--foo') - >>> args = parser.parse_args(['--foo', 'BAR']) - >>> vars(args) - {'foo': 'BAR'} + This class is deliberately simple, just an :class:`object` subclass with a + readable string representation. If you prefer to have dict-like view of the + attributes, you can use the standard Python idiom, :func:`vars`:: -It may also be useful to have an :class:`ArgumentParser` assign attributes to an -already existing object, rather than a new :class:`Namespace` object. This can -be achieved by specifying the ``namespace=`` keyword argument:: - - >>> class C: - ... pass - ... - >>> c = C() - >>> parser = argparse.ArgumentParser() - >>> parser.add_argument('--foo') - >>> parser.parse_args(args=['--foo', 'BAR'], namespace=c) - >>> c.foo - 'BAR' + >>> parser = argparse.ArgumentParser() + >>> parser.add_argument('--foo') + >>> args = parser.parse_args(['--foo', 'BAR']) + >>> vars(args) + {'foo': 'BAR'} + + It may also be useful to have an :class:`ArgumentParser` assign attributes to an + already existing object, rather than a new :class:`Namespace` object. This can + be achieved by specifying the ``namespace=`` keyword argument:: + + >>> class C: + ... pass + ... + >>> c = C() + >>> parser = argparse.ArgumentParser() + >>> parser.add_argument('--foo') + >>> parser.parse_args(args=['--foo', 'BAR'], namespace=c) + >>> c.foo + 'BAR' Other utilities @@ -1710,38 +1520,38 @@ Other utilities Sub-commands ^^^^^^^^^^^^ -.. method:: ArgumentParser.add_subparsers([title], [description], [prog], \ +.. method:: ArgumentParser.add_subparsers(*, [title], [description], [prog], \ [parser_class], [action], \ - [option_strings], [dest], [required], \ + [dest], [required], \ [help], [metavar]) - Many programs split up their functionality into a number of sub-commands, - for example, the ``svn`` program can invoke sub-commands like ``svn + Many programs split up their functionality into a number of subcommands, + for example, the ``svn`` program can invoke subcommands like ``svn checkout``, ``svn update``, and ``svn commit``. Splitting up functionality this way can be a particularly good idea when a program performs several different functions which require different kinds of command-line arguments. - :class:`ArgumentParser` supports the creation of such sub-commands with the - :meth:`add_subparsers` method. The :meth:`add_subparsers` method is normally + :class:`ArgumentParser` supports the creation of such subcommands with the + :meth:`!add_subparsers` method. The :meth:`!add_subparsers` method is normally called with no arguments and returns a special action object. This object has a single method, :meth:`~_SubParsersAction.add_parser`, which takes a - command name and any :class:`ArgumentParser` constructor arguments, and - returns an :class:`ArgumentParser` object that can be modified as usual. + command name and any :class:`!ArgumentParser` constructor arguments, and + returns an :class:`!ArgumentParser` object that can be modified as usual. Description of parameters: - * title - title for the sub-parser group in help output; by default + * *title* - title for the sub-parser group in help output; by default "subcommands" if description is provided, otherwise uses title for positional arguments - * description - description for the sub-parser group in help output, by + * *description* - description for the sub-parser group in help output, by default ``None`` - * prog - usage information that will be displayed with sub-command help, + * *prog* - usage information that will be displayed with sub-command help, by default the name of the program and any positional arguments before the subparser argument - * parser_class - class which will be used to create sub-parser instances, by - default the class of the current parser (e.g. ArgumentParser) + * *parser_class* - class which will be used to create sub-parser instances, by + default the class of the current parser (e.g. :class:`ArgumentParser`) * action_ - the basic type of action to be taken when this argument is encountered at the command line @@ -1754,15 +1564,15 @@ Sub-commands * help_ - help for sub-parser group in help output, by default ``None`` - * metavar_ - string presenting available sub-commands in help; by default it - is ``None`` and presents sub-commands in form {cmd1, cmd2, ..} + * metavar_ - string presenting available subcommands in help; by default it + is ``None`` and presents subcommands in form {cmd1, cmd2, ..} Some example usage:: >>> # create the top-level parser >>> parser = argparse.ArgumentParser(prog='PROG') >>> parser.add_argument('--foo', action='store_true', help='foo help') - >>> subparsers = parser.add_subparsers(help='sub-command help') + >>> subparsers = parser.add_subparsers(help='subcommand help') >>> >>> # create the parser for the "a" command >>> parser_a = subparsers.add_parser('a', help='a help') @@ -1770,7 +1580,7 @@ Sub-commands >>> >>> # create the parser for the "b" command >>> parser_b = subparsers.add_parser('b', help='b help') - >>> parser_b.add_argument('--baz', choices='XYZ', help='baz help') + >>> parser_b.add_argument('--baz', choices=('X', 'Y', 'Z'), help='baz help') >>> >>> # parse some argument lists >>> parser.parse_args(['a', '12']) @@ -1797,7 +1607,7 @@ Sub-commands usage: PROG [-h] [--foo] {a,b} ... positional arguments: - {a,b} sub-command help + {a,b} subcommand help a a help b b help @@ -1858,7 +1668,7 @@ Sub-commands that each subparser knows which Python function it should execute. For example:: - >>> # sub-command functions + >>> # subcommand functions >>> def foo(args): ... print(args.x * args.y) ... @@ -1907,7 +1717,7 @@ Sub-commands Namespace(subparser_name='2', y='frobble') .. versionchanged:: 3.7 - New *required* keyword argument. + New *required* keyword-only parameter. FileType objects @@ -1943,13 +1753,14 @@ FileType objects Argument groups ^^^^^^^^^^^^^^^ -.. method:: ArgumentParser.add_argument_group(title=None, description=None) +.. method:: ArgumentParser.add_argument_group(title=None, description=None, *, \ + [argument_default], [conflict_handler]) By default, :class:`ArgumentParser` groups command-line arguments into "positional arguments" and "options" when displaying help messages. When there is a better conceptual grouping of arguments than this default one, appropriate groups can be created using the - :meth:`add_argument_group` method:: + :meth:`!add_argument_group` method:: >>> parser = argparse.ArgumentParser(prog='PROG', add_help=False) >>> group = parser.add_argument_group('group') @@ -1966,7 +1777,7 @@ Argument groups has an :meth:`~ArgumentParser.add_argument` method just like a regular :class:`ArgumentParser`. When an argument is added to the group, the parser treats it just like a normal argument, but displays the argument in a - separate group for help messages. The :meth:`add_argument_group` method + separate group for help messages. The :meth:`!add_argument_group` method accepts *title* and *description* arguments which can be used to customize this display:: @@ -1988,6 +1799,11 @@ Argument groups --bar BAR bar help + The optional, keyword-only parameters argument_default_ and conflict_handler_ + allow for finer-grained control of the behavior of the argument group. These + parameters have the same meaning as in the :class:`ArgumentParser` constructor, + but apply specifically to the argument group rather than the entire parser. + Note that any arguments not in your user-defined groups will end up back in the usual "positional arguments" and "optional arguments" sections. @@ -2003,7 +1819,7 @@ Mutual exclusion .. method:: ArgumentParser.add_mutually_exclusive_group(required=False) - Create a mutually exclusive group. :mod:`argparse` will make sure that only + Create a mutually exclusive group. :mod:`!argparse` will make sure that only one of the arguments in the mutually exclusive group was present on the command line:: @@ -2140,20 +1956,20 @@ Partial parsing .. method:: ArgumentParser.parse_known_args(args=None, namespace=None) -Sometimes a script may only parse a few of the command-line arguments, passing -the remaining arguments on to another script or program. In these cases, the -:meth:`~ArgumentParser.parse_known_args` method can be useful. It works much like -:meth:`~ArgumentParser.parse_args` except that it does not produce an error when -extra arguments are present. Instead, it returns a two item tuple containing -the populated namespace and the list of remaining argument strings. + Sometimes a script may only parse a few of the command-line arguments, passing + the remaining arguments on to another script or program. In these cases, the + :meth:`~ArgumentParser.parse_known_args` method can be useful. It works much like + :meth:`~ArgumentParser.parse_args` except that it does not produce an error when + extra arguments are present. Instead, it returns a two item tuple containing + the populated namespace and the list of remaining argument strings. -:: + :: - >>> parser = argparse.ArgumentParser() - >>> parser.add_argument('--foo', action='store_true') - >>> parser.add_argument('bar') - >>> parser.parse_known_args(['--foo', '--badger', 'BAR', 'spam']) - (Namespace(bar='BAR', foo=True), ['--badger', 'spam']) + >>> parser = argparse.ArgumentParser() + >>> parser.add_argument('--foo', action='store_true') + >>> parser.add_argument('bar') + >>> parser.parse_known_args(['--foo', '--badger', 'BAR', 'spam']) + (Namespace(bar='BAR', foo=True), ['--badger', 'spam']) .. warning:: :ref:`Prefix matching ` rules apply to @@ -2190,8 +2006,8 @@ Exiting methods .. method:: ArgumentParser.exit(status=0, message=None) This method terminates the program, exiting with the specified *status* - and, if given, it prints a *message* before that. The user can override - this method to handle these steps differently:: + and, if given, it prints a *message* to :data:`sys.stderr` before that. + The user can override this method to handle these steps differently:: class ErrorCatchingArgumentParser(argparse.ArgumentParser): def exit(self, status=0, message=None): @@ -2201,8 +2017,8 @@ Exiting methods .. method:: ArgumentParser.error(message) - This method prints a usage message including the *message* to the - standard error and terminates the program with a status code of 2. + This method prints a usage message, including the *message*, to + :data:`sys.stderr` and terminates the program with a status code of 2. Intermixed parsing @@ -2211,90 +2027,66 @@ Intermixed parsing .. method:: ArgumentParser.parse_intermixed_args(args=None, namespace=None) .. method:: ArgumentParser.parse_known_intermixed_args(args=None, namespace=None) -A number of Unix commands allow the user to intermix optional arguments with -positional arguments. The :meth:`~ArgumentParser.parse_intermixed_args` -and :meth:`~ArgumentParser.parse_known_intermixed_args` methods -support this parsing style. - -These parsers do not support all the argparse features, and will raise -exceptions if unsupported features are used. In particular, subparsers, -and mutually exclusive groups that include both -optionals and positionals are not supported. - -The following example shows the difference between -:meth:`~ArgumentParser.parse_known_args` and -:meth:`~ArgumentParser.parse_intermixed_args`: the former returns ``['2', -'3']`` as unparsed arguments, while the latter collects all the positionals -into ``rest``. :: + A number of Unix commands allow the user to intermix optional arguments with + positional arguments. The :meth:`~ArgumentParser.parse_intermixed_args` + and :meth:`~ArgumentParser.parse_known_intermixed_args` methods + support this parsing style. - >>> parser = argparse.ArgumentParser() - >>> parser.add_argument('--foo') - >>> parser.add_argument('cmd') - >>> parser.add_argument('rest', nargs='*', type=int) - >>> parser.parse_known_args('doit 1 --foo bar 2 3'.split()) - (Namespace(cmd='doit', foo='bar', rest=[1]), ['2', '3']) - >>> parser.parse_intermixed_args('doit 1 --foo bar 2 3'.split()) - Namespace(cmd='doit', foo='bar', rest=[1, 2, 3]) - -:meth:`~ArgumentParser.parse_known_intermixed_args` returns a two item tuple -containing the populated namespace and the list of remaining argument strings. -:meth:`~ArgumentParser.parse_intermixed_args` raises an error if there are any -remaining unparsed argument strings. + These parsers do not support all the :mod:`!argparse` features, and will raise + exceptions if unsupported features are used. In particular, subparsers, + and mutually exclusive groups that include both + optionals and positionals are not supported. -.. versionadded:: 3.7 + The following example shows the difference between + :meth:`~ArgumentParser.parse_known_args` and + :meth:`~ArgumentParser.parse_intermixed_args`: the former returns ``['2', + '3']`` as unparsed arguments, while the latter collects all the positionals + into ``rest``. :: -.. _upgrading-optparse-code: - -Upgrading optparse code ------------------------ - -Originally, the :mod:`argparse` module had attempted to maintain compatibility -with :mod:`optparse`. However, :mod:`optparse` was difficult to extend -transparently, particularly with the changes required to support the new -``nargs=`` specifiers and better usage messages. When most everything in -:mod:`optparse` had either been copy-pasted over or monkey-patched, it no -longer seemed practical to try to maintain the backwards compatibility. - -The :mod:`argparse` module improves on the standard library :mod:`optparse` -module in a number of ways including: - -* Handling positional arguments. -* Supporting sub-commands. -* Allowing alternative option prefixes like ``+`` and ``/``. -* Handling zero-or-more and one-or-more style arguments. -* Producing more informative usage messages. -* Providing a much simpler interface for custom ``type`` and ``action``. + >>> parser = argparse.ArgumentParser() + >>> parser.add_argument('--foo') + >>> parser.add_argument('cmd') + >>> parser.add_argument('rest', nargs='*', type=int) + >>> parser.parse_known_args('doit 1 --foo bar 2 3'.split()) + (Namespace(cmd='doit', foo='bar', rest=[1]), ['2', '3']) + >>> parser.parse_intermixed_args('doit 1 --foo bar 2 3'.split()) + Namespace(cmd='doit', foo='bar', rest=[1, 2, 3]) -A partial upgrade path from :mod:`optparse` to :mod:`argparse`: + :meth:`~ArgumentParser.parse_known_intermixed_args` returns a two item tuple + containing the populated namespace and the list of remaining argument strings. + :meth:`~ArgumentParser.parse_intermixed_args` raises an error if there are any + remaining unparsed argument strings. -* Replace all :meth:`optparse.OptionParser.add_option` calls with - :meth:`ArgumentParser.add_argument` calls. + .. versionadded:: 3.7 -* Replace ``(options, args) = parser.parse_args()`` with ``args = - parser.parse_args()`` and add additional :meth:`ArgumentParser.add_argument` - calls for the positional arguments. Keep in mind that what was previously - called ``options``, now in the :mod:`argparse` context is called ``args``. -* Replace :meth:`optparse.OptionParser.disable_interspersed_args` - by using :meth:`~ArgumentParser.parse_intermixed_args` instead of - :meth:`~ArgumentParser.parse_args`. +Registering custom types or actions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -* Replace callback actions and the ``callback_*`` keyword arguments with - ``type`` or ``action`` arguments. +.. method:: ArgumentParser.register(registry_name, value, object) -* Replace string names for ``type`` keyword arguments with the corresponding - type objects (e.g. int, float, complex, etc). + Sometimes it's desirable to use a custom string in error messages to provide + more user-friendly output. In these cases, :meth:`!register` can be used to + register custom actions or types with a parser and allow you to reference the + type by their registered name instead of their callable name. -* Replace :class:`optparse.Values` with :class:`Namespace` and - :exc:`optparse.OptionError` and :exc:`optparse.OptionValueError` with - :exc:`ArgumentError`. + The :meth:`!register` method accepts three arguments - a *registry_name*, + specifying the internal registry where the object will be stored (e.g., + ``action``, ``type``), *value*, which is the key under which the object will + be registered, and object, the callable to be registered. -* Replace strings with implicit arguments such as ``%default`` or ``%prog`` with - the standard Python syntax to use dictionaries to format strings, that is, - ``%(default)s`` and ``%(prog)s``. + The following example shows how to register a custom type with a parser:: -* Replace the OptionParser constructor ``version`` argument with a call to - ``parser.add_argument('--version', action='version', version='')``. + >>> import argparse + >>> parser = argparse.ArgumentParser() + >>> parser.register('type', 'hexadecimal integer', lambda s: int(s, 16)) + >>> parser.add_argument('--foo', type='hexadecimal integer') + _StoreAction(option_strings=['--foo'], dest='foo', nargs=None, const=None, default=None, type='hexadecimal integer', choices=None, required=False, help=None, metavar=None, deprecated=False) + >>> parser.parse_args(['--foo', '0xFA']) + Namespace(foo=250) + >>> parser.parse_args(['--foo', '1.2']) + usage: PROG [-h] [--foo FOO] + PROG: error: argument --foo: invalid 'hexadecimal integer' value: '1.2' Exceptions ---------- @@ -2309,3 +2101,12 @@ Exceptions .. exception:: ArgumentTypeError Raised when something goes wrong converting a command line string to a type. + + +.. rubric:: Guides and Tutorials + +.. toctree:: + :maxdepth: 1 + + ../howto/argparse.rst + ../howto/argparse-optparse.rst diff --git a/Doc/library/array.rst b/Doc/library/array.rst index beaa8cda..b4e656a7 100644 --- a/Doc/library/array.rst +++ b/Doc/library/array.rst @@ -9,7 +9,7 @@ -------------- This module defines an object type which can compactly represent an array of -basic values: characters, integers, floating point numbers. Arrays are sequence +basic values: characters, integers, floating-point numbers. Arrays are sequence types and behave very much like lists, except that the type of objects stored in them is constrained. The type is specified at object creation time by using a :dfn:`type code`, which is a single character. The following type codes are @@ -253,7 +253,7 @@ The string representation is guaranteed to be able to be converted back to an array with the same type and value using :func:`eval`, so long as the :class:`~array.array` class has been imported using ``from array import array``. Variables ``inf`` and ``nan`` must also be defined if it contains -corresponding floating point values. +corresponding floating-point values. Examples:: array('l') diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index 1c0c808e..6a98d9b3 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -157,9 +157,9 @@ Root nodes A Python module, as with :ref:`file input `. Node type generated by :func:`ast.parse` in the default ``"exec"`` *mode*. - *body* is a :class:`list` of the module's :ref:`ast-statements`. + ``body`` is a :class:`list` of the module's :ref:`ast-statements`. - *type_ignores* is a :class:`list` of the module's type ignore comments; + ``type_ignores`` is a :class:`list` of the module's type ignore comments; see :func:`ast.parse` for more details. .. doctest:: @@ -179,7 +179,7 @@ Root nodes A single Python :ref:`expression input `. Node type generated by :func:`ast.parse` when *mode* is ``"eval"``. - *body* is a single node, + ``body`` is a single node, one of the :ref:`expression types `. .. doctest:: @@ -194,7 +194,7 @@ Root nodes A single :ref:`interactive input `, like in :ref:`tut-interac`. Node type generated by :func:`ast.parse` when *mode* is ``"single"``. - *body* is a :class:`list` of :ref:`statement nodes `. + ``body`` is a :class:`list` of :ref:`statement nodes `. .. doctest:: @@ -223,9 +223,9 @@ Root nodes # type: (int, int) -> int return a + b - *argtypes* is a :class:`list` of :ref:`expression nodes `. + ``argtypes`` is a :class:`list` of :ref:`expression nodes `. - *returns* is a single :ref:`expression node `. + ``returns`` is a single :ref:`expression node `. .. doctest:: @@ -881,11 +881,15 @@ Statements .. class:: AnnAssign(target, annotation, value, simple) An assignment with a type annotation. ``target`` is a single node and can - be a :class:`Name`, a :class:`Attribute` or a :class:`Subscript`. + be a :class:`Name`, an :class:`Attribute` or a :class:`Subscript`. ``annotation`` is the annotation, such as a :class:`Constant` or :class:`Name` - node. ``value`` is a single optional node. ``simple`` is a boolean integer - set to True for a :class:`Name` node in ``target`` that do not appear in - between parenthesis and are hence pure names and not expressions. + node. ``value`` is a single optional node. + + ``simple`` is always either 0 (indicating a "complex" target) or 1 + (indicating a "simple" target). A "simple" target consists solely of a + :class:`Name` node that does not appear between parentheses; all other + targets are considered complex. Only simple targets appear in + the :attr:`~object.__annotations__` dictionary of modules and classes. .. doctest:: @@ -2000,7 +2004,7 @@ Function and class definitions YieldFrom(value) A ``yield`` or ``yield from`` expression. Because these are expressions, they - must be wrapped in a :class:`Expr` node if the value sent back is not used. + must be wrapped in an :class:`Expr` node if the value sent back is not used. .. doctest:: @@ -2056,8 +2060,7 @@ Function and class definitions * ``name`` is a raw string for the class name * ``bases`` is a list of nodes for explicitly specified base classes. * ``keywords`` is a list of :class:`.keyword` nodes, principally for 'metaclass'. - Other keywords will be passed to the metaclass, as per `PEP-3115 - `_. + Other keywords will be passed to the metaclass, as per :pep:`3115`. * ``body`` is a list of nodes representing the code within the class definition. * ``decorator_list`` is a list of nodes, as in :class:`FunctionDef`. @@ -2167,7 +2170,7 @@ and classes for traversing abstract syntax trees: If ``type_comments=True`` is given, the parser is modified to check and return type comments as specified by :pep:`484` and :pep:`526`. This is equivalent to adding :data:`ast.PyCF_TYPE_COMMENTS` to the - flags passed to :func:`compile()`. This will report syntax errors + flags passed to :func:`compile`. This will report syntax errors for misplaced type comments. Without this flag, type comments will be ignored, and the ``type_comment`` field on selected AST nodes will always be ``None``. In addition, the locations of ``# type: diff --git a/Doc/library/asynchat.rst b/Doc/library/asynchat.rst new file mode 100644 index 00000000..5e5c3a99 --- /dev/null +++ b/Doc/library/asynchat.rst @@ -0,0 +1,17 @@ +:mod:`!asynchat` --- Asynchronous socket command/response handler +================================================================= + +.. module:: asynchat + :synopsis: Removed in 3.12. + :deprecated: + +.. deprecated-removed:: 3.6 3.12 + +This module is no longer part of the Python standard library. +It was :ref:`removed in Python 3.12 ` after +being deprecated in Python 3.6. The removal was decided in :pep:`594`. + +Applications should use the :mod:`asyncio` module instead. + +The last version of Python that provided the :mod:`!asynchat` module was +`Python 3.11 `_. diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index ba0ee1b6..53aaae41 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -126,7 +126,7 @@ Running and stopping the loop Run the event loop until :meth:`stop` is called. - If :meth:`stop` is called before :meth:`run_forever()` is called, + If :meth:`stop` is called before :meth:`run_forever` is called, the loop will poll the I/O selector once with a timeout of zero, run all callbacks scheduled in response to I/O events (and those that were already scheduled), and then exit. @@ -165,7 +165,7 @@ Running and stopping the loop .. coroutinemethod:: loop.shutdown_asyncgens() Schedule all currently open :term:`asynchronous generator` objects to - close with an :meth:`~agen.aclose()` call. After calling this method, + close with an :meth:`~agen.aclose` call. After calling this method, the event loop will issue a warning if a new asynchronous generator is iterated. This should be used to reliably finalize all scheduled asynchronous generators. @@ -1139,6 +1139,14 @@ DNS Asynchronous version of :meth:`socket.getnameinfo`. +.. note:: + Both *getaddrinfo* and *getnameinfo* internally utilize their synchronous + versions through the loop's default thread pool executor. + When this executor is saturated, these methods may experience delays, + which higher-level networking libraries may report as increased timeouts. + To mitigate this, consider using a custom executor for other user tasks, + or setting a default executor with a larger number of workers. + .. versionchanged:: 3.7 Both *getaddrinfo* and *getnameinfo* methods were always documented to return a coroutine, but prior to Python 3.7 they were, in fact, @@ -1238,6 +1246,9 @@ Executing code in thread or process pools The *executor* argument should be an :class:`concurrent.futures.Executor` instance. The default executor is used if *executor* is ``None``. + The default executor can be set by :meth:`loop.set_default_executor`, + otherwise, a :class:`concurrent.futures.ThreadPoolExecutor` will be + lazy-initialized and used by :func:`run_in_executor` if needed. Example:: @@ -1375,7 +1386,7 @@ Allows customizing how exceptions are handled in the event loop. This method should not be overloaded in subclassed event loops. For custom exception handling, use - the :meth:`set_exception_handler()` method. + the :meth:`set_exception_handler` method. Enabling debug mode ^^^^^^^^^^^^^^^^^^^ @@ -1458,7 +1469,7 @@ async/await code consider using the high-level * *stdin* can be any of these: * a file-like object - * an existing file descriptor (a positive integer), for example those created with :meth:`os.pipe()` + * an existing file descriptor (a positive integer), for example those created with :meth:`os.pipe` * the :const:`subprocess.PIPE` constant (default) which will create a new pipe and connect it, * the value ``None`` which will make the subprocess inherit the file @@ -1739,7 +1750,7 @@ on Unix and :class:`ProactorEventLoop` on Windows. .. seealso:: `MSDN documentation on I/O Completion Ports - `_. + `_. .. class:: AbstractEventLoop diff --git a/Doc/library/asyncio-future.rst b/Doc/library/asyncio-future.rst index 893ae551..9dce0731 100644 --- a/Doc/library/asyncio-future.rst +++ b/Doc/library/asyncio-future.rst @@ -120,20 +120,20 @@ Future Object a :exc:`CancelledError` exception. If the Future's result isn't yet available, this method raises - a :exc:`InvalidStateError` exception. + an :exc:`InvalidStateError` exception. .. method:: set_result(result) Mark the Future as *done* and set its result. - Raises a :exc:`InvalidStateError` error if the Future is + Raises an :exc:`InvalidStateError` error if the Future is already *done*. .. method:: set_exception(exception) Mark the Future as *done* and set an exception. - Raises a :exc:`InvalidStateError` error if the Future is + Raises an :exc:`InvalidStateError` error if the Future is already *done*. .. method:: done() diff --git a/Doc/library/asyncio-llapi-index.rst b/Doc/library/asyncio-llapi-index.rst index 67136ba6..3e21054a 100644 --- a/Doc/library/asyncio-llapi-index.rst +++ b/Doc/library/asyncio-llapi-index.rst @@ -56,10 +56,10 @@ See also the main documentation section about the * - :meth:`loop.close` - Close the event loop. - * - :meth:`loop.is_running()` + * - :meth:`loop.is_running` - Return ``True`` if the event loop is running. - * - :meth:`loop.is_closed()` + * - :meth:`loop.is_closed` - Return ``True`` if the event loop is closed. * - ``await`` :meth:`loop.shutdown_asyncgens` diff --git a/Doc/library/asyncio-queue.rst b/Doc/library/asyncio-queue.rst index d86fbc21..63afc411 100644 --- a/Doc/library/asyncio-queue.rst +++ b/Doc/library/asyncio-queue.rst @@ -55,7 +55,7 @@ Queue Return ``True`` if there are :attr:`maxsize` items in the queue. If the queue was initialized with ``maxsize=0`` (the default), - then :meth:`full()` never returns ``True``. + then :meth:`full` never returns ``True``. .. coroutinemethod:: get() diff --git a/Doc/library/asyncio-runner.rst b/Doc/library/asyncio-runner.rst index b68b2570..e2cff48e 100644 --- a/Doc/library/asyncio-runner.rst +++ b/Doc/library/asyncio-runner.rst @@ -89,7 +89,7 @@ Runner context manager current one. By default :func:`asyncio.new_event_loop` is used and set as current event loop with :func:`asyncio.set_event_loop` if *loop_factory* is ``None``. - Basically, :func:`asyncio.run()` example can be rewritten with the runner usage:: + Basically, :func:`asyncio.run` example can be rewritten with the runner usage:: async def main(): await asyncio.sleep(1) diff --git a/Doc/library/asyncio-sync.rst b/Doc/library/asyncio-sync.rst index 05bdf548..4caa8b9b 100644 --- a/Doc/library/asyncio-sync.rst +++ b/Doc/library/asyncio-sync.rst @@ -262,8 +262,9 @@ Condition Wait until a predicate becomes *true*. The predicate must be a callable which result will be - interpreted as a boolean value. The final value is the - return value. + interpreted as a boolean value. The method will repeatedly + :meth:`~Condition.wait` until the predicate evaluates to *true*. + The final value is the return value. Semaphore @@ -428,7 +429,7 @@ Barrier .. coroutinemethod:: abort() Put the barrier into a broken state. This causes any active or future - calls to :meth:`wait` to fail with the :class:`BrokenBarrierError`. + calls to :meth:`~Barrier.wait` to fail with the :class:`BrokenBarrierError`. Use this for example if one of the tasks needs to abort, to avoid infinite waiting tasks. diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 6c046ebe..0ba6e84d 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -158,7 +158,7 @@ other coroutines:: # Nothing happens if we just call "nested()". # A coroutine object is created but not awaited, # so it *won't run at all*. - nested() + nested() # will raise a "RuntimeWarning". # Let's do it differently now and await it: print(await nested()) # will print "42". @@ -386,6 +386,53 @@ The same special case is made for :exc:`KeyboardInterrupt` and :exc:`SystemExit` as in the previous paragraph. +Terminating a Task Group +------------------------ + +While terminating a task group is not natively supported by the standard +library, termination can be achieved by adding an exception-raising task +to the task group and ignoring the raised exception: + +.. code-block:: python + + import asyncio + from asyncio import TaskGroup + + class TerminateTaskGroup(Exception): + """Exception raised to terminate a task group.""" + + async def force_terminate_task_group(): + """Used to force termination of a task group.""" + raise TerminateTaskGroup() + + async def job(task_id, sleep_time): + print(f'Task {task_id}: start') + await asyncio.sleep(sleep_time) + print(f'Task {task_id}: done') + + async def main(): + try: + async with TaskGroup() as group: + # spawn some tasks + group.create_task(job(1, 0.5)) + group.create_task(job(2, 1.5)) + # sleep for 1 second + await asyncio.sleep(1) + # add an exception-raising task to force the group to terminate + group.create_task(force_terminate_task_group()) + except* TerminateTaskGroup: + pass + + asyncio.run(main()) + +Expected output: + +.. code-block:: text + + Task 1: start + Task 2: start + Task 1: done + Sleeping ======== @@ -1104,7 +1151,7 @@ Task Object a :exc:`CancelledError` exception. If the Task's result isn't yet available, this method raises - a :exc:`InvalidStateError` exception. + an :exc:`InvalidStateError` exception. .. method:: exception() diff --git a/Doc/library/asyncio.rst b/Doc/library/asyncio.rst index 184f981c..1fb575d7 100644 --- a/Doc/library/asyncio.rst +++ b/Doc/library/asyncio.rst @@ -56,8 +56,12 @@ Additionally, there are **low-level** APIs for * :ref:`bridge ` callback-based libraries and code with async/await syntax. +.. include:: ../includes/wasm-notavail.rst + .. _asyncio-cli: +.. rubric:: asyncio REPL + You can experiment with an ``asyncio`` concurrent context in the REPL: .. code-block:: pycon @@ -70,7 +74,10 @@ You can experiment with an ``asyncio`` concurrent context in the REPL: >>> await asyncio.sleep(10, result='hello') 'hello' -.. include:: ../includes/wasm-notavail.rst +.. audit-event:: cpython.run_stdin "" "" + +.. versionchanged:: 3.12.5 (also 3.11.10, 3.10.15, 3.9.20, and 3.8.20) + Emits audit events. .. We use the "rubric" directive here to avoid creating the "Reference" subsection in the TOC. diff --git a/Doc/library/asyncore.rst b/Doc/library/asyncore.rst new file mode 100644 index 00000000..22c9881c --- /dev/null +++ b/Doc/library/asyncore.rst @@ -0,0 +1,17 @@ +:mod:`!asyncore` --- Asynchronous socket handler +================================================ + +.. module:: asyncore + :synopsis: Removed in 3.12. + :deprecated: + +.. deprecated-removed:: 3.6 3.12 + +This module is no longer part of the Python standard library. +It was :ref:`removed in Python 3.12 ` after +being deprecated in Python 3.6. The removal was decided in :pep:`594`. + +Applications should use the :mod:`asyncio` module instead. + +The last version of Python that provided the :mod:`!asyncore` module was +`Python 3.11 `_. diff --git a/Doc/library/builtins.rst b/Doc/library/builtins.rst index 644344e7..c4979db5 100644 --- a/Doc/library/builtins.rst +++ b/Doc/library/builtins.rst @@ -7,10 +7,7 @@ -------------- This module provides direct access to all 'built-in' identifiers of Python; for -example, ``builtins.open`` is the full name for the built-in function -:func:`open`. See :ref:`built-in-funcs` and :ref:`built-in-consts` for -documentation. - +example, ``builtins.open`` is the full name for the built-in function :func:`open`. This module is not normally accessed explicitly by most applications, but can be useful in modules that provide objects with the same name as a built-in value, @@ -40,3 +37,10 @@ available as part of their globals. The value of ``__builtins__`` is normally either this module or the value of this module's :attr:`~object.__dict__` attribute. Since this is an implementation detail, it may not be used by alternate implementations of Python. + +.. seealso:: + + * :ref:`built-in-consts` + * :ref:`bltin-exceptions` + * :ref:`built-in-funcs` + * :ref:`bltin-types` diff --git a/Doc/library/calendar.rst b/Doc/library/calendar.rst index 02d659f9..102bc287 100644 --- a/Doc/library/calendar.rst +++ b/Doc/library/calendar.rst @@ -393,13 +393,22 @@ The :mod:`calendar` module exports the following data attributes: .. data:: day_name - An array that represents the days of the week in the current locale. + A sequence that represents the days of the week in the current locale, + where Monday is day number 0. + + >>> import calendar + >>> list(calendar.day_name) + ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] .. data:: day_abbr - An array that represents the abbreviated days of the week in the current locale. + A sequence that represents the abbreviated days of the week in the current locale, + where Mon is day number 0. + >>> import calendar + >>> list(calendar.day_abbr) + ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] .. data:: MONDAY TUESDAY @@ -426,17 +435,24 @@ The :mod:`calendar` module exports the following data attributes: .. data:: month_name - An array that represents the months of the year in the current locale. This + A sequence that represents the months of the year in the current locale. This follows normal convention of January being month number 1, so it has a length of 13 and ``month_name[0]`` is the empty string. + >>> import calendar + >>> list(calendar.month_name) + ['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] + .. data:: month_abbr - An array that represents the abbreviated months of the year in the current + A sequence that represents the abbreviated months of the year in the current locale. This follows normal convention of January being month number 1, so it has a length of 13 and ``month_abbr[0]`` is the empty string. + >>> import calendar + >>> list(calendar.month_abbr) + ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] .. data:: JANUARY FEBRUARY diff --git a/Doc/library/cmath.rst b/Doc/library/cmath.rst index 381a8332..f122e364 100644 --- a/Doc/library/cmath.rst +++ b/Doc/library/cmath.rst @@ -221,19 +221,21 @@ Classification functions ``False`` otherwise. Whether or not two values are considered close is determined according to - given absolute and relative tolerances. + given absolute and relative tolerances. If no errors occur, the result will + be: ``abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)``. *rel_tol* is the relative tolerance -- it is the maximum allowed difference between *a* and *b*, relative to the larger absolute value of *a* or *b*. For example, to set a tolerance of 5%, pass ``rel_tol=0.05``. The default tolerance is ``1e-09``, which assures that the two values are the same - within about 9 decimal digits. *rel_tol* must be greater than zero. - - *abs_tol* is the minimum absolute tolerance -- useful for comparisons near - zero. *abs_tol* must be at least zero. - - If no errors occur, the result will be: - ``abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)``. + within about 9 decimal digits. *rel_tol* must be nonnegative and less + than ``1.0``. + + *abs_tol* is the absolute tolerance; it defaults to ``0.0`` and it must be + nonnegative. When comparing ``x`` to ``0.0``, ``isclose(x, 0)`` is computed + as ``abs(x) <= rel_tol * abs(x)``, which is ``False`` for any ``x`` and + rel_tol less than ``1.0``. So add an appropriate positive abs_tol argument + to the call. The IEEE 754 special values of ``NaN``, ``inf``, and ``-inf`` will be handled according to IEEE rules. Specifically, ``NaN`` is not considered diff --git a/Doc/library/collections.abc.rst b/Doc/library/collections.abc.rst index ea27436f..0adbd305 100644 --- a/Doc/library/collections.abc.rst +++ b/Doc/library/collections.abc.rst @@ -216,6 +216,9 @@ Collections Abstract Base Classes -- Detailed Descriptions ABC for classes that provide the :meth:`~object.__call__` method. + See :ref:`annotating-callables` for details on how to use + :class:`!Callable` in type annotations. + .. class:: Iterable ABC for classes that provide the :meth:`~container.__iter__` method. @@ -253,6 +256,9 @@ Collections Abstract Base Classes -- Detailed Descriptions :meth:`~generator.send`, :meth:`~generator.throw` and :meth:`~generator.close` methods. + See :ref:`annotating-generators-and-coroutines` + for details on using :class:`!Generator` in type annotations. + .. versionadded:: 3.5 .. class:: Sequence @@ -331,6 +337,11 @@ Collections Abstract Base Classes -- Detailed Descriptions Using ``isinstance(gencoro, Coroutine)`` for them will return ``False``. Use :func:`inspect.isawaitable` to detect them. + See :ref:`annotating-generators-and-coroutines` + for details on using :class:`!Coroutine` in type annotations. + The variance and order of type parameters correspond to those of + :class:`Generator`. + .. versionadded:: 3.5 .. class:: AsyncIterable @@ -352,6 +363,9 @@ Collections Abstract Base Classes -- Detailed Descriptions ABC for :term:`asynchronous generator` classes that implement the protocol defined in :pep:`525` and :pep:`492`. + See :ref:`annotating-generators-and-coroutines` + for details on using :class:`!AsyncGenerator` in type annotations. + .. versionadded:: 3.6 .. class:: Buffer diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst index fedf1914..c4586afd 100644 --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -99,7 +99,7 @@ The class can be used to simulate nested scopes and is useful in templating. :func:`super` function. A reference to ``d.parents`` is equivalent to: ``ChainMap(*d.maps[1:])``. - Note, the iteration order of a :class:`ChainMap()` is determined by + Note, the iteration order of a :class:`ChainMap` is determined by scanning the mappings last to first:: >>> baseline = {'music': 'bach', 'art': 'rembrandt'} @@ -783,10 +783,10 @@ sequence of key-value pairs into a dictionary of lists: When each key is encountered for the first time, it is not already in the mapping; so an entry is automatically created using the :attr:`~defaultdict.default_factory` -function which returns an empty :class:`list`. The :meth:`list.append` +function which returns an empty :class:`list`. The :meth:`!list.append` operation then attaches the value to the new list. When keys are encountered again, the look-up proceeds normally (returning the list for that key) and the -:meth:`list.append` operation adds another value to the list. This technique is +:meth:`!list.append` operation adds another value to the list. This technique is simpler and faster than an equivalent technique using :meth:`dict.setdefault`: >>> d = {} @@ -874,8 +874,8 @@ they add the ability to access fields by name instead of position index. ``(1, 2)``, then ``x`` will be a required argument, ``y`` will default to ``1``, and ``z`` will default to ``2``. - If *module* is defined, the ``__module__`` attribute of the named tuple is - set to that value. + If *module* is defined, the :attr:`~type.__module__` attribute of the + named tuple is set to that value. Named tuple instances do not have per-instance dictionaries, so they are lightweight and require no more memory than regular tuples. @@ -1163,8 +1163,11 @@ Some differences from :class:`dict` still remain: In addition to the usual mapping methods, ordered dictionaries also support reverse iteration using :func:`reversed`. +.. _collections_OrderedDict__eq__: + Equality tests between :class:`OrderedDict` objects are order-sensitive -and are implemented as ``list(od1.items())==list(od2.items())``. +and are roughly equivalent to ``list(od1.items())==list(od2.items())``. + Equality tests between :class:`OrderedDict` objects and other :class:`~collections.abc.Mapping` objects are order-insensitive like regular dictionaries. This allows :class:`OrderedDict` objects to be substituted @@ -1180,7 +1183,7 @@ anywhere a regular dictionary is used. method. .. versionchanged:: 3.9 - Added merge (``|``) and update (``|=``) operators, specified in :pep:`584`. + Added merge (``|``) and update (``|=``) operators, specified in :pep:`584`. :class:`OrderedDict` Examples and Recipes diff --git a/Doc/library/colorsys.rst b/Doc/library/colorsys.rst index 125d62b1..ffebf4e4 100644 --- a/Doc/library/colorsys.rst +++ b/Doc/library/colorsys.rst @@ -14,7 +14,7 @@ The :mod:`colorsys` module defines bidirectional conversions of color values between colors expressed in the RGB (Red Green Blue) color space used in computer monitors and three other coordinate systems: YIQ, HLS (Hue Lightness Saturation) and HSV (Hue Saturation Value). Coordinates in all of these color -spaces are floating point values. In the YIQ space, the Y coordinate is between +spaces are floating-point values. In the YIQ space, the Y coordinate is between 0 and 1, but the I and Q coordinates can be positive or negative. In all other spaces, the coordinates are all between 0 and 1. diff --git a/Doc/library/compileall.rst b/Doc/library/compileall.rst index f2c64334..1cf40fa6 100644 --- a/Doc/library/compileall.rst +++ b/Doc/library/compileall.rst @@ -90,7 +90,7 @@ compile Python sources. .. option:: -j N Use *N* workers to compile the files within the given directory. - If ``0`` is used, then the result of :func:`os.cpu_count()` + If ``0`` is used, then the result of :func:`os.cpu_count` will be used. .. option:: --invalidation-mode [timestamp|checked-hash|unchecked-hash] diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst index 560260e8..4f3549d9 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -54,6 +54,7 @@ can be customized by end users easily. import os os.remove("example.ini") + os.remove("override.ini") Quick Start @@ -147,23 +148,28 @@ case-insensitive and stored in lowercase [1]_. It is possible to read several configurations into a single :class:`ConfigParser`, where the most recently added configuration has the highest priority. Any conflicting keys are taken from the more recent -configuration while the previously existing keys are retained. +configuration while the previously existing keys are retained. The example +below reads in an ``override.ini`` file, which will override any conflicting +keys from the ``example.ini`` file. + +.. code-block:: ini + + [DEFAULT] + ServerAliveInterval = -1 .. doctest:: - >>> another_config = configparser.ConfigParser() - >>> another_config.read('example.ini') - ['example.ini'] - >>> another_config['topsecret.server.example']['Port'] - '50022' - >>> another_config.read_string("[topsecret.server.example]\nPort=48484") - >>> another_config['topsecret.server.example']['Port'] - '48484' - >>> another_config.read_dict({"topsecret.server.example": {"Port": 21212}}) - >>> another_config['topsecret.server.example']['Port'] - '21212' - >>> another_config['topsecret.server.example']['ForwardX11'] - 'no' + >>> config_override = configparser.ConfigParser() + >>> config_override['DEFAULT'] = {'ServerAliveInterval': '-1'} + >>> with open('override.ini', 'w') as configfile: + ... config_override.write(configfile) + ... + >>> config_override = configparser.ConfigParser() + >>> config_override.read(['example.ini', 'override.ini']) + ['example.ini', 'override.ini'] + >>> print(config_override.get('DEFAULT', 'ServerAliveInterval')) + -1 + This behaviour is equivalent to a :meth:`ConfigParser.read` call with several files passed to the *filenames* parameter. @@ -955,9 +961,34 @@ ConfigParser Objects When *converters* is given, it should be a dictionary where each key represents the name of a type converter and each value is a callable implementing the conversion from string to the desired datatype. Every - converter gets its own corresponding :meth:`!get*()` method on the parser + converter gets its own corresponding :meth:`!get*` method on the parser object and section proxies. + It is possible to read several configurations into a single + :class:`ConfigParser`, where the most recently added configuration has the + highest priority. Any conflicting keys are taken from the more recent + configuration while the previously existing keys are retained. The example + below reads in an ``override.ini`` file, which will override any conflicting + keys from the ``example.ini`` file. + + .. code-block:: ini + + [DEFAULT] + ServerAliveInterval = -1 + + .. doctest:: + + >>> config_override = configparser.ConfigParser() + >>> config_override['DEFAULT'] = {'ServerAliveInterval': '-1'} + >>> with open('override.ini', 'w') as configfile: + ... config_override.write(configfile) + ... + >>> config_override = configparser.ConfigParser() + >>> config_override.read(['example.ini', 'override.ini']) + ['example.ini', 'override.ini'] + >>> print(config_override.get('DEFAULT', 'ServerAliveInterval')) + -1 + .. versionchanged:: 3.1 The default *dict_type* is :class:`collections.OrderedDict`. @@ -970,7 +1001,7 @@ ConfigParser Objects The *converters* argument was added. .. versionchanged:: 3.7 - The *defaults* argument is read with :meth:`read_dict()`, + The *defaults* argument is read with :meth:`read_dict`, providing consistent behavior across the parser: non-string keys and values are implicitly converted to strings. @@ -1123,7 +1154,7 @@ ConfigParser Objects .. method:: getfloat(section, option, *, raw=False, vars=None[, fallback]) A convenience method which coerces the *option* in the specified *section* - to a floating point number. See :meth:`get` for explanation of *raw*, + to a floating-point number. See :meth:`get` for explanation of *raw*, *vars* and *fallback*. diff --git a/Doc/library/constants.rst b/Doc/library/constants.rst index 93a7244f..3eceecc4 100644 --- a/Doc/library/constants.rst +++ b/Doc/library/constants.rst @@ -79,6 +79,8 @@ A small number of constants live in the built-in namespace. They are: :exc:`SyntaxError`), so they can be considered "true" constants. +.. _site-consts: + Constants added by the :mod:`site` module ----------------------------------------- @@ -94,6 +96,13 @@ should not be used in programs. (i.e. EOF) to exit", and when called, raise :exc:`SystemExit` with the specified exit code. +.. data:: help + :noindex: + + Object that when printed, prints the message "Type help() for interactive + help, or help(object) for help about object.", and when called, + acts as described :func:`elsewhere `. + .. data:: copyright credits diff --git a/Doc/library/contextlib.rst b/Doc/library/contextlib.rst index 27cf9944..f5b34944 100644 --- a/Doc/library/contextlib.rst +++ b/Doc/library/contextlib.rst @@ -322,7 +322,7 @@ Functions and classes provided: .. versionchanged:: 3.12 ``suppress`` now supports suppressing exceptions raised as - part of an :exc:`BaseExceptionGroup`. + part of a :exc:`BaseExceptionGroup`. .. function:: redirect_stdout(new_target) diff --git a/Doc/library/contextvars.rst b/Doc/library/contextvars.rst index 8ae386b4..2a79dfe8 100644 --- a/Doc/library/contextvars.rst +++ b/Doc/library/contextvars.rst @@ -15,7 +15,7 @@ function and the :class:`~contextvars.Context` class should be used to manage the current context in asynchronous frameworks. Context managers that have state should use Context Variables -instead of :func:`threading.local()` to prevent their state from +instead of :func:`threading.local` to prevent their state from bleeding to other code unexpectedly, when used in concurrent code. See also :pep:`567` for additional details. @@ -146,7 +146,7 @@ Manual Context Management Every thread will have a different top-level :class:`~contextvars.Context` object. This means that a :class:`ContextVar` object behaves in a similar - fashion to :func:`threading.local()` when values are assigned in different + fashion to :func:`threading.local` when values are assigned in different threads. Context implements the :class:`collections.abc.Mapping` interface. @@ -254,7 +254,7 @@ client:: # without passing it explicitly to this function. client_addr = client_addr_var.get() - return f'Good bye, client @ {client_addr}\n'.encode() + return f'Good bye, client @ {client_addr}\r\n'.encode() async def handle_request(reader, writer): addr = writer.transport.get_extra_info('socket').getpeername() @@ -268,9 +268,10 @@ client:: print(line) if not line.strip(): break - writer.write(line) - writer.write(render_goodbye()) + writer.write(b'HTTP/1.1 200 OK\r\n') # status line + writer.write(b'\r\n') # headers + writer.write(render_goodbye()) # body writer.close() async def main(): @@ -282,5 +283,6 @@ client:: asyncio.run(main()) - # To test it you can use telnet: + # To test it you can use telnet or curl: # telnet 127.0.0.1 8081 + # curl 127.0.0.1:8081 diff --git a/Doc/library/csv.rst b/Doc/library/csv.rst index 533cdf13..8e432078 100644 --- a/Doc/library/csv.rst +++ b/Doc/library/csv.rst @@ -365,6 +365,12 @@ The :mod:`csv` module defines the following constants: .. versionadded:: 3.12 +.. note:: + + Due to a bug, constants :data:`QUOTE_NOTNULL` and :data:`QUOTE_STRINGS` + do not affect behaviour of :class:`reader` objects. + This bug is fixed in Python 3.13. + The :mod:`csv` module defines the following exception: diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index e01bd927..4b5c8f8b 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -51,7 +51,7 @@ function call fails. Here are some examples for Windows. Note that ``msvcrt`` is the MS standard C -library containing most standard C functions, and uses the cdecl calling +library containing most standard C functions, and uses the ``cdecl`` calling convention:: >>> from ctypes import * @@ -107,7 +107,7 @@ Functions are accessed as attributes of dll objects:: Note that win32 system dlls like ``kernel32`` and ``user32`` often export ANSI as well as UNICODE versions of a function. The UNICODE version is exported with -an ``W`` appended to the name, while the ANSI version is exported with an ``A`` +a ``W`` appended to the name, while the ANSI version is exported with an ``A`` appended to the name. The win32 ``GetModuleHandle`` function, which returns a *module handle* for a given module name, has the following C prototype, and a macro is used to expose one of them as ``GetModuleHandle`` depending on whether @@ -383,7 +383,7 @@ as calling functions with a fixed number of parameters. On some platforms, and i particular ARM64 for Apple Platforms, the calling convention for variadic functions is different than that for regular functions. -On those platforms it is required to specify the :attr:`~_FuncPtr.argtypes` +On those platforms it is required to specify the :attr:`~_CFuncPtr.argtypes` attribute for the regular, non-variadic, function arguments: .. code-block:: python3 @@ -391,7 +391,7 @@ attribute for the regular, non-variadic, function arguments: libc.printf.argtypes = [ctypes.c_char_p] Because specifying the attribute does not inhibit portability it is advised to always -specify :attr:`~_FuncPtr.argtypes` for all variadic functions. +specify :attr:`~_CFuncPtr.argtypes` for all variadic functions. .. _ctypes-calling-functions-with-own-custom-data-types: @@ -426,9 +426,9 @@ Specifying the required argument types (function prototypes) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ It is possible to specify the required argument types of functions exported from -DLLs by setting the :attr:`~_FuncPtr.argtypes` attribute. +DLLs by setting the :attr:`~_CFuncPtr.argtypes` attribute. -:attr:`~_FuncPtr.argtypes` must be a sequence of C data types (the :func:`!printf` function is +:attr:`~_CFuncPtr.argtypes` must be a sequence of C data types (the :func:`!printf` function is probably not a good example here, because it takes a variable number and different types of parameters depending on the format string, on the other hand this is quite handy to experiment with this feature):: @@ -453,7 +453,7 @@ prototype for a C function), and tries to convert the arguments to valid types:: If you have defined your own classes which you pass to function calls, you have to implement a :meth:`~_CData.from_param` class method for them to be able to use them -in the :attr:`~_FuncPtr.argtypes` sequence. The :meth:`~_CData.from_param` class method receives +in the :attr:`~_CFuncPtr.argtypes` sequence. The :meth:`~_CData.from_param` class method receives the Python object passed to the function call, it should do a typecheck or whatever is needed to make sure this object is acceptable, and then return the object itself, its :attr:`!_as_parameter_` attribute, or whatever you want to @@ -476,7 +476,7 @@ Return types By default functions are assumed to return the C :c:expr:`int` type. Other -return types can be specified by setting the :attr:`~_FuncPtr.restype` attribute of the +return types can be specified by setting the :attr:`~_CFuncPtr.restype` attribute of the function object. The C prototype of :c:func:`time` is ``time_t time(time_t *)``. Because :c:type:`time_t` @@ -485,7 +485,7 @@ specify the :attr:`!restype` attribute:: >>> libc.time.restype = c_time_t -The argument types can be specified using :attr:`~_FuncPtr.argtypes`:: +The argument types can be specified using :attr:`~_CFuncPtr.argtypes`:: >>> libc.time.argtypes = (POINTER(c_time_t),) @@ -508,7 +508,7 @@ a string pointer and a char, and returns a pointer to a string:: >>> If you want to avoid the :func:`ord("x") ` calls above, you can set the -:attr:`~_FuncPtr.argtypes` attribute, and the second argument will be converted from a +:attr:`~_CFuncPtr.argtypes` attribute, and the second argument will be converted from a single character Python bytes object into a C char: .. doctest:: @@ -527,7 +527,7 @@ single character Python bytes object into a C char: >>> You can also use a callable Python object (a function or a class for example) as -the :attr:`~_FuncPtr.restype` attribute, if the foreign function returns an integer. The +the :attr:`~_CFuncPtr.restype` attribute, if the foreign function returns an integer. The callable will be called with the *integer* the C function returns, and the result of this call will be used as the result of your function call. This is useful to check for error return values and automatically raise an exception:: @@ -555,7 +555,7 @@ get the string representation of an error code, and *returns* an exception. :func:`GetLastError` to retrieve it. Please note that a much more powerful error checking mechanism is available -through the :attr:`~_FuncPtr.errcheck` attribute; +through the :attr:`~_CFuncPtr.errcheck` attribute; see the reference manual for details. @@ -855,7 +855,7 @@ Type conversions ^^^^^^^^^^^^^^^^ Usually, ctypes does strict type checking. This means, if you have -``POINTER(c_int)`` in the :attr:`~_FuncPtr.argtypes` list of a function or as the type of +``POINTER(c_int)`` in the :attr:`~_CFuncPtr.argtypes` list of a function or as the type of a member field in a structure definition, only instances of exactly the same type are accepted. There are some exceptions to this rule, where ctypes accepts other objects. For example, you can pass compatible array instances instead of @@ -876,7 +876,7 @@ pointer types. So, for ``POINTER(c_int)``, ctypes accepts an array of c_int:: >>> In addition, if a function argument is explicitly declared to be a pointer type -(such as ``POINTER(c_int)``) in :attr:`~_FuncPtr.argtypes`, an object of the pointed +(such as ``POINTER(c_int)``) in :attr:`~_CFuncPtr.argtypes`, an object of the pointed type (``c_int`` in this case) can be passed to the function. ctypes will apply the required :func:`byref` conversion in this case automatically. @@ -1390,13 +1390,15 @@ way is to instantiate one of the following classes: .. class:: OleDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=None) - Windows only: Instances of this class represent loaded shared libraries, + Instances of this class represent loaded shared libraries, functions in these libraries use the ``stdcall`` calling convention, and are assumed to return the windows specific :class:`HRESULT` code. :class:`HRESULT` values contain information specifying whether the function call failed or succeeded, together with additional error code. If the return value signals a failure, an :class:`OSError` is automatically raised. + .. availability:: Windows + .. versionchanged:: 3.3 :exc:`WindowsError` used to be raised, which is now an alias of :exc:`OSError`. @@ -1408,14 +1410,17 @@ way is to instantiate one of the following classes: .. class:: WinDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=None) - Windows only: Instances of this class represent loaded shared libraries, + Instances of this class represent loaded shared libraries, functions in these libraries use the ``stdcall`` calling convention, and are assumed to return :c:expr:`int` by default. + .. availability:: Windows + .. versionchanged:: 3.12 The *name* parameter can now be a :term:`path-like object`. + The Python :term:`global interpreter lock` is released before calling any function exported by these libraries, and reacquired afterwards. @@ -1551,13 +1556,17 @@ These prefabricated library loaders are available: .. data:: windll :noindex: - Windows only: Creates :class:`WinDLL` instances. + Creates :class:`WinDLL` instances. + + .. availability:: Windows .. data:: oledll :noindex: - Windows only: Creates :class:`OleDLL` instances. + Creates :class:`OleDLL` instances. + + .. availability:: Windows .. data:: pydll @@ -1604,10 +1613,20 @@ As explained in the previous section, foreign functions can be accessed as attributes of loaded shared libraries. The function objects created in this way by default accept any number of arguments, accept any ctypes data instances as arguments, and return the default result type specified by the library loader. -They are instances of a private class: +They are instances of a private local class :class:`!_FuncPtr` (not exposed +in :mod:`!ctypes`) which inherits from the private :class:`_CFuncPtr` class: + +.. doctest:: + + >>> import ctypes + >>> lib = ctypes.CDLL(None) + >>> issubclass(lib._FuncPtr, ctypes._CFuncPtr) + True + >>> lib._FuncPtr is ctypes._CFuncPtr + False -.. class:: _FuncPtr +.. class:: _CFuncPtr Base class for C callable foreign functions. @@ -1719,11 +1738,13 @@ See :ref:`ctypes-callback-functions` for examples. .. function:: WINFUNCTYPE(restype, *argtypes, use_errno=False, use_last_error=False) - Windows only: The returned function prototype creates functions that use the + The returned function prototype creates functions that use the ``stdcall`` calling convention. The function will release the GIL during the call. *use_errno* and *use_last_error* have the same meaning as above. + .. availability:: Windows + .. function:: PYFUNCTYPE(restype, *argtypes) @@ -1773,7 +1794,7 @@ different ways, depending on the type and number of the parameters in the call: The optional *paramflags* parameter creates foreign function wrappers with much more functionality than the features described above. -*paramflags* must be a tuple of the same length as :attr:`~_FuncPtr.argtypes`. +*paramflags* must be a tuple of the same length as :attr:`~_CFuncPtr.argtypes`. Each item in this tuple contains further information about a parameter, it must be a tuple containing one, two, or three items. @@ -1844,7 +1865,7 @@ value if there is a single one, or a tuple containing the output parameter values when there are more than one, so the GetWindowRect function now returns a RECT instance, when called. -Output parameters can be combined with the :attr:`~_FuncPtr.errcheck` protocol to do +Output parameters can be combined with the :attr:`~_CFuncPtr.errcheck` protocol to do further output processing and error checking. The win32 ``GetWindowRect`` api function returns a ``BOOL`` to signal success or failure, so this function could do the error checking, and raises an exception when the api call failed:: @@ -1857,7 +1878,7 @@ do the error checking, and raises an exception when the api call failed:: >>> GetWindowRect.errcheck = errcheck >>> -If the :attr:`~_FuncPtr.errcheck` function returns the argument tuple it receives +If the :attr:`~_CFuncPtr.errcheck` function returns the argument tuple it receives unchanged, :mod:`ctypes` continues the normal processing it does on the output parameters. If you want to return a tuple of window coordinates instead of a ``RECT`` instance, you can retrieve the fields in the function and return them @@ -1949,17 +1970,21 @@ Utility functions .. function:: DllCanUnloadNow() - Windows only: This function is a hook which allows implementing in-process + This function is a hook which allows implementing in-process COM servers with ctypes. It is called from the DllCanUnloadNow function that the _ctypes extension dll exports. + .. availability:: Windows + .. function:: DllGetClassObject() - Windows only: This function is a hook which allows implementing in-process + This function is a hook which allows implementing in-process COM servers with ctypes. It is called from the DllGetClassObject function that the ``_ctypes`` extension dll exports. + .. availability:: Windows + .. function:: find_library(name) :module: ctypes.util @@ -1975,7 +2000,7 @@ Utility functions .. function:: find_msvcrt() :module: ctypes.util - Windows only: return the filename of the VC runtime library used by Python, + Returns the filename of the VC runtime library used by Python, and by the extension modules. If the name of the library cannot be determined, ``None`` is returned. @@ -1983,20 +2008,27 @@ Utility functions with a call to the ``free(void *)``, it is important that you use the function in the same library that allocated the memory. + .. availability:: Windows + .. function:: FormatError([code]) - Windows only: Returns a textual description of the error code *code*. If no + Returns a textual description of the error code *code*. If no error code is specified, the last error code is used by calling the Windows api function GetLastError. + .. availability:: Windows + .. function:: GetLastError() - Windows only: Returns the last error code set by Windows in the calling thread. + Returns the last error code set by Windows in the calling thread. This function calls the Windows ``GetLastError()`` function directly, it does not return the ctypes-private copy of the error code. + .. availability:: Windows + + .. function:: get_errno() Returns the current value of the ctypes-private copy of the system @@ -2006,11 +2038,14 @@ Utility functions .. function:: get_last_error() - Windows only: returns the current value of the ctypes-private copy of the system + Returns the current value of the ctypes-private copy of the system :data:`!LastError` variable in the calling thread. + .. availability:: Windows + .. audit-event:: ctypes.get_last_error "" ctypes.get_last_error + .. function:: memmove(dst, src, count) Same as the standard C memmove library function: copies *count* bytes from @@ -2059,10 +2094,12 @@ Utility functions .. function:: set_last_error(value) - Windows only: set the current value of the ctypes-private copy of the system + Sets the current value of the ctypes-private copy of the system :data:`!LastError` variable in the calling thread to *value* and return the previous value. + .. availability:: Windows + .. audit-event:: ctypes.set_last_error error ctypes.set_last_error @@ -2083,12 +2120,14 @@ Utility functions .. function:: WinError(code=None, descr=None) - Windows only: this function is probably the worst-named thing in ctypes. It + This function is probably the worst-named thing in ctypes. It creates an instance of :exc:`OSError`. If *code* is not specified, ``GetLastError`` is called to determine the error code. If *descr* is not specified, :func:`FormatError` is called to get a textual description of the error. + .. availability:: Windows + .. versionchanged:: 3.3 An instance of :exc:`WindowsError` used to be created, which is now an alias of :exc:`OSError`. @@ -2157,7 +2196,7 @@ Data types This method adapts *obj* to a ctypes type. It is called with the actual object used in a foreign function call when the type is present in the - foreign function's :attr:`~_FuncPtr.argtypes` tuple; + foreign function's :attr:`~_CFuncPtr.argtypes` tuple; it must return an object that can be used as a function call parameter. All ctypes data types have a default implementation of this classmethod @@ -2223,7 +2262,7 @@ Fundamental data types Fundamental data types, when returned as foreign function call results, or, for example, by retrieving structure field members or array items, are transparently converted to native Python types. In other words, if a foreign function has a -:attr:`~_FuncPtr.restype` of :class:`c_char_p`, you will always receive a Python bytes +:attr:`~_CFuncPtr.restype` of :class:`c_char_p`, you will always receive a Python bytes object, *not* a :class:`c_char_p` instance. .. XXX above is false, it actually returns a Unicode string @@ -2428,9 +2467,11 @@ These are the fundamental ctypes data types: .. class:: HRESULT - Windows only: Represents a :c:type:`!HRESULT` value, which contains success or + Represents a :c:type:`!HRESULT` value, which contains success or error information for a function or method call. + .. availability:: Windows + .. class:: py_object diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst index e4a9cd4e..87b532fb 100644 --- a/Doc/library/dataclasses.rst +++ b/Doc/library/dataclasses.rst @@ -124,7 +124,7 @@ Module contents - *unsafe_hash*: If ``False`` (the default), a :meth:`~object.__hash__` method is generated according to how *eq* and *frozen* are set. - :meth:`!__hash__` is used by built-in :meth:`hash()`, and when objects are + :meth:`!__hash__` is used by built-in :meth:`hash`, and when objects are added to hashed collections such as dictionaries and sets. Having a :meth:`!__hash__` implies that instances of the class are immutable. Mutability is a complicated property that depends on the programmer's @@ -185,10 +185,21 @@ Module contents - *slots*: If true (the default is ``False``), :attr:`~object.__slots__` attribute will be generated and new class will be returned instead of the original one. If :attr:`!__slots__` is already defined in the class, then :exc:`TypeError` - is raised. Calling no-arg :func:`super` in dataclasses using ``slots=True`` will result in - the following exception being raised: - ``TypeError: super(type, obj): obj must be an instance or subtype of type``. - The two-arg :func:`super` is a valid workaround. See :gh:`90562` for full details. + is raised. + + .. warning:: + Calling no-arg :func:`super` in dataclasses using ``slots=True`` + will result in the following exception being raised: + ``TypeError: super(type, obj): obj must be an instance or subtype of type``. + The two-arg :func:`super` is a valid workaround. + See :gh:`90562` for full details. + + .. warning:: + Passing parameters to a base class :meth:`~object.__init_subclass__` + when using ``slots=True`` will result in a :exc:`TypeError`. + Either use ``__init_subclass__`` with no parameters + or use default values as a workaround. + See :gh:`91126` for full details. .. versionadded:: 3.10 @@ -204,7 +215,8 @@ Module contents - *weakref_slot*: If true (the default is ``False``), add a slot named "__weakref__", which is required to make an instance - weakref-able. It is an error to specify ``weakref_slot=True`` + :func:`weakref-able `. + It is an error to specify ``weakref_slot=True`` without also specifying ``slots=True``. .. versionadded:: 3.11 diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst index 4ba9d6df..54ab05e4 100644 --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -48,7 +48,7 @@ Aware and Naive Objects ----------------------- Date and time objects may be categorized as "aware" or "naive" depending on -whether or not they include timezone information. +whether or not they include time zone information. With sufficient knowledge of applicable algorithmic and political time adjustments, such as time zone and daylight saving time information, @@ -58,7 +58,7 @@ interpretation. [#]_ A **naive** object does not contain enough information to unambiguously locate itself relative to other date/time objects. Whether a naive object represents -Coordinated Universal Time (UTC), local time, or time in some other timezone is +Coordinated Universal Time (UTC), local time, or time in some other time zone is purely up to the program, just like it is up to the program whether a particular number represents metres, miles, or mass. Naive objects are easy to understand and to work with, at the cost of ignoring some aspects of reality. @@ -70,9 +70,9 @@ These :class:`tzinfo` objects capture information about the offset from UTC time, the time zone name, and whether daylight saving time is in effect. Only one concrete :class:`tzinfo` class, the :class:`timezone` class, is -supplied by the :mod:`!datetime` module. The :class:`timezone` class can -represent simple timezones with fixed offsets from UTC, such as UTC itself or -North American EST and EDT timezones. Supporting timezones at deeper levels of +supplied by the :mod:`!datetime` module. The :class:`!timezone` class can +represent simple time zones with fixed offsets from UTC, such as UTC itself or +North American EST and EDT time zones. Supporting time zones at deeper levels of detail is up to the application. The rules for time adjustment across the world are more political than rational, change frequently, and there is no standard suitable for every application aside from UTC. @@ -95,7 +95,7 @@ The :mod:`!datetime` module exports the following constants: .. attribute:: UTC - Alias for the UTC timezone singleton :attr:`datetime.timezone.utc`. + Alias for the UTC time zone singleton :attr:`datetime.timezone.utc`. .. versionadded:: 3.11 @@ -180,19 +180,19 @@ Objects of the :class:`date` type are always naive. An object of type :class:`.time` or :class:`.datetime` may be aware or naive. -A :class:`.datetime` object *d* is aware if both of the following hold: +A :class:`.datetime` object ``d`` is aware if both of the following hold: 1. ``d.tzinfo`` is not ``None`` 2. ``d.tzinfo.utcoffset(d)`` does not return ``None`` -Otherwise, *d* is naive. +Otherwise, ``d`` is naive. -A :class:`.time` object *t* is aware if both of the following hold: +A :class:`.time` object ``t`` is aware if both of the following hold: 1. ``t.tzinfo`` is not ``None`` 2. ``t.tzinfo.utcoffset(None)`` does not return ``None``. -Otherwise, *t* is naive. +Otherwise, ``t`` is naive. The distinction between aware and naive doesn't apply to :class:`timedelta` objects. @@ -283,17 +283,37 @@ Class attributes: Note that, because of normalization, ``timedelta.max`` is greater than ``-timedelta.min``. ``-timedelta.max`` is not representable as a :class:`timedelta` object. + Instance attributes (read-only): -+------------------+--------------------------------------------+ -| Attribute | Value | -+==================+============================================+ -| ``days`` | Between -999999999 and 999999999 inclusive | -+------------------+--------------------------------------------+ -| ``seconds`` | Between 0 and 86399 inclusive | -+------------------+--------------------------------------------+ -| ``microseconds`` | Between 0 and 999999 inclusive | -+------------------+--------------------------------------------+ +.. attribute:: timedelta.days + + Between -999,999,999 and 999,999,999 inclusive. + + +.. attribute:: timedelta.seconds + + Between 0 and 86,399 inclusive. + + .. caution:: + + It is a somewhat common bug for code to unintentionally use this attribute + when it is actually intended to get a :meth:`~timedelta.total_seconds` + value instead: + + .. doctest:: + + >>> from datetime import timedelta + >>> duration = timedelta(seconds=11235813) + >>> duration.days, duration.seconds + (130, 3813) + >>> duration.total_seconds() + 11235813.0 + +.. attribute:: timedelta.microseconds + + Between 0 and 999,999 inclusive. + Supported operations: @@ -338,14 +358,14 @@ Supported operations: +--------------------------------+-----------------------------------------------+ | ``q, r = divmod(t1, t2)`` | Computes the quotient and the remainder: | | | ``q = t1 // t2`` (3) and ``r = t1 % t2``. | -| | q is an integer and r is a :class:`timedelta` | -| | object. | +| | ``q`` is an integer and ``r`` is a | +| | :class:`timedelta` object. | +--------------------------------+-----------------------------------------------+ | ``+t1`` | Returns a :class:`timedelta` object with the | | | same value. (2) | +--------------------------------+-----------------------------------------------+ | ``-t1`` | Equivalent to ``timedelta(-t1.days, | -| | -t1.seconds*, -t1.microseconds)``, | +| | -t1.seconds, -t1.microseconds)``, | | | and to ``t1 * -1``. (1)(4) | +--------------------------------+-----------------------------------------------+ | ``abs(t)`` | Equivalent to ``+t`` when ``t.days >= 0``, | @@ -506,7 +526,7 @@ Other constructors, all class methods: January 1 of year 1 has ordinal 1. :exc:`ValueError` is raised unless ``1 <= ordinal <= - date.max.toordinal()``. For any date *d*, + date.max.toordinal()``. For any date ``d``, ``date.fromordinal(d.toordinal()) == d``. @@ -658,7 +678,7 @@ Instance methods: .. method:: date.toordinal() Return the proleptic Gregorian ordinal of the date, where January 1 of year 1 - has ordinal 1. For any :class:`date` object *d*, + has ordinal 1. For any :class:`date` object ``d``, ``date.fromordinal(d.toordinal()) == d``. @@ -710,7 +730,7 @@ Instance methods: .. method:: date.__str__() - For a date *d*, ``str(d)`` is equivalent to ``d.isoformat()``. + For a date ``d``, ``str(d)`` is equivalent to ``d.isoformat()``. .. method:: date.ctime() @@ -850,7 +870,7 @@ Other constructors, all class methods: .. classmethod:: datetime.today() - Return the current local datetime, with :attr:`.tzinfo` ``None``. + Return the current local date and time, with :attr:`.tzinfo` ``None``. Equivalent to:: @@ -876,6 +896,10 @@ Other constructors, all class methods: This function is preferred over :meth:`today` and :meth:`utcnow`. + .. note:: + + Subsequent calls to :meth:`!datetime.now` may return the same + instant depending on the precision of the underlying clock. .. classmethod:: datetime.utcnow() @@ -987,7 +1011,7 @@ Other constructors, all class methods: is used. If the *date* argument is a :class:`.datetime` object, its time components and :attr:`.tzinfo` attributes are ignored. - For any :class:`.datetime` object *d*, + For any :class:`.datetime` object ``d``, ``d == datetime.combine(d.date(), d.time(), d.tzinfo)``. .. versionchanged:: 3.6 @@ -1034,7 +1058,7 @@ Other constructors, all class methods: .. versionadded:: 3.7 .. versionchanged:: 3.11 Previously, this method only supported formats that could be emitted by - :meth:`date.isoformat()` or :meth:`datetime.isoformat()`. + :meth:`date.isoformat` or :meth:`datetime.isoformat`. .. classmethod:: datetime.fromisocalendar(year, week, day) @@ -1051,7 +1075,7 @@ Other constructors, all class methods: Return a :class:`.datetime` corresponding to *date_string*, parsed according to *format*. - If *format* does not contain microseconds or timezone information, this is equivalent to:: + If *format* does not contain microseconds or time zone information, this is equivalent to:: datetime(*(time.strptime(date_string, format)[0:6])) @@ -1176,11 +1200,11 @@ Supported operations: If both are naive, or both are aware and have the same :attr:`~.datetime.tzinfo` attribute, the :attr:`~.datetime.tzinfo` attributes are ignored, and the result is a :class:`timedelta` - object *t* such that ``datetime2 + t == datetime1``. No time zone adjustments + object ``t`` such that ``datetime2 + t == datetime1``. No time zone adjustments are done in this case. If both are aware and have different :attr:`~.datetime.tzinfo` attributes, ``a-b`` acts - as if *a* and *b* were first converted to naive UTC datetimes. The + as if ``a`` and ``b`` were first converted to naive UTC datetimes. The result is ``(a.replace(tzinfo=None) - a.utcoffset()) - (b.replace(tzinfo=None) - b.utcoffset())`` except that the implementation never overflows. @@ -1267,22 +1291,22 @@ Instance methods: If provided, *tz* must be an instance of a :class:`tzinfo` subclass, and its :meth:`utcoffset` and :meth:`dst` methods must not return ``None``. If *self* - is naive, it is presumed to represent time in the system timezone. + is naive, it is presumed to represent time in the system time zone. If called without arguments (or with ``tz=None``) the system local - timezone is assumed for the target timezone. The ``.tzinfo`` attribute of the converted + time zone is assumed for the target time zone. The ``.tzinfo`` attribute of the converted datetime instance will be set to an instance of :class:`timezone` with the zone name and offset obtained from the OS. If ``self.tzinfo`` is *tz*, ``self.astimezone(tz)`` is equal to *self*: no adjustment of date or time data is performed. Else the result is local - time in the timezone *tz*, representing the same UTC time as *self*: after + time in the time zone *tz*, representing the same UTC time as *self*: after ``astz = dt.astimezone(tz)``, ``astz - astz.utcoffset()`` will have the same date and time data as ``dt - dt.utcoffset()``. - If you merely want to attach a time zone object *tz* to a datetime *dt* without + If you merely want to attach a :class:`timezone` object *tz* to a datetime *dt* without adjustment of date and time data, use ``dt.replace(tzinfo=tz)``. If you - merely want to remove the time zone object from an aware datetime *dt* without + merely want to remove the :class:`!timezone` object from an aware datetime *dt* without conversion of date and time data, use ``dt.replace(tzinfo=None)``. Note that the default :meth:`tzinfo.fromutc` method can be overridden in a @@ -1292,7 +1316,7 @@ Instance methods: def astimezone(self, tz): if self.tzinfo is tz: return self - # Convert self to UTC, and attach the new time zone object. + # Convert self to UTC, and attach the new timezone object. utc = (self - self.utcoffset()).replace(tzinfo=tz) # Convert from UTC to tz's local time. return tz.fromutc(utc) @@ -1353,11 +1377,11 @@ Instance methods: .. method:: datetime.utctimetuple() - If :class:`.datetime` instance *d* is naive, this is the same as + If :class:`.datetime` instance ``d`` is naive, this is the same as ``d.timetuple()`` except that :attr:`~.time.struct_time.tm_isdst` is forced to 0 regardless of what ``d.dst()`` returns. DST is never in effect for a UTC time. - If *d* is aware, *d* is normalized to UTC time, by subtracting + If ``d`` is aware, ``d`` is normalized to UTC time, by subtracting ``d.utcoffset()``, and a :class:`time.struct_time` for the normalized time is returned. :attr:`!tm_isdst` is forced to 0. Note that an :exc:`OverflowError` may be raised if ``d.year`` was @@ -1406,7 +1430,7 @@ Instance methods: There is no method to obtain the POSIX timestamp directly from a naive :class:`.datetime` instance representing UTC time. If your - application uses this convention and your system timezone is not + application uses this convention and your system time zone is not set to UTC, you can obtain the POSIX timestamp by supplying ``tzinfo=timezone.utc``:: @@ -1505,7 +1529,7 @@ Instance methods: .. method:: datetime.__str__() - For a :class:`.datetime` instance *d*, ``str(d)`` is equivalent to + For a :class:`.datetime` instance ``d``, ``str(d)`` is equivalent to ``d.isoformat(' ')``. @@ -1752,7 +1776,7 @@ Instance attributes (read-only): .. versionadded:: 3.6 :class:`.time` objects support equality and order comparisons, -where *a* is considered less than *b* when *a* precedes *b* in time. +where ``a`` is considered less than ``b`` when ``a`` precedes ``b`` in time. Naive and aware :class:`!time` objects are never equal. Order comparison between naive and aware :class:`!time` objects raises @@ -1817,7 +1841,7 @@ Other constructor: .. versionadded:: 3.7 .. versionchanged:: 3.11 Previously, this method only supported formats that could be emitted by - :meth:`time.isoformat()`. + :meth:`time.isoformat`. Instance methods: @@ -1880,7 +1904,7 @@ Instance methods: .. method:: time.__str__() - For a time *t*, ``str(t)`` is equivalent to ``t.isoformat()``. + For a time ``t``, ``str(t)`` is equivalent to ``t.isoformat()``. .. method:: time.strftime(format) @@ -1974,7 +1998,7 @@ Examples of working with a :class:`.time` object:: supply implementations of the standard :class:`tzinfo` methods needed by the :class:`.datetime` methods you use. The :mod:`!datetime` module provides :class:`timezone`, a simple concrete subclass of :class:`tzinfo` which can - represent timezones with fixed offset from UTC such as UTC itself or North + represent time zones with fixed offset from UTC such as UTC itself or North American EST and EDT. Special requirement for pickling: A :class:`tzinfo` subclass must have an @@ -2099,14 +2123,14 @@ When a :class:`.datetime` object is passed in response to a :class:`.datetime` method, ``dt.tzinfo`` is the same object as *self*. :class:`tzinfo` methods can rely on this, unless user code calls :class:`tzinfo` methods directly. The intent is that the :class:`tzinfo` methods interpret *dt* as being in local -time, and not need worry about objects in other timezones. +time, and not need worry about objects in other time zones. There is one more :class:`tzinfo` method that a subclass may wish to override: .. method:: tzinfo.fromutc(dt) - This is called from the default :class:`datetime.astimezone()` + This is called from the default :meth:`datetime.astimezone` implementation. When called from that, ``dt.tzinfo`` is *self*, and *dt*'s date and time data are to be viewed as expressing a UTC time. The purpose of :meth:`fromutc` is to adjust the date and time data, returning an @@ -2216,12 +2240,12 @@ only EST (fixed offset -5 hours), or only EDT (fixed offset -4 hours)). :mod:`zoneinfo` The :mod:`!datetime` module has a basic :class:`timezone` class (for handling arbitrary fixed offsets from UTC) and its :attr:`timezone.utc` - attribute (a UTC timezone instance). + attribute (a UTC :class:`!timezone` instance). - ``zoneinfo`` brings the *IANA timezone database* (also known as the Olson + ``zoneinfo`` brings the *IANA time zone database* (also known as the Olson database) to Python, and its usage is recommended. - `IANA timezone database `_ + `IANA time zone database `_ The Time Zone Database (often called tz, tzdata or zoneinfo) contains code and data that represent the history of local time for many representative locations around the globe. It is updated periodically to reflect changes @@ -2235,10 +2259,10 @@ only EST (fixed offset -5 hours), or only EDT (fixed offset -4 hours)). ------------------------- The :class:`timezone` class is a subclass of :class:`tzinfo`, each -instance of which represents a timezone defined by a fixed offset from +instance of which represents a time zone defined by a fixed offset from UTC. -Objects of this class cannot be used to represent timezone information in the +Objects of this class cannot be used to represent time zone information in the locations where different offsets are used in different days of the year or where historical changes have been made to civil time. @@ -2299,7 +2323,7 @@ Class attributes: .. attribute:: timezone.utc - The UTC timezone, ``timezone(timedelta(0))``. + The UTC time zone, ``timezone(timedelta(0))``. .. index:: @@ -2508,7 +2532,7 @@ Using ``datetime.strptime(date_string, format)`` is equivalent to:: datetime(*(time.strptime(date_string, format)[0:6])) -except when the format includes sub-second components or timezone offset +except when the format includes sub-second components or time zone offset information, which are supported in ``datetime.strptime`` but are discarded by ``time.strptime``. diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst index 9aa4254a..c5544f62 100644 --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -1,4 +1,4 @@ -:mod:`!decimal` --- Decimal fixed point and floating point arithmetic +:mod:`!decimal` --- Decimal fixed-point and floating-point arithmetic ===================================================================== .. module:: decimal @@ -31,7 +31,7 @@ -------------- The :mod:`decimal` module provides support for fast correctly rounded -decimal floating point arithmetic. It offers several advantages over the +decimal floating-point arithmetic. It offers several advantages over the :class:`float` datatype: * Decimal "is based on a floating-point model which was designed with people @@ -207,7 +207,7 @@ a decimal raises :class:`InvalidOperation`:: .. versionchanged:: 3.3 Decimals interact well with much of the rest of Python. Here is a small decimal -floating point flying circus: +floating-point flying circus: .. doctest:: :options: +NORMALIZE_WHITESPACE @@ -373,7 +373,7 @@ Decimal objects digits, and an integer exponent. For example, ``Decimal((0, (1, 4, 1, 4), -3))`` returns ``Decimal('1.414')``. - If *value* is a :class:`float`, the binary floating point value is losslessly + If *value* is a :class:`float`, the binary floating-point value is losslessly converted to its exact decimal equivalent. This conversion can often require 53 or more digits of precision. For example, ``Decimal(float('1.1'))`` converts to @@ -403,7 +403,7 @@ Decimal objects Underscores are allowed for grouping, as with integral and floating-point literals in code. - Decimal floating point objects share many properties with the other built-in + Decimal floating-point objects share many properties with the other built-in numeric types such as :class:`float` and :class:`int`. All of the usual math operations and special methods apply. Likewise, decimal objects can be copied, pickled, printed, used as dictionary keys, used as set elements, @@ -445,7 +445,7 @@ Decimal objects Mixed-type comparisons between :class:`Decimal` instances and other numeric types are now fully supported. - In addition to the standard numeric properties, decimal floating point + In addition to the standard numeric properties, decimal floating-point objects also have a number of specialized methods: @@ -897,6 +897,48 @@ Decimal objects :const:`Rounded`. If given, applies *rounding*; otherwise, uses the rounding method in either the supplied *context* or the current context. + Decimal numbers can be rounded using the :func:`.round` function: + + .. describe:: round(number) + .. describe:: round(number, ndigits) + + If *ndigits* is not given or ``None``, + returns the nearest :class:`int` to *number*, + rounding ties to even, and ignoring the rounding mode of the + :class:`Decimal` context. Raises :exc:`OverflowError` if *number* is an + infinity or :exc:`ValueError` if it is a (quiet or signaling) NaN. + + If *ndigits* is an :class:`int`, the context's rounding mode is respected + and a :class:`Decimal` representing *number* rounded to the nearest + multiple of ``Decimal('1E-ndigits')`` is returned; in this case, + ``round(number, ndigits)`` is equivalent to + ``self.quantize(Decimal('1E-ndigits'))``. Returns ``Decimal('NaN')`` if + *number* is a quiet NaN. Raises :class:`InvalidOperation` if *number* + is an infinity, a signaling NaN, or if the length of the coefficient after + the quantize operation would be greater than the current context's + precision. In other words, for the non-corner cases: + + * if *ndigits* is positive, return *number* rounded to *ndigits* decimal + places; + * if *ndigits* is zero, return *number* rounded to the nearest integer; + * if *ndigits* is negative, return *number* rounded to the nearest + multiple of ``10**abs(ndigits)``. + + For example:: + + >>> from decimal import Decimal, getcontext, ROUND_DOWN + >>> getcontext().rounding = ROUND_DOWN + >>> round(Decimal('3.75')) # context rounding ignored + 4 + >>> round(Decimal('3.5')) # round-ties-to-even + 4 + >>> round(Decimal('3.75'), 0) # uses the context rounding + Decimal('3') + >>> round(Decimal('3.75'), 1) + Decimal('3.7') + >>> round(Decimal('3.75'), -1) + Decimal('0E+1') + .. _logical_operands_label: @@ -1699,7 +1741,7 @@ The following table summarizes the hierarchy of signals:: .. _decimal-notes: -Floating Point Notes +Floating-Point Notes -------------------- @@ -1712,7 +1754,7 @@ can still incur round-off error when non-zero digits exceed the fixed precision. The effects of round-off error can be amplified by the addition or subtraction of nearly offsetting quantities resulting in loss of significance. Knuth -provides two instructive examples where rounded floating point arithmetic with +provides two instructive examples where rounded floating-point arithmetic with insufficient precision causes the breakdown of the associative and distributive properties of addition: @@ -1802,7 +1844,7 @@ treated as equal and their sign is informational. In addition to the two signed zeros which are distinct yet equal, there are various representations of zero with differing precisions yet equivalent in value. This takes a bit of getting used to. For an eye accustomed to -normalized floating point representations, it is not immediately obvious that +normalized floating-point representations, it is not immediately obvious that the following calculation returns a value equal to zero: >>> 1 / Decimal('Infinity') @@ -2129,7 +2171,7 @@ value unchanged: Q. Is there a way to convert a regular float to a :class:`Decimal`? -A. Yes, any binary floating point number can be exactly expressed as a +A. Yes, any binary floating-point number can be exactly expressed as a Decimal though an exact conversion may take more precision than intuition would suggest: @@ -2183,7 +2225,7 @@ Q. Is the CPython implementation fast for large numbers? A. Yes. In the CPython and PyPy3 implementations, the C/CFFI versions of the decimal module integrate the high speed `libmpdec `_ library for -arbitrary precision correctly rounded decimal floating point arithmetic [#]_. +arbitrary precision correctly rounded decimal floating-point arithmetic [#]_. ``libmpdec`` uses `Karatsuba multiplication `_ for medium-sized numbers and the `Number Theoretic Transform diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index e3920587..f9f82d25 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -850,7 +850,8 @@ iterations of the loop. .. opcode:: GET_LEN - Perform ``STACK.append(len(STACK[-1]))``. + Perform ``STACK.append(len(STACK[-1]))``. Used in :keyword:`match` statements where + comparison with structure of pattern is needed. .. versionadded:: 3.10 @@ -995,11 +996,15 @@ iterations of the loop. .. opcode:: BUILD_TUPLE (count) Creates a tuple consuming *count* items from the stack, and pushes the - resulting tuple onto the stack.:: + resulting tuple onto the stack:: - assert count > 0 - STACK, values = STACK[:-count], STACK[-count:] - STACK.append(tuple(values)) + if count == 0: + value = () + else: + value = tuple(STACK[-count:]) + STACK = STACK[:-count] + + STACK.append(value) .. opcode:: BUILD_LIST (count) @@ -1128,7 +1133,10 @@ iterations of the loop. .. opcode:: COMPARE_OP (opname) Performs a Boolean operation. The operation name can be found in - ``cmp_op[opname]``. + ``cmp_op[opname >> 4]``. + + .. versionchanged:: 3.12 + The cmp_op index is now stored in the four-highest bits of oparg instead of the four-lowest bits of oparg. .. opcode:: IS_OP (invert) @@ -1455,7 +1463,7 @@ iterations of the loop. end = STACK.pop() start = STACK.pop() - STACK.append(slice(start, stop)) + STACK.append(slice(start, end)) if it is 3, implements:: @@ -1592,7 +1600,7 @@ iterations of the loop. | ``INTRINSIC_STOPITERATION_ERROR`` | Extracts the return value from a | | | ``StopIteration`` exception. | +-----------------------------------+-----------------------------------+ - | ``INTRINSIC_ASYNC_GEN_WRAP`` | Wraps an aync generator value | + | ``INTRINSIC_ASYNC_GEN_WRAP`` | Wraps an async generator value | +-----------------------------------+-----------------------------------+ | ``INTRINSIC_UNARY_POSITIVE`` | Performs the unary ``+`` | | | operation | diff --git a/Doc/library/distutils.rst b/Doc/library/distutils.rst new file mode 100644 index 00000000..af63e035 --- /dev/null +++ b/Doc/library/distutils.rst @@ -0,0 +1,17 @@ +:mod:`!distutils` --- Building and installing Python modules +============================================================ + +.. module:: distutils + :synopsis: Removed in 3.12. + :deprecated: + +.. deprecated-removed:: 3.10 3.12 + +This module is no longer part of the Python standard library. +It was :ref:`removed in Python 3.12 ` after +being deprecated in Python 3.10. The removal was decided in :pep:`632`, +which has `migration advice +`_. + +The last version of Python that provided the :mod:`!distutils` module was +`Python 3.11 `_. diff --git a/Doc/library/email.compat32-message.rst b/Doc/library/email.compat32-message.rst index c4c322a8..4285c436 100644 --- a/Doc/library/email.compat32-message.rst +++ b/Doc/library/email.compat32-message.rst @@ -7,6 +7,7 @@ :synopsis: The base class representing email messages in a fashion backward compatible with Python 3.2 :noindex: + :no-index: The :class:`Message` class is very similar to the @@ -104,7 +105,7 @@ Here are the methods of the :class:`Message` class: .. method:: __str__() - Equivalent to :meth:`.as_string()`. Allows ``str(msg)`` to produce a + Equivalent to :meth:`.as_string`. Allows ``str(msg)`` to produce a string containing the formatted message. @@ -142,7 +143,7 @@ Here are the methods of the :class:`Message` class: .. method:: __bytes__() - Equivalent to :meth:`.as_bytes()`. Allows ``bytes(msg)`` to produce a + Equivalent to :meth:`.as_bytes`. Allows ``bytes(msg)`` to produce a bytes object containing the formatted message. .. versionadded:: 3.4 diff --git a/Doc/library/email.contentmanager.rst b/Doc/library/email.contentmanager.rst index 34121f8c..a86e2274 100644 --- a/Doc/library/email.contentmanager.rst +++ b/Doc/library/email.contentmanager.rst @@ -58,11 +58,12 @@ * the type itself (``typ``) * the type's fully qualified name (``typ.__module__ + '.' + typ.__qualname__``). - * the type's qualname (``typ.__qualname__``) - * the type's name (``typ.__name__``). + * the type's :attr:`qualname ` (``typ.__qualname__``) + * the type's :attr:`name ` (``typ.__name__``). If none of the above match, repeat all of the checks above for each of - the types in the :term:`MRO` (``typ.__mro__``). Finally, if no other key + the types in the :term:`MRO` (:attr:`typ.__mro__ `). + Finally, if no other key yields a handler, check for a handler for the key ``None``. If there is no handler for ``None``, raise a :exc:`KeyError` for the fully qualified name of the type. diff --git a/Doc/library/email.errors.rst b/Doc/library/email.errors.rst index 33ab4265..f8f43d82 100644 --- a/Doc/library/email.errors.rst +++ b/Doc/library/email.errors.rst @@ -58,6 +58,13 @@ The following exception classes are defined in the :mod:`email.errors` module: :class:`~email.mime.nonmultipart.MIMENonMultipart` (e.g. :class:`~email.mime.image.MIMEImage`). + +.. exception:: HeaderWriteError() + + Raised when an error occurs when the :mod:`~email.generator` outputs + headers. + + .. exception:: MessageDefect() This is the base class for all defects found when parsing email messages. diff --git a/Doc/library/email.header.rst b/Doc/library/email.header.rst index 6e230d5f..219fad0d 100644 --- a/Doc/library/email.header.rst +++ b/Doc/library/email.header.rst @@ -77,7 +77,7 @@ Here is the :class:`Header` class description: The maximum line length can be specified explicitly via *maxlinelen*. For splitting the first line to a shorter value (to account for the field header which isn't included in *s*, e.g. :mailheader:`Subject`) pass in the name of the - field in *header_name*. The default *maxlinelen* is 76, and the default value + field in *header_name*. The default *maxlinelen* is 78, and the default value for *header_name* is ``None``, meaning it is not taken into account for the first line of a long, split header. diff --git a/Doc/library/email.headerregistry.rst b/Doc/library/email.headerregistry.rst index bcbd00c8..7f804493 100644 --- a/Doc/library/email.headerregistry.rst +++ b/Doc/library/email.headerregistry.rst @@ -317,7 +317,7 @@ variant, :attr:`~.BaseHeader.max_count` is set to 1. class. When *use_default_map* is ``True`` (the default), the standard mapping of header names to classes is copied in to the registry during initialization. *base_class* is always the last class in the generated - class's ``__bases__`` list. + class's :class:`~type.__bases__` list. The default mappings are: diff --git a/Doc/library/email.message.rst b/Doc/library/email.message.rst index e9cce1af..71d6e321 100644 --- a/Doc/library/email.message.rst +++ b/Doc/library/email.message.rst @@ -124,7 +124,7 @@ message objects. .. method:: __bytes__() - Equivalent to :meth:`.as_bytes()`. Allows ``bytes(msg)`` to produce a + Equivalent to :meth:`.as_bytes`. Allows ``bytes(msg)`` to produce a bytes object containing the serialized message. diff --git a/Doc/library/email.policy.rst b/Doc/library/email.policy.rst index 83feedf7..51d65dc5 100644 --- a/Doc/library/email.policy.rst +++ b/Doc/library/email.policy.rst @@ -229,6 +229,24 @@ added matters. To illustrate:: .. versionadded:: 3.6 + + .. attribute:: verify_generated_headers + + If ``True`` (the default), the generator will raise + :exc:`~email.errors.HeaderWriteError` instead of writing a header + that is improperly folded or delimited, such that it would + be parsed as multiple headers or joined with adjacent data. + Such headers can be generated by custom header classes or bugs + in the ``email`` module. + + As it's a security feature, this defaults to ``True`` even in the + :class:`~email.policy.Compat32` policy. + For backwards compatible, but unsafe, behavior, it must be set to + ``False`` explicitly. + + .. versionadded:: 3.12.5 + + The following :class:`Policy` method is intended to be called by code using the email library to create policy instances with custom settings: diff --git a/Doc/library/email.utils.rst b/Doc/library/email.utils.rst index 092bfa81..1cb744b5 100644 --- a/Doc/library/email.utils.rst +++ b/Doc/library/email.utils.rst @@ -58,13 +58,18 @@ of the new API. begins with angle brackets, they are stripped off. -.. function:: parseaddr(address) +.. function:: parseaddr(address, *, strict=True) Parse address -- which should be the value of some address-containing field such as :mailheader:`To` or :mailheader:`Cc` -- into its constituent *realname* and *email address* parts. Returns a tuple of that information, unless the parse fails, in which case a 2-tuple of ``('', '')`` is returned. + If *strict* is true, use a strict parser which rejects malformed inputs. + + .. versionchanged:: 3.12.6 + Add *strict* optional parameter and reject malformed inputs by default. + .. function:: formataddr(pair, charset='utf-8') @@ -82,12 +87,15 @@ of the new API. Added the *charset* option. -.. function:: getaddresses(fieldvalues) +.. function:: getaddresses(fieldvalues, *, strict=True) This method returns a list of 2-tuples of the form returned by ``parseaddr()``. *fieldvalues* is a sequence of header field values as might be returned by - :meth:`Message.get_all `. Here's a simple - example that gets all the recipients of a message:: + :meth:`Message.get_all `. + + If *strict* is true, use a strict parser which rejects malformed inputs. + + Here's a simple example that gets all the recipients of a message:: from email.utils import getaddresses @@ -97,6 +105,9 @@ of the new API. resent_ccs = msg.get_all('resent-cc', []) all_recipients = getaddresses(tos + ccs + resent_tos + resent_ccs) + .. versionchanged:: 3.12.6 + Add *strict* optional parameter and reject malformed inputs by default. + .. function:: parsedate(date) @@ -148,7 +159,7 @@ of the new API. Fri, 09 Nov 2001 01:08:47 -0000 - Optional *timeval* if given is a floating point time value as accepted by + Optional *timeval* if given is a floating-point time value as accepted by :func:`time.gmtime` and :func:`time.localtime`, otherwise the current time is used. diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index 10acff61..a4b6a53d 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -44,7 +44,7 @@ using function-call syntax:: ... BLUE = 3 >>> # functional syntax - >>> Color = Enum('Color', ['RED', 'GREEN', 'BLUE']) + >>> Color = Enum('Color', [('RED', 1), ('GREEN', 2), ('BLUE', 3)]) Even though we can use :keyword:`class` syntax to create Enums, Enums are not normal Python classes. See @@ -517,7 +517,7 @@ Data Types ``Flag`` is the same as :class:`Enum`, but its members support the bitwise operators ``&`` (*AND*), ``|`` (*OR*), ``^`` (*XOR*), and ``~`` (*INVERT*); - the results of those operators are members of the enumeration. + the results of those operations are (aliases of) members of the enumeration. .. method:: __contains__(self, value) @@ -560,6 +560,8 @@ Data Types >>> len(white) 3 + .. versionadded:: 3.11 + .. method:: __bool__(self): Returns *True* if any members in flag, *False* otherwise:: diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst index de46518e..537547f6 100644 --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -412,8 +412,8 @@ The following exceptions are the exceptions that are usually raised. represented. This cannot occur for integers (which would rather raise :exc:`MemoryError` than give up). However, for historical reasons, OverflowError is sometimes raised for integers that are outside a required - range. Because of the lack of standardization of floating point exception - handling in C, most floating point operations are not checked. + range. Because of the lack of standardization of floating-point exception + handling in C, most floating-point operations are not checked. .. exception:: RecursionError diff --git a/Doc/library/fileinput.rst b/Doc/library/fileinput.rst index 94a4139f..8f32b11e 100644 --- a/Doc/library/fileinput.rst +++ b/Doc/library/fileinput.rst @@ -47,7 +47,7 @@ Lines are returned with any newlines intact, which means that the last line in a file may not have one. You can control how files are opened by providing an opening hook via the -*openhook* parameter to :func:`fileinput.input` or :class:`FileInput()`. The +*openhook* parameter to :func:`fileinput.input` or :func:`FileInput`. The hook must be a function that takes two arguments, *filename* and *mode*, and returns an accordingly opened file-like object. If *encoding* and/or *errors* are specified, they will be passed to the hook as additional keyword arguments. diff --git a/Doc/library/fractions.rst b/Doc/library/fractions.rst index 42569ec8..11591cb3 100644 --- a/Doc/library/fractions.rst +++ b/Doc/library/fractions.rst @@ -31,7 +31,7 @@ another rational number, or from a string. :class:`Fraction` instance with the same value. The next two versions accept either a :class:`float` or a :class:`decimal.Decimal` instance, and return a :class:`Fraction` instance with exactly the same value. Note that due to the - usual issues with binary floating-point (see :ref:`tut-fp-issues`), the + usual issues with binary floating point (see :ref:`tut-fp-issues`), the argument to ``Fraction(1.1)`` is not exactly equal to 11/10, and so ``Fraction(1.1)`` does *not* return ``Fraction(11, 10)`` as one might expect. (But see the documentation for the :meth:`limit_denominator` method below.) @@ -87,7 +87,7 @@ another rational number, or from a string. .. versionchanged:: 3.9 The :func:`math.gcd` function is now used to normalize the *numerator* - and *denominator*. :func:`math.gcd` always return a :class:`int` type. + and *denominator*. :func:`math.gcd` always returns an :class:`int` type. Previously, the GCD type depended on *numerator* and *denominator*. .. versionchanged:: 3.11 diff --git a/Doc/library/ftplib.rst b/Doc/library/ftplib.rst index 8c39dc00..bb153220 100644 --- a/Doc/library/ftplib.rst +++ b/Doc/library/ftplib.rst @@ -243,7 +243,7 @@ FTP objects Retrieve a file in binary transfer mode. :param str cmd: - An appropriate ``STOR`` command: :samp:`"STOR {filename}"`. + An appropriate ``RETR`` command: :samp:`"RETR {filename}"`. :param callback: A single parameter callable that is called diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 6901c021..d26e79d1 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -57,7 +57,7 @@ are always available. They are listed here in alphabetical order. .. function:: abs(x) Return the absolute value of a number. The argument may be an - integer, a floating point number, or an object implementing + integer, a floating-point number, or an object implementing :meth:`~object.__abs__`. If the argument is a complex number, its magnitude is returned. @@ -161,7 +161,7 @@ are always available. They are listed here in alphabetical order. This function drops you into the debugger at the call site. Specifically, it calls :func:`sys.breakpointhook`, passing ``args`` and ``kws`` straight through. By default, ``sys.breakpointhook()`` calls - :func:`pdb.set_trace()` expecting no arguments. In this case, it is + :func:`pdb.set_trace` expecting no arguments. In this case, it is purely a convenience function so you don't have to explicitly import :mod:`pdb` or type as much code to enter the debugger. However, :func:`sys.breakpointhook` can be set to some other function and @@ -283,9 +283,11 @@ are always available. They are listed here in alphabetical order. :func:`property`. .. versionchanged:: 3.10 - Class methods now inherit the method attributes (``__module__``, - ``__name__``, ``__qualname__``, ``__doc__`` and ``__annotations__``) and - have a new ``__wrapped__`` attribute. + Class methods now inherit the method attributes + (:attr:`~function.__module__`, :attr:`~function.__name__`, + :attr:`~function.__qualname__`, :attr:`~function.__doc__` and + :attr:`~function.__annotations__`) and have a new ``__wrapped__`` + attribute. .. versionchanged:: 3.11 Class methods can no longer wrap other :term:`descriptors ` such as @@ -538,7 +540,7 @@ are always available. They are listed here in alphabetical order. Take two (non-complex) numbers as arguments and return a pair of numbers consisting of their quotient and remainder when using integer division. With mixed operand types, the rules for binary arithmetic operators apply. For - integers, the result is the same as ``(a // b, a % b)``. For floating point + integers, the result is the same as ``(a // b, a % b)``. For floating-point numbers the result is ``(q, a % b)``, where *q* is usually ``math.floor(a / b)`` but may be 1 less than that. In any case ``q * b + a % b`` is very close to *a*, if ``a % b`` is non-zero it has the same sign as *b*, and ``0 @@ -586,6 +588,11 @@ are always available. They are listed here in alphabetical order. :returns: The result of the evaluated expression. :raises: Syntax errors are reported as exceptions. + .. warning:: + + This function executes arbitrary code. Calling it with + user-supplied input may lead to security vulnerabilities. + 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 @@ -632,6 +639,11 @@ are always available. They are listed here in alphabetical order. .. function:: exec(object, globals=None, locals=None, /, *, closure=None) + .. warning:: + + This function executes arbitrary code. Calling it with + user-supplied input may lead to security vulnerabilities. + This function supports dynamic execution of Python code. *object* must be either a string or a code object. If it is a string, the string is parsed as a suite of Python statements which is then executed (unless a syntax error @@ -714,7 +726,7 @@ are always available. They are listed here in alphabetical order. single: NaN single: Infinity - Return a floating point number constructed from a number or a string. + Return a floating-point number constructed from a number or a string. Examples: @@ -755,8 +767,8 @@ are always available. They are listed here in alphabetical order. Case is not significant, so, for example, "inf", "Inf", "INFINITY", and "iNfINity" are all acceptable spellings for positive infinity. - Otherwise, if the argument is an integer or a floating point number, a - floating point number with the same value (within Python's floating point + Otherwise, if the argument is an integer or a floating-point number, a + floating-point number with the same value (within Python's floating-point precision) is returned. If the argument is outside the range of a Python float, an :exc:`OverflowError` will be raised. @@ -983,7 +995,7 @@ are always available. They are listed here in alphabetical order. ``int(x)`` returns ``x.__int__()``. If the argument defines :meth:`~object.__index__`, it returns ``x.__index__()``. If the argument defines :meth:`~object.__trunc__`, it returns ``x.__trunc__()``. - For floating point numbers, this truncates towards zero. + For floating-point numbers, this truncates towards zero. If the argument is not a number or if *base* is given, then it must be a string, :class:`bytes`, or :class:`bytearray` instance representing an integer @@ -1211,14 +1223,16 @@ are always available. They are listed here in alphabetical order. .. class:: object() - Return a new featureless object. :class:`object` is a base for all classes. - It has methods that are common to all instances of Python classes. This - function does not accept any arguments. + This is the ultimate base class of all other classes. It has methods + that are common to all instances of Python classes. When the constructor + is called, it returns a new featureless object. The constructor does not + accept any arguments. .. note:: - :class:`object` does *not* have a :attr:`~object.__dict__`, so you can't - assign arbitrary attributes to an instance of the :class:`object` class. + :class:`object` instances do *not* have :attr:`~object.__dict__` + attributes, so you can't assign arbitrary attributes to an instance of + :class:`object`. .. function:: oct(x) @@ -1267,7 +1281,7 @@ are always available. They are listed here in alphabetical order. (which on *some* Unix systems, means that *all* writes append to the end of the file regardless of the current seek position). In text mode, if *encoding* is not specified the encoding used is platform-dependent: - :func:`locale.getencoding()` is called to get the current locale encoding. + :func:`locale.getencoding` is called to get the current locale encoding. (For reading and writing raw bytes use binary mode and leave *encoding* unspecified.) The available modes are: @@ -1440,7 +1454,7 @@ are always available. They are listed here in alphabetical order. (where :func:`open` is declared), :mod:`os`, :mod:`os.path`, :mod:`tempfile`, and :mod:`shutil`. - .. audit-event:: open file,mode,flags open + .. audit-event:: open path,mode,flags open The ``mode`` and ``flags`` arguments may have been modified or inferred from the original call. @@ -1496,7 +1510,9 @@ are always available. They are listed here in alphabetical order. returns ``100``, but ``pow(10, -2)`` returns ``0.01``. For a negative base of type :class:`int` or :class:`float` and a non-integral exponent, a complex result is delivered. For example, ``pow(-9, 0.5)`` returns a value close - to ``3j``. + to ``3j``. Whereas, for a negative base of type :class:`int` or :class:`float` + with an integral exponent, a float result is delivered. For example, + ``pow(-9, 2.0)`` returns ``81.0``. For :class:`int` operands *base* and *exp*, if *mod* is present, *mod* must also be of integer type and *mod* must be nonzero. If *mod* is present and @@ -1829,10 +1845,11 @@ are always available. They are listed here in alphabetical order. For more information on static methods, see :ref:`types`. .. versionchanged:: 3.10 - Static methods now inherit the method attributes (``__module__``, - ``__name__``, ``__qualname__``, ``__doc__`` and ``__annotations__``), - have a new ``__wrapped__`` attribute, and are now callable as regular - functions. + Static methods now inherit the method attributes + (:attr:`~function.__module__`, :attr:`~function.__name__`, + :attr:`~function.__qualname__`, :attr:`~function.__doc__` and + :attr:`~function.__annotations__`), have a new ``__wrapped__`` attribute, + and are now callable as regular functions. .. index:: @@ -1857,7 +1874,7 @@ are always available. They are listed here in alphabetical order. For some use cases, there are good alternatives to :func:`sum`. The preferred, fast way to concatenate a sequence of strings is by calling - ``''.join(sequence)``. To add floating point values with extended precision, + ``''.join(sequence)``. To add floating-point values with extended precision, see :func:`math.fsum`\. To concatenate a series of iterables, consider using :func:`itertools.chain`. @@ -1879,14 +1896,14 @@ are always available. They are listed here in alphabetical order. to be searched. The search starts from the class right after the *type*. - For example, if :attr:`~class.__mro__` of *object_or_type* is + For example, if :attr:`~type.__mro__` of *object_or_type* is ``D -> B -> C -> A -> object`` and the value of *type* is ``B``, then :func:`super` searches ``C -> A -> object``. - The :attr:`~class.__mro__` attribute of the *object_or_type* lists the method - resolution search order used by both :func:`getattr` and :func:`super`. The - attribute is dynamic and can change whenever the inheritance hierarchy is - updated. + The :attr:`~type.__mro__` attribute of the class corresponding to + *object_or_type* lists the method resolution search order used by both + :func:`getattr` and :func:`super`. The attribute is dynamic and can change + whenever the inheritance hierarchy is updated. If the second argument is omitted, the super object returned is unbound. If the second argument is an object, ``isinstance(obj, type)`` must be true. If @@ -1955,28 +1972,30 @@ are always available. They are listed here in alphabetical order. With one argument, return the type of an *object*. The return value is a type object and generally the same object as returned by - :attr:`object.__class__ `. + :attr:`object.__class__`. The :func:`isinstance` built-in function is recommended for testing the type of an object, because it takes subclasses into account. - With three arguments, return a new type object. This is essentially a dynamic form of the :keyword:`class` statement. The *name* string is - the class name and becomes the :attr:`~definition.__name__` attribute. + the class name and becomes the :attr:`~type.__name__` attribute. The *bases* tuple contains the base classes and becomes the - :attr:`~class.__bases__` attribute; if empty, :class:`object`, the + :attr:`~type.__bases__` attribute; if empty, :class:`object`, the ultimate base of all classes, is added. The *dict* dictionary contains attribute and method definitions for the class body; it may be copied - or wrapped before becoming the :attr:`~object.__dict__` attribute. - The following two statements create identical :class:`type` objects: + or wrapped before becoming the :attr:`~type.__dict__` attribute. + The following two statements create identical :class:`!type` objects: >>> class X: ... a = 1 ... >>> X = type('X', (), dict(a=1)) - See also :ref:`bltin-type-objects`. + See also: + + * :ref:`Documentation on attributes and methods on classes `. + * :ref:`bltin-type-objects` Keyword arguments provided to the three argument form are passed to the appropriate metaclass machinery (usually :meth:`~object.__init_subclass__`) @@ -1986,18 +2005,18 @@ are always available. They are listed here in alphabetical order. See also :ref:`class-customization`. .. versionchanged:: 3.6 - Subclasses of :class:`type` which don't override ``type.__new__`` may no + Subclasses of :class:`!type` which don't override ``type.__new__`` may no longer use the one-argument form to get the type of an object. .. function:: vars() vars(object) Return the :attr:`~object.__dict__` attribute for a module, class, instance, - or any other object with a :attr:`~object.__dict__` attribute. + or any other object with a :attr:`!__dict__` attribute. Objects such as modules and instances have an updateable :attr:`~object.__dict__` attribute; however, other objects may have write restrictions on their - :attr:`~object.__dict__` attributes (for example, classes use a + :attr:`!__dict__` attributes (for example, classes use a :class:`types.MappingProxyType` to prevent direct dictionary updates). Without an argument, :func:`vars` acts like :func:`locals`. Note, the diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst index 655e05f4..4bd2ecd9 100644 --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -34,7 +34,7 @@ The :mod:`functools` module defines the following functions: Returns the same as ``lru_cache(maxsize=None)``, creating a thin wrapper around a dictionary lookup for the function arguments. Because it never needs to evict old values, this is smaller and faster than - :func:`lru_cache()` with a size limit. + :func:`lru_cache` with a size limit. For example:: @@ -218,7 +218,7 @@ The :mod:`functools` module defines the following functions: cache. See :ref:`faq-cache-method-calls` An `LRU (least recently used) cache - `_ + `_ works best when the most recent calls are the best predictors of upcoming calls (for example, the most popular articles on a news server tend to change each day). The cache's size limit assures that the cache does not @@ -490,6 +490,25 @@ The :mod:`functools` module defines the following functions: ... print(arg.real, arg.imag) ... + For code that dispatches on a collections type (e.g., ``list``), but wants + to typehint the items of the collection (e.g., ``list[int]``), the + dispatch type should be passed explicitly to the decorator itself with the + typehint going into the function definition:: + + >>> @fun.register(list) + ... def _(arg: list[int], verbose=False): + ... if verbose: + ... print("Enumerate this:") + ... for i, elem in enumerate(arg): + ... print(i, elem) + + .. note:: + + At runtime the function will dispatch on an instance of a list regardless + of the type contained within the list i.e. ``[1,2,3]`` will be + dispatched the same as ``["foo", "bar", "baz"]``. The annotation + provided in this example is for static type checkers only and has no + runtime impact. To enable registering :term:`lambdas` and pre-existing functions, the :func:`register` attribute can also be used in a functional form:: @@ -644,10 +663,11 @@ The :mod:`functools` module defines the following functions: attributes of the wrapper function are updated with the corresponding attributes from the original function. The default values for these arguments are the module level constants ``WRAPPER_ASSIGNMENTS`` (which assigns to the wrapper - function's ``__module__``, ``__name__``, ``__qualname__``, ``__annotations__``, - ``__type_params__``, and ``__doc__``, the documentation string) - and ``WRAPPER_UPDATES`` (which - updates the wrapper function's ``__dict__``, i.e. the instance dictionary). + function's :attr:`~function.__module__`, :attr:`~function.__name__`, + :attr:`~function.__qualname__`, :attr:`~function.__annotations__`, + :attr:`~function.__type_params__`, and :attr:`~function.__doc__`, the + documentation string) and ``WRAPPER_UPDATES`` (which updates the wrapper + function's :attr:`~function.__dict__`, i.e. the instance dictionary). To allow access to the original function for introspection and other purposes (e.g. bypassing a caching decorator such as :func:`lru_cache`), this function @@ -668,7 +688,7 @@ The :mod:`functools` module defines the following functions: .. versionchanged:: 3.2 The ``__wrapped__`` attribute is now automatically added. - The ``__annotations__`` attribute is now copied by default. + The :attr:`~function.__annotations__` attribute is now copied by default. Missing attributes no longer trigger an :exc:`AttributeError`. .. versionchanged:: 3.4 @@ -677,7 +697,7 @@ The :mod:`functools` module defines the following functions: (see :issue:`17482`) .. versionchanged:: 3.12 - The ``__type_params__`` attribute is now copied by default. + The :attr:`~function.__type_params__` attribute is now copied by default. .. decorator:: wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES) @@ -739,9 +759,10 @@ have three read-only attributes: The keyword arguments that will be supplied when the :class:`partial` object is called. -:class:`partial` objects are like :class:`function` objects in that they are -callable, weak referenceable, and can have attributes. There are some important -differences. For instance, the :attr:`~definition.__name__` and :attr:`__doc__` attributes +:class:`partial` objects are like :ref:`function objects ` +in that they are callable, weak referenceable, and can have attributes. +There are some important differences. For instance, the +:attr:`~function.__name__` and :attr:`function.__doc__` attributes are not created automatically. Also, :class:`partial` objects defined in classes behave like static methods and do not transform into bound methods during instance attribute look-up. diff --git a/Doc/library/getopt.rst b/Doc/library/getopt.rst index ef07ce9d..13f1d964 100644 --- a/Doc/library/getopt.rst +++ b/Doc/library/getopt.rst @@ -92,6 +92,8 @@ exception: An example using only Unix style options: +.. doctest:: + >>> import getopt >>> args = '-a -b -cfoo -d bar a1 a2'.split() >>> args @@ -104,6 +106,8 @@ An example using only Unix style options: Using long option names is equally easy: +.. doctest:: + >>> s = '--condition=foo --testing --output-file abc.def -x a1 a2' >>> args = s.split() >>> args @@ -115,7 +119,9 @@ Using long option names is equally easy: >>> args ['a1', 'a2'] -In a script, typical usage is something like this:: +In a script, typical usage is something like this: + +.. testcode:: import getopt, sys @@ -145,7 +151,9 @@ In a script, typical usage is something like this:: main() Note that an equivalent command line interface could be produced with less code -and more informative help and error messages by using the :mod:`argparse` module:: +and more informative help and error messages by using the :mod:`argparse` module: + +.. testcode:: import argparse diff --git a/Doc/library/getpass.rst b/Doc/library/getpass.rst index b364b1fe..5c0de188 100644 --- a/Doc/library/getpass.rst +++ b/Doc/library/getpass.rst @@ -49,4 +49,4 @@ The :mod:`getpass` module provides two functions: systems which support the :mod:`pwd` module, otherwise, an exception is raised. - In general, this function should be preferred over :func:`os.getlogin()`. + In general, this function should be preferred over :func:`os.getlogin`. diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst index a2fff0f9..30088666 100644 --- a/Doc/library/gzip.rst +++ b/Doc/library/gzip.rst @@ -194,7 +194,9 @@ The module defines the following items: .. versionchanged:: 3.11 Speed is improved by compressing all data at once instead of in a streamed fashion. Calls with *mtime* set to ``0`` are delegated to - :func:`zlib.compress` for better speed. + :func:`zlib.compress` for better speed. In this situation the + output may contain a gzip header "OS" byte value other than 255 + "unknown" as supplied by the underlying zlib implementation. .. function:: decompress(data) diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst index 8f4c42d0..e2881a99 100644 --- a/Doc/library/hashlib.rst +++ b/Doc/library/hashlib.rst @@ -653,7 +653,7 @@ on the hash function used in digital signatures. by the signer. (`NIST SP-800-106 "Randomized Hashing for Digital Signatures" - `_) + `_) In BLAKE2 the salt is processed as a one-time input to the hash function during initialization, rather than as an input to each compression function. @@ -807,8 +807,8 @@ Domain Dedication 1.0 Universal: .. _NIST-SP-800-132: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf .. _stackexchange pbkdf2 iterations question: https://security.stackexchange.com/questions/3959/recommended-of-iterations-when-using-pbkdf2-sha256/ .. _Attacks on cryptographic hash algorithms: https://en.wikipedia.org/wiki/Cryptographic_hash_function#Attacks_on_cryptographic_hash_algorithms -.. _the FIPS 180-4 standard: https://csrc.nist.gov/publications/detail/fips/180/4/final -.. _the FIPS 202 standard: https://csrc.nist.gov/publications/detail/fips/202/final +.. _the FIPS 180-4 standard: https://csrc.nist.gov/pubs/fips/180-4/upd1/final +.. _the FIPS 202 standard: https://csrc.nist.gov/pubs/fips/202/final .. _HACL\* project: https://github.com/hacl-star/hacl-star @@ -825,7 +825,7 @@ Domain Dedication 1.0 Universal: https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.180-4.pdf The FIPS 180-4 publication on Secure Hash Algorithms. - https://csrc.nist.gov/publications/detail/fips/202/final + https://csrc.nist.gov/pubs/fips/202/final The FIPS 202 publication on the SHA-3 Standard. https://www.blake2.net/ diff --git a/Doc/library/http.cookiejar.rst b/Doc/library/http.cookiejar.rst index 31ac8baf..23ddecf8 100644 --- a/Doc/library/http.cookiejar.rst +++ b/Doc/library/http.cookiejar.rst @@ -137,7 +137,7 @@ The following classes are provided: The Netscape protocol with the bugs fixed. Uses :mailheader:`Set-Cookie2` in place of :mailheader:`Set-Cookie`. Not widely used. - http://kristol.org/cookie/errata.html + https://kristol.org/cookie/errata.html Unfinished errata to :rfc:`2965`. :rfc:`2964` - Use of HTTP State Management diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst index fcc314a8..d2e43f03 100644 --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -263,7 +263,7 @@ provides three different variants: Adds a blank line (indicating the end of the HTTP headers in the response) - to the headers buffer and calls :meth:`flush_headers()`. + to the headers buffer and calls :meth:`flush_headers`. .. versionchanged:: 3.2 The buffered headers are written to the output stream. @@ -378,7 +378,7 @@ provides three different variants: If the request was mapped to a file, it is opened. Any :exc:`OSError` exception in opening the requested file is mapped to a ``404``, - ``'File not found'`` error. If there was a ``'If-Modified-Since'`` + ``'File not found'`` error. If there was an ``'If-Modified-Since'`` header in the request, and the file was not modified after this time, a ``304``, ``'Not Modified'`` response is sent. Otherwise, the content type is guessed by calling the :meth:`guess_type` method, which in turn diff --git a/Doc/library/imp.rst b/Doc/library/imp.rst new file mode 100644 index 00000000..3dc4c568 --- /dev/null +++ b/Doc/library/imp.rst @@ -0,0 +1,18 @@ +:mod:`!imp` --- Access the import internals +=========================================== + +.. module:: imp + :synopsis: Removed in 3.12. + :deprecated: + +.. deprecated-removed:: 3.4 3.12 + +This module is no longer part of the Python standard library. +It was :ref:`removed in Python 3.12 ` after +being deprecated in Python 3.4. + +The :ref:`removal notice ` includes guidance for +migrating code from :mod:`!imp` to :mod:`importlib`. + +The last version of Python that provided the :mod:`!imp` module was +`Python 3.11 `_. diff --git a/Doc/library/importlib.metadata.rst b/Doc/library/importlib.metadata.rst index 3f407ba4..289e02cc 100644 --- a/Doc/library/importlib.metadata.rst +++ b/Doc/library/importlib.metadata.rst @@ -100,6 +100,13 @@ You can also get a :ref:`distribution's version number `, list its :ref:`requirements`. +.. exception:: PackageNotFoundError + + Subclass of :class:`ModuleNotFoundError` raised by several functions in this + module when queried for a distribution package which is not installed in the + current Python environment. + + Functional API ============== @@ -111,31 +118,53 @@ This package provides the following functionality via its public API. Entry points ------------ -The ``entry_points()`` function returns a collection of entry points. -Entry points are represented by ``EntryPoint`` instances; -each ``EntryPoint`` has a ``.name``, ``.group``, and ``.value`` attributes and -a ``.load()`` method to resolve the value. There are also ``.module``, -``.attr``, and ``.extras`` attributes for getting the components of the -``.value`` attribute. +.. function:: entry_points(**select_params) + + Returns a :class:`EntryPoints` instance describing entry points for the + current environment. Any given keyword parameters are passed to the + :meth:`!select` method for comparison to the attributes of + the individual entry point definitions. + + Note: it is not currently possible to query for entry points based on + their :attr:`!EntryPoint.dist` attribute (as different :class:`!Distribution` + instances do not currently compare equal, even if they have the same attributes) + +.. class:: EntryPoints + + Details of a collection of installed entry points. + + Also provides a ``.groups`` attribute that reports all identified entry + point groups, and a ``.names`` attribute that reports all identified entry + point names. + +.. class:: EntryPoint + + Details of an installed entry point. + + Each :class:`!EntryPoint` instance has ``.name``, ``.group``, and ``.value`` + attributes and a ``.load()`` method to resolve the value. There are also + ``.module``, ``.attr``, and ``.extras`` attributes for getting the + components of the ``.value`` attribute, and ``.dist`` for obtaining + information regarding the distribution package that provides the entry point. Query all entry points:: >>> eps = entry_points() # doctest: +SKIP -The ``entry_points()`` function returns an ``EntryPoints`` object, -a collection of all ``EntryPoint`` objects with ``names`` and ``groups`` +The :func:`!entry_points` function returns a :class:`!EntryPoints` object, +a collection of all :class:`!EntryPoint` objects with ``names`` and ``groups`` attributes for convenience:: >>> sorted(eps.groups) # doctest: +SKIP ['console_scripts', 'distutils.commands', 'distutils.setup_keywords', 'egg_info.writers', 'setuptools.installation'] -``EntryPoints`` has a ``select`` method to select entry points +:class:`!EntryPoints` has a :meth:`!select` method to select entry points matching specific properties. Select entry points in the ``console_scripts`` group:: >>> scripts = eps.select(group='console_scripts') # doctest: +SKIP -Equivalently, since ``entry_points`` passes keyword arguments +Equivalently, since :func:`!entry_points` passes keyword arguments through to select:: >>> scripts = entry_points(group='console_scripts') # doctest: +SKIP @@ -187,31 +216,41 @@ for compatibility options. Distribution metadata --------------------- -Every `Distribution Package `_ includes some metadata, -which you can extract using the -``metadata()`` function:: +.. function:: metadata(distribution_name) + + Return the distribution metadata corresponding to the named + distribution package as a :class:`PackageMetadata` instance. + + Raises :exc:`PackageNotFoundError` if the named distribution + package is not installed in the current Python environment. + +.. class:: PackageMetadata + + A concrete implementation of the + `PackageMetadata protocol `_. + + In addition to providing the defined protocol methods and attributes, subscripting + the instance is equivalent to calling the :meth:`!get` method. + +Every `Distribution Package `_ +includes some metadata, which you can extract using the :func:`!metadata` function:: >>> wheel_metadata = metadata('wheel') # doctest: +SKIP -The keys of the returned data structure, a ``PackageMetadata``, -name the metadata keywords, and +The keys of the returned data structure name the metadata keywords, and the values are returned unparsed from the distribution metadata:: >>> wheel_metadata['Requires-Python'] # doctest: +SKIP '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*' -``PackageMetadata`` also presents a ``json`` attribute that returns +:class:`PackageMetadata` also presents a :attr:`!json` attribute that returns all the metadata in a JSON-compatible form per :PEP:`566`:: >>> wheel_metadata.json['requires_python'] '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*' -.. note:: - - The actual type of the object returned by ``metadata()`` is an - implementation detail and should be accessed only through the interface - described by the - `PackageMetadata protocol `_. +The full set of available metadata is not described here. +See the PyPA `Core metadata specification `_ for additional details. .. versionchanged:: 3.10 The ``Description`` is now included in the metadata when presented @@ -225,7 +264,15 @@ all the metadata in a JSON-compatible form per :PEP:`566`:: Distribution versions --------------------- -The ``version()`` function is the quickest way to get a +.. function:: version(distribution_name) + + Return the installed distribution package version for the named + distribution package. + + Raises :exc:`PackageNotFoundError` if the named distribution + package is not installed in the current Python environment. + +The :func:`!version` function is the quickest way to get a `Distribution Package `_'s version number, as a string:: @@ -238,12 +285,28 @@ number, as a string:: Distribution files ------------------ -You can also get the full set of files contained within a distribution. The -``files()`` function takes a `Distribution Package `_ name -and returns all of the -files installed by this distribution. Each file object returned is a -``PackagePath``, a :class:`pathlib.PurePath` derived object with additional ``dist``, -``size``, and ``hash`` properties as indicated by the metadata. For example:: +.. function:: files(distribution_name) + + Return the full set of files contained within the named + distribution package. + + Raises :exc:`PackageNotFoundError` if the named distribution + package is not installed in the current Python environment. + + Returns :const:`None` if the distribution is found but the installation + database records reporting the files associated with the distribuion package + are missing. + +.. class:: PackagePath + + A :class:`pathlib.PurePath` derived object with additional ``dist``, + ``size``, and ``hash`` properties corresponding to the distribution + package's installation metadata for that file. + +The :func:`!files` function takes a +`Distribution Package `_ +name and returns all of the files installed by this distribution. Each file is reported +as a :class:`PackagePath` instance. For example:: >>> util = [p for p in files('wheel') if 'util.py' in str(p)][0] # doctest: +SKIP >>> util # doctest: +SKIP @@ -266,16 +329,16 @@ Once you have the file, you can also read its contents:: return s.encode('utf-8') return s -You can also use the ``locate`` method to get a the absolute path to the -file:: +You can also use the :meth:`!locate` method to get the absolute +path to the file:: >>> util.locate() # doctest: +SKIP PosixPath('/home/gustav/example/lib/site-packages/wheel/util.py') In the case where the metadata file listing files -(RECORD or SOURCES.txt) is missing, ``files()`` will -return ``None``. The caller may wish to wrap calls to -``files()`` in `always_iterable +(``RECORD`` or ``SOURCES.txt``) is missing, :func:`!files` will +return :const:`None`. The caller may wish to wrap calls to +:func:`!files` in `always_iterable `_ or otherwise guard against this condition if the target distribution is not known to have the metadata present. @@ -285,8 +348,16 @@ distribution is not known to have the metadata present. Distribution requirements ------------------------- +.. function:: requires(distribution_name) + + Return the declared dependency specifiers for the named + distribution package. + + Raises :exc:`PackageNotFoundError` if the named distribution + package is not installed in the current Python environment. + To get the full set of requirements for a `Distribution Package `_, -use the ``requires()`` +use the :func:`!requires` function:: >>> requires('wheel') # doctest: +SKIP @@ -299,6 +370,16 @@ function:: Mapping import to distribution packages --------------------------------------- +.. function:: packages_distributions() + + Return a mapping from the top level module and import package + names found via :attr:`sys.meta_path` to the names of the distribution + packages (if any) that provide the corresponding files. + + To allow for namespace packages (which may have members provided by + multiple distribution packages), each top level import name maps to a + list of distribution names rather than mapping directly to a single name. + A convenience method to resolve the `Distribution Package `_ name (or names, in the case of a namespace package) that provide each importable top-level @@ -318,23 +399,42 @@ function is not reliable with such installs. Distributions ============= -While the above API is the most common and convenient usage, you can get all -of that information from the ``Distribution`` class. A ``Distribution`` is an -abstract object that represents the metadata for -a Python `Distribution Package `_. You can -get the ``Distribution`` instance:: +.. function:: distribution(distribution_name) + + Return a :class:`Distribution` instance describing the named + distribution package. + + Raises :exc:`PackageNotFoundError` if the named distribution + package is not installed in the current Python environment. + +.. class:: Distribution + + Details of an installed distribution package. + + Note: different :class:`!Distribution` instances do not currently compare + equal, even if they relate to the same installed distribution and + accordingly have the same attributes. + +While the module level API described above is the most common and convenient usage, +you can get all of that information from the :class:`!Distribution` class. +:class:`!Distribution` is an abstract object that represents the metadata for +a Python `Distribution Package `_. +You can get the concreate :class:`!Distribution` subclass instance for an installed +distribution package by calling the :func:`distribution` function:: >>> from importlib.metadata import distribution # doctest: +SKIP >>> dist = distribution('wheel') # doctest: +SKIP + >>> type(dist) # doctest: +SKIP + Thus, an alternative way to get the version number is through the -``Distribution`` instance:: +:class:`!Distribution` instance:: >>> dist.version # doctest: +SKIP '0.32.3' -There are all kinds of additional metadata available on the ``Distribution`` -instance:: +There are all kinds of additional metadata available on :class:`!Distribution` +instances:: >>> dist.metadata['Requires-Python'] # doctest: +SKIP '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*' @@ -342,7 +442,7 @@ instance:: 'MIT' The full set of available metadata is not described here. -See the `Core metadata specifications `_ for additional details. +See the PyPA `Core metadata specification `_ for additional details. Distribution Discovery diff --git a/Doc/library/importlib.resources.abc.rst b/Doc/library/importlib.resources.abc.rst index 5ea8044e..54995ddb 100644 --- a/Doc/library/importlib.resources.abc.rst +++ b/Doc/library/importlib.resources.abc.rst @@ -22,7 +22,7 @@ something like a data file that lives next to the ``__init__.py`` file of the package. The purpose of this class is to help abstract out the accessing of such data files so that it does not matter if - the package and its data file(s) are stored in a e.g. zip file + the package and its data file(s) are stored e.g. in a zip file versus on the file system. For any of methods of this class, a *resource* argument is diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index d92bb2f8..e4e09b09 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -249,7 +249,7 @@ ABC hierarchy:: An abstract method for finding a :term:`spec ` for the specified module. If this is a top-level import, *path* will be ``None``. Otherwise, this is a search for a subpackage or - module and *path* will be the value of :attr:`__path__` from the + module and *path* will be the value of :attr:`~module.__path__` from the parent package. If a spec cannot be found, ``None`` is returned. When passed in, ``target`` is a module object that the finder may use to make a more educated guess about what spec to return. @@ -355,34 +355,12 @@ ABC hierarchy:: (note that some of these attributes can change when a module is reloaded): - - :attr:`__name__` - The module's fully qualified name. - It is ``'__main__'`` for an executed module. - - - :attr:`__file__` - The location the :term:`loader` used to load the module. - For example, for modules loaded from a .py file this is the filename. - It is not set on all modules (e.g. built-in modules). - - - :attr:`__cached__` - The filename of a compiled version of the module's code. - It is not set on all modules (e.g. built-in modules). - - - :attr:`__path__` - The list of locations where the package's submodules will be found. - Most of the time this is a single directory. - The import system passes this attribute to ``__import__()`` and to finders - in the same way as :data:`sys.path` but just for the package. - It is not set on non-package modules so it can be used - as an indicator that the module is a package. - - - :attr:`__package__` - The fully qualified name of the package the module is in (or the - empty string for a top-level module). - If the module is a package then this is the same as :attr:`__name__`. - - - :attr:`__loader__` - The :term:`loader` used to load the module. + - :attr:`module.__name__` + - :attr:`module.__file__` + - :attr:`module.__cached__` + - :attr:`module.__path__` + - :attr:`module.__package__` + - :attr:`module.__loader__` *(deprecated)* When :meth:`exec_module` is available then backwards-compatible functionality is provided. @@ -418,7 +396,8 @@ ABC hierarchy:: can implement this abstract method to give direct access to the data stored. :exc:`OSError` is to be raised if the *path* cannot be found. The *path* is expected to be constructed using a module's - :attr:`__file__` attribute or an item from a package's :attr:`__path__`. + :attr:`~module.__file__` attribute or an item from a package's + :attr:`~module.__path__`. .. versionchanged:: 3.4 Raises :exc:`OSError` instead of :exc:`NotImplementedError`. @@ -505,9 +484,9 @@ ABC hierarchy:: .. abstractmethod:: get_filename(fullname) - An abstract method that is to return the value of :attr:`__file__` for - the specified module. If no path is available, :exc:`ImportError` is - raised. + An abstract method that is to return the value of + :attr:`~module.__file__` for the specified module. If no path is + available, :exc:`ImportError` is raised. If source code is available, then the method should return the path to the source file, regardless of whether a bytecode was used to load the @@ -657,7 +636,7 @@ ABC hierarchy:: something like a data file that lives next to the ``__init__.py`` file of the package. The purpose of this class is to help abstract out the accessing of such data files so that it does not matter if - the package and its data file(s) are stored in a e.g. zip file + the package and its data file(s) are stored e.g. in a zip file versus on the file system. For any of methods of this class, a *resource* argument is @@ -1166,79 +1145,74 @@ find and load modules. .. class:: ModuleSpec(name, loader, *, origin=None, loader_state=None, is_package=None) A specification for a module's import-system-related state. This is - typically exposed as the module's :attr:`__spec__` attribute. In the - descriptions below, the names in parentheses give the corresponding - attribute available directly on the module object, - e.g. ``module.__spec__.origin == module.__file__``. Note, however, that + typically exposed as the module's :attr:`~module.__spec__` attribute. Many + of these attributes are also available directly on a module: for example, + ``module.__spec__.origin == module.__file__``. Note, however, that while the *values* are usually equivalent, they can differ since there is - no synchronization between the two objects. For example, it is possible to update - the module's :attr:`__file__` at runtime and this will not be automatically - reflected in the module's :attr:`__spec__.origin`, and vice versa. + no synchronization between the two objects. For example, it is possible to + update the module's :attr:`~module.__file__` at runtime and this will not be + automatically reflected in the module's + :attr:`__spec__.origin `, and vice versa. .. versionadded:: 3.4 .. attribute:: name - (:attr:`__name__`) - - The module's fully qualified name. - The :term:`finder` should always set this attribute to a non-empty string. + The module's fully qualified name (see :attr:`module.__name__`). + The :term:`finder` should always set this attribute to a non-empty string. .. attribute:: loader - (:attr:`__loader__`) - - The :term:`loader` used to load the module. - The :term:`finder` should always set this attribute. + The :term:`loader` used to load the module (see :attr:`module.__loader__`). + The :term:`finder` should always set this attribute. .. attribute:: origin - (:attr:`__file__`) - - The location the :term:`loader` should use to load the module. - For example, for modules loaded from a .py file this is the filename. - The :term:`finder` should always set this attribute to a meaningful value - for the :term:`loader` to use. In the uncommon case that there is not one - (like for namespace packages), it should be set to ``None``. + The location the :term:`loader` should use to load the module + (see :attr:`module.__file__`). + For example, for modules loaded from a ``.py`` file this is the filename. + The :term:`finder` should always set this attribute to a meaningful value + for the :term:`loader` to use. In the uncommon case that there is not one + (like for namespace packages), it should be set to ``None``. .. attribute:: submodule_search_locations - (:attr:`__path__`) + A (possibly empty) :term:`sequence` of strings enumerating the locations + in which a package's submodules will be found + (see :attr:`module.__path__`). Most of the time there will only be a + single directory in this list. - The list of locations where the package's submodules will be found. - Most of the time this is a single directory. - The :term:`finder` should set this attribute to a list, even an empty one, to indicate - to the import system that the module is a package. It should be set to ``None`` for - non-package modules. It is set automatically later to a special object for - namespace packages. + The :term:`finder` should set this attribute to a sequence, even an empty + one, to indicate + to the import system that the module is a package. It should be set to ``None`` for + non-package modules. It is set automatically later to a special object for + namespace packages. .. attribute:: loader_state - The :term:`finder` may set this attribute to an object containing additional, - module-specific data to use when loading the module. Otherwise it should be - set to ``None``. + The :term:`finder` may set this attribute to an object containing additional, + module-specific data to use when loading the module. Otherwise it should be + set to ``None``. .. attribute:: cached - (:attr:`__cached__`) - - The filename of a compiled version of the module's code. - The :term:`finder` should always set this attribute but it may be ``None`` - for modules that do not need compiled code stored. + The filename of a compiled version of the module's code + (see :attr:`module.__cached__`). + The :term:`finder` should always set this attribute but it may be ``None`` + for modules that do not need compiled code stored. .. attribute:: parent - (:attr:`__package__`) - - (Read-only) The fully qualified name of the package the module is in (or the - empty string for a top-level module). - If the module is a package then this is the same as :attr:`name`. + (Read-only) The fully qualified name of the package the module is in (or the + empty string for a top-level module). + See :attr:`module.__package__`. + If the module is a package then this is the same as :attr:`name`. .. attribute:: has_location - ``True`` if the spec's :attr:`origin` refers to a loadable location, - ``False`` otherwise. This value impacts how :attr:`origin` is interpreted - and how the module's :attr:`__file__` is populated. + ``True`` if the spec's :attr:`origin` refers to a loadable location, + ``False`` otherwise. This value impacts how :attr:`!origin` is interpreted + and how the module's :attr:`~module.__file__` is populated. :mod:`importlib.util` -- Utility code for importers @@ -1360,8 +1334,8 @@ an :term:`importer`. .. versionchanged:: 3.7 Raises :exc:`ModuleNotFoundError` instead of :exc:`AttributeError` if - **package** is in fact not a package (i.e. lacks a :attr:`__path__` - attribute). + **package** is in fact not a package (i.e. lacks a + :attr:`~module.__path__` attribute). .. function:: module_from_spec(spec) @@ -1521,20 +1495,34 @@ Note that if ``name`` is a submodule (contains a dot), Importing a source file directly '''''''''''''''''''''''''''''''' -To import a Python source file directly, use the following recipe:: +This recipe should be used with caution: it is an approximation of an import +statement where the file path is specified directly, rather than +:data:`sys.path` being searched. Alternatives should first be considered first, +such as modifying :data:`sys.path` when a proper module is required, or using +:func:`runpy.run_path` when the global namespace resulting from running a Python +file is appropriate. - import importlib.util - import sys +To import a Python source file directly from a path, use the following recipe:: + + import importlib.util + import sys - # For illustrative purposes. - import tokenize - file_path = tokenize.__file__ - module_name = tokenize.__name__ - spec = importlib.util.spec_from_file_location(module_name, file_path) - module = importlib.util.module_from_spec(spec) - sys.modules[module_name] = module - spec.loader.exec_module(module) + def import_from_path(module_name, file_path): + spec = importlib.util.spec_from_file_location(module_name, file_path) + module = importlib.util.module_from_spec(spec) + sys.modules[module_name] = module + spec.loader.exec_module(module) + return module + + + # For illustrative purposes only (use of `json` is arbitrary). + import json + file_path = json.__file__ + module_name = json.__name__ + + # Similar outcome as `import json`. + json = import_from_path(module_name, file_path) Implementing lazy imports @@ -1560,7 +1548,6 @@ The example below shows how to implement lazy imports:: False - Setting up an importer '''''''''''''''''''''' diff --git a/Doc/library/index.rst b/Doc/library/index.rst index 0b348ae6..951fbcf1 100644 --- a/Doc/library/index.rst +++ b/Doc/library/index.rst @@ -75,4 +75,5 @@ the `Python Package Index `_. unix.rst cmdline.rst superseded.rst + removed.rst security_warnings.rst diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 7d1aab8e..93a1ed0f 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -42,220 +42,233 @@ attributes (see :ref:`import-mod-attrs` for module attributes): .. this function name is too big to fit in the ascii-art table below .. |coroutine-origin-link| replace:: :func:`sys.set_coroutine_origin_tracking_depth` -+-----------+-------------------+---------------------------+ -| Type | Attribute | Description | -+===========+===================+===========================+ -| class | __doc__ | documentation string | -+-----------+-------------------+---------------------------+ -| | __name__ | name with which this | -| | | class was defined | -+-----------+-------------------+---------------------------+ -| | __qualname__ | qualified name | -+-----------+-------------------+---------------------------+ -| | __module__ | name of module in which | -| | | this class was defined | -+-----------+-------------------+---------------------------+ -| | __type_params__ | A tuple containing the | -| | | :ref:`type parameters | -| | | ` of | -| | | a generic class | -+-----------+-------------------+---------------------------+ -| method | __doc__ | documentation string | -+-----------+-------------------+---------------------------+ -| | __name__ | name with which this | -| | | method was defined | -+-----------+-------------------+---------------------------+ -| | __qualname__ | qualified name | -+-----------+-------------------+---------------------------+ -| | __func__ | function object | -| | | containing implementation | -| | | of method | -+-----------+-------------------+---------------------------+ -| | __self__ | instance to which this | -| | | method is bound, or | -| | | ``None`` | -+-----------+-------------------+---------------------------+ -| | __module__ | name of module in which | -| | | this method was defined | -+-----------+-------------------+---------------------------+ -| function | __doc__ | documentation string | -+-----------+-------------------+---------------------------+ -| | __name__ | name with which this | -| | | function was defined | -+-----------+-------------------+---------------------------+ -| | __qualname__ | qualified name | -+-----------+-------------------+---------------------------+ -| | __code__ | code object containing | -| | | compiled function | -| | | :term:`bytecode` | -+-----------+-------------------+---------------------------+ -| | __defaults__ | tuple of any default | -| | | values for positional or | -| | | keyword parameters | -+-----------+-------------------+---------------------------+ -| | __kwdefaults__ | mapping of any default | -| | | values for keyword-only | -| | | parameters | -+-----------+-------------------+---------------------------+ -| | __globals__ | global namespace in which | -| | | this function was defined | -+-----------+-------------------+---------------------------+ -| | __builtins__ | builtins namespace | -+-----------+-------------------+---------------------------+ -| | __annotations__ | mapping of parameters | -| | | names to annotations; | -| | | ``"return"`` key is | -| | | reserved for return | -| | | annotations. | -+-----------+-------------------+---------------------------+ -| | __type_params__ | A tuple containing the | -| | | :ref:`type parameters | -| | | ` of | -| | | a generic function | -+-----------+-------------------+---------------------------+ -| | __module__ | name of module in which | -| | | this function was defined | -+-----------+-------------------+---------------------------+ -| traceback | tb_frame | frame object at this | -| | | level | -+-----------+-------------------+---------------------------+ -| | tb_lasti | index of last attempted | -| | | instruction in bytecode | -+-----------+-------------------+---------------------------+ -| | tb_lineno | current line number in | -| | | Python source code | -+-----------+-------------------+---------------------------+ -| | tb_next | next inner traceback | -| | | object (called by this | -| | | level) | -+-----------+-------------------+---------------------------+ -| frame | f_back | next outer frame object | -| | | (this frame's caller) | -+-----------+-------------------+---------------------------+ -| | f_builtins | builtins namespace seen | -| | | by this frame | -+-----------+-------------------+---------------------------+ -| | f_code | code object being | -| | | executed in this frame | -+-----------+-------------------+---------------------------+ -| | f_globals | global namespace seen by | -| | | this frame | -+-----------+-------------------+---------------------------+ -| | f_lasti | index of last attempted | -| | | instruction in bytecode | -+-----------+-------------------+---------------------------+ -| | f_lineno | current line number in | -| | | Python source code | -+-----------+-------------------+---------------------------+ -| | f_locals | local namespace seen by | -| | | this frame | -+-----------+-------------------+---------------------------+ -| | f_trace | tracing function for this | -| | | frame, or ``None`` | -+-----------+-------------------+---------------------------+ -| code | co_argcount | number of arguments (not | -| | | including keyword only | -| | | arguments, \* or \*\* | -| | | args) | -+-----------+-------------------+---------------------------+ -| | co_code | string of raw compiled | -| | | bytecode | -+-----------+-------------------+---------------------------+ -| | co_cellvars | tuple of names of cell | -| | | variables (referenced by | -| | | containing scopes) | -+-----------+-------------------+---------------------------+ -| | co_consts | tuple of constants used | -| | | in the bytecode | -+-----------+-------------------+---------------------------+ -| | co_filename | name of file in which | -| | | this code object was | -| | | created | -+-----------+-------------------+---------------------------+ -| | co_firstlineno | number of first line in | -| | | Python source code | -+-----------+-------------------+---------------------------+ -| | co_flags | bitmap of ``CO_*`` flags, | -| | | read more :ref:`here | -| | | `| -+-----------+-------------------+---------------------------+ -| | co_lnotab | encoded mapping of line | -| | | numbers to bytecode | -| | | indices | -+-----------+-------------------+---------------------------+ -| | co_freevars | tuple of names of free | -| | | variables (referenced via | -| | | a function's closure) | -+-----------+-------------------+---------------------------+ -| | co_posonlyargcount| number of positional only | -| | | arguments | -+-----------+-------------------+---------------------------+ -| | co_kwonlyargcount | number of keyword only | -| | | arguments (not including | -| | | \*\* arg) | -+-----------+-------------------+---------------------------+ -| | co_name | name with which this code | -| | | object was defined | -+-----------+-------------------+---------------------------+ -| | co_qualname | fully qualified name with | -| | | which this code object | -| | | was defined | -+-----------+-------------------+---------------------------+ -| | co_names | tuple of names other | -| | | than arguments and | -| | | function locals | -+-----------+-------------------+---------------------------+ -| | co_nlocals | number of local variables | -+-----------+-------------------+---------------------------+ -| | co_stacksize | virtual machine stack | -| | | space required | -+-----------+-------------------+---------------------------+ -| | co_varnames | tuple of names of | -| | | arguments and local | -| | | variables | -+-----------+-------------------+---------------------------+ -| generator | __name__ | name | -+-----------+-------------------+---------------------------+ -| | __qualname__ | qualified name | -+-----------+-------------------+---------------------------+ -| | gi_frame | frame | -+-----------+-------------------+---------------------------+ -| | gi_running | is the generator running? | -+-----------+-------------------+---------------------------+ -| | gi_code | code | -+-----------+-------------------+---------------------------+ -| | gi_yieldfrom | object being iterated by | -| | | ``yield from``, or | -| | | ``None`` | -+-----------+-------------------+---------------------------+ -| coroutine | __name__ | name | -+-----------+-------------------+---------------------------+ -| | __qualname__ | qualified name | -+-----------+-------------------+---------------------------+ -| | cr_await | object being awaited on, | -| | | or ``None`` | -+-----------+-------------------+---------------------------+ -| | cr_frame | frame | -+-----------+-------------------+---------------------------+ -| | cr_running | is the coroutine running? | -+-----------+-------------------+---------------------------+ -| | cr_code | code | -+-----------+-------------------+---------------------------+ -| | cr_origin | where coroutine was | -| | | created, or ``None``. See | -| | | |coroutine-origin-link| | -+-----------+-------------------+---------------------------+ -| builtin | __doc__ | documentation string | -+-----------+-------------------+---------------------------+ -| | __name__ | original name of this | -| | | function or method | -+-----------+-------------------+---------------------------+ -| | __qualname__ | qualified name | -+-----------+-------------------+---------------------------+ -| | __self__ | instance to which a | -| | | method is bound, or | -| | | ``None`` | -+-----------+-------------------+---------------------------+ ++-----------------+-------------------+---------------------------+ +| Type | Attribute | Description | ++=================+===================+===========================+ +| class | __doc__ | documentation string | ++-----------------+-------------------+---------------------------+ +| | __name__ | name with which this | +| | | class was defined | ++-----------------+-------------------+---------------------------+ +| | __qualname__ | qualified name | ++-----------------+-------------------+---------------------------+ +| | __module__ | name of module in which | +| | | this class was defined | ++-----------------+-------------------+---------------------------+ +| | __type_params__ | A tuple containing the | +| | | :ref:`type parameters | +| | | ` of | +| | | a generic class | ++-----------------+-------------------+---------------------------+ +| method | __doc__ | documentation string | ++-----------------+-------------------+---------------------------+ +| | __name__ | name with which this | +| | | method was defined | ++-----------------+-------------------+---------------------------+ +| | __qualname__ | qualified name | ++-----------------+-------------------+---------------------------+ +| | __func__ | function object | +| | | containing implementation | +| | | of method | ++-----------------+-------------------+---------------------------+ +| | __self__ | instance to which this | +| | | method is bound, or | +| | | ``None`` | ++-----------------+-------------------+---------------------------+ +| | __module__ | name of module in which | +| | | this method was defined | ++-----------------+-------------------+---------------------------+ +| function | __doc__ | documentation string | ++-----------------+-------------------+---------------------------+ +| | __name__ | name with which this | +| | | function was defined | ++-----------------+-------------------+---------------------------+ +| | __qualname__ | qualified name | ++-----------------+-------------------+---------------------------+ +| | __code__ | code object containing | +| | | compiled function | +| | | :term:`bytecode` | ++-----------------+-------------------+---------------------------+ +| | __defaults__ | tuple of any default | +| | | values for positional or | +| | | keyword parameters | ++-----------------+-------------------+---------------------------+ +| | __kwdefaults__ | mapping of any default | +| | | values for keyword-only | +| | | parameters | ++-----------------+-------------------+---------------------------+ +| | __globals__ | global namespace in which | +| | | this function was defined | ++-----------------+-------------------+---------------------------+ +| | __builtins__ | builtins namespace | ++-----------------+-------------------+---------------------------+ +| | __annotations__ | mapping of parameters | +| | | names to annotations; | +| | | ``"return"`` key is | +| | | reserved for return | +| | | annotations. | ++-----------------+-------------------+---------------------------+ +| | __type_params__ | A tuple containing the | +| | | :ref:`type parameters | +| | | ` of | +| | | a generic function | ++-----------------+-------------------+---------------------------+ +| | __module__ | name of module in which | +| | | this function was defined | ++-----------------+-------------------+---------------------------+ +| traceback | tb_frame | frame object at this | +| | | level | ++-----------------+-------------------+---------------------------+ +| | tb_lasti | index of last attempted | +| | | instruction in bytecode | ++-----------------+-------------------+---------------------------+ +| | tb_lineno | current line number in | +| | | Python source code | ++-----------------+-------------------+---------------------------+ +| | tb_next | next inner traceback | +| | | object (called by this | +| | | level) | ++-----------------+-------------------+---------------------------+ +| frame | f_back | next outer frame object | +| | | (this frame's caller) | ++-----------------+-------------------+---------------------------+ +| | f_builtins | builtins namespace seen | +| | | by this frame | ++-----------------+-------------------+---------------------------+ +| | f_code | code object being | +| | | executed in this frame | ++-----------------+-------------------+---------------------------+ +| | f_globals | global namespace seen by | +| | | this frame | ++-----------------+-------------------+---------------------------+ +| | f_lasti | index of last attempted | +| | | instruction in bytecode | ++-----------------+-------------------+---------------------------+ +| | f_lineno | current line number in | +| | | Python source code | ++-----------------+-------------------+---------------------------+ +| | f_locals | local namespace seen by | +| | | this frame | ++-----------------+-------------------+---------------------------+ +| | f_trace | tracing function for this | +| | | frame, or ``None`` | ++-----------------+-------------------+---------------------------+ +| code | co_argcount | number of arguments (not | +| | | including keyword only | +| | | arguments, \* or \*\* | +| | | args) | ++-----------------+-------------------+---------------------------+ +| | co_code | string of raw compiled | +| | | bytecode | ++-----------------+-------------------+---------------------------+ +| | co_cellvars | tuple of names of cell | +| | | variables (referenced by | +| | | containing scopes) | ++-----------------+-------------------+---------------------------+ +| | co_consts | tuple of constants used | +| | | in the bytecode | ++-----------------+-------------------+---------------------------+ +| | co_filename | name of file in which | +| | | this code object was | +| | | created | ++-----------------+-------------------+---------------------------+ +| | co_firstlineno | number of first line in | +| | | Python source code | ++-----------------+-------------------+---------------------------+ +| | co_flags | bitmap of ``CO_*`` flags, | +| | | read more :ref:`here | +| | | `| ++-----------------+-------------------+---------------------------+ +| | co_lnotab | encoded mapping of line | +| | | numbers to bytecode | +| | | indices | ++-----------------+-------------------+---------------------------+ +| | co_freevars | tuple of names of free | +| | | variables (referenced via | +| | | a function's closure) | ++-----------------+-------------------+---------------------------+ +| | co_posonlyargcount| number of positional only | +| | | arguments | ++-----------------+-------------------+---------------------------+ +| | co_kwonlyargcount | number of keyword only | +| | | arguments (not including | +| | | \*\* arg) | ++-----------------+-------------------+---------------------------+ +| | co_name | name with which this code | +| | | object was defined | ++-----------------+-------------------+---------------------------+ +| | co_qualname | fully qualified name with | +| | | which this code object | +| | | was defined | ++-----------------+-------------------+---------------------------+ +| | co_names | tuple of names other | +| | | than arguments and | +| | | function locals | ++-----------------+-------------------+---------------------------+ +| | co_nlocals | number of local variables | ++-----------------+-------------------+---------------------------+ +| | co_stacksize | virtual machine stack | +| | | space required | ++-----------------+-------------------+---------------------------+ +| | co_varnames | tuple of names of | +| | | arguments and local | +| | | variables | ++-----------------+-------------------+---------------------------+ +| generator | __name__ | name | ++-----------------+-------------------+---------------------------+ +| | __qualname__ | qualified name | ++-----------------+-------------------+---------------------------+ +| | gi_frame | frame | ++-----------------+-------------------+---------------------------+ +| | gi_running | is the generator running? | ++-----------------+-------------------+---------------------------+ +| | gi_code | code | ++-----------------+-------------------+---------------------------+ +| | gi_yieldfrom | object being iterated by | +| | | ``yield from``, or | +| | | ``None`` | ++-----------------+-------------------+---------------------------+ +| async generator | __name__ | name | ++-----------------+-------------------+---------------------------+ +| | __qualname__ | qualified name | ++-----------------+-------------------+---------------------------+ +| | ag_await | object being awaited on, | +| | | or ``None`` | ++-----------------+-------------------+---------------------------+ +| | ag_frame | frame | ++-----------------+-------------------+---------------------------+ +| | ag_running | is the generator running? | ++-----------------+-------------------+---------------------------+ +| | ag_code | code | ++-----------------+-------------------+---------------------------+ +| coroutine | __name__ | name | ++-----------------+-------------------+---------------------------+ +| | __qualname__ | qualified name | ++-----------------+-------------------+---------------------------+ +| | cr_await | object being awaited on, | +| | | or ``None`` | ++-----------------+-------------------+---------------------------+ +| | cr_frame | frame | ++-----------------+-------------------+---------------------------+ +| | cr_running | is the coroutine running? | ++-----------------+-------------------+---------------------------+ +| | cr_code | code | ++-----------------+-------------------+---------------------------+ +| | cr_origin | where coroutine was | +| | | created, or ``None``. See | +| | | |coroutine-origin-link| | ++-----------------+-------------------+---------------------------+ +| builtin | __doc__ | documentation string | ++-----------------+-------------------+---------------------------+ +| | __name__ | original name of this | +| | | function or method | ++-----------------+-------------------+---------------------------+ +| | __qualname__ | qualified name | ++-----------------+-------------------+---------------------------+ +| | __self__ | instance to which a | +| | | method is bound, or | +| | | ``None`` | ++-----------------+-------------------+---------------------------+ .. versionchanged:: 3.5 @@ -437,7 +450,7 @@ attributes (see :ref:`import-mod-attrs` for module attributes): .. versionchanged:: 3.8 Functions wrapped in :func:`functools.partial` now return ``True`` if the - wrapped function is a :term:`asynchronous generator` function. + wrapped function is an :term:`asynchronous generator` function. .. function:: isasyncgen(object) @@ -497,7 +510,7 @@ attributes (see :ref:`import-mod-attrs` for module attributes): has a :meth:`~object.__get__` method but not a :meth:`~object.__set__` method, but beyond that the set of attributes varies. A :attr:`~definition.__name__` attribute is usually - sensible, and :attr:`!__doc__` often is. + sensible, and :attr:`~definition.__doc__` often is. Methods implemented via descriptors that also pass one of the other tests return ``False`` from the :func:`ismethoddescriptor` test, simply because the @@ -896,7 +909,7 @@ function. .. attribute:: Parameter.kind.description - Describes a enum value of :attr:`Parameter.kind`. + Describes an enum value of :attr:`Parameter.kind`. .. versionadded:: 3.8 @@ -973,7 +986,8 @@ function. .. attribute:: BoundArguments.kwargs A dict of keyword arguments values. Dynamically computed from the - :attr:`arguments` attribute. + :attr:`arguments` attribute. Arguments that can be passed positionally + are included in :attr:`args` instead. .. attribute:: BoundArguments.signature @@ -1191,7 +1205,7 @@ Classes and functions This function handles several details for you: * If ``eval_str`` is true, values of type ``str`` will - be un-stringized using :func:`eval()`. This is intended + be un-stringized using :func:`eval`. This is intended for use with stringized annotations (``from __future__ import annotations``). * If ``obj`` doesn't have an annotations dict, returns an @@ -1205,16 +1219,16 @@ Classes and functions * Always, always, always returns a freshly created dict. ``eval_str`` controls whether or not values of type ``str`` are replaced - with the result of calling :func:`eval()` on those values: + with the result of calling :func:`eval` on those values: - * If eval_str is true, :func:`eval()` is called on values of type ``str``. - (Note that ``get_annotations`` doesn't catch exceptions; if :func:`eval()` + * If eval_str is true, :func:`eval` is called on values of type ``str``. + (Note that ``get_annotations`` doesn't catch exceptions; if :func:`eval` raises an exception, it will unwind the stack past the ``get_annotations`` call.) * If eval_str is false (the default), values of type ``str`` are unchanged. - ``globals`` and ``locals`` are passed in to :func:`eval()`; see the documentation - for :func:`eval()` for more information. If ``globals`` or ``locals`` + ``globals`` and ``locals`` are passed in to :func:`eval`; see the documentation + for :func:`eval` for more information. If ``globals`` or ``locals`` is ``None``, this function may replace that value with a context-specific default, contingent on ``type(obj)``: diff --git a/Doc/library/io.rst b/Doc/library/io.rst index 748c4996..f793d7a7 100644 --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -55,7 +55,7 @@ the backing store is natively made of bytes (such as in the case of a file), encoding and decoding of data is made transparently as well as optional translation of platform-specific newline characters. -The easiest way to create a text stream is with :meth:`open()`, optionally +The easiest way to create a text stream is with :meth:`open`, optionally specifying an encoding:: f = open("myfile.txt", "r", encoding="utf-8") @@ -77,7 +77,7 @@ objects. No encoding, decoding, or newline translation is performed. This category of streams can be used for all kinds of non-text data, and also when manual control over the handling of text data is desired. -The easiest way to create a binary stream is with :meth:`open()` with ``'b'`` in +The easiest way to create a binary stream is with :meth:`open` with ``'b'`` in the mode string:: f = open("myfile.jpg", "rb") @@ -950,7 +950,7 @@ Text I/O :class:`TextIOBase`. *encoding* gives the name of the encoding that the stream will be decoded or - encoded with. It defaults to :func:`locale.getencoding()`. + encoded with. It defaults to :func:`locale.getencoding`. ``encoding="locale"`` can be used to specify the current locale's encoding explicitly. See :ref:`io-text-encoding` for more information. @@ -1182,7 +1182,7 @@ re-enter a buffered object which it is already accessing, a :exc:`RuntimeError` is raised. Note this doesn't prohibit a different thread from entering the buffered object. -The above implicitly extends to text files, since the :func:`open()` function +The above implicitly extends to text files, since the :func:`open` function will wrap a buffered object inside a :class:`TextIOWrapper`. This includes -standard streams and therefore affects the built-in :func:`print()` function as +standard streams and therefore affects the built-in :func:`print` function as well. diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst index d359451b..d780969c 100644 --- a/Doc/library/ipaddress.rst +++ b/Doc/library/ipaddress.rst @@ -983,7 +983,7 @@ The module also provides the following module level functions: .. function:: collapse_addresses(addresses) Return an iterator of the collapsed :class:`IPv4Network` or - :class:`IPv6Network` objects. *addresses* is an iterator of + :class:`IPv6Network` objects. *addresses* is an :term:`iterable` of :class:`IPv4Network` or :class:`IPv6Network` objects. A :exc:`TypeError` is raised if *addresses* contains mixed version objects. @@ -1003,7 +1003,7 @@ The module also provides the following module level functions: doesn't make sense. There are some times however, where you may wish to have :mod:`ipaddress` sort these anyway. If you need to do this, you can use - this function as the *key* argument to :func:`sorted()`. + this function as the *key* argument to :func:`sorted`. *obj* is either a network or address object. diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 21bb3f1f..047d805e 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -329,7 +329,7 @@ loops that truncate the stream. yield n n += step - When counting with floating point numbers, better accuracy can sometimes be + When counting with floating-point numbers, better accuracy can sometimes be achieved by substituting multiplicative code such as: ``(start + step * i for i in count())``. @@ -676,24 +676,37 @@ loops that truncate the stream. Roughly equivalent to:: def tee(iterable, n=2): - iterator = iter(iterable) - shared_link = [None, None] - return tuple(_tee(iterator, shared_link) for _ in range(n)) - - def _tee(iterator, link): - try: - while True: - if link[1] is None: - link[0] = next(iterator) - link[1] = [None, None] - value, link = link - yield value - except StopIteration: - return - - Once a :func:`tee` has been created, the original *iterable* should not be - used anywhere else; otherwise, the *iterable* could get advanced without - the tee objects being informed. + if n < 0: + raise ValueError + if n == 0: + return () + iterator = _tee(iterable) + result = [iterator] + for _ in range(n - 1): + result.append(_tee(iterator)) + return tuple(result) + + class _tee: + + def __init__(self, iterable): + it = iter(iterable) + if isinstance(it, _tee): + self.iterator = it.iterator + self.link = it.link + else: + self.iterator = it + self.link = [None, None] + + def __iter__(self): + return self + + def __next__(self): + link = self.link + if link[1] is None: + link[0] = next(self.iterator) + link[1] = [None, None] + value, self.link = link + return value ``tee`` iterators are not threadsafe. A :exc:`RuntimeError` may be raised when simultaneously using iterators returned by the same :func:`tee` diff --git a/Doc/library/json.rst b/Doc/library/json.rst index a1aba65c..88882aee 100644 --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -13,7 +13,7 @@ `JSON (JavaScript Object Notation) `_, specified by :rfc:`7159` (which obsoletes :rfc:`4627`) and by -`ECMA-404 `_, +`ECMA-404 `_, is a lightweight data interchange format inspired by `JavaScript `_ object literal syntax (although it is not a strict subset of JavaScript [#rfc-errata]_ ). @@ -230,28 +230,28 @@ Basic Usage *object_hook* is an optional function that will be called with the result of any object literal decoded (a :class:`dict`). The return value of - *object_hook* will be used instead of the :class:`dict`. This feature can be used - to implement custom decoders (e.g. `JSON-RPC `_ - class hinting). + *object_hook* will be used instead of the :class:`dict`. This feature can + be used to implement custom decoders (e.g. `JSON-RPC + `_ class hinting). *object_pairs_hook* is an optional function that will be called with the result of any object literal decoded with an ordered list of pairs. The return value of *object_pairs_hook* will be used instead of the - :class:`dict`. This feature can be used to implement custom decoders. - If *object_hook* is also defined, the *object_pairs_hook* takes priority. + :class:`dict`. This feature can be used to implement custom decoders. If + *object_hook* is also defined, the *object_pairs_hook* takes priority. .. versionchanged:: 3.1 Added support for *object_pairs_hook*. - *parse_float*, if specified, will be called with the string of every JSON - float to be decoded. By default, this is equivalent to ``float(num_str)``. - This can be used to use another datatype or parser for JSON floats - (e.g. :class:`decimal.Decimal`). + *parse_float* is an optional function that will be called with the string of + every JSON float to be decoded. By default, this is equivalent to + ``float(num_str)``. This can be used to use another datatype or parser for + JSON floats (e.g. :class:`decimal.Decimal`). - *parse_int*, if specified, will be called with the string of every JSON int - to be decoded. By default, this is equivalent to ``int(num_str)``. This can - be used to use another datatype or parser for JSON integers - (e.g. :class:`float`). + *parse_int* is an optional function that will be called with the string of + every JSON int to be decoded. By default, this is equivalent to + ``int(num_str)``. This can be used to use another datatype or parser for + JSON integers (e.g. :class:`float`). .. versionchanged:: 3.11 The default *parse_int* of :func:`int` now limits the maximum length of @@ -259,10 +259,9 @@ Basic Usage conversion length limitation ` to help avoid denial of service attacks. - *parse_constant*, if specified, will be called with one of the following - strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``. - This can be used to raise an exception if invalid JSON numbers - are encountered. + *parse_constant* is an optional function that will be called with one of the + following strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``. This can be + used to raise an exception if invalid JSON numbers are encountered. .. versionchanged:: 3.1 *parse_constant* doesn't get called on 'null', 'true', 'false' anymore. @@ -334,34 +333,33 @@ Encoders and Decoders It also understands ``NaN``, ``Infinity``, and ``-Infinity`` as their corresponding ``float`` values, which is outside the JSON spec. - *object_hook*, if specified, will be called with the result of every JSON - object decoded and its return value will be used in place of the given - :class:`dict`. This can be used to provide custom deserializations (e.g. to - support `JSON-RPC `_ class hinting). + *object_hook* is an optional function that will be called with the result of + every JSON object decoded and its return value will be used in place of the + given :class:`dict`. This can be used to provide custom deserializations + (e.g. to support `JSON-RPC `_ class hinting). - *object_pairs_hook*, if specified will be called with the result of every - JSON object decoded with an ordered list of pairs. The return value of - *object_pairs_hook* will be used instead of the :class:`dict`. This - feature can be used to implement custom decoders. If *object_hook* is also - defined, the *object_pairs_hook* takes priority. + *object_pairs_hook* is an optional function that will be called with the + result of every JSON object decoded with an ordered list of pairs. The + return value of *object_pairs_hook* will be used instead of the + :class:`dict`. This feature can be used to implement custom decoders. If + *object_hook* is also defined, the *object_pairs_hook* takes priority. .. versionchanged:: 3.1 Added support for *object_pairs_hook*. - *parse_float*, if specified, will be called with the string of every JSON - float to be decoded. By default, this is equivalent to ``float(num_str)``. - This can be used to use another datatype or parser for JSON floats - (e.g. :class:`decimal.Decimal`). + *parse_float* is an optional function that will be called with the string of + every JSON float to be decoded. By default, this is equivalent to + ``float(num_str)``. This can be used to use another datatype or parser for + JSON floats (e.g. :class:`decimal.Decimal`). - *parse_int*, if specified, will be called with the string of every JSON int - to be decoded. By default, this is equivalent to ``int(num_str)``. This can - be used to use another datatype or parser for JSON integers - (e.g. :class:`float`). + *parse_int* is an optional function that will be called with the string of + every JSON int to be decoded. By default, this is equivalent to + ``int(num_str)``. This can be used to use another datatype or parser for + JSON integers (e.g. :class:`float`). - *parse_constant*, if specified, will be called with one of the following - strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``. - This can be used to raise an exception if invalid JSON numbers - are encountered. + *parse_constant* is an optional function that will be called with one of the + following strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``. This can be + used to raise an exception if invalid JSON numbers are encountered. If *strict* is false (``True`` is the default), then control characters will be allowed inside strings. Control characters in this context are @@ -548,7 +546,7 @@ Standard Compliance and Interoperability ---------------------------------------- The JSON format is specified by :rfc:`7159` and by -`ECMA-404 `_. +`ECMA-404 `_. This section details this module's level of compliance with the RFC. For simplicity, :class:`JSONEncoder` and :class:`JSONDecoder` subclasses, and parameters other than those explicitly mentioned, are not considered. diff --git a/Doc/library/locale.rst b/Doc/library/locale.rst index 10c37639..fee5aba7 100644 --- a/Doc/library/locale.rst +++ b/Doc/library/locale.rst @@ -281,7 +281,8 @@ The :mod:`locale` module defines the following exception and functions: .. data:: ERA - Get a string that represents the era used in the current locale. + Get a string which describes how years are counted and displayed for + each era in a locale. Most locales do not define this value. An example of a locale which does define this value is the Japanese one. In Japan, the traditional @@ -290,9 +291,10 @@ The :mod:`locale` module defines the following exception and functions: Normally it should not be necessary to use this value directly. Specifying the ``E`` modifier in their format strings causes the :func:`time.strftime` - function to use this information. The format of the returned string is not - specified, and therefore you should not assume knowledge of it on different - systems. + function to use this information. + The format of the returned string is specified in *The Open Group Base + Specifications Issue 8*, paragraph `7.3.5.2 LC_TIME C-Language Access + `_. .. data:: ERA_D_T_FMT @@ -311,8 +313,9 @@ The :mod:`locale` module defines the following exception and functions: .. data:: ALT_DIGITS - Get a representation of up to 100 values used to represent the values - 0 to 99. + Get a string consisting of up to 100 semicolon-separated symbols used + to represent the values 0 to 99 in a locale-specific way. + In most locales this is an empty string. .. function:: getdefaultlocale([envvars]) @@ -434,7 +437,7 @@ The :mod:`locale` module defines the following exception and functions: .. function:: format_string(format, val, grouping=False, monetary=False) Formats a number *val* according to the current :const:`LC_NUMERIC` setting. - The format follows the conventions of the ``%`` operator. For floating point + The format follows the conventions of the ``%`` operator. For floating-point values, the decimal point is modified if appropriate. If *grouping* is ``True``, also takes the grouping into account. @@ -465,7 +468,7 @@ The :mod:`locale` module defines the following exception and functions: .. function:: str(float) - Formats a floating point number using the same format as the built-in function + Formats a floating-point number using the same format as the built-in function ``str(float)``, but takes the decimal point into account. diff --git a/Doc/library/logging.config.rst b/Doc/library/logging.config.rst index 23aac191..bc85f430 100644 --- a/Doc/library/logging.config.rst +++ b/Doc/library/logging.config.rst @@ -69,7 +69,7 @@ in :mod:`logging` itself) and defining handlers which are declared either in dictConfigClass(config).configure() For example, a subclass of :class:`DictConfigurator` could call - ``DictConfigurator.__init__()`` in its own :meth:`__init__()`, then + ``DictConfigurator.__init__()`` in its own :meth:`__init__`, then set up custom prefixes which would be usable in the subsequent :meth:`configure` call. :attr:`dictConfigClass` would be bound to this new subclass, and then :func:`dictConfig` could be called exactly as @@ -752,13 +752,17 @@ The ``queue`` and ``listener`` keys are optional. If the ``queue`` key is present, the corresponding value can be one of the following: -* An actual instance of :class:`queue.Queue` or a subclass thereof. This is of course - only possible if you are constructing or modifying the configuration dictionary in - code. +* An object implementing the :meth:`Queue.put_nowait ` + and :meth:`Queue.get ` public API. For instance, this may be + an actual instance of :class:`queue.Queue` or a subclass thereof, or a proxy + obtained by :meth:`multiprocessing.managers.SyncManager.Queue`. + + This is of course only possible if you are constructing or modifying + the configuration dictionary in code. * A string that resolves to a callable which, when called with no arguments, returns - the :class:`queue.Queue` instance to use. That callable could be a - :class:`queue.Queue` subclass or a function which returns a suitable queue instance, + the queue instance to use. That callable could be a :class:`queue.Queue` subclass + or a function which returns a suitable queue instance, such as ``my.module.queue_factory()``. * A dict with a ``'()'`` key which is constructed in the usual way as discussed in diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst index c6ab3744..5d0bfcb1 100644 --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -304,7 +304,8 @@ in a module, ``__name__`` is the module's name in the Python package namespace. parameter mirrors the equivalent one in the :mod:`warnings` module. The fourth keyword argument is *extra* which can be used to pass a - dictionary which is used to populate the __dict__ of the :class:`LogRecord` + dictionary which is used to populate the :attr:`~object.__dict__` of the + :class:`LogRecord` created for the logging event with user-defined attributes. These custom attributes can then be used as you like. For example, they could be incorporated into logged messages. For example:: @@ -1094,11 +1095,11 @@ information into logging calls. For a usage example, see the section on .. attribute:: manager - Delegates to the underlying :attr:`!manager`` on *logger*. + Delegates to the underlying :attr:`!manager` on *logger*. .. attribute:: _log - Delegates to the underlying :meth:`!_log`` method on *logger*. + Delegates to the underlying :meth:`!_log` method on *logger*. In addition to the above, :class:`LoggerAdapter` supports the following methods of :class:`Logger`: :meth:`~Logger.debug`, :meth:`~Logger.info`, diff --git a/Doc/library/mailbox.rst b/Doc/library/mailbox.rst index 1e4e7283..6eb8dec4 100644 --- a/Doc/library/mailbox.rst +++ b/Doc/library/mailbox.rst @@ -1278,7 +1278,7 @@ When an :class:`!MHMessage` instance is created based upon a .. method:: get_visible() - Return an :class:`Message` instance whose headers are the message's + Return a :class:`Message` instance whose headers are the message's visible headers and whose body is empty. diff --git a/Doc/library/marshal.rst b/Doc/library/marshal.rst index ce549b73..a85d9206 100644 --- a/Doc/library/marshal.rst +++ b/Doc/library/marshal.rst @@ -38,8 +38,8 @@ supports a substantially wider range of objects than marshal. Not all Python object types are supported; in general, only objects whose value is independent from a particular invocation of Python can be written and read by -this module. The following types are supported: booleans, integers, floating -point numbers, complex numbers, strings, bytes, bytearrays, tuples, lists, sets, +this module. The following types are supported: booleans, integers, floating-point +numbers, complex numbers, strings, bytes, bytearrays, tuples, lists, sets, frozensets, dictionaries, and code objects, where it should be understood that tuples, lists, sets, frozensets and dictionaries are only supported as long as the values contained therein are themselves supported. The @@ -121,7 +121,7 @@ In addition, the following constants are defined: Indicates the format that the module uses. Version 0 is the historical format, version 1 shares interned strings and version 2 uses a binary format - for floating point numbers. + for floating-point numbers. Version 3 adds support for object instancing and recursion. The current version is 4. diff --git a/Doc/library/math.rst b/Doc/library/math.rst index b6a7d98a..fb852712 100644 --- a/Doc/library/math.rst +++ b/Doc/library/math.rst @@ -107,7 +107,7 @@ Number-theoretic and representation functions .. function:: fsum(iterable) - Return an accurate floating point sum of values in the iterable. Avoids + Return an accurate floating-point sum of values in the iterable. Avoids loss of precision by tracking multiple intermediate partial sums. The algorithm's accuracy depends on IEEE-754 arithmetic guarantees and the @@ -117,7 +117,7 @@ Number-theoretic and representation functions least significant bit. For further discussion and two alternative approaches, see the `ASPN cookbook - recipes for accurate floating point summation + recipes for accurate floating-point summation `_\. @@ -142,19 +142,21 @@ Number-theoretic and representation functions ``False`` otherwise. Whether or not two values are considered close is determined according to - given absolute and relative tolerances. + given absolute and relative tolerances. If no errors occur, the result will + be: ``abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)``. *rel_tol* is the relative tolerance -- it is the maximum allowed difference between *a* and *b*, relative to the larger absolute value of *a* or *b*. For example, to set a tolerance of 5%, pass ``rel_tol=0.05``. The default tolerance is ``1e-09``, which assures that the two values are the same - within about 9 decimal digits. *rel_tol* must be greater than zero. + within about 9 decimal digits. *rel_tol* must be nonnegative and less + than ``1.0``. - *abs_tol* is the minimum absolute tolerance -- useful for comparisons near - zero. *abs_tol* must be at least zero. - - If no errors occur, the result will be: - ``abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)``. + *abs_tol* is the absolute tolerance; it defaults to ``0.0`` and it must be + nonnegative. When comparing ``x`` to ``0.0``, ``isclose(x, 0)`` is computed + as ``abs(x) <= rel_tol * abs(x)``, which is ``False`` for any ``x`` and + rel_tol less than ``1.0``. So add an appropriate positive abs_tol argument + to the call. The IEEE 754 special values of ``NaN``, ``inf``, and ``-inf`` will be handled according to IEEE rules. Specifically, ``NaN`` is not considered @@ -288,7 +290,7 @@ Number-theoretic and representation functions If the result of the remainder operation is zero, that zero will have the same sign as *x*. - On platforms using IEEE 754 binary floating-point, the result of this + On platforms using IEEE 754 binary floating point, the result of this operation is always exactly representable: no rounding error is introduced. .. versionadded:: 3.7 diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst index 930b4793..1522285b 100644 --- a/Doc/library/mimetypes.rst +++ b/Doc/library/mimetypes.rst @@ -272,3 +272,13 @@ than one MIME-type database; it provides an interface similar to the one of the types, else to the list of non-standard types. .. versionadded:: 3.2 + + + .. method:: MimeTypes.add_type(type, ext, strict=True) + + Add a mapping from the MIME type *type* to the extension *ext*. When the + extension is already known, the new type will replace the old one. When the type + is already known the extension will be added to the list of known extensions. + + When *strict* is ``True`` (the default), the mapping will be added to the + official MIME types, otherwise to the non-standard ones. diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index d6474ef9..3fec8608 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -254,6 +254,7 @@ processes: p.join() Queues are thread and process safe. + Any object put into a :mod:`~multiprocessing` queue will be serialized. **Pipes** @@ -281,6 +282,8 @@ processes: of corruption from processes using different ends of the pipe at the same time. + The :meth:`~Connection.send` method serializes the object and + :meth:`~Connection.recv` re-creates the object. Synchronization between processes ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -502,7 +505,7 @@ The :mod:`multiprocessing` package mostly replicates the API of the The constructor should always be called with keyword arguments. *group* should always be ``None``; it exists solely for compatibility with :class:`threading.Thread`. *target* is the callable object to be invoked by - the :meth:`run()` method. It defaults to ``None``, meaning nothing is + the :meth:`run` method. It defaults to ``None``, meaning nothing is called. *name* is the process name (see :attr:`name` for more details). *args* is the argument tuple for the target invocation. *kwargs* is a dictionary of keyword arguments for the target invocation. If provided, @@ -639,7 +642,7 @@ The :mod:`multiprocessing` package mostly replicates the API of the You can use this value if you want to wait on several events at once using :func:`multiprocessing.connection.wait`. Otherwise - calling :meth:`join()` is simpler. + calling :meth:`join` is simpler. On Windows, this is an OS handle usable with the ``WaitForSingleObject`` and ``WaitForMultipleObjects`` family of API calls. On POSIX, this is @@ -666,7 +669,7 @@ The :mod:`multiprocessing` package mostly replicates the API of the .. method:: kill() - Same as :meth:`terminate()` but using the ``SIGKILL`` signal on POSIX. + Same as :meth:`terminate` but using the ``SIGKILL`` signal on POSIX. .. versionadded:: 3.7 @@ -709,7 +712,7 @@ The :mod:`multiprocessing` package mostly replicates the API of the .. exception:: BufferTooShort - Exception raised by :meth:`Connection.recv_bytes_into()` when the supplied + Exception raised by :meth:`Connection.recv_bytes_into` when the supplied buffer object is too small for the message read. If ``e`` is an instance of :exc:`BufferTooShort` then ``e.args[0]`` will give @@ -745,6 +748,11 @@ If you use :class:`JoinableQueue` then you **must** call semaphore used to count the number of unfinished tasks may eventually overflow, raising an exception. +One difference from other Python queue implementations, is that :mod:`multiprocessing` +queues serializes all objects that are put into them using :mod:`pickle`. +The object return by the get method is a re-created object that does not share memory +with the original object. + Note that one can also create a shared queue by using a manager object -- see :ref:`multiprocessing-managers`. @@ -811,6 +819,8 @@ For an example of the usage of queues for interprocess communication see used for receiving messages and ``conn2`` can only be used for sending messages. + The :meth:`~multiprocessing.Connection.send` method serializes the object using + :mod:`pickle` and the :meth:`~multiprocessing.Connection.recv` re-creates the object. .. class:: Queue([maxsize]) @@ -837,6 +847,8 @@ For an example of the usage of queues for interprocess communication see Return ``True`` if the queue is empty, ``False`` otherwise. Because of multithreading/multiprocessing semantics, this is not reliable. + May raise an :exc:`OSError` on closed queues. (not guaranteed) + .. method:: full() Return ``True`` if the queue is full, ``False`` otherwise. Because of @@ -940,6 +952,8 @@ For an example of the usage of queues for interprocess communication see Return ``True`` if the queue is empty, ``False`` otherwise. + Always raises an :exc:`OSError` if the SimpleQueue is closed. + .. method:: get() Remove and return an item from the queue. @@ -1452,17 +1466,6 @@ object -- see :ref:`multiprocessing-managers`. On macOS, ``sem_timedwait`` is unsupported, so calling ``acquire()`` with a timeout will emulate that function's behavior using a sleeping loop. -.. note:: - - If the SIGINT signal generated by :kbd:`Ctrl-C` arrives while the main thread is - blocked by a call to :meth:`BoundedSemaphore.acquire`, :meth:`Lock.acquire`, - :meth:`RLock.acquire`, :meth:`Semaphore.acquire`, :meth:`Condition.acquire` - or :meth:`Condition.wait` then the call will be immediately interrupted and - :exc:`KeyboardInterrupt` will be raised. - - This differs from the behaviour of :mod:`threading` where SIGINT will be - ignored while the equivalent blocking calls are in progress. - .. note:: Some of this package's functionality requires a functioning shared semaphore @@ -2948,7 +2951,7 @@ Beware of replacing :data:`sys.stdin` with a "file like object" resulting in a bad file descriptor error, but introduces a potential danger to applications which replace :func:`sys.stdin` with a "file-like object" with output buffering. This danger is that if multiple processes call - :meth:`~io.IOBase.close()` on this file-like object, it could result in the same + :meth:`~io.IOBase.close` on this file-like object, it could result in the same data being flushed to the object multiple times, resulting in corruption. If you write a file-like object and implement your own caching, you can diff --git a/Doc/library/nntplib.rst b/Doc/library/nntplib.rst index 143e4e0c..fde0bfc9 100644 --- a/Doc/library/nntplib.rst +++ b/Doc/library/nntplib.rst @@ -484,14 +484,14 @@ tuples or objects that the method normally returns will be empty. .. method:: NNTP.head(message_spec=None, *, file=None) - Same as :meth:`article()`, but sends a ``HEAD`` command. The *lines* + Same as :meth:`article`, but sends a ``HEAD`` command. The *lines* returned (or written to *file*) will only contain the message headers, not the body. .. method:: NNTP.body(message_spec=None, *, file=None) - Same as :meth:`article()`, but sends a ``BODY`` command. The *lines* + Same as :meth:`article`, but sends a ``BODY`` command. The *lines* returned (or written to *file*) will only contain the message body, not the headers. @@ -513,7 +513,7 @@ tuples or objects that the method normally returns will be empty. Send an ``IHAVE`` command. *message_id* is the id of the message to send to the server (enclosed in ``'<'`` and ``'>'``). The *data* parameter - and the return value are the same as for :meth:`post()`. + and the return value are the same as for :meth:`post`. .. method:: NNTP.date() @@ -560,7 +560,7 @@ them have been superseded by newer commands in :rfc:`3977`. Send an ``XOVER`` command. *start* and *end* are article numbers delimiting the range of articles to select. The return value is the - same of for :meth:`over()`. It is recommended to use :meth:`over()` + same of for :meth:`over`. It is recommended to use :meth:`over` instead, since it will automatically use the newer ``OVER`` command if available. diff --git a/Doc/library/optparse.rst b/Doc/library/optparse.rst index fc652d23..15b5d5c3 100644 --- a/Doc/library/optparse.rst +++ b/Doc/library/optparse.rst @@ -1351,7 +1351,7 @@ The whole point of creating and populating an OptionParser is to call its the list of arguments to process (default: ``sys.argv[1:]``) ``values`` - an :class:`Values` object to store option arguments in (default: a + a :class:`Values` object to store option arguments in (default: a new instance of :class:`Values`) -- if you give an existing object, the option defaults will not be initialized on it diff --git a/Doc/library/os.path.rst b/Doc/library/os.path.rst index c5004c3f..51e89087 100644 --- a/Doc/library/os.path.rst +++ b/Doc/library/os.path.rst @@ -81,7 +81,7 @@ the :mod:`glob` module.) Return the longest common sub-path of each pathname in the sequence *paths*. Raise :exc:`ValueError` if *paths* contain both absolute - and relative pathnames, the *paths* are on the different drives or + and relative pathnames, if *paths* are on different drives, or if *paths* is empty. Unlike :func:`commonprefix`, this returns a valid path. @@ -198,14 +198,14 @@ the :mod:`glob` module.) .. function:: getatime(path) - Return the time of last access of *path*. The return value is a floating point number giving + Return the time of last access of *path*. The return value is a floating-point number giving the number of seconds since the epoch (see the :mod:`time` module). Raise :exc:`OSError` if the file does not exist or is inaccessible. .. function:: getmtime(path) - Return the time of last modification of *path*. The return value is a floating point number + Return the time of last modification of *path*. The return value is a floating-point number giving the number of seconds since the epoch (see the :mod:`time` module). Raise :exc:`OSError` if the file does not exist or is inaccessible. @@ -359,7 +359,7 @@ the :mod:`glob` module.) that contains symbolic links. On Windows, it converts forward slashes to backward slashes. To normalize case, use :func:`normcase`. - .. note:: + .. note:: On POSIX systems, in accordance with `IEEE Std 1003.1 2013 Edition; 4.13 Pathname Resolution `_, if a pathname begins with exactly two slashes, the first component diff --git a/Doc/library/os.rst b/Doc/library/os.rst index a793d244..18e58249 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -113,8 +113,8 @@ of the UTF-8 encoding: * Use UTF-8 as the :term:`filesystem encoding `. -* :func:`sys.getfilesystemencoding()` returns ``'utf-8'``. -* :func:`locale.getpreferredencoding()` returns ``'utf-8'`` (the *do_setlocale* +* :func:`sys.getfilesystemencoding` returns ``'utf-8'``. +* :func:`locale.getpreferredencoding` returns ``'utf-8'`` (the *do_setlocale* argument has no effect). * :data:`sys.stdin`, :data:`sys.stdout`, and :data:`sys.stderr` all use UTF-8 as their text encoding, with the ``surrogateescape`` @@ -133,8 +133,8 @@ level APIs also exhibit different default behaviours: * Command line arguments, environment variables and filenames are decoded to text using the UTF-8 encoding. -* :func:`os.fsdecode()` and :func:`os.fsencode()` use the UTF-8 encoding. -* :func:`open()`, :func:`io.open()`, and :func:`codecs.open()` use the UTF-8 +* :func:`os.fsdecode` and :func:`os.fsencode` use the UTF-8 encoding. +* :func:`open`, :func:`io.open`, and :func:`codecs.open` use the UTF-8 encoding by default. However, they still use the strict error handler by default so that attempting to open a binary file in text mode is likely to raise an exception rather than producing nonsense data. @@ -1497,7 +1497,7 @@ or `the MSDN `_ on Windo .. function:: pwritev(fd, buffers, offset, flags=0, /) - Write the *buffers* contents to file descriptor *fd* at a offset *offset*, + Write the *buffers* contents to file descriptor *fd* at an offset *offset*, leaving the file offset unchanged. *buffers* must be a sequence of :term:`bytes-like objects `. Buffers are processed in array order. Entire contents of the first buffer is written before @@ -2756,7 +2756,7 @@ features: .. versionchanged:: 3.6 Added support for the :term:`context manager` protocol and the - :func:`~scandir.close()` method. If a :func:`scandir` iterator is neither + :func:`~scandir.close` method. If a :func:`scandir` iterator is neither exhausted nor explicitly closed a :exc:`ResourceWarning` will be emitted in its destructor. @@ -3571,6 +3571,7 @@ features: os.remove(os.path.join(root, name)) for name in dirs: os.rmdir(os.path.join(root, name)) + os.rmdir(top) .. audit-event:: os.walk top,topdown,onerror,followlinks os.walk @@ -3701,7 +3702,7 @@ features: new file descriptor is :ref:`non-inheritable `. *initval* is the initial value of the event counter. The initial value - must be an 32 bit unsigned integer. Please note that the initial value is + must be a 32 bit unsigned integer. Please note that the initial value is limited to a 32 bit unsigned int although the event counter is an unsigned 64 bit integer with a maximum value of 2\ :sup:`64`\ -\ 2. @@ -3780,7 +3781,7 @@ features: .. data:: EFD_SEMAPHORE - Provide semaphore-like semantics for reads from a :func:`eventfd` file + Provide semaphore-like semantics for reads from an :func:`eventfd` file descriptor. On read the internal counter is decremented by one. .. availability:: Linux >= 2.6.30 @@ -4244,8 +4245,7 @@ written in Python, such as a mail server's external command delivery program. only be sent to console processes which share a common console window, e.g., some subprocesses. Any other value for *sig* will cause the process to be unconditionally killed by the TerminateProcess API, and the exit code - will be set to *sig*. The Windows version of :func:`kill` additionally takes - process handles to be killed. + will be set to *sig*. See also :func:`signal.pthread_kill`. diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index d4b0e072..c5cf4063 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -21,6 +21,12 @@ inherit from pure paths but also provide I/O operations. .. image:: pathlib-inheritance.png :align: center :class: invert-in-dark-mode + :alt: Inheritance diagram showing the classes available in pathlib. The + most basic class is PurePath, which has three direct subclasses: + PurePosixPath, PureWindowsPath, and Path. Further to these four + classes, there are two classes that use multiple inheritance: + PosixPath subclasses PurePosixPath and Path, and WindowsPath + subclasses PureWindowsPath and Path. If you've never used this module before or just aren't sure which class is right for your task, :class:`Path` is most likely what you need. It instantiates @@ -161,8 +167,8 @@ we also call *flavours*: A subclass of :class:`PurePath`, this path flavour represents non-Windows filesystem paths:: - >>> PurePosixPath('/etc') - PurePosixPath('/etc') + >>> PurePosixPath('/etc/hosts') + PurePosixPath('/etc/hosts') *pathsegments* is specified similarly to :class:`PurePath`. @@ -171,8 +177,8 @@ we also call *flavours*: A subclass of :class:`PurePath`, this path flavour represents Windows filesystem paths, including `UNC paths`_:: - >>> PureWindowsPath('c:/Program Files/') - PureWindowsPath('c:/Program Files') + >>> PureWindowsPath('c:/', 'Users', 'Ximénez') + PureWindowsPath('c:/Users/Ximénez') >>> PureWindowsPath('//server/share/file') PureWindowsPath('//server/share/file') @@ -756,8 +762,8 @@ calls on path objects. There are three ways to instantiate concrete paths: A subclass of :class:`Path` and :class:`PurePosixPath`, this class represents concrete non-Windows filesystem paths:: - >>> PosixPath('/etc') - PosixPath('/etc') + >>> PosixPath('/etc/hosts') + PosixPath('/etc/hosts') *pathsegments* is specified similarly to :class:`PurePath`. @@ -766,8 +772,8 @@ calls on path objects. There are three ways to instantiate concrete paths: A subclass of :class:`Path` and :class:`PureWindowsPath`, this class represents concrete Windows filesystem paths:: - >>> WindowsPath('c:/Program Files/') - WindowsPath('c:/Program Files') + >>> WindowsPath('c:/', 'Users', 'Ximénez') + WindowsPath('c:/Users/Ximénez') *pathsegments* is specified similarly to :class:`PurePath`. @@ -789,23 +795,119 @@ bugs or failures in your application):: % (cls.__name__,)) NotImplementedError: cannot instantiate 'WindowsPath' on your system +Some concrete path methods can raise an :exc:`OSError` if a system call fails +(for example because the path doesn't exist). + + +Expanding and resolving paths +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. classmethod:: Path.home() + + Return a new path object representing the user's home directory (as + returned by :func:`os.path.expanduser` with ``~`` construct). If the home + directory can't be resolved, :exc:`RuntimeError` is raised. + + :: + + >>> Path.home() + PosixPath('/home/antoine') + + .. versionadded:: 3.5 + + +.. method:: Path.expanduser() + + Return a new path with expanded ``~`` and ``~user`` constructs, + as returned by :meth:`os.path.expanduser`. If a home directory can't be + resolved, :exc:`RuntimeError` is raised. + + :: + + >>> p = PosixPath('~/films/Monty Python') + >>> p.expanduser() + PosixPath('/home/eric/films/Monty Python') + + .. versionadded:: 3.5 + + +.. classmethod:: Path.cwd() + + Return a new path object representing the current directory (as returned + by :func:`os.getcwd`):: + + >>> Path.cwd() + PosixPath('/home/antoine/pathlib') + + +.. method:: Path.absolute() + + Make the path absolute, without normalization or resolving symlinks. + Returns a new path object:: + + >>> p = Path('tests') + >>> p + PosixPath('tests') + >>> p.absolute() + PosixPath('/home/antoine/pathlib/tests') + + +.. method:: Path.resolve(strict=False) + + Make the path absolute, resolving any symlinks. A new path object is + returned:: + + >>> p = Path() + >>> p + PosixPath('.') + >>> p.resolve() + PosixPath('/home/antoine/pathlib') + + "``..``" components are also eliminated (this is the only method to do so):: + + >>> p = Path('docs/../setup.py') + >>> p.resolve() + PosixPath('/home/antoine/pathlib/setup.py') + + If the path doesn't exist and *strict* is ``True``, :exc:`FileNotFoundError` + is raised. If *strict* is ``False``, the path is resolved as far as possible + and any remainder is appended without checking whether it exists. If an + infinite loop is encountered along the resolution path, :exc:`RuntimeError` + is raised. + + .. versionchanged:: 3.6 + The *strict* parameter was added (pre-3.6 behavior is strict). + + +.. method:: Path.readlink() + + Return the path to which the symbolic link points (as returned by + :func:`os.readlink`):: + + >>> p = Path('mylink') + >>> p.symlink_to('setup.py') + >>> p.readlink() + PosixPath('setup.py') + + .. versionadded:: 3.9 + Querying file type and status ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. versionchanged:: 3.8 - :meth:`~Path.exists()`, :meth:`~Path.is_dir()`, :meth:`~Path.is_file()`, - :meth:`~Path.is_mount()`, :meth:`~Path.is_symlink()`, - :meth:`~Path.is_block_device()`, :meth:`~Path.is_char_device()`, - :meth:`~Path.is_fifo()`, :meth:`~Path.is_socket()` now return ``False`` + :meth:`~Path.exists`, :meth:`~Path.is_dir`, :meth:`~Path.is_file`, + :meth:`~Path.is_mount`, :meth:`~Path.is_symlink`, + :meth:`~Path.is_block_device`, :meth:`~Path.is_char_device`, + :meth:`~Path.is_fifo`, :meth:`~Path.is_socket` now return ``False`` instead of raising an exception for paths that contain characters unrepresentable at the OS level. .. method:: Path.stat(*, follow_symlinks=True) - Return a :class:`os.stat_result` object containing information about this path, like :func:`os.stat`. + Return an :class:`os.stat_result` object containing information about this path, like :func:`os.stat`. The result is looked up at each call to this method. This method normally follows symlinks; to stat a symlink add the argument @@ -1040,71 +1142,32 @@ Reading and writing files .. versionadded:: 3.5 -Other methods -^^^^^^^^^^^^^ - -Many of these methods can raise an :exc:`OSError` if a system call fails (for -example because the path doesn't exist). - - -.. classmethod:: Path.cwd() - - Return a new path object representing the current directory (as returned - by :func:`os.getcwd`):: - - >>> Path.cwd() - PosixPath('/home/antoine/pathlib') - - -.. classmethod:: Path.home() - - Return a new path object representing the user's home directory (as - returned by :func:`os.path.expanduser` with ``~`` construct). If the home - directory can't be resolved, :exc:`RuntimeError` is raised. - - :: - - >>> Path.home() - PosixPath('/home/antoine') - - .. versionadded:: 3.5 - - -.. method:: Path.chmod(mode, *, follow_symlinks=True) - - Change the file mode and permissions, like :func:`os.chmod`. - - This method normally follows symlinks. Some Unix flavours support changing - permissions on the symlink itself; on these platforms you may add the - argument ``follow_symlinks=False``, or use :meth:`~Path.lchmod`. - - :: - - >>> p = Path('setup.py') - >>> p.stat().st_mode - 33277 - >>> p.chmod(0o444) - >>> p.stat().st_mode - 33060 - - .. versionchanged:: 3.10 - The *follow_symlinks* parameter was added. - - -.. method:: Path.expanduser() +Reading directories +^^^^^^^^^^^^^^^^^^^ - Return a new path with expanded ``~`` and ``~user`` constructs, - as returned by :meth:`os.path.expanduser`. If a home directory can't be - resolved, :exc:`RuntimeError` is raised. +.. method:: Path.iterdir() - :: + When the path points to a directory, yield path objects of the directory + contents:: - >>> p = PosixPath('~/films/Monty Python') - >>> p.expanduser() - PosixPath('/home/eric/films/Monty Python') + >>> p = Path('docs') + >>> for child in p.iterdir(): child + ... + PosixPath('docs/conf.py') + PosixPath('docs/_templates') + PosixPath('docs/make.bat') + PosixPath('docs/index.rst') + PosixPath('docs/_build') + PosixPath('docs/_static') + PosixPath('docs/Makefile') - .. versionadded:: 3.5 + The children are yielded in arbitrary order, and the special entries + ``'.'`` and ``'..'`` are not included. If a file is removed from or added + to the directory after creating the iterator, it is unspecified whether + a path object for that file is included. + If the path is not a directory or otherwise inaccessible, :exc:`OSError` is + raised. .. method:: Path.glob(pattern, *, case_sensitive=None) @@ -1150,32 +1213,33 @@ example because the path doesn't exist). The *case_sensitive* parameter was added. -.. method:: Path.group() +.. method:: Path.rglob(pattern, *, case_sensitive=None) - Return the name of the group owning the file. :exc:`KeyError` is raised - if the file's gid isn't found in the system database. + Glob the given relative *pattern* recursively. This is like calling + :func:`Path.glob` with "``**/``" added in front of the *pattern*, where + *patterns* are the same as for :mod:`fnmatch`:: + >>> sorted(Path().rglob("*.py")) + [PosixPath('build/lib/pathlib.py'), + PosixPath('docs/conf.py'), + PosixPath('pathlib.py'), + PosixPath('setup.py'), + PosixPath('test_pathlib.py')] -.. method:: Path.iterdir() + By default, or when the *case_sensitive* keyword-only argument is set to + ``None``, this method matches paths using platform-specific casing rules: + typically, case-sensitive on POSIX, and case-insensitive on Windows. + Set *case_sensitive* to ``True`` or ``False`` to override this behaviour. - When the path points to a directory, yield path objects of the directory - contents:: + .. audit-event:: pathlib.Path.rglob self,pattern pathlib.Path.rglob - >>> p = Path('docs') - >>> for child in p.iterdir(): child - ... - PosixPath('docs/conf.py') - PosixPath('docs/_templates') - PosixPath('docs/make.bat') - PosixPath('docs/index.rst') - PosixPath('docs/_build') - PosixPath('docs/_static') - PosixPath('docs/Makefile') + .. versionchanged:: 3.11 + Return only directories if *pattern* ends with a pathname components + separator (:data:`~os.sep` or :data:`~os.altsep`). + + .. versionchanged:: 3.12 + The *case_sensitive* parameter was added. - The children are yielded in arbitrary order, and the special entries - ``'.'`` and ``'..'`` are not included. If a file is removed from or added - to the directory after creating the iterator, whether a path object for - that file be included is unspecified. .. method:: Path.walk(top_down=True, on_error=None, follow_symlinks=False) @@ -1208,7 +1272,7 @@ example because the path doesn't exist). This can be used to prune the search, or to impose a specific order of visiting, or even to inform :meth:`Path.walk` about directories the caller creates or renames before it resumes :meth:`Path.walk` again. Modifying *dirnames* when - *top_down* is false has no effect on the behavior of :meth:`Path.walk()` since the + *top_down* is false has no effect on the behavior of :meth:`Path.walk` since the directories in *dirnames* have already been generated by the time *dirnames* is yielded to the caller. @@ -1272,16 +1336,27 @@ example because the path doesn't exist). .. versionadded:: 3.12 -.. method:: Path.lchmod(mode) - Like :meth:`Path.chmod` but, if the path points to a symbolic link, the - symbolic link's mode is changed rather than its target's. +Creating files and directories +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. method:: Path.touch(mode=0o666, exist_ok=True) + + Create a file at this given path. If *mode* is given, it is combined + with the process's ``umask`` value to determine the file mode and access + flags. If the file already exists, the function succeeds when *exist_ok* + is true (and its modification time is updated to the current time), + otherwise :exc:`FileExistsError` is raised. + + .. seealso:: + The :meth:`~Path.open`, :meth:`~Path.write_text` and + :meth:`~Path.write_bytes` methods are often used to create files. .. method:: Path.mkdir(mode=0o777, parents=False, exist_ok=False) Create a new directory at this given path. If *mode* is given, it is - combined with the process' ``umask`` value to determine the file mode + combined with the process's ``umask`` value to determine the file mode and access flags. If the path already exists, :exc:`FileExistsError` is raised. @@ -1303,30 +1378,51 @@ example because the path doesn't exist). The *exist_ok* parameter was added. -.. method:: Path.owner() - - Return the name of the user owning the file. :exc:`KeyError` is raised - if the file's uid isn't found in the system database. +.. method:: Path.symlink_to(target, target_is_directory=False) + Make this path a symbolic link pointing to *target*. -.. method:: Path.readlink() + On Windows, a symlink represents either a file or a directory, and does not + morph to the target dynamically. If the target is present, the type of the + symlink will be created to match. Otherwise, the symlink will be created + as a directory if *target_is_directory* is true or a file symlink (the + default) otherwise. On non-Windows platforms, *target_is_directory* is ignored. - Return the path to which the symbolic link points (as returned by - :func:`os.readlink`):: + :: >>> p = Path('mylink') >>> p.symlink_to('setup.py') - >>> p.readlink() - PosixPath('setup.py') + >>> p.resolve() + PosixPath('/home/antoine/pathlib/setup.py') + >>> p.stat().st_size + 956 + >>> p.lstat().st_size + 8 - .. versionadded:: 3.9 + .. note:: + The order of arguments (link, target) is the reverse + of :func:`os.symlink`'s. + + +.. method:: Path.hardlink_to(target) + + Make this path a hard link to the same file as *target*. + + .. note:: + The order of arguments (link, target) is the reverse + of :func:`os.link`'s. + + .. versionadded:: 3.10 +Renaming and deleting +^^^^^^^^^^^^^^^^^^^^^ + .. method:: Path.rename(target) - Rename this file or directory to the given *target*, and return a new Path - instance pointing to *target*. On Unix, if *target* exists and is a file, - it will be replaced silently if the user has permission. + Rename this file or directory to the given *target*, and return a new + :class:`!Path` instance pointing to *target*. On Unix, if *target* exists + and is a file, it will be replaced silently if the user has permission. On Windows, if *target* exists, :exc:`FileExistsError` will be raised. *target* can be either a string or another path object:: @@ -1340,93 +1436,42 @@ example because the path doesn't exist). 'some text' The target path may be absolute or relative. Relative paths are interpreted - relative to the current working directory, *not* the directory of the Path - object. + relative to the current working directory, *not* the directory of the + :class:`!Path` object. It is implemented in terms of :func:`os.rename` and gives the same guarantees. .. versionchanged:: 3.8 - Added return value, return the new Path instance. + Added return value, return the new :class:`!Path` instance. .. method:: Path.replace(target) - Rename this file or directory to the given *target*, and return a new Path - instance pointing to *target*. If *target* points to an existing file or - empty directory, it will be unconditionally replaced. + Rename this file or directory to the given *target*, and return a new + :class:`!Path` instance pointing to *target*. If *target* points to an + existing file or empty directory, it will be unconditionally replaced. The target path may be absolute or relative. Relative paths are interpreted - relative to the current working directory, *not* the directory of the Path - object. + relative to the current working directory, *not* the directory of the + :class:`!Path` object. .. versionchanged:: 3.8 - Added return value, return the new Path instance. - - -.. method:: Path.absolute() - - Make the path absolute, without normalization or resolving symlinks. - Returns a new path object:: - - >>> p = Path('tests') - >>> p - PosixPath('tests') - >>> p.absolute() - PosixPath('/home/antoine/pathlib/tests') - - -.. method:: Path.resolve(strict=False) - - Make the path absolute, resolving any symlinks. A new path object is - returned:: - - >>> p = Path() - >>> p - PosixPath('.') - >>> p.resolve() - PosixPath('/home/antoine/pathlib') - - "``..``" components are also eliminated (this is the only method to do so):: + Added return value, return the new :class:`!Path` instance. - >>> p = Path('docs/../setup.py') - >>> p.resolve() - PosixPath('/home/antoine/pathlib/setup.py') - - If the path doesn't exist and *strict* is ``True``, :exc:`FileNotFoundError` - is raised. If *strict* is ``False``, the path is resolved as far as possible - and any remainder is appended without checking whether it exists. If an - infinite loop is encountered along the resolution path, :exc:`RuntimeError` - is raised. - - .. versionchanged:: 3.6 - The *strict* parameter was added (pre-3.6 behavior is strict). -.. method:: Path.rglob(pattern, *, case_sensitive=None) - - Glob the given relative *pattern* recursively. This is like calling - :func:`Path.glob` with "``**/``" added in front of the *pattern*, where - *patterns* are the same as for :mod:`fnmatch`:: - - >>> sorted(Path().rglob("*.py")) - [PosixPath('build/lib/pathlib.py'), - PosixPath('docs/conf.py'), - PosixPath('pathlib.py'), - PosixPath('setup.py'), - PosixPath('test_pathlib.py')] +.. method:: Path.unlink(missing_ok=False) - By default, or when the *case_sensitive* keyword-only argument is set to - ``None``, this method matches paths using platform-specific casing rules: - typically, case-sensitive on POSIX, and case-insensitive on Windows. - Set *case_sensitive* to ``True`` or ``False`` to override this behaviour. + Remove this file or symbolic link. If the path points to a directory, + use :func:`Path.rmdir` instead. - .. audit-event:: pathlib.Path.rglob self,pattern pathlib.Path.rglob + If *missing_ok* is false (the default), :exc:`FileNotFoundError` is + raised if the path does not exist. - .. versionchanged:: 3.11 - Return only directories if *pattern* ends with a pathname components - separator (:data:`~os.sep` or :data:`~os.altsep`). + If *missing_ok* is true, :exc:`FileNotFoundError` exceptions will be + ignored (same behavior as the POSIX ``rm -f`` command). - .. versionchanged:: 3.12 - The *case_sensitive* parameter was added. + .. versionchanged:: 3.8 + The *missing_ok* parameter was added. .. method:: Path.rmdir() @@ -1434,64 +1479,46 @@ example because the path doesn't exist). Remove this directory. The directory must be empty. -.. method:: Path.symlink_to(target, target_is_directory=False) - - Make this path a symbolic link pointing to *target*. - - On Windows, a symlink represents either a file or a directory, and does not - morph to the target dynamically. If the target is present, the type of the - symlink will be created to match. Otherwise, the symlink will be created - as a directory if *target_is_directory* is ``True`` or a file symlink (the - default) otherwise. On non-Windows platforms, *target_is_directory* is ignored. - - :: +Permissions and ownership +^^^^^^^^^^^^^^^^^^^^^^^^^ - >>> p = Path('mylink') - >>> p.symlink_to('setup.py') - >>> p.resolve() - PosixPath('/home/antoine/pathlib/setup.py') - >>> p.stat().st_size - 956 - >>> p.lstat().st_size - 8 +.. method:: Path.owner() - .. note:: - The order of arguments (link, target) is the reverse - of :func:`os.symlink`'s. + Return the name of the user owning the file. :exc:`KeyError` is raised + if the file's user identifier (UID) isn't found in the system database. -.. method:: Path.hardlink_to(target) - Make this path a hard link to the same file as *target*. +.. method:: Path.group() - .. note:: - The order of arguments (link, target) is the reverse - of :func:`os.link`'s. + Return the name of the group owning the file. :exc:`KeyError` is raised + if the file's group identifier (GID) isn't found in the system database. - .. versionadded:: 3.10 +.. method:: Path.chmod(mode, *, follow_symlinks=True) -.. method:: Path.touch(mode=0o666, exist_ok=True) + Change the file mode and permissions, like :func:`os.chmod`. - Create a file at this given path. If *mode* is given, it is combined - with the process' ``umask`` value to determine the file mode and access - flags. If the file already exists, the function succeeds if *exist_ok* - is true (and its modification time is updated to the current time), - otherwise :exc:`FileExistsError` is raised. + This method normally follows symlinks. Some Unix flavours support changing + permissions on the symlink itself; on these platforms you may add the + argument ``follow_symlinks=False``, or use :meth:`~Path.lchmod`. + :: -.. method:: Path.unlink(missing_ok=False) + >>> p = Path('setup.py') + >>> p.stat().st_mode + 33277 + >>> p.chmod(0o444) + >>> p.stat().st_mode + 33060 - Remove this file or symbolic link. If the path points to a directory, - use :func:`Path.rmdir` instead. + .. versionchanged:: 3.10 + The *follow_symlinks* parameter was added. - If *missing_ok* is false (the default), :exc:`FileNotFoundError` is - raised if the path does not exist. - If *missing_ok* is true, :exc:`FileNotFoundError` exceptions will be - ignored (same behavior as the POSIX ``rm -f`` command). +.. method:: Path.lchmod(mode) - .. versionchanged:: 3.8 - The *missing_ok* parameter was added. + Like :meth:`Path.chmod` but, if the path points to a symbolic link, the + symbolic link's mode is changed rather than its target's. Correspondence to tools in the :mod:`os` module @@ -1500,51 +1527,54 @@ Correspondence to tools in the :mod:`os` module Below is a table mapping various :mod:`os` functions to their corresponding :class:`PurePath`/:class:`Path` equivalent. -.. note:: - - Not all pairs of functions/methods below are equivalent. Some of them, - despite having some overlapping use-cases, have different semantics. They - include :func:`os.path.abspath` and :meth:`Path.absolute`, - :func:`os.path.relpath` and :meth:`PurePath.relative_to`. - -==================================== ============================== -:mod:`os` and :mod:`os.path` :mod:`pathlib` -==================================== ============================== -:func:`os.path.abspath` :meth:`Path.absolute` [#]_ -:func:`os.path.realpath` :meth:`Path.resolve` -:func:`os.chmod` :meth:`Path.chmod` -:func:`os.mkdir` :meth:`Path.mkdir` -:func:`os.makedirs` :meth:`Path.mkdir` -:func:`os.rename` :meth:`Path.rename` -:func:`os.replace` :meth:`Path.replace` -:func:`os.rmdir` :meth:`Path.rmdir` -:func:`os.remove`, :func:`os.unlink` :meth:`Path.unlink` -:func:`os.getcwd` :func:`Path.cwd` -:func:`os.path.exists` :meth:`Path.exists` -:func:`os.path.expanduser` :meth:`Path.expanduser` and - :meth:`Path.home` -:func:`os.listdir` :meth:`Path.iterdir` -:func:`os.walk` :meth:`Path.walk` -:func:`os.path.isdir` :meth:`Path.is_dir` -:func:`os.path.isfile` :meth:`Path.is_file` -:func:`os.path.islink` :meth:`Path.is_symlink` -:func:`os.link` :meth:`Path.hardlink_to` -:func:`os.symlink` :meth:`Path.symlink_to` -:func:`os.readlink` :meth:`Path.readlink` -:func:`os.path.relpath` :meth:`PurePath.relative_to` [#]_ -:func:`os.stat` :meth:`Path.stat`, - :meth:`Path.owner`, - :meth:`Path.group` -:func:`os.path.isabs` :meth:`PurePath.is_absolute` -:func:`os.path.join` :func:`PurePath.joinpath` -:func:`os.path.basename` :attr:`PurePath.name` -:func:`os.path.dirname` :attr:`PurePath.parent` -:func:`os.path.samefile` :meth:`Path.samefile` -:func:`os.path.splitext` :attr:`PurePath.stem` and - :attr:`PurePath.suffix` -==================================== ============================== +===================================== ============================================== +:mod:`os` and :mod:`os.path` :mod:`pathlib` +===================================== ============================================== +:func:`os.path.dirname` :attr:`PurePath.parent` +:func:`os.path.basename` :attr:`PurePath.name` +:func:`os.path.splitext` :attr:`PurePath.stem`, :attr:`PurePath.suffix` +:func:`os.path.join` :meth:`PurePath.joinpath` +:func:`os.path.isabs` :meth:`PurePath.is_absolute` +:func:`os.path.relpath` :meth:`PurePath.relative_to` [1]_ +:func:`os.path.expanduser` :meth:`Path.expanduser` [2]_ +:func:`os.path.realpath` :meth:`Path.resolve` +:func:`os.path.abspath` :meth:`Path.absolute` [3]_ +:func:`os.path.exists` :meth:`Path.exists` +:func:`os.path.isfile` :meth:`Path.is_file` +:func:`os.path.isdir` :meth:`Path.is_dir` +:func:`os.path.islink` :meth:`Path.is_symlink` +:func:`os.path.isjunction` :meth:`Path.is_junction` +:func:`os.path.ismount` :meth:`Path.is_mount` +:func:`os.path.samefile` :meth:`Path.samefile` +:func:`os.getcwd` :meth:`Path.cwd` +:func:`os.stat` :meth:`Path.stat` +:func:`os.lstat` :meth:`Path.lstat` +:func:`os.listdir` :meth:`Path.iterdir` +:func:`os.walk` :meth:`Path.walk` [4]_ +:func:`os.mkdir`, :func:`os.makedirs` :meth:`Path.mkdir` +:func:`os.link` :meth:`Path.hardlink_to` +:func:`os.symlink` :meth:`Path.symlink_to` +:func:`os.readlink` :meth:`Path.readlink` +:func:`os.rename` :meth:`Path.rename` +:func:`os.replace` :meth:`Path.replace` +:func:`os.remove`, :func:`os.unlink` :meth:`Path.unlink` +:func:`os.rmdir` :meth:`Path.rmdir` +:func:`os.chmod` :meth:`Path.chmod` +:func:`os.lchmod` :meth:`Path.lchmod` +===================================== ============================================== .. rubric:: Footnotes -.. [#] :func:`os.path.abspath` normalizes the resulting path, which may change its meaning in the presence of symlinks, while :meth:`Path.absolute` does not. -.. [#] :meth:`PurePath.relative_to` requires ``self`` to be the subpath of the argument, but :func:`os.path.relpath` does not. +.. [1] :func:`os.path.relpath` calls :func:`~os.path.abspath` to make paths + absolute and remove "``..``" parts, whereas :meth:`PurePath.relative_to` + is a lexical operation that raises :exc:`ValueError` when its inputs' + anchors differ (e.g. if one path is absolute and the other relative.) +.. [2] :func:`os.path.expanduser` returns the path unchanged if the home + directory can't be resolved, whereas :meth:`Path.expanduser` raises + :exc:`RuntimeError`. +.. [3] :func:`os.path.abspath` removes "``..``" components without resolving + symlinks, which may change the meaning of the path, whereas + :meth:`Path.absolute` leaves any "``..``" components in the path. +.. [4] :func:`os.walk` always follows symlinks when categorizing paths into + *dirnames* and *filenames*, whereas :meth:`Path.walk` categorizes all + symlinks into *filenames* when *follow_symlinks* is false (the default.) diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 8a6ee9c5..32c41b8b 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -49,7 +49,7 @@ You can then step through the code following this statement, and continue running without the debugger using the :pdbcmd:`continue` command. .. versionchanged:: 3.7 - The built-in :func:`breakpoint()`, when called with defaults, can be used + The built-in :func:`breakpoint`, when called with defaults, can be used instead of ``import pdb; pdb.set_trace()``. :: diff --git a/Doc/library/pkgutil.rst b/Doc/library/pkgutil.rst index 5d4ff34b..4a39d53a 100644 --- a/Doc/library/pkgutil.rst +++ b/Doc/library/pkgutil.rst @@ -26,7 +26,8 @@ support. __path__ = extend_path(__path__, __name__) For each directory on :data:`sys.path` that has a subdirectory that matches the - package name, add the subdirectory to the package's :attr:`__path__`. This is useful + package name, add the subdirectory to the package's + :attr:`~module.__path__`. This is useful if one wants to distribute different parts of a single logical package as multiple directories. @@ -34,9 +35,9 @@ support. *name* argument. This feature is similar to :file:`\*.pth` files (see the :mod:`site` module for more information), except that it doesn't special-case lines starting with ``import``. A :file:`\*.pkg` file is trusted at face - value: apart from checking for duplicates, all entries found in a - :file:`\*.pkg` file are added to the path, regardless of whether they exist - on the filesystem. (This is a feature.) + value: apart from skipping blank lines and ignoring comments, all entries + found in a :file:`\*.pkg` file are added to the path, regardless of whether + they exist on the filesystem (this is a feature). If the input path is not a list (as is the case for frozen packages) it is returned unchanged. The input path is not modified; an extended copy is diff --git a/Doc/library/pprint.rst b/Doc/library/pprint.rst index df706c10..2985f31b 100644 --- a/Doc/library/pprint.rst +++ b/Doc/library/pprint.rst @@ -35,24 +35,66 @@ Dictionaries are sorted by key before the display is computed. Functions --------- -.. function:: pp(object, *args, sort_dicts=False, **kwargs) - - Prints the formatted representation of *object* followed by a newline. - If *sort_dicts* is false (the default), dictionaries will be displayed with - their keys in insertion order, otherwise the dict keys will be sorted. - *args* and *kwargs* will be passed to :func:`~pprint.pprint` as formatting - parameters. - - >>> import pprint - >>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni'] - >>> stuff.insert(0, stuff) - >>> pprint.pp(stuff) - [, - 'spam', - 'eggs', - 'lumberjack', - 'knights', - 'ni'] +.. function:: pp(object, stream=None, indent=1, width=80, depth=None, *, \ + compact=False, sort_dicts=False, underscore_numbers=False) + + Prints the formatted representation of *object*, followed by a newline. + This function may be used in the interactive interpreter + instead of the :func:`print` function for inspecting values. + Tip: you can reassign ``print = pprint.pp`` for use within a scope. + + :param object: + The object to be printed. + + :param stream: + A file-like object to which the output will be written + by calling its :meth:`!write` method. + If ``None`` (the default), :data:`sys.stdout` is used. + :type stream: :term:`file-like object` | None + + :param int indent: + The amount of indentation added for each nesting level. + + :param int width: + The desired maximum number of characters per line in the output. + If a structure cannot be formatted within the width constraint, + a best effort will be made. + + :param depth: + The number of nesting levels which may be printed. + If the data structure being printed is too deep, + the next contained level is replaced by ``...``. + If ``None`` (the default), there is no constraint + on the depth of the objects being formatted. + :type depth: int | None + + :param bool compact: + Control the way long :term:`sequences ` are formatted. + If ``False`` (the default), + each item of a sequence will be formatted on a separate line, + otherwise as many items as will fit within the *width* + will be formatted on each output line. + + :param bool sort_dicts: + If ``True``, dictionaries will be formatted with + their keys sorted, otherwise + they will be displayed in insertion order (the default). + + :param bool underscore_numbers: + If ``True``, + integers will be formatted with the ``_`` character for a thousands separator, + otherwise underscores are not displayed (the default). + + >>> import pprint + >>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni'] + >>> stuff.insert(0, stuff) + >>> pprint.pp(stuff) + [, + 'spam', + 'eggs', + 'lumberjack', + 'knights', + 'ni'] .. versionadded:: 3.8 @@ -60,19 +102,10 @@ Functions .. function:: pprint(object, stream=None, indent=1, width=80, depth=None, *, \ compact=False, sort_dicts=True, underscore_numbers=False) - Prints the formatted representation of *object* on *stream*, followed by a - newline. If *stream* is ``None``, :data:`sys.stdout` is used. This may be used - in the interactive interpreter instead of the :func:`print` function for - inspecting values (you can even reassign ``print = pprint.pprint`` for use - within a scope). - - The configuration parameters *stream*, *indent*, *width*, *depth*, - *compact*, *sort_dicts* and *underscore_numbers* are passed to the - :class:`PrettyPrinter` constructor and their meanings are as - described in its documentation below. + Alias for :func:`~pprint.pp` with *sort_dicts* set to ``True`` by default, + which would automatically sort the dictionaries' keys, + you might want to use :func:`~pprint.pp` instead where it is ``False`` by default. - Note that *sort_dicts* is ``True`` by default and you might want to use - :func:`~pprint.pp` instead where it is ``False`` by default. .. function:: pformat(object, indent=1, width=80, depth=None, *, \ compact=False, sort_dicts=True, underscore_numbers=False) @@ -80,7 +113,7 @@ Functions Return the formatted representation of *object* as a string. *indent*, *width*, *depth*, *compact*, *sort_dicts* and *underscore_numbers* are passed to the :class:`PrettyPrinter` constructor as formatting parameters - and their meanings are as described in its documentation below. + and their meanings are as described in the documentation above. .. function:: isreadable(object) @@ -119,51 +152,39 @@ Functions PrettyPrinter Objects --------------------- -This module defines one class: - -.. First the implementation class: - - .. index:: single: ...; placeholder .. class:: PrettyPrinter(indent=1, width=80, depth=None, stream=None, *, \ compact=False, sort_dicts=True, underscore_numbers=False) - Construct a :class:`PrettyPrinter` instance. This constructor understands - several keyword parameters. - - *stream* (default :data:`!sys.stdout`) is a :term:`file-like object` to - which the output will be written by calling its :meth:`!write` method. - If both *stream* and :data:`!sys.stdout` are ``None``, then - :meth:`~PrettyPrinter.pprint` silently returns. + Construct a :class:`PrettyPrinter` instance. - Other values configure the manner in which nesting of complex data - structures is displayed. + Arguments have the same meaning as for :func:`~pprint.pp`. + Note that they are in a different order, and that *sort_dicts* defaults to ``True``. - *indent* (default 1) specifies the amount of indentation added for - each nesting level. - - *depth* controls the number of nesting levels which may be printed; if - the data structure being printed is too deep, the next contained level - is replaced by ``...``. By default, there is no constraint on the - depth of the objects being formatted. - - *width* (default 80) specifies the desired maximum number of characters per - line in the output. If a structure cannot be formatted within the width - constraint, a best effort will be made. - - *compact* impacts the way that long sequences (lists, tuples, sets, etc) - are formatted. If *compact* is false (the default) then each item of a - sequence will be formatted on a separate line. If *compact* is true, as - many items as will fit within the *width* will be formatted on each output - line. - - If *sort_dicts* is true (the default), dictionaries will be formatted with - their keys sorted, otherwise they will display in insertion order. + >>> import pprint + >>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni'] + >>> stuff.insert(0, stuff[:]) + >>> pp = pprint.PrettyPrinter(indent=4) + >>> pp.pprint(stuff) + [ ['spam', 'eggs', 'lumberjack', 'knights', 'ni'], + 'spam', + 'eggs', + 'lumberjack', + 'knights', + 'ni'] + >>> pp = pprint.PrettyPrinter(width=41, compact=True) + >>> pp.pprint(stuff) + [['spam', 'eggs', 'lumberjack', + 'knights', 'ni'], + 'spam', 'eggs', 'lumberjack', 'knights', + 'ni'] + >>> tup = ('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead', + ... ('parrot', ('fresh fruit',)))))))) + >>> pp = pprint.PrettyPrinter(depth=6) + >>> pp.pprint(tup) + ('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead', (...))))))) - If *underscore_numbers* is true, integers will be formatted with the - ``_`` character for a thousands separator, otherwise underscores are not - displayed (the default). .. versionchanged:: 3.4 Added the *compact* parameter. @@ -177,29 +198,6 @@ This module defines one class: .. versionchanged:: 3.11 No longer attempts to write to :data:`!sys.stdout` if it is ``None``. - >>> import pprint - >>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni'] - >>> stuff.insert(0, stuff[:]) - >>> pp = pprint.PrettyPrinter(indent=4) - >>> pp.pprint(stuff) - [ ['spam', 'eggs', 'lumberjack', 'knights', 'ni'], - 'spam', - 'eggs', - 'lumberjack', - 'knights', - 'ni'] - >>> pp = pprint.PrettyPrinter(width=41, compact=True) - >>> pp.pprint(stuff) - [['spam', 'eggs', 'lumberjack', - 'knights', 'ni'], - 'spam', 'eggs', 'lumberjack', 'knights', - 'ni'] - >>> tup = ('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead', - ... ('parrot', ('fresh fruit',)))))))) - >>> pp = pprint.PrettyPrinter(depth=6) - >>> pp.pprint(tup) - ('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead', (...))))))) - :class:`PrettyPrinter` instances have the following methods: @@ -269,7 +267,7 @@ let's fetch information about a project from `PyPI `_:: >>> import json >>> import pprint >>> from urllib.request import urlopen - >>> with urlopen('https://pypi.org/pypi/sampleproject/json') as resp: + >>> with urlopen('https://pypi.org/pypi/sampleproject/1.2.0/json') as resp: ... project_info = json.load(resp)['info'] In its basic form, :func:`~pprint.pp` shows the whole object:: diff --git a/Doc/library/profile.rst b/Doc/library/profile.rst index cc059b66..b89655ea 100644 --- a/Doc/library/profile.rst +++ b/Doc/library/profile.rst @@ -675,7 +675,7 @@ you are using :class:`profile.Profile` or :class:`cProfile.Profile`, that you choose (see :ref:`profile-calibration`). For most machines, a timer that returns a lone integer value will provide the best results in terms of low overhead during profiling. (:func:`os.times` is *pretty* bad, as it - returns a tuple of floating point values). If you want to substitute a + returns a tuple of floating-point values). If you want to substitute a better timer in the cleanest fashion, derive a class and hardwire a replacement dispatch method that best handles your timer call, along with the appropriate calibration constant. @@ -692,7 +692,7 @@ you are using :class:`profile.Profile` or :class:`cProfile.Profile`, As the :class:`cProfile.Profile` class cannot be calibrated, custom timer functions should be used with care and should be as fast as possible. For the best results with a custom timer, it might be necessary to hard-code it - in the C source of the internal :mod:`_lsprof` module. + in the C source of the internal :mod:`!_lsprof` module. Python 3.3 adds several new functions in :mod:`time` that can be used to make precise measurements of process or wall-clock time. For example, see diff --git a/Doc/library/pydoc.rst b/Doc/library/pydoc.rst index f7ca1e04..e8f153ee 100644 --- a/Doc/library/pydoc.rst +++ b/Doc/library/pydoc.rst @@ -21,7 +21,7 @@ modules. The documentation can be presented as pages of text on the console, served to a web browser, or saved to HTML files. For modules, classes, functions and methods, the displayed documentation is -derived from the docstring (i.e. the :attr:`!__doc__` attribute) of the object, +derived from the docstring (i.e. the :attr:`~definition.__doc__` attribute) of the object, and recursively of its documentable members. If there is no docstring, :mod:`!pydoc` tries to obtain a description from the block of comment lines just above the definition of the class, function or method in the source file, or at @@ -52,8 +52,9 @@ produced for that file. only execute code when a file is invoked as a script and not just imported. When printing output to the console, :program:`pydoc` attempts to paginate the -output for easier reading. If the :envvar:`PAGER` environment variable is set, -:program:`pydoc` will use its value as a pagination program. +output for easier reading. If either the :envvar:`MANPAGER` or the +:envvar:`PAGER` environment variable is set, :program:`pydoc` will use its +value as a pagination program. When both are set, :envvar:`MANPAGER` is used. Specifying a ``-w`` flag before the argument will cause HTML documentation to be written out to a file in the current directory, instead of displaying text diff --git a/Doc/library/random.rst b/Doc/library/random.rst index 10c88ac6..a589bf76 100644 --- a/Doc/library/random.rst +++ b/Doc/library/random.rst @@ -194,8 +194,8 @@ Functions for sequences For a given seed, the :func:`choices` function with equal weighting typically produces a different sequence than repeated calls to - :func:`choice`. The algorithm used by :func:`choices` uses floating - point arithmetic for internal consistency and speed. The algorithm used + :func:`choice`. The algorithm used by :func:`choices` uses floating-point + arithmetic for internal consistency and speed. The algorithm used by :func:`choice` defaults to integer arithmetic with repeated selections to avoid small biases from round-off error. @@ -292,12 +292,12 @@ be found in any statistics text. .. function:: random() - Return the next random floating point number in the range ``0.0 <= X < 1.0`` + Return the next random floating-point number in the range ``0.0 <= X < 1.0`` .. function:: uniform(a, b) - Return a random floating point number *N* such that ``a <= N <= b`` for + Return a random floating-point number *N* such that ``a <= N <= b`` for ``a <= b`` and ``b <= N <= a`` for ``b < a``. The end-point value ``b`` may or may not be included in the range @@ -307,7 +307,7 @@ be found in any statistics text. .. function:: triangular(low, high, mode) - Return a random floating point number *N* such that ``low <= N <= high`` and + Return a random floating-point number *N* such that ``low <= N <= high`` and with the specified *mode* between those bounds. The *low* and *high* bounds default to zero and one. The *mode* argument defaults to the midpoint between the bounds, giving a symmetric distribution. diff --git a/Doc/library/re.rst b/Doc/library/re.rst index 220bd687..0a8391a0 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -101,7 +101,7 @@ The special characters are: ``.`` (Dot.) In the default mode, this matches any character except a newline. If the :const:`DOTALL` flag has been specified, this matches any character - including a newline. + including a newline. ``(?s:.)`` matches any character regardless of flags. .. index:: single: ^ (caret); in regular expressions @@ -572,6 +572,12 @@ character ``'$'``. Word boundaries are determined by the current locale if the :py:const:`~re.LOCALE` flag is used. + .. note:: + + Note that ``\B`` does not match an empty string, which differs from + RE implementations in other programming languages such as Perl. + This behavior is kept for compatibility reasons. + .. index:: single: \d; in regular expressions ``\d`` @@ -600,10 +606,9 @@ character ``'$'``. ``\s`` For Unicode (str) patterns: - Matches Unicode whitespace characters (which includes - ``[ \t\n\r\f\v]``, and also many other characters, for example the - non-breaking spaces mandated by typography rules in many - languages). + Matches Unicode whitespace characters (as defined by :py:meth:`str.isspace`). + This includes ``[ \t\n\r\f\v]``, and also many other characters, for example the + non-breaking spaces mandated by typography rules in many languages. Matches ``[ \t\n\r\f\v]`` if the :py:const:`~re.ASCII` flag is used. @@ -911,6 +916,10 @@ Functions ``None`` if no position in the string matches the pattern; note that this is different from finding a zero-length match at some point in the string. + The expression's behaviour can be modified by specifying a *flags* value. + Values can be any of the `flags`_ variables, combined using bitwise OR + (the ``|`` operator). + .. function:: match(pattern, string, flags=0) @@ -925,6 +934,10 @@ Functions If you want to locate a match anywhere in *string*, use :func:`search` instead (see also :ref:`search-vs-match`). + The expression's behaviour can be modified by specifying a *flags* value. + Values can be any of the `flags`_ variables, combined using bitwise OR + (the ``|`` operator). + .. function:: fullmatch(pattern, string, flags=0) @@ -932,6 +945,10 @@ Functions corresponding :class:`~re.Match`. Return ``None`` if the string does not match the pattern; note that this is different from a zero-length match. + The expression's behaviour can be modified by specifying a *flags* value. + Values can be any of the `flags`_ variables, combined using bitwise OR + (the ``|`` operator). + .. versionadded:: 3.4 @@ -974,6 +991,10 @@ Functions >>> re.split(r'(\W*)', '...words...') ['', '...', '', '', 'w', '', 'o', '', 'r', '', 'd', '', 's', '...', '', '', ''] + The expression's behaviour can be modified by specifying a *flags* value. + Values can be any of the `flags`_ variables, combined using bitwise OR + (the ``|`` operator). + .. versionchanged:: 3.1 Added the optional flags argument. @@ -999,6 +1020,10 @@ Functions >>> re.findall(r'(\w+)=(\d+)', 'set width=20 and height=10') [('width', '20'), ('height', '10')] + The expression's behaviour can be modified by specifying a *flags* value. + Values can be any of the `flags`_ variables, combined using bitwise OR + (the ``|`` operator). + .. versionchanged:: 3.7 Non-empty matches can now start just after a previous empty match. @@ -1010,6 +1035,10 @@ Functions is scanned left-to-right, and matches are returned in the order found. Empty matches are included in the result. + The expression's behaviour can be modified by specifying a *flags* value. + Values can be any of the `flags`_ variables, combined using bitwise OR + (the ``|`` operator). + .. versionchanged:: 3.7 Non-empty matches can now start just after a previous empty match. @@ -1065,6 +1094,10 @@ Functions character ``'0'``. The backreference ``\g<0>`` substitutes in the entire substring matched by the RE. + The expression's behaviour can be modified by specifying a *flags* value. + Values can be any of the `flags`_ variables, combined using bitwise OR + (the ``|`` operator). + .. versionchanged:: 3.1 Added the optional flags argument. @@ -1100,6 +1133,10 @@ Functions .. versionchanged:: 3.5 Unmatched groups are replaced with an empty string. + The expression's behaviour can be modified by specifying a *flags* value. + Values can be any of the `flags`_ variables, combined using bitwise OR + (the ``|`` operator). + .. function:: escape(pattern) diff --git a/Doc/library/readline.rst b/Doc/library/readline.rst index 43cf8d5c..f02aec8a 100644 --- a/Doc/library/readline.rst +++ b/Doc/library/readline.rst @@ -44,6 +44,10 @@ Readline library in general. python:bind -v python:bind ^I rl_complete + Also note that different libraries may use different history file formats. + When switching the underlying library, existing history files may become + unusable. + Init file --------- diff --git a/Doc/library/removed.rst b/Doc/library/removed.rst new file mode 100644 index 00000000..4aafb088 --- /dev/null +++ b/Doc/library/removed.rst @@ -0,0 +1,20 @@ +:tocdepth: 1 + +.. _removed: + +*************** +Removed Modules +*************** + +The modules described in this chapter have been removed from the Python +standard library. They are documented here to help people find replacements. + + +.. toctree:: + :maxdepth: 1 + + asynchat.rst + asyncore.rst + distutils.rst + imp.rst + smtpd.rst diff --git a/Doc/library/resource.rst b/Doc/library/resource.rst index 7465bc54..02009d82 100644 --- a/Doc/library/resource.rst +++ b/Doc/library/resource.rst @@ -305,7 +305,7 @@ These functions are used to retrieve resource usage information: elements. The fields :attr:`ru_utime` and :attr:`ru_stime` of the return value are - floating point values representing the amount of time spent executing in user + floating-point values representing the amount of time spent executing in user mode and the amount of time spent executing in system mode, respectively. The remaining values are integers. Consult the :manpage:`getrusage(2)` man page for detailed information about these values. A brief summary is presented here: diff --git a/Doc/library/secrets.rst b/Doc/library/secrets.rst index 1401a925..75dafc54 100644 --- a/Doc/library/secrets.rst +++ b/Doc/library/secrets.rst @@ -52,7 +52,7 @@ randomness that your operating system provides. .. function:: randbits(k) - Return an int with *k* random bits. + Return a non-negative int with *k* random bits. Generating tokens diff --git a/Doc/library/select.rst b/Doc/library/select.rst index 06ebaf02..f23a249f 100644 --- a/Doc/library/select.rst +++ b/Doc/library/select.rst @@ -129,7 +129,7 @@ The module defines the following: Empty iterables are allowed, but acceptance of three empty iterables is platform-dependent. (It is known to work on Unix but not on Windows.) The - optional *timeout* argument specifies a time-out as a floating point number + optional *timeout* argument specifies a time-out as a floating-point number in seconds. When the *timeout* argument is omitted the function blocks until at least one file descriptor is ready. A time-out value of zero specifies a poll and never blocks. diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index 49d2c7ff..08128f87 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -439,8 +439,10 @@ Directory and files operations *mode* is a permission mask passed to :func:`os.access`, by default determining if the file exists and is executable. - When no *path* is specified, the results of :func:`os.environ` are used, - returning either the "PATH" value or a fallback of :data:`os.defpath`. + *path* is a "``PATH`` string" specifying the directories to look in, + delimited by :data:`os.pathsep`. When no *path* is specified, the + :envvar:`PATH` environment variable is read from :data:`os.environ`, + falling back to :data:`os.defpath` if it is not set. On Windows, the current directory is prepended to the *path* if *mode* does not include ``os.X_OK``. When the *mode* does include ``os.X_OK``, the @@ -449,9 +451,9 @@ Directory and files operations consulting the current working directory for executables: set the environment variable ``NoDefaultCurrentDirectoryInExePath``. - Also on Windows, the ``PATHEXT`` variable is used to resolve commands - that may not already include an extension. For example, if you call - ``shutil.which("python")``, :func:`which` will search ``PATHEXT`` + Also on Windows, the :envvar:`PATHEXT` environment variable is used to + resolve commands that may not already include an extension. For example, + if you call ``shutil.which("python")``, :func:`which` will search ``PATHEXT`` to know that it should look for ``python.exe`` within the *path* directories. For example, on Windows:: @@ -479,12 +481,6 @@ Directory and files operations or ends with an extension that is in ``PATHEXT``; and filenames that have no extension can now be found. - .. versionchanged:: 3.12.1 - On Windows, if *mode* includes ``os.X_OK``, executables with an - extension in ``PATHEXT`` will be preferred over executables without a - matching extension. - This brings behavior closer to that of Python 3.11. - .. exception:: Error This exception collects exceptions that are raised during a multi-file diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst index 60f21bc9..641a6c02 100644 --- a/Doc/library/signal.rst +++ b/Doc/library/signal.rst @@ -425,7 +425,7 @@ The :mod:`signal` module defines the following functions: signal to a particular Python thread would be to force a running system call to fail with :exc:`InterruptedError`. - Use :func:`threading.get_ident()` or the :attr:`~threading.Thread.ident` + Use :func:`threading.get_ident` or the :attr:`~threading.Thread.ident` attribute of :class:`threading.Thread` objects to get a suitable value for *thread_id*. diff --git a/Doc/library/site.rst b/Doc/library/site.rst index f5cf81fb..514eed31 100644 --- a/Doc/library/site.rst +++ b/Doc/library/site.rst @@ -15,8 +15,9 @@ import can be suppressed using the interpreter's :option:`-S` option. .. index:: triple: module; search; path -Importing this module will append site-specific paths to the module search path -and add a few builtins, unless :option:`-S` was used. In that case, this module +Importing this module normally appends site-specific paths to the module search path +and adds :ref:`callables `, including :func:`help` to the built-in +namespace. However, Python startup option :option:`-S` blocks this and this module can be safely imported with no automatic modifications to the module search path or additions to the builtins. To explicitly trigger the usual site-specific additions, call the :func:`main` function. diff --git a/Doc/library/smtpd.rst b/Doc/library/smtpd.rst new file mode 100644 index 00000000..c704f4a2 --- /dev/null +++ b/Doc/library/smtpd.rst @@ -0,0 +1,18 @@ +:mod:`!smtpd` --- SMTP Server +============================= + +.. module:: smtpd + :synopsis: Removed in 3.12. + :deprecated: + +.. deprecated-removed:: 3.6 3.12 + +This module is no longer part of the Python standard library. +It was :ref:`removed in Python 3.12 ` after +being deprecated in Python 3.6. The removal was decided in :pep:`594`. + +A possible replacement is the third-party :pypi:`aiosmtpd` library. This +library is not maintained or supported by the Python core team. + +The last version of Python that provided the :mod:`!smtpd` module was +`Python 3.11 `_. diff --git a/Doc/library/smtplib.rst b/Doc/library/smtplib.rst index 2511ef7f..7cd530a5 100644 --- a/Doc/library/smtplib.rst +++ b/Doc/library/smtplib.rst @@ -556,34 +556,33 @@ This example prompts the user for addresses needed in the message envelope ('To' and 'From' addresses), and the message to be delivered. Note that the headers to be included with the message must be included in the message as entered; this example doesn't do any processing of the :rfc:`822` headers. In particular, the -'To' and 'From' addresses must be included in the message headers explicitly. :: +'To' and 'From' addresses must be included in the message headers explicitly:: import smtplib - def prompt(prompt): - return input(prompt).strip() + def prompt(title): + return input(title).strip() - fromaddr = prompt("From: ") - toaddrs = prompt("To: ").split() + from_addr = prompt("From: ") + to_addrs = prompt("To: ").split() print("Enter message, end with ^D (Unix) or ^Z (Windows):") # Add the From: and To: headers at the start! - msg = ("From: %s\r\nTo: %s\r\n\r\n" - % (fromaddr, ", ".join(toaddrs))) + lines = [f"From: {from_addr}", f"To: {', '.join(to_addrs)}", ""] while True: try: line = input() except EOFError: break - if not line: - break - msg = msg + line + else: + lines.append(line) + msg = "\r\n".join(lines) print("Message length is", len(msg)) - server = smtplib.SMTP('localhost') + server = smtplib.SMTP("localhost") server.set_debuglevel(1) - server.sendmail(fromaddr, toaddrs, msg) + server.sendmail(from_addr, to_addrs, msg) server.quit() .. note:: diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 10f03b3f..dd4c2f83 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -695,6 +695,13 @@ Constants .. versionadded:: 3.12 +.. data:: SHUT_RD + SHUT_WR + SHUT_RDWR + + These constants are used by the :meth:`~socket.socket.shutdown` method of socket objects. + + .. availability:: not WASI. Functions ^^^^^^^^^ @@ -724,7 +731,7 @@ The following functions all create :ref:`socket objects `. of :meth:`socket.getpeername` but not the actual OS resource. 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()`. + :meth:`socket.close`. The newly created socket is :ref:`non-inheritable `. @@ -908,7 +915,9 @@ The :mod:`socket` module also offers various network-related services: .. versionadded:: 3.7 -.. function:: getaddrinfo(host, port, family=0, type=0, proto=0, flags=0) +.. function:: getaddrinfo(host, port, family=AF_UNSPEC, type=0, proto=0, flags=0) + + This function wraps the C function ``getaddrinfo`` of the underlying system. Translate the *host*/*port* argument into a sequence of 5-tuples that contain all the necessary arguments for creating a socket connected to that service. @@ -918,8 +927,10 @@ The :mod:`socket` module also offers various network-related services: and *port*, you can pass ``NULL`` to the underlying C API. The *family*, *type* and *proto* arguments can be optionally specified - in order to narrow the list of addresses returned. Passing zero as a - value for each of these arguments selects the full range of results. + in order to provide options and limit the list of addresses returned. + Pass their default values (:data:`AF_UNSPEC`, 0, and 0, respectively) + to not limit the results. See the note below for details. + The *flags* argument can be one or several of the ``AI_*`` constants, and will influence how results are computed and returned. For example, :const:`AI_NUMERICHOST` will disable domain name resolution @@ -939,6 +950,29 @@ The :mod:`socket` module also offers various network-related services: :const:`AF_INET6`), and is meant to be passed to the :meth:`socket.connect` method. + .. note:: + + If you intend to use results from :func:`!getaddrinfo` to create a socket + (rather than, for example, retrieve *canonname*), + consider limiting the results by *type* (e.g. :data:`SOCK_STREAM` or + :data:`SOCK_DGRAM`) and/or *proto* (e.g. :data:`IPPROTO_TCP` or + :data:`IPPROTO_UDP`) that your application can handle. + + The behavior with default values of *family*, *type*, *proto* + and *flags* is system-specific. + + Many systems (for example, most Linux configurations) will return a sorted + list of all matching addresses. + These addresses should generally be tried in order until a connection succeeds + (possibly tried in parallel, for example, using a `Happy Eyeballs`_ algorithm). + In these cases, limiting the *type* and/or *proto* can help eliminate + unsuccessful or unusable connection attempts. + + Some systems will, however, only return a single address. + (For example, this was reported on Solaris and AIX configurations.) + On these systems, limiting the *type* and/or *proto* helps ensure that + this address is usable. + .. audit-event:: socket.getaddrinfo host,port,family,type,protocol socket.getaddrinfo The following example fetches address information for a hypothetical TCP @@ -958,6 +992,8 @@ The :mod:`socket` module also offers various network-related services: for IPv6 multicast addresses, string representing an address will not contain ``%scope_id`` part. +.. _Happy Eyeballs: https://en.wikipedia.org/wiki/Happy_Eyeballs + .. function:: getfqdn([name]) Return a fully qualified domain name for *name*. If *name* is omitted or empty, @@ -1403,7 +1439,7 @@ to sockets. .. method:: socket.close() Mark the socket closed. The underlying system resource (e.g. a file - descriptor) is also closed when all file objects from :meth:`makefile()` + descriptor) is also closed when all file objects from :meth:`makefile` are closed. Once that happens, all future operations on the socket object will fail. The remote end will receive no more data (after queued data is flushed). @@ -1418,10 +1454,10 @@ to sockets. .. note:: - :meth:`close()` releases the resource associated with a connection but + :meth:`close` releases the resource associated with a connection but does not necessarily close the connection immediately. If you want - to close the connection in a timely fashion, call :meth:`shutdown()` - before :meth:`close()`. + to close the connection in a timely fashion, call :meth:`shutdown` + before :meth:`close`. .. method:: socket.connect(address) @@ -1917,7 +1953,7 @@ to sockets. .. method:: socket.settimeout(value) Set a timeout on blocking socket operations. The *value* argument can be a - nonnegative floating point number expressing seconds, or ``None``. + nonnegative floating-point number expressing seconds, or ``None``. If a non-zero value is given, subsequent socket operations will raise a :exc:`timeout` exception if the timeout period *value* has elapsed before the operation has completed. If zero is given, the socket is put in @@ -2030,7 +2066,7 @@ can be changed by calling :func:`setdefaulttimeout`. in non-blocking mode. Also, the blocking and timeout modes are shared between file descriptors and socket objects that refer to the same network endpoint. This implementation detail can have visible consequences if e.g. you decide - to use the :meth:`~socket.fileno()` of a socket. + to use the :meth:`~socket.fileno` of a socket. Timeouts and the ``connect`` method ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 70f1e05a..3078ec29 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -127,7 +127,7 @@ and call :meth:`res.fetchone() ` to fetch the resulting row: We can see that the table has been created, as the query returns a :class:`tuple` containing the table's name. If we query ``sqlite_master`` for a non-existent table ``spam``, -:meth:`!res.fetchone()` will return ``None``: +:meth:`!res.fetchone` will return ``None``: .. doctest:: @@ -519,21 +519,20 @@ Module constants The mappings from SQLite threading modes to DB-API 2.0 threadsafety levels are as follows: - +------------------+-----------------+----------------------+-------------------------------+ - | SQLite threading | `threadsafety`_ | `SQLITE_THREADSAFE`_ | DB-API 2.0 meaning | - | mode | | | | - +==================+=================+======================+===============================+ - | single-thread | 0 | 0 | Threads may not share the | - | | | | module | - +------------------+-----------------+----------------------+-------------------------------+ - | multi-thread | 1 | 2 | Threads may share the module, | - | | | | but not connections | - +------------------+-----------------+----------------------+-------------------------------+ - | serialized | 3 | 1 | Threads may share the module, | - | | | | connections and cursors | - +------------------+-----------------+----------------------+-------------------------------+ - - .. _threadsafety: https://peps.python.org/pep-0249/#threadsafety + +------------------+----------------------+----------------------+-------------------------------+ + | SQLite threading | :pep:`threadsafety | `SQLITE_THREADSAFE`_ | DB-API 2.0 meaning | + | mode | <0249#threadsafety>` | | | + +==================+======================+======================+===============================+ + | single-thread | 0 | 0 | Threads may not share the | + | | | | module | + +------------------+----------------------+----------------------+-------------------------------+ + | multi-thread | 1 | 2 | Threads may share the module, | + | | | | but not connections | + +------------------+----------------------+----------------------+-------------------------------+ + | serialized | 3 | 1 | Threads may share the module, | + | | | | connections and cursors | + +------------------+----------------------+----------------------+-------------------------------+ + .. _SQLITE_THREADSAFE: https://sqlite.org/compile.html#threadsafe .. versionchanged:: 3.11 @@ -2421,6 +2420,7 @@ Some useful URI tricks include: >>> con.execute("CREATE TABLE readonly(data)") Traceback (most recent call last): OperationalError: attempt to write a readonly database + >>> con.close() * Do not implicitly create a new database file if it does not already exist; will raise :exc:`~sqlite3.OperationalError` if unable to create a new file: diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index 8fb0d505..f78ab7b1 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -1021,25 +1021,25 @@ SSL Sockets SSL sockets provide the following methods of :ref:`socket-objects`: - - :meth:`~socket.socket.accept()` - - :meth:`~socket.socket.bind()` - - :meth:`~socket.socket.close()` - - :meth:`~socket.socket.connect()` - - :meth:`~socket.socket.detach()` - - :meth:`~socket.socket.fileno()` - - :meth:`~socket.socket.getpeername()`, :meth:`~socket.socket.getsockname()` - - :meth:`~socket.socket.getsockopt()`, :meth:`~socket.socket.setsockopt()` - - :meth:`~socket.socket.gettimeout()`, :meth:`~socket.socket.settimeout()`, - :meth:`~socket.socket.setblocking()` - - :meth:`~socket.socket.listen()` - - :meth:`~socket.socket.makefile()` - - :meth:`~socket.socket.recv()`, :meth:`~socket.socket.recv_into()` + - :meth:`~socket.socket.accept` + - :meth:`~socket.socket.bind` + - :meth:`~socket.socket.close` + - :meth:`~socket.socket.connect` + - :meth:`~socket.socket.detach` + - :meth:`~socket.socket.fileno` + - :meth:`~socket.socket.getpeername`, :meth:`~socket.socket.getsockname` + - :meth:`~socket.socket.getsockopt`, :meth:`~socket.socket.setsockopt` + - :meth:`~socket.socket.gettimeout`, :meth:`~socket.socket.settimeout`, + :meth:`~socket.socket.setblocking` + - :meth:`~socket.socket.listen` + - :meth:`~socket.socket.makefile` + - :meth:`~socket.socket.recv`, :meth:`~socket.socket.recv_into` (but passing a non-zero ``flags`` argument is not allowed) - - :meth:`~socket.socket.send()`, :meth:`~socket.socket.sendall()` (with + - :meth:`~socket.socket.send`, :meth:`~socket.socket.sendall` (with the same limitation) - - :meth:`~socket.socket.sendfile()` (but :mod:`os.sendfile` will be used - for plain-text sockets only, else :meth:`~socket.socket.send()` will be used) - - :meth:`~socket.socket.shutdown()` + - :meth:`~socket.socket.sendfile` (but :mod:`os.sendfile` will be used + for plain-text sockets only, else :meth:`~socket.socket.send` will be used) + - :meth:`~socket.socket.shutdown` However, since the SSL (and TLS) protocol has its own framing atop of TCP, the SSL sockets abstraction can, in certain respects, diverge from @@ -1428,6 +1428,19 @@ to speed up repeated connections from the same clients. :data:`PROTOCOL_TLS`, :data:`PROTOCOL_TLS_CLIENT`, and :data:`PROTOCOL_TLS_SERVER` use TLS 1.2 as minimum TLS version. + .. note:: + + :class:`SSLContext` only supports limited mutation once it has been used + by a connection. Adding new certificates to the internal trust store is + allowed, but changing ciphers, verification settings, or mTLS + certificates may result in surprising behavior. + + .. note:: + + :class:`SSLContext` is designed to be shared and used by multiple + connections. + Thus, it is thread-safe as long as it is not reconfigured after being + used by a connection. :class:`SSLContext` objects have the following methods and attributes: @@ -1509,7 +1522,7 @@ to speed up repeated connections from the same clients. The *capath* string, if present, is the path to a directory containing several CA certificates in PEM format, following an `OpenSSL specific layout - `_. + `_. The *cadata* object, if present, is either an ASCII string of one or more PEM-encoded certificates or a :term:`bytes-like object` of DER-encoded @@ -1584,7 +1597,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 - `_. + `_. 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. @@ -1684,7 +1697,7 @@ to speed up repeated connections from the same clients. IDN-encoded internationalized domain name, the *server_name_callback* receives a decoded U-label (``"pythön.org"``). - If there is an decoding error on the server name, the TLS connection will + If there is a decoding error on the server name, the TLS connection will terminate with an :const:`ALERT_DESCRIPTION_INTERNAL_ERROR` fatal TLS alert message to the client. @@ -1816,7 +1829,7 @@ to speed up repeated connections from the same clients. .. method:: SSLContext.session_stats() Get statistics about the SSL sessions created or managed by this context. - A dictionary is returned which maps the names of each `piece of information `_ to their + A dictionary is returned which maps the names of each `piece of information `_ to their numeric values. For example, here is the total number of hits and misses in the session cache since the context was created:: @@ -1959,7 +1972,7 @@ to speed up repeated connections from the same clients. .. attribute:: SSLContext.security_level An integer representing the `security level - `_ + `_ for the context. This attribute is read-only. .. versionadded:: 3.10 @@ -2556,7 +2569,7 @@ Verifying certificates When calling the :class:`SSLContext` constructor directly, :const:`CERT_NONE` is the default. Since it does not authenticate the other -peer, it can be insecure, especially in client mode where most of time you +peer, it can be insecure, especially in client mode where most of the time you would like to ensure the authenticity of the server you're talking to. Therefore, when in client mode, it is highly recommended to use :const:`CERT_REQUIRED`. However, it is in itself not sufficient; you also @@ -2605,7 +2618,7 @@ enabled when negotiating a SSL session is possible through the :meth:`SSLContext.set_ciphers` method. Starting from Python 3.2.3, the ssl module disables certain weak ciphers by default, but you may want to further restrict the cipher choice. Be sure to read OpenSSL's documentation -about the `cipher list format `_. +about the `cipher list format `_. If you want to check which ciphers are enabled by a given cipher list, use :meth:`SSLContext.get_ciphers` or the ``openssl ciphers`` command on your system. diff --git a/Doc/library/statistics.rst b/Doc/library/statistics.rst index 6da3bced..ce1b8a11 100644 --- a/Doc/library/statistics.rst +++ b/Doc/library/statistics.rst @@ -73,7 +73,7 @@ or sample. ======================= =============================================================== :func:`mean` Arithmetic mean ("average") of data. -:func:`fmean` Fast, floating point arithmetic mean, with optional weighting. +:func:`fmean` Fast, floating-point arithmetic mean, with optional weighting. :func:`geometric_mean` Geometric mean of data. :func:`harmonic_mean` Harmonic mean of data. :func:`median` Median (middle value) of data. @@ -408,6 +408,12 @@ However, for reading convenience, most of the examples show sorted sequences. >>> mode(["red", "blue", "blue", "red", "green", "red", "red"]) 'red' + Only hashable inputs are supported. To handle type :class:`set`, + consider casting to :class:`frozenset`. To handle type :class:`list`, + consider casting to :class:`tuple`. For mixed or nested inputs, consider + using this slower quadratic algorithm that only depends on equality tests: + ``max(data, key=data.count)``. + .. versionchanged:: 3.8 Now handles multimodal datasets by returning the first mode encountered. Formerly, it raised :exc:`StatisticsError` when more than one mode was diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index d11bfb80..cc67a378 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -209,18 +209,18 @@ Numeric Types --- :class:`int`, :class:`float`, :class:`complex` pair: object; numeric pair: object; Boolean pair: object; integer - pair: object; floating point + pair: object; floating-point pair: object; complex number pair: C; language -There are three distinct numeric types: :dfn:`integers`, :dfn:`floating -point numbers`, and :dfn:`complex numbers`. In addition, Booleans are a -subtype of integers. Integers have unlimited precision. Floating point +There are three distinct numeric types: :dfn:`integers`, :dfn:`floating-point +numbers`, and :dfn:`complex numbers`. In addition, Booleans are a +subtype of integers. Integers have unlimited precision. Floating-point numbers are usually implemented using :c:expr:`double` in C; information -about the precision and internal representation of floating point +about the precision and internal representation of floating-point numbers for the machine on which your program is running is available in :data:`sys.float_info`. Complex numbers have a real and imaginary -part, which are each a floating point number. To extract these parts +part, which are each a floating-point number. To extract these parts from a complex number *z*, use ``z.real`` and ``z.imag``. (The standard library includes the additional numeric types :mod:`fractions.Fraction`, for rationals, and :mod:`decimal.Decimal`, for floating-point numbers with @@ -229,7 +229,7 @@ user-definable precision.) .. index:: pair: numeric; literals pair: integer; literals - pair: floating point; literals + pair: floating-point; literals pair: complex number; literals pair: hexadecimal; literals pair: octal; literals @@ -238,7 +238,7 @@ user-definable precision.) Numbers are created by numeric literals or as the result of built-in functions and operators. Unadorned integer literals (including hex, octal and binary numbers) yield integers. Numeric literals containing a decimal point or an -exponent sign yield floating point numbers. Appending ``'j'`` or ``'J'`` to a +exponent sign yield floating-point numbers. Appending ``'j'`` or ``'J'`` to a numeric literal yields an imaginary number (a complex number with a zero real part) which you can add to an integer or float to get a complex number with real and imaginary parts. @@ -832,7 +832,7 @@ over ``&``, ``|`` and ``^``. .. deprecated:: 3.12 The use of the bitwise inversion operator ``~`` is deprecated and will - raise an error in Python 3.14. + raise an error in Python 3.16. :class:`bool` is a subclass of :class:`int` (see :ref:`typesnumeric`). In many numeric contexts, ``False`` and ``True`` behave like the integers 0 and 1, respectively. @@ -1209,8 +1209,9 @@ accepts integers that meet the value restriction ``0 <= x <= 255``). | ``s.pop()`` or ``s.pop(i)`` | retrieves the item at *i* and | \(2) | | | also removes it from *s* | | +------------------------------+--------------------------------+---------------------+ -| ``s.remove(x)`` | remove the first item from *s* | \(3) | -| | where ``s[i]`` is equal to *x* | | +| ``s.remove(x)`` | removes the first item from | \(3) | +| | *s* where ``s[i]`` is equal to | | +| | *x* | | +------------------------------+--------------------------------+---------------------+ | ``s.reverse()`` | reverses the items of *s* in | \(4) | | | place | | @@ -1220,7 +1221,7 @@ accepts integers that meet the value restriction ``0 <= x <= 255``). Notes: (1) - *t* must have the same length as the slice it is replacing. + If *k* is not equal to ``1``, *t* must have the same length as the slice it is replacing. (2) The optional argument *i* defaults to ``-1``, so that by default the last @@ -1497,8 +1498,8 @@ objects that compare equal might have different :attr:`~range.start`, .. seealso:: * The `linspace recipe `_ - shows how to implement a lazy version of range suitable for floating - point applications. + shows how to implement a lazy version of range suitable for floating-point + applications. .. index:: single: string; text sequence type @@ -2092,8 +2093,9 @@ expression support in the :mod:`re` module). If *sep* is given, consecutive delimiters are not grouped together and are deemed to delimit empty strings (for example, ``'1,,2'.split(',')`` returns ``['1', '', '2']``). The *sep* argument may consist of multiple characters - (for example, ``'1<>2<>3'.split('<>')`` returns ``['1', '2', '3']``). - Splitting an empty string with a specified separator returns ``['']``. + as a single delimiter (to split with multiple delimiters, use + :func:`re.split`). Splitting an empty string with a specified separator + returns ``['']``. For example:: @@ -2103,6 +2105,8 @@ expression support in the :mod:`re` module). ['1', '2,3'] >>> '1,2,,3,'.split(',') ['1', '2', '', '3', ''] + >>> '1<>2<>3<4'.split('<>') + ['1', '2', '3<4'] If *sep* is not specified or is ``None``, a different splitting algorithm is applied: runs of consecutive whitespace are regarded as a single separator, @@ -2430,19 +2434,19 @@ The conversion types are: +------------+-----------------------------------------------------+-------+ | ``'X'`` | Signed hexadecimal (uppercase). | \(2) | +------------+-----------------------------------------------------+-------+ -| ``'e'`` | Floating point exponential format (lowercase). | \(3) | +| ``'e'`` | Floating-point exponential format (lowercase). | \(3) | +------------+-----------------------------------------------------+-------+ -| ``'E'`` | Floating point exponential format (uppercase). | \(3) | +| ``'E'`` | Floating-point exponential format (uppercase). | \(3) | +------------+-----------------------------------------------------+-------+ -| ``'f'`` | Floating point decimal format. | \(3) | +| ``'f'`` | Floating-point decimal format. | \(3) | +------------+-----------------------------------------------------+-------+ -| ``'F'`` | Floating point decimal format. | \(3) | +| ``'F'`` | Floating-point decimal format. | \(3) | +------------+-----------------------------------------------------+-------+ -| ``'g'`` | Floating point format. Uses lowercase exponential | \(4) | +| ``'g'`` | Floating-point format. Uses lowercase exponential | \(4) | | | format if exponent is less than -4 or not less than | | | | precision, decimal format otherwise. | | +------------+-----------------------------------------------------+-------+ -| ``'G'`` | Floating point format. Uses uppercase exponential | \(4) | +| ``'G'`` | Floating-point format. Uses uppercase exponential | \(4) | | | format if exponent is less than -4 or not less than | | | | precision, decimal format otherwise. | | +------------+-----------------------------------------------------+-------+ @@ -3140,10 +3144,9 @@ produce new objects. If *sep* is given, consecutive delimiters are not grouped together and are deemed to delimit empty subsequences (for example, ``b'1,,2'.split(b',')`` returns ``[b'1', b'', b'2']``). The *sep* argument may consist of a - multibyte sequence (for example, ``b'1<>2<>3'.split(b'<>')`` returns - ``[b'1', b'2', b'3']``). Splitting an empty sequence with a specified - separator returns ``[b'']`` or ``[bytearray(b'')]`` depending on the type - of object being split. The *sep* argument may be any + multibyte sequence as a single delimiter. Splitting an empty sequence with + a specified separator returns ``[b'']`` or ``[bytearray(b'')]`` depending + on the type of object being split. The *sep* argument may be any :term:`bytes-like object`. For example:: @@ -3154,6 +3157,8 @@ produce new objects. [b'1', b'2,3'] >>> b'1,2,,3,'.split(b',') [b'1', b'2', b'', b'3', b''] + >>> b'1<>2<>3<4'.split(b'<>') + [b'1', b'2', b'3<4'] If *sep* is not specified or is ``None``, a different splitting algorithm is applied: runs of consecutive ASCII whitespace are regarded as a single @@ -3427,7 +3432,7 @@ place, and instead produce new objects. ``b'abcdefghijklmnopqrstuvwxyz'``. Uppercase ASCII characters are those byte values in the sequence ``b'ABCDEFGHIJKLMNOPQRSTUVWXYZ'``. - Unlike :func:`str.swapcase()`, it is always the case that + Unlike :func:`str.swapcase`, it is always the case that ``bin.swapcase().swapcase() == bin`` for the binary versions. Case conversions are symmetrical in ASCII, even though that is not generally true for arbitrary Unicode code points. @@ -3648,19 +3653,19 @@ The conversion types are: +------------+-----------------------------------------------------+-------+ | ``'X'`` | Signed hexadecimal (uppercase). | \(2) | +------------+-----------------------------------------------------+-------+ -| ``'e'`` | Floating point exponential format (lowercase). | \(3) | +| ``'e'`` | Floating-point exponential format (lowercase). | \(3) | +------------+-----------------------------------------------------+-------+ -| ``'E'`` | Floating point exponential format (uppercase). | \(3) | +| ``'E'`` | Floating-point exponential format (uppercase). | \(3) | +------------+-----------------------------------------------------+-------+ -| ``'f'`` | Floating point decimal format. | \(3) | +| ``'f'`` | Floating-point decimal format. | \(3) | +------------+-----------------------------------------------------+-------+ -| ``'F'`` | Floating point decimal format. | \(3) | +| ``'F'`` | Floating-point decimal format. | \(3) | +------------+-----------------------------------------------------+-------+ -| ``'g'`` | Floating point format. Uses lowercase exponential | \(4) | +| ``'g'`` | Floating-point format. Uses lowercase exponential | \(4) | | | format if exponent is less than -4 or not less than | | | | precision, decimal format otherwise. | | +------------+-----------------------------------------------------+-------+ -| ``'G'`` | Floating point format. Uses uppercase exponential | \(4) | +| ``'G'`` | Floating-point format. Uses uppercase exponential | \(4) | | | format if exponent is less than -4 or not less than | | | | precision, decimal format otherwise. | | +------------+-----------------------------------------------------+-------+ @@ -3882,7 +3887,7 @@ copying. >>> a == b False - Note that, as with floating point numbers, ``v is w`` does *not* imply + Note that, as with floating-point numbers, ``v is w`` does *not* imply ``v == w`` for memoryview objects. .. versionchanged:: 3.3 @@ -3973,7 +3978,7 @@ copying. dangling resources) as soon as possible. After this method has been called, any further operation on the view - raises a :class:`ValueError` (except :meth:`release()` itself which can + raises a :class:`ValueError` (except :meth:`release` itself which can be called multiple times):: >>> m = memoryview(b'abc') @@ -4455,14 +4460,14 @@ can be used interchangeably to index the same dictionary entry. ``dict([('foo', 100), ('bar', 200)])``, ``dict(foo=100, bar=200)`` If no positional argument is given, an empty dictionary is created. - If a positional argument is given and it is a mapping object, a dictionary - is created with the same key-value pairs as the mapping object. Otherwise, - the positional argument must be an :term:`iterable` object. Each item in - the iterable must itself be an iterable with exactly two objects. The - first object of each item becomes a key in the new dictionary, and the - second object the corresponding value. If a key occurs more than once, the - last value for that key becomes the corresponding value in the new - dictionary. + If a positional argument is given and it defines a ``keys()`` method, a + dictionary is created by calling :meth:`~object.__getitem__` on the argument with + each returned key from the method. Otherwise, the positional argument must be an + :term:`iterable` object. Each item in the iterable must itself be an iterable + with exactly two elements. The first element of each item becomes a key in the + new dictionary, and the second element the corresponding value. If a key occurs + more than once, the last value for that key becomes the corresponding value in + the new dictionary. If keyword arguments are given, the keyword arguments and their values are added to the dictionary created from the positional argument. If a key @@ -4556,7 +4561,7 @@ can be used interchangeably to index the same dictionary entry. Return a shallow copy of the dictionary. - .. classmethod:: fromkeys(iterable, value=None) + .. classmethod:: fromkeys(iterable, value=None, /) Create a new dictionary with keys from *iterable* and values set to *value*. @@ -4619,10 +4624,11 @@ can be used interchangeably to index the same dictionary entry. Update the dictionary with the key/value pairs from *other*, overwriting existing keys. Return ``None``. - :meth:`update` accepts either another dictionary object or an iterable of - key/value pairs (as tuples or other iterables of length two). If keyword - arguments are specified, the dictionary is then updated with those - key/value pairs: ``d.update(red=1, blue=2)``. + :meth:`update` accepts either another object with a ``keys()`` method (in + which case :meth:`~object.__getitem__` is called with every key returned from + the method) or an iterable of key/value pairs (as tuples or other iterables + of length two). If keyword arguments are specified, the dictionary is then + updated with those key/value pairs: ``d.update(red=1, blue=2)``. .. method:: values() @@ -5472,22 +5478,6 @@ types, where they are relevant. Some of these are not reported by the :func:`dir` built-in function. -.. attribute:: object.__dict__ - - A dictionary or other mapping object used to store an object's (writable) - attributes. - - -.. attribute:: instance.__class__ - - The class to which a class instance belongs. - - -.. attribute:: class.__bases__ - - The tuple of base classes of a class object. - - .. attribute:: definition.__name__ The name of the class, function, method, descriptor, or @@ -5502,35 +5492,23 @@ types, where they are relevant. Some of these are not reported by the .. versionadded:: 3.3 -.. attribute:: definition.__type_params__ - - The :ref:`type parameters ` of generic classes, functions, - and :ref:`type aliases `. - - .. versionadded:: 3.12 +.. attribute:: definition.__module__ + The name of the module in which a class or function was defined. -.. attribute:: class.__mro__ - This attribute is a tuple of classes that are considered when looking for - base classes during method resolution. +.. attribute:: definition.__doc__ + The documentation string of a class or function, or ``None`` if undefined. -.. method:: class.mro() - This method can be overridden by a metaclass to customize the method - resolution order for its instances. It is called at class instantiation, and - its result is stored in :attr:`~class.__mro__`. - - -.. method:: class.__subclasses__ +.. attribute:: definition.__type_params__ - Each class keeps a list of weak references to its immediate subclasses. This - method returns a list of all those references still alive. The list is in - definition order. Example:: + The :ref:`type parameters ` of generic classes, functions, + and :ref:`type aliases `. For classes and functions that + are not generic, this will be an empty tuple. - >>> int.__subclasses__() - [, , , ] + .. versionadded:: 3.12 .. _int_max_str_digits: diff --git a/Doc/library/string.rst b/Doc/library/string.rst index c3c0d732..a000bb49 100644 --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -350,8 +350,9 @@ The meaning of the various alignment options is as follows: | ``'='`` | Forces the padding to be placed after the sign (if any) | | | but before the digits. This is used for printing fields | | | in the form '+000000120'. This alignment option is only | -| | valid for numeric types. It becomes the default for | -| | numbers when '0' immediately precedes the field width. | +| | valid for numeric types, excluding :class:`complex`. | +| | It becomes the default for numbers when '0' immediately | +| | precedes the field width. | +---------+----------------------------------------------------------+ | ``'^'`` | Forces the field to be centered within the available | | | space. | @@ -418,7 +419,7 @@ instead. .. index:: single: _ (underscore); in string formatting The ``'_'`` option signals the use of an underscore for a thousands -separator for floating point presentation types and for integer +separator for floating-point presentation types and for integer presentation type ``'d'``. For integer presentation types ``'b'``, ``'o'``, ``'x'``, and ``'X'``, underscores will be inserted every 4 digits. For other presentation types, specifying this option is an @@ -432,9 +433,9 @@ including any prefixes, separators, and other formatting characters. If not specified, then the field width will be determined by the content. When no explicit alignment is given, preceding the *width* field by a zero -(``'0'``) character enables -sign-aware zero-padding for numeric types. This is equivalent to a *fill* -character of ``'0'`` with an *alignment* type of ``'='``. +(``'0'``) character enables sign-aware zero-padding for numeric types, +excluding :class:`complex`. This is equivalent to a *fill* character of +``'0'`` with an *alignment* type of ``'='``. .. versionchanged:: 3.10 Preceding the *width* field by ``'0'`` no longer affects the default @@ -491,9 +492,9 @@ The available integer presentation types are: +---------+----------------------------------------------------------+ In addition to the above presentation types, integers can be formatted -with the floating point presentation types listed below (except +with the floating-point presentation types listed below (except ``'n'`` and ``None``). When doing so, :func:`float` is used to convert the -integer to a floating point number before formatting. +integer to a floating-point number before formatting. The available presentation types for :class:`float` and :class:`~decimal.Decimal` values are: @@ -509,9 +510,8 @@ The available presentation types for :class:`float` and | | significant digits. With no precision given, uses a | | | precision of ``6`` digits after the decimal point for | | | :class:`float`, and shows all coefficient digits | - | | for :class:`~decimal.Decimal`. If no digits follow the | - | | decimal point, the decimal point is also removed unless | - | | the ``#`` option is used. | + | | for :class:`~decimal.Decimal`. If ``p=0``, the decimal | + | | point is omitted unless the ``#`` option is used. | +---------+----------------------------------------------------------+ | ``'E'`` | Scientific notation. Same as ``'e'`` except it uses | | | an upper case 'E' as the separator character. | @@ -522,9 +522,8 @@ The available presentation types for :class:`float` and | | precision given, uses a precision of ``6`` digits after | | | the decimal point for :class:`float`, and uses a | | | precision large enough to show all coefficient digits | - | | for :class:`~decimal.Decimal`. If no digits follow the | - | | decimal point, the decimal point is also removed unless | - | | the ``#`` option is used. | + | | for :class:`~decimal.Decimal`. If ``p=0``, the decimal | + | | point is omitted unless the ``#`` option is used. | +---------+----------------------------------------------------------+ | ``'F'`` | Fixed-point notation. Same as ``'f'``, but converts | | | ``nan`` to ``NAN`` and ``inf`` to ``INF``. | @@ -574,11 +573,13 @@ The available presentation types for :class:`float` and | ``'%'`` | Percentage. Multiplies the number by 100 and displays | | | in fixed (``'f'``) format, followed by a percent sign. | +---------+----------------------------------------------------------+ - | None | For :class:`float` this is the same as ``'g'``, except | + | None | For :class:`float` this is like the ``'g'`` type, except | | | that when fixed-point notation is used to format the | | | result, it always includes at least one digit past the | - | | decimal point. The precision used is as large as needed | - | | to represent the given value faithfully. | + | | decimal point, and switches to the scientific notation | + | | when ``exp >= p - 1``. When the precision is not | + | | specified, the latter will be as large as needed to | + | | represent the given value faithfully. | | | | | | For :class:`~decimal.Decimal`, this is the same as | | | either ``'g'`` or ``'G'`` depending on the value of | @@ -588,6 +589,20 @@ The available presentation types for :class:`float` and | | as altered by the other format modifiers. | +---------+----------------------------------------------------------+ +The result should be correctly rounded to a given precision ``p`` of digits +after the decimal point. The rounding mode for :class:`float` matches that +of the :func:`round` builtin. For :class:`~decimal.Decimal`, the rounding +mode of the current :ref:`context ` will be used. + +The available presentation types for :class:`complex` are the same as those for +:class:`float` (``'%'`` is not allowed). Both the real and imaginary components +of a complex number are formatted as floating-point numbers, according to the +specified presentation type. They are separated by the mandatory sign of the +imaginary part, the latter being terminated by a ``j`` suffix. If the presentation +type is missing, the result will match the output of :func:`str` (complex numbers with +a non-zero real part are also surrounded by parentheses), possibly altered by +other format modifiers. + .. _formatexamples: diff --git a/Doc/library/struct.rst b/Doc/library/struct.rst index 346784d8..29bce521 100644 --- a/Doc/library/struct.rst +++ b/Doc/library/struct.rst @@ -275,9 +275,9 @@ Notes: (1) .. index:: single: ? (question mark); in struct format strings - The ``'?'`` conversion code corresponds to the :c:expr:`_Bool` type defined by - C99. If this type is not available, it is simulated using a :c:expr:`char`. In - standard mode, it is always represented by one byte. + The ``'?'`` conversion code corresponds to the :c:expr:`_Bool` type + defined by C standards since C99. In standard mode, it is + represented by one byte. (2) When attempting to pack a non-integer using any of the integer conversion diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst index 33f96a2f..755ff4c6 100644 --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -608,7 +608,7 @@ functions. If *group* is not ``None``, the setregid() system call will be made in the child process prior to the execution of the subprocess. If the provided - value is a string, it will be looked up via :func:`grp.getgrnam()` and + value is a string, it will be looked up via :func:`grp.getgrnam` and the value in ``gr_gid`` will be used. If the value is an integer, it will be passed verbatim. (POSIX only) @@ -618,7 +618,7 @@ functions. If *extra_groups* is not ``None``, the setgroups() system call will be made in the child process prior to the execution of the subprocess. Strings provided in *extra_groups* will be looked up via - :func:`grp.getgrnam()` and the values in ``gr_gid`` will be used. + :func:`grp.getgrnam` and the values in ``gr_gid`` will be used. Integer values will be passed verbatim. (POSIX only) .. availability:: POSIX @@ -626,7 +626,7 @@ functions. If *user* is not ``None``, the setreuid() system call will be made in the child process prior to the execution of the subprocess. If the provided - value is a string, it will be looked up via :func:`pwd.getpwnam()` and + value is a string, it will be looked up via :func:`pwd.getpwnam` and the value in ``pw_uid`` will be used. If the value is an integer, it will be passed verbatim. (POSIX only) @@ -1110,7 +1110,7 @@ The :mod:`subprocess` module exposes the following constants. .. data:: NORMAL_PRIORITY_CLASS A :class:`Popen` ``creationflags`` parameter to specify that a new process - will have an normal priority. (default) + will have a normal priority. (default) .. versionadded:: 3.7 diff --git a/Doc/library/symtable.rst b/Doc/library/symtable.rst index fc2d79b7..de9a9615 100644 --- a/Doc/library/symtable.rst +++ b/Doc/library/symtable.rst @@ -127,8 +127,39 @@ Examining Symbol Tables .. method:: get_methods() - Return a tuple containing the names of methods declared in the class. - + Return a tuple containing the names of method-like functions declared + in the class. + + Here, the term 'method' designates *any* function defined in the class + body via :keyword:`def` or :keyword:`async def`. + + Functions defined in a deeper scope (e.g., in an inner class) are not + picked up by :meth:`get_methods`. + + For example: + + >>> import symtable + >>> st = symtable.symtable(''' + ... def outer(): pass + ... + ... class A: + ... def f(): + ... def w(): pass + ... + ... def g(self): pass + ... + ... @classmethod + ... async def h(cls): pass + ... + ... global outer + ... def outer(self): pass + ... ''', 'test', 'exec') + >>> class_A = st.get_children()[1] + >>> class_A.get_methods() + ('f', 'g', 'h') + + Although ``A().f()`` raises :exc:`TypeError` at runtime, ``A.f`` is still + considered as a method-like function. .. class:: Symbol diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 03f1f309..90c794e3 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -724,11 +724,11 @@ always available. regardless of their size. This function is mainly useful for tracking and debugging memory leaks. Because of the interpreter's internal caches, the result can vary from call to call; you may have to call - :func:`_clear_type_cache()` and :func:`gc.collect()` to get more + :func:`_clear_type_cache` and :func:`gc.collect` to get more predictable results. If a Python build or implementation cannot reasonably compute this - information, :func:`getallocatedblocks()` is allowed to return 0 instead. + information, :func:`getallocatedblocks` is allowed to return 0 instead. .. versionadded:: 3.4 @@ -907,6 +907,35 @@ always available. It is not guaranteed to exist in all implementations of Python. +.. function:: getobjects(limit[, type]) + + This function only exists if CPython was built using the + specialized configure option :option:`--with-trace-refs`. + It is intended only for debugging garbage-collection issues. + + Return a list of up to *limit* dynamically allocated Python objects. + If *type* is given, only objects of that exact type (not subtypes) + are included. + + Objects from the list are not safe to use. + Specifically, the result will include objects from all interpreters that + share their object allocator state (that is, ones created with + :c:member:`PyInterpreterConfig.use_main_obmalloc` set to 1 + or using :c:func:`Py_NewInterpreter`, and the + :ref:`main interpreter `). + Mixing objects from different interpreters may lead to crashes + or other unexpected behavior. + + .. impl-detail:: + + This function should be used for specialized purposes only. + It is not guaranteed to exist in all implementations of Python. + + .. versionchanged:: 3.12.8 + + The result may include objects from other interpreters. + + .. function:: getprofile() .. index:: @@ -1239,7 +1268,8 @@ always available. that implement Python's default import semantics. The :meth:`~importlib.abc.MetaPathFinder.find_spec` method is called with at least the absolute name of the module being imported. If the module to be - imported is contained in a package, then the parent package's :attr:`__path__` + imported is contained in a package, then the parent package's + :attr:`~module.__path__` attribute is passed in as a second argument. The method returns a :term:`module spec`, or ``None`` if the module cannot be found. diff --git a/Doc/library/sysconfig.rst b/Doc/library/sysconfig.rst index 75672913..aaccc043 100644 --- a/Doc/library/sysconfig.rst +++ b/Doc/library/sysconfig.rst @@ -305,7 +305,7 @@ Installation path functions mix with those by the other. End users should not use this function, but :func:`get_default_scheme` and - :func:`get_preferred_scheme()` instead. + :func:`get_preferred_scheme` instead. .. versionadded:: 3.10 @@ -376,7 +376,7 @@ Other functions This is used mainly to distinguish platform-specific build directories and platform-specific built distributions. Typically includes the OS name and - version and the architecture (as supplied by 'os.uname()'), although the + version and the architecture (as supplied by :func:`os.uname`), although the exact information included depends on the OS; e.g., on Linux, the kernel version isn't particularly important. diff --git a/Doc/library/tarfile.rst b/Doc/library/tarfile.rst index bd745c78..0352cddb 100644 --- a/Doc/library/tarfile.rst +++ b/Doc/library/tarfile.rst @@ -608,7 +608,7 @@ be finalized; only the internally used file object will be closed. See the it is best practice to only do so in top-level applications or :mod:`site configuration `. To set a global default this way, a filter function needs to be wrapped in - :func:`staticmethod()` to prevent injection of a ``self`` argument. + :func:`staticmethod` to prevent injection of a ``self`` argument. .. method:: TarFile.add(name, arcname=None, recursive=True, *, filter=None) diff --git a/Doc/library/test.rst b/Doc/library/test.rst index 64bf8174..71661896 100644 --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -940,7 +940,7 @@ The :mod:`test.support` module defines the following functions: other modules, possibly a C backend (like ``csv`` and its ``_csv``). The *extra* argument can be a set of names that wouldn't otherwise be automatically - detected as "public", like objects without a proper ``__module__`` + detected as "public", like objects without a proper :attr:`~definition.__module__` attribute. If provided, it will be added to the automatically detected ones. The *not_exported* argument can be a set of names that must not be treated @@ -1695,7 +1695,7 @@ The :mod:`test.support.warnings_helper` module provides support for warnings tes .. function:: check_warnings(*filters, quiet=True) - A convenience wrapper for :func:`warnings.catch_warnings()` that makes it + A convenience wrapper for :func:`warnings.catch_warnings` that makes it easier to test that a warning was correctly raised. It is approximately equivalent to calling ``warnings.catch_warnings(record=True)`` with :meth:`warnings.simplefilter` set to ``always`` and with the option to diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst index c88dcabc..5d94a776 100644 --- a/Doc/library/threading.rst +++ b/Doc/library/threading.rst @@ -409,7 +409,7 @@ since it is impossible to detect the termination of alien threads. timeout occurs. When the *timeout* argument is present and not ``None``, it should be a - floating point number specifying a timeout for the operation in seconds + floating-point number specifying a timeout for the operation in seconds (or fractions thereof). As :meth:`~Thread.join` always returns ``None``, you must call :meth:`~Thread.is_alive` after :meth:`~Thread.join` to decide whether a timeout happened -- if the thread is still alive, the @@ -790,7 +790,7 @@ item to the buffer only needs to wake up one consumer thread. occurs. Once awakened or timed out, it re-acquires the lock and returns. When the *timeout* argument is present and not ``None``, it should be a - floating point number specifying a timeout for the operation in seconds + floating-point number specifying a timeout for the operation in seconds (or fractions thereof). When the underlying lock is an :class:`RLock`, it is not released using @@ -1014,10 +1014,10 @@ method. The :meth:`~Event.wait` method blocks until the flag is true. has not expired. The return value represents the reason that this blocking method returned; ``True`` if returning because the internal flag is set to true, or ``False`` if a timeout is given and - the the internal flag did not become true within the given wait time. + the internal flag did not become true within the given wait time. When the timeout argument is present and not ``None``, it should be a - floating point number specifying a timeout for the operation in seconds, + floating-point number specifying a timeout for the operation in seconds, or fractions thereof. .. versionchanged:: 3.1 diff --git a/Doc/library/time.rst b/Doc/library/time.rst index d792d563..db53296e 100644 --- a/Doc/library/time.rst +++ b/Doc/library/time.rst @@ -69,7 +69,7 @@ An explanation of some terminology and conventions is in order. systems, the clock "ticks" only 50 or 100 times a second. * On the other hand, the precision of :func:`.time` and :func:`sleep` is better - than their Unix equivalents: times are expressed as floating point numbers, + than their Unix equivalents: times are expressed as floating-point numbers, :func:`.time` returns the most accurate time available (using Unix :c:func:`!gettimeofday` where available), and :func:`sleep` will accept a time with a nonzero fraction (Unix :c:func:`!select` is used to implement this, where @@ -273,7 +273,7 @@ Functions This is the inverse function of :func:`localtime`. Its argument is the :class:`struct_time` or full 9-tuple (since the dst flag is needed; use ``-1`` as the dst flag if it is unknown) which expresses the time in *local* time, not - UTC. It returns a floating point number, for compatibility with :func:`.time`. + UTC. It returns a floating-point number, for compatibility with :func:`.time`. If the input value cannot be represented as a valid time, either :exc:`OverflowError` or :exc:`ValueError` will be raised (which depends on whether the invalid value is caught by Python or the underlying C libraries). @@ -358,7 +358,7 @@ Functions .. function:: sleep(secs) Suspend execution of the calling thread for the given number of seconds. - The argument may be a floating point number to indicate a more precise sleep + The argument may be a floating-point number to indicate a more precise sleep time. If the sleep is interrupted by a signal and no exception is raised by the @@ -372,7 +372,7 @@ Functions threads ready to run, the function returns immediately, and the thread continues execution. On Windows 8.1 and newer the implementation uses a `high-resolution timer - `_ + `_ which provides resolution of 100 nanoseconds. If *secs* is zero, ``Sleep(0)`` is used. Unix implementation: @@ -460,6 +460,9 @@ Functions | | | | | | | | +-----------+------------------------------------------------+-------+ + | ``%u`` | Day of the week (Monday is 1; Sunday is 7) | | + | | as a decimal number [1, 7]. | | + +-----------+------------------------------------------------+-------+ | ``%w`` | Weekday as a decimal number [0(Sunday),6]. | | | | | | +-----------+------------------------------------------------+-------+ @@ -492,6 +495,16 @@ Functions | ``%Z`` | Time zone name (no characters if no time zone | | | | exists). Deprecated. [1]_ | | +-----------+------------------------------------------------+-------+ + | ``%G`` | ISO 8601 year (similar to ``%Y`` but follows | | + | | the rules for the ISO 8601 calendar year). | | + | | The year starts with the week that contains | | + | | the first Thursday of the calendar year. | | + +-----------+------------------------------------------------+-------+ + | ``%V`` | ISO 8601 week number (as a decimal number | | + | | [01,53]). The first week of the year is the | | + | | one that contains the first Thursday of the | | + | | year. Weeks start on Monday. | | + +-----------+------------------------------------------------+-------+ | ``%%`` | A literal ``'%'`` character. | | +-----------+------------------------------------------------+-------+ @@ -642,13 +655,13 @@ Functions .. function:: time() -> float - Return the time in seconds since the epoch_ as a floating point + Return the time in seconds since the epoch_ as a floating-point number. The handling of `leap seconds`_ is platform dependent. On Windows and most Unix systems, the leap seconds are not counted towards the time in seconds since the epoch_. This is commonly referred to as `Unix time `_. - Note that even though the time is always returned as a floating point + Note that even though the time is always returned as a floating-point number, not all systems provide time with a better precision than 1 second. While this function normally returns non-decreasing values, it can return a lower value than a previous call if the system clock has been set back diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index fd9125bc..843e994d 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -58,7 +58,7 @@ details that are unchanged. * `Modern Tkinter for Busy Python Developers `_ By Mark Roseman. (ISBN 978-1999149567) - * `Python GUI programming with Tkinter `_ + * `Python GUI programming with Tkinter `_ By Alan D. Moore. (ISBN 978-1788835886) * `Programming Python `_ diff --git a/Doc/library/token.rst b/Doc/library/token.rst index 9368ced9..6d06ae82 100644 --- a/Doc/library/token.rst +++ b/Doc/library/token.rst @@ -75,10 +75,17 @@ the :mod:`tokenize` module. :noindex: Token value indicating that a type comment was recognized. Such - tokens are only produced when :func:`ast.parse()` is invoked with + tokens are only produced when :func:`ast.parse` is invoked with ``type_comments=True``. +.. data:: EXACT_TOKEN_TYPES + + A dictionary mapping the string representation of a token to its numeric code. + + .. versionadded:: 3.8 + + .. versionchanged:: 3.5 Added :data:`AWAIT` and :data:`ASYNC` tokens. diff --git a/Doc/library/tomllib.rst b/Doc/library/tomllib.rst index b523ad93..521a7a17 100644 --- a/Doc/library/tomllib.rst +++ b/Doc/library/tomllib.rst @@ -13,7 +13,7 @@ -------------- -This module provides an interface for parsing TOML (Tom's Obvious Minimal +This module provides an interface for parsing TOML 1.0.0 (Tom's Obvious Minimal Language, `https://toml.io `_). This module does not support writing TOML. diff --git a/Doc/library/traceback.rst b/Doc/library/traceback.rst index 85dae821..9d57c354 100644 --- a/Doc/library/traceback.rst +++ b/Doc/library/traceback.rst @@ -8,11 +8,15 @@ -------------- -This module provides a standard interface to extract, format and print stack -traces of Python programs. It exactly mimics the behavior of the Python -interpreter when it prints a stack trace. This is useful when you want to print -stack traces under program control, such as in a "wrapper" around the -interpreter. +This module provides a standard interface to extract, format and print +stack traces of Python programs. It is more flexible than the +interpreter's default traceback display, and therefore makes it +possible to configure certain aspects of the output. Finally, +it contains a utility for capturing enough information about an +exception to print it later, without the need to save a reference +to the actual exception. Since exceptions can be the roots of large +objects graph, this utility can significantly improve +memory management. .. index:: pair: object; traceback @@ -29,7 +33,20 @@ which are assigned to the :attr:`~BaseException.__traceback__` field of Module :mod:`pdb` Interactive source code debugger for Python programs. -The module defines the following functions: +The module's API can be divided into two parts: + +* Module-level functions offering basic functionality, which are useful for interactive + inspection of exceptions and tracebacks. + +* :class:`TracebackException` class and its helper classes + :class:`StackSummary` and :class:`FrameSummary`. These offer both more + flexibility in the output generated and the ability to store the information + necessary for later formatting without holding references to actual exception + and traceback objects. + + +Module-Level Functions +---------------------- .. function:: print_tb(tb, limit=None, file=None) @@ -42,6 +59,14 @@ The module defines the following functions: :term:`file ` or :term:`file-like object` to receive the output. + .. note:: + + The meaning of the *limit* parameter is different than the meaning + of :const:`sys.tracebacklimit`. A negative *limit* value corresponds to + a positive value of :const:`!sys.tracebacklimit`, whereas the behaviour of + a positive *limit* value cannot be achieved with + :const:`!sys.tracebacklimit`. + .. versionchanged:: 3.5 Added negative *limit* support. @@ -222,7 +247,6 @@ The module defines the following functions: .. versionadded:: 3.5 -The module also defines the following classes: :class:`!TracebackException` Objects ------------------------------------ @@ -230,12 +254,17 @@ The module also defines the following classes: .. versionadded:: 3.5 :class:`!TracebackException` objects are created from actual exceptions to -capture data for later printing in a lightweight fashion. +capture data for later printing. They offer a more lightweight method of +storing this information by avoiding holding references to +:ref:`traceback` and :ref:`frame` objects +In addition, they expose more options to configure the output compared to +the module-level functions described above. .. class:: TracebackException(exc_type, exc_value, exc_traceback, *, limit=None, lookup_lines=True, capture_locals=False, compact=False, max_group_width=15, max_group_depth=10) - Capture an exception for later rendering. *limit*, *lookup_lines* and - *capture_locals* are as for the :class:`StackSummary` class. + Capture an exception for later rendering. The meaning of *limit*, + *lookup_lines* and *capture_locals* are as for the :class:`StackSummary` + class. If *compact* is true, only data that is required by :class:`!TracebackException`'s :meth:`format` method @@ -480,8 +509,8 @@ in a :ref:`traceback `. .. _traceback-example: -Traceback Examples ------------------- +Examples of Using the Module-Level Functions +-------------------------------------------- This simple example implements a basic read-eval-print loop, similar to (but less useful than) the standard Python interactive interpreter loop. For a more @@ -520,8 +549,7 @@ exception and traceback: try: lumberjack() - except IndexError: - exc = sys.exception() + except IndexError as exc: print("*** print_tb:") traceback.print_tb(exc.__traceback__, limit=1, file=sys.stdout) print("*** print_exception:") @@ -619,5 +647,88 @@ This last example demonstrates the final few formatting functions: [' File "spam.py", line 3, in \n spam.eggs()\n', ' File "eggs.py", line 42, in eggs\n return "bacon"\n'] >>> an_error = IndexError('tuple index out of range') - >>> traceback.format_exception_only(type(an_error), an_error) + >>> traceback.format_exception_only(an_error) ['IndexError: tuple index out of range\n'] + + +Examples of Using :class:`TracebackException` +--------------------------------------------- + +With the helper class, we have more options:: + + >>> import sys + >>> from traceback import TracebackException + >>> + >>> def lumberjack(): + ... bright_side_of_life() + ... + >>> def bright_side_of_life(): + ... t = "bright", "side", "of", "life" + ... return t[5] + ... + >>> try: + ... lumberjack() + ... except IndexError as e: + ... exc = e + ... + >>> try: + ... try: + ... lumberjack() + ... except: + ... 1/0 + ... except Exception as e: + ... chained_exc = e + ... + >>> # limit works as with the module-level functions + >>> TracebackException.from_exception(exc, limit=-2).print() + Traceback (most recent call last): + File "", line 6, in lumberjack + bright_side_of_life() + ~~~~~~~~~~~~~~~~~~~^^ + File "", line 10, in bright_side_of_life + return t[5] + ~^^^ + IndexError: tuple index out of range + + >>> # capture_locals adds local variables in frames + >>> TracebackException.from_exception(exc, limit=-2, capture_locals=True).print() + Traceback (most recent call last): + File "", line 6, in lumberjack + bright_side_of_life() + ~~~~~~~~~~~~~~~~~~~^^ + File "", line 10, in bright_side_of_life + return t[5] + ~^^^ + t = ("bright", "side", "of", "life") + IndexError: tuple index out of range + + >>> # The *chain* kwarg to print() controls whether chained + >>> # exceptions are displayed + >>> TracebackException.from_exception(chained_exc).print() + Traceback (most recent call last): + File "", line 4, in + lumberjack() + ~~~~~~~~~~^^ + File "", line 7, in lumberjack + bright_side_of_life() + ~~~~~~~~~~~~~~~~~~~^^ + File "", line 11, in bright_side_of_life + return t[5] + ~^^^ + IndexError: tuple index out of range + + During handling of the above exception, another exception occurred: + + Traceback (most recent call last): + File "", line 6, in + 1/0 + ~^~ + ZeroDivisionError: division by zero + + >>> TracebackException.from_exception(chained_exc).print(chain=False) + Traceback (most recent call last): + File "", line 6, in + 1/0 + ~^~ + ZeroDivisionError: division by zero + diff --git a/Doc/library/types.rst b/Doc/library/types.rst index 64263532..ce31a248 100644 --- a/Doc/library/types.rst +++ b/Doc/library/types.rst @@ -91,8 +91,8 @@ Dynamic Type Creation For classes that have an ``__orig_bases__`` attribute, this function returns the value of ``cls.__orig_bases__``. - For classes without the ``__orig_bases__`` attribute, ``cls.__bases__`` is - returned. + For classes without the ``__orig_bases__`` attribute, + :attr:`cls.__bases__ ` is returned. Examples:: @@ -260,63 +260,18 @@ Standard names are defined for the following types: The type of :term:`modules `. The constructor takes the name of the module to be created and optionally its :term:`docstring`. - .. note:: - Use :func:`importlib.util.module_from_spec` to create a new module if you - wish to set the various import-controlled attributes. - - .. attribute:: __doc__ - - The :term:`docstring` of the module. Defaults to ``None``. - - .. attribute:: __loader__ - - The :term:`loader` which loaded the module. Defaults to ``None``. - - This attribute is to match :attr:`importlib.machinery.ModuleSpec.loader` - as stored in the :attr:`__spec__` object. - - .. note:: - A future version of Python may stop setting this attribute by default. - To guard against this potential change, preferably read from the - :attr:`__spec__` attribute instead or use - ``getattr(module, "__loader__", None)`` if you explicitly need to use - this attribute. - - .. versionchanged:: 3.4 - Defaults to ``None``. Previously the attribute was optional. - - .. attribute:: __name__ - - The name of the module. Expected to match - :attr:`importlib.machinery.ModuleSpec.name`. - - .. attribute:: __package__ - - Which :term:`package` a module belongs to. If the module is top-level - (i.e. not a part of any specific package) then the attribute should be set - to ``''``, else it should be set to the name of the package (which can be - :attr:`__name__` if the module is a package itself). Defaults to ``None``. - - This attribute is to match :attr:`importlib.machinery.ModuleSpec.parent` - as stored in the :attr:`__spec__` object. - - .. note:: - A future version of Python may stop setting this attribute by default. - To guard against this potential change, preferably read from the - :attr:`__spec__` attribute instead or use - ``getattr(module, "__package__", None)`` if you explicitly need to use - this attribute. - - .. versionchanged:: 3.4 - Defaults to ``None``. Previously the attribute was optional. - - .. attribute:: __spec__ - - A record of the module's import-system-related state. Expected to be an - instance of :class:`importlib.machinery.ModuleSpec`. + .. seealso:: - .. versionadded:: 3.4 + :ref:`Documentation on module objects ` + Provides details on the special attributes that can be found on + instances of :class:`!ModuleType`. + :func:`importlib.util.module_from_spec` + Modules created using the :class:`!ModuleType` constructor are + created with many of their special attributes unset or set to default + values. :func:`!module_from_spec` provides a more robust way of + creating :class:`!ModuleType` instances which ensures the various + attributes are set appropriately. .. data:: EllipsisType @@ -392,7 +347,7 @@ Standard names are defined for the following types: In addition, when a class is defined with a :attr:`~object.__slots__` attribute, then for each slot, an instance of :class:`!MemberDescriptorType` will be added as an attribute - on the class. This allows the slot to appear in the class's :attr:`~object.__dict__`. + on the class. This allows the slot to appear in the class's :attr:`~type.__dict__`. .. impl-detail:: diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 1a5c21d3..54a19ae0 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -27,12 +27,13 @@ This module provides runtime support for type hints. Consider the function below:: - def moon_weight(earth_weight: float) -> str: - return f'On the moon, you would weigh {earth_weight * 0.166} kilograms.' + def surface_area_of_cube(edge_length: float) -> str: + return f"The surface area of the cube is {6 * edge_length ** 2}." -The function ``moon_weight`` takes an argument expected to be an instance of :class:`float`, -as indicated by the *type hint* ``earth_weight: float``. The function is expected to -return an instance of :class:`str`, as indicated by the ``-> str`` hint. +The function ``surface_area_of_cube`` takes an argument expected to +be an instance of :class:`float`, as indicated by the :term:`type hint` +``edge_length: float``. The function is expected to return an instance +of :class:`str`, as indicated by the ``-> str`` hint. While type hints can be simple classes like :class:`float` or :class:`str`, they can also be more complex. The :mod:`typing` module provides a vocabulary of @@ -97,8 +98,9 @@ Type aliases are useful for simplifying complex type signatures. For example:: # The static type checker will treat the previous type signature as # being exactly equivalent to this one. def broadcast_message( - message: str, - servers: Sequence[tuple[tuple[str, int], dict[str, str]]]) -> None: + message: str, + servers: Sequence[tuple[tuple[str, int], dict[str, str]]] + ) -> None: ... The :keyword:`type` statement is new in Python 3.12. For backwards @@ -206,7 +208,7 @@ Annotating callable objects =========================== Functions -- or other :term:`callable` objects -- can be annotated using -:class:`collections.abc.Callable` or :data:`typing.Callable`. +:class:`collections.abc.Callable` or deprecated :data:`typing.Callable`. ``Callable[[int], str]`` signifies a function that takes a single parameter of type :class:`int` and returns a :class:`str`. @@ -399,7 +401,7 @@ The type of class objects ========================= A variable annotated with ``C`` may accept a value of type ``C``. In -contrast, a variable annotated with ``type[C]`` (or +contrast, a variable annotated with ``type[C]`` (or deprecated :class:`typing.Type[C] `) may accept values that are classes themselves -- specifically, it will accept the *class object* of ``C``. For example:: @@ -439,6 +441,72 @@ For example:: ``type[Any]`` is equivalent to :class:`type`, which is the root of Python's :ref:`metaclass hierarchy `. + +.. _annotating-generators-and-coroutines: + +Annotating generators and coroutines +==================================== + +A generator can be annotated using the generic type +:class:`Generator[YieldType, SendType, ReturnType] `. +For example:: + + def echo_round() -> Generator[int, float, str]: + sent = yield 0 + while sent >= 0: + sent = yield round(sent) + return 'Done' + +Note that unlike many other generic classes in the standard library, +the ``SendType`` of :class:`~collections.abc.Generator` behaves +contravariantly, not covariantly or invariantly. + +If your generator will only yield values, set the ``SendType`` and +``ReturnType`` to ``None``:: + + def infinite_stream(start: int) -> Generator[int, None, None]: + while True: + yield start + start += 1 + +Alternatively, annotate your generator as having a return type of +either ``Iterable[YieldType]`` or ``Iterator[YieldType]``:: + + def infinite_stream(start: int) -> Iterator[int]: + while True: + yield start + start += 1 + +Async generators are handled in a similar fashion, but don't +expect a ``ReturnType`` type argument +(:class:`AsyncGenerator[YieldType, SendType] `):: + + async def infinite_stream(start: int) -> AsyncGenerator[int, None]: + while True: + yield start + start = await increment(start) + +As in the synchronous case, +:class:`AsyncIterable[YieldType] ` +and :class:`AsyncIterator[YieldType] ` are +available as well:: + + async def infinite_stream(start: int) -> AsyncIterator[int]: + while True: + yield start + start = await increment(start) + +Coroutines can be annotated using +:class:`Coroutine[YieldType, SendType, ReturnType] `. +Generic arguments correspond to those of :class:`~collections.abc.Generator`, +for example:: + + from collections.abc import Coroutine + c: Coroutine[list[str], str, int] # Some coroutine defined elsewhere + x = c.send('hi') # Inferred type of 'x' is list[str] + async def bar() -> None: + y = await c # Inferred type of 'y' is int + .. _user-defined-generics: User-defined generic types @@ -1337,6 +1405,23 @@ These can be used as types in annotations. They all support subscription using >>> X.__metadata__ ('very', 'important', 'metadata') + * At runtime, if you want to retrieve the original + type wrapped by ``Annotated``, use the :attr:`!__origin__` attribute: + + .. doctest:: + + >>> from typing import Annotated, get_origin + >>> Password = Annotated[str, "secret"] + >>> Password.__origin__ + + + Note that using :func:`get_origin` will return ``Annotated`` itself: + + .. doctest:: + + >>> get_origin(Password) + + .. seealso:: :pep:`593` - Flexible function and variable annotations @@ -1394,8 +1479,8 @@ These can be used as types in annotations. They all support subscription using print("Not a list of strings!") If ``is_str_list`` is a class or instance method, then the type in - ``TypeGuard`` maps to the type of the second parameter after ``cls`` or - ``self``. + ``TypeGuard`` maps to the type of the second parameter (after ``cls`` or + ``self``). In short, the form ``def foo(arg: TypeA) -> TypeGuard[TypeB]: ...``, means that if ``foo(arg)`` returns ``True``, then ``arg`` narrows from @@ -1524,11 +1609,11 @@ without the dedicated syntax, as documented below. class Sequence[T]: # T is a TypeVar ... - This syntax can also be used to create bound and constrained type + This syntax can also be used to create bounded and constrained type variables:: - class StrSequence[S: str]: # S is a TypeVar bound to str - ... + class StrSequence[S: str]: # S is a TypeVar with a `str` upper bound; + ... # we can say that S is "bounded by `str`" class StrOrBytesSequence[A: (str, bytes)]: # A is a TypeVar constrained to str or bytes @@ -1561,8 +1646,8 @@ without the dedicated syntax, as documented below. """Add two strings or bytes objects together.""" return x + y - Note that type variables can be *bound*, *constrained*, or neither, but - cannot be both bound *and* constrained. + Note that type variables can be *bounded*, *constrained*, or neither, but + cannot be both bounded *and* constrained. The variance of type variables is inferred by type checkers when they are created through the :ref:`type parameter syntax ` or when @@ -1572,8 +1657,8 @@ without the dedicated syntax, as documented below. By default, manually created type variables are invariant. See :pep:`484` and :pep:`695` for more details. - Bound type variables and constrained type variables have different - semantics in several important ways. Using a *bound* type variable means + Bounded type variables and constrained type variables have different + semantics in several important ways. Using a *bounded* type variable means that the ``TypeVar`` will be solved using the most specific type possible:: x = print_capitalized('a string') @@ -1587,8 +1672,8 @@ without the dedicated syntax, as documented below. z = print_capitalized(45) # error: int is not a subtype of str - Type variables can be bound to concrete types, abstract types (ABCs or - protocols), and even unions of types:: + The upper bound of a type variable can be a concrete type, abstract type + (ABC or Protocol), or even a union of types:: # Can be anything with an __abs__ method def print_abs[T: SupportsAbs](arg: T) -> None: @@ -1632,7 +1717,7 @@ without the dedicated syntax, as documented below. .. attribute:: __bound__ - The bound of the type variable, if any. + The upper bound of the type variable, if any. .. versionchanged:: 3.12 @@ -1749,8 +1834,8 @@ without the dedicated syntax, as documented below. of ``*args``:: def call_soon[*Ts]( - callback: Callable[[*Ts], None], - *args: *Ts + callback: Callable[[*Ts], None], + *args: *Ts ) -> None: ... callback(*args) @@ -1818,7 +1903,7 @@ without the dedicated syntax, as documented below. return x + y Without ``ParamSpec``, the simplest way to annotate this previously was to - use a :class:`TypeVar` with bound ``Callable[..., Any]``. However this + use a :class:`TypeVar` with upper bound ``Callable[..., Any]``. However this causes two problems: 1. The type checker can't type check the ``inner`` function because @@ -2011,7 +2096,9 @@ types. Backward-compatible usage:: - # For creating a generic NamedTuple on Python 3.11 or lower + # For creating a generic NamedTuple on Python 3.11 + T = TypeVar("T") + class Group(NamedTuple, Generic[T]): key: T group: list[T] @@ -2513,7 +2600,7 @@ Functions and decorators .. seealso:: `Unreachable Code and Exhaustiveness Checking - `__ has more + `__ has more information about exhaustiveness checking with static typing. .. versionadded:: 3.11 @@ -2896,7 +2983,8 @@ Introspection helpers empty dictionary is returned. * If *obj* is a class ``C``, the function returns a dictionary that merges annotations from ``C``'s base classes with those on ``C`` directly. This - is done by traversing ``C.__mro__`` and iteratively combining + is done by traversing :attr:`C.__mro__ ` and iteratively + combining ``__annotations__`` dictionaries. Annotations on classes appearing earlier in the :term:`method resolution order` always take precedence over annotations on classes appearing later in the method resolution order. @@ -2942,6 +3030,7 @@ Introspection helpers assert get_origin(str) is None assert get_origin(Dict[str, int]) is dict assert get_origin(Union[int, str]) is Union + assert get_origin(Annotated[str, "metadata"]) is Annotated P = ParamSpec('P') assert get_origin(P.args) is P assert get_origin(P.kwargs) is P @@ -3071,14 +3160,9 @@ Aliases to built-in types Deprecated alias to :class:`dict`. Note that to annotate arguments, it is preferred - to use an abstract collection type such as :class:`Mapping` + to use an abstract collection type such as :class:`~collections.abc.Mapping` rather than to use :class:`dict` or :class:`!typing.Dict`. - This type can be used as follows:: - - def count_words(text: str) -> Dict[str, int]: - ... - .. deprecated:: 3.9 :class:`builtins.dict ` now supports subscripting (``[]``). See :pep:`585` and :ref:`types-genericalias`. @@ -3088,16 +3172,9 @@ Aliases to built-in types Deprecated alias to :class:`list`. Note that to annotate arguments, it is preferred - to use an abstract collection type such as :class:`Sequence` or - :class:`Iterable` rather than to use :class:`list` or :class:`!typing.List`. - - This type may be used as follows:: - - def vec2[T: (int, float)](x: T, y: T) -> List[T]: - return [x, y] - - def keep_positives[T: (int, float)](vector: Sequence[T]) -> List[T]: - return [item for item in vector if item > 0] + to use an abstract collection type such as + :class:`~collections.abc.Sequence` or :class:`~collections.abc.Iterable` + rather than to use :class:`list` or :class:`!typing.List`. .. deprecated:: 3.9 :class:`builtins.list ` now supports subscripting (``[]``). @@ -3108,8 +3185,8 @@ Aliases to built-in types Deprecated alias to :class:`builtins.set `. Note that to annotate arguments, it is preferred - to use an abstract collection type such as :class:`AbstractSet` - rather than to use :class:`set` or :class:`!typing.Set`. + to use an abstract collection type such as :class:`collections.abc.Set` + rather than to use :class:`set` or :class:`typing.Set`. .. deprecated:: 3.9 :class:`builtins.set ` now supports subscripting (``[]``). @@ -3313,11 +3390,6 @@ Aliases to container ABCs in :mod:`collections.abc` Deprecated alias to :class:`collections.abc.Mapping`. - This type can be used as follows:: - - def get_position_in_index(word_list: Mapping[str, int], word: str) -> int: - return word_list[word] - .. deprecated:: 3.9 :class:`collections.abc.Mapping` now supports subscripting (``[]``). See :pep:`585` and :ref:`types-genericalias`. @@ -3381,14 +3453,9 @@ Aliases to asynchronous ABCs in :mod:`collections.abc` Deprecated alias to :class:`collections.abc.Coroutine`. - The variance and order of type variables - correspond to those of :class:`Generator`, for example:: - - from collections.abc import Coroutine - c: Coroutine[list[str], str, int] # Some coroutine defined elsewhere - x = c.send('hi') # Inferred type of 'x' is list[str] - async def bar() -> None: - y = await c # Inferred type of 'y' is int + See :ref:`annotating-generators-and-coroutines` + for details on using :class:`collections.abc.Coroutine` + and ``typing.Coroutine`` in type annotations. .. versionadded:: 3.5.3 @@ -3400,34 +3467,9 @@ Aliases to asynchronous ABCs in :mod:`collections.abc` Deprecated alias to :class:`collections.abc.AsyncGenerator`. - An async generator can be annotated by the generic type - ``AsyncGenerator[YieldType, SendType]``. For example:: - - async def echo_round() -> AsyncGenerator[int, float]: - sent = yield 0 - while sent >= 0.0: - rounded = await round(sent) - sent = yield rounded - - Unlike normal generators, async generators cannot return a value, so there - is no ``ReturnType`` type parameter. As with :class:`Generator`, the - ``SendType`` behaves contravariantly. - - If your generator will only yield values, set the ``SendType`` to - ``None``:: - - async def infinite_stream(start: int) -> AsyncGenerator[int, None]: - while True: - yield start - start = await increment(start) - - Alternatively, annotate your generator as having a return type of - either ``AsyncIterable[YieldType]`` or ``AsyncIterator[YieldType]``:: - - async def infinite_stream(start: int) -> AsyncIterator[int]: - while True: - yield start - start = await increment(start) + See :ref:`annotating-generators-and-coroutines` + for details on using :class:`collections.abc.AsyncGenerator` + and ``typing.AsyncGenerator`` in type annotations. .. versionadded:: 3.6.1 @@ -3506,34 +3548,9 @@ Aliases to other ABCs in :mod:`collections.abc` Deprecated alias to :class:`collections.abc.Generator`. - A generator can be annotated by the generic type - ``Generator[YieldType, SendType, ReturnType]``. For example:: - - def echo_round() -> Generator[int, float, str]: - sent = yield 0 - while sent >= 0: - sent = yield round(sent) - return 'Done' - - Note that unlike many other generics in the typing module, the ``SendType`` - of :class:`Generator` behaves contravariantly, not covariantly or - invariantly. - - If your generator will only yield values, set the ``SendType`` and - ``ReturnType`` to ``None``:: - - def infinite_stream(start: int) -> Generator[int, None, None]: - while True: - yield start - start += 1 - - Alternatively, annotate your generator as having a return type of - either ``Iterable[YieldType]`` or ``Iterator[YieldType]``:: - - def infinite_stream(start: int) -> Iterator[int]: - while True: - yield start - start += 1 + See :ref:`annotating-generators-and-coroutines` + for details on using :class:`collections.abc.Generator` + and ``typing.Generator`` in type annotations. .. deprecated:: 3.9 :class:`collections.abc.Generator` now supports subscripting (``[]``). diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index 8dcb8c2a..84f34a06 100644 --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -68,7 +68,7 @@ available, and then make assertions about how they have been used: 3 >>> thing.method.assert_called_with(3, 4, 5, key='value') -:attr:`side_effect` allows you to perform side effects, including raising an +:attr:`~Mock.side_effect` allows you to perform side effects, including raising an exception when a mock is called: >>> from unittest.mock import Mock @@ -237,7 +237,7 @@ the *new_callable* argument to :func:`patch`. Accessing any attribute not in this list will raise an :exc:`AttributeError`. If *spec* is an object (rather than a list of strings) then - :attr:`~instance.__class__` returns the class of the spec object. This + :attr:`~object.__class__` returns the class of the spec object. This allows mocks to pass :func:`isinstance` tests. * *spec_set*: A stricter variant of *spec*. If used, attempting to *set* @@ -397,6 +397,8 @@ the *new_callable* argument to :func:`patch`. The reset_mock method resets all the call attributes on a mock object: + .. doctest:: + >>> mock = Mock(return_value=None) >>> mock('hello') >>> mock.called @@ -405,20 +407,41 @@ the *new_callable* argument to :func:`patch`. >>> mock.called False - .. versionchanged:: 3.6 - Added two keyword-only arguments to the reset_mock function. - This can be useful where you want to make a series of assertions that - reuse the same object. Note that :meth:`reset_mock` *doesn't* clear the + reuse the same object. + + *return_value* parameter when set to ``True`` resets :attr:`return_value`: + + .. doctest:: + + >>> mock = Mock(return_value=5) + >>> mock('hello') + 5 + >>> mock.reset_mock(return_value=True) + >>> mock('hello') # doctest: +ELLIPSIS + + + *side_effect* parameter when set to ``True`` resets :attr:`side_effect`: + + .. doctest:: + + >>> mock = Mock(side_effect=ValueError) + >>> mock('hello') + Traceback (most recent call last): + ... + ValueError + >>> mock.reset_mock(side_effect=True) + >>> mock('hello') # doctest: +ELLIPSIS + + + Note that :meth:`reset_mock` *doesn't* clear the :attr:`return_value`, :attr:`side_effect` or any child attributes you have - set using normal assignment by default. In case you want to reset - :attr:`return_value` or :attr:`side_effect`, then pass the corresponding - parameter as ``True``. Child mocks and the return value mock - (if any) are reset as well. + set using normal assignment by default. - .. note:: *return_value*, and *side_effect* are keyword-only - arguments. + Child mocks are reset as well. + .. versionchanged:: 3.6 + Added two keyword-only arguments to the reset_mock function. .. method:: mock_add_spec(spec, spec_set=False) @@ -733,8 +756,8 @@ the *new_callable* argument to :func:`patch`. .. attribute:: __class__ - Normally the :attr:`__class__` attribute of an object will return its type. - For a mock object with a :attr:`spec`, ``__class__`` returns the spec class + Normally the :attr:`!__class__` attribute of an object will return its type. + For a mock object with a :attr:`!spec`, :attr:`!__class__` returns the spec class instead. This allows mock objects to pass :func:`isinstance` tests for the object they are replacing / masquerading as: @@ -742,7 +765,7 @@ the *new_callable* argument to :func:`patch`. >>> isinstance(mock, int) True - :attr:`__class__` is assignable to, this allows a mock to pass an + :attr:`!__class__` is assignable to, this allows a mock to pass an :func:`isinstance` check without forcing you to use a spec: >>> mock = Mock() @@ -756,8 +779,8 @@ the *new_callable* argument to :func:`patch`. meaning of :class:`Mock`, with the exception of *return_value* and *side_effect* which have no meaning on a non-callable mock. -Mock objects that use a class or an instance as a :attr:`spec` or -:attr:`spec_set` are able to pass :func:`isinstance` tests: +Mock objects that use a class or an instance as a :attr:`!spec` or +:attr:`!spec_set` are able to pass :func:`isinstance` tests: >>> mock = Mock(spec=SomeClass) >>> isinstance(mock, SomeClass) @@ -856,6 +879,20 @@ object:: 3 >>> p.assert_called_once_with() +.. caution:: + + If an :exc:`AttributeError` is raised by :class:`PropertyMock`, + it will be interpreted as a missing descriptor and + :meth:`~object.__getattr__` will be called on the parent mock:: + + >>> m = MagicMock() + >>> no_attribute = PropertyMock(side_effect=AttributeError) + >>> type(m).my_property = no_attribute + >>> m.my_property + + + See :meth:`~object.__getattr__` for details. + .. class:: AsyncMock(spec=None, side_effect=None, return_value=DEFAULT, wraps=None, name=None, spec_set=None, unsafe=False, **kwargs) @@ -1112,7 +1149,7 @@ Calls made to the object will be recorded in the attributes like :attr:`~Mock.call_args` and :attr:`~Mock.call_args_list`. If :attr:`~Mock.side_effect` is set then it will be called after the call has -been recorded, so if :attr:`side_effect` raises an exception the call is still +been recorded, so if :attr:`!side_effect` raises an exception the call is still recorded. The simplest way to make a mock raise an exception when called is to make @@ -1133,8 +1170,8 @@ The simplest way to make a mock raise an exception when called is to make >>> m.mock_calls [call(1, 2, 3), call('two', 'three', 'four')] -If :attr:`side_effect` is a function then whatever that function returns is what -calls to the mock return. The :attr:`side_effect` function is called with the +If :attr:`~Mock.side_effect` is a function then whatever that function returns is what +calls to the mock return. The :attr:`!side_effect` function is called with the same arguments as the mock. This allows you to vary the return value of the call dynamically, based on the input: @@ -1151,7 +1188,7 @@ call dynamically, based on the input: If you want the mock to still return the default return value (a new mock), or any set return value, then there are two ways of doing this. Either return -:attr:`mock.return_value` from inside :attr:`side_effect`, or return :data:`DEFAULT`: +:attr:`~Mock.return_value` from inside :attr:`~Mock.side_effect`, or return :data:`DEFAULT`: >>> m = MagicMock() >>> def side_effect(*args, **kwargs): @@ -1168,8 +1205,8 @@ any set return value, then there are two ways of doing this. Either return >>> m() 3 -To remove a :attr:`side_effect`, and return to the default behaviour, set the -:attr:`side_effect` to ``None``: +To remove a :attr:`~Mock.side_effect`, and return to the default behaviour, set the +:attr:`!side_effect` to ``None``: >>> m = MagicMock(return_value=6) >>> def side_effect(*args, **kwargs): @@ -1182,7 +1219,7 @@ To remove a :attr:`side_effect`, and return to the default behaviour, set the >>> m() 6 -The :attr:`side_effect` can also be any iterable object. Repeated calls to the mock +The :attr:`~Mock.side_effect` can also be any iterable object. Repeated calls to the mock will return values from the iterable (until the iterable is exhausted and a :exc:`StopIteration` is raised): @@ -1223,7 +1260,7 @@ objects of any type. You may want a mock object to return ``False`` to a :func:`hasattr` call, or raise an :exc:`AttributeError` when an attribute is fetched. You can do this by providing -an object as a :attr:`spec` for a mock, but that isn't always convenient. +an object as a :attr:`!spec` for a mock, but that isn't always convenient. You "block" attributes by deleting them. Once deleted, accessing an attribute will raise an :exc:`AttributeError`. @@ -1392,7 +1429,7 @@ patch If you are patching builtins in a module then you don't need to pass ``create=True``, it will be added by default. - Patch can be used as a :class:`TestCase` class decorator. It works by + Patch can be used as a :class:`~unittest.TestCase` class decorator. It works by decorating each test method in the class. This reduces the boilerplate code when your test methods share a common patchings set. :func:`patch` finds tests by looking for method names that start with ``patch.TEST_PREFIX``. @@ -1430,7 +1467,7 @@ If the class is instantiated multiple times you could use can set the *return_value* to be anything you want. To configure return values on methods of *instances* on the patched class -you must do this on the :attr:`return_value`. For example:: +you must do this on the :attr:`~Mock.return_value`. For example:: >>> class Class: ... def method(self): @@ -1751,13 +1788,13 @@ context manager is a dictionary where created mocks are keyed by name:: patch methods: start and stop ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -All the patchers have :meth:`start` and :meth:`stop` methods. These make it simpler to do +All the patchers have :meth:`!start` and :meth:`!stop` methods. These make it simpler to do patching in ``setUp`` methods or where you want to do multiple patches without nesting decorators or with statements. To use them call :func:`patch`, :func:`patch.object` or :func:`patch.dict` as normal and keep a reference to the returned ``patcher`` object. You can then -call :meth:`start` to put the patch in place and :meth:`stop` to undo it. +call :meth:`!start` to put the patch in place and :meth:`!stop` to undo it. If you are using :func:`patch` to create a mock for you then it will be returned by the call to ``patcher.start``. :: @@ -1774,7 +1811,7 @@ the call to ``patcher.start``. :: A typical use case for this might be for doing multiple patches in the ``setUp`` -method of a :class:`TestCase`:: +method of a :class:`~unittest.TestCase`:: >>> class MyTest(unittest.TestCase): ... def setUp(self): @@ -2447,7 +2484,7 @@ behaviour you can switch it off by setting the module level switch Alternatively you can just use ``vars(my_mock)`` (instance members) and ``dir(type(my_mock))`` (type members) to bypass the filtering irrespective of -:const:`mock.FILTER_DIR`. +:const:`FILTER_DIR`. mock_open @@ -2462,7 +2499,7 @@ mock_open 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`, + *read_data* is a string for the :meth:`~io.RawIOBase.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 @@ -2474,7 +2511,7 @@ mock_open .. versionchanged:: 3.4 Added :meth:`~io.IOBase.readline` and :meth:`~io.IOBase.readlines` support. - The mock of :meth:`~io.IOBase.read` changed to consume *read_data* rather + The mock of :meth:`~io.RawIOBase.read` changed to consume *read_data* rather than returning it on each call. .. versionchanged:: 3.5 @@ -2526,7 +2563,7 @@ And for reading files:: Autospeccing ~~~~~~~~~~~~ -Autospeccing is based on the existing :attr:`spec` feature of mock. It limits the +Autospeccing is based on the existing :attr:`!spec` feature of mock. It limits the api of mocks to the api of an original object (the spec), but it is recursive (implemented lazily) so that attributes of mocks only have the same api as the attributes of the spec. In addition mocked functions / methods have the @@ -2551,8 +2588,8 @@ unit tests. Testing everything in isolation is all fine and dandy, but if you don't test how your units are "wired together" there is still lots of room for bugs that tests might have caught. -:mod:`mock` already provides a feature to help with this, called speccing. If you -use a class or instance as the :attr:`spec` for a mock then you can only access +:mod:`unittest.mock` already provides a feature to help with this, called speccing. If you +use a class or instance as the :attr:`!spec` for a mock then you can only access attributes on the mock that exist on the real class: >>> from urllib import request @@ -2590,7 +2627,7 @@ Here's an example of it in use:: >>> mock_request.Request -You can see that :class:`request.Request` has a spec. :class:`request.Request` takes two +You can see that :class:`!request.Request` has a spec. :class:`!request.Request` takes two arguments in the constructor (one of which is *self*). Here's what happens if we try to call it incorrectly:: @@ -2606,8 +2643,8 @@ specced mocks):: >>> req -:class:`Request` objects are not callable, so the return value of instantiating our -mocked out :class:`request.Request` is a non-callable mock. With the spec in place +:class:`!Request` objects are not callable, so the return value of instantiating our +mocked out :class:`!request.Request` is a non-callable mock. With the spec in place any typos in our asserts will raise the correct error:: >>> req.add_header('spam', 'eggs') @@ -2759,8 +2796,8 @@ Sealing mocks .. versionadded:: 3.7 -Order of precedence of :attr:`side_effect`, :attr:`return_value` and *wraps* ----------------------------------------------------------------------------- +Order of precedence of :attr:`!side_effect`, :attr:`!return_value` and *wraps* +------------------------------------------------------------------------------ The order of their precedence is: diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst index 68a8ddee..54ea8bb4 100644 --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -2308,8 +2308,8 @@ Loading and running tests (see :ref:`Warning control `), otherwise it will be set to ``'default'``. - Calling ``main`` actually returns an instance of the ``TestProgram`` class. - This stores the result of the tests run as the ``result`` attribute. + Calling ``main`` returns an object with the ``result`` attribute that contains + the result of the tests run as a :class:`unittest.TestResult`. .. versionchanged:: 3.1 The *exit* parameter was added. @@ -2521,7 +2521,7 @@ Signal Handling .. versionadded:: 3.2 The :option:`-c/--catch ` command-line option to unittest, -along with the ``catchbreak`` parameter to :func:`unittest.main()`, provide +along with the ``catchbreak`` parameter to :func:`unittest.main`, provide more friendly handling of control-C during a test run. With catch break behavior enabled control-C will allow the currently running test to complete, and the test run will then end and report all the results so far. A second diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst index cd402e87..b32b4af1 100644 --- a/Doc/library/urllib.parse.rst +++ b/Doc/library/urllib.parse.rst @@ -173,7 +173,7 @@ or on combining URL components into a URL string. Added IPv6 URL parsing capabilities. .. versionchanged:: 3.3 - The fragment is now parsed for all URL schemes (unless *allow_fragment* is + The fragment is now parsed for all URL schemes (unless *allow_fragments* is false), in accordance with :rfc:`3986`. Previously, an allowlist of schemes that support fragments existed. @@ -395,6 +395,15 @@ or on combining URL components into a URL string. If you do not want that behavior, preprocess the *url* with :func:`urlsplit` and :func:`urlunsplit`, removing possible *scheme* and *netloc* parts. + .. warning:: + + Because an absolute URL may be passed as the ``url`` parameter, it is + generally **not secure** to use ``urljoin`` with an attacker-controlled + ``url``. For example in, + ``urljoin("https://website.com/users/", username)``, if ``username`` can + contain an absolute URL, the result of ``urljoin`` will be the absolute + URL. + .. versionchanged:: 3.5 diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst index 8705adfb..0c5aa045 100644 --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -160,16 +160,28 @@ The :mod:`urllib.request` module defines the following functions: .. function:: pathname2url(path) - Convert the pathname *path* from the local syntax for a path to the form used in - the path component of a URL. This does not produce a complete URL. The return - value will already be quoted using the :func:`~urllib.parse.quote` function. + Convert the given local path to a ``file:`` URL. This function uses + :func:`~urllib.parse.quote` function to encode the path. For historical + reasons, the return value omits the ``file:`` scheme prefix. This example + shows the function being used on Windows:: + >>> from urllib.request import pathname2url + >>> path = 'C:\\Program Files' + >>> 'file:' + pathname2url(path) + 'file:///C:/Program%20Files' -.. function:: url2pathname(path) - Convert the path component *path* from a percent-encoded URL to the local syntax for a - path. This does not accept a complete URL. This function uses - :func:`~urllib.parse.unquote` to decode *path*. +.. function:: url2pathname(url) + + Convert the given ``file:`` URL to a local path. This function uses + :func:`~urllib.parse.unquote` to decode the URL. For historical reasons, + the given value *must* omit the ``file:`` scheme prefix. This example shows + the function being used on Windows:: + + >>> from urllib.request import url2pathname + >>> url = 'file:///C:/Program%20Files' + >>> url2pathname(url.removeprefix('file:')) + 'C:\\Program Files' .. function:: getproxies() @@ -252,7 +264,7 @@ The following classes are provided: *method* should be a string that indicates the HTTP request method that will be used (e.g. ``'HEAD'``). If provided, its value is stored in the - :attr:`~Request.method` attribute and is used by :meth:`get_method()`. + :attr:`~Request.method` attribute and is used by :meth:`get_method`. The default is ``'GET'`` if *data* is ``None`` or ``'POST'`` otherwise. Subclasses may indicate a different default method by setting the :attr:`~Request.method` attribute in the class itself. @@ -1103,7 +1115,7 @@ FileHandler Objects .. versionchanged:: 3.2 This method is applicable only for local hostnames. When a remote - hostname is given, an :exc:`~urllib.error.URLError` is raised. + hostname is given, a :exc:`~urllib.error.URLError` is raised. .. _data-handler-objects: @@ -1118,7 +1130,7 @@ DataHandler Objects ignores white spaces in base64 encoded data URLs so the URL may be wrapped in whatever source file it comes from. But even though some browsers don't mind about a missing padding at the end of a base64 encoded data URL, this - implementation will raise an :exc:`ValueError` in that case. + implementation will raise a :exc:`ValueError` in that case. .. _ftp-handler-objects: diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst index 57b0ee71..9eb0e9d1 100644 --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -37,14 +37,14 @@ A virtual environment is (amongst other things): are by default isolated from software in other virtual environments and Python interpreters and libraries installed in the operating system. -* Contained in a directory, conventionally either named ``venv`` or ``.venv`` in +* Contained in a directory, conventionally named ``.venv`` or ``venv`` in the project directory, or under a container directory for lots of virtual environments, such as ``~/.virtualenvs``. * Not checked into source control systems such as Git. * Considered as disposable -- it should be simple to delete and recreate it from - scratch. You don't place any project code in the environment + scratch. You don't place any project code in the environment. * Not considered as movable or copyable -- you just recreate the same environment in the target location. @@ -61,7 +61,117 @@ See :pep:`405` for more background on Python virtual environments. Creating virtual environments ----------------------------- -.. include:: /using/venv-create.inc +:ref:`Virtual environments ` are created by executing the ``venv`` +module: + +.. code-block:: shell + + python -m venv /path/to/new/virtual/environment + +This creates the target directory (including parent directories as needed) +and places a :file:`pyvenv.cfg` file in it with a ``home`` key +pointing to the Python installation from which the command was run. +It also creates a :file:`bin` (or :file:`Scripts` on Windows) subdirectory +containing a copy or symlink of the Python executable +(as appropriate for the platform or arguments used at environment creation time). +It also creates a :file:`lib/pythonX.Y/site-packages` subdirectory +(on Windows, this is :file:`Lib\site-packages`). +If an existing directory is specified, it will be re-used. + +.. versionchanged:: 3.5 + The use of ``venv`` is now recommended for creating virtual environments. + +.. deprecated-removed:: 3.6 3.8 + :program:`pyvenv` was the recommended tool for creating virtual environments + for Python 3.3 and 3.4, and replaced in 3.5 by executing ``venv`` directly. + +.. highlight:: none + +On Windows, invoke the ``venv`` command as follows: + +.. code-block:: ps1con + + PS> python -m venv C:\path\to\new\virtual\environment + +The command, if run with ``-h``, will show the available options:: + + usage: venv [-h] [--system-site-packages] [--symlinks | --copies] [--clear] + [--upgrade] [--without-pip] [--prompt PROMPT] [--upgrade-deps] + ENV_DIR [ENV_DIR ...] + + Creates virtual Python environments in one or more target directories. + + positional arguments: + ENV_DIR A directory to create the environment in. + + options: + -h, --help show this help message and exit + --system-site-packages + Give the virtual environment access to the system + site-packages dir. + --symlinks Try to use symlinks rather than copies, when + symlinks are not the default for the platform. + --copies Try to use copies rather than symlinks, even when + symlinks are the default for the platform. + --clear Delete the contents of the environment directory + if it already exists, before environment creation. + --upgrade Upgrade the environment directory to use this + version of Python, assuming Python has been + upgraded in-place. + --without-pip Skips installing or upgrading pip in the virtual + environment (pip is bootstrapped by default) + --prompt PROMPT Provides an alternative prompt prefix for this + environment. + --upgrade-deps Upgrade core dependencies (pip) to the latest + version in PyPI + + Once an environment has been created, you may wish to activate it, e.g. by + sourcing an activate script in its bin directory. + + +.. versionchanged:: 3.4 + Installs pip by default, added the ``--without-pip`` and ``--copies`` + options. + +.. versionchanged:: 3.4 + In earlier versions, if the target directory already existed, an error was + raised, unless the ``--clear`` or ``--upgrade`` option was provided. + +.. versionchanged:: 3.9 + Add ``--upgrade-deps`` option to upgrade pip + setuptools to the latest on PyPI. + +.. versionchanged:: 3.12 + + ``setuptools`` is no longer a core venv dependency. + +.. note:: + While symlinks are supported on Windows, they are not recommended. Of + particular note is that double-clicking ``python.exe`` in File Explorer + will resolve the symlink eagerly and ignore the virtual environment. + +.. note:: + On Microsoft Windows, it may be required to enable the ``Activate.ps1`` + script by setting the execution policy for the user. You can do this by + issuing the following PowerShell command: + + .. code-block:: powershell + + PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser + + See `About Execution Policies + `_ + for more information. + +The created :file:`pyvenv.cfg` file also includes the +``include-system-site-packages`` key, set to ``true`` if ``venv`` is +run with the ``--system-site-packages`` option, ``false`` otherwise. + +Unless the ``--without-pip`` option is given, :mod:`ensurepip` will be +invoked to bootstrap ``pip`` into the virtual environment. + +Multiple paths can be given to ``venv``, in which case an identical virtual +environment will be created, according to the given options, at each provided +path. .. _venv-explanation: @@ -95,7 +205,7 @@ containing the virtual environment): | +------------+--------------------------------------------------+ | | csh/tcsh | :samp:`$ source {}/bin/activate.csh` | | +------------+--------------------------------------------------+ -| | PowerShell | :samp:`$ {}/bin/Activate.ps1` | +| | pwsh | :samp:`$ {}/bin/Activate.ps1` | +-------------+------------+--------------------------------------------------+ | Windows | cmd.exe | :samp:`C:\\> {}\\Scripts\\activate.bat` | | +------------+--------------------------------------------------+ @@ -117,7 +227,7 @@ should be runnable without activating it. In order to achieve this, scripts installed into virtual environments have a "shebang" line which points to the environment's Python interpreter, -i.e. :samp:`#!/{}/bin/python`. +:samp:`#!/{}/bin/python`. This means that the script will run with that interpreter regardless of the value of :envvar:`PATH`. On Windows, "shebang" line processing is supported if you have the :ref:`launcher` installed. Thus, double-clicking an installed @@ -167,29 +277,29 @@ creation according to their needs, the :class:`EnvBuilder` class. The :class:`EnvBuilder` class accepts the following keyword arguments on instantiation: - * ``system_site_packages`` -- a Boolean value indicating that the system Python + * *system_site_packages* -- a boolean value indicating that the system Python site-packages should be available to the environment (defaults to ``False``). - * ``clear`` -- a Boolean value which, if true, will delete the contents of + * *clear* -- a boolean value which, if true, will delete the contents of any existing target directory, before creating the environment. - * ``symlinks`` -- a Boolean value indicating whether to attempt to symlink the + * *symlinks* -- a boolean value indicating whether to attempt to symlink the Python binary rather than copying. - * ``upgrade`` -- a Boolean value which, if true, will upgrade an existing + * *upgrade* -- a boolean value which, if true, will upgrade an existing environment with the running Python - for use when that Python has been upgraded in-place (defaults to ``False``). - * ``with_pip`` -- a Boolean value which, if true, ensures pip is + * *with_pip* -- a boolean value which, if true, ensures pip is installed in the virtual environment. This uses :mod:`ensurepip` with the ``--default-pip`` option. - * ``prompt`` -- a String to be used after virtual environment is activated + * *prompt* -- a string to be used after virtual environment is activated (defaults to ``None`` which means directory name of the environment would be used). If the special string ``"."`` is provided, the basename of the current directory is used as the prompt. - * ``upgrade_deps`` -- Update the base venv modules to the latest on PyPI + * *upgrade_deps* -- Update the base venv modules to the latest on PyPI .. versionchanged:: 3.4 Added the ``with_pip`` parameter @@ -200,10 +310,7 @@ creation according to their needs, the :class:`EnvBuilder` class. .. versionchanged:: 3.9 Added the ``upgrade_deps`` parameter - Creators of third-party virtual environment tools will be free to use the - provided :class:`EnvBuilder` class as a base class. - - The returned env-builder is an object which has a method, ``create``: + :class:`EnvBuilder` may be used as a base class. .. method:: create(env_dir) @@ -303,14 +410,14 @@ creation according to their needs, the :class:`EnvBuilder` class. .. method:: upgrade_dependencies(context) - Upgrades the core venv dependency packages (currently ``pip``) + Upgrades the core venv dependency packages (currently :pypi:`pip`) in the environment. This is done by shelling out to the ``pip`` executable in the environment. .. versionadded:: 3.9 .. versionchanged:: 3.12 - ``setuptools`` is no longer a core venv dependency. + :pypi:`setuptools` is no longer a core venv dependency. .. method:: post_setup(context) @@ -318,25 +425,15 @@ creation according to their needs, the :class:`EnvBuilder` class. implementations to pre-install packages in the virtual environment or perform other post-creation steps. - .. versionchanged:: 3.7.2 - Windows now uses redirector scripts for ``python[w].exe`` instead of - copying the actual binaries. In 3.7.2 only :meth:`setup_python` does - nothing unless running from a build in the source tree. - - .. versionchanged:: 3.7.3 - Windows copies the redirector scripts as part of :meth:`setup_python` - instead of :meth:`setup_scripts`. This was not the case in 3.7.2. - When using symlinks, the original executables will be linked. - - In addition, :class:`EnvBuilder` provides this utility method that can be - called from :meth:`setup_scripts` or :meth:`post_setup` in subclasses to - assist in installing custom scripts into the virtual environment. - .. method:: install_scripts(context, path) + This method can be + called from :meth:`setup_scripts` or :meth:`post_setup` in subclasses to + assist in installing custom scripts into the virtual environment. + *path* is the path to a directory that should contain subdirectories - "common", "posix", "nt", each containing scripts destined for the bin - directory in the environment. The contents of "common" and the + ``common``, ``posix``, ``nt``; each containing scripts destined for the + ``bin`` directory in the environment. The contents of ``common`` and the directory corresponding to :data:`os.name` are copied after some text replacement of placeholders: @@ -358,6 +455,16 @@ creation according to their needs, the :class:`EnvBuilder` class. The directories are allowed to exist (for when an existing environment is being upgraded). + .. versionchanged:: 3.7.2 + Windows now uses redirector scripts for ``python[w].exe`` instead of + copying the actual binaries. In 3.7.2 only :meth:`setup_python` does + nothing unless running from a build in the source tree. + + .. versionchanged:: 3.7.3 + Windows copies the redirector scripts as part of :meth:`setup_python` + instead of :meth:`setup_scripts`. This was not the case in 3.7.2. + When using symlinks, the original executables will be linked. + There is also a module-level convenience function: .. function:: create(env_dir, system_site_packages=False, clear=False, \ @@ -370,13 +477,13 @@ There is also a module-level convenience function: .. versionadded:: 3.3 .. versionchanged:: 3.4 - Added the ``with_pip`` parameter + Added the *with_pip* parameter .. versionchanged:: 3.6 - Added the ``prompt`` parameter + Added the *prompt* parameter .. versionchanged:: 3.9 - Added the ``upgrade_deps`` parameter + Added the *upgrade_deps* parameter An example of extending ``EnvBuilder`` -------------------------------------- diff --git a/Doc/library/warnings.rst b/Doc/library/warnings.rst index df38eaf8..53a402e3 100644 --- a/Doc/library/warnings.rst +++ b/Doc/library/warnings.rst @@ -178,6 +178,19 @@ If a warning is reported and doesn't match any registered filter then the "default" action is applied (hence its name). + +.. _repeated-warning-suppression-criteria: + +Repeated Warning Suppression Criteria +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The filters that suppress repeated warnings apply the following criteria to determine if a warning is considered a repeat: + +- ``"default"``: A warning is considered a repeat only if the (*message*, *category*, *module*, *lineno*) are all the same. +- ``"module"``: A warning is considered a repeat if the (*message*, *category*, *module*) are the same, ignoring the line number. +- ``"once"``: A warning is considered a repeat if the (*message*, *category*) are the same, ignoring the module and line number. + + .. _describing-warning-filters: Describing Warning Filters @@ -396,7 +409,7 @@ Available Functions ------------------- -.. function:: warn(message, category=None, stacklevel=1, source=None, *, skip_file_prefixes=None) +.. function:: warn(message, category=None, stacklevel=1, source=None, *, skip_file_prefixes=()) Issue a warning, or maybe ignore it or raise an exception. The *category* argument, if given, must be a :ref:`warning category class `; it @@ -545,6 +558,9 @@ Available Context Managers passed to :func:`simplefilter` as if it were called immediately on entering the context. + See :ref:`warning-filter` for the meaning of the *category* and *lineno* + parameters. + .. note:: The :class:`catch_warnings` manager works by replacing and diff --git a/Doc/library/wave.rst b/Doc/library/wave.rst index ba0ed23b..454f0541 100644 --- a/Doc/library/wave.rst +++ b/Doc/library/wave.rst @@ -46,8 +46,8 @@ The :mod:`wave` module defines the following function and exception: the file object. The :func:`.open` function may be used in a :keyword:`with` statement. When - the :keyword:`!with` block completes, the :meth:`Wave_read.close()` or - :meth:`Wave_write.close()` method is called. + the :keyword:`!with` block completes, the :meth:`Wave_read.close` or + :meth:`Wave_write.close` method is called. .. versionchanged:: 3.4 Added support for unseekable files. diff --git a/Doc/library/weakref.rst b/Doc/library/weakref.rst index d6e062df..2a25ed04 100644 --- a/Doc/library/weakref.rst +++ b/Doc/library/weakref.rst @@ -197,7 +197,7 @@ See :ref:`__slots__ documentation ` for details. >>> del k1 # d = {k2: 2} .. versionchanged:: 3.9 - Added support for ``|`` and ``|=`` operators, specified in :pep:`584`. + Added support for ``|`` and ``|=`` operators, as specified in :pep:`584`. :class:`WeakKeyDictionary` objects have an additional method that exposes the internal references directly. The references are not guaranteed to diff --git a/Doc/library/webbrowser.rst b/Doc/library/webbrowser.rst index df22c5f5..c34b2170 100644 --- a/Doc/library/webbrowser.rst +++ b/Doc/library/webbrowser.rst @@ -62,6 +62,8 @@ The following functions are defined: (note that under many window managers this will occur regardless of the setting of this variable). + Returns ``True`` if a browser was successfully launched, ``False`` otherwise. + Note that on some platforms, trying to open a filename using this function, may work and start the operating system's associated program. However, this is neither supported nor portable. @@ -74,11 +76,16 @@ The following functions are defined: Open *url* in a new window of the default browser, if possible, otherwise, open *url* in the only browser window. + Returns ``True`` if a browser was successfully launched, ``False`` otherwise. + + .. function:: open_new_tab(url) Open *url* in a new page ("tab") of the default browser, if possible, otherwise equivalent to :func:`open_new`. + Returns ``True`` if a browser was successfully launched, ``False`` otherwise. + .. function:: get(using=None) diff --git a/Doc/library/wsgiref.rst b/Doc/library/wsgiref.rst index 6faf7e8c..95327736 100644 --- a/Doc/library/wsgiref.rst +++ b/Doc/library/wsgiref.rst @@ -783,8 +783,8 @@ in :pep:`3333`. .. class:: StartResponse() - A :class:`typing.Protocol` describing `start_response() - `_ + A :class:`typing.Protocol` describing :pep:`start_response() + <3333#the-start-response-callable>` callables (:pep:`3333`). .. data:: WSGIEnvironment @@ -797,18 +797,18 @@ in :pep:`3333`. .. class:: InputStream() - A :class:`typing.Protocol` describing a `WSGI Input Stream - `_. + A :class:`typing.Protocol` describing a :pep:`WSGI Input Stream + <3333#input-and-error-streams>`. .. class:: ErrorStream() - A :class:`typing.Protocol` describing a `WSGI Error Stream - `_. + A :class:`typing.Protocol` describing a :pep:`WSGI Error Stream + <3333#input-and-error-streams>`. .. class:: FileWrapper() - A :class:`typing.Protocol` describing a `file wrapper - `_. + A :class:`typing.Protocol` describing a :pep:`file wrapper + <3333#optional-platform-specific-file-handling>`. See :class:`wsgiref.util.FileWrapper` for a concrete implementation of this protocol. diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst index 2fedd99e..9acb7169 100644 --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -508,7 +508,7 @@ Functions `C14N 2.0 `_ transformation function. Canonicalization is a way to normalise XML output in a way that allows - byte-by-byte comparisons and digital signatures. It reduced the freedom + byte-by-byte comparisons and digital signatures. It reduces the freedom that XML serializers have and instead generates a more constrained XML representation. The main restrictions regard the placement of namespace declarations, the ordering of attributes, and ignorable whitespace. @@ -869,6 +869,7 @@ Element Objects .. module:: xml.etree.ElementTree :noindex: + :no-index: .. class:: Element(tag, attrib={}, **extra) @@ -965,7 +966,7 @@ Element Objects .. method:: extend(subelements) - Appends *subelements* from a sequence object with zero or more elements. + Appends *subelements* from an iterable of elements. Raises :exc:`TypeError` if a subelement is not an :class:`Element`. .. versionadded:: 3.2 @@ -1053,9 +1054,10 @@ Element Objects :meth:`~object.__getitem__`, :meth:`~object.__setitem__`, :meth:`~object.__len__`. - Caution: Elements with no subelements will test as ``False``. Testing the - truth value of an Element is deprecated and will raise an exception in - Python 3.14. Use specific ``len(elem)`` or ``elem is None`` test instead.:: + Caution: Elements with no subelements will test as ``False``. In a future + release of Python, all elements will test as ``True`` regardless of whether + subelements exist. Instead, prefer explicit ``len(elem)`` or + ``elem is not None`` tests.:: element = root.find('foo') @@ -1368,7 +1370,7 @@ XMLParser Objects .. versionchanged:: 3.8 Parameters are now :ref:`keyword-only `. - The *html* argument no longer supported. + The *html* argument is no longer supported. .. method:: close() diff --git a/Doc/library/xmlrpc.client.rst b/Doc/library/xmlrpc.client.rst index 614fb19d..c57f433e 100644 --- a/Doc/library/xmlrpc.client.rst +++ b/Doc/library/xmlrpc.client.rst @@ -165,7 +165,7 @@ between conformable Python objects and XML on the wire. A good description of XML-RPC operation and client software in several languages. Contains pretty much everything an XML-RPC client developer needs to know. - `XML-RPC Introspection `_ + `XML-RPC Introspection `_ Describes the XML-RPC protocol extension for introspection. `XML-RPC Specification `_ diff --git a/Doc/library/zipapp.rst b/Doc/library/zipapp.rst index cf561b45..cdaba07a 100644 --- a/Doc/library/zipapp.rst +++ b/Doc/library/zipapp.rst @@ -332,7 +332,7 @@ Formally, the Python zip application format is therefore: interpreter name, and then a newline (``b'\n'``) character. The interpreter name can be anything acceptable to the OS "shebang" processing, or the Python launcher on Windows. The interpreter should be encoded in UTF-8 on Windows, - and in :func:`sys.getfilesystemencoding()` on POSIX. + and in :func:`sys.getfilesystemencoding` on POSIX. 2. Standard zipfile data, as generated by the :mod:`zipfile` module. The zipfile content *must* include a file called ``__main__.py`` (which must be in the "root" of the zipfile - i.e., it cannot be in a subdirectory). The diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 374404bf..ddb1337f 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -245,13 +245,12 @@ handler is started. This search inspects the :keyword:`!except` clauses in turn until one is found that matches the exception. An expression-less :keyword:`!except` clause, if present, must be last; it matches any exception. -For an :keyword:`!except` clause with an expression, -that expression is evaluated, and the clause matches the exception -if the resulting object is "compatible" with the exception. An object is -compatible with an exception if the object is the class or a -:term:`non-virtual base class ` of the exception object, -or a tuple containing an item that is the class or a non-virtual base class -of the exception object. + +For an :keyword:`!except` clause with an expression, the +expression must evaluate to an exception type or a tuple of exception types. +The raised exception matches an :keyword:`!except` clause whose expression evaluates +to the class or a :term:`non-virtual base class ` of the exception object, +or to a tuple that contains such a class. If no :keyword:`!except` clause matches the exception, the search for an exception handler @@ -378,8 +377,10 @@ exception group with an empty message string. :: ... ExceptionGroup('', (BlockingIOError())) -An :keyword:`!except*` clause must have a matching type, -and this type cannot be a subclass of :exc:`BaseExceptionGroup`. +An :keyword:`!except*` clause must have a matching expression; it cannot be ``except*:``. +Furthermore, this expression cannot contain exception group types, because that would +have ambiguous semantics. + It is not possible to mix :keyword:`except` and :keyword:`!except*` in the same :keyword:`try`. :keyword:`break`, :keyword:`continue` and :keyword:`return` @@ -533,18 +534,15 @@ is semantically equivalent to:: enter = type(manager).__enter__ exit = type(manager).__exit__ value = enter(manager) - hit_except = False try: TARGET = value SUITE except: - hit_except = True if not exit(manager, *sys.exc_info()): raise - finally: - if not hit_except: - exit(manager, None, None, None) + else: + exit(manager, None, None, None) With more than one item, the context managers are processed as if multiple :keyword:`with` statements were nested:: @@ -840,7 +838,7 @@ A literal pattern corresponds to most : | "None" : | "True" : | "False" - : | `signed_number`: NUMBER | "-" NUMBER + signed_number: ["-"] NUMBER The rule ``strings`` and the token ``NUMBER`` are defined in the :doc:`standard Python grammar <./grammar>`. Triple-quoted strings are @@ -1216,9 +1214,10 @@ A function definition defines a user-defined function object (see section : | `parameter_list_no_posonly` parameter_list_no_posonly: `defparameter` ("," `defparameter`)* ["," [`parameter_list_starargs`]] : | `parameter_list_starargs` - parameter_list_starargs: "*" [`parameter`] ("," `defparameter`)* ["," ["**" `parameter` [","]]] + parameter_list_starargs: "*" [`star_parameter`] ("," `defparameter`)* ["," ["**" `parameter` [","]]] : | "**" `parameter` [","] parameter: `identifier` [":" `expression`] + star_parameter: `identifier` [":" ["*"] `expression`] defparameter: `parameter` ["=" `expression`] funcname: `identifier` @@ -1325,7 +1324,8 @@ and may only be passed by positional arguments. Parameters may have an :term:`annotation ` of the form "``: expression``" following the parameter name. Any parameter may have an annotation, even those of the form -``*identifier`` or ``**identifier``. Functions may have "return" annotation of +``*identifier`` or ``**identifier``. (As a special case, parameters of the form +``*identifier`` may have an annotation "``: *expression``".) Functions may have "return" annotation of the form "``-> expression``" after the parameter list. These annotations can be any valid Python expression. The presence of annotations does not change the semantics of a function. The annotation values are available as values of @@ -1336,6 +1336,10 @@ enables postponed evaluation. Otherwise, they are evaluated when the function definition is executed. In this case annotations may be evaluated in a different order than they appear in the source code. +.. versionchanged:: 3.11 + Parameters of the form "``*identifier``" may have an annotation + "``: *expression``". See :pep:`646`. + .. index:: pair: lambda; expression It is also possible to create anonymous functions (functions not bound to a @@ -1421,7 +1425,7 @@ dictionary. The class name is bound to this class object in the original local namespace. The order in which attributes are defined in the class body is preserved -in the new class's ``__dict__``. Note that this is reliable only right +in the new class's :attr:`~type.__dict__`. Note that this is reliable only right after the class is created and only for classes that were defined using the definition syntax. @@ -1452,8 +1456,8 @@ decorators. The result is then bound to the class name. A list of :ref:`type parameters ` may be given in square brackets immediately after the class's name. This indicates to static type checkers that the class is generic. At runtime, -the type parameters can be retrieved from the class's ``__type_params__`` -attribute. See :ref:`generic-classes` for more. +the type parameters can be retrieved from the class's +:attr:`~type.__type_params__` attribute. See :ref:`generic-classes` for more. .. versionchanged:: 3.12 Type parameter lists are new in Python 3.12. @@ -1663,8 +1667,8 @@ with more precision. The scope of type parameters is modeled with a special function (technically, an :ref:`annotation scope `) that wraps the creation of the generic object. -Generic functions, classes, and type aliases have a :attr:`!__type_params__` -attribute listing their type parameters. +Generic functions, classes, and type aliases have a +:attr:`~definition.__type_params__` attribute listing their type parameters. Type parameters come in three kinds: @@ -1876,5 +1880,5 @@ like ``TYPE_PARAMS_OF_ListOrSet`` are not actually bound at runtime. therefore the function's :term:`docstring`. .. [#] A string literal appearing as the first statement in the class body is - transformed into the namespace's ``__doc__`` item and therefore the class's - :term:`docstring`. + transformed into the namespace's :attr:`~type.__doc__` item and therefore + the class's :term:`docstring`. diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 602014de..e19a365f 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -106,12 +106,16 @@ that mutable object is changed. Types affect almost all aspects of object behavior. Even the importance of object identity is affected in some sense: for immutable types, operations that compute new values may actually return a reference to any existing object with -the same type and value, while for mutable objects this is not allowed. E.g., -after ``a = 1; b = 1``, ``a`` and ``b`` may or may not refer to the same object -with the value one, depending on the implementation, but after ``c = []; d = -[]``, ``c`` and ``d`` are guaranteed to refer to two different, unique, newly -created empty lists. (Note that ``c = d = []`` assigns the same object to both -``c`` and ``d``.) +the same type and value, while for mutable objects this is not allowed. +For example, after ``a = 1; b = 1``, *a* and *b* may or may not refer to +the same object with the value one, depending on the implementation. +This is because :class:`int` is an immutable type, so the reference to ``1`` +can be reused. This behaviour depends on the implementation used, so should +not be relied upon, but is something to be aware of when making use of object +identity tests. +However, after ``c = []; d = []``, *c* and *d* are guaranteed to refer to two +different, unique, newly created empty lists. (Note that ``e = f = []`` assigns +the *same* object to both *e* and *f*.) .. _types: @@ -215,7 +219,7 @@ properties: * A sign is shown only when the number is negative. -Python distinguishes between integers, floating point numbers, and complex +Python distinguishes between integers, floating-point numbers, and complex numbers: @@ -259,18 +263,18 @@ Booleans (:class:`bool`) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. index:: - pair: object; floating point - pair: floating point; number + pair: object; floating-point + pair: floating-point; number pair: C; language pair: Java; language -These represent machine-level double precision floating point numbers. You are +These represent machine-level double precision floating-point numbers. You are at the mercy of the underlying machine architecture (and C or Java implementation) for the accepted range and handling of overflow. Python does not -support single-precision floating point numbers; the savings in processor and +support single-precision floating-point numbers; the savings in processor and memory usage that are usually the reason for using these are dwarfed by the overhead of using objects in Python, so there is no reason to complicate the -language with two kinds of floating point numbers. +language with two kinds of floating-point numbers. :class:`numbers.Complex` (:class:`complex`) @@ -281,7 +285,7 @@ language with two kinds of floating point numbers. pair: complex; number These represent complex numbers as a pair of machine-level double precision -floating point numbers. The same caveats apply as for floating point numbers. +floating-point numbers. The same caveats apply as for floating-point numbers. The real and imaginary parts of a complex number ``z`` can be retrieved through the read-only attributes ``z.real`` and ``z.imag``. @@ -373,7 +377,7 @@ Bytes A bytes object is an immutable array. The items are 8-bit bytes, represented by integers in the range 0 <= x < 256. Bytes literals - (like ``b'abc'``) and the built-in :func:`bytes()` constructor + (like ``b'abc'``) and the built-in :func:`bytes` constructor can be used to create bytes objects. Also, bytes objects can be decoded to strings via the :meth:`~bytes.decode` method. @@ -492,7 +496,7 @@ in the same order they were added sequentially over the dictionary. Replacing an existing key does not change the order, however removing a key and re-inserting it will add it to the end instead of keeping its old place. -Dictionaries are mutable; they can be created by the ``{...}`` notation (see +Dictionaries are mutable; they can be created by the ``{}`` notation (see section :ref:`dict`). .. index:: @@ -587,7 +591,6 @@ Most of these attributes check the type of the assigned value: * - .. attribute:: function.__doc__ - The function's documentation string, or ``None`` if unavailable. - Not inherited by subclasses. * - .. attribute:: function.__name__ - The function's name. @@ -727,14 +730,7 @@ When an instance method object is derived from a :class:`classmethod` object, th itself, so that calling either ``x.f(1)`` or ``C.f(1)`` is equivalent to calling ``f(C,1)`` where ``f`` is the underlying function. -Note that the transformation from :ref:`function object ` -to instance method -object happens each time the attribute is retrieved from the instance. In -some cases, a fruitful optimization is to assign the attribute to a local -variable and call that local variable. Also notice that this -transformation only happens for user-defined functions; other callable -objects (and all non-callable objects) are retrieved without -transformation. It is also important to note that user-defined functions +It is important to note that user-defined functions which are attributes of a class instance are not converted to bound methods; this *only* happens when the function is an attribute of the class. @@ -853,6 +849,8 @@ Instances of arbitrary classes can be made callable by defining a :meth:`~object.__call__` method in their class. +.. _module-objects: + Modules ------- @@ -878,47 +876,225 @@ Attribute assignment updates the module's namespace dictionary, e.g., .. index:: single: __name__ (module attribute) - single: __doc__ (module attribute) + single: __spec__ (module attribute) + single: __package__ (module attribute) + single: __loader__ (module attribute) + single: __path__ (module attribute) single: __file__ (module attribute) + single: __cached__ (module attribute) + single: __doc__ (module attribute) single: __annotations__ (module attribute) pair: module; namespace -Predefined (writable) attributes: +.. _import-mod-attrs: + +Import-related attributes on module objects +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Module objects have the following attributes that relate to the +:ref:`import system `. When a module is created using the machinery associated +with the import system, these attributes are filled in based on the module's +:term:`spec `, before the :term:`loader` executes and loads the +module. + +To create a module dynamically rather than using the import system, +it's recommended to use :func:`importlib.util.module_from_spec`, +which will set the various import-controlled attributes to appropriate values. +It's also possible to use the :class:`types.ModuleType` constructor to create +modules directly, but this technique is more error-prone, as most attributes +must be manually set on the module object after it has been created when using +this approach. + +.. caution:: + + With the exception of :attr:`~module.__name__`, it is **strongly** + recommended that you rely on :attr:`~module.__spec__` and its attributes + instead of any of the other individual attributes listed in this subsection. + Note that updating an attribute on :attr:`!__spec__` will not update the + corresponding attribute on the module itself: + + .. doctest:: + + >>> import typing + >>> typing.__name__, typing.__spec__.name + ('typing', 'typing') + >>> typing.__spec__.name = 'spelling' + >>> typing.__name__, typing.__spec__.name + ('typing', 'spelling') + >>> typing.__name__ = 'keyboard_smashing' + >>> typing.__name__, typing.__spec__.name + ('keyboard_smashing', 'spelling') + +.. attribute:: module.__name__ + + The name used to uniquely identify the module in the import system. + For a directly executed module, this will be set to ``"__main__"``. + + This attribute must be set to the fully qualified name of the module. + It is expected to match the value of + :attr:`module.__spec__.name `. + +.. attribute:: module.__spec__ + + A record of the module's import-system-related state. + + Set to the :class:`module spec ` that was + used when importing the module. See :ref:`module-specs` for more details. + + .. versionadded:: 3.4 + +.. attribute:: module.__package__ + + The :term:`package` a module belongs to. + + If the module is top-level (that is, not a part of any specific package) + then the attribute should be set to ``''`` (the empty string). Otherwise, + it should be set to the name of the module's package (which can be equal to + :attr:`module.__name__` if the module itself is a package). See :pep:`366` + for further details. + + This attribute is used instead of :attr:`~module.__name__` to calculate + explicit relative imports for main modules. It defaults to ``None`` for + modules created dynamically using the :class:`types.ModuleType` constructor; + use :func:`importlib.util.module_from_spec` instead to ensure the attribute + is set to a :class:`str`. + + It is **strongly** recommended that you use + :attr:`module.__spec__.parent ` + instead of :attr:`!module.__package__`. :attr:`__package__` is now only used + as a fallback if :attr:`!__spec__.parent` is not set, and this fallback + path is deprecated. + + .. versionchanged:: 3.4 + This attribute now defaults to ``None`` for modules created dynamically + using the :class:`types.ModuleType` constructor. + Previously the attribute was optional. + + .. versionchanged:: 3.6 + The value of :attr:`!__package__` is expected to be the same as + :attr:`__spec__.parent `. + :attr:`__package__` is now only used as a fallback during import + resolution if :attr:`!__spec__.parent` is not defined. + + .. versionchanged:: 3.10 + :exc:`ImportWarning` is raised if an import resolution falls back to + :attr:`!__package__` instead of + :attr:`__spec__.parent `. + + .. versionchanged:: 3.12 + Raise :exc:`DeprecationWarning` instead of :exc:`ImportWarning` when + falling back to :attr:`!__package__` during import resolution. + +.. attribute:: module.__loader__ + + The :term:`loader` object that the import machinery used to load the module. + + This attribute is mostly useful for introspection, but can be used for + additional loader-specific functionality, for example getting data + associated with a loader. + + :attr:`!__loader__` defaults to ``None`` for modules created dynamically + using the :class:`types.ModuleType` constructor; + use :func:`importlib.util.module_from_spec` instead to ensure the attribute + is set to a :term:`loader` object. + + It is **strongly** recommended that you use + :attr:`module.__spec__.loader ` + instead of :attr:`!module.__loader__`. + + .. versionchanged:: 3.4 + This attribute now defaults to ``None`` for modules created dynamically + using the :class:`types.ModuleType` constructor. + Previously the attribute was optional. + + .. deprecated-removed:: 3.12 3.16 + Setting :attr:`!__loader__` on a module while failing to set + :attr:`!__spec__.loader` is deprecated. In Python 3.16, + :attr:`!__loader__` will cease to be set or taken into consideration by + the import system or the standard library. + +.. attribute:: module.__path__ + + A (possibly empty) :term:`sequence` of strings enumerating the locations + where the package's submodules will be found. Non-package modules should + not have a :attr:`!__path__` attribute. See :ref:`package-path-rules` for + more details. + + It is **strongly** recommended that you use + :attr:`module.__spec__.submodule_search_locations ` + instead of :attr:`!module.__path__`. + +.. attribute:: module.__file__ +.. attribute:: module.__cached__ + + :attr:`!__file__` and :attr:`!__cached__` are both optional attributes that + may or may not be set. Both attributes should be a :class:`str` when they + are available. + + :attr:`!__file__` indicates the pathname of the file from which the module + was loaded (if loaded from a file), or the pathname of the shared library + file for extension modules loaded dynamically from a shared library. + It might be missing for certain types of modules, such as C modules that are + statically linked into the interpreter, and the + :ref:`import system ` may opt to leave it unset if it + has no semantic meaning (for example, a module loaded from a database). + + If :attr:`!__file__` is set then the :attr:`!__cached__` attribute might + also be set, which is the path to any compiled version of + the code (for example, a byte-compiled file). The file does not need to exist + to set this attribute; the path can simply point to where the + compiled file *would* exist (see :pep:`3147`). + + Note that :attr:`!__cached__` may be set even if :attr:`!__file__` is not + set. However, that scenario is quite atypical. Ultimately, the + :term:`loader` is what makes use of the module spec provided by the + :term:`finder` (from which :attr:`!__file__` and :attr:`!__cached__` are + derived). So if a loader can load from a cached module but otherwise does + not load from a file, that atypical scenario may be appropriate. + + It is **strongly** recommended that you use + :attr:`module.__spec__.cached ` + instead of :attr:`!module.__cached__`. + +Other writable attributes on module objects +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As well as the import-related attributes listed above, module objects also have +the following writable attributes: - :attr:`__name__` - The module's name. +.. attribute:: module.__doc__ - :attr:`__doc__` - The module's documentation string, or ``None`` if - unavailable. + The module's documentation string, or ``None`` if unavailable. + See also: :attr:`__doc__ attributes `. - :attr:`__file__` - The pathname of the file from which the - module was loaded, if it was loaded from a file. - The :attr:`__file__` - attribute may be missing for certain types of modules, such as C modules - that are statically linked into the interpreter. For extension modules - loaded dynamically from a shared library, it's the pathname of the shared - library file. +.. attribute:: module.__annotations__ - :attr:`__annotations__` - A dictionary containing - :term:`variable annotations ` collected during - module body execution. For best practices on working - with :attr:`__annotations__`, please see :ref:`annotations-howto`. + A dictionary containing + :term:`variable annotations ` collected during module + body execution. For best practices on working with :attr:`__annotations__`, + please see :ref:`annotations-howto`. + +Module dictionaries +^^^^^^^^^^^^^^^^^^^ + +Module objects also have the following special read-only attribute: .. index:: single: __dict__ (module attribute) +.. attribute:: module.__dict__ -Special read-only attribute: :attr:`~object.__dict__` is the module's -namespace as a dictionary object. + The module's namespace as a dictionary object. Uniquely among the attributes + listed here, :attr:`!__dict__` cannot be accessed as a global variable from + within a module; it can only be accessed as an attribute on module objects. -.. impl-detail:: + .. impl-detail:: + + Because of the way CPython clears module dictionaries, the module + dictionary will be cleared when the module falls out of scope even if the + dictionary still has live references. To avoid this, copy the dictionary + or keep the module around while using its dictionary directly. - Because of the way CPython clears module dictionaries, the module - dictionary will be cleared when the module falls out of scope even if the - dictionary still has live references. To avoid this, copy the dictionary - or keep the module around while using its dictionary directly. +.. _class-attrs-and-methods: Custom classes -------------- @@ -962,6 +1138,9 @@ of a base class. A class object can be called (see above) to yield a class instance (see below). +Special attributes +^^^^^^^^^^^^^^^^^^ + .. index:: single: __name__ (class attribute) single: __module__ (class attribute) @@ -971,35 +1150,86 @@ A class object can be called (see above) to yield a class instance (see below). single: __annotations__ (class attribute) single: __type_params__ (class attribute) -Special attributes: +.. list-table:: + :header-rows: 1 - :attr:`~definition.__name__` - The class name. + * - Attribute + - Meaning - :attr:`__module__` - The name of the module in which the class was defined. + * - .. attribute:: type.__name__ + - The class's name. + See also: :attr:`__name__ attributes `. - :attr:`~object.__dict__` - The dictionary containing the class's namespace. + * - .. attribute:: type.__qualname__ + - The class's :term:`qualified name`. + See also: :attr:`__qualname__ attributes `. + + * - .. attribute:: type.__module__ + - The name of the module in which the class was defined. + + * - .. attribute:: type.__dict__ + - A :class:`mapping proxy ` + providing a read-only view of the class's namespace. + See also: :attr:`__dict__ attributes `. + + * - .. attribute:: type.__bases__ + - A :class:`tuple` containing the class's bases. + In most cases, for a class defined as ``class X(A, B, C)``, + ``X.__bases__`` will be exactly equal to ``(A, B, C)``. + + * - .. attribute:: type.__doc__ + - The class's documentation string, or ``None`` if undefined. + Not inherited by subclasses. + + * - .. attribute:: type.__annotations__ + - A dictionary containing + :term:`variable annotations ` + collected during class body execution. For best practices on working + with :attr:`!__annotations__`, please see :ref:`annotations-howto`. + + .. caution:: - :attr:`~class.__bases__` - A tuple containing the base classes, in the order of - their occurrence in the base class list. + Accessing the :attr:`!__annotations__` attribute of a class + object directly may yield incorrect results in the presence of + metaclasses. In addition, the attribute may not exist for + some classes. Use :func:`inspect.get_annotations` to + retrieve class annotations safely. - :attr:`__doc__` - The class's documentation string, or ``None`` if undefined. + * - .. attribute:: type.__type_params__ + - A :class:`tuple` containing the :ref:`type parameters ` of + a :ref:`generic class `. + + .. versionadded:: 3.12 + + * - .. attribute:: type.__mro__ + - The :class:`tuple` of classes that are considered when looking for + base classes during method resolution. + + +Special methods +^^^^^^^^^^^^^^^ + +In addition to the special attributes described above, all Python classes also +have the following two methods available: + +.. method:: type.mro - :attr:`__annotations__` - A dictionary containing - :term:`variable annotations ` - collected during class body execution. For best practices on - working with :attr:`__annotations__`, please see - :ref:`annotations-howto`. + This method can be overridden by a metaclass to customize the method + resolution order for its instances. It is called at class instantiation, + and its result is stored in :attr:`~type.__mro__`. - :attr:`__type_params__` - A tuple containing the :ref:`type parameters ` of - a :ref:`generic class `. +.. method:: type.__subclasses__ + Each class keeps a list of weak references to its immediate subclasses. This + method returns a list of all those references still alive. The list is in + definition order. Example: + + .. doctest:: + + >>> class A: pass + >>> class B(A): pass + >>> A.__subclasses__() + [] Class instances --------------- @@ -1039,12 +1269,22 @@ dictionary directly. Class instances can pretend to be numbers, sequences, or mappings if they have methods with certain special names. See section :ref:`specialnames`. +Special attributes +^^^^^^^^^^^^^^^^^^ + .. index:: single: __dict__ (instance attribute) single: __class__ (instance attribute) -Special attributes: :attr:`~object.__dict__` is the attribute dictionary; -:attr:`~instance.__class__` is the instance's class. +.. attribute:: object.__class__ + + The class to which a class instance belongs. + +.. attribute:: object.__dict__ + + A dictionary or other mapping object used to store an object's (writable) + attributes. Not all instances have a :attr:`!__dict__` attribute; see the + section on :ref:`slots` for more details. I/O objects (also known as file objects) @@ -1188,7 +1428,7 @@ Special read-only attributes .. deprecated:: 3.12 This attribute of code objects is deprecated, and may be removed in - Python 3.14. + Python 3.15. * - .. attribute:: codeobject.co_stacksize - The required stack size of the code object @@ -1643,6 +1883,8 @@ Basic customization It is not guaranteed that :meth:`__del__` methods are called for objects that still exist when the interpreter exits. + :class:`weakref.finalize` provides a straightforward way to register + a cleanup function to be called when an object is garbage collected. .. note:: @@ -1700,7 +1942,8 @@ Basic customization "informal" string representation of instances of that class is required. This is typically used for debugging, so it is important that the representation - is information-rich and unambiguous. + is information-rich and unambiguous. A default implementation is provided by the + :class:`object` class itself. .. index:: single: string; __str__() (object method) @@ -1710,10 +1953,10 @@ Basic customization .. method:: object.__str__(self) - Called by :func:`str(object) ` and the built-in functions - :func:`format` and :func:`print` to compute the "informal" or nicely + Called by :func:`str(object) `, the default :meth:`__format__` implementation, + and the built-in function :func:`print`, to compute the "informal" or nicely printable string representation of an object. The return value must be a - :ref:`string ` object. + :ref:`str ` object. This method differs from :meth:`object.__repr__` in that there is no expectation that :meth:`__str__` return a valid Python expression: a more @@ -1730,7 +1973,8 @@ Basic customization .. index:: pair: built-in function; bytes Called by :ref:`bytes ` to compute a byte-string representation - of an object. This should return a :class:`bytes` object. + of an object. This should return a :class:`bytes` object. The :class:`object` + class itself does not provide this method. .. index:: single: string; __format__() (object method) @@ -1754,6 +1998,9 @@ Basic customization The return value must be a string object. + The default implementation by the :class:`object` class should be given + an empty *format_spec* string. It delegates to :meth:`__str__`. + .. versionchanged:: 3.4 The __format__ method of ``object`` itself raises a :exc:`TypeError` if passed any non-empty string. @@ -1796,6 +2043,12 @@ Basic customization ``(x` with multiple slotted parent @@ -2547,7 +2801,7 @@ in the local namespace as the defined class. When a new class is created by ``type.__new__``, the object provided as the namespace parameter is copied to a new ordered mapping and the original object is discarded. The new copy is wrapped in a read-only proxy, which -becomes the :attr:`~object.__dict__` attribute of the class object. +becomes the :attr:`~type.__dict__` attribute of the class object. .. seealso:: @@ -2575,14 +2829,14 @@ order to allow the addition of Abstract Base Classes (ABCs) as "virtual base classes" to any class or type (including built-in types), including other ABCs. -.. method:: class.__instancecheck__(self, instance) +.. method:: type.__instancecheck__(self, instance) Return true if *instance* should be considered a (direct or indirect) instance of *class*. If defined, called to implement ``isinstance(instance, class)``. -.. method:: class.__subclasscheck__(self, subclass) +.. method:: type.__subclasscheck__(self, subclass) Return true if *subclass* should be considered a (direct or indirect) subclass of *class*. If defined, called to implement ``issubclass(subclass, @@ -2598,8 +2852,8 @@ case the instance is itself a class. :pep:`3119` - Introducing Abstract Base Classes Includes the specification for customizing :func:`isinstance` and - :func:`issubclass` behavior through :meth:`~class.__instancecheck__` and - :meth:`~class.__subclasscheck__`, with motivation for this functionality + :func:`issubclass` behavior through :meth:`~type.__instancecheck__` and + :meth:`~type.__subclasscheck__`, with motivation for this functionality in the context of adding Abstract Base Classes (see the :mod:`abc` module) to the language. @@ -2757,6 +3011,7 @@ Emulating callable objects Called when the instance is "called" as a function; if this method is defined, ``x(arg1, arg2, ...)`` roughly translates to ``type(x).__call__(x, arg1, ...)``. + The :class:`object` class itself does not provide this method. .. _sequence-types: @@ -2764,10 +3019,11 @@ Emulating callable objects Emulating container types ------------------------- -The following methods can be defined to implement container objects. Containers -usually are :term:`sequences ` (such as :class:`lists ` or +The following methods can be defined to implement container objects. None of them +are provided by the :class:`object` class itself. Containers usually are +:term:`sequences ` (such as :class:`lists ` or :class:`tuples `) or :term:`mappings ` (like -:class:`dictionaries `), +:term:`dictionaries `), but can represent other containers as well. The first set of methods is used either to emulate a sequence or to emulate a mapping; the difference is that for a sequence, the allowable keys should be the integers *k* for which ``0 <= k < @@ -3130,6 +3386,7 @@ Typical uses of context managers include saving and restoring various kinds of global state, locking and unlocking resources, closing opened files, etc. For more information on context managers, see :ref:`typecontextmanager`. +The :class:`object` class itself does not provide the context manager methods. .. method:: object.__enter__(self) @@ -3334,6 +3591,8 @@ are awaitable. Must return an :term:`iterator`. Should be used to implement :term:`awaitable` objects. For instance, :class:`asyncio.Future` implements this method to be compatible with the :keyword:`await` expression. + The :class:`object` class itself is not awaitable and does not provide + this method. .. note:: @@ -3419,6 +3678,9 @@ its ``__anext__`` method. Asynchronous iterators can be used in an :keyword:`async for` statement. +The :class:`object` class itself does not provide these methods. + + .. method:: object.__aiter__(self) Must return an *asynchronous iterator* object. @@ -3465,6 +3727,8 @@ suspend execution in its ``__aenter__`` and ``__aexit__`` methods. Asynchronous context managers can be used in an :keyword:`async with` statement. +The :class:`object` class itself does not provide these methods. + .. method:: object.__aenter__(self) Semantically similar to :meth:`~object.__enter__`, the only diff --git a/Doc/reference/executionmodel.rst b/Doc/reference/executionmodel.rst index ed50faed..44b852d4 100644 --- a/Doc/reference/executionmodel.rst +++ b/Doc/reference/executionmodel.rst @@ -225,8 +225,8 @@ Annotation scopes differ from function scopes in the following ways: statements in inner scopes. This includes only type parameters, as no other syntactic elements that can appear within annotation scopes can introduce new names. * While annotation scopes have an internal name, that name is not reflected in the - :term:`__qualname__ ` of objects defined within the scope. - Instead, the :attr:`!__qualname__` + :term:`qualified name` of objects defined within the scope. + Instead, the :attr:`~definition.__qualname__` of such objects is as if the object were defined in the enclosing scope. .. versionadded:: 3.12 diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 38f00ae2..6c178ad8 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -33,7 +33,7 @@ implementation for built-in types works as follows: * If either argument is a complex number, the other is converted to complex; -* otherwise, if either argument is a floating point number, the other is +* otherwise, if either argument is a floating-point number, the other is converted to floating point; * otherwise, both must be integers and no conversion is necessary. @@ -83,18 +83,47 @@ exception. pair: name; mangling pair: private; names -**Private name mangling:** When an identifier that textually occurs in a class -definition begins with two or more underscore characters and does not end in two -or more underscores, it is considered a :dfn:`private name` of that class. -Private names are transformed to a longer form before code is generated for -them. The transformation inserts the class name, with leading underscores -removed and a single underscore inserted, in front of the name. For example, -the identifier ``__spam`` occurring in a class named ``Ham`` will be transformed -to ``_Ham__spam``. This transformation is independent of the syntactical -context in which the identifier is used. If the transformed name is extremely -long (longer than 255 characters), implementation defined truncation may happen. -If the class name consists only of underscores, no transformation is done. +Private name mangling +^^^^^^^^^^^^^^^^^^^^^ +When an identifier that textually occurs in a class definition begins with two +or more underscore characters and does not end in two or more underscores, it +is considered a :dfn:`private name` of that class. + +.. seealso:: + + The :ref:`class specifications `. + +More precisely, private names are transformed to a longer form before code is +generated for them. If the transformed name is longer than 255 characters, +implementation-defined truncation may happen. + +The transformation is independent of the syntactical context in which the +identifier is used but only the following private identifiers are mangled: + +- Any name used as the name of a variable that is assigned or read or any + name of an attribute being accessed. + + The :attr:`~definition.__name__` attribute of nested functions, classes, and + type aliases is however not mangled. + +- The name of imported modules, e.g., ``__spam`` in ``import __spam``. + If the module is part of a package (i.e., its name contains a dot), + the name is *not* mangled, e.g., the ``__foo`` in ``import __foo.bar`` + is not mangled. + +- The name of an imported member, e.g., ``__f`` in ``from spam import __f``. + +The transformation rule is defined as follows: + +- The class name, with leading underscores removed and a single leading + underscore inserted, is inserted in front of the identifier, e.g., the + identifier ``__spam`` occurring in a class named ``Foo``, ``_Foo`` or + ``__Foo`` is transformed to ``_Foo__spam``. + +- If the class name consists only of underscores, the transformation is the + identity, e.g., the identifier ``__spam`` occurring in a class named ``_`` + or ``__`` is left as is. .. _atom-literals: @@ -110,8 +139,8 @@ Python supports string and bytes literals and various numeric literals: : | `integer` | `floatnumber` | `imagnumber` Evaluation of a literal yields an object of the given type (string, bytes, -integer, floating point number, complex number) with the given value. The value -may be approximated in the case of floating point and imaginary (complex) +integer, floating-point number, complex number) with the given value. The value +may be approximated in the case of floating-point and imaginary (complex) literals. See section :ref:`literals` for details. .. index:: @@ -218,10 +247,12 @@ A comprehension in an :keyword:`!async def` function may consist of either a :keyword:`!for` or :keyword:`!async for` clause following the leading expression, may contain additional :keyword:`!for` or :keyword:`!async for` clauses, and may also use :keyword:`await` expressions. -If a comprehension contains either :keyword:`!async for` clauses or -:keyword:`!await` expressions or other asynchronous comprehensions it is called -an :dfn:`asynchronous comprehension`. An asynchronous comprehension may -suspend the execution of the coroutine function in which it appears. + +If a comprehension contains :keyword:`!async for` clauses, or if it contains +:keyword:`!await` expressions or other asynchronous comprehensions anywhere except +the iterable expression in the leftmost :keyword:`!for` clause, it is called an +:dfn:`asynchronous comprehension`. An asynchronous comprehension may suspend the +execution of the coroutine function in which it appears. See also :pep:`530`. .. versionadded:: 3.6 @@ -253,7 +284,7 @@ A list display is a possibly empty series of expressions enclosed in square brackets: .. productionlist:: python-grammar - list_display: "[" [`starred_list` | `comprehension`] "]" + list_display: "[" [`flexible_expression_list` | `comprehension`] "]" A list display yields a new list object, the contents being specified by either a list of expressions or a comprehension. When a comma-separated list of @@ -278,7 +309,7 @@ A set display is denoted by curly braces and distinguishable from dictionary displays by the lack of colons separating keys and values: .. productionlist:: python-grammar - set_display: "{" (`starred_list` | `comprehension`) "}" + set_display: "{" (`flexible_expression_list` | `comprehension`) "}" A set display yields a new mutable set object, the contents being specified by either a sequence of expressions or a comprehension. When a comma-separated @@ -423,7 +454,7 @@ Yield expressions .. productionlist:: python-grammar yield_atom: "(" `yield_expression` ")" yield_from: "yield" "from" `expression` - yield_expression: "yield" `expression_list` | `yield_from` + yield_expression: "yield" `yield_list` | `yield_from` The yield expression is used when defining a :term:`generator` function or an :term:`asynchronous generator` function and @@ -454,9 +485,9 @@ When a generator function is called, it returns an iterator known as a generator. That generator then controls the execution of the generator function. The execution starts when one of the generator's methods is called. At that time, the execution proceeds to the first yield expression, where it is -suspended again, returning the value of :token:`~python-grammar:expression_list` +suspended again, returning the value of :token:`~python-grammar:yield_list` to the generator's caller, -or ``None`` if :token:`~python-grammar:expression_list` is omitted. +or ``None`` if :token:`~python-grammar:yield_list` is omitted. By suspended, we mean that all local state is retained, including the current bindings of local variables, the instruction pointer, the internal evaluation stack, and the state of any exception handling. @@ -545,7 +576,7 @@ is already executing raises a :exc:`ValueError` exception. :meth:`~generator.__next__` method, the current yield expression always evaluates to :const:`None`. The execution then continues to the next yield expression, where the generator is suspended again, and the value of the - :token:`~python-grammar:expression_list` is returned to :meth:`__next__`'s + :token:`~python-grammar:yield_list` is returned to :meth:`__next__`'s caller. If the generator exits without yielding another value, a :exc:`StopIteration` exception is raised. @@ -657,7 +688,7 @@ how a generator object would be used in a :keyword:`for` statement. Calling one of the asynchronous generator's methods returns an :term:`awaitable` object, and the execution starts when this object is awaited on. At that time, the execution proceeds to the first yield expression, where it is suspended -again, returning the value of :token:`~python-grammar:expression_list` to the +again, returning the value of :token:`~python-grammar:yield_list` to the awaiting coroutine. As with a generator, suspension means that all local state is retained, including the current bindings of local variables, the instruction pointer, the internal evaluation stack, and the state of any exception handling. @@ -721,7 +752,7 @@ which are used to control the execution of a generator function. asynchronous generator function is resumed with an :meth:`~agen.__anext__` method, the current yield expression always evaluates to :const:`None` in the returned awaitable, which when run will continue to the next yield - expression. The value of the :token:`~python-grammar:expression_list` of the + expression. The value of the :token:`~python-grammar:yield_list` of the yield expression is the value of the :exc:`StopIteration` exception raised by the completing coroutine. If the asynchronous generator exits without yielding another value, the awaitable instead raises a @@ -734,7 +765,7 @@ which are used to control the execution of a generator function. .. coroutinemethod:: agen.asend(value) Returns an awaitable which when run resumes the execution of the - asynchronous generator. As with the :meth:`~generator.send()` method for a + asynchronous generator. As with the :meth:`~generator.send` method for a generator, this "sends" a value into the asynchronous generator function, and the *value* argument becomes the result of the current yield expression. The awaitable returned by the :meth:`asend` method will return the next @@ -854,7 +885,7 @@ will generally select an element from the container. The subscription of a :ref:`GenericAlias ` object. .. productionlist:: python-grammar - subscription: `primary` "[" `expression_list` "]" + subscription: `primary` "[" `flexible_expression_list` "]" When an object is subscripted, the interpreter will evaluate the primary and the expression list. @@ -866,9 +897,13 @@ primary is subscripted, the evaluated result of the expression list will be passed to one of these methods. For more details on when ``__class_getitem__`` is called instead of ``__getitem__``, see :ref:`classgetitem-versus-getitem`. -If the expression list contains at least one comma, it will evaluate to a -:class:`tuple` containing the items of the expression list. Otherwise, the -expression list will evaluate to the value of the list's sole member. +If the expression list contains at least one comma, or if any of the expressions +are starred, the expression list will evaluate to a :class:`tuple` containing +the items of the expression list. Otherwise, the expression list will evaluate +to the value of the list's sole member. + +.. versionchanged:: 3.11 + Expressions in an expression list may be starred. See :pep:`646`. For built-in objects, there are two types of objects that support subscription via :meth:`~object.__getitem__`: @@ -1114,7 +1149,8 @@ a user-defined function: first thing the code block will do is bind the formal parameters to the arguments; this is described in section :ref:`function`. When the code block executes a :keyword:`return` statement, this specifies the return value of the - function call. + function call. If execution reaches the end of the code block without + executing a :keyword:`return` statement, the return value is ``None``. a built-in function or method: .. index:: @@ -1204,7 +1240,8 @@ Raising ``0.0`` to a negative power results in a :exc:`ZeroDivisionError`. Raising a negative number to a fractional power results in a :class:`complex` number. (In earlier versions it raised a :exc:`ValueError`.) -This operation can be customized using the special :meth:`~object.__pow__` method. +This operation can be customized using the special :meth:`~object.__pow__` and +:meth:`~object.__rpow__` methods. .. _unary: @@ -1292,6 +1329,9 @@ This operation can be customized using the special :meth:`~object.__mul__` and The ``@`` (at) operator is intended to be used for matrix multiplication. No builtin Python types implement this operator. +This operation can be customized using the special :meth:`~object.__matmul__` and +:meth:`~object.__rmatmul__` methods. + .. versionadded:: 3.5 .. index:: @@ -1307,8 +1347,10 @@ integer; the result is that of mathematical division with the 'floor' function applied to the result. Division by zero raises the :exc:`ZeroDivisionError` exception. -This operation can be customized using the special :meth:`~object.__truediv__` and -:meth:`~object.__floordiv__` methods. +The division operation can be customized using the special :meth:`~object.__truediv__` +and :meth:`~object.__rtruediv__` methods. +The floor division operation can be customized using the special +:meth:`~object.__floordiv__` and :meth:`~object.__rfloordiv__` methods. .. index:: single: modulo @@ -1317,7 +1359,7 @@ This operation can be customized using the special :meth:`~object.__truediv__` a The ``%`` (modulo) operator yields the remainder from the division of the first argument by the second. The numeric arguments are first converted to a common type. A zero right argument raises the :exc:`ZeroDivisionError` exception. The -arguments may be floating point numbers, e.g., ``3.14%0.7`` equals ``0.34`` +arguments may be floating-point numbers, e.g., ``3.14%0.7`` equals ``0.34`` (since ``3.14`` equals ``4*0.7 + 0.34``.) The modulo operator always yields a result with the same sign as its second operand (or zero); the absolute value of the result is strictly smaller than the absolute value of the second operand @@ -1333,11 +1375,12 @@ also overloaded by string objects to perform old-style string formatting (also known as interpolation). The syntax for string formatting is described in the Python Library Reference, section :ref:`old-string-formatting`. -The *modulo* operation can be customized using the special :meth:`~object.__mod__` method. +The *modulo* operation can be customized using the special :meth:`~object.__mod__` +and :meth:`~object.__rmod__` methods. The floor division operator, the modulo operator, and the :func:`divmod` -function are not defined for complex numbers. Instead, convert to a floating -point number using the :func:`abs` function if appropriate. +function are not defined for complex numbers. Instead, convert to a +floating-point number using the :func:`abs` function if appropriate. .. index:: single: addition @@ -1360,7 +1403,8 @@ This operation can be customized using the special :meth:`~object.__add__` and The ``-`` (subtraction) operator yields the difference of its arguments. The numeric arguments are first converted to a common type. -This operation can be customized using the special :meth:`~object.__sub__` method. +This operation can be customized using the special :meth:`~object.__sub__` and +:meth:`~object.__rsub__` methods. .. _shifting: @@ -1381,8 +1425,10 @@ The shifting operations have lower priority than the arithmetic operations: 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. -This operation can be customized using the special :meth:`~object.__lshift__` and -:meth:`~object.__rshift__` methods. +The left shift operation can be customized using the special :meth:`~object.__lshift__` +and :meth:`~object.__rlshift__` methods. +The right shift operation can be customized using the special :meth:`~object.__rshift__` +and :meth:`~object.__rrshift__` methods. .. index:: pair: exception; ValueError @@ -1857,10 +1903,12 @@ Expression lists single: , (comma); expression list .. productionlist:: python-grammar + starred_expression: ["*"] `or_expr` + flexible_expression: `assignment_expression` | `starred_expression` + flexible_expression_list: `flexible_expression` ("," `flexible_expression`)* [","] + starred_expression_list: `starred_expression` ("," `starred_expression`)* [","] expression_list: `expression` ("," `expression`)* [","] - starred_list: `starred_item` ("," `starred_item`)* [","] - starred_expression: `expression` | (`starred_item` ",")* [`starred_item`] - starred_item: `assignment_expression` | "*" `or_expr` + yield_list: `expression_list` | `starred_expression` "," [`starred_expression_list`] .. index:: pair: object; tuple @@ -1881,6 +1929,9 @@ the unpacking. .. versionadded:: 3.5 Iterable unpacking in expression lists, originally proposed by :pep:`448`. +.. versionadded:: 3.11 + Any item in an expression list may be starred. See :pep:`646`. + .. index:: pair: trailing; comma A trailing comma is required only to create a one-item tuple, diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst index f8c97241..ac363e8c 100644 --- a/Doc/reference/import.rst +++ b/Doc/reference/import.rst @@ -281,7 +281,7 @@ When the named module is not found in :data:`sys.modules`, Python next searches :data:`sys.meta_path`, which contains a list of meta path finder objects. These finders are queried in order to see if they know how to handle the named module. Meta path finders must implement a method called -:meth:`~importlib.abc.MetaPathFinder.find_spec()` which takes three arguments: +:meth:`~importlib.abc.MetaPathFinder.find_spec` which takes three arguments: a name, an import path, and (optionally) a target module. The meta path finder can use any strategy it wants to determine whether it can handle the named module or not. @@ -292,7 +292,7 @@ spec object. If it cannot handle the named module, it returns ``None``. If a spec, then a :exc:`ModuleNotFoundError` is raised. Any other exceptions raised are simply propagated up, aborting the import process. -The :meth:`~importlib.abc.MetaPathFinder.find_spec()` method of meta path +The :meth:`~importlib.abc.MetaPathFinder.find_spec` method of meta path finders is called with two or three arguments. The first is the fully qualified name of the module being imported, for example ``foo.bar.baz``. The second argument is the path entries to use for the module search. For @@ -513,8 +513,10 @@ holding is that if you have ``sys.modules['spam']`` and ``sys.modules['spam.foo']`` (as you would after the above import), the latter must appear as the ``foo`` attribute of the former. -Module spec ------------ +.. _module-specs: + +Module specs +------------ The import machinery uses a variety of information about each module during import, especially before loading. Most of the information is @@ -527,155 +529,44 @@ and the loader that executes it. Most importantly, it allows the import machinery to perform the boilerplate operations of loading, whereas without a module spec the loader had that responsibility. -The module's spec is exposed as the ``__spec__`` attribute on a module object. +The module's spec is exposed as :attr:`module.__spec__`. Setting +:attr:`!__spec__` appropriately applies equally to +:ref:`modules initialized during interpreter startup `. +The one exception is ``__main__``, where :attr:`!__spec__` is +:ref:`set to None in some cases `. + See :class:`~importlib.machinery.ModuleSpec` for details on the contents of the module spec. .. versionadded:: 3.4 -.. _import-mod-attrs: - -Import-related module attributes --------------------------------- - -The import machinery fills in these attributes on each module object -during loading, based on the module's spec, before the loader executes -the module. - -It is **strongly** recommended that you rely on :attr:`__spec__` and -its attributes instead of any of the other individual attributes -listed below. - -.. attribute:: __name__ - - The ``__name__`` attribute must be set to the fully qualified name of - the module. This name is used to uniquely identify the module in - the import system. - -.. attribute:: __loader__ - - The ``__loader__`` attribute must be set to the loader object that - the import machinery used when loading the module. This is mostly - for introspection, but can be used for additional loader-specific - functionality, for example getting data associated with a loader. - - It is **strongly** recommended that you rely on :attr:`__spec__` - instead of this attribute. - - .. versionchanged:: 3.12 - The value of ``__loader__`` is expected to be the same as - ``__spec__.loader``. The use of ``__loader__`` is deprecated and slated - for removal in Python 3.14. - -.. attribute:: __package__ - - The module's ``__package__`` attribute may be set. Its value must - be a string, but it can be the same value as its ``__name__``. When - the module is a package, its ``__package__`` value should be set to - its ``__name__``. When the module is not a package, ``__package__`` - should be set to the empty string for top-level modules, or for - submodules, to the parent package's name. See :pep:`366` for further - details. - - This attribute is used instead of ``__name__`` to calculate explicit - relative imports for main modules, as defined in :pep:`366`. - - It is **strongly** recommended that you rely on :attr:`__spec__` - instead of this attribute. - - .. versionchanged:: 3.6 - The value of ``__package__`` is expected to be the same as - ``__spec__.parent``. - - .. versionchanged:: 3.10 - :exc:`ImportWarning` is raised if import falls back to - ``__package__`` instead of - :attr:`~importlib.machinery.ModuleSpec.parent`. - - .. versionchanged:: 3.12 - Raise :exc:`DeprecationWarning` instead of :exc:`ImportWarning` - when falling back to ``__package__``. - - -.. attribute:: __spec__ - - The ``__spec__`` attribute must be set to the module spec that was - used when importing the module. Setting ``__spec__`` - appropriately applies equally to :ref:`modules initialized during - interpreter startup `. The one exception is ``__main__``, - where ``__spec__`` is :ref:`set to None in some cases `. - - When ``__spec__.parent`` is not set, ``__package__`` is used as - a fallback. - - .. versionadded:: 3.4 - - .. versionchanged:: 3.6 - ``__spec__.parent`` is used as a fallback when ``__package__`` is - not defined. - -.. attribute:: __path__ - - If the module is a package (either regular or namespace), the module - object's ``__path__`` attribute must be set. The value must be - iterable, but may be empty if ``__path__`` has no further significance. - If ``__path__`` is not empty, it must produce strings when iterated - over. More details on the semantics of ``__path__`` are given - :ref:`below `. - - Non-package modules should not have a ``__path__`` attribute. - -.. attribute:: __file__ -.. attribute:: __cached__ - - ``__file__`` is optional (if set, value must be a string). It indicates - the pathname of the file from which the module was loaded (if - loaded from a file), or the pathname of the shared library file - for extension modules loaded dynamically from a shared library. - It might be missing for certain types of modules, such as C - modules that are statically linked into the interpreter, and the - import system may opt to leave it unset if it has no semantic - meaning (e.g. a module loaded from a database). - - If ``__file__`` is set then the ``__cached__`` attribute might also - be set, which is the path to any compiled version of - the code (e.g. byte-compiled file). The file does not need to exist - to set this attribute; the path can simply point to where the - compiled file would exist (see :pep:`3147`). - - Note that ``__cached__`` may be set even if ``__file__`` is not - set. However, that scenario is quite atypical. Ultimately, the - loader is what makes use of the module spec provided by the finder - (from which ``__file__`` and ``__cached__`` are derived). So - if a loader can load from a cached module but otherwise does not load - from a file, that atypical scenario may be appropriate. - - It is **strongly** recommended that you rely on :attr:`__spec__` - instead of ``__cached__``. - .. _package-path-rules: -module.__path__ ---------------- +__path__ attributes on modules +------------------------------ -By definition, if a module has a ``__path__`` attribute, it is a package. +The :attr:`~module.__path__` attribute should be a (possibly empty) +:term:`sequence` of strings enumerating the locations where the package's +submodules will be found. By definition, if a module has a :attr:`!__path__` +attribute, it is a :term:`package`. -A package's ``__path__`` attribute is used during imports of its subpackages. +A package's :attr:`~module.__path__` attribute is used during imports of its +subpackages. Within the import machinery, it functions much the same as :data:`sys.path`, i.e. providing a list of locations to search for modules during import. -However, ``__path__`` is typically much more constrained than -:data:`sys.path`. +However, :attr:`!__path__` is typically much more constrained than +:data:`!sys.path`. -``__path__`` must be an iterable of strings, but it may be empty. The same rules used for :data:`sys.path` also apply to a package's -``__path__``, and :data:`sys.path_hooks` (described below) are -consulted when traversing a package's ``__path__``. +:attr:`!__path__`. :data:`sys.path_hooks` (described below) are +consulted when traversing a package's :attr:`!__path__`. -A package's ``__init__.py`` file may set or alter the package's ``__path__`` +A package's ``__init__.py`` file may set or alter the package's +:attr:`~module.__path__` attribute, and this was typically the way namespace packages were implemented prior to :pep:`420`. With the adoption of :pep:`420`, namespace packages no -longer need to supply ``__init__.py`` files containing only ``__path__`` -manipulation code; the import machinery automatically sets ``__path__`` +longer need to supply ``__init__.py`` files containing only :attr:`!__path__` +manipulation code; the import machinery automatically sets :attr:`!__path__` correctly for the namespace package. Module reprs diff --git a/Doc/reference/introduction.rst b/Doc/reference/introduction.rst index cf186705..b7b70e6b 100644 --- a/Doc/reference/introduction.rst +++ b/Doc/reference/introduction.rst @@ -74,7 +74,7 @@ PyPy and a Just in Time compiler. One of the goals of the project is to encourage experimentation with the language itself by making it easier to modify the interpreter (since it is written in Python). Additional information is - available on `the PyPy project's home page `_. + available on `the PyPy project's home page `_. Each of these implementations varies in some way from the language as documented in this manual, or introduces specific information beyond what's covered in the diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst index 103d6ef0..41d8fbae 100644 --- a/Doc/reference/lexical_analysis.rst +++ b/Doc/reference/lexical_analysis.rst @@ -284,11 +284,10 @@ UAX-31, with elaboration and changes as defined below; see also :pep:`3131` for further details. Within the ASCII range (U+0001..U+007F), the valid characters for identifiers -are the same as in Python 2.x: the uppercase and lowercase letters ``A`` through +include the uppercase and lowercase letters ``A`` through ``Z``, the underscore ``_`` and, except for the first character, the digits ``0`` through ``9``. - -Python 3.0 introduces additional characters from outside the ASCII range (see +Python 3.0 introduced additional characters from outside the ASCII range (see :pep:`3131`). For these characters, the classification uses the version of the Unicode Character Database as included in the :mod:`unicodedata` module. @@ -503,11 +502,10 @@ must be expressed with escapes. single: r"; raw string literal Both string and bytes literals may optionally be prefixed with a letter ``'r'`` -or ``'R'``; such strings are called :dfn:`raw strings` and treat backslashes as -literal characters. As a result, in string literals, ``'\U'`` and ``'\u'`` -escapes in raw strings are not treated specially. Given that Python 2.x's raw -unicode literals behave differently than Python 3.x's the ``'ur'`` syntax -is not supported. +or ``'R'``; such constructs are called :dfn:`raw string literals` +and :dfn:`raw bytes literals` respectively and treat backslashes as +literal characters. As a result, in raw string literals, ``'\U'`` and ``'\u'`` +escapes are not treated specially. .. versionadded:: 3.3 The ``'rb'`` prefix of raw bytes literals has been added as a synonym @@ -879,10 +877,10 @@ Numeric literals ---------------- .. index:: number, numeric literal, integer literal - floating point literal, hexadecimal literal + floating-point literal, hexadecimal literal octal literal, binary literal, decimal literal, imaginary literal, complex literal -There are three types of numeric literals: integers, floating point numbers, and +There are three types of numeric literals: integers, floating-point numbers, and imaginary numbers. There are no complex literals (complex numbers can be formed by adding a real number and an imaginary number). @@ -943,10 +941,10 @@ Some examples of integer literals:: single: _ (underscore); in numeric literal .. _floating: -Floating point literals +Floating-point literals ----------------------- -Floating point literals are described by the following lexical definitions: +Floating-point literals are described by the following lexical definitions: .. productionlist:: python-grammar floatnumber: `pointfloat` | `exponentfloat` @@ -958,10 +956,10 @@ Floating point literals are described by the following lexical definitions: Note that the integer and exponent parts are always interpreted using radix 10. For example, ``077e010`` is legal, and denotes the same number as ``77e10``. The -allowed range of floating point literals is implementation-dependent. As in +allowed range of floating-point literals is implementation-dependent. As in integer literals, underscores are supported for digit grouping. -Some examples of floating point literals:: +Some examples of floating-point literals:: 3.14 10. .001 1e100 3.14e-10 0e0 3.14_15_93 @@ -982,9 +980,9 @@ Imaginary literals are described by the following lexical definitions: imagnumber: (`floatnumber` | `digitpart`) ("j" | "J") An imaginary literal yields a complex number with a real part of 0.0. Complex -numbers are represented as a pair of floating point numbers and have the same +numbers are represented as a pair of floating-point numbers and have the same restrictions on their range. To create a complex number with a nonzero real -part, add a floating point number to it, e.g., ``(3+4j)``. Some examples of +part, add a floating-point number to it, e.g., ``(3+4j)``. Some examples of imaginary literals:: 3.14j 10.j 10j .001j 1e100j 3.14e-10j 3.14_15_93j @@ -1019,9 +1017,9 @@ The following tokens serve as delimiters in the grammar: .. code-block:: none ( ) [ ] { } - , : . ; @ = -> - += -= *= /= //= %= @= - &= |= ^= >>= <<= **= + , : ! . ; @ = + -> += -= *= /= //= %= + @= &= |= ^= >>= <<= **= The period can also occur in floating-point and imaginary literals. A sequence of three periods has a special meaning as an ellipsis literal. The second half diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index a2534821..5e3ede69 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -293,7 +293,7 @@ statements, cannot be an unpacking) and the expression list, performs the binary operation specific to the type of assignment on the two operands, and assigns the result to the original target. The target is only evaluated once. -An augmented assignment expression like ``x += 1`` can be rewritten as ``x = x + +An augmented assignment statement like ``x += 1`` can be rewritten as ``x = x + 1`` to achieve a similar, but not exactly equal effect. In the augmented version, ``x`` is only evaluated once. Also, when possible, the actual operation is performed *in-place*, meaning that rather than creating a new object and @@ -333,7 +333,9 @@ statement, of a variable or attribute annotation and an optional assignment stat The difference from normal :ref:`assignment` is that only a single target is allowed. -For simple names as assignment targets, if in class or module scope, +The assignment target is considered "simple" if it consists of a single +name that is not enclosed in parentheses. +For simple assignment targets, if in class or module scope, the annotations are evaluated and stored in a special class or module attribute :attr:`__annotations__` that is a dictionary mapping from variable names (mangled if private) to @@ -341,7 +343,8 @@ evaluated annotations. This attribute is writable and is automatically created at the start of class or module body execution, if annotations are found statically. -For expressions as assignment targets, the annotations are evaluated if +If the assignment target is not simple (an attribute, subscript node, or +parenthesized name), the annotation is evaluated if in class or module scope, but not stored. If a name is annotated in a function scope, then this name is local for @@ -403,9 +406,9 @@ The extended form, ``assert expression1, expression2``, is equivalent to :: These equivalences assume that :const:`__debug__` and :exc:`AssertionError` refer to the built-in variables with those names. In the current implementation, the -built-in variable :const:`__debug__` is ``True`` under normal circumstances, +built-in variable ``__debug__`` is ``True`` under normal circumstances, ``False`` when optimization is requested (command line option :option:`-O`). The current -code generator emits no code for an assert statement when optimization is +code generator emits no code for an :keyword:`assert` statement when optimization is requested at compile time. Note that it is unnecessary to include the source code for the expression that failed in the error message; it will be displayed as part of the stack trace. @@ -528,8 +531,8 @@ The :keyword:`!yield` statement yield_stmt: `yield_expression` A :keyword:`yield` statement is semantically equivalent to a :ref:`yield -expression `. The yield statement can be used to omit the parentheses -that would otherwise be required in the equivalent yield expression +expression `. The ``yield`` statement can be used to omit the +parentheses that would otherwise be required in the equivalent yield expression statement. For example, the yield statements :: yield @@ -541,7 +544,7 @@ are equivalent to the yield expression statements :: (yield from ) Yield expressions and statements are only used when defining a :term:`generator` -function, and are only used in the body of the generator function. Using yield +function, and are only used in the body of the generator function. Using :keyword:`yield` in a function definition is sufficient to cause that definition to create a generator function instead of a normal function. @@ -961,25 +964,14 @@ The :keyword:`!global` statement .. productionlist:: python-grammar global_stmt: "global" `identifier` ("," `identifier`)* -The :keyword:`global` statement is a declaration which holds for the entire -current code block. It means that the listed identifiers are to be interpreted -as globals. It would be impossible to assign to a global variable without +The :keyword:`global` statement causes the listed identifiers to be interpreted +as globals. It would be impossible to assign to a global variable without :keyword:`!global`, although free variables may refer to globals without being declared global. -Names listed in a :keyword:`global` statement must not be used in the same code -block textually preceding that :keyword:`!global` statement. - -Names listed in a :keyword:`global` statement must not be defined as formal -parameters, or as targets in :keyword:`with` statements or :keyword:`except` clauses, or in a :keyword:`for` target list, :keyword:`class` -definition, function definition, :keyword:`import` statement, or variable -annotation. - -.. impl-detail:: - - The current implementation does not enforce some of these restrictions, but - programs should not abuse this freedom, as future implementations may enforce - them or silently change the meaning of the program. +The :keyword:`global` statement applies to the entire scope of a function or +class body. A :exc:`SyntaxError` is raised if a variable is used or +assigned to prior to its global declaration in the scope. .. index:: pair: built-in function; exec @@ -1015,7 +1007,7 @@ identifiers. If a name is bound in more than one nonlocal scope, the nearest binding is used. If a name is not bound in any nonlocal scope, or if there is no nonlocal scope, a :exc:`SyntaxError` is raised. -The nonlocal statement applies to the entire scope of a function or +The :keyword:`nonlocal` statement applies to the entire scope of a function or class body. A :exc:`SyntaxError` is raised if a variable is used or assigned to prior to its nonlocal declaration in the scope. diff --git a/Doc/requirements-oldest-sphinx.txt b/Doc/requirements-oldest-sphinx.txt index 3ae65bc9..3483faea 100644 --- a/Doc/requirements-oldest-sphinx.txt +++ b/Doc/requirements-oldest-sphinx.txt @@ -7,29 +7,29 @@ blurb python-docs-theme>=2022.1 # Generated from: -# pip install "Sphinx~=6.2.1" +# pip install "Sphinx~=7.2.6" # pip freeze # -# Sphinx 6.2.1 comes from ``needs_sphinx = '6.2.1'`` in ``Doc/conf.py``. +# Sphinx 7.2.6 comes from ``needs_sphinx = '7.2.6'`` in ``Doc/conf.py``. alabaster==0.7.16 -Babel==2.15.0 -certifi==2024.2.2 -charset-normalizer==3.3.2 -docutils==0.19 -idna==3.7 +Babel==2.16.0 +certifi==2024.8.30 +charset-normalizer==3.4.0 +docutils==0.20.1 +idna==3.10 imagesize==1.4.1 Jinja2==3.1.4 -MarkupSafe==2.1.5 -packaging==24.0 +MarkupSafe==3.0.1 +packaging==24.1 Pygments==2.18.0 -requests==2.32.2 +requests==2.32.3 snowballstemmer==2.2.0 -Sphinx==6.2.1 -sphinxcontrib-applehelp==1.0.8 -sphinxcontrib-devhelp==1.0.6 -sphinxcontrib-htmlhelp==2.0.5 +Sphinx==7.2.6 +sphinxcontrib-applehelp==2.0.0 +sphinxcontrib-devhelp==2.0.0 +sphinxcontrib-htmlhelp==2.1.0 sphinxcontrib-jsmath==1.0.1 -sphinxcontrib-qthelp==1.0.7 -sphinxcontrib-serializinghtml==1.1.10 -urllib3==2.2.1 +sphinxcontrib-qthelp==2.0.0 +sphinxcontrib-serializinghtml==2.0.0 +urllib3==2.2.3 diff --git a/Doc/requirements.txt b/Doc/requirements.txt index b47a9d8a..5105786c 100644 --- a/Doc/requirements.txt +++ b/Doc/requirements.txt @@ -6,12 +6,12 @@ # Sphinx version is pinned so that new versions that introduce new warnings # won't suddenly cause build failures. Updating the version is fine as long # as no warnings are raised by doing so. -sphinx~=7.3.0 +sphinx~=8.1.0 blurb -sphinxext-opengraph==0.7.5 -sphinx-notfound-page==1.0.0 +sphinxext-opengraph~=0.9.0 +sphinx-notfound-page~=1.0.0 # The theme used by the documentation is stored separately, so we need # to install that as well. diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 108ad393..c665ddd1 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -14,8 +14,6 @@ Doc/c-api/type.rst Doc/c-api/typeobj.rst Doc/extending/extending.rst Doc/glossary.rst -Doc/howto/descriptor.rst -Doc/howto/enum.rst Doc/library/2to3.rst Doc/library/aifc.rst Doc/library/ast.rst @@ -91,7 +89,6 @@ Doc/library/xmlrpc.server.rst Doc/library/zlib.rst Doc/reference/compound_stmts.rst Doc/reference/datamodel.rst -Doc/tutorial/datastructures.rst Doc/using/windows.rst Doc/whatsnew/2.4.rst Doc/whatsnew/2.5.rst diff --git a/Doc/tools/check-warnings.py b/Doc/tools/check-warnings.py index c50b0063..8f92ab29 100644 --- a/Doc/tools/check-warnings.py +++ b/Doc/tools/check-warnings.py @@ -2,6 +2,7 @@ """ Check the output of running Sphinx in nit-picky mode (missing references). """ + from __future__ import annotations import argparse @@ -14,7 +15,7 @@ from typing import TextIO # Fail if NEWS nit found before this line number -NEWS_NIT_THRESHOLD = 200 +NEWS_NIT_THRESHOLD = 300 # Exclude these whether they're dirty or clean, # because they trigger a rebuild of dirty files. @@ -206,7 +207,9 @@ def annotate_diff( def fail_if_regression( - warnings: list[str], files_with_expected_nits: set[str], files_with_nits: set[str] + warnings: list[str], + files_with_expected_nits: set[str], + files_with_nits: set[str], ) -> int: """ Ensure some files always pass Sphinx nit-picky mode (no missing references). @@ -252,17 +255,11 @@ def fail_if_new_news_nit(warnings: list[str], threshold: int) -> int: """ Ensure no warnings are found in the NEWS file before a given line number. """ - news_nits = ( - warning - for warning in warnings - if "/build/NEWS:" in warning - ) + news_nits = (warning for warning in warnings if "/build/NEWS:" in warning) # Nits found before the threshold line new_news_nits = [ - nit - for nit in news_nits - if int(nit.split(":")[1]) <= threshold + nit for nit in news_nits if int(nit.split(":")[1]) <= threshold ] if new_news_nits: @@ -311,7 +308,8 @@ def main(argv: list[str] | None = None) -> int: exit_code = 0 wrong_directory_msg = "Must run this script from the repo root" - assert Path("Doc").exists() and Path("Doc").is_dir(), wrong_directory_msg + if not Path("Doc").exists() or not Path("Doc").is_dir(): + raise RuntimeError(wrong_directory_msg) with Path("Doc/sphinx-warnings.txt").open(encoding="UTF-8") as f: warnings = f.read().splitlines() @@ -339,7 +337,9 @@ def main(argv: list[str] | None = None) -> int: ) if args.fail_if_improved: - exit_code += fail_if_improved(files_with_expected_nits, files_with_nits) + exit_code += fail_if_improved( + files_with_expected_nits, files_with_nits + ) if args.fail_if_new_news_nit: exit_code += fail_if_new_news_nit(warnings, args.fail_if_new_news_nit) diff --git a/Doc/tools/extensions/audit_events.py b/Doc/tools/extensions/audit_events.py new file mode 100644 index 00000000..23d82c0f --- /dev/null +++ b/Doc/tools/extensions/audit_events.py @@ -0,0 +1,264 @@ +"""Support for documenting audit events.""" + +from __future__ import annotations + +import re +from typing import TYPE_CHECKING + +from docutils import nodes +from sphinx.errors import NoUri +from sphinx.locale import _ as sphinx_gettext +from sphinx.transforms.post_transforms import SphinxPostTransform +from sphinx.util import logging +from sphinx.util.docutils import SphinxDirective + +if TYPE_CHECKING: + from collections.abc import Iterator + + from sphinx.application import Sphinx + from sphinx.builders import Builder + from sphinx.environment import BuildEnvironment + +logger = logging.getLogger(__name__) + +# This list of sets are allowable synonyms for event argument names. +# If two names are in the same set, they are treated as equal for the +# purposes of warning. This won't help if the number of arguments is +# different! +_SYNONYMS = [ + frozenset({"file", "path", "fd"}), +] + + +class AuditEvents: + def __init__(self) -> None: + self.events: dict[str, list[str]] = {} + self.sources: dict[str, list[tuple[str, str]]] = {} + + def __iter__(self) -> Iterator[tuple[str, list[str], tuple[str, str]]]: + for name, args in self.events.items(): + for source in self.sources[name]: + yield name, args, source + + def add_event( + self, name, args: list[str], source: tuple[str, str] + ) -> None: + if name in self.events: + self._check_args_match(name, args) + else: + self.events[name] = args + self.sources.setdefault(name, []).append(source) + + def _check_args_match(self, name: str, args: list[str]) -> None: + current_args = self.events[name] + msg = ( + f"Mismatched arguments for audit-event {name}: " + f"{current_args!r} != {args!r}" + ) + if current_args == args: + return + if len(current_args) != len(args): + logger.warning(msg) + return + for a1, a2 in zip(current_args, args, strict=False): + if a1 == a2: + continue + if any(a1 in s and a2 in s for s in _SYNONYMS): + continue + logger.warning(msg) + return + + def id_for(self, name) -> str: + source_count = len(self.sources.get(name, ())) + name_clean = re.sub(r"\W", "_", name) + return f"audit_event_{name_clean}_{source_count}" + + def rows(self) -> Iterator[tuple[str, list[str], list[tuple[str, str]]]]: + for name in sorted(self.events.keys()): + yield name, self.events[name], self.sources[name] + + +def initialise_audit_events(app: Sphinx) -> None: + """Initialise the audit_events attribute on the environment.""" + if not hasattr(app.env, "audit_events"): + app.env.audit_events = AuditEvents() + + +def audit_events_purge( + app: Sphinx, env: BuildEnvironment, docname: str +) -> None: + """This is to remove traces of removed documents from env.audit_events.""" + fresh_audit_events = AuditEvents() + for name, args, (doc, target) in env.audit_events: + if doc != docname: + fresh_audit_events.add_event(name, args, (doc, target)) + + +def audit_events_merge( + app: Sphinx, + env: BuildEnvironment, + docnames: list[str], + other: BuildEnvironment, +) -> None: + """In Sphinx parallel builds, this merges audit_events from subprocesses.""" + for name, args, source in other.audit_events: + env.audit_events.add_event(name, args, source) + + +class AuditEvent(SphinxDirective): + has_content = True + required_arguments = 1 + optional_arguments = 2 + final_argument_whitespace = True + + _label = [ + sphinx_gettext( + "Raises an :ref:`auditing event ` " + "{name} with no arguments." + ), + sphinx_gettext( + "Raises an :ref:`auditing event ` " + "{name} with argument {args}." + ), + sphinx_gettext( + "Raises an :ref:`auditing event ` " + "{name} with arguments {args}." + ), + ] + + def run(self) -> list[nodes.paragraph]: + name = self.arguments[0] + if len(self.arguments) >= 2 and self.arguments[1]: + args = [ + arg + for argument in self.arguments[1].strip("'\"").split(",") + if (arg := argument.strip()) + ] + else: + args = [] + ids = [] + try: + target = self.arguments[2].strip("\"'") + except (IndexError, TypeError): + target = None + if not target: + target = self.env.audit_events.id_for(name) + ids.append(target) + self.env.audit_events.add_event(name, args, (self.env.docname, target)) + + node = nodes.paragraph("", classes=["audit-hook"], ids=ids) + self.set_source_info(node) + if self.content: + node.rawsource = '\n'.join(self.content) # for gettext + self.state.nested_parse(self.content, self.content_offset, node) + else: + num_args = min(2, len(args)) + text = self._label[num_args].format( + name=f"``{name}``", + args=", ".join(f"``{a}``" for a in args), + ) + node.rawsource = text # for gettext + parsed, messages = self.state.inline_text(text, self.lineno) + node += parsed + node += messages + return [node] + + +class audit_event_list(nodes.General, nodes.Element): # noqa: N801 + pass + + +class AuditEventListDirective(SphinxDirective): + def run(self) -> list[audit_event_list]: + return [audit_event_list()] + + +class AuditEventListTransform(SphinxPostTransform): + default_priority = 500 + + def run(self) -> None: + if self.document.next_node(audit_event_list) is None: + return + + table = self._make_table(self.app.builder, self.env.docname) + for node in self.document.findall(audit_event_list): + node.replace_self(table) + + def _make_table(self, builder: Builder, docname: str) -> nodes.table: + table = nodes.table(cols=3) + group = nodes.tgroup( + "", + nodes.colspec(colwidth=30), + nodes.colspec(colwidth=55), + nodes.colspec(colwidth=15), + cols=3, + ) + head = nodes.thead() + body = nodes.tbody() + + table += group + group += head + group += body + + head += nodes.row( + "", + nodes.entry("", nodes.paragraph("", "Audit event")), + nodes.entry("", nodes.paragraph("", "Arguments")), + nodes.entry("", nodes.paragraph("", "References")), + ) + + for name, args, sources in builder.env.audit_events.rows(): + body += self._make_row(builder, docname, name, args, sources) + + return table + + @staticmethod + def _make_row( + builder: Builder, + docname: str, + name: str, + args: list[str], + sources: list[tuple[str, str]], + ) -> nodes.row: + row = nodes.row() + name_node = nodes.paragraph("", nodes.Text(name)) + row += nodes.entry("", name_node) + + args_node = nodes.paragraph() + for arg in args: + args_node += nodes.literal(arg, arg) + args_node += nodes.Text(", ") + if len(args_node.children) > 0: + args_node.children.pop() # remove trailing comma + row += nodes.entry("", args_node) + + backlinks_node = nodes.paragraph() + backlinks = enumerate(sorted(set(sources)), start=1) + for i, (doc, label) in backlinks: + if isinstance(label, str): + ref = nodes.reference("", f"[{i}]", internal=True) + try: + target = ( + f"{builder.get_relative_uri(docname, doc)}#{label}" + ) + except NoUri: + continue + else: + ref["refuri"] = target + backlinks_node += ref + row += nodes.entry("", backlinks_node) + return row + + +def setup(app: Sphinx): + app.add_directive("audit-event", AuditEvent) + app.add_directive("audit-event-table", AuditEventListDirective) + app.add_post_transform(AuditEventListTransform) + app.connect("builder-inited", initialise_audit_events) + app.connect("env-purge-doc", audit_events_purge) + app.connect("env-merge-info", audit_events_merge) + return { + "version": "1.0", + "parallel_read_safe": True, + "parallel_write_safe": True, + } diff --git a/Doc/tools/extensions/availability.py b/Doc/tools/extensions/availability.py new file mode 100644 index 00000000..897af70a --- /dev/null +++ b/Doc/tools/extensions/availability.py @@ -0,0 +1,123 @@ +"""Support for documenting platform availability""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +from docutils import nodes +from sphinx import addnodes +from sphinx.util import logging +from sphinx.util.docutils import SphinxDirective + +if TYPE_CHECKING: + from sphinx.application import Sphinx + from sphinx.util.typing import ExtensionMetadata + +logger = logging.getLogger("availability") + +# known platform, libc, and threading implementations +_PLATFORMS = frozenset({ + "AIX", + "Android", + "BSD", + "DragonFlyBSD", + "Emscripten", + "FreeBSD", + "Linux", + "macOS", + "NetBSD", + "OpenBSD", + "POSIX", + "Solaris", + "Unix", + "VxWorks", + "WASI", + "Windows", +}) +_LIBC = frozenset({ + "BSD libc", + "glibc", + "musl", +}) +_THREADING = frozenset({ + # POSIX platforms with pthreads + "pthreads", +}) +KNOWN_PLATFORMS = _PLATFORMS | _LIBC | _THREADING + + +class Availability(SphinxDirective): + has_content = True + required_arguments = 1 + optional_arguments = 0 + final_argument_whitespace = True + + def run(self) -> list[nodes.container]: + title = "Availability" + refnode = addnodes.pending_xref( + title, + nodes.inline(title, title, classes=["xref", "std", "std-ref"]), + refdoc=self.env.docname, + refdomain="std", + refexplicit=True, + reftarget="availability", + reftype="ref", + refwarn=True, + ) + sep = nodes.Text(": ") + parsed, msgs = self.state.inline_text(self.arguments[0], self.lineno) + pnode = nodes.paragraph(title, "", refnode, sep, *parsed, *msgs) + self.set_source_info(pnode) + cnode = nodes.container("", pnode, classes=["availability"]) + self.set_source_info(cnode) + if self.content: + self.state.nested_parse(self.content, self.content_offset, cnode) + self.parse_platforms() + + return [cnode] + + def parse_platforms(self) -> dict[str, str | bool]: + """Parse platform information from arguments + + Arguments is a comma-separated string of platforms. A platform may + be prefixed with "not " to indicate that a feature is not available. + + Example:: + + .. availability:: Windows, Linux >= 4.2, not WASI + + Arguments like "Linux >= 3.17 with glibc >= 2.27" are currently not + parsed into separate tokens. + """ + platforms = {} + for arg in self.arguments[0].rstrip(".").split(","): + arg = arg.strip() + platform, _, version = arg.partition(" >= ") + if platform.startswith("not "): + version = False + platform = platform.removeprefix("not ") + elif not version: + version = True + platforms[platform] = version + + if unknown := set(platforms).difference(KNOWN_PLATFORMS): + logger.warning( + "Unknown platform%s or syntax '%s' in '.. availability:: %s', " + "see %s:KNOWN_PLATFORMS for a set of known platforms.", + "s" if len(platforms) != 1 else "", + " ".join(sorted(unknown)), + self.arguments[0], + __file__, + ) + + return platforms + + +def setup(app: Sphinx) -> ExtensionMetadata: + app.add_directive("availability", Availability) + + return { + "version": "1.0", + "parallel_read_safe": True, + "parallel_write_safe": True, + } diff --git a/Doc/tools/extensions/c_annotations.py b/Doc/tools/extensions/c_annotations.py index 7916b178..50065d34 100644 --- a/Doc/tools/extensions/c_annotations.py +++ b/Doc/tools/extensions/c_annotations.py @@ -1,226 +1,302 @@ -""" - c_annotations.py - ~~~~~~~~~~~~~~~~ - - Supports annotations for C API elements: +"""Support annotations for C API elements. - * reference count annotations for C API functions. Based on - refcount.py and anno-api.py in the old Python documentation tools. +* Reference count annotations for C API functions. +* Stable ABI annotations +* Limited API annotations - * stable API annotations +Configuration: +* Set ``refcount_file`` to the path to the reference count data file. +* Set ``stable_abi_file`` to the path to stable ABI list. +""" - Usage: - * Set the `refcount_file` config value to the path to the reference - count data file. - * Set the `stable_abi_file` config value to the path to stable ABI list. +from __future__ import annotations - :copyright: Copyright 2007-2014 by Georg Brandl. - :license: Python license. -""" +import csv +import dataclasses +from pathlib import Path +from typing import TYPE_CHECKING -from os import path +import sphinx from docutils import nodes -from docutils.parsers.rst import directives -from docutils.parsers.rst import Directive from docutils.statemachine import StringList -from sphinx.locale import _ as sphinx_gettext -import csv - from sphinx import addnodes -from sphinx.domains.c import CObject +from sphinx.locale import _ as sphinx_gettext +from sphinx.util.docutils import SphinxDirective +if TYPE_CHECKING: + from sphinx.application import Sphinx + from sphinx.util.typing import ExtensionMetadata -REST_ROLE_MAP = { - 'function': 'func', - 'macro': 'macro', - 'member': 'member', - 'type': 'type', - 'var': 'data', +ROLE_TO_OBJECT_TYPE = { + "func": "function", + "macro": "macro", + "member": "member", + "type": "type", + "data": "var", } -class RCEntry: - def __init__(self, name): - self.name = name - self.args = [] - self.result_type = '' - self.result_refs = None - - -class Annotations: - def __init__(self, refcount_filename, stable_abi_file): - self.refcount_data = {} - with open(refcount_filename, encoding='utf8') as fp: - for line in fp: - line = line.strip() - if line[:1] in ("", "#"): - # blank lines and comments - continue - parts = line.split(":", 4) - if len(parts) != 5: - raise ValueError(f"Wrong field count in {line!r}") - function, type, arg, refcount, comment = parts - # Get the entry, creating it if needed: - try: - entry = self.refcount_data[function] - except KeyError: - entry = self.refcount_data[function] = RCEntry(function) - if not refcount or refcount == "null": - refcount = None - else: - refcount = int(refcount) - # Update the entry with the new parameter or the result - # information. - if arg: - entry.args.append((arg, type, refcount)) - else: - entry.result_type = type - entry.result_refs = refcount - - self.stable_abi_data = {} - with open(stable_abi_file, encoding='utf8') as fp: - for record in csv.DictReader(fp): - name = record['name'] - self.stable_abi_data[name] = record - - def add_annotations(self, app, doctree): - for node in doctree.findall(addnodes.desc_content): - par = node.parent - if par['domain'] != 'c': - continue - if not par[0].has_key('ids') or not par[0]['ids']: - continue - name = par[0]['ids'][0] - if name.startswith("c."): - name = name[2:] - - objtype = par['objtype'] - - # Stable ABI annotation. These have two forms: - # Part of the [Stable ABI](link). - # Part of the [Stable ABI](link) since version X.Y. - # For structs, there's some more info in the message: - # Part of the [Limited API](link) (as an opaque struct). - # Part of the [Stable ABI](link) (including all members). - # Part of the [Limited API](link) (Only some members are part - # of the stable ABI.). - # ... all of which can have "since version X.Y" appended. - record = self.stable_abi_data.get(name) - if record: - if record['role'] != objtype: - raise ValueError( - f"Object type mismatch in limited API annotation " - f"for {name}: {record['role']!r} != {objtype!r}") - stable_added = record['added'] - message = sphinx_gettext('Part of the') - message = message.center(len(message) + 2) - emph_node = nodes.emphasis(message, message, - classes=['stableabi']) - ref_node = addnodes.pending_xref( - 'Stable ABI', refdomain="std", reftarget='stable', - reftype='ref', refexplicit="False") - struct_abi_kind = record['struct_abi_kind'] - if struct_abi_kind in {'opaque', 'members'}: - ref_node += nodes.Text(sphinx_gettext('Limited API')) - else: - ref_node += nodes.Text(sphinx_gettext('Stable ABI')) - emph_node += ref_node - if struct_abi_kind == 'opaque': - emph_node += nodes.Text(' ' + sphinx_gettext('(as an opaque struct)')) - elif struct_abi_kind == 'full-abi': - emph_node += nodes.Text(' ' + sphinx_gettext('(including all members)')) - if record['ifdef_note']: - emph_node += nodes.Text(' ' + record['ifdef_note']) - if stable_added == '3.2': - # Stable ABI was introduced in 3.2. - pass - else: - emph_node += nodes.Text(' ' + sphinx_gettext('since version %s') % stable_added) - emph_node += nodes.Text('.') - if struct_abi_kind == 'members': - emph_node += nodes.Text( - ' ' + sphinx_gettext('(Only some members are part of the stable ABI.)')) - node.insert(0, emph_node) - - # Unstable API annotation. - if name.startswith('PyUnstable'): - warn_node = nodes.admonition( - classes=['unstable-c-api', 'warning']) - message = sphinx_gettext('This is') + ' ' - emph_node = nodes.emphasis(message, message) - ref_node = addnodes.pending_xref( - 'Unstable API', refdomain="std", - reftarget='unstable-c-api', - reftype='ref', refexplicit="False") - ref_node += nodes.Text(sphinx_gettext('Unstable API')) - emph_node += ref_node - emph_node += nodes.Text(sphinx_gettext('. It may change without warning in minor releases.')) - warn_node += emph_node - node.insert(0, warn_node) - - # Return value annotation - if objtype != 'function': - continue - entry = self.refcount_data.get(name) - if not entry: - continue - elif not entry.result_type.endswith("Object*"): - continue - classes = ['refcount'] - if entry.result_refs is None: - rc = sphinx_gettext('Return value: Always NULL.') - classes.append('return_null') - elif entry.result_refs: - rc = sphinx_gettext('Return value: New reference.') - classes.append('return_new_ref') - else: - rc = sphinx_gettext('Return value: Borrowed reference.') - classes.append('return_borrowed_ref') - node.insert(0, nodes.emphasis(rc, rc, classes=classes)) - - -def init_annotations(app): - annotations = Annotations( - path.join(app.srcdir, app.config.refcount_file), - path.join(app.srcdir, app.config.stable_abi_file), +@dataclasses.dataclass(slots=True) +class RefCountEntry: + # Name of the function. + name: str + # List of (argument name, type, refcount effect) tuples. + # (Currently not used. If it was, a dataclass might work better.) + args: list = dataclasses.field(default_factory=list) + # Return type of the function. + result_type: str = "" + # Reference count effect for the return value. + result_refs: int | None = None + + +@dataclasses.dataclass(frozen=True, slots=True) +class StableABIEntry: + # Role of the object. + # Source: Each [item_kind] in stable_abi.toml is mapped to a C Domain role. + role: str + # Name of the object. + # Source: [.*] in stable_abi.toml. + name: str + # Version when the object was added to the stable ABI. + # (Source: [.*.added] in stable_abi.toml. + added: str + # An explananatory blurb for the ifdef. + # Source: ``feature_macro.*.doc`` in stable_abi.toml. + ifdef_note: str + # Defines how much of the struct is exposed. Only relevant for structs. + # Source: [.*.struct_abi_kind] in stable_abi.toml. + struct_abi_kind: str + + +def read_refcount_data(refcount_filename: Path) -> dict[str, RefCountEntry]: + refcount_data = {} + refcounts = refcount_filename.read_text(encoding="utf8") + for line in refcounts.splitlines(): + line = line.strip() + if not line or line.startswith("#"): + # blank lines and comments + continue + + # Each line is of the form + # function ':' type ':' [param name] ':' [refcount effect] ':' [comment] + parts = line.split(":", 4) + if len(parts) != 5: + raise ValueError(f"Wrong field count in {line!r}") + function, type, arg, refcount, _comment = parts + + # Get the entry, creating it if needed: + try: + entry = refcount_data[function] + except KeyError: + entry = refcount_data[function] = RefCountEntry(function) + if not refcount or refcount == "null": + refcount = None + else: + refcount = int(refcount) + # Update the entry with the new parameter + # or the result information. + if arg: + entry.args.append((arg, type, refcount)) + else: + entry.result_type = type + entry.result_refs = refcount + + return refcount_data + + +def read_stable_abi_data(stable_abi_file: Path) -> dict[str, StableABIEntry]: + stable_abi_data = {} + with open(stable_abi_file, encoding="utf8") as fp: + for record in csv.DictReader(fp): + name = record["name"] + stable_abi_data[name] = StableABIEntry(**record) + + return stable_abi_data + + +def add_annotations(app: Sphinx, doctree: nodes.document) -> None: + state = app.env.domaindata["c_annotations"] + refcount_data = state["refcount_data"] + stable_abi_data = state["stable_abi_data"] + for node in doctree.findall(addnodes.desc_content): + par = node.parent + if par["domain"] != "c": + continue + if not par[0].get("ids", None): + continue + name = par[0]["ids"][0].removeprefix("c.") + objtype = par["objtype"] + + # Stable ABI annotation. + if record := stable_abi_data.get(name): + if ROLE_TO_OBJECT_TYPE[record.role] != objtype: + msg = ( + f"Object type mismatch in limited API annotation for {name}: " + f"{ROLE_TO_OBJECT_TYPE[record.role]!r} != {objtype!r}" + ) + raise ValueError(msg) + annotation = _stable_abi_annotation(record) + node.insert(0, annotation) + + # Unstable API annotation. + if name.startswith("PyUnstable"): + annotation = _unstable_api_annotation() + node.insert(0, annotation) + + # Return value annotation + if objtype != "function": + continue + if name not in refcount_data: + continue + entry = refcount_data[name] + if not entry.result_type.endswith("Object*"): + continue + annotation = _return_value_annotation(entry.result_refs) + node.insert(0, annotation) + + +def _stable_abi_annotation(record: StableABIEntry) -> nodes.emphasis: + """Create the Stable ABI annotation. + + These have two forms: + Part of the `Stable ABI `_. + Part of the `Stable ABI `_ since version X.Y. + For structs, there's some more info in the message: + Part of the `Limited API `_ (as an opaque struct). + Part of the `Stable ABI `_ (including all members). + Part of the `Limited API `_ (Only some members are part + of the stable ABI.). + ... all of which can have "since version X.Y" appended. + """ + stable_added = record.added + message = sphinx_gettext("Part of the") + message = message.center(len(message) + 2) + emph_node = nodes.emphasis(message, message, classes=["stableabi"]) + ref_node = addnodes.pending_xref( + "Stable ABI", + refdomain="std", + reftarget="stable", + reftype="ref", + refexplicit="False", ) - app.connect('doctree-read', annotations.add_annotations) + struct_abi_kind = record.struct_abi_kind + if struct_abi_kind in {"opaque", "members"}: + ref_node += nodes.Text(sphinx_gettext("Limited API")) + else: + ref_node += nodes.Text(sphinx_gettext("Stable ABI")) + emph_node += ref_node + if struct_abi_kind == "opaque": + emph_node += nodes.Text(" " + sphinx_gettext("(as an opaque struct)")) + elif struct_abi_kind == "full-abi": + emph_node += nodes.Text( + " " + sphinx_gettext("(including all members)") + ) + if record.ifdef_note: + emph_node += nodes.Text(f" {record.ifdef_note}") + if stable_added == "3.2": + # Stable ABI was introduced in 3.2. + pass + else: + emph_node += nodes.Text( + " " + sphinx_gettext("since version %s") % stable_added + ) + emph_node += nodes.Text(".") + if struct_abi_kind == "members": + msg = " " + sphinx_gettext( + "(Only some members are part of the stable ABI.)" + ) + emph_node += nodes.Text(msg) + return emph_node - class LimitedAPIList(Directive): - has_content = False - required_arguments = 0 - optional_arguments = 0 - final_argument_whitespace = True +def _unstable_api_annotation() -> nodes.admonition: + ref_node = addnodes.pending_xref( + "Unstable API", + nodes.Text(sphinx_gettext("Unstable API")), + refdomain="std", + reftarget="unstable-c-api", + reftype="ref", + refexplicit="False", + ) + emph_node = nodes.emphasis( + "This is ", + sphinx_gettext("This is") + " ", + ref_node, + nodes.Text( + sphinx_gettext( + ". It may change without warning in minor releases." + ) + ), + ) + return nodes.admonition( + "", + emph_node, + classes=["unstable-c-api", "warning"], + ) - def run(self): - content = [] - for record in annotations.stable_abi_data.values(): - role = REST_ROLE_MAP[record['role']] - name = record['name'] - content.append(f'* :c:{role}:`{name}`') - pnode = nodes.paragraph() - self.state.nested_parse(StringList(content), 0, pnode) - return [pnode] +def _return_value_annotation(result_refs: int | None) -> nodes.emphasis: + classes = ["refcount"] + if result_refs is None: + rc = sphinx_gettext("Return value: Always NULL.") + classes.append("return_null") + elif result_refs: + rc = sphinx_gettext("Return value: New reference.") + classes.append("return_new_ref") + else: + rc = sphinx_gettext("Return value: Borrowed reference.") + classes.append("return_borrowed_ref") + return nodes.emphasis(rc, rc, classes=classes) - app.add_directive('limited-api-list', LimitedAPIList) +class LimitedAPIList(SphinxDirective): + has_content = False + required_arguments = 0 + optional_arguments = 0 + final_argument_whitespace = True -def setup(app): - app.add_config_value('refcount_file', '', True) - app.add_config_value('stable_abi_file', '', True) - app.connect('builder-inited', init_annotations) + def run(self) -> list[nodes.Node]: + state = self.env.domaindata["c_annotations"] + content = [ + f"* :c:{record.role}:`{record.name}`" + for record in state["stable_abi_data"].values() + ] + node = nodes.paragraph() + self.state.nested_parse(StringList(content), 0, node) + return [node] + + +def init_annotations(app: Sphinx) -> None: + # Using domaindata is a bit hack-ish, + # but allows storing state without a global variable or closure. + app.env.domaindata["c_annotations"] = state = {} + state["refcount_data"] = read_refcount_data( + Path(app.srcdir, app.config.refcount_file) + ) + state["stable_abi_data"] = read_stable_abi_data( + Path(app.srcdir, app.config.stable_abi_file) + ) - # monkey-patch C object... - CObject.option_spec = { - 'noindex': directives.flag, - 'stableabi': directives.flag, - } - old_handle_signature = CObject.handle_signature - def new_handle_signature(self, sig, signode): - signode.parent['stableabi'] = 'stableabi' in self.options - return old_handle_signature(self, sig, signode) - CObject.handle_signature = new_handle_signature - return {'version': '1.0', 'parallel_read_safe': True} +def setup(app: Sphinx) -> ExtensionMetadata: + app.add_config_value("refcount_file", "", "env", types={str}) + app.add_config_value("stable_abi_file", "", "env", types={str}) + app.add_directive("limited-api-list", LimitedAPIList) + app.connect("builder-inited", init_annotations) + app.connect("doctree-read", add_annotations) + + if sphinx.version_info[:2] < (7, 2): + from docutils.parsers.rst import directives + from sphinx.domains.c import CObject + + # monkey-patch C object... + CObject.option_spec |= { + "no-index-entry": directives.flag, + "no-contents-entry": directives.flag, + } + + return { + "version": "1.0", + "parallel_read_safe": True, + "parallel_write_safe": True, + } diff --git a/Doc/tools/extensions/escape4chm.py b/Doc/tools/extensions/escape4chm.py deleted file mode 100644 index 89970975..00000000 --- a/Doc/tools/extensions/escape4chm.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -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 pathlib -import re -from html.entities import codepoint2name - -from sphinx.util.logging import getLogger - -# 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 getattr(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 fixup_keywords(app, exception): - # only works for .chm output - if getattr(app.builder, 'name', '') != 'htmlhelp' or exception: - return - - getLogger(__name__).info('fixing HTML escapes in keywords file...') - outdir = pathlib.Path(app.builder.outdir) - outname = app.builder.config.htmlhelp_basename - with open(outdir / (outname + '.hhk'), 'rb') as f: - index = f.read() - with open(outdir / (outname + '.hhk'), 'wb') as f: - f.write(index.replace(b''', b''')) - -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) - # `build-finished` event emitted when all the files have been - # output. - app.connect('build-finished', fixup_keywords) - - return {'version': '1.0', 'parallel_read_safe': True} diff --git a/Doc/tools/extensions/glossary_search.py b/Doc/tools/extensions/glossary_search.py index 7c93b1e4..502b6cd9 100644 --- a/Doc/tools/extensions/glossary_search.py +++ b/Doc/tools/extensions/glossary_search.py @@ -1,63 +1,63 @@ -# -*- coding: utf-8 -*- -""" - glossary_search.py - ~~~~~~~~~~~~~~~~ +"""Feature search results for glossary items prominently.""" - Feature search results for glossary items prominently. +from __future__ import annotations - :license: Python license. -""" import json -import os.path -from docutils.nodes import definition_list_item +from pathlib import Path +from typing import TYPE_CHECKING + +from docutils import nodes from sphinx.addnodes import glossary from sphinx.util import logging +if TYPE_CHECKING: + from sphinx.application import Sphinx + from sphinx.util.typing import ExtensionMetadata logger = logging.getLogger(__name__) -STATIC_DIR = '_static' -JSON = 'glossary.json' -def process_glossary_nodes(app, doctree, fromdocname): +def process_glossary_nodes( + app: Sphinx, + doctree: nodes.document, + _docname: str, +) -> None: if app.builder.format != 'html' or app.builder.embedded: return - terms = {} + if hasattr(app.env, 'glossary_terms'): + terms = app.env.glossary_terms + else: + terms = app.env.glossary_terms = {} for node in doctree.findall(glossary): - for glossary_item in node.findall(definition_list_item): - term = glossary_item[0].astext().lower() - definition = glossary_item[1] + for glossary_item in node.findall(nodes.definition_list_item): + term = glossary_item[0].astext() + definition = glossary_item[-1] rendered = app.builder.render_partial(definition) - terms[term] = { - 'title': glossary_item[0].astext(), - 'body': rendered['html_body'] + terms[term.lower()] = { + 'title': term, + 'body': rendered['html_body'], } - if hasattr(app.env, 'glossary_terms'): - app.env.glossary_terms.update(terms) - else: - app.env.glossary_terms = terms -def on_build_finish(app, exc): - if not hasattr(app.env, 'glossary_terms'): - return - if not app.env.glossary_terms: +def write_glossary_json(app: Sphinx, _exc: Exception) -> None: + if not getattr(app.env, 'glossary_terms', None): return - logger.info(f'Writing {JSON}', color='green') - - dest_dir = os.path.join(app.outdir, STATIC_DIR) - os.makedirs(dest_dir, exist_ok=True) - - with open(os.path.join(dest_dir, JSON), 'w') as f: - json.dump(app.env.glossary_terms, f) + logger.info('Writing glossary.json', color='green') + dest = Path(app.outdir, '_static', 'glossary.json') + dest.parent.mkdir(exist_ok=True) + dest.write_text(json.dumps(app.env.glossary_terms), encoding='utf-8') -def setup(app): +def setup(app: Sphinx) -> ExtensionMetadata: app.connect('doctree-resolved', process_glossary_nodes) - app.connect('build-finished', on_build_finish) + app.connect('build-finished', write_glossary_json) - return {'version': '0.1', 'parallel_read_safe': True} + return { + 'version': '1.0', + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } diff --git a/Doc/tools/extensions/lexers/__init__.py b/Doc/tools/extensions/lexers/__init__.py new file mode 100644 index 00000000..e12ac5be --- /dev/null +++ b/Doc/tools/extensions/lexers/__init__.py @@ -0,0 +1,15 @@ +from .asdl_lexer import ASDLLexer +from .peg_lexer import PEGLexer + + +def setup(app): + # Used for highlighting Parser/Python.asdl in library/ast.rst + app.add_lexer("asdl", ASDLLexer) + # Used for highlighting Grammar/python.gram in reference/grammar.rst + app.add_lexer("peg", PEGLexer) + + return { + "version": "1.0", + "parallel_read_safe": True, + "parallel_write_safe": True, + } diff --git a/Doc/tools/extensions/asdl_highlight.py b/Doc/tools/extensions/lexers/asdl_lexer.py similarity index 62% rename from Doc/tools/extensions/asdl_highlight.py rename to Doc/tools/extensions/lexers/asdl_lexer.py index 42863a4b..3a74174a 100644 --- a/Doc/tools/extensions/asdl_highlight.py +++ b/Doc/tools/extensions/lexers/asdl_lexer.py @@ -1,15 +1,6 @@ -import sys -from pathlib import Path +from pygments.lexer import RegexLexer, bygroups, include +from pygments.token import Comment, Keyword, Name, Operator, Punctuation, Text -CPYTHON_ROOT = Path(__file__).resolve().parent.parent.parent.parent -sys.path.append(str(CPYTHON_ROOT / "Parser")) - -from pygments.lexer import RegexLexer, bygroups, include, words -from pygments.token import (Comment, Keyword, Name, Operator, - Punctuation, Text) - -from asdl import builtin_types -from sphinx.highlighting import lexers class ASDLLexer(RegexLexer): name = "ASDL" @@ -34,7 +25,10 @@ class ASDLLexer(RegexLexer): r"(\w+)(\*\s|\?\s|\s)(\w+)", bygroups(Name.Builtin.Pseudo, Operator, Name), ), - (words(builtin_types), Name.Builtin), + # Keep in line with ``builtin_types`` from Parser/asdl.py. + # ASDL's 4 builtin types are + # constant, identifier, int, string + ("constant|identifier|int|string", Name.Builtin), (r"attributes", Name.Builtin), ( _name + _text_ws + "(=)", @@ -46,8 +40,3 @@ class ASDLLexer(RegexLexer): (r".", Text), ], } - - -def setup(app): - lexers["asdl"] = ASDLLexer() - return {'version': '1.0', 'parallel_read_safe': True} diff --git a/Doc/tools/extensions/peg_highlight.py b/Doc/tools/extensions/lexers/peg_lexer.py similarity index 94% rename from Doc/tools/extensions/peg_highlight.py rename to Doc/tools/extensions/lexers/peg_lexer.py index 5ab5530d..06f9f8eb 100644 --- a/Doc/tools/extensions/peg_highlight.py +++ b/Doc/tools/extensions/lexers/peg_lexer.py @@ -1,8 +1,6 @@ from pygments.lexer import RegexLexer, bygroups, include from pygments.token import Comment, Keyword, Name, Operator, Punctuation, Text -from sphinx.highlighting import lexers - class PEGLexer(RegexLexer): """Pygments Lexer for PEG grammar (.gram) files @@ -81,8 +79,3 @@ class PEGLexer(RegexLexer): (r".", Text), ], } - - -def setup(app): - lexers["peg"] = PEGLexer() - return {"version": "1.0", "parallel_read_safe": True} diff --git a/Doc/tools/extensions/patchlevel.py b/Doc/tools/extensions/patchlevel.py index 617f28c2..9ccaec3d 100644 --- a/Doc/tools/extensions/patchlevel.py +++ b/Doc/tools/extensions/patchlevel.py @@ -1,68 +1,81 @@ -# -*- coding: utf-8 -*- -""" - patchlevel.py - ~~~~~~~~~~~~~ +"""Extract version information from Include/patchlevel.h.""" - Extract version info from Include/patchlevel.h. - Adapted from Doc/tools/getversioninfo. +import re +import sys +from pathlib import Path +from typing import Literal, NamedTuple - :copyright: 2007-2008 by Georg Brandl. - :license: Python license. -""" +CPYTHON_ROOT = Path( + __file__, # cpython/Doc/tools/extensions/patchlevel.py + "..", # cpython/Doc/tools/extensions + "..", # cpython/Doc/tools + "..", # cpython/Doc + "..", # cpython +).resolve() +PATCHLEVEL_H = CPYTHON_ROOT / "Include" / "patchlevel.h" -from __future__ import print_function +RELEASE_LEVELS = { + "PY_RELEASE_LEVEL_ALPHA": "alpha", + "PY_RELEASE_LEVEL_BETA": "beta", + "PY_RELEASE_LEVEL_GAMMA": "candidate", + "PY_RELEASE_LEVEL_FINAL": "final", +} -import os -import re -import sys -def get_header_version_info(srcdir): - patchlevel_h = os.path.join(srcdir, '..', 'Include', 'patchlevel.h') +class version_info(NamedTuple): # noqa: N801 + major: int #: Major release number + minor: int #: Minor release number + micro: int #: Patch release number + releaselevel: Literal["alpha", "beta", "candidate", "final"] + serial: int #: Serial release number - # This won't pick out all #defines, but it will pick up the ones we - # care about. - rx = re.compile(r'\s*#define\s+([a-zA-Z][a-zA-Z_0-9]*)\s+([a-zA-Z_0-9]+)') - d = {} - with open(patchlevel_h) as f: - for line in f: - m = rx.match(line) - if m is not None: - name, value = m.group(1, 2) - d[name] = value +def get_header_version_info() -> version_info: + # Capture PY_ prefixed #defines. + pat = re.compile(r"\s*#define\s+(PY_\w*)\s+(\w+)", re.ASCII) - release = version = '%s.%s' % (d['PY_MAJOR_VERSION'], d['PY_MINOR_VERSION']) - micro = int(d['PY_MICRO_VERSION']) - release += '.' + str(micro) + defines = {} + patchlevel_h = PATCHLEVEL_H.read_text(encoding="utf-8") + for line in patchlevel_h.splitlines(): + if (m := pat.match(line)) is not None: + name, value = m.groups() + defines[name] = value - level = d['PY_RELEASE_LEVEL'] - suffixes = { - 'PY_RELEASE_LEVEL_ALPHA': 'a', - 'PY_RELEASE_LEVEL_BETA': 'b', - 'PY_RELEASE_LEVEL_GAMMA': 'rc', - } - if level != 'PY_RELEASE_LEVEL_FINAL': - release += suffixes[level] + str(int(d['PY_RELEASE_SERIAL'])) - return version, release + return version_info( + major=int(defines["PY_MAJOR_VERSION"]), + minor=int(defines["PY_MINOR_VERSION"]), + micro=int(defines["PY_MICRO_VERSION"]), + releaselevel=RELEASE_LEVELS[defines["PY_RELEASE_LEVEL"]], + serial=int(defines["PY_RELEASE_SERIAL"]), + ) -def get_sys_version_info(): - major, minor, micro, level, serial = sys.version_info - release = version = '%s.%s' % (major, minor) - release += '.%s' % micro - if level != 'final': - release += '%s%s' % (level[0], serial) +def format_version_info(info: version_info) -> tuple[str, str]: + version = f"{info.major}.{info.minor}" + release = f"{info.major}.{info.minor}.{info.micro}" + if info.releaselevel != "final": + suffix = {"alpha": "a", "beta": "b", "candidate": "rc"} + release += f"{suffix[info.releaselevel]}{info.serial}" return version, release def get_version_info(): try: - return get_header_version_info('.') - except (IOError, OSError): - version, release = get_sys_version_info() - print('Can\'t get version info from Include/patchlevel.h, ' \ - 'using version of this interpreter (%s).' % release, file=sys.stderr) + info = get_header_version_info() + return format_version_info(info) + except OSError: + version, release = format_version_info(sys.version_info) + print( + f"Failed to get version info from Include/patchlevel.h, " + f"using version of this interpreter ({release}).", + file=sys.stderr, + ) return version, release -if __name__ == '__main__': - print(get_header_version_info('.')[1]) + +if __name__ == "__main__": + short_ver, full_ver = format_version_info(get_header_version_info()) + if sys.argv[1:2] == ["--short"]: + print(short_ver) + else: + print(full_ver) diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index caf14599..615c7f1f 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -15,16 +15,15 @@ from time import asctime from pprint import pformat -from docutils import nodes, utils +from docutils import nodes from docutils.io import StringOutput -from docutils.parsers.rst import Directive -from docutils.utils import new_document +from docutils.parsers.rst import directives +from docutils.utils import new_document, unescape from sphinx import addnodes from sphinx.builders import Builder -from sphinx.domains.python import PyFunction, PyMethod -from sphinx.errors import NoUri +from sphinx.domains.changeset import VersionChange, versionlabels, versionlabel_classes +from sphinx.domains.python import PyFunction, PyMethod, PyModule from sphinx.locale import _ as sphinx_gettext -from sphinx.util import logging from sphinx.util.docutils import SphinxDirective from sphinx.writers.text import TextWriter, TextTranslator from sphinx.util.display import status_iterator @@ -48,11 +47,14 @@ std.token_re = re.compile(r'`((~?[\w-]*:)?\w+)`') +# backport :no-index: +PyModule.option_spec['no-index'] = directives.flag + # Support for marking up and linking to bugs.python.org issues def issue_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): - issue = utils.unescape(text) + issue = unescape(text) # sanity check: there are no bpo issues within these two values if 47261 < int(issue) < 400000: msg = inliner.reporter.error(f'The BPO ID {text!r} seems too high -- ' @@ -67,7 +69,7 @@ def issue_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): # Support for marking up and linking to GitHub issues def gh_issue_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): - issue = utils.unescape(text) + issue = unescape(text) # sanity check: all GitHub issues have ID >= 32426 # even though some of them are also valid BPO IDs if int(issue) < 32426: @@ -82,7 +84,7 @@ def gh_issue_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): # Support for marking up implementation details -class ImplementationDetail(Directive): +class ImplementationDetail(SphinxDirective): has_content = True final_argument_whitespace = True @@ -105,217 +107,6 @@ def run(self): return [pnode] -# Support for documenting platform availability - -class Availability(SphinxDirective): - - has_content = True - required_arguments = 1 - optional_arguments = 0 - final_argument_whitespace = True - - # known platform, libc, and threading implementations - known_platforms = frozenset({ - "AIX", "Android", "BSD", "DragonFlyBSD", "Emscripten", "FreeBSD", - "Linux", "NetBSD", "OpenBSD", "POSIX", "Solaris", "Unix", "VxWorks", - "WASI", "Windows", "macOS", - # libc - "BSD libc", "glibc", "musl", - # POSIX platforms with pthreads - "pthreads", - }) - - def run(self): - availability_ref = ':ref:`Availability `: ' - avail_nodes, avail_msgs = self.state.inline_text( - availability_ref + self.arguments[0], - self.lineno) - pnode = nodes.paragraph(availability_ref + self.arguments[0], - '', *avail_nodes, *avail_msgs) - self.set_source_info(pnode) - cnode = nodes.container("", pnode, classes=["availability"]) - self.set_source_info(cnode) - if self.content: - self.state.nested_parse(self.content, self.content_offset, cnode) - self.parse_platforms() - - return [cnode] - - def parse_platforms(self): - """Parse platform information from arguments - - Arguments is a comma-separated string of platforms. A platform may - be prefixed with "not " to indicate that a feature is not available. - - Example:: - - .. availability:: Windows, Linux >= 4.2, not Emscripten, not WASI - - Arguments like "Linux >= 3.17 with glibc >= 2.27" are currently not - parsed into separate tokens. - """ - platforms = {} - for arg in self.arguments[0].rstrip(".").split(","): - arg = arg.strip() - platform, _, version = arg.partition(" >= ") - if platform.startswith("not "): - version = False - platform = platform[4:] - elif not version: - version = True - platforms[platform] = version - - unknown = set(platforms).difference(self.known_platforms) - if unknown: - cls = type(self) - logger = logging.getLogger(cls.__qualname__) - logger.warning( - f"Unknown platform(s) or syntax '{' '.join(sorted(unknown))}' " - f"in '.. availability:: {self.arguments[0]}', see " - f"{__file__}:{cls.__qualname__}.known_platforms for a set " - "known platforms." - ) - - return platforms - - -# Support for documenting audit event - -def audit_events_purge(app, env, docname): - """This is to remove from env.all_audit_events old traces of removed - documents. - """ - if not hasattr(env, 'all_audit_events'): - return - fresh_all_audit_events = {} - for name, event in env.all_audit_events.items(): - event["source"] = [(d, t) for d, t in event["source"] if d != docname] - if event["source"]: - # Only keep audit_events that have at least one source. - fresh_all_audit_events[name] = event - env.all_audit_events = fresh_all_audit_events - - -def audit_events_merge(app, env, docnames, other): - """In Sphinx parallel builds, this merges env.all_audit_events from - subprocesses. - - all_audit_events is a dict of names, with values like: - {'source': [(docname, target), ...], 'args': args} - """ - if not hasattr(other, 'all_audit_events'): - return - if not hasattr(env, 'all_audit_events'): - env.all_audit_events = {} - for name, value in other.all_audit_events.items(): - if name in env.all_audit_events: - env.all_audit_events[name]["source"].extend(value["source"]) - else: - env.all_audit_events[name] = value - - -class AuditEvent(Directive): - - has_content = True - required_arguments = 1 - optional_arguments = 2 - final_argument_whitespace = True - - _label = [ - sphinx_gettext("Raises an :ref:`auditing event ` {name} with no arguments."), - sphinx_gettext("Raises an :ref:`auditing event ` {name} with argument {args}."), - sphinx_gettext("Raises an :ref:`auditing event ` {name} with arguments {args}."), - ] - - @property - def logger(self): - cls = type(self) - return logging.getLogger(cls.__module__ + "." + cls.__name__) - - def run(self): - name = self.arguments[0] - if len(self.arguments) >= 2 and self.arguments[1]: - args = (a.strip() for a in self.arguments[1].strip("'\"").split(",")) - args = [a for a in args if a] - else: - args = [] - - label = self._label[min(2, len(args))] - text = label.format(name="``{}``".format(name), - args=", ".join("``{}``".format(a) for a in args if a)) - - env = self.state.document.settings.env - if not hasattr(env, 'all_audit_events'): - env.all_audit_events = {} - - new_info = { - 'source': [], - 'args': args - } - info = env.all_audit_events.setdefault(name, new_info) - if info is not new_info: - if not self._do_args_match(info['args'], new_info['args']): - self.logger.warning( - "Mismatched arguments for audit-event {}: {!r} != {!r}" - .format(name, info['args'], new_info['args']) - ) - - ids = [] - try: - target = self.arguments[2].strip("\"'") - except (IndexError, TypeError): - target = None - if not target: - target = "audit_event_{}_{}".format( - re.sub(r'\W', '_', name), - len(info['source']), - ) - ids.append(target) - - info['source'].append((env.docname, target)) - - pnode = nodes.paragraph(text, classes=["audit-hook"], ids=ids) - pnode.line = self.lineno - if self.content: - self.state.nested_parse(self.content, self.content_offset, pnode) - else: - n, m = self.state.inline_text(text, self.lineno) - pnode.extend(n + m) - - return [pnode] - - # This list of sets are allowable synonyms for event argument names. - # If two names are in the same set, they are treated as equal for the - # purposes of warning. This won't help if number of arguments is - # different! - _SYNONYMS = [ - {"file", "path", "fd"}, - ] - - def _do_args_match(self, args1, args2): - if args1 == args2: - return True - if len(args1) != len(args2): - return False - for a1, a2 in zip(args1, args2): - if a1 == a2: - continue - if any(a1 in s and a2 in s for s in self._SYNONYMS): - continue - return False - return True - - -class audit_event_list(nodes.General, nodes.Element): - pass - - -class AuditEventListDirective(Directive): - - def run(self): - return [audit_event_list('')] - - # Support for documenting decorators class PyDecoratorMixin(object): @@ -393,60 +184,55 @@ def run(self): return PyMethod.run(self) -# Support for documenting version of removal in deprecations +# Support for documenting version of changes, additions, deprecations -class DeprecatedRemoved(Directive): - has_content = True +def expand_version_arg(argument, release): + """Expand "next" to the current version""" + if argument == 'next': + return sphinx_gettext('{} (unreleased)').format(release) + return argument + + +class PyVersionChange(VersionChange): + def run(self): + # Replace the 'next' special token with the current development version + self.arguments[0] = expand_version_arg(self.arguments[0], + self.config.release) + return super().run() + + +class DeprecatedRemoved(VersionChange): required_arguments = 2 - optional_arguments = 1 - final_argument_whitespace = True - option_spec = {} - _deprecated_label = sphinx_gettext('Deprecated since version {deprecated}, will be removed in version {removed}') - _removed_label = sphinx_gettext('Deprecated since version {deprecated}, removed in version {removed}') + _deprecated_label = sphinx_gettext('Deprecated since version %s, will be removed in version %s') + _removed_label = sphinx_gettext('Deprecated since version %s, removed in version %s') def run(self): - node = addnodes.versionmodified() - node.document = self.state.document - node['type'] = 'deprecated-removed' - version = (self.arguments[0], self.arguments[1]) - node['version'] = version - env = self.state.document.settings.env - current_version = tuple(int(e) for e in env.config.version.split('.')) - removed_version = tuple(int(e) for e in self.arguments[1].split('.')) + # Replace the first two arguments (deprecated version and removed version) + # with a single tuple of both versions. + version_deprecated = expand_version_arg(self.arguments[0], + self.config.release) + version_removed = self.arguments.pop(1) + if version_removed == 'next': + raise ValueError( + 'deprecated-removed:: second argument cannot be `next`') + self.arguments[0] = version_deprecated, version_removed + + # Set the label based on if we have reached the removal version + current_version = tuple(map(int, self.config.version.split('.'))) + removed_version = tuple(map(int, version_removed.split('.'))) if current_version < removed_version: - label = self._deprecated_label - else: - label = self._removed_label - - text = label.format(deprecated=self.arguments[0], removed=self.arguments[1]) - if len(self.arguments) == 3: - inodes, messages = self.state.inline_text(self.arguments[2], - self.lineno+1) - para = nodes.paragraph(self.arguments[2], '', *inodes, translatable=False) - node.append(para) - else: - messages = [] - if self.content: - self.state.nested_parse(self.content, self.content_offset, node) - if len(node): - if isinstance(node[0], nodes.paragraph) and node[0].rawsource: - content = nodes.inline(node[0].rawsource, translatable=True) - content.source = node[0].source - content.line = node[0].line - content += node[0].children - node[0].replace_self(nodes.paragraph('', '', content, translatable=False)) - node[0].insert(0, nodes.inline('', '%s: ' % text, - classes=['versionmodified'])) + versionlabels[self.name] = self._deprecated_label + versionlabel_classes[self.name] = 'deprecated' else: - para = nodes.paragraph('', '', - nodes.inline('', '%s.' % text, - classes=['versionmodified']), - translatable=False) - node.append(para) - env = self.state.document.settings.env - env.get_domain('changeset').note_changeset(node) - return [node] + messages + versionlabels[self.name] = self._removed_label + versionlabel_classes[self.name] = 'removed' + try: + return super().run() + finally: + # reset versionlabels and versionlabel_classes + versionlabels[self.name] = '' + versionlabel_classes[self.name] = '' # Support for including Misc/NEWS @@ -456,7 +242,7 @@ def run(self): whatsnew_re = re.compile(r"(?im)^what's new in (.*?)\??$") -class MiscNews(Directive): +class MiscNews(SphinxDirective): has_content = False required_arguments = 1 optional_arguments = 0 @@ -471,7 +257,7 @@ def run(self): if not source_dir: source_dir = path.dirname(path.abspath(source)) fpath = path.join(source_dir, fname) - self.state.document.settings.record_dependencies.add(fpath) + self.env.note_dependency(path.abspath(fpath)) try: with io.open(fpath, encoding='utf-8') as fp: content = fp.read() @@ -603,70 +389,6 @@ def parse_monitoring_event(env, sig, signode): return sig -def process_audit_events(app, doctree, fromdocname): - for node in doctree.findall(audit_event_list): - break - else: - return - - env = app.builder.env - - table = nodes.table(cols=3) - group = nodes.tgroup( - '', - nodes.colspec(colwidth=30), - nodes.colspec(colwidth=55), - nodes.colspec(colwidth=15), - cols=3, - ) - head = nodes.thead() - body = nodes.tbody() - - table += group - group += head - group += body - - row = nodes.row() - row += nodes.entry('', nodes.paragraph('', nodes.Text('Audit event'))) - row += nodes.entry('', nodes.paragraph('', nodes.Text('Arguments'))) - row += nodes.entry('', nodes.paragraph('', nodes.Text('References'))) - head += row - - for name in sorted(getattr(env, "all_audit_events", ())): - audit_event = env.all_audit_events[name] - - row = nodes.row() - node = nodes.paragraph('', nodes.Text(name)) - row += nodes.entry('', node) - - node = nodes.paragraph() - for i, a in enumerate(audit_event['args']): - if i: - node += nodes.Text(", ") - node += nodes.literal(a, nodes.Text(a)) - row += nodes.entry('', node) - - node = nodes.paragraph() - backlinks = enumerate(sorted(set(audit_event['source'])), start=1) - for i, (doc, label) in backlinks: - if isinstance(label, str): - ref = nodes.reference("", nodes.Text("[{}]".format(i)), internal=True) - try: - ref['refuri'] = "{}#{}".format( - app.builder.get_relative_uri(fromdocname, doc), - label, - ) - except NoUri: - continue - node += ref - row += nodes.entry('', node) - - body += row - - for node in doctree.findall(audit_event_list): - node.replace_self(table) - - def patch_pairindextypes(app, _env) -> None: """Remove all entries from ``pairindextypes`` before writing POT files. @@ -695,9 +417,10 @@ def setup(app): app.add_role('issue', issue_role) app.add_role('gh', gh_issue_role) app.add_directive('impl-detail', ImplementationDetail) - app.add_directive('availability', Availability) - app.add_directive('audit-event', AuditEvent) - app.add_directive('audit-event-table', AuditEventListDirective) + app.add_directive('versionadded', PyVersionChange, override=True) + app.add_directive('versionchanged', PyVersionChange, override=True) + app.add_directive('versionremoved', PyVersionChange, override=True) + app.add_directive('deprecated', PyVersionChange, override=True) app.add_directive('deprecated-removed', DeprecatedRemoved) app.add_builder(PydocTopicsBuilder) app.add_object_type('opcode', 'opcode', '%s (opcode)', parse_opcode_signature) @@ -712,8 +435,6 @@ def setup(app): app.add_directive_to_domain('py', 'awaitablemethod', PyAwaitableMethod) app.add_directive_to_domain('py', 'abstractmethod', PyAbstractMethod) app.add_directive('miscnews', MiscNews) + app.add_css_file('sidebar-wrap.css') app.connect('env-check-consistency', patch_pairindextypes) - app.connect('doctree-resolved', process_audit_events) - app.connect('env-merge-info', audit_events_merge) - app.connect('env-purge-doc', audit_events_purge) return {'version': '1.0', 'parallel_read_safe': True} diff --git a/Doc/tools/static/glossary_search.js b/Doc/tools/static/glossary_search.js new file mode 100644 index 00000000..13d728dc --- /dev/null +++ b/Doc/tools/static/glossary_search.js @@ -0,0 +1,47 @@ +"use strict"; + +const GLOSSARY_PAGE = "glossary.html"; + +const glossary_search = async () => { + const response = await fetch("_static/glossary.json"); + if (!response.ok) { + throw new Error("Failed to fetch glossary.json"); + } + const glossary = await response.json(); + + const params = new URLSearchParams(document.location.search).get("q"); + if (!params) { + return; + } + + const searchParam = params.toLowerCase(); + const glossaryItem = glossary[searchParam]; + if (!glossaryItem) { + return; + } + + // set up the title text with a link to the glossary page + const glossaryTitle = document.getElementById("glossary-title"); + glossaryTitle.textContent = "Glossary: " + glossaryItem.title; + const linkTarget = searchParam.replace(/ /g, "-"); + glossaryTitle.href = GLOSSARY_PAGE + "#term-" + linkTarget; + + // rewrite any anchor links (to other glossary terms) + // to have a full reference to the glossary page + const glossaryBody = document.getElementById("glossary-body"); + glossaryBody.innerHTML = glossaryItem.body; + const anchorLinks = glossaryBody.querySelectorAll('a[href^="#"]'); + anchorLinks.forEach(function (link) { + const currentUrl = link.getAttribute("href"); + link.href = GLOSSARY_PAGE + currentUrl; + }); + + const glossaryResult = document.getElementById("glossary-result"); + glossaryResult.style.display = ""; +}; + +if (document.readyState !== "loading") { + glossary_search().catch(console.error); +} else { + document.addEventListener("DOMContentLoaded", glossary_search); +} diff --git a/Doc/tools/static/rtd_switcher.js b/Doc/tools/static/rtd_switcher.js new file mode 100644 index 00000000..2bf01a00 --- /dev/null +++ b/Doc/tools/static/rtd_switcher.js @@ -0,0 +1,55 @@ + function onSwitch(event) { + const option = event.target.selectedIndex; + const item = event.target.options[option]; + window.location.href = item.dataset.url; + } + + document.addEventListener("readthedocs-addons-data-ready", function(event) { + const config = event.detail.data() + const versionSelect = ` + + `; + + // Prepend the current language to the options on the selector + let languages = config.projects.translations.concat(config.projects.current); + languages = languages.sort((a, b) => a.language.name.localeCompare(b.language.name)); + + const languageSelect = ` + + `; + + // Query all the placeholders because there are different ones for Desktop/Mobile + const versionPlaceholders = document.querySelectorAll(".version_switcher_placeholder"); + for (placeholder of versionPlaceholders) { + placeholder.innerHTML = versionSelect; + let selectElement = placeholder.querySelector("select"); + selectElement.addEventListener("change", onSwitch); + } + + const languagePlaceholders = document.querySelectorAll(".language_switcher_placeholder"); + for (placeholder of languagePlaceholders) { + placeholder.innerHTML = languageSelect; + let selectElement = placeholder.querySelector("select"); + selectElement.addEventListener("change", onSwitch); + } + }); diff --git a/Doc/tools/static/sidebar-wrap.css b/Doc/tools/static/sidebar-wrap.css new file mode 100644 index 00000000..0a80f516 --- /dev/null +++ b/Doc/tools/static/sidebar-wrap.css @@ -0,0 +1,6 @@ +div.sphinxsidebarwrapper { + overflow-x: scroll; +} +div.sphinxsidebarwrapper li code { + overflow-wrap: normal; +} diff --git a/Doc/tools/templates/download.html b/Doc/tools/templates/download.html index b5353d6f..45ec436f 100644 --- a/Doc/tools/templates/download.html +++ b/Doc/tools/templates/download.html @@ -1,64 +1,75 @@ {% extends "layout.html" %} -{% set title = 'Download' %} +{% set title = _('Download') %} {% if daily is defined %} - {% set dlbase = pathto('archives', 1) %} + {% set dl_base = pathto('archives', resource=True) %} + {% set dl_version = version %} {% else %} {# The link below returns HTTP 404 until the first related alpha release. This is expected; use daily documentation builds for CPython development. #} - {% set dlbase = 'https://docs.python.org/ftp/python/doc/' + release %} + {% set dl_base = 'https://www.python.org/ftp/python/doc/' + release %} + {% set dl_version = release %} {% endif %} {% block body %} -

Download Python {{ release }} Documentation

+

{% trans %}Download Python {{ dl_version }} Documentation{% endtrans %}

-{% if last_updated %}

Last updated on: {{ last_updated }}.

{% endif %} +{% if last_updated %}

{% trans %}Last updated on: {{ last_updated }}.{% endtrans %}

{% endif %} -

To download an archive containing all the documents for this version of -Python in one of various formats, follow one of links in this table.

+

{% trans %}To download an archive containing all the documents for this version of +Python in one of various formats, follow one of links in this table.{% endtrans %}

- - - - + + + + - - - + + + + - - - + + + + - - - + + + + - - + + + + + + + +
FormatPacked as .zipPacked as .tar.bz2
PDF (US-Letter paper size)Download (ca. 13 MiB)Download (ca. 13 MiB)
{% trans %}Format{% endtrans %}{% trans %}Packed as .zip{% endtrans %}{% trans %}Packed as .tar.bz2{% endtrans %}
PDF (A4 paper size)Download (ca. 13 MiB)Download (ca. 13 MiB)
{% trans %}PDF{% endtrans %}{% trans download_size="17" %}Download (ca. {{ download_size }} MiB){% endtrans %}{% trans download_size="17" %}Download (ca. {{ download_size }} MiB){% endtrans %}
HTMLDownload (ca. 9 MiB)Download (ca. 6 MiB)
{% trans %}HTML{% endtrans %}{% trans download_size="13" %}Download (ca. {{ download_size }} MiB){% endtrans %}{% trans download_size="8" %}Download (ca. {{ download_size }} MiB){% endtrans %}
Plain TextDownload (ca. 3 MiB)Download (ca. 2 MiB)
{% trans %}Plain text{% endtrans %}{% trans download_size="4" %}Download (ca. {{ download_size }} MiB){% endtrans %}{% trans download_size="3" %}Download (ca. {{ download_size }} MiB){% endtrans %}
EPUBDownload (ca. 5 MiB)
{% trans %}Texinfo{% endtrans %}{% trans download_size="9" %}Download (ca. {{ download_size }} MiB){% endtrans %}{% trans download_size="7" %}Download (ca. {{ download_size }} MiB){% endtrans %}
{% trans %}EPUB{% endtrans %}{% trans download_size="6" %}Download (ca. {{ download_size }} MiB){% endtrans %}
-

These archives contain all the content in the documentation.

+

{% trans %}These archives contain all the content in the documentation.{% endtrans %}

-

Unpacking

+

{% trans %}Unpacking{% endtrans %}

-

Unix users should download the .tar.bz2 archives; these are bzipped tar +

{% trans %}Unix users should download the .tar.bz2 archives; these are bzipped tar archives and can be handled in the usual way using tar and the bzip2 program. The Info-ZIP unzip program can be used to handle the ZIP archives if desired. The .tar.bz2 archives provide the -best compression and fastest download times.

+best compression and fastest download times.{% endtrans %}

-

Windows users can use the ZIP archives since those are customary on that -platform. These are created on Unix using the Info-ZIP zip program.

+

{% trans %}Windows users can use the ZIP archives since those are customary on that +platform. These are created on Unix using the Info-ZIP zip program.{% endtrans %}

-

Problems

+

{% trans %}Problems{% endtrans %}

-

If you have comments or suggestions for the Python documentation, please send -email to docs@python.org.

+

{% trans %}If you have comments or suggestions for the Python documentation, please send +email to docs@python.org.{% endtrans %}

{% endblock %} diff --git a/Doc/tools/templates/indexcontent.html b/Doc/tools/templates/indexcontent.html index 6f854e86..2686f48d 100644 --- a/Doc/tools/templates/indexcontent.html +++ b/Doc/tools/templates/indexcontent.html @@ -33,6 +33,8 @@

{{ docstitle|e }}

{% trans %}C API reference{% endtrans %}

+ @@ -57,7 +59,7 @@

{{ docstitle|e }}

- + diff --git a/Doc/tools/templates/layout.html b/Doc/tools/templates/layout.html index e9311478..b09fd21a 100644 --- a/Doc/tools/templates/layout.html +++ b/Doc/tools/templates/layout.html @@ -26,6 +26,9 @@ {% endblock %} {% block extrahead %} + {% if builder == "html" and enable_analytics %} + + {% endif %} {% if builder != "htmlhelp" %} {% if pagename == 'whatsnew/changelog' and not embedded %} @@ -43,90 +46,7 @@ {{ super() }} {%- if not embedded %} - - + + {%- endif %} {% endblock %} diff --git a/Doc/tools/templates/search.html b/Doc/tools/templates/search.html index 85297446..6ddac5f8 100644 --- a/Doc/tools/templates/search.html +++ b/Doc/tools/templates/search.html @@ -2,61 +2,16 @@ {% block extrahead %} {{ super() }} - + +{% endblock %} +{% block searchresults %} +
+ {# For glossary_search.js #} + +
{% endblock %} diff --git a/Doc/tutorial/classes.rst b/Doc/tutorial/classes.rst index 1b64741c..49256896 100644 --- a/Doc/tutorial/classes.rst +++ b/Doc/tutorial/classes.rst @@ -276,8 +276,8 @@ definition looked like this:: then ``MyClass.i`` and ``MyClass.f`` are valid attribute references, returning an integer and a function object, respectively. Class attributes can also be assigned to, so you can change the value of ``MyClass.i`` by assignment. -:attr:`!__doc__` is also a valid attribute, returning the docstring belonging to -the class: ``"A simple example class"``. +:attr:`~type.__doc__` is also a valid attribute, returning the docstring +belonging to the class: ``"A simple example class"``. Class *instantiation* uses function notation. Just pretend that the class object is a parameterless function that returns a new instance of the class. @@ -688,6 +688,11 @@ current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, as long as it occurs within the definition of a class. +.. seealso:: + + The :ref:`private name mangling specifications ` + for details and special cases. + Name mangling is helpful for letting subclasses override methods without breaking intraclass method calls. For example:: @@ -927,6 +932,6 @@ Examples:: .. [#] Except for one thing. Module objects have a secret read-only attribute called :attr:`~object.__dict__` which returns the dictionary used to implement the module's - namespace; the name :attr:`~object.__dict__` is an attribute but not a global name. + namespace; the name ``__dict__`` is an attribute but not a global name. Obviously, using this violates the abstraction of namespace implementation, and should be restricted to things like post-mortem debuggers. diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst index 77444f9c..8261bbdb 100644 --- a/Doc/tutorial/controlflow.rst +++ b/Doc/tutorial/controlflow.rst @@ -61,7 +61,7 @@ they appear in the sequence. For example (no pun intended): :: >>> # Measure some strings: - ... words = ['cat', 'window', 'defenestrate'] + >>> words = ['cat', 'window', 'defenestrate'] >>> for w in words: ... print(w, len(w)) ... @@ -160,21 +160,60 @@ arguments. In chapter :ref:`tut-structures`, we will discuss in more detail abo .. _tut-break: -:keyword:`!break` and :keyword:`!continue` Statements, and :keyword:`!else` Clauses on Loops -============================================================================================ +:keyword:`!break` and :keyword:`!continue` Statements +===================================================== The :keyword:`break` statement breaks out of the innermost enclosing -:keyword:`for` or :keyword:`while` loop. +:keyword:`for` or :keyword:`while` loop:: -A :keyword:`!for` or :keyword:`!while` loop can include an :keyword:`!else` clause. + >>> for n in range(2, 10): + ... for x in range(2, n): + ... if n % x == 0: + ... print(f"{n} equals {x} * {n//x}") + ... break + ... + 4 equals 2 * 2 + 6 equals 2 * 3 + 8 equals 2 * 4 + 9 equals 3 * 3 + +The :keyword:`continue` statement continues with the next +iteration of the loop:: + + >>> for num in range(2, 10): + ... if num % 2 == 0: + ... print(f"Found an even number {num}") + ... continue + ... print(f"Found an odd number {num}") + ... + Found an even number 2 + Found an odd number 3 + Found an even number 4 + Found an odd number 5 + Found an even number 6 + Found an odd number 7 + Found an even number 8 + Found an odd number 9 + +.. _tut-for-else: +.. _break-and-continue-statements-and-else-clauses-on-loops: + +:keyword:`!else` Clauses on Loops +================================= + +In a :keyword:`!for` or :keyword:`!while` loop the :keyword:`!break` statement +may be paired with an :keyword:`!else` clause. If the loop finishes without +executing the :keyword:`!break`, the :keyword:`!else` clause executes. In a :keyword:`for` loop, the :keyword:`!else` clause is executed -after the loop reaches its final iteration. +after the loop finishes its final iteration, that is, if no break occurred. In a :keyword:`while` loop, it's executed after the loop's condition becomes false. -In either kind of loop, the :keyword:`!else` clause is **not** executed -if the loop was terminated by a :keyword:`break`. +In either kind of loop, the :keyword:`!else` clause is **not** executed if the +loop was terminated by a :keyword:`break`. Of course, other ways of ending the +loop early, such as a :keyword:`return` or a raised exception, will also skip +execution of the :keyword:`else` clause. This is exemplified in the following :keyword:`!for` loop, which searches for prime numbers:: @@ -198,32 +237,19 @@ which searches for prime numbers:: 9 equals 3 * 3 (Yes, this is the correct code. Look closely: the ``else`` clause belongs to -the :keyword:`for` loop, **not** the :keyword:`if` statement.) +the ``for`` loop, **not** the ``if`` statement.) -When used with a loop, the ``else`` clause has more in common with the -``else`` clause of a :keyword:`try` statement than it does with that of -:keyword:`if` statements: a :keyword:`try` statement's ``else`` clause runs -when no exception occurs, and a loop's ``else`` clause runs when no ``break`` -occurs. For more on the :keyword:`!try` statement and exceptions, see -:ref:`tut-handling`. - -The :keyword:`continue` statement, also borrowed from C, continues with the next -iteration of the loop:: +One way to think of the else clause is to imagine it paired with the ``if`` +inside the loop. As the loop executes, it will run a sequence like +if/if/if/else. The ``if`` is inside the loop, encountered a number of times. If +the condition is ever true, a ``break`` will happen. If the condition is never +true, the ``else`` clause outside the loop will execute. - >>> for num in range(2, 10): - ... if num % 2 == 0: - ... print("Found an even number", num) - ... continue - ... print("Found an odd number", num) - ... - Found an even number 2 - Found an odd number 3 - Found an even number 4 - Found an odd number 5 - Found an even number 6 - Found an odd number 7 - Found an even number 8 - Found an odd number 9 +When used with a loop, the ``else`` clause has more in common with the ``else`` +clause of a :keyword:`try` statement than it does with that of ``if`` +statements: a ``try`` statement's ``else`` clause runs when no exception +occurs, and a loop's ``else`` clause runs when no ``break`` occurs. For more on +the ``try`` statement and exceptions, see :ref:`tut-handling`. .. _tut-pass: @@ -436,8 +462,8 @@ Defining Functions We can create a function that writes the Fibonacci series to an arbitrary boundary:: - >>> def fib(n): # write Fibonacci series up to n - ... """Print a Fibonacci series up to n.""" + >>> def fib(n): # write Fibonacci series less than n + ... """Print a Fibonacci series less than n.""" ... a, b = 0, 1 ... while a < n: ... print(a, end=' ') @@ -445,7 +471,7 @@ boundary:: ... print() ... >>> # Now call the function we just defined: - ... fib(2000) + >>> fib(2000) 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 .. index:: @@ -807,7 +833,7 @@ parameters as there is a ``/`` in the function definition:: File "", line 1, in TypeError: pos_only_arg() got some positional-only arguments passed as keyword arguments: 'arg' -The third function ``kwd_only_args`` only allows keyword arguments as indicated +The third function ``kwd_only_arg`` only allows keyword arguments as indicated by a ``*`` in the function definition:: >>> kwd_only_arg(3) diff --git a/Doc/tutorial/datastructures.rst b/Doc/tutorial/datastructures.rst index a1492298..263b0c2e 100644 --- a/Doc/tutorial/datastructures.rst +++ b/Doc/tutorial/datastructures.rst @@ -19,13 +19,13 @@ objects: .. method:: list.append(x) :noindex: - Add an item to the end of the list. Equivalent to ``a[len(a):] = [x]``. + Add an item to the end of the list. Similar to ``a[len(a):] = [x]``. .. method:: list.extend(iterable) :noindex: - Extend the list by appending all the items from the iterable. Equivalent to + Extend the list by appending all the items from the iterable. Similar to ``a[len(a):] = iterable``. @@ -56,7 +56,7 @@ objects: .. method:: list.clear() :noindex: - Remove all items from the list. Equivalent to ``del a[:]``. + Remove all items from the list. Similar to ``del a[:]``. .. method:: list.index(x[, start[, end]]) @@ -93,7 +93,7 @@ objects: .. method:: list.copy() :noindex: - Return a shallow copy of the list. Equivalent to ``a[:]``. + Return a shallow copy of the list. Similar to ``a[:]``. An example that uses most of the list methods:: @@ -142,8 +142,8 @@ Using Lists as Stacks The list methods make it very easy to use a list as a stack, where the last element added is the first element retrieved ("last-in, first-out"). To add an -item to the top of the stack, use :meth:`~list.append`. To retrieve an item from the -top of the stack, use :meth:`~list.pop` without an explicit index. For example:: +item to the top of the stack, use :meth:`!~list.append`. To retrieve an item from the +top of the stack, use :meth:`!~list.pop` without an explicit index. For example:: >>> stack = [3, 4, 5] >>> stack.append(6) @@ -340,7 +340,7 @@ The :keyword:`!del` statement ============================= There is a way to remove an item from a list given its index instead of its -value: the :keyword:`del` statement. This differs from the :meth:`~list.pop` method +value: the :keyword:`del` statement. This differs from the :meth:`!~list.pop` method which returns a value. The :keyword:`!del` statement can also be used to remove slices from a list or clear the entire list (which we did earlier by assignment of an empty list to the slice). For example:: @@ -383,16 +383,16 @@ A tuple consists of a number of values separated by commas, for instance:: >>> t (12345, 54321, 'hello!') >>> # Tuples may be nested: - ... u = t, (1, 2, 3, 4, 5) + >>> u = t, (1, 2, 3, 4, 5) >>> u ((12345, 54321, 'hello!'), (1, 2, 3, 4, 5)) >>> # Tuples are immutable: - ... t[0] = 88888 + >>> t[0] = 88888 Traceback (most recent call last): File "", line 1, in TypeError: 'tuple' object does not support item assignment >>> # but they can contain mutable objects: - ... v = ([1, 2, 3], [3, 2, 1]) + >>> v = ([1, 2, 3], [3, 2, 1]) >>> v ([1, 2, 3], [3, 2, 1]) @@ -465,7 +465,7 @@ Here is a brief demonstration:: False >>> # Demonstrate set operations on unique letters from two words - ... + >>> >>> a = set('abracadabra') >>> b = set('alacazam') >>> a # unique letters in a @@ -500,8 +500,8 @@ any immutable type; strings and numbers can always be keys. Tuples can be used as keys if they contain only strings, numbers, or tuples; if a tuple contains any mutable object either directly or indirectly, it cannot be used as a key. You can't use lists as keys, since lists can be modified in place using index -assignments, slice assignments, or methods like :meth:`~list.append` and -:meth:`~list.extend`. +assignments, slice assignments, or methods like :meth:`!~list.append` and +:meth:`!~list.extend`. It is best to think of a dictionary as a set of *key: value* pairs, with the requirement that the keys are unique (within one dictionary). A pair of diff --git a/Doc/tutorial/errors.rst b/Doc/tutorial/errors.rst index 981b14f5..247b2f64 100644 --- a/Doc/tutorial/errors.rst +++ b/Doc/tutorial/errors.rst @@ -23,7 +23,7 @@ complaint you get while you are still learning Python:: ^^^^^ SyntaxError: invalid syntax -The parser repeats the offending line and displays little 'arrow's pointing +The parser repeats the offending line and displays little arrows pointing at the token in the line where the error was detected. The error may be caused by the absence of a token *before* the indicated token. In the example, the error is detected at the function :func:`print`, since a colon diff --git a/Doc/tutorial/floatingpoint.rst b/Doc/tutorial/floatingpoint.rst index 0795e2fe..dfe2d1d3 100644 --- a/Doc/tutorial/floatingpoint.rst +++ b/Doc/tutorial/floatingpoint.rst @@ -6,7 +6,7 @@ .. _tut-fp-issues: ************************************************** -Floating Point Arithmetic: Issues and Limitations +Floating-Point Arithmetic: Issues and Limitations ************************************************** .. sectionauthor:: Tim Peters @@ -88,7 +88,7 @@ the one with 17 significant digits, ``0.10000000000000001``. Starting with Python 3.1, Python (on most systems) is now able to choose the shortest of these and simply display ``0.1``. -Note that this is in the very nature of binary floating-point: this is not a bug +Note that this is in the very nature of binary floating point: this is not a bug in Python, and it is not a bug in your code either. You'll see the same kind of thing in all languages that support your hardware's floating-point arithmetic (although some languages may not *display* the difference by default, or in all @@ -148,13 +148,13 @@ Binary floating-point arithmetic holds many surprises like this. The problem with "0.1" is explained in precise detail below, in the "Representation Error" section. See `Examples of Floating Point Problems `_ for -a pleasant summary of how binary floating-point works and the kinds of +a pleasant summary of how binary floating point works and the kinds of problems commonly encountered in practice. Also see `The Perils of Floating Point `_ for a more complete account of other common surprises. As that says near the end, "there are no easy answers." Still, don't be unduly -wary of floating-point! The errors in Python float operations are inherited +wary of floating point! The errors in Python float operations are inherited from the floating-point hardware, and on most machines are on the order of no more than 1 part in 2\*\*53 per operation. That's more than adequate for most tasks, but you do need to keep in mind that it's not decimal arithmetic and @@ -230,7 +230,7 @@ accumulate to the point where they affect the final total: >>> sum([0.1] * 10) == 1.0 True -The :func:`math.fsum()` goes further and tracks all of the "lost digits" +The :func:`math.fsum` goes further and tracks all of the "lost digits" as values are added onto a running total so that the result has only a single rounding. This is slower than :func:`sum` but will be more accurate in uncommon cases where large magnitude inputs mostly cancel diff --git a/Doc/tutorial/inputoutput.rst b/Doc/tutorial/inputoutput.rst index 857068a5..35b8c7cd 100644 --- a/Doc/tutorial/inputoutput.rst +++ b/Doc/tutorial/inputoutput.rst @@ -87,12 +87,12 @@ Some examples:: >>> print(s) The value of x is 32.5, and y is 40000... >>> # The repr() of a string adds string quotes and backslashes: - ... hello = 'hello, world\n' + >>> hello = 'hello, world\n' >>> hellos = repr(hello) >>> print(hellos) 'hello, world\n' >>> # The argument to repr() may be any Python object: - ... repr((x, y, ('spam', 'eggs'))) + >>> repr((x, y, ('spam', 'eggs'))) "(32.5, 40000, ('spam', 'eggs'))" The :mod:`string` module contains a :class:`~string.Template` class that offers @@ -100,6 +100,13 @@ yet another way to substitute values into strings, using placeholders like ``$x`` and replacing them with values from a dictionary, but offers much less control of the formatting. +.. index:: + single: formatted string literal + single: interpolated string literal + single: string; formatted literal + single: string; interpolated literal + single: f-string + single: fstring .. _tut-f-strings: @@ -279,9 +286,11 @@ left with zeros. It understands about plus and minus signs:: Old string formatting --------------------- -The % operator (modulo) can also be used for string formatting. Given ``'string' -% values``, instances of ``%`` in ``string`` are replaced with zero or more -elements of ``values``. This operation is commonly known as string +The % operator (modulo) can also be used for string formatting. +Given ``format % values`` (where *format* is a string), +``%`` conversion specifications in *format* are replaced with +zero or more elements of *values*. +This operation is commonly known as string interpolation. For example:: >>> import math diff --git a/Doc/tutorial/introduction.rst b/Doc/tutorial/introduction.rst index 0f16dae8..65e3b193 100644 --- a/Doc/tutorial/introduction.rst +++ b/Doc/tutorial/introduction.rst @@ -62,7 +62,7 @@ For example:: 20 >>> (50 - 5*6) / 4 5.0 - >>> 8 / 5 # division always returns a floating point number + >>> 8 / 5 # division always returns a floating-point number 1.6 The integer numbers (e.g. ``2``, ``4``, ``20``) have type :class:`int`, @@ -197,21 +197,19 @@ and workarounds. String literals can span multiple lines. One way is using triple-quotes: ``"""..."""`` or ``'''...'''``. End of lines are automatically included in the string, but it's possible to prevent this by adding a ``\`` at -the end of the line. The following example:: - - print("""\ +the end of the line. In the following example, the initial newline is not +included:: + + >>> print("""\ + ... Usage: thingy [OPTIONS] + ... -h Display this usage message + ... -H hostname Hostname to connect to + ... """) Usage: thingy [OPTIONS] -h Display this usage message -H hostname Hostname to connect to - """) - -produces the following output (note that the initial newline is not included): -.. code-block:: text - - Usage: thingy [OPTIONS] - -h Display this usage message - -H hostname Hostname to connect to + >>> Strings can be concatenated (glued together) with the ``+`` operator, and repeated with ``*``:: @@ -501,8 +499,8 @@ together. For instance, we can write an initial sub-sequence of the as follows:: >>> # Fibonacci series: - ... # the sum of two elements defines the next - ... a, b = 0, 1 + >>> # the sum of two elements defines the next + >>> a, b = 0, 1 >>> while a < 10: ... print(a) ... a, b = b, a+b @@ -544,7 +542,7 @@ This example introduces several new features. * The :func:`print` function writes the value of the argument(s) it is given. It differs from just writing the expression you want to write (as we did earlier in the calculator examples) in the way it handles multiple arguments, - floating point quantities, and strings. Strings are printed without quotes, + floating-point quantities, and strings. Strings are printed without quotes, and a space is inserted between items, so you can format things nicely, like this:: diff --git a/Doc/tutorial/modules.rst b/Doc/tutorial/modules.rst index 0316239e..de7aa0e2 100644 --- a/Doc/tutorial/modules.rst +++ b/Doc/tutorial/modules.rst @@ -585,8 +585,9 @@ as the main module of a Python application must always use absolute imports. Packages in Multiple Directories -------------------------------- -Packages support one more special attribute, :attr:`__path__`. This is -initialized to be a list containing the name of the directory holding the +Packages support one more special attribute, :attr:`~module.__path__`. This is +initialized to be a :term:`sequence` of strings containing the name of the +directory holding the package's :file:`__init__.py` before the code in that file is executed. This variable can be modified; doing so affects future searches for modules and subpackages contained in the package. diff --git a/Doc/tutorial/stdlib.rst b/Doc/tutorial/stdlib.rst index 6bae279c..ca9dadb4 100644 --- a/Doc/tutorial/stdlib.rst +++ b/Doc/tutorial/stdlib.rst @@ -138,7 +138,7 @@ Mathematics =========== The :mod:`math` module gives access to the underlying C library functions for -floating point math:: +floating-point math:: >>> import math >>> math.cos(math.pi / 4) diff --git a/Doc/tutorial/stdlib2.rst b/Doc/tutorial/stdlib2.rst index 33f311db..b6d36365 100644 --- a/Doc/tutorial/stdlib2.rst +++ b/Doc/tutorial/stdlib2.rst @@ -293,7 +293,7 @@ Many data structure needs can be met with the built-in list type. However, sometimes there is a need for alternative implementations with different performance trade-offs. -The :mod:`array` module provides an :class:`~array.array()` object that is like +The :mod:`array` module provides an :class:`~array.array` object that is like a list that stores only homogeneous data and stores it more compactly. The following example shows an array of numbers stored as two byte unsigned binary numbers (typecode ``"H"``) rather than the usual 16 bytes per entry for regular @@ -306,7 +306,7 @@ lists of Python int objects:: >>> a[1:3] array('H', [10, 700]) -The :mod:`collections` module provides a :class:`~collections.deque()` object +The :mod:`collections` module provides a :class:`~collections.deque` object that is like a list with faster appends and pops from the left side but slower lookups in the middle. These objects are well suited for implementing queues and breadth first tree searches:: @@ -352,11 +352,11 @@ not want to run a full list sort:: .. _tut-decimal-fp: -Decimal Floating Point Arithmetic +Decimal Floating-Point Arithmetic ================================= The :mod:`decimal` module offers a :class:`~decimal.Decimal` datatype for -decimal floating point arithmetic. Compared to the built-in :class:`float` +decimal floating-point arithmetic. Compared to the built-in :class:`float` implementation of binary floating point, the class is especially helpful for * financial applications and other uses which require exact decimal diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index 82fbc82b..50f6eb8c 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -24,7 +24,7 @@ Command line When invoking Python, you may specify any of these options:: - python [-bBdEhiIOqsSuvVWx?] [-c command | -m module-name | script | - ] [args] + python [-bBdEhiIOPqRsSuvVWx?] [-c command | -m module-name | script | - ] [args] The most common use case is, of course, a simple invocation of a script:: @@ -440,6 +440,7 @@ Miscellaneous options -Wdefault # Warn once per call location -Werror # Convert to exceptions -Walways # Warn every time + -Wall # Same as -Walways -Wmodule # Warn once per calling module -Wonce # Warn once per Python process -Wignore # Never warn @@ -719,6 +720,11 @@ conflict. This variable can also be modified by Python code using :data:`os.environ` to force inspect mode on program termination. + .. audit-event:: cpython.run_stdin "" "" + + .. versionchanged:: 3.12.5 (also 3.11.10, 3.10.15, 3.9.20, and 3.8.20) + Emits audit events. + .. envvar:: PYTHONUNBUFFERED @@ -842,6 +848,7 @@ conflict. PYTHONWARNINGS=default # Warn once per call location PYTHONWARNINGS=error # Convert to exceptions PYTHONWARNINGS=always # Warn every time + PYTHONWARNINGS=all # Same as PYTHONWARNINGS=always PYTHONWARNINGS=module # Warn once per calling module PYTHONWARNINGS=once # Warn once per Python process PYTHONWARNINGS=ignore # Never warn @@ -943,7 +950,7 @@ conflict. 'surrogatepass' are used. This may also be enabled at runtime with - :func:`sys._enablelegacywindowsfsencoding()`. + :func:`sys._enablelegacywindowsfsencoding`. .. availability:: Windows. diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index 0e605b38..fed1d1e2 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -14,8 +14,8 @@ Features required to build CPython: `_ are not required. -* Support for `IEEE 754 `_ floating - point numbers and `floating point Not-a-Number (NaN) +* Support for `IEEE 754 `_ + floating-point numbers and `floating-point Not-a-Number (NaN) `_. * Support for threads. @@ -459,7 +459,7 @@ Debug options Effects: * Define the ``Py_TRACE_REFS`` macro. - * Add :func:`!sys.getobjects` function. + * Add :func:`sys.getobjects` function. * Add :envvar:`PYTHONDUMPREFS` environment variable. This build is not ABI compatible with release build (default build) or debug diff --git a/Doc/using/mac.rst b/Doc/using/mac.rst index 31d37aad..8b67652d 100644 --- a/Doc/using/mac.rst +++ b/Doc/using/mac.rst @@ -155,7 +155,7 @@ https://www.activestate.com; it can also be built from source. A number of alternative macOS GUI toolkits are available: * `PySide `__: Official Python bindings to the - `Qt GUI toolkit `__. + `Qt GUI toolkit `__. * `PyQt `__: Alternative Python bindings to Qt. diff --git a/Doc/using/unix.rst b/Doc/using/unix.rst index 58838c28..a2bcdab0 100644 --- a/Doc/using/unix.rst +++ b/Doc/using/unix.rst @@ -17,12 +17,12 @@ On Linux Python comes preinstalled on most Linux distributions, and is available as a package on all others. However there are certain features you might want to use -that are not available on your distro's package. You can easily compile the +that are not available on your distro's package. You can compile the latest version of Python from source. -In the event that Python doesn't come preinstalled and isn't in the repositories as -well, you can easily make packages for your own distro. Have a look at the -following links: +In the event that the latest version of Python doesn't come preinstalled and isn't +in the repositories as well, you can make packages for your own distro. Have a +look at the following links: .. seealso:: diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index 013374f2..2a507675 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -394,7 +394,7 @@ When writing to the Windows Registry, the following behaviors exist: For more detail on the technical basis for these limitations, please consult Microsoft's documentation on packaged full-trust apps, currently available at `docs.microsoft.com/en-us/windows/msix/desktop/desktop-to-uwp-behind-the-scenes -`_ +`_ .. _windows-nuget: @@ -475,7 +475,7 @@ dependents, such as Idle), pip and the Python documentation are not included. .. note:: The embedded distribution does not include the `Microsoft C Runtime - `_ and it is + `_ and it is the responsibility of the application installer to provide this. The runtime may have already been installed on a user's system previously or automatically via Windows Update, and can be detected by finding @@ -548,7 +548,7 @@ key features: Popular scientific modules (such as numpy, scipy and pandas) and the ``conda`` package manager. -`Enthought Deployment Manager `_ +`Enthought Deployment Manager `_ "The Next Generation Python Environment and Package Manager". Previously Enthought provided Canopy, but it `reached end of life in 2016 @@ -618,13 +618,13 @@ System variables, you need non-restricted access to your machine .. seealso:: - https://docs.microsoft.com/en-us/windows/win32/procthread/environment-variables + https://learn.microsoft.com/windows/win32/procthread/environment-variables Overview of environment variables on Windows - https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/set_1 + https://learn.microsoft.com/windows-server/administration/windows-commands/set_1 The ``set`` command, for temporarily modifying environment variables - https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/setx + https://learn.microsoft.com/windows-server/administration/windows-commands/setx The ``setx`` command, for permanently modifying environment variables @@ -1222,13 +1222,13 @@ is a collection of modules for advanced Windows-specific support. This includes utilities for: * `Component Object Model - `_ + `_ (COM) * Win32 API calls * Registry * Event log * `Microsoft Foundation Classes - `_ + `_ (MFC) user interfaces `PythonWin `_ + `Win32 How Do I...? `_ by Tim Golden `Python and COM `_ diff --git a/Doc/whatsnew/2.1.rst b/Doc/whatsnew/2.1.rst index b4002f06..f23f27c9 100644 --- a/Doc/whatsnew/2.1.rst +++ b/Doc/whatsnew/2.1.rst @@ -443,8 +443,8 @@ Python syntax:: f.grammar = "A ::= B (C D)*" The dictionary containing attributes can be accessed as the function's -:attr:`~object.__dict__`. Unlike the :attr:`~object.__dict__` attribute of class instances, in -functions you can actually assign a new dictionary to :attr:`~object.__dict__`, though +:attr:`~function.__dict__`. Unlike the :attr:`~type.__dict__` attribute of class instances, in +functions you can actually assign a new dictionary to :attr:`~function.__dict__`, though the new value is restricted to a regular Python dictionary; you *can't* be tricky and set it to a :class:`!UserDict` instance, or any other random object that behaves like a mapping. @@ -644,9 +644,9 @@ New and Improved Modules lists the function arguments and the local variables for each frame. * Various functions in the :mod:`time` module, such as :func:`~time.asctime` and - :func:`~time.localtime`, require a floating point argument containing the time in + :func:`~time.localtime`, require a floating-point argument containing the time in seconds since the epoch. The most common use of these functions is to work with - the current time, so the floating point argument has been made optional; when a + the current time, so the floating-point argument has been made optional; when a value isn't provided, the current time will be used. For example, log file entries usually need a string containing the current time; in Python 2.1, ``time.asctime()`` can be used, instead of the lengthier diff --git a/Doc/whatsnew/2.2.rst b/Doc/whatsnew/2.2.rst index d4dbe057..856be5ec 100644 --- a/Doc/whatsnew/2.2.rst +++ b/Doc/whatsnew/2.2.rst @@ -171,7 +171,7 @@ attributes of their own: * :attr:`~definition.__name__` is the attribute's name. -* :attr:`!__doc__` is the attribute's docstring. +* :attr:`~definition.__doc__` is the attribute's docstring. * ``__get__(object)`` is a method that retrieves the attribute value from *object*. @@ -186,7 +186,8 @@ are:: descriptor = obj.__class__.x descriptor.__get__(obj) -For methods, :meth:`!descriptor.__get__` returns a temporary object that's +For methods, :meth:`descriptor.__get__ ` returns a temporary +object that's callable, and wraps up the instance and the method to be called on it. This is also why static methods and class methods are now possible; they have descriptors that wrap up just the method, or the method and the class. As a @@ -1249,7 +1250,7 @@ Some of the more notable changes are: * The :func:`pow` built-in function no longer supports 3 arguments when floating-point numbers are supplied. ``pow(x, y, z)`` returns ``(x**y) % z``, - but this is never useful for floating point numbers, and the final result varies + but this is never useful for floating-point numbers, and the final result varies unpredictably depending on the platform. A call such as ``pow(2.0, 8.0, 7.0)`` will now raise a :exc:`TypeError` exception. diff --git a/Doc/whatsnew/2.3.rst b/Doc/whatsnew/2.3.rst index e2f1bbf7..93a36e74 100644 --- a/Doc/whatsnew/2.3.rst +++ b/Doc/whatsnew/2.3.rst @@ -1113,10 +1113,10 @@ Here are all of the changes that Python 2.3 makes to the core Python language. * One of the noted incompatibilities between old- and new-style classes has been - removed: you can now assign to the :attr:`~definition.__name__` and :attr:`~class.__bases__` + removed: you can now assign to the :attr:`~type.__name__` and :attr:`~type.__bases__` attributes of new-style classes. There are some restrictions on what can be - assigned to :attr:`~class.__bases__` along the lines of those relating to assigning to - an instance's :attr:`~instance.__class__` attribute. + assigned to :attr:`!__bases__` along the lines of those relating to assigning to + an instance's :attr:`~object.__class__` attribute. .. ====================================================================== @@ -1382,7 +1382,7 @@ complete list of changes, or look through the CVS logs for all the details. In Python 2.4, the default will change to always returning floats. Application developers should enable this feature only if all their libraries - work properly when confronted with floating point time stamps, or if they use + work properly when confronted with floating-point time stamps, or if they use the tuple API. If used, the feature should be activated on an application level instead of trying to enable it on a per-use basis. @@ -1925,8 +1925,8 @@ Changes to Python's build process and to the C API include: dependence on a system version or local installation of Expat. * If you dynamically allocate type objects in your extension, you should be - aware of a change in the rules relating to the :attr:`!__module__` and - :attr:`~definition.__name__` attributes. In summary, you will want to ensure the type's + aware of a change in the rules relating to the :attr:`~type.__module__` and + :attr:`~type.__name__` attributes. In summary, you will want to ensure the type's dictionary contains a ``'__module__'`` key; making the module name the part of the type name leading up to the final period will no longer have the desired effect. For more detail, read the API reference documentation or the source. diff --git a/Doc/whatsnew/2.4.rst b/Doc/whatsnew/2.4.rst index f085f5c6..909abfb2 100644 --- a/Doc/whatsnew/2.4.rst +++ b/Doc/whatsnew/2.4.rst @@ -684,11 +684,11 @@ includes a quick-start tutorial and a reference. Written by Facundo Batista and implemented by Facundo Batista, Eric Price, Raymond Hettinger, Aahz, and Tim Peters. - http://www.lahey.com/float.htm + `http://www.lahey.com/float.htm `__ The article uses Fortran code to illustrate many of the problems that floating-point inaccuracy can cause. - http://speleotrove.com/decimal/ + https://speleotrove.com/decimal/ A description of a decimal-based representation. This representation is being proposed as a standard, and underlies the new Python decimal type. Much of this material was written by Mike Cowlishaw, designer of the Rexx language. @@ -757,7 +757,7 @@ API that perform ASCII-only conversions, ignoring the locale setting: :c:expr:`double` to an ASCII string. The code for these functions came from the GLib library -(https://developer-old.gnome.org/glib/2.26/), whose developers kindly +(`https://developer-old.gnome.org/glib/2.26/ `__), whose developers kindly relicensed the relevant functions and donated them to the Python Software Foundation. The :mod:`locale` module can now change the numeric locale, letting extensions such as GTK+ produce the correct results. diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst index 6aa3e459..802c3a90 100644 --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -1724,7 +1724,7 @@ attribute of the function object to change this:: :mod:`ctypes` also provides a wrapper for Python's C API as the ``ctypes.pythonapi`` object. This object does *not* release the global interpreter lock before calling a function, because the lock must be held when -calling into the interpreter's code. There's a :class:`py_object()` type +calling into the interpreter's code. There's a :class:`~ctypes.py_object` type constructor that will create a :c:expr:`PyObject *` pointer. A simple usage:: import ctypes @@ -1734,7 +1734,7 @@ constructor that will create a :c:expr:`PyObject *` pointer. A simple usage:: ctypes.py_object("abc"), ctypes.py_object(1)) # d is now {'abc', 1}. -Don't forget to use :class:`py_object()`; if it's omitted you end up with a +Don't forget to use :func:`~ctypes.py_object`; if it's omitted you end up with a segmentation fault. :mod:`ctypes` has been around for a while, but people still write and diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index d2a82d5c..e04684b9 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -502,12 +502,12 @@ Python's :option:`-m` switch allows running a module as a script. When you ran a module that was located inside a package, relative imports didn't work correctly. -The fix for Python 2.6 adds a :attr:`__package__` attribute to -modules. When this attribute is present, relative imports will be +The fix for Python 2.6 adds a :attr:`module.__package__` attribute. +When this attribute is present, relative imports will be relative to the value of this attribute instead of the -:attr:`__name__` attribute. +:attr:`~module.__name__` attribute. -PEP 302-style importers can then set :attr:`__package__` as necessary. +PEP 302-style importers can then set :attr:`~module.__package__` as necessary. The :mod:`runpy` module that implements the :option:`-m` switch now does this, so relative imports will now work correctly in scripts running from inside a package. @@ -1453,7 +1453,7 @@ that will be the numerator and denominator of the resulting fraction. :: Fraction(5, 3) For converting floating-point numbers to rationals, -the float type now has an :meth:`as_integer_ratio()` method that returns +the float type now has an :meth:`as_integer_ratio` method that returns the numerator and denominator for a fraction that evaluates to the same floating-point value:: @@ -2273,7 +2273,7 @@ changes, or look through the Subversion logs for all the details. (Contributed by Guido van Rossum from work for Google App Engine; :issue:`3487`.) -* The :mod:`rlcompleter` module's :meth:`Completer.complete()` method +* The :mod:`rlcompleter` module's :meth:`Completer.complete` method will now ignore exceptions triggered while evaluating a name. (Fixed by Lorenz Quack; :issue:`2250`.) @@ -2566,7 +2566,7 @@ changes, or look through the Subversion logs for all the details. :meth:`tracer`, and :meth:`speed` methods. * The ability to set new shapes for the turtle, and to define a new coordinate system. - * Turtles now have an :meth:`undo()` method that can roll back actions. + * Turtles now have an :meth:`undo` method that can roll back actions. * Simple support for reacting to input events such as mouse and keyboard activity, making it possible to write simple games. * A :file:`turtle.cfg` file can be used to customize the starting appearance @@ -3051,7 +3051,7 @@ Changes to Python's build process and to the C API include: * Several functions return information about the platform's floating-point support. :c:func:`PyFloat_GetMax` returns - the maximum representable floating point value, + the maximum representable floating-point value, and :c:func:`PyFloat_GetMin` returns the minimum positive value. :c:func:`PyFloat_GetInfo` returns an object containing more information from the :file:`float.h` file, such as diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst index 585c704a..1231bd76 100644 --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -291,7 +291,7 @@ modules. configuration files can now be read, modified, and then written back in their original order. -* The :meth:`~collections.somenamedtuple._asdict()` method for +* The :meth:`~collections.somenamedtuple._asdict` method for :func:`collections.namedtuple` now returns an ordered dictionary with the values appearing in the same order as the underlying tuple indices. @@ -1198,7 +1198,7 @@ changes, or look through the Subversion logs for all the details. of the operands. Previously such comparisons would fall back to Python's default rules for comparing objects, which produced arbitrary results based on their type. Note that you still cannot combine - :class:`!Decimal` and floating-point in other operations such as addition, + :class:`!Decimal` and floating point in other operations such as addition, since you should be explicitly choosing how to convert between float and :class:`!Decimal`. (Fixed by Mark Dickinson; :issue:`2531`.) @@ -1548,7 +1548,7 @@ changes, or look through the Subversion logs for all the details. *ciphers* argument that's a string listing the encryption algorithms to be allowed; the format of the string is described `in the OpenSSL documentation - `__. + `__. (Added by Antoine Pitrou; :issue:`8322`.) Another change makes the extension load all of OpenSSL's ciphers and @@ -2680,14 +2680,12 @@ automatic ``PATH`` modifications to have ``pip`` available from the command line by default, otherwise it can still be accessed through the Python launcher for Windows as ``py -m pip``. -As `discussed in the PEP`__, platform packagers may choose not to install +As :pep:`discussed in the PEP <0477#disabling-ensurepip-by-downstream-distributors>`, +platform packagers may choose not to install these commands by default, as long as, when invoked, they provide clear and simple directions on how to install them on that platform (usually using the system package manager). -__ https://peps.python.org/pep-0477/#disabling-ensurepip-by-downstream-distributors - - Documentation Changes ~~~~~~~~~~~~~~~~~~~~~ diff --git a/Doc/whatsnew/3.0.rst b/Doc/whatsnew/3.0.rst index 22e44671..766db5ec 100644 --- a/Doc/whatsnew/3.0.rst +++ b/Doc/whatsnew/3.0.rst @@ -357,8 +357,8 @@ New Syntax provides a standardized way of annotating a function's parameters and return value. There are no semantics attached to such annotations except that they can be introspected at runtime using - the :attr:`__annotations__` attribute. The intent is to encourage - experimentation through metaclasses, decorators or frameworks. + the :attr:`~object.__annotations__` attribute. The intent is to + encourage experimentation through metaclasses, decorators or frameworks. * :pep:`3102`: Keyword-only arguments. Named parameters occurring after ``*args`` in the parameter list *must* be specified using diff --git a/Doc/whatsnew/3.1.rst b/Doc/whatsnew/3.1.rst index 7ecc34ab..fd427421 100644 --- a/Doc/whatsnew/3.1.rst +++ b/Doc/whatsnew/3.1.rst @@ -205,9 +205,9 @@ Some smaller changes made to the core Python language are: (Contributed by Mark Dickinson; :issue:`4707`.) -* Python now uses David Gay's algorithm for finding the shortest floating - point representation that doesn't change its value. This should help - mitigate some of the confusion surrounding binary floating point +* Python now uses David Gay's algorithm for finding the shortest floating-point + representation that doesn't change its value. This should help + mitigate some of the confusion surrounding binary floating-point numbers. The significance is easily seen with a number like ``1.1`` which does not @@ -215,7 +215,7 @@ Some smaller changes made to the core Python language are: equivalent, an expression like ``float('1.1')`` evaluates to the nearest representable value which is ``0x1.199999999999ap+0`` in hex or ``1.100000000000000088817841970012523233890533447265625`` in decimal. That - nearest value was and still is used in subsequent floating point + nearest value was and still is used in subsequent floating-point calculations. What is new is how the number gets displayed. Formerly, Python used a @@ -224,7 +224,7 @@ Some smaller changes made to the core Python language are: using 17 digits was that it relied on IEEE-754 guarantees to assure that ``eval(repr(1.1))`` would round-trip exactly to its original value. The disadvantage is that many people found the output to be confusing (mistaking - intrinsic limitations of binary floating point representation as being a + intrinsic limitations of binary floating-point representation as being a problem with Python itself). The new algorithm for ``repr(1.1)`` is smarter and returns ``'1.1'``. @@ -236,8 +236,8 @@ Some smaller changes made to the core Python language are: it does not change the underlying values. So, it is still the case that ``1.1 + 2.2 != 3.3`` even though the representations may suggest otherwise. - The new algorithm depends on certain features in the underlying floating - point implementation. If the required features are not found, the old + The new algorithm depends on certain features in the underlying floating-point + implementation. If the required features are not found, the old algorithm will continue to be used. Also, the text pickle protocols assure cross-platform portability by using the old algorithm. @@ -550,7 +550,7 @@ Porting to Python 3.1 This section lists previously described changes and other bugfixes that may require changes to your code: -* The new floating point string representations can break existing doctests. +* The new floating-point string representations can break existing doctests. For example:: def e(): diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 30b39aad..9c647972 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -1233,7 +1233,7 @@ also now un-stringize stringized annotations. itertools --------- -Add :func:`itertools.pairwise()`. +Add :func:`itertools.pairwise`. (Contributed by Raymond Hettinger in :issue:`38200`.) linecache @@ -1245,14 +1245,14 @@ When a module does not define ``__loader__``, fall back to ``__spec__.loader``. os -- -Add :func:`os.cpu_count()` support for VxWorks RTOS. +Add :func:`os.cpu_count` support for VxWorks RTOS. (Contributed by Peixing Xin in :issue:`41440`.) Add a new function :func:`os.eventfd` and related helpers to wrap the ``eventfd2`` syscall on Linux. (Contributed by Christian Heimes in :issue:`41001`.) -Add :func:`os.splice()` that allows to move data between two file +Add :func:`os.splice` that allows to move data between two file descriptors without copying between kernel address space and user address space, where one of the file descriptors must refer to a pipe. (Contributed by Pablo Galindo in :issue:`41625`.) @@ -1292,7 +1292,7 @@ functions in the :mod:`os` module. platform -------- -Add :func:`platform.freedesktop_os_release()` to retrieve operation system +Add :func:`platform.freedesktop_os_release` to retrieve operation system identification from `freedesktop.org os-release `_ standard file. (Contributed by Christian Heimes in :issue:`28468`.) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 5e272478..84805f93 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -768,6 +768,21 @@ functools (Contributed by Yurii Karabas in :issue:`46014`.) +.. _whatsnew311-gzip: + +gzip +---- + +* The :func:`gzip.compress` function is now faster when used with the + **mtime=0** argument as it delegates the compression entirely to a single + :func:`zlib.compress` operation. There is one side effect of this change: The + gzip file header contains an "OS" byte in its header. That was traditionally + always set to a value of 255 representing "unknown" by the :mod:`gzip` + module. Now, when using :func:`~gzip.compress` with **mtime=0**, it may be + set to a different value by the underlying zlib C library Python was linked + against. + (See :gh:`112346` for details on the side effect.) + .. _whatsnew311-hashlib: hashlib @@ -2017,8 +2032,8 @@ Removed C APIs are :ref:`listed separately `. It was introduced in Python 3.4 but has been broken since Python 3.7. (Contributed by Inada Naoki in :issue:`23882`.) -* Removed the undocumented private :meth:`!float.__set_format__()` method, - previously known as :meth:`!float.__setformat__()` in Python 3.7. +* Removed the undocumented private :meth:`!float.__set_format__` method, + previously known as :meth:`!float.__setformat__` in Python 3.7. Its docstring said: "You probably don't want to use this function. It exists mainly to be used in Python's test suite." (Contributed by Victor Stinner in :issue:`46852`.) @@ -2123,7 +2138,7 @@ Build Changes :issue:`45440` and :issue:`46640`.) * Support for `IEEE 754 `_ - floating point numbers. + floating-point numbers. (Contributed by Victor Stinner in :issue:`46917`.) * The :c:macro:`!Py_NO_NAN` macro has been removed. diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 6ba04c62..ee347d20 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -59,7 +59,7 @@ Summary -- Release highlights .. This section singles out the most important changes in Python 3.12. Brevity is key. -Python 3.12 is the latest stable release of the Python programming language, +Python 3.12 is a stable release of the Python programming language, with a mix of changes to the language and the standard library. The library changes focus on cleaning up deprecated APIs, usability, and correctness. Of note, the :mod:`!distutils` package has been removed from the standard library. @@ -154,7 +154,7 @@ Important deprecations, removals or restrictions: reducing the size of every :class:`str` object by at least 8 bytes. * :pep:`632`: Remove the :mod:`!distutils` package. - See `the migration guide `_ + See :pep:`the migration guide <0632#migration-advice>` for advice replacing the APIs it provided. The third-party `Setuptools `__ package continues to provide :mod:`!distutils`, @@ -739,7 +739,7 @@ inspect itertools --------- -* Add :class:`itertools.batched()` for collecting into even-sized +* Add :func:`itertools.batched` for collecting into even-sized tuples where the last batch may be shorter than the rest. (Contributed by Raymond Hettinger in :gh:`98363`.) @@ -1265,7 +1265,7 @@ Deprecated We added the warning to raise awareness as issues encountered by code doing this are becoming more frequent. See the :func:`os.fork` documentation for more details along with `this discussion on fork being incompatible with threads - `_ for *why* we're now surfacing this + `_ for *why* we're now surfacing this longstanding platform compatibility problem to developers. When this warning appears due to usage of :mod:`multiprocessing` or @@ -1320,173 +1320,39 @@ Deprecated may be removed in a future version of Python. Use the single-arg versions of these functions instead. (Contributed by Ofey Chan in :gh:`89874`.) -* :exc:`DeprecationWarning` is now raised when ``__package__`` on a - module differs from ``__spec__.parent`` (previously it was - :exc:`ImportWarning`). +* :exc:`DeprecationWarning` is now raised when :attr:`~module.__package__` on a + module differs from + :attr:`__spec__.parent ` (previously + it was :exc:`ImportWarning`). (Contributed by Brett Cannon in :gh:`65961`.) -* Setting ``__package__`` or ``__cached__`` on a module is deprecated, - and will cease to be set or taken into consideration by the import system in Python 3.14. - (Contributed by Brett Cannon in :gh:`65961`.) +* Setting :attr:`~module.__package__` or :attr:`~module.__cached__` on a + module is deprecated, and will cease to be set or taken into consideration by + the import system in Python 3.14. (Contributed by Brett Cannon in :gh:`65961`.) * The bitwise inversion operator (``~``) on bool is deprecated. It will throw an - error in Python 3.14. Use ``not`` for logical negation of bools instead. + error in Python 3.16. Use ``not`` for logical negation of bools instead. In the rare case that you really need the bitwise inversion of the underlying ``int``, convert to int explicitly: ``~int(x)``. (Contributed by Tim Hoffmann in :gh:`103487`.) * Accessing :attr:`~codeobject.co_lnotab` on code objects was deprecated in Python 3.10 via :pep:`626`, - but it only got a proper :exc:`DeprecationWarning` in 3.12, - therefore it will be removed in 3.14. + but it only got a proper :exc:`DeprecationWarning` in 3.12. + May be removed in 3.15. (Contributed by Nikita Sobolev in :gh:`101866`.) -Pending Removal in Python 3.13 ------------------------------- - -The following modules and APIs have been deprecated in earlier Python releases, -and will be removed in Python 3.13. - -Modules (see :pep:`594`): - -* :mod:`aifc` -* :mod:`audioop` -* :mod:`cgi` -* :mod:`cgitb` -* :mod:`chunk` -* :mod:`crypt` -* :mod:`imghdr` -* :mod:`mailcap` -* :mod:`msilib` -* :mod:`nis` -* :mod:`nntplib` -* :mod:`ossaudiodev` -* :mod:`pipes` -* :mod:`sndhdr` -* :mod:`spwd` -* :mod:`sunau` -* :mod:`telnetlib` -* :mod:`uu` -* :mod:`xdrlib` - -Other modules: - -* :mod:`!lib2to3`, and the :program:`2to3` program (:gh:`84540`) - -APIs: - -* :class:`!configparser.LegacyInterpolation` (:gh:`90765`) -* ``locale.resetlocale()`` (:gh:`90817`) -* :meth:`!turtle.RawTurtle.settiltangle` (:gh:`50096`) -* :func:`!unittest.findTestCases` (:gh:`50096`) -* :func:`!unittest.getTestCaseNames` (:gh:`50096`) -* :func:`!unittest.makeSuite` (:gh:`50096`) -* :meth:`!unittest.TestProgram.usageExit` (:gh:`67048`) -* :class:`!webbrowser.MacOSX` (:gh:`86421`) -* :class:`classmethod` descriptor chaining (:gh:`89519`) -* :mod:`importlib.resources` deprecated methods: - - * ``contents()`` - * ``is_resource()`` - * ``open_binary()`` - * ``open_text()`` - * ``path()`` - * ``read_binary()`` - * ``read_text()`` - - Use :func:`importlib.resources.files()` instead. Refer to `importlib-resources: Migrating from Legacy - `_ (:gh:`106531`) - -Pending Removal in Python 3.14 ------------------------------- - -The following APIs have been deprecated -and will be removed in Python 3.14. - -* :mod:`argparse`: The *type*, *choices*, and *metavar* parameters - of :class:`!argparse.BooleanOptionalAction` - -* :mod:`ast`: - - * :class:`!ast.Num` - * :class:`!ast.Str` - * :class:`!ast.Bytes` - * :class:`!ast.NameConstant` - * :class:`!ast.Ellipsis` - -* :mod:`asyncio`: - - * :class:`!asyncio.MultiLoopChildWatcher` - * :class:`!asyncio.FastChildWatcher` - * :class:`!asyncio.AbstractChildWatcher` - * :class:`!asyncio.SafeChildWatcher` - * :func:`!asyncio.set_child_watcher` - * :func:`!asyncio.get_child_watcher`, - * :meth:`!asyncio.AbstractEventLoopPolicy.set_child_watcher` - * :meth:`!asyncio.AbstractEventLoopPolicy.get_child_watcher` - -* :mod:`collections.abc`: :class:`!collections.abc.ByteString`. - -* :mod:`email`: the *isdst* parameter in :func:`email.utils.localtime`. - -* :mod:`importlib.abc`: - - * :class:`!importlib.abc.ResourceReader` - * :class:`!importlib.abc.Traversable` - * :class:`!importlib.abc.TraversableResources` - -* :mod:`itertools`: Support for copy, deepcopy, and pickle operations. - -* :mod:`pkgutil`: - - * :func:`!pkgutil.find_loader` - * :func:`!pkgutil.get_loader`. - -* :mod:`pty`: - - * :func:`!pty.master_open` - * :func:`!pty.slave_open` +.. include:: ../deprecations/pending-removal-in-3.13.rst -* :mod:`shutil`: The *onerror* argument of :func:`shutil.rmtree` - -* :mod:`typing`: :class:`!typing.ByteString` - -* :mod:`xml.etree.ElementTree`: Testing the truth value of an :class:`xml.etree.ElementTree.Element`. - -* The ``__package__`` and ``__cached__`` attributes on module objects. - -* The :attr:`~codeobject.co_lnotab` attribute of code objects. - -Pending Removal in Python 3.15 ------------------------------- +.. include:: ../deprecations/pending-removal-in-3.14.rst -The following APIs have been deprecated -and will be removed in Python 3.15. +.. include:: ../deprecations/pending-removal-in-3.15.rst -APIs: +.. include:: ../deprecations/pending-removal-in-3.16.rst -* :func:`locale.getdefaultlocale` (:gh:`90817`) - - -Pending Removal in Future Versions ----------------------------------- - -The following APIs were deprecated in earlier Python versions and will be removed, -although there is currently no date scheduled for their removal. - -* :mod:`array`'s ``'u'`` format code (:gh:`57281`) - -* :class:`typing.Text` (:gh:`92332`) - -* Currently Python accepts numeric literals immediately followed by keywords, - for example ``0in x``, ``1or x``, ``0if 1else 2``. It allows confusing - and ambiguous expressions like ``[0x1for x in y]`` (which can be - interpreted as ``[0x1 for x in y]`` or ``[0x1f or x in y]``). - A syntax warning is raised if the numeric literal is - immediately followed by one of keywords :keyword:`and`, :keyword:`else`, - :keyword:`for`, :keyword:`if`, :keyword:`in`, :keyword:`is` and :keyword:`or`. - In a future release it will be changed to a syntax error. (:gh:`87999`) +.. include:: ../deprecations/pending-removal-in-future.rst +.. _whatsnew312-removed: Removed ======= @@ -1513,6 +1379,8 @@ configparser * :class:`configparser.ConfigParser` no longer has a ``readfp`` method. Use :meth:`~configparser.ConfigParser.read_file` instead. +.. _whatsnew312-removed-distutils: + distutils --------- @@ -1570,9 +1438,9 @@ hashlib ------- * Remove the pure Python implementation of :mod:`hashlib`'s - :func:`hashlib.pbkdf2_hmac()`, deprecated in Python 3.10. Python 3.10 and + :func:`hashlib.pbkdf2_hmac`, deprecated in Python 3.10. Python 3.10 and newer requires OpenSSL 1.1.1 (:pep:`644`): this OpenSSL version provides - a C implementation of :func:`~hashlib.pbkdf2_hmac()` which is faster. + a C implementation of :func:`~hashlib.pbkdf2_hmac` which is faster. (Contributed by Victor Stinner in :gh:`94199`.) importlib @@ -1581,7 +1449,7 @@ importlib * Many previously deprecated cleanups in :mod:`importlib` have now been completed: - * References to, and support for :meth:`!module_repr()` has been removed. + * References to, and support for :meth:`!module_repr` has been removed. (Contributed by Barry Warsaw in :gh:`97850`.) * ``importlib.util.set_package``, ``importlib.util.set_loader`` and @@ -1594,6 +1462,8 @@ importlib * ``importlib.abc.Finder``, ``pkgutil.ImpImporter``, and ``pkgutil.ImpLoader`` have been removed. (Contributed by Barry Warsaw in :gh:`98040`.) +.. _whatsnew312-removed-imp: + imp --- @@ -2035,7 +1905,7 @@ New Features The :c:macro:`Py_TPFLAGS_MANAGED_DICT` and :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` flags have been added. This allows extensions classes to support object - ``__dict__`` and weakrefs with less bookkeeping, + :attr:`~object.__dict__` and weakrefs with less bookkeeping, using less memory and with faster access. * API for performing calls using @@ -2154,7 +2024,7 @@ Porting to Python 3.12 internal-only field directly. To get a list of subclasses, call the Python method - :py:meth:`~class.__subclasses__` (using :c:func:`PyObject_CallMethod`, + :py:meth:`~type.__subclasses__` (using :c:func:`PyObject_CallMethod`, for example). * Add support of more formatting options (left aligning, octals, uppercase @@ -2173,7 +2043,7 @@ Porting to Python 3.12 :c:func:`PyUnicode_FromFormatV`. (Contributed by Philip Georgi in :gh:`95504`.) -* Extension classes wanting to add a ``__dict__`` or weak reference slot +* Extension classes wanting to add a :attr:`~object.__dict__` or weak reference slot should use :c:macro:`Py_TPFLAGS_MANAGED_DICT` and :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` instead of ``tp_dictoffset`` and ``tp_weaklistoffset``, respectively. @@ -2358,92 +2228,13 @@ Deprecated overrides :c:member:`~PyTypeObject.tp_new` is deprecated. Call the metaclass instead. -Pending Removal in Python 3.14 -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. Add deprecations above alphabetically, not here at the end. -* The ``ma_version_tag`` field in :c:type:`PyDictObject` for extension modules - (:pep:`699`; :gh:`101193`). +.. include:: ../deprecations/c-api-pending-removal-in-3.14.rst -* Global configuration variables: +.. include:: ../deprecations/c-api-pending-removal-in-3.15.rst - * :c:var:`Py_DebugFlag`: use :c:member:`PyConfig.parser_debug` - * :c:var:`Py_VerboseFlag`: use :c:member:`PyConfig.verbose` - * :c:var:`Py_QuietFlag`: use :c:member:`PyConfig.quiet` - * :c:var:`Py_InteractiveFlag`: use :c:member:`PyConfig.interactive` - * :c:var:`Py_InspectFlag`: use :c:member:`PyConfig.inspect` - * :c:var:`Py_OptimizeFlag`: use :c:member:`PyConfig.optimization_level` - * :c:var:`Py_NoSiteFlag`: use :c:member:`PyConfig.site_import` - * :c:var:`Py_BytesWarningFlag`: use :c:member:`PyConfig.bytes_warning` - * :c:var:`Py_FrozenFlag`: use :c:member:`PyConfig.pathconfig_warnings` - * :c:var:`Py_IgnoreEnvironmentFlag`: use :c:member:`PyConfig.use_environment` - * :c:var:`Py_DontWriteBytecodeFlag`: use :c:member:`PyConfig.write_bytecode` - * :c:var:`Py_NoUserSiteDirectory`: use :c:member:`PyConfig.user_site_directory` - * :c:var:`Py_UnbufferedStdioFlag`: use :c:member:`PyConfig.buffered_stdio` - * :c:var:`Py_HashRandomizationFlag`: use :c:member:`PyConfig.use_hash_seed` - and :c:member:`PyConfig.hash_seed` - * :c:var:`Py_IsolatedFlag`: use :c:member:`PyConfig.isolated` - * :c:var:`Py_LegacyWindowsFSEncodingFlag`: use :c:member:`PyPreConfig.legacy_windows_fs_encoding` - * :c:var:`Py_LegacyWindowsStdioFlag`: use :c:member:`PyConfig.legacy_windows_stdio` - * :c:var:`!Py_FileSystemDefaultEncoding`: use :c:member:`PyConfig.filesystem_encoding` - * :c:var:`!Py_HasFileSystemDefaultEncoding`: use :c:member:`PyConfig.filesystem_encoding` - * :c:var:`!Py_FileSystemDefaultEncodeErrors`: use :c:member:`PyConfig.filesystem_errors` - * :c:var:`!Py_UTF8Mode`: use :c:member:`PyPreConfig.utf8_mode` (see :c:func:`Py_PreInitialize`) - - The :c:func:`Py_InitializeFromConfig` API should be used with - :c:type:`PyConfig` instead. - -* Creating :c:data:`immutable types ` with mutable - bases (:gh:`95388`). - -Pending Removal in Python 3.15 -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -* :c:func:`PyImport_ImportModuleNoBlock`: use :c:func:`PyImport_ImportModule` -* :c:type:`!Py_UNICODE_WIDE` type: use :c:type:`wchar_t` -* :c:type:`Py_UNICODE` type: use :c:type:`wchar_t` -* Python initialization functions: - - * :c:func:`PySys_ResetWarnOptions`: clear :data:`sys.warnoptions` and - :data:`!warnings.filters` - * :c:func:`Py_GetExecPrefix`: get :data:`sys.exec_prefix` - * :c:func:`Py_GetPath`: get :data:`sys.path` - * :c:func:`Py_GetPrefix`: get :data:`sys.prefix` - * :c:func:`Py_GetProgramFullPath`: get :data:`sys.executable` - * :c:func:`Py_GetProgramName`: get :data:`sys.executable` - * :c:func:`Py_GetPythonHome`: get :c:member:`PyConfig.home` or - the :envvar:`PYTHONHOME` environment variable - -Pending Removal in Future Versions -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The following APIs are deprecated and will be removed, -although there is currently no date scheduled for their removal. - -* :c:macro:`Py_TPFLAGS_HAVE_FINALIZE`: unneeded since Python 3.8 -* :c:func:`PyErr_Fetch`: use :c:func:`PyErr_GetRaisedException` -* :c:func:`PyErr_NormalizeException`: use :c:func:`PyErr_GetRaisedException` -* :c:func:`PyErr_Restore`: use :c:func:`PyErr_SetRaisedException` -* :c:func:`PyModule_GetFilename`: use :c:func:`PyModule_GetFilenameObject` -* :c:func:`PyOS_AfterFork`: use :c:func:`PyOS_AfterFork_Child` -* :c:func:`PySlice_GetIndicesEx`: use :c:func:`PySlice_Unpack` and :c:func:`PySlice_AdjustIndices` -* :c:func:`!PyUnicode_AsDecodedObject`: use :c:func:`PyCodec_Decode` -* :c:func:`!PyUnicode_AsDecodedUnicode`: use :c:func:`PyCodec_Decode` -* :c:func:`!PyUnicode_AsEncodedObject`: use :c:func:`PyCodec_Encode` -* :c:func:`!PyUnicode_AsEncodedUnicode`: use :c:func:`PyCodec_Encode` -* :c:func:`PyUnicode_READY`: unneeded since Python 3.12 -* :c:func:`!PyErr_Display`: use :c:func:`PyErr_DisplayException` -* :c:func:`!_PyErr_ChainExceptions`: use ``_PyErr_ChainExceptions1`` -* :c:member:`!PyBytesObject.ob_shash` member: - call :c:func:`PyObject_Hash` instead -* :c:member:`!PyDictObject.ma_version_tag` member -* Thread Local Storage (TLS) API: - - * :c:func:`PyThread_create_key`: use :c:func:`PyThread_tss_alloc` - * :c:func:`PyThread_delete_key`: use :c:func:`PyThread_tss_free` - * :c:func:`PyThread_set_key_value`: use :c:func:`PyThread_tss_set` - * :c:func:`PyThread_get_key_value`: use :c:func:`PyThread_tss_get` - * :c:func:`PyThread_delete_key_value`: use :c:func:`PyThread_tss_delete` - * :c:func:`PyThread_ReInitTLS`: unneeded since Python 3.7 +.. include:: ../deprecations/c-api-pending-removal-in-future.rst Removed ------- @@ -2476,3 +2267,48 @@ ipaddress * Fixed ``is_global`` and ``is_private`` behavior in ``IPv4Address``, ``IPv6Address``, ``IPv4Network`` and ``IPv6Network``. + + +Notable changes in 3.12.5 +========================= + +email +----- + + +* Headers with embedded newlines are now quoted on output. + + The :mod:`~email.generator` will now refuse to serialize (write) headers + that are improperly folded or delimited, such that they would be parsed as + multiple headers or joined with adjacent data. + If you need to turn this safety feature off, + set :attr:`~email.policy.Policy.verify_generated_headers`. + (Contributed by Bas Bloemsaat and Petr Viktorin in :gh:`121650`.) + + +Notable changes in 3.12.6 +========================= + +email +----- + +* :func:`email.utils.getaddresses` and :func:`email.utils.parseaddr` now return + ``('', '')`` 2-tuples in more situations where invalid email addresses are + encountered, instead of potentially inaccurate values. + An optional *strict* parameter was added to these two functions: + use ``strict=False`` to get the old behavior, accepting malformed inputs. + ``getattr(email.utils, 'supports_strict_parsing', False)`` can be used to + check if the *strict* paramater is available. + (Contributed by Thomas Dwyer and Victor Stinner for :gh:`102988` to improve + the CVE-2023-27043 fix.) + + +Notable changes in 3.12.8 +========================= + +sys +--- + +* The previously undocumented special function :func:`sys.getobjects`, + which only exists in specialized builds of Python, may now return objects + from other interpreters than the one it's called in. diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst index 1300b759..135ecda4 100644 --- a/Doc/whatsnew/3.2.rst +++ b/Doc/whatsnew/3.2.rst @@ -312,8 +312,8 @@ cluttering source directories, the *pyc* files are now collected in a Aside from the filenames and target directories, the new scheme has a few aspects that are visible to the programmer: -* Imported modules now have a :attr:`__cached__` attribute which stores the name - of the actual file that was imported: +* Imported modules now have a :attr:`~module.__cached__` attribute which stores + the name of the actual file that was imported: >>> import collections >>> collections.__cached__ # doctest: +SKIP @@ -531,7 +531,7 @@ Some smaller changes made to the core Python language are: (Proposed and implemented by Mark Dickinson; :issue:`9337`.) -* :class:`memoryview` objects now have a :meth:`~memoryview.release()` method +* :class:`memoryview` objects now have a :meth:`~memoryview.release` method and they also now support the context management protocol. This allows timely release of any resources that were acquired when requesting a buffer from the original object. @@ -1312,7 +1312,7 @@ An early decision to limit the interoperability of various numeric types has been relaxed. It is still unsupported (and ill-advised) to have implicit mixing in arithmetic expressions such as ``Decimal('1.1') + float('1.1')`` because the latter loses information in the process of constructing the binary -float. However, since existing floating point value can be converted losslessly +float. However, since existing floating-point value can be converted losslessly to either a decimal or rational representation, it makes sense to add them to the constructor and to support mixed-type comparisons. @@ -1325,7 +1325,7 @@ the constructor and to support mixed-type comparisons. and :class:`fractions.Fraction` (:issue:`2531` and :issue:`8188`). Similar changes were made to :class:`fractions.Fraction` so that the -:meth:`~fractions.Fraction.from_float()` and :meth:`~fractions.Fraction.from_decimal` +:meth:`~fractions.Fraction.from_float` and :meth:`~fractions.Fraction.from_decimal` methods are no longer needed (:issue:`8294`): >>> from decimal import Decimal @@ -1622,7 +1622,7 @@ socket The :mod:`socket` module has two new improvements. -* Socket objects now have a :meth:`~socket.socket.detach()` method which puts +* Socket objects now have a :meth:`~socket.socket.detach` method which puts the socket into closed state without actually closing the underlying file descriptor. The latter can then be reused for other purposes. (Added by Antoine Pitrou; :issue:`8524`.) @@ -1650,7 +1650,7 @@ for secure (encrypted, authenticated) internet connections: * The :func:`ssl.wrap_socket() ` constructor function now takes a *ciphers* argument. The *ciphers* string lists the allowed encryption algorithms using the format described in the `OpenSSL documentation - `__. + `__. * When linked against recent versions of OpenSSL, the :mod:`ssl` module now supports the Server Name Indication extension to the TLS protocol, allowing @@ -1859,11 +1859,11 @@ asyncore -------- :class:`!asyncore.dispatcher` now provides a -:meth:`!handle_accepted()` method +:meth:`!handle_accepted` method returning a ``(sock, addr)`` pair which is called when a connection has actually been established with a new remote endpoint. This is supposed to be used as a -replacement for old :meth:`!handle_accept()` and avoids -the user to call :meth:`!accept()` directly. +replacement for old :meth:`!handle_accept` and avoids +the user to call :meth:`!accept` directly. (Contributed by Giampaolo Rodolà; :issue:`6706`.) @@ -2321,7 +2321,7 @@ Multi-threading intervals and reduced overhead due to lock contention and the number of ensuing system calls. The notion of a "check interval" to allow thread switches has been abandoned and replaced by an absolute duration expressed in - seconds. This parameter is tunable through :func:`sys.setswitchinterval()`. + seconds. This parameter is tunable through :func:`sys.setswitchinterval`. It currently defaults to 5 milliseconds. Additional details about the implementation can be read from a `python-dev diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 0f810c17..92656090 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -549,9 +549,11 @@ separation of binary and text data). PEP 3155: Qualified name for classes and functions ================================================== -Functions and class objects have a new ``__qualname__`` attribute representing +Functions and class objects have a new :attr:`~definition.__qualname__` +attribute representing the "path" from the module top-level to their definition. For global functions -and classes, this is the same as ``__name__``. For other functions and classes, +and classes, this is the same as :attr:`~definition.__name__`. +For other functions and classes, it provides better information about where they were actually defined, and how they might be accessible from the global scope. @@ -779,8 +781,8 @@ Other Language Changes Some smaller changes made to the core Python language are: * Added support for Unicode name aliases and named sequences. - Both :func:`unicodedata.lookup()` and ``'\N{...}'`` now resolve name aliases, - and :func:`unicodedata.lookup()` resolves named sequences too. + Both :func:`unicodedata.lookup` and ``'\N{...}'`` now resolve name aliases, + and :func:`unicodedata.lookup` resolves named sequences too. (Contributed by Ezio Melotti in :issue:`12753`.) @@ -1097,12 +1099,12 @@ decimal C-module and libmpdec written by Stefan Krah. The new C version of the decimal module integrates the high speed libmpdec -library for arbitrary precision correctly rounded decimal floating point +library for arbitrary precision correctly rounded decimal floating-point arithmetic. libmpdec conforms to IBM's General Decimal Arithmetic Specification. Performance gains range from 10x for database applications to 100x for numerically intensive applications. These numbers are expected gains -for standard precisions used in decimal floating point arithmetic. Since +for standard precisions used in decimal floating-point arithmetic. Since the precision is user configurable, the exact figures may vary. For example, in integer bignum arithmetic the differences can be significantly higher. diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst index 33635c6d..6213915c 100644 --- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -215,13 +215,12 @@ automatic ``PATH`` modifications to have ``pip`` available from the command line by default, otherwise it can still be accessed through the Python launcher for Windows as ``py -m pip``. -As `discussed in the PEP`__, platform packagers may choose not to install +As :pep:`discussed in the PEP <0453#recommendations-for-downstream-distributors>` +platform packagers may choose not to install these commands by default, as long as, when invoked, they provide clear and simple directions on how to install them on that platform (usually using the system package manager). -__ https://peps.python.org/pep-0453/#recommendations-for-downstream-distributors - .. note:: To avoid conflicts between parallel Python 2 and Python 3 installations, @@ -1495,7 +1494,7 @@ The dictionary returned by :meth:`.SSLSocket.getpeercert` contains additional stat ---- -The :mod:`stat` module is now backed by a C implementation in :mod:`_stat`. A C +The :mod:`stat` module is now backed by a C implementation in :mod:`!_stat`. A C implementation is required as most of the values aren't standardized and are platform-dependent. (Contributed by Christian Heimes in :issue:`11016`.) @@ -1963,11 +1962,11 @@ Other Improvements `_ will build python, run the test suite, and generate an HTML coverage report for the C codebase using ``gcov`` and `lcov - `_. + `_. * The ``-R`` option to the :ref:`python regression test suite ` now also checks for memory allocation leaks, using - :func:`sys.getallocatedblocks()`. (Contributed by Antoine Pitrou in + :func:`sys.getallocatedblocks`. (Contributed by Antoine Pitrou in :issue:`13390`.) * ``python -m`` now works with namespace packages. @@ -1980,7 +1979,7 @@ Other Improvements now works correctly (previously it silently returned the first python module in the file). (Contributed by Václav Šmilauer in :issue:`16421`.) -* A new opcode, :opcode:`LOAD_CLASSDEREF`, has been added to fix a bug in the +* A new opcode, :opcode:`!LOAD_CLASSDEREF`, has been added to fix a bug in the loading of free variables in class bodies that could be triggered by certain uses of :ref:`__prepare__ `. (Contributed by Benjamin Peterson in :issue:`17853`.) @@ -2272,7 +2271,8 @@ Changes in the Python API :func:`super` and falling through all the way to the ABCs. For compatibility, catch both :exc:`NotImplementedError` or the appropriate exception as needed. -* The module type now initializes the :attr:`__package__` and :attr:`__loader__` +* The module type now initializes the :attr:`~module.__package__` and + :attr:`~module.__loader__` attributes to ``None`` by default. To determine if these attributes were set in a backwards-compatible fashion, use e.g. ``getattr(module, '__loader__', None) is not None``. (:issue:`17115`.) diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst index 06bcd354..b18fbb00 100644 --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -423,8 +423,8 @@ are declared in the annotations:: return 'Hello ' + name While these annotations are available at runtime through the usual -:attr:`__annotations__` attribute, *no automatic type checking happens at -runtime*. Instead, it is assumed that a separate off-line type checker +:attr:`~object.__annotations__` attribute, *no automatic type checking happens +at runtime*. Instead, it is assumed that a separate off-line type checker (e.g. `mypy `_) will be used for on-demand source code analysis. @@ -1667,7 +1667,7 @@ Both the :class:`!SMTPServer` and :class:`!SMTPChannel` classes now accept a *decode_data* keyword argument to determine if the ``DATA`` portion of the SMTP transaction is decoded using the ``"utf-8"`` codec or is instead provided to the -:meth:`!SMTPServer.process_message()` +:meth:`!SMTPServer.process_message` method as a byte string. The default is ``True`` for backward compatibility reasons, but will change to ``False`` in Python 3.6. If *decode_data* is set to ``False``, the ``process_message`` method must be prepared to accept keyword @@ -1677,14 +1677,14 @@ arguments. The :class:`!SMTPServer` class now advertises the ``8BITMIME`` extension (:rfc:`6152`) if *decode_data* has been set ``True``. If the client specifies ``BODY=8BITMIME`` on the ``MAIL`` command, it is passed to -:meth:`!SMTPServer.process_message()` +:meth:`!SMTPServer.process_message` via the *mail_options* keyword. (Contributed by Milan Oberkirch and R. David Murray in :issue:`21795`.) The :class:`!SMTPServer` class now also supports the ``SMTPUTF8`` extension (:rfc:`6531`: Internationalized Email). If the client specified ``SMTPUTF8 BODY=8BITMIME`` on the ``MAIL`` command, they are passed to -:meth:`!SMTPServer.process_message()` +:meth:`!SMTPServer.process_message` via the *mail_options* keyword. It is the responsibility of the ``process_message`` method to correctly handle the ``SMTPUTF8`` data. (Contributed by Milan Oberkirch in :issue:`21725`.) @@ -1935,8 +1935,8 @@ specifying the namespace in which the code will be running. tkinter ------- -The :mod:`tkinter._fix` module used for setting up the Tcl/Tk environment -on Windows has been replaced by a private function in the :mod:`_tkinter` +The :mod:`!tkinter._fix` module used for setting up the Tcl/Tk environment +on Windows has been replaced by a private function in the :mod:`!_tkinter` module which makes no permanent changes to environment variables. (Contributed by Zachary Ware in :issue:`20035`.) @@ -2405,7 +2405,7 @@ Changes in the Python API error-prone and has been removed in Python 3.5. See :issue:`13936` for full details. -* The :meth:`ssl.SSLSocket.send()` method now raises either +* The :meth:`ssl.SSLSocket.send` method now raises either :exc:`ssl.SSLWantReadError` or :exc:`ssl.SSLWantWriteError` on a non-blocking socket if the operation would block. Previously, it would return ``0``. (Contributed by Nikolaus Rath in :issue:`20951`.) @@ -2526,9 +2526,9 @@ Changes in the C API to format the :func:`repr` of the object. (Contributed by Serhiy Storchaka in :issue:`22453`.) -* Because the lack of the :attr:`__module__` attribute breaks pickling and +* Because the lack of the :attr:`~type.__module__` attribute breaks pickling and introspection, a deprecation warning is now raised for builtin types without - the :attr:`__module__` attribute. This would be an AttributeError in + the :attr:`~type.__module__` attribute. This will be an :exc:`AttributeError` in the future. (Contributed by Serhiy Storchaka in :issue:`20204`.) diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst index e91e6dc1..aa72cf4f 100644 --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -261,7 +261,7 @@ allowed. The :ref:`string formatting ` language also now has support for the ``'_'`` option to signal the use of an underscore for a thousands -separator for floating point presentation types and for integer +separator for floating-point presentation types and for integer presentation type ``'d'``. For integer presentation types ``'b'``, ``'o'``, ``'x'``, and ``'X'``, underscores will be inserted every 4 digits:: @@ -511,10 +511,10 @@ correct. Prior to Python 3.6, data loss could result when using bytes paths on Windows. With this change, using bytes to represent paths is now supported on Windows, provided those bytes are encoded with the encoding returned by -:func:`sys.getfilesystemencoding()`, which now defaults to ``'utf-8'``. +:func:`sys.getfilesystemencoding`, which now defaults to ``'utf-8'``. Applications that do not use str to represent paths should use -:func:`os.fsencode()` and :func:`os.fsdecode()` to ensure their bytes are +:func:`os.fsencode` and :func:`os.fsdecode` to ensure their bytes are correctly encoded. To revert to the previous behaviour, set :envvar:`PYTHONLEGACYWINDOWSFSENCODING` or call :func:`sys._enablelegacywindowsfsencoding`. @@ -549,7 +549,7 @@ PEP 520: Preserving Class Attribute Definition Order Attributes in a class definition body have a natural ordering: the same order in which the names appear in the source. This order is now -preserved in the new class's :attr:`~object.__dict__` attribute. +preserved in the new class's :attr:`~type.__dict__` attribute. Also, the effective default class *execution* namespace (returned from :ref:`type.__prepare__() `) is now an insertion-order-preserving @@ -780,7 +780,7 @@ for managing secrets, such as account authentication, tokens, and similar. Note that the pseudo-random generators in the :mod:`random` module should *NOT* be used for security purposes. Use :mod:`secrets` - on Python 3.6+ and :func:`os.urandom()` on Python 3.5 and earlier. + on Python 3.6+ and :func:`os.urandom` on Python 3.5 and earlier. .. seealso:: @@ -934,7 +934,7 @@ asynchronous generators. The :func:`~collections.namedtuple` function now accepts an optional keyword argument *module*, which, when specified, is used for -the ``__module__`` attribute of the returned named tuple class. +the :attr:`~type.__module__` attribute of the returned named tuple class. (Contributed by Raymond Hettinger in :issue:`17941`.) The *verbose* and *rename* arguments for @@ -1316,7 +1316,7 @@ Storchaka in :issue:`24164`.) pickletools ----------- -:func:`pickletools.dis()` now outputs the implicit memo index for the +:func:`pickletools.dis` now outputs the implicit memo index for the ``MEMOIZE`` opcode. (Contributed by Serhiy Storchaka in :issue:`25382`.) @@ -2377,16 +2377,16 @@ There have been several major changes to the :term:`bytecode` in Python 3.6. * The function call opcodes have been heavily reworked for better performance and simpler implementation. - The :opcode:`MAKE_FUNCTION`, :opcode:`CALL_FUNCTION`, - :opcode:`CALL_FUNCTION_KW` and :opcode:`BUILD_MAP_UNPACK_WITH_CALL` opcodes + The :opcode:`MAKE_FUNCTION`, :opcode:`!CALL_FUNCTION`, + :opcode:`!CALL_FUNCTION_KW` and :opcode:`!BUILD_MAP_UNPACK_WITH_CALL` opcodes have been modified, the new :opcode:`CALL_FUNCTION_EX` and - :opcode:`BUILD_TUPLE_UNPACK_WITH_CALL` have been added, and + :opcode:`!BUILD_TUPLE_UNPACK_WITH_CALL` have been added, and ``CALL_FUNCTION_VAR``, ``CALL_FUNCTION_VAR_KW`` and ``MAKE_CLOSURE`` opcodes have been removed. (Contributed by Demur Rumed in :issue:`27095`, and Serhiy Storchaka in :issue:`27213`, :issue:`28257`.) -* The new :opcode:`SETUP_ANNOTATIONS` and :opcode:`STORE_ANNOTATION` opcodes +* The new :opcode:`SETUP_ANNOTATIONS` and :opcode:`!STORE_ANNOTATION` opcodes have been added to support the new :term:`variable annotation` syntax. (Contributed by Ivan Levkivskyi in :issue:`27985`.) diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index 71831fc6..7e4b189d 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -339,7 +339,7 @@ PEP 564: New Time Functions With Nanosecond Resolution ------------------------------------------------------ The resolution of clocks in modern systems can exceed the limited precision -of a floating point number returned by the :func:`time.time` function +of a floating-point number returned by the :func:`time.time` function and its variants. To avoid loss of precision, :pep:`564` adds six new "nanosecond" variants of the existing timer functions to the :mod:`time` module: @@ -353,7 +353,7 @@ module: The new functions return the number of nanoseconds as an integer value. -`Measurements `_ +:pep:`Measurements <0564#annex-clocks-resolution-in-python>` show that on Linux and Windows the resolution of :func:`time.time_ns` is approximately 3 times better than that of :func:`time.time`. @@ -603,7 +603,7 @@ The new :mod:`importlib.resources` module provides several new APIs and one new ABC for access to, opening, and reading *resources* inside packages. Resources are roughly similar to files inside packages, but they needn't be actual files on the physical file system. Module loaders can provide a -:meth:`get_resource_reader()` function which returns +:meth:`get_resource_reader` function which returns a :class:`importlib.abc.ResourceReader` instance to support this new API. Built-in file path loaders and zip file loaders both support this. @@ -2017,11 +2017,11 @@ importlib --------- Methods -:meth:`!MetaPathFinder.find_module()` +:meth:`!MetaPathFinder.find_module` (replaced by :meth:`MetaPathFinder.find_spec() `) and -:meth:`!PathEntryFinder.find_loader()` +:meth:`!PathEntryFinder.find_loader` (replaced by :meth:`PathEntryFinder.find_spec() `) both deprecated in Python 3.4 now emit :exc:`DeprecationWarning`. @@ -2048,7 +2048,7 @@ The :mod:`macpath` is now deprecated and will be removed in Python 3.8. threading --------- -:mod:`dummy_threading` and :mod:`_dummy_thread` have been deprecated. It is +:mod:`!dummy_threading` and :mod:`!_dummy_thread` have been deprecated. It is no longer possible to build Python with threading disabled. Use :mod:`threading` instead. (Contributed by Antoine Pitrou in :issue:`31370`.) @@ -2184,7 +2184,7 @@ The following features and APIs have been removed from Python 3.7: ``socket.socketpair`` on Python 3.5 and newer. * :mod:`asyncio` no longer exports the :mod:`selectors` and - :mod:`_overlapped` modules as ``asyncio.selectors`` and + :mod:`!_overlapped` modules as ``asyncio.selectors`` and ``asyncio._overlapped``. Replace ``from asyncio import selectors`` with ``import selectors``. @@ -2366,7 +2366,7 @@ Changes in the Python API positions 2--3. To match only blank lines, the pattern should be rewritten as ``r'(?m)^[^\S\n]*$'``. - :func:`re.sub()` now replaces empty matches adjacent to a previous + :func:`re.sub` now replaces empty matches adjacent to a previous non-empty match. For example ``re.sub('x*', '-', 'abxd')`` returns now ``'-a-b--d-'`` instead of ``'-a-b-d-'`` (the first minus between 'b' and 'd' replaces 'x', and the second minus replaces an empty string between @@ -2425,7 +2425,7 @@ Changes in the Python API to :meth:`ArgumentParser.add_subparsers() `. (Contributed by Anthony Sottile in :issue:`26510`.) -* :meth:`ast.literal_eval()` is now stricter. Addition and subtraction of +* :meth:`ast.literal_eval` is now stricter. Addition and subtraction of arbitrary numbers are no longer allowed. (Contributed by Serhiy Storchaka in :issue:`31778`.) @@ -2476,10 +2476,10 @@ avoiding possible problems use new functions :c:func:`PySlice_Unpack` and CPython bytecode changes ------------------------ -There are two new opcodes: :opcode:`LOAD_METHOD` and :opcode:`CALL_METHOD`. +There are two new opcodes: :opcode:`LOAD_METHOD` and :opcode:`!CALL_METHOD`. (Contributed by Yury Selivanov and INADA Naoki in :issue:`26110`.) -The :opcode:`STORE_ANNOTATION` opcode has been removed. +The :opcode:`!STORE_ANNOTATION` opcode has been removed. (Contributed by Mark Shannon in :issue:`32550`.) diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index ae049a31..c1f3717b 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -936,7 +936,7 @@ Add option ``--json-lines`` to parse every input line as a separate JSON object. logging ------- -Added a *force* keyword argument to :func:`logging.basicConfig()` +Added a *force* keyword argument to :func:`logging.basicConfig`. When set to true, any existing handlers attached to the root logger are removed and closed before carrying out the configuration specified by the other arguments. @@ -1077,16 +1077,16 @@ pathlib ------- :mod:`pathlib.Path` methods that return a boolean result like -:meth:`~pathlib.Path.exists()`, :meth:`~pathlib.Path.is_dir()`, -:meth:`~pathlib.Path.is_file()`, :meth:`~pathlib.Path.is_mount()`, -:meth:`~pathlib.Path.is_symlink()`, :meth:`~pathlib.Path.is_block_device()`, -:meth:`~pathlib.Path.is_char_device()`, :meth:`~pathlib.Path.is_fifo()`, -:meth:`~pathlib.Path.is_socket()` now return ``False`` instead of raising +:meth:`~pathlib.Path.exists`, :meth:`~pathlib.Path.is_dir`, +:meth:`~pathlib.Path.is_file`, :meth:`~pathlib.Path.is_mount`, +:meth:`~pathlib.Path.is_symlink`, :meth:`~pathlib.Path.is_block_device`, +:meth:`~pathlib.Path.is_char_device`, :meth:`~pathlib.Path.is_fifo`, +:meth:`~pathlib.Path.is_socket` now return ``False`` instead of raising :exc:`ValueError` or its subclass :exc:`UnicodeEncodeError` for paths that contain characters unrepresentable at the OS level. (Contributed by Serhiy Storchaka in :issue:`33721`.) -Added :meth:`!pathlib.Path.link_to()` which creates a hard link pointing +Added :meth:`!pathlib.Path.link_to` which creates a hard link pointing to a path. (Contributed by Joannah Nanjekye in :issue:`26978`) Note that ``link_to`` was deprecated in 3.10 and removed in 3.12 in @@ -1170,13 +1170,13 @@ recursively removing their contents first. socket ------ -Added :meth:`~socket.create_server()` and :meth:`~socket.has_dualstack_ipv6()` +Added :meth:`~socket.create_server` and :meth:`~socket.has_dualstack_ipv6` convenience functions to automate the necessary tasks usually involved when creating a server socket, including accepting both IPv4 and IPv6 connections on the same socket. (Contributed by Giampaolo Rodolà in :issue:`17561`.) -The :func:`socket.if_nameindex()`, :func:`socket.if_nametoindex()`, and -:func:`socket.if_indextoname()` functions have been implemented on Windows. +The :func:`socket.if_nameindex`, :func:`socket.if_nametoindex`, and +:func:`socket.if_indextoname` functions have been implemented on Windows. (Contributed by Zackery Spytz in :issue:`37007`.) @@ -1192,11 +1192,11 @@ post-handshake authentication. statistics ---------- -Added :func:`statistics.fmean` as a faster, floating point variant of -:func:`statistics.mean()`. (Contributed by Raymond Hettinger and +Added :func:`statistics.fmean` as a faster, floating-point variant of +:func:`statistics.mean`. (Contributed by Raymond Hettinger and Steven D'Aprano in :issue:`35904`.) -Added :func:`statistics.geometric_mean()` +Added :func:`statistics.geometric_mean` (Contributed by Raymond Hettinger in :issue:`27181`.) Added :func:`statistics.multimode` that returns a list of the most @@ -1367,10 +1367,10 @@ Added :class:`~unittest.mock.AsyncMock` to support an asynchronous version of have been added as well. (Contributed by Lisa Roach in :issue:`26467`). -Added :func:`~unittest.addModuleCleanup()` and -:meth:`~unittest.TestCase.addClassCleanup()` to unittest to support -cleanups for :func:`~unittest.setUpModule()` and -:meth:`~unittest.TestCase.setUpClass()`. +Added :func:`~unittest.addModuleCleanup` and +:meth:`~unittest.TestCase.addClassCleanup` to unittest to support +cleanups for :func:`~unittest.setUpModule` and +:meth:`~unittest.TestCase.setUpClass`. (Contributed by Lisa Roach in :issue:`24412`.) Several mock assert functions now also print a list of actual calls upon @@ -1432,7 +1432,7 @@ and ``{namespace}*`` which returns all tags in the given namespace. (Contributed by Stefan Behnel in :issue:`28238`.) The :mod:`xml.etree.ElementTree` module provides a new function -:func:`–xml.etree.ElementTree.canonicalize()` that implements C14N 2.0. +:func:`–xml.etree.ElementTree.canonicalize` that implements C14N 2.0. (Contributed by Stefan Behnel in :issue:`13611`.) The target object of :class:`xml.etree.ElementTree.XMLParser` can @@ -1712,7 +1712,7 @@ Deprecated the ``l*gettext()`` functions. (Contributed by Serhiy Storchaka in :issue:`33710`.) -* The :meth:`~threading.Thread.isAlive()` method of :class:`threading.Thread` +* The :meth:`~threading.Thread.isAlive` method of :class:`threading.Thread` has been deprecated. (Contributed by Donghee Na in :issue:`35283`.) @@ -1755,7 +1755,7 @@ The following features and APIs have been removed from Python 3.8: * Starting with Python 3.3, importing ABCs from :mod:`collections` was deprecated, and importing should be done from :mod:`collections.abc`. Being able to import from collections was marked for removal in 3.8, but has been - delayed to 3.9. (See :issue:`36952`.) + delayed to 3.9. (See :gh:`81134`.) * The :mod:`macpath` module, deprecated in Python 3.7, has been removed. (Contributed by Victor Stinner in :issue:`35471`.) @@ -2152,11 +2152,11 @@ CPython bytecode changes cleaning-up code for :keyword:`break`, :keyword:`continue` and :keyword:`return`. - Removed opcodes :opcode:`BREAK_LOOP`, :opcode:`CONTINUE_LOOP`, - :opcode:`SETUP_LOOP` and :opcode:`SETUP_EXCEPT`. Added new opcodes - :opcode:`ROT_FOUR`, :opcode:`BEGIN_FINALLY`, :opcode:`CALL_FINALLY` and - :opcode:`POP_FINALLY`. Changed the behavior of :opcode:`END_FINALLY` - and :opcode:`WITH_CLEANUP_START`. + Removed opcodes :opcode:`!BREAK_LOOP`, :opcode:`!CONTINUE_LOOP`, + :opcode:`!SETUP_LOOP` and :opcode:`!SETUP_EXCEPT`. Added new opcodes + :opcode:`!ROT_FOUR`, :opcode:`!BEGIN_FINALLY`, :opcode:`!CALL_FINALLY` and + :opcode:`!POP_FINALLY`. Changed the behavior of :opcode:`!END_FINALLY` + and :opcode:`!WITH_CLEANUP_START`. (Contributed by Mark Shannon, Antoine Pitrou and Serhiy Storchaka in :issue:`17611`.) diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index f32224ae..48965c27 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -408,8 +408,8 @@ Added :func:`curses.get_escdelay`, :func:`curses.set_escdelay`, datetime -------- -The :meth:`~datetime.date.isocalendar()` of :class:`datetime.date` -and :meth:`~datetime.datetime.isocalendar()` of :class:`datetime.datetime` +The :meth:`~datetime.date.isocalendar` of :class:`datetime.date` +and :meth:`~datetime.datetime.isocalendar` of :class:`datetime.datetime` methods now returns a :func:`~collections.namedtuple` instead of a :class:`tuple`. (Contributed by Donghee Na in :issue:`24416`.) @@ -610,7 +610,7 @@ convert a wait status to an exit code. pathlib ------- -Added :meth:`pathlib.Path.readlink()` which acts similarly to +Added :meth:`pathlib.Path.readlink` which acts similarly to :func:`os.readlink`. (Contributed by Girts Folkmanis in :issue:`30618`) @@ -637,7 +637,8 @@ pydoc ----- The documentation string is now shown not only for class, function, -method etc, but for any object that has its own ``__doc__`` attribute. +method etc, but for any object that has its own :attr:`~definition.__doc__` +attribute. (Contributed by Serhiy Storchaka in :issue:`40257`.) random @@ -983,13 +984,13 @@ Removed (Contributed by Victor Stinner in :issue:`37312`.) * ``aifc.openfp()`` alias to ``aifc.open()``, ``sunau.openfp()`` alias to - ``sunau.open()``, and ``wave.openfp()`` alias to :func:`wave.open()` have been + ``sunau.open()``, and ``wave.openfp()`` alias to :func:`wave.open` have been removed. They were deprecated since Python 3.7. (Contributed by Victor Stinner in :issue:`37320`.) -* The :meth:`!isAlive()` method of :class:`threading.Thread` +* The :meth:`!isAlive` method of :class:`threading.Thread` has been removed. It was deprecated since Python 3.8. - Use :meth:`~threading.Thread.is_alive()` instead. + Use :meth:`~threading.Thread.is_alive` instead. (Contributed by Donghee Na in :issue:`37804`.) * Methods ``getchildren()`` and ``getiterator()`` of classes diff --git a/Include/floatobject.h b/Include/floatobject.h index 999441ac..8963c168 100644 --- a/Include/floatobject.h +++ b/Include/floatobject.h @@ -2,7 +2,7 @@ /* Float object interface */ /* -PyFloatObject represents a (double precision) floating point number. +PyFloatObject represents a (double precision) floating-point number. */ #ifndef Py_FLOATOBJECT_H diff --git a/Include/internal/pycore_dtoa.h b/Include/internal/pycore_dtoa.h index 4d9681d5..899d413b 100644 --- a/Include/internal/pycore_dtoa.h +++ b/Include/internal/pycore_dtoa.h @@ -11,8 +11,6 @@ extern "C" { #include "pycore_pymath.h" // _PY_SHORT_FLOAT_REPR -#if _PY_SHORT_FLOAT_REPR == 1 - typedef uint32_t ULong; struct @@ -22,15 +20,15 @@ Bigint { ULong x[1]; }; -#ifdef Py_USING_MEMORY_DEBUGGER +#if defined(Py_USING_MEMORY_DEBUGGER) || _PY_SHORT_FLOAT_REPR == 0 struct _dtoa_state { int _not_used; }; -#define _dtoa_interp_state_INIT(INTERP) \ +#define _dtoa_state_INIT(INTERP) \ {0} -#else // !Py_USING_MEMORY_DEBUGGER +#else // !Py_USING_MEMORY_DEBUGGER && _PY_SHORT_FLOAT_REPR != 0 /* The size of the Bigint freelist */ #define Bigint_Kmax 7 @@ -65,8 +63,6 @@ PyAPI_FUNC(char *) _Py_dg_dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve); PyAPI_FUNC(void) _Py_dg_freedtoa(char *s); -#endif // _PY_SHORT_FLOAT_REPR == 1 - #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index ad7d74c5..4d355b2b 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -200,7 +200,7 @@ _PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame); /* Gets the PyFrameObject for this frame, lazily * creating it if necessary. - * Returns a borrowed referennce */ + * Returns a borrowed reference */ static inline PyFrameObject * _PyFrame_GetFrameObject(_PyInterpreterFrame *frame) { @@ -213,9 +213,6 @@ _PyFrame_GetFrameObject(_PyInterpreterFrame *frame) return _PyFrame_MakeAndSetFrameObject(frame); } -void -_PyFrame_ClearLocals(_PyInterpreterFrame *frame); - /* Clears all references in the frame. * If take is non-zero, then the _PyInterpreterFrame frame * may be transferred to the frame object it references diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 909fe90b..75765254 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -550,21 +550,16 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(anon_setcomp)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(anon_string)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(anon_unknown)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(close_br)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(dbl_close_br)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(dbl_open_br)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(dbl_percent)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(defaults)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(dot)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(dot_locals)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(empty)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(generic_base)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(json_decoder)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(kwdefaults)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(list_err)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(newline)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(open_br)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(percent)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(shim_name)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(type_params)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(utf_8)); @@ -577,7 +572,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(TextIOWrapper)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(True)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(WarningMessage)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_WindowsConsoleIO)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__IOBase_closed)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__abc_tpflags__)); @@ -766,6 +760,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_lock_unlock_module)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_loop)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_needs_com_addref_)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_only_immortal)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_pack_)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_restype_)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_showwarnmsg)); @@ -777,7 +772,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_uninitialized_submodules)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_warn_unawaited_coroutine)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_xoptions)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(a)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(abs_tol)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(access)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(add)); @@ -797,7 +791,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(attribute)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(authorizer_callback)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(autocommit)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(b)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(backtick)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(base)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(before)); @@ -815,7 +808,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(byteorder)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(bytes)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(bytes_per_sep)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(c)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(c_call)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(c_exception)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(c_return)); @@ -868,7 +860,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(count)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(covariant)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cwd)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(d)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(data)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(database)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(decode)); @@ -896,7 +887,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(dst)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(dst_dir_fd)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(duration)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(e)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(eager_start)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(effective_ids)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(element_factory)); @@ -1057,7 +1047,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(mro)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(msg)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(mycmp)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(n)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(n_arg)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(n_fields)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(n_sequence_fields)); @@ -1102,7 +1091,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(outgoing)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(overlapped)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(owner)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(p)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(pages)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(parent)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(password)); @@ -1130,7 +1118,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ps2)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(query)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(quotetabs)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(r)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(raw)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(read)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(read1)); @@ -1154,7 +1141,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(return)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reverse)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reversed)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(s)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(salt)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(sched_priority)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(scheduler)); @@ -1257,7 +1243,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(writable)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(write)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(write_through)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(x)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(year)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(zdict)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(strings).ascii[0]); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 26c1be3b..4f5bfd98 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -36,21 +36,16 @@ struct _Py_global_strings { STRUCT_FOR_STR(anon_setcomp, "") STRUCT_FOR_STR(anon_string, "") STRUCT_FOR_STR(anon_unknown, "") - STRUCT_FOR_STR(close_br, "}") STRUCT_FOR_STR(dbl_close_br, "}}") STRUCT_FOR_STR(dbl_open_br, "{{") STRUCT_FOR_STR(dbl_percent, "%%") STRUCT_FOR_STR(defaults, ".defaults") - STRUCT_FOR_STR(dot, ".") STRUCT_FOR_STR(dot_locals, ".") STRUCT_FOR_STR(empty, "") STRUCT_FOR_STR(generic_base, ".generic_base") STRUCT_FOR_STR(json_decoder, "json.decoder") STRUCT_FOR_STR(kwdefaults, ".kwdefaults") STRUCT_FOR_STR(list_err, "list index out of range") - STRUCT_FOR_STR(newline, "\n") - STRUCT_FOR_STR(open_br, "{") - STRUCT_FOR_STR(percent, "%") STRUCT_FOR_STR(shim_name, "") STRUCT_FOR_STR(type_params, ".type_params") STRUCT_FOR_STR(utf_8, "utf-8") @@ -66,7 +61,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(TextIOWrapper) STRUCT_FOR_ID(True) STRUCT_FOR_ID(WarningMessage) - STRUCT_FOR_ID(_) STRUCT_FOR_ID(_WindowsConsoleIO) STRUCT_FOR_ID(__IOBase_closed) STRUCT_FOR_ID(__abc_tpflags__) @@ -255,6 +249,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(_lock_unlock_module) STRUCT_FOR_ID(_loop) STRUCT_FOR_ID(_needs_com_addref_) + STRUCT_FOR_ID(_only_immortal) STRUCT_FOR_ID(_pack_) STRUCT_FOR_ID(_restype_) STRUCT_FOR_ID(_showwarnmsg) @@ -266,7 +261,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(_uninitialized_submodules) STRUCT_FOR_ID(_warn_unawaited_coroutine) STRUCT_FOR_ID(_xoptions) - STRUCT_FOR_ID(a) STRUCT_FOR_ID(abs_tol) STRUCT_FOR_ID(access) STRUCT_FOR_ID(add) @@ -286,7 +280,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(attribute) STRUCT_FOR_ID(authorizer_callback) STRUCT_FOR_ID(autocommit) - STRUCT_FOR_ID(b) STRUCT_FOR_ID(backtick) STRUCT_FOR_ID(base) STRUCT_FOR_ID(before) @@ -304,7 +297,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(byteorder) STRUCT_FOR_ID(bytes) STRUCT_FOR_ID(bytes_per_sep) - STRUCT_FOR_ID(c) STRUCT_FOR_ID(c_call) STRUCT_FOR_ID(c_exception) STRUCT_FOR_ID(c_return) @@ -357,7 +349,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(count) STRUCT_FOR_ID(covariant) STRUCT_FOR_ID(cwd) - STRUCT_FOR_ID(d) STRUCT_FOR_ID(data) STRUCT_FOR_ID(database) STRUCT_FOR_ID(decode) @@ -385,7 +376,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(dst) STRUCT_FOR_ID(dst_dir_fd) STRUCT_FOR_ID(duration) - STRUCT_FOR_ID(e) STRUCT_FOR_ID(eager_start) STRUCT_FOR_ID(effective_ids) STRUCT_FOR_ID(element_factory) @@ -546,7 +536,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(mro) STRUCT_FOR_ID(msg) STRUCT_FOR_ID(mycmp) - STRUCT_FOR_ID(n) STRUCT_FOR_ID(n_arg) STRUCT_FOR_ID(n_fields) STRUCT_FOR_ID(n_sequence_fields) @@ -591,7 +580,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(outgoing) STRUCT_FOR_ID(overlapped) STRUCT_FOR_ID(owner) - STRUCT_FOR_ID(p) STRUCT_FOR_ID(pages) STRUCT_FOR_ID(parent) STRUCT_FOR_ID(password) @@ -619,7 +607,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(ps2) STRUCT_FOR_ID(query) STRUCT_FOR_ID(quotetabs) - STRUCT_FOR_ID(r) STRUCT_FOR_ID(raw) STRUCT_FOR_ID(read) STRUCT_FOR_ID(read1) @@ -643,7 +630,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(return) STRUCT_FOR_ID(reverse) STRUCT_FOR_ID(reversed) - STRUCT_FOR_ID(s) STRUCT_FOR_ID(salt) STRUCT_FOR_ID(sched_priority) STRUCT_FOR_ID(scheduler) @@ -746,7 +732,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(writable) STRUCT_FOR_ID(write) STRUCT_FOR_ID(write_through) - STRUCT_FOR_ID(x) STRUCT_FOR_ID(year) STRUCT_FOR_ID(zdict) } identifiers; @@ -769,6 +754,10 @@ struct _Py_global_strings { (_Py_SINGLETON(strings.identifiers._py_ ## NAME._ascii.ob_base)) #define _Py_STR(NAME) \ (_Py_SINGLETON(strings.literals._py_ ## NAME._ascii.ob_base)) +#define _Py_LATIN1_CHR(CH) \ + ((CH) < 128 \ + ? (PyObject*)&_Py_SINGLETON(strings).ascii[(CH)] \ + : (PyObject*)&_Py_SINGLETON(strings).latin1[(CH) - 128]) /* _Py_DECLARE_STR() should precede all uses of _Py_STR() in a function. diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 63e74a65..546f98d9 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -70,6 +70,13 @@ static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n) static inline void _Py_SetImmortal(PyObject *op) { +#ifdef Py_DEBUG + // For strings, use _PyUnicode_InternImmortal instead. + if (PyUnicode_CheckExact(op)) { + assert(PyUnicode_CHECK_INTERNED(op) == SSTATE_INTERNED_IMMORTAL + || PyUnicode_CHECK_INTERNED(op) == SSTATE_INTERNED_IMMORTAL_STATIC); + } +#endif if (op) { op->ob_refcnt = _Py_IMMORTAL_REFCNT; } diff --git a/Include/internal/pycore_object_state.h b/Include/internal/pycore_object_state.h index 65feb5af..6e07b1a0 100644 --- a/Include/internal/pycore_object_state.h +++ b/Include/internal/pycore_object_state.h @@ -24,7 +24,13 @@ struct _py_object_state { * together via the _ob_prev and _ob_next members of a PyObject, which * exist only in a Py_TRACE_REFS build. */ - PyObject refchain; + PyObject *refchain; + /* In most cases, refchain points to _refchain_obj. + * In sub-interpreters that share objmalloc state with the main interp, + * refchain points to the main interpreter's _refchain_obj, and their own + * _refchain_obj is unused. + */ + PyObject _refchain_obj; #endif int _not_used; }; diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index e5f9e17e..ad90ea68 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -132,15 +132,8 @@ extern PyTypeObject _PyExc_MemoryError; .context_ver = 1, \ } -#ifdef Py_TRACE_REFS -# define _py_object_state_INIT(INTERP) \ - { \ - .refchain = {&INTERP.object_state.refchain, &INTERP.object_state.refchain}, \ - } -#else # define _py_object_state_INIT(INTERP) \ { 0 } -#endif // global objects diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index dbfb633c..460a6c79 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -542,21 +542,16 @@ extern "C" { INIT_STR(anon_setcomp, ""), \ INIT_STR(anon_string, ""), \ INIT_STR(anon_unknown, ""), \ - INIT_STR(close_br, "}"), \ INIT_STR(dbl_close_br, "}}"), \ INIT_STR(dbl_open_br, "{{"), \ INIT_STR(dbl_percent, "%%"), \ INIT_STR(defaults, ".defaults"), \ - INIT_STR(dot, "."), \ INIT_STR(dot_locals, "."), \ INIT_STR(empty, ""), \ INIT_STR(generic_base, ".generic_base"), \ INIT_STR(json_decoder, "json.decoder"), \ INIT_STR(kwdefaults, ".kwdefaults"), \ INIT_STR(list_err, "list index out of range"), \ - INIT_STR(newline, "\n"), \ - INIT_STR(open_br, "{"), \ - INIT_STR(percent, "%"), \ INIT_STR(shim_name, ""), \ INIT_STR(type_params, ".type_params"), \ INIT_STR(utf_8, "utf-8"), \ @@ -572,7 +567,6 @@ extern "C" { INIT_ID(TextIOWrapper), \ INIT_ID(True), \ INIT_ID(WarningMessage), \ - INIT_ID(_), \ INIT_ID(_WindowsConsoleIO), \ INIT_ID(__IOBase_closed), \ INIT_ID(__abc_tpflags__), \ @@ -761,6 +755,7 @@ extern "C" { INIT_ID(_lock_unlock_module), \ INIT_ID(_loop), \ INIT_ID(_needs_com_addref_), \ + INIT_ID(_only_immortal), \ INIT_ID(_pack_), \ INIT_ID(_restype_), \ INIT_ID(_showwarnmsg), \ @@ -772,7 +767,6 @@ extern "C" { INIT_ID(_uninitialized_submodules), \ INIT_ID(_warn_unawaited_coroutine), \ INIT_ID(_xoptions), \ - INIT_ID(a), \ INIT_ID(abs_tol), \ INIT_ID(access), \ INIT_ID(add), \ @@ -792,7 +786,6 @@ extern "C" { INIT_ID(attribute), \ INIT_ID(authorizer_callback), \ INIT_ID(autocommit), \ - INIT_ID(b), \ INIT_ID(backtick), \ INIT_ID(base), \ INIT_ID(before), \ @@ -810,7 +803,6 @@ extern "C" { INIT_ID(byteorder), \ INIT_ID(bytes), \ INIT_ID(bytes_per_sep), \ - INIT_ID(c), \ INIT_ID(c_call), \ INIT_ID(c_exception), \ INIT_ID(c_return), \ @@ -863,7 +855,6 @@ extern "C" { INIT_ID(count), \ INIT_ID(covariant), \ INIT_ID(cwd), \ - INIT_ID(d), \ INIT_ID(data), \ INIT_ID(database), \ INIT_ID(decode), \ @@ -891,7 +882,6 @@ extern "C" { INIT_ID(dst), \ INIT_ID(dst_dir_fd), \ INIT_ID(duration), \ - INIT_ID(e), \ INIT_ID(eager_start), \ INIT_ID(effective_ids), \ INIT_ID(element_factory), \ @@ -1052,7 +1042,6 @@ extern "C" { INIT_ID(mro), \ INIT_ID(msg), \ INIT_ID(mycmp), \ - INIT_ID(n), \ INIT_ID(n_arg), \ INIT_ID(n_fields), \ INIT_ID(n_sequence_fields), \ @@ -1097,7 +1086,6 @@ extern "C" { INIT_ID(outgoing), \ INIT_ID(overlapped), \ INIT_ID(owner), \ - INIT_ID(p), \ INIT_ID(pages), \ INIT_ID(parent), \ INIT_ID(password), \ @@ -1125,7 +1113,6 @@ extern "C" { INIT_ID(ps2), \ INIT_ID(query), \ INIT_ID(quotetabs), \ - INIT_ID(r), \ INIT_ID(raw), \ INIT_ID(read), \ INIT_ID(read1), \ @@ -1149,7 +1136,6 @@ extern "C" { INIT_ID(return), \ INIT_ID(reverse), \ INIT_ID(reversed), \ - INIT_ID(s), \ INIT_ID(salt), \ INIT_ID(sched_priority), \ INIT_ID(scheduler), \ @@ -1252,7 +1238,6 @@ extern "C" { INIT_ID(writable), \ INIT_ID(write), \ INIT_ID(write_through), \ - INIT_ID(x), \ INIT_ID(year), \ INIT_ID(zdict), \ } diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 63f76fc5..4fdbc91a 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -143,6 +143,8 @@ PyAPI_DATA(PyTypeObject) _PyBufferWrapper_Type; PyObject * _PySuper_Lookup(PyTypeObject *su_type, PyObject *su_obj, PyObject *name, int *meth_found); +extern int _PyType_AddMethod(PyTypeObject *, PyMethodDef *); + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_unicodeobject.h b/Include/internal/pycore_unicodeobject.h index 1bb0f366..cecdabe4 100644 --- a/Include/internal/pycore_unicodeobject.h +++ b/Include/internal/pycore_unicodeobject.h @@ -13,17 +13,31 @@ extern "C" { void _PyUnicode_ExactDealloc(PyObject *op); Py_ssize_t _PyUnicode_InternedSize(void); +Py_ssize_t _PyUnicode_InternedSize_Immortal(void); /* runtime lifecycle */ extern void _PyUnicode_InitState(PyInterpreterState *); extern PyStatus _PyUnicode_InitGlobalObjects(PyInterpreterState *); +extern PyStatus _PyUnicode_InitInternDict(PyInterpreterState *); extern PyStatus _PyUnicode_InitTypes(PyInterpreterState *); extern void _PyUnicode_Fini(PyInterpreterState *); extern void _PyUnicode_FiniTypes(PyInterpreterState *); extern PyTypeObject _PyUnicodeASCIIIter_Type; +/* Interning */ + +// All these are "ref-neutral", like the public PyUnicode_InternInPlace. + +// Explicit interning routines: +PyAPI_FUNC(void) _PyUnicode_InternMortal(PyInterpreterState *interp, PyObject **); +PyAPI_FUNC(void) _PyUnicode_InternImmortal(PyInterpreterState *interp, PyObject **); +// Left here to help backporting: +PyAPI_FUNC(void) _PyUnicode_InternInPlace(PyInterpreterState *interp, PyObject **p); +// Only for statically allocated strings: +extern void _PyUnicode_InternStatic(PyInterpreterState *interp, PyObject **); + /* other API */ struct _Py_unicode_runtime_ids { @@ -60,9 +74,11 @@ struct _Py_unicode_state { struct _Py_unicode_ids ids; }; -extern void _PyUnicode_InternInPlace(PyInterpreterState *interp, PyObject **p); extern void _PyUnicode_ClearInterned(PyInterpreterState *interp); +// Like PyUnicode_AsUTF8(), but check for embedded null characters. +extern const char* _PyUnicode_AsUTF8NoNUL(PyObject *); + #ifdef __cplusplus } diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 9f9e23f5..90c61bcd 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -13,2081 +13,2817 @@ static inline void _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { PyObject *string; string = &_Py_ID(CANCELLED); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(FINISHED); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(False); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(JSONDecodeError); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(PENDING); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(Py_Repr); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(TextIOWrapper); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(True); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(WarningMessage); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); - string = &_Py_ID(_); - assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_WindowsConsoleIO); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__IOBase_closed); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__abc_tpflags__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__abs__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__abstractmethods__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__add__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__aenter__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__aexit__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__aiter__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__all__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__and__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__anext__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__annotations__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__args__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__asyncio_running_event_loop__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__await__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__bases__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__bool__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__buffer__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__build_class__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__builtins__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__bytes__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__call__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__cantrace__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__class__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__class_getitem__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__classcell__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__classdict__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__classdictcell__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__complex__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__contains__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__copy__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__ctypes_from_outparam__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__del__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__delattr__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__delete__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__delitem__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__dict__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__dictoffset__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__dir__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__divmod__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__doc__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__enter__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__eq__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__exit__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__file__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__float__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__floordiv__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__format__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__fspath__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__ge__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__get__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__getattr__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__getattribute__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__getinitargs__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__getitem__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__getnewargs__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__getnewargs_ex__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__getstate__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__gt__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__hash__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__iadd__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__iand__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__ifloordiv__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__ilshift__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__imatmul__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__imod__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__import__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__imul__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__index__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__init__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__init_subclass__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__instancecheck__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__int__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__invert__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__ior__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__ipow__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__irshift__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__isabstractmethod__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__isub__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__iter__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__itruediv__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__ixor__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__le__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__len__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__length_hint__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__lltrace__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__loader__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__lshift__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__lt__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__main__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__matmul__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__missing__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__mod__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__module__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__mro_entries__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__mul__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__name__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__ne__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__neg__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__new__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__newobj__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__newobj_ex__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__next__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__notes__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__or__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__orig_class__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__origin__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__package__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__parameters__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__path__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__pos__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__pow__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__prepare__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__qualname__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__radd__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__rand__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__rdivmod__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__reduce__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__reduce_ex__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__release_buffer__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__repr__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__reversed__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__rfloordiv__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__rlshift__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__rmatmul__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__rmod__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__rmul__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__ror__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__round__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__rpow__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__rrshift__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__rshift__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__rsub__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__rtruediv__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__rxor__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__set__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__set_name__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__setattr__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__setitem__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__setstate__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__sizeof__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__slotnames__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__slots__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__spec__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__str__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__sub__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__subclasscheck__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__subclasshook__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__truediv__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__trunc__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__type_params__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__typing_is_unpacked_typevartuple__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__typing_prepare_subst__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__typing_subst__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__typing_unpacked_tuple_args__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__warningregistry__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__weaklistoffset__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__weakref__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__xor__); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_abc_impl); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_abstract_); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_active); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_annotation); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_anonymous_); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_argtypes_); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_as_parameter_); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_asyncio_future_blocking); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_blksize); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_bootstrap); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_check_retval_); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_dealloc_warn); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_feature_version); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_fields_); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_finalizing); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_find_and_load); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_fix_up_module); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_flags_); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_get_sourcefile); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_handle_fromlist); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_initializing); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_io); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_is_text_encoding); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_length_); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_limbo); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_lock_unlock_module); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_loop); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_needs_com_addref_); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(_only_immortal); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_pack_); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_restype_); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_showwarnmsg); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_shutdown); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_slotnames); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_strptime_datetime); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_swappedbytes_); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_type_); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_uninitialized_submodules); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_warn_unawaited_coroutine); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_xoptions); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); - string = &_Py_ID(a); - assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(abs_tol); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(access); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(add); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(add_done_callback); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(after_in_child); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(after_in_parent); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(aggregate_class); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(alias); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(append); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(arg); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(argdefs); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(args); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(arguments); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(argv); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(as_integer_ratio); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(ast); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(attribute); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(authorizer_callback); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(autocommit); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); - string = &_Py_ID(b); - assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(backtick); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(base); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(before); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(big); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(binary_form); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(block); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(bound); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(buffer); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(buffer_callback); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(buffer_size); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(buffering); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(buffers); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(bufsize); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(builtins); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(byteorder); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(bytes); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(bytes_per_sep); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); - string = &_Py_ID(c); - assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(c_call); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(c_exception); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(c_return); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(cached_statements); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(cadata); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(cafile); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(call); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(call_exception_handler); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(call_soon); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(cancel); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(capath); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(category); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(cb_type); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(certfile); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(check_same_thread); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(clear); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(close); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(closed); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(closefd); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(closure); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(co_argcount); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(co_cellvars); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(co_code); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(co_consts); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(co_exceptiontable); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(co_filename); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(co_firstlineno); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(co_flags); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(co_freevars); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(co_kwonlyargcount); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(co_linetable); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(co_name); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(co_names); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(co_nlocals); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(co_posonlyargcount); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(co_qualname); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(co_stacksize); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(co_varnames); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(code); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(command); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(comment_factory); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(compile_mode); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(consts); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(context); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(contravariant); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(cookie); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(copy); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(copyreg); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(coro); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(count); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(covariant); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(cwd); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); - string = &_Py_ID(d); - assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(data); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(database); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(decode); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(decoder); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(default); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(defaultaction); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(delete); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(depth); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(detect_types); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(deterministic); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(device); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(dict); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(dictcomp); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(difference_update); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(digest); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(digest_size); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(digestmod); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(dir_fd); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(discard); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(dispatch_table); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(displayhook); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(dklen); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(doc); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(dont_inherit); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(dst); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(dst_dir_fd); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(duration); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); - string = &_Py_ID(e); - assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(eager_start); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(effective_ids); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(element_factory); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(encode); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(encoding); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(end); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(end_lineno); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(end_offset); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(endpos); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(entrypoint); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(env); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(errors); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(event); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(eventmask); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(exc_type); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(exc_value); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(excepthook); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(exception); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(existing_file_name); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(exp); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(extend); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(extra_tokens); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(facility); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(factory); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(false); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(family); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(fanout); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(fd); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(fd2); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(fdel); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(fget); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(file); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(file_actions); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(filename); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(fileno); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(filepath); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(fillvalue); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(filters); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(final); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(find_class); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(fix_imports); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(flags); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(flush); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(follow_symlinks); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(format); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(frequency); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(from_param); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(fromlist); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(fromtimestamp); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(fromutc); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(fset); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(func); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(future); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(generation); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(genexpr); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(get); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(get_debug); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(get_event_loop); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(get_loop); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(get_source); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(getattr); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(getstate); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(gid); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(globals); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(groupindex); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(groups); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(handle); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(hash_name); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(header); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(headers); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(hi); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(hook); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(id); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(ident); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(ignore); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(imag); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(importlib); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(in_fd); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(incoming); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(indexgroup); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(inf); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(infer_variance); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(inheritable); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(initial); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(initial_bytes); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(initial_value); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(initval); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(inner_size); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(input); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(insert_comments); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(insert_pis); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(instructions); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(intern); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(intersection); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(is_running); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(isatty); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(isinstance); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(isoformat); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(isolation_level); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(istext); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(item); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(items); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(iter); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(iterable); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(iterations); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(join); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(jump); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(keepends); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(key); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(keyfile); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(keys); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(kind); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(kw); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(kw1); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(kw2); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(lambda); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(last); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(last_exc); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(last_node); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(last_traceback); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(last_type); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(last_value); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(latin1); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(leaf_size); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(len); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(length); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(level); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(limit); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(line); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(line_buffering); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(lineno); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(listcomp); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(little); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(lo); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(locale); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(locals); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(logoption); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(loop); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(mapping); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(match); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(max_length); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(maxdigits); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(maxevents); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(maxmem); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(maxsplit); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(maxvalue); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(memLevel); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(memlimit); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(message); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(metaclass); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(metadata); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(method); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(mod); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(mode); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(module); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(module_globals); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(modules); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(mro); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(msg); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(mycmp); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); - string = &_Py_ID(n); - assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(n_arg); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(n_fields); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(n_sequence_fields); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(n_unnamed_fields); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(name); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(name_from); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(namespace_separator); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(namespaces); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(narg); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(ndigits); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(new_file_name); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(new_limit); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(newline); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(newlines); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(next); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(nlocals); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(node_depth); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(node_offset); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(ns); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(nstype); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(nt); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(null); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(number); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(obj); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(object); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(offset); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(offset_dst); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(offset_src); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(on_type_read); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(onceregistry); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(only_keys); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(oparg); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(opcode); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(open); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(opener); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(operation); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(optimize); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(options); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(order); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(origin); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(out_fd); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(outgoing); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(overlapped); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(owner); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); - string = &_Py_ID(p); - assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(pages); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(parent); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(password); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(path); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(pattern); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(peek); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(persistent_id); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(persistent_load); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(person); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(pi_factory); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(pid); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(policy); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(pos); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(pos1); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(pos2); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(posix); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(print_file_and_line); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(priority); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(progress); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(progress_handler); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(progress_routine); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(proto); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(protocol); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(ps1); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(ps2); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(query); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(quotetabs); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); - string = &_Py_ID(r); - assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(raw); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(read); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(read1); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(readable); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(readall); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(readinto); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(readinto1); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(readline); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(readonly); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(real); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(reducer_override); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(registry); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(rel_tol); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(release); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(reload); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(repl); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(replace); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(reserved); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(reset); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(resetids); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(return); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(reverse); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(reversed); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); - string = &_Py_ID(s); - assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(salt); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(sched_priority); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(scheduler); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(seek); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(seekable); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(selectors); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(self); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(send); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(sep); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(sequence); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(server_hostname); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(server_side); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(session); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(setcomp); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(setpgroup); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(setsid); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(setsigdef); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(setsigmask); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(setstate); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(shape); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(show_cmd); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(signed); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(size); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(sizehint); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(skip_file_prefixes); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(sleep); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(sock); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(sort); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(sound); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(source); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(source_traceback); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(spam); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(src); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(src_dir_fd); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(stacklevel); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(start); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(statement); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(status); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(stderr); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(stdin); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(stdout); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(step); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(steps); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(store_name); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(strategy); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(strftime); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(strict); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(strict_mode); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(string); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(sub_key); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(symmetric_difference_update); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(tabsize); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(tag); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(target); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(target_is_directory); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(task); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(tb_frame); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(tb_lasti); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(tb_lineno); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(tb_next); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(tell); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(template); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(term); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(text); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(threading); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(throw); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(timeout); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(times); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(timetuple); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(top); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(trace_callback); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(traceback); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(trailers); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(translate); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(true); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(truncate); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(twice); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(txt); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(type); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(type_params); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(tz); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(tzname); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(uid); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(unlink); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(unraisablehook); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(uri); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(usedforsecurity); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(value); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(values); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(version); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(volume); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(warnings); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(warnoptions); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(wbits); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(week); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(weekday); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(which); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(who); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(withdata); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(writable); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(write); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(write_through); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); - string = &_Py_ID(x); - assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(year); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(zdict); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_STR(empty); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_STR(dbl_percent); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_STR(dot_locals); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_STR(defaults); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_STR(generic_base); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_STR(kwdefaults); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_STR(type_params); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_STR(anon_dictcomp); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_STR(anon_genexpr); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_STR(anon_lambda); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_STR(anon_listcomp); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_STR(anon_module); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_STR(anon_setcomp); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_STR(shim_name); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_STR(anon_string); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_STR(anon_unknown); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_STR(json_decoder); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_STR(list_err); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_STR(utf_8); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_STR(dbl_open_br); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_STR(dbl_close_br); + _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); - _PyUnicode_InternInPlace(interp, &string); + assert(PyUnicode_GET_LENGTH(string) != 1); } /* End auto-generated code */ #ifdef __cplusplus diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 07e77187..6c597837 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -18,12 +18,12 @@ /*--start constants--*/ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 12 -#define PY_MICRO_VERSION 4 +#define PY_MICRO_VERSION 8 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL #define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.12.4" +#define PY_VERSION "3.12.8" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Include/pymacro.h b/Include/pymacro.h index 342d2a7b..d5700dc3 100644 --- a/Include/pymacro.h +++ b/Include/pymacro.h @@ -15,11 +15,11 @@ // MSVC makes static_assert a keyword in C11-17, contrary to the standards. // // In C++11 and C2x, static_assert is a keyword, redefining is undefined -// behaviour. So only define if building as C (if __STDC_VERSION__ is defined), -// not C++, and only for C11-17. +// behaviour. So only define if building as C, not C++ (if __cplusplus is +// not defined), and only for C11-17. #if !defined(static_assert) && (defined(__GNUC__) || defined(__clang__)) \ - && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L \ - && __STDC_VERSION__ <= 201710L + && !defined(__cplusplus) && defined(__STDC_VERSION__) \ + && __STDC_VERSION__ >= 201112L && __STDC_VERSION__ <= 201710L # define static_assert _Static_assert #endif diff --git a/InternalDocs/string_interning.md b/InternalDocs/string_interning.md new file mode 100644 index 00000000..4d0de118 --- /dev/null +++ b/InternalDocs/string_interning.md @@ -0,0 +1,122 @@ +# String interning + +*Interned* strings are conceptually part of an interpreter-global +*set* of interned strings, meaning that: +- no two interned strings have the same content (across an interpreter); +- two interned strings can be safely compared using pointer equality + (Python `is`). + +This is used to optimize dict and attribute lookups, among other things. + +Python uses two different mechanisms to intern strings: singletons and +dynamic interning. + +## Singletons + +The 256 possible one-character latin-1 strings, which can be retrieved with +`_Py_LATIN1_CHR(c)`, are stored in statically allocated arrays, +`_PyRuntime.static_objects.strings.ascii` and +`_PyRuntime.static_objects.strings.latin1`. + +Longer singleton strings are marked in C source with `_Py_ID` (if the string +is a valid C identifier fragment) or `_Py_STR` (if it needs a separate +C-compatible name.) +These are also stored in statically allocated arrays. +They are collected from CPython sources using `make regen-global-objects` +(`Tools/build/generate_global_objects.py`), which generates code +for declaration, initialization and finalization. + +The empty string is one of the singletons: `_Py_STR(empty)`. + +Deep-frozen modules (see `Tools/build/deepfreeze.py`) use either singletons, +or statically allocated strings. These are added to `INTERNED_STRINGS` +at runtime initialization, when deepfreeze modules are loaded. + +These sets of singletons (`_Py_LATIN1_CHR`, `_Py_ID`, `_Py_STR`, deepfreeze) +are disjoint. +If you have such a singleton, it (and no other copy) will be interned. + +These singletons are interned in a runtime-global lookup table, +`_PyRuntime.cached_objects.interned_strings` (`INTERNED_STRINGS`), +at runtime initialization, and immutable until it's torn down +at runtime finalization. +It is shared across threads and interpreters without any synchronization. + + +## Dynamically allocated strings + +All other strings are allocated dynamically, and have their +`_PyUnicode_STATE(s).statically_allocated` flag set to zero. +When interned, such strings are added to an interpreter-wide dict, +`PyInterpreterState.cached_objects.interned_strings`. + +The key and value of each entry in this dict reference the same object. + + +## Immortality and reference counting + +Invariant: Every immortal string is interned. + +In practice, this means that you must not use `_Py_SetImmortal` on +a string. (If you know it's already immortal, don't immortalize it; +if you know it's not interned you might be immortalizing a redundant copy; +if it's interned and mortal it needs extra processing in +`_PyUnicode_InternImmortal`.) + +The converse is not true: interned strings can be mortal. +For mortal interned strings: +- the 2 references from the interned dict (key & value) are excluded from + their refcount +- the deallocator (`unicode_dealloc`) removes the string from the interned dict +- at shutdown, when the interned dict is cleared, the references are added back + +As with any type, you should only immortalize strings that will live until +interpreter shutdown. +We currently also immortalize strings contained in code objects and similar, +specifically in the compiler and in `marshal`. +These are “close enough” to immortal: even in use cases like hot reloading +or `eval`-ing user input, the number of distinct identifiers and string +constants expected to stay low. + + +## Internal API + +We have the following *internal* API for interning: + +- `_PyUnicode_InternMortal`: just intern the string +- `_PyUnicode_InternImmortal`: intern, and immortalize the result +- `_PyUnicode_InternStatic`: intern a static singleton (`_Py_STR`, `_Py_ID` + or one-byte). Not for general use. + +All take an interpreter state, and a pointer to a `PyObject*` which they +modify in place. + +The functions take ownership of (“steal”) the reference to their argument, +and update the argument with a *new* reference. +This means: +- They're “reference neutral”. +- They must not be called with a borrowed reference. + + +## State + +The intern state (retrieved by `PyUnicode_CHECK_INTERNED(s)`; +stored in `_PyUnicode_STATE(s).interned`) can be: + +- `SSTATE_NOT_INTERNED` (defined as 0, which is useful in a boolean context) +- `SSTATE_INTERNED_MORTAL` (1) +- `SSTATE_INTERNED_IMMORTAL` (2) +- `SSTATE_INTERNED_IMMORTAL_STATIC` (3) + +The valid transitions between these states are: + +- For dynamically allocated strings: + + - 0 -> 1 (`_PyUnicode_InternMortal`) + - 1 -> 2 or 0 -> 2 (`_PyUnicode_InternImmortal`) + + Using `_PyUnicode_InternStatic` on these is an error; the other cases + don't change the state. + +- Singletons are interned (0 -> 3) at runtime init; + after that all interning functions don't change the state. diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py index 601107d2..09745658 100644 --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -973,7 +973,7 @@ def clear(self): def update(self, other=(), /, **kwds): ''' D.update([E, ]**F) -> None. Update D from mapping/iterable E and F. - If E present and has a .keys() method, does: for k in E: D[k] = E[k] + If E present and has a .keys() method, does: for k in E.keys(): D[k] = E[k] If E present and lacks .keys() method, does: for (k, v) in E: D[k] = v In either case, this is followed by: for k, v in F.items(): D[k] = v ''' diff --git a/Lib/_pydatetime.py b/Lib/_pydatetime.py index cd0ea900..ad6292e1 100644 --- a/Lib/_pydatetime.py +++ b/Lib/_pydatetime.py @@ -970,6 +970,8 @@ def __new__(cls, year, month=None, day=None): @classmethod def fromtimestamp(cls, t): "Construct a date from a POSIX timestamp (like time.time())." + if t is None: + raise TypeError("'NoneType' object cannot be interpreted as an integer") y, m, d, hh, mm, ss, weekday, jday, dst = _time.localtime(t) return cls(y, m, d) diff --git a/Lib/_pydecimal.py b/Lib/_pydecimal.py index 613123ec..75df3db2 100644 --- a/Lib/_pydecimal.py +++ b/Lib/_pydecimal.py @@ -424,7 +424,7 @@ def sin(x): # numbers.py for more detail. class Decimal(object): - """Floating point class for decimal arithmetic.""" + """Floating-point class for decimal arithmetic.""" __slots__ = ('_exp','_int','_sign', '_is_special') # Generally, the value of the Decimal instance is given by diff --git a/Lib/_strptime.py b/Lib/_strptime.py index 798cf9f9..dfd2bc5d 100644 --- a/Lib/_strptime.py +++ b/Lib/_strptime.py @@ -14,6 +14,7 @@ import locale import calendar from re import compile as re_compile +from re import sub as re_sub from re import IGNORECASE from re import escape as re_escape from datetime import (date as datetime_date, @@ -27,6 +28,18 @@ def _getlang(): # Figure out what the current language is set to. return locale.getlocale(locale.LC_TIME) +def _findall(haystack, needle): + # Find all positions of needle in haystack. + if not needle: + return + i = 0 + while True: + i = haystack.find(needle, i) + if i < 0: + break + yield i + i += len(needle) + class LocaleTime(object): """Stores and handles locale-specific information related to time. @@ -101,7 +114,8 @@ def __calc_am_pm(self): am_pm = [] for hour in (1, 22): time_tuple = time.struct_time((1999,3,17,hour,44,55,2,76,0)) - am_pm.append(time.strftime("%p", time_tuple).lower()) + # br_FR has AM/PM info (' ',' '). + am_pm.append(time.strftime("%p", time_tuple).lower().strip()) self.am_pm = am_pm def __calc_date_time(self): @@ -113,42 +127,130 @@ def __calc_date_time(self): # values within the format string is very important; it eliminates # possible ambiguity for what something represents. time_tuple = time.struct_time((1999,3,17,22,44,55,2,76,0)) - date_time = [None, None, None] - date_time[0] = time.strftime("%c", time_tuple).lower() - date_time[1] = time.strftime("%x", time_tuple).lower() - date_time[2] = time.strftime("%X", time_tuple).lower() - replacement_pairs = [('%', '%%'), (self.f_weekday[2], '%A'), - (self.f_month[3], '%B'), (self.a_weekday[2], '%a'), - (self.a_month[3], '%b'), (self.am_pm[1], '%p'), - ('1999', '%Y'), ('99', '%y'), ('22', '%H'), - ('44', '%M'), ('55', '%S'), ('76', '%j'), - ('17', '%d'), ('03', '%m'), ('3', '%m'), - # '3' needed for when no leading zero. - ('2', '%w'), ('10', '%I')] - replacement_pairs.extend([(tz, "%Z") for tz_values in self.timezone - for tz in tz_values]) - for offset,directive in ((0,'%c'), (1,'%x'), (2,'%X')): - current_format = date_time[offset] - for old, new in replacement_pairs: + time_tuple2 = time.struct_time((1999,1,3,1,1,1,6,3,0)) + replacement_pairs = [ + ('1999', '%Y'), ('99', '%y'), ('22', '%H'), + ('44', '%M'), ('55', '%S'), ('76', '%j'), + ('17', '%d'), ('03', '%m'), ('3', '%m'), + # '3' needed for when no leading zero. + ('2', '%w'), ('10', '%I'), + # Non-ASCII digits + ('\u0661\u0669\u0669\u0669', '%Y'), + ('\u0669\u0669', '%Oy'), + ('\u0662\u0662', '%OH'), + ('\u0664\u0664', '%OM'), + ('\u0665\u0665', '%OS'), + ('\u0661\u0667', '%Od'), + ('\u0660\u0663', '%Om'), + ('\u0663', '%Om'), + ('\u0662', '%Ow'), + ('\u0661\u0660', '%OI'), + ] + date_time = [] + for directive in ('%c', '%x', '%X'): + current_format = time.strftime(directive, time_tuple).lower() + current_format = current_format.replace('%', '%%') + # The month and the day of the week formats are treated specially + # because of a possible ambiguity in some locales where the full + # and abbreviated names are equal or names of different types + # are equal. See doc of __find_month_format for more details. + lst, fmt = self.__find_weekday_format(directive) + if lst: + current_format = current_format.replace(lst[2], fmt, 1) + lst, fmt = self.__find_month_format(directive) + if lst: + current_format = current_format.replace(lst[3], fmt, 1) + if self.am_pm[1]: # Must deal with possible lack of locale info # manifesting itself as the empty string (e.g., Swedish's # lack of AM/PM info) or a platform returning a tuple of empty # strings (e.g., MacOS 9 having timezone as ('','')). - if old: - current_format = current_format.replace(old, new) + current_format = current_format.replace(self.am_pm[1], '%p') + for tz_values in self.timezone: + for tz in tz_values: + if tz: + current_format = current_format.replace(tz, "%Z") + # Transform all non-ASCII digits to digits in range U+0660 to U+0669. + current_format = re_sub(r'\d(?3[0-1]|[1-2]\d|0[1-9]|[1-9]| [1-9])", 'f': r"(?P[0-9]{1,6})", 'H': r"(?P2[0-3]|[0-1]\d|\d)", - 'I': r"(?P1[0-2]|0[1-9]|[1-9])", + 'I': r"(?P1[0-2]|0[1-9]|[1-9]| [1-9])", 'G': r"(?P\d\d\d\d)", 'j': r"(?P36[0-6]|3[0-5]\d|[1-2]\d\d|0[1-9]\d|00[1-9]|[1-9]\d|0[1-9]|[1-9])", 'm': r"(?P1[0-2]|0[1-9]|[1-9])", @@ -210,11 +312,15 @@ def __init__(self, locale_time=None): 'Z': self.__seqToRE((tz for tz_names in self.locale_time.timezone for tz in tz_names), 'Z'), - '%': '%'}) - base.__setitem__('W', base.__getitem__('U').replace('U', 'W')) - base.__setitem__('c', self.pattern(self.locale_time.LC_date_time)) - base.__setitem__('x', self.pattern(self.locale_time.LC_date)) + '%': '%'} + for d in 'dmyHIMS': + mapping['O' + d] = r'(?P<%s>\d\d|\d| \d)' % d + mapping['Ow'] = r'(?P\d)' + mapping['W'] = mapping['U'].replace('U', 'W') + base.__init__(mapping) base.__setitem__('X', self.pattern(self.locale_time.LC_time)) + base.__setitem__('x', self.pattern(self.locale_time.LC_date)) + base.__setitem__('c', self.pattern(self.locale_time.LC_date_time)) def __seqToRE(self, to_convert, directive): """Convert a list to a regex string for matching a directive. @@ -242,21 +348,16 @@ def pattern(self, format): regex syntax are escaped. """ - processed_format = '' # The sub() call escapes all characters that might be misconstrued # as regex syntax. Cannot use re.escape since we have to deal with # format directives (%m, etc.). - regex_chars = re_compile(r"([\\.^$*+?\(\){}\[\]|])") - format = regex_chars.sub(r"\\\1", format) - whitespace_replacement = re_compile(r'\s+') - format = whitespace_replacement.sub(r'\\s+', format) - while '%' in format: - directive_index = format.index('%')+1 - processed_format = "%s%s%s" % (processed_format, - format[:directive_index-1], - self[format[directive_index]]) - format = format[directive_index+1:] - return "%s%s" % (processed_format, format) + format = re_sub(r"([\\.^$*+?\(\){}\[\]|])", r"\\\1", format) + format = re_sub(r'\s+', r'\\s+', format) + format = re_sub(r"'", "['\u02bc]", format) # needed for br_FR + def repl(m): + return self[m[1]] + format = re_sub(r'%(O?.)', repl, format) + return format def compile(self, format): """Return a compiled re object for the format string.""" diff --git a/Lib/argparse.py b/Lib/argparse.py index 120cb6c8..2a8b501a 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -263,13 +263,12 @@ def add_argument(self, action): # find all invocations get_invocation = self._format_action_invocation - invocations = [get_invocation(action)] + invocation_lengths = [len(get_invocation(action)) + self._current_indent] for subaction in self._iter_indented_subactions(action): - invocations.append(get_invocation(subaction)) + invocation_lengths.append(len(get_invocation(subaction)) + self._current_indent) # update the maximum item length - invocation_length = max(map(len, invocations)) - action_length = invocation_length + self._current_indent + action_length = max(invocation_lengths) self._action_max_length = max(self._action_max_length, action_length) @@ -565,8 +564,7 @@ def _format_action(self, action): def _format_action_invocation(self, action): if not action.option_strings: default = self._get_default_metavar_for_positional(action) - metavar, = self._metavar_formatter(action, default)(1) - return metavar + return ' '.join(self._metavar_formatter(action, default)(1)) else: parts = [] @@ -590,8 +588,7 @@ def _metavar_formatter(self, action, default_metavar): if action.metavar is not None: result = action.metavar elif action.choices is not None: - choice_strs = [str(choice) for choice in action.choices] - result = '{%s}' % ','.join(choice_strs) + result = '{%s}' % ','.join(map(str, action.choices)) else: result = default_metavar @@ -639,8 +636,7 @@ def _expand_help(self, action): if hasattr(params[name], '__name__'): params[name] = params[name].__name__ if params.get('choices') is not None: - choices_str = ', '.join([str(c) for c in params['choices']]) - params['choices'] = choices_str + params['choices'] = ', '.join(map(str, params['choices'])) return self._get_help_string(action) % params def _iter_indented_subactions(self, action): @@ -753,11 +749,19 @@ def _get_action_name(argument): elif argument.option_strings: return '/'.join(argument.option_strings) elif argument.metavar not in (None, SUPPRESS): - return argument.metavar + metavar = argument.metavar + if not isinstance(metavar, tuple): + return metavar + if argument.nargs == ZERO_OR_MORE and len(metavar) == 2: + return '%s[, %s]' % metavar + elif argument.nargs == ONE_OR_MORE: + return '%s[, %s]' % metavar + else: + return ', '.join(metavar) elif argument.dest not in (None, SUPPRESS): return argument.dest elif argument.choices: - return '{' + ','.join(argument.choices) + '}' + return '{%s}' % ','.join(map(str, argument.choices)) else: return None @@ -1270,7 +1274,8 @@ def __call__(self, parser, namespace, values, option_string=None): setattr(namespace, key, value) if arg_strings: - vars(namespace).setdefault(_UNRECOGNIZED_ARGS_ATTR, []) + if not hasattr(namespace, _UNRECOGNIZED_ARGS_ATTR): + setattr(namespace, _UNRECOGNIZED_ARGS_ATTR, []) getattr(namespace, _UNRECOGNIZED_ARGS_ATTR).extend(arg_strings) class _ExtendAction(_AppendAction): @@ -1557,7 +1562,11 @@ def _add_container_actions(self, container): # NOTE: if add_mutually_exclusive_group ever gains title= and # description= then this code will need to be expanded as above for group in container._mutually_exclusive_groups: - mutex_group = self.add_mutually_exclusive_group( + if group._container is container: + cont = self + else: + cont = title_group_map[group._container.title] + mutex_group = cont.add_mutually_exclusive_group( required=group.required) # map the actions to their new mutex group @@ -1576,9 +1585,8 @@ def _get_positional_kwargs(self, dest, **kwargs): # mark positional arguments as required if at least one is # always required - if kwargs.get('nargs') not in [OPTIONAL, ZERO_OR_MORE]: - kwargs['required'] = True - if kwargs.get('nargs') == ZERO_OR_MORE and 'default' not in kwargs: + nargs = kwargs.get('nargs') + if nargs not in [OPTIONAL, ZERO_OR_MORE, REMAINDER, SUPPRESS, 0]: kwargs['required'] = True # return the keyword arguments with no option strings @@ -1843,14 +1851,14 @@ def _get_kwargs(self): # ================================== def add_subparsers(self, **kwargs): if self._subparsers is not None: - self.error(_('cannot have multiple subparser arguments')) + raise ArgumentError(None, _('cannot have multiple subparser arguments')) # add the parser class to the arguments if it's not present kwargs.setdefault('parser_class', type(self)) if 'title' in kwargs or 'description' in kwargs: - title = _(kwargs.pop('title', 'subcommands')) - description = _(kwargs.pop('description', None)) + title = kwargs.pop('title', _('subcommands')) + description = kwargs.pop('description', None) self._subparsers = self.add_argument_group(title, description) else: self._subparsers = self._positionals @@ -1895,11 +1903,17 @@ def _get_positional_actions(self): def parse_args(self, args=None, namespace=None): args, argv = self.parse_known_args(args, namespace) if argv: - msg = _('unrecognized arguments: %s') - self.error(msg % ' '.join(argv)) + msg = _('unrecognized arguments: %s') % ' '.join(argv) + if self.exit_on_error: + self.error(msg) + else: + raise ArgumentError(None, msg) return args def parse_known_args(self, args=None, namespace=None): + return self._parse_known_args2(args, namespace, intermixed=False) + + def _parse_known_args2(self, args, namespace, intermixed): if args is None: # args default to the system args args = _sys.argv[1:] @@ -1926,18 +1940,18 @@ def parse_known_args(self, args=None, namespace=None): # parse the arguments and exit if there are any errors if self.exit_on_error: try: - namespace, args = self._parse_known_args(args, namespace) + namespace, args = self._parse_known_args(args, namespace, intermixed) except ArgumentError as err: self.error(str(err)) else: - namespace, args = self._parse_known_args(args, namespace) + namespace, args = self._parse_known_args(args, namespace, intermixed) if hasattr(namespace, _UNRECOGNIZED_ARGS_ATTR): args.extend(getattr(namespace, _UNRECOGNIZED_ARGS_ATTR)) delattr(namespace, _UNRECOGNIZED_ARGS_ATTR) return namespace, args - def _parse_known_args(self, arg_strings, namespace): + def _parse_known_args(self, arg_strings, namespace, intermixed): # replace arg strings that are file references if self.fromfile_prefix_chars is not None: arg_strings = self._read_args_from_files(arg_strings) @@ -1969,11 +1983,11 @@ def _parse_known_args(self, arg_strings, namespace): # otherwise, add the arg to the arg strings # and note the index if it was an option else: - option_tuple = self._parse_optional(arg_string) - if option_tuple is None: + option_tuples = self._parse_optional(arg_string) + if option_tuples is None: pattern = 'A' else: - option_string_indices[i] = option_tuple + option_string_indices[i] = option_tuples pattern = 'O' arg_string_pattern_parts.append(pattern) @@ -1989,9 +2003,8 @@ def take_action(action, argument_strings, option_string=None): argument_values = self._get_values(action, argument_strings) # error if this argument is not allowed with other previously - # seen arguments, assuming that actions that use the default - # value don't really count as "present" - if argument_values is not action.default: + # seen arguments + if action.option_strings or argument_strings: seen_non_default_actions.add(action) for conflict_action in action_conflicts.get(action, []): if conflict_action in seen_non_default_actions: @@ -2008,8 +2021,16 @@ def take_action(action, argument_strings, option_string=None): def consume_optional(start_index): # get the optional identified at this index - option_tuple = option_string_indices[start_index] - action, option_string, sep, explicit_arg = option_tuple + option_tuples = option_string_indices[start_index] + # if multiple actions match, the option string was ambiguous + if len(option_tuples) > 1: + options = ', '.join([option_string + for action, option_string, sep, explicit_arg in option_tuples]) + args = {'option': arg_strings[start_index], 'matches': options} + msg = _('ambiguous option: %(option)s could match %(matches)s') + raise ArgumentError(None, msg % args) + + action, option_string, sep, explicit_arg = option_tuples[0] # identify additional optionals in the same arg string # (e.g. -xyz is the same as -x -y -z if no args are required) @@ -2020,6 +2041,7 @@ def consume_optional(start_index): # if we found no optional action, skip it if action is None: extras.append(arg_strings[start_index]) + extras_pattern.append('O') return start_index + 1 # if there is an explicit argument, try to match the @@ -2055,6 +2077,7 @@ def consume_optional(start_index): sep = '' else: extras.append(char + explicit_arg) + extras_pattern.append('O') stop = start_index + 1 break # if the action expect exactly one argument, we've @@ -2105,6 +2128,15 @@ def consume_positionals(start_index): # and add the Positional and its args to the list for action, arg_count in zip(positionals, arg_counts): args = arg_strings[start_index: start_index + arg_count] + # Strip out the first '--' if it is not in REMAINDER arg. + if action.nargs == PARSER: + if arg_strings_pattern[start_index] == '-': + assert args[0] == '--' + args.remove('--') + elif action.nargs != REMAINDER: + if (arg_strings_pattern.find('-', start_index, + start_index + arg_count) >= 0): + args.remove('--') start_index += arg_count take_action(action, args) @@ -2116,6 +2148,7 @@ def consume_positionals(start_index): # consume Positionals and Optionals alternately, until we have # passed the last option string extras = [] + extras_pattern = [] start_index = 0 if option_string_indices: max_option_string_index = max(option_string_indices) @@ -2128,7 +2161,7 @@ def consume_positionals(start_index): index for index in option_string_indices if index >= start_index]) - if start_index != next_option_string_index: + if not intermixed and start_index != next_option_string_index: positionals_end_index = consume_positionals(start_index) # only try to parse the next optional if we didn't consume @@ -2144,16 +2177,35 @@ def consume_positionals(start_index): if start_index not in option_string_indices: strings = arg_strings[start_index:next_option_string_index] extras.extend(strings) + extras_pattern.extend(arg_strings_pattern[start_index:next_option_string_index]) start_index = next_option_string_index # consume the next optional and any arguments for it start_index = consume_optional(start_index) - # consume any positionals following the last Optional - stop_index = consume_positionals(start_index) + if not intermixed: + # consume any positionals following the last Optional + stop_index = consume_positionals(start_index) - # if we didn't consume all the argument strings, there were extras - extras.extend(arg_strings[stop_index:]) + # if we didn't consume all the argument strings, there were extras + extras.extend(arg_strings[stop_index:]) + else: + extras.extend(arg_strings[start_index:]) + extras_pattern.extend(arg_strings_pattern[start_index:]) + extras_pattern = ''.join(extras_pattern) + assert len(extras_pattern) == len(extras) + # consume all positionals + arg_strings = [s for s, c in zip(extras, extras_pattern) if c != 'O'] + arg_strings_pattern = extras_pattern.replace('O', '') + stop_index = consume_positionals(0) + # leave unknown optionals and non-consumed positionals in extras + for i, c in enumerate(extras_pattern): + if not stop_index: + break + if c != 'O': + stop_index -= 1 + extras[i] = None + extras = [s for s in extras if s is not None] # make sure all required actions were present and also convert # action defaults which were not given as arguments @@ -2175,7 +2227,7 @@ def consume_positionals(start_index): self._get_value(action, action.default)) if required_actions: - self.error(_('the following arguments are required: %s') % + raise ArgumentError(None, _('the following arguments are required: %s') % ', '.join(required_actions)) # make sure all required groups had one option present @@ -2191,7 +2243,7 @@ def consume_positionals(start_index): for action in group._group_actions if action.help is not SUPPRESS] msg = _('one of the arguments %s is required') - self.error(msg % ' '.join(names)) + raise ArgumentError(None, msg % ' '.join(names)) # return the updated namespace and the extra arguments return namespace, extras @@ -2218,7 +2270,7 @@ def _read_args_from_files(self, arg_strings): arg_strings = self._read_args_from_files(arg_strings) new_arg_strings.extend(arg_strings) except OSError as err: - self.error(str(err)) + raise ArgumentError(None, str(err)) # return the modified argument list return new_arg_strings @@ -2251,18 +2303,19 @@ def _match_argument(self, action, arg_strings_pattern): def _match_arguments_partial(self, actions, arg_strings_pattern): # progressively shorten the actions list by slicing off the # final actions until we find a match - result = [] for i in range(len(actions), 0, -1): actions_slice = actions[:i] pattern = ''.join([self._get_nargs_pattern(action) for action in actions_slice]) match = _re.match(pattern, arg_strings_pattern) if match is not None: - result.extend([len(string) for string in match.groups()]) - break - - # return the list of arg string counts - return result + result = [len(string) for string in match.groups()] + if (match.end() < len(arg_strings_pattern) + and arg_strings_pattern[match.end()] == 'O'): + while result and not result[-1]: + del result[-1] + return result + return [] def _parse_optional(self, arg_string): # if it's an empty string, it was meant to be a positional @@ -2276,7 +2329,7 @@ def _parse_optional(self, arg_string): # if the option string is present in the parser, return the action if arg_string in self._option_string_actions: action = self._option_string_actions[arg_string] - return action, arg_string, None, None + return [(action, arg_string, None, None)] # if it's just a single character, it was meant to be positional if len(arg_string) == 1: @@ -2286,25 +2339,14 @@ def _parse_optional(self, arg_string): option_string, sep, explicit_arg = arg_string.partition('=') if sep and option_string in self._option_string_actions: action = self._option_string_actions[option_string] - return action, option_string, sep, explicit_arg + return [(action, option_string, sep, explicit_arg)] # search through all possible prefixes of the option string # and all actions in the parser for possible interpretations option_tuples = self._get_option_tuples(arg_string) - # if multiple actions match, the option string was ambiguous - if len(option_tuples) > 1: - options = ', '.join([option_string - for action, option_string, sep, explicit_arg in option_tuples]) - args = {'option': arg_string, 'matches': options} - msg = _('ambiguous option: %(option)s could match %(matches)s') - self.error(msg % args) - - # if exactly one action matched, this segmentation is good, - # so return the parsed action - elif len(option_tuples) == 1: - option_tuple, = option_tuples - return option_tuple + if option_tuples: + return option_tuples # if it was not found as an option, but it looks like a negative # number, it was meant to be positional @@ -2319,7 +2361,7 @@ def _parse_optional(self, arg_string): # it was meant to be an optional but there is no such option # in this parser (though it might be a valid option in a subparser) - return None, arg_string, None, None + return [(None, arg_string, None, None)] def _get_option_tuples(self, option_string): result = [] @@ -2342,7 +2384,9 @@ def _get_option_tuples(self, option_string): # but multiple character options always have to have their argument # separate elif option_string[0] in chars and option_string[1] not in chars: - option_prefix = option_string + option_prefix, sep, explicit_arg = option_string.partition('=') + if not sep: + sep = explicit_arg = None short_option_prefix = option_string[:2] short_explicit_arg = option_string[2:] @@ -2351,14 +2395,14 @@ def _get_option_tuples(self, option_string): action = self._option_string_actions[option_string] tup = action, option_string, '', short_explicit_arg result.append(tup) - elif option_string.startswith(option_prefix): + elif self.allow_abbrev and option_string.startswith(option_prefix): action = self._option_string_actions[option_string] - tup = action, option_string, None, None + tup = action, option_string, sep, explicit_arg result.append(tup) # shouldn't ever get here else: - self.error(_('unexpected option string: %s') % option_string) + raise ArgumentError(None, _('unexpected option string: %s') % option_string) # return the collected option tuples return result @@ -2367,43 +2411,40 @@ def _get_nargs_pattern(self, action): # in all examples below, we have to allow for '--' args # which are represented as '-' in the pattern nargs = action.nargs + # if this is an optional action, -- is not allowed + option = action.option_strings # the default (None) is assumed to be a single argument if nargs is None: - nargs_pattern = '(-*A-*)' + nargs_pattern = '([A])' if option else '(-*A-*)' # allow zero or one arguments elif nargs == OPTIONAL: - nargs_pattern = '(-*A?-*)' + nargs_pattern = '(A?)' if option else '(-*A?-*)' # allow zero or more arguments elif nargs == ZERO_OR_MORE: - nargs_pattern = '(-*[A-]*)' + nargs_pattern = '(A*)' if option else '(-*[A-]*)' # allow one or more arguments elif nargs == ONE_OR_MORE: - nargs_pattern = '(-*A[A-]*)' + nargs_pattern = '(A+)' if option else '(-*A[A-]*)' # allow any number of options or arguments elif nargs == REMAINDER: - nargs_pattern = '([-AO]*)' + nargs_pattern = '([AO]*)' if option else '(.*)' # allow one argument followed by any number of options or arguments elif nargs == PARSER: - nargs_pattern = '(-*A[-AO]*)' + nargs_pattern = '(A[AO]*)' if option else '(-*A[-AO]*)' # suppress action, like nargs=0 elif nargs == SUPPRESS: - nargs_pattern = '(-*-*)' + nargs_pattern = '()' if option else '(-*)' # all others should be integers else: - nargs_pattern = '(-*%s-*)' % '-*'.join('A' * nargs) - - # if this is an optional action, -- is not allowed - if action.option_strings: - nargs_pattern = nargs_pattern.replace('-*', '') - nargs_pattern = nargs_pattern.replace('-', '') + nargs_pattern = '([AO]{%d})' % nargs if option else '((?:-*A){%d}-*)' % nargs # return the pattern return nargs_pattern @@ -2415,8 +2456,11 @@ def _get_nargs_pattern(self, action): def parse_intermixed_args(self, args=None, namespace=None): args, argv = self.parse_known_intermixed_args(args, namespace) if argv: - msg = _('unrecognized arguments: %s') - self.error(msg % ' '.join(argv)) + msg = _('unrecognized arguments: %s') % ' '.join(argv) + if self.exit_on_error: + self.error(msg) + else: + raise ArgumentError(None, msg) return args def parse_known_intermixed_args(self, args=None, namespace=None): @@ -2427,10 +2471,6 @@ def parse_known_intermixed_args(self, args=None, namespace=None): # are then parsed. If the parser definition is incompatible with the # intermixed assumptions (e.g. use of REMAINDER, subparsers) a # TypeError is raised. - # - # positionals are 'deactivated' by setting nargs and default to - # SUPPRESS. This blocks the addition of that positional to the - # namespace positionals = self._get_positional_actions() a = [action for action in positionals @@ -2439,78 +2479,19 @@ def parse_known_intermixed_args(self, args=None, namespace=None): raise TypeError('parse_intermixed_args: positional arg' ' with nargs=%s'%a[0].nargs) - if [action.dest for group in self._mutually_exclusive_groups - for action in group._group_actions if action in positionals]: - raise TypeError('parse_intermixed_args: positional in' - ' mutuallyExclusiveGroup') - - try: - save_usage = self.usage - try: - if self.usage is None: - # capture the full usage for use in error messages - self.usage = self.format_usage()[7:] - for action in positionals: - # deactivate positionals - action.save_nargs = action.nargs - # action.nargs = 0 - action.nargs = SUPPRESS - action.save_default = action.default - action.default = SUPPRESS - namespace, remaining_args = self.parse_known_args(args, - namespace) - for action in positionals: - # remove the empty positional values from namespace - if (hasattr(namespace, action.dest) - and getattr(namespace, action.dest)==[]): - from warnings import warn - warn('Do not expect %s in %s' % (action.dest, namespace)) - delattr(namespace, action.dest) - finally: - # restore nargs and usage before exiting - for action in positionals: - action.nargs = action.save_nargs - action.default = action.save_default - optionals = self._get_optional_actions() - try: - # parse positionals. optionals aren't normally required, but - # they could be, so make sure they aren't. - for action in optionals: - action.save_required = action.required - action.required = False - for group in self._mutually_exclusive_groups: - group.save_required = group.required - group.required = False - namespace, extras = self.parse_known_args(remaining_args, - namespace) - finally: - # restore parser values before exiting - for action in optionals: - action.required = action.save_required - for group in self._mutually_exclusive_groups: - group.required = group.save_required - finally: - self.usage = save_usage - return namespace, extras + return self._parse_known_args2(args, namespace, intermixed=True) # ======================== # Value conversion methods # ======================== def _get_values(self, action, arg_strings): - # for everything but PARSER, REMAINDER args, strip out first '--' - if not action.option_strings and action.nargs not in [PARSER, REMAINDER]: - try: - arg_strings.remove('--') - except ValueError: - pass - # optional argument produces a default when not present if not arg_strings and action.nargs == OPTIONAL: if action.option_strings: value = action.const else: value = action.default - if isinstance(value, str): + if isinstance(value, str) and value is not SUPPRESS: value = self._get_value(action, value) self._check_value(action, value) @@ -2581,11 +2562,15 @@ def _get_value(self, action, arg_string): def _check_value(self, action, value): # converted value must be one of the choices (if specified) - if action.choices is not None and value not in action.choices: - args = {'value': value, - 'choices': ', '.join(map(repr, action.choices))} - msg = _('invalid choice: %(value)r (choose from %(choices)s)') - raise ArgumentError(action, msg % args) + choices = action.choices + if choices is not None: + if isinstance(choices, str): + choices = iter(choices) + if value not in choices: + args = {'value': str(value), + 'choices': ', '.join(map(str, action.choices))} + msg = _('invalid choice: %(value)r (choose from %(choices)s)') + raise ArgumentError(action, msg % args) # ======================= # Help-formatting methods diff --git a/Lib/asyncio/__main__.py b/Lib/asyncio/__main__.py index c39a31d7..29e528ae 100644 --- a/Lib/asyncio/__main__.py +++ b/Lib/asyncio/__main__.py @@ -2,6 +2,7 @@ import asyncio import code import concurrent.futures +import contextvars import inspect import sys import threading @@ -17,6 +18,7 @@ def __init__(self, locals, loop): super().__init__(locals) self.compile.compiler.flags |= ast.PyCF_ALLOW_TOP_LEVEL_AWAIT self.loop = loop + self.context = contextvars.copy_context() def runcode(self, code): future = concurrent.futures.Future() @@ -46,12 +48,12 @@ def callback(): return try: - repl_future = self.loop.create_task(coro) + repl_future = self.loop.create_task(coro, context=self.context) futures._chain_future(repl_future, future) except BaseException as exc: future.set_exception(exc) - loop.call_soon_threadsafe(callback) + loop.call_soon_threadsafe(callback, context=self.context) try: return future.result() @@ -89,6 +91,8 @@ def run(self): if __name__ == '__main__': + sys.audit("cpython.run_stdin") + loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 29eff049..3146f7f3 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -17,7 +17,6 @@ import collections.abc import concurrent.futures import errno -import functools import heapq import itertools import os @@ -994,8 +993,7 @@ async def _connect_sock(self, exceptions, addr_info, local_addr_infos=None): except OSError as exc: msg = ( f'error while attempting to bind on ' - f'address {laddr!r}: ' - f'{exc.strerror.lower()}' + f'address {laddr!r}: {str(exc).lower()}' ) exc = OSError(exc.errno, msg) my_exceptions.append(exc) @@ -1107,11 +1105,18 @@ async def create_connection( except OSError: continue else: # using happy eyeballs - sock, _, _ = await staggered.staggered_race( - (functools.partial(self._connect_sock, - exceptions, addrinfo, laddr_infos) - for addrinfo in infos), - happy_eyeballs_delay, loop=self) + sock = (await staggered.staggered_race( + ( + # can't use functools.partial as it keeps a reference + # to exceptions + lambda addrinfo=addrinfo: self._connect_sock( + exceptions, addrinfo, laddr_infos + ) + for addrinfo in infos + ), + happy_eyeballs_delay, + loop=self, + ))[0] # can't use sock, _, _ as it keeks a reference to exceptions if sock is None: exceptions = [exc for sub in exceptions for exc in sub] @@ -1561,7 +1566,7 @@ async def create_server( except OSError as err: msg = ('error while attempting ' 'to bind on address %r: %s' - % (sa, err.strerror.lower())) + % (sa, str(err).lower())) if err.errno == errno.EADDRNOTAVAIL: # Assume the family is not enabled (bpo-30945) sockets.pop() diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py index 97fc4e3f..0c530bbd 100644 --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -194,8 +194,7 @@ def result(self): the future is done and has an exception set, this exception is raised. """ if self._state == _CANCELLED: - exc = self._make_cancelled_error() - raise exc + raise self._make_cancelled_error() if self._state != _FINISHED: raise exceptions.InvalidStateError('Result is not ready.') self.__log_traceback = False @@ -212,8 +211,7 @@ def exception(self): InvalidStateError. """ if self._state == _CANCELLED: - exc = self._make_cancelled_error() - raise exc + raise self._make_cancelled_error() if self._state != _FINISHED: raise exceptions.InvalidStateError('Exception is not set.') self.__log_traceback = False @@ -272,9 +270,13 @@ def set_exception(self, exception): raise exceptions.InvalidStateError(f'{self._state}: {self!r}') if isinstance(exception, type): exception = exception() - if type(exception) is StopIteration: - raise TypeError("StopIteration interacts badly with generators " - "and cannot be raised into a Future") + if isinstance(exception, StopIteration): + new_exc = RuntimeError("StopIteration interacts badly with " + "generators and cannot be raised into a " + "Future") + new_exc.__cause__ = exception + new_exc.__context__ = exception + exception = new_exc self._exception = exception self._exception_tb = exception.__traceback__ self._state = _FINISHED diff --git a/Lib/asyncio/sslproto.py b/Lib/asyncio/sslproto.py index e51669a2..29e72b1f 100644 --- a/Lib/asyncio/sslproto.py +++ b/Lib/asyncio/sslproto.py @@ -101,7 +101,7 @@ def get_protocol(self): return self._ssl_protocol._app_protocol def is_closing(self): - return self._closed + return self._closed or self._ssl_protocol._is_transport_closing() def close(self): """Close the transport. @@ -379,6 +379,9 @@ def _get_app_transport(self): self._app_transport_created = True return self._app_transport + def _is_transport_closing(self): + return self._transport is not None and self._transport.is_closing() + def connection_made(self, transport): """Called when the low-level connection is made. diff --git a/Lib/asyncio/staggered.py b/Lib/asyncio/staggered.py index 451a53a1..0f4df885 100644 --- a/Lib/asyncio/staggered.py +++ b/Lib/asyncio/staggered.py @@ -3,7 +3,6 @@ __all__ = 'staggered_race', import contextlib -import typing from . import events from . import exceptions as exceptions_mod @@ -11,16 +10,7 @@ from . import tasks -async def staggered_race( - coro_fns: typing.Iterable[typing.Callable[[], typing.Awaitable]], - delay: typing.Optional[float], - *, - loop: events.AbstractEventLoop = None, -) -> typing.Tuple[ - typing.Any, - typing.Optional[int], - typing.List[typing.Optional[Exception]] -]: +async def staggered_race(coro_fns, delay, *, loop=None): """Run coroutines with staggered start times and take the first to finish. This method takes an iterable of coroutine functions. The first one is @@ -79,8 +69,11 @@ async def staggered_race( exceptions = [] running_tasks = [] - async def run_one_coro( - previous_failed: typing.Optional[locks.Event]) -> None: + async def run_one_coro(ok_to_start, previous_failed) -> None: + # in eager tasks this waits for the calling task to append this task + # to running_tasks, in regular tasks this wait is a no-op that does + # not yield a future. See gh-124309. + await ok_to_start.wait() # Wait for the previous task to finish, or for delay seconds if previous_failed is not None: with contextlib.suppress(exceptions_mod.TimeoutError): @@ -96,8 +89,12 @@ async def run_one_coro( return # Start task that will run the next coroutine this_failed = locks.Event() - next_task = loop.create_task(run_one_coro(this_failed)) + next_ok_to_start = locks.Event() + next_task = loop.create_task(run_one_coro(next_ok_to_start, this_failed)) running_tasks.append(next_task) + # next_task has been appended to running_tasks so next_task is ok to + # start. + next_ok_to_start.set() assert len(running_tasks) == this_index + 2 # Prepare place to put this coroutine's exceptions if not won exceptions.append(None) @@ -127,8 +124,11 @@ async def run_one_coro( if i != this_index: t.cancel() - first_task = loop.create_task(run_one_coro(None)) + ok_to_start = locks.Event() + first_task = loop.create_task(run_one_coro(ok_to_start, None)) running_tasks.append(first_task) + # first_task has been appended to running_tasks so first_task is ok to start. + ok_to_start.set() try: # Wait for a growing list of tasks to all finish: poor man's version of # curio's TaskGroup or trio's nursery @@ -144,6 +144,7 @@ async def run_one_coro( raise d.exception() return winner_result, winner_index, exceptions finally: + del exceptions # Make sure no tasks are left running if we leave this function for t in running_tasks: t.cancel() diff --git a/Lib/asyncio/taskgroups.py b/Lib/asyncio/taskgroups.py index d264e51f..aada3ffa 100644 --- a/Lib/asyncio/taskgroups.py +++ b/Lib/asyncio/taskgroups.py @@ -66,6 +66,20 @@ async def __aenter__(self): return self async def __aexit__(self, et, exc, tb): + tb = None + try: + return await self._aexit(et, exc) + finally: + # Exceptions are heavy objects that can have object + # cycles (bad for GC); let's not keep a reference to + # a bunch of them. It would be nicer to use a try/finally + # in __aexit__ directly but that introduced some diff noise + self._parent_task = None + self._errors = None + self._base_error = None + exc = None + + async def _aexit(self, et, exc): self._exiting = True if (exc is not None and @@ -126,25 +140,34 @@ async def __aexit__(self, et, exc, tb): assert not self._tasks if self._base_error is not None: - raise self._base_error + try: + raise self._base_error + finally: + exc = None # Propagate CancelledError if there is one, except if there # are other errors -- those have priority. - if propagate_cancellation_error and not self._errors: - raise propagate_cancellation_error + try: + if propagate_cancellation_error and not self._errors: + try: + raise propagate_cancellation_error + finally: + exc = None + finally: + propagate_cancellation_error = None if et is not None and et is not exceptions.CancelledError: self._errors.append(exc) if self._errors: - # Exceptions are heavy objects that can have object - # cycles (bad for GC); let's not keep a reference to - # a bunch of them. try: - me = BaseExceptionGroup('unhandled errors in a TaskGroup', self._errors) - raise me from None + raise BaseExceptionGroup( + 'unhandled errors in a TaskGroup', + self._errors, + ) from None finally: - self._errors = None + exc = None + def create_task(self, coro, *, name=None, context=None): """Create a new task in this group and return it. diff --git a/Lib/bdb.py b/Lib/bdb.py index 564d6c5e..196e6b17 100644 --- a/Lib/bdb.py +++ b/Lib/bdb.py @@ -295,9 +295,10 @@ def _set_caller_tracefunc(self, current_frame): # Issue #13183: pdb skips frames after hitting a breakpoint and running # step commands. # Restore the trace function in the caller (that may not have been set - # for performance reasons) when returning from the current frame. + # for performance reasons) when returning from the current frame, unless + # the caller is the botframe. caller_frame = current_frame.f_back - if caller_frame and not caller_frame.f_trace: + if caller_frame and not caller_frame.f_trace and caller_frame is not self.botframe: caller_frame.f_trace = self.trace_dispatch # Derived classes and clients can call the following methods diff --git a/Lib/calendar.py b/Lib/calendar.py index 97d7cab3..35096484 100644 --- a/Lib/calendar.py +++ b/Lib/calendar.py @@ -28,7 +28,9 @@ error = ValueError # Exceptions raised for bad input -class IllegalMonthError(ValueError): +# This is trick for backward compatibility. Since 3.13, we will raise IllegalMonthError instead of +# IndexError for bad month number(out of 1-12). But we can't remove IndexError for backward compatibility. +class IllegalMonthError(ValueError, IndexError): def __init__(self, month): self.month = month def __str__(self): @@ -158,11 +160,14 @@ def weekday(year, month, day): return Day(datetime.date(year, month, day).weekday()) -def monthrange(year, month): - """Return weekday (0-6 ~ Mon-Sun) and number of days (28-31) for - year, month.""" +def _validate_month(month): if not 1 <= month <= 12: raise IllegalMonthError(month) + +def monthrange(year, month): + """Return weekday of first day of month (0-6 ~ Mon-Sun) + and number of days (28-31) for year, month.""" + _validate_month(month) day1 = weekday(year, month, 1) ndays = mdays[month] + (month == FEBRUARY and isleap(year)) return day1, ndays @@ -370,6 +375,8 @@ def formatmonthname(self, theyear, themonth, width, withyear=True): """ Return a formatted month name. """ + _validate_month(themonth) + s = month_name[themonth] if withyear: s = "%s %r" % (s, theyear) @@ -500,6 +507,7 @@ def formatmonthname(self, theyear, themonth, withyear=True): """ Return a month name as a table row. """ + _validate_month(themonth) if withyear: s = '%s %s' % (month_name[themonth], theyear) else: @@ -781,6 +789,8 @@ def main(args): if options.month is None: optdict["c"] = options.spacing optdict["m"] = options.months + if options.month is not None: + _validate_month(options.month) if options.year is None: result = cal.formatyear(datetime.date.today().year, **optdict) elif options.month is None: diff --git a/Lib/code.py b/Lib/code.py index 2bd5fa3e..cb7dd44b 100644 --- a/Lib/code.py +++ b/Lib/code.py @@ -105,29 +105,21 @@ def showsyntaxerror(self, filename=None): The output is written by self.write(), below. """ - type, value, tb = sys.exc_info() - sys.last_exc = value - sys.last_type = type - sys.last_value = value - sys.last_traceback = tb - if filename and type is SyntaxError: - # Work hard to stuff the correct filename in the exception - try: - msg, (dummy_filename, lineno, offset, line) = value.args - except ValueError: - # Not the format we expect; leave it alone - pass - else: - # Stuff in the right filename - value = SyntaxError(msg, (filename, lineno, offset, line)) - sys.last_exc = sys.last_value = value - if sys.excepthook is sys.__excepthook__: - lines = traceback.format_exception_only(type, value) - self.write(''.join(lines)) - else: - # If someone has set sys.excepthook, we let that take precedence - # over self.write - sys.excepthook(type, value, tb) + try: + typ, value, tb = sys.exc_info() + if filename and typ is SyntaxError: + # Work hard to stuff the correct filename in the exception + try: + msg, (dummy_filename, lineno, offset, line) = value.args + except ValueError: + # Not the format we expect; leave it alone + pass + else: + # Stuff in the right filename + value = SyntaxError(msg, (filename, lineno, offset, line)) + self._showtraceback(typ, value, None) + finally: + typ = value = tb = None def showtraceback(self): """Display the exception that just occurred. @@ -137,19 +129,34 @@ def showtraceback(self): The output is written by self.write(), below. """ - sys.last_type, sys.last_value, last_tb = ei = sys.exc_info() - sys.last_traceback = last_tb - sys.last_exc = ei[1] try: - lines = traceback.format_exception(ei[0], ei[1], last_tb.tb_next) - if sys.excepthook is sys.__excepthook__: - self.write(''.join(lines)) - else: - # If someone has set sys.excepthook, we let that take precedence - # over self.write - sys.excepthook(ei[0], ei[1], last_tb) + typ, value, tb = sys.exc_info() + self._showtraceback(typ, value, tb.tb_next) finally: - last_tb = ei = None + typ = value = tb = None + + def _showtraceback(self, typ, value, tb): + sys.last_type = typ + sys.last_traceback = tb + sys.last_exc = sys.last_value = value = value.with_traceback(tb) + if sys.excepthook is sys.__excepthook__: + lines = traceback.format_exception(typ, value, tb) + self.write(''.join(lines)) + else: + # If someone has set sys.excepthook, we let that take precedence + # over self.write + try: + sys.excepthook(typ, value, tb) + except SystemExit: + raise + except BaseException as e: + e.__context__ = None + e = e.with_traceback(e.__traceback__.tb_next) + print('Error in sys.excepthook:', file=sys.stderr) + sys.__excepthook__(type(e), e, e.__traceback__) + print(file=sys.stderr) + print('Original exception was:', file=sys.stderr) + sys.__excepthook__(typ, value, tb) def write(self, data): """Write a string. diff --git a/Lib/colorsys.py b/Lib/colorsys.py index bc897bd0..e97f9171 100644 --- a/Lib/colorsys.py +++ b/Lib/colorsys.py @@ -24,7 +24,7 @@ __all__ = ["rgb_to_yiq","yiq_to_rgb","rgb_to_hls","hls_to_rgb", "rgb_to_hsv","hsv_to_rgb"] -# Some floating point constants +# Some floating-point constants ONE_THIRD = 1.0/3.0 ONE_SIXTH = 1.0/6.0 diff --git a/Lib/concurrent/futures/__init__.py b/Lib/concurrent/futures/__init__.py index 292e886d..72de617a 100644 --- a/Lib/concurrent/futures/__init__.py +++ b/Lib/concurrent/futures/__init__.py @@ -23,6 +23,7 @@ 'ALL_COMPLETED', 'CancelledError', 'TimeoutError', + 'InvalidStateError', 'BrokenExecutor', 'Future', 'Executor', diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index 0e452883..ff7c17ef 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -68,27 +68,31 @@ class _ThreadWakeup: def __init__(self): self._closed = False + self._lock = threading.Lock() self._reader, self._writer = mp.Pipe(duplex=False) def close(self): - # Please note that we do not take the shutdown lock when + # Please note that we do not take the self._lock when # calling clear() (to avoid deadlocking) so this method can # only be called safely from the same thread as all calls to - # clear() even if you hold the shutdown lock. Otherwise we + # clear() even if you hold the lock. Otherwise we # might try to read from the closed pipe. - if not self._closed: - self._closed = True - self._writer.close() - self._reader.close() + with self._lock: + if not self._closed: + self._closed = True + self._writer.close() + self._reader.close() def wakeup(self): - if not self._closed: - self._writer.send_bytes(b"") + with self._lock: + if not self._closed: + self._writer.send_bytes(b"") def clear(self): - if not self._closed: - while self._reader.poll(): - self._reader.recv_bytes() + if self._closed: + raise RuntimeError('operation on closed _ThreadWakeup') + while self._reader.poll(): + self._reader.recv_bytes() def _python_exit(): @@ -167,10 +171,8 @@ def __init__(self, work_id, fn, args, kwargs): class _SafeQueue(Queue): """Safe Queue set exception to the future object linked to a job""" - def __init__(self, max_size=0, *, ctx, pending_work_items, shutdown_lock, - thread_wakeup): + def __init__(self, max_size=0, *, ctx, pending_work_items, thread_wakeup): self.pending_work_items = pending_work_items - self.shutdown_lock = shutdown_lock self.thread_wakeup = thread_wakeup super().__init__(max_size, ctx=ctx) @@ -179,8 +181,7 @@ def _on_queue_feeder_error(self, e, obj): tb = format_exception(type(e), e, e.__traceback__) e.__cause__ = _RemoteTraceback('\n"""\n{}"""'.format(''.join(tb))) work_item = self.pending_work_items.pop(obj.work_id, None) - with self.shutdown_lock: - self.thread_wakeup.wakeup() + self.thread_wakeup.wakeup() # work_item can be None if another process terminated. In this # case, the executor_manager_thread fails all work_items # with BrokenProcessPool @@ -305,12 +306,10 @@ def __init__(self, executor): # will wake up the queue management thread so that it can terminate # if there is no pending work item. def weakref_cb(_, - thread_wakeup=self.thread_wakeup, - shutdown_lock=self.shutdown_lock): + thread_wakeup=self.thread_wakeup): mp.util.debug('Executor collected: triggering callback for' ' QueueManager wakeup') - with shutdown_lock: - thread_wakeup.wakeup() + thread_wakeup.wakeup() self.executor_reference = weakref.ref(executor, weakref_cb) @@ -438,11 +437,6 @@ def wait_result_broken_or_wakeup(self): elif wakeup_reader in ready: is_broken = False - # No need to hold the _shutdown_lock here because: - # 1. we're the only thread to use the wakeup reader - # 2. we're also the only thread to call thread_wakeup.close() - # 3. we want to avoid a possible deadlock when both reader and writer - # would block (gh-105829) self.thread_wakeup.clear() return result_item, is_broken, cause @@ -740,10 +734,9 @@ def __init__(self, max_workers=None, mp_context=None, # as it could result in a deadlock if a worker process dies with the # _result_queue write lock still acquired. # - # _shutdown_lock must be locked to access _ThreadWakeup.close() and - # .wakeup(). Care must also be taken to not call clear or close from - # more than one thread since _ThreadWakeup.clear() is not protected by - # the _shutdown_lock + # Care must be taken to only call clear and close from the + # executor_manager_thread, since _ThreadWakeup.clear() is not protected + # by a lock. self._executor_manager_thread_wakeup = _ThreadWakeup() # Create communication channels for the executor @@ -754,7 +747,6 @@ def __init__(self, max_workers=None, mp_context=None, self._call_queue = _SafeQueue( max_size=queue_size, ctx=self._mp_context, pending_work_items=self._pending_work_items, - shutdown_lock=self._shutdown_lock, thread_wakeup=self._executor_manager_thread_wakeup) # Killed worker processes can produce spurious "broken pipe" # tracebacks in the queue's own worker thread. But we detect killed diff --git a/Lib/concurrent/futures/thread.py b/Lib/concurrent/futures/thread.py index 3b3a36a5..61dbff8a 100644 --- a/Lib/concurrent/futures/thread.py +++ b/Lib/concurrent/futures/thread.py @@ -41,6 +41,7 @@ def _python_exit(): os.register_at_fork(before=_global_shutdown_lock.acquire, after_in_child=_global_shutdown_lock._at_fork_reinit, after_in_parent=_global_shutdown_lock.release) + os.register_at_fork(after_in_child=_threads_queues.clear) class _WorkItem: diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index c32a30fb..09a86bd2 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1176,7 +1176,7 @@ def _get_slots(cls): slots = [] if getattr(cls, '__weakrefoffset__', -1) != 0: slots.append('__weakref__') - if getattr(cls, '__dictrefoffset__', -1) != 0: + if getattr(cls, '__dictoffset__', -1) != 0: slots.append('__dict__') yield from slots case str(slot): diff --git a/Lib/decimal.py b/Lib/decimal.py index d61e374b..4d8e15cb 100644 --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -1,6 +1,6 @@ -"""Decimal fixed point and floating point arithmetic. +"""Decimal fixed-point and floating-point arithmetic. -This is an implementation of decimal floating point arithmetic based on +This is an implementation of decimal floating-point arithmetic based on the General Decimal Arithmetic Specification: http://speleotrove.com/decimal/decarith.html diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py index ab3c3031..ec2215a5 100644 --- a/Lib/email/_header_value_parser.py +++ b/Lib/email/_header_value_parser.py @@ -92,6 +92,8 @@ ASPECIALS = TSPECIALS | set("*'%") ATTRIBUTE_ENDS = ASPECIALS | WSP EXTENDED_ATTRIBUTE_ENDS = ATTRIBUTE_ENDS - set('%') +NLSET = {'\n', '\r'} +SPECIALSNL = SPECIALS | NLSET def quote_string(value): return '"'+str(value).replace('\\', '\\\\').replace('"', r'\"')+'"' @@ -2802,9 +2804,13 @@ def _refold_parse_tree(parse_tree, *, policy): wrap_as_ew_blocked -= 1 continue tstr = str(part) - if part.token_type == 'ptext' and set(tstr) & SPECIALS: - # Encode if tstr contains special characters. - want_encoding = True + if not want_encoding: + if part.token_type == 'ptext': + # Encode if tstr contains special characters. + want_encoding = not SPECIALSNL.isdisjoint(tstr) + else: + # Encode if tstr contains newlines. + want_encoding = not NLSET.isdisjoint(tstr) try: tstr.encode(encoding) charset = encoding @@ -2988,6 +2994,7 @@ def _fold_as_ew(to_encode, lines, maxlen, last_ew, ew_combine_allowed, charset, excess = len(encoded_word) - remaining_space lines[-1] += encoded_word to_encode = to_encode[len(to_encode_word):] + leading_whitespace = '' if to_encode: lines.append(' ') diff --git a/Lib/email/_policybase.py b/Lib/email/_policybase.py index 2ec54fba..c9f0d743 100644 --- a/Lib/email/_policybase.py +++ b/Lib/email/_policybase.py @@ -157,6 +157,13 @@ class Policy(_PolicyBase, metaclass=abc.ABCMeta): message_factory -- the class to use to create new message objects. If the value is None, the default is Message. + verify_generated_headers + -- if true, the generator verifies that each header + they are properly folded, so that a parser won't + treat it as multiple headers, start-of-body, or + part of another header. + This is a check against custom Header & fold() + implementations. """ raise_on_defect = False @@ -165,6 +172,7 @@ class Policy(_PolicyBase, metaclass=abc.ABCMeta): max_line_length = 78 mangle_from_ = False message_factory = None + verify_generated_headers = True def handle_defect(self, obj, defect): """Based on policy, either raise defect or call register_defect. @@ -294,12 +302,12 @@ def header_source_parse(self, sourcelines): """+ The name is parsed as everything up to the ':' and returned unmodified. The value is determined by stripping leading whitespace off the - remainder of the first line, joining all subsequent lines together, and + remainder of the first line joined with all subsequent lines, and stripping any trailing carriage return or linefeed characters. """ name, value = sourcelines[0].split(':', 1) - value = value.lstrip(' \t') + ''.join(sourcelines[1:]) + value = ''.join((value, *sourcelines[1:])).lstrip(' \t\r\n') return (name, value.rstrip('\r\n')) def header_store_parse(self, name, value): diff --git a/Lib/email/errors.py b/Lib/email/errors.py index 3ad00565..02aa5ece 100644 --- a/Lib/email/errors.py +++ b/Lib/email/errors.py @@ -29,6 +29,10 @@ class CharsetError(MessageError): """An illegal charset was given.""" +class HeaderWriteError(MessageError): + """Error while writing headers.""" + + # These are parsing defects which the parser was able to work around. class MessageDefect(ValueError): """Base class for a message defect.""" diff --git a/Lib/email/generator.py b/Lib/email/generator.py index c8056ad4..47b9df8f 100644 --- a/Lib/email/generator.py +++ b/Lib/email/generator.py @@ -14,12 +14,14 @@ from copy import deepcopy from io import StringIO, BytesIO from email.utils import _has_surrogates +from email.errors import HeaderWriteError UNDERSCORE = '_' NL = '\n' # XXX: no longer used by the code below. NLCRE = re.compile(r'\r\n|\r|\n') fcre = re.compile(r'^From ', re.MULTILINE) +NEWLINE_WITHOUT_FWSP = re.compile(r'\r\n[^ \t]|\r[^ \n\t]|\n[^ \t]') class Generator: @@ -222,7 +224,16 @@ def _dispatch(self, msg): def _write_headers(self, msg): for h, v in msg.raw_items(): - self.write(self.policy.fold(h, v)) + folded = self.policy.fold(h, v) + if self.policy.verify_generated_headers: + linesep = self.policy.linesep + if not folded.endswith(self.policy.linesep): + raise HeaderWriteError( + f'folded header does not end with {linesep!r}: {folded!r}') + if NEWLINE_WITHOUT_FWSP.search(folded.removesuffix(linesep)): + raise HeaderWriteError( + f'folded header contains newline: {folded!r}') + self.write(folded) # A blank line always separates headers from body self.write(self._NL) diff --git a/Lib/email/policy.py b/Lib/email/policy.py index 46b7de5b..6e109b65 100644 --- a/Lib/email/policy.py +++ b/Lib/email/policy.py @@ -119,13 +119,13 @@ def header_source_parse(self, sourcelines): """+ The name is parsed as everything up to the ':' and returned unmodified. The value is determined by stripping leading whitespace off the - remainder of the first line, joining all subsequent lines together, and + remainder of the first line joined with all subsequent lines, and stripping any trailing carriage return or linefeed characters. (This is the same as Compat32). """ name, value = sourcelines[0].split(':', 1) - value = value.lstrip(' \t') + ''.join(sourcelines[1:]) + value = ''.join((value, *sourcelines[1:])).lstrip(' \t\r\n') return (name, value.rstrip('\r\n')) def header_store_parse(self, name, value): diff --git a/Lib/email/utils.py b/Lib/email/utils.py index aa949aa9..e53abc8b 100644 --- a/Lib/email/utils.py +++ b/Lib/email/utils.py @@ -48,6 +48,7 @@ specialsre = re.compile(r'[][\\()<>@,:;".]') escapesre = re.compile(r'[\\"]') + def _has_surrogates(s): """Return True if s may contain surrogate-escaped binary data.""" # This check is based on the fact that unless there are surrogates, utf8 @@ -106,12 +107,127 @@ def formataddr(pair, charset='utf-8'): return address +def _iter_escaped_chars(addr): + pos = 0 + escape = False + for pos, ch in enumerate(addr): + if escape: + yield (pos, '\\' + ch) + escape = False + elif ch == '\\': + escape = True + else: + yield (pos, ch) + if escape: + yield (pos, '\\') + + +def _strip_quoted_realnames(addr): + """Strip real names between quotes.""" + if '"' not in addr: + # Fast path + return addr + + start = 0 + open_pos = None + result = [] + for pos, ch in _iter_escaped_chars(addr): + if ch == '"': + if open_pos is None: + open_pos = pos + else: + if start != open_pos: + result.append(addr[start:open_pos]) + start = pos + 1 + open_pos = None + + if start < len(addr): + result.append(addr[start:]) + + return ''.join(result) -def getaddresses(fieldvalues): - """Return a list of (REALNAME, EMAIL) for each fieldvalue.""" - all = COMMASPACE.join(str(v) for v in fieldvalues) - a = _AddressList(all) - return a.addresslist + +supports_strict_parsing = True + +def getaddresses(fieldvalues, *, strict=True): + """Return a list of (REALNAME, EMAIL) or ('','') for each fieldvalue. + + When parsing fails for a fieldvalue, a 2-tuple of ('', '') is returned in + its place. + + If strict is true, use a strict parser which rejects malformed inputs. + """ + + # If strict is true, if the resulting list of parsed addresses is greater + # than the number of fieldvalues in the input list, a parsing error has + # occurred and consequently a list containing a single empty 2-tuple [('', + # '')] is returned in its place. This is done to avoid invalid output. + # + # Malformed input: getaddresses(['alice@example.com ']) + # Invalid output: [('', 'alice@example.com'), ('', 'bob@example.com')] + # Safe output: [('', '')] + + if not strict: + all = COMMASPACE.join(str(v) for v in fieldvalues) + a = _AddressList(all) + return a.addresslist + + fieldvalues = [str(v) for v in fieldvalues] + fieldvalues = _pre_parse_validation(fieldvalues) + addr = COMMASPACE.join(fieldvalues) + a = _AddressList(addr) + result = _post_parse_validation(a.addresslist) + + # Treat output as invalid if the number of addresses is not equal to the + # expected number of addresses. + n = 0 + for v in fieldvalues: + # When a comma is used in the Real Name part it is not a deliminator. + # So strip those out before counting the commas. + v = _strip_quoted_realnames(v) + # Expected number of addresses: 1 + number of commas + n += 1 + v.count(',') + if len(result) != n: + return [('', '')] + + return result + + +def _check_parenthesis(addr): + # Ignore parenthesis in quoted real names. + addr = _strip_quoted_realnames(addr) + + opens = 0 + for pos, ch in _iter_escaped_chars(addr): + if ch == '(': + opens += 1 + elif ch == ')': + opens -= 1 + if opens < 0: + return False + return (opens == 0) + + +def _pre_parse_validation(email_header_fields): + accepted_values = [] + for v in email_header_fields: + if not _check_parenthesis(v): + v = "('', '')" + accepted_values.append(v) + + return accepted_values + + +def _post_parse_validation(parsed_email_header_tuples): + accepted_values = [] + # The parser would have parsed a correctly formatted domain-literal + # The existence of an [ after parsing indicates a parsing failure + for v in parsed_email_header_tuples: + if '[' in v[1]: + v = ('', '') + accepted_values.append(v) + + return accepted_values def _format_timetuple_and_zone(timetuple, zone): @@ -128,7 +244,7 @@ def formatdate(timeval=None, localtime=False, usegmt=False): Fri, 09 Nov 2001 01:08:47 -0000 - Optional timeval if given is a floating point time value as accepted by + Optional timeval if given is a floating-point time value as accepted by gmtime() and localtime(), otherwise the current time is used. Optional localtime is a flag that when True, interprets timeval, and @@ -205,16 +321,33 @@ def parsedate_to_datetime(data): tzinfo=datetime.timezone(datetime.timedelta(seconds=tz))) -def parseaddr(addr): +def parseaddr(addr, *, strict=True): """ Parse addr into its constituent realname and email address parts. Return a tuple of realname and email address, unless the parse fails, in which case return a 2-tuple of ('', ''). + + If strict is True, use a strict parser which rejects malformed inputs. """ - addrs = _AddressList(addr).addresslist - if not addrs: - return '', '' + if not strict: + addrs = _AddressList(addr).addresslist + if not addrs: + return ('', '') + return addrs[0] + + if isinstance(addr, list): + addr = addr[0] + + if not isinstance(addr, str): + return ('', '') + + addr = _pre_parse_validation([addr])[0] + addrs = _post_parse_validation(_AddressList(addr).addresslist) + + if not addrs or len(addrs) > 1: + return ('', '') + return addrs[0] diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index 2ac872c2..35d04d2f 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -10,7 +10,7 @@ __all__ = ["version", "bootstrap"] _PACKAGE_NAMES = ('pip',) -_PIP_VERSION = "24.0" +_PIP_VERSION = "24.3.1" _PROJECTS = [ ("pip", _PIP_VERSION, "py3"), ] diff --git a/Lib/ensurepip/_bundled/pip-24.0-py3-none-any.whl b/Lib/ensurepip/_bundled/pip-24.0-py3-none-any.whl deleted file mode 100644 index 2e6aa9d2..00000000 Binary files a/Lib/ensurepip/_bundled/pip-24.0-py3-none-any.whl and /dev/null differ diff --git a/Lib/ensurepip/_bundled/pip-24.3.1-py3-none-any.whl b/Lib/ensurepip/_bundled/pip-24.3.1-py3-none-any.whl new file mode 100644 index 00000000..5f1d35be Binary files /dev/null and b/Lib/ensurepip/_bundled/pip-24.3.1-py3-none-any.whl differ diff --git a/Lib/enum.py b/Lib/enum.py index af561383..eaa517e2 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -487,7 +487,7 @@ def __setitem__(self, key, value): # accepts iterable as multiple arguments? value = t(auto_valued) except TypeError: - # then pass them in singlely + # then pass them in singly value = t(*auto_valued) self._member_names[key] = None if non_auto_store: @@ -592,19 +592,13 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k classdict['_all_bits_'] = 0 classdict['_inverted_'] = None try: - exc = None enum_class = super().__new__(metacls, cls, bases, classdict, **kwds) except Exception as e: - # since 3.12 the line "Error calling __set_name__ on '_proto_member' instance ..." - # is tacked on to the error instead of raising a RuntimeError - # recreate the exception to discard - exc = type(e)(str(e)) - exc.__cause__ = e.__cause__ - exc.__context__ = e.__context__ - tb = e.__traceback__ - if exc is not None: - raise exc.with_traceback(tb) - # + # since 3.12 the note "Error calling __set_name__ on '_proto_member' instance ..." + # is tacked on to the error instead of raising a RuntimeError, so discard it + if hasattr(e, '__notes__'): + del e.__notes__ + raise # update classdict with any changes made by __init_subclass__ classdict.update(enum_class.__dict__) # diff --git a/Lib/filecmp.py b/Lib/filecmp.py index 30bd900f..6fdb48f7 100644 --- a/Lib/filecmp.py +++ b/Lib/filecmp.py @@ -160,12 +160,14 @@ def phase2(self): # Distinguish files, directories, funnies ok = True try: a_stat = os.stat(a_path) - except OSError: + except (OSError, ValueError): + # See https://github.com/python/cpython/issues/122400 + # for the rationale for protecting against ValueError. # print('Can\'t stat', a_path, ':', why.args[1]) ok = False try: b_stat = os.stat(b_path) - except OSError: + except (OSError, ValueError): # print('Can\'t stat', b_path, ':', why.args[1]) ok = False @@ -280,12 +282,12 @@ def cmpfiles(a, b, common, shallow=True): # Return: # 0 for equal # 1 for different -# 2 for funny cases (can't stat, etc.) +# 2 for funny cases (can't stat, NUL bytes, etc.) # def _cmp(a, b, sh, abs=abs, cmp=cmp): try: return not abs(cmp(a, b, sh)) - except OSError: + except (OSError, ValueError): return 2 diff --git a/Lib/fractions.py b/Lib/fractions.py index 88b418fe..e3a8bbcf 100644 --- a/Lib/fractions.py +++ b/Lib/fractions.py @@ -825,8 +825,10 @@ def __pow__(a, b): # A fractional power will generally produce an # irrational number. return float(a) ** float(b) - else: + elif isinstance(b, (float, complex)): return float(a) ** b + else: + return NotImplemented def __rpow__(b, a): """a ** b""" diff --git a/Lib/functools.py b/Lib/functools.py index 1f1ba638..f6849899 100644 --- a/Lib/functools.py +++ b/Lib/functools.py @@ -238,12 +238,14 @@ def reduce(function, sequence, initial=_initial_missing): """ reduce(function, iterable[, initial]) -> value - Apply a function of two arguments cumulatively to the items of a sequence - or iterable, from left to right, so as to reduce the iterable to a single - value. For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates - ((((1+2)+3)+4)+5). If initial is present, it is placed before the items - of the iterable in the calculation, and serves as a default when the - iterable is empty. + Apply a function of two arguments cumulatively to the items of an iterable, from left to right. + + This effectively reduces the iterable to a single value. If initial is present, + it is placed before the items of the iterable in the calculation, and serves as + a default when the iterable is empty. + + For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) + calculates ((((1 + 2) + 3) + 4) + 5). """ it = iter(sequence) @@ -372,15 +374,13 @@ def __init__(self, func, /, *args, **keywords): self.keywords = keywords def __repr__(self): - args = ", ".join(map(repr, self.args)) - keywords = ", ".join("{}={!r}".format(k, v) - for k, v in self.keywords.items()) - format_string = "{module}.{cls}({func}, {args}, {keywords})" - return format_string.format(module=self.__class__.__module__, - cls=self.__class__.__qualname__, - func=self.func, - args=args, - keywords=keywords) + cls = type(self) + module = cls.__module__ + qualname = cls.__qualname__ + args = [repr(self.func)] + args.extend(map(repr, self.args)) + args.extend(f"{k}={v!r}" for k, v in self.keywords.items()) + return f"{module}.{qualname}({', '.join(args)})" def _make_unbound_method(self): def _method(cls_or_self, /, *args, **keywords): diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py index 35ac2dc6..6b9ed24a 100644 --- a/Lib/http/cookies.py +++ b/Lib/http/cookies.py @@ -184,8 +184,13 @@ def _quote(str): return '"' + str.translate(_Translator) + '"' -_OctalPatt = re.compile(r"\\[0-3][0-7][0-7]") -_QuotePatt = re.compile(r"[\\].") +_unquote_sub = re.compile(r'\\(?:([0-3][0-7][0-7])|(.))').sub + +def _unquote_replace(m): + if m[1]: + return chr(int(m[1], 8)) + else: + return m[2] def _unquote(str): # If there aren't any doublequotes, @@ -205,36 +210,13 @@ def _unquote(str): # \012 --> \n # \" --> " # - i = 0 - n = len(str) - res = [] - while 0 <= i < n: - o_match = _OctalPatt.search(str, i) - q_match = _QuotePatt.search(str, i) - if not o_match and not q_match: # Neither matched - res.append(str[i:]) - break - # else: - j = k = -1 - if o_match: - j = o_match.start(0) - if q_match: - k = q_match.start(0) - if q_match and (not o_match or k < j): # QuotePatt matched - res.append(str[i:k]) - res.append(str[k+1]) - i = k + 2 - else: # OctalPatt matched - res.append(str[i:j]) - res.append(chr(int(str[j+1:j+4], 8))) - i = j + 4 - return _nulljoin(res) + return _unquote_sub(_unquote_replace, str) # The _getdate() routine is used to set the expiration time in the cookie's HTTP # header. By default, _getdate() returns the current time in the appropriate # "expires" format for a Set-Cookie header. The one optional argument is an # offset from now, in seconds. For example, an offset of -3600 means "one hour -# ago". The offset may be a floating point number. +# ago". The offset may be a floating-point number. # _weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] diff --git a/Lib/idlelib/HISTORY.txt b/Lib/idlelib/HISTORY.txt index 731fabd1..a601b25b 100644 --- a/Lib/idlelib/HISTORY.txt +++ b/Lib/idlelib/HISTORY.txt @@ -277,7 +277,7 @@ Command to format a paragraph. Debug menu: JIT (Just-In-Time) stack viewer toggle -- if set, the stack viewer -automaticall pops up when you get a traceback. +automatically pops up when you get a traceback. Windows menu: diff --git a/Lib/idlelib/Icons/README.txt b/Lib/idlelib/Icons/README.txt index d91c4d5d..e245bc0b 100644 --- a/Lib/idlelib/Icons/README.txt +++ b/Lib/idlelib/Icons/README.txt @@ -1,13 +1,51 @@ -The IDLE icons are from https://bugs.python.org/issue1490384 +IDLE-PYTHON LOGOS -Created by Andrew Clover. +These are sent to tk on Windows, *NIX, and non-Aqua macOS +in pyshell following "# set application icon". -The original sources are available from Andrew's website: + +2006?: Andrew Clover made variously sized python icons for win23. https://www.doxdesk.com/software/py/pyicons.html -Various different formats and sizes are available at this GitHub Pull Request: -https://github.com/python/cpython/pull/17473 +2006: 16, 32, and 48 bit .png versions were copied to CPython +as Python application icons, maybe in PC/icons/py.ico. +https://github.com/python/cpython/issues/43372 + +2014: They were copied (perhaps a bit revised) to idlelib/Icons. +https://github.com/python/cpython/issues/64605 +.gif versions were also added. + +2020: Add Clover's 256-bit image. +https://github.com/python/cpython/issues/82620 +Other fixups were done. + +The idle.ico file used for Windows was created with ImageMagick: + $ convert idle_16.png idle_32.png idle_48.png idle_256.png idle.ico +** This needs redoing whenever files are changed. +?? Do Start, Desktop, and Taskbar use idlelib/Icons files? + +Issue added Windows Store PC/icons/idlex44.png and .../idlex150.png. +https://github.com/python/cpython/pull/22817 +?? Should these be updated with major changes? + +2022: Optimize .png images in CPython repository with external program. +https://github.com/python/cpython/pull/21348 +idle.ico (and idlex##) were not updated. + +The idlexx.gif files are only needed for *nix running tcl/tk 8.5. +As of 2022, this was known true for 1 'major' Linux distribution. +(Same would be true for any non-Aqua macOS with 8.5, but now none?) +Can be deleted when we require 8.6 or it is known always used. + +Future: Derivatives of Python logo should be submitted for approval. +PSF Trademark Working Group / Committee psf-trademarks@python.org +https://www.python.org/community/logos/ # Original files +https://www.python.org/psf/trademarks-faq/ +https://www.python.org/psf/trademarks/ # Usage. + + +OTHER GIFS: These are used by browsers using idlelib.tree. +At least some will not be used when tree is replaced by ttk.Treeview. -The idle.ico file was created with ImageMagick: - $ convert idle_16.png idle_32.png idle_48.png idle_256.png idle.ico +Edited 2024 August 26 by TJR. diff --git a/Lib/idlelib/News3.txt b/Lib/idlelib/News3.txt index d60f9242..2735ad7e 100644 --- a/Lib/idlelib/News3.txt +++ b/Lib/idlelib/News3.txt @@ -4,6 +4,16 @@ Released after 2023-10-02 ========================= +gh-120083: Add explicit black IDLE Hovertip foreground color needed for +recent macOS. Fixes Sonoma showing unreadable white on pale yellow. +Patch by John Riggles. + +gh-122482: Change About IDLE to direct users to discuss.python.org +instead of the now unused idle-dev email and mailing list. + +gh-78889: Stop Shell freezes by blocking user access to non-method +sys.stdout.shell attributes, which are all private. + gh-78955: Use user-selected color theme for Help => IDLE Doc. gh-96905: In idlelib code, stop redefining built-ins 'dict' and 'object'. @@ -567,14 +577,14 @@ bpo-33679: Enable theme-specific color configuration for Code Context. color setting, default or custom, on the extensions tab, that applied to all themes.) For built-in themes, the foreground is the same as normal text and the background is a contrasting gray. Context colors for -custom themes are set on the Hightlights tab along with other colors. +custom themes are set on the Highlights tab along with other colors. When one starts IDLE from a console and loads a custom theme without definitions for 'context', one will see a warning message on the console. bpo-33642: Display up to maxlines non-blank lines for Code Context. If there is no current context, show a single blank line. (Previously, -the Code Contex had numlines lines, usually with some blank.) The use +the Code Context had numlines lines, usually with some blank.) The use of a new option, 'maxlines' (default 15), avoids possible interference with user settings of the old option, 'numlines' (default 3). @@ -728,7 +738,7 @@ not affect their keyset-specific customization after 3.6.3. and vice versa. Initial patch by Charles Wohlganger, revised by Terry Jan Reedy. -bpo-31051: Rearrange condigdialog General tab. +bpo-31051: Rearrange configdialog General tab. Sort non-Help options into Window (Shell+Editor) and Editor (only). Leave room for the addition of new options. Patch by Terry Jan Reedy. diff --git a/Lib/idlelib/TODO.txt b/Lib/idlelib/TODO.txt index e2f1ac0f..41b86b0c 100644 --- a/Lib/idlelib/TODO.txt +++ b/Lib/idlelib/TODO.txt @@ -179,7 +179,7 @@ it -- i.e. you can only edit the current command, and the cursor can't escape from the command area. (Albert Brandl) - Set X11 class to "idle/Idle", set icon and title to something -beginning with "idle" -- for window manangers. (Randall Hopper) +beginning with "idle" -- for window managers. (Randall Hopper) - Config files editable through a preferences dialog. (me) DONE diff --git a/Lib/idlelib/config.py b/Lib/idlelib/config.py index 6a5acac9..d10c88a4 100644 --- a/Lib/idlelib/config.py +++ b/Lib/idlelib/config.py @@ -600,7 +600,7 @@ def GetCoreKeys(self, keySetName=None): """ # TODO: = dict(sorted([(v-event, keys), ...]))? keyBindings={ - # vitual-event: list of key events. + # virtual-event: list of key events. '<>': ['', ''], '<>': ['', ''], '<>': ['', ''], diff --git a/Lib/idlelib/configdialog.py b/Lib/idlelib/configdialog.py index eedf97bf..4d2adb48 100644 --- a/Lib/idlelib/configdialog.py +++ b/Lib/idlelib/configdialog.py @@ -111,7 +111,7 @@ def create_widgets(self): load_configs: Load pages except for extensions. activate_config_changes: Tell editors to reload. """ - self.frame = frame = Frame(self, padding="5px") + self.frame = frame = Frame(self, padding=5) self.frame.grid(sticky="nwes") self.note = note = Notebook(frame) self.extpage = ExtPage(note) diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 7bfa0932..c76db20c 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -914,7 +914,7 @@ def RemoveKeybindings(self): def ApplyKeybindings(self): """Apply the virtual, configurable keybindings. - Alse update hotkeys to current keyset. + Also update hotkeys to current keyset. """ # Called from configdialog.activate_config_changes. self.mainmenu.default_keydefs = keydefs = idleConf.GetCurrentKeySet() diff --git a/Lib/idlelib/extend.txt b/Lib/idlelib/extend.txt index b482f76c..2522758c 100644 --- a/Lib/idlelib/extend.txt +++ b/Lib/idlelib/extend.txt @@ -52,7 +52,7 @@ should probably be refined in the future.) Extensions are not required to define menu entries for all the events they implement. (They are also not required to create keybindings, but in that -case there must be empty bindings in cofig-extensions.def) +case there must be empty bindings in config-extensions.def) Here is a partial example from zzdummy.py: diff --git a/Lib/idlelib/grep.py b/Lib/idlelib/grep.py index ef143499..42048ff2 100644 --- a/Lib/idlelib/grep.py +++ b/Lib/idlelib/grep.py @@ -190,7 +190,7 @@ def grep_it(self, prog, path): def _grep_dialog(parent): # htest # - from tkinter import Toplevel, Text, SEL, END + from tkinter import Toplevel, Text, SEL from tkinter.ttk import Frame, Button from idlelib.pyshell import PyShellFileList diff --git a/Lib/idlelib/help.html b/Lib/idlelib/help.html index 827d230b..2a4adc6a 100644 --- a/Lib/idlelib/help.html +++ b/Lib/idlelib/help.html @@ -5,7 +5,7 @@ - IDLE — Python 3.13.0a2 documentation + IDLE — Python 3.14.0a0 documentation @@ -18,7 +18,7 @@ @@ -26,6 +26,7 @@ + @@ -45,6 +46,8 @@ + + @@ -184,7 +187,7 @@

Navigation

  • - 3.13.0a2 Documentation » + 3.14.0a0 Documentation »
  • @@ -554,7 +557,7 @@

    Key bindingsControl key on Windows and -Unix and the Command key on macOS. (And all such dicussions +Unix and the Command key on macOS. (And all such discussions assume that the keys have not been re-bound to something else.)

    @@ -694,7 +697,7 @@

    Shell window -
  • C-c attemps to interrupt statement execution (but may fail).

  • +
  • C-c attempts to interrupt statement execution (but may fail).

  • C-d closes Shell if typed at a >>> prompt.

  • Alt-p and Alt-n (C-p and C-n on macOS) retrieve to the current prompt the previous or next previously @@ -1136,7 +1139,7 @@

    Navigation

  • - 3.13.0a2 Documentation » + 3.14.0a0 Documentation »
  • @@ -1180,7 +1183,7 @@

    Navigation



    - Last updated on Jan 17, 2024 (06:57 UTC). + Last updated on Oct 14, 2024 (20:27 UTC). Found a bug?
    diff --git a/Lib/idlelib/help_about.py b/Lib/idlelib/help_about.py index aa1c3528..81c65f62 100644 --- a/Lib/idlelib/help_about.py +++ b/Lib/idlelib/help_about.py @@ -85,15 +85,18 @@ def create_widgets(self): byline = Label(frame_background, text=byline_text, justify=LEFT, fg=self.fg, bg=self.bg) byline.grid(row=2, column=0, sticky=W, columnspan=3, padx=10, pady=5) - email = Label(frame_background, text='email: idle-dev@python.org', - justify=LEFT, fg=self.fg, bg=self.bg) - email.grid(row=6, column=0, columnspan=2, sticky=W, padx=10, pady=0) + + forums_url = "https://discuss.python.org" + forums = Label(frame_background, text="Python forums: "+forums_url, + justify=LEFT, fg=self.fg, bg=self.bg) + forums.grid(row=6, column=0, sticky=W, padx=10, pady=0) + forums.bind("", lambda event: webbrowser.open(forums_url)) docs_url = ("https://docs.python.org/%d.%d/library/idle.html" % sys.version_info[:2]) docs = Label(frame_background, text=docs_url, justify=LEFT, fg=self.fg, bg=self.bg) docs.grid(row=7, column=0, columnspan=2, sticky=W, padx=10, pady=0) - docs.bind("", lambda event: webbrowser.open(docs['text'])) + docs.bind("", lambda event: webbrowser.open(docs_url)) Frame(frame_background, borderwidth=1, relief=SUNKEN, height=2, bg=self.bg).grid(row=8, column=0, sticky=EW, @@ -123,9 +126,7 @@ def create_widgets(self): height=2, bg=self.bg).grid(row=11, column=0, sticky=EW, columnspan=3, padx=5, pady=5) - idle = Label(frame_background, - text='IDLE', - fg=self.fg, bg=self.bg) + idle = Label(frame_background, text='IDLE', fg=self.fg, bg=self.bg) idle.grid(row=12, column=0, sticky=W, padx=10, pady=0) idle_buttons = Frame(frame_background, bg=self.bg) idle_buttons.grid(row=13, column=0, columnspan=3, sticky=NSEW) diff --git a/Lib/idlelib/idle_test/example_stub.pyi b/Lib/idlelib/idle_test/example_stub.pyi index 17b58010..abcdbc17 100644 --- a/Lib/idlelib/idle_test/example_stub.pyi +++ b/Lib/idlelib/idle_test/example_stub.pyi @@ -1,4 +1,4 @@ -" Example to test recognition of .pyi file as Python source code. +# An example file to test recognition of a .pyi file as Python source code. class Example: def method(self, argument1: str, argument2: list[int]) -> None: ... diff --git a/Lib/idlelib/idle_test/test_outwin.py b/Lib/idlelib/idle_test/test_outwin.py index d6e85ad6..81f4aad7 100644 --- a/Lib/idlelib/idle_test/test_outwin.py +++ b/Lib/idlelib/idle_test/test_outwin.py @@ -1,6 +1,7 @@ "Test outwin, coverage 76%." from idlelib import outwin +import sys import unittest from test.support import requires from tkinter import Tk, Text @@ -18,6 +19,10 @@ def setUpClass(cls): root.withdraw() w = cls.window = outwin.OutputWindow(None, None, None, root) cls.text = w.text = Text(root) + if sys.platform == 'darwin': # Issue 112938 + cls.text.update = cls.text.update_idletasks + # Without this, test write, writelines, and goto... fail. + # The reasons and why macOS-specific are unclear. @classmethod def tearDownClass(cls): diff --git a/Lib/idlelib/outwin.py b/Lib/idlelib/outwin.py index 5ed3f35a..8baa6575 100644 --- a/Lib/idlelib/outwin.py +++ b/Lib/idlelib/outwin.py @@ -112,7 +112,7 @@ def write(self, s, tags=(), mark="insert"): assert isinstance(s, str) self.text.insert(mark, s, tags) self.text.see(mark) - self.text.update_idletasks() + self.text.update() return len(s) def writelines(self, lines): diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index d8b2652d..e882c6cb 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -706,7 +706,7 @@ def prepend_syspath(self, filename): del _filename, _sys, _dirname, _dir \n""".format(filename)) - def showsyntaxerror(self, filename=None): + def showsyntaxerror(self, filename=None, **kwargs): """Override Interactive Interpreter method: Use Colorizing Color the offending position instead of printing it and pointing at it diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index 53e80a9b..2faeba67 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -101,11 +101,11 @@ def handle_tk_events(tcl=tcl): # Thread shared globals: Establish a queue between a subthread (which handles # the socket) and the main thread (which runs user code), plus global -# completion, exit and interruptable (the main thread) flags: +# completion, exit and interruptible (the main thread) flags: exit_now = False quitting = False -interruptable = False +interruptible = False def main(del_exitfunc=False): """Start the Python execution server in a subprocess @@ -436,6 +436,9 @@ class StdioFile(io.TextIOBase): def __init__(self, shell, tags, encoding='utf-8', errors='strict'): self.shell = shell + # GH-78889: accessing unpickleable attributes freezes Shell. + # IDLE only needs methods; allow 'width' for possible use. + self.shell._RPCProxy__attributes = {'width': 1} self.tags = tags self._encoding = encoding self._errors = errors @@ -572,14 +575,14 @@ def __init__(self, rpchandler): self.locals = {} def runcode(self, code): - global interruptable + global interruptible try: self.user_exc_info = None - interruptable = True + interruptible = True try: exec(code, self.locals) finally: - interruptable = False + interruptible = False except SystemExit as e: if e.args: # SystemExit called with an argument. ob = e.args[0] @@ -605,7 +608,7 @@ def runcode(self, code): flush_stdout() def interrupt_the_server(self): - if interruptable: + if interruptible: thread.interrupt_main() def start_the_debugger(self, gui_adap_oid): diff --git a/Lib/idlelib/searchbase.py b/Lib/idlelib/searchbase.py index 64ed50c7..c68a6ca3 100644 --- a/Lib/idlelib/searchbase.py +++ b/Lib/idlelib/searchbase.py @@ -86,7 +86,7 @@ def create_widgets(self): top.wm_iconname(self.icon) _setup_dialog(top) self.top = top - self.frame = Frame(top, padding="5px") + self.frame = Frame(top, padding=5) self.frame.grid(sticky="nwes") top.grid_columnconfigure(0, weight=100) top.grid_rowconfigure(0, weight=100) diff --git a/Lib/idlelib/tooltip.py b/Lib/idlelib/tooltip.py index 3983690d..df5b1fe1 100644 --- a/Lib/idlelib/tooltip.py +++ b/Lib/idlelib/tooltip.py @@ -144,7 +144,8 @@ def hidetip(self): 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): + def __init__(self, anchor_widget, text, hover_delay=1000, + foreground="#000000", background="#ffffe0"): """Create a text tooltip with a mouse hover delay. anchor_widget: the widget next to which the tooltip will be shown @@ -156,10 +157,13 @@ def __init__(self, anchor_widget, text, hover_delay=1000): """ super().__init__(anchor_widget, hover_delay=hover_delay) self.text = text + self.foreground = foreground + self.background = background def showcontents(self): label = Label(self.tipwindow, text=self.text, justify=LEFT, - background="#ffffe0", relief=SOLID, borderwidth=1) + relief=SOLID, borderwidth=1, + foreground=self.foreground, background=self.background) label.pack() diff --git a/Lib/idlelib/tree.py b/Lib/idlelib/tree.py index 0726d7e2..182ce718 100644 --- a/Lib/idlelib/tree.py +++ b/Lib/idlelib/tree.py @@ -83,6 +83,8 @@ def wheel_event(event, widget=None): class TreeNode: + dy = 0 + def __init__(self, canvas, parent, item): self.canvas = canvas self.parent = parent @@ -199,23 +201,22 @@ def update(self): def draw(self, x, y): # XXX This hard-codes too many geometry constants! - dy = 20 self.x, self.y = x, y self.drawicon() self.drawtext() if self.state != 'expanded': - return y + dy + return y + TreeNode.dy # draw children if not self.children: sublist = self.item._GetSubList() if not sublist: # _IsExpandable() was mistaken; that's allowed - return y+17 + return y + TreeNode.dy for item in sublist: child = self.__class__(self.canvas, self, item) self.children.append(child) cx = x+20 - cy = y + dy + cy = y + TreeNode.dy cylast = 0 for child in self.children: cylast = cy @@ -289,6 +290,11 @@ def drawtext(self): self.label.bind("", lambda e: wheel_event(e, self.canvas)) self.label.bind("", lambda e: wheel_event(e, self.canvas)) self.text_id = id + if TreeNode.dy == 0: + # The first row doesn't matter what the dy is, just measure its + # size to get the value of the subsequent dy + coords = self.canvas.bbox(id) + TreeNode.dy = max(20, coords[3] - coords[1] - 3) def select_or_edit(self, event=None): if self.selected and self.item.IsEditable(): diff --git a/Lib/importlib/__init__.py b/Lib/importlib/__init__.py index 707c081c..5b92442f 100644 --- a/Lib/importlib/__init__.py +++ b/Lib/importlib/__init__.py @@ -105,7 +105,7 @@ def reload(module): try: name = module.__name__ except AttributeError: - raise TypeError("reload() argument must be a module") + raise TypeError("reload() argument must be a module") from None if sys.modules.get(name) is not module: raise ImportError(f"module {name} not in sys.modules", name=name) diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 61dafc0f..9b8a8dfc 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -204,7 +204,11 @@ def _write_atomic(path, data, mode=0o666): # We first write data to a temporary file, and then use os.replace() to # perform an atomic rename. with _io.FileIO(fd, 'wb') as file: - file.write(data) + bytes_written = file.write(data) + if bytes_written != len(data): + # Raise an OSError so the 'except' below cleans up the partially + # written file. + raise OSError("os.write() didn't write the full pyc file") _os.replace(path_tmp, path) except OSError: try: diff --git a/Lib/importlib/metadata/__init__.py b/Lib/importlib/metadata/__init__.py index 54156e93..e6ca1782 100644 --- a/Lib/importlib/metadata/__init__.py +++ b/Lib/importlib/metadata/__init__.py @@ -534,7 +534,7 @@ def _read_files_egginfo_installed(self): paths = ( (subdir / name) .resolve() - .relative_to(self.locate_file('').resolve()) + .relative_to(self.locate_file('').resolve(), walk_up=True) .as_posix() for name in text.splitlines() ) diff --git a/Lib/importlib/resources/readers.py b/Lib/importlib/resources/readers.py index c3cdf769..8e2d8e82 100644 --- a/Lib/importlib/resources/readers.py +++ b/Lib/importlib/resources/readers.py @@ -31,8 +31,10 @@ def files(self): class ZipReader(abc.TraversableResources): def __init__(self, loader, module): - _, _, name = module.rpartition('.') - self.prefix = loader.prefix.replace('\\', '/') + name + '/' + self.prefix = loader.prefix.replace('\\', '/') + if loader.is_package(module): + _, _, name = module.rpartition('.') + self.prefix += name + '/' self.archive = loader.archive def open_resource(self, resource): diff --git a/Lib/importlib/util.py b/Lib/importlib/util.py index 3743e6aa..4b836f47 100644 --- a/Lib/importlib/util.py +++ b/Lib/importlib/util.py @@ -13,7 +13,6 @@ import _imp import sys -import threading import types @@ -253,6 +252,9 @@ def create_module(self, spec): def exec_module(self, module): """Make the module load lazily.""" + # Threading is only needed for lazy loading, and importlib.util can + # be pulled in at interpreter startup, so defer until needed. + import threading module.__spec__.loader = self.loader module.__loader__ = self.loader # Don't need to worry about deep-copying as trying to set an attribute diff --git a/Lib/inspect.py b/Lib/inspect.py index 497169da..b630cb28 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -280,7 +280,13 @@ def get_annotations(obj, *, globals=None, locals=None, eval_str=False): if globals is None: globals = obj_globals if locals is None: - locals = obj_locals + locals = obj_locals or {} + + # "Inject" type parameters into the local namespace + # (unless they are shadowed by assignments *in* the local namespace), + # as a way of emulating annotation scopes when calling `eval()` + if type_params := getattr(obj, "__type_params__", ()): + locals = {param.__name__: param for param in type_params} | locals return_value = {key: value if not isinstance(value, str) else eval(value, globals, locals) @@ -401,13 +407,13 @@ def isgeneratorfunction(obj): return _has_code_flag(obj, CO_GENERATOR) # A marker for markcoroutinefunction and iscoroutinefunction. -_is_coroutine_marker = object() +_is_coroutine_mark = object() def _has_coroutine_mark(f): while ismethod(f): f = f.__func__ f = functools._unwrap_partial(f) - return getattr(f, "_is_coroutine_marker", None) is _is_coroutine_marker + return getattr(f, "_is_coroutine_marker", None) is _is_coroutine_mark def markcoroutinefunction(func): """ @@ -415,7 +421,7 @@ def markcoroutinefunction(func): """ if hasattr(func, '__func__'): func = func.__func__ - func._is_coroutine_marker = _is_coroutine_marker + func._is_coroutine_marker = _is_coroutine_mark return func def iscoroutinefunction(obj): @@ -1632,11 +1638,15 @@ def getclosurevars(func): global_vars = {} builtin_vars = {} unbound_names = set() - for name in code.co_names: - if name in ("None", "True", "False"): - # Because these used to be builtins instead of keywords, they - # may still show up as name references. We ignore them. - continue + global_names = set() + for instruction in dis.get_instructions(code): + opname = instruction.opname + name = instruction.argval + if opname == "LOAD_ATTR": + unbound_names.add(name) + elif opname == "LOAD_GLOBAL": + global_names.add(name) + for name in global_names: try: global_vars[name] = global_ns[name] except KeyError: diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index d8f3b5e2..76031ded 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -310,7 +310,7 @@ def collapse_addresses(addresses): [IPv4Network('192.0.2.0/24')] Args: - addresses: An iterator of IPv4Network or IPv6Network objects. + addresses: An iterable of IPv4Network or IPv6Network objects. Returns: An iterator of the collapsed IPv(4|6)Network objects. @@ -2001,6 +2001,9 @@ def is_multicast(self): See RFC 2373 2.7 for details. """ + ipv4_mapped = self.ipv4_mapped + if ipv4_mapped is not None: + return ipv4_mapped.is_multicast return self in self._constants._multicast_network @property @@ -2012,6 +2015,9 @@ def is_reserved(self): reserved IPv6 Network ranges. """ + ipv4_mapped = self.ipv4_mapped + if ipv4_mapped is not None: + return ipv4_mapped.is_reserved return any(self in x for x in self._constants._reserved_networks) @property @@ -2022,6 +2028,9 @@ def is_link_local(self): A boolean, True if the address is reserved per RFC 4291. """ + ipv4_mapped = self.ipv4_mapped + if ipv4_mapped is not None: + return ipv4_mapped.is_link_local return self in self._constants._linklocal_network @property @@ -2078,6 +2087,9 @@ def is_global(self): ``is_global`` has value opposite to :attr:`is_private`, except for the ``100.64.0.0/10`` IPv4 range where they are both ``False``. """ + ipv4_mapped = self.ipv4_mapped + if ipv4_mapped is not None: + return ipv4_mapped.is_global return not self.is_private @property @@ -2089,6 +2101,9 @@ def is_unspecified(self): RFC 2373 2.5.2. """ + ipv4_mapped = self.ipv4_mapped + if ipv4_mapped is not None: + return ipv4_mapped.is_unspecified return self._ip == 0 @property @@ -2332,6 +2347,8 @@ class _IPv6Constants: IPv6Network('2001:db8::/32'), # IANA says N/A, let's consider it not globally reachable to be safe IPv6Network('2002::/16'), + # RFC 9637: https://www.rfc-editor.org/rfc/rfc9637.html#section-6-2.2 + IPv6Network('3fff::/20'), IPv6Network('fc00::/7'), IPv6Network('fe80::/10'), ] diff --git a/Lib/json/decoder.py b/Lib/json/decoder.py index c5d9ae2d..5e5effea 100644 --- a/Lib/json/decoder.py +++ b/Lib/json/decoder.py @@ -50,17 +50,18 @@ def __reduce__(self): } +HEXDIGITS = re.compile(r'[0-9A-Fa-f]{4}', FLAGS) STRINGCHUNK = re.compile(r'(.*?)(["\\\x00-\x1f])', FLAGS) BACKSLASH = { '"': '"', '\\': '\\', '/': '/', 'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r', 't': '\t', } -def _decode_uXXXX(s, pos): - esc = s[pos + 1:pos + 5] - if len(esc) == 4 and esc[1] not in 'xX': +def _decode_uXXXX(s, pos, _m=HEXDIGITS.match): + esc = _m(s, pos + 1) + if esc is not None: try: - return int(esc, 16) + return int(esc.group(), 16) except ValueError: pass msg = "Invalid \\uXXXX escape" diff --git a/Lib/json/scanner.py b/Lib/json/scanner.py index 7a61cfc2..09089751 100644 --- a/Lib/json/scanner.py +++ b/Lib/json/scanner.py @@ -9,7 +9,7 @@ __all__ = ['make_scanner'] NUMBER_RE = re.compile( - r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?', + r'(-?(?:0|[1-9][0-9]*))(\.[0-9]+)?([eE][-+]?[0-9]+)?', (re.VERBOSE | re.MULTILINE | re.DOTALL)) def py_make_scanner(context): diff --git a/Lib/linecache.py b/Lib/linecache.py index ed4c9700..248cba93 100644 --- a/Lib/linecache.py +++ b/Lib/linecache.py @@ -70,7 +70,7 @@ def checkcache(filename=None): continue # no-op for files loaded via a __loader__ try: stat = os.stat(fullname) - except OSError: + except (OSError, ValueError): cache.pop(filename, None) continue if size != stat.st_size or mtime != stat.st_mtime: @@ -128,10 +128,12 @@ def updatecache(filename, module_globals=None): try: stat = os.stat(fullname) break - except OSError: + except (OSError, ValueError): pass else: return [] + except ValueError: # may be raised by os.stat() + return [] try: with tokenize.open(fullname) as fp: lines = fp.readlines() diff --git a/Lib/logging/config.py b/Lib/logging/config.py index 1824d0aa..c128bc7a 100644 --- a/Lib/logging/config.py +++ b/Lib/logging/config.py @@ -500,6 +500,33 @@ def as_tuple(self, value): value = tuple(value) return value +def _is_queue_like_object(obj): + """Check that *obj* implements the Queue API.""" + if isinstance(obj, (queue.Queue, queue.SimpleQueue)): + return True + # defer importing multiprocessing as much as possible + from multiprocessing.queues import Queue as MPQueue + if isinstance(obj, MPQueue): + return True + # Depending on the multiprocessing start context, we cannot create + # a multiprocessing.managers.BaseManager instance 'mm' to get the + # runtime type of mm.Queue() or mm.JoinableQueue() (see gh-119819). + # + # Since we only need an object implementing the Queue API, we only + # do a protocol check, but we do not use typing.runtime_checkable() + # and typing.Protocol to reduce import time (see gh-121723). + # + # Ideally, we would have wanted to simply use strict type checking + # instead of a protocol-based type checking since the latter does + # not check the method signatures. + # + # Note that only 'put_nowait' and 'get' are required by the logging + # queue handler and queue listener (see gh-124653) and that other + # methods are either optional or unused. + minimal_queue_interface = ['put_nowait', 'get'] + return all(callable(getattr(obj, method, None)) + for method in minimal_queue_interface) + class DictConfigurator(BaseConfigurator): """ Configure logging using a dictionary-like object to describe the @@ -787,25 +814,20 @@ def configure_handler(self, config): # if 'handlers' not in config: # raise ValueError('No handlers specified for a QueueHandler') if 'queue' in config: - from multiprocessing.queues import Queue as MPQueue - from multiprocessing import Manager as MM - proxy_queue = MM().Queue() - proxy_joinable_queue = MM().JoinableQueue() qspec = config['queue'] - if not isinstance(qspec, (queue.Queue, MPQueue, - type(proxy_queue), type(proxy_joinable_queue))): - if isinstance(qspec, str): - q = self.resolve(qspec) - if not callable(q): - raise TypeError('Invalid queue specifier %r' % qspec) - q = q() - elif isinstance(qspec, dict): - if '()' not in qspec: - raise TypeError('Invalid queue specifier %r' % qspec) - q = self.configure_custom(dict(qspec)) - else: + + if isinstance(qspec, str): + q = self.resolve(qspec) + if not callable(q): raise TypeError('Invalid queue specifier %r' % qspec) - config['queue'] = q + config['queue'] = q() + elif isinstance(qspec, dict): + if '()' not in qspec: + raise TypeError('Invalid queue specifier %r' % qspec) + config['queue'] = self.configure_custom(dict(qspec)) + elif not _is_queue_like_object(qspec): + raise TypeError('Invalid queue specifier %r' % qspec) + if 'listener' in config: lspec = config['listener'] if isinstance(lspec, type): diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index 1ae6bb84..73757758 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -187,15 +187,18 @@ def shouldRollover(self, record): Basically, see if the supplied record would cause the file to exceed the size limit we have. """ - # See bpo-45401: Never rollover anything other than regular files - if os.path.exists(self.baseFilename) and not os.path.isfile(self.baseFilename): - return False if self.stream is None: # delay was set... self.stream = self._open() if self.maxBytes > 0: # are we rolling over? + pos = self.stream.tell() + if not pos: + # gh-116263: Never rollover an empty file + return False msg = "%s\n" % self.format(record) - self.stream.seek(0, 2) #due to non-posix-compliant Windows feature - if self.stream.tell() + len(msg) >= self.maxBytes: + if pos + len(msg) >= self.maxBytes: + # See bpo-45401: Never rollover anything other than regular files + if os.path.exists(self.baseFilename) and not os.path.isfile(self.baseFilename): + return False return True return False diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py index 3cc027aa..10f3ddc5 100644 --- a/Lib/mimetypes.py +++ b/Lib/mimetypes.py @@ -551,6 +551,8 @@ def _default_mime_types(): '.csv' : 'text/csv', '.html' : 'text/html', '.htm' : 'text/html', + '.md' : 'text/markdown', + '.markdown': 'text/markdown', '.n3' : 'text/n3', '.txt' : 'text/plain', '.bat' : 'text/plain', diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py index d0582e3c..fdbc3bda 100644 --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -956,7 +956,7 @@ def answer_challenge(connection, authkey: bytes): f'Protocol error, expected challenge: {message=}') message = message[len(_CHALLENGE):] if len(message) < _MD5ONLY_MESSAGE_LENGTH: - raise AuthenticationError('challenge too short: {len(message)} bytes') + raise AuthenticationError(f'challenge too short: {len(message)} bytes') digest = _create_response(authkey, message) connection.send_bytes(digest) response = connection.recv_bytes(256) # reject large message diff --git a/Lib/multiprocessing/forkserver.py b/Lib/multiprocessing/forkserver.py index 4642707d..9fb56327 100644 --- a/Lib/multiprocessing/forkserver.py +++ b/Lib/multiprocessing/forkserver.py @@ -167,6 +167,8 @@ def ensure_running(self): def main(listener_fd, alive_r, preload, main_path=None, sys_path=None): '''Run forkserver.''' if preload: + if sys_path is not None: + sys.path[:] = sys_path if '__main__' in preload and main_path is not None: process.current_process()._inheriting = True try: diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py index 75d9c18c..010d16e1 100644 --- a/Lib/multiprocessing/managers.py +++ b/Lib/multiprocessing/managers.py @@ -755,22 +755,29 @@ class BaseProxy(object): _address_to_local = {} _mutex = util.ForkAwareThreadLock() + # Each instance gets a `_serial` number. Unlike `id(...)`, this number + # is never reused. + _next_serial = 1 + def __init__(self, token, serializer, manager=None, authkey=None, exposed=None, incref=True, manager_owned=False): with BaseProxy._mutex: - tls_idset = BaseProxy._address_to_local.get(token.address, None) - if tls_idset is None: - tls_idset = util.ForkAwareLocal(), ProcessLocalSet() - BaseProxy._address_to_local[token.address] = tls_idset + tls_serials = BaseProxy._address_to_local.get(token.address, None) + if tls_serials is None: + tls_serials = util.ForkAwareLocal(), ProcessLocalSet() + BaseProxy._address_to_local[token.address] = tls_serials + + self._serial = BaseProxy._next_serial + BaseProxy._next_serial += 1 # self._tls is used to record the connection used by this # thread to communicate with the manager at token.address - self._tls = tls_idset[0] + self._tls = tls_serials[0] - # self._idset is used to record the identities of all shared - # objects for which the current process owns references and + # self._all_serials is a set used to record the identities of all + # shared objects for which the current process owns references and # which are in the manager at token.address - self._idset = tls_idset[1] + self._all_serials = tls_serials[1] self._token = token self._id = self._token.id @@ -850,20 +857,20 @@ def _incref(self): dispatch(conn, None, 'incref', (self._id,)) util.debug('INCREF %r', self._token.id) - self._idset.add(self._id) + self._all_serials.add(self._serial) state = self._manager and self._manager._state self._close = util.Finalize( self, BaseProxy._decref, - args=(self._token, self._authkey, state, - self._tls, self._idset, self._Client), + args=(self._token, self._serial, self._authkey, state, + self._tls, self._all_serials, self._Client), exitpriority=10 ) @staticmethod - def _decref(token, authkey, state, tls, idset, _Client): - idset.discard(token.id) + def _decref(token, serial, authkey, state, tls, idset, _Client): + idset.discard(serial) # check whether manager is still alive if state is None or state.value == State.STARTED: diff --git a/Lib/multiprocessing/synchronize.py b/Lib/multiprocessing/synchronize.py index 3ccbfe31..0f682b9a 100644 --- a/Lib/multiprocessing/synchronize.py +++ b/Lib/multiprocessing/synchronize.py @@ -174,7 +174,7 @@ def __repr__(self): name = process.current_process().name if threading.current_thread().name != 'MainThread': name += '|' + threading.current_thread().name - elif self._semlock._get_value() == 1: + elif not self._semlock._is_zero(): name = 'None' elif self._semlock._count() > 0: name = 'SomeOtherThread' @@ -200,7 +200,7 @@ def __repr__(self): if threading.current_thread().name != 'MainThread': name += '|' + threading.current_thread().name count = self._semlock._count() - elif self._semlock._get_value() == 1: + elif not self._semlock._is_zero(): name, count = 'None', 0 elif self._semlock._count() > 0: name, count = 'SomeOtherThread', 'nonzero' diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 2e290dcf..c05e965f 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -561,28 +561,21 @@ def normpath(path): 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 - abspath = _abspath_fallback + 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) else: # use native Windows method on Windows def abspath(path): @@ -590,7 +583,27 @@ def abspath(path): try: return _getfullpathname(normpath(path)) except (OSError, ValueError): - return _abspath_fallback(path) + # See gh-75230, handle outside for cleaner traceback + pass + path = os.fspath(path) + if not isabs(path): + if isinstance(path, bytes): + sep = b'\\' + getcwd = os.getcwdb + else: + sep = '\\' + getcwd = os.getcwd + drive, root, path = splitroot(path) + # Either drive or root can be nonempty, but not both. + if drive or root: + try: + path = join(_getfullpathname(drive + root), path) + except (OSError, ValueError): + # Drive "\0:" cannot exist; use the root directory. + path = drive + sep + path + else: + path = join(getcwd(), path) + return normpath(path) try: from nt import _getfinalpathname, readlink as _nt_readlink diff --git a/Lib/nturl2path.py b/Lib/nturl2path.py index 61852aff..757fd01b 100644 --- a/Lib/nturl2path.py +++ b/Lib/nturl2path.py @@ -15,32 +15,29 @@ def url2pathname(url): # become # C:\foo\bar\spam.foo import string, urllib.parse + if url[:3] == '///': + # URL has an empty authority section, so the path begins on the third + # character. + url = url[2:] + elif url[:12] == '//localhost/': + # Skip past 'localhost' authority. + url = url[11:] + if url[:3] == '///': + # Skip past extra slash before UNC drive in URL path. + url = url[1:] # Windows itself uses ":" even in URLs. url = url.replace(':', '|') if not '|' in url: # No drive specifier, just convert slashes - if url[:4] == '////': - # path is something like ////host/path/on/remote/host - # convert this to \\host\path\on\remote\host - # (notice halving of slashes at the start of the path) - url = url[2:] - components = url.split('/') # make sure not to convert quoted slashes :-) - return urllib.parse.unquote('\\'.join(components)) + return urllib.parse.unquote(url.replace('/', '\\')) comp = url.split('|') if len(comp) != 2 or comp[0][-1] not in string.ascii_letters: error = 'Bad URL: ' + url raise OSError(error) drive = comp[0][-1].upper() - components = comp[1].split('/') - path = drive + ':' - for comp in components: - if comp: - path = path + '\\' + urllib.parse.unquote(comp) - # Issue #11474 - handing url such as |c/| - if path.endswith(':') and url.endswith('/'): - path += '\\' - return path + tail = urllib.parse.unquote(comp[1].replace('/', '\\')) + return drive + ':' + tail def pathname2url(p): """OS-specific conversion from a file system path to a relative URL @@ -52,30 +49,21 @@ def pathname2url(p): import urllib.parse # First, clean up some special forms. We are going to sacrifice # the additional information anyway - if p[:4] == '\\\\?\\': + p = p.replace('\\', '/') + if p[:4] == '//?/': p = p[4:] - if p[:4].upper() == 'UNC\\': - p = '\\' + p[4:] + if p[:4].upper() == 'UNC/': + p = '//' + p[4:] elif p[1:2] != ':': raise OSError('Bad path: ' + p) if not ':' in p: - # No drive specifier, just convert slashes and quote the name - if p[:2] == '\\\\': - # path is something like \\host\path\on\remote\host - # convert this to ////host/path/on/remote/host - # (notice doubling of slashes at the start of the path) - p = '\\\\' + p - components = p.split('\\') - return urllib.parse.quote('/'.join(components)) + # No DOS drive specified, just quote the pathname + return urllib.parse.quote(p) comp = p.split(':', maxsplit=2) if len(comp) != 2 or len(comp[0]) > 1: error = 'Bad path: ' + p raise OSError(error) drive = urllib.parse.quote(comp[0].upper()) - components = comp[1].split('\\') - path = '///' + drive + ':' - for comp in components: - if comp: - path = path + '/' + urllib.parse.quote(comp) - return path + tail = urllib.parse.quote(comp[1]) + return '///' + drive + ':' + tail diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 65ff0ee1..02eb5c25 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -359,9 +359,9 @@ def __init__(self, *args): paths = [] for arg in args: if isinstance(arg, PurePath): - if arg._flavour is ntpath and self._flavour is posixpath: + if arg._flavour is not self._flavour: # GH-103631: Convert separators for backwards compatibility. - paths.extend(path.replace('\\', '/') for path in arg._raw_paths) + paths.append(arg.as_posix()) else: paths.extend(arg._raw_paths) else: diff --git a/Lib/pdb.py b/Lib/pdb.py index 225c9f25..1e1b5ea4 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -96,7 +96,7 @@ class Restart(Exception): "post_mortem", "help"] def find_function(funcname, filename): - cre = re.compile(r'def\s+%s\s*[(]' % re.escape(funcname)) + cre = re.compile(r'def\s+%s(\s*\[.+\])?\s*[(]' % re.escape(funcname)) try: fp = tokenize.open(filename) except OSError: @@ -321,8 +321,7 @@ def user_call(self, frame, argument_list): def user_line(self, frame): """This function is called when we stop or break at this line.""" if self._wait_for_mainpyfile: - if (self.mainpyfile != self.canonic(frame.f_code.co_filename) - or frame.f_lineno <= 0): + if (self.mainpyfile != self.canonic(frame.f_code.co_filename)): return self._wait_for_mainpyfile = False if self.bp_commands(frame): @@ -395,7 +394,7 @@ def _cmdloop(self): # Called before loop, handles display expressions # Set up convenience variable containers - def preloop(self): + def _show_display(self): displaying = self.displaying.get(self.curframe) if displaying: for expr, oldvalue in displaying.items(): @@ -419,10 +418,16 @@ def interaction(self, frame, traceback): else: Pdb._previous_sigint_handler = None self.setup(frame, traceback) - # if we have more commands to process, do not show the stack entry - if not self.cmdqueue: - self.print_stack_entry(self.stack[self.curindex]) + # We should print the stack entry if and only if the user input + # is expected, and we should print it right before the user input. + # We achieve this by appending _pdbcmd_print_frame_status to the + # command queue. If cmdqueue is not exausted, the user input is + # not expected and we will not print the stack entry. + self.cmdqueue.append('_pdbcmd_print_frame_status') self._cmdloop() + # If _pdbcmd_print_frame_status is not used, pop it out + if self.cmdqueue and self.cmdqueue[-1] == '_pdbcmd_print_frame_status': + self.cmdqueue.pop() self.forget() def displayhook(self, obj): @@ -524,6 +529,10 @@ def onecmd(self, line): a breakpoint command list definition. """ if not self.commands_defining: + if line.startswith('_pdbcmd'): + command, arg, line = self.parseline(line) + if hasattr(self, command): + return getattr(self, command)(arg) return cmd.Cmd.onecmd(self, line) else: return self.handle_command_def(line) @@ -623,6 +632,12 @@ def _complete_expression(self, text, line, begidx, endidx): # Complete a simple name. return [n for n in ns.keys() if n.startswith(text)] + # Pdb meta commands, only intended to be used internally by pdb + + def _pdbcmd_print_frame_status(self, arg): + self.print_stack_entry(self.stack[self.curindex]) + self._show_display() + # Command definitions, called by cmdloop() # The argument is the remaining string on the command line # Return true to exit from the command loop diff --git a/Lib/pickle.py b/Lib/pickle.py index 6e3c61fd..ea5f1c5d 100644 --- a/Lib/pickle.py +++ b/Lib/pickle.py @@ -314,16 +314,17 @@ def load_frame(self, frame_size): # Tools used for pickling. def _getattribute(obj, name): + top = obj for subpath in name.split('.'): if subpath == '': raise AttributeError("Can't get local attribute {!r} on {!r}" - .format(name, obj)) + .format(name, top)) try: parent = obj obj = getattr(obj, subpath) except AttributeError: raise AttributeError("Can't get attribute {!r} on {!r}" - .format(name, obj)) from None + .format(name, top)) from None return obj, parent def whichmodule(obj, name): @@ -396,6 +397,8 @@ def decode_long(data): return int.from_bytes(data, byteorder='little', signed=True) +_NoValue = object() + # Pickling machinery class _Pickler: @@ -530,10 +533,11 @@ def save(self, obj, save_persistent_id=True): self.framer.commit_frame() # Check for persistent id (defined by a subclass) - pid = self.persistent_id(obj) - if pid is not None and save_persistent_id: - self.save_pers(pid) - return + if save_persistent_id: + pid = self.persistent_id(obj) + if pid is not None: + self.save_pers(pid) + return # Check the memo x = self.memo.get(id(obj)) @@ -780,14 +784,10 @@ def save_float(self, obj): self.write(FLOAT + repr(obj).encode("ascii") + b'\n') dispatch[float] = save_float - def save_bytes(self, obj): - if self.proto < 3: - if not obj: # bytes object is empty - self.save_reduce(bytes, (), obj=obj) - else: - self.save_reduce(codecs.encode, - (str(obj, 'latin1'), 'latin1'), obj=obj) - return + def _save_bytes_no_memo(self, obj): + # helper for writing bytes objects for protocol >= 3 + # without memoizing them + assert self.proto >= 3 n = len(obj) if n <= 0xff: self.write(SHORT_BINBYTES + pack("= 5 + # without memoizing them + assert self.proto >= 5 + n = len(obj) + if n >= self.framer._FRAME_SIZE_TARGET: + self._write_large_bytes(BYTEARRAY8 + pack("= self.framer._FRAME_SIZE_TARGET: - self._write_large_bytes(BYTEARRAY8 + pack("= 5") with obj.raw() as m: if not m.contiguous: @@ -830,10 +846,18 @@ def save_picklebuffer(self, obj): if in_band: # Write data in-band # XXX The C implementation avoids a copy here + buf = m.tobytes() + in_memo = id(buf) in self.memo if m.readonly: - self.save_bytes(m.tobytes()) + if in_memo: + self._save_bytes_no_memo(buf) + else: + self.save_bytes(buf) else: - self.save_bytearray(m.tobytes()) + if in_memo: + self._save_bytearray_no_memo(buf) + else: + self.save_bytearray(buf) else: # Write data out-of-band self.write(NEXT_BUFFER) @@ -1070,11 +1094,16 @@ def save_global(self, obj, name=None): (obj, module_name, name)) if self.proto >= 2: - code = _extension_registry.get((module_name, name)) - if code: - assert code > 0 + code = _extension_registry.get((module_name, name), _NoValue) + if code is not _NoValue: if code <= 0xff: - write(EXT1 + pack("= 3: - write(GLOBAL + bytes(module_name, "utf-8") + b'\n' + - bytes(name, "utf-8") + b'\n') + elif '.' in name: + # In protocol < 4, objects with multi-part __qualname__ + # are represented as + # getattr(getattr(..., attrname1), attrname2). + dotted_path = name.split('.') + name = dotted_path.pop(0) + save = self.save + for attrname in dotted_path: + save(getattr) + if self.proto < 2: + write(MARK) + self._save_toplevel_by_name(module_name, name) + for attrname in dotted_path: + save(attrname) + if self.proto < 2: + write(TUPLE) + else: + write(TUPLE2) + write(REDUCE) + else: + self._save_toplevel_by_name(module_name, name) + + self.memoize(obj) + + def _save_toplevel_by_name(self, module_name, name): + if self.proto >= 3: + # Non-ASCII identifiers are supported only with protocols >= 3. + self.write(GLOBAL + bytes(module_name, "utf-8") + b'\n' + + bytes(name, "utf-8") + b'\n') else: if self.fix_imports: r_name_mapping = _compat_pickle.REVERSE_NAME_MAPPING @@ -1102,14 +1155,12 @@ def save_global(self, obj, name=None): elif module_name in r_import_mapping: module_name = r_import_mapping[module_name] try: - write(GLOBAL + bytes(module_name, "ascii") + b'\n' + - bytes(name, "ascii") + b'\n') + self.write(GLOBAL + bytes(module_name, "ascii") + b'\n' + + bytes(name, "ascii") + b'\n') except UnicodeEncodeError: raise PicklingError( "can't pickle global identifier '%s.%s' using " - "pickle protocol %i" % (module, name, self.proto)) from None - - self.memoize(obj) + "pickle protocol %i" % (module_name, name, self.proto)) from None def save_type(self, obj): if obj is type(None): @@ -1546,9 +1597,8 @@ def load_ext4(self): dispatch[EXT4[0]] = load_ext4 def get_extension(self, code): - nil = [] - obj = _extension_cache.get(code, nil) - if obj is not nil: + obj = _extension_cache.get(code, _NoValue) + if obj is not _NoValue: self.append(obj) return key = _inverted_registry.get(code) diff --git a/Lib/pickletools.py b/Lib/pickletools.py index 51ee4a7a..33a51492 100644 --- a/Lib/pickletools.py +++ b/Lib/pickletools.py @@ -312,7 +312,7 @@ def read_uint8(f): doc="Eight-byte unsigned integer, little-endian.") -def read_stringnl(f, decode=True, stripquotes=True): +def read_stringnl(f, decode=True, stripquotes=True, *, encoding='latin-1'): r""" >>> import io >>> read_stringnl(io.BytesIO(b"'abcd'\nefg\n")) @@ -356,7 +356,7 @@ def read_stringnl(f, decode=True, stripquotes=True): raise ValueError("no string quotes around %r" % data) if decode: - data = codecs.escape_decode(data)[0].decode("ascii") + data = codecs.escape_decode(data)[0].decode(encoding) return data stringnl = ArgumentDescriptor( @@ -370,7 +370,7 @@ def read_stringnl(f, decode=True, stripquotes=True): """) def read_stringnl_noescape(f): - return read_stringnl(f, stripquotes=False) + return read_stringnl(f, stripquotes=False, encoding='utf-8') stringnl_noescape = ArgumentDescriptor( name='stringnl_noescape', @@ -2513,7 +2513,10 @@ def dis(pickle, out=None, memo=None, indentlevel=4, annotate=0): # make a mild effort to align arguments line += ' ' * (10 - len(opcode.name)) if arg is not None: - line += ' ' + repr(arg) + if opcode.name in ("STRING", "BINSTRING", "SHORT_BINSTRING"): + line += ' ' + ascii(arg) + else: + line += ' ' + repr(arg) if markmsg: line += ' ' + markmsg if annotate: diff --git a/Lib/pstats.py b/Lib/pstats.py index 51bcca84..f3611777 100644 --- a/Lib/pstats.py +++ b/Lib/pstats.py @@ -83,7 +83,7 @@ class Stats: method now take arbitrarily many file names as arguments. All the print methods now take an argument that indicates how many lines - to print. If the arg is a floating point number between 0 and 1.0, then + to print. If the arg is a floating-point number between 0 and 1.0, then it is taken as a decimal percentage of the available lines to be printed (e.g., .1 means print 10% of all available lines). If it is an integer, it is taken to mean the number of lines of data that you wish to have diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 9a881239..e3745e54 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -2148,7 +2148,7 @@ def help(self, request, is_cli=False): elif request in self.symbols: self.showsymbol(request) elif request in ['True', 'False', 'None']: # special case these keywords since they are objects too - doc(eval(request), 'Help on %s:', is_cli=is_cli) + doc(eval(request), 'Help on %s:', output=self._output, is_cli=is_cli) elif request in self.keywords: self.showtopic(request) elif request in self.topics: self.showtopic(request) elif request: doc(request, 'Help on %s:', output=self._output, is_cli=is_cli) @@ -2241,7 +2241,11 @@ def showtopic(self, topic, more_xrefs=''): text = 'Related help topics: ' + ', '.join(xrefs.split()) + '\n' wrapped_text = textwrap.wrap(text, 72) doc += '\n%s\n' % '\n'.join(wrapped_text) - pager(doc) + + if self._output is None: + pager(doc) + else: + self.output.write(doc) def _gettopic(self, topic, more_xrefs=''): """Return unbuffered tuple of (topic, xrefs). diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index e9e6337c..12523999 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Thu Jun 6 20:20:21 2024 +# Autogenerated by Sphinx on Tue Dec 3 19:41:14 2024 # as part of the release process. topics = {'assert': 'The "assert" statement\n' '**********************\n' @@ -29,13 +29,12 @@ '(command\n' 'line option "-O"). The current code generator emits no code for ' 'an\n' - 'assert statement when optimization is requested at compile time. ' - 'Note\n' - 'that it is unnecessary to include the source code for the ' - 'expression\n' - 'that failed in the error message; it will be displayed as part of ' - 'the\n' - 'stack trace.\n' + '"assert" statement when optimization is requested at compile ' + 'time.\n' + 'Note that it is unnecessary to include the source code for the\n' + 'expression that failed in the error message; it will be displayed ' + 'as\n' + 'part of the stack trace.\n' '\n' 'Assignments to "__debug__" are illegal. The value for the ' 'built-in\n' @@ -308,10 +307,10 @@ 'target.\n' 'The target is only evaluated once.\n' '\n' - 'An augmented assignment expression like "x += 1" can be ' - 'rewritten as\n' - '"x = x + 1" to achieve a similar, but not exactly equal ' - 'effect. In the\n' + 'An augmented assignment statement like "x += 1" can be ' + 'rewritten as "x\n' + '= x + 1" to achieve a similar, but not exactly equal effect. ' + 'In the\n' 'augmented version, "x" is only evaluated once. Also, when ' 'possible,\n' 'the actual operation is performed *in-place*, meaning that ' @@ -362,21 +361,26 @@ 'a single\n' 'target is allowed.\n' '\n' - 'For simple names as assignment targets, if in class or module ' - 'scope,\n' - 'the annotations are evaluated and stored in a special class or ' - 'module\n' - 'attribute "__annotations__" that is a dictionary mapping from ' - 'variable\n' - 'names (mangled if private) to evaluated annotations. This ' - 'attribute is\n' - 'writable and is automatically created at the start of class or ' - 'module\n' - 'body execution, if annotations are found statically.\n' - '\n' - 'For expressions as assignment targets, the annotations are ' + 'The assignment target is considered “simple” if it consists of ' + 'a\n' + 'single name that is not enclosed in parentheses. For simple ' + 'assignment\n' + 'targets, if in class or module scope, the annotations are ' 'evaluated\n' - 'if in class or module scope, but not stored.\n' + 'and stored in a special class or module attribute ' + '"__annotations__"\n' + 'that is a dictionary mapping from variable names (mangled if ' + 'private)\n' + 'to evaluated annotations. This attribute is writable and is\n' + 'automatically created at the start of class or module body ' + 'execution,\n' + 'if annotations are found statically.\n' + '\n' + 'If the assignment target is not simple (an attribute, ' + 'subscript node,\n' + 'or parenthesized name), the annotation is evaluated if in ' + 'class or\n' + 'module scope, but not stored.\n' '\n' 'If a name is annotated in a function scope, then this name is ' 'local\n' @@ -555,31 +559,67 @@ 'evaluate it\n' 'raises a "NameError" exception.\n' '\n' - '**Private name mangling:** When an identifier that ' - 'textually occurs in\n' - 'a class definition begins with two or more underscore ' - 'characters and\n' - 'does not end in two or more underscores, it is ' - 'considered a *private\n' - 'name* of that class. Private names are transformed to a ' - 'longer form\n' - 'before code is generated for them. The transformation ' - 'inserts the\n' - 'class name, with leading underscores removed and a ' - 'single underscore\n' - 'inserted, in front of the name. For example, the ' - 'identifier "__spam"\n' - 'occurring in a class named "Ham" will be transformed to ' - '"_Ham__spam".\n' - 'This transformation is independent of the syntactical ' + '\n' + 'Private name mangling\n' + '=====================\n' + '\n' + 'When an identifier that textually occurs in a class ' + 'definition begins\n' + 'with two or more underscore characters and does not end ' + 'in two or more\n' + 'underscores, it is considered a *private name* of that ' + 'class.\n' + '\n' + 'See also: The class specifications.\n' + '\n' + 'More precisely, private names are transformed to a ' + 'longer form before\n' + 'code is generated for them. If the transformed name is ' + 'longer than\n' + '255 characters, implementation-defined truncation may ' + 'happen.\n' + '\n' + 'The transformation is independent of the syntactical ' 'context in which\n' - 'the identifier is used. If the transformed name is ' - 'extremely long\n' - '(longer than 255 characters), implementation defined ' - 'truncation may\n' - 'happen. If the class name consists only of underscores, ' - 'no\n' - 'transformation is done.\n', + 'the identifier is used but only the following private ' + 'identifiers are\n' + 'mangled:\n' + '\n' + '* Any name used as the name of a variable that is ' + 'assigned or read or\n' + ' any name of an attribute being accessed.\n' + '\n' + ' The "__name__" attribute of nested functions, classes, ' + 'and type\n' + ' aliases is however not mangled.\n' + '\n' + '* The name of imported modules, e.g., "__spam" in ' + '"import __spam". If\n' + ' the module is part of a package (i.e., its name ' + 'contains a dot), the\n' + ' name is *not* mangled, e.g., the "__foo" in "import ' + '__foo.bar" is\n' + ' not mangled.\n' + '\n' + '* The name of an imported member, e.g., "__f" in "from ' + 'spam import\n' + ' __f".\n' + '\n' + 'The transformation rule is defined as follows:\n' + '\n' + '* The class name, with leading underscores removed and a ' + 'single\n' + ' leading underscore inserted, is inserted in front of ' + 'the identifier,\n' + ' e.g., the identifier "__spam" occurring in a class ' + 'named "Foo",\n' + ' "_Foo" or "__Foo" is transformed to "_Foo__spam".\n' + '\n' + '* If the class name consists only of underscores, the ' + 'transformation\n' + ' is the identity, e.g., the identifier "__spam" ' + 'occurring in a class\n' + ' named "_" or "__" is left as is.\n', 'atom-literals': 'Literals\n' '********\n' '\n' @@ -592,10 +632,10 @@ '\n' 'Evaluation of a literal yields an object of the given type ' '(string,\n' - 'bytes, integer, floating point number, complex number) with ' + 'bytes, integer, floating-point number, complex number) with ' 'the given\n' 'value. The value may be approximated in the case of ' - 'floating point\n' + 'floating-point\n' 'and imaginary (complex) literals. See section Literals for ' 'details.\n' '\n' @@ -632,7 +672,8 @@ 'should either\n' ' return the (computed) attribute value or raise an ' '"AttributeError"\n' - ' exception.\n' + ' exception. The "object" class itself does not provide ' + 'this method.\n' '\n' ' Note that if the attribute is found through the ' 'normal mechanism,\n' @@ -815,7 +856,9 @@ 'parents). In the\n' 'examples below, “the attribute” refers to the attribute ' 'whose name is\n' - 'the key of the property in the owner class’ "__dict__".\n' + 'the key of the property in the owner class’ "__dict__". ' + 'The "object"\n' + 'class itself does not implement any of these protocols.\n' '\n' 'object.__get__(self, instance, owner=None)\n' '\n' @@ -1053,11 +1096,13 @@ 'to the class\n' ' where it is defined. *__slots__* declared in parents ' 'are available\n' - ' in child classes. However, child subclasses will get a ' - '"__dict__"\n' - ' and *__weakref__* unless they also define *__slots__* ' - '(which should\n' - ' only contain names of any *additional* slots).\n' + ' in child classes. However, instances of a child ' + 'subclass will get a\n' + ' "__dict__" and *__weakref__* unless the subclass also ' + 'defines\n' + ' *__slots__* (which should only contain names of any ' + '*additional*\n' + ' slots).\n' '\n' '* If a class defines a slot also defined in a base ' 'class, the instance\n' @@ -1163,10 +1208,10 @@ 'target.\n' 'The target is only evaluated once.\n' '\n' - 'An augmented assignment expression like "x += 1" can be ' - 'rewritten as\n' - '"x = x + 1" to achieve a similar, but not exactly equal effect. ' - 'In the\n' + 'An augmented assignment statement like "x += 1" can be ' + 'rewritten as "x\n' + '= x + 1" to achieve a similar, but not exactly equal effect. In ' + 'the\n' 'augmented version, "x" is only evaluated once. Also, when ' 'possible,\n' 'the actual operation is performed *in-place*, meaning that ' @@ -1239,6 +1284,10 @@ 'The "@" (at) operator is intended to be used for matrix\n' 'multiplication. No builtin Python types implement this operator.\n' '\n' + 'This operation can be customized using the special "__matmul__()" ' + 'and\n' + '"__rmatmul__()" methods.\n' + '\n' 'Added in version 3.5.\n' '\n' 'The "/" (division) and "//" (floor division) operators yield the\n' @@ -1251,17 +1300,19 @@ 'result. Division by zero raises the "ZeroDivisionError" ' 'exception.\n' '\n' - 'This operation can be customized using the special "__truediv__()" ' + 'The division operation can be customized using the special\n' + '"__truediv__()" and "__rtruediv__()" methods. The floor division\n' + 'operation can be customized using the special "__floordiv__()" ' 'and\n' - '"__floordiv__()" methods.\n' + '"__rfloordiv__()" methods.\n' '\n' 'The "%" (modulo) operator yields the remainder from the division ' 'of\n' 'the first argument by the second. The numeric arguments are ' 'first\n' 'converted to a common type. A zero right argument raises the\n' - '"ZeroDivisionError" exception. The arguments may be floating ' - 'point\n' + '"ZeroDivisionError" exception. The arguments may be ' + 'floating-point\n' 'numbers, e.g., "3.14%0.7" equals "0.34" (since "3.14" equals ' '"4*0.7 +\n' '0.34".) The modulo operator always yields a result with the same ' @@ -1288,13 +1339,13 @@ '\n' 'The *modulo* operation can be customized using the special ' '"__mod__()"\n' - 'method.\n' + 'and "__rmod__()" methods.\n' '\n' 'The floor division operator, the modulo operator, and the ' '"divmod()"\n' 'function are not defined for complex numbers. Instead, convert to ' 'a\n' - 'floating point number using the "abs()" function if appropriate.\n' + 'floating-point number using the "abs()" function if appropriate.\n' '\n' 'The "+" (addition) operator yields the sum of its arguments. The\n' 'arguments must either both be numbers or both be sequences of the ' @@ -1313,7 +1364,8 @@ 'The numeric arguments are first converted to a common type.\n' '\n' 'This operation can be customized using the special "__sub__()" ' - 'method.\n', + 'and\n' + '"__rsub__()" methods.\n', 'bitwise': 'Binary bitwise operations\n' '*************************\n' '\n' @@ -1479,7 +1531,9 @@ ' Called when the instance is “called” as a function; if ' 'this method\n' ' is defined, "x(arg1, arg2, ...)" roughly translates to\n' - ' "type(x).__call__(x, arg1, ...)".\n', + ' "type(x).__call__(x, arg1, ...)". The "object" class ' + 'itself does\n' + ' not provide this method.\n', 'calls': 'Calls\n' '*****\n' '\n' @@ -1664,6 +1718,9 @@ ' Function definitions. When the code block executes a "return"\n' ' statement, this specifies the return value of the function ' 'call.\n' + ' If execution reaches the end of the code block without executing ' + 'a\n' + ' "return" statement, the return value is "None".\n' '\n' 'a built-in function or method:\n' ' The result is up to the interpreter; see Built-in Functions for ' @@ -2388,18 +2445,16 @@ 'An\n' 'expression-less "except" clause, if present, must be last; it ' 'matches\n' - 'any exception. For an "except" clause with an expression, that\n' - 'expression is evaluated, and the clause matches the exception if ' - 'the\n' - 'resulting object is “compatible” with the exception. An object ' - 'is\n' - 'compatible with an exception if the object is the class or a ' - '*non-\n' - 'virtual base class* of the exception object, or a tuple ' - 'containing an\n' - 'item that is the class or a non-virtual base class of the ' - 'exception\n' - 'object.\n' + 'any exception.\n' + '\n' + 'For an "except" clause with an expression, the expression must\n' + 'evaluate to an exception type or a tuple of exception types. ' + 'The\n' + 'raised exception matches an "except" clause whose expression ' + 'evaluates\n' + 'to the class or a *non-virtual base class* of the exception ' + 'object, or\n' + 'to a tuple that contains such a class.\n' '\n' 'If no "except" clause matches the exception, the search for an\n' 'exception handler continues in the surrounding code and on the\n' @@ -2548,13 +2603,16 @@ ' ...\n' " ExceptionGroup('', (BlockingIOError()))\n" '\n' - 'An "except*" clause must have a matching type, and this type ' - 'cannot be\n' - 'a subclass of "BaseExceptionGroup". It is not possible to mix ' - '"except"\n' - 'and "except*" in the same "try". "break", "continue" and ' - '"return"\n' - 'cannot appear in an "except*" clause.\n' + 'An "except*" clause must have a matching expression; it cannot ' + 'be\n' + '"except*:". Furthermore, this expression cannot contain ' + 'exception\n' + 'group types, because that would have ambiguous semantics.\n' + '\n' + 'It is not possible to mix "except" and "except*" in the same ' + '"try".\n' + '"break", "continue" and "return" cannot appear in an "except*" ' + 'clause.\n' '\n' '\n' '"else" clause\n' @@ -2711,18 +2769,15 @@ ' enter = type(manager).__enter__\n' ' exit = type(manager).__exit__\n' ' value = enter(manager)\n' - ' hit_except = False\n' '\n' ' try:\n' ' TARGET = value\n' ' SUITE\n' ' except:\n' - ' hit_except = True\n' ' if not exit(manager, *sys.exc_info()):\n' ' raise\n' - ' finally:\n' - ' if not hit_except:\n' - ' exit(manager, None, None, None)\n' + ' else:\n' + ' exit(manager, None, None, None)\n' '\n' 'With more than one item, the context managers are processed as ' 'if\n' @@ -3052,7 +3107,7 @@ ' | "None"\n' ' | "True"\n' ' | "False"\n' - ' | signed_number: NUMBER | "-" NUMBER\n' + ' signed_number ::= ["-"] NUMBER\n' '\n' 'The rule "strings" and the token "NUMBER" are defined in the ' 'standard\n' @@ -3522,10 +3577,12 @@ ' parameter_list_no_posonly ::= defparameter ("," ' 'defparameter)* ["," [parameter_list_starargs]]\n' ' | parameter_list_starargs\n' - ' parameter_list_starargs ::= "*" [parameter] ("," ' + ' parameter_list_starargs ::= "*" [star_parameter] ("," ' 'defparameter)* ["," ["**" parameter [","]]]\n' ' | "**" parameter [","]\n' ' parameter ::= identifier [":" expression]\n' + ' star_parameter ::= identifier [":" ["*"] ' + 'expression]\n' ' defparameter ::= parameter ["=" expression]\n' ' funcname ::= identifier\n' '\n' @@ -3653,27 +3710,31 @@ 'expression"”\n' 'following the parameter name. Any parameter may have an ' 'annotation,\n' - 'even those of the form "*identifier" or "**identifier". ' - 'Functions may\n' - 'have “return” annotation of the form “"-> expression"” after ' - 'the\n' - 'parameter list. These annotations can be any valid Python ' - 'expression.\n' - 'The presence of annotations does not change the semantics of a\n' - 'function. The annotation values are available as values of a\n' - 'dictionary keyed by the parameters’ names in the ' - '"__annotations__"\n' - 'attribute of the function object. If the "annotations" import ' - 'from\n' - '"__future__" is used, annotations are preserved as strings at ' - 'runtime\n' - 'which enables postponed evaluation. Otherwise, they are ' - 'evaluated\n' - 'when the function definition is executed. In this case ' - 'annotations\n' - 'may be evaluated in a different order than they appear in the ' - 'source\n' - 'code.\n' + 'even those of the form "*identifier" or "**identifier". (As a ' + 'special\n' + 'case, parameters of the form "*identifier" may have an ' + 'annotation “":\n' + '*expression"”.) Functions may have “return” annotation of the ' + 'form\n' + '“"-> expression"” after the parameter list. These annotations ' + 'can be\n' + 'any valid Python expression. The presence of annotations does ' + 'not\n' + 'change the semantics of a function. The annotation values are\n' + 'available as values of a dictionary keyed by the parameters’ ' + 'names in\n' + 'the "__annotations__" attribute of the function object. If the\n' + '"annotations" import from "__future__" is used, annotations are\n' + 'preserved as strings at runtime which enables postponed ' + 'evaluation.\n' + 'Otherwise, they are evaluated when the function definition is\n' + 'executed. In this case annotations may be evaluated in a ' + 'different\n' + 'order than they appear in the source code.\n' + '\n' + 'Changed in version 3.11: Parameters of the form “"*identifier"” ' + 'may\n' + 'have an annotation “": *expression"”. See **PEP 646**.\n' '\n' 'It is also possible to create anonymous functions (functions not ' 'bound\n' @@ -4332,6 +4393,9 @@ '\n' 'For more information on context managers, see Context ' 'Manager Types.\n' + 'The "object" class itself does not provide the context ' + 'manager\n' + 'methods.\n' '\n' 'object.__enter__(self)\n' '\n' @@ -4400,7 +4464,7 @@ 'converted to\n' ' complex;\n' '\n' - '* otherwise, if either argument is a floating point number, ' + '* otherwise, if either argument is a floating-point number, ' 'the other\n' ' is converted to floating point;\n' '\n' @@ -4511,6 +4575,10 @@ ' It is not guaranteed that "__del__()" methods are called ' 'for\n' ' objects that still exist when the interpreter exits.\n' + ' "weakref.finalize" provides a straightforward way to ' + 'register a\n' + ' cleanup function to be called when an object is garbage ' + 'collected.\n' '\n' ' Note:\n' '\n' @@ -4597,17 +4665,20 @@ '\n' ' This is typically used for debugging, so it is important ' 'that the\n' - ' representation is information-rich and unambiguous.\n' + ' representation is information-rich and unambiguous. A ' + 'default\n' + ' implementation is provided by the "object" class ' + 'itself.\n' '\n' 'object.__str__(self)\n' '\n' - ' Called by "str(object)" and the built-in functions ' - '"format()" and\n' - ' "print()" to compute the “informal” or nicely printable ' - 'string\n' - ' representation of an object. The return value must be a ' - 'string\n' - ' object.\n' + ' Called by "str(object)", the default "__format__()" ' + 'implementation,\n' + ' and the built-in function "print()", to compute the ' + '“informal” or\n' + ' nicely printable string representation of an object. ' + 'The return\n' + ' value must be a str object.\n' '\n' ' This method differs from "object.__repr__()" in that ' 'there is no\n' @@ -4623,7 +4694,9 @@ '\n' ' Called by bytes to compute a byte-string representation ' 'of an\n' - ' object. This should return a "bytes" object.\n' + ' object. This should return a "bytes" object. The ' + '"object" class\n' + ' itself does not provide this method.\n' '\n' 'object.__format__(self, format_spec)\n' '\n' @@ -4651,6 +4724,11 @@ '\n' ' The return value must be a string object.\n' '\n' + ' The default implementation by the "object" class should ' + 'be given an\n' + ' empty *format_spec* string. It delegates to ' + '"__str__()".\n' + '\n' ' Changed in version 3.4: The __format__ method of ' '"object" itself\n' ' raises a "TypeError" if passed any non-empty string.\n' @@ -4708,6 +4786,16 @@ ' ordering operations from a single root operation, see\n' ' "functools.total_ordering()".\n' '\n' + ' By default, the "object" class provides implementations ' + 'consistent\n' + ' with Value comparisons: equality compares according to ' + 'object\n' + ' identity, and order comparisons raise "TypeError". Each ' + 'default\n' + ' method may generate these results directly, but may also ' + 'return\n' + ' "NotImplemented".\n' + '\n' ' See the paragraph on "__hash__()" for some important ' 'notes on\n' ' creating *hashable* objects which support custom ' @@ -4794,12 +4882,13 @@ '\n' ' User-defined classes have "__eq__()" and "__hash__()" ' 'methods by\n' - ' default; with them, all objects compare unequal (except ' - 'with\n' - ' themselves) and "x.__hash__()" returns an appropriate ' - 'value such\n' - ' that "x == y" implies both that "x is y" and "hash(x) == ' - 'hash(y)".\n' + ' default (inherited from the "object" class); with them, ' + 'all objects\n' + ' compare unequal (except with themselves) and ' + '"x.__hash__()" returns\n' + ' an appropriate value such that "x == y" implies both ' + 'that "x is y"\n' + ' and "hash(x) == hash(y)".\n' '\n' ' A class that overrides "__eq__()" and does not define ' '"__hash__()"\n' @@ -4870,9 +4959,9 @@ 'the object is\n' ' considered true if its result is nonzero. If a class ' 'defines\n' - ' neither "__len__()" nor "__bool__()", all its instances ' - 'are\n' - ' considered true.\n', + ' neither "__len__()" nor "__bool__()" (which is true of ' + 'the "object"\n' + ' class itself), all its instances are considered true.\n', 'debugger': '"pdb" — The Python Debugger\n' '***************************\n' '\n' @@ -6178,11 +6267,11 @@ '\n' '* While annotation scopes have an internal name, that name is ' 'not\n' - ' reflected in the *__qualname__* of objects defined within the ' - 'scope.\n' - ' Instead, the "__qualname__" of such objects is as if the ' - 'object were\n' - ' defined in the enclosing scope.\n' + ' reflected in the *qualified name* of objects defined within ' + 'the\n' + ' scope. Instead, the "__qualname__" of such objects is as if ' + 'the\n' + ' object were defined in the enclosing scope.\n' '\n' 'Added in version 3.12: Annotation scopes were introduced in ' 'Python\n' @@ -6380,12 +6469,17 @@ 'exprlists': 'Expression lists\n' '****************\n' '\n' - ' expression_list ::= expression ("," expression)* [","]\n' - ' starred_list ::= starred_item ("," starred_item)* ' + ' starred_expression ::= ["*"] or_expr\n' + ' flexible_expression ::= assignment_expression | ' + 'starred_expression\n' + ' flexible_expression_list ::= flexible_expression ("," ' + 'flexible_expression)* [","]\n' + ' starred_expression_list ::= starred_expression ("," ' + 'starred_expression)* [","]\n' + ' expression_list ::= expression ("," expression)* ' '[","]\n' - ' starred_expression ::= expression | (starred_item ",")* ' - '[starred_item]\n' - ' starred_item ::= assignment_expression | "*" or_expr\n' + ' yield_list ::= expression_list | ' + 'starred_expression "," [starred_expression_list]\n' '\n' 'Except when part of a list or set display, an expression list\n' 'containing at least one comma yields a tuple. The length of ' @@ -6404,6 +6498,10 @@ 'Added in version 3.5: Iterable unpacking in expression lists,\n' 'originally proposed by **PEP 448**.\n' '\n' + 'Added in version 3.11: Any item in an expression list may be ' + 'starred.\n' + 'See **PEP 646**.\n' + '\n' 'A trailing comma is required only to create a one-item tuple, ' 'such as\n' '"1,"; it is optional in all other cases. A single expression ' @@ -6413,10 +6511,10 @@ 'that expression. (To create an empty tuple, use an empty pair ' 'of\n' 'parentheses: "()".)\n', - 'floating': 'Floating point literals\n' + 'floating': 'Floating-point literals\n' '***********************\n' '\n' - 'Floating point literals are described by the following lexical\n' + 'Floating-point literals are described by the following lexical\n' 'definitions:\n' '\n' ' floatnumber ::= pointfloat | exponentfloat\n' @@ -6430,12 +6528,12 @@ 'using\n' 'radix 10. For example, "077e010" is legal, and denotes the same ' 'number\n' - 'as "77e10". The allowed range of floating point literals is\n' + 'as "77e10". The allowed range of floating-point literals is\n' 'implementation-dependent. As in integer literals, underscores ' 'are\n' 'supported for digit grouping.\n' '\n' - 'Some examples of floating point literals:\n' + 'Some examples of floating-point literals:\n' '\n' ' 3.14 10. .001 1e100 3.14e-10 0e0 ' '3.14_15_93\n' @@ -6732,10 +6830,12 @@ 'printing fields |\n' '| | in the form ‘+000000120’. This alignment ' 'option is only |\n' - '| | valid for numeric types. It becomes the ' - 'default for |\n' - '| | numbers when ‘0’ immediately precedes the ' - 'field width. |\n' + '| | valid for numeric types, excluding "complex". ' + 'It becomes |\n' + '| | the default for numbers when ‘0’ immediately ' + 'precedes the |\n' + '| | field ' + 'width. |\n' '+-----------+------------------------------------------------------------+\n' '| "\'^\'" | Forces the field to be centered within the ' 'available |\n' @@ -6818,7 +6918,7 @@ '\n' 'The "\'_\'" option signals the use of an underscore for a ' 'thousands\n' - 'separator for floating point presentation types and for ' + 'separator for floating-point presentation types and for ' 'integer\n' 'presentation type "\'d\'". For integer presentation types ' '"\'b\'", "\'o\'",\n' @@ -6842,9 +6942,9 @@ 'field by a\n' 'zero ("\'0\'") character enables sign-aware zero-padding ' 'for numeric\n' - 'types. This is equivalent to a *fill* character of "\'0\'" ' - 'with an\n' - '*alignment* type of "\'=\'".\n' + 'types, excluding "complex". This is equivalent to a *fill* ' + 'character\n' + 'of "\'0\'" with an *alignment* type of "\'=\'".\n' '\n' 'Changed in version 3.10: Preceding the *width* field by ' '"\'0\'" no\n' @@ -6945,11 +7045,11 @@ '\n' 'In addition to the above presentation types, integers can ' 'be formatted\n' - 'with the floating point presentation types listed below ' + 'with the floating-point presentation types listed below ' '(except "\'n\'"\n' 'and "None"). When doing so, "float()" is used to convert ' 'the integer\n' - 'to a floating point number before formatting.\n' + 'to a floating-point number before formatting.\n' '\n' 'The available presentation types for "float" and "Decimal" ' 'values are:\n' @@ -6975,12 +7075,10 @@ 'of "6" digits |\n' ' | | after the decimal point for "float", and ' 'shows all |\n' - ' | | coefficient digits for "Decimal". If no ' - 'digits follow the |\n' - ' | | decimal point, the decimal point is also ' - 'removed unless |\n' - ' | | the "#" option is ' - 'used. |\n' + ' | | coefficient digits for "Decimal". If ' + '"p=0", the decimal |\n' + ' | | point is omitted unless the "#" option is ' + 'used. |\n' ' ' '+-----------+------------------------------------------------------------+\n' ' | "\'E\'" | Scientific notation. Same as "\'e\'" ' @@ -6999,12 +7097,10 @@ 'decimal point for |\n' ' | | "float", and uses a precision large enough ' 'to show all |\n' - ' | | coefficient digits for "Decimal". If no ' - 'digits follow the |\n' - ' | | decimal point, the decimal point is also ' - 'removed unless |\n' - ' | | the "#" option is ' - 'used. |\n' + ' | | coefficient digits for "Decimal". If ' + '"p=0", the decimal |\n' + ' | | point is omitted unless the "#" option is ' + 'used. |\n' ' ' '+-----------+------------------------------------------------------------+\n' ' | "\'F\'" | Fixed-point notation. Same as "\'f\'", ' @@ -7089,18 +7185,22 @@ 'percent sign. |\n' ' ' '+-----------+------------------------------------------------------------+\n' - ' | None | For "float" this is the same as "\'g\'", ' - 'except that when |\n' - ' | | fixed-point notation is used to format the ' - 'result, it |\n' + ' | None | For "float" this is like the "\'g\'" type, ' + 'except that when |\n' + ' | | fixed- point notation is used to format ' + 'the result, it |\n' ' | | always includes at least one digit past ' - 'the decimal point. |\n' - ' | | The precision used is as large as needed ' - 'to represent the |\n' - ' | | given value faithfully. For "Decimal", ' - 'this is the same |\n' - ' | | as either "\'g\'" or "\'G\'" depending on ' - 'the value of |\n' + 'the decimal point, |\n' + ' | | and switches to the scientific notation ' + 'when "exp >= p - |\n' + ' | | 1". When the precision is not specified, ' + 'the latter will |\n' + ' | | be as large as needed to represent the ' + 'given value |\n' + ' | | faithfully. For "Decimal", this is the ' + 'same as either |\n' + ' | | "\'g\'" or "\'G\'" depending on the value ' + 'of |\n' ' | | "context.capitals" for the current decimal ' 'context. The |\n' ' | | overall effect is to match the output of ' @@ -7110,6 +7210,32 @@ ' ' '+-----------+------------------------------------------------------------+\n' '\n' + 'The result should be correctly rounded to a given precision ' + '"p" of\n' + 'digits after the decimal point. The rounding mode for ' + '"float" matches\n' + 'that of the "round()" builtin. For "Decimal", the rounding ' + 'mode of\n' + 'the current context will be used.\n' + '\n' + 'The available presentation types for "complex" are the same ' + 'as those\n' + 'for "float" ("\'%\'" is not allowed). Both the real and ' + 'imaginary\n' + 'components of a complex number are formatted as ' + 'floating-point\n' + 'numbers, according to the specified presentation type. ' + 'They are\n' + 'separated by the mandatory sign of the imaginary part, the ' + 'latter\n' + 'being terminated by a "j" suffix. If the presentation type ' + 'is\n' + 'missing, the result will match the output of "str()" ' + '(complex numbers\n' + 'with a non-zero real part are also surrounded by ' + 'parentheses),\n' + 'possibly altered by other format modifiers.\n' + '\n' '\n' 'Format examples\n' '===============\n' @@ -7290,10 +7416,12 @@ ' parameter_list_no_posonly ::= defparameter ("," ' 'defparameter)* ["," [parameter_list_starargs]]\n' ' | parameter_list_starargs\n' - ' parameter_list_starargs ::= "*" [parameter] ("," ' + ' parameter_list_starargs ::= "*" [star_parameter] ("," ' 'defparameter)* ["," ["**" parameter [","]]]\n' ' | "**" parameter [","]\n' ' parameter ::= identifier [":" expression]\n' + ' star_parameter ::= identifier [":" ["*"] ' + 'expression]\n' ' defparameter ::= parameter ["=" expression]\n' ' funcname ::= identifier\n' '\n' @@ -7421,27 +7549,31 @@ 'expression"”\n' 'following the parameter name. Any parameter may have an ' 'annotation,\n' - 'even those of the form "*identifier" or "**identifier". ' - 'Functions may\n' - 'have “return” annotation of the form “"-> expression"” after ' - 'the\n' - 'parameter list. These annotations can be any valid Python ' - 'expression.\n' - 'The presence of annotations does not change the semantics of a\n' - 'function. The annotation values are available as values of a\n' - 'dictionary keyed by the parameters’ names in the ' - '"__annotations__"\n' - 'attribute of the function object. If the "annotations" import ' - 'from\n' - '"__future__" is used, annotations are preserved as strings at ' - 'runtime\n' - 'which enables postponed evaluation. Otherwise, they are ' - 'evaluated\n' - 'when the function definition is executed. In this case ' - 'annotations\n' - 'may be evaluated in a different order than they appear in the ' - 'source\n' - 'code.\n' + 'even those of the form "*identifier" or "**identifier". (As a ' + 'special\n' + 'case, parameters of the form "*identifier" may have an ' + 'annotation “":\n' + '*expression"”.) Functions may have “return” annotation of the ' + 'form\n' + '“"-> expression"” after the parameter list. These annotations ' + 'can be\n' + 'any valid Python expression. The presence of annotations does ' + 'not\n' + 'change the semantics of a function. The annotation values are\n' + 'available as values of a dictionary keyed by the parameters’ ' + 'names in\n' + 'the "__annotations__" attribute of the function object. If the\n' + '"annotations" import from "__future__" is used, annotations are\n' + 'preserved as strings at runtime which enables postponed ' + 'evaluation.\n' + 'Otherwise, they are evaluated when the function definition is\n' + 'executed. In this case annotations may be evaluated in a ' + 'different\n' + 'order than they appear in the source code.\n' + '\n' + 'Changed in version 3.11: Parameters of the form “"*identifier"” ' + 'may\n' + 'have an annotation “": *expression"”. See **PEP 646**.\n' '\n' 'It is also possible to create anonymous functions (functions not ' 'bound\n' @@ -7497,33 +7629,17 @@ '\n' ' global_stmt ::= "global" identifier ("," identifier)*\n' '\n' - 'The "global" statement is a declaration which holds for the ' - 'entire\n' - 'current code block. It means that the listed identifiers are to ' - 'be\n' - 'interpreted as globals. It would be impossible to assign to a ' - 'global\n' - 'variable without "global", although free variables may refer to\n' - 'globals without being declared global.\n' - '\n' - 'Names listed in a "global" statement must not be used in the same ' - 'code\n' - 'block textually preceding that "global" statement.\n' + 'The "global" statement causes the listed identifiers to be ' + 'interpreted\n' + 'as globals. It would be impossible to assign to a global variable\n' + 'without "global", although free variables may refer to globals ' + 'without\n' + 'being declared global.\n' '\n' - 'Names listed in a "global" statement must not be defined as ' - 'formal\n' - 'parameters, or as targets in "with" statements or "except" ' - 'clauses, or\n' - 'in a "for" target list, "class" definition, function definition,\n' - '"import" statement, or variable annotation.\n' - '\n' - '**CPython implementation detail:** The current implementation does ' - 'not\n' - 'enforce some of these restrictions, but programs should not abuse ' - 'this\n' - 'freedom, as future implementations may enforce them or silently ' - 'change\n' - 'the meaning of the program.\n' + 'The "global" statement applies to the entire scope of a function ' + 'or\n' + 'class body. A "SyntaxError" is raised if a variable is used or\n' + 'assigned to prior to its global declaration in the scope.\n' '\n' '**Programmer’s note:** "global" is a directive to the parser. It\n' 'applies only to code parsed at the same time as the "global"\n' @@ -7610,19 +7726,16 @@ '\n' 'Within the ASCII range (U+0001..U+007F), the valid characters ' 'for\n' - 'identifiers are the same as in Python 2.x: the uppercase and ' - 'lowercase\n' - 'letters "A" through "Z", the underscore "_" and, except for ' - 'the first\n' - 'character, the digits "0" through "9".\n' - '\n' - 'Python 3.0 introduces additional characters from outside the ' - 'ASCII\n' - 'range (see **PEP 3131**). For these characters, the ' - 'classification\n' - 'uses the version of the Unicode Character Database as ' - 'included in the\n' - '"unicodedata" module.\n' + 'identifiers include the uppercase and lowercase letters "A" ' + 'through\n' + '"Z", the underscore "_" and, except for the first character, ' + 'the\n' + 'digits "0" through "9". Python 3.0 introduced additional ' + 'characters\n' + 'from outside the ASCII range (see **PEP 3131**). For these\n' + 'characters, the classification uses the version of the ' + 'Unicode\n' + 'Character Database as included in the "unicodedata" module.\n' '\n' 'Identifiers are unlimited in length. Case is significant.\n' '\n' @@ -7807,11 +7920,11 @@ '\n' 'An imaginary literal yields a complex number with a real part ' 'of 0.0.\n' - 'Complex numbers are represented as a pair of floating point ' + 'Complex numbers are represented as a pair of floating-point ' 'numbers\n' 'and have the same restrictions on their range. To create a ' 'complex\n' - 'number with a nonzero real part, add a floating point number to ' + 'number with a nonzero real part, add a floating-point number to ' 'it,\n' 'e.g., "(3+4j)". Some examples of imaginary literals:\n' '\n' @@ -8197,7 +8310,8 @@ 'in\n' 'square brackets:\n' '\n' - ' list_display ::= "[" [starred_list | comprehension] "]"\n' + ' list_display ::= "[" [flexible_expression_list | comprehension] ' + '"]"\n' '\n' 'A list display yields a new list object, the contents being ' 'specified\n' @@ -8448,11 +8562,9 @@ ' can introduce new names.\n' '\n' '* While annotation scopes have an internal name, that name is not\n' - ' reflected in the *__qualname__* of objects defined within the ' - 'scope.\n' - ' Instead, the "__qualname__" of such objects is as if the object ' - 'were\n' - ' defined in the enclosing scope.\n' + ' reflected in the *qualified name* of objects defined within the\n' + ' scope. Instead, the "__qualname__" of such objects is as if the\n' + ' object were defined in the enclosing scope.\n' '\n' 'Added in version 3.12: Annotation scopes were introduced in ' 'Python\n' @@ -8587,8 +8699,8 @@ 'scope,\n' 'or if there is no nonlocal scope, a "SyntaxError" is raised.\n' '\n' - 'The nonlocal statement applies to the entire scope of a function ' - 'or\n' + 'The "nonlocal" statement applies to the entire scope of a ' + 'function or\n' 'class body. A "SyntaxError" is raised if a variable is used or\n' 'assigned to prior to its nonlocal declaration in the scope.\n' '\n' @@ -8605,8 +8717,8 @@ 'numbers': 'Numeric literals\n' '****************\n' '\n' - 'There are three types of numeric literals: integers, floating ' - 'point\n' + 'There are three types of numeric literals: integers, ' + 'floating-point\n' 'numbers, and imaginary numbers. There are no complex literals\n' '(complex numbers can be formed by adding a real number and an\n' 'imaginary number).\n' @@ -8938,16 +9050,22 @@ 'types, operations that compute new values may actually return a\n' 'reference to any existing object with the same type and value, ' 'while\n' - 'for mutable objects this is not allowed. E.g., after "a = 1; b = ' - '1",\n' - '"a" and "b" may or may not refer to the same object with the ' - 'value\n' - 'one, depending on the implementation, but after "c = []; d = []", ' - '"c"\n' - 'and "d" are guaranteed to refer to two different, unique, newly\n' - 'created empty lists. (Note that "c = d = []" assigns the same ' - 'object\n' - 'to both "c" and "d".)\n', + 'for mutable objects this is not allowed. For example, after "a = ' + '1; b\n' + '= 1", *a* and *b* may or may not refer to the same object with ' + 'the\n' + 'value one, depending on the implementation. This is because "int" ' + 'is\n' + 'an immutable type, so the reference to "1" can be reused. This\n' + 'behaviour depends on the implementation used, so should not be ' + 'relied\n' + 'upon, but is something to be aware of when making use of object\n' + 'identity tests. However, after "c = []; d = []", *c* and *d* are\n' + 'guaranteed to refer to two different, unique, newly created ' + 'empty\n' + 'lists. (Note that "e = f = []" assigns the *same* object to both ' + '*e*\n' + 'and *f*.)\n', 'operator-summary': 'Operator precedence\n' '*******************\n' '\n' @@ -9176,8 +9294,8 @@ '"complex"\n' 'number. (In earlier versions it raised a "ValueError".)\n' '\n' - 'This operation can be customized using the special "__pow__()" ' - 'method.\n', + 'This operation can be customized using the special "__pow__()" and\n' + '"__rpow__()" methods.\n', 'raise': 'The "raise" statement\n' '*********************\n' '\n' @@ -9340,56 +9458,58 @@ '\n' 'The following methods can be defined to implement ' 'container objects.\n' - 'Containers usually are *sequences* (such as "lists" or ' - '"tuples") or\n' - '*mappings* (like "dictionaries"), but can represent other ' - 'containers\n' - 'as well. The first set of methods is used either to ' - 'emulate a\n' - 'sequence or to emulate a mapping; the difference is that ' - 'for a\n' - 'sequence, the allowable keys should be the integers *k* ' - 'for which "0\n' - '<= k < N" where *N* is the length of the sequence, or ' - '"slice" objects,\n' - 'which define a range of items. It is also recommended ' - 'that mappings\n' - 'provide the methods "keys()", "values()", "items()", ' - '"get()",\n' - '"clear()", "setdefault()", "pop()", "popitem()", "copy()", ' + 'None of them are provided by the "object" class itself. ' + 'Containers\n' + 'usually are *sequences* (such as "lists" or "tuples") or ' + '*mappings*\n' + '(like *dictionaries*), but can represent other containers ' + 'as well.\n' + 'The first set of methods is used either to emulate a ' + 'sequence or to\n' + 'emulate a mapping; the difference is that for a sequence, ' + 'the\n' + 'allowable keys should be the integers *k* for which "0 <= ' + 'k < N" where\n' + '*N* is the length of the sequence, or "slice" objects, ' + 'which define a\n' + 'range of items. It is also recommended that mappings ' + 'provide the\n' + 'methods "keys()", "values()", "items()", "get()", ' + '"clear()",\n' + '"setdefault()", "pop()", "popitem()", "copy()", and ' + '"update()"\n' + 'behaving similar to those for Python’s standard ' + '"dictionary" objects.\n' + 'The "collections.abc" module provides a "MutableMapping" ' + '*abstract\n' + 'base class* to help create those methods from a base set ' + 'of\n' + '"__getitem__()", "__setitem__()", "__delitem__()", and ' + '"keys()".\n' + 'Mutable sequences should provide methods "append()", ' + '"count()",\n' + '"index()", "extend()", "insert()", "pop()", "remove()", ' + '"reverse()"\n' + 'and "sort()", like Python standard "list" objects. ' + 'Finally, sequence\n' + 'types should implement addition (meaning concatenation) ' 'and\n' - '"update()" behaving similar to those for Python’s ' - 'standard\n' - '"dictionary" objects. The "collections.abc" module ' - 'provides a\n' - '"MutableMapping" *abstract base class* to help create ' - 'those methods\n' - 'from a base set of "__getitem__()", "__setitem__()", ' - '"__delitem__()",\n' - 'and "keys()". Mutable sequences should provide methods ' - '"append()",\n' - '"count()", "index()", "extend()", "insert()", "pop()", ' - '"remove()",\n' - '"reverse()" and "sort()", like Python standard "list" ' - 'objects.\n' - 'Finally, sequence types should implement addition ' - '(meaning\n' - 'concatenation) and multiplication (meaning repetition) by ' - 'defining the\n' - 'methods "__add__()", "__radd__()", "__iadd__()", ' - '"__mul__()",\n' - '"__rmul__()" and "__imul__()" described below; they should ' - 'not define\n' - 'other numerical operators. It is recommended that both ' - 'mappings and\n' - 'sequences implement the "__contains__()" method to allow ' - 'efficient use\n' - 'of the "in" operator; for mappings, "in" should search the ' - 'mapping’s\n' - 'keys; for sequences, it should search through the values. ' - 'It is\n' - 'further recommended that both mappings and sequences ' - 'implement the\n' + 'multiplication (meaning repetition) by defining the ' + 'methods\n' + '"__add__()", "__radd__()", "__iadd__()", "__mul__()", ' + '"__rmul__()" and\n' + '"__imul__()" described below; they should not define other ' + 'numerical\n' + 'operators. It is recommended that both mappings and ' + 'sequences\n' + 'implement the "__contains__()" method to allow efficient ' + 'use of the\n' + '"in" operator; for mappings, "in" should search the ' + 'mapping’s keys;\n' + 'for sequences, it should search through the values. It is ' + 'further\n' + 'recommended that both mappings and sequences implement ' + 'the\n' '"__iter__()" method to allow efficient iteration through ' 'the\n' 'container; for mappings, "__iter__()" should iterate ' @@ -9591,9 +9711,12 @@ 'the\n' 'second argument.\n' '\n' - 'This operation can be customized using the special ' - '"__lshift__()" and\n' - '"__rshift__()" methods.\n' + 'The left shift operation can be customized using the special\n' + '"__lshift__()" and "__rlshift__()" methods. The right shift ' + 'operation\n' + 'can be customized using the special "__rshift__()" and ' + '"__rrshift__()"\n' + 'methods.\n' '\n' 'A right shift by *n* bits is defined as floor division by ' '"pow(2,n)".\n' @@ -9659,20 +9782,6 @@ 'not reported\n' 'by the "dir()" built-in function.\n' '\n' - 'object.__dict__\n' - '\n' - ' A dictionary or other mapping object used to store an ' - 'object’s\n' - ' (writable) attributes.\n' - '\n' - 'instance.__class__\n' - '\n' - ' The class to which a class instance belongs.\n' - '\n' - 'class.__bases__\n' - '\n' - ' The tuple of base classes of a class object.\n' - '\n' 'definition.__name__\n' '\n' ' The name of the class, function, method, descriptor, or ' @@ -9687,39 +9796,26 @@ '\n' ' Added in version 3.3.\n' '\n' - 'definition.__type_params__\n' - '\n' - ' The type parameters of generic classes, functions, and ' - 'type\n' - ' aliases.\n' - '\n' - ' Added in version 3.12.\n' - '\n' - 'class.__mro__\n' + 'definition.__module__\n' '\n' - ' This attribute is a tuple of classes that are considered ' - 'when\n' - ' looking for base classes during method resolution.\n' + ' The name of the module in which a class or function was ' + 'defined.\n' '\n' - 'class.mro()\n' + 'definition.__doc__\n' '\n' - ' This method can be overridden by a metaclass to customize ' - 'the\n' - ' method resolution order for its instances. It is called ' - 'at class\n' - ' instantiation, and its result is stored in "__mro__".\n' + ' The documentation string of a class or function, or ' + '"None" if\n' + ' undefined.\n' '\n' - 'class.__subclasses__()\n' + 'definition.__type_params__\n' '\n' - ' Each class keeps a list of weak references to its ' - 'immediate\n' - ' subclasses. This method returns a list of all those ' - 'references\n' - ' still alive. The list is in definition order. Example:\n' + ' The type parameters of generic classes, functions, and ' + 'type\n' + ' aliases. For classes and functions that are not generic, ' + 'this will\n' + ' be an empty tuple.\n' '\n' - ' >>> int.__subclasses__()\n' - " [, , , " - "]\n", + ' Added in version 3.12.\n', 'specialnames': 'Special method names\n' '********************\n' '\n' @@ -9863,6 +9959,10 @@ ' It is not guaranteed that "__del__()" methods are called ' 'for\n' ' objects that still exist when the interpreter exits.\n' + ' "weakref.finalize" provides a straightforward way to ' + 'register a\n' + ' cleanup function to be called when an object is garbage ' + 'collected.\n' '\n' ' Note:\n' '\n' @@ -9949,17 +10049,19 @@ '\n' ' This is typically used for debugging, so it is important ' 'that the\n' - ' representation is information-rich and unambiguous.\n' + ' representation is information-rich and unambiguous. A ' + 'default\n' + ' implementation is provided by the "object" class itself.\n' '\n' 'object.__str__(self)\n' '\n' - ' Called by "str(object)" and the built-in functions ' - '"format()" and\n' - ' "print()" to compute the “informal” or nicely printable ' - 'string\n' - ' representation of an object. The return value must be a ' - 'string\n' - ' object.\n' + ' Called by "str(object)", the default "__format__()" ' + 'implementation,\n' + ' and the built-in function "print()", to compute the ' + '“informal” or\n' + ' nicely printable string representation of an object. The ' + 'return\n' + ' value must be a str object.\n' '\n' ' This method differs from "object.__repr__()" in that ' 'there is no\n' @@ -9975,7 +10077,9 @@ '\n' ' Called by bytes to compute a byte-string representation ' 'of an\n' - ' object. This should return a "bytes" object.\n' + ' object. This should return a "bytes" object. The "object" ' + 'class\n' + ' itself does not provide this method.\n' '\n' 'object.__format__(self, format_spec)\n' '\n' @@ -10003,6 +10107,10 @@ '\n' ' The return value must be a string object.\n' '\n' + ' The default implementation by the "object" class should ' + 'be given an\n' + ' empty *format_spec* string. It delegates to "__str__()".\n' + '\n' ' Changed in version 3.4: The __format__ method of "object" ' 'itself\n' ' raises a "TypeError" if passed any non-empty string.\n' @@ -10060,6 +10168,16 @@ ' ordering operations from a single root operation, see\n' ' "functools.total_ordering()".\n' '\n' + ' By default, the "object" class provides implementations ' + 'consistent\n' + ' with Value comparisons: equality compares according to ' + 'object\n' + ' identity, and order comparisons raise "TypeError". Each ' + 'default\n' + ' method may generate these results directly, but may also ' + 'return\n' + ' "NotImplemented".\n' + '\n' ' See the paragraph on "__hash__()" for some important ' 'notes on\n' ' creating *hashable* objects which support custom ' @@ -10145,12 +10263,13 @@ '\n' ' User-defined classes have "__eq__()" and "__hash__()" ' 'methods by\n' - ' default; with them, all objects compare unequal (except ' - 'with\n' - ' themselves) and "x.__hash__()" returns an appropriate ' - 'value such\n' - ' that "x == y" implies both that "x is y" and "hash(x) == ' - 'hash(y)".\n' + ' default (inherited from the "object" class); with them, ' + 'all objects\n' + ' compare unequal (except with themselves) and ' + '"x.__hash__()" returns\n' + ' an appropriate value such that "x == y" implies both that ' + '"x is y"\n' + ' and "hash(x) == hash(y)".\n' '\n' ' A class that overrides "__eq__()" and does not define ' '"__hash__()"\n' @@ -10219,9 +10338,9 @@ 'object is\n' ' considered true if its result is nonzero. If a class ' 'defines\n' - ' neither "__len__()" nor "__bool__()", all its instances ' - 'are\n' - ' considered true.\n' + ' neither "__len__()" nor "__bool__()" (which is true of ' + 'the "object"\n' + ' class itself), all its instances are considered true.\n' '\n' '\n' 'Customizing attribute access\n' @@ -10245,7 +10364,8 @@ 'either\n' ' return the (computed) attribute value or raise an ' '"AttributeError"\n' - ' exception.\n' + ' exception. The "object" class itself does not provide ' + 'this method.\n' '\n' ' Note that if the attribute is found through the normal ' 'mechanism,\n' @@ -10425,7 +10545,9 @@ 'parents). In the\n' 'examples below, “the attribute” refers to the attribute ' 'whose name is\n' - 'the key of the property in the owner class’ "__dict__".\n' + 'the key of the property in the owner class’ "__dict__". The ' + '"object"\n' + 'class itself does not implement any of these protocols.\n' '\n' 'object.__get__(self, instance, owner=None)\n' '\n' @@ -10661,11 +10783,13 @@ 'the class\n' ' where it is defined. *__slots__* declared in parents are ' 'available\n' - ' in child classes. However, child subclasses will get a ' - '"__dict__"\n' - ' and *__weakref__* unless they also define *__slots__* ' - '(which should\n' - ' only contain names of any *additional* slots).\n' + ' in child classes. However, instances of a child subclass ' + 'will get a\n' + ' "__dict__" and *__weakref__* unless the subclass also ' + 'defines\n' + ' *__slots__* (which should only contain names of any ' + '*additional*\n' + ' slots).\n' '\n' '* If a class defines a slot also defined in a base class, ' 'the instance\n' @@ -11082,7 +11206,7 @@ 'built-in\n' 'types), including other ABCs.\n' '\n' - 'class.__instancecheck__(self, instance)\n' + 'type.__instancecheck__(self, instance)\n' '\n' ' Return true if *instance* should be considered a (direct ' 'or\n' @@ -11090,7 +11214,7 @@ 'implement\n' ' "isinstance(instance, class)".\n' '\n' - 'class.__subclasscheck__(self, subclass)\n' + 'type.__subclasscheck__(self, subclass)\n' '\n' ' Return true if *subclass* should be considered a (direct ' 'or\n' @@ -11306,7 +11430,9 @@ ' Called when the instance is “called” as a function; if ' 'this method\n' ' is defined, "x(arg1, arg2, ...)" roughly translates to\n' - ' "type(x).__call__(x, arg1, ...)".\n' + ' "type(x).__call__(x, arg1, ...)". The "object" class ' + 'itself does\n' + ' not provide this method.\n' '\n' '\n' 'Emulating container types\n' @@ -11314,54 +11440,54 @@ '\n' 'The following methods can be defined to implement container ' 'objects.\n' - 'Containers usually are *sequences* (such as "lists" or ' - '"tuples") or\n' - '*mappings* (like "dictionaries"), but can represent other ' - 'containers\n' - 'as well. The first set of methods is used either to emulate ' - 'a\n' - 'sequence or to emulate a mapping; the difference is that for ' - 'a\n' - 'sequence, the allowable keys should be the integers *k* for ' - 'which "0\n' - '<= k < N" where *N* is the length of the sequence, or ' - '"slice" objects,\n' - 'which define a range of items. It is also recommended that ' - 'mappings\n' - 'provide the methods "keys()", "values()", "items()", ' - '"get()",\n' - '"clear()", "setdefault()", "pop()", "popitem()", "copy()", ' - 'and\n' - '"update()" behaving similar to those for Python’s standard\n' - '"dictionary" objects. The "collections.abc" module provides ' - 'a\n' - '"MutableMapping" *abstract base class* to help create those ' - 'methods\n' - 'from a base set of "__getitem__()", "__setitem__()", ' - '"__delitem__()",\n' - 'and "keys()". Mutable sequences should provide methods ' - '"append()",\n' - '"count()", "index()", "extend()", "insert()", "pop()", ' - '"remove()",\n' - '"reverse()" and "sort()", like Python standard "list" ' + 'None of them are provided by the "object" class itself. ' + 'Containers\n' + 'usually are *sequences* (such as "lists" or "tuples") or ' + '*mappings*\n' + '(like *dictionaries*), but can represent other containers as ' + 'well.\n' + 'The first set of methods is used either to emulate a ' + 'sequence or to\n' + 'emulate a mapping; the difference is that for a sequence, ' + 'the\n' + 'allowable keys should be the integers *k* for which "0 <= k ' + '< N" where\n' + '*N* is the length of the sequence, or "slice" objects, which ' + 'define a\n' + 'range of items. It is also recommended that mappings ' + 'provide the\n' + 'methods "keys()", "values()", "items()", "get()", ' + '"clear()",\n' + '"setdefault()", "pop()", "popitem()", "copy()", and ' + '"update()"\n' + 'behaving similar to those for Python’s standard "dictionary" ' 'objects.\n' - 'Finally, sequence types should implement addition (meaning\n' - 'concatenation) and multiplication (meaning repetition) by ' - 'defining the\n' - 'methods "__add__()", "__radd__()", "__iadd__()", ' - '"__mul__()",\n' - '"__rmul__()" and "__imul__()" described below; they should ' - 'not define\n' - 'other numerical operators. It is recommended that both ' - 'mappings and\n' - 'sequences implement the "__contains__()" method to allow ' - 'efficient use\n' - 'of the "in" operator; for mappings, "in" should search the ' - 'mapping’s\n' - 'keys; for sequences, it should search through the values. ' - 'It is\n' - 'further recommended that both mappings and sequences ' - 'implement the\n' + 'The "collections.abc" module provides a "MutableMapping" ' + '*abstract\n' + 'base class* to help create those methods from a base set of\n' + '"__getitem__()", "__setitem__()", "__delitem__()", and ' + '"keys()".\n' + 'Mutable sequences should provide methods "append()", ' + '"count()",\n' + '"index()", "extend()", "insert()", "pop()", "remove()", ' + '"reverse()"\n' + 'and "sort()", like Python standard "list" objects. Finally, ' + 'sequence\n' + 'types should implement addition (meaning concatenation) and\n' + 'multiplication (meaning repetition) by defining the methods\n' + '"__add__()", "__radd__()", "__iadd__()", "__mul__()", ' + '"__rmul__()" and\n' + '"__imul__()" described below; they should not define other ' + 'numerical\n' + 'operators. It is recommended that both mappings and ' + 'sequences\n' + 'implement the "__contains__()" method to allow efficient use ' + 'of the\n' + '"in" operator; for mappings, "in" should search the ' + 'mapping’s keys;\n' + 'for sequences, it should search through the values. It is ' + 'further\n' + 'recommended that both mappings and sequences implement the\n' '"__iter__()" method to allow efficient iteration through ' 'the\n' 'container; for mappings, "__iter__()" should iterate through ' @@ -11777,6 +11903,9 @@ '\n' 'For more information on context managers, see Context ' 'Manager Types.\n' + 'The "object" class itself does not provide the context ' + 'manager\n' + 'methods.\n' '\n' 'object.__enter__(self)\n' '\n' @@ -12657,11 +12786,11 @@ ' and are deemed to delimit empty strings (for example,\n' ' "\'1,,2\'.split(\',\')" returns "[\'1\', \'\', ' '\'2\']"). The *sep* argument\n' - ' may consist of multiple characters (for example,\n' - ' "\'1<>2<>3\'.split(\'<>\')" returns "[\'1\', \'2\', ' - '\'3\']"). Splitting an\n' - ' empty string with a specified separator returns ' - '"[\'\']".\n' + ' may consist of multiple characters as a single ' + 'delimiter (to split\n' + ' with multiple delimiters, use "re.split()"). Splitting ' + 'an empty\n' + ' string with a specified separator returns "[\'\']".\n' '\n' ' For example:\n' '\n' @@ -12671,6 +12800,8 @@ " ['1', '2,3']\n" " >>> '1,2,,3,'.split(',')\n" " ['1', '2', '', '3', '']\n" + " >>> '1<>2<>3<4'.split('<>')\n" + " ['1', '2', '3<4']\n" '\n' ' If *sep* is not specified or is "None", a different ' 'splitting\n' @@ -13013,15 +13144,13 @@ 'greater must be expressed with escapes.\n' '\n' 'Both string and bytes literals may optionally be prefixed with a\n' - 'letter "\'r\'" or "\'R\'"; such strings are called *raw strings* ' - 'and treat\n' - 'backslashes as literal characters. As a result, in string ' - 'literals,\n' - '"\'\\U\'" and "\'\\u\'" escapes in raw strings are not treated ' - 'specially.\n' - 'Given that Python 2.x’s raw unicode literals behave differently ' - 'than\n' - 'Python 3.x’s the "\'ur\'" syntax is not supported.\n' + 'letter "\'r\'" or "\'R\'"; such constructs are called *raw ' + 'string\n' + 'literals* and *raw bytes literals* respectively and treat ' + 'backslashes\n' + 'as literal characters. As a result, in raw string literals, ' + '"\'\\U\'"\n' + 'and "\'\\u\'" escapes are not treated specially.\n' '\n' 'Added in version 3.3: The "\'rb\'" prefix of raw bytes literals ' 'has been\n' @@ -13212,7 +13341,8 @@ '*generic\n' 'class* will generally return a GenericAlias object.\n' '\n' - ' subscription ::= primary "[" expression_list "]"\n' + ' subscription ::= primary "[" flexible_expression_list ' + '"]"\n' '\n' 'When an object is subscripted, the interpreter will ' 'evaluate the\n' @@ -13231,13 +13361,18 @@ 'see\n' '__class_getitem__ versus __getitem__.\n' '\n' - 'If the expression list contains at least one comma, it will ' - 'evaluate\n' - 'to a "tuple" containing the items of the expression list. ' - 'Otherwise,\n' - 'the expression list will evaluate to the value of the ' - 'list’s sole\n' - 'member.\n' + 'If the expression list contains at least one comma, or if ' + 'any of the\n' + 'expressions are starred, the expression list will evaluate ' + 'to a\n' + '"tuple" containing the items of the expression list. ' + 'Otherwise, the\n' + 'expression list will evaluate to the value of the list’s ' + 'sole member.\n' + '\n' + 'Changed in version 3.11: Expressions in an expression list ' + 'may be\n' + 'starred. See **PEP 646**.\n' '\n' 'For built-in objects, there are two types of objects that ' 'support\n' @@ -13351,14 +13486,15 @@ 'clauses in turn until one is found that matches the exception. An\n' 'expression-less "except" clause, if present, must be last; it ' 'matches\n' - 'any exception. For an "except" clause with an expression, that\n' - 'expression is evaluated, and the clause matches the exception if the\n' - 'resulting object is “compatible” with the exception. An object is\n' - 'compatible with an exception if the object is the class or a *non-\n' - 'virtual base class* of the exception object, or a tuple containing ' - 'an\n' - 'item that is the class or a non-virtual base class of the exception\n' - 'object.\n' + 'any exception.\n' + '\n' + 'For an "except" clause with an expression, the expression must\n' + 'evaluate to an exception type or a tuple of exception types. The\n' + 'raised exception matches an "except" clause whose expression ' + 'evaluates\n' + 'to the class or a *non-virtual base class* of the exception object, ' + 'or\n' + 'to a tuple that contains such a class.\n' '\n' 'If no "except" clause matches the exception, the search for an\n' 'exception handler continues in the surrounding code and on the\n' @@ -13487,12 +13623,13 @@ ' ...\n' " ExceptionGroup('', (BlockingIOError()))\n" '\n' - 'An "except*" clause must have a matching type, and this type cannot ' - 'be\n' - 'a subclass of "BaseExceptionGroup". It is not possible to mix ' - '"except"\n' - 'and "except*" in the same "try". "break", "continue" and "return"\n' - 'cannot appear in an "except*" clause.\n' + 'An "except*" clause must have a matching expression; it cannot be\n' + '"except*:". Furthermore, this expression cannot contain exception\n' + 'group types, because that would have ambiguous semantics.\n' + '\n' + 'It is not possible to mix "except" and "except*" in the same "try".\n' + '"break", "continue" and "return" cannot appear in an "except*" ' + 'clause.\n' '\n' '\n' '"else" clause\n' @@ -13653,7 +13790,7 @@ '\n' '* A sign is shown only when the number is negative.\n' '\n' - 'Python distinguishes between integers, floating point numbers, and\n' + 'Python distinguishes between integers, floating-point numbers, and\n' 'complex numbers:\n' '\n' '\n' @@ -13698,28 +13835,28 @@ '"numbers.Real" ("float")\n' '------------------------\n' '\n' - 'These represent machine-level double precision floating point ' + 'These represent machine-level double precision floating-point ' 'numbers.\n' 'You are at the mercy of the underlying machine architecture (and C ' 'or\n' 'Java implementation) for the accepted range and handling of ' 'overflow.\n' - 'Python does not support single-precision floating point numbers; ' + 'Python does not support single-precision floating-point numbers; ' 'the\n' 'savings in processor and memory usage that are usually the reason ' 'for\n' 'using these are dwarfed by the overhead of using objects in Python, ' 'so\n' 'there is no reason to complicate the language with two kinds of\n' - 'floating point numbers.\n' + 'floating-point numbers.\n' '\n' '\n' '"numbers.Complex" ("complex")\n' '-----------------------------\n' '\n' 'These represent complex numbers as a pair of machine-level double\n' - 'precision floating point numbers. The same caveats apply as for\n' - 'floating point numbers. The real and imaginary parts of a complex\n' + 'precision floating-point numbers. The same caveats apply as for\n' + 'floating-point numbers. The real and imaginary parts of a complex\n' 'number "z" can be retrieved through the read-only attributes ' '"z.real"\n' 'and "z.imag".\n' @@ -13913,8 +14050,7 @@ 'however removing a key and re-inserting it will add it to the end\n' 'instead of keeping its old place.\n' '\n' - 'Dictionaries are mutable; they can be created by the "{...}" ' - 'notation\n' + 'Dictionaries are mutable; they can be created by the "{}" notation\n' '(see section Dictionary displays).\n' '\n' 'The extension modules "dbm.ndbm" and "dbm.gnu" provide additional\n' @@ -13985,8 +14121,8 @@ '|====================================================|====================================================|\n' '| function.__doc__ | The ' 'function’s documentation string, or "None" if |\n' - '| | unavailable. ' - 'Not inherited by subclasses. |\n' + '| | ' + 'unavailable. |\n' '+----------------------------------------------------+----------------------------------------------------+\n' '| function.__name__ | The ' 'function’s name. See also: "__name__ |\n' @@ -14134,21 +14270,10 @@ 'to\n' 'calling "f(C,1)" where "f" is the underlying function.\n' '\n' - 'Note that the transformation from function object to instance ' - 'method\n' - 'object happens each time the attribute is retrieved from the ' - 'instance.\n' - 'In some cases, a fruitful optimization is to assign the attribute ' - 'to a\n' - 'local variable and call that local variable. Also notice that this\n' - 'transformation only happens for user-defined functions; other ' - 'callable\n' - 'objects (and all non-callable objects) are retrieved without\n' - 'transformation. It is also important to note that user-defined\n' - 'functions which are attributes of a class instance are not ' - 'converted\n' - 'to bound methods; this *only* happens when the function is an\n' - 'attribute of the class.\n' + 'It is important to note that user-defined functions which are\n' + 'attributes of a class instance are not converted to bound methods;\n' + 'this *only* happens when the function is an attribute of the ' + 'class.\n' '\n' '\n' 'Generator functions\n' @@ -14285,43 +14410,254 @@ 'e.g.,\n' '"m.x = 1" is equivalent to "m.__dict__["x"] = 1".\n' '\n' - 'Predefined (writable) attributes:\n' '\n' - ' "__name__"\n' - ' The module’s name.\n' + 'Import-related attributes on module objects\n' + '-------------------------------------------\n' + '\n' + 'Module objects have the following attributes that relate to the ' + 'import\n' + 'system. When a module is created using the machinery associated ' + 'with\n' + 'the import system, these attributes are filled in based on the\n' + 'module’s *spec*, before the *loader* executes and loads the ' + 'module.\n' + '\n' + 'To create a module dynamically rather than using the import ' + 'system,\n' + 'it’s recommended to use "importlib.util.module_from_spec()", which\n' + 'will set the various import-controlled attributes to appropriate\n' + 'values. It’s also possible to use the "types.ModuleType" ' + 'constructor\n' + 'to create modules directly, but this technique is more error-prone, ' + 'as\n' + 'most attributes must be manually set on the module object after it ' + 'has\n' + 'been created when using this approach.\n' + '\n' + 'Caution:\n' + '\n' + ' With the exception of "__name__", it is **strongly** recommended\n' + ' that you rely on "__spec__" and its attributes instead of any of ' + 'the\n' + ' other individual attributes listed in this subsection. Note that\n' + ' updating an attribute on "__spec__" will not update the\n' + ' corresponding attribute on the module itself:\n' + '\n' + ' >>> import typing\n' + ' >>> typing.__name__, typing.__spec__.name\n' + " ('typing', 'typing')\n" + " >>> typing.__spec__.name = 'spelling'\n" + ' >>> typing.__name__, typing.__spec__.name\n' + " ('typing', 'spelling')\n" + " >>> typing.__name__ = 'keyboard_smashing'\n" + ' >>> typing.__name__, typing.__spec__.name\n' + " ('keyboard_smashing', 'spelling')\n" + '\n' + 'module.__name__\n' + '\n' + ' The name used to uniquely identify the module in the import ' + 'system.\n' + ' For a directly executed module, this will be set to ' + '""__main__"".\n' + '\n' + ' This attribute must be set to the fully qualified name of the\n' + ' module. It is expected to match the value of\n' + ' "module.__spec__.name".\n' + '\n' + 'module.__spec__\n' + '\n' + ' A record of the module’s import-system-related state.\n' + '\n' + ' Set to the "module spec" that was used when importing the ' + 'module.\n' + ' See Module specs for more details.\n' + '\n' + ' Added in version 3.4.\n' + '\n' + 'module.__package__\n' + '\n' + ' The *package* a module belongs to.\n' + '\n' + ' If the module is top-level (that is, not a part of any specific\n' + ' package) then the attribute should be set to "\'\'" (the empty\n' + ' string). Otherwise, it should be set to the name of the ' + 'module’s\n' + ' package (which can be equal to "module.__name__" if the module\n' + ' itself is a package). See **PEP 366** for further details.\n' + '\n' + ' This attribute is used instead of "__name__" to calculate ' + 'explicit\n' + ' relative imports for main modules. It defaults to "None" for\n' + ' modules created dynamically using the "types.ModuleType"\n' + ' constructor; use "importlib.util.module_from_spec()" instead to\n' + ' ensure the attribute is set to a "str".\n' + '\n' + ' It is **strongly** recommended that you use\n' + ' "module.__spec__.parent" instead of "module.__package__".\n' + ' "__package__" is now only used as a fallback if ' + '"__spec__.parent"\n' + ' is not set, and this fallback path is deprecated.\n' + '\n' + ' Changed in version 3.4: This attribute now defaults to "None" ' + 'for\n' + ' modules created dynamically using the "types.ModuleType"\n' + ' constructor. Previously the attribute was optional.\n' + '\n' + ' Changed in version 3.6: The value of "__package__" is expected ' + 'to\n' + ' be the same as "__spec__.parent". "__package__" is now only used ' + 'as\n' + ' a fallback during import resolution if "__spec__.parent" is not\n' + ' defined.\n' '\n' - ' "__doc__"\n' - ' The module’s documentation string, or "None" if unavailable.\n' + ' Changed in version 3.10: "ImportWarning" is raised if an import\n' + ' resolution falls back to "__package__" instead of\n' + ' "__spec__.parent".\n' '\n' - ' "__file__"\n' - ' The pathname of the file from which the module was loaded, if ' - 'it\n' - ' was loaded from a file. The "__file__" attribute may be ' - 'missing\n' - ' for certain types of modules, such as C modules that are\n' - ' statically linked into the interpreter. For extension ' + ' Changed in version 3.12: Raise "DeprecationWarning" instead of\n' + ' "ImportWarning" when falling back to "__package__" during ' + 'import\n' + ' resolution.\n' + '\n' + 'module.__loader__\n' + '\n' + ' The *loader* object that the import machinery used to load the\n' + ' module.\n' + '\n' + ' This attribute is mostly useful for introspection, but can be ' + 'used\n' + ' for additional loader-specific functionality, for example ' + 'getting\n' + ' data associated with a loader.\n' + '\n' + ' "__loader__" defaults to "None" for modules created dynamically\n' + ' using the "types.ModuleType" constructor; use\n' + ' "importlib.util.module_from_spec()" instead to ensure the ' + 'attribute\n' + ' is set to a *loader* object.\n' + '\n' + ' It is **strongly** recommended that you use\n' + ' "module.__spec__.loader" instead of "module.__loader__".\n' + '\n' + ' Changed in version 3.4: This attribute now defaults to "None" ' + 'for\n' + ' modules created dynamically using the "types.ModuleType"\n' + ' constructor. Previously the attribute was optional.\n' + '\n' + ' Deprecated since version 3.12, will be removed in version 3.16:\n' + ' Setting "__loader__" on a module while failing to set\n' + ' "__spec__.loader" is deprecated. In Python 3.16, "__loader__" ' + 'will\n' + ' cease to be set or taken into consideration by the import system ' + 'or\n' + ' the standard library.\n' + '\n' + 'module.__path__\n' + '\n' + ' A (possibly empty) *sequence* of strings enumerating the ' + 'locations\n' + ' where the package’s submodules will be found. Non-package ' 'modules\n' - ' loaded dynamically from a shared library, it’s the pathname ' - 'of\n' - ' the shared library file.\n' + ' should not have a "__path__" attribute. See __path__ attributes ' + 'on\n' + ' modules for more details.\n' '\n' - ' "__annotations__"\n' - ' A dictionary containing *variable annotations* collected ' - 'during\n' - ' module body execution. For best practices on working with\n' - ' "__annotations__", please see Annotations Best Practices.\n' + ' It is **strongly** recommended that you use\n' + ' "module.__spec__.submodule_search_locations" instead of\n' + ' "module.__path__".\n' '\n' - 'Special read-only attribute: "__dict__" is the module’s namespace ' - 'as a\n' - 'dictionary object.\n' + 'module.__file__\n' '\n' - '**CPython implementation detail:** Because of the way CPython ' - 'clears\n' - 'module dictionaries, the module dictionary will be cleared when ' + 'module.__cached__\n' + '\n' + ' "__file__" and "__cached__" are both optional attributes that ' + 'may\n' + ' or may not be set. Both attributes should be a "str" when they ' + 'are\n' + ' available.\n' + '\n' + ' "__file__" indicates the pathname of the file from which the ' + 'module\n' + ' was loaded (if loaded from a file), or the pathname of the ' + 'shared\n' + ' library file for extension modules loaded dynamically from a ' + 'shared\n' + ' library. It might be missing for certain types of modules, such ' + 'as\n' + ' C modules that are statically linked into the interpreter, and ' 'the\n' - 'module falls out of scope even if the dictionary still has live\n' - 'references. To avoid this, copy the dictionary or keep the module\n' - 'around while using its dictionary directly.\n' + ' import system may opt to leave it unset if it has no semantic\n' + ' meaning (for example, a module loaded from a database).\n' + '\n' + ' If "__file__" is set then the "__cached__" attribute might also ' + 'be\n' + ' set, which is the path to any compiled version of the code ' + '(for\n' + ' example, a byte-compiled file). The file does not need to exist ' + 'to\n' + ' set this attribute; the path can simply point to where the ' + 'compiled\n' + ' file *would* exist (see **PEP 3147**).\n' + '\n' + ' Note that "__cached__" may be set even if "__file__" is not ' + 'set.\n' + ' However, that scenario is quite atypical. Ultimately, the ' + '*loader*\n' + ' is what makes use of the module spec provided by the *finder* ' + '(from\n' + ' which "__file__" and "__cached__" are derived). So if a loader ' + 'can\n' + ' load from a cached module but otherwise does not load from a ' + 'file,\n' + ' that atypical scenario may be appropriate.\n' + '\n' + ' It is **strongly** recommended that you use\n' + ' "module.__spec__.cached" instead of "module.__cached__".\n' + '\n' + '\n' + 'Other writable attributes on module objects\n' + '-------------------------------------------\n' + '\n' + 'As well as the import-related attributes listed above, module ' + 'objects\n' + 'also have the following writable attributes:\n' + '\n' + 'module.__doc__\n' + '\n' + ' The module’s documentation string, or "None" if unavailable. ' + 'See\n' + ' also: "__doc__ attributes".\n' + '\n' + 'module.__annotations__\n' + '\n' + ' A dictionary containing *variable annotations* collected during\n' + ' module body execution. For best practices on working with\n' + ' "__annotations__", please see Annotations Best Practices.\n' + '\n' + '\n' + 'Module dictionaries\n' + '-------------------\n' + '\n' + 'Module objects also have the following special read-only ' + 'attribute:\n' + '\n' + 'module.__dict__\n' + '\n' + ' The module’s namespace as a dictionary object. Uniquely among ' + 'the\n' + ' attributes listed here, "__dict__" cannot be accessed as a ' + 'global\n' + ' variable from within a module; it can only be accessed as an\n' + ' attribute on module objects.\n' + '\n' + ' **CPython implementation detail:** Because of the way CPython\n' + ' clears module dictionaries, the module dictionary will be ' + 'cleared\n' + ' when the module falls out of scope even if the dictionary still ' + 'has\n' + ' live references. To avoid this, copy the dictionary or keep ' + 'the\n' + ' module around while using its dictionary directly.\n' '\n' '\n' 'Custom classes\n' @@ -14367,32 +14703,104 @@ 'A class object can be called (see above) to yield a class instance\n' '(see below).\n' '\n' - 'Special attributes:\n' '\n' - ' "__name__"\n' - ' The class name.\n' + 'Special attributes\n' + '------------------\n' + '\n' + '+----------------------------------------------------+----------------------------------------------------+\n' + '| Attribute | ' + 'Meaning |\n' + '|====================================================|====================================================|\n' + '| type.__name__ | The class’s ' + 'name. See also: "__name__ attributes". |\n' + '+----------------------------------------------------+----------------------------------------------------+\n' + '| type.__qualname__ | The class’s ' + '*qualified name*. See also: |\n' + '| | ' + '"__qualname__ attributes". |\n' + '+----------------------------------------------------+----------------------------------------------------+\n' + '| type.__module__ | The name of ' + 'the module in which the class was |\n' + '| | ' + 'defined. |\n' + '+----------------------------------------------------+----------------------------------------------------+\n' + '| type.__dict__ | A "mapping ' + 'proxy" providing a read-only view of |\n' + '| | the class’s ' + 'namespace. See also: "__dict__ |\n' + '| | ' + 'attributes". |\n' + '+----------------------------------------------------+----------------------------------------------------+\n' + '| type.__bases__ | A "tuple" ' + 'containing the class’s bases. In most |\n' + '| | cases, for a ' + 'class defined as "class X(A, B, C)", |\n' + '| | ' + '"X.__bases__" will be exactly equal to "(A, B, |\n' + '| | ' + 'C)". |\n' + '+----------------------------------------------------+----------------------------------------------------+\n' + '| type.__doc__ | The class’s ' + 'documentation string, or "None" if |\n' + '| | undefined. ' + 'Not inherited by subclasses. |\n' + '+----------------------------------------------------+----------------------------------------------------+\n' + '| type.__annotations__ | A dictionary ' + 'containing *variable annotations* |\n' + '| | collected ' + 'during class body execution. For best |\n' + '| | practices on ' + 'working with "__annotations__", |\n' + '| | please see ' + 'Annotations Best Practices. Caution: |\n' + '| | Accessing ' + 'the "__annotations__" attribute of a |\n' + '| | class object ' + 'directly may yield incorrect results |\n' + '| | in the ' + 'presence of metaclasses. In addition, the |\n' + '| | attribute ' + 'may not exist for some classes. Use |\n' + '| | ' + '"inspect.get_annotations()" to retrieve class |\n' + '| | annotations ' + 'safely. |\n' + '+----------------------------------------------------+----------------------------------------------------+\n' + '| type.__type_params__ | A "tuple" ' + 'containing the type parameters of a |\n' + '| | generic ' + 'class. Added in version 3.12. |\n' + '+----------------------------------------------------+----------------------------------------------------+\n' + '| type.__mro__ | The "tuple" ' + 'of classes that are considered when |\n' + '| | looking for ' + 'base classes during method resolution. |\n' + '+----------------------------------------------------+----------------------------------------------------+\n' + '\n' + '\n' + 'Special methods\n' + '---------------\n' '\n' - ' "__module__"\n' - ' The name of the module in which the class was defined.\n' + 'In addition to the special attributes described above, all Python\n' + 'classes also have the following two methods available:\n' '\n' - ' "__dict__"\n' - ' The dictionary containing the class’s namespace.\n' + 'type.mro()\n' '\n' - ' "__bases__"\n' - ' A tuple containing the base classes, in the order of their\n' - ' occurrence in the base class list.\n' + ' This method can be overridden by a metaclass to customize the\n' + ' method resolution order for its instances. It is called at ' + 'class\n' + ' instantiation, and its result is stored in "__mro__".\n' '\n' - ' "__doc__"\n' - ' The class’s documentation string, or "None" if undefined.\n' + 'type.__subclasses__()\n' '\n' - ' "__annotations__"\n' - ' A dictionary containing *variable annotations* collected ' - 'during\n' - ' class body execution. For best practices on working with\n' - ' "__annotations__", please see Annotations Best Practices.\n' + ' Each class keeps a list of weak references to its immediate\n' + ' subclasses. This method returns a list of all those references\n' + ' still alive. The list is in definition order. Example:\n' '\n' - ' "__type_params__"\n' - ' A tuple containing the type parameters of a generic class.\n' + ' >>> class A: pass\n' + ' >>> class B(A): pass\n' + ' >>> A.__subclasses__()\n' + " []\n" '\n' '\n' 'Class instances\n' @@ -14432,8 +14840,19 @@ 'they have methods with certain special names. See section Special\n' 'method names.\n' '\n' - 'Special attributes: "__dict__" is the attribute dictionary;\n' - '"__class__" is the instance’s class.\n' + '\n' + 'Special attributes\n' + '------------------\n' + '\n' + 'object.__class__\n' + '\n' + ' The class to which a class instance belongs.\n' + '\n' + 'object.__dict__\n' + '\n' + ' A dictionary or other mapping object used to store an object’s\n' + ' (writable) attributes. Not all instances have a "__dict__"\n' + ' attribute; see the section on __slots__ for more details.\n' '\n' '\n' 'I/O objects (also known as file objects)\n' @@ -14573,7 +14992,7 @@ '| | version ' '3.12: This attribute of code objects is |\n' '| | deprecated, ' - 'and may be removed in Python 3.14. |\n' + 'and may be removed in Python 3.15. |\n' '+----------------------------------------------------+----------------------------------------------------+\n' '| codeobject.co_stacksize | The required ' 'stack size of the code object |\n' @@ -15028,21 +15447,23 @@ '\n' ' If no positional argument is given, an empty dictionary ' 'is created.\n' - ' If a positional argument is given and it is a mapping ' - 'object, a\n' - ' dictionary is created with the same key-value pairs as ' - 'the mapping\n' - ' object. Otherwise, the positional argument must be an ' - '*iterable*\n' - ' object. Each item in the iterable must itself be an ' - 'iterable with\n' - ' exactly two objects. The first object of each item ' - 'becomes a key\n' - ' in the new dictionary, and the second object the ' - 'corresponding\n' - ' value. If a key occurs more than once, the last value ' - 'for that key\n' - ' becomes the corresponding value in the new dictionary.\n' + ' If a positional argument is given and it defines a ' + '"keys()" method,\n' + ' a dictionary is created by calling "__getitem__()" on the ' + 'argument\n' + ' with each returned key from the method. Otherwise, the ' + 'positional\n' + ' argument must be an *iterable* object. Each item in the ' + 'iterable\n' + ' must itself be an iterable with exactly two elements. ' + 'The first\n' + ' element of each item becomes a key in the new dictionary, ' + 'and the\n' + ' second element the corresponding value. If a key occurs ' + 'more than\n' + ' once, the last value for that key becomes the ' + 'corresponding value\n' + ' in the new dictionary.\n' '\n' ' If keyword arguments are given, the keyword arguments and ' 'their\n' @@ -15155,7 +15576,7 @@ '\n' ' Return a shallow copy of the dictionary.\n' '\n' - ' classmethod fromkeys(iterable, value=None)\n' + ' classmethod fromkeys(iterable, value=None, /)\n' '\n' ' Create a new dictionary with keys from *iterable* and ' 'values set\n' @@ -15237,15 +15658,17 @@ '*other*,\n' ' overwriting existing keys. Return "None".\n' '\n' - ' "update()" accepts either another dictionary object or ' - 'an\n' - ' iterable of key/value pairs (as tuples or other ' - 'iterables of\n' - ' length two). If keyword arguments are specified, the ' - 'dictionary\n' - ' is then updated with those key/value pairs: ' - '"d.update(red=1,\n' - ' blue=2)".\n' + ' "update()" accepts either another object with a ' + '"keys()" method\n' + ' (in which case "__getitem__()" is called with every ' + 'key returned\n' + ' from the method) or an iterable of key/value pairs (as ' + 'tuples or\n' + ' other iterables of length two). If keyword arguments ' + 'are\n' + ' specified, the dictionary is then updated with those ' + 'key/value\n' + ' pairs: "d.update(red=1, blue=2)".\n' '\n' ' values()\n' '\n' @@ -15910,8 +16333,8 @@ '| | also removes it from ' '*s* | |\n' '+--------------------------------+----------------------------------+-----------------------+\n' - '| "s.remove(x)" | remove the first item from ' - '*s* | (3) |\n' + '| "s.remove(x)" | removes the first item from ' + '*s* | (3) |\n' '| | where "s[i]" is equal to ' '*x* | |\n' '+--------------------------------+----------------------------------+-----------------------+\n' @@ -15923,7 +16346,9 @@ '\n' 'Notes:\n' '\n' - '1. *t* must have the same length as the slice it is replacing.\n' + '1. If *k* is not equal to "1", *t* must have the same length as ' + 'the\n' + ' slice it is replacing.\n' '\n' '2. The optional argument *i* defaults to "-1", so that by ' 'default the\n' @@ -16280,7 +16705,7 @@ '\n' ' * The linspace recipe shows how to implement a lazy version of ' 'range\n' - ' suitable for floating point applications.\n', + ' suitable for floating-point applications.\n', 'typesseq-mutable': 'Mutable Sequence Types\n' '**********************\n' '\n' @@ -16373,8 +16798,8 @@ '| | also removes it from ' '*s* | |\n' '+--------------------------------+----------------------------------+-----------------------+\n' - '| "s.remove(x)" | remove the first item ' - 'from *s* | (3) |\n' + '| "s.remove(x)" | removes the first ' + 'item from *s* | (3) |\n' '| | where "s[i]" is equal ' 'to *x* | |\n' '+--------------------------------+----------------------------------+-----------------------+\n' @@ -16387,8 +16812,9 @@ '\n' 'Notes:\n' '\n' - '1. *t* must have the same length as the slice it is ' - 'replacing.\n' + '1. If *k* is not equal to "1", *t* must have the same ' + 'length as the\n' + ' slice it is replacing.\n' '\n' '2. The optional argument *i* defaults to "-1", so that ' 'by default the\n' @@ -16550,18 +16976,15 @@ ' enter = type(manager).__enter__\n' ' exit = type(manager).__exit__\n' ' value = enter(manager)\n' - ' hit_except = False\n' '\n' ' try:\n' ' TARGET = value\n' ' SUITE\n' ' except:\n' - ' hit_except = True\n' ' if not exit(manager, *sys.exc_info()):\n' ' raise\n' - ' finally:\n' - ' if not hit_except:\n' - ' exit(manager, None, None, None)\n' + ' else:\n' + ' exit(manager, None, None, None)\n' '\n' 'With more than one item, the context managers are processed as if\n' 'multiple "with" statements were nested:\n' @@ -16602,7 +17025,8 @@ '\n' 'A "yield" statement is semantically equivalent to a yield ' 'expression.\n' - 'The yield statement can be used to omit the parentheses that would\n' + 'The "yield" statement can be used to omit the parentheses that ' + 'would\n' 'otherwise be required in the equivalent yield expression ' 'statement.\n' 'For example, the yield statements\n' @@ -16618,10 +17042,9 @@ 'Yield expressions and statements are only used when defining a\n' '*generator* function, and are only used in the body of the ' 'generator\n' - 'function. Using yield in a function definition is sufficient to ' - 'cause\n' - 'that definition to create a generator function instead of a normal\n' - 'function.\n' + 'function. Using "yield" in a function definition is sufficient to\n' + 'cause that definition to create a generator function instead of a\n' + 'normal function.\n' '\n' 'For full details of "yield" semantics, refer to the Yield ' 'expressions\n' diff --git a/Lib/re/_casefix.py b/Lib/re/_casefix.py index 06507d08..fed2d84f 100644 --- a/Lib/re/_casefix.py +++ b/Lib/re/_casefix.py @@ -1,4 +1,4 @@ -# Auto-generated by Tools/scripts/generate_re_casefix.py. +# Auto-generated by Tools/build/generate_re_casefix.py. # Maps the code of lowercased character to codes of different lowercased # characters which have the same uppercase. diff --git a/Lib/re/_compiler.py b/Lib/re/_compiler.py index 285c2193..bb97f9fd 100644 --- a/Lib/re/_compiler.py +++ b/Lib/re/_compiler.py @@ -250,11 +250,11 @@ def _optimize_charset(charset, iscased=None, fixup=None, fixes=None): while True: try: if op is LITERAL: - if fixup: - lo = fixup(av) - charmap[lo] = 1 - if fixes and lo in fixes: - for k in fixes[lo]: + if fixup: # IGNORECASE and not LOCALE + av = fixup(av) + charmap[av] = 1 + if fixes and av in fixes: + for k in fixes[av]: charmap[k] = 1 if not hascased and iscased(av): hascased = True @@ -262,7 +262,7 @@ def _optimize_charset(charset, iscased=None, fixup=None, fixes=None): charmap[av] = 1 elif op is RANGE: r = range(av[0], av[1]+1) - if fixup: + if fixup: # IGNORECASE and not LOCALE if fixes: for i in map(fixup, r): charmap[i] = 1 @@ -289,8 +289,7 @@ def _optimize_charset(charset, iscased=None, fixup=None, fixes=None): # Character set contains non-BMP character codes. # For range, all BMP characters in the range are already # proceeded. - if fixup: - hascased = True + if fixup: # IGNORECASE and not LOCALE # For now, IN_UNI_IGNORE+LITERAL and # IN_UNI_IGNORE+RANGE_UNI_IGNORE work for all non-BMP # characters, because two characters (at least one of @@ -301,7 +300,13 @@ def _optimize_charset(charset, iscased=None, fixup=None, fixes=None): # Also, both c.lower() and c.lower().upper() are single # characters for every non-BMP character. if op is RANGE: - op = RANGE_UNI_IGNORE + if fixes: # not ASCII + op = RANGE_UNI_IGNORE + hascased = True + else: + assert op is LITERAL + if not hascased and iscased(av): + hascased = True tail.append((op, av)) break diff --git a/Lib/reprlib.py b/Lib/reprlib.py index a7b37630..85c1b94a 100644 --- a/Lib/reprlib.py +++ b/Lib/reprlib.py @@ -35,6 +35,17 @@ def wrapper(self): return decorating_function class Repr: + _lookup = { + 'tuple': 'builtins', + 'list': 'builtins', + 'array': 'array', + 'set': 'builtins', + 'frozenset': 'builtins', + 'deque': 'collections', + 'dict': 'builtins', + 'str': 'builtins', + 'int': 'builtins' + } def __init__( self, *, maxlevel=6, maxtuple=6, maxlist=6, maxarray=5, maxdict=4, @@ -59,14 +70,24 @@ def repr(self, x): return self.repr1(x, self.maxlevel) def repr1(self, x, level): - typename = type(x).__name__ + cls = type(x) + typename = cls.__name__ + if ' ' in typename: parts = typename.split() typename = '_'.join(parts) - if hasattr(self, 'repr_' + typename): - return getattr(self, 'repr_' + typename)(x, level) - else: - return self.repr_instance(x, level) + + method = getattr(self, 'repr_' + typename, None) + if method: + # not defined in this class + if typename not in self._lookup: + return method(x, level) + module = getattr(cls, '__module__', None) + # defined in this class and is the module intended + if module == self._lookup[typename]: + return method(x, level) + + return self.repr_instance(x, level) def _join(self, pieces, level): if self.indent is None: diff --git a/Lib/runpy.py b/Lib/runpy.py index 42f896c9..ef54d328 100644 --- a/Lib/runpy.py +++ b/Lib/runpy.py @@ -247,17 +247,17 @@ def _get_main_module_details(error=ImportError): sys.modules[main_name] = saved_main -def _get_code_from_file(run_name, fname): +def _get_code_from_file(fname): # Check for a compiled file first from pkgutil import read_code - decoded_path = os.path.abspath(os.fsdecode(fname)) - with io.open_code(decoded_path) as f: + code_path = os.path.abspath(fname) + with io.open_code(code_path) as f: code = read_code(f) if code is None: # That didn't work, so try it as normal source code - with io.open_code(decoded_path) as f: + with io.open_code(code_path) as f: code = compile(f.read(), fname, 'exec') - return code, fname + return code def run_path(path_name, init_globals=None, run_name=None): """Execute code located at the specified filesystem location. @@ -279,12 +279,13 @@ def run_path(path_name, init_globals=None, run_name=None): pkg_name = run_name.rpartition(".")[0] from pkgutil import get_importer importer = get_importer(path_name) + path_name = os.fsdecode(path_name) if isinstance(importer, type(None)): # Not a valid sys.path entry, so run the code directly # execfile() doesn't help as we want to allow compiled files - code, fname = _get_code_from_file(run_name, path_name) + code = _get_code_from_file(path_name) return _run_module_code(code, init_globals, run_name, - pkg_name=pkg_name, script_name=fname) + pkg_name=pkg_name, script_name=path_name) else: # Finder is defined for path, so add it to # the start of sys.path diff --git a/Lib/sched.py b/Lib/sched.py index 14613cf2..fb20639d 100644 --- a/Lib/sched.py +++ b/Lib/sched.py @@ -11,7 +11,7 @@ implement simulated time by writing your own functions. This can also be used to integrate scheduling with STDWIN events; the delay function is allowed to modify the queue. Time can be expressed as -integers or floating point numbers, as long as it is consistent. +integers or floating-point numbers, as long as it is consistent. Events are specified by tuples (time, priority, action, argument, kwargs). As in UNIX, lower priority numbers mean higher priority; in this diff --git a/Lib/shutil.py b/Lib/shutil.py index 20ad1cb5..2d285691 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -1534,21 +1534,21 @@ def which(cmd, mode=os.F_OK | os.X_OK, path=None): if sys.platform == "win32": # PATHEXT is necessary to check on Windows. pathext_source = os.getenv("PATHEXT") or _WIN_DEFAULT_PATHEXT - pathext = [ext for ext in pathext_source.split(os.pathsep) if ext] + pathext = pathext_source.split(os.pathsep) + pathext = [ext.rstrip('.') for ext in pathext if ext] if use_bytes: pathext = [os.fsencode(ext) for ext in pathext] - files = ([cmd] + [cmd + ext for ext in pathext]) + files = [cmd + ext for ext in pathext] - # gh-109590. If we are looking for an executable, we need to look - # for a PATHEXT match. The first cmd is the direct match - # (e.g. python.exe instead of python) - # Check that direct match first if and only if the extension is in PATHEXT - # Otherwise check it last - suffix = os.path.splitext(files[0])[1].upper() - if mode & os.X_OK and not any(suffix == ext.upper() for ext in pathext): - files.append(files.pop(0)) + # If X_OK in mode, simulate the cmd.exe behavior: look at direct + # match if and only if the extension is in PATHEXT. + # If X_OK not in mode, simulate the first result of where.exe: + # always look at direct match before a PATHEXT match. + normcmd = cmd.upper() + if not (mode & os.X_OK) or any(normcmd.endswith(ext.upper()) for ext in pathext): + files.insert(0, cmd) else: # On other platforms you don't have things like PATHEXT to tell you # what file suffixes are executable, so just pass on cmd as-is. @@ -1557,7 +1557,7 @@ def which(cmd, mode=os.F_OK | os.X_OK, path=None): seen = set() for dir in path: normdir = os.path.normcase(dir) - if not normdir in seen: + if normdir not in seen: seen.add(normdir) for thefile in files: name = os.path.join(dir, thefile) diff --git a/Lib/site.py b/Lib/site.py index 924cfbec..aed254ad 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -426,8 +426,9 @@ def setcopyright(): """Set 'copyright' and 'credits' in builtins""" builtins.copyright = _sitebuiltins._Printer("copyright", sys.copyright) builtins.credits = _sitebuiltins._Printer("credits", """\ - Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands - for supporting Python development. See www.python.org for more information.""") + Thanks to CWI, CNRI, BeOpen, Zope Corporation, the Python Software + Foundation, and a cast of thousands for supporting Python + development. See www.python.org for more information.""") files, dirs = [], [] # Not all modules are required to have a __file__ attribute. See # PEP 420 for more details. diff --git a/Lib/socket.py b/Lib/socket.py index d796082e..c1880c4e 100644 --- a/Lib/socket.py +++ b/Lib/socket.py @@ -592,16 +592,65 @@ def fromshare(info): return socket(0, 0, 0, info) __all__.append("fromshare") -if hasattr(_socket, "socketpair"): +# Origin: https://gist.github.com/4325783, by Geert Jansen. Public domain. +# This is used if _socket doesn't natively provide socketpair. It's +# always defined so that it can be patched in for testing purposes. +def _fallback_socketpair(family=AF_INET, type=SOCK_STREAM, proto=0): + if family == AF_INET: + host = _LOCALHOST + elif family == AF_INET6: + host = _LOCALHOST_V6 + else: + raise ValueError("Only AF_INET and AF_INET6 socket address families " + "are supported") + if type != SOCK_STREAM: + raise ValueError("Only SOCK_STREAM socket type is supported") + if proto != 0: + raise ValueError("Only protocol zero is supported") + + # We create a connected TCP socket. Note the trick with + # setblocking(False) that prevents us from having to create a thread. + lsock = socket(family, type, proto) + try: + lsock.bind((host, 0)) + lsock.listen() + # On IPv6, ignore flow_info and scope_id + addr, port = lsock.getsockname()[:2] + csock = socket(family, type, proto) + try: + csock.setblocking(False) + try: + csock.connect((addr, port)) + except (BlockingIOError, InterruptedError): + pass + csock.setblocking(True) + ssock, _ = lsock.accept() + except: + csock.close() + raise + finally: + lsock.close() - def socketpair(family=None, type=SOCK_STREAM, proto=0): - """socketpair([family[, type[, proto]]]) -> (socket object, socket object) + # Authenticating avoids using a connection from something else + # able to connect to {host}:{port} instead of us. + # We expect only AF_INET and AF_INET6 families. + try: + if ( + ssock.getsockname() != csock.getpeername() + or csock.getsockname() != ssock.getpeername() + ): + raise ConnectionError("Unexpected peer connection") + except: + # getsockname() and getpeername() can fail + # if either socket isn't connected. + ssock.close() + csock.close() + raise - Create a pair of socket objects from the sockets returned by the platform - socketpair() function. - The arguments are the same as for socket() except the default family is - AF_UNIX if defined on the platform; otherwise, the default is AF_INET. - """ + return (ssock, csock) + +if hasattr(_socket, "socketpair"): + def socketpair(family=None, type=SOCK_STREAM, proto=0): if family is None: try: family = AF_UNIX @@ -613,44 +662,7 @@ def socketpair(family=None, type=SOCK_STREAM, proto=0): return a, b else: - - # Origin: https://gist.github.com/4325783, by Geert Jansen. Public domain. - def socketpair(family=AF_INET, type=SOCK_STREAM, proto=0): - if family == AF_INET: - host = _LOCALHOST - elif family == AF_INET6: - host = _LOCALHOST_V6 - else: - raise ValueError("Only AF_INET and AF_INET6 socket address families " - "are supported") - if type != SOCK_STREAM: - raise ValueError("Only SOCK_STREAM socket type is supported") - if proto != 0: - raise ValueError("Only protocol zero is supported") - - # We create a connected TCP socket. Note the trick with - # setblocking(False) that prevents us from having to create a thread. - lsock = socket(family, type, proto) - try: - lsock.bind((host, 0)) - lsock.listen() - # On IPv6, ignore flow_info and scope_id - addr, port = lsock.getsockname()[:2] - csock = socket(family, type, proto) - try: - csock.setblocking(False) - try: - csock.connect((addr, port)) - except (BlockingIOError, InterruptedError): - pass - csock.setblocking(True) - ssock, _ = lsock.accept() - except: - csock.close() - raise - finally: - lsock.close() - return (ssock, csock) + socketpair = _fallback_socketpair __all__.append("socketpair") socketpair.__doc__ = """socketpair([family[, type[, proto]]]) -> (socket object, socket object) diff --git a/Lib/ssl.py b/Lib/ssl.py index 983c2db6..42ebb8ed 100644 --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -513,18 +513,17 @@ def set_alpn_protocols(self, alpn_protocols): self._set_alpn_protocols(protos) def _load_windows_store_certs(self, storename, purpose): - certs = bytearray() try: for cert, encoding, trust in enum_certificates(storename): # CA certs are never PKCS#7 encoded if encoding == "x509_asn": if trust is True or purpose.oid in trust: - certs.extend(cert) + try: + self.load_verify_locations(cadata=cert) + except SSLError as exc: + warnings.warn(f"Bad certificate in Windows certificate store: {exc!s}") except PermissionError: warnings.warn("unable to enumerate Windows certificate store") - if certs: - self.load_verify_locations(cadata=certs) - return certs def load_default_certs(self, purpose=Purpose.SERVER_AUTH): if not isinstance(purpose, _ASN1Object): diff --git a/Lib/statistics.py b/Lib/statistics.py index 6bd214bb..db108b3e 100644 --- a/Lib/statistics.py +++ b/Lib/statistics.py @@ -11,7 +11,7 @@ Function Description ================== ================================================== mean Arithmetic mean (average) of data. -fmean Fast, floating point arithmetic mean. +fmean Fast, floating-point arithmetic mean. geometric_mean Geometric mean of data. harmonic_mean Harmonic mean of data. median Median (middle value) of data. diff --git a/Lib/symtable.py b/Lib/symtable.py index 4b0bc6f4..f95639be 100644 --- a/Lib/symtable.py +++ b/Lib/symtable.py @@ -217,8 +217,37 @@ def get_methods(self): """ if self.__methods is None: d = {} + + def is_local_symbol(ident): + flags = self._table.symbols.get(ident, 0) + return ((flags >> SCOPE_OFF) & SCOPE_MASK) == LOCAL + for st in self._table.children: - d[st.name] = 1 + # pick the function-like symbols that are local identifiers + if is_local_symbol(st.name): + match st.type: + case _symtable.TYPE_FUNCTION: + # generators are of type TYPE_FUNCTION with a ".0" + # parameter as a first parameter (which makes them + # distinguishable from a function named 'genexpr') + if st.name == 'genexpr' and '.0' in st.varnames: + continue + d[st.name] = 1 + case _symtable.TYPE_TYPE_PARAM: + # Get the function-def block in the annotation + # scope 'st' with the same identifier, if any. + scope_name = st.name + for c in st.children: + if c.name == scope_name and c.type == _symtable.TYPE_FUNCTION: + # A generic generator of type TYPE_FUNCTION + # cannot be a direct child of 'st' (but it + # can be a descendant), e.g.: + # + # class A: + # type genexpr[genexpr] = (x for x in []) + assert scope_name != 'genexpr' or '.0' not in c.varnames + d[scope_name] = 1 + break self.__methods = tuple(d) return self.__methods diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py index 122d441b..517b13ac 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -169,9 +169,7 @@ def joinuser(*args): _PY_VERSION = sys.version.split()[0] _PY_VERSION_SHORT = f'{sys.version_info[0]}.{sys.version_info[1]}' _PY_VERSION_SHORT_NO_DOT = f'{sys.version_info[0]}{sys.version_info[1]}' -_PREFIX = os.path.normpath(sys.prefix) _BASE_PREFIX = os.path.normpath(sys.base_prefix) -_EXEC_PREFIX = os.path.normpath(sys.exec_prefix) _BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix) # Mutex guarding initialization of _CONFIG_VARS. _CONFIG_VARS_LOCK = threading.RLock() @@ -642,8 +640,10 @@ def _init_config_vars(): # Normalized versions of prefix and exec_prefix are handy to have; # in fact, these are the standard versions used most places in the # Distutils. - _CONFIG_VARS['prefix'] = _PREFIX - _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX + _PREFIX = os.path.normpath(sys.prefix) + _EXEC_PREFIX = os.path.normpath(sys.exec_prefix) + _CONFIG_VARS['prefix'] = _PREFIX # FIXME: This gets overwriten by _init_posix. + _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX # FIXME: This gets overwriten by _init_posix. _CONFIG_VARS['py_version'] = _PY_VERSION _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT _CONFIG_VARS['py_version_nodot'] = _PY_VERSION_SHORT_NO_DOT @@ -711,6 +711,7 @@ def get_config_vars(*args): With arguments, return a list of values that result from looking up each argument in the configuration variable dictionary. """ + global _CONFIG_VARS_INITIALIZED # Avoid claiming the lock once initialization is complete. if not _CONFIG_VARS_INITIALIZED: @@ -721,6 +722,15 @@ def get_config_vars(*args): # don't re-enter init_config_vars(). if _CONFIG_VARS is None: _init_config_vars() + else: + # If the site module initialization happened after _CONFIG_VARS was + # initialized, a virtual environment might have been activated, resulting in + # variables like sys.prefix changing their value, so we need to re-init the + # config vars (see GH-126789). + if _CONFIG_VARS['base'] != os.path.normpath(sys.prefix): + with _CONFIG_VARS_LOCK: + _CONFIG_VARS_INITIALIZED = False + _init_config_vars() if args: vals = [] diff --git a/Lib/tabnanny.py b/Lib/tabnanny.py index e2ac6837..d06c4c22 100755 --- a/Lib/tabnanny.py +++ b/Lib/tabnanny.py @@ -107,14 +107,14 @@ def check(file): errprint("%r: Token Error: %s" % (file, msg)) return - except SyntaxError as msg: - errprint("%r: Token Error: %s" % (file, msg)) - return - except IndentationError as msg: errprint("%r: Indentation Error: %s" % (file, msg)) return + except SyntaxError as msg: + errprint("%r: Syntax Error: %s" % (file, msg)) + return + except NannyNag as nag: badline = nag.get_lineno() line = nag.get_line() diff --git a/Lib/tarfile.py b/Lib/tarfile.py index e1487e38..0a0f31ec 100755 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -843,6 +843,9 @@ def data_filter(member, dest_path): # Sentinel for replace() defaults, meaning "don't change the attribute" _KEEP = object() +# Header length is digits followed by a space. +_header_length_prefix_re = re.compile(br"([0-9]{1,20}) ") + class TarInfo(object): """Informational class which holds the details about an archive member given by a tar header block. @@ -1412,37 +1415,59 @@ def _proc_pax(self, tarfile): else: pax_headers = tarfile.pax_headers.copy() - # Check if the pax header contains a hdrcharset field. This tells us - # the encoding of the path, linkpath, uname and gname fields. Normally, - # these fields are UTF-8 encoded but since POSIX.1-2008 tar - # implementations are allowed to store them as raw binary strings if - # the translation to UTF-8 fails. - match = re.search(br"\d+ hdrcharset=([^\n]+)\n", buf) - if match is not None: - pax_headers["hdrcharset"] = match.group(1).decode("utf-8") - - # For the time being, we don't care about anything other than "BINARY". - # The only other value that is currently allowed by the standard is - # "ISO-IR 10646 2000 UTF-8" in other words UTF-8. - hdrcharset = pax_headers.get("hdrcharset") - if hdrcharset == "BINARY": - encoding = tarfile.encoding - else: - encoding = "utf-8" - # Parse pax header information. A record looks like that: # "%d %s=%s\n" % (length, keyword, value). length is the size # of the complete record including the length field itself and - # the newline. keyword and value are both UTF-8 encoded strings. - regex = re.compile(br"(\d+) ([^=]+)=") + # the newline. pos = 0 - while match := regex.match(buf, pos): - length, keyword = match.groups() - length = int(length) - if length == 0: + encoding = None + raw_headers = [] + while len(buf) > pos and buf[pos] != 0x00: + if not (match := _header_length_prefix_re.match(buf, pos)): + raise InvalidHeaderError("invalid header") + try: + length = int(match.group(1)) + except ValueError: + raise InvalidHeaderError("invalid header") + # Headers must be at least 5 bytes, shortest being '5 x=\n'. + # Value is allowed to be empty. + if length < 5: + raise InvalidHeaderError("invalid header") + if pos + length > len(buf): + raise InvalidHeaderError("invalid header") + + header_value_end_offset = match.start(1) + length - 1 # Last byte of the header + keyword_and_value = buf[match.end(1) + 1:header_value_end_offset] + raw_keyword, equals, raw_value = keyword_and_value.partition(b"=") + + # Check the framing of the header. The last character must be '\n' (0x0A) + if not raw_keyword or equals != b"=" or buf[header_value_end_offset] != 0x0A: raise InvalidHeaderError("invalid header") - value = buf[match.end(2) + 1:match.start(1) + length - 1] + raw_headers.append((length, raw_keyword, raw_value)) + + # Check if the pax header contains a hdrcharset field. This tells us + # the encoding of the path, linkpath, uname and gname fields. Normally, + # these fields are UTF-8 encoded but since POSIX.1-2008 tar + # implementations are allowed to store them as raw binary strings if + # the translation to UTF-8 fails. For the time being, we don't care about + # anything other than "BINARY". The only other value that is currently + # allowed by the standard is "ISO-IR 10646 2000 UTF-8" in other words UTF-8. + # Note that we only follow the initial 'hdrcharset' setting to preserve + # the initial behavior of the 'tarfile' module. + if raw_keyword == b"hdrcharset" and encoding is None: + if raw_value == b"BINARY": + encoding = tarfile.encoding + else: # This branch ensures only the first 'hdrcharset' header is used. + encoding = "utf-8" + pos += length + + # If no explicit hdrcharset is set, we use UTF-8 as a default. + if encoding is None: + encoding = "utf-8" + + # After parsing the raw headers we can decode them to text. + for length, raw_keyword, raw_value in raw_headers: # Normally, we could just use "utf-8" as the encoding and "strict" # as the error handler, but we better not take the risk. For # example, GNU tar <= 1.23 is known to store filenames it cannot @@ -1450,17 +1475,16 @@ def _proc_pax(self, tarfile): # hdrcharset=BINARY header). # We first try the strict standard encoding, and if that fails we # fall back on the user's encoding and error handler. - keyword = self._decode_pax_field(keyword, "utf-8", "utf-8", + keyword = self._decode_pax_field(raw_keyword, "utf-8", "utf-8", tarfile.errors) if keyword in PAX_NAME_FIELDS: - value = self._decode_pax_field(value, encoding, tarfile.encoding, + value = self._decode_pax_field(raw_value, encoding, tarfile.encoding, tarfile.errors) else: - value = self._decode_pax_field(value, "utf-8", "utf-8", + value = self._decode_pax_field(raw_value, "utf-8", "utf-8", tarfile.errors) pax_headers[keyword] = value - pos += length # Fetch the next header. try: @@ -1475,7 +1499,7 @@ def _proc_pax(self, tarfile): elif "GNU.sparse.size" in pax_headers: # GNU extended sparse format version 0.0. - self._proc_gnusparse_00(next, pax_headers, buf) + self._proc_gnusparse_00(next, raw_headers) elif pax_headers.get("GNU.sparse.major") == "1" and pax_headers.get("GNU.sparse.minor") == "0": # GNU extended sparse format version 1.0. @@ -1497,15 +1521,24 @@ def _proc_pax(self, tarfile): return next - def _proc_gnusparse_00(self, next, pax_headers, buf): + def _proc_gnusparse_00(self, next, raw_headers): """Process a GNU tar extended sparse header, version 0.0. """ offsets = [] - for match in re.finditer(br"\d+ GNU.sparse.offset=(\d+)\n", buf): - offsets.append(int(match.group(1))) numbytes = [] - for match in re.finditer(br"\d+ GNU.sparse.numbytes=(\d+)\n", buf): - numbytes.append(int(match.group(1))) + for _, keyword, value in raw_headers: + if keyword == b"GNU.sparse.offset": + try: + offsets.append(int(value.decode())) + except ValueError: + raise InvalidHeaderError("invalid header") + + elif keyword == b"GNU.sparse.numbytes": + try: + numbytes.append(int(value.decode())) + except ValueError: + raise InvalidHeaderError("invalid header") + next.sparse = list(zip(offsets, numbytes)) def _proc_gnusparse_01(self, next, pax_headers): diff --git a/Lib/test/_test_eintr.py b/Lib/test/_test_eintr.py index 15586f15..493932d6 100644 --- a/Lib/test/_test_eintr.py +++ b/Lib/test/_test_eintr.py @@ -18,6 +18,7 @@ import socket import subprocess import sys +import textwrap import time import unittest @@ -492,29 +493,31 @@ def test_devpoll(self): self.check_elapsed_time(dt) -class FNTLEINTRTest(EINTRBaseTest): +class FCNTLEINTRTest(EINTRBaseTest): def _lock(self, lock_func, lock_name): self.addCleanup(os_helper.unlink, os_helper.TESTFN) - code = '\n'.join(( - "import fcntl, time", - "with open('%s', 'wb') as f:" % os_helper.TESTFN, - " fcntl.%s(f, fcntl.LOCK_EX)" % lock_name, - " time.sleep(%s)" % self.sleep_time)) - start_time = time.monotonic() - proc = self.subprocess(code) + rd1, wr1 = os.pipe() + rd2, wr2 = os.pipe() + for fd in (rd1, wr1, rd2, wr2): + self.addCleanup(os.close, fd) + code = textwrap.dedent(f""" + import fcntl, os, time + with open('{os_helper.TESTFN}', 'wb') as f: + fcntl.{lock_name}(f, fcntl.LOCK_EX) + os.write({wr1}, b"ok") + _ = os.read({rd2}, 2) # wait for parent process + time.sleep({self.sleep_time}) + """) + proc = self.subprocess(code, pass_fds=[wr1, rd2]) with kill_on_error(proc): with open(os_helper.TESTFN, 'wb') as f: # synchronize the subprocess + ok = os.read(rd1, 2) + self.assertEqual(ok, b"ok") + + # notify the child that the parent is ready start_time = time.monotonic() - for _ in support.sleeping_retry(support.LONG_TIMEOUT, error=False): - try: - lock_func(f, fcntl.LOCK_EX | fcntl.LOCK_NB) - lock_func(f, fcntl.LOCK_UN) - except BlockingIOError: - break - else: - dt = time.monotonic() - start_time - raise Exception("failed to sync child in %.1f sec" % dt) + os.write(wr2, b"go") # the child locked the file just a moment ago for 'sleep_time' seconds # that means that the lock below will block for 'sleep_time' minus some diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 39551234..3b4415b5 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -12,6 +12,7 @@ import sys import os import gc +import importlib import errno import functools import signal @@ -19,8 +20,10 @@ import socket import random import logging +import shutil import subprocess import struct +import tempfile import operator import pickle import weakref @@ -254,6 +257,9 @@ def __call__(self, *args, **kwds): class BaseTestCase(object): ALLOWED_TYPES = ('processes', 'manager', 'threads') + # If not empty, limit which start method suites run this class. + START_METHODS: set[str] = set() + start_method = None # set by install_tests_in_module_dict() def assertTimingAlmostEqual(self, a, b): if CHECK_TIMINGS: @@ -1332,6 +1338,23 @@ def _on_queue_feeder_error(e, obj): self.assertTrue(not_serializable_obj.reduce_was_called) self.assertTrue(not_serializable_obj.on_queue_feeder_error_was_called) + def test_closed_queue_empty_exceptions(self): + # Assert that checking the emptiness of an unused closed queue + # does not raise an OSError. The rationale is that q.close() is + # a no-op upon construction and becomes effective once the queue + # has been used (e.g., by calling q.put()). + for q in multiprocessing.Queue(), multiprocessing.JoinableQueue(): + q.close() # this is a no-op since the feeder thread is None + q.join_thread() # this is also a no-op + self.assertTrue(q.empty()) + + for q in multiprocessing.Queue(), multiprocessing.JoinableQueue(): + q.put('foo') # make sure that the queue is 'used' + q.close() # close the feeder thread + q.join_thread() # make sure to join the feeder thread + with self.assertRaisesRegex(OSError, 'is closed'): + q.empty() + def test_closed_queue_put_get_exceptions(self): for q in multiprocessing.Queue(), multiprocessing.JoinableQueue(): q.close() @@ -1345,6 +1368,66 @@ def test_closed_queue_put_get_exceptions(self): class _TestLock(BaseTestCase): + @staticmethod + def _acquire(lock, l=None): + lock.acquire() + if l is not None: + l.append(repr(lock)) + + @staticmethod + def _acquire_event(lock, event): + lock.acquire() + event.set() + time.sleep(1.0) + + def test_repr_lock(self): + if self.TYPE != 'processes': + self.skipTest('test not appropriate for {}'.format(self.TYPE)) + + lock = self.Lock() + self.assertEqual(f'', repr(lock)) + + lock.acquire() + self.assertEqual(f'', repr(lock)) + lock.release() + + tname = 'T1' + l = [] + t = threading.Thread(target=self._acquire, + args=(lock, l), + name=tname) + t.start() + time.sleep(0.1) + self.assertEqual(f'', l[0]) + lock.release() + + t = threading.Thread(target=self._acquire, + args=(lock,), + name=tname) + t.start() + time.sleep(0.1) + self.assertEqual('', repr(lock)) + lock.release() + + pname = 'P1' + l = multiprocessing.Manager().list() + p = self.Process(target=self._acquire, + args=(lock, l), + name=pname) + p.start() + p.join() + self.assertEqual(f'', l[0]) + + lock = self.Lock() + event = self.Event() + p = self.Process(target=self._acquire_event, + args=(lock, event), + name='P2') + p.start() + event.wait() + self.assertEqual(f'', repr(lock)) + p.terminate() + def test_lock(self): lock = self.Lock() self.assertEqual(lock.acquire(), True) @@ -1352,6 +1435,68 @@ def test_lock(self): self.assertEqual(lock.release(), None) self.assertRaises((ValueError, threading.ThreadError), lock.release) + @staticmethod + def _acquire_release(lock, timeout, l=None, n=1): + for _ in range(n): + lock.acquire() + if l is not None: + l.append(repr(lock)) + time.sleep(timeout) + for _ in range(n): + lock.release() + + def test_repr_rlock(self): + if self.TYPE != 'processes': + self.skipTest('test not appropriate for {}'.format(self.TYPE)) + + lock = self.RLock() + self.assertEqual('', repr(lock)) + + n = 3 + for _ in range(n): + lock.acquire() + self.assertEqual(f'', repr(lock)) + for _ in range(n): + lock.release() + + t, l = [], [] + for i in range(n): + t.append(threading.Thread(target=self._acquire_release, + args=(lock, 0.1, l, i+1), + name=f'T{i+1}')) + t[-1].start() + for t_ in t: + t_.join() + for i in range(n): + self.assertIn(f'', l) + + + t = threading.Thread(target=self._acquire_release, + args=(lock, 0.2), + name=f'T1') + t.start() + time.sleep(0.1) + self.assertEqual('', repr(lock)) + time.sleep(0.2) + + pname = 'P1' + l = multiprocessing.Manager().list() + p = self.Process(target=self._acquire_release, + args=(lock, 0.1, l), + name=pname) + p.start() + p.join() + self.assertEqual(f'', l[0]) + + event = self.Event() + lock = self.RLock() + p = self.Process(target=self._acquire_event, + args=(lock, event)) + p.start() + event.wait() + self.assertEqual('', repr(lock)) + p.join() + def test_rlock(self): lock = self.RLock() self.assertEqual(lock.acquire(), True) @@ -5638,6 +5783,8 @@ def test_resource_tracker_sigterm(self): # Catchable signal (ignored by semaphore tracker) self.check_resource_tracker_death(signal.SIGTERM, False) + @unittest.skipIf(sys.platform.startswith("netbsd"), + "gh-125620: Skip on NetBSD due to long wait for SIGKILL process termination.") def test_resource_tracker_sigkill(self): # Uncatchable signal. self.check_resource_tracker_death(signal.SIGKILL, True) @@ -5691,6 +5838,15 @@ def _test_empty(cls, queue, child_can_start, parent_can_continue): finally: parent_can_continue.set() + def test_empty_exceptions(self): + # Assert that checking emptiness of a closed queue raises + # an OSError, independently of whether the queue was used + # or not. This differs from Queue and JoinableQueue. + q = multiprocessing.SimpleQueue() + q.close() # close the pipe + with self.assertRaisesRegex(OSError, 'is closed'): + q.empty() + def test_empty(self): queue = multiprocessing.SimpleQueue() child_can_start = multiprocessing.Event() @@ -6037,6 +6193,76 @@ def submain(): pass self.assertFalse(err, msg=err.decode('utf-8')) +class _TestSpawnedSysPath(BaseTestCase): + """Test that sys.path is setup in forkserver and spawn processes.""" + + ALLOWED_TYPES = {'processes'} + # Not applicable to fork which inherits everything from the process as is. + START_METHODS = {"forkserver", "spawn"} + + def setUp(self): + self._orig_sys_path = list(sys.path) + self._temp_dir = tempfile.mkdtemp(prefix="test_sys_path-") + self._mod_name = "unique_test_mod" + module_path = os.path.join(self._temp_dir, f"{self._mod_name}.py") + with open(module_path, "w", encoding="utf-8") as mod: + mod.write("# A simple test module\n") + sys.path[:] = [p for p in sys.path if p] # remove any existing ""s + sys.path.insert(0, self._temp_dir) + sys.path.insert(0, "") # Replaced with an abspath in child. + self.assertIn(self.start_method, self.START_METHODS) + self._ctx = multiprocessing.get_context(self.start_method) + + def tearDown(self): + sys.path[:] = self._orig_sys_path + shutil.rmtree(self._temp_dir, ignore_errors=True) + + @staticmethod + def enq_imported_module_names(queue): + queue.put(tuple(sys.modules)) + + def test_forkserver_preload_imports_sys_path(self): + if self._ctx.get_start_method() != "forkserver": + self.skipTest("forkserver specific test.") + self.assertNotIn(self._mod_name, sys.modules) + multiprocessing.forkserver._forkserver._stop() # Must be fresh. + self._ctx.set_forkserver_preload( + ["test.test_multiprocessing_forkserver", self._mod_name]) + q = self._ctx.Queue() + proc = self._ctx.Process( + target=self.enq_imported_module_names, args=(q,)) + proc.start() + proc.join() + child_imported_modules = q.get() + q.close() + self.assertIn(self._mod_name, child_imported_modules) + + @staticmethod + def enq_sys_path_and_import(queue, mod_name): + queue.put(sys.path) + try: + importlib.import_module(mod_name) + except ImportError as exc: + queue.put(exc) + else: + queue.put(None) + + def test_child_sys_path(self): + q = self._ctx.Queue() + proc = self._ctx.Process( + target=self.enq_sys_path_and_import, args=(q, self._mod_name)) + proc.start() + proc.join() + child_sys_path = q.get() + import_error = q.get() + q.close() + self.assertNotIn("", child_sys_path) # replaced by an abspath + self.assertIn(self._temp_dir, child_sys_path) # our addition + # ignore the first element, it is the absolute "" replacement + self.assertEqual(child_sys_path[1:], sys.path[1:]) + self.assertIsNone(import_error, msg=f"child could not import {self._mod_name}") + + class MiscTestCase(unittest.TestCase): def test__all__(self): # Just make sure names in not_exported are excluded @@ -6213,6 +6439,8 @@ def install_tests_in_module_dict(remote_globs, start_method, if base is BaseTestCase: continue assert set(base.ALLOWED_TYPES) <= ALL_TYPES, base.ALLOWED_TYPES + if base.START_METHODS and start_method not in base.START_METHODS: + continue # class not intended for this start method. for type_ in base.ALLOWED_TYPES: if only_type and type_ != only_type: continue @@ -6226,6 +6454,7 @@ class Temp(base, Mixin, unittest.TestCase): Temp = hashlib_helper.requires_hashdigest('sha256')(Temp) Temp.__name__ = Temp.__qualname__ = newname Temp.__module__ = __module__ + Temp.start_method = start_method remote_globs[newname] = Temp elif issubclass(base, unittest.TestCase): if only_type: diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c index b1471f75..6703cf19 100644 --- a/Lib/test/clinic.test.c +++ b/Lib/test/clinic.test.c @@ -1984,7 +1984,7 @@ test_keywords(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObjec PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(a), &_Py_ID(b), }, + .ob_item = { _Py_LATIN1_CHR('a'), _Py_LATIN1_CHR('b'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2018,7 +2018,7 @@ test_keywords(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObjec static PyObject * test_keywords_impl(PyObject *module, PyObject *a, PyObject *b) -/*[clinic end generated code: output=73d46a9ae3320f96 input=0d3484844749c05b]*/ +/*[clinic end generated code: output=13ba007e1c842a37 input=0d3484844749c05b]*/ /*[clinic input] @@ -2054,7 +2054,7 @@ test_keywords_kwonly(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(a), &_Py_ID(b), }, + .ob_item = { _Py_LATIN1_CHR('a'), _Py_LATIN1_CHR('b'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2088,7 +2088,7 @@ test_keywords_kwonly(PyObject *module, PyObject *const *args, Py_ssize_t nargs, static PyObject * test_keywords_kwonly_impl(PyObject *module, PyObject *a, PyObject *b) -/*[clinic end generated code: output=c9f02a41f425897d input=384adc78bfa0bff7]*/ +/*[clinic end generated code: output=789799a6d2d6eb4d input=384adc78bfa0bff7]*/ /*[clinic input] @@ -2125,7 +2125,7 @@ test_keywords_opt(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyO PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(a), &_Py_ID(b), &_Py_ID(c), }, + .ob_item = { _Py_LATIN1_CHR('a'), _Py_LATIN1_CHR('b'), _Py_LATIN1_CHR('c'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2172,7 +2172,7 @@ test_keywords_opt(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyO static PyObject * test_keywords_opt_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c) -/*[clinic end generated code: output=b35d4e66f7283e46 input=eda7964f784f4607]*/ +/*[clinic end generated code: output=42430dd8ea5afde6 input=eda7964f784f4607]*/ /*[clinic input] @@ -2211,7 +2211,7 @@ test_keywords_opt_kwonly(PyObject *module, PyObject *const *args, Py_ssize_t nar PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(a), &_Py_ID(b), &_Py_ID(c), &_Py_ID(d), }, + .ob_item = { _Py_LATIN1_CHR('a'), _Py_LATIN1_CHR('b'), _Py_LATIN1_CHR('c'), _Py_LATIN1_CHR('d'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2269,7 +2269,7 @@ test_keywords_opt_kwonly(PyObject *module, PyObject *const *args, Py_ssize_t nar static PyObject * test_keywords_opt_kwonly_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c, PyObject *d) -/*[clinic end generated code: output=ede7e6e65106bf2b input=209387a4815e5082]*/ +/*[clinic end generated code: output=f312c35c380d2bf9 input=209387a4815e5082]*/ /*[clinic input] @@ -2307,7 +2307,7 @@ test_keywords_kwonly_opt(PyObject *module, PyObject *const *args, Py_ssize_t nar PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(a), &_Py_ID(b), &_Py_ID(c), }, + .ob_item = { _Py_LATIN1_CHR('a'), _Py_LATIN1_CHR('b'), _Py_LATIN1_CHR('c'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2354,7 +2354,7 @@ test_keywords_kwonly_opt(PyObject *module, PyObject *const *args, Py_ssize_t nar static PyObject * test_keywords_kwonly_opt_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c) -/*[clinic end generated code: output=36d4df939a4c3eef input=18393cc64fa000f4]*/ +/*[clinic end generated code: output=3937da2a8233ebe0 input=18393cc64fa000f4]*/ /*[clinic input] @@ -2390,7 +2390,7 @@ test_posonly_keywords(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(b), }, + .ob_item = { _Py_LATIN1_CHR('b'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2424,7 +2424,7 @@ test_posonly_keywords(PyObject *module, PyObject *const *args, Py_ssize_t nargs, static PyObject * test_posonly_keywords_impl(PyObject *module, PyObject *a, PyObject *b) -/*[clinic end generated code: output=4835f4b6cf386c28 input=1767b0ebdf06060e]*/ +/*[clinic end generated code: output=6b4f6dd5f4db3877 input=1767b0ebdf06060e]*/ /*[clinic input] @@ -2461,7 +2461,7 @@ test_posonly_kwonly(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(c), }, + .ob_item = { _Py_LATIN1_CHR('c'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2495,7 +2495,7 @@ test_posonly_kwonly(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P static PyObject * test_posonly_kwonly_impl(PyObject *module, PyObject *a, PyObject *c) -/*[clinic end generated code: output=2570ea156a8d3cb5 input=9042f2818f664839]*/ +/*[clinic end generated code: output=8bef2a8198e70b26 input=9042f2818f664839]*/ /*[clinic input] @@ -2534,7 +2534,7 @@ test_posonly_keywords_kwonly(PyObject *module, PyObject *const *args, Py_ssize_t PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(b), &_Py_ID(c), }, + .ob_item = { _Py_LATIN1_CHR('b'), _Py_LATIN1_CHR('c'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2571,7 +2571,7 @@ test_posonly_keywords_kwonly(PyObject *module, PyObject *const *args, Py_ssize_t static PyObject * test_posonly_keywords_kwonly_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c) -/*[clinic end generated code: output=aaa0e6b5ce02900d input=29546ebdca492fea]*/ +/*[clinic end generated code: output=a44b8ae8300955e1 input=29546ebdca492fea]*/ /*[clinic input] @@ -2610,7 +2610,7 @@ test_posonly_keywords_opt(PyObject *module, PyObject *const *args, Py_ssize_t na PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(b), &_Py_ID(c), &_Py_ID(d), }, + .ob_item = { _Py_LATIN1_CHR('b'), _Py_LATIN1_CHR('c'), _Py_LATIN1_CHR('d'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2659,7 +2659,7 @@ test_posonly_keywords_opt(PyObject *module, PyObject *const *args, Py_ssize_t na static PyObject * test_posonly_keywords_opt_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c, PyObject *d) -/*[clinic end generated code: output=1d9f2d8420d0a85f input=cdf5a9625e554e9b]*/ +/*[clinic end generated code: output=cae6647c9e8e0238 input=cdf5a9625e554e9b]*/ /*[clinic input] @@ -2697,7 +2697,7 @@ test_posonly_keywords_opt2(PyObject *module, PyObject *const *args, Py_ssize_t n PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(b), &_Py_ID(c), }, + .ob_item = { _Py_LATIN1_CHR('b'), _Py_LATIN1_CHR('c'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2744,7 +2744,7 @@ test_posonly_keywords_opt2(PyObject *module, PyObject *const *args, Py_ssize_t n static PyObject * test_posonly_keywords_opt2_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c) -/*[clinic end generated code: output=a83caa0505b296cf input=1581299d21d16f14]*/ +/*[clinic end generated code: output=6526fd08aafa2149 input=1581299d21d16f14]*/ /*[clinic input] @@ -2783,7 +2783,7 @@ test_posonly_opt_keywords_opt(PyObject *module, PyObject *const *args, Py_ssize_ PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(c), &_Py_ID(d), }, + .ob_item = { _Py_LATIN1_CHR('c'), _Py_LATIN1_CHR('d'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2837,7 +2837,7 @@ test_posonly_opt_keywords_opt(PyObject *module, PyObject *const *args, Py_ssize_ static PyObject * test_posonly_opt_keywords_opt_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c, PyObject *d) -/*[clinic end generated code: output=0b24fba3dc04d26b input=408798ec3d42949f]*/ +/*[clinic end generated code: output=b8d01e98443738c2 input=408798ec3d42949f]*/ /*[clinic input] @@ -2877,7 +2877,7 @@ test_posonly_kwonly_opt(PyObject *module, PyObject *const *args, Py_ssize_t narg PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(b), &_Py_ID(c), &_Py_ID(d), }, + .ob_item = { _Py_LATIN1_CHR('b'), _Py_LATIN1_CHR('c'), _Py_LATIN1_CHR('d'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2926,7 +2926,7 @@ test_posonly_kwonly_opt(PyObject *module, PyObject *const *args, Py_ssize_t narg static PyObject * test_posonly_kwonly_opt_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c, PyObject *d) -/*[clinic end generated code: output=592b217bca2f7bcc input=8d8e5643bbbc2309]*/ +/*[clinic end generated code: output=81d71c288f13d4dc input=8d8e5643bbbc2309]*/ /*[clinic input] @@ -2965,7 +2965,7 @@ test_posonly_kwonly_opt2(PyObject *module, PyObject *const *args, Py_ssize_t nar PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(b), &_Py_ID(c), }, + .ob_item = { _Py_LATIN1_CHR('b'), _Py_LATIN1_CHR('c'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -3012,7 +3012,7 @@ test_posonly_kwonly_opt2(PyObject *module, PyObject *const *args, Py_ssize_t nar static PyObject * test_posonly_kwonly_opt2_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c) -/*[clinic end generated code: output=b8b00420826bc11f input=f7e5eed94f75fff0]*/ +/*[clinic end generated code: output=a717d2a1a3310289 input=f7e5eed94f75fff0]*/ /*[clinic input] @@ -3052,7 +3052,7 @@ test_posonly_opt_kwonly_opt(PyObject *module, PyObject *const *args, Py_ssize_t PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(c), &_Py_ID(d), }, + .ob_item = { _Py_LATIN1_CHR('c'), _Py_LATIN1_CHR('d'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -3106,7 +3106,7 @@ test_posonly_opt_kwonly_opt(PyObject *module, PyObject *const *args, Py_ssize_t static PyObject * test_posonly_opt_kwonly_opt_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c, PyObject *d) -/*[clinic end generated code: output=3b9ee879ebee285a input=1e557dc979d120fd]*/ +/*[clinic end generated code: output=0f50b4b8d45cf2de input=1e557dc979d120fd]*/ /*[clinic input] @@ -3148,7 +3148,7 @@ test_posonly_keywords_kwonly_opt(PyObject *module, PyObject *const *args, Py_ssi PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(b), &_Py_ID(c), &_Py_ID(d), &_Py_ID(e), }, + .ob_item = { _Py_LATIN1_CHR('b'), _Py_LATIN1_CHR('c'), _Py_LATIN1_CHR('d'), _Py_LATIN1_CHR('e'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -3200,7 +3200,7 @@ static PyObject * test_posonly_keywords_kwonly_opt_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c, PyObject *d, PyObject *e) -/*[clinic end generated code: output=d380f84f81cc0e45 input=c3884a4f956fdc89]*/ +/*[clinic end generated code: output=8dac8d2a4e6105fa input=c3884a4f956fdc89]*/ /*[clinic input] @@ -3240,7 +3240,7 @@ test_posonly_keywords_kwonly_opt2(PyObject *module, PyObject *const *args, Py_ss PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(b), &_Py_ID(c), &_Py_ID(d), }, + .ob_item = { _Py_LATIN1_CHR('b'), _Py_LATIN1_CHR('c'), _Py_LATIN1_CHR('d'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -3289,7 +3289,7 @@ test_posonly_keywords_kwonly_opt2(PyObject *module, PyObject *const *args, Py_ss static PyObject * test_posonly_keywords_kwonly_opt2_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c, PyObject *d) -/*[clinic end generated code: output=ee629e962cb06992 input=68d01d7c0f6dafb0]*/ +/*[clinic end generated code: output=5a96d521e6414f5d input=68d01d7c0f6dafb0]*/ /*[clinic input] @@ -3332,7 +3332,7 @@ test_posonly_keywords_opt_kwonly_opt(PyObject *module, PyObject *const *args, Py PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(b), &_Py_ID(c), &_Py_ID(d), &_Py_ID(e), }, + .ob_item = { _Py_LATIN1_CHR('b'), _Py_LATIN1_CHR('c'), _Py_LATIN1_CHR('d'), _Py_LATIN1_CHR('e'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -3393,7 +3393,7 @@ static PyObject * test_posonly_keywords_opt_kwonly_opt_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c, PyObject *d, PyObject *e) -/*[clinic end generated code: output=a2721babb42ecfd1 input=d0883d45876f186c]*/ +/*[clinic end generated code: output=d5a474dcd5dc3e9f input=d0883d45876f186c]*/ /*[clinic input] @@ -3436,7 +3436,7 @@ test_posonly_keywords_opt2_kwonly_opt(PyObject *module, PyObject *const *args, P PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(b), &_Py_ID(c), &_Py_ID(d), &_Py_ID(e), }, + .ob_item = { _Py_LATIN1_CHR('b'), _Py_LATIN1_CHR('c'), _Py_LATIN1_CHR('d'), _Py_LATIN1_CHR('e'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -3502,7 +3502,7 @@ static PyObject * test_posonly_keywords_opt2_kwonly_opt_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c, PyObject *d, PyObject *e) -/*[clinic end generated code: output=0626203eedb6e7e8 input=c95e2e1ec93035ad]*/ +/*[clinic end generated code: output=ac239c5ee8a74408 input=c95e2e1ec93035ad]*/ /*[clinic input] @@ -3547,7 +3547,7 @@ test_posonly_opt_keywords_opt_kwonly_opt(PyObject *module, PyObject *const *args PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(c), &_Py_ID(d), &_Py_ID(e), &_Py_ID(f), }, + .ob_item = { _Py_LATIN1_CHR('c'), _Py_LATIN1_CHR('d'), _Py_LATIN1_CHR('e'), _Py_LATIN1_CHR('f'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -3621,7 +3621,7 @@ test_posonly_opt_keywords_opt_kwonly_opt_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c, PyObject *d, PyObject *e, PyObject *f) -/*[clinic end generated code: output=07d8acc04558a5a0 input=9914857713c5bbf8]*/ +/*[clinic end generated code: output=638bbd0005639342 input=9914857713c5bbf8]*/ /*[clinic input] test_keyword_only_parameter @@ -4017,7 +4017,7 @@ test_vararg(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(a), }, + .ob_item = { _Py_LATIN1_CHR('a'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -4052,7 +4052,7 @@ test_vararg(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject static PyObject * test_vararg_impl(PyObject *module, PyObject *a, PyObject *args) -/*[clinic end generated code: output=880365c61ae205d7 input=81d33815ad1bae6e]*/ +/*[clinic end generated code: output=1411e464f358a7ba input=81d33815ad1bae6e]*/ /*[clinic input] test_vararg_with_default @@ -4089,7 +4089,7 @@ test_vararg_with_default(PyObject *module, PyObject *const *args, Py_ssize_t nar PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(a), &_Py_ID(b), }, + .ob_item = { _Py_LATIN1_CHR('a'), _Py_LATIN1_CHR('b'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -4135,7 +4135,7 @@ test_vararg_with_default(PyObject *module, PyObject *const *args, Py_ssize_t nar static PyObject * test_vararg_with_default_impl(PyObject *module, PyObject *a, PyObject *args, int b) -/*[clinic end generated code: output=291e9a5a09831128 input=6e110b54acd9b22d]*/ +/*[clinic end generated code: output=f09d4b917063ca41 input=6e110b54acd9b22d]*/ /*[clinic input] test_vararg_with_only_defaults @@ -4172,7 +4172,7 @@ test_vararg_with_only_defaults(PyObject *module, PyObject *const *args, Py_ssize PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(b), &_Py_ID(c), }, + .ob_item = { _Py_LATIN1_CHR('b'), _Py_LATIN1_CHR('c'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -4223,7 +4223,7 @@ test_vararg_with_only_defaults(PyObject *module, PyObject *const *args, Py_ssize static PyObject * test_vararg_with_only_defaults_impl(PyObject *module, PyObject *args, int b, PyObject *c) -/*[clinic end generated code: output=dd21b28f0db26a4b input=fa56a709a035666e]*/ +/*[clinic end generated code: output=cc6590b8805d5433 input=fa56a709a035666e]*/ /*[clinic input] test_paramname_module @@ -4490,7 +4490,7 @@ Test_cls_with_param(TestObj *self, PyTypeObject *cls, PyObject *const *args, Py_ PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(a), }, + .ob_item = { _Py_LATIN1_CHR('a'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -4525,7 +4525,7 @@ Test_cls_with_param(TestObj *self, PyTypeObject *cls, PyObject *const *args, Py_ static PyObject * Test_cls_with_param_impl(TestObj *self, PyTypeObject *cls, int a) -/*[clinic end generated code: output=00218e7f583e6c81 input=af158077bd237ef9]*/ +/*[clinic end generated code: output=107b46f09870e1f8 input=af158077bd237ef9]*/ /*[clinic input] @@ -4838,7 +4838,7 @@ Test___init__(PyObject *self, PyObject *args, PyObject *kwargs) PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(a), }, + .ob_item = { _Py_LATIN1_CHR('a'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -4872,7 +4872,7 @@ Test___init__(PyObject *self, PyObject *args, PyObject *kwargs) static int Test___init___impl(TestObj *self, PyObject *a) -/*[clinic end generated code: output=0b9ca79638ab3ecb input=a8f9222a6ab35c59]*/ +/*[clinic end generated code: output=0e1239b9bc247bc1 input=a8f9222a6ab35c59]*/ /*[clinic input] diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index 404894ac..903a43aa 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -1331,6 +1331,11 @@ def test_insane_fromtimestamp(self): self.assertRaises(OverflowError, self.theclass.fromtimestamp, insane) + def test_fromtimestamp_with_none_arg(self): + # See gh-120268 for more details + with self.assertRaises(TypeError): + self.theclass.fromtimestamp(None) + def test_today(self): import time @@ -2811,11 +2816,32 @@ def test_more_strftime(self): self.assertEqual(t.strftime("%z"), "-0200" + z) self.assertEqual(t.strftime("%:z"), "-02:00:" + z) - # bpo-34482: Check that surrogates don't cause a crash. - try: - t.strftime('%y\ud800%m %H\ud800%M') - except UnicodeEncodeError: - pass + def test_strftime_special(self): + t = self.theclass(2004, 12, 31, 6, 22, 33, 47) + s1 = t.strftime('%c') + s2 = t.strftime('%B') + # gh-52551, gh-78662: Unicode strings should pass through strftime, + # independently from locale. + self.assertEqual(t.strftime('\U0001f40d'), '\U0001f40d') + self.assertEqual(t.strftime('\U0001f4bb%c\U0001f40d%B'), f'\U0001f4bb{s1}\U0001f40d{s2}') + self.assertEqual(t.strftime('%c\U0001f4bb%B\U0001f40d'), f'{s1}\U0001f4bb{s2}\U0001f40d') + # Lone surrogates should pass through. + self.assertEqual(t.strftime('\ud83d'), '\ud83d') + self.assertEqual(t.strftime('\udc0d'), '\udc0d') + self.assertEqual(t.strftime('\ud83d%c\udc0d%B'), f'\ud83d{s1}\udc0d{s2}') + self.assertEqual(t.strftime('%c\ud83d%B\udc0d'), f'{s1}\ud83d{s2}\udc0d') + self.assertEqual(t.strftime('%c\udc0d%B\ud83d'), f'{s1}\udc0d{s2}\ud83d') + # Surrogate pairs should not recombine. + self.assertEqual(t.strftime('\ud83d\udc0d'), '\ud83d\udc0d') + self.assertEqual(t.strftime('%c\ud83d\udc0d%B'), f'{s1}\ud83d\udc0d{s2}') + # Surrogate-escaped bytes should not recombine. + self.assertEqual(t.strftime('\udcf0\udc9f\udc90\udc8d'), '\udcf0\udc9f\udc90\udc8d') + self.assertEqual(t.strftime('%c\udcf0\udc9f\udc90\udc8d%B'), f'{s1}\udcf0\udc9f\udc90\udc8d{s2}') + # gh-124531: The null character should not terminate the format string. + self.assertEqual(t.strftime('\0'), '\0') + self.assertEqual(t.strftime('\0'*1000), '\0'*1000) + self.assertEqual(t.strftime('\0%c\0%B'), f'\0{s1}\0{s2}') + self.assertEqual(t.strftime('%c\0%B\0'), f'{s1}\0{s2}\0') def test_extract(self): dt = self.theclass(2002, 3, 4, 18, 45, 3, 1234) @@ -3568,6 +3594,33 @@ def test_strftime(self): # gh-85432: The parameter was named "fmt" in the pure-Python impl. t.strftime(format="%f") + def test_strftime_special(self): + t = self.theclass(1, 2, 3, 4) + s1 = t.strftime('%I%p%Z') + s2 = t.strftime('%X') + # gh-52551, gh-78662: Unicode strings should pass through strftime, + # independently from locale. + self.assertEqual(t.strftime('\U0001f40d'), '\U0001f40d') + self.assertEqual(t.strftime('\U0001f4bb%I%p%Z\U0001f40d%X'), f'\U0001f4bb{s1}\U0001f40d{s2}') + self.assertEqual(t.strftime('%I%p%Z\U0001f4bb%X\U0001f40d'), f'{s1}\U0001f4bb{s2}\U0001f40d') + # Lone surrogates should pass through. + self.assertEqual(t.strftime('\ud83d'), '\ud83d') + self.assertEqual(t.strftime('\udc0d'), '\udc0d') + self.assertEqual(t.strftime('\ud83d%I%p%Z\udc0d%X'), f'\ud83d{s1}\udc0d{s2}') + self.assertEqual(t.strftime('%I%p%Z\ud83d%X\udc0d'), f'{s1}\ud83d{s2}\udc0d') + self.assertEqual(t.strftime('%I%p%Z\udc0d%X\ud83d'), f'{s1}\udc0d{s2}\ud83d') + # Surrogate pairs should not recombine. + self.assertEqual(t.strftime('\ud83d\udc0d'), '\ud83d\udc0d') + self.assertEqual(t.strftime('%I%p%Z\ud83d\udc0d%X'), f'{s1}\ud83d\udc0d{s2}') + # Surrogate-escaped bytes should not recombine. + self.assertEqual(t.strftime('\udcf0\udc9f\udc90\udc8d'), '\udcf0\udc9f\udc90\udc8d') + self.assertEqual(t.strftime('%I%p%Z\udcf0\udc9f\udc90\udc8d%X'), f'{s1}\udcf0\udc9f\udc90\udc8d{s2}') + # gh-124531: The null character should not terminate the format string. + self.assertEqual(t.strftime('\0'), '\0') + self.assertEqual(t.strftime('\0'*1000), '\0'*1000) + self.assertEqual(t.strftime('\0%I%p%Z\0%X'), f'\0{s1}\0{s2}') + self.assertEqual(t.strftime('%I%p%Z\0%X\0'), f'{s1}\0{s2}\0') + def test_format(self): t = self.theclass(1, 2, 3, 4) self.assertEqual(t.__format__(''), str(t)) @@ -3997,9 +4050,8 @@ def tzname(self, dt): return self.tz self.assertRaises(TypeError, t.strftime, "%Z") # Issue #6697: - if '_Fast' in self.__class__.__name__: - Badtzname.tz = '\ud800' - self.assertRaises(ValueError, t.strftime, "%Z") + Badtzname.tz = '\ud800' + self.assertEqual(t.strftime("%Z"), '\ud800') def test_hash_edge_cases(self): # Offsets that overflow a basic time. diff --git a/Lib/test/decimaltestdata/ddFMA.decTest b/Lib/test/decimaltestdata/ddFMA.decTest index 9094fc01..7f2e5230 100644 --- a/Lib/test/decimaltestdata/ddFMA.decTest +++ b/Lib/test/decimaltestdata/ddFMA.decTest @@ -1663,7 +1663,7 @@ ddfma375087 fma 1 12345678 1E-33 -> 12345678.00000001 Inexac ddfma375088 fma 1 12345678 1E-34 -> 12345678.00000001 Inexact Rounded ddfma375089 fma 1 12345678 1E-35 -> 12345678.00000001 Inexact Rounded --- desctructive subtraction (from remainder tests) +-- destructive subtraction (from remainder tests) -- +++ some of these will be off-by-one remainder vs remainderNear diff --git a/Lib/test/decimaltestdata/ddQuantize.decTest b/Lib/test/decimaltestdata/ddQuantize.decTest index 91776201..e1c5674d 100644 --- a/Lib/test/decimaltestdata/ddQuantize.decTest +++ b/Lib/test/decimaltestdata/ddQuantize.decTest @@ -462,7 +462,7 @@ ddqua520 quantize 1.234 1e359 -> 0E+359 Inexact Rounded ddqua521 quantize 123.456 1e359 -> 0E+359 Inexact Rounded ddqua522 quantize 1.234 1e359 -> 0E+359 Inexact Rounded ddqua523 quantize 123.456 1e359 -> 0E+359 Inexact Rounded --- next four are "won't fit" overfl +-- next four are "won't fit" overflow ddqua526 quantize 1.234 1e-299 -> NaN Invalid_operation ddqua527 quantize 123.456 1e-299 -> NaN Invalid_operation ddqua528 quantize 1.234 1e-299 -> NaN Invalid_operation diff --git a/Lib/test/decimaltestdata/ddRemainder.decTest b/Lib/test/decimaltestdata/ddRemainder.decTest index 5bd1e32d..b1866d39 100644 --- a/Lib/test/decimaltestdata/ddRemainder.decTest +++ b/Lib/test/decimaltestdata/ddRemainder.decTest @@ -422,7 +422,7 @@ ddrem757 remainder 1 sNaN -> NaN Invalid_operation ddrem758 remainder 1000 sNaN -> NaN Invalid_operation ddrem759 remainder Inf -sNaN -> -NaN Invalid_operation --- propaging NaNs +-- propagating NaNs ddrem760 remainder NaN1 NaN7 -> NaN1 ddrem761 remainder sNaN2 NaN8 -> NaN2 Invalid_operation ddrem762 remainder NaN3 sNaN9 -> NaN9 Invalid_operation diff --git a/Lib/test/decimaltestdata/ddRemainderNear.decTest b/Lib/test/decimaltestdata/ddRemainderNear.decTest index 6ba64eba..bbe82ea3 100644 --- a/Lib/test/decimaltestdata/ddRemainderNear.decTest +++ b/Lib/test/decimaltestdata/ddRemainderNear.decTest @@ -450,7 +450,7 @@ ddrmn757 remaindernear 1 sNaN -> NaN Invalid_operation ddrmn758 remaindernear 1000 sNaN -> NaN Invalid_operation ddrmn759 remaindernear Inf -sNaN -> -NaN Invalid_operation --- propaging NaNs +-- propagating NaNs ddrmn760 remaindernear NaN1 NaN7 -> NaN1 ddrmn761 remaindernear sNaN2 NaN8 -> NaN2 Invalid_operation ddrmn762 remaindernear NaN3 sNaN9 -> NaN9 Invalid_operation diff --git a/Lib/test/decimaltestdata/dqRemainder.decTest b/Lib/test/decimaltestdata/dqRemainder.decTest index bae8eae5..e0aaca37 100644 --- a/Lib/test/decimaltestdata/dqRemainder.decTest +++ b/Lib/test/decimaltestdata/dqRemainder.decTest @@ -418,7 +418,7 @@ dqrem757 remainder 1 sNaN -> NaN Invalid_operation dqrem758 remainder 1000 sNaN -> NaN Invalid_operation dqrem759 remainder Inf -sNaN -> -NaN Invalid_operation --- propaging NaNs +-- propagating NaNs dqrem760 remainder NaN1 NaN7 -> NaN1 dqrem761 remainder sNaN2 NaN8 -> NaN2 Invalid_operation dqrem762 remainder NaN3 sNaN9 -> NaN9 Invalid_operation diff --git a/Lib/test/decimaltestdata/dqRemainderNear.decTest b/Lib/test/decimaltestdata/dqRemainderNear.decTest index b850626f..2c5c3f50 100644 --- a/Lib/test/decimaltestdata/dqRemainderNear.decTest +++ b/Lib/test/decimaltestdata/dqRemainderNear.decTest @@ -450,7 +450,7 @@ dqrmn757 remaindernear 1 sNaN -> NaN Invalid_operation dqrmn758 remaindernear 1000 sNaN -> NaN Invalid_operation dqrmn759 remaindernear Inf -sNaN -> -NaN Invalid_operation --- propaging NaNs +-- propagating NaNs dqrmn760 remaindernear NaN1 NaN7 -> NaN1 dqrmn761 remaindernear sNaN2 NaN8 -> NaN2 Invalid_operation dqrmn762 remaindernear NaN3 sNaN9 -> NaN9 Invalid_operation diff --git a/Lib/test/decimaltestdata/exp.decTest b/Lib/test/decimaltestdata/exp.decTest index 6a7af23b..e01d7a8f 100644 --- a/Lib/test/decimaltestdata/exp.decTest +++ b/Lib/test/decimaltestdata/exp.decTest @@ -28,7 +28,7 @@ rounding: half_even maxExponent: 384 minexponent: -383 --- basics (examples in specificiation, etc.) +-- basics (examples in specification, etc.) expx001 exp -Infinity -> 0 expx002 exp -10 -> 0.0000453999298 Inexact Rounded expx003 exp -1 -> 0.367879441 Inexact Rounded diff --git a/Lib/test/decimaltestdata/remainder.decTest b/Lib/test/decimaltestdata/remainder.decTest index 7a1061b1..4f59b332 100644 --- a/Lib/test/decimaltestdata/remainder.decTest +++ b/Lib/test/decimaltestdata/remainder.decTest @@ -435,7 +435,7 @@ remx757 remainder 1 sNaN -> NaN Invalid_operation remx758 remainder 1000 sNaN -> NaN Invalid_operation remx759 remainder Inf -sNaN -> -NaN Invalid_operation --- propaging NaNs +-- propagating NaNs remx760 remainder NaN1 NaN7 -> NaN1 remx761 remainder sNaN2 NaN8 -> NaN2 Invalid_operation remx762 remainder NaN3 sNaN9 -> NaN9 Invalid_operation diff --git a/Lib/test/decimaltestdata/remainderNear.decTest b/Lib/test/decimaltestdata/remainderNear.decTest index b768b9e0..000b1424 100644 --- a/Lib/test/decimaltestdata/remainderNear.decTest +++ b/Lib/test/decimaltestdata/remainderNear.decTest @@ -498,7 +498,7 @@ rmnx758 remaindernear 1000 sNaN -> NaN Invalid_operation rmnx759 remaindernear Inf sNaN -> NaN Invalid_operation rmnx760 remaindernear NaN sNaN -> NaN Invalid_operation --- propaging NaNs +-- propagating NaNs rmnx761 remaindernear NaN1 NaN7 -> NaN1 rmnx762 remaindernear sNaN2 NaN8 -> NaN2 Invalid_operation rmnx763 remaindernear NaN3 -sNaN9 -> -NaN9 Invalid_operation diff --git a/Lib/test/ieee754.txt b/Lib/test/ieee754.txt index a8b8a0a2..3e986cdb 100644 --- a/Lib/test/ieee754.txt +++ b/Lib/test/ieee754.txt @@ -51,7 +51,7 @@ nan >>> INF / INF nan -However unambigous operations with inf return inf: +However unambiguous operations with inf return inf: >>> INF * INF inf >>> 1.5 * INF diff --git a/Lib/test/libregrtest/logger.py b/Lib/test/libregrtest/logger.py index a1257069..fa1d4d57 100644 --- a/Lib/test/libregrtest/logger.py +++ b/Lib/test/libregrtest/logger.py @@ -43,7 +43,10 @@ def log(self, line: str = '') -> None: def get_load_avg(self) -> float | None: if hasattr(os, 'getloadavg'): - return os.getloadavg()[0] + try: + return os.getloadavg()[0] + except OSError: + pass if self.win_load_tracker is not None: return self.win_load_tracker.getloadavg() return None diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py index e41646d2..04404cbc 100644 --- a/Lib/test/libregrtest/main.py +++ b/Lib/test/libregrtest/main.py @@ -508,7 +508,7 @@ def _run_tests(self, selected: TestTuple, tests: TestList | None) -> int: setup_process() if (runtests.hunt_refleak is not None) and (not self.num_workers): - # gh-109739: WindowsLoadTracker thread interfers with refleak check + # gh-109739: WindowsLoadTracker thread interferes with refleak check use_load_tracker = False else: # WindowsLoadTracker is only needed on Windows diff --git a/Lib/test/libregrtest/refleak.py b/Lib/test/libregrtest/refleak.py index a257d102..ab5921c7 100644 --- a/Lib/test/libregrtest/refleak.py +++ b/Lib/test/libregrtest/refleak.py @@ -109,7 +109,7 @@ def get_pooled_int(value): getunicodeinternedsize = sys.getunicodeinternedsize fd_count = os_helper.fd_count # initialize variables to make pyflakes quiet - rc_before = alloc_before = fd_before = interned_before = 0 + rc_before = alloc_before = fd_before = interned_immortal_before = 0 if not quiet: print("beginning", repcount, "repetitions. Showing number of leaks " @@ -135,9 +135,11 @@ def get_pooled_int(value): # Also, readjust the reference counts and alloc blocks by ignoring # any strings that might have been interned during test_func. These # strings will be deallocated at runtime shutdown - interned_after = getunicodeinternedsize() - alloc_after = getallocatedblocks() - interned_after - rc_after = gettotalrefcount() - interned_after * 2 + interned_immortal_after = getunicodeinternedsize( + # Use an internal-only keyword argument that mypy doesn't know yet + _only_immortal=True) # type: ignore[call-arg] + alloc_after = getallocatedblocks() - interned_immortal_after + rc_after = gettotalrefcount() - interned_immortal_after * 2 fd_after = fd_count() rc_deltas[i] = get_pooled_int(rc_after - rc_before) @@ -164,7 +166,7 @@ def get_pooled_int(value): alloc_before = alloc_after rc_before = rc_after fd_before = fd_after - interned_before = interned_after + interned_immortal_before = interned_immortal_after restore_support_xml(xml_filename) @@ -239,9 +241,13 @@ def dash_R_cleanup(fs, ps, pic, zdc, abcs): abs_classes = filter(isabstract, abs_classes) for abc in abs_classes: for obj in abc.__subclasses__() + [abc]: - for ref in abcs.get(obj, set()): - if ref() is not None: - obj.register(ref()) + refs = abcs.get(obj, None) + if refs is not None: + obj._abc_registry_clear() + for ref in refs: + subclass = ref() + if subclass is not None: + obj.register(subclass) obj._abc_caches_clear() # Clear caches diff --git a/Lib/test/libregrtest/testresult.py b/Lib/test/libregrtest/testresult.py index de23fdd5..1820f354 100644 --- a/Lib/test/libregrtest/testresult.py +++ b/Lib/test/libregrtest/testresult.py @@ -9,6 +9,7 @@ import traceback import unittest from test import support +from test.libregrtest.utils import sanitize_xml class RegressionTestResult(unittest.TextTestResult): USE_XML = False @@ -65,23 +66,24 @@ def _add_result(self, test, capture=False, **args): if capture: if self._stdout_buffer is not None: stdout = self._stdout_buffer.getvalue().rstrip() - ET.SubElement(e, 'system-out').text = stdout + ET.SubElement(e, 'system-out').text = sanitize_xml(stdout) if self._stderr_buffer is not None: stderr = self._stderr_buffer.getvalue().rstrip() - ET.SubElement(e, 'system-err').text = stderr + ET.SubElement(e, 'system-err').text = sanitize_xml(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)) + e2.set(k2, sanitize_xml(str(v2))) else: - e2.text = str(v2) + e2.text = sanitize_xml(str(v2)) else: - e2.text = str(v) + e2.text = sanitize_xml(str(v)) @classmethod def __makeErrorDict(cls, err_type, err_value, err_tb): diff --git a/Lib/test/libregrtest/utils.py b/Lib/test/libregrtest/utils.py index 265dbf9a..dabed3c3 100644 --- a/Lib/test/libregrtest/utils.py +++ b/Lib/test/libregrtest/utils.py @@ -5,6 +5,7 @@ import os.path import platform import random +import re import shlex import signal import subprocess @@ -263,6 +264,12 @@ def clear_caches(): for f in typing._cleanups: f() + import inspect + abs_classes = filter(inspect.isabstract, typing.__dict__.values()) + for abc in abs_classes: + for obj in abc.__subclasses__() + [abc]: + obj._abc_caches_clear() + try: fractions = sys.modules['fractions'] except KeyError: @@ -336,6 +343,11 @@ def get_build_info(): if support.check_cflags_pgo(): # PGO (--enable-optimizations) optimizations.append('PGO') + + if support.check_bolt_optimized(): + # BOLT (--enable-bolt) + optimizations.append('BOLT') + if optimizations: build.append('+'.join(optimizations)) @@ -710,3 +722,24 @@ def get_signal_name(exitcode): pass return None + + +ILLEGAL_XML_CHARS_RE = re.compile( + '[' + # Control characters; newline (\x0A and \x0D) and TAB (\x09) are legal + '\x00-\x08\x0B\x0C\x0E-\x1F' + # Surrogate characters + '\uD800-\uDFFF' + # Special Unicode characters + '\uFFFE' + '\uFFFF' + # Match multiple sequential invalid characters for better efficiency + ']+') + +def _sanitize_xml_replace(regs): + text = regs[0] + return ''.join(f'\\x{ord(ch):02x}' if ch <= '\xff' else ascii(ch)[1:-1] + for ch in text) + +def sanitize_xml(text): + return ILLEGAL_XML_CHARS_RE.sub(_sanitize_xml_replace, text) diff --git a/Lib/test/list_tests.py b/Lib/test/list_tests.py index b1ef3325..ac13b110 100644 --- a/Lib/test/list_tests.py +++ b/Lib/test/list_tests.py @@ -191,6 +191,14 @@ def test_setslice(self): self.assertRaises(TypeError, a.__setitem__) + def test_slice_assign_iterator(self): + x = self.type2test(range(5)) + x[0:3] = reversed(range(3)) + self.assertEqual(x, self.type2test([2, 1, 0, 3, 4])) + + x[:] = reversed(range(3)) + self.assertEqual(x, self.type2test([2, 1, 0])) + def test_delslice(self): a = self.type2test([0, 1]) del a[1:2] diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py index 024c6deb..8c8f8901 100644 --- a/Lib/test/lock_tests.py +++ b/Lib/test/lock_tests.py @@ -1013,6 +1013,10 @@ def multipass(self, results, n): self.assertEqual(self.barrier.n_waiting, 0) self.assertFalse(self.barrier.broken) + def test_constructor(self): + self.assertRaises(ValueError, self.barriertype, parties=0) + self.assertRaises(ValueError, self.barriertype, parties=-1) + def test_barrier(self, passes=1): """ Test that a barrier is passed in lockstep diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py index 5b9bcece..85710a97 100644 --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -26,7 +26,7 @@ from test import support from test.support import os_helper from test.support import ( - TestFailed, run_with_locale, no_tracing, + TestFailed, run_with_locales, no_tracing, _2G, _4G, bigmemtest ) from test.support.import_helper import forget @@ -144,6 +144,14 @@ class E(C): def __getinitargs__(self): return () +import __main__ +__main__.C = C +C.__module__ = "__main__" +__main__.D = D +D.__module__ = "__main__" +__main__.E = E +E.__module__ = "__main__" + # Simple mutable object. class Object: pass @@ -157,14 +165,6 @@ def __reduce__(self): # Shouldn't support the recursion itself return K, (self.value,) -import __main__ -__main__.C = C -C.__module__ = "__main__" -__main__.D = D -D.__module__ = "__main__" -__main__.E = E -E.__module__ = "__main__" - class myint(int): def __init__(self, x): self.str = str(x) @@ -1179,6 +1179,153 @@ def test_compat_unpickle(self): self.assertIs(type(unpickled), collections.UserDict) self.assertEqual(unpickled, collections.UserDict({1: 2})) + def test_load_global(self): + self.assertIs(self.loads(b'cbuiltins\nstr\n.'), str) + self.assertIs(self.loads(b'cmath\nlog\n.'), math.log) + self.assertIs(self.loads(b'cos.path\njoin\n.'), os.path.join) + self.assertIs(self.loads(b'\x80\x04cbuiltins\nstr.upper\n.'), str.upper) + with support.swap_item(sys.modules, 'mödule', types.SimpleNamespace(glöbal=42)): + self.assertEqual(self.loads(b'\x80\x04cm\xc3\xb6dule\ngl\xc3\xb6bal\n.'), 42) + + self.assertRaises(UnicodeDecodeError, self.loads, b'c\xff\nlog\n.') + self.assertRaises(UnicodeDecodeError, self.loads, b'cmath\n\xff\n.') + self.assertRaises(self.truncated_errors, self.loads, b'c\nlog\n.') + self.assertRaises(self.truncated_errors, self.loads, b'cmath\n\n.') + self.assertRaises(self.truncated_errors, self.loads, b'\x80\x04cmath\n\n.') + + def test_load_stack_global(self): + self.assertIs(self.loads(b'\x8c\x08builtins\x8c\x03str\x93.'), str) + self.assertIs(self.loads(b'\x8c\x04math\x8c\x03log\x93.'), math.log) + self.assertIs(self.loads(b'\x8c\x07os.path\x8c\x04join\x93.'), + os.path.join) + self.assertIs(self.loads(b'\x80\x04\x8c\x08builtins\x8c\x09str.upper\x93.'), + str.upper) + with support.swap_item(sys.modules, 'mödule', types.SimpleNamespace(glöbal=42)): + self.assertEqual(self.loads(b'\x80\x04\x8c\x07m\xc3\xb6dule\x8c\x07gl\xc3\xb6bal\x93.'), 42) + + self.assertRaises(UnicodeDecodeError, self.loads, b'\x8c\x01\xff\x8c\x03log\x93.') + self.assertRaises(UnicodeDecodeError, self.loads, b'\x8c\x04math\x8c\x01\xff\x93.') + self.assertRaises(ValueError, self.loads, b'\x8c\x00\x8c\x03log\x93.') + self.assertRaises(AttributeError, self.loads, b'\x8c\x04math\x8c\x00\x93.') + self.assertRaises(AttributeError, self.loads, b'\x80\x04\x8c\x04math\x8c\x00\x93.') + + self.assertRaises(pickle.UnpicklingError, self.loads, b'N\x8c\x03log\x93.') + self.assertRaises(pickle.UnpicklingError, self.loads, b'\x8c\x04mathN\x93.') + self.assertRaises(pickle.UnpicklingError, self.loads, b'\x80\x04\x8c\x04mathN\x93.') + + def test_find_class(self): + unpickler = self.unpickler(io.BytesIO()) + unpickler_nofix = self.unpickler(io.BytesIO(), fix_imports=False) + unpickler4 = self.unpickler(io.BytesIO(b'\x80\x04N.')) + unpickler4.load() + + self.assertIs(unpickler.find_class('__builtin__', 'str'), str) + self.assertRaises(ModuleNotFoundError, + unpickler_nofix.find_class, '__builtin__', 'str') + self.assertIs(unpickler.find_class('builtins', 'str'), str) + self.assertIs(unpickler_nofix.find_class('builtins', 'str'), str) + self.assertIs(unpickler.find_class('math', 'log'), math.log) + self.assertIs(unpickler.find_class('os.path', 'join'), os.path.join) + self.assertIs(unpickler.find_class('os.path', 'join'), os.path.join) + + self.assertIs(unpickler4.find_class('builtins', 'str.upper'), str.upper) + with self.assertRaises(AttributeError): + unpickler.find_class('builtins', 'str.upper') + + with self.assertRaises(AttributeError): + unpickler.find_class('math', 'spam') + with self.assertRaises(AttributeError): + unpickler4.find_class('math', 'spam') + with self.assertRaises(AttributeError): + unpickler.find_class('math', 'log.spam') + with self.assertRaises(AttributeError): + unpickler4.find_class('math', 'log.spam') + with self.assertRaises(AttributeError): + unpickler.find_class('math', 'log..spam') + with self.assertRaises(AttributeError): + unpickler4.find_class('math', 'log..spam') + with self.assertRaises(AttributeError): + unpickler.find_class('math', '') + with self.assertRaises(AttributeError): + unpickler4.find_class('math', '') + self.assertRaises(ModuleNotFoundError, unpickler.find_class, 'spam', 'log') + self.assertRaises(ValueError, unpickler.find_class, '', 'log') + + self.assertRaises(TypeError, unpickler.find_class, None, 'log') + self.assertRaises(TypeError, unpickler.find_class, 'math', None) + self.assertRaises((TypeError, AttributeError), unpickler4.find_class, 'math', None) + + def test_custom_find_class(self): + def loads(data): + class Unpickler(self.unpickler): + def find_class(self, module_name, global_name): + return (module_name, global_name) + return Unpickler(io.BytesIO(data)).load() + + self.assertEqual(loads(b'cmath\nlog\n.'), ('math', 'log')) + self.assertEqual(loads(b'\x8c\x04math\x8c\x03log\x93.'), ('math', 'log')) + + def loads(data): + class Unpickler(self.unpickler): + @staticmethod + def find_class(module_name, global_name): + return (module_name, global_name) + return Unpickler(io.BytesIO(data)).load() + + self.assertEqual(loads(b'cmath\nlog\n.'), ('math', 'log')) + self.assertEqual(loads(b'\x8c\x04math\x8c\x03log\x93.'), ('math', 'log')) + + def loads(data): + class Unpickler(self.unpickler): + @classmethod + def find_class(cls, module_name, global_name): + return (module_name, global_name) + return Unpickler(io.BytesIO(data)).load() + + self.assertEqual(loads(b'cmath\nlog\n.'), ('math', 'log')) + self.assertEqual(loads(b'\x8c\x04math\x8c\x03log\x93.'), ('math', 'log')) + + def loads(data): + class Unpickler(self.unpickler): + pass + def find_class(module_name, global_name): + return (module_name, global_name) + unpickler = Unpickler(io.BytesIO(data)) + unpickler.find_class = find_class + return unpickler.load() + + self.assertEqual(loads(b'cmath\nlog\n.'), ('math', 'log')) + self.assertEqual(loads(b'\x8c\x04math\x8c\x03log\x93.'), ('math', 'log')) + + def test_bad_ext_code(self): + # unregistered extension code + self.check_unpickling_error(ValueError, b'\x82\x01.') + self.check_unpickling_error(ValueError, b'\x82\xff.') + self.check_unpickling_error(ValueError, b'\x83\x01\x00.') + self.check_unpickling_error(ValueError, b'\x83\xff\xff.') + self.check_unpickling_error(ValueError, b'\x84\x01\x00\x00\x00.') + self.check_unpickling_error(ValueError, b'\x84\xff\xff\xff\x7f.') + # EXT specifies code <= 0 + self.check_unpickling_error(pickle.UnpicklingError, b'\x82\x00.') + self.check_unpickling_error(pickle.UnpicklingError, b'\x83\x00\x00.') + self.check_unpickling_error(pickle.UnpicklingError, b'\x84\x00\x00\x00\x00.') + self.check_unpickling_error(pickle.UnpicklingError, b'\x84\x00\x00\x00\x80.') + self.check_unpickling_error(pickle.UnpicklingError, b'\x84\xff\xff\xff\xff.') + + @support.cpython_only + def test_bad_ext_inverted_registry(self): + code = 1 + def check(key, exc): + with support.swap_item(copyreg._inverted_registry, code, key): + with self.assertRaises(exc): + self.loads(b'\x82\x01.') + check(None, ValueError) + check((), ValueError) + check((__name__,), (TypeError, ValueError)) + check((__name__, "MyList", "x"), (TypeError, ValueError)) + check((__name__, None), (TypeError, ValueError)) + check((None, "MyList"), (TypeError, ValueError)) + def test_bad_reduce(self): self.assertEqual(self.loads(b'cbuiltins\nint\n)R.'), 0) self.check_unpickling_error(TypeError, b'N)R.') @@ -1197,6 +1344,41 @@ def test_bad_newobj_ex(self): self.check_unpickling_error(error, b'cbuiltins\nint\nN}\x92.') self.check_unpickling_error(error, b'cbuiltins\nint\n)N\x92.') + def test_bad_state(self): + c = C() + c.x = None + base = b'c__main__\nC\n)\x81' + self.assertEqual(self.loads(base + b'}X\x01\x00\x00\x00xNsb.'), c) + self.assertEqual(self.loads(base + b'N}X\x01\x00\x00\x00xNs\x86b.'), c) + # non-hashable dict key + self.check_unpickling_error(TypeError, base + b'}]Nsb.') + # state = list + error = (pickle.UnpicklingError, AttributeError) + self.check_unpickling_error(error, base + b'](}}eb.') + # state = 1-tuple + self.check_unpickling_error(error, base + b'}\x85b.') + # state = 3-tuple + self.check_unpickling_error(error, base + b'}}}\x87b.') + # non-hashable slot name + self.check_unpickling_error(TypeError, base + b'}}]Ns\x86b.') + # non-string slot name + self.check_unpickling_error(TypeError, base + b'}}NNs\x86b.') + # dict = True + self.check_unpickling_error(error, base + b'\x88}\x86b.') + # slots dict = True + self.check_unpickling_error(error, base + b'}\x88\x86b.') + + class BadKey1: + count = 1 + def __hash__(self): + if not self.count: + raise CustomError + self.count -= 1 + return 42 + __main__.BadKey1 = BadKey1 + # bad hashable dict key + self.check_unpickling_error(CustomError, base + b'}c__main__\nBadKey1\n)\x81Nsb.') + def test_bad_stack(self): badpickles = [ b'.', # STOP @@ -1443,6 +1625,498 @@ def t(): [ToBeUnpickled] * 2) +class AbstractPicklingErrorTests: + # Subclass must define self.dumps, self.pickler. + + def test_bad_reduce_result(self): + obj = REX([print, ()]) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(pickle.PicklingError): + self.dumps(obj, proto) + + obj = REX((print,)) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(pickle.PicklingError): + self.dumps(obj, proto) + + obj = REX((print, (), None, None, None, None, None)) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(pickle.PicklingError): + self.dumps(obj, proto) + + def test_bad_reconstructor(self): + obj = REX((42, ())) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(pickle.PicklingError): + self.dumps(obj, proto) + + def test_unpickleable_reconstructor(self): + obj = REX((UnpickleableCallable(), ())) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(CustomError): + self.dumps(obj, proto) + + def test_bad_reconstructor_args(self): + obj = REX((print, [])) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(pickle.PicklingError): + self.dumps(obj, proto) + + def test_unpickleable_reconstructor_args(self): + obj = REX((print, (1, 2, UNPICKLEABLE))) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(CustomError): + self.dumps(obj, proto) + + def test_bad_newobj_args(self): + obj = REX((copyreg.__newobj__, ())) + for proto in protocols[2:]: + with self.subTest(proto=proto): + with self.assertRaises((IndexError, pickle.PicklingError)) as cm: + self.dumps(obj, proto) + + obj = REX((copyreg.__newobj__, [REX])) + for proto in protocols[2:]: + with self.subTest(proto=proto): + with self.assertRaises((IndexError, pickle.PicklingError)): + self.dumps(obj, proto) + + def test_bad_newobj_class(self): + obj = REX((copyreg.__newobj__, (NoNew(),))) + for proto in protocols[2:]: + with self.subTest(proto=proto): + with self.assertRaises(pickle.PicklingError): + self.dumps(obj, proto) + + def test_wrong_newobj_class(self): + obj = REX((copyreg.__newobj__, (str,))) + for proto in protocols[2:]: + with self.subTest(proto=proto): + with self.assertRaises(pickle.PicklingError): + self.dumps(obj, proto) + + def test_unpickleable_newobj_class(self): + class LocalREX(REX): pass + obj = LocalREX((copyreg.__newobj__, (LocalREX,))) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises((pickle.PicklingError, AttributeError)): + self.dumps(obj, proto) + + def test_unpickleable_newobj_args(self): + obj = REX((copyreg.__newobj__, (REX, 1, 2, UNPICKLEABLE))) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(CustomError): + self.dumps(obj, proto) + + def test_bad_newobj_ex_args(self): + obj = REX((copyreg.__newobj_ex__, ())) + for proto in protocols[2:]: + with self.subTest(proto=proto): + with self.assertRaises((ValueError, pickle.PicklingError)): + self.dumps(obj, proto) + + obj = REX((copyreg.__newobj_ex__, 42)) + for proto in protocols[2:]: + with self.subTest(proto=proto): + with self.assertRaises(pickle.PicklingError): + self.dumps(obj, proto) + + obj = REX((copyreg.__newobj_ex__, (REX, 42, {}))) + is_py = self.pickler is pickle._Pickler + for proto in protocols[2:4] if is_py else protocols[2:]: + with self.subTest(proto=proto): + with self.assertRaises((TypeError, pickle.PicklingError)): + self.dumps(obj, proto) + + obj = REX((copyreg.__newobj_ex__, (REX, (), []))) + for proto in protocols[2:4] if is_py else protocols[2:]: + with self.subTest(proto=proto): + with self.assertRaises((TypeError, pickle.PicklingError)): + self.dumps(obj, proto) + + def test_bad_newobj_ex__class(self): + obj = REX((copyreg.__newobj_ex__, (NoNew(), (), {}))) + for proto in protocols[2:]: + with self.subTest(proto=proto): + with self.assertRaises(pickle.PicklingError): + self.dumps(obj, proto) + + def test_wrong_newobj_ex_class(self): + if self.pickler is not pickle._Pickler: + self.skipTest('only verified in the Python implementation') + obj = REX((copyreg.__newobj_ex__, (str, (), {}))) + for proto in protocols[2:]: + with self.subTest(proto=proto): + with self.assertRaises(pickle.PicklingError): + self.dumps(obj, proto) + + def test_unpickleable_newobj_ex_class(self): + class LocalREX(REX): pass + obj = LocalREX((copyreg.__newobj_ex__, (LocalREX, (), {}))) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises((pickle.PicklingError, AttributeError)): + self.dumps(obj, proto) + + def test_unpickleable_newobj_ex_args(self): + obj = REX((copyreg.__newobj_ex__, (REX, (1, 2, UNPICKLEABLE), {}))) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(CustomError): + self.dumps(obj, proto) + + def test_unpickleable_newobj_ex_kwargs(self): + obj = REX((copyreg.__newobj_ex__, (REX, (), {'a': UNPICKLEABLE}))) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(CustomError): + self.dumps(obj, proto) + + def test_unpickleable_state(self): + obj = REX_state(UNPICKLEABLE) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(CustomError): + self.dumps(obj, proto) + + def test_bad_state_setter(self): + if self.pickler is pickle._Pickler: + self.skipTest('only verified in the C implementation') + obj = REX((print, (), 'state', None, None, 42)) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(pickle.PicklingError): + self.dumps(obj, proto) + + def test_unpickleable_state_setter(self): + obj = REX((print, (), 'state', None, None, UnpickleableCallable())) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(CustomError): + self.dumps(obj, proto) + + def test_unpickleable_state_with_state_setter(self): + obj = REX((print, (), UNPICKLEABLE, None, None, print)) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(CustomError): + self.dumps(obj, proto) + + def test_bad_object_list_items(self): + # Issue4176: crash when 4th and 5th items of __reduce__() + # are not iterators + obj = REX((list, (), None, 42)) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises((TypeError, pickle.PicklingError)): + self.dumps(obj, proto) + + if self.pickler is not pickle._Pickler: + # Python implementation is less strict and also accepts iterables. + obj = REX((list, (), None, [])) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises((TypeError, pickle.PicklingError)): + self.dumps(obj, proto) + + def test_unpickleable_object_list_items(self): + obj = REX_six([1, 2, UNPICKLEABLE]) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(CustomError): + self.dumps(obj, proto) + + def test_bad_object_dict_items(self): + # Issue4176: crash when 4th and 5th items of __reduce__() + # are not iterators + obj = REX((dict, (), None, None, 42)) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises((TypeError, pickle.PicklingError)): + self.dumps(obj, proto) + + for proto in protocols: + obj = REX((dict, (), None, None, iter([('a',)]))) + with self.subTest(proto=proto): + with self.assertRaises((ValueError, TypeError)): + self.dumps(obj, proto) + + if self.pickler is not pickle._Pickler: + # Python implementation is less strict and also accepts iterables. + obj = REX((dict, (), None, None, [])) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises((TypeError, pickle.PicklingError)): + self.dumps(obj, proto) + + def test_unpickleable_object_dict_items(self): + obj = REX_seven({'a': UNPICKLEABLE}) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(CustomError): + self.dumps(obj, proto) + + def test_unpickleable_list_items(self): + obj = [1, [2, 3, UNPICKLEABLE]] + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(CustomError): + self.dumps(obj, proto) + for n in [0, 1, 1000, 1005]: + obj = [*range(n), UNPICKLEABLE] + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(CustomError): + self.dumps(obj, proto) + + def test_unpickleable_tuple_items(self): + obj = (1, (2, 3, UNPICKLEABLE)) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(CustomError): + self.dumps(obj, proto) + obj = (*range(10), UNPICKLEABLE) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(CustomError): + self.dumps(obj, proto) + + def test_unpickleable_dict_items(self): + obj = {'a': {'b': UNPICKLEABLE}} + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(CustomError): + self.dumps(obj, proto) + for n in [0, 1, 1000, 1005]: + obj = dict.fromkeys(range(n)) + obj['a'] = UNPICKLEABLE + for proto in protocols: + with self.subTest(proto=proto, n=n): + with self.assertRaises(CustomError): + self.dumps(obj, proto) + + def test_unpickleable_set_items(self): + obj = {UNPICKLEABLE} + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(CustomError): + self.dumps(obj, proto) + + def test_unpickleable_frozenset_items(self): + obj = frozenset({frozenset({UNPICKLEABLE})}) + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(CustomError): + self.dumps(obj, proto) + + def test_global_lookup_error(self): + # Global name does not exist + obj = REX('spam') + obj.__module__ = __name__ + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(pickle.PicklingError): + self.dumps(obj, proto) + + obj.__module__ = 'nonexisting' + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(pickle.PicklingError): + self.dumps(obj, proto) + + obj.__module__ = '' + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises((ValueError, pickle.PicklingError)): + self.dumps(obj, proto) + + obj.__module__ = None + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(pickle.PicklingError): + self.dumps(obj, proto) + + def test_nonencodable_global_name_error(self): + for proto in protocols[:4]: + with self.subTest(proto=proto): + name = 'nonascii\xff' if proto < 3 else 'nonencodable\udbff' + obj = REX(name) + obj.__module__ = __name__ + with support.swap_item(globals(), name, obj): + with self.assertRaises((UnicodeEncodeError, pickle.PicklingError)): + self.dumps(obj, proto) + + def test_nonencodable_module_name_error(self): + for proto in protocols[:4]: + with self.subTest(proto=proto): + name = 'nonascii\xff' if proto < 3 else 'nonencodable\udbff' + obj = REX('test') + obj.__module__ = name + mod = types.SimpleNamespace(test=obj) + with support.swap_item(sys.modules, name, mod): + with self.assertRaises((UnicodeEncodeError, pickle.PicklingError)): + self.dumps(obj, proto) + + def test_nested_lookup_error(self): + # Nested name does not exist + obj = REX('AbstractPickleTests.spam') + obj.__module__ = __name__ + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(pickle.PicklingError): + self.dumps(obj, proto) + + obj.__module__ = None + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(pickle.PicklingError): + self.dumps(obj, proto) + + def test_wrong_object_lookup_error(self): + # Name is bound to different object + obj = REX('AbstractPickleTests') + obj.__module__ = __name__ + AbstractPickleTests.ham = [] + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(pickle.PicklingError): + self.dumps(obj, proto) + + obj.__module__ = None + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises(pickle.PicklingError): + self.dumps(obj, proto) + + def test_local_lookup_error(self): + # Test that whichmodule() errors out cleanly when looking up + # an assumed globally-reachable object fails. + def f(): + pass + # Since the function is local, lookup will fail + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises((AttributeError, pickle.PicklingError)): + self.dumps(f, proto) + # Same without a __module__ attribute (exercises a different path + # in _pickle.c). + del f.__module__ + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises((AttributeError, pickle.PicklingError)): + self.dumps(f, proto) + # Yet a different path. + f.__name__ = f.__qualname__ + for proto in protocols: + with self.subTest(proto=proto): + with self.assertRaises((AttributeError, pickle.PicklingError)): + self.dumps(f, proto) + + def test_reduce_ex_None(self): + if self.pickler is pickle._Pickler: + self.skipTest('only verified in the C implementation') + c = REX_None() + with self.assertRaises(TypeError): + self.dumps(c) + + def test_reduce_None(self): + c = R_None() + with self.assertRaises(TypeError): + self.dumps(c) + + @no_tracing + def test_bad_getattr(self): + # Issue #3514: crash when there is an infinite loop in __getattr__ + x = BadGetattr() + for proto in range(2): + with support.infinite_recursion(25): + self.assertRaises(RuntimeError, self.dumps, x, proto) + for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): + s = self.dumps(x, proto) + + def test_picklebuffer_error(self): + # PickleBuffer forbidden with protocol < 5 + pb = pickle.PickleBuffer(b"foobar") + for proto in range(0, 5): + with self.subTest(proto=proto): + with self.assertRaises(pickle.PickleError) as cm: + self.dumps(pb, proto) + self.assertEqual(str(cm.exception), + 'PickleBuffer can only be pickled with protocol >= 5') + + def test_non_continuous_buffer(self): + for proto in protocols[5:]: + with self.subTest(proto=proto): + pb = pickle.PickleBuffer(memoryview(b"foobar")[::2]) + with self.assertRaises((pickle.PicklingError, BufferError)): + self.dumps(pb, proto) + + def test_buffer_callback_error(self): + def buffer_callback(buffers): + raise CustomError + pb = pickle.PickleBuffer(b"foobar") + with self.assertRaises(CustomError): + self.dumps(pb, 5, buffer_callback=buffer_callback) + + def test_evil_pickler_mutating_collection(self): + # https://github.com/python/cpython/issues/92930 + global Clearer + class Clearer: + pass + + def check(collection): + class EvilPickler(self.pickler): + def persistent_id(self, obj): + if isinstance(obj, Clearer): + collection.clear() + return None + pickler = EvilPickler(io.BytesIO(), proto) + try: + pickler.dump(collection) + except RuntimeError as e: + expected = "changed size during iteration" + self.assertIn(expected, str(e)) + + for proto in protocols: + check([Clearer()]) + check([Clearer(), Clearer()]) + check({Clearer()}) + check({Clearer(), Clearer()}) + check({Clearer(): 1}) + check({Clearer(): 1, Clearer(): 2}) + check({1: Clearer(), 2: Clearer()}) + + @support.cpython_only + def test_bad_ext_code(self): + # This should never happen in normal circumstances, because the type + # and the value of the extension code is checked in copyreg.add_extension(). + key = (__name__, 'MyList') + def check(code, exc): + assert key not in copyreg._extension_registry + assert code not in copyreg._inverted_registry + with (support.swap_item(copyreg._extension_registry, key, code), + support.swap_item(copyreg._inverted_registry, code, key)): + for proto in protocols[2:]: + with self.assertRaises(exc): + self.dumps(MyList, proto) + + check(object(), TypeError) + check(None, TypeError) + check(-1, (RuntimeError, struct.error)) + check(0, RuntimeError) + check(2**31, (RuntimeError, OverflowError, struct.error)) + check(2**1000, (OverflowError, struct.error)) + check(-2**1000, (OverflowError, struct.error)) + class AbstractPickleTests: # Subclass must define self.dumps, self.loads. @@ -1845,6 +2519,25 @@ def test_bytes(self): p = self.dumps(s, proto) self.assert_is_copy(s, self.loads(p)) + def test_bytes_memoization(self): + for proto in protocols: + for array_type in [bytes, ZeroCopyBytes]: + for s in b'', b'xyz', b'xyz'*100: + with self.subTest(proto=proto, array_type=array_type, s=s, independent=False): + b = array_type(s) + p = self.dumps((b, b), proto) + x, y = self.loads(p) + self.assertIs(x, y) + self.assert_is_copy((b, b), (x, y)) + + with self.subTest(proto=proto, array_type=array_type, s=s, independent=True): + b1, b2 = array_type(s), array_type(s) + p = self.dumps((b1, b2), proto) + # Note that (b1, b2) = self.loads(p) might have identical + # components, i.e., b1 is b2, but this is not always the + # case if the content is large (equality still holds). + self.assert_is_copy((b1, b2), self.loads(p)) + def test_bytearray(self): for proto in protocols: for s in b'', b'xyz', b'xyz'*100: @@ -1864,13 +2557,31 @@ def test_bytearray(self): self.assertNotIn(b'bytearray', p) self.assertTrue(opcode_in_pickle(pickle.BYTEARRAY8, p)) - def test_bytearray_memoization_bug(self): + def test_bytearray_memoization(self): for proto in protocols: - for s in b'', b'xyz', b'xyz'*100: - b = bytearray(s) - p = self.dumps((b, b), proto) - b1, b2 = self.loads(p) - self.assertIs(b1, b2) + for array_type in [bytearray, ZeroCopyBytearray]: + for s in b'', b'xyz', b'xyz'*100: + with self.subTest(proto=proto, array_type=array_type, s=s, independent=False): + b = array_type(s) + p = self.dumps((b, b), proto) + b1, b2 = self.loads(p) + self.assertIs(b1, b2) + + with self.subTest(proto=proto, array_type=array_type, s=s, independent=True): + b1a, b2a = array_type(s), array_type(s) + # Unlike bytes, equal but independent bytearray objects are + # never identical. + self.assertIsNot(b1a, b2a) + + p = self.dumps((b1a, b2a), proto) + b1b, b2b = self.loads(p) + self.assertIsNot(b1b, b2b) + + self.assertIsNot(b1a, b1b) + self.assert_is_copy(b1a, b1b) + + self.assertIsNot(b2a, b2b) + self.assert_is_copy(b2a, b2b) def test_ints(self): for proto in protocols: @@ -1915,7 +2626,7 @@ def test_float(self): got = self.loads(pickle) self.assert_is_copy(value, got) - @run_with_locale('LC_ALL', 'de_DE', 'fr_FR') + @run_with_locales('LC_ALL', 'de_DE', 'fr_FR', '') def test_float_format(self): # make sure that floats are formatted locale independent with proto 0 self.assertEqual(self.dumps(1.2, 0)[0:3], b'F1.') @@ -2416,38 +3127,11 @@ def test_reduce_calls_base(self): y = self.loads(s) self.assertEqual(y._reduce_called, 1) - @no_tracing - def test_bad_getattr(self): - # Issue #3514: crash when there is an infinite loop in __getattr__ - x = BadGetattr() - for proto in range(2): - with support.infinite_recursion(): - self.assertRaises(RuntimeError, self.dumps, x, proto) - for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): - s = self.dumps(x, proto) - - def test_reduce_bad_iterator(self): - # Issue4176: crash when 4th and 5th items of __reduce__() - # are not iterators - class C(object): - def __reduce__(self): - # 4th item is not an iterator - return list, (), None, [], None - class D(object): - def __reduce__(self): - # 5th item is not an iterator - return dict, (), None, None, [] - - # Python implementation is less strict and also accepts iterables. - for proto in protocols: - try: - self.dumps(C(), proto) - except pickle.PicklingError: - pass - try: - self.dumps(D(), proto) - except pickle.PicklingError: - pass + def test_pickle_setstate_None(self): + c = C_None_setstate() + p = self.dumps(c) + with self.assertRaises((AttributeError, TypeError)): + self.loads(p) def test_many_puts_and_gets(self): # Test that internal data structures correctly deal with lots of @@ -2765,6 +3449,18 @@ class Recursive: self.assertIs(unpickled, Recursive) del Recursive.mod # break reference loop + def test_recursive_nested_names2(self): + global Recursive + class Recursive: + pass + Recursive.ref = Recursive + Recursive.__qualname__ = 'Recursive.ref' + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(proto=proto): + unpickled = self.loads(self.dumps(Recursive, proto)) + self.assertIs(unpickled, Recursive) + del Recursive.ref # break reference loop + def test_py_methods(self): global PyMethodsTest class PyMethodsTest: @@ -2885,27 +3581,6 @@ def test_compat_pickle(self): self.assertIn(('c%s\n%s' % (mod, name)).encode(), pickled) self.assertIs(type(self.loads(pickled)), type(val)) - def test_local_lookup_error(self): - # Test that whichmodule() errors out cleanly when looking up - # an assumed globally-reachable object fails. - def f(): - pass - # Since the function is local, lookup will fail - for proto in range(0, pickle.HIGHEST_PROTOCOL + 1): - with self.assertRaises((AttributeError, pickle.PicklingError)): - pickletools.dis(self.dumps(f, proto)) - # Same without a __module__ attribute (exercises a different path - # in _pickle.c). - del f.__module__ - for proto in range(0, pickle.HIGHEST_PROTOCOL + 1): - with self.assertRaises((AttributeError, pickle.PicklingError)): - pickletools.dis(self.dumps(f, proto)) - # Yet a different path. - f.__name__ = f.__qualname__ - for proto in range(0, pickle.HIGHEST_PROTOCOL + 1): - with self.assertRaises((AttributeError, pickle.PicklingError)): - pickletools.dis(self.dumps(f, proto)) - # # PEP 574 tests below # @@ -3016,20 +3691,6 @@ def test_oob_buffers_writable_to_readonly(self): self.assertIs(type(new), type(obj)) self.assertEqual(new, obj) - def test_picklebuffer_error(self): - # PickleBuffer forbidden with protocol < 5 - pb = pickle.PickleBuffer(b"foobar") - for proto in range(0, 5): - with self.assertRaises(pickle.PickleError): - self.dumps(pb, proto) - - def test_buffer_callback_error(self): - def buffer_callback(buffers): - 1/0 - pb = pickle.PickleBuffer(b"foobar") - with self.assertRaises(ZeroDivisionError): - self.dumps(pb, 5, buffer_callback=buffer_callback) - def test_buffers_error(self): pb = pickle.PickleBuffer(b"foobar") for proto in range(5, pickle.HIGHEST_PROTOCOL + 1): @@ -3121,37 +3782,6 @@ def __reduce__(self): expected = "changed size during iteration" self.assertIn(expected, str(e)) - def test_evil_pickler_mutating_collection(self): - # https://github.com/python/cpython/issues/92930 - if not hasattr(self, "pickler"): - raise self.skipTest(f"{type(self)} has no associated pickler type") - - global Clearer - class Clearer: - pass - - def check(collection): - class EvilPickler(self.pickler): - def persistent_id(self, obj): - if isinstance(obj, Clearer): - collection.clear() - return None - pickler = EvilPickler(io.BytesIO(), proto) - try: - pickler.dump(collection) - except RuntimeError as e: - expected = "changed size during iteration" - self.assertIn(expected, str(e)) - - for proto in protocols: - check([Clearer()]) - check([Clearer(), Clearer()]) - check({Clearer()}) - check({Clearer(), Clearer()}) - check({Clearer(): 1}) - check({Clearer(): 1, Clearer(): 2}) - check({1: Clearer(), 2: Clearer()}) - class BigmemPickleTests: @@ -3282,6 +3912,18 @@ def test_huge_str_64b(self, size): # Test classes for reduce_ex +class R: + def __init__(self, reduce=None): + self.reduce = reduce + def __reduce__(self, proto): + return self.reduce + +class REX: + def __init__(self, reduce_ex=None): + self.reduce_ex = reduce_ex + def __reduce_ex__(self, proto): + return self.reduce_ex + class REX_one(object): """No __reduce_ex__ here, but inheriting it from object""" _reduce_called = 0 @@ -3357,6 +3999,34 @@ def __setstate__(self, state): def __reduce__(self): return type(self), (), self.state +class REX_None: + """ Setting __reduce_ex__ to None should fail """ + __reduce_ex__ = None + +class R_None: + """ Setting __reduce__ to None should fail """ + __reduce__ = None + +class C_None_setstate: + """ Setting __setstate__ to None should fail """ + def __getstate__(self): + return 1 + + __setstate__ = None + +class CustomError(Exception): + pass + +class Unpickleable: + def __reduce__(self): + raise CustomError + +UNPICKLEABLE = Unpickleable() + +class UnpickleableCallable(Unpickleable): + def __call__(self, *args, **kwargs): + pass + # Test classes for newobj @@ -3406,7 +4076,9 @@ class MyIntWithNew2(MyIntWithNew): class SlotList(MyList): __slots__ = ["foo"] -class SimpleNewObj(int): +# Ruff "redefined while unused" false positive here due to `global` variables +# being assigned (and then restored) from within test methods earlier in the file +class SimpleNewObj(int): # noqa: F811 def __init__(self, *args, **kwargs): # raise an error, to make sure this isn't called raise TypeError("SimpleNewObj.__init__() didn't expect to get called") @@ -3425,6 +4097,12 @@ class BadGetattr: def __getattr__(self, key): self.foo +class NoNew: + def __getattribute__(self, name): + if name == '__new__': + raise AttributeError + return super().__getattribute__(name) + class AbstractPickleModuleTests: @@ -3497,7 +4175,7 @@ def raises_oserror(self, *args, **kwargs): raise OSError @property def bad_property(self): - 1/0 + raise CustomError # File without read and readline class F: @@ -3518,23 +4196,23 @@ class F: class F: read = bad_property readline = raises_oserror - self.assertRaises(ZeroDivisionError, self.Unpickler, F()) + self.assertRaises(CustomError, self.Unpickler, F()) # File with bad readline class F: readline = bad_property read = raises_oserror - self.assertRaises(ZeroDivisionError, self.Unpickler, F()) + self.assertRaises(CustomError, self.Unpickler, F()) # File with bad readline, no read class F: readline = bad_property - self.assertRaises(ZeroDivisionError, self.Unpickler, F()) + self.assertRaises(CustomError, self.Unpickler, F()) # File with bad read, no readline class F: read = bad_property - self.assertRaises((AttributeError, ZeroDivisionError), self.Unpickler, F()) + self.assertRaises((AttributeError, CustomError), self.Unpickler, F()) # File with bad peek class F: @@ -3543,7 +4221,7 @@ class F: readline = raises_oserror try: self.Unpickler(F()) - except ZeroDivisionError: + except CustomError: pass # File with bad readinto @@ -3553,7 +4231,7 @@ class F: readline = raises_oserror try: self.Unpickler(F()) - except ZeroDivisionError: + except CustomError: pass def test_pickler_bad_file(self): @@ -3566,8 +4244,8 @@ class F: class F: @property def write(self): - 1/0 - self.assertRaises(ZeroDivisionError, self.Pickler, F()) + raise CustomError + self.assertRaises(CustomError, self.Pickler, F()) def check_dumps_loads_oob_buffers(self, dumps, loads): # No need to do the full gamut of tests here, just enough to @@ -3675,9 +4353,15 @@ def test_return_correct_type(self): def test_protocol0_is_ascii_only(self): non_ascii_str = "\N{EMPTY SET}" - self.assertRaises(pickle.PicklingError, self.dumps, non_ascii_str, 0) + with self.assertRaises(pickle.PicklingError) as cm: + self.dumps(non_ascii_str, 0) + self.assertEqual(str(cm.exception), + 'persistent IDs in protocol 0 must be ASCII strings') pickled = pickle.PERSID + non_ascii_str.encode('utf-8') + b'\n.' - self.assertRaises(pickle.UnpicklingError, self.loads, pickled) + with self.assertRaises(pickle.UnpicklingError) as cm: + self.loads(pickled) + self.assertEqual(str(cm.exception), + 'persistent IDs in protocol 0 must be ASCII strings') class AbstractPicklerUnpicklerObjectTests: diff --git a/Lib/test/pyclbr_input.py b/Lib/test/pyclbr_input.py index 19ccd62d..5535edbf 100644 --- a/Lib/test/pyclbr_input.py +++ b/Lib/test/pyclbr_input.py @@ -12,17 +12,19 @@ class B (object): def bm(self): pass class C (B): - foo = Other().foo - om = Other.om - d = 10 - # XXX: This causes test_pyclbr.py to fail, but only because the - # introspection-based is_method() code in the test can't - # distinguish between this and a genuine method function like m(). - # The pyclbr.py module gets this right as it parses the text. + # This one is correctly considered by both test_pyclbr.py and pyclbr.py + # as a non-method of C. + foo = Other().foo + + # This causes test_pyclbr.py to fail, but only because the + # introspection-based is_method() code in the test can't + # distinguish between this and a genuine method function like m(). # - #f = f + # The pyclbr.py module gets this right as it parses the text. + om = Other.om + f = f def m(self): pass @@ -31,3 +33,53 @@ def sm(self): pass @classmethod def cm(self): pass + +# Check that mangling is correctly handled + +class a: + def a(self): pass + def _(self): pass + def _a(self): pass + def __(self): pass + def ___(self): pass + def __a(self): pass + +class _: + def a(self): pass + def _(self): pass + def _a(self): pass + def __(self): pass + def ___(self): pass + def __a(self): pass + +class __: + def a(self): pass + def _(self): pass + def _a(self): pass + def __(self): pass + def ___(self): pass + def __a(self): pass + +class ___: + def a(self): pass + def _(self): pass + def _a(self): pass + def __(self): pass + def ___(self): pass + def __a(self): pass + +class _a: + def a(self): pass + def _(self): pass + def _a(self): pass + def __(self): pass + def ___(self): pass + def __a(self): pass + +class __a: + def a(self): pass + def _(self): pass + def _a(self): pass + def __(self): pass + def ___(self): pass + def __a(self): pass diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 4e793f15..ba57eb30 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -43,7 +43,7 @@ "requires_limited_api", "requires_specialization", # sys "MS_WINDOWS", "is_jython", "is_android", "is_emscripten", "is_wasi", - "check_impl_detail", "unix_shell", "setswitchinterval", + "is_apple_mobile", "check_impl_detail", "unix_shell", "setswitchinterval", # os "get_pagesize", # network @@ -58,6 +58,7 @@ "LOOPBACK_TIMEOUT", "INTERNET_TIMEOUT", "SHORT_TIMEOUT", "LONG_TIMEOUT", "Py_DEBUG", "EXCEEDS_RECURSION_LIMIT", "C_RECURSION_LIMIT", "skip_on_s390x", + "BrokenIter", ] @@ -249,22 +250,16 @@ class USEROBJECTFLAGS(ctypes.Structure): # process not running under the same user id as the current console # user. To avoid that, raise an exception if the window manager # connection is not available. - from ctypes import cdll, c_int, pointer, Structure - from ctypes.util import find_library - - app_services = cdll.LoadLibrary(find_library("ApplicationServices")) - - if app_services.CGMainDisplayID() == 0: - reason = "gui tests cannot run without OS X window manager" + import subprocess + try: + rc = subprocess.run(["launchctl", "managername"], + capture_output=True, check=True) + managername = rc.stdout.decode("utf-8").strip() + except subprocess.CalledProcessError: + reason = "unable to detect macOS launchd job manager" else: - class ProcessSerialNumber(Structure): - _fields_ = [("highLongOfPSN", c_int), - ("lowLongOfPSN", c_int)] - psn = ProcessSerialNumber() - psn_p = pointer(psn) - if ( (app_services.GetCurrentProcess(psn_p) < 0) or - (app_services.SetFrontProcess(psn_p) < 0) ): - reason = "cannot run without OS X gui process" + if managername != "Aqua": + reason = f"{managername=} -- can only run in a macOS GUI session" # check on every platform whether tkinter can actually do anything if not reason: @@ -386,7 +381,7 @@ def skip_if_buildbot(reason=None): reason = 'not suitable for buildbots' try: isbuildbot = getpass.getuser().lower() == 'buildbot' - except (KeyError, EnvironmentError) as err: + except (KeyError, OSError) as err: warnings.warn(f'getpass.getuser() failed {err}.', RuntimeWarning) isbuildbot = False return unittest.skipIf(isbuildbot, reason) @@ -530,7 +525,7 @@ def requires_legacy_unicode_capi(): is_android = hasattr(sys, 'getandroidapilevel') -if sys.platform not in ('win32', 'vxworks'): +if sys.platform not in {"win32", "vxworks", "ios", "tvos", "watchos"}: unix_shell = '/system/bin/sh' if is_android else '/bin/sh' else: unix_shell = None @@ -540,19 +535,35 @@ def requires_legacy_unicode_capi(): is_emscripten = sys.platform == "emscripten" is_wasi = sys.platform == "wasi" -has_fork_support = hasattr(os, "fork") and not is_emscripten and not is_wasi +# Apple mobile platforms (iOS/tvOS/watchOS) are POSIX-like but do not +# have subprocess or fork support. +is_apple_mobile = sys.platform in {"ios", "tvos", "watchos"} +is_apple = is_apple_mobile or sys.platform == "darwin" + +has_fork_support = hasattr(os, "fork") and not ( + is_emscripten + or is_wasi + or is_apple_mobile +) def requires_fork(): return unittest.skipUnless(has_fork_support, "requires working os.fork()") -has_subprocess_support = not is_emscripten and not is_wasi +has_subprocess_support = not ( + is_emscripten + or is_wasi + or is_apple_mobile +) def requires_subprocess(): """Used for subprocess, os.spawn calls, fd inheritance""" return unittest.skipUnless(has_subprocess_support, "requires subprocess support") # Emscripten's socket emulation and WASI sockets have limitations. -has_socket_support = not is_emscripten and not is_wasi +has_socket_support = not ( + is_emscripten + or is_wasi +) def requires_working_socket(*, module=False): """Skip tests or modules that require working sockets @@ -816,10 +827,20 @@ def check_cflags_pgo(): _align = '0P' _vheader = _header + 'n' +def check_bolt_optimized(): + # Always return false, if the platform is WASI, + # because BOLT optimization does not support WASM binary. + if is_wasi: + return False + config_args = sysconfig.get_config_var('CONFIG_ARGS') or '' + return '--enable-bolt' in config_args + + def calcobjsize(fmt): import struct return struct.calcsize(_header + fmt + _align) + def calcvobjsize(fmt): import struct return struct.calcsize(_vheader + fmt + _align) @@ -843,8 +864,8 @@ def check_sizeof(test, o, size): test.assertEqual(result, size, msg) #======================================================================= -# Decorator for running a function in a different locale, correctly resetting -# it afterwards. +# Decorator/context manager for running a code in a different locale, +# correctly resetting it afterwards. @contextlib.contextmanager def run_with_locale(catstr, *locales): @@ -855,16 +876,21 @@ def run_with_locale(catstr, *locales): except AttributeError: # if the test author gives us an invalid category string raise - except: + except Exception: # cannot retrieve original locale, so do nothing locale = orig_locale = None + if '' not in locales: + raise unittest.SkipTest('no locales') else: for loc in locales: try: locale.setlocale(category, loc) break - except: + except locale.Error: pass + else: + if '' not in locales: + raise unittest.SkipTest(f'no locales {locales}') try: yield @@ -872,6 +898,46 @@ def run_with_locale(catstr, *locales): if locale and orig_locale: locale.setlocale(category, orig_locale) +#======================================================================= +# Decorator for running a function in multiple locales (if they are +# availasble) and resetting the original locale afterwards. + +def run_with_locales(catstr, *locales): + def deco(func): + @functools.wraps(func) + def wrapper(self, /, *args, **kwargs): + dry_run = '' in locales + try: + import locale + category = getattr(locale, catstr) + orig_locale = locale.setlocale(category) + except AttributeError: + # if the test author gives us an invalid category string + raise + except Exception: + # cannot retrieve original locale, so do nothing + pass + else: + try: + for loc in locales: + with self.subTest(locale=loc): + try: + locale.setlocale(category, loc) + except locale.Error: + self.skipTest(f'no locale {loc!r}') + else: + dry_run = False + func(self, *args, **kwargs) + finally: + locale.setlocale(category, orig_locale) + if dry_run: + # no locales available, so just run the test + # with the current locale + with self.subTest(locale=None): + func(self, *args, **kwargs) + return wrapper + return deco + #======================================================================= # Decorator for running a function in a specific timezone, correctly # resetting it afterwards. @@ -2384,9 +2450,9 @@ def adjust_int_max_str_digits(max_digits): else: C_RECURSION_LIMIT = 10000 -#Windows doesn't have os.uname() but it doesn't support s390x. -skip_on_s390x = unittest.skipIf(hasattr(os, 'uname') and os.uname().machine == 's390x', - 'skipped on s390x') +# Windows doesn't have os.uname() but it doesn't support s390x. +is_s390x = hasattr(os, 'uname') and os.uname().machine == 's390x' +skip_on_s390x = unittest.skipIf(is_s390x, 'skipped on s390x') _BASE_COPY_SRC_DIR_IGNORED_NAMES = frozenset({ # SRC_DIR/.git @@ -2413,3 +2479,75 @@ def copy_python_src_ignore(path, names): 'build', } return ignored + + +def iter_builtin_types(): + for obj in __builtins__.values(): + if not isinstance(obj, type): + continue + cls = obj + if cls.__module__ != 'builtins': + continue + yield cls + + +def iter_slot_wrappers(cls): + assert cls.__module__ == 'builtins', cls + + def is_slot_wrapper(name, value): + if not isinstance(value, types.WrapperDescriptorType): + assert not repr(value).startswith(' ' + line for line in data.splitlines()) + return indent + f'{name}:\n' + prefixed_lines + + def run(self, *args, **subprocess_args): + if subprocess_args.get('shell'): + raise ValueError('Running the subprocess in shell mode is not supported.') + default_args = { + 'capture_output': True, + 'check': True, + } + try: + result = subprocess.run([self.interpreter, *args], **default_args | subprocess_args) + except subprocess.CalledProcessError as e: + if e.returncode != 0: + self._logger.error( + f'Interpreter returned non-zero exit status {e.returncode}.\n' + + self._format_output('COMMAND', shlex.join(e.cmd)) + '\n' + + self._format_output('STDOUT', e.stdout.decode()) + '\n' + + self._format_output('STDERR', e.stderr.decode()) + '\n' + ) + raise + else: + return result diff --git a/Lib/test/test__locale.py b/Lib/test/test__locale.py index 0947464b..89c20325 100644 --- a/Lib/test/test__locale.py +++ b/Lib/test/test__locale.py @@ -1,4 +1,4 @@ -from _locale import (setlocale, LC_ALL, LC_CTYPE, LC_NUMERIC, localeconv, Error) +from _locale import (setlocale, LC_ALL, LC_CTYPE, LC_NUMERIC, LC_TIME, localeconv, Error) try: from _locale import (RADIXCHAR, THOUSEP, nl_langinfo) except ImportError: @@ -26,7 +26,10 @@ 'bs_BA', 'fr_LU', 'kl_GL', 'fa_IR', 'de_BE', 'sv_SE', 'it_CH', 'uk_UA', 'eu_ES', 'vi_VN', 'af_ZA', 'nb_NO', 'en_DK', 'tg_TJ', 'ps_AF', 'en_US', 'fr_FR.ISO8859-1', 'fr_FR.UTF-8', 'fr_FR.ISO8859-15@euro', - 'ru_RU.KOI8-R', 'ko_KR.eucKR'] + 'ru_RU.KOI8-R', 'ko_KR.eucKR', + 'ja_JP.UTF-8', 'lzh_TW.UTF-8', 'my_MM.UTF-8', 'or_IN.UTF-8', 'shn_MM.UTF-8', + 'ar_AE.UTF-8', 'bn_IN.UTF-8', 'mr_IN.UTF-8', 'th_TH.TIS620', +] def setUpModule(): global candidate_locales @@ -74,6 +77,27 @@ def accept(loc): 'ps_AF': ('\u066b', '\u066c'), } +known_alt_digits = { + 'C': (0, {}), + 'en_US': (0, {}), + 'fa_IR': (100, {0: '\u06f0\u06f0', 10: '\u06f1\u06f0', 99: '\u06f9\u06f9'}), + 'ja_JP': (100, {1: '\u4e00', 10: '\u5341', 99: '\u4e5d\u5341\u4e5d'}), + 'lzh_TW': (32, {0: '\u3007', 10: '\u5341', 31: '\u5345\u4e00'}), + 'my_MM': (100, {0: '\u1040\u1040', 10: '\u1041\u1040', 99: '\u1049\u1049'}), + 'or_IN': (100, {0: '\u0b66', 10: '\u0b67\u0b66', 99: '\u0b6f\u0b6f'}), + 'shn_MM': (100, {0: '\u1090\u1090', 10: '\u1091\u1090', 99: '\u1099\u1099'}), + 'ar_AE': (100, {0: '\u0660', 10: '\u0661\u0660', 99: '\u0669\u0669'}), + 'bn_IN': (100, {0: '\u09e6', 10: '\u09e7\u09e6', 99: '\u09ef\u09ef'}), +} + +known_era = { + 'C': (0, ''), + 'en_US': (0, ''), + 'ja_JP': (11, '+:1:2019/05/01:2019/12/31:令和:%EC元年'), + 'zh_TW': (3, '+:1:1912/01/01:1912/12/31:民國:%EC元年'), + 'th_TW': (1, '+:1:-543/01/01:+*:พ.ศ.:%EC %Ey'), +} + if sys.platform == 'win32': # ps_AF doesn't work on Windows: see bpo-38324 (msg361830) del known_numerics['ps_AF'] @@ -176,6 +200,80 @@ def test_lc_numeric_basic(self): if not tested: self.skipTest('no suitable locales') + @unittest.skipUnless(nl_langinfo, "nl_langinfo is not available") + @unittest.skipUnless(hasattr(locale, 'ALT_DIGITS'), "requires locale.ALT_DIGITS") + @unittest.skipIf( + support.is_emscripten or support.is_wasi, + "musl libc issue on Emscripten, bpo-46390" + ) + def test_alt_digits_nl_langinfo(self): + # Test nl_langinfo(ALT_DIGITS) + tested = False + for loc in candidate_locales: + with self.subTest(locale=loc): + try: + setlocale(LC_TIME, loc) + setlocale(LC_CTYPE, loc) + except Error: + self.skipTest(f'no locale {loc!r}') + continue + + with self.subTest(locale=loc): + alt_digits = nl_langinfo(locale.ALT_DIGITS) + self.assertIsInstance(alt_digits, str) + alt_digits = alt_digits.split(';') if alt_digits else [] + if alt_digits: + self.assertGreaterEqual(len(alt_digits), 10, alt_digits) + loc1 = loc.split('.', 1)[0] + if loc1 in known_alt_digits: + count, samples = known_alt_digits[loc1] + if count and not alt_digits: + self.skipTest(f'ALT_DIGITS is not set for locale {loc!r} on this platform') + self.assertEqual(len(alt_digits), count, alt_digits) + for i in samples: + self.assertEqual(alt_digits[i], samples[i]) + tested = True + if not tested: + self.skipTest('no suitable locales') + + @unittest.skipUnless(nl_langinfo, "nl_langinfo is not available") + @unittest.skipUnless(hasattr(locale, 'ERA'), "requires locale.ERA") + @unittest.skipIf( + support.is_emscripten or support.is_wasi, + "musl libc issue on Emscripten, bpo-46390" + ) + def test_era_nl_langinfo(self): + # Test nl_langinfo(ERA) + tested = False + for loc in candidate_locales: + with self.subTest(locale=loc): + try: + setlocale(LC_TIME, loc) + setlocale(LC_CTYPE, loc) + except Error: + self.skipTest(f'no locale {loc!r}') + continue + + with self.subTest(locale=loc): + era = nl_langinfo(locale.ERA) + self.assertIsInstance(era, str) + if era: + self.assertEqual(era.count(':'), (era.count(';') + 1) * 5, era) + + loc1 = loc.split('.', 1)[0] + if loc1 in known_era: + count, sample = known_era[loc1] + if count: + if not era: + self.skipTest(f'ERA is not set for locale {loc!r} on this platform') + self.assertGreaterEqual(era.count(';') + 1, count) + self.assertIn(sample, era) + else: + self.assertEqual(era, '') + tested = True + if not tested: + self.skipTest('no suitable locales') + def test_float_parsing(self): # Bug #1391872: Test whether float parsing is okay on European # locales. diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 940c93bc..01d2a9f2 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -15,7 +15,9 @@ import argparse import warnings +from enum import StrEnum from test.support import os_helper +from test.support.i18n_helper import TestTranslationsBase, update_translation_snapshots from unittest import mock @@ -280,16 +282,18 @@ def test_failures(self, tester): parser = self._get_parser(tester) for args_str in tester.failures: args = args_str.split() - with tester.assertRaises(ArgumentParserError, msg=args): - parser.parse_args(args) + with tester.subTest(args=args): + with tester.assertRaises(ArgumentParserError, msg=args): + parser.parse_args(args) def test_successes(self, tester): parser = self._get_parser(tester) for args, expected_ns in tester.successes: if isinstance(args, str): args = args.split() - result_ns = self._parse_args(parser, args) - tester.assertEqual(expected_ns, result_ns) + with tester.subTest(args=args): + result_ns = self._parse_args(parser, args) + tester.assertEqual(expected_ns, result_ns) # add tests for each combination of an optionals adding method # and an arg parsing method @@ -378,15 +382,22 @@ class TestOptionalsSingleDashAmbiguous(ParserTestCase): """Test Optionals that partially match but are not subsets""" argument_signatures = [Sig('-foobar'), Sig('-foorab')] - failures = ['-f', '-f a', '-fa', '-foa', '-foo', '-fo', '-foo b'] + failures = ['-f', '-f a', '-fa', '-foa', '-foo', '-fo', '-foo b', + '-f=a', '-foo=b'] successes = [ ('', NS(foobar=None, foorab=None)), ('-foob a', NS(foobar='a', foorab=None)), + ('-foob=a', NS(foobar='a', foorab=None)), ('-foor a', NS(foobar=None, foorab='a')), + ('-foor=a', NS(foobar=None, foorab='a')), ('-fooba a', NS(foobar='a', foorab=None)), + ('-fooba=a', NS(foobar='a', foorab=None)), ('-foora a', NS(foobar=None, foorab='a')), + ('-foora=a', NS(foobar=None, foorab='a')), ('-foobar a', NS(foobar='a', foorab=None)), + ('-foobar=a', NS(foobar='a', foorab=None)), ('-foorab a', NS(foobar=None, foorab='a')), + ('-foorab=a', NS(foobar=None, foorab='a')), ] @@ -677,7 +688,7 @@ class TestOptionalsChoices(ParserTestCase): argument_signatures = [ Sig('-f', choices='abc'), Sig('-g', type=int, choices=range(5))] - failures = ['a', '-f d', '-fad', '-ga', '-g 6'] + failures = ['a', '-f d', '-f ab', '-fad', '-ga', '-g 6'] successes = [ ('', NS(f=None, g=None)), ('-f a', NS(f='a', g=None)), @@ -916,7 +927,9 @@ class TestOptionalsAllowLongAbbreviation(ParserTestCase): successes = [ ('', NS(foo=None, foobaz=None, fooble=False)), ('--foo 7', NS(foo='7', foobaz=None, fooble=False)), + ('--foo=7', NS(foo='7', foobaz=None, fooble=False)), ('--fooba a', NS(foo=None, foobaz='a', fooble=False)), + ('--fooba=a', NS(foo=None, foobaz='a', fooble=False)), ('--foobl --foo g', NS(foo='g', foobaz=None, fooble=True)), ] @@ -955,6 +968,23 @@ class TestOptionalsDisallowLongAbbreviationPrefixChars(ParserTestCase): ] +class TestOptionalsDisallowSingleDashLongAbbreviation(ParserTestCase): + """Do not allow abbreviations of long options at all""" + + parser_signature = Sig(allow_abbrev=False) + argument_signatures = [ + Sig('-foo'), + Sig('-foodle', action='store_true'), + Sig('-foonly'), + ] + failures = ['-foon 3', '-food', '-food -foo 2'] + successes = [ + ('', NS(foo=None, foodle=False, foonly=None)), + ('-foo 3', NS(foo='3', foodle=False, foonly=None)), + ('-foonly 7 -foodle -foo 2', NS(foo='2', foodle=True, foonly='7')), + ] + + class TestDisallowLongAbbreviationAllowsShortGrouping(ParserTestCase): """Do not allow abbreviations of long options at all""" @@ -993,6 +1023,34 @@ class TestDisallowLongAbbreviationAllowsShortGroupingPrefix(ParserTestCase): ] +class TestStrEnumChoices(TestCase): + class Color(StrEnum): + RED = "red" + GREEN = "green" + BLUE = "blue" + + def test_parse_enum_value(self): + parser = argparse.ArgumentParser() + parser.add_argument('--color', choices=self.Color) + args = parser.parse_args(['--color', 'red']) + self.assertEqual(args.color, self.Color.RED) + + def test_help_message_contains_enum_choices(self): + parser = argparse.ArgumentParser() + parser.add_argument('--color', choices=self.Color, help='Choose a color') + self.assertIn('[--color {red,green,blue}]', parser.format_usage()) + self.assertIn(' --color {red,green,blue}', parser.format_help()) + + def test_invalid_enum_value_raises_error(self): + parser = argparse.ArgumentParser(exit_on_error=False) + parser.add_argument('--color', choices=self.Color) + self.assertRaisesRegex( + argparse.ArgumentError, + r"invalid choice: 'yellow' \(choose from red, green, blue\)", + parser.parse_args, + ['--color', 'yellow'], + ) + # ================ # Positional tests # ================ @@ -1132,57 +1190,87 @@ class TestPositionalsNargs2None(ParserTestCase): class TestPositionalsNargsNoneZeroOrMore(ParserTestCase): """Test a Positional with no nargs followed by one with unlimited""" - argument_signatures = [Sig('foo'), Sig('bar', nargs='*')] - failures = ['', '--foo'] + argument_signatures = [Sig('-x'), Sig('foo'), Sig('bar', nargs='*')] + failures = ['', '--foo', 'a b -x X c'] successes = [ - ('a', NS(foo='a', bar=[])), - ('a b', NS(foo='a', bar=['b'])), - ('a b c', NS(foo='a', bar=['b', 'c'])), + ('a', NS(x=None, foo='a', bar=[])), + ('a b', NS(x=None, foo='a', bar=['b'])), + ('a b c', NS(x=None, foo='a', bar=['b', 'c'])), + ('-x X a', NS(x='X', foo='a', bar=[])), + ('a -x X', NS(x='X', foo='a', bar=[])), + ('-x X a b', NS(x='X', foo='a', bar=['b'])), + ('a -x X b', NS(x='X', foo='a', bar=['b'])), + ('a b -x X', NS(x='X', foo='a', bar=['b'])), + ('-x X a b c', NS(x='X', foo='a', bar=['b', 'c'])), + ('a -x X b c', NS(x='X', foo='a', bar=['b', 'c'])), + ('a b c -x X', NS(x='X', foo='a', bar=['b', 'c'])), ] class TestPositionalsNargsNoneOneOrMore(ParserTestCase): """Test a Positional with no nargs followed by one with one or more""" - argument_signatures = [Sig('foo'), Sig('bar', nargs='+')] - failures = ['', '--foo', 'a'] + argument_signatures = [Sig('-x'), Sig('foo'), Sig('bar', nargs='+')] + failures = ['', '--foo', 'a', 'a b -x X c'] successes = [ - ('a b', NS(foo='a', bar=['b'])), - ('a b c', NS(foo='a', bar=['b', 'c'])), + ('a b', NS(x=None, foo='a', bar=['b'])), + ('a b c', NS(x=None, foo='a', bar=['b', 'c'])), + ('-x X a b', NS(x='X', foo='a', bar=['b'])), + ('a -x X b', NS(x='X', foo='a', bar=['b'])), + ('a b -x X', NS(x='X', foo='a', bar=['b'])), + ('-x X a b c', NS(x='X', foo='a', bar=['b', 'c'])), + ('a -x X b c', NS(x='X', foo='a', bar=['b', 'c'])), + ('a b c -x X', NS(x='X', foo='a', bar=['b', 'c'])), ] class TestPositionalsNargsNoneOptional(ParserTestCase): """Test a Positional with no nargs followed by one with an Optional""" - argument_signatures = [Sig('foo'), Sig('bar', nargs='?')] + argument_signatures = [Sig('-x'), Sig('foo'), Sig('bar', nargs='?')] failures = ['', '--foo', 'a b c'] successes = [ - ('a', NS(foo='a', bar=None)), - ('a b', NS(foo='a', bar='b')), + ('a', NS(x=None, foo='a', bar=None)), + ('a b', NS(x=None, foo='a', bar='b')), + ('-x X a', NS(x='X', foo='a', bar=None)), + ('a -x X', NS(x='X', foo='a', bar=None)), + ('-x X a b', NS(x='X', foo='a', bar='b')), + ('a -x X b', NS(x='X', foo='a', bar='b')), + ('a b -x X', NS(x='X', foo='a', bar='b')), ] class TestPositionalsNargsZeroOrMoreNone(ParserTestCase): """Test a Positional with unlimited nargs followed by one with none""" - argument_signatures = [Sig('foo', nargs='*'), Sig('bar')] - failures = ['', '--foo'] + argument_signatures = [Sig('-x'), Sig('foo', nargs='*'), Sig('bar')] + failures = ['', '--foo', 'a -x X b', 'a -x X b c', 'a b -x X c'] successes = [ - ('a', NS(foo=[], bar='a')), - ('a b', NS(foo=['a'], bar='b')), - ('a b c', NS(foo=['a', 'b'], bar='c')), + ('a', NS(x=None, foo=[], bar='a')), + ('a b', NS(x=None, foo=['a'], bar='b')), + ('a b c', NS(x=None, foo=['a', 'b'], bar='c')), + ('-x X a', NS(x='X', foo=[], bar='a')), + ('a -x X', NS(x='X', foo=[], bar='a')), + ('-x X a b', NS(x='X', foo=['a'], bar='b')), + ('a b -x X', NS(x='X', foo=['a'], bar='b')), + ('-x X a b c', NS(x='X', foo=['a', 'b'], bar='c')), + ('a b c -x X', NS(x='X', foo=['a', 'b'], bar='c')), ] class TestPositionalsNargsOneOrMoreNone(ParserTestCase): """Test a Positional with one or more nargs followed by one with none""" - argument_signatures = [Sig('foo', nargs='+'), Sig('bar')] - failures = ['', '--foo', 'a'] + argument_signatures = [Sig('-x'), Sig('foo', nargs='+'), Sig('bar')] + failures = ['', '--foo', 'a', 'a -x X b c', 'a b -x X c'] successes = [ - ('a b', NS(foo=['a'], bar='b')), - ('a b c', NS(foo=['a', 'b'], bar='c')), + ('a b', NS(x=None, foo=['a'], bar='b')), + ('a b c', NS(x=None, foo=['a', 'b'], bar='c')), + ('-x X a b', NS(x='X', foo=['a'], bar='b')), + ('a -x X b', NS(x='X', foo=['a'], bar='b')), + ('a b -x X', NS(x='X', foo=['a'], bar='b')), + ('-x X a b c', NS(x='X', foo=['a', 'b'], bar='c')), + ('a b c -x X', NS(x='X', foo=['a', 'b'], bar='c')), ] @@ -1267,14 +1355,21 @@ class TestPositionalsNargsNoneZeroOrMore1(ParserTestCase): """Test three Positionals: no nargs, unlimited nargs and 1 nargs""" argument_signatures = [ + Sig('-x'), Sig('foo'), Sig('bar', nargs='*'), Sig('baz', nargs=1), ] - failures = ['', '--foo', 'a'] + failures = ['', '--foo', 'a', 'a b -x X c'] successes = [ - ('a b', NS(foo='a', bar=[], baz=['b'])), - ('a b c', NS(foo='a', bar=['b'], baz=['c'])), + ('a b', NS(x=None, foo='a', bar=[], baz=['b'])), + ('a b c', NS(x=None, foo='a', bar=['b'], baz=['c'])), + ('-x X a b', NS(x='X', foo='a', bar=[], baz=['b'])), + ('a -x X b', NS(x='X', foo='a', bar=[], baz=['b'])), + ('a b -x X', NS(x='X', foo='a', bar=[], baz=['b'])), + ('-x X a b c', NS(x='X', foo='a', bar=['b'], baz=['c'])), + ('a -x X b c', NS(x='X', foo='a', bar=['b'], baz=['c'])), + ('a b c -x X', NS(x='X', foo='a', bar=['b'], baz=['c'])), ] @@ -1282,14 +1377,22 @@ class TestPositionalsNargsNoneOneOrMore1(ParserTestCase): """Test three Positionals: no nargs, one or more nargs and 1 nargs""" argument_signatures = [ + Sig('-x'), Sig('foo'), Sig('bar', nargs='+'), Sig('baz', nargs=1), ] - failures = ['', '--foo', 'a', 'b'] + failures = ['', '--foo', 'a', 'b', 'a b -x X c d', 'a b c -x X d'] successes = [ - ('a b c', NS(foo='a', bar=['b'], baz=['c'])), - ('a b c d', NS(foo='a', bar=['b', 'c'], baz=['d'])), + ('a b c', NS(x=None, foo='a', bar=['b'], baz=['c'])), + ('a b c d', NS(x=None, foo='a', bar=['b', 'c'], baz=['d'])), + ('-x X a b c', NS(x='X', foo='a', bar=['b'], baz=['c'])), + ('a -x X b c', NS(x='X', foo='a', bar=['b'], baz=['c'])), + ('a b -x X c', NS(x='X', foo='a', bar=['b'], baz=['c'])), + ('a b c -x X', NS(x='X', foo='a', bar=['b'], baz=['c'])), + ('-x X a b c d', NS(x='X', foo='a', bar=['b', 'c'], baz=['d'])), + ('a -x X b c d', NS(x='X', foo='a', bar=['b', 'c'], baz=['d'])), + ('a b c d -x X', NS(x='X', foo='a', bar=['b', 'c'], baz=['d'])), ] @@ -1297,14 +1400,21 @@ class TestPositionalsNargsNoneOptional1(ParserTestCase): """Test three Positionals: no nargs, optional narg and 1 nargs""" argument_signatures = [ + Sig('-x'), Sig('foo'), Sig('bar', nargs='?', default=0.625), Sig('baz', nargs=1), ] - failures = ['', '--foo', 'a'] + failures = ['', '--foo', 'a', 'a b -x X c'] successes = [ - ('a b', NS(foo='a', bar=0.625, baz=['b'])), - ('a b c', NS(foo='a', bar='b', baz=['c'])), + ('a b', NS(x=None, foo='a', bar=0.625, baz=['b'])), + ('a b c', NS(x=None, foo='a', bar='b', baz=['c'])), + ('-x X a b', NS(x='X', foo='a', bar=0.625, baz=['b'])), + ('a -x X b', NS(x='X', foo='a', bar=0.625, baz=['b'])), + ('a b -x X', NS(x='X', foo='a', bar=0.625, baz=['b'])), + ('-x X a b c', NS(x='X', foo='a', bar='b', baz=['c'])), + ('a -x X b c', NS(x='X', foo='a', bar='b', baz=['c'])), + ('a b c -x X', NS(x='X', foo='a', bar='b', baz=['c'])), ] @@ -1481,6 +1591,9 @@ class TestNargsRemainder(ParserTestCase): successes = [ ('X', NS(x='X', y=[], z=None)), ('-z Z X', NS(x='X', y=[], z='Z')), + ('-z Z X A B', NS(x='X', y=['A', 'B'], z='Z')), + ('X -z Z A B', NS(x='X', y=['-z', 'Z', 'A', 'B'], z=None)), + ('X A -z Z B', NS(x='X', y=['A', '-z', 'Z', 'B'], z=None)), ('X A B -z Z', NS(x='X', y=['A', 'B', '-z', 'Z'], z=None)), ('X Y --foo', NS(x='X', y=['Y', '--foo'], z=None)), ] @@ -1517,18 +1630,24 @@ class TestDefaultSuppress(ParserTestCase): """Test actions with suppressed defaults""" argument_signatures = [ - Sig('foo', nargs='?', default=argparse.SUPPRESS), - Sig('bar', nargs='*', default=argparse.SUPPRESS), + Sig('foo', nargs='?', type=int, default=argparse.SUPPRESS), + Sig('bar', nargs='*', type=int, default=argparse.SUPPRESS), Sig('--baz', action='store_true', default=argparse.SUPPRESS), + Sig('--qux', nargs='?', type=int, default=argparse.SUPPRESS), + Sig('--quux', nargs='*', type=int, default=argparse.SUPPRESS), ] - failures = ['-x'] + failures = ['-x', 'a', '1 a'] successes = [ ('', NS()), - ('a', NS(foo='a')), - ('a b', NS(foo='a', bar=['b'])), + ('1', NS(foo=1)), + ('1 2', NS(foo=1, bar=[2])), ('--baz', NS(baz=True)), - ('a --baz', NS(foo='a', baz=True)), - ('--baz a b', NS(foo='a', bar=['b'], baz=True)), + ('1 --baz', NS(foo=1, baz=True)), + ('--baz 1 2', NS(foo=1, bar=[2], baz=True)), + ('--qux', NS(qux=None)), + ('--qux 1', NS(qux=1)), + ('--quux', NS(quux=[])), + ('--quux 1 2', NS(quux=[1, 2])), ] @@ -2126,7 +2245,9 @@ def _get_parser(self, subparser_help=False, prefix_chars=None, else: subparsers_kwargs['help'] = 'command help' subparsers = parser.add_subparsers(**subparsers_kwargs) - self.assertArgumentParserError(parser.add_subparsers) + self.assertRaisesRegex(argparse.ArgumentError, + 'cannot have multiple subparser arguments', + parser.add_subparsers) # add first sub-parser parser1_kwargs = dict(description='1 description') @@ -2136,14 +2257,14 @@ def _get_parser(self, subparser_help=False, prefix_chars=None, parser1_kwargs['aliases'] = ['1alias1', '1alias2'] parser1 = subparsers.add_parser('1', **parser1_kwargs) parser1.add_argument('-w', type=int, help='w help') - parser1.add_argument('x', choices='abc', help='x help') + parser1.add_argument('x', choices=['a', 'b', 'c'], help='x help') # add second sub-parser parser2_kwargs = dict(description='2 description') if subparser_help: parser2_kwargs['help'] = '2 help' parser2 = subparsers.add_parser('2', **parser2_kwargs) - parser2.add_argument('-y', choices='123', help='y help') + parser2.add_argument('-y', choices=['1', '2', '3'], help='y help') parser2.add_argument('z', type=complex, nargs='*', help='z help') # add third sub-parser @@ -2210,6 +2331,40 @@ def test_parse_known_args(self): (NS(foo=False, bar=0.5, w=7, x='b'), ['-W', '-X', 'Y', 'Z']), ) + def test_parse_known_args_to_class_namespace(self): + class C: + pass + self.assertEqual( + self.parser.parse_known_args('0.5 1 b -w 7 -p'.split(), namespace=C), + (C, ['-p']), + ) + self.assertIs(C.foo, False) + self.assertEqual(C.bar, 0.5) + self.assertEqual(C.w, 7) + self.assertEqual(C.x, 'b') + + def test_abbreviation(self): + parser = ErrorRaisingArgumentParser() + parser.add_argument('--foodle') + parser.add_argument('--foonly') + subparsers = parser.add_subparsers() + parser1 = subparsers.add_parser('bar') + parser1.add_argument('--fo') + parser1.add_argument('--foonew') + + self.assertEqual(parser.parse_args(['--food', 'baz', 'bar']), + NS(foodle='baz', foonly=None, fo=None, foonew=None)) + self.assertEqual(parser.parse_args(['--foon', 'baz', 'bar']), + NS(foodle=None, foonly='baz', fo=None, foonew=None)) + self.assertArgumentParserError(parser.parse_args, ['--fo', 'baz', 'bar']) + self.assertEqual(parser.parse_args(['bar', '--fo', 'baz']), + NS(foodle=None, foonly=None, fo='baz', foonew=None)) + self.assertEqual(parser.parse_args(['bar', '--foo', 'baz']), + NS(foodle=None, foonly=None, fo=None, foonew='baz')) + self.assertEqual(parser.parse_args(['bar', '--foon', 'baz']), + NS(foodle=None, foonly=None, fo=None, foonew='baz')) + self.assertArgumentParserError(parser.parse_args, ['bar', '--food', 'baz']) + def test_parse_known_args_with_single_dash_option(self): parser = ErrorRaisingArgumentParser() parser.add_argument('-k', '--known', action='count', default=0) @@ -2297,7 +2452,7 @@ def test_wrong_argument_subparsers_no_destination_error(self): parser.parse_args(('baz',)) self.assertRegex( excinfo.exception.stderr, - r"error: argument {foo,bar}: invalid choice: 'baz' \(choose from 'foo', 'bar'\)\n$" + r"error: argument {foo,bar}: invalid choice: 'baz' \(choose from foo, bar\)\n$" ) def test_optional_subparsers(self): @@ -2755,6 +2910,35 @@ def test_groups_parents(self): -x X '''.format(progname, ' ' if progname else '' ))) + def test_mutex_groups_parents(self): + parent = ErrorRaisingArgumentParser(add_help=False) + g = parent.add_argument_group(title='g', description='gd') + g.add_argument('-w') + g.add_argument('-x') + m = g.add_mutually_exclusive_group() + m.add_argument('-y') + m.add_argument('-z') + parser = ErrorRaisingArgumentParser(prog='PROG', parents=[parent]) + + self.assertRaises(ArgumentParserError, parser.parse_args, + ['-y', 'Y', '-z', 'Z']) + + parser_help = parser.format_help() + self.assertEqual(parser_help, textwrap.dedent('''\ + usage: PROG [-h] [-w W] [-x X] [-y Y | -z Z] + + options: + -h, --help show this help message and exit + + g: + gd + + -w W + -x X + -y Y + -z Z + ''')) + # ============================== # Mutually exclusive group tests # ============================== @@ -2831,26 +3015,30 @@ def test_failures_when_not_required(self): parse_args = self.get_parser(required=False).parse_args error = ArgumentParserError for args_string in self.failures: - self.assertRaises(error, parse_args, args_string.split()) + with self.subTest(args=args_string): + self.assertRaises(error, parse_args, args_string.split()) def test_failures_when_required(self): parse_args = self.get_parser(required=True).parse_args error = ArgumentParserError for args_string in self.failures + ['']: - self.assertRaises(error, parse_args, args_string.split()) + with self.subTest(args=args_string): + self.assertRaises(error, parse_args, args_string.split()) def test_successes_when_not_required(self): parse_args = self.get_parser(required=False).parse_args successes = self.successes + self.successes_when_not_required for args_string, expected_ns in successes: - actual_ns = parse_args(args_string.split()) - self.assertEqual(actual_ns, expected_ns) + with self.subTest(args=args_string): + actual_ns = parse_args(args_string.split()) + self.assertEqual(actual_ns, expected_ns) def test_successes_when_required(self): parse_args = self.get_parser(required=True).parse_args for args_string, expected_ns in self.successes: - actual_ns = parse_args(args_string.split()) - self.assertEqual(actual_ns, expected_ns) + with self.subTest(args=args_string): + actual_ns = parse_args(args_string.split()) + self.assertEqual(actual_ns, expected_ns) def test_usage_when_not_required(self): format_usage = self.get_parser(required=False).format_usage @@ -3027,7 +3215,7 @@ def get_parser(self, required): group = parser.add_mutually_exclusive_group(required=required) group.add_argument('--foo', action='store_true', help='FOO') group.add_argument('--spam', help='SPAM') - group.add_argument('badger', nargs='*', default='X', help='BADGER') + group.add_argument('badger', nargs='*', help='BADGER') return parser failures = [ @@ -3038,13 +3226,13 @@ def get_parser(self, required): '--foo X Y', ] successes = [ - ('--foo', NS(foo=True, spam=None, badger='X')), - ('--spam S', NS(foo=False, spam='S', badger='X')), + ('--foo', NS(foo=True, spam=None, badger=[])), + ('--spam S', NS(foo=False, spam='S', badger=[])), ('X', NS(foo=False, spam=None, badger=['X'])), ('X Y Z', NS(foo=False, spam=None, badger=['X', 'Y', 'Z'])), ] successes_when_not_required = [ - ('', NS(foo=False, spam=None, badger='X')), + ('', NS(foo=False, spam=None, badger=[])), ] usage_when_not_required = '''\ @@ -3237,6 +3425,111 @@ def get_parser(self, required): test_successes_when_not_required = None test_successes_when_required = None + +class TestMutuallyExclusiveOptionalOptional(MEMixin, TestCase): + def get_parser(self, required=None): + parser = ErrorRaisingArgumentParser(prog='PROG') + group = parser.add_mutually_exclusive_group(required=required) + group.add_argument('--foo') + group.add_argument('--bar', nargs='?') + return parser + + failures = [ + '--foo X --bar Y', + '--foo X --bar', + ] + successes = [ + ('--foo X', NS(foo='X', bar=None)), + ('--bar X', NS(foo=None, bar='X')), + ('--bar', NS(foo=None, bar=None)), + ] + successes_when_not_required = [ + ('', NS(foo=None, bar=None)), + ] + usage_when_required = '''\ + usage: PROG [-h] (--foo FOO | --bar [BAR]) + ''' + usage_when_not_required = '''\ + usage: PROG [-h] [--foo FOO | --bar [BAR]] + ''' + help = '''\ + + options: + -h, --help show this help message and exit + --foo FOO + --bar [BAR] + ''' + + +class TestMutuallyExclusiveOptionalWithDefault(MEMixin, TestCase): + def get_parser(self, required=None): + parser = ErrorRaisingArgumentParser(prog='PROG') + group = parser.add_mutually_exclusive_group(required=required) + group.add_argument('--foo') + group.add_argument('--bar', type=bool, default=True) + return parser + + failures = [ + '--foo X --bar Y', + '--foo X --bar=', + ] + successes = [ + ('--foo X', NS(foo='X', bar=True)), + ('--bar X', NS(foo=None, bar=True)), + ('--bar=', NS(foo=None, bar=False)), + ] + successes_when_not_required = [ + ('', NS(foo=None, bar=True)), + ] + usage_when_required = '''\ + usage: PROG [-h] (--foo FOO | --bar BAR) + ''' + usage_when_not_required = '''\ + usage: PROG [-h] [--foo FOO | --bar BAR] + ''' + help = '''\ + + options: + -h, --help show this help message and exit + --foo FOO + --bar BAR + ''' + + +class TestMutuallyExclusivePositionalWithDefault(MEMixin, TestCase): + def get_parser(self, required=None): + parser = ErrorRaisingArgumentParser(prog='PROG') + group = parser.add_mutually_exclusive_group(required=required) + group.add_argument('--foo') + group.add_argument('bar', nargs='?', type=bool, default=True) + return parser + + failures = [ + '--foo X Y', + ] + successes = [ + ('--foo X', NS(foo='X', bar=True)), + ('X', NS(foo=None, bar=True)), + ] + successes_when_not_required = [ + ('', NS(foo=None, bar=True)), + ] + usage_when_required = '''\ + usage: PROG [-h] (--foo FOO | bar) + ''' + usage_when_not_required = '''\ + usage: PROG [-h] [--foo FOO | bar] + ''' + help = '''\ + + positional arguments: + bar + + options: + -h, --help show this help message and exit + --foo FOO + ''' + # ================================================= # Mutually exclusive group in parent parser tests # ================================================= @@ -4197,7 +4490,7 @@ class TestHelpVariableExpansion(HelpTestCase): help='x %(prog)s %(default)s %(type)s %%'), Sig('-y', action='store_const', default=42, const='XXX', help='y %(prog)s %(default)s %(const)s'), - Sig('--foo', choices='abc', + Sig('--foo', choices=['a', 'b', 'c'], help='foo %(prog)s %(default)s %(choices)s'), Sig('--bar', default='baz', choices=[1, 2], metavar='BBB', help='bar %(prog)s %(default)s %(dest)s'), @@ -4440,7 +4733,7 @@ class TestHelpNone(HelpTestCase): version = '' -class TestHelpTupleMetavar(HelpTestCase): +class TestHelpTupleMetavarOptional(HelpTestCase): """Test specifying metavar as a tuple""" parser_signature = Sig(prog='PROG') @@ -4467,6 +4760,34 @@ class TestHelpTupleMetavar(HelpTestCase): version = '' +class TestHelpTupleMetavarPositional(HelpTestCase): + """Test specifying metavar on a Positional as a tuple""" + + parser_signature = Sig(prog='PROG') + argument_signatures = [ + Sig('w', help='w help', nargs='+', metavar=('W1', 'W2')), + Sig('x', help='x help', nargs='*', metavar=('X1', 'X2')), + Sig('y', help='y help', nargs=3, metavar=('Y1', 'Y2', 'Y3')), + Sig('z', help='z help', nargs='?', metavar=('Z1',)), + ] + argument_group_signatures = [] + usage = '''\ + usage: PROG [-h] W1 [W2 ...] [X1 [X2 ...]] Y1 Y2 Y3 [Z1] + ''' + help = usage + '''\ + + positional arguments: + W1 W2 w help + X1 X2 x help + Y1 Y2 Y3 y help + Z1 z help + + options: + -h, --help show this help message and exit + ''' + version = '' + + class TestHelpRawText(HelpTestCase): """Test the RawTextHelpFormatter""" @@ -4760,6 +5081,46 @@ def custom_type(string): version = '' +class TestHelpUsageLongSubparserCommand(TestCase): + """Test that subparser commands are formatted correctly in help""" + maxDiff = None + + def test_parent_help(self): + def custom_formatter(prog): + return argparse.RawTextHelpFormatter(prog, max_help_position=50) + + parent_parser = argparse.ArgumentParser( + prog='PROG', + formatter_class=custom_formatter + ) + + cmd_subparsers = parent_parser.add_subparsers(title="commands", + metavar='CMD', + help='command to use') + cmd_subparsers.add_parser("add", + help="add something") + + cmd_subparsers.add_parser("remove", + help="remove something") + + cmd_subparsers.add_parser("a-very-long-command", + help="command that does something") + + parser_help = parent_parser.format_help() + self.assertEqual(parser_help, textwrap.dedent('''\ + usage: PROG [-h] CMD ... + + options: + -h, --help show this help message and exit + + commands: + CMD command to use + add add something + remove remove something + a-very-long-command command that does something + ''')) + + # ===================================== # Optional/Positional constructor tests # ===================================== @@ -4767,15 +5128,15 @@ def custom_type(string): class TestInvalidArgumentConstructors(TestCase): """Test a bunch of invalid Argument constructors""" - def assertTypeError(self, *args, **kwargs): + def assertTypeError(self, *args, errmsg=None, **kwargs): parser = argparse.ArgumentParser() - self.assertRaises(TypeError, parser.add_argument, - *args, **kwargs) + self.assertRaisesRegex(TypeError, errmsg, parser.add_argument, + *args, **kwargs) - def assertValueError(self, *args, **kwargs): + def assertValueError(self, *args, errmsg=None, **kwargs): parser = argparse.ArgumentParser() - self.assertRaises(ValueError, parser.add_argument, - *args, **kwargs) + self.assertRaisesRegex(ValueError, errmsg, parser.add_argument, + *args, **kwargs) def test_invalid_keyword_arguments(self): self.assertTypeError('-x', bar=None) @@ -4785,8 +5146,9 @@ def test_invalid_keyword_arguments(self): def test_missing_destination(self): self.assertTypeError() - for action in ['append', 'store']: - self.assertTypeError(action=action) + for action in ['store', 'append', 'extend']: + with self.subTest(action=action): + self.assertTypeError(action=action) def test_invalid_option_strings(self): self.assertValueError('--') @@ -4800,10 +5162,8 @@ def test_invalid_action(self): self.assertValueError('-x', action='foo') self.assertValueError('foo', action='baz') self.assertValueError('--foo', action=('store', 'append')) - parser = argparse.ArgumentParser() - with self.assertRaises(ValueError) as cm: - parser.add_argument("--foo", action="store-true") - self.assertIn('unknown action', str(cm.exception)) + self.assertValueError('--foo', action="store-true", + errmsg='unknown action') def test_multiple_dest(self): parser = argparse.ArgumentParser() @@ -4816,39 +5176,47 @@ def test_multiple_dest(self): def test_no_argument_actions(self): for action in ['store_const', 'store_true', 'store_false', 'append_const', 'count']: - for attrs in [dict(type=int), dict(nargs='+'), - dict(choices='ab')]: - self.assertTypeError('-x', action=action, **attrs) + with self.subTest(action=action): + for attrs in [dict(type=int), dict(nargs='+'), + dict(choices=['a', 'b'])]: + with self.subTest(attrs=attrs): + self.assertTypeError('-x', action=action, **attrs) + self.assertTypeError('x', action=action, **attrs) + self.assertTypeError('-x', action=action, nargs=0) + self.assertTypeError('x', action=action, nargs=0) def test_no_argument_no_const_actions(self): # options with zero arguments for action in ['store_true', 'store_false', 'count']: + with self.subTest(action=action): + # const is always disallowed + self.assertTypeError('-x', const='foo', action=action) - # const is always disallowed - self.assertTypeError('-x', const='foo', action=action) - - # nargs is always disallowed - self.assertTypeError('-x', nargs='*', action=action) + # nargs is always disallowed + self.assertTypeError('-x', nargs='*', action=action) def test_more_than_one_argument_actions(self): - for action in ['store', 'append']: - - # nargs=0 is disallowed - self.assertValueError('-x', nargs=0, action=action) - self.assertValueError('spam', nargs=0, action=action) - - # const is disallowed with non-optional arguments - for nargs in [1, '*', '+']: - self.assertValueError('-x', const='foo', - nargs=nargs, action=action) - self.assertValueError('spam', const='foo', - nargs=nargs, action=action) + for action in ['store', 'append', 'extend']: + with self.subTest(action=action): + # nargs=0 is disallowed + action_name = 'append' if action == 'extend' else action + self.assertValueError('-x', nargs=0, action=action, + errmsg=f'nargs for {action_name} actions must be != 0') + self.assertValueError('spam', nargs=0, action=action, + errmsg=f'nargs for {action_name} actions must be != 0') + + # const is disallowed with non-optional arguments + for nargs in [1, '*', '+']: + self.assertValueError('-x', const='foo', + nargs=nargs, action=action) + self.assertValueError('spam', const='foo', + nargs=nargs, action=action) def test_required_const_actions(self): for action in ['store_const', 'append_const']: - - # nargs is always disallowed - self.assertTypeError('-x', nargs='+', action=action) + with self.subTest(action=action): + # nargs is always disallowed + self.assertTypeError('-x', nargs='+', action=action) def test_parsers_action_missing_params(self): self.assertTypeError('command', action='parsers') @@ -5381,8 +5749,34 @@ def test_zero_or_more_optional(self): args = parser.parse_args([]) self.assertEqual(NS(x=[]), args) - def test_double_dash(self): - parser = argparse.ArgumentParser() + +class TestDoubleDash(TestCase): + def test_single_argument_option(self): + parser = argparse.ArgumentParser(exit_on_error=False) + parser.add_argument('-f', '--foo') + parser.add_argument('bar', nargs='*') + + args = parser.parse_args(['--foo=--']) + self.assertEqual(NS(foo='--', bar=[]), args) + self.assertRaisesRegex(argparse.ArgumentError, + 'argument -f/--foo: expected one argument', + parser.parse_args, ['--foo', '--']) + args = parser.parse_args(['-f--']) + self.assertEqual(NS(foo='--', bar=[]), args) + self.assertRaisesRegex(argparse.ArgumentError, + 'argument -f/--foo: expected one argument', + parser.parse_args, ['-f', '--']) + args = parser.parse_args(['--foo', 'a', '--', 'b', 'c']) + self.assertEqual(NS(foo='a', bar=['b', 'c']), args) + args = parser.parse_args(['a', 'b', '--foo', 'c']) + self.assertEqual(NS(foo='c', bar=['a', 'b']), args) + args = parser.parse_args(['a', '--', 'b', '--foo', 'c']) + self.assertEqual(NS(foo=None, bar=['a', 'b', '--foo', 'c']), args) + args = parser.parse_args(['a', '--', 'b', '--', 'c', '--foo', 'd']) + self.assertEqual(NS(foo=None, bar=['a', 'b', '--', 'c', '--foo', 'd']), args) + + def test_multiple_argument_option(self): + parser = argparse.ArgumentParser(exit_on_error=False) parser.add_argument('-f', '--foo', nargs='*') parser.add_argument('bar', nargs='*') @@ -5396,6 +5790,91 @@ def test_double_dash(self): self.assertEqual(NS(foo=[], bar=[]), args) args = parser.parse_args(['--foo', 'a', 'b', '--', 'c', 'd']) self.assertEqual(NS(foo=['a', 'b'], bar=['c', 'd']), args) + args = parser.parse_args(['a', 'b', '--foo', 'c', 'd']) + self.assertEqual(NS(foo=['c', 'd'], bar=['a', 'b']), args) + args = parser.parse_args(['a', '--', 'b', '--foo', 'c', 'd']) + self.assertEqual(NS(foo=None, bar=['a', 'b', '--foo', 'c', 'd']), args) + args, argv = parser.parse_known_args(['a', 'b', '--foo', 'c', '--', 'd']) + self.assertEqual(NS(foo=['c'], bar=['a', 'b']), args) + self.assertEqual(argv, ['--', 'd']) + + def test_multiple_double_dashes(self): + parser = argparse.ArgumentParser(exit_on_error=False) + parser.add_argument('foo') + parser.add_argument('bar', nargs='*') + + args = parser.parse_args(['--', 'a', 'b', 'c']) + self.assertEqual(NS(foo='a', bar=['b', 'c']), args) + args = parser.parse_args(['a', '--', 'b', 'c']) + self.assertEqual(NS(foo='a', bar=['b', 'c']), args) + args = parser.parse_args(['a', 'b', '--', 'c']) + self.assertEqual(NS(foo='a', bar=['b', 'c']), args) + args = parser.parse_args(['a', '--', 'b', '--', 'c']) + self.assertEqual(NS(foo='a', bar=['b', '--', 'c']), args) + args = parser.parse_args(['--', '--', 'a', '--', 'b', 'c']) + self.assertEqual(NS(foo='--', bar=['a', '--', 'b', 'c']), args) + + def test_remainder(self): + parser = argparse.ArgumentParser(exit_on_error=False) + parser.add_argument('foo') + parser.add_argument('bar', nargs='...') + + args = parser.parse_args(['--', 'a', 'b', 'c']) + self.assertEqual(NS(foo='a', bar=['b', 'c']), args) + args = parser.parse_args(['a', '--', 'b', 'c']) + self.assertEqual(NS(foo='a', bar=['b', 'c']), args) + args = parser.parse_args(['a', 'b', '--', 'c']) + self.assertEqual(NS(foo='a', bar=['b', '--', 'c']), args) + args = parser.parse_args(['a', '--', 'b', '--', 'c']) + self.assertEqual(NS(foo='a', bar=['b', '--', 'c']), args) + + parser = argparse.ArgumentParser(exit_on_error=False) + parser.add_argument('--foo') + parser.add_argument('bar', nargs='...') + args = parser.parse_args(['--foo', 'a', '--', 'b', '--', 'c']) + self.assertEqual(NS(foo='a', bar=['--', 'b', '--', 'c']), args) + + def test_subparser(self): + parser = argparse.ArgumentParser(exit_on_error=False) + parser.add_argument('foo') + subparsers = parser.add_subparsers() + parser1 = subparsers.add_parser('run') + parser1.add_argument('-f') + parser1.add_argument('bar', nargs='*') + + args = parser.parse_args(['x', 'run', 'a', 'b', '-f', 'c']) + self.assertEqual(NS(foo='x', f='c', bar=['a', 'b']), args) + args = parser.parse_args(['x', 'run', 'a', 'b', '--', '-f', 'c']) + self.assertEqual(NS(foo='x', f=None, bar=['a', 'b', '-f', 'c']), args) + args = parser.parse_args(['x', 'run', 'a', '--', 'b', '-f', 'c']) + self.assertEqual(NS(foo='x', f=None, bar=['a', 'b', '-f', 'c']), args) + args = parser.parse_args(['x', 'run', '--', 'a', 'b', '-f', 'c']) + self.assertEqual(NS(foo='x', f=None, bar=['a', 'b', '-f', 'c']), args) + args = parser.parse_args(['x', '--', 'run', 'a', 'b', '-f', 'c']) + self.assertEqual(NS(foo='x', f='c', bar=['a', 'b']), args) + args = parser.parse_args(['--', 'x', 'run', 'a', 'b', '-f', 'c']) + self.assertEqual(NS(foo='x', f='c', bar=['a', 'b']), args) + args = parser.parse_args(['x', 'run', '--', 'a', '--', 'b']) + self.assertEqual(NS(foo='x', f=None, bar=['a', '--', 'b']), args) + args = parser.parse_args(['x', '--', 'run', '--', 'a', '--', 'b']) + self.assertEqual(NS(foo='x', f=None, bar=['a', '--', 'b']), args) + self.assertRaisesRegex(argparse.ArgumentError, + "invalid choice: '--'", + parser.parse_args, ['--', 'x', '--', 'run', 'a', 'b']) + + def test_subparser_after_multiple_argument_option(self): + parser = argparse.ArgumentParser(exit_on_error=False) + parser.add_argument('--foo', nargs='*') + subparsers = parser.add_subparsers() + parser1 = subparsers.add_parser('run') + parser1.add_argument('-f') + parser1.add_argument('bar', nargs='*') + + args = parser.parse_args(['--foo', 'x', 'y', '--', 'run', 'a', 'b', '-f', 'c']) + self.assertEqual(NS(foo=['x', 'y'], f='c', bar=['a', 'b']), args) + self.assertRaisesRegex(argparse.ArgumentError, + "invalid choice: '--'", + parser.parse_args, ['--foo', 'x', '--', '--', 'run', 'a', 'b']) # =========================== @@ -5417,14 +5896,25 @@ def test_basic(self): args, extras = parser.parse_known_args(argv) # cannot parse the '1,2,3' - self.assertEqual(NS(bar='y', cmd='cmd', foo='x', rest=[]), args) - self.assertEqual(["1", "2", "3"], extras) + self.assertEqual(NS(bar='y', cmd='cmd', foo='x', rest=[1]), args) + self.assertEqual(["2", "3"], extras) + args, extras = parser.parse_known_intermixed_args(argv) + self.assertEqual(NS(bar='y', cmd='cmd', foo='x', rest=[1, 2, 3]), args) + self.assertEqual([], extras) + # unknown optionals go into extras + argv = 'cmd --foo x --error 1 2 --bar y 3'.split() + args, extras = parser.parse_known_intermixed_args(argv) + self.assertEqual(NS(bar='y', cmd='cmd', foo='x', rest=[1, 2, 3]), args) + self.assertEqual(['--error'], extras) argv = 'cmd --foo x 1 --error 2 --bar y 3'.split() args, extras = parser.parse_known_intermixed_args(argv) - # unknown optionals go into extras - self.assertEqual(NS(bar='y', cmd='cmd', foo='x', rest=[1]), args) - self.assertEqual(['--error', '2', '3'], extras) + self.assertEqual(NS(bar='y', cmd='cmd', foo='x', rest=[1, 2, 3]), args) + self.assertEqual(['--error'], extras) + argv = 'cmd --foo x 1 2 --error --bar y 3'.split() + args, extras = parser.parse_known_intermixed_args(argv) + self.assertEqual(NS(bar='y', cmd='cmd', foo='x', rest=[1, 2, 3]), args) + self.assertEqual(['--error'], extras) # restores attributes that were temporarily changed self.assertIsNone(parser.usage) @@ -5443,28 +5933,45 @@ def test_remainder(self): parser.parse_intermixed_args(argv) self.assertRegex(str(cm.exception), r'\.\.\.') - def test_exclusive(self): - # mutually exclusive group; intermixed works fine - parser = ErrorRaisingArgumentParser(prog='PROG') + def test_required_exclusive(self): + # required mutually exclusive group; intermixed works fine + parser = argparse.ArgumentParser(prog='PROG', exit_on_error=False) group = parser.add_mutually_exclusive_group(required=True) group.add_argument('--foo', action='store_true', help='FOO') group.add_argument('--spam', help='SPAM') parser.add_argument('badger', nargs='*', default='X', help='BADGER') + args = parser.parse_intermixed_args('--foo 1 2'.split()) + self.assertEqual(NS(badger=['1', '2'], foo=True, spam=None), args) args = parser.parse_intermixed_args('1 --foo 2'.split()) self.assertEqual(NS(badger=['1', '2'], foo=True, spam=None), args) - self.assertRaises(ArgumentParserError, parser.parse_intermixed_args, '1 2'.split()) + self.assertRaisesRegex(argparse.ArgumentError, + 'one of the arguments --foo --spam is required', + parser.parse_intermixed_args, '1 2'.split()) self.assertEqual(group.required, True) - def test_exclusive_incompatible(self): - # mutually exclusive group including positional - fail - parser = ErrorRaisingArgumentParser(prog='PROG') + def test_required_exclusive_with_positional(self): + # required mutually exclusive group with positional argument + parser = argparse.ArgumentParser(prog='PROG', exit_on_error=False) group = parser.add_mutually_exclusive_group(required=True) group.add_argument('--foo', action='store_true', help='FOO') group.add_argument('--spam', help='SPAM') group.add_argument('badger', nargs='*', default='X', help='BADGER') - self.assertRaises(TypeError, parser.parse_intermixed_args, []) + args = parser.parse_intermixed_args(['--foo']) + self.assertEqual(NS(foo=True, spam=None, badger='X'), args) + args = parser.parse_intermixed_args(['a', 'b']) + self.assertEqual(NS(foo=False, spam=None, badger=['a', 'b']), args) + self.assertRaisesRegex(argparse.ArgumentError, + 'one of the arguments --foo --spam badger is required', + parser.parse_intermixed_args, []) + self.assertRaisesRegex(argparse.ArgumentError, + 'argument badger: not allowed with argument --foo', + parser.parse_intermixed_args, ['--foo', 'a', 'b']) + self.assertRaisesRegex(argparse.ArgumentError, + 'argument badger: not allowed with argument --foo', + parser.parse_intermixed_args, ['a', '--foo', 'b']) self.assertEqual(group.required, True) + class TestIntermixedMessageContentError(TestCase): # case where Intermixed gives different error message # error is raised by 1st parsing step @@ -5482,7 +5989,7 @@ def test_missing_argument_name_in_message(self): with self.assertRaises(ArgumentParserError) as cm: parser.parse_intermixed_args([]) msg = str(cm.exception) - self.assertNotRegex(msg, 'req_pos') + self.assertRegex(msg, 'req_pos') self.assertRegex(msg, 'req_opt') # ========================== @@ -5732,7 +6239,8 @@ def test_help_with_metavar(self): class TestExitOnError(TestCase): def setUp(self): - self.parser = argparse.ArgumentParser(exit_on_error=False) + self.parser = argparse.ArgumentParser(exit_on_error=False, + fromfile_prefix_chars='@') self.parser.add_argument('--integers', metavar='N', type=int) def test_exit_on_error_with_good_args(self): @@ -5743,6 +6251,153 @@ def test_exit_on_error_with_bad_args(self): with self.assertRaises(argparse.ArgumentError): self.parser.parse_args('--integers a'.split()) + def test_unrecognized_args(self): + self.assertRaisesRegex(argparse.ArgumentError, + 'unrecognized arguments: --foo bar', + self.parser.parse_args, '--foo bar'.split()) + + def test_unrecognized_intermixed_args(self): + self.assertRaisesRegex(argparse.ArgumentError, + 'unrecognized arguments: --foo bar', + self.parser.parse_intermixed_args, '--foo bar'.split()) + + def test_required_args(self): + self.parser.add_argument('bar') + self.parser.add_argument('baz') + self.assertRaisesRegex(argparse.ArgumentError, + 'the following arguments are required: bar, baz$', + self.parser.parse_args, []) + + def test_required_args_with_metavar(self): + self.parser.add_argument('bar') + self.parser.add_argument('baz', metavar='BaZ') + self.assertRaisesRegex(argparse.ArgumentError, + 'the following arguments are required: bar, BaZ$', + self.parser.parse_args, []) + + def test_required_args_n(self): + self.parser.add_argument('bar') + self.parser.add_argument('baz', nargs=3) + self.assertRaisesRegex(argparse.ArgumentError, + 'the following arguments are required: bar, baz$', + self.parser.parse_args, []) + + def test_required_args_n_with_metavar(self): + self.parser.add_argument('bar') + self.parser.add_argument('baz', nargs=3, metavar=('B', 'A', 'Z')) + self.assertRaisesRegex(argparse.ArgumentError, + 'the following arguments are required: bar, B, A, Z$', + self.parser.parse_args, []) + + def test_required_args_optional(self): + self.parser.add_argument('bar') + self.parser.add_argument('baz', nargs='?') + self.assertRaisesRegex(argparse.ArgumentError, + 'the following arguments are required: bar$', + self.parser.parse_args, []) + + def test_required_args_zero_or_more(self): + self.parser.add_argument('bar') + self.parser.add_argument('baz', nargs='*') + self.assertRaisesRegex(argparse.ArgumentError, + 'the following arguments are required: bar$', + self.parser.parse_args, []) + + def test_required_args_one_or_more(self): + self.parser.add_argument('bar') + self.parser.add_argument('baz', nargs='+') + self.assertRaisesRegex(argparse.ArgumentError, + 'the following arguments are required: bar, baz$', + self.parser.parse_args, []) + + def test_required_args_one_or_more_with_metavar(self): + self.parser.add_argument('bar') + self.parser.add_argument('baz', nargs='+', metavar=('BaZ1', 'BaZ2')) + self.assertRaisesRegex(argparse.ArgumentError, + r'the following arguments are required: bar, BaZ1\[, BaZ2]$', + self.parser.parse_args, []) + + def test_required_args_remainder(self): + self.parser.add_argument('bar') + self.parser.add_argument('baz', nargs='...') + self.assertRaisesRegex(argparse.ArgumentError, + 'the following arguments are required: bar$', + self.parser.parse_args, []) + + def test_required_mutually_exclusive_args(self): + group = self.parser.add_mutually_exclusive_group(required=True) + group.add_argument('--bar') + group.add_argument('--baz') + self.assertRaisesRegex(argparse.ArgumentError, + 'one of the arguments --bar --baz is required', + self.parser.parse_args, []) + + def test_conflicting_mutually_exclusive_args_optional_with_metavar(self): + group = self.parser.add_mutually_exclusive_group() + group.add_argument('--bar') + group.add_argument('baz', nargs='?', metavar='BaZ') + self.assertRaisesRegex(argparse.ArgumentError, + 'argument BaZ: not allowed with argument --bar$', + self.parser.parse_args, ['--bar', 'a', 'b']) + self.assertRaisesRegex(argparse.ArgumentError, + 'argument --bar: not allowed with argument BaZ$', + self.parser.parse_args, ['a', '--bar', 'b']) + + def test_conflicting_mutually_exclusive_args_zero_or_more_with_metavar1(self): + group = self.parser.add_mutually_exclusive_group() + group.add_argument('--bar') + group.add_argument('baz', nargs='*', metavar=('BAZ1',)) + self.assertRaisesRegex(argparse.ArgumentError, + 'argument BAZ1: not allowed with argument --bar$', + self.parser.parse_args, ['--bar', 'a', 'b']) + self.assertRaisesRegex(argparse.ArgumentError, + 'argument --bar: not allowed with argument BAZ1$', + self.parser.parse_args, ['a', '--bar', 'b']) + + def test_conflicting_mutually_exclusive_args_zero_or_more_with_metavar2(self): + group = self.parser.add_mutually_exclusive_group() + group.add_argument('--bar') + group.add_argument('baz', nargs='*', metavar=('BAZ1', 'BAZ2')) + self.assertRaisesRegex(argparse.ArgumentError, + r'argument BAZ1\[, BAZ2]: not allowed with argument --bar$', + self.parser.parse_args, ['--bar', 'a', 'b']) + self.assertRaisesRegex(argparse.ArgumentError, + r'argument --bar: not allowed with argument BAZ1\[, BAZ2]$', + self.parser.parse_args, ['a', '--bar', 'b']) + + def test_ambiguous_option(self): + self.parser.add_argument('--foobaz') + self.parser.add_argument('--fooble', action='store_true') + self.parser.add_argument('--foogle') + self.assertRaisesRegex(argparse.ArgumentError, + "ambiguous option: --foob could match --foobaz, --fooble", + self.parser.parse_args, ['--foob']) + self.assertRaisesRegex(argparse.ArgumentError, + "ambiguous option: --foob=1 could match --foobaz, --fooble$", + self.parser.parse_args, ['--foob=1']) + self.assertRaisesRegex(argparse.ArgumentError, + "ambiguous option: --foob could match --foobaz, --fooble$", + self.parser.parse_args, ['--foob', '1', '--foogle', '2']) + self.assertRaisesRegex(argparse.ArgumentError, + "ambiguous option: --foob=1 could match --foobaz, --fooble$", + self.parser.parse_args, ['--foob=1', '--foogle', '2']) + + def test_os_error(self): + self.parser.add_argument('file') + self.assertRaisesRegex(argparse.ArgumentError, + "No such file or directory: 'no-such-file'", + self.parser.parse_args, ['@no-such-file']) + + +# ================= +# Translation tests +# ================= + +class TestTranslations(TestTranslationsBase): + + def test_translations(self): + self.assertMsgidsEqual(argparse) + def tearDownModule(): # Remove global references to avoid looking like we have refleaks. @@ -5751,4 +6406,8 @@ def tearDownModule(): if __name__ == '__main__': + # To regenerate translation snapshots + if len(sys.argv) > 1 and sys.argv[1] == '--snapshot-update': + update_translation_snapshots(argparse) + sys.exit(0) unittest.main() diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py index 5b2c107a..9c21cf03 100755 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -1437,7 +1437,7 @@ def test_byteswap(self): self.assertEqual(a, b) else: # On alphas treating the byte swapped bit patters as - # floats/doubles results in floating point exceptions + # floats/doubles results in floating-point exceptions # => compare the 8bit string values instead self.assertNotEqual(a.tobytes(), b.tobytes()) b.byteswap() diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py deleted file mode 100644 index a357fbfd..00000000 --- a/Lib/test/test_ast.py +++ /dev/null @@ -1,3078 +0,0 @@ -import ast -import builtins -import dis -import enum -import os -import re -import sys -import textwrap -import types -import unittest -import warnings -import weakref -from functools import partial -from textwrap import dedent - -from test import support -from test.support.import_helper import import_fresh_module -from test.support import os_helper, script_helper -from test.support.ast_helper import ASTTestMixin - -def to_tuple(t): - if t is None or isinstance(t, (str, int, complex)) or t is Ellipsis: - return t - elif isinstance(t, list): - return [to_tuple(e) for e in t] - result = [t.__class__.__name__] - if hasattr(t, 'lineno') and hasattr(t, 'col_offset'): - result.append((t.lineno, t.col_offset)) - if hasattr(t, 'end_lineno') and hasattr(t, 'end_col_offset'): - result[-1] += (t.end_lineno, t.end_col_offset) - if t._fields is None: - return tuple(result) - for f in t._fields: - result.append(to_tuple(getattr(t, f))) - return tuple(result) - - -# These tests are compiled through "exec" -# There should be at least one test per statement -exec_tests = [ - # None - "None", - # Module docstring - "'module docstring'", - # FunctionDef - "def f(): pass", - # FunctionDef with docstring - "def f(): 'function docstring'", - # FunctionDef with arg - "def f(a): pass", - # FunctionDef with arg and default value - "def f(a=0): pass", - # FunctionDef with varargs - "def f(*args): pass", - # FunctionDef with varargs as TypeVarTuple - "def f(*args: *Ts): pass", - # FunctionDef with varargs as unpacked Tuple - "def f(*args: *tuple[int, ...]): pass", - # FunctionDef with varargs as unpacked Tuple *and* TypeVarTuple - "def f(*args: *tuple[int, *Ts]): pass", - # FunctionDef with kwargs - "def f(**kwargs): pass", - # FunctionDef with all kind of args and docstring - "def f(a, b=1, c=None, d=[], e={}, *args, f=42, **kwargs): 'doc for f()'", - # FunctionDef with type annotation on return involving unpacking - "def f() -> tuple[*Ts]: pass", - "def f() -> tuple[int, *Ts]: pass", - "def f() -> tuple[int, *tuple[int, ...]]: pass", - # ClassDef - "class C:pass", - # ClassDef with docstring - "class C: 'docstring for class C'", - # ClassDef, new style class - "class C(object): pass", - # Return - "def f():return 1", - # Delete - "del v", - # Assign - "v = 1", - "a,b = c", - "(a,b) = c", - "[a,b] = c", - # AnnAssign with unpacked types - "x: tuple[*Ts]", - "x: tuple[int, *Ts]", - "x: tuple[int, *tuple[str, ...]]", - # AugAssign - "v += 1", - # For - "for v in v:pass", - # While - "while v:pass", - # If - "if v:pass", - # If-Elif - "if a:\n pass\nelif b:\n pass", - # If-Elif-Else - "if a:\n pass\nelif b:\n pass\nelse:\n pass", - # With - "with x as y: pass", - "with x as y, z as q: pass", - # Raise - "raise Exception('string')", - # TryExcept - "try:\n pass\nexcept Exception:\n pass", - # TryFinally - "try:\n pass\nfinally:\n pass", - # TryStarExcept - "try:\n pass\nexcept* Exception:\n pass", - # Assert - "assert v", - # Import - "import sys", - # ImportFrom - "from sys import v", - # Global - "global v", - # Expr - "1", - # Pass, - "pass", - # Break - "for v in v:break", - # Continue - "for v in v:continue", - # for statements with naked tuples (see http://bugs.python.org/issue6704) - "for a,b in c: pass", - "for (a,b) in c: pass", - "for [a,b] in c: pass", - # Multiline generator expression (test for .lineno & .col_offset) - """( - ( - Aa - , - Bb - ) - for - Aa - , - Bb in Cc - )""", - # dictcomp - "{a : b for w in x for m in p if g}", - # dictcomp with naked tuple - "{a : b for v,w in x}", - # setcomp - "{r for l in x if g}", - # setcomp with naked tuple - "{r for l,m in x}", - # AsyncFunctionDef - "async def f():\n 'async function'\n await something()", - # AsyncFor - "async def f():\n async for e in i: 1\n else: 2", - # AsyncWith - "async def f():\n async with a as b: 1", - # PEP 448: Additional Unpacking Generalizations - "{**{1:2}, 2:3}", - "{*{1, 2}, 3}", - # Asynchronous comprehensions - "async def f():\n [i async for b in c]", - # Decorated FunctionDef - "@deco1\n@deco2()\n@deco3(1)\ndef f(): pass", - # Decorated AsyncFunctionDef - "@deco1\n@deco2()\n@deco3(1)\nasync def f(): pass", - # Decorated ClassDef - "@deco1\n@deco2()\n@deco3(1)\nclass C: pass", - # Decorator with generator argument - "@deco(a for a in b)\ndef f(): pass", - # Decorator with attribute - "@a.b.c\ndef f(): pass", - # Simple assignment expression - "(a := 1)", - # Positional-only arguments - "def f(a, /,): pass", - "def f(a, /, c, d, e): pass", - "def f(a, /, c, *, d, e): pass", - "def f(a, /, c, *, d, e, **kwargs): pass", - # Positional-only arguments with defaults - "def f(a=1, /,): pass", - "def f(a=1, /, b=2, c=4): pass", - "def f(a=1, /, b=2, *, c=4): pass", - "def f(a=1, /, b=2, *, c): pass", - "def f(a=1, /, b=2, *, c=4, **kwargs): pass", - "def f(a=1, /, b=2, *, c, **kwargs): pass", - # Type aliases - "type X = int", - "type X[T] = int", - "type X[T, *Ts, **P] = (T, Ts, P)", - "type X[T: int, *Ts, **P] = (T, Ts, P)", - "type X[T: (int, str), *Ts, **P] = (T, Ts, P)", - # Generic classes - "class X[T]: pass", - "class X[T, *Ts, **P]: pass", - "class X[T: int, *Ts, **P]: pass", - "class X[T: (int, str), *Ts, **P]: pass", - # Generic functions - "def f[T](): pass", - "def f[T, *Ts, **P](): pass", - "def f[T: int, *Ts, **P](): pass", - "def f[T: (int, str), *Ts, **P](): pass", -] - -# These are compiled through "single" -# because of overlap with "eval", it just tests what -# can't be tested with "eval" -single_tests = [ - "1+2" -] - -# These are compiled through "eval" -# It should test all expressions -eval_tests = [ - # None - "None", - # BoolOp - "a and b", - # BinOp - "a + b", - # UnaryOp - "not v", - # Lambda - "lambda:None", - # Dict - "{ 1:2 }", - # Empty dict - "{}", - # Set - "{None,}", - # Multiline dict (test for .lineno & .col_offset) - """{ - 1 - : - 2 - }""", - # ListComp - "[a for b in c if d]", - # GeneratorExp - "(a for b in c if d)", - # Comprehensions with multiple for targets - "[(a,b) for a,b in c]", - "[(a,b) for (a,b) in c]", - "[(a,b) for [a,b] in c]", - "{(a,b) for a,b in c}", - "{(a,b) for (a,b) in c}", - "{(a,b) for [a,b] in c}", - "((a,b) for a,b in c)", - "((a,b) for (a,b) in c)", - "((a,b) for [a,b] in c)", - # Yield - yield expressions can't work outside a function - # - # Compare - "1 < 2 < 3", - # Call - "f(1,2,c=3,*d,**e)", - # Call with multi-character starred - "f(*[0, 1])", - # Call with a generator argument - "f(a for a in b)", - # Num - "10", - # Str - "'string'", - # Attribute - "a.b", - # Subscript - "a[b:c]", - # Name - "v", - # List - "[1,2,3]", - # Empty list - "[]", - # Tuple - "1,2,3", - # Tuple - "(1,2,3)", - # Empty tuple - "()", - # Combination - "a.b.c.d(a.b[1:2])", -] - -# TODO: expr_context, slice, boolop, operator, unaryop, cmpop, comprehension -# excepthandler, arguments, keywords, alias - -class AST_Tests(unittest.TestCase): - maxDiff = None - - def _is_ast_node(self, name, node): - if not isinstance(node, type): - return False - if "ast" not in node.__module__: - return False - return name != 'AST' and name[0].isupper() - - def _assertTrueorder(self, ast_node, parent_pos): - if not isinstance(ast_node, ast.AST) or ast_node._fields is None: - return - if isinstance(ast_node, (ast.expr, ast.stmt, ast.excepthandler)): - node_pos = (ast_node.lineno, ast_node.col_offset) - self.assertGreaterEqual(node_pos, parent_pos) - parent_pos = (ast_node.lineno, ast_node.col_offset) - for name in ast_node._fields: - value = getattr(ast_node, name) - if isinstance(value, list): - first_pos = parent_pos - if value and name == 'decorator_list': - first_pos = (value[0].lineno, value[0].col_offset) - for child in value: - self._assertTrueorder(child, first_pos) - elif value is not None: - self._assertTrueorder(value, parent_pos) - self.assertEqual(ast_node._fields, ast_node.__match_args__) - - def test_AST_objects(self): - x = ast.AST() - self.assertEqual(x._fields, ()) - x.foobar = 42 - self.assertEqual(x.foobar, 42) - self.assertEqual(x.__dict__["foobar"], 42) - - with self.assertRaises(AttributeError): - x.vararg - - with self.assertRaises(TypeError): - # "ast.AST constructor takes 0 positional arguments" - ast.AST(2) - - def test_AST_garbage_collection(self): - class X: - pass - a = ast.AST() - a.x = X() - a.x.a = a - ref = weakref.ref(a.x) - del a - support.gc_collect() - self.assertIsNone(ref()) - - def test_snippets(self): - for input, output, kind in ((exec_tests, exec_results, "exec"), - (single_tests, single_results, "single"), - (eval_tests, eval_results, "eval")): - for i, o in zip(input, output): - with self.subTest(action="parsing", input=i): - ast_tree = compile(i, "?", kind, ast.PyCF_ONLY_AST) - self.assertEqual(to_tuple(ast_tree), o) - self._assertTrueorder(ast_tree, (0, 0)) - with self.subTest(action="compiling", input=i, kind=kind): - compile(ast_tree, "?", kind) - - def test_ast_validation(self): - # compile() is the only function that calls PyAST_Validate - snippets_to_validate = exec_tests + single_tests + eval_tests - for snippet in snippets_to_validate: - tree = ast.parse(snippet) - compile(tree, '', 'exec') - - def test_invalid_position_information(self): - invalid_linenos = [ - (10, 1), (-10, -11), (10, -11), (-5, -2), (-5, 1) - ] - - for lineno, end_lineno in invalid_linenos: - with self.subTest(f"Check invalid linenos {lineno}:{end_lineno}"): - snippet = "a = 1" - tree = ast.parse(snippet) - tree.body[0].lineno = lineno - tree.body[0].end_lineno = end_lineno - with self.assertRaises(ValueError): - compile(tree, '', 'exec') - - invalid_col_offsets = [ - (10, 1), (-10, -11), (10, -11), (-5, -2), (-5, 1) - ] - for col_offset, end_col_offset in invalid_col_offsets: - with self.subTest(f"Check invalid col_offset {col_offset}:{end_col_offset}"): - snippet = "a = 1" - tree = ast.parse(snippet) - tree.body[0].col_offset = col_offset - tree.body[0].end_col_offset = end_col_offset - with self.assertRaises(ValueError): - compile(tree, '', 'exec') - - def test_compilation_of_ast_nodes_with_default_end_position_values(self): - tree = ast.Module(body=[ - ast.Import(names=[ast.alias(name='builtins', lineno=1, col_offset=0)], lineno=1, col_offset=0), - ast.Import(names=[ast.alias(name='traceback', lineno=0, col_offset=0)], lineno=0, col_offset=1) - ], type_ignores=[]) - - # Check that compilation doesn't crash. Note: this may crash explicitly only on debug mode. - compile(tree, "", "exec") - - def test_slice(self): - slc = ast.parse("x[::]").body[0].value.slice - self.assertIsNone(slc.upper) - self.assertIsNone(slc.lower) - self.assertIsNone(slc.step) - - def test_from_import(self): - im = ast.parse("from . import y").body[0] - self.assertIsNone(im.module) - - def test_non_interned_future_from_ast(self): - mod = ast.parse("from __future__ import division") - self.assertIsInstance(mod.body[0], ast.ImportFrom) - mod.body[0].module = " __future__ ".strip() - compile(mod, "", "exec") - - def test_alias(self): - im = ast.parse("from bar import y").body[0] - self.assertEqual(len(im.names), 1) - alias = im.names[0] - self.assertEqual(alias.name, 'y') - self.assertIsNone(alias.asname) - self.assertEqual(alias.lineno, 1) - self.assertEqual(alias.end_lineno, 1) - self.assertEqual(alias.col_offset, 16) - self.assertEqual(alias.end_col_offset, 17) - - im = ast.parse("from bar import *").body[0] - alias = im.names[0] - self.assertEqual(alias.name, '*') - self.assertIsNone(alias.asname) - self.assertEqual(alias.lineno, 1) - self.assertEqual(alias.end_lineno, 1) - self.assertEqual(alias.col_offset, 16) - self.assertEqual(alias.end_col_offset, 17) - - im = ast.parse("from bar import y as z").body[0] - alias = im.names[0] - self.assertEqual(alias.name, "y") - self.assertEqual(alias.asname, "z") - self.assertEqual(alias.lineno, 1) - self.assertEqual(alias.end_lineno, 1) - self.assertEqual(alias.col_offset, 16) - self.assertEqual(alias.end_col_offset, 22) - - im = ast.parse("import bar as foo").body[0] - alias = im.names[0] - self.assertEqual(alias.name, "bar") - self.assertEqual(alias.asname, "foo") - self.assertEqual(alias.lineno, 1) - self.assertEqual(alias.end_lineno, 1) - self.assertEqual(alias.col_offset, 7) - self.assertEqual(alias.end_col_offset, 17) - - def test_base_classes(self): - self.assertTrue(issubclass(ast.For, ast.stmt)) - self.assertTrue(issubclass(ast.Name, ast.expr)) - self.assertTrue(issubclass(ast.stmt, ast.AST)) - self.assertTrue(issubclass(ast.expr, ast.AST)) - self.assertTrue(issubclass(ast.comprehension, ast.AST)) - self.assertTrue(issubclass(ast.Gt, ast.AST)) - - def test_import_deprecated(self): - ast = import_fresh_module('ast') - depr_regex = ( - r'ast\.{} is deprecated and will be removed in Python 3.14; ' - r'use ast\.Constant instead' - ) - for name in 'Num', 'Str', 'Bytes', 'NameConstant', 'Ellipsis': - with self.assertWarnsRegex(DeprecationWarning, depr_regex.format(name)): - getattr(ast, name) - - def test_field_attr_existence_deprecated(self): - with warnings.catch_warnings(): - warnings.filterwarnings('ignore', '', DeprecationWarning) - from ast import Num, Str, Bytes, NameConstant, Ellipsis - - for name in ('Num', 'Str', 'Bytes', 'NameConstant', 'Ellipsis'): - item = getattr(ast, name) - if self._is_ast_node(name, item): - with self.subTest(item): - with self.assertWarns(DeprecationWarning): - x = item() - if isinstance(x, ast.AST): - self.assertIs(type(x._fields), tuple) - - def test_field_attr_existence(self): - for name, item in ast.__dict__.items(): - # These emit DeprecationWarnings - if name in {'Num', 'Str', 'Bytes', 'NameConstant', 'Ellipsis'}: - continue - # constructor has a different signature - if name == 'Index': - continue - if self._is_ast_node(name, item): - x = item() - if isinstance(x, ast.AST): - self.assertIs(type(x._fields), tuple) - - def test_arguments(self): - x = ast.arguments() - self.assertEqual(x._fields, ('posonlyargs', 'args', 'vararg', 'kwonlyargs', - 'kw_defaults', 'kwarg', 'defaults')) - - with self.assertRaises(AttributeError): - x.args - self.assertIsNone(x.vararg) - - x = ast.arguments(*range(1, 8)) - self.assertEqual(x.args, 2) - self.assertEqual(x.vararg, 3) - - def test_field_attr_writable_deprecated(self): - with warnings.catch_warnings(): - warnings.filterwarnings('ignore', '', DeprecationWarning) - x = ast.Num() - # We can assign to _fields - x._fields = 666 - self.assertEqual(x._fields, 666) - - def test_field_attr_writable(self): - x = ast.Constant() - # We can assign to _fields - x._fields = 666 - self.assertEqual(x._fields, 666) - - def test_classattrs_deprecated(self): - with warnings.catch_warnings(): - warnings.filterwarnings('ignore', '', DeprecationWarning) - from ast import Num, Str, Bytes, NameConstant, Ellipsis - - with warnings.catch_warnings(record=True) as wlog: - warnings.filterwarnings('always', '', DeprecationWarning) - x = ast.Num() - self.assertEqual(x._fields, ('value', 'kind')) - - with self.assertRaises(AttributeError): - x.value - - with self.assertRaises(AttributeError): - x.n - - x = ast.Num(42) - self.assertEqual(x.value, 42) - self.assertEqual(x.n, 42) - - with self.assertRaises(AttributeError): - x.lineno - - with self.assertRaises(AttributeError): - x.foobar - - x = ast.Num(lineno=2) - self.assertEqual(x.lineno, 2) - - x = ast.Num(42, lineno=0) - self.assertEqual(x.lineno, 0) - self.assertEqual(x._fields, ('value', 'kind')) - self.assertEqual(x.value, 42) - self.assertEqual(x.n, 42) - - self.assertRaises(TypeError, ast.Num, 1, None, 2) - self.assertRaises(TypeError, ast.Num, 1, None, 2, lineno=0) - - # Arbitrary keyword arguments are supported - self.assertEqual(ast.Num(1, foo='bar').foo, 'bar') - - with self.assertRaisesRegex(TypeError, "Num got multiple values for argument 'n'"): - ast.Num(1, n=2) - - self.assertEqual(ast.Num(42).n, 42) - self.assertEqual(ast.Num(4.25).n, 4.25) - self.assertEqual(ast.Num(4.25j).n, 4.25j) - self.assertEqual(ast.Str('42').s, '42') - self.assertEqual(ast.Bytes(b'42').s, b'42') - self.assertIs(ast.NameConstant(True).value, True) - self.assertIs(ast.NameConstant(False).value, False) - self.assertIs(ast.NameConstant(None).value, None) - - self.assertEqual([str(w.message) for w in wlog], [ - 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', - 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', - 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', - 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', - 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', - 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', - 'ast.Str is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'Attribute s is deprecated and will be removed in Python 3.14; use value instead', - 'ast.Bytes is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'Attribute s is deprecated and will be removed in Python 3.14; use value instead', - 'ast.NameConstant is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'ast.NameConstant is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'ast.NameConstant is deprecated and will be removed in Python 3.14; use ast.Constant instead', - ]) - - def test_classattrs(self): - x = ast.Constant() - self.assertEqual(x._fields, ('value', 'kind')) - - with self.assertRaises(AttributeError): - x.value - - x = ast.Constant(42) - self.assertEqual(x.value, 42) - - with self.assertRaises(AttributeError): - x.lineno - - with self.assertRaises(AttributeError): - x.foobar - - x = ast.Constant(lineno=2) - self.assertEqual(x.lineno, 2) - - x = ast.Constant(42, lineno=0) - self.assertEqual(x.lineno, 0) - self.assertEqual(x._fields, ('value', 'kind')) - self.assertEqual(x.value, 42) - - self.assertRaises(TypeError, ast.Constant, 1, None, 2) - self.assertRaises(TypeError, ast.Constant, 1, None, 2, lineno=0) - - # Arbitrary keyword arguments are supported - self.assertEqual(ast.Constant(1, foo='bar').foo, 'bar') - - with self.assertRaisesRegex(TypeError, "Constant got multiple values for argument 'value'"): - ast.Constant(1, value=2) - - self.assertEqual(ast.Constant(42).value, 42) - self.assertEqual(ast.Constant(4.25).value, 4.25) - self.assertEqual(ast.Constant(4.25j).value, 4.25j) - self.assertEqual(ast.Constant('42').value, '42') - self.assertEqual(ast.Constant(b'42').value, b'42') - self.assertIs(ast.Constant(True).value, True) - self.assertIs(ast.Constant(False).value, False) - self.assertIs(ast.Constant(None).value, None) - self.assertIs(ast.Constant(...).value, ...) - - def test_realtype(self): - with warnings.catch_warnings(): - warnings.filterwarnings('ignore', '', DeprecationWarning) - from ast import Num, Str, Bytes, NameConstant, Ellipsis - - with warnings.catch_warnings(record=True) as wlog: - warnings.filterwarnings('always', '', DeprecationWarning) - self.assertIs(type(ast.Num(42)), ast.Constant) - self.assertIs(type(ast.Num(4.25)), ast.Constant) - self.assertIs(type(ast.Num(4.25j)), ast.Constant) - self.assertIs(type(ast.Str('42')), ast.Constant) - self.assertIs(type(ast.Bytes(b'42')), ast.Constant) - self.assertIs(type(ast.NameConstant(True)), ast.Constant) - self.assertIs(type(ast.NameConstant(False)), ast.Constant) - self.assertIs(type(ast.NameConstant(None)), ast.Constant) - self.assertIs(type(ast.Ellipsis()), ast.Constant) - - self.assertEqual([str(w.message) for w in wlog], [ - 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'ast.Str is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'ast.Bytes is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'ast.NameConstant is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'ast.NameConstant is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'ast.NameConstant is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'ast.Ellipsis is deprecated and will be removed in Python 3.14; use ast.Constant instead', - ]) - - def test_isinstance(self): - from ast import Constant - - with warnings.catch_warnings(): - warnings.filterwarnings('ignore', '', DeprecationWarning) - from ast import Num, Str, Bytes, NameConstant, Ellipsis - - cls_depr_msg = ( - 'ast.{} is deprecated and will be removed in Python 3.14; ' - 'use ast.Constant instead' - ) - - assertNumDeprecated = partial( - self.assertWarnsRegex, DeprecationWarning, cls_depr_msg.format("Num") - ) - assertStrDeprecated = partial( - self.assertWarnsRegex, DeprecationWarning, cls_depr_msg.format("Str") - ) - assertBytesDeprecated = partial( - self.assertWarnsRegex, DeprecationWarning, cls_depr_msg.format("Bytes") - ) - assertNameConstantDeprecated = partial( - self.assertWarnsRegex, - DeprecationWarning, - cls_depr_msg.format("NameConstant") - ) - assertEllipsisDeprecated = partial( - self.assertWarnsRegex, DeprecationWarning, cls_depr_msg.format("Ellipsis") - ) - - for arg in 42, 4.2, 4.2j: - with self.subTest(arg=arg): - with assertNumDeprecated(): - n = Num(arg) - with assertNumDeprecated(): - self.assertIsInstance(n, Num) - - with assertStrDeprecated(): - s = Str('42') - with assertStrDeprecated(): - self.assertIsInstance(s, Str) - - with assertBytesDeprecated(): - b = Bytes(b'42') - with assertBytesDeprecated(): - self.assertIsInstance(b, Bytes) - - for arg in True, False, None: - with self.subTest(arg=arg): - with assertNameConstantDeprecated(): - n = NameConstant(arg) - with assertNameConstantDeprecated(): - self.assertIsInstance(n, NameConstant) - - with assertEllipsisDeprecated(): - e = Ellipsis() - with assertEllipsisDeprecated(): - self.assertIsInstance(e, Ellipsis) - - for arg in 42, 4.2, 4.2j: - with self.subTest(arg=arg): - with assertNumDeprecated(): - self.assertIsInstance(Constant(arg), Num) - - with assertStrDeprecated(): - self.assertIsInstance(Constant('42'), Str) - - with assertBytesDeprecated(): - self.assertIsInstance(Constant(b'42'), Bytes) - - for arg in True, False, None: - with self.subTest(arg=arg): - with assertNameConstantDeprecated(): - self.assertIsInstance(Constant(arg), NameConstant) - - with assertEllipsisDeprecated(): - self.assertIsInstance(Constant(...), Ellipsis) - - with assertStrDeprecated(): - s = Str('42') - assertNumDeprecated(self.assertNotIsInstance, s, Num) - assertBytesDeprecated(self.assertNotIsInstance, s, Bytes) - - with assertNumDeprecated(): - n = Num(42) - assertStrDeprecated(self.assertNotIsInstance, n, Str) - assertNameConstantDeprecated(self.assertNotIsInstance, n, NameConstant) - assertEllipsisDeprecated(self.assertNotIsInstance, n, Ellipsis) - - with assertNameConstantDeprecated(): - n = NameConstant(True) - with assertNumDeprecated(): - self.assertNotIsInstance(n, Num) - - with assertNameConstantDeprecated(): - n = NameConstant(False) - with assertNumDeprecated(): - self.assertNotIsInstance(n, Num) - - for arg in '42', True, False: - with self.subTest(arg=arg): - with assertNumDeprecated(): - self.assertNotIsInstance(Constant(arg), Num) - - assertStrDeprecated(self.assertNotIsInstance, Constant(42), Str) - assertBytesDeprecated(self.assertNotIsInstance, Constant('42'), Bytes) - assertNameConstantDeprecated(self.assertNotIsInstance, Constant(42), NameConstant) - assertEllipsisDeprecated(self.assertNotIsInstance, Constant(42), Ellipsis) - assertNumDeprecated(self.assertNotIsInstance, Constant(), Num) - assertStrDeprecated(self.assertNotIsInstance, Constant(), Str) - assertBytesDeprecated(self.assertNotIsInstance, Constant(), Bytes) - assertNameConstantDeprecated(self.assertNotIsInstance, Constant(), NameConstant) - assertEllipsisDeprecated(self.assertNotIsInstance, Constant(), Ellipsis) - - class S(str): pass - with assertStrDeprecated(): - self.assertIsInstance(Constant(S('42')), Str) - with assertNumDeprecated(): - self.assertNotIsInstance(Constant(S('42')), Num) - - def test_constant_subclasses_deprecated(self): - with warnings.catch_warnings(): - warnings.filterwarnings('ignore', '', DeprecationWarning) - from ast import Num - - with warnings.catch_warnings(record=True) as wlog: - warnings.filterwarnings('always', '', DeprecationWarning) - class N(ast.Num): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.z = 'spam' - class N2(ast.Num): - pass - - n = N(42) - self.assertEqual(n.n, 42) - self.assertEqual(n.z, 'spam') - self.assertIs(type(n), N) - self.assertIsInstance(n, N) - self.assertIsInstance(n, ast.Num) - self.assertNotIsInstance(n, N2) - self.assertNotIsInstance(ast.Num(42), N) - n = N(n=42) - self.assertEqual(n.n, 42) - self.assertIs(type(n), N) - - self.assertEqual([str(w.message) for w in wlog], [ - 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', - 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', - 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', - 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', - ]) - - def test_constant_subclasses(self): - class N(ast.Constant): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.z = 'spam' - class N2(ast.Constant): - pass - - n = N(42) - self.assertEqual(n.value, 42) - self.assertEqual(n.z, 'spam') - self.assertEqual(type(n), N) - self.assertTrue(isinstance(n, N)) - self.assertTrue(isinstance(n, ast.Constant)) - self.assertFalse(isinstance(n, N2)) - self.assertFalse(isinstance(ast.Constant(42), N)) - n = N(value=42) - self.assertEqual(n.value, 42) - self.assertEqual(type(n), N) - - def test_module(self): - body = [ast.Constant(42)] - x = ast.Module(body, []) - self.assertEqual(x.body, body) - - def test_nodeclasses(self): - # Zero arguments constructor explicitly allowed - x = ast.BinOp() - self.assertEqual(x._fields, ('left', 'op', 'right')) - - # Random attribute allowed too - x.foobarbaz = 5 - self.assertEqual(x.foobarbaz, 5) - - n1 = ast.Constant(1) - n3 = ast.Constant(3) - addop = ast.Add() - x = ast.BinOp(n1, addop, n3) - self.assertEqual(x.left, n1) - self.assertEqual(x.op, addop) - self.assertEqual(x.right, n3) - - x = ast.BinOp(1, 2, 3) - self.assertEqual(x.left, 1) - self.assertEqual(x.op, 2) - self.assertEqual(x.right, 3) - - x = ast.BinOp(1, 2, 3, lineno=0) - self.assertEqual(x.left, 1) - self.assertEqual(x.op, 2) - self.assertEqual(x.right, 3) - self.assertEqual(x.lineno, 0) - - # node raises exception when given too many arguments - self.assertRaises(TypeError, ast.BinOp, 1, 2, 3, 4) - # node raises exception when given too many arguments - self.assertRaises(TypeError, ast.BinOp, 1, 2, 3, 4, lineno=0) - - # can set attributes through kwargs too - x = ast.BinOp(left=1, op=2, right=3, lineno=0) - self.assertEqual(x.left, 1) - self.assertEqual(x.op, 2) - self.assertEqual(x.right, 3) - self.assertEqual(x.lineno, 0) - - # Random kwargs also allowed - x = ast.BinOp(1, 2, 3, foobarbaz=42) - self.assertEqual(x.foobarbaz, 42) - - def test_no_fields(self): - # this used to fail because Sub._fields was None - x = ast.Sub() - self.assertEqual(x._fields, ()) - - def test_pickling(self): - import pickle - - for protocol in range(pickle.HIGHEST_PROTOCOL + 1): - for ast in (compile(i, "?", "exec", 0x400) for i in exec_tests): - ast2 = pickle.loads(pickle.dumps(ast, protocol)) - self.assertEqual(to_tuple(ast2), to_tuple(ast)) - - def test_invalid_sum(self): - pos = dict(lineno=2, col_offset=3) - m = ast.Module([ast.Expr(ast.expr(**pos), **pos)], []) - with self.assertRaises(TypeError) as cm: - compile(m, "", "exec") - self.assertIn("but got ", "exec") - self.assertIn("identifier must be of type str", str(cm.exception)) - - def test_invalid_constant(self): - for invalid_constant in int, (1, 2, int), frozenset((1, 2, int)): - e = ast.Expression(body=ast.Constant(invalid_constant)) - ast.fix_missing_locations(e) - with self.assertRaisesRegex( - TypeError, "invalid type in Constant: type" - ): - compile(e, "", "eval") - - def test_empty_yield_from(self): - # Issue 16546: yield from value is not optional. - empty_yield_from = ast.parse("def f():\n yield from g()") - empty_yield_from.body[0].body[0].value.value = None - with self.assertRaises(ValueError) as cm: - compile(empty_yield_from, "", "exec") - self.assertIn("field 'value' is required", str(cm.exception)) - - @support.cpython_only - def test_issue31592(self): - # There shouldn't be an assertion failure in case of a bad - # unicodedata.normalize(). - import unicodedata - def bad_normalize(*args): - return None - with support.swap_attr(unicodedata, 'normalize', bad_normalize): - self.assertRaises(TypeError, ast.parse, '\u03D5') - - def test_issue18374_binop_col_offset(self): - tree = ast.parse('4+5+6+7') - parent_binop = tree.body[0].value - child_binop = parent_binop.left - grandchild_binop = child_binop.left - self.assertEqual(parent_binop.col_offset, 0) - self.assertEqual(parent_binop.end_col_offset, 7) - self.assertEqual(child_binop.col_offset, 0) - self.assertEqual(child_binop.end_col_offset, 5) - self.assertEqual(grandchild_binop.col_offset, 0) - self.assertEqual(grandchild_binop.end_col_offset, 3) - - tree = ast.parse('4+5-\\\n 6-7') - parent_binop = tree.body[0].value - child_binop = parent_binop.left - grandchild_binop = child_binop.left - self.assertEqual(parent_binop.col_offset, 0) - self.assertEqual(parent_binop.lineno, 1) - self.assertEqual(parent_binop.end_col_offset, 4) - self.assertEqual(parent_binop.end_lineno, 2) - - self.assertEqual(child_binop.col_offset, 0) - self.assertEqual(child_binop.lineno, 1) - self.assertEqual(child_binop.end_col_offset, 2) - self.assertEqual(child_binop.end_lineno, 2) - - self.assertEqual(grandchild_binop.col_offset, 0) - self.assertEqual(grandchild_binop.lineno, 1) - self.assertEqual(grandchild_binop.end_col_offset, 3) - self.assertEqual(grandchild_binop.end_lineno, 1) - - def test_issue39579_dotted_name_end_col_offset(self): - tree = ast.parse('@a.b.c\ndef f(): pass') - attr_b = tree.body[0].decorator_list[0].value - self.assertEqual(attr_b.end_col_offset, 4) - - def test_ast_asdl_signature(self): - self.assertEqual(ast.withitem.__doc__, "withitem(expr context_expr, expr? optional_vars)") - self.assertEqual(ast.GtE.__doc__, "GtE") - self.assertEqual(ast.Name.__doc__, "Name(identifier id, expr_context ctx)") - self.assertEqual(ast.cmpop.__doc__, "cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn") - expressions = [f" | {node.__doc__}" for node in ast.expr.__subclasses__()] - expressions[0] = f"expr = {ast.expr.__subclasses__()[0].__doc__}" - self.assertCountEqual(ast.expr.__doc__.split("\n"), expressions) - - def test_positional_only_feature_version(self): - ast.parse('def foo(x, /): ...', feature_version=(3, 8)) - ast.parse('def bar(x=1, /): ...', feature_version=(3, 8)) - with self.assertRaises(SyntaxError): - ast.parse('def foo(x, /): ...', feature_version=(3, 7)) - with self.assertRaises(SyntaxError): - ast.parse('def bar(x=1, /): ...', feature_version=(3, 7)) - - ast.parse('lambda x, /: ...', feature_version=(3, 8)) - ast.parse('lambda x=1, /: ...', feature_version=(3, 8)) - with self.assertRaises(SyntaxError): - ast.parse('lambda x, /: ...', feature_version=(3, 7)) - with self.assertRaises(SyntaxError): - ast.parse('lambda x=1, /: ...', feature_version=(3, 7)) - - def test_assignment_expression_feature_version(self): - ast.parse('(x := 0)', feature_version=(3, 8)) - with self.assertRaises(SyntaxError): - ast.parse('(x := 0)', feature_version=(3, 7)) - - def test_conditional_context_managers_parse_with_low_feature_version(self): - # regression test for gh-115881 - ast.parse('with (x() if y else z()): ...', feature_version=(3, 8)) - - def test_exception_groups_feature_version(self): - code = dedent(''' - try: ... - except* Exception: ... - ''') - ast.parse(code) - with self.assertRaises(SyntaxError): - ast.parse(code, feature_version=(3, 10)) - - def test_type_params_feature_version(self): - samples = [ - "type X = int", - "class X[T]: pass", - "def f[T](): pass", - ] - for sample in samples: - with self.subTest(sample): - ast.parse(sample) - with self.assertRaises(SyntaxError): - ast.parse(sample, feature_version=(3, 11)) - - def test_invalid_major_feature_version(self): - with self.assertRaises(ValueError): - ast.parse('pass', feature_version=(2, 7)) - with self.assertRaises(ValueError): - ast.parse('pass', feature_version=(4, 0)) - - def test_constant_as_name(self): - for constant in "True", "False", "None": - expr = ast.Expression(ast.Name(constant, ast.Load())) - ast.fix_missing_locations(expr) - with self.assertRaisesRegex(ValueError, f"identifier field can't represent '{constant}' constant"): - compile(expr, "", "eval") - - def test_precedence_enum(self): - class _Precedence(enum.IntEnum): - """Precedence table that originated from python grammar.""" - NAMED_EXPR = enum.auto() # := - TUPLE = enum.auto() # , - YIELD = enum.auto() # 'yield', 'yield from' - TEST = enum.auto() # 'if'-'else', 'lambda' - OR = enum.auto() # 'or' - AND = enum.auto() # 'and' - NOT = enum.auto() # 'not' - CMP = enum.auto() # '<', '>', '==', '>=', '<=', '!=', - # 'in', 'not in', 'is', 'is not' - EXPR = enum.auto() - BOR = EXPR # '|' - BXOR = enum.auto() # '^' - BAND = enum.auto() # '&' - SHIFT = enum.auto() # '<<', '>>' - ARITH = enum.auto() # '+', '-' - TERM = enum.auto() # '*', '@', '/', '%', '//' - FACTOR = enum.auto() # unary '+', '-', '~' - POWER = enum.auto() # '**' - AWAIT = enum.auto() # 'await' - ATOM = enum.auto() - def next(self): - try: - return self.__class__(self + 1) - except ValueError: - return self - enum._test_simple_enum(_Precedence, ast._Precedence) - - @unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI") - @support.cpython_only - def test_ast_recursion_limit(self): - fail_depth = support.C_RECURSION_LIMIT + 1 - crash_depth = 100_000 - success_depth = int(support.C_RECURSION_LIMIT * 0.9) - - def check_limit(prefix, repeated): - expect_ok = prefix + repeated * success_depth - ast.parse(expect_ok) - for depth in (fail_depth, crash_depth): - broken = prefix + repeated * depth - details = "Compiling ({!r} + {!r} * {})".format( - prefix, repeated, depth) - with self.assertRaises(RecursionError, msg=details): - with support.infinite_recursion(): - ast.parse(broken) - - check_limit("a", "()") - check_limit("a", ".b") - check_limit("a", "[0]") - check_limit("a", "*a") - - def test_null_bytes(self): - with self.assertRaises(SyntaxError, - msg="source code string cannot contain null bytes"): - ast.parse("a\0b") - - def assert_none_check(self, node: type[ast.AST], attr: str, source: str) -> None: - with self.subTest(f"{node.__name__}.{attr}"): - tree = ast.parse(source) - found = 0 - for child in ast.walk(tree): - if isinstance(child, node): - setattr(child, attr, None) - found += 1 - self.assertEqual(found, 1) - e = re.escape(f"field '{attr}' is required for {node.__name__}") - with self.assertRaisesRegex(ValueError, f"^{e}$"): - compile(tree, "", "exec") - - def test_none_checks(self) -> None: - tests = [ - (ast.alias, "name", "import spam as SPAM"), - (ast.arg, "arg", "def spam(SPAM): spam"), - (ast.comprehension, "target", "[spam for SPAM in spam]"), - (ast.comprehension, "iter", "[spam for spam in SPAM]"), - (ast.keyword, "value", "spam(**SPAM)"), - (ast.match_case, "pattern", "match spam:\n case SPAM: spam"), - (ast.withitem, "context_expr", "with SPAM: spam"), - ] - for node, attr, source in tests: - self.assert_none_check(node, attr, source) - -class ASTHelpers_Test(unittest.TestCase): - maxDiff = None - - def test_parse(self): - a = ast.parse('foo(1 + 1)') - b = compile('foo(1 + 1)', '', 'exec', ast.PyCF_ONLY_AST) - self.assertEqual(ast.dump(a), ast.dump(b)) - - def test_parse_in_error(self): - try: - 1/0 - except Exception: - with self.assertRaises(SyntaxError) as e: - ast.literal_eval(r"'\U'") - self.assertIsNotNone(e.exception.__context__) - - def test_dump(self): - node = ast.parse('spam(eggs, "and cheese")') - self.assertEqual(ast.dump(node), - "Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load()), " - "args=[Name(id='eggs', ctx=Load()), Constant(value='and cheese')], " - "keywords=[]))], type_ignores=[])" - ) - self.assertEqual(ast.dump(node, annotate_fields=False), - "Module([Expr(Call(Name('spam', Load()), [Name('eggs', Load()), " - "Constant('and cheese')], []))], [])" - ) - self.assertEqual(ast.dump(node, include_attributes=True), - "Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load(), " - "lineno=1, col_offset=0, end_lineno=1, end_col_offset=4), " - "args=[Name(id='eggs', ctx=Load(), lineno=1, col_offset=5, " - "end_lineno=1, end_col_offset=9), Constant(value='and cheese', " - "lineno=1, col_offset=11, end_lineno=1, end_col_offset=23)], keywords=[], " - "lineno=1, col_offset=0, end_lineno=1, end_col_offset=24), " - "lineno=1, col_offset=0, end_lineno=1, end_col_offset=24)], type_ignores=[])" - ) - - def test_dump_indent(self): - node = ast.parse('spam(eggs, "and cheese")') - self.assertEqual(ast.dump(node, indent=3), """\ -Module( - body=[ - Expr( - value=Call( - func=Name(id='spam', ctx=Load()), - args=[ - Name(id='eggs', ctx=Load()), - Constant(value='and cheese')], - keywords=[]))], - type_ignores=[])""") - self.assertEqual(ast.dump(node, annotate_fields=False, indent='\t'), """\ -Module( -\t[ -\t\tExpr( -\t\t\tCall( -\t\t\t\tName('spam', Load()), -\t\t\t\t[ -\t\t\t\t\tName('eggs', Load()), -\t\t\t\t\tConstant('and cheese')], -\t\t\t\t[]))], -\t[])""") - self.assertEqual(ast.dump(node, include_attributes=True, indent=3), """\ -Module( - body=[ - Expr( - value=Call( - func=Name( - id='spam', - ctx=Load(), - lineno=1, - col_offset=0, - end_lineno=1, - end_col_offset=4), - args=[ - Name( - id='eggs', - ctx=Load(), - lineno=1, - col_offset=5, - end_lineno=1, - end_col_offset=9), - Constant( - value='and cheese', - lineno=1, - col_offset=11, - end_lineno=1, - end_col_offset=23)], - keywords=[], - lineno=1, - col_offset=0, - end_lineno=1, - end_col_offset=24), - lineno=1, - col_offset=0, - end_lineno=1, - end_col_offset=24)], - type_ignores=[])""") - - def test_dump_incomplete(self): - node = ast.Raise(lineno=3, col_offset=4) - self.assertEqual(ast.dump(node), - "Raise()" - ) - self.assertEqual(ast.dump(node, include_attributes=True), - "Raise(lineno=3, col_offset=4)" - ) - node = ast.Raise(exc=ast.Name(id='e', ctx=ast.Load()), lineno=3, col_offset=4) - self.assertEqual(ast.dump(node), - "Raise(exc=Name(id='e', ctx=Load()))" - ) - self.assertEqual(ast.dump(node, annotate_fields=False), - "Raise(Name('e', Load()))" - ) - self.assertEqual(ast.dump(node, include_attributes=True), - "Raise(exc=Name(id='e', ctx=Load()), lineno=3, col_offset=4)" - ) - self.assertEqual(ast.dump(node, annotate_fields=False, include_attributes=True), - "Raise(Name('e', Load()), lineno=3, col_offset=4)" - ) - node = ast.Raise(cause=ast.Name(id='e', ctx=ast.Load())) - self.assertEqual(ast.dump(node), - "Raise(cause=Name(id='e', ctx=Load()))" - ) - self.assertEqual(ast.dump(node, annotate_fields=False), - "Raise(cause=Name('e', Load()))" - ) - - def test_copy_location(self): - src = ast.parse('1 + 1', mode='eval') - src.body.right = ast.copy_location(ast.Constant(2), src.body.right) - self.assertEqual(ast.dump(src, include_attributes=True), - 'Expression(body=BinOp(left=Constant(value=1, lineno=1, col_offset=0, ' - 'end_lineno=1, end_col_offset=1), op=Add(), right=Constant(value=2, ' - 'lineno=1, col_offset=4, end_lineno=1, end_col_offset=5), lineno=1, ' - 'col_offset=0, end_lineno=1, end_col_offset=5))' - ) - src = ast.Call(col_offset=1, lineno=1, end_lineno=1, end_col_offset=1) - new = ast.copy_location(src, ast.Call(col_offset=None, lineno=None)) - self.assertIsNone(new.end_lineno) - self.assertIsNone(new.end_col_offset) - self.assertEqual(new.lineno, 1) - self.assertEqual(new.col_offset, 1) - - def test_fix_missing_locations(self): - src = ast.parse('write("spam")') - src.body.append(ast.Expr(ast.Call(ast.Name('spam', ast.Load()), - [ast.Constant('eggs')], []))) - self.assertEqual(src, ast.fix_missing_locations(src)) - self.maxDiff = None - self.assertEqual(ast.dump(src, include_attributes=True), - "Module(body=[Expr(value=Call(func=Name(id='write', ctx=Load(), " - "lineno=1, col_offset=0, end_lineno=1, end_col_offset=5), " - "args=[Constant(value='spam', lineno=1, col_offset=6, end_lineno=1, " - "end_col_offset=12)], keywords=[], lineno=1, col_offset=0, end_lineno=1, " - "end_col_offset=13), lineno=1, col_offset=0, end_lineno=1, " - "end_col_offset=13), Expr(value=Call(func=Name(id='spam', ctx=Load(), " - "lineno=1, col_offset=0, end_lineno=1, end_col_offset=0), " - "args=[Constant(value='eggs', lineno=1, col_offset=0, end_lineno=1, " - "end_col_offset=0)], keywords=[], lineno=1, col_offset=0, end_lineno=1, " - "end_col_offset=0), lineno=1, col_offset=0, end_lineno=1, end_col_offset=0)], " - "type_ignores=[])" - ) - - def test_increment_lineno(self): - src = ast.parse('1 + 1', mode='eval') - self.assertEqual(ast.increment_lineno(src, n=3), src) - self.assertEqual(ast.dump(src, include_attributes=True), - 'Expression(body=BinOp(left=Constant(value=1, lineno=4, col_offset=0, ' - 'end_lineno=4, end_col_offset=1), op=Add(), right=Constant(value=1, ' - 'lineno=4, col_offset=4, end_lineno=4, end_col_offset=5), lineno=4, ' - 'col_offset=0, end_lineno=4, end_col_offset=5))' - ) - # issue10869: do not increment lineno of root twice - src = ast.parse('1 + 1', mode='eval') - self.assertEqual(ast.increment_lineno(src.body, n=3), src.body) - self.assertEqual(ast.dump(src, include_attributes=True), - 'Expression(body=BinOp(left=Constant(value=1, lineno=4, col_offset=0, ' - 'end_lineno=4, end_col_offset=1), op=Add(), right=Constant(value=1, ' - 'lineno=4, col_offset=4, end_lineno=4, end_col_offset=5), lineno=4, ' - 'col_offset=0, end_lineno=4, end_col_offset=5))' - ) - src = ast.Call( - func=ast.Name("test", ast.Load()), args=[], keywords=[], lineno=1 - ) - self.assertEqual(ast.increment_lineno(src).lineno, 2) - self.assertIsNone(ast.increment_lineno(src).end_lineno) - - def test_increment_lineno_on_module(self): - src = ast.parse(dedent("""\ - a = 1 - b = 2 # type: ignore - c = 3 - d = 4 # type: ignore@tag - """), type_comments=True) - ast.increment_lineno(src, n=5) - self.assertEqual(src.type_ignores[0].lineno, 7) - self.assertEqual(src.type_ignores[1].lineno, 9) - self.assertEqual(src.type_ignores[1].tag, '@tag') - - def test_iter_fields(self): - node = ast.parse('foo()', mode='eval') - d = dict(ast.iter_fields(node.body)) - self.assertEqual(d.pop('func').id, 'foo') - self.assertEqual(d, {'keywords': [], 'args': []}) - - def test_iter_child_nodes(self): - node = ast.parse("spam(23, 42, eggs='leek')", mode='eval') - self.assertEqual(len(list(ast.iter_child_nodes(node.body))), 4) - iterator = ast.iter_child_nodes(node.body) - self.assertEqual(next(iterator).id, 'spam') - self.assertEqual(next(iterator).value, 23) - self.assertEqual(next(iterator).value, 42) - self.assertEqual(ast.dump(next(iterator)), - "keyword(arg='eggs', value=Constant(value='leek'))" - ) - - def test_get_docstring(self): - node = ast.parse('"""line one\n line two"""') - self.assertEqual(ast.get_docstring(node), - 'line one\nline two') - - node = ast.parse('class foo:\n """line one\n line two"""') - self.assertEqual(ast.get_docstring(node.body[0]), - 'line one\nline two') - - node = ast.parse('def foo():\n """line one\n line two"""') - self.assertEqual(ast.get_docstring(node.body[0]), - 'line one\nline two') - - node = ast.parse('async def foo():\n """spam\n ham"""') - self.assertEqual(ast.get_docstring(node.body[0]), 'spam\nham') - - def test_get_docstring_none(self): - self.assertIsNone(ast.get_docstring(ast.parse(''))) - node = ast.parse('x = "not docstring"') - self.assertIsNone(ast.get_docstring(node)) - node = ast.parse('def foo():\n pass') - self.assertIsNone(ast.get_docstring(node)) - - node = ast.parse('class foo:\n pass') - self.assertIsNone(ast.get_docstring(node.body[0])) - node = ast.parse('class foo:\n x = "not docstring"') - self.assertIsNone(ast.get_docstring(node.body[0])) - node = ast.parse('class foo:\n def bar(self): pass') - self.assertIsNone(ast.get_docstring(node.body[0])) - - node = ast.parse('def foo():\n pass') - self.assertIsNone(ast.get_docstring(node.body[0])) - node = ast.parse('def foo():\n x = "not docstring"') - self.assertIsNone(ast.get_docstring(node.body[0])) - - node = ast.parse('async def foo():\n pass') - self.assertIsNone(ast.get_docstring(node.body[0])) - node = ast.parse('async def foo():\n x = "not docstring"') - self.assertIsNone(ast.get_docstring(node.body[0])) - - def test_multi_line_docstring_col_offset_and_lineno_issue16806(self): - node = ast.parse( - '"""line one\nline two"""\n\n' - 'def foo():\n """line one\n line two"""\n\n' - ' def bar():\n """line one\n line two"""\n' - ' """line one\n line two"""\n' - '"""line one\nline two"""\n\n' - ) - self.assertEqual(node.body[0].col_offset, 0) - self.assertEqual(node.body[0].lineno, 1) - self.assertEqual(node.body[1].body[0].col_offset, 2) - self.assertEqual(node.body[1].body[0].lineno, 5) - self.assertEqual(node.body[1].body[1].body[0].col_offset, 4) - self.assertEqual(node.body[1].body[1].body[0].lineno, 9) - self.assertEqual(node.body[1].body[2].col_offset, 2) - self.assertEqual(node.body[1].body[2].lineno, 11) - self.assertEqual(node.body[2].col_offset, 0) - self.assertEqual(node.body[2].lineno, 13) - - def test_elif_stmt_start_position(self): - node = ast.parse('if a:\n pass\nelif b:\n pass\n') - elif_stmt = node.body[0].orelse[0] - self.assertEqual(elif_stmt.lineno, 3) - self.assertEqual(elif_stmt.col_offset, 0) - - def test_elif_stmt_start_position_with_else(self): - node = ast.parse('if a:\n pass\nelif b:\n pass\nelse:\n pass\n') - elif_stmt = node.body[0].orelse[0] - self.assertEqual(elif_stmt.lineno, 3) - self.assertEqual(elif_stmt.col_offset, 0) - - def test_starred_expr_end_position_within_call(self): - node = ast.parse('f(*[0, 1])') - starred_expr = node.body[0].value.args[0] - self.assertEqual(starred_expr.end_lineno, 1) - self.assertEqual(starred_expr.end_col_offset, 9) - - def test_literal_eval(self): - self.assertEqual(ast.literal_eval('[1, 2, 3]'), [1, 2, 3]) - self.assertEqual(ast.literal_eval('{"foo": 42}'), {"foo": 42}) - self.assertEqual(ast.literal_eval('(True, False, None)'), (True, False, None)) - self.assertEqual(ast.literal_eval('{1, 2, 3}'), {1, 2, 3}) - self.assertEqual(ast.literal_eval('b"hi"'), b"hi") - self.assertEqual(ast.literal_eval('set()'), set()) - self.assertRaises(ValueError, ast.literal_eval, 'foo()') - self.assertEqual(ast.literal_eval('6'), 6) - self.assertEqual(ast.literal_eval('+6'), 6) - self.assertEqual(ast.literal_eval('-6'), -6) - self.assertEqual(ast.literal_eval('3.25'), 3.25) - self.assertEqual(ast.literal_eval('+3.25'), 3.25) - self.assertEqual(ast.literal_eval('-3.25'), -3.25) - self.assertEqual(repr(ast.literal_eval('-0.0')), '-0.0') - self.assertRaises(ValueError, ast.literal_eval, '++6') - self.assertRaises(ValueError, ast.literal_eval, '+True') - self.assertRaises(ValueError, ast.literal_eval, '2+3') - - def test_literal_eval_str_int_limit(self): - with support.adjust_int_max_str_digits(4000): - ast.literal_eval('3'*4000) # no error - with self.assertRaises(SyntaxError) as err_ctx: - ast.literal_eval('3'*4001) - self.assertIn('Exceeds the limit ', str(err_ctx.exception)) - self.assertIn(' Consider hexadecimal ', str(err_ctx.exception)) - - def test_literal_eval_complex(self): - # Issue #4907 - self.assertEqual(ast.literal_eval('6j'), 6j) - self.assertEqual(ast.literal_eval('-6j'), -6j) - self.assertEqual(ast.literal_eval('6.75j'), 6.75j) - self.assertEqual(ast.literal_eval('-6.75j'), -6.75j) - self.assertEqual(ast.literal_eval('3+6j'), 3+6j) - self.assertEqual(ast.literal_eval('-3+6j'), -3+6j) - self.assertEqual(ast.literal_eval('3-6j'), 3-6j) - self.assertEqual(ast.literal_eval('-3-6j'), -3-6j) - self.assertEqual(ast.literal_eval('3.25+6.75j'), 3.25+6.75j) - self.assertEqual(ast.literal_eval('-3.25+6.75j'), -3.25+6.75j) - self.assertEqual(ast.literal_eval('3.25-6.75j'), 3.25-6.75j) - self.assertEqual(ast.literal_eval('-3.25-6.75j'), -3.25-6.75j) - self.assertEqual(ast.literal_eval('(3+6j)'), 3+6j) - self.assertRaises(ValueError, ast.literal_eval, '-6j+3') - self.assertRaises(ValueError, ast.literal_eval, '-6j+3j') - self.assertRaises(ValueError, ast.literal_eval, '3+-6j') - self.assertRaises(ValueError, ast.literal_eval, '3+(0+6j)') - self.assertRaises(ValueError, ast.literal_eval, '-(3+6j)') - - def test_literal_eval_malformed_dict_nodes(self): - malformed = ast.Dict(keys=[ast.Constant(1), ast.Constant(2)], values=[ast.Constant(3)]) - self.assertRaises(ValueError, ast.literal_eval, malformed) - malformed = ast.Dict(keys=[ast.Constant(1)], values=[ast.Constant(2), ast.Constant(3)]) - self.assertRaises(ValueError, ast.literal_eval, malformed) - - def test_literal_eval_trailing_ws(self): - self.assertEqual(ast.literal_eval(" -1"), -1) - self.assertEqual(ast.literal_eval("\t\t-1"), -1) - self.assertEqual(ast.literal_eval(" \t -1"), -1) - self.assertRaises(IndentationError, ast.literal_eval, "\n -1") - - def test_literal_eval_malformed_lineno(self): - msg = r'malformed node or string on line 3:' - with self.assertRaisesRegex(ValueError, msg): - ast.literal_eval("{'a': 1,\n'b':2,\n'c':++3,\n'd':4}") - - node = ast.UnaryOp( - ast.UAdd(), ast.UnaryOp(ast.UAdd(), ast.Constant(6))) - self.assertIsNone(getattr(node, 'lineno', None)) - msg = r'malformed node or string:' - with self.assertRaisesRegex(ValueError, msg): - ast.literal_eval(node) - - def test_literal_eval_syntax_errors(self): - with self.assertRaisesRegex(SyntaxError, "unexpected indent"): - ast.literal_eval(r''' - \ - (\ - \ ''') - - def test_bad_integer(self): - # issue13436: Bad error message with invalid numeric values - body = [ast.ImportFrom(module='time', - names=[ast.alias(name='sleep')], - level=None, - lineno=None, col_offset=None)] - mod = ast.Module(body, []) - with self.assertRaises(ValueError) as cm: - compile(mod, 'test', 'exec') - self.assertIn("invalid integer value: None", str(cm.exception)) - - def test_level_as_none(self): - body = [ast.ImportFrom(module='time', - names=[ast.alias(name='sleep', - lineno=0, col_offset=0)], - level=None, - lineno=0, col_offset=0)] - mod = ast.Module(body, []) - code = compile(mod, 'test', 'exec') - ns = {} - exec(code, ns) - self.assertIn('sleep', ns) - - def test_recursion_direct(self): - e = ast.UnaryOp(op=ast.Not(), lineno=0, col_offset=0) - e.operand = e - with self.assertRaises(RecursionError): - with support.infinite_recursion(): - compile(ast.Expression(e), "", "eval") - - def test_recursion_indirect(self): - e = ast.UnaryOp(op=ast.Not(), lineno=0, col_offset=0) - f = ast.UnaryOp(op=ast.Not(), lineno=0, col_offset=0) - e.operand = f - f.operand = e - with self.assertRaises(RecursionError): - with support.infinite_recursion(): - compile(ast.Expression(e), "", "eval") - - -class ASTValidatorTests(unittest.TestCase): - - def mod(self, mod, msg=None, mode="exec", *, exc=ValueError): - mod.lineno = mod.col_offset = 0 - ast.fix_missing_locations(mod) - if msg is None: - compile(mod, "", mode) - else: - with self.assertRaises(exc) as cm: - compile(mod, "", mode) - self.assertIn(msg, str(cm.exception)) - - def expr(self, node, msg=None, *, exc=ValueError): - mod = ast.Module([ast.Expr(node)], []) - self.mod(mod, msg, exc=exc) - - def stmt(self, stmt, msg=None): - mod = ast.Module([stmt], []) - self.mod(mod, msg) - - def test_module(self): - m = ast.Interactive([ast.Expr(ast.Name("x", ast.Store()))]) - self.mod(m, "must have Load context", "single") - m = ast.Expression(ast.Name("x", ast.Store())) - self.mod(m, "must have Load context", "eval") - - def _check_arguments(self, fac, check): - def arguments(args=None, posonlyargs=None, vararg=None, - kwonlyargs=None, kwarg=None, - defaults=None, kw_defaults=None): - if args is None: - args = [] - if posonlyargs is None: - posonlyargs = [] - if kwonlyargs is None: - kwonlyargs = [] - if defaults is None: - defaults = [] - if kw_defaults is None: - kw_defaults = [] - args = ast.arguments(args, posonlyargs, vararg, kwonlyargs, - kw_defaults, kwarg, defaults) - return fac(args) - args = [ast.arg("x", ast.Name("x", ast.Store()))] - check(arguments(args=args), "must have Load context") - check(arguments(posonlyargs=args), "must have Load context") - check(arguments(kwonlyargs=args), "must have Load context") - check(arguments(defaults=[ast.Constant(3)]), - "more positional defaults than args") - check(arguments(kw_defaults=[ast.Constant(4)]), - "length of kwonlyargs is not the same as kw_defaults") - args = [ast.arg("x", ast.Name("x", ast.Load()))] - check(arguments(args=args, defaults=[ast.Name("x", ast.Store())]), - "must have Load context") - args = [ast.arg("a", ast.Name("x", ast.Load())), - ast.arg("b", ast.Name("y", ast.Load()))] - check(arguments(kwonlyargs=args, - kw_defaults=[None, ast.Name("x", ast.Store())]), - "must have Load context") - - def test_funcdef(self): - a = ast.arguments([], [], None, [], [], None, []) - f = ast.FunctionDef("x", a, [], [], None, None, []) - self.stmt(f, "empty body on FunctionDef") - f = ast.FunctionDef("x", a, [ast.Pass()], [ast.Name("x", ast.Store())], None, None, []) - self.stmt(f, "must have Load context") - f = ast.FunctionDef("x", a, [ast.Pass()], [], - ast.Name("x", ast.Store()), None, []) - self.stmt(f, "must have Load context") - f = ast.FunctionDef("x", ast.arguments(), [ast.Pass()]) - self.stmt(f) - def fac(args): - return ast.FunctionDef("x", args, [ast.Pass()], [], None, None, []) - self._check_arguments(fac, self.stmt) - - def test_funcdef_pattern_matching(self): - # gh-104799: New fields on FunctionDef should be added at the end - def matcher(node): - match node: - case ast.FunctionDef("foo", ast.arguments(args=[ast.arg("bar")]), - [ast.Pass()], - [ast.Name("capybara", ast.Load())], - ast.Name("pacarana", ast.Load())): - return True - case _: - return False - - code = """ - @capybara - def foo(bar) -> pacarana: - pass - """ - source = ast.parse(textwrap.dedent(code)) - funcdef = source.body[0] - self.assertIsInstance(funcdef, ast.FunctionDef) - self.assertTrue(matcher(funcdef)) - - def test_classdef(self): - def cls(bases=None, keywords=None, body=None, decorator_list=None, type_params=None): - if bases is None: - bases = [] - if keywords is None: - keywords = [] - if body is None: - body = [ast.Pass()] - if decorator_list is None: - decorator_list = [] - if type_params is None: - type_params = [] - return ast.ClassDef("myclass", bases, keywords, - body, decorator_list, type_params) - self.stmt(cls(bases=[ast.Name("x", ast.Store())]), - "must have Load context") - self.stmt(cls(keywords=[ast.keyword("x", ast.Name("x", ast.Store()))]), - "must have Load context") - self.stmt(cls(body=[]), "empty body on ClassDef") - self.stmt(cls(body=[None]), "None disallowed") - self.stmt(cls(decorator_list=[ast.Name("x", ast.Store())]), - "must have Load context") - - def test_delete(self): - self.stmt(ast.Delete([]), "empty targets on Delete") - self.stmt(ast.Delete([None]), "None disallowed") - self.stmt(ast.Delete([ast.Name("x", ast.Load())]), - "must have Del context") - - def test_assign(self): - self.stmt(ast.Assign([], ast.Constant(3)), "empty targets on Assign") - self.stmt(ast.Assign([None], ast.Constant(3)), "None disallowed") - self.stmt(ast.Assign([ast.Name("x", ast.Load())], ast.Constant(3)), - "must have Store context") - self.stmt(ast.Assign([ast.Name("x", ast.Store())], - ast.Name("y", ast.Store())), - "must have Load context") - - def test_augassign(self): - aug = ast.AugAssign(ast.Name("x", ast.Load()), ast.Add(), - ast.Name("y", ast.Load())) - self.stmt(aug, "must have Store context") - aug = ast.AugAssign(ast.Name("x", ast.Store()), ast.Add(), - ast.Name("y", ast.Store())) - self.stmt(aug, "must have Load context") - - def test_for(self): - x = ast.Name("x", ast.Store()) - y = ast.Name("y", ast.Load()) - p = ast.Pass() - self.stmt(ast.For(x, y, [], []), "empty body on For") - self.stmt(ast.For(ast.Name("x", ast.Load()), y, [p], []), - "must have Store context") - self.stmt(ast.For(x, ast.Name("y", ast.Store()), [p], []), - "must have Load context") - e = ast.Expr(ast.Name("x", ast.Store())) - self.stmt(ast.For(x, y, [e], []), "must have Load context") - self.stmt(ast.For(x, y, [p], [e]), "must have Load context") - - def test_while(self): - self.stmt(ast.While(ast.Constant(3), [], []), "empty body on While") - self.stmt(ast.While(ast.Name("x", ast.Store()), [ast.Pass()], []), - "must have Load context") - self.stmt(ast.While(ast.Constant(3), [ast.Pass()], - [ast.Expr(ast.Name("x", ast.Store()))]), - "must have Load context") - - def test_if(self): - self.stmt(ast.If(ast.Constant(3), [], []), "empty body on If") - i = ast.If(ast.Name("x", ast.Store()), [ast.Pass()], []) - self.stmt(i, "must have Load context") - i = ast.If(ast.Constant(3), [ast.Expr(ast.Name("x", ast.Store()))], []) - self.stmt(i, "must have Load context") - i = ast.If(ast.Constant(3), [ast.Pass()], - [ast.Expr(ast.Name("x", ast.Store()))]) - self.stmt(i, "must have Load context") - - def test_with(self): - p = ast.Pass() - self.stmt(ast.With([], [p]), "empty items on With") - i = ast.withitem(ast.Constant(3), None) - self.stmt(ast.With([i], []), "empty body on With") - i = ast.withitem(ast.Name("x", ast.Store()), None) - self.stmt(ast.With([i], [p]), "must have Load context") - i = ast.withitem(ast.Constant(3), ast.Name("x", ast.Load())) - self.stmt(ast.With([i], [p]), "must have Store context") - - def test_raise(self): - r = ast.Raise(None, ast.Constant(3)) - self.stmt(r, "Raise with cause but no exception") - r = ast.Raise(ast.Name("x", ast.Store()), None) - self.stmt(r, "must have Load context") - r = ast.Raise(ast.Constant(4), ast.Name("x", ast.Store())) - self.stmt(r, "must have Load context") - - def test_try(self): - p = ast.Pass() - t = ast.Try([], [], [], [p]) - self.stmt(t, "empty body on Try") - t = ast.Try([ast.Expr(ast.Name("x", ast.Store()))], [], [], [p]) - self.stmt(t, "must have Load context") - t = ast.Try([p], [], [], []) - self.stmt(t, "Try has neither except handlers nor finalbody") - t = ast.Try([p], [], [p], [p]) - self.stmt(t, "Try has orelse but no except handlers") - t = ast.Try([p], [ast.ExceptHandler(None, "x", [])], [], []) - self.stmt(t, "empty body on ExceptHandler") - e = [ast.ExceptHandler(ast.Name("x", ast.Store()), "y", [p])] - self.stmt(ast.Try([p], e, [], []), "must have Load context") - e = [ast.ExceptHandler(None, "x", [p])] - t = ast.Try([p], e, [ast.Expr(ast.Name("x", ast.Store()))], [p]) - self.stmt(t, "must have Load context") - t = ast.Try([p], e, [p], [ast.Expr(ast.Name("x", ast.Store()))]) - self.stmt(t, "must have Load context") - - def test_try_star(self): - p = ast.Pass() - t = ast.TryStar([], [], [], [p]) - self.stmt(t, "empty body on TryStar") - t = ast.TryStar([ast.Expr(ast.Name("x", ast.Store()))], [], [], [p]) - self.stmt(t, "must have Load context") - t = ast.TryStar([p], [], [], []) - self.stmt(t, "TryStar has neither except handlers nor finalbody") - t = ast.TryStar([p], [], [p], [p]) - self.stmt(t, "TryStar has orelse but no except handlers") - t = ast.TryStar([p], [ast.ExceptHandler(None, "x", [])], [], []) - self.stmt(t, "empty body on ExceptHandler") - e = [ast.ExceptHandler(ast.Name("x", ast.Store()), "y", [p])] - self.stmt(ast.TryStar([p], e, [], []), "must have Load context") - e = [ast.ExceptHandler(None, "x", [p])] - t = ast.TryStar([p], e, [ast.Expr(ast.Name("x", ast.Store()))], [p]) - self.stmt(t, "must have Load context") - t = ast.TryStar([p], e, [p], [ast.Expr(ast.Name("x", ast.Store()))]) - self.stmt(t, "must have Load context") - - def test_assert(self): - self.stmt(ast.Assert(ast.Name("x", ast.Store()), None), - "must have Load context") - assrt = ast.Assert(ast.Name("x", ast.Load()), - ast.Name("y", ast.Store())) - self.stmt(assrt, "must have Load context") - - def test_import(self): - self.stmt(ast.Import([]), "empty names on Import") - - def test_importfrom(self): - imp = ast.ImportFrom(None, [ast.alias("x", None)], -42) - self.stmt(imp, "Negative ImportFrom level") - self.stmt(ast.ImportFrom(None, [], 0), "empty names on ImportFrom") - - def test_global(self): - self.stmt(ast.Global([]), "empty names on Global") - - def test_nonlocal(self): - self.stmt(ast.Nonlocal([]), "empty names on Nonlocal") - - def test_expr(self): - e = ast.Expr(ast.Name("x", ast.Store())) - self.stmt(e, "must have Load context") - - def test_boolop(self): - b = ast.BoolOp(ast.And(), []) - self.expr(b, "less than 2 values") - b = ast.BoolOp(ast.And(), [ast.Constant(3)]) - self.expr(b, "less than 2 values") - b = ast.BoolOp(ast.And(), [ast.Constant(4), None]) - self.expr(b, "None disallowed") - b = ast.BoolOp(ast.And(), [ast.Constant(4), ast.Name("x", ast.Store())]) - self.expr(b, "must have Load context") - - def test_unaryop(self): - u = ast.UnaryOp(ast.Not(), ast.Name("x", ast.Store())) - self.expr(u, "must have Load context") - - def test_lambda(self): - a = ast.arguments([], [], None, [], [], None, []) - self.expr(ast.Lambda(a, ast.Name("x", ast.Store())), - "must have Load context") - def fac(args): - return ast.Lambda(args, ast.Name("x", ast.Load())) - self._check_arguments(fac, self.expr) - - def test_ifexp(self): - l = ast.Name("x", ast.Load()) - s = ast.Name("y", ast.Store()) - for args in (s, l, l), (l, s, l), (l, l, s): - self.expr(ast.IfExp(*args), "must have Load context") - - def test_dict(self): - d = ast.Dict([], [ast.Name("x", ast.Load())]) - self.expr(d, "same number of keys as values") - d = ast.Dict([ast.Name("x", ast.Load())], [None]) - self.expr(d, "None disallowed") - - def test_set(self): - self.expr(ast.Set([None]), "None disallowed") - s = ast.Set([ast.Name("x", ast.Store())]) - self.expr(s, "must have Load context") - - def _check_comprehension(self, fac): - self.expr(fac([]), "comprehension with no generators") - g = ast.comprehension(ast.Name("x", ast.Load()), - ast.Name("x", ast.Load()), [], 0) - self.expr(fac([g]), "must have Store context") - g = ast.comprehension(ast.Name("x", ast.Store()), - ast.Name("x", ast.Store()), [], 0) - self.expr(fac([g]), "must have Load context") - x = ast.Name("x", ast.Store()) - y = ast.Name("y", ast.Load()) - g = ast.comprehension(x, y, [None], 0) - self.expr(fac([g]), "None disallowed") - g = ast.comprehension(x, y, [ast.Name("x", ast.Store())], 0) - self.expr(fac([g]), "must have Load context") - - def _simple_comp(self, fac): - g = ast.comprehension(ast.Name("x", ast.Store()), - ast.Name("x", ast.Load()), [], 0) - self.expr(fac(ast.Name("x", ast.Store()), [g]), - "must have Load context") - def wrap(gens): - return fac(ast.Name("x", ast.Store()), gens) - self._check_comprehension(wrap) - - def test_listcomp(self): - self._simple_comp(ast.ListComp) - - def test_setcomp(self): - self._simple_comp(ast.SetComp) - - def test_generatorexp(self): - self._simple_comp(ast.GeneratorExp) - - def test_dictcomp(self): - g = ast.comprehension(ast.Name("y", ast.Store()), - ast.Name("p", ast.Load()), [], 0) - c = ast.DictComp(ast.Name("x", ast.Store()), - ast.Name("y", ast.Load()), [g]) - self.expr(c, "must have Load context") - c = ast.DictComp(ast.Name("x", ast.Load()), - ast.Name("y", ast.Store()), [g]) - self.expr(c, "must have Load context") - def factory(comps): - k = ast.Name("x", ast.Load()) - v = ast.Name("y", ast.Load()) - return ast.DictComp(k, v, comps) - self._check_comprehension(factory) - - def test_yield(self): - self.expr(ast.Yield(ast.Name("x", ast.Store())), "must have Load") - self.expr(ast.YieldFrom(ast.Name("x", ast.Store())), "must have Load") - - def test_compare(self): - left = ast.Name("x", ast.Load()) - comp = ast.Compare(left, [ast.In()], []) - self.expr(comp, "no comparators") - comp = ast.Compare(left, [ast.In()], [ast.Constant(4), ast.Constant(5)]) - self.expr(comp, "different number of comparators and operands") - comp = ast.Compare(ast.Constant("blah"), [ast.In()], [left]) - self.expr(comp) - comp = ast.Compare(left, [ast.In()], [ast.Constant("blah")]) - self.expr(comp) - - def test_call(self): - func = ast.Name("x", ast.Load()) - args = [ast.Name("y", ast.Load())] - keywords = [ast.keyword("w", ast.Name("z", ast.Load()))] - call = ast.Call(ast.Name("x", ast.Store()), args, keywords) - self.expr(call, "must have Load context") - call = ast.Call(func, [None], keywords) - self.expr(call, "None disallowed") - bad_keywords = [ast.keyword("w", ast.Name("z", ast.Store()))] - call = ast.Call(func, args, bad_keywords) - self.expr(call, "must have Load context") - - def test_num(self): - with warnings.catch_warnings(record=True) as wlog: - warnings.filterwarnings('ignore', '', DeprecationWarning) - from ast import Num - - with warnings.catch_warnings(record=True) as wlog: - warnings.filterwarnings('always', '', DeprecationWarning) - class subint(int): - pass - class subfloat(float): - pass - class subcomplex(complex): - pass - for obj in "0", "hello": - self.expr(ast.Num(obj)) - for obj in subint(), subfloat(), subcomplex(): - self.expr(ast.Num(obj), "invalid type", exc=TypeError) - - self.assertEqual([str(w.message) for w in wlog], [ - 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', - 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', - ]) - - def test_attribute(self): - attr = ast.Attribute(ast.Name("x", ast.Store()), "y", ast.Load()) - self.expr(attr, "must have Load context") - - def test_subscript(self): - sub = ast.Subscript(ast.Name("x", ast.Store()), ast.Constant(3), - ast.Load()) - self.expr(sub, "must have Load context") - x = ast.Name("x", ast.Load()) - sub = ast.Subscript(x, ast.Name("y", ast.Store()), - ast.Load()) - self.expr(sub, "must have Load context") - s = ast.Name("x", ast.Store()) - for args in (s, None, None), (None, s, None), (None, None, s): - sl = ast.Slice(*args) - self.expr(ast.Subscript(x, sl, ast.Load()), - "must have Load context") - sl = ast.Tuple([], ast.Load()) - self.expr(ast.Subscript(x, sl, ast.Load())) - sl = ast.Tuple([s], ast.Load()) - self.expr(ast.Subscript(x, sl, ast.Load()), "must have Load context") - - def test_starred(self): - left = ast.List([ast.Starred(ast.Name("x", ast.Load()), ast.Store())], - ast.Store()) - assign = ast.Assign([left], ast.Constant(4)) - self.stmt(assign, "must have Store context") - - def _sequence(self, fac): - self.expr(fac([None], ast.Load()), "None disallowed") - self.expr(fac([ast.Name("x", ast.Store())], ast.Load()), - "must have Load context") - - def test_list(self): - self._sequence(ast.List) - - def test_tuple(self): - self._sequence(ast.Tuple) - - def test_nameconstant(self): - with warnings.catch_warnings(record=True) as wlog: - warnings.filterwarnings('ignore', '', DeprecationWarning) - from ast import NameConstant - - with warnings.catch_warnings(record=True) as wlog: - warnings.filterwarnings('always', '', DeprecationWarning) - self.expr(ast.NameConstant(4)) - - self.assertEqual([str(w.message) for w in wlog], [ - 'ast.NameConstant is deprecated and will be removed in Python 3.14; use ast.Constant instead', - ]) - - @support.requires_resource('cpu') - def test_stdlib_validates(self): - stdlib = os.path.dirname(ast.__file__) - tests = [fn for fn in os.listdir(stdlib) if fn.endswith(".py")] - tests.extend(["test/test_grammar.py", "test/test_unpack_ex.py"]) - for module in tests: - with self.subTest(module): - fn = os.path.join(stdlib, module) - with open(fn, "r", encoding="utf-8") as fp: - source = fp.read() - mod = ast.parse(source, fn) - compile(mod, fn, "exec") - - constant_1 = ast.Constant(1) - pattern_1 = ast.MatchValue(constant_1) - - constant_x = ast.Constant('x') - pattern_x = ast.MatchValue(constant_x) - - constant_true = ast.Constant(True) - pattern_true = ast.MatchSingleton(True) - - name_carter = ast.Name('carter', ast.Load()) - - _MATCH_PATTERNS = [ - ast.MatchValue( - ast.Attribute( - ast.Attribute( - ast.Name('x', ast.Store()), - 'y', ast.Load() - ), - 'z', ast.Load() - ) - ), - ast.MatchValue( - ast.Attribute( - ast.Attribute( - ast.Name('x', ast.Load()), - 'y', ast.Store() - ), - 'z', ast.Load() - ) - ), - ast.MatchValue( - ast.Constant(...) - ), - ast.MatchValue( - ast.Constant(True) - ), - ast.MatchValue( - ast.Constant((1,2,3)) - ), - ast.MatchSingleton('string'), - ast.MatchSequence([ - ast.MatchSingleton('string') - ]), - ast.MatchSequence( - [ - ast.MatchSequence( - [ - ast.MatchSingleton('string') - ] - ) - ] - ), - ast.MatchMapping( - [constant_1, constant_true], - [pattern_x] - ), - ast.MatchMapping( - [constant_true, constant_1], - [pattern_x, pattern_1], - rest='True' - ), - ast.MatchMapping( - [constant_true, ast.Starred(ast.Name('lol', ast.Load()), ast.Load())], - [pattern_x, pattern_1], - rest='legit' - ), - ast.MatchClass( - ast.Attribute( - ast.Attribute( - constant_x, - 'y', ast.Load()), - 'z', ast.Load()), - patterns=[], kwd_attrs=[], kwd_patterns=[] - ), - ast.MatchClass( - name_carter, - patterns=[], - kwd_attrs=['True'], - kwd_patterns=[pattern_1] - ), - ast.MatchClass( - name_carter, - patterns=[], - kwd_attrs=[], - kwd_patterns=[pattern_1] - ), - ast.MatchClass( - name_carter, - patterns=[ast.MatchSingleton('string')], - kwd_attrs=[], - kwd_patterns=[] - ), - ast.MatchClass( - name_carter, - patterns=[ast.MatchStar()], - kwd_attrs=[], - kwd_patterns=[] - ), - ast.MatchClass( - name_carter, - patterns=[], - kwd_attrs=[], - kwd_patterns=[ast.MatchStar()] - ), - ast.MatchClass( - constant_true, # invalid name - patterns=[], - kwd_attrs=['True'], - kwd_patterns=[pattern_1] - ), - ast.MatchSequence( - [ - ast.MatchStar("True") - ] - ), - ast.MatchAs( - name='False' - ), - ast.MatchOr( - [] - ), - ast.MatchOr( - [pattern_1] - ), - ast.MatchOr( - [pattern_1, pattern_x, ast.MatchSingleton('xxx')] - ), - ast.MatchAs(name="_"), - ast.MatchStar(name="x"), - ast.MatchSequence([ast.MatchStar("_")]), - ast.MatchMapping([], [], rest="_"), - ] - - def test_match_validation_pattern(self): - name_x = ast.Name('x', ast.Load()) - for pattern in self._MATCH_PATTERNS: - with self.subTest(ast.dump(pattern, indent=4)): - node = ast.Match( - subject=name_x, - cases = [ - ast.match_case( - pattern=pattern, - body = [ast.Pass()] - ) - ] - ) - node = ast.fix_missing_locations(node) - module = ast.Module([node], []) - with self.assertRaises(ValueError): - compile(module, "", "exec") - - -class ConstantTests(unittest.TestCase): - """Tests on the ast.Constant node type.""" - - def compile_constant(self, value): - tree = ast.parse("x = 123") - - node = tree.body[0].value - new_node = ast.Constant(value=value) - ast.copy_location(new_node, node) - tree.body[0].value = new_node - - code = compile(tree, "", "exec") - - ns = {} - exec(code, ns) - return ns['x'] - - def test_validation(self): - with self.assertRaises(TypeError) as cm: - self.compile_constant([1, 2, 3]) - self.assertEqual(str(cm.exception), - "got an invalid type in Constant: list") - - def test_singletons(self): - for const in (None, False, True, Ellipsis, b'', frozenset()): - with self.subTest(const=const): - value = self.compile_constant(const) - self.assertIs(value, const) - - def test_values(self): - nested_tuple = (1,) - nested_frozenset = frozenset({1}) - for level in range(3): - nested_tuple = (nested_tuple, 2) - nested_frozenset = frozenset({nested_frozenset, 2}) - values = (123, 123.0, 123j, - "unicode", b'bytes', - tuple("tuple"), frozenset("frozenset"), - nested_tuple, nested_frozenset) - for value in values: - with self.subTest(value=value): - result = self.compile_constant(value) - self.assertEqual(result, value) - - def test_assign_to_constant(self): - tree = ast.parse("x = 1") - - target = tree.body[0].targets[0] - new_target = ast.Constant(value=1) - ast.copy_location(new_target, target) - tree.body[0].targets[0] = new_target - - with self.assertRaises(ValueError) as cm: - compile(tree, "string", "exec") - self.assertEqual(str(cm.exception), - "expression which can't be assigned " - "to in Store context") - - def test_get_docstring(self): - tree = ast.parse("'docstring'\nx = 1") - self.assertEqual(ast.get_docstring(tree), 'docstring') - - def get_load_const(self, tree): - # Compile to bytecode, disassemble and get parameter of LOAD_CONST - # instructions - co = compile(tree, '', 'exec') - consts = [] - for instr in dis.get_instructions(co): - if instr.opname == 'LOAD_CONST' or instr.opname == 'RETURN_CONST': - consts.append(instr.argval) - return consts - - @support.cpython_only - def test_load_const(self): - consts = [None, - True, False, - 124, - 2.0, - 3j, - "unicode", - b'bytes', - (1, 2, 3)] - - code = '\n'.join(['x={!r}'.format(const) for const in consts]) - code += '\nx = ...' - consts.extend((Ellipsis, None)) - - tree = ast.parse(code) - self.assertEqual(self.get_load_const(tree), - consts) - - # Replace expression nodes with constants - for assign, const in zip(tree.body, consts): - assert isinstance(assign, ast.Assign), ast.dump(assign) - new_node = ast.Constant(value=const) - ast.copy_location(new_node, assign.value) - assign.value = new_node - - self.assertEqual(self.get_load_const(tree), - consts) - - def test_literal_eval(self): - tree = ast.parse("1 + 2") - binop = tree.body[0].value - - new_left = ast.Constant(value=10) - ast.copy_location(new_left, binop.left) - binop.left = new_left - - new_right = ast.Constant(value=20j) - ast.copy_location(new_right, binop.right) - binop.right = new_right - - self.assertEqual(ast.literal_eval(binop), 10+20j) - - def test_string_kind(self): - c = ast.parse('"x"', mode='eval').body - self.assertEqual(c.value, "x") - self.assertEqual(c.kind, None) - - c = ast.parse('u"x"', mode='eval').body - self.assertEqual(c.value, "x") - self.assertEqual(c.kind, "u") - - c = ast.parse('r"x"', mode='eval').body - self.assertEqual(c.value, "x") - self.assertEqual(c.kind, None) - - c = ast.parse('b"x"', mode='eval').body - self.assertEqual(c.value, b"x") - self.assertEqual(c.kind, None) - - -class EndPositionTests(unittest.TestCase): - """Tests for end position of AST nodes. - - Testing end positions of nodes requires a bit of extra care - because of how LL parsers work. - """ - def _check_end_pos(self, ast_node, end_lineno, end_col_offset): - self.assertEqual(ast_node.end_lineno, end_lineno) - self.assertEqual(ast_node.end_col_offset, end_col_offset) - - def _check_content(self, source, ast_node, content): - self.assertEqual(ast.get_source_segment(source, ast_node), content) - - def _parse_value(self, s): - # Use duck-typing to support both single expression - # and a right hand side of an assignment statement. - return ast.parse(s).body[0].value - - def test_lambda(self): - s = 'lambda x, *y: None' - lam = self._parse_value(s) - self._check_content(s, lam.body, 'None') - self._check_content(s, lam.args.args[0], 'x') - self._check_content(s, lam.args.vararg, 'y') - - def test_func_def(self): - s = dedent(''' - def func(x: int, - *args: str, - z: float = 0, - **kwargs: Any) -> bool: - return True - ''').strip() - fdef = ast.parse(s).body[0] - self._check_end_pos(fdef, 5, 15) - self._check_content(s, fdef.body[0], 'return True') - self._check_content(s, fdef.args.args[0], 'x: int') - self._check_content(s, fdef.args.args[0].annotation, 'int') - self._check_content(s, fdef.args.kwarg, 'kwargs: Any') - self._check_content(s, fdef.args.kwarg.annotation, 'Any') - - def test_call(self): - s = 'func(x, y=2, **kw)' - call = self._parse_value(s) - self._check_content(s, call.func, 'func') - self._check_content(s, call.keywords[0].value, '2') - self._check_content(s, call.keywords[1].value, 'kw') - - def test_call_noargs(self): - s = 'x[0]()' - call = self._parse_value(s) - self._check_content(s, call.func, 'x[0]') - self._check_end_pos(call, 1, 6) - - def test_class_def(self): - s = dedent(''' - class C(A, B): - x: int = 0 - ''').strip() - cdef = ast.parse(s).body[0] - self._check_end_pos(cdef, 2, 14) - self._check_content(s, cdef.bases[1], 'B') - self._check_content(s, cdef.body[0], 'x: int = 0') - - def test_class_kw(self): - s = 'class S(metaclass=abc.ABCMeta): pass' - cdef = ast.parse(s).body[0] - self._check_content(s, cdef.keywords[0].value, 'abc.ABCMeta') - - def test_multi_line_str(self): - s = dedent(''' - x = """Some multi-line text. - - It goes on starting from same indent.""" - ''').strip() - assign = ast.parse(s).body[0] - self._check_end_pos(assign, 3, 40) - self._check_end_pos(assign.value, 3, 40) - - def test_continued_str(self): - s = dedent(''' - x = "first part" \\ - "second part" - ''').strip() - assign = ast.parse(s).body[0] - self._check_end_pos(assign, 2, 13) - self._check_end_pos(assign.value, 2, 13) - - def test_suites(self): - # We intentionally put these into the same string to check - # that empty lines are not part of the suite. - s = dedent(''' - while True: - pass - - if one(): - x = None - elif other(): - y = None - else: - z = None - - for x, y in stuff: - assert True - - try: - raise RuntimeError - except TypeError as e: - pass - - pass - ''').strip() - mod = ast.parse(s) - while_loop = mod.body[0] - if_stmt = mod.body[1] - for_loop = mod.body[2] - try_stmt = mod.body[3] - pass_stmt = mod.body[4] - - self._check_end_pos(while_loop, 2, 8) - self._check_end_pos(if_stmt, 9, 12) - self._check_end_pos(for_loop, 12, 15) - self._check_end_pos(try_stmt, 17, 8) - self._check_end_pos(pass_stmt, 19, 4) - - self._check_content(s, while_loop.test, 'True') - self._check_content(s, if_stmt.body[0], 'x = None') - self._check_content(s, if_stmt.orelse[0].test, 'other()') - self._check_content(s, for_loop.target, 'x, y') - self._check_content(s, try_stmt.body[0], 'raise RuntimeError') - self._check_content(s, try_stmt.handlers[0].type, 'TypeError') - - def test_fstring(self): - s = 'x = f"abc {x + y} abc"' - fstr = self._parse_value(s) - binop = fstr.values[1].value - self._check_content(s, binop, 'x + y') - - def test_fstring_multi_line(self): - s = dedent(''' - f"""Some multi-line text. - { - arg_one - + - arg_two - } - It goes on...""" - ''').strip() - fstr = self._parse_value(s) - binop = fstr.values[1].value - self._check_end_pos(binop, 5, 7) - self._check_content(s, binop.left, 'arg_one') - self._check_content(s, binop.right, 'arg_two') - - def test_import_from_multi_line(self): - s = dedent(''' - from x.y.z import ( - a, b, c as c - ) - ''').strip() - imp = ast.parse(s).body[0] - self._check_end_pos(imp, 3, 1) - self._check_end_pos(imp.names[2], 2, 16) - - def test_slices(self): - s1 = 'f()[1, 2] [0]' - s2 = 'x[ a.b: c.d]' - sm = dedent(''' - x[ a.b: f () , - g () : c.d - ] - ''').strip() - i1, i2, im = map(self._parse_value, (s1, s2, sm)) - self._check_content(s1, i1.value, 'f()[1, 2]') - self._check_content(s1, i1.value.slice, '1, 2') - self._check_content(s2, i2.slice.lower, 'a.b') - self._check_content(s2, i2.slice.upper, 'c.d') - self._check_content(sm, im.slice.elts[0].upper, 'f ()') - self._check_content(sm, im.slice.elts[1].lower, 'g ()') - self._check_end_pos(im, 3, 3) - - def test_binop(self): - s = dedent(''' - (1 * 2 + (3 ) + - 4 - ) - ''').strip() - binop = self._parse_value(s) - self._check_end_pos(binop, 2, 6) - self._check_content(s, binop.right, '4') - self._check_content(s, binop.left, '1 * 2 + (3 )') - self._check_content(s, binop.left.right, '3') - - def test_boolop(self): - s = dedent(''' - if (one_condition and - (other_condition or yet_another_one)): - pass - ''').strip() - bop = ast.parse(s).body[0].test - self._check_end_pos(bop, 2, 44) - self._check_content(s, bop.values[1], - 'other_condition or yet_another_one') - - def test_tuples(self): - s1 = 'x = () ;' - s2 = 'x = 1 , ;' - s3 = 'x = (1 , 2 ) ;' - sm = dedent(''' - x = ( - a, b, - ) - ''').strip() - t1, t2, t3, tm = map(self._parse_value, (s1, s2, s3, sm)) - self._check_content(s1, t1, '()') - self._check_content(s2, t2, '1 ,') - self._check_content(s3, t3, '(1 , 2 )') - self._check_end_pos(tm, 3, 1) - - def test_attribute_spaces(self): - s = 'func(x. y .z)' - call = self._parse_value(s) - self._check_content(s, call, s) - self._check_content(s, call.args[0], 'x. y .z') - - def test_redundant_parenthesis(self): - s = '( ( ( a + b ) ) )' - v = ast.parse(s).body[0].value - self.assertEqual(type(v).__name__, 'BinOp') - self._check_content(s, v, 'a + b') - s2 = 'await ' + s - v = ast.parse(s2).body[0].value.value - self.assertEqual(type(v).__name__, 'BinOp') - self._check_content(s2, v, 'a + b') - - def test_trailers_with_redundant_parenthesis(self): - tests = ( - ('( ( ( a ) ) ) ( )', 'Call'), - ('( ( ( a ) ) ) ( b )', 'Call'), - ('( ( ( a ) ) ) [ b ]', 'Subscript'), - ('( ( ( a ) ) ) . b', 'Attribute'), - ) - for s, t in tests: - with self.subTest(s): - v = ast.parse(s).body[0].value - self.assertEqual(type(v).__name__, t) - self._check_content(s, v, s) - s2 = 'await ' + s - v = ast.parse(s2).body[0].value.value - self.assertEqual(type(v).__name__, t) - self._check_content(s2, v, s) - - def test_displays(self): - s1 = '[{}, {1, }, {1, 2,} ]' - s2 = '{a: b, f (): g () ,}' - c1 = self._parse_value(s1) - c2 = self._parse_value(s2) - self._check_content(s1, c1.elts[0], '{}') - self._check_content(s1, c1.elts[1], '{1, }') - self._check_content(s1, c1.elts[2], '{1, 2,}') - self._check_content(s2, c2.keys[1], 'f ()') - self._check_content(s2, c2.values[1], 'g ()') - - def test_comprehensions(self): - s = dedent(''' - x = [{x for x, y in stuff - if cond.x} for stuff in things] - ''').strip() - cmp = self._parse_value(s) - self._check_end_pos(cmp, 2, 37) - self._check_content(s, cmp.generators[0].iter, 'things') - self._check_content(s, cmp.elt.generators[0].iter, 'stuff') - self._check_content(s, cmp.elt.generators[0].ifs[0], 'cond.x') - self._check_content(s, cmp.elt.generators[0].target, 'x, y') - - def test_yield_await(self): - s = dedent(''' - async def f(): - yield x - await y - ''').strip() - fdef = ast.parse(s).body[0] - self._check_content(s, fdef.body[0].value, 'yield x') - self._check_content(s, fdef.body[1].value, 'await y') - - def test_source_segment_multi(self): - s_orig = dedent(''' - x = ( - a, b, - ) + () - ''').strip() - s_tuple = dedent(''' - ( - a, b, - ) - ''').strip() - binop = self._parse_value(s_orig) - self.assertEqual(ast.get_source_segment(s_orig, binop.left), s_tuple) - - def test_source_segment_padded(self): - s_orig = dedent(''' - class C: - def fun(self) -> None: - "ЖЖЖЖЖ" - ''').strip() - s_method = ' def fun(self) -> None:\n' \ - ' "ЖЖЖЖЖ"' - cdef = ast.parse(s_orig).body[0] - self.assertEqual(ast.get_source_segment(s_orig, cdef.body[0], padded=True), - s_method) - - def test_source_segment_endings(self): - s = 'v = 1\r\nw = 1\nx = 1\n\ry = 1\rz = 1\r\n' - v, w, x, y, z = ast.parse(s).body - self._check_content(s, v, 'v = 1') - self._check_content(s, w, 'w = 1') - self._check_content(s, x, 'x = 1') - self._check_content(s, y, 'y = 1') - self._check_content(s, z, 'z = 1') - - def test_source_segment_tabs(self): - s = dedent(''' - class C: - \t\f def fun(self) -> None: - \t\f pass - ''').strip() - s_method = ' \t\f def fun(self) -> None:\n' \ - ' \t\f pass' - - cdef = ast.parse(s).body[0] - self.assertEqual(ast.get_source_segment(s, cdef.body[0], padded=True), s_method) - - def test_source_segment_newlines(self): - s = 'def f():\n pass\ndef g():\r pass\r\ndef h():\r\n pass\r\n' - f, g, h = ast.parse(s).body - self._check_content(s, f, 'def f():\n pass') - self._check_content(s, g, 'def g():\r pass') - self._check_content(s, h, 'def h():\r\n pass') - - s = 'def f():\n a = 1\r b = 2\r\n c = 3\n' - f = ast.parse(s).body[0] - self._check_content(s, f, s.rstrip()) - - def test_source_segment_missing_info(self): - s = 'v = 1\r\nw = 1\nx = 1\n\ry = 1\r\n' - v, w, x, y = ast.parse(s).body - del v.lineno - del w.end_lineno - del x.col_offset - del y.end_col_offset - self.assertIsNone(ast.get_source_segment(s, v)) - self.assertIsNone(ast.get_source_segment(s, w)) - self.assertIsNone(ast.get_source_segment(s, x)) - self.assertIsNone(ast.get_source_segment(s, y)) - -class BaseNodeVisitorCases: - # Both `NodeVisitor` and `NodeTranformer` must raise these warnings: - def test_old_constant_nodes(self): - class Visitor(self.visitor_class): - def visit_Num(self, node): - log.append((node.lineno, 'Num', node.n)) - def visit_Str(self, node): - log.append((node.lineno, 'Str', node.s)) - def visit_Bytes(self, node): - log.append((node.lineno, 'Bytes', node.s)) - def visit_NameConstant(self, node): - log.append((node.lineno, 'NameConstant', node.value)) - def visit_Ellipsis(self, node): - log.append((node.lineno, 'Ellipsis', ...)) - mod = ast.parse(dedent('''\ - i = 42 - f = 4.25 - c = 4.25j - s = 'string' - b = b'bytes' - t = True - n = None - e = ... - ''')) - visitor = Visitor() - log = [] - with warnings.catch_warnings(record=True) as wlog: - warnings.filterwarnings('always', '', DeprecationWarning) - visitor.visit(mod) - self.assertEqual(log, [ - (1, 'Num', 42), - (2, 'Num', 4.25), - (3, 'Num', 4.25j), - (4, 'Str', 'string'), - (5, 'Bytes', b'bytes'), - (6, 'NameConstant', True), - (7, 'NameConstant', None), - (8, 'Ellipsis', ...), - ]) - self.assertEqual([str(w.message) for w in wlog], [ - 'visit_Num is deprecated; add visit_Constant', - 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', - 'visit_Num is deprecated; add visit_Constant', - 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', - 'visit_Num is deprecated; add visit_Constant', - 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', - 'visit_Str is deprecated; add visit_Constant', - 'Attribute s is deprecated and will be removed in Python 3.14; use value instead', - 'visit_Bytes is deprecated; add visit_Constant', - 'Attribute s is deprecated and will be removed in Python 3.14; use value instead', - 'visit_NameConstant is deprecated; add visit_Constant', - 'visit_NameConstant is deprecated; add visit_Constant', - 'visit_Ellipsis is deprecated; add visit_Constant', - ]) - - -class NodeVisitorTests(BaseNodeVisitorCases, unittest.TestCase): - visitor_class = ast.NodeVisitor - - -class NodeTransformerTests(ASTTestMixin, BaseNodeVisitorCases, unittest.TestCase): - visitor_class = ast.NodeTransformer - - def assertASTTransformation(self, tranformer_class, - initial_code, expected_code): - initial_ast = ast.parse(dedent(initial_code)) - expected_ast = ast.parse(dedent(expected_code)) - - tranformer = tranformer_class() - result_ast = ast.fix_missing_locations(tranformer.visit(initial_ast)) - - self.assertASTEqual(result_ast, expected_ast) - - def test_node_remove_single(self): - code = 'def func(arg) -> SomeType: ...' - expected = 'def func(arg): ...' - - # Since `FunctionDef.returns` is defined as a single value, we test - # the `if isinstance(old_value, AST):` branch here. - class SomeTypeRemover(ast.NodeTransformer): - def visit_Name(self, node: ast.Name): - self.generic_visit(node) - if node.id == 'SomeType': - return None - return node - - self.assertASTTransformation(SomeTypeRemover, code, expected) - - def test_node_remove_from_list(self): - code = """ - def func(arg): - print(arg) - yield arg - """ - expected = """ - def func(arg): - print(arg) - """ - - # Since `FunctionDef.body` is defined as a list, we test - # the `if isinstance(old_value, list):` branch here. - class YieldRemover(ast.NodeTransformer): - def visit_Expr(self, node: ast.Expr): - self.generic_visit(node) - if isinstance(node.value, ast.Yield): - return None # Remove `yield` from a function - return node - - self.assertASTTransformation(YieldRemover, code, expected) - - def test_node_return_list(self): - code = """ - class DSL(Base, kw1=True): ... - """ - expected = """ - class DSL(Base, kw1=True, kw2=True, kw3=False): ... - """ - - class ExtendKeywords(ast.NodeTransformer): - def visit_keyword(self, node: ast.keyword): - self.generic_visit(node) - if node.arg == 'kw1': - return [ - node, - ast.keyword('kw2', ast.Constant(True)), - ast.keyword('kw3', ast.Constant(False)), - ] - return node - - self.assertASTTransformation(ExtendKeywords, code, expected) - - def test_node_mutate(self): - code = """ - def func(arg): - print(arg) - """ - expected = """ - def func(arg): - log(arg) - """ - - class PrintToLog(ast.NodeTransformer): - def visit_Call(self, node: ast.Call): - self.generic_visit(node) - if isinstance(node.func, ast.Name) and node.func.id == 'print': - node.func.id = 'log' - return node - - self.assertASTTransformation(PrintToLog, code, expected) - - def test_node_replace(self): - code = """ - def func(arg): - print(arg) - """ - expected = """ - def func(arg): - logger.log(arg, debug=True) - """ - - class PrintToLog(ast.NodeTransformer): - def visit_Call(self, node: ast.Call): - self.generic_visit(node) - if isinstance(node.func, ast.Name) and node.func.id == 'print': - return ast.Call( - func=ast.Attribute( - ast.Name('logger', ctx=ast.Load()), - attr='log', - ctx=ast.Load(), - ), - args=node.args, - keywords=[ast.keyword('debug', ast.Constant(True))], - ) - return node - - self.assertASTTransformation(PrintToLog, code, expected) - - -@support.cpython_only -class ModuleStateTests(unittest.TestCase): - # bpo-41194, bpo-41261, bpo-41631: The _ast module uses a global state. - - def check_ast_module(self): - # Check that the _ast module still works as expected - code = 'x + 1' - filename = '' - mode = 'eval' - - # Create _ast.AST subclasses instances - ast_tree = compile(code, filename, mode, flags=ast.PyCF_ONLY_AST) - - # Call PyAST_Check() - code = compile(ast_tree, filename, mode) - self.assertIsInstance(code, types.CodeType) - - def test_reload_module(self): - # bpo-41194: Importing the _ast module twice must not crash. - with support.swap_item(sys.modules, '_ast', None): - del sys.modules['_ast'] - import _ast as ast1 - - del sys.modules['_ast'] - import _ast as ast2 - - self.check_ast_module() - - # Unloading the two _ast module instances must not crash. - del ast1 - del ast2 - support.gc_collect() - - self.check_ast_module() - - def test_sys_modules(self): - # bpo-41631: Test reproducing a Mercurial crash when PyAST_Check() - # imported the _ast module internally. - lazy_mod = object() - - def my_import(name, *args, **kw): - sys.modules[name] = lazy_mod - return lazy_mod - - with support.swap_item(sys.modules, '_ast', None): - del sys.modules['_ast'] - - with support.swap_attr(builtins, '__import__', my_import): - # Test that compile() does not import the _ast module - self.check_ast_module() - self.assertNotIn('_ast', sys.modules) - - # Sanity check of the test itself - import _ast - self.assertIs(_ast, lazy_mod) - - def test_subinterpreter(self): - # bpo-41631: Importing and using the _ast module in a subinterpreter - # must not crash. - code = dedent(''' - import _ast - import ast - import gc - import sys - import types - - # Create _ast.AST subclasses instances and call PyAST_Check() - ast_tree = compile('x+1', '', 'eval', - flags=ast.PyCF_ONLY_AST) - code = compile(ast_tree, 'string', 'eval') - if not isinstance(code, types.CodeType): - raise AssertionError - - # Unloading the _ast module must not crash. - del ast, _ast - del sys.modules['ast'], sys.modules['_ast'] - gc.collect() - ''') - res = support.run_in_subinterp(code) - self.assertEqual(res, 0) - - -class ASTMainTests(unittest.TestCase): - # Tests `ast.main()` function. - - def test_cli_file_input(self): - code = "print(1, 2, 3)" - expected = ast.dump(ast.parse(code), indent=3) - - with os_helper.temp_dir() as tmp_dir: - filename = os.path.join(tmp_dir, "test_module.py") - with open(filename, 'w', encoding='utf-8') as f: - f.write(code) - res, _ = script_helper.run_python_until_end("-m", "ast", filename) - - self.assertEqual(res.err, b"") - self.assertEqual(expected.splitlines(), - res.out.decode("utf8").splitlines()) - self.assertEqual(res.rc, 0) - - -def main(): - if __name__ != '__main__': - return - if sys.argv[1:] == ['-g']: - for statements, kind in ((exec_tests, "exec"), (single_tests, "single"), - (eval_tests, "eval")): - print(kind+"_results = [") - for statement in statements: - tree = ast.parse(statement, "?", kind) - print("%r," % (to_tuple(tree),)) - print("]") - print("main()") - raise SystemExit - unittest.main() - -#### EVERYTHING BELOW IS GENERATED BY python Lib/test/test_ast.py -g ##### -exec_results = [ -('Module', [('Expr', (1, 0, 1, 4), ('Constant', (1, 0, 1, 4), None, None))], []), -('Module', [('Expr', (1, 0, 1, 18), ('Constant', (1, 0, 1, 18), 'module docstring', None))], []), -('Module', [('FunctionDef', (1, 0, 1, 13), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 9, 1, 13))], [], None, None, [])], []), -('Module', [('FunctionDef', (1, 0, 1, 29), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (1, 9, 1, 29), ('Constant', (1, 9, 1, 29), 'function docstring', None))], [], None, None, [])], []), -('Module', [('FunctionDef', (1, 0, 1, 14), 'f', ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None)], None, [], [], None, []), [('Pass', (1, 10, 1, 14))], [], None, None, [])], []), -('Module', [('FunctionDef', (1, 0, 1, 16), 'f', ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None)], None, [], [], None, [('Constant', (1, 8, 1, 9), 0, None)]), [('Pass', (1, 12, 1, 16))], [], None, None, [])], []), -('Module', [('FunctionDef', (1, 0, 1, 18), 'f', ('arguments', [], [], ('arg', (1, 7, 1, 11), 'args', None, None), [], [], None, []), [('Pass', (1, 14, 1, 18))], [], None, None, [])], []), -('Module', [('FunctionDef', (1, 0, 1, 23), 'f', ('arguments', [], [], ('arg', (1, 7, 1, 16), 'args', ('Starred', (1, 13, 1, 16), ('Name', (1, 14, 1, 16), 'Ts', ('Load',)), ('Load',)), None), [], [], None, []), [('Pass', (1, 19, 1, 23))], [], None, None, [])], []), -('Module', [('FunctionDef', (1, 0, 1, 36), 'f', ('arguments', [], [], ('arg', (1, 7, 1, 29), 'args', ('Starred', (1, 13, 1, 29), ('Subscript', (1, 14, 1, 29), ('Name', (1, 14, 1, 19), 'tuple', ('Load',)), ('Tuple', (1, 20, 1, 28), [('Name', (1, 20, 1, 23), 'int', ('Load',)), ('Constant', (1, 25, 1, 28), Ellipsis, None)], ('Load',)), ('Load',)), ('Load',)), None), [], [], None, []), [('Pass', (1, 32, 1, 36))], [], None, None, [])], []), -('Module', [('FunctionDef', (1, 0, 1, 36), 'f', ('arguments', [], [], ('arg', (1, 7, 1, 29), 'args', ('Starred', (1, 13, 1, 29), ('Subscript', (1, 14, 1, 29), ('Name', (1, 14, 1, 19), 'tuple', ('Load',)), ('Tuple', (1, 20, 1, 28), [('Name', (1, 20, 1, 23), 'int', ('Load',)), ('Starred', (1, 25, 1, 28), ('Name', (1, 26, 1, 28), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), ('Load',)), None), [], [], None, []), [('Pass', (1, 32, 1, 36))], [], None, None, [])], []), -('Module', [('FunctionDef', (1, 0, 1, 21), 'f', ('arguments', [], [], None, [], [], ('arg', (1, 8, 1, 14), 'kwargs', None, None), []), [('Pass', (1, 17, 1, 21))], [], None, None, [])], []), -('Module', [('FunctionDef', (1, 0, 1, 71), 'f', ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None), ('arg', (1, 9, 1, 10), 'b', None, None), ('arg', (1, 14, 1, 15), 'c', None, None), ('arg', (1, 22, 1, 23), 'd', None, None), ('arg', (1, 28, 1, 29), 'e', None, None)], ('arg', (1, 35, 1, 39), 'args', None, None), [('arg', (1, 41, 1, 42), 'f', None, None)], [('Constant', (1, 43, 1, 45), 42, None)], ('arg', (1, 49, 1, 55), 'kwargs', None, None), [('Constant', (1, 11, 1, 12), 1, None), ('Constant', (1, 16, 1, 20), None, None), ('List', (1, 24, 1, 26), [], ('Load',)), ('Dict', (1, 30, 1, 32), [], [])]), [('Expr', (1, 58, 1, 71), ('Constant', (1, 58, 1, 71), 'doc for f()', None))], [], None, None, [])], []), -('Module', [('FunctionDef', (1, 0, 1, 27), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 23, 1, 27))], [], ('Subscript', (1, 11, 1, 21), ('Name', (1, 11, 1, 16), 'tuple', ('Load',)), ('Tuple', (1, 17, 1, 20), [('Starred', (1, 17, 1, 20), ('Name', (1, 18, 1, 20), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), None, [])], []), -('Module', [('FunctionDef', (1, 0, 1, 32), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 28, 1, 32))], [], ('Subscript', (1, 11, 1, 26), ('Name', (1, 11, 1, 16), 'tuple', ('Load',)), ('Tuple', (1, 17, 1, 25), [('Name', (1, 17, 1, 20), 'int', ('Load',)), ('Starred', (1, 22, 1, 25), ('Name', (1, 23, 1, 25), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), None, [])], []), -('Module', [('FunctionDef', (1, 0, 1, 45), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 41, 1, 45))], [], ('Subscript', (1, 11, 1, 39), ('Name', (1, 11, 1, 16), 'tuple', ('Load',)), ('Tuple', (1, 17, 1, 38), [('Name', (1, 17, 1, 20), 'int', ('Load',)), ('Starred', (1, 22, 1, 38), ('Subscript', (1, 23, 1, 38), ('Name', (1, 23, 1, 28), 'tuple', ('Load',)), ('Tuple', (1, 29, 1, 37), [('Name', (1, 29, 1, 32), 'int', ('Load',)), ('Constant', (1, 34, 1, 37), Ellipsis, None)], ('Load',)), ('Load',)), ('Load',))], ('Load',)), ('Load',)), None, [])], []), -('Module', [('ClassDef', (1, 0, 1, 12), 'C', [], [], [('Pass', (1, 8, 1, 12))], [], [])], []), -('Module', [('ClassDef', (1, 0, 1, 32), 'C', [], [], [('Expr', (1, 9, 1, 32), ('Constant', (1, 9, 1, 32), 'docstring for class C', None))], [], [])], []), -('Module', [('ClassDef', (1, 0, 1, 21), 'C', [('Name', (1, 8, 1, 14), 'object', ('Load',))], [], [('Pass', (1, 17, 1, 21))], [], [])], []), -('Module', [('FunctionDef', (1, 0, 1, 16), 'f', ('arguments', [], [], None, [], [], None, []), [('Return', (1, 8, 1, 16), ('Constant', (1, 15, 1, 16), 1, None))], [], None, None, [])], []), -('Module', [('Delete', (1, 0, 1, 5), [('Name', (1, 4, 1, 5), 'v', ('Del',))])], []), -('Module', [('Assign', (1, 0, 1, 5), [('Name', (1, 0, 1, 1), 'v', ('Store',))], ('Constant', (1, 4, 1, 5), 1, None), None)], []), -('Module', [('Assign', (1, 0, 1, 7), [('Tuple', (1, 0, 1, 3), [('Name', (1, 0, 1, 1), 'a', ('Store',)), ('Name', (1, 2, 1, 3), 'b', ('Store',))], ('Store',))], ('Name', (1, 6, 1, 7), 'c', ('Load',)), None)], []), -('Module', [('Assign', (1, 0, 1, 9), [('Tuple', (1, 0, 1, 5), [('Name', (1, 1, 1, 2), 'a', ('Store',)), ('Name', (1, 3, 1, 4), 'b', ('Store',))], ('Store',))], ('Name', (1, 8, 1, 9), 'c', ('Load',)), None)], []), -('Module', [('Assign', (1, 0, 1, 9), [('List', (1, 0, 1, 5), [('Name', (1, 1, 1, 2), 'a', ('Store',)), ('Name', (1, 3, 1, 4), 'b', ('Store',))], ('Store',))], ('Name', (1, 8, 1, 9), 'c', ('Load',)), None)], []), -('Module', [('AnnAssign', (1, 0, 1, 13), ('Name', (1, 0, 1, 1), 'x', ('Store',)), ('Subscript', (1, 3, 1, 13), ('Name', (1, 3, 1, 8), 'tuple', ('Load',)), ('Tuple', (1, 9, 1, 12), [('Starred', (1, 9, 1, 12), ('Name', (1, 10, 1, 12), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), None, 1)], []), -('Module', [('AnnAssign', (1, 0, 1, 18), ('Name', (1, 0, 1, 1), 'x', ('Store',)), ('Subscript', (1, 3, 1, 18), ('Name', (1, 3, 1, 8), 'tuple', ('Load',)), ('Tuple', (1, 9, 1, 17), [('Name', (1, 9, 1, 12), 'int', ('Load',)), ('Starred', (1, 14, 1, 17), ('Name', (1, 15, 1, 17), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), None, 1)], []), -('Module', [('AnnAssign', (1, 0, 1, 31), ('Name', (1, 0, 1, 1), 'x', ('Store',)), ('Subscript', (1, 3, 1, 31), ('Name', (1, 3, 1, 8), 'tuple', ('Load',)), ('Tuple', (1, 9, 1, 30), [('Name', (1, 9, 1, 12), 'int', ('Load',)), ('Starred', (1, 14, 1, 30), ('Subscript', (1, 15, 1, 30), ('Name', (1, 15, 1, 20), 'tuple', ('Load',)), ('Tuple', (1, 21, 1, 29), [('Name', (1, 21, 1, 24), 'str', ('Load',)), ('Constant', (1, 26, 1, 29), Ellipsis, None)], ('Load',)), ('Load',)), ('Load',))], ('Load',)), ('Load',)), None, 1)], []), -('Module', [('AugAssign', (1, 0, 1, 6), ('Name', (1, 0, 1, 1), 'v', ('Store',)), ('Add',), ('Constant', (1, 5, 1, 6), 1, None))], []), -('Module', [('For', (1, 0, 1, 15), ('Name', (1, 4, 1, 5), 'v', ('Store',)), ('Name', (1, 9, 1, 10), 'v', ('Load',)), [('Pass', (1, 11, 1, 15))], [], None)], []), -('Module', [('While', (1, 0, 1, 12), ('Name', (1, 6, 1, 7), 'v', ('Load',)), [('Pass', (1, 8, 1, 12))], [])], []), -('Module', [('If', (1, 0, 1, 9), ('Name', (1, 3, 1, 4), 'v', ('Load',)), [('Pass', (1, 5, 1, 9))], [])], []), -('Module', [('If', (1, 0, 4, 6), ('Name', (1, 3, 1, 4), 'a', ('Load',)), [('Pass', (2, 2, 2, 6))], [('If', (3, 0, 4, 6), ('Name', (3, 5, 3, 6), 'b', ('Load',)), [('Pass', (4, 2, 4, 6))], [])])], []), -('Module', [('If', (1, 0, 6, 6), ('Name', (1, 3, 1, 4), 'a', ('Load',)), [('Pass', (2, 2, 2, 6))], [('If', (3, 0, 6, 6), ('Name', (3, 5, 3, 6), 'b', ('Load',)), [('Pass', (4, 2, 4, 6))], [('Pass', (6, 2, 6, 6))])])], []), -('Module', [('With', (1, 0, 1, 17), [('withitem', ('Name', (1, 5, 1, 6), 'x', ('Load',)), ('Name', (1, 10, 1, 11), 'y', ('Store',)))], [('Pass', (1, 13, 1, 17))], None)], []), -('Module', [('With', (1, 0, 1, 25), [('withitem', ('Name', (1, 5, 1, 6), 'x', ('Load',)), ('Name', (1, 10, 1, 11), 'y', ('Store',))), ('withitem', ('Name', (1, 13, 1, 14), 'z', ('Load',)), ('Name', (1, 18, 1, 19), 'q', ('Store',)))], [('Pass', (1, 21, 1, 25))], None)], []), -('Module', [('Raise', (1, 0, 1, 25), ('Call', (1, 6, 1, 25), ('Name', (1, 6, 1, 15), 'Exception', ('Load',)), [('Constant', (1, 16, 1, 24), 'string', None)], []), None)], []), -('Module', [('Try', (1, 0, 4, 6), [('Pass', (2, 2, 2, 6))], [('ExceptHandler', (3, 0, 4, 6), ('Name', (3, 7, 3, 16), 'Exception', ('Load',)), None, [('Pass', (4, 2, 4, 6))])], [], [])], []), -('Module', [('Try', (1, 0, 4, 6), [('Pass', (2, 2, 2, 6))], [], [], [('Pass', (4, 2, 4, 6))])], []), -('Module', [('TryStar', (1, 0, 4, 6), [('Pass', (2, 2, 2, 6))], [('ExceptHandler', (3, 0, 4, 6), ('Name', (3, 8, 3, 17), 'Exception', ('Load',)), None, [('Pass', (4, 2, 4, 6))])], [], [])], []), -('Module', [('Assert', (1, 0, 1, 8), ('Name', (1, 7, 1, 8), 'v', ('Load',)), None)], []), -('Module', [('Import', (1, 0, 1, 10), [('alias', (1, 7, 1, 10), 'sys', None)])], []), -('Module', [('ImportFrom', (1, 0, 1, 17), 'sys', [('alias', (1, 16, 1, 17), 'v', None)], 0)], []), -('Module', [('Global', (1, 0, 1, 8), ['v'])], []), -('Module', [('Expr', (1, 0, 1, 1), ('Constant', (1, 0, 1, 1), 1, None))], []), -('Module', [('Pass', (1, 0, 1, 4))], []), -('Module', [('For', (1, 0, 1, 16), ('Name', (1, 4, 1, 5), 'v', ('Store',)), ('Name', (1, 9, 1, 10), 'v', ('Load',)), [('Break', (1, 11, 1, 16))], [], None)], []), -('Module', [('For', (1, 0, 1, 19), ('Name', (1, 4, 1, 5), 'v', ('Store',)), ('Name', (1, 9, 1, 10), 'v', ('Load',)), [('Continue', (1, 11, 1, 19))], [], None)], []), -('Module', [('For', (1, 0, 1, 18), ('Tuple', (1, 4, 1, 7), [('Name', (1, 4, 1, 5), 'a', ('Store',)), ('Name', (1, 6, 1, 7), 'b', ('Store',))], ('Store',)), ('Name', (1, 11, 1, 12), 'c', ('Load',)), [('Pass', (1, 14, 1, 18))], [], None)], []), -('Module', [('For', (1, 0, 1, 20), ('Tuple', (1, 4, 1, 9), [('Name', (1, 5, 1, 6), 'a', ('Store',)), ('Name', (1, 7, 1, 8), 'b', ('Store',))], ('Store',)), ('Name', (1, 13, 1, 14), 'c', ('Load',)), [('Pass', (1, 16, 1, 20))], [], None)], []), -('Module', [('For', (1, 0, 1, 20), ('List', (1, 4, 1, 9), [('Name', (1, 5, 1, 6), 'a', ('Store',)), ('Name', (1, 7, 1, 8), 'b', ('Store',))], ('Store',)), ('Name', (1, 13, 1, 14), 'c', ('Load',)), [('Pass', (1, 16, 1, 20))], [], None)], []), -('Module', [('Expr', (1, 0, 11, 5), ('GeneratorExp', (1, 0, 11, 5), ('Tuple', (2, 4, 6, 5), [('Name', (3, 4, 3, 6), 'Aa', ('Load',)), ('Name', (5, 7, 5, 9), 'Bb', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (8, 4, 10, 6), [('Name', (8, 4, 8, 6), 'Aa', ('Store',)), ('Name', (10, 4, 10, 6), 'Bb', ('Store',))], ('Store',)), ('Name', (10, 10, 10, 12), 'Cc', ('Load',)), [], 0)]))], []), -('Module', [('Expr', (1, 0, 1, 34), ('DictComp', (1, 0, 1, 34), ('Name', (1, 1, 1, 2), 'a', ('Load',)), ('Name', (1, 5, 1, 6), 'b', ('Load',)), [('comprehension', ('Name', (1, 11, 1, 12), 'w', ('Store',)), ('Name', (1, 16, 1, 17), 'x', ('Load',)), [], 0), ('comprehension', ('Name', (1, 22, 1, 23), 'm', ('Store',)), ('Name', (1, 27, 1, 28), 'p', ('Load',)), [('Name', (1, 32, 1, 33), 'g', ('Load',))], 0)]))], []), -('Module', [('Expr', (1, 0, 1, 20), ('DictComp', (1, 0, 1, 20), ('Name', (1, 1, 1, 2), 'a', ('Load',)), ('Name', (1, 5, 1, 6), 'b', ('Load',)), [('comprehension', ('Tuple', (1, 11, 1, 14), [('Name', (1, 11, 1, 12), 'v', ('Store',)), ('Name', (1, 13, 1, 14), 'w', ('Store',))], ('Store',)), ('Name', (1, 18, 1, 19), 'x', ('Load',)), [], 0)]))], []), -('Module', [('Expr', (1, 0, 1, 19), ('SetComp', (1, 0, 1, 19), ('Name', (1, 1, 1, 2), 'r', ('Load',)), [('comprehension', ('Name', (1, 7, 1, 8), 'l', ('Store',)), ('Name', (1, 12, 1, 13), 'x', ('Load',)), [('Name', (1, 17, 1, 18), 'g', ('Load',))], 0)]))], []), -('Module', [('Expr', (1, 0, 1, 16), ('SetComp', (1, 0, 1, 16), ('Name', (1, 1, 1, 2), 'r', ('Load',)), [('comprehension', ('Tuple', (1, 7, 1, 10), [('Name', (1, 7, 1, 8), 'l', ('Store',)), ('Name', (1, 9, 1, 10), 'm', ('Store',))], ('Store',)), ('Name', (1, 14, 1, 15), 'x', ('Load',)), [], 0)]))], []), -('Module', [('AsyncFunctionDef', (1, 0, 3, 18), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (2, 1, 2, 17), ('Constant', (2, 1, 2, 17), 'async function', None)), ('Expr', (3, 1, 3, 18), ('Await', (3, 1, 3, 18), ('Call', (3, 7, 3, 18), ('Name', (3, 7, 3, 16), 'something', ('Load',)), [], [])))], [], None, None, [])], []), -('Module', [('AsyncFunctionDef', (1, 0, 3, 8), 'f', ('arguments', [], [], None, [], [], None, []), [('AsyncFor', (2, 1, 3, 8), ('Name', (2, 11, 2, 12), 'e', ('Store',)), ('Name', (2, 16, 2, 17), 'i', ('Load',)), [('Expr', (2, 19, 2, 20), ('Constant', (2, 19, 2, 20), 1, None))], [('Expr', (3, 7, 3, 8), ('Constant', (3, 7, 3, 8), 2, None))], None)], [], None, None, [])], []), -('Module', [('AsyncFunctionDef', (1, 0, 2, 21), 'f', ('arguments', [], [], None, [], [], None, []), [('AsyncWith', (2, 1, 2, 21), [('withitem', ('Name', (2, 12, 2, 13), 'a', ('Load',)), ('Name', (2, 17, 2, 18), 'b', ('Store',)))], [('Expr', (2, 20, 2, 21), ('Constant', (2, 20, 2, 21), 1, None))], None)], [], None, None, [])], []), -('Module', [('Expr', (1, 0, 1, 14), ('Dict', (1, 0, 1, 14), [None, ('Constant', (1, 10, 1, 11), 2, None)], [('Dict', (1, 3, 1, 8), [('Constant', (1, 4, 1, 5), 1, None)], [('Constant', (1, 6, 1, 7), 2, None)]), ('Constant', (1, 12, 1, 13), 3, None)]))], []), -('Module', [('Expr', (1, 0, 1, 12), ('Set', (1, 0, 1, 12), [('Starred', (1, 1, 1, 8), ('Set', (1, 2, 1, 8), [('Constant', (1, 3, 1, 4), 1, None), ('Constant', (1, 6, 1, 7), 2, None)]), ('Load',)), ('Constant', (1, 10, 1, 11), 3, None)]))], []), -('Module', [('AsyncFunctionDef', (1, 0, 2, 21), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (2, 1, 2, 21), ('ListComp', (2, 1, 2, 21), ('Name', (2, 2, 2, 3), 'i', ('Load',)), [('comprehension', ('Name', (2, 14, 2, 15), 'b', ('Store',)), ('Name', (2, 19, 2, 20), 'c', ('Load',)), [], 1)]))], [], None, None, [])], []), -('Module', [('FunctionDef', (4, 0, 4, 13), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (4, 9, 4, 13))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])], None, None, [])], []), -('Module', [('AsyncFunctionDef', (4, 0, 4, 19), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (4, 15, 4, 19))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])], None, None, [])], []), -('Module', [('ClassDef', (4, 0, 4, 13), 'C', [], [], [('Pass', (4, 9, 4, 13))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])], [])], []), -('Module', [('FunctionDef', (2, 0, 2, 13), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (2, 9, 2, 13))], [('Call', (1, 1, 1, 19), ('Name', (1, 1, 1, 5), 'deco', ('Load',)), [('GeneratorExp', (1, 5, 1, 19), ('Name', (1, 6, 1, 7), 'a', ('Load',)), [('comprehension', ('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 17, 1, 18), 'b', ('Load',)), [], 0)])], [])], None, None, [])], []), -('Module', [('FunctionDef', (2, 0, 2, 13), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (2, 9, 2, 13))], [('Attribute', (1, 1, 1, 6), ('Attribute', (1, 1, 1, 4), ('Name', (1, 1, 1, 2), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',))], None, None, [])], []), -('Module', [('Expr', (1, 0, 1, 8), ('NamedExpr', (1, 1, 1, 7), ('Name', (1, 1, 1, 2), 'a', ('Store',)), ('Constant', (1, 6, 1, 7), 1, None)))], []), -('Module', [('FunctionDef', (1, 0, 1, 18), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [], None, [], [], None, []), [('Pass', (1, 14, 1, 18))], [], None, None, [])], []), -('Module', [('FunctionDef', (1, 0, 1, 26), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None), ('arg', (1, 15, 1, 16), 'd', None, None), ('arg', (1, 18, 1, 19), 'e', None, None)], None, [], [], None, []), [('Pass', (1, 22, 1, 26))], [], None, None, [])], []), -('Module', [('FunctionDef', (1, 0, 1, 29), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None)], None, [('arg', (1, 18, 1, 19), 'd', None, None), ('arg', (1, 21, 1, 22), 'e', None, None)], [None, None], None, []), [('Pass', (1, 25, 1, 29))], [], None, None, [])], []), -('Module', [('FunctionDef', (1, 0, 1, 39), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None)], None, [('arg', (1, 18, 1, 19), 'd', None, None), ('arg', (1, 21, 1, 22), 'e', None, None)], [None, None], ('arg', (1, 26, 1, 32), 'kwargs', None, None), []), [('Pass', (1, 35, 1, 39))], [], None, None, [])], []), -('Module', [('FunctionDef', (1, 0, 1, 20), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [], None, [], [], None, [('Constant', (1, 8, 1, 9), 1, None)]), [('Pass', (1, 16, 1, 20))], [], None, None, [])], []), -('Module', [('FunctionDef', (1, 0, 1, 29), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None), ('arg', (1, 19, 1, 20), 'c', None, None)], None, [], [], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None), ('Constant', (1, 21, 1, 22), 4, None)]), [('Pass', (1, 25, 1, 29))], [], None, None, [])], []), -('Module', [('FunctionDef', (1, 0, 1, 32), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [('Constant', (1, 24, 1, 25), 4, None)], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 28, 1, 32))], [], None, None, [])], []), -('Module', [('FunctionDef', (1, 0, 1, 30), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [None], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 26, 1, 30))], [], None, None, [])], []), -('Module', [('FunctionDef', (1, 0, 1, 42), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [('Constant', (1, 24, 1, 25), 4, None)], ('arg', (1, 29, 1, 35), 'kwargs', None, None), [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 38, 1, 42))], [], None, None, [])], []), -('Module', [('FunctionDef', (1, 0, 1, 40), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [None], ('arg', (1, 27, 1, 33), 'kwargs', None, None), [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 36, 1, 40))], [], None, None, [])], []), -('Module', [('TypeAlias', (1, 0, 1, 12), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [], ('Name', (1, 9, 1, 12), 'int', ('Load',)))], []), -('Module', [('TypeAlias', (1, 0, 1, 15), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 8), 'T', None)], ('Name', (1, 12, 1, 15), 'int', ('Load',)))], []), -('Module', [('TypeAlias', (1, 0, 1, 32), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 8), 'T', None), ('TypeVarTuple', (1, 10, 1, 13), 'Ts'), ('ParamSpec', (1, 15, 1, 18), 'P')], ('Tuple', (1, 22, 1, 32), [('Name', (1, 23, 1, 24), 'T', ('Load',)), ('Name', (1, 26, 1, 28), 'Ts', ('Load',)), ('Name', (1, 30, 1, 31), 'P', ('Load',))], ('Load',)))], []), -('Module', [('TypeAlias', (1, 0, 1, 37), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 13), 'T', ('Name', (1, 10, 1, 13), 'int', ('Load',))), ('TypeVarTuple', (1, 15, 1, 18), 'Ts'), ('ParamSpec', (1, 20, 1, 23), 'P')], ('Tuple', (1, 27, 1, 37), [('Name', (1, 28, 1, 29), 'T', ('Load',)), ('Name', (1, 31, 1, 33), 'Ts', ('Load',)), ('Name', (1, 35, 1, 36), 'P', ('Load',))], ('Load',)))], []), -('Module', [('TypeAlias', (1, 0, 1, 44), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 20), 'T', ('Tuple', (1, 10, 1, 20), [('Name', (1, 11, 1, 14), 'int', ('Load',)), ('Name', (1, 16, 1, 19), 'str', ('Load',))], ('Load',))), ('TypeVarTuple', (1, 22, 1, 25), 'Ts'), ('ParamSpec', (1, 27, 1, 30), 'P')], ('Tuple', (1, 34, 1, 44), [('Name', (1, 35, 1, 36), 'T', ('Load',)), ('Name', (1, 38, 1, 40), 'Ts', ('Load',)), ('Name', (1, 42, 1, 43), 'P', ('Load',))], ('Load',)))], []), -('Module', [('ClassDef', (1, 0, 1, 16), 'X', [], [], [('Pass', (1, 12, 1, 16))], [], [('TypeVar', (1, 8, 1, 9), 'T', None)])], []), -('Module', [('ClassDef', (1, 0, 1, 26), 'X', [], [], [('Pass', (1, 22, 1, 26))], [], [('TypeVar', (1, 8, 1, 9), 'T', None), ('TypeVarTuple', (1, 11, 1, 14), 'Ts'), ('ParamSpec', (1, 16, 1, 19), 'P')])], []), -('Module', [('ClassDef', (1, 0, 1, 31), 'X', [], [], [('Pass', (1, 27, 1, 31))], [], [('TypeVar', (1, 8, 1, 14), 'T', ('Name', (1, 11, 1, 14), 'int', ('Load',))), ('TypeVarTuple', (1, 16, 1, 19), 'Ts'), ('ParamSpec', (1, 21, 1, 24), 'P')])], []), -('Module', [('ClassDef', (1, 0, 1, 38), 'X', [], [], [('Pass', (1, 34, 1, 38))], [], [('TypeVar', (1, 8, 1, 21), 'T', ('Tuple', (1, 11, 1, 21), [('Name', (1, 12, 1, 15), 'int', ('Load',)), ('Name', (1, 17, 1, 20), 'str', ('Load',))], ('Load',))), ('TypeVarTuple', (1, 23, 1, 26), 'Ts'), ('ParamSpec', (1, 28, 1, 31), 'P')])], []), -('Module', [('FunctionDef', (1, 0, 1, 16), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 12, 1, 16))], [], None, None, [('TypeVar', (1, 6, 1, 7), 'T', None)])], []), -('Module', [('FunctionDef', (1, 0, 1, 26), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 22, 1, 26))], [], None, None, [('TypeVar', (1, 6, 1, 7), 'T', None), ('TypeVarTuple', (1, 9, 1, 12), 'Ts'), ('ParamSpec', (1, 14, 1, 17), 'P')])], []), -('Module', [('FunctionDef', (1, 0, 1, 31), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 27, 1, 31))], [], None, None, [('TypeVar', (1, 6, 1, 12), 'T', ('Name', (1, 9, 1, 12), 'int', ('Load',))), ('TypeVarTuple', (1, 14, 1, 17), 'Ts'), ('ParamSpec', (1, 19, 1, 22), 'P')])], []), -('Module', [('FunctionDef', (1, 0, 1, 38), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 34, 1, 38))], [], None, None, [('TypeVar', (1, 6, 1, 19), 'T', ('Tuple', (1, 9, 1, 19), [('Name', (1, 10, 1, 13), 'int', ('Load',)), ('Name', (1, 15, 1, 18), 'str', ('Load',))], ('Load',))), ('TypeVarTuple', (1, 21, 1, 24), 'Ts'), ('ParamSpec', (1, 26, 1, 29), 'P')])], []), -] -single_results = [ -('Interactive', [('Expr', (1, 0, 1, 3), ('BinOp', (1, 0, 1, 3), ('Constant', (1, 0, 1, 1), 1, None), ('Add',), ('Constant', (1, 2, 1, 3), 2, None)))]), -] -eval_results = [ -('Expression', ('Constant', (1, 0, 1, 4), None, None)), -('Expression', ('BoolOp', (1, 0, 1, 7), ('And',), [('Name', (1, 0, 1, 1), 'a', ('Load',)), ('Name', (1, 6, 1, 7), 'b', ('Load',))])), -('Expression', ('BinOp', (1, 0, 1, 5), ('Name', (1, 0, 1, 1), 'a', ('Load',)), ('Add',), ('Name', (1, 4, 1, 5), 'b', ('Load',)))), -('Expression', ('UnaryOp', (1, 0, 1, 5), ('Not',), ('Name', (1, 4, 1, 5), 'v', ('Load',)))), -('Expression', ('Lambda', (1, 0, 1, 11), ('arguments', [], [], None, [], [], None, []), ('Constant', (1, 7, 1, 11), None, None))), -('Expression', ('Dict', (1, 0, 1, 7), [('Constant', (1, 2, 1, 3), 1, None)], [('Constant', (1, 4, 1, 5), 2, None)])), -('Expression', ('Dict', (1, 0, 1, 2), [], [])), -('Expression', ('Set', (1, 0, 1, 7), [('Constant', (1, 1, 1, 5), None, None)])), -('Expression', ('Dict', (1, 0, 5, 6), [('Constant', (2, 6, 2, 7), 1, None)], [('Constant', (4, 10, 4, 11), 2, None)])), -('Expression', ('ListComp', (1, 0, 1, 19), ('Name', (1, 1, 1, 2), 'a', ('Load',)), [('comprehension', ('Name', (1, 7, 1, 8), 'b', ('Store',)), ('Name', (1, 12, 1, 13), 'c', ('Load',)), [('Name', (1, 17, 1, 18), 'd', ('Load',))], 0)])), -('Expression', ('GeneratorExp', (1, 0, 1, 19), ('Name', (1, 1, 1, 2), 'a', ('Load',)), [('comprehension', ('Name', (1, 7, 1, 8), 'b', ('Store',)), ('Name', (1, 12, 1, 13), 'c', ('Load',)), [('Name', (1, 17, 1, 18), 'd', ('Load',))], 0)])), -('Expression', ('ListComp', (1, 0, 1, 20), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11, 1, 14), [('Name', (1, 11, 1, 12), 'a', ('Store',)), ('Name', (1, 13, 1, 14), 'b', ('Store',))], ('Store',)), ('Name', (1, 18, 1, 19), 'c', ('Load',)), [], 0)])), -('Expression', ('ListComp', (1, 0, 1, 22), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11, 1, 16), [('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 14, 1, 15), 'b', ('Store',))], ('Store',)), ('Name', (1, 20, 1, 21), 'c', ('Load',)), [], 0)])), -('Expression', ('ListComp', (1, 0, 1, 22), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('List', (1, 11, 1, 16), [('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 14, 1, 15), 'b', ('Store',))], ('Store',)), ('Name', (1, 20, 1, 21), 'c', ('Load',)), [], 0)])), -('Expression', ('SetComp', (1, 0, 1, 20), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11, 1, 14), [('Name', (1, 11, 1, 12), 'a', ('Store',)), ('Name', (1, 13, 1, 14), 'b', ('Store',))], ('Store',)), ('Name', (1, 18, 1, 19), 'c', ('Load',)), [], 0)])), -('Expression', ('SetComp', (1, 0, 1, 22), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11, 1, 16), [('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 14, 1, 15), 'b', ('Store',))], ('Store',)), ('Name', (1, 20, 1, 21), 'c', ('Load',)), [], 0)])), -('Expression', ('SetComp', (1, 0, 1, 22), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('List', (1, 11, 1, 16), [('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 14, 1, 15), 'b', ('Store',))], ('Store',)), ('Name', (1, 20, 1, 21), 'c', ('Load',)), [], 0)])), -('Expression', ('GeneratorExp', (1, 0, 1, 20), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11, 1, 14), [('Name', (1, 11, 1, 12), 'a', ('Store',)), ('Name', (1, 13, 1, 14), 'b', ('Store',))], ('Store',)), ('Name', (1, 18, 1, 19), 'c', ('Load',)), [], 0)])), -('Expression', ('GeneratorExp', (1, 0, 1, 22), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11, 1, 16), [('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 14, 1, 15), 'b', ('Store',))], ('Store',)), ('Name', (1, 20, 1, 21), 'c', ('Load',)), [], 0)])), -('Expression', ('GeneratorExp', (1, 0, 1, 22), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('List', (1, 11, 1, 16), [('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 14, 1, 15), 'b', ('Store',))], ('Store',)), ('Name', (1, 20, 1, 21), 'c', ('Load',)), [], 0)])), -('Expression', ('Compare', (1, 0, 1, 9), ('Constant', (1, 0, 1, 1), 1, None), [('Lt',), ('Lt',)], [('Constant', (1, 4, 1, 5), 2, None), ('Constant', (1, 8, 1, 9), 3, None)])), -('Expression', ('Call', (1, 0, 1, 17), ('Name', (1, 0, 1, 1), 'f', ('Load',)), [('Constant', (1, 2, 1, 3), 1, None), ('Constant', (1, 4, 1, 5), 2, None), ('Starred', (1, 10, 1, 12), ('Name', (1, 11, 1, 12), 'd', ('Load',)), ('Load',))], [('keyword', (1, 6, 1, 9), 'c', ('Constant', (1, 8, 1, 9), 3, None)), ('keyword', (1, 13, 1, 16), None, ('Name', (1, 15, 1, 16), 'e', ('Load',)))])), -('Expression', ('Call', (1, 0, 1, 10), ('Name', (1, 0, 1, 1), 'f', ('Load',)), [('Starred', (1, 2, 1, 9), ('List', (1, 3, 1, 9), [('Constant', (1, 4, 1, 5), 0, None), ('Constant', (1, 7, 1, 8), 1, None)], ('Load',)), ('Load',))], [])), -('Expression', ('Call', (1, 0, 1, 15), ('Name', (1, 0, 1, 1), 'f', ('Load',)), [('GeneratorExp', (1, 1, 1, 15), ('Name', (1, 2, 1, 3), 'a', ('Load',)), [('comprehension', ('Name', (1, 8, 1, 9), 'a', ('Store',)), ('Name', (1, 13, 1, 14), 'b', ('Load',)), [], 0)])], [])), -('Expression', ('Constant', (1, 0, 1, 2), 10, None)), -('Expression', ('Constant', (1, 0, 1, 8), 'string', None)), -('Expression', ('Attribute', (1, 0, 1, 3), ('Name', (1, 0, 1, 1), 'a', ('Load',)), 'b', ('Load',))), -('Expression', ('Subscript', (1, 0, 1, 6), ('Name', (1, 0, 1, 1), 'a', ('Load',)), ('Slice', (1, 2, 1, 5), ('Name', (1, 2, 1, 3), 'b', ('Load',)), ('Name', (1, 4, 1, 5), 'c', ('Load',)), None), ('Load',))), -('Expression', ('Name', (1, 0, 1, 1), 'v', ('Load',))), -('Expression', ('List', (1, 0, 1, 7), [('Constant', (1, 1, 1, 2), 1, None), ('Constant', (1, 3, 1, 4), 2, None), ('Constant', (1, 5, 1, 6), 3, None)], ('Load',))), -('Expression', ('List', (1, 0, 1, 2), [], ('Load',))), -('Expression', ('Tuple', (1, 0, 1, 5), [('Constant', (1, 0, 1, 1), 1, None), ('Constant', (1, 2, 1, 3), 2, None), ('Constant', (1, 4, 1, 5), 3, None)], ('Load',))), -('Expression', ('Tuple', (1, 0, 1, 7), [('Constant', (1, 1, 1, 2), 1, None), ('Constant', (1, 3, 1, 4), 2, None), ('Constant', (1, 5, 1, 6), 3, None)], ('Load',))), -('Expression', ('Tuple', (1, 0, 1, 2), [], ('Load',))), -('Expression', ('Call', (1, 0, 1, 17), ('Attribute', (1, 0, 1, 7), ('Attribute', (1, 0, 1, 5), ('Attribute', (1, 0, 1, 3), ('Name', (1, 0, 1, 1), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',)), 'd', ('Load',)), [('Subscript', (1, 8, 1, 16), ('Attribute', (1, 8, 1, 11), ('Name', (1, 8, 1, 9), 'a', ('Load',)), 'b', ('Load',)), ('Slice', (1, 12, 1, 15), ('Constant', (1, 12, 1, 13), 1, None), ('Constant', (1, 14, 1, 15), 2, None), None), ('Load',))], [])), -] -main() diff --git a/Lib/test/test_ast/__init__.py b/Lib/test/test_ast/__init__.py new file mode 100644 index 00000000..9a89d27b --- /dev/null +++ b/Lib/test/test_ast/__init__.py @@ -0,0 +1,7 @@ +import os + +from test import support + + +def load_tests(*args): + return support.load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_ast/snippets.py b/Lib/test/test_ast/snippets.py new file mode 100644 index 00000000..6ed466fe --- /dev/null +++ b/Lib/test/test_ast/snippets.py @@ -0,0 +1,400 @@ +import ast +import sys + +from test.test_ast.utils import to_tuple + + +# These tests are compiled through "exec" +# There should be at least one test per statement +exec_tests = [ + # None + "None", + # Module docstring + "'module docstring'", + # FunctionDef + "def f(): pass", + # FunctionDef with docstring + "def f(): 'function docstring'", + # FunctionDef with arg + "def f(a): pass", + # FunctionDef with arg and default value + "def f(a=0): pass", + # FunctionDef with varargs + "def f(*args): pass", + # FunctionDef with varargs as TypeVarTuple + "def f(*args: *Ts): pass", + # FunctionDef with varargs as unpacked Tuple + "def f(*args: *tuple[int, ...]): pass", + # FunctionDef with varargs as unpacked Tuple *and* TypeVarTuple + "def f(*args: *tuple[int, *Ts]): pass", + # FunctionDef with kwargs + "def f(**kwargs): pass", + # FunctionDef with all kind of args and docstring + "def f(a, b=1, c=None, d=[], e={}, *args, f=42, **kwargs): 'doc for f()'", + # FunctionDef with type annotation on return involving unpacking + "def f() -> tuple[*Ts]: pass", + "def f() -> tuple[int, *Ts]: pass", + "def f() -> tuple[int, *tuple[int, ...]]: pass", + # ClassDef + "class C:pass", + # ClassDef with docstring + "class C: 'docstring for class C'", + # ClassDef, new style class + "class C(object): pass", + # Return + "def f():return 1", + # Delete + "del v", + # Assign + "v = 1", + "a,b = c", + "(a,b) = c", + "[a,b] = c", + # AnnAssign with unpacked types + "x: tuple[*Ts]", + "x: tuple[int, *Ts]", + "x: tuple[int, *tuple[str, ...]]", + # AugAssign + "v += 1", + # For + "for v in v:pass", + # While + "while v:pass", + # If + "if v:pass", + # If-Elif + "if a:\n pass\nelif b:\n pass", + # If-Elif-Else + "if a:\n pass\nelif b:\n pass\nelse:\n pass", + # With + "with x as y: pass", + "with x as y, z as q: pass", + # Raise + "raise Exception('string')", + # TryExcept + "try:\n pass\nexcept Exception:\n pass", + # TryFinally + "try:\n pass\nfinally:\n pass", + # TryStarExcept + "try:\n pass\nexcept* Exception:\n pass", + # Assert + "assert v", + # Import + "import sys", + # ImportFrom + "from sys import v", + # Global + "global v", + # Expr + "1", + # Pass, + "pass", + # Break + "for v in v:break", + # Continue + "for v in v:continue", + # for statements with naked tuples (see http://bugs.python.org/issue6704) + "for a,b in c: pass", + "for (a,b) in c: pass", + "for [a,b] in c: pass", + # Multiline generator expression (test for .lineno & .col_offset) + """( + ( + Aa + , + Bb + ) + for + Aa + , + Bb in Cc + )""", + # dictcomp + "{a : b for w in x for m in p if g}", + # dictcomp with naked tuple + "{a : b for v,w in x}", + # setcomp + "{r for l in x if g}", + # setcomp with naked tuple + "{r for l,m in x}", + # AsyncFunctionDef + "async def f():\n 'async function'\n await something()", + # AsyncFor + "async def f():\n async for e in i: 1\n else: 2", + # AsyncWith + "async def f():\n async with a as b: 1", + # PEP 448: Additional Unpacking Generalizations + "{**{1:2}, 2:3}", + "{*{1, 2}, 3}", + # Asynchronous comprehensions + "async def f():\n [i async for b in c]", + # Decorated FunctionDef + "@deco1\n@deco2()\n@deco3(1)\ndef f(): pass", + # Decorated AsyncFunctionDef + "@deco1\n@deco2()\n@deco3(1)\nasync def f(): pass", + # Decorated ClassDef + "@deco1\n@deco2()\n@deco3(1)\nclass C: pass", + # Decorator with generator argument + "@deco(a for a in b)\ndef f(): pass", + # Decorator with attribute + "@a.b.c\ndef f(): pass", + # Simple assignment expression + "(a := 1)", + # Positional-only arguments + "def f(a, /,): pass", + "def f(a, /, c, d, e): pass", + "def f(a, /, c, *, d, e): pass", + "def f(a, /, c, *, d, e, **kwargs): pass", + # Positional-only arguments with defaults + "def f(a=1, /,): pass", + "def f(a=1, /, b=2, c=4): pass", + "def f(a=1, /, b=2, *, c=4): pass", + "def f(a=1, /, b=2, *, c): pass", + "def f(a=1, /, b=2, *, c=4, **kwargs): pass", + "def f(a=1, /, b=2, *, c, **kwargs): pass", + # Type aliases + "type X = int", + "type X[T] = int", + "type X[T, *Ts, **P] = (T, Ts, P)", + "type X[T: int, *Ts, **P] = (T, Ts, P)", + "type X[T: (int, str), *Ts, **P] = (T, Ts, P)", + # Generic classes + "class X[T]: pass", + "class X[T, *Ts, **P]: pass", + "class X[T: int, *Ts, **P]: pass", + "class X[T: (int, str), *Ts, **P]: pass", + # Generic functions + "def f[T](): pass", + "def f[T, *Ts, **P](): pass", + "def f[T: int, *Ts, **P](): pass", + "def f[T: (int, str), *Ts, **P](): pass", +] + +# These are compiled through "single" +# because of overlap with "eval", it just tests what +# can't be tested with "eval" +single_tests = ["1+2"] + +# These are compiled through "eval" +# It should test all expressions +eval_tests = [ + # None + "None", + # BoolOp + "a and b", + # BinOp + "a + b", + # UnaryOp + "not v", + # Lambda + "lambda:None", + # Dict + "{ 1:2 }", + # Empty dict + "{}", + # Set + "{None,}", + # Multiline dict (test for .lineno & .col_offset) + """{ + 1 + : + 2 + }""", + # ListComp + "[a for b in c if d]", + # GeneratorExp + "(a for b in c if d)", + # Comprehensions with multiple for targets + "[(a,b) for a,b in c]", + "[(a,b) for (a,b) in c]", + "[(a,b) for [a,b] in c]", + "{(a,b) for a,b in c}", + "{(a,b) for (a,b) in c}", + "{(a,b) for [a,b] in c}", + "((a,b) for a,b in c)", + "((a,b) for (a,b) in c)", + "((a,b) for [a,b] in c)", + # Yield - yield expressions can't work outside a function + # + # Compare + "1 < 2 < 3", + # Call + "f(1,2,c=3,*d,**e)", + # Call with multi-character starred + "f(*[0, 1])", + # Call with a generator argument + "f(a for a in b)", + # Num + "10", + # Str + "'string'", + # Attribute + "a.b", + # Subscript + "a[b:c]", + # Name + "v", + # List + "[1,2,3]", + # Empty list + "[]", + # Tuple + "1,2,3", + # Tuple + "(1,2,3)", + # Empty tuple + "()", + # Combination + "a.b.c.d(a.b[1:2])", +] + + +def main(): + if __name__ != '__main__': + return + if sys.argv[1:] == ['-g']: + for statements, kind in ((exec_tests, "exec"), (single_tests, "single"), + (eval_tests, "eval")): + print(kind+"_results = [") + for statement in statements: + tree = ast.parse(statement, "?", kind) + print("%r," % (to_tuple(tree),)) + print("]") + print("main()") + raise SystemExit + unittest.main() + +#### EVERYTHING BELOW IS GENERATED BY python Lib/test/test_ast/snippets.py -g ##### +exec_results = [ +('Module', [('Expr', (1, 0, 1, 4), ('Constant', (1, 0, 1, 4), None, None))], []), +('Module', [('Expr', (1, 0, 1, 18), ('Constant', (1, 0, 1, 18), 'module docstring', None))], []), +('Module', [('FunctionDef', (1, 0, 1, 13), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 9, 1, 13))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 29), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (1, 9, 1, 29), ('Constant', (1, 9, 1, 29), 'function docstring', None))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 14), 'f', ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None)], None, [], [], None, []), [('Pass', (1, 10, 1, 14))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 16), 'f', ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None)], None, [], [], None, [('Constant', (1, 8, 1, 9), 0, None)]), [('Pass', (1, 12, 1, 16))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 18), 'f', ('arguments', [], [], ('arg', (1, 7, 1, 11), 'args', None, None), [], [], None, []), [('Pass', (1, 14, 1, 18))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 23), 'f', ('arguments', [], [], ('arg', (1, 7, 1, 16), 'args', ('Starred', (1, 13, 1, 16), ('Name', (1, 14, 1, 16), 'Ts', ('Load',)), ('Load',)), None), [], [], None, []), [('Pass', (1, 19, 1, 23))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 36), 'f', ('arguments', [], [], ('arg', (1, 7, 1, 29), 'args', ('Starred', (1, 13, 1, 29), ('Subscript', (1, 14, 1, 29), ('Name', (1, 14, 1, 19), 'tuple', ('Load',)), ('Tuple', (1, 20, 1, 28), [('Name', (1, 20, 1, 23), 'int', ('Load',)), ('Constant', (1, 25, 1, 28), Ellipsis, None)], ('Load',)), ('Load',)), ('Load',)), None), [], [], None, []), [('Pass', (1, 32, 1, 36))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 36), 'f', ('arguments', [], [], ('arg', (1, 7, 1, 29), 'args', ('Starred', (1, 13, 1, 29), ('Subscript', (1, 14, 1, 29), ('Name', (1, 14, 1, 19), 'tuple', ('Load',)), ('Tuple', (1, 20, 1, 28), [('Name', (1, 20, 1, 23), 'int', ('Load',)), ('Starred', (1, 25, 1, 28), ('Name', (1, 26, 1, 28), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), ('Load',)), None), [], [], None, []), [('Pass', (1, 32, 1, 36))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 21), 'f', ('arguments', [], [], None, [], [], ('arg', (1, 8, 1, 14), 'kwargs', None, None), []), [('Pass', (1, 17, 1, 21))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 71), 'f', ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None), ('arg', (1, 9, 1, 10), 'b', None, None), ('arg', (1, 14, 1, 15), 'c', None, None), ('arg', (1, 22, 1, 23), 'd', None, None), ('arg', (1, 28, 1, 29), 'e', None, None)], ('arg', (1, 35, 1, 39), 'args', None, None), [('arg', (1, 41, 1, 42), 'f', None, None)], [('Constant', (1, 43, 1, 45), 42, None)], ('arg', (1, 49, 1, 55), 'kwargs', None, None), [('Constant', (1, 11, 1, 12), 1, None), ('Constant', (1, 16, 1, 20), None, None), ('List', (1, 24, 1, 26), [], ('Load',)), ('Dict', (1, 30, 1, 32), [], [])]), [('Expr', (1, 58, 1, 71), ('Constant', (1, 58, 1, 71), 'doc for f()', None))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 27), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 23, 1, 27))], [], ('Subscript', (1, 11, 1, 21), ('Name', (1, 11, 1, 16), 'tuple', ('Load',)), ('Tuple', (1, 17, 1, 20), [('Starred', (1, 17, 1, 20), ('Name', (1, 18, 1, 20), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 32), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 28, 1, 32))], [], ('Subscript', (1, 11, 1, 26), ('Name', (1, 11, 1, 16), 'tuple', ('Load',)), ('Tuple', (1, 17, 1, 25), [('Name', (1, 17, 1, 20), 'int', ('Load',)), ('Starred', (1, 22, 1, 25), ('Name', (1, 23, 1, 25), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 45), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 41, 1, 45))], [], ('Subscript', (1, 11, 1, 39), ('Name', (1, 11, 1, 16), 'tuple', ('Load',)), ('Tuple', (1, 17, 1, 38), [('Name', (1, 17, 1, 20), 'int', ('Load',)), ('Starred', (1, 22, 1, 38), ('Subscript', (1, 23, 1, 38), ('Name', (1, 23, 1, 28), 'tuple', ('Load',)), ('Tuple', (1, 29, 1, 37), [('Name', (1, 29, 1, 32), 'int', ('Load',)), ('Constant', (1, 34, 1, 37), Ellipsis, None)], ('Load',)), ('Load',)), ('Load',))], ('Load',)), ('Load',)), None, [])], []), +('Module', [('ClassDef', (1, 0, 1, 12), 'C', [], [], [('Pass', (1, 8, 1, 12))], [], [])], []), +('Module', [('ClassDef', (1, 0, 1, 32), 'C', [], [], [('Expr', (1, 9, 1, 32), ('Constant', (1, 9, 1, 32), 'docstring for class C', None))], [], [])], []), +('Module', [('ClassDef', (1, 0, 1, 21), 'C', [('Name', (1, 8, 1, 14), 'object', ('Load',))], [], [('Pass', (1, 17, 1, 21))], [], [])], []), +('Module', [('FunctionDef', (1, 0, 1, 16), 'f', ('arguments', [], [], None, [], [], None, []), [('Return', (1, 8, 1, 16), ('Constant', (1, 15, 1, 16), 1, None))], [], None, None, [])], []), +('Module', [('Delete', (1, 0, 1, 5), [('Name', (1, 4, 1, 5), 'v', ('Del',))])], []), +('Module', [('Assign', (1, 0, 1, 5), [('Name', (1, 0, 1, 1), 'v', ('Store',))], ('Constant', (1, 4, 1, 5), 1, None), None)], []), +('Module', [('Assign', (1, 0, 1, 7), [('Tuple', (1, 0, 1, 3), [('Name', (1, 0, 1, 1), 'a', ('Store',)), ('Name', (1, 2, 1, 3), 'b', ('Store',))], ('Store',))], ('Name', (1, 6, 1, 7), 'c', ('Load',)), None)], []), +('Module', [('Assign', (1, 0, 1, 9), [('Tuple', (1, 0, 1, 5), [('Name', (1, 1, 1, 2), 'a', ('Store',)), ('Name', (1, 3, 1, 4), 'b', ('Store',))], ('Store',))], ('Name', (1, 8, 1, 9), 'c', ('Load',)), None)], []), +('Module', [('Assign', (1, 0, 1, 9), [('List', (1, 0, 1, 5), [('Name', (1, 1, 1, 2), 'a', ('Store',)), ('Name', (1, 3, 1, 4), 'b', ('Store',))], ('Store',))], ('Name', (1, 8, 1, 9), 'c', ('Load',)), None)], []), +('Module', [('AnnAssign', (1, 0, 1, 13), ('Name', (1, 0, 1, 1), 'x', ('Store',)), ('Subscript', (1, 3, 1, 13), ('Name', (1, 3, 1, 8), 'tuple', ('Load',)), ('Tuple', (1, 9, 1, 12), [('Starred', (1, 9, 1, 12), ('Name', (1, 10, 1, 12), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), None, 1)], []), +('Module', [('AnnAssign', (1, 0, 1, 18), ('Name', (1, 0, 1, 1), 'x', ('Store',)), ('Subscript', (1, 3, 1, 18), ('Name', (1, 3, 1, 8), 'tuple', ('Load',)), ('Tuple', (1, 9, 1, 17), [('Name', (1, 9, 1, 12), 'int', ('Load',)), ('Starred', (1, 14, 1, 17), ('Name', (1, 15, 1, 17), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), None, 1)], []), +('Module', [('AnnAssign', (1, 0, 1, 31), ('Name', (1, 0, 1, 1), 'x', ('Store',)), ('Subscript', (1, 3, 1, 31), ('Name', (1, 3, 1, 8), 'tuple', ('Load',)), ('Tuple', (1, 9, 1, 30), [('Name', (1, 9, 1, 12), 'int', ('Load',)), ('Starred', (1, 14, 1, 30), ('Subscript', (1, 15, 1, 30), ('Name', (1, 15, 1, 20), 'tuple', ('Load',)), ('Tuple', (1, 21, 1, 29), [('Name', (1, 21, 1, 24), 'str', ('Load',)), ('Constant', (1, 26, 1, 29), Ellipsis, None)], ('Load',)), ('Load',)), ('Load',))], ('Load',)), ('Load',)), None, 1)], []), +('Module', [('AugAssign', (1, 0, 1, 6), ('Name', (1, 0, 1, 1), 'v', ('Store',)), ('Add',), ('Constant', (1, 5, 1, 6), 1, None))], []), +('Module', [('For', (1, 0, 1, 15), ('Name', (1, 4, 1, 5), 'v', ('Store',)), ('Name', (1, 9, 1, 10), 'v', ('Load',)), [('Pass', (1, 11, 1, 15))], [], None)], []), +('Module', [('While', (1, 0, 1, 12), ('Name', (1, 6, 1, 7), 'v', ('Load',)), [('Pass', (1, 8, 1, 12))], [])], []), +('Module', [('If', (1, 0, 1, 9), ('Name', (1, 3, 1, 4), 'v', ('Load',)), [('Pass', (1, 5, 1, 9))], [])], []), +('Module', [('If', (1, 0, 4, 6), ('Name', (1, 3, 1, 4), 'a', ('Load',)), [('Pass', (2, 2, 2, 6))], [('If', (3, 0, 4, 6), ('Name', (3, 5, 3, 6), 'b', ('Load',)), [('Pass', (4, 2, 4, 6))], [])])], []), +('Module', [('If', (1, 0, 6, 6), ('Name', (1, 3, 1, 4), 'a', ('Load',)), [('Pass', (2, 2, 2, 6))], [('If', (3, 0, 6, 6), ('Name', (3, 5, 3, 6), 'b', ('Load',)), [('Pass', (4, 2, 4, 6))], [('Pass', (6, 2, 6, 6))])])], []), +('Module', [('With', (1, 0, 1, 17), [('withitem', ('Name', (1, 5, 1, 6), 'x', ('Load',)), ('Name', (1, 10, 1, 11), 'y', ('Store',)))], [('Pass', (1, 13, 1, 17))], None)], []), +('Module', [('With', (1, 0, 1, 25), [('withitem', ('Name', (1, 5, 1, 6), 'x', ('Load',)), ('Name', (1, 10, 1, 11), 'y', ('Store',))), ('withitem', ('Name', (1, 13, 1, 14), 'z', ('Load',)), ('Name', (1, 18, 1, 19), 'q', ('Store',)))], [('Pass', (1, 21, 1, 25))], None)], []), +('Module', [('Raise', (1, 0, 1, 25), ('Call', (1, 6, 1, 25), ('Name', (1, 6, 1, 15), 'Exception', ('Load',)), [('Constant', (1, 16, 1, 24), 'string', None)], []), None)], []), +('Module', [('Try', (1, 0, 4, 6), [('Pass', (2, 2, 2, 6))], [('ExceptHandler', (3, 0, 4, 6), ('Name', (3, 7, 3, 16), 'Exception', ('Load',)), None, [('Pass', (4, 2, 4, 6))])], [], [])], []), +('Module', [('Try', (1, 0, 4, 6), [('Pass', (2, 2, 2, 6))], [], [], [('Pass', (4, 2, 4, 6))])], []), +('Module', [('TryStar', (1, 0, 4, 6), [('Pass', (2, 2, 2, 6))], [('ExceptHandler', (3, 0, 4, 6), ('Name', (3, 8, 3, 17), 'Exception', ('Load',)), None, [('Pass', (4, 2, 4, 6))])], [], [])], []), +('Module', [('Assert', (1, 0, 1, 8), ('Name', (1, 7, 1, 8), 'v', ('Load',)), None)], []), +('Module', [('Import', (1, 0, 1, 10), [('alias', (1, 7, 1, 10), 'sys', None)])], []), +('Module', [('ImportFrom', (1, 0, 1, 17), 'sys', [('alias', (1, 16, 1, 17), 'v', None)], 0)], []), +('Module', [('Global', (1, 0, 1, 8), ['v'])], []), +('Module', [('Expr', (1, 0, 1, 1), ('Constant', (1, 0, 1, 1), 1, None))], []), +('Module', [('Pass', (1, 0, 1, 4))], []), +('Module', [('For', (1, 0, 1, 16), ('Name', (1, 4, 1, 5), 'v', ('Store',)), ('Name', (1, 9, 1, 10), 'v', ('Load',)), [('Break', (1, 11, 1, 16))], [], None)], []), +('Module', [('For', (1, 0, 1, 19), ('Name', (1, 4, 1, 5), 'v', ('Store',)), ('Name', (1, 9, 1, 10), 'v', ('Load',)), [('Continue', (1, 11, 1, 19))], [], None)], []), +('Module', [('For', (1, 0, 1, 18), ('Tuple', (1, 4, 1, 7), [('Name', (1, 4, 1, 5), 'a', ('Store',)), ('Name', (1, 6, 1, 7), 'b', ('Store',))], ('Store',)), ('Name', (1, 11, 1, 12), 'c', ('Load',)), [('Pass', (1, 14, 1, 18))], [], None)], []), +('Module', [('For', (1, 0, 1, 20), ('Tuple', (1, 4, 1, 9), [('Name', (1, 5, 1, 6), 'a', ('Store',)), ('Name', (1, 7, 1, 8), 'b', ('Store',))], ('Store',)), ('Name', (1, 13, 1, 14), 'c', ('Load',)), [('Pass', (1, 16, 1, 20))], [], None)], []), +('Module', [('For', (1, 0, 1, 20), ('List', (1, 4, 1, 9), [('Name', (1, 5, 1, 6), 'a', ('Store',)), ('Name', (1, 7, 1, 8), 'b', ('Store',))], ('Store',)), ('Name', (1, 13, 1, 14), 'c', ('Load',)), [('Pass', (1, 16, 1, 20))], [], None)], []), +('Module', [('Expr', (1, 0, 11, 5), ('GeneratorExp', (1, 0, 11, 5), ('Tuple', (2, 4, 6, 5), [('Name', (3, 4, 3, 6), 'Aa', ('Load',)), ('Name', (5, 7, 5, 9), 'Bb', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (8, 4, 10, 6), [('Name', (8, 4, 8, 6), 'Aa', ('Store',)), ('Name', (10, 4, 10, 6), 'Bb', ('Store',))], ('Store',)), ('Name', (10, 10, 10, 12), 'Cc', ('Load',)), [], 0)]))], []), +('Module', [('Expr', (1, 0, 1, 34), ('DictComp', (1, 0, 1, 34), ('Name', (1, 1, 1, 2), 'a', ('Load',)), ('Name', (1, 5, 1, 6), 'b', ('Load',)), [('comprehension', ('Name', (1, 11, 1, 12), 'w', ('Store',)), ('Name', (1, 16, 1, 17), 'x', ('Load',)), [], 0), ('comprehension', ('Name', (1, 22, 1, 23), 'm', ('Store',)), ('Name', (1, 27, 1, 28), 'p', ('Load',)), [('Name', (1, 32, 1, 33), 'g', ('Load',))], 0)]))], []), +('Module', [('Expr', (1, 0, 1, 20), ('DictComp', (1, 0, 1, 20), ('Name', (1, 1, 1, 2), 'a', ('Load',)), ('Name', (1, 5, 1, 6), 'b', ('Load',)), [('comprehension', ('Tuple', (1, 11, 1, 14), [('Name', (1, 11, 1, 12), 'v', ('Store',)), ('Name', (1, 13, 1, 14), 'w', ('Store',))], ('Store',)), ('Name', (1, 18, 1, 19), 'x', ('Load',)), [], 0)]))], []), +('Module', [('Expr', (1, 0, 1, 19), ('SetComp', (1, 0, 1, 19), ('Name', (1, 1, 1, 2), 'r', ('Load',)), [('comprehension', ('Name', (1, 7, 1, 8), 'l', ('Store',)), ('Name', (1, 12, 1, 13), 'x', ('Load',)), [('Name', (1, 17, 1, 18), 'g', ('Load',))], 0)]))], []), +('Module', [('Expr', (1, 0, 1, 16), ('SetComp', (1, 0, 1, 16), ('Name', (1, 1, 1, 2), 'r', ('Load',)), [('comprehension', ('Tuple', (1, 7, 1, 10), [('Name', (1, 7, 1, 8), 'l', ('Store',)), ('Name', (1, 9, 1, 10), 'm', ('Store',))], ('Store',)), ('Name', (1, 14, 1, 15), 'x', ('Load',)), [], 0)]))], []), +('Module', [('AsyncFunctionDef', (1, 0, 3, 18), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (2, 1, 2, 17), ('Constant', (2, 1, 2, 17), 'async function', None)), ('Expr', (3, 1, 3, 18), ('Await', (3, 1, 3, 18), ('Call', (3, 7, 3, 18), ('Name', (3, 7, 3, 16), 'something', ('Load',)), [], [])))], [], None, None, [])], []), +('Module', [('AsyncFunctionDef', (1, 0, 3, 8), 'f', ('arguments', [], [], None, [], [], None, []), [('AsyncFor', (2, 1, 3, 8), ('Name', (2, 11, 2, 12), 'e', ('Store',)), ('Name', (2, 16, 2, 17), 'i', ('Load',)), [('Expr', (2, 19, 2, 20), ('Constant', (2, 19, 2, 20), 1, None))], [('Expr', (3, 7, 3, 8), ('Constant', (3, 7, 3, 8), 2, None))], None)], [], None, None, [])], []), +('Module', [('AsyncFunctionDef', (1, 0, 2, 21), 'f', ('arguments', [], [], None, [], [], None, []), [('AsyncWith', (2, 1, 2, 21), [('withitem', ('Name', (2, 12, 2, 13), 'a', ('Load',)), ('Name', (2, 17, 2, 18), 'b', ('Store',)))], [('Expr', (2, 20, 2, 21), ('Constant', (2, 20, 2, 21), 1, None))], None)], [], None, None, [])], []), +('Module', [('Expr', (1, 0, 1, 14), ('Dict', (1, 0, 1, 14), [None, ('Constant', (1, 10, 1, 11), 2, None)], [('Dict', (1, 3, 1, 8), [('Constant', (1, 4, 1, 5), 1, None)], [('Constant', (1, 6, 1, 7), 2, None)]), ('Constant', (1, 12, 1, 13), 3, None)]))], []), +('Module', [('Expr', (1, 0, 1, 12), ('Set', (1, 0, 1, 12), [('Starred', (1, 1, 1, 8), ('Set', (1, 2, 1, 8), [('Constant', (1, 3, 1, 4), 1, None), ('Constant', (1, 6, 1, 7), 2, None)]), ('Load',)), ('Constant', (1, 10, 1, 11), 3, None)]))], []), +('Module', [('AsyncFunctionDef', (1, 0, 2, 21), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (2, 1, 2, 21), ('ListComp', (2, 1, 2, 21), ('Name', (2, 2, 2, 3), 'i', ('Load',)), [('comprehension', ('Name', (2, 14, 2, 15), 'b', ('Store',)), ('Name', (2, 19, 2, 20), 'c', ('Load',)), [], 1)]))], [], None, None, [])], []), +('Module', [('FunctionDef', (4, 0, 4, 13), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (4, 9, 4, 13))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])], None, None, [])], []), +('Module', [('AsyncFunctionDef', (4, 0, 4, 19), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (4, 15, 4, 19))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])], None, None, [])], []), +('Module', [('ClassDef', (4, 0, 4, 13), 'C', [], [], [('Pass', (4, 9, 4, 13))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])], [])], []), +('Module', [('FunctionDef', (2, 0, 2, 13), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (2, 9, 2, 13))], [('Call', (1, 1, 1, 19), ('Name', (1, 1, 1, 5), 'deco', ('Load',)), [('GeneratorExp', (1, 5, 1, 19), ('Name', (1, 6, 1, 7), 'a', ('Load',)), [('comprehension', ('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 17, 1, 18), 'b', ('Load',)), [], 0)])], [])], None, None, [])], []), +('Module', [('FunctionDef', (2, 0, 2, 13), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (2, 9, 2, 13))], [('Attribute', (1, 1, 1, 6), ('Attribute', (1, 1, 1, 4), ('Name', (1, 1, 1, 2), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',))], None, None, [])], []), +('Module', [('Expr', (1, 0, 1, 8), ('NamedExpr', (1, 1, 1, 7), ('Name', (1, 1, 1, 2), 'a', ('Store',)), ('Constant', (1, 6, 1, 7), 1, None)))], []), +('Module', [('FunctionDef', (1, 0, 1, 18), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [], None, [], [], None, []), [('Pass', (1, 14, 1, 18))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 26), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None), ('arg', (1, 15, 1, 16), 'd', None, None), ('arg', (1, 18, 1, 19), 'e', None, None)], None, [], [], None, []), [('Pass', (1, 22, 1, 26))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 29), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None)], None, [('arg', (1, 18, 1, 19), 'd', None, None), ('arg', (1, 21, 1, 22), 'e', None, None)], [None, None], None, []), [('Pass', (1, 25, 1, 29))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 39), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None)], None, [('arg', (1, 18, 1, 19), 'd', None, None), ('arg', (1, 21, 1, 22), 'e', None, None)], [None, None], ('arg', (1, 26, 1, 32), 'kwargs', None, None), []), [('Pass', (1, 35, 1, 39))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 20), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [], None, [], [], None, [('Constant', (1, 8, 1, 9), 1, None)]), [('Pass', (1, 16, 1, 20))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 29), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None), ('arg', (1, 19, 1, 20), 'c', None, None)], None, [], [], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None), ('Constant', (1, 21, 1, 22), 4, None)]), [('Pass', (1, 25, 1, 29))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 32), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [('Constant', (1, 24, 1, 25), 4, None)], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 28, 1, 32))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 30), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [None], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 26, 1, 30))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 42), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [('Constant', (1, 24, 1, 25), 4, None)], ('arg', (1, 29, 1, 35), 'kwargs', None, None), [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 38, 1, 42))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 40), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [None], ('arg', (1, 27, 1, 33), 'kwargs', None, None), [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 36, 1, 40))], [], None, None, [])], []), +('Module', [('TypeAlias', (1, 0, 1, 12), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [], ('Name', (1, 9, 1, 12), 'int', ('Load',)))], []), +('Module', [('TypeAlias', (1, 0, 1, 15), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 8), 'T', None)], ('Name', (1, 12, 1, 15), 'int', ('Load',)))], []), +('Module', [('TypeAlias', (1, 0, 1, 32), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 8), 'T', None), ('TypeVarTuple', (1, 10, 1, 13), 'Ts'), ('ParamSpec', (1, 15, 1, 18), 'P')], ('Tuple', (1, 22, 1, 32), [('Name', (1, 23, 1, 24), 'T', ('Load',)), ('Name', (1, 26, 1, 28), 'Ts', ('Load',)), ('Name', (1, 30, 1, 31), 'P', ('Load',))], ('Load',)))], []), +('Module', [('TypeAlias', (1, 0, 1, 37), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 13), 'T', ('Name', (1, 10, 1, 13), 'int', ('Load',))), ('TypeVarTuple', (1, 15, 1, 18), 'Ts'), ('ParamSpec', (1, 20, 1, 23), 'P')], ('Tuple', (1, 27, 1, 37), [('Name', (1, 28, 1, 29), 'T', ('Load',)), ('Name', (1, 31, 1, 33), 'Ts', ('Load',)), ('Name', (1, 35, 1, 36), 'P', ('Load',))], ('Load',)))], []), +('Module', [('TypeAlias', (1, 0, 1, 44), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 20), 'T', ('Tuple', (1, 10, 1, 20), [('Name', (1, 11, 1, 14), 'int', ('Load',)), ('Name', (1, 16, 1, 19), 'str', ('Load',))], ('Load',))), ('TypeVarTuple', (1, 22, 1, 25), 'Ts'), ('ParamSpec', (1, 27, 1, 30), 'P')], ('Tuple', (1, 34, 1, 44), [('Name', (1, 35, 1, 36), 'T', ('Load',)), ('Name', (1, 38, 1, 40), 'Ts', ('Load',)), ('Name', (1, 42, 1, 43), 'P', ('Load',))], ('Load',)))], []), +('Module', [('ClassDef', (1, 0, 1, 16), 'X', [], [], [('Pass', (1, 12, 1, 16))], [], [('TypeVar', (1, 8, 1, 9), 'T', None)])], []), +('Module', [('ClassDef', (1, 0, 1, 26), 'X', [], [], [('Pass', (1, 22, 1, 26))], [], [('TypeVar', (1, 8, 1, 9), 'T', None), ('TypeVarTuple', (1, 11, 1, 14), 'Ts'), ('ParamSpec', (1, 16, 1, 19), 'P')])], []), +('Module', [('ClassDef', (1, 0, 1, 31), 'X', [], [], [('Pass', (1, 27, 1, 31))], [], [('TypeVar', (1, 8, 1, 14), 'T', ('Name', (1, 11, 1, 14), 'int', ('Load',))), ('TypeVarTuple', (1, 16, 1, 19), 'Ts'), ('ParamSpec', (1, 21, 1, 24), 'P')])], []), +('Module', [('ClassDef', (1, 0, 1, 38), 'X', [], [], [('Pass', (1, 34, 1, 38))], [], [('TypeVar', (1, 8, 1, 21), 'T', ('Tuple', (1, 11, 1, 21), [('Name', (1, 12, 1, 15), 'int', ('Load',)), ('Name', (1, 17, 1, 20), 'str', ('Load',))], ('Load',))), ('TypeVarTuple', (1, 23, 1, 26), 'Ts'), ('ParamSpec', (1, 28, 1, 31), 'P')])], []), +('Module', [('FunctionDef', (1, 0, 1, 16), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 12, 1, 16))], [], None, None, [('TypeVar', (1, 6, 1, 7), 'T', None)])], []), +('Module', [('FunctionDef', (1, 0, 1, 26), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 22, 1, 26))], [], None, None, [('TypeVar', (1, 6, 1, 7), 'T', None), ('TypeVarTuple', (1, 9, 1, 12), 'Ts'), ('ParamSpec', (1, 14, 1, 17), 'P')])], []), +('Module', [('FunctionDef', (1, 0, 1, 31), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 27, 1, 31))], [], None, None, [('TypeVar', (1, 6, 1, 12), 'T', ('Name', (1, 9, 1, 12), 'int', ('Load',))), ('TypeVarTuple', (1, 14, 1, 17), 'Ts'), ('ParamSpec', (1, 19, 1, 22), 'P')])], []), +('Module', [('FunctionDef', (1, 0, 1, 38), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 34, 1, 38))], [], None, None, [('TypeVar', (1, 6, 1, 19), 'T', ('Tuple', (1, 9, 1, 19), [('Name', (1, 10, 1, 13), 'int', ('Load',)), ('Name', (1, 15, 1, 18), 'str', ('Load',))], ('Load',))), ('TypeVarTuple', (1, 21, 1, 24), 'Ts'), ('ParamSpec', (1, 26, 1, 29), 'P')])], []), +] +single_results = [ +('Interactive', [('Expr', (1, 0, 1, 3), ('BinOp', (1, 0, 1, 3), ('Constant', (1, 0, 1, 1), 1, None), ('Add',), ('Constant', (1, 2, 1, 3), 2, None)))]), +] +eval_results = [ +('Expression', ('Constant', (1, 0, 1, 4), None, None)), +('Expression', ('BoolOp', (1, 0, 1, 7), ('And',), [('Name', (1, 0, 1, 1), 'a', ('Load',)), ('Name', (1, 6, 1, 7), 'b', ('Load',))])), +('Expression', ('BinOp', (1, 0, 1, 5), ('Name', (1, 0, 1, 1), 'a', ('Load',)), ('Add',), ('Name', (1, 4, 1, 5), 'b', ('Load',)))), +('Expression', ('UnaryOp', (1, 0, 1, 5), ('Not',), ('Name', (1, 4, 1, 5), 'v', ('Load',)))), +('Expression', ('Lambda', (1, 0, 1, 11), ('arguments', [], [], None, [], [], None, []), ('Constant', (1, 7, 1, 11), None, None))), +('Expression', ('Dict', (1, 0, 1, 7), [('Constant', (1, 2, 1, 3), 1, None)], [('Constant', (1, 4, 1, 5), 2, None)])), +('Expression', ('Dict', (1, 0, 1, 2), [], [])), +('Expression', ('Set', (1, 0, 1, 7), [('Constant', (1, 1, 1, 5), None, None)])), +('Expression', ('Dict', (1, 0, 5, 6), [('Constant', (2, 6, 2, 7), 1, None)], [('Constant', (4, 10, 4, 11), 2, None)])), +('Expression', ('ListComp', (1, 0, 1, 19), ('Name', (1, 1, 1, 2), 'a', ('Load',)), [('comprehension', ('Name', (1, 7, 1, 8), 'b', ('Store',)), ('Name', (1, 12, 1, 13), 'c', ('Load',)), [('Name', (1, 17, 1, 18), 'd', ('Load',))], 0)])), +('Expression', ('GeneratorExp', (1, 0, 1, 19), ('Name', (1, 1, 1, 2), 'a', ('Load',)), [('comprehension', ('Name', (1, 7, 1, 8), 'b', ('Store',)), ('Name', (1, 12, 1, 13), 'c', ('Load',)), [('Name', (1, 17, 1, 18), 'd', ('Load',))], 0)])), +('Expression', ('ListComp', (1, 0, 1, 20), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11, 1, 14), [('Name', (1, 11, 1, 12), 'a', ('Store',)), ('Name', (1, 13, 1, 14), 'b', ('Store',))], ('Store',)), ('Name', (1, 18, 1, 19), 'c', ('Load',)), [], 0)])), +('Expression', ('ListComp', (1, 0, 1, 22), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11, 1, 16), [('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 14, 1, 15), 'b', ('Store',))], ('Store',)), ('Name', (1, 20, 1, 21), 'c', ('Load',)), [], 0)])), +('Expression', ('ListComp', (1, 0, 1, 22), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('List', (1, 11, 1, 16), [('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 14, 1, 15), 'b', ('Store',))], ('Store',)), ('Name', (1, 20, 1, 21), 'c', ('Load',)), [], 0)])), +('Expression', ('SetComp', (1, 0, 1, 20), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11, 1, 14), [('Name', (1, 11, 1, 12), 'a', ('Store',)), ('Name', (1, 13, 1, 14), 'b', ('Store',))], ('Store',)), ('Name', (1, 18, 1, 19), 'c', ('Load',)), [], 0)])), +('Expression', ('SetComp', (1, 0, 1, 22), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11, 1, 16), [('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 14, 1, 15), 'b', ('Store',))], ('Store',)), ('Name', (1, 20, 1, 21), 'c', ('Load',)), [], 0)])), +('Expression', ('SetComp', (1, 0, 1, 22), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('List', (1, 11, 1, 16), [('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 14, 1, 15), 'b', ('Store',))], ('Store',)), ('Name', (1, 20, 1, 21), 'c', ('Load',)), [], 0)])), +('Expression', ('GeneratorExp', (1, 0, 1, 20), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11, 1, 14), [('Name', (1, 11, 1, 12), 'a', ('Store',)), ('Name', (1, 13, 1, 14), 'b', ('Store',))], ('Store',)), ('Name', (1, 18, 1, 19), 'c', ('Load',)), [], 0)])), +('Expression', ('GeneratorExp', (1, 0, 1, 22), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11, 1, 16), [('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 14, 1, 15), 'b', ('Store',))], ('Store',)), ('Name', (1, 20, 1, 21), 'c', ('Load',)), [], 0)])), +('Expression', ('GeneratorExp', (1, 0, 1, 22), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('List', (1, 11, 1, 16), [('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 14, 1, 15), 'b', ('Store',))], ('Store',)), ('Name', (1, 20, 1, 21), 'c', ('Load',)), [], 0)])), +('Expression', ('Compare', (1, 0, 1, 9), ('Constant', (1, 0, 1, 1), 1, None), [('Lt',), ('Lt',)], [('Constant', (1, 4, 1, 5), 2, None), ('Constant', (1, 8, 1, 9), 3, None)])), +('Expression', ('Call', (1, 0, 1, 17), ('Name', (1, 0, 1, 1), 'f', ('Load',)), [('Constant', (1, 2, 1, 3), 1, None), ('Constant', (1, 4, 1, 5), 2, None), ('Starred', (1, 10, 1, 12), ('Name', (1, 11, 1, 12), 'd', ('Load',)), ('Load',))], [('keyword', (1, 6, 1, 9), 'c', ('Constant', (1, 8, 1, 9), 3, None)), ('keyword', (1, 13, 1, 16), None, ('Name', (1, 15, 1, 16), 'e', ('Load',)))])), +('Expression', ('Call', (1, 0, 1, 10), ('Name', (1, 0, 1, 1), 'f', ('Load',)), [('Starred', (1, 2, 1, 9), ('List', (1, 3, 1, 9), [('Constant', (1, 4, 1, 5), 0, None), ('Constant', (1, 7, 1, 8), 1, None)], ('Load',)), ('Load',))], [])), +('Expression', ('Call', (1, 0, 1, 15), ('Name', (1, 0, 1, 1), 'f', ('Load',)), [('GeneratorExp', (1, 1, 1, 15), ('Name', (1, 2, 1, 3), 'a', ('Load',)), [('comprehension', ('Name', (1, 8, 1, 9), 'a', ('Store',)), ('Name', (1, 13, 1, 14), 'b', ('Load',)), [], 0)])], [])), +('Expression', ('Constant', (1, 0, 1, 2), 10, None)), +('Expression', ('Constant', (1, 0, 1, 8), 'string', None)), +('Expression', ('Attribute', (1, 0, 1, 3), ('Name', (1, 0, 1, 1), 'a', ('Load',)), 'b', ('Load',))), +('Expression', ('Subscript', (1, 0, 1, 6), ('Name', (1, 0, 1, 1), 'a', ('Load',)), ('Slice', (1, 2, 1, 5), ('Name', (1, 2, 1, 3), 'b', ('Load',)), ('Name', (1, 4, 1, 5), 'c', ('Load',)), None), ('Load',))), +('Expression', ('Name', (1, 0, 1, 1), 'v', ('Load',))), +('Expression', ('List', (1, 0, 1, 7), [('Constant', (1, 1, 1, 2), 1, None), ('Constant', (1, 3, 1, 4), 2, None), ('Constant', (1, 5, 1, 6), 3, None)], ('Load',))), +('Expression', ('List', (1, 0, 1, 2), [], ('Load',))), +('Expression', ('Tuple', (1, 0, 1, 5), [('Constant', (1, 0, 1, 1), 1, None), ('Constant', (1, 2, 1, 3), 2, None), ('Constant', (1, 4, 1, 5), 3, None)], ('Load',))), +('Expression', ('Tuple', (1, 0, 1, 7), [('Constant', (1, 1, 1, 2), 1, None), ('Constant', (1, 3, 1, 4), 2, None), ('Constant', (1, 5, 1, 6), 3, None)], ('Load',))), +('Expression', ('Tuple', (1, 0, 1, 2), [], ('Load',))), +('Expression', ('Call', (1, 0, 1, 17), ('Attribute', (1, 0, 1, 7), ('Attribute', (1, 0, 1, 5), ('Attribute', (1, 0, 1, 3), ('Name', (1, 0, 1, 1), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',)), 'd', ('Load',)), [('Subscript', (1, 8, 1, 16), ('Attribute', (1, 8, 1, 11), ('Name', (1, 8, 1, 9), 'a', ('Load',)), 'b', ('Load',)), ('Slice', (1, 12, 1, 15), ('Constant', (1, 12, 1, 13), 1, None), ('Constant', (1, 14, 1, 15), 2, None), None), ('Load',))], [])), +] +main() diff --git a/Lib/test/test_ast/test_ast.py b/Lib/test/test_ast/test_ast.py new file mode 100644 index 00000000..f07e2d02 --- /dev/null +++ b/Lib/test/test_ast/test_ast.py @@ -0,0 +1,2781 @@ +import ast +import builtins +import dis +import enum +import os +import re +import sys +import textwrap +import types +import unittest +import warnings +import weakref +from functools import partial +from textwrap import dedent + +from test import support +from test.support.import_helper import import_fresh_module +from test.support import os_helper, script_helper +from test.support.ast_helper import ASTTestMixin +from test.test_ast.utils import to_tuple +from test.test_ast.snippets import ( + eval_tests, eval_results, exec_tests, exec_results, single_tests, single_results +) + + +class AST_Tests(unittest.TestCase): + maxDiff = None + + def _is_ast_node(self, name, node): + if not isinstance(node, type): + return False + if "ast" not in node.__module__: + return False + return name != "AST" and name[0].isupper() + + def _assertTrueorder(self, ast_node, parent_pos): + if not isinstance(ast_node, ast.AST) or ast_node._fields is None: + return + if isinstance(ast_node, (ast.expr, ast.stmt, ast.excepthandler)): + node_pos = (ast_node.lineno, ast_node.col_offset) + self.assertGreaterEqual(node_pos, parent_pos) + parent_pos = (ast_node.lineno, ast_node.col_offset) + for name in ast_node._fields: + value = getattr(ast_node, name) + if isinstance(value, list): + first_pos = parent_pos + if value and name == "decorator_list": + first_pos = (value[0].lineno, value[0].col_offset) + for child in value: + self._assertTrueorder(child, first_pos) + elif value is not None: + self._assertTrueorder(value, parent_pos) + self.assertEqual(ast_node._fields, ast_node.__match_args__) + + def test_AST_objects(self): + x = ast.AST() + self.assertEqual(x._fields, ()) + x.foobar = 42 + self.assertEqual(x.foobar, 42) + self.assertEqual(x.__dict__["foobar"], 42) + + with self.assertRaises(AttributeError): + x.vararg + + with self.assertRaises(TypeError): + # "ast.AST constructor takes 0 positional arguments" + ast.AST(2) + + def test_AST_fields_NULL_check(self): + # See: https://github.com/python/cpython/issues/126105 + old_value = ast.AST._fields + + def cleanup(): + ast.AST._fields = old_value + self.addCleanup(cleanup) + + del ast.AST._fields + + msg = "type object 'ast.AST' has no attribute '_fields'" + # Both examples used to crash: + with self.assertRaisesRegex(AttributeError, msg): + ast.AST(arg1=123) + with self.assertRaisesRegex(AttributeError, msg): + ast.AST() + + def test_AST_garbage_collection(self): + class X: + pass + + a = ast.AST() + a.x = X() + a.x.a = a + ref = weakref.ref(a.x) + del a + support.gc_collect() + self.assertIsNone(ref()) + + def test_snippets(self): + for input, output, kind in ( + (exec_tests, exec_results, "exec"), + (single_tests, single_results, "single"), + (eval_tests, eval_results, "eval"), + ): + for i, o in zip(input, output): + with self.subTest(action="parsing", input=i): + ast_tree = compile(i, "?", kind, ast.PyCF_ONLY_AST) + self.assertEqual(to_tuple(ast_tree), o) + self._assertTrueorder(ast_tree, (0, 0)) + with self.subTest(action="compiling", input=i, kind=kind): + compile(ast_tree, "?", kind) + + def test_ast_validation(self): + # compile() is the only function that calls PyAST_Validate + snippets_to_validate = exec_tests + single_tests + eval_tests + for snippet in snippets_to_validate: + tree = ast.parse(snippet) + compile(tree, "", "exec") + + def test_invalid_position_information(self): + invalid_linenos = [(10, 1), (-10, -11), (10, -11), (-5, -2), (-5, 1)] + + for lineno, end_lineno in invalid_linenos: + with self.subTest(f"Check invalid linenos {lineno}:{end_lineno}"): + snippet = "a = 1" + tree = ast.parse(snippet) + tree.body[0].lineno = lineno + tree.body[0].end_lineno = end_lineno + with self.assertRaises(ValueError): + compile(tree, "", "exec") + + invalid_col_offsets = [(10, 1), (-10, -11), (10, -11), (-5, -2), (-5, 1)] + for col_offset, end_col_offset in invalid_col_offsets: + with self.subTest( + f"Check invalid col_offset {col_offset}:{end_col_offset}" + ): + snippet = "a = 1" + tree = ast.parse(snippet) + tree.body[0].col_offset = col_offset + tree.body[0].end_col_offset = end_col_offset + with self.assertRaises(ValueError): + compile(tree, "", "exec") + + def test_compilation_of_ast_nodes_with_default_end_position_values(self): + tree = ast.Module( + body=[ + ast.Import( + names=[ast.alias(name="builtins", lineno=1, col_offset=0)], + lineno=1, + col_offset=0, + ), + ast.Import( + names=[ast.alias(name="traceback", lineno=0, col_offset=0)], + lineno=0, + col_offset=1, + ), + ], + type_ignores=[], + ) + + # Check that compilation doesn't crash. Note: this may crash explicitly only on debug mode. + compile(tree, "", "exec") + + def test_slice(self): + slc = ast.parse("x[::]").body[0].value.slice + self.assertIsNone(slc.upper) + self.assertIsNone(slc.lower) + self.assertIsNone(slc.step) + + def test_from_import(self): + im = ast.parse("from . import y").body[0] + self.assertIsNone(im.module) + + def test_non_interned_future_from_ast(self): + mod = ast.parse("from __future__ import division") + self.assertIsInstance(mod.body[0], ast.ImportFrom) + mod.body[0].module = " __future__ ".strip() + compile(mod, "", "exec") + + def test_alias(self): + im = ast.parse("from bar import y").body[0] + self.assertEqual(len(im.names), 1) + alias = im.names[0] + self.assertEqual(alias.name, "y") + self.assertIsNone(alias.asname) + self.assertEqual(alias.lineno, 1) + self.assertEqual(alias.end_lineno, 1) + self.assertEqual(alias.col_offset, 16) + self.assertEqual(alias.end_col_offset, 17) + + im = ast.parse("from bar import *").body[0] + alias = im.names[0] + self.assertEqual(alias.name, "*") + self.assertIsNone(alias.asname) + self.assertEqual(alias.lineno, 1) + self.assertEqual(alias.end_lineno, 1) + self.assertEqual(alias.col_offset, 16) + self.assertEqual(alias.end_col_offset, 17) + + im = ast.parse("from bar import y as z").body[0] + alias = im.names[0] + self.assertEqual(alias.name, "y") + self.assertEqual(alias.asname, "z") + self.assertEqual(alias.lineno, 1) + self.assertEqual(alias.end_lineno, 1) + self.assertEqual(alias.col_offset, 16) + self.assertEqual(alias.end_col_offset, 22) + + im = ast.parse("import bar as foo").body[0] + alias = im.names[0] + self.assertEqual(alias.name, "bar") + self.assertEqual(alias.asname, "foo") + self.assertEqual(alias.lineno, 1) + self.assertEqual(alias.end_lineno, 1) + self.assertEqual(alias.col_offset, 7) + self.assertEqual(alias.end_col_offset, 17) + + def test_base_classes(self): + self.assertTrue(issubclass(ast.For, ast.stmt)) + self.assertTrue(issubclass(ast.Name, ast.expr)) + self.assertTrue(issubclass(ast.stmt, ast.AST)) + self.assertTrue(issubclass(ast.expr, ast.AST)) + self.assertTrue(issubclass(ast.comprehension, ast.AST)) + self.assertTrue(issubclass(ast.Gt, ast.AST)) + + def test_import_deprecated(self): + ast = import_fresh_module("ast") + depr_regex = ( + r"ast\.{} is deprecated and will be removed in Python 3.14; " + r"use ast\.Constant instead" + ) + for name in "Num", "Str", "Bytes", "NameConstant", "Ellipsis": + with self.assertWarnsRegex(DeprecationWarning, depr_regex.format(name)): + getattr(ast, name) + + def test_field_attr_existence_deprecated(self): + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", "", DeprecationWarning) + from ast import Num, Str, Bytes, NameConstant, Ellipsis + + for name in ("Num", "Str", "Bytes", "NameConstant", "Ellipsis"): + item = getattr(ast, name) + if self._is_ast_node(name, item): + with self.subTest(item): + with self.assertWarns(DeprecationWarning): + x = item() + if isinstance(x, ast.AST): + self.assertIs(type(x._fields), tuple) + + def test_field_attr_existence(self): + for name, item in ast.__dict__.items(): + # These emit DeprecationWarnings + if name in {"Num", "Str", "Bytes", "NameConstant", "Ellipsis"}: + continue + # constructor has a different signature + if name == "Index": + continue + if self._is_ast_node(name, item): + x = item() + if isinstance(x, ast.AST): + self.assertIs(type(x._fields), tuple) + + def test_arguments(self): + x = ast.arguments() + self.assertEqual( + x._fields, + ( + "posonlyargs", + "args", + "vararg", + "kwonlyargs", + "kw_defaults", + "kwarg", + "defaults", + ), + ) + + with self.assertRaises(AttributeError): + x.args + self.assertIsNone(x.vararg) + + x = ast.arguments(*range(1, 8)) + self.assertEqual(x.args, 2) + self.assertEqual(x.vararg, 3) + + def test_field_attr_writable_deprecated(self): + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", "", DeprecationWarning) + x = ast.Num() + # We can assign to _fields + x._fields = 666 + self.assertEqual(x._fields, 666) + + def test_field_attr_writable(self): + x = ast.Constant() + # We can assign to _fields + x._fields = 666 + self.assertEqual(x._fields, 666) + + def test_classattrs_deprecated(self): + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", "", DeprecationWarning) + from ast import Num, Str, Bytes, NameConstant, Ellipsis + + with warnings.catch_warnings(record=True) as wlog: + warnings.filterwarnings("always", "", DeprecationWarning) + x = ast.Num() + self.assertEqual(x._fields, ("value", "kind")) + + with self.assertRaises(AttributeError): + x.value + + with self.assertRaises(AttributeError): + x.n + + x = ast.Num(42) + self.assertEqual(x.value, 42) + self.assertEqual(x.n, 42) + + with self.assertRaises(AttributeError): + x.lineno + + with self.assertRaises(AttributeError): + x.foobar + + x = ast.Num(lineno=2) + self.assertEqual(x.lineno, 2) + + x = ast.Num(42, lineno=0) + self.assertEqual(x.lineno, 0) + self.assertEqual(x._fields, ("value", "kind")) + self.assertEqual(x.value, 42) + self.assertEqual(x.n, 42) + + self.assertRaises(TypeError, ast.Num, 1, None, 2) + self.assertRaises(TypeError, ast.Num, 1, None, 2, lineno=0) + + # Arbitrary keyword arguments are supported + self.assertEqual(ast.Num(1, foo="bar").foo, "bar") + + with self.assertRaisesRegex( + TypeError, "Num got multiple values for argument 'n'" + ): + ast.Num(1, n=2) + + self.assertEqual(ast.Num(42).n, 42) + self.assertEqual(ast.Num(4.25).n, 4.25) + self.assertEqual(ast.Num(4.25j).n, 4.25j) + self.assertEqual(ast.Str("42").s, "42") + self.assertEqual(ast.Bytes(b"42").s, b"42") + self.assertIs(ast.NameConstant(True).value, True) + self.assertIs(ast.NameConstant(False).value, False) + self.assertIs(ast.NameConstant(None).value, None) + + self.assertEqual( + [str(w.message) for w in wlog], + [ + "ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "Attribute n is deprecated and will be removed in Python 3.14; use value instead", + "ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "Attribute n is deprecated and will be removed in Python 3.14; use value instead", + "ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "Attribute n is deprecated and will be removed in Python 3.14; use value instead", + "ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "Attribute n is deprecated and will be removed in Python 3.14; use value instead", + "ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "Attribute n is deprecated and will be removed in Python 3.14; use value instead", + "ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "Attribute n is deprecated and will be removed in Python 3.14; use value instead", + "ast.Str is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "Attribute s is deprecated and will be removed in Python 3.14; use value instead", + "ast.Bytes is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "Attribute s is deprecated and will be removed in Python 3.14; use value instead", + "ast.NameConstant is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "ast.NameConstant is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "ast.NameConstant is deprecated and will be removed in Python 3.14; use ast.Constant instead", + ], + ) + + def test_classattrs(self): + x = ast.Constant() + self.assertEqual(x._fields, ("value", "kind")) + + with self.assertRaises(AttributeError): + x.value + + x = ast.Constant(42) + self.assertEqual(x.value, 42) + + with self.assertRaises(AttributeError): + x.lineno + + with self.assertRaises(AttributeError): + x.foobar + + x = ast.Constant(lineno=2) + self.assertEqual(x.lineno, 2) + + x = ast.Constant(42, lineno=0) + self.assertEqual(x.lineno, 0) + self.assertEqual(x._fields, ("value", "kind")) + self.assertEqual(x.value, 42) + + self.assertRaises(TypeError, ast.Constant, 1, None, 2) + self.assertRaises(TypeError, ast.Constant, 1, None, 2, lineno=0) + + # Arbitrary keyword arguments are supported + self.assertEqual(ast.Constant(1, foo="bar").foo, "bar") + + with self.assertRaisesRegex( + TypeError, "Constant got multiple values for argument 'value'" + ): + ast.Constant(1, value=2) + + self.assertEqual(ast.Constant(42).value, 42) + self.assertEqual(ast.Constant(4.25).value, 4.25) + self.assertEqual(ast.Constant(4.25j).value, 4.25j) + self.assertEqual(ast.Constant("42").value, "42") + self.assertEqual(ast.Constant(b"42").value, b"42") + self.assertIs(ast.Constant(True).value, True) + self.assertIs(ast.Constant(False).value, False) + self.assertIs(ast.Constant(None).value, None) + self.assertIs(ast.Constant(...).value, ...) + + def test_realtype(self): + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", "", DeprecationWarning) + from ast import Num, Str, Bytes, NameConstant, Ellipsis + + with warnings.catch_warnings(record=True) as wlog: + warnings.filterwarnings("always", "", DeprecationWarning) + self.assertIs(type(ast.Num(42)), ast.Constant) + self.assertIs(type(ast.Num(4.25)), ast.Constant) + self.assertIs(type(ast.Num(4.25j)), ast.Constant) + self.assertIs(type(ast.Str("42")), ast.Constant) + self.assertIs(type(ast.Bytes(b"42")), ast.Constant) + self.assertIs(type(ast.NameConstant(True)), ast.Constant) + self.assertIs(type(ast.NameConstant(False)), ast.Constant) + self.assertIs(type(ast.NameConstant(None)), ast.Constant) + self.assertIs(type(ast.Ellipsis()), ast.Constant) + + self.assertEqual( + [str(w.message) for w in wlog], + [ + "ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "ast.Str is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "ast.Bytes is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "ast.NameConstant is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "ast.NameConstant is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "ast.NameConstant is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "ast.Ellipsis is deprecated and will be removed in Python 3.14; use ast.Constant instead", + ], + ) + + def test_isinstance(self): + from ast import Constant + + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", "", DeprecationWarning) + from ast import Num, Str, Bytes, NameConstant, Ellipsis + + cls_depr_msg = ( + "ast.{} is deprecated and will be removed in Python 3.14; " + "use ast.Constant instead" + ) + + assertNumDeprecated = partial( + self.assertWarnsRegex, DeprecationWarning, cls_depr_msg.format("Num") + ) + assertStrDeprecated = partial( + self.assertWarnsRegex, DeprecationWarning, cls_depr_msg.format("Str") + ) + assertBytesDeprecated = partial( + self.assertWarnsRegex, DeprecationWarning, cls_depr_msg.format("Bytes") + ) + assertNameConstantDeprecated = partial( + self.assertWarnsRegex, + DeprecationWarning, + cls_depr_msg.format("NameConstant"), + ) + assertEllipsisDeprecated = partial( + self.assertWarnsRegex, DeprecationWarning, cls_depr_msg.format("Ellipsis") + ) + + for arg in 42, 4.2, 4.2j: + with self.subTest(arg=arg): + with assertNumDeprecated(): + n = Num(arg) + with assertNumDeprecated(): + self.assertIsInstance(n, Num) + + with assertStrDeprecated(): + s = Str("42") + with assertStrDeprecated(): + self.assertIsInstance(s, Str) + + with assertBytesDeprecated(): + b = Bytes(b"42") + with assertBytesDeprecated(): + self.assertIsInstance(b, Bytes) + + for arg in True, False, None: + with self.subTest(arg=arg): + with assertNameConstantDeprecated(): + n = NameConstant(arg) + with assertNameConstantDeprecated(): + self.assertIsInstance(n, NameConstant) + + with assertEllipsisDeprecated(): + e = Ellipsis() + with assertEllipsisDeprecated(): + self.assertIsInstance(e, Ellipsis) + + for arg in 42, 4.2, 4.2j: + with self.subTest(arg=arg): + with assertNumDeprecated(): + self.assertIsInstance(Constant(arg), Num) + + with assertStrDeprecated(): + self.assertIsInstance(Constant("42"), Str) + + with assertBytesDeprecated(): + self.assertIsInstance(Constant(b"42"), Bytes) + + for arg in True, False, None: + with self.subTest(arg=arg): + with assertNameConstantDeprecated(): + self.assertIsInstance(Constant(arg), NameConstant) + + with assertEllipsisDeprecated(): + self.assertIsInstance(Constant(...), Ellipsis) + + with assertStrDeprecated(): + s = Str("42") + assertNumDeprecated(self.assertNotIsInstance, s, Num) + assertBytesDeprecated(self.assertNotIsInstance, s, Bytes) + + with assertNumDeprecated(): + n = Num(42) + assertStrDeprecated(self.assertNotIsInstance, n, Str) + assertNameConstantDeprecated(self.assertNotIsInstance, n, NameConstant) + assertEllipsisDeprecated(self.assertNotIsInstance, n, Ellipsis) + + with assertNameConstantDeprecated(): + n = NameConstant(True) + with assertNumDeprecated(): + self.assertNotIsInstance(n, Num) + + with assertNameConstantDeprecated(): + n = NameConstant(False) + with assertNumDeprecated(): + self.assertNotIsInstance(n, Num) + + for arg in "42", True, False: + with self.subTest(arg=arg): + with assertNumDeprecated(): + self.assertNotIsInstance(Constant(arg), Num) + + assertStrDeprecated(self.assertNotIsInstance, Constant(42), Str) + assertBytesDeprecated(self.assertNotIsInstance, Constant("42"), Bytes) + assertNameConstantDeprecated( + self.assertNotIsInstance, Constant(42), NameConstant + ) + assertEllipsisDeprecated(self.assertNotIsInstance, Constant(42), Ellipsis) + assertNumDeprecated(self.assertNotIsInstance, Constant(), Num) + assertStrDeprecated(self.assertNotIsInstance, Constant(), Str) + assertBytesDeprecated(self.assertNotIsInstance, Constant(), Bytes) + assertNameConstantDeprecated(self.assertNotIsInstance, Constant(), NameConstant) + assertEllipsisDeprecated(self.assertNotIsInstance, Constant(), Ellipsis) + + class S(str): + pass + + with assertStrDeprecated(): + self.assertIsInstance(Constant(S("42")), Str) + with assertNumDeprecated(): + self.assertNotIsInstance(Constant(S("42")), Num) + + def test_constant_subclasses_deprecated(self): + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", "", DeprecationWarning) + from ast import Num + + with warnings.catch_warnings(record=True) as wlog: + warnings.filterwarnings("always", "", DeprecationWarning) + + class N(ast.Num): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.z = "spam" + + class N2(ast.Num): + pass + + n = N(42) + self.assertEqual(n.n, 42) + self.assertEqual(n.z, "spam") + self.assertIs(type(n), N) + self.assertIsInstance(n, N) + self.assertIsInstance(n, ast.Num) + self.assertNotIsInstance(n, N2) + self.assertNotIsInstance(ast.Num(42), N) + n = N(n=42) + self.assertEqual(n.n, 42) + self.assertIs(type(n), N) + + self.assertEqual( + [str(w.message) for w in wlog], + [ + "Attribute n is deprecated and will be removed in Python 3.14; use value instead", + "Attribute n is deprecated and will be removed in Python 3.14; use value instead", + "ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "Attribute n is deprecated and will be removed in Python 3.14; use value instead", + "Attribute n is deprecated and will be removed in Python 3.14; use value instead", + ], + ) + + def test_constant_subclasses(self): + class N(ast.Constant): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.z = "spam" + + class N2(ast.Constant): + pass + + n = N(42) + self.assertEqual(n.value, 42) + self.assertEqual(n.z, "spam") + self.assertEqual(type(n), N) + self.assertTrue(isinstance(n, N)) + self.assertTrue(isinstance(n, ast.Constant)) + self.assertFalse(isinstance(n, N2)) + self.assertFalse(isinstance(ast.Constant(42), N)) + n = N(value=42) + self.assertEqual(n.value, 42) + self.assertEqual(type(n), N) + + def test_module(self): + body = [ast.Constant(42)] + x = ast.Module(body, []) + self.assertEqual(x.body, body) + + def test_nodeclasses(self): + # Zero arguments constructor explicitly allowed + x = ast.BinOp() + self.assertEqual(x._fields, ("left", "op", "right")) + + # Random attribute allowed too + x.foobarbaz = 5 + self.assertEqual(x.foobarbaz, 5) + + n1 = ast.Constant(1) + n3 = ast.Constant(3) + addop = ast.Add() + x = ast.BinOp(n1, addop, n3) + self.assertEqual(x.left, n1) + self.assertEqual(x.op, addop) + self.assertEqual(x.right, n3) + + x = ast.BinOp(1, 2, 3) + self.assertEqual(x.left, 1) + self.assertEqual(x.op, 2) + self.assertEqual(x.right, 3) + + x = ast.BinOp(1, 2, 3, lineno=0) + self.assertEqual(x.left, 1) + self.assertEqual(x.op, 2) + self.assertEqual(x.right, 3) + self.assertEqual(x.lineno, 0) + + # node raises exception when given too many arguments + self.assertRaises(TypeError, ast.BinOp, 1, 2, 3, 4) + # node raises exception when given too many arguments + self.assertRaises(TypeError, ast.BinOp, 1, 2, 3, 4, lineno=0) + + # can set attributes through kwargs too + x = ast.BinOp(left=1, op=2, right=3, lineno=0) + self.assertEqual(x.left, 1) + self.assertEqual(x.op, 2) + self.assertEqual(x.right, 3) + self.assertEqual(x.lineno, 0) + + # Random kwargs also allowed + x = ast.BinOp(1, 2, 3, foobarbaz=42) + self.assertEqual(x.foobarbaz, 42) + + def test_no_fields(self): + # this used to fail because Sub._fields was None + x = ast.Sub() + self.assertEqual(x._fields, ()) + + def test_pickling(self): + import pickle + + for protocol in range(pickle.HIGHEST_PROTOCOL + 1): + for ast in (compile(i, "?", "exec", 0x400) for i in exec_tests): + ast2 = pickle.loads(pickle.dumps(ast, protocol)) + self.assertEqual(to_tuple(ast2), to_tuple(ast)) + + def test_invalid_sum(self): + pos = dict(lineno=2, col_offset=3) + m = ast.Module([ast.Expr(ast.expr(**pos), **pos)], []) + with self.assertRaises(TypeError) as cm: + compile(m, "", "exec") + self.assertIn("but got ", "exec") + self.assertIn("identifier must be of type str", str(cm.exception)) + + def test_invalid_constant(self): + for invalid_constant in int, (1, 2, int), frozenset((1, 2, int)): + e = ast.Expression(body=ast.Constant(invalid_constant)) + ast.fix_missing_locations(e) + with self.assertRaisesRegex(TypeError, "invalid type in Constant: type"): + compile(e, "", "eval") + + def test_empty_yield_from(self): + # Issue 16546: yield from value is not optional. + empty_yield_from = ast.parse("def f():\n yield from g()") + empty_yield_from.body[0].body[0].value.value = None + with self.assertRaises(ValueError) as cm: + compile(empty_yield_from, "", "exec") + self.assertIn("field 'value' is required", str(cm.exception)) + + @support.cpython_only + def test_issue31592(self): + # There shouldn't be an assertion failure in case of a bad + # unicodedata.normalize(). + import unicodedata + + def bad_normalize(*args): + return None + + with support.swap_attr(unicodedata, "normalize", bad_normalize): + self.assertRaises(TypeError, ast.parse, "\u03d5") + + def test_issue18374_binop_col_offset(self): + tree = ast.parse("4+5+6+7") + parent_binop = tree.body[0].value + child_binop = parent_binop.left + grandchild_binop = child_binop.left + self.assertEqual(parent_binop.col_offset, 0) + self.assertEqual(parent_binop.end_col_offset, 7) + self.assertEqual(child_binop.col_offset, 0) + self.assertEqual(child_binop.end_col_offset, 5) + self.assertEqual(grandchild_binop.col_offset, 0) + self.assertEqual(grandchild_binop.end_col_offset, 3) + + tree = ast.parse("4+5-\\\n 6-7") + parent_binop = tree.body[0].value + child_binop = parent_binop.left + grandchild_binop = child_binop.left + self.assertEqual(parent_binop.col_offset, 0) + self.assertEqual(parent_binop.lineno, 1) + self.assertEqual(parent_binop.end_col_offset, 4) + self.assertEqual(parent_binop.end_lineno, 2) + + self.assertEqual(child_binop.col_offset, 0) + self.assertEqual(child_binop.lineno, 1) + self.assertEqual(child_binop.end_col_offset, 2) + self.assertEqual(child_binop.end_lineno, 2) + + self.assertEqual(grandchild_binop.col_offset, 0) + self.assertEqual(grandchild_binop.lineno, 1) + self.assertEqual(grandchild_binop.end_col_offset, 3) + self.assertEqual(grandchild_binop.end_lineno, 1) + + def test_issue39579_dotted_name_end_col_offset(self): + tree = ast.parse("@a.b.c\ndef f(): pass") + attr_b = tree.body[0].decorator_list[0].value + self.assertEqual(attr_b.end_col_offset, 4) + + def test_ast_asdl_signature(self): + self.assertEqual( + ast.withitem.__doc__, "withitem(expr context_expr, expr? optional_vars)" + ) + self.assertEqual(ast.GtE.__doc__, "GtE") + self.assertEqual(ast.Name.__doc__, "Name(identifier id, expr_context ctx)") + self.assertEqual( + ast.cmpop.__doc__, + "cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn", + ) + expressions = [f" | {node.__doc__}" for node in ast.expr.__subclasses__()] + expressions[0] = f"expr = {ast.expr.__subclasses__()[0].__doc__}" + self.assertCountEqual(ast.expr.__doc__.split("\n"), expressions) + + def test_positional_only_feature_version(self): + ast.parse("def foo(x, /): ...", feature_version=(3, 8)) + ast.parse("def bar(x=1, /): ...", feature_version=(3, 8)) + with self.assertRaises(SyntaxError): + ast.parse("def foo(x, /): ...", feature_version=(3, 7)) + with self.assertRaises(SyntaxError): + ast.parse("def bar(x=1, /): ...", feature_version=(3, 7)) + + ast.parse("lambda x, /: ...", feature_version=(3, 8)) + ast.parse("lambda x=1, /: ...", feature_version=(3, 8)) + with self.assertRaises(SyntaxError): + ast.parse("lambda x, /: ...", feature_version=(3, 7)) + with self.assertRaises(SyntaxError): + ast.parse("lambda x=1, /: ...", feature_version=(3, 7)) + + def test_assignment_expression_feature_version(self): + ast.parse("(x := 0)", feature_version=(3, 8)) + with self.assertRaises(SyntaxError): + ast.parse("(x := 0)", feature_version=(3, 7)) + + def test_conditional_context_managers_parse_with_low_feature_version(self): + # regression test for gh-115881 + ast.parse("with (x() if y else z()): ...", feature_version=(3, 8)) + + def test_exception_groups_feature_version(self): + code = dedent(""" + try: ... + except* Exception: ... + """) + ast.parse(code) + with self.assertRaises(SyntaxError): + ast.parse(code, feature_version=(3, 10)) + + def test_type_params_feature_version(self): + samples = [ + "type X = int", + "class X[T]: pass", + "def f[T](): pass", + ] + for sample in samples: + with self.subTest(sample): + ast.parse(sample) + with self.assertRaises(SyntaxError): + ast.parse(sample, feature_version=(3, 11)) + + def test_invalid_major_feature_version(self): + with self.assertRaises(ValueError): + ast.parse("pass", feature_version=(2, 7)) + with self.assertRaises(ValueError): + ast.parse("pass", feature_version=(4, 0)) + + def test_constant_as_name(self): + for constant in "True", "False", "None": + expr = ast.Expression(ast.Name(constant, ast.Load())) + ast.fix_missing_locations(expr) + with self.assertRaisesRegex( + ValueError, f"identifier field can't represent '{constant}' constant" + ): + compile(expr, "", "eval") + + def test_precedence_enum(self): + class _Precedence(enum.IntEnum): + """Precedence table that originated from python grammar.""" + + NAMED_EXPR = enum.auto() # := + TUPLE = enum.auto() # , + YIELD = enum.auto() # 'yield', 'yield from' + TEST = enum.auto() # 'if'-'else', 'lambda' + OR = enum.auto() # 'or' + AND = enum.auto() # 'and' + NOT = enum.auto() # 'not' + CMP = enum.auto() # '<', '>', '==', '>=', '<=', '!=', + # 'in', 'not in', 'is', 'is not' + EXPR = enum.auto() + BOR = EXPR # '|' + BXOR = enum.auto() # '^' + BAND = enum.auto() # '&' + SHIFT = enum.auto() # '<<', '>>' + ARITH = enum.auto() # '+', '-' + TERM = enum.auto() # '*', '@', '/', '%', '//' + FACTOR = enum.auto() # unary '+', '-', '~' + POWER = enum.auto() # '**' + AWAIT = enum.auto() # 'await' + ATOM = enum.auto() + + def next(self): + try: + return self.__class__(self + 1) + except ValueError: + return self + + enum._test_simple_enum(_Precedence, ast._Precedence) + + @unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI") + @support.cpython_only + def test_ast_recursion_limit(self): + fail_depth = support.C_RECURSION_LIMIT + 1 + crash_depth = 100_000 + success_depth = int(support.C_RECURSION_LIMIT * 0.9) + + def check_limit(prefix, repeated): + expect_ok = prefix + repeated * success_depth + ast.parse(expect_ok) + for depth in (fail_depth, crash_depth): + broken = prefix + repeated * depth + details = "Compiling ({!r} + {!r} * {})".format(prefix, repeated, depth) + with self.assertRaises(RecursionError, msg=details): + with support.infinite_recursion(): + ast.parse(broken) + + check_limit("a", "()") + check_limit("a", ".b") + check_limit("a", "[0]") + check_limit("a", "*a") + + def test_null_bytes(self): + with self.assertRaises( + SyntaxError, msg="source code string cannot contain null bytes" + ): + ast.parse("a\0b") + + def assert_none_check(self, node: type[ast.AST], attr: str, source: str) -> None: + with self.subTest(f"{node.__name__}.{attr}"): + tree = ast.parse(source) + found = 0 + for child in ast.walk(tree): + if isinstance(child, node): + setattr(child, attr, None) + found += 1 + self.assertEqual(found, 1) + e = re.escape(f"field '{attr}' is required for {node.__name__}") + with self.assertRaisesRegex(ValueError, f"^{e}$"): + compile(tree, "", "exec") + + def test_none_checks(self) -> None: + tests = [ + (ast.alias, "name", "import spam as SPAM"), + (ast.arg, "arg", "def spam(SPAM): spam"), + (ast.comprehension, "target", "[spam for SPAM in spam]"), + (ast.comprehension, "iter", "[spam for spam in SPAM]"), + (ast.keyword, "value", "spam(**SPAM)"), + (ast.match_case, "pattern", "match spam:\n case SPAM: spam"), + (ast.withitem, "context_expr", "with SPAM: spam"), + ] + for node, attr, source in tests: + self.assert_none_check(node, attr, source) + + +class ASTHelpers_Test(unittest.TestCase): + maxDiff = None + + def test_parse(self): + a = ast.parse("foo(1 + 1)") + b = compile("foo(1 + 1)", "", "exec", ast.PyCF_ONLY_AST) + self.assertEqual(ast.dump(a), ast.dump(b)) + + def test_parse_in_error(self): + try: + 1 / 0 + except Exception: + with self.assertRaises(SyntaxError) as e: + ast.literal_eval(r"'\U'") + self.assertIsNotNone(e.exception.__context__) + + def test_dump(self): + node = ast.parse('spam(eggs, "and cheese")') + self.assertEqual( + ast.dump(node), + "Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load()), " + "args=[Name(id='eggs', ctx=Load()), Constant(value='and cheese')], " + "keywords=[]))], type_ignores=[])", + ) + self.assertEqual( + ast.dump(node, annotate_fields=False), + "Module([Expr(Call(Name('spam', Load()), [Name('eggs', Load()), " + "Constant('and cheese')], []))], [])", + ) + self.assertEqual( + ast.dump(node, include_attributes=True), + "Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load(), " + "lineno=1, col_offset=0, end_lineno=1, end_col_offset=4), " + "args=[Name(id='eggs', ctx=Load(), lineno=1, col_offset=5, " + "end_lineno=1, end_col_offset=9), Constant(value='and cheese', " + "lineno=1, col_offset=11, end_lineno=1, end_col_offset=23)], keywords=[], " + "lineno=1, col_offset=0, end_lineno=1, end_col_offset=24), " + "lineno=1, col_offset=0, end_lineno=1, end_col_offset=24)], type_ignores=[])", + ) + + def test_dump_indent(self): + node = ast.parse('spam(eggs, "and cheese")') + self.assertEqual( + ast.dump(node, indent=3), + """\ +Module( + body=[ + Expr( + value=Call( + func=Name(id='spam', ctx=Load()), + args=[ + Name(id='eggs', ctx=Load()), + Constant(value='and cheese')], + keywords=[]))], + type_ignores=[])""", + ) + self.assertEqual( + ast.dump(node, annotate_fields=False, indent="\t"), + """\ +Module( +\t[ +\t\tExpr( +\t\t\tCall( +\t\t\t\tName('spam', Load()), +\t\t\t\t[ +\t\t\t\t\tName('eggs', Load()), +\t\t\t\t\tConstant('and cheese')], +\t\t\t\t[]))], +\t[])""", + ) + self.assertEqual( + ast.dump(node, include_attributes=True, indent=3), + """\ +Module( + body=[ + Expr( + value=Call( + func=Name( + id='spam', + ctx=Load(), + lineno=1, + col_offset=0, + end_lineno=1, + end_col_offset=4), + args=[ + Name( + id='eggs', + ctx=Load(), + lineno=1, + col_offset=5, + end_lineno=1, + end_col_offset=9), + Constant( + value='and cheese', + lineno=1, + col_offset=11, + end_lineno=1, + end_col_offset=23)], + keywords=[], + lineno=1, + col_offset=0, + end_lineno=1, + end_col_offset=24), + lineno=1, + col_offset=0, + end_lineno=1, + end_col_offset=24)], + type_ignores=[])""", + ) + + def test_dump_incomplete(self): + node = ast.Raise(lineno=3, col_offset=4) + self.assertEqual(ast.dump(node), "Raise()") + self.assertEqual( + ast.dump(node, include_attributes=True), "Raise(lineno=3, col_offset=4)" + ) + node = ast.Raise(exc=ast.Name(id="e", ctx=ast.Load()), lineno=3, col_offset=4) + self.assertEqual(ast.dump(node), "Raise(exc=Name(id='e', ctx=Load()))") + self.assertEqual( + ast.dump(node, annotate_fields=False), "Raise(Name('e', Load()))" + ) + self.assertEqual( + ast.dump(node, include_attributes=True), + "Raise(exc=Name(id='e', ctx=Load()), lineno=3, col_offset=4)", + ) + self.assertEqual( + ast.dump(node, annotate_fields=False, include_attributes=True), + "Raise(Name('e', Load()), lineno=3, col_offset=4)", + ) + node = ast.Raise(cause=ast.Name(id="e", ctx=ast.Load())) + self.assertEqual(ast.dump(node), "Raise(cause=Name(id='e', ctx=Load()))") + self.assertEqual( + ast.dump(node, annotate_fields=False), "Raise(cause=Name('e', Load()))" + ) + + def test_copy_location(self): + src = ast.parse("1 + 1", mode="eval") + src.body.right = ast.copy_location(ast.Constant(2), src.body.right) + self.assertEqual( + ast.dump(src, include_attributes=True), + "Expression(body=BinOp(left=Constant(value=1, lineno=1, col_offset=0, " + "end_lineno=1, end_col_offset=1), op=Add(), right=Constant(value=2, " + "lineno=1, col_offset=4, end_lineno=1, end_col_offset=5), lineno=1, " + "col_offset=0, end_lineno=1, end_col_offset=5))", + ) + src = ast.Call(col_offset=1, lineno=1, end_lineno=1, end_col_offset=1) + new = ast.copy_location(src, ast.Call(col_offset=None, lineno=None)) + self.assertIsNone(new.end_lineno) + self.assertIsNone(new.end_col_offset) + self.assertEqual(new.lineno, 1) + self.assertEqual(new.col_offset, 1) + + def test_fix_missing_locations(self): + src = ast.parse('write("spam")') + src.body.append( + ast.Expr(ast.Call(ast.Name("spam", ast.Load()), [ast.Constant("eggs")], [])) + ) + self.assertEqual(src, ast.fix_missing_locations(src)) + self.maxDiff = None + self.assertEqual( + ast.dump(src, include_attributes=True), + "Module(body=[Expr(value=Call(func=Name(id='write', ctx=Load(), " + "lineno=1, col_offset=0, end_lineno=1, end_col_offset=5), " + "args=[Constant(value='spam', lineno=1, col_offset=6, end_lineno=1, " + "end_col_offset=12)], keywords=[], lineno=1, col_offset=0, end_lineno=1, " + "end_col_offset=13), lineno=1, col_offset=0, end_lineno=1, " + "end_col_offset=13), Expr(value=Call(func=Name(id='spam', ctx=Load(), " + "lineno=1, col_offset=0, end_lineno=1, end_col_offset=0), " + "args=[Constant(value='eggs', lineno=1, col_offset=0, end_lineno=1, " + "end_col_offset=0)], keywords=[], lineno=1, col_offset=0, end_lineno=1, " + "end_col_offset=0), lineno=1, col_offset=0, end_lineno=1, end_col_offset=0)], " + "type_ignores=[])", + ) + + def test_increment_lineno(self): + src = ast.parse("1 + 1", mode="eval") + self.assertEqual(ast.increment_lineno(src, n=3), src) + self.assertEqual( + ast.dump(src, include_attributes=True), + "Expression(body=BinOp(left=Constant(value=1, lineno=4, col_offset=0, " + "end_lineno=4, end_col_offset=1), op=Add(), right=Constant(value=1, " + "lineno=4, col_offset=4, end_lineno=4, end_col_offset=5), lineno=4, " + "col_offset=0, end_lineno=4, end_col_offset=5))", + ) + # issue10869: do not increment lineno of root twice + src = ast.parse("1 + 1", mode="eval") + self.assertEqual(ast.increment_lineno(src.body, n=3), src.body) + self.assertEqual( + ast.dump(src, include_attributes=True), + "Expression(body=BinOp(left=Constant(value=1, lineno=4, col_offset=0, " + "end_lineno=4, end_col_offset=1), op=Add(), right=Constant(value=1, " + "lineno=4, col_offset=4, end_lineno=4, end_col_offset=5), lineno=4, " + "col_offset=0, end_lineno=4, end_col_offset=5))", + ) + src = ast.Call( + func=ast.Name("test", ast.Load()), args=[], keywords=[], lineno=1 + ) + self.assertEqual(ast.increment_lineno(src).lineno, 2) + self.assertIsNone(ast.increment_lineno(src).end_lineno) + + def test_increment_lineno_on_module(self): + src = ast.parse( + dedent("""\ + a = 1 + b = 2 # type: ignore + c = 3 + d = 4 # type: ignore@tag + """), + type_comments=True, + ) + ast.increment_lineno(src, n=5) + self.assertEqual(src.type_ignores[0].lineno, 7) + self.assertEqual(src.type_ignores[1].lineno, 9) + self.assertEqual(src.type_ignores[1].tag, "@tag") + + def test_iter_fields(self): + node = ast.parse("foo()", mode="eval") + d = dict(ast.iter_fields(node.body)) + self.assertEqual(d.pop("func").id, "foo") + self.assertEqual(d, {"keywords": [], "args": []}) + + def test_iter_child_nodes(self): + node = ast.parse("spam(23, 42, eggs='leek')", mode="eval") + self.assertEqual(len(list(ast.iter_child_nodes(node.body))), 4) + iterator = ast.iter_child_nodes(node.body) + self.assertEqual(next(iterator).id, "spam") + self.assertEqual(next(iterator).value, 23) + self.assertEqual(next(iterator).value, 42) + self.assertEqual( + ast.dump(next(iterator)), + "keyword(arg='eggs', value=Constant(value='leek'))", + ) + + def test_get_docstring(self): + node = ast.parse('"""line one\n line two"""') + self.assertEqual(ast.get_docstring(node), "line one\nline two") + + node = ast.parse('class foo:\n """line one\n line two"""') + self.assertEqual(ast.get_docstring(node.body[0]), "line one\nline two") + + node = ast.parse('def foo():\n """line one\n line two"""') + self.assertEqual(ast.get_docstring(node.body[0]), "line one\nline two") + + node = ast.parse('async def foo():\n """spam\n ham"""') + self.assertEqual(ast.get_docstring(node.body[0]), "spam\nham") + + node = ast.parse('async def foo():\n """spam\n ham"""') + self.assertEqual(ast.get_docstring(node.body[0], clean=False), "spam\n ham") + + node = ast.parse("x") + self.assertRaises(TypeError, ast.get_docstring, node.body[0]) + + def test_get_docstring_none(self): + self.assertIsNone(ast.get_docstring(ast.parse(""))) + node = ast.parse('x = "not docstring"') + self.assertIsNone(ast.get_docstring(node)) + node = ast.parse("def foo():\n pass") + self.assertIsNone(ast.get_docstring(node)) + + node = ast.parse("class foo:\n pass") + self.assertIsNone(ast.get_docstring(node.body[0])) + node = ast.parse('class foo:\n x = "not docstring"') + self.assertIsNone(ast.get_docstring(node.body[0])) + node = ast.parse("class foo:\n def bar(self): pass") + self.assertIsNone(ast.get_docstring(node.body[0])) + + node = ast.parse("def foo():\n pass") + self.assertIsNone(ast.get_docstring(node.body[0])) + node = ast.parse('def foo():\n x = "not docstring"') + self.assertIsNone(ast.get_docstring(node.body[0])) + + node = ast.parse("async def foo():\n pass") + self.assertIsNone(ast.get_docstring(node.body[0])) + node = ast.parse('async def foo():\n x = "not docstring"') + self.assertIsNone(ast.get_docstring(node.body[0])) + + node = ast.parse("async def foo():\n 42") + self.assertIsNone(ast.get_docstring(node.body[0])) + + def test_multi_line_docstring_col_offset_and_lineno_issue16806(self): + node = ast.parse( + '"""line one\nline two"""\n\n' + 'def foo():\n """line one\n line two"""\n\n' + ' def bar():\n """line one\n line two"""\n' + ' """line one\n line two"""\n' + '"""line one\nline two"""\n\n' + ) + self.assertEqual(node.body[0].col_offset, 0) + self.assertEqual(node.body[0].lineno, 1) + self.assertEqual(node.body[1].body[0].col_offset, 2) + self.assertEqual(node.body[1].body[0].lineno, 5) + self.assertEqual(node.body[1].body[1].body[0].col_offset, 4) + self.assertEqual(node.body[1].body[1].body[0].lineno, 9) + self.assertEqual(node.body[1].body[2].col_offset, 2) + self.assertEqual(node.body[1].body[2].lineno, 11) + self.assertEqual(node.body[2].col_offset, 0) + self.assertEqual(node.body[2].lineno, 13) + + def test_elif_stmt_start_position(self): + node = ast.parse("if a:\n pass\nelif b:\n pass\n") + elif_stmt = node.body[0].orelse[0] + self.assertEqual(elif_stmt.lineno, 3) + self.assertEqual(elif_stmt.col_offset, 0) + + def test_elif_stmt_start_position_with_else(self): + node = ast.parse("if a:\n pass\nelif b:\n pass\nelse:\n pass\n") + elif_stmt = node.body[0].orelse[0] + self.assertEqual(elif_stmt.lineno, 3) + self.assertEqual(elif_stmt.col_offset, 0) + + def test_starred_expr_end_position_within_call(self): + node = ast.parse("f(*[0, 1])") + starred_expr = node.body[0].value.args[0] + self.assertEqual(starred_expr.end_lineno, 1) + self.assertEqual(starred_expr.end_col_offset, 9) + + def test_literal_eval(self): + self.assertEqual(ast.literal_eval("[1, 2, 3]"), [1, 2, 3]) + self.assertEqual(ast.literal_eval('{"foo": 42}'), {"foo": 42}) + self.assertEqual(ast.literal_eval("(True, False, None)"), (True, False, None)) + self.assertEqual(ast.literal_eval("{1, 2, 3}"), {1, 2, 3}) + self.assertEqual(ast.literal_eval('b"hi"'), b"hi") + self.assertEqual(ast.literal_eval("set()"), set()) + self.assertRaises(ValueError, ast.literal_eval, "foo()") + self.assertEqual(ast.literal_eval("6"), 6) + self.assertEqual(ast.literal_eval("+6"), 6) + self.assertEqual(ast.literal_eval("-6"), -6) + self.assertEqual(ast.literal_eval("3.25"), 3.25) + self.assertEqual(ast.literal_eval("+3.25"), 3.25) + self.assertEqual(ast.literal_eval("-3.25"), -3.25) + self.assertEqual(repr(ast.literal_eval("-0.0")), "-0.0") + self.assertRaises(ValueError, ast.literal_eval, "++6") + self.assertRaises(ValueError, ast.literal_eval, "+True") + self.assertRaises(ValueError, ast.literal_eval, "2+3") + + def test_literal_eval_str_int_limit(self): + with support.adjust_int_max_str_digits(4000): + ast.literal_eval("3" * 4000) # no error + with self.assertRaises(SyntaxError) as err_ctx: + ast.literal_eval("3" * 4001) + self.assertIn("Exceeds the limit ", str(err_ctx.exception)) + self.assertIn(" Consider hexadecimal ", str(err_ctx.exception)) + + def test_literal_eval_complex(self): + # Issue #4907 + self.assertEqual(ast.literal_eval("6j"), 6j) + self.assertEqual(ast.literal_eval("-6j"), -6j) + self.assertEqual(ast.literal_eval("6.75j"), 6.75j) + self.assertEqual(ast.literal_eval("-6.75j"), -6.75j) + self.assertEqual(ast.literal_eval("3+6j"), 3 + 6j) + self.assertEqual(ast.literal_eval("-3+6j"), -3 + 6j) + self.assertEqual(ast.literal_eval("3-6j"), 3 - 6j) + self.assertEqual(ast.literal_eval("-3-6j"), -3 - 6j) + self.assertEqual(ast.literal_eval("3.25+6.75j"), 3.25 + 6.75j) + self.assertEqual(ast.literal_eval("-3.25+6.75j"), -3.25 + 6.75j) + self.assertEqual(ast.literal_eval("3.25-6.75j"), 3.25 - 6.75j) + self.assertEqual(ast.literal_eval("-3.25-6.75j"), -3.25 - 6.75j) + self.assertEqual(ast.literal_eval("(3+6j)"), 3 + 6j) + self.assertRaises(ValueError, ast.literal_eval, "-6j+3") + self.assertRaises(ValueError, ast.literal_eval, "-6j+3j") + self.assertRaises(ValueError, ast.literal_eval, "3+-6j") + self.assertRaises(ValueError, ast.literal_eval, "3+(0+6j)") + self.assertRaises(ValueError, ast.literal_eval, "-(3+6j)") + + def test_literal_eval_malformed_dict_nodes(self): + malformed = ast.Dict( + keys=[ast.Constant(1), ast.Constant(2)], values=[ast.Constant(3)] + ) + self.assertRaises(ValueError, ast.literal_eval, malformed) + malformed = ast.Dict( + keys=[ast.Constant(1)], values=[ast.Constant(2), ast.Constant(3)] + ) + self.assertRaises(ValueError, ast.literal_eval, malformed) + + def test_literal_eval_trailing_ws(self): + self.assertEqual(ast.literal_eval(" -1"), -1) + self.assertEqual(ast.literal_eval("\t\t-1"), -1) + self.assertEqual(ast.literal_eval(" \t -1"), -1) + self.assertRaises(IndentationError, ast.literal_eval, "\n -1") + + def test_literal_eval_malformed_lineno(self): + msg = r"malformed node or string on line 3:" + with self.assertRaisesRegex(ValueError, msg): + ast.literal_eval("{'a': 1,\n'b':2,\n'c':++3,\n'd':4}") + + node = ast.UnaryOp(ast.UAdd(), ast.UnaryOp(ast.UAdd(), ast.Constant(6))) + self.assertIsNone(getattr(node, "lineno", None)) + msg = r"malformed node or string:" + with self.assertRaisesRegex(ValueError, msg): + ast.literal_eval(node) + + def test_literal_eval_syntax_errors(self): + with self.assertRaisesRegex(SyntaxError, "unexpected indent"): + ast.literal_eval(r""" + \ + (\ + \ """) + + def test_bad_integer(self): + # issue13436: Bad error message with invalid numeric values + body = [ + ast.ImportFrom( + module="time", + names=[ast.alias(name="sleep")], + level=None, + lineno=None, + col_offset=None, + ) + ] + mod = ast.Module(body, []) + with self.assertRaises(ValueError) as cm: + compile(mod, "test", "exec") + self.assertIn("invalid integer value: None", str(cm.exception)) + + def test_level_as_none(self): + body = [ + ast.ImportFrom( + module="time", + names=[ast.alias(name="sleep", lineno=0, col_offset=0)], + level=None, + lineno=0, + col_offset=0, + ) + ] + mod = ast.Module(body, []) + code = compile(mod, "test", "exec") + ns = {} + exec(code, ns) + self.assertIn("sleep", ns) + + def test_recursion_direct(self): + e = ast.UnaryOp(op=ast.Not(), lineno=0, col_offset=0) + e.operand = e + with self.assertRaises(RecursionError): + with support.infinite_recursion(): + compile(ast.Expression(e), "", "eval") + + def test_recursion_indirect(self): + e = ast.UnaryOp(op=ast.Not(), lineno=0, col_offset=0) + f = ast.UnaryOp(op=ast.Not(), lineno=0, col_offset=0) + e.operand = f + f.operand = e + with self.assertRaises(RecursionError): + with support.infinite_recursion(): + compile(ast.Expression(e), "", "eval") + + +class ASTValidatorTests(unittest.TestCase): + def mod(self, mod, msg=None, mode="exec", *, exc=ValueError): + mod.lineno = mod.col_offset = 0 + ast.fix_missing_locations(mod) + if msg is None: + compile(mod, "", mode) + else: + with self.assertRaises(exc) as cm: + compile(mod, "", mode) + self.assertIn(msg, str(cm.exception)) + + def expr(self, node, msg=None, *, exc=ValueError): + mod = ast.Module([ast.Expr(node)], []) + self.mod(mod, msg, exc=exc) + + def stmt(self, stmt, msg=None): + mod = ast.Module([stmt], []) + self.mod(mod, msg) + + def test_module(self): + m = ast.Interactive([ast.Expr(ast.Name("x", ast.Store()))]) + self.mod(m, "must have Load context", "single") + m = ast.Expression(ast.Name("x", ast.Store())) + self.mod(m, "must have Load context", "eval") + + def _check_arguments(self, fac, check): + def arguments( + args=None, + posonlyargs=None, + vararg=None, + kwonlyargs=None, + kwarg=None, + defaults=None, + kw_defaults=None, + ): + if args is None: + args = [] + if posonlyargs is None: + posonlyargs = [] + if kwonlyargs is None: + kwonlyargs = [] + if defaults is None: + defaults = [] + if kw_defaults is None: + kw_defaults = [] + args = ast.arguments( + args, posonlyargs, vararg, kwonlyargs, kw_defaults, kwarg, defaults + ) + return fac(args) + + args = [ast.arg("x", ast.Name("x", ast.Store()))] + check(arguments(args=args), "must have Load context") + check(arguments(posonlyargs=args), "must have Load context") + check(arguments(kwonlyargs=args), "must have Load context") + check( + arguments(defaults=[ast.Constant(3)]), "more positional defaults than args" + ) + check( + arguments(kw_defaults=[ast.Constant(4)]), + "length of kwonlyargs is not the same as kw_defaults", + ) + args = [ast.arg("x", ast.Name("x", ast.Load()))] + check( + arguments(args=args, defaults=[ast.Name("x", ast.Store())]), + "must have Load context", + ) + args = [ + ast.arg("a", ast.Name("x", ast.Load())), + ast.arg("b", ast.Name("y", ast.Load())), + ] + check( + arguments(kwonlyargs=args, kw_defaults=[None, ast.Name("x", ast.Store())]), + "must have Load context", + ) + + def test_funcdef(self): + a = ast.arguments([], [], None, [], [], None, []) + f = ast.FunctionDef("x", a, [], [], None, None, []) + self.stmt(f, "empty body on FunctionDef") + f = ast.FunctionDef( + "x", a, [ast.Pass()], [ast.Name("x", ast.Store())], None, None, [] + ) + self.stmt(f, "must have Load context") + f = ast.FunctionDef( + "x", a, [ast.Pass()], [], ast.Name("x", ast.Store()), None, [] + ) + self.stmt(f, "must have Load context") + f = ast.FunctionDef("x", ast.arguments(), [ast.Pass()]) + self.stmt(f) + + def fac(args): + return ast.FunctionDef("x", args, [ast.Pass()], [], None, None, []) + + self._check_arguments(fac, self.stmt) + + def test_funcdef_pattern_matching(self): + # gh-104799: New fields on FunctionDef should be added at the end + def matcher(node): + match node: + case ast.FunctionDef( + "foo", + ast.arguments(args=[ast.arg("bar")]), + [ast.Pass()], + [ast.Name("capybara", ast.Load())], + ast.Name("pacarana", ast.Load()), + ): + return True + case _: + return False + + code = """ + @capybara + def foo(bar) -> pacarana: + pass + """ + source = ast.parse(textwrap.dedent(code)) + funcdef = source.body[0] + self.assertIsInstance(funcdef, ast.FunctionDef) + self.assertTrue(matcher(funcdef)) + + def test_classdef(self): + def cls( + bases=None, keywords=None, body=None, decorator_list=None, type_params=None + ): + if bases is None: + bases = [] + if keywords is None: + keywords = [] + if body is None: + body = [ast.Pass()] + if decorator_list is None: + decorator_list = [] + if type_params is None: + type_params = [] + return ast.ClassDef( + "myclass", bases, keywords, body, decorator_list, type_params + ) + + self.stmt(cls(bases=[ast.Name("x", ast.Store())]), "must have Load context") + self.stmt( + cls(keywords=[ast.keyword("x", ast.Name("x", ast.Store()))]), + "must have Load context", + ) + self.stmt(cls(body=[]), "empty body on ClassDef") + self.stmt(cls(body=[None]), "None disallowed") + self.stmt( + cls(decorator_list=[ast.Name("x", ast.Store())]), "must have Load context" + ) + + def test_delete(self): + self.stmt(ast.Delete([]), "empty targets on Delete") + self.stmt(ast.Delete([None]), "None disallowed") + self.stmt(ast.Delete([ast.Name("x", ast.Load())]), "must have Del context") + + def test_assign(self): + self.stmt(ast.Assign([], ast.Constant(3)), "empty targets on Assign") + self.stmt(ast.Assign([None], ast.Constant(3)), "None disallowed") + self.stmt( + ast.Assign([ast.Name("x", ast.Load())], ast.Constant(3)), + "must have Store context", + ) + self.stmt( + ast.Assign([ast.Name("x", ast.Store())], ast.Name("y", ast.Store())), + "must have Load context", + ) + + def test_augassign(self): + aug = ast.AugAssign( + ast.Name("x", ast.Load()), ast.Add(), ast.Name("y", ast.Load()) + ) + self.stmt(aug, "must have Store context") + aug = ast.AugAssign( + ast.Name("x", ast.Store()), ast.Add(), ast.Name("y", ast.Store()) + ) + self.stmt(aug, "must have Load context") + + def test_for(self): + x = ast.Name("x", ast.Store()) + y = ast.Name("y", ast.Load()) + p = ast.Pass() + self.stmt(ast.For(x, y, [], []), "empty body on For") + self.stmt( + ast.For(ast.Name("x", ast.Load()), y, [p], []), "must have Store context" + ) + self.stmt( + ast.For(x, ast.Name("y", ast.Store()), [p], []), "must have Load context" + ) + e = ast.Expr(ast.Name("x", ast.Store())) + self.stmt(ast.For(x, y, [e], []), "must have Load context") + self.stmt(ast.For(x, y, [p], [e]), "must have Load context") + + def test_while(self): + self.stmt(ast.While(ast.Constant(3), [], []), "empty body on While") + self.stmt( + ast.While(ast.Name("x", ast.Store()), [ast.Pass()], []), + "must have Load context", + ) + self.stmt( + ast.While( + ast.Constant(3), [ast.Pass()], [ast.Expr(ast.Name("x", ast.Store()))] + ), + "must have Load context", + ) + + def test_if(self): + self.stmt(ast.If(ast.Constant(3), [], []), "empty body on If") + i = ast.If(ast.Name("x", ast.Store()), [ast.Pass()], []) + self.stmt(i, "must have Load context") + i = ast.If(ast.Constant(3), [ast.Expr(ast.Name("x", ast.Store()))], []) + self.stmt(i, "must have Load context") + i = ast.If( + ast.Constant(3), [ast.Pass()], [ast.Expr(ast.Name("x", ast.Store()))] + ) + self.stmt(i, "must have Load context") + + def test_with(self): + p = ast.Pass() + self.stmt(ast.With([], [p]), "empty items on With") + i = ast.withitem(ast.Constant(3), None) + self.stmt(ast.With([i], []), "empty body on With") + i = ast.withitem(ast.Name("x", ast.Store()), None) + self.stmt(ast.With([i], [p]), "must have Load context") + i = ast.withitem(ast.Constant(3), ast.Name("x", ast.Load())) + self.stmt(ast.With([i], [p]), "must have Store context") + + def test_raise(self): + r = ast.Raise(None, ast.Constant(3)) + self.stmt(r, "Raise with cause but no exception") + r = ast.Raise(ast.Name("x", ast.Store()), None) + self.stmt(r, "must have Load context") + r = ast.Raise(ast.Constant(4), ast.Name("x", ast.Store())) + self.stmt(r, "must have Load context") + + def test_try(self): + p = ast.Pass() + t = ast.Try([], [], [], [p]) + self.stmt(t, "empty body on Try") + t = ast.Try([ast.Expr(ast.Name("x", ast.Store()))], [], [], [p]) + self.stmt(t, "must have Load context") + t = ast.Try([p], [], [], []) + self.stmt(t, "Try has neither except handlers nor finalbody") + t = ast.Try([p], [], [p], [p]) + self.stmt(t, "Try has orelse but no except handlers") + t = ast.Try([p], [ast.ExceptHandler(None, "x", [])], [], []) + self.stmt(t, "empty body on ExceptHandler") + e = [ast.ExceptHandler(ast.Name("x", ast.Store()), "y", [p])] + self.stmt(ast.Try([p], e, [], []), "must have Load context") + e = [ast.ExceptHandler(None, "x", [p])] + t = ast.Try([p], e, [ast.Expr(ast.Name("x", ast.Store()))], [p]) + self.stmt(t, "must have Load context") + t = ast.Try([p], e, [p], [ast.Expr(ast.Name("x", ast.Store()))]) + self.stmt(t, "must have Load context") + + def test_try_star(self): + p = ast.Pass() + t = ast.TryStar([], [], [], [p]) + self.stmt(t, "empty body on TryStar") + t = ast.TryStar([ast.Expr(ast.Name("x", ast.Store()))], [], [], [p]) + self.stmt(t, "must have Load context") + t = ast.TryStar([p], [], [], []) + self.stmt(t, "TryStar has neither except handlers nor finalbody") + t = ast.TryStar([p], [], [p], [p]) + self.stmt(t, "TryStar has orelse but no except handlers") + t = ast.TryStar([p], [ast.ExceptHandler(None, "x", [])], [], []) + self.stmt(t, "empty body on ExceptHandler") + e = [ast.ExceptHandler(ast.Name("x", ast.Store()), "y", [p])] + self.stmt(ast.TryStar([p], e, [], []), "must have Load context") + e = [ast.ExceptHandler(None, "x", [p])] + t = ast.TryStar([p], e, [ast.Expr(ast.Name("x", ast.Store()))], [p]) + self.stmt(t, "must have Load context") + t = ast.TryStar([p], e, [p], [ast.Expr(ast.Name("x", ast.Store()))]) + self.stmt(t, "must have Load context") + + def test_assert(self): + self.stmt( + ast.Assert(ast.Name("x", ast.Store()), None), "must have Load context" + ) + assrt = ast.Assert(ast.Name("x", ast.Load()), ast.Name("y", ast.Store())) + self.stmt(assrt, "must have Load context") + + def test_import(self): + self.stmt(ast.Import([]), "empty names on Import") + + def test_importfrom(self): + imp = ast.ImportFrom(None, [ast.alias("x", None)], -42) + self.stmt(imp, "Negative ImportFrom level") + self.stmt(ast.ImportFrom(None, [], 0), "empty names on ImportFrom") + + def test_global(self): + self.stmt(ast.Global([]), "empty names on Global") + + def test_nonlocal(self): + self.stmt(ast.Nonlocal([]), "empty names on Nonlocal") + + def test_expr(self): + e = ast.Expr(ast.Name("x", ast.Store())) + self.stmt(e, "must have Load context") + + def test_boolop(self): + b = ast.BoolOp(ast.And(), []) + self.expr(b, "less than 2 values") + b = ast.BoolOp(ast.And(), [ast.Constant(3)]) + self.expr(b, "less than 2 values") + b = ast.BoolOp(ast.And(), [ast.Constant(4), None]) + self.expr(b, "None disallowed") + b = ast.BoolOp(ast.And(), [ast.Constant(4), ast.Name("x", ast.Store())]) + self.expr(b, "must have Load context") + + def test_unaryop(self): + u = ast.UnaryOp(ast.Not(), ast.Name("x", ast.Store())) + self.expr(u, "must have Load context") + + def test_lambda(self): + a = ast.arguments([], [], None, [], [], None, []) + self.expr(ast.Lambda(a, ast.Name("x", ast.Store())), "must have Load context") + + def fac(args): + return ast.Lambda(args, ast.Name("x", ast.Load())) + + self._check_arguments(fac, self.expr) + + def test_ifexp(self): + l = ast.Name("x", ast.Load()) + s = ast.Name("y", ast.Store()) + for args in (s, l, l), (l, s, l), (l, l, s): + self.expr(ast.IfExp(*args), "must have Load context") + + def test_dict(self): + d = ast.Dict([], [ast.Name("x", ast.Load())]) + self.expr(d, "same number of keys as values") + d = ast.Dict([ast.Name("x", ast.Load())], [None]) + self.expr(d, "None disallowed") + + def test_set(self): + self.expr(ast.Set([None]), "None disallowed") + s = ast.Set([ast.Name("x", ast.Store())]) + self.expr(s, "must have Load context") + + def _check_comprehension(self, fac): + self.expr(fac([]), "comprehension with no generators") + g = ast.comprehension( + ast.Name("x", ast.Load()), ast.Name("x", ast.Load()), [], 0 + ) + self.expr(fac([g]), "must have Store context") + g = ast.comprehension( + ast.Name("x", ast.Store()), ast.Name("x", ast.Store()), [], 0 + ) + self.expr(fac([g]), "must have Load context") + x = ast.Name("x", ast.Store()) + y = ast.Name("y", ast.Load()) + g = ast.comprehension(x, y, [None], 0) + self.expr(fac([g]), "None disallowed") + g = ast.comprehension(x, y, [ast.Name("x", ast.Store())], 0) + self.expr(fac([g]), "must have Load context") + + def _simple_comp(self, fac): + g = ast.comprehension( + ast.Name("x", ast.Store()), ast.Name("x", ast.Load()), [], 0 + ) + self.expr(fac(ast.Name("x", ast.Store()), [g]), "must have Load context") + + def wrap(gens): + return fac(ast.Name("x", ast.Store()), gens) + + self._check_comprehension(wrap) + + def test_listcomp(self): + self._simple_comp(ast.ListComp) + + def test_setcomp(self): + self._simple_comp(ast.SetComp) + + def test_generatorexp(self): + self._simple_comp(ast.GeneratorExp) + + def test_dictcomp(self): + g = ast.comprehension( + ast.Name("y", ast.Store()), ast.Name("p", ast.Load()), [], 0 + ) + c = ast.DictComp(ast.Name("x", ast.Store()), ast.Name("y", ast.Load()), [g]) + self.expr(c, "must have Load context") + c = ast.DictComp(ast.Name("x", ast.Load()), ast.Name("y", ast.Store()), [g]) + self.expr(c, "must have Load context") + + def factory(comps): + k = ast.Name("x", ast.Load()) + v = ast.Name("y", ast.Load()) + return ast.DictComp(k, v, comps) + + self._check_comprehension(factory) + + def test_yield(self): + self.expr(ast.Yield(ast.Name("x", ast.Store())), "must have Load") + self.expr(ast.YieldFrom(ast.Name("x", ast.Store())), "must have Load") + + def test_compare(self): + left = ast.Name("x", ast.Load()) + comp = ast.Compare(left, [ast.In()], []) + self.expr(comp, "no comparators") + comp = ast.Compare(left, [ast.In()], [ast.Constant(4), ast.Constant(5)]) + self.expr(comp, "different number of comparators and operands") + comp = ast.Compare(ast.Constant("blah"), [ast.In()], [left]) + self.expr(comp) + comp = ast.Compare(left, [ast.In()], [ast.Constant("blah")]) + self.expr(comp) + + def test_call(self): + func = ast.Name("x", ast.Load()) + args = [ast.Name("y", ast.Load())] + keywords = [ast.keyword("w", ast.Name("z", ast.Load()))] + call = ast.Call(ast.Name("x", ast.Store()), args, keywords) + self.expr(call, "must have Load context") + call = ast.Call(func, [None], keywords) + self.expr(call, "None disallowed") + bad_keywords = [ast.keyword("w", ast.Name("z", ast.Store()))] + call = ast.Call(func, args, bad_keywords) + self.expr(call, "must have Load context") + + def test_num(self): + with warnings.catch_warnings(record=True) as wlog: + warnings.filterwarnings("ignore", "", DeprecationWarning) + from ast import Num + + with warnings.catch_warnings(record=True) as wlog: + warnings.filterwarnings("always", "", DeprecationWarning) + + class subint(int): + pass + + class subfloat(float): + pass + + class subcomplex(complex): + pass + + for obj in "0", "hello": + self.expr(ast.Num(obj)) + for obj in subint(), subfloat(), subcomplex(): + self.expr(ast.Num(obj), "invalid type", exc=TypeError) + + self.assertEqual( + [str(w.message) for w in wlog], + [ + "ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead", + "ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead", + ], + ) + + def test_attribute(self): + attr = ast.Attribute(ast.Name("x", ast.Store()), "y", ast.Load()) + self.expr(attr, "must have Load context") + + def test_subscript(self): + sub = ast.Subscript(ast.Name("x", ast.Store()), ast.Constant(3), ast.Load()) + self.expr(sub, "must have Load context") + x = ast.Name("x", ast.Load()) + sub = ast.Subscript(x, ast.Name("y", ast.Store()), ast.Load()) + self.expr(sub, "must have Load context") + s = ast.Name("x", ast.Store()) + for args in (s, None, None), (None, s, None), (None, None, s): + sl = ast.Slice(*args) + self.expr(ast.Subscript(x, sl, ast.Load()), "must have Load context") + sl = ast.Tuple([], ast.Load()) + self.expr(ast.Subscript(x, sl, ast.Load())) + sl = ast.Tuple([s], ast.Load()) + self.expr(ast.Subscript(x, sl, ast.Load()), "must have Load context") + + def test_starred(self): + left = ast.List( + [ast.Starred(ast.Name("x", ast.Load()), ast.Store())], ast.Store() + ) + assign = ast.Assign([left], ast.Constant(4)) + self.stmt(assign, "must have Store context") + + def _sequence(self, fac): + self.expr(fac([None], ast.Load()), "None disallowed") + self.expr( + fac([ast.Name("x", ast.Store())], ast.Load()), "must have Load context" + ) + + def test_list(self): + self._sequence(ast.List) + + def test_tuple(self): + self._sequence(ast.Tuple) + + def test_nameconstant(self): + with warnings.catch_warnings(record=True) as wlog: + warnings.filterwarnings("ignore", "", DeprecationWarning) + from ast import NameConstant + + with warnings.catch_warnings(record=True) as wlog: + warnings.filterwarnings("always", "", DeprecationWarning) + self.expr(ast.NameConstant(4)) + + self.assertEqual( + [str(w.message) for w in wlog], + [ + "ast.NameConstant is deprecated and will be removed in Python 3.14; use ast.Constant instead", + ], + ) + + @support.requires_resource("cpu") + def test_stdlib_validates(self): + stdlib = os.path.dirname(ast.__file__) + tests = [fn for fn in os.listdir(stdlib) if fn.endswith(".py")] + tests.extend(["test/test_grammar.py", "test/test_unpack_ex.py"]) + for module in tests: + with self.subTest(module): + fn = os.path.join(stdlib, module) + with open(fn, "r", encoding="utf-8") as fp: + source = fp.read() + mod = ast.parse(source, fn) + compile(mod, fn, "exec") + + constant_1 = ast.Constant(1) + pattern_1 = ast.MatchValue(constant_1) + + constant_x = ast.Constant("x") + pattern_x = ast.MatchValue(constant_x) + + constant_true = ast.Constant(True) + pattern_true = ast.MatchSingleton(True) + + name_carter = ast.Name("carter", ast.Load()) + + _MATCH_PATTERNS = [ + ast.MatchValue( + ast.Attribute( + ast.Attribute(ast.Name("x", ast.Store()), "y", ast.Load()), + "z", + ast.Load(), + ) + ), + ast.MatchValue( + ast.Attribute( + ast.Attribute(ast.Name("x", ast.Load()), "y", ast.Store()), + "z", + ast.Load(), + ) + ), + ast.MatchValue(ast.Constant(...)), + ast.MatchValue(ast.Constant(True)), + ast.MatchValue(ast.Constant((1, 2, 3))), + ast.MatchSingleton("string"), + ast.MatchSequence([ast.MatchSingleton("string")]), + ast.MatchSequence([ast.MatchSequence([ast.MatchSingleton("string")])]), + ast.MatchMapping([constant_1, constant_true], [pattern_x]), + ast.MatchMapping( + [constant_true, constant_1], [pattern_x, pattern_1], rest="True" + ), + ast.MatchMapping( + [constant_true, ast.Starred(ast.Name("lol", ast.Load()), ast.Load())], + [pattern_x, pattern_1], + rest="legit", + ), + ast.MatchClass( + ast.Attribute(ast.Attribute(constant_x, "y", ast.Load()), "z", ast.Load()), + patterns=[], + kwd_attrs=[], + kwd_patterns=[], + ), + ast.MatchClass( + name_carter, patterns=[], kwd_attrs=["True"], kwd_patterns=[pattern_1] + ), + ast.MatchClass( + name_carter, patterns=[], kwd_attrs=[], kwd_patterns=[pattern_1] + ), + ast.MatchClass( + name_carter, + patterns=[ast.MatchSingleton("string")], + kwd_attrs=[], + kwd_patterns=[], + ), + ast.MatchClass( + name_carter, patterns=[ast.MatchStar()], kwd_attrs=[], kwd_patterns=[] + ), + ast.MatchClass( + name_carter, patterns=[], kwd_attrs=[], kwd_patterns=[ast.MatchStar()] + ), + ast.MatchClass( + constant_true, # invalid name + patterns=[], + kwd_attrs=["True"], + kwd_patterns=[pattern_1], + ), + ast.MatchSequence([ast.MatchStar("True")]), + ast.MatchAs(name="False"), + ast.MatchOr([]), + ast.MatchOr([pattern_1]), + ast.MatchOr([pattern_1, pattern_x, ast.MatchSingleton("xxx")]), + ast.MatchAs(name="_"), + ast.MatchStar(name="x"), + ast.MatchSequence([ast.MatchStar("_")]), + ast.MatchMapping([], [], rest="_"), + ] + + def test_match_validation_pattern(self): + name_x = ast.Name("x", ast.Load()) + for pattern in self._MATCH_PATTERNS: + with self.subTest(ast.dump(pattern, indent=4)): + node = ast.Match( + subject=name_x, + cases=[ast.match_case(pattern=pattern, body=[ast.Pass()])], + ) + node = ast.fix_missing_locations(node) + module = ast.Module([node], []) + with self.assertRaises(ValueError): + compile(module, "", "exec") + + +class ConstantTests(unittest.TestCase): + """Tests on the ast.Constant node type.""" + + def compile_constant(self, value): + tree = ast.parse("x = 123") + + node = tree.body[0].value + new_node = ast.Constant(value=value) + ast.copy_location(new_node, node) + tree.body[0].value = new_node + + code = compile(tree, "", "exec") + + ns = {} + exec(code, ns) + return ns["x"] + + def test_validation(self): + with self.assertRaises(TypeError) as cm: + self.compile_constant([1, 2, 3]) + self.assertEqual(str(cm.exception), "got an invalid type in Constant: list") + + def test_singletons(self): + for const in (None, False, True, Ellipsis, b"", frozenset()): + with self.subTest(const=const): + value = self.compile_constant(const) + self.assertIs(value, const) + + def test_values(self): + nested_tuple = (1,) + nested_frozenset = frozenset({1}) + for level in range(3): + nested_tuple = (nested_tuple, 2) + nested_frozenset = frozenset({nested_frozenset, 2}) + values = ( + 123, + 123.0, + 123j, + "unicode", + b"bytes", + tuple("tuple"), + frozenset("frozenset"), + nested_tuple, + nested_frozenset, + ) + for value in values: + with self.subTest(value=value): + result = self.compile_constant(value) + self.assertEqual(result, value) + + def test_assign_to_constant(self): + tree = ast.parse("x = 1") + + target = tree.body[0].targets[0] + new_target = ast.Constant(value=1) + ast.copy_location(new_target, target) + tree.body[0].targets[0] = new_target + + with self.assertRaises(ValueError) as cm: + compile(tree, "string", "exec") + self.assertEqual( + str(cm.exception), + "expression which can't be assigned " "to in Store context", + ) + + def test_get_docstring(self): + tree = ast.parse("'docstring'\nx = 1") + self.assertEqual(ast.get_docstring(tree), "docstring") + + def get_load_const(self, tree): + # Compile to bytecode, disassemble and get parameter of LOAD_CONST + # instructions + co = compile(tree, "", "exec") + consts = [] + for instr in dis.get_instructions(co): + if instr.opname == "LOAD_CONST" or instr.opname == "RETURN_CONST": + consts.append(instr.argval) + return consts + + @support.cpython_only + def test_load_const(self): + consts = [None, True, False, 124, 2.0, 3j, "unicode", b"bytes", (1, 2, 3)] + + code = "\n".join(["x={!r}".format(const) for const in consts]) + code += "\nx = ..." + consts.extend((Ellipsis, None)) + + tree = ast.parse(code) + self.assertEqual(self.get_load_const(tree), consts) + + # Replace expression nodes with constants + for assign, const in zip(tree.body, consts): + assert isinstance(assign, ast.Assign), ast.dump(assign) + new_node = ast.Constant(value=const) + ast.copy_location(new_node, assign.value) + assign.value = new_node + + self.assertEqual(self.get_load_const(tree), consts) + + def test_literal_eval(self): + tree = ast.parse("1 + 2") + binop = tree.body[0].value + + new_left = ast.Constant(value=10) + ast.copy_location(new_left, binop.left) + binop.left = new_left + + new_right = ast.Constant(value=20j) + ast.copy_location(new_right, binop.right) + binop.right = new_right + + self.assertEqual(ast.literal_eval(binop), 10 + 20j) + + def test_string_kind(self): + c = ast.parse('"x"', mode="eval").body + self.assertEqual(c.value, "x") + self.assertEqual(c.kind, None) + + c = ast.parse('u"x"', mode="eval").body + self.assertEqual(c.value, "x") + self.assertEqual(c.kind, "u") + + c = ast.parse('r"x"', mode="eval").body + self.assertEqual(c.value, "x") + self.assertEqual(c.kind, None) + + c = ast.parse('b"x"', mode="eval").body + self.assertEqual(c.value, b"x") + self.assertEqual(c.kind, None) + + +class EndPositionTests(unittest.TestCase): + """Tests for end position of AST nodes. + + Testing end positions of nodes requires a bit of extra care + because of how LL parsers work. + """ + + def _check_end_pos(self, ast_node, end_lineno, end_col_offset): + self.assertEqual(ast_node.end_lineno, end_lineno) + self.assertEqual(ast_node.end_col_offset, end_col_offset) + + def _check_content(self, source, ast_node, content): + self.assertEqual(ast.get_source_segment(source, ast_node), content) + + def _parse_value(self, s): + # Use duck-typing to support both single expression + # and a right hand side of an assignment statement. + return ast.parse(s).body[0].value + + def test_lambda(self): + s = "lambda x, *y: None" + lam = self._parse_value(s) + self._check_content(s, lam.body, "None") + self._check_content(s, lam.args.args[0], "x") + self._check_content(s, lam.args.vararg, "y") + + def test_func_def(self): + s = dedent(""" + def func(x: int, + *args: str, + z: float = 0, + **kwargs: Any) -> bool: + return True + """).strip() + fdef = ast.parse(s).body[0] + self._check_end_pos(fdef, 5, 15) + self._check_content(s, fdef.body[0], "return True") + self._check_content(s, fdef.args.args[0], "x: int") + self._check_content(s, fdef.args.args[0].annotation, "int") + self._check_content(s, fdef.args.kwarg, "kwargs: Any") + self._check_content(s, fdef.args.kwarg.annotation, "Any") + + def test_call(self): + s = "func(x, y=2, **kw)" + call = self._parse_value(s) + self._check_content(s, call.func, "func") + self._check_content(s, call.keywords[0].value, "2") + self._check_content(s, call.keywords[1].value, "kw") + + def test_call_noargs(self): + s = "x[0]()" + call = self._parse_value(s) + self._check_content(s, call.func, "x[0]") + self._check_end_pos(call, 1, 6) + + def test_class_def(self): + s = dedent(""" + class C(A, B): + x: int = 0 + """).strip() + cdef = ast.parse(s).body[0] + self._check_end_pos(cdef, 2, 14) + self._check_content(s, cdef.bases[1], "B") + self._check_content(s, cdef.body[0], "x: int = 0") + + def test_class_kw(self): + s = "class S(metaclass=abc.ABCMeta): pass" + cdef = ast.parse(s).body[0] + self._check_content(s, cdef.keywords[0].value, "abc.ABCMeta") + + def test_multi_line_str(self): + s = dedent(''' + x = """Some multi-line text. + + It goes on starting from same indent.""" + ''').strip() + assign = ast.parse(s).body[0] + self._check_end_pos(assign, 3, 40) + self._check_end_pos(assign.value, 3, 40) + + def test_continued_str(self): + s = dedent(""" + x = "first part" \\ + "second part" + """).strip() + assign = ast.parse(s).body[0] + self._check_end_pos(assign, 2, 13) + self._check_end_pos(assign.value, 2, 13) + + def test_suites(self): + # We intentionally put these into the same string to check + # that empty lines are not part of the suite. + s = dedent(""" + while True: + pass + + if one(): + x = None + elif other(): + y = None + else: + z = None + + for x, y in stuff: + assert True + + try: + raise RuntimeError + except TypeError as e: + pass + + pass + """).strip() + mod = ast.parse(s) + while_loop = mod.body[0] + if_stmt = mod.body[1] + for_loop = mod.body[2] + try_stmt = mod.body[3] + pass_stmt = mod.body[4] + + self._check_end_pos(while_loop, 2, 8) + self._check_end_pos(if_stmt, 9, 12) + self._check_end_pos(for_loop, 12, 15) + self._check_end_pos(try_stmt, 17, 8) + self._check_end_pos(pass_stmt, 19, 4) + + self._check_content(s, while_loop.test, "True") + self._check_content(s, if_stmt.body[0], "x = None") + self._check_content(s, if_stmt.orelse[0].test, "other()") + self._check_content(s, for_loop.target, "x, y") + self._check_content(s, try_stmt.body[0], "raise RuntimeError") + self._check_content(s, try_stmt.handlers[0].type, "TypeError") + + def test_fstring(self): + s = 'x = f"abc {x + y} abc"' + fstr = self._parse_value(s) + binop = fstr.values[1].value + self._check_content(s, binop, "x + y") + + def test_fstring_multi_line(self): + s = dedent(''' + f"""Some multi-line text. + { + arg_one + + + arg_two + } + It goes on...""" + ''').strip() + fstr = self._parse_value(s) + binop = fstr.values[1].value + self._check_end_pos(binop, 5, 7) + self._check_content(s, binop.left, "arg_one") + self._check_content(s, binop.right, "arg_two") + + def test_import_from_multi_line(self): + s = dedent(""" + from x.y.z import ( + a, b, c as c + ) + """).strip() + imp = ast.parse(s).body[0] + self._check_end_pos(imp, 3, 1) + self._check_end_pos(imp.names[2], 2, 16) + + def test_slices(self): + s1 = "f()[1, 2] [0]" + s2 = "x[ a.b: c.d]" + sm = dedent(""" + x[ a.b: f () , + g () : c.d + ] + """).strip() + i1, i2, im = map(self._parse_value, (s1, s2, sm)) + self._check_content(s1, i1.value, "f()[1, 2]") + self._check_content(s1, i1.value.slice, "1, 2") + self._check_content(s2, i2.slice.lower, "a.b") + self._check_content(s2, i2.slice.upper, "c.d") + self._check_content(sm, im.slice.elts[0].upper, "f ()") + self._check_content(sm, im.slice.elts[1].lower, "g ()") + self._check_end_pos(im, 3, 3) + + def test_binop(self): + s = dedent(""" + (1 * 2 + (3 ) + + 4 + ) + """).strip() + binop = self._parse_value(s) + self._check_end_pos(binop, 2, 6) + self._check_content(s, binop.right, "4") + self._check_content(s, binop.left, "1 * 2 + (3 )") + self._check_content(s, binop.left.right, "3") + + def test_boolop(self): + s = dedent(""" + if (one_condition and + (other_condition or yet_another_one)): + pass + """).strip() + bop = ast.parse(s).body[0].test + self._check_end_pos(bop, 2, 44) + self._check_content(s, bop.values[1], "other_condition or yet_another_one") + + def test_tuples(self): + s1 = "x = () ;" + s2 = "x = 1 , ;" + s3 = "x = (1 , 2 ) ;" + sm = dedent(""" + x = ( + a, b, + ) + """).strip() + t1, t2, t3, tm = map(self._parse_value, (s1, s2, s3, sm)) + self._check_content(s1, t1, "()") + self._check_content(s2, t2, "1 ,") + self._check_content(s3, t3, "(1 , 2 )") + self._check_end_pos(tm, 3, 1) + + def test_attribute_spaces(self): + s = "func(x. y .z)" + call = self._parse_value(s) + self._check_content(s, call, s) + self._check_content(s, call.args[0], "x. y .z") + + def test_redundant_parenthesis(self): + s = "( ( ( a + b ) ) )" + v = ast.parse(s).body[0].value + self.assertEqual(type(v).__name__, "BinOp") + self._check_content(s, v, "a + b") + s2 = "await " + s + v = ast.parse(s2).body[0].value.value + self.assertEqual(type(v).__name__, "BinOp") + self._check_content(s2, v, "a + b") + + def test_trailers_with_redundant_parenthesis(self): + tests = ( + ("( ( ( a ) ) ) ( )", "Call"), + ("( ( ( a ) ) ) ( b )", "Call"), + ("( ( ( a ) ) ) [ b ]", "Subscript"), + ("( ( ( a ) ) ) . b", "Attribute"), + ) + for s, t in tests: + with self.subTest(s): + v = ast.parse(s).body[0].value + self.assertEqual(type(v).__name__, t) + self._check_content(s, v, s) + s2 = "await " + s + v = ast.parse(s2).body[0].value.value + self.assertEqual(type(v).__name__, t) + self._check_content(s2, v, s) + + def test_displays(self): + s1 = "[{}, {1, }, {1, 2,} ]" + s2 = "{a: b, f (): g () ,}" + c1 = self._parse_value(s1) + c2 = self._parse_value(s2) + self._check_content(s1, c1.elts[0], "{}") + self._check_content(s1, c1.elts[1], "{1, }") + self._check_content(s1, c1.elts[2], "{1, 2,}") + self._check_content(s2, c2.keys[1], "f ()") + self._check_content(s2, c2.values[1], "g ()") + + def test_comprehensions(self): + s = dedent(""" + x = [{x for x, y in stuff + if cond.x} for stuff in things] + """).strip() + cmp = self._parse_value(s) + self._check_end_pos(cmp, 2, 37) + self._check_content(s, cmp.generators[0].iter, "things") + self._check_content(s, cmp.elt.generators[0].iter, "stuff") + self._check_content(s, cmp.elt.generators[0].ifs[0], "cond.x") + self._check_content(s, cmp.elt.generators[0].target, "x, y") + + def test_yield_await(self): + s = dedent(""" + async def f(): + yield x + await y + """).strip() + fdef = ast.parse(s).body[0] + self._check_content(s, fdef.body[0].value, "yield x") + self._check_content(s, fdef.body[1].value, "await y") + + def test_source_segment_multi(self): + s_orig = dedent(""" + x = ( + a, b, + ) + () + """).strip() + s_tuple = dedent(""" + ( + a, b, + ) + """).strip() + binop = self._parse_value(s_orig) + self.assertEqual(ast.get_source_segment(s_orig, binop.left), s_tuple) + + def test_source_segment_padded(self): + s_orig = dedent(""" + class C: + def fun(self) -> None: + "ЖЖЖЖЖ" + """).strip() + s_method = " def fun(self) -> None:\n" ' "ЖЖЖЖЖ"' + cdef = ast.parse(s_orig).body[0] + self.assertEqual( + ast.get_source_segment(s_orig, cdef.body[0], padded=True), s_method + ) + + def test_source_segment_endings(self): + s = "v = 1\r\nw = 1\nx = 1\n\ry = 1\rz = 1\r\n" + v, w, x, y, z = ast.parse(s).body + self._check_content(s, v, "v = 1") + self._check_content(s, w, "w = 1") + self._check_content(s, x, "x = 1") + self._check_content(s, y, "y = 1") + self._check_content(s, z, "z = 1") + + def test_source_segment_tabs(self): + s = dedent(""" + class C: + \t\f def fun(self) -> None: + \t\f pass + """).strip() + s_method = " \t\f def fun(self) -> None:\n" " \t\f pass" + + cdef = ast.parse(s).body[0] + self.assertEqual(ast.get_source_segment(s, cdef.body[0], padded=True), s_method) + + def test_source_segment_newlines(self): + s = "def f():\n pass\ndef g():\r pass\r\ndef h():\r\n pass\r\n" + f, g, h = ast.parse(s).body + self._check_content(s, f, "def f():\n pass") + self._check_content(s, g, "def g():\r pass") + self._check_content(s, h, "def h():\r\n pass") + + s = "def f():\n a = 1\r b = 2\r\n c = 3\n" + f = ast.parse(s).body[0] + self._check_content(s, f, s.rstrip()) + + def test_source_segment_missing_info(self): + s = "v = 1\r\nw = 1\nx = 1\n\ry = 1\r\n" + v, w, x, y = ast.parse(s).body + del v.lineno + del w.end_lineno + del x.col_offset + del y.end_col_offset + self.assertIsNone(ast.get_source_segment(s, v)) + self.assertIsNone(ast.get_source_segment(s, w)) + self.assertIsNone(ast.get_source_segment(s, x)) + self.assertIsNone(ast.get_source_segment(s, y)) + + +class BaseNodeVisitorCases: + # Both `NodeVisitor` and `NodeTranformer` must raise these warnings: + def test_old_constant_nodes(self): + class Visitor(self.visitor_class): + def visit_Num(self, node): + log.append((node.lineno, "Num", node.n)) + + def visit_Str(self, node): + log.append((node.lineno, "Str", node.s)) + + def visit_Bytes(self, node): + log.append((node.lineno, "Bytes", node.s)) + + def visit_NameConstant(self, node): + log.append((node.lineno, "NameConstant", node.value)) + + def visit_Ellipsis(self, node): + log.append((node.lineno, "Ellipsis", ...)) + + mod = ast.parse( + dedent("""\ + i = 42 + f = 4.25 + c = 4.25j + s = 'string' + b = b'bytes' + t = True + n = None + e = ... + """) + ) + visitor = Visitor() + log = [] + with warnings.catch_warnings(record=True) as wlog: + warnings.filterwarnings("always", "", DeprecationWarning) + visitor.visit(mod) + self.assertEqual( + log, + [ + (1, "Num", 42), + (2, "Num", 4.25), + (3, "Num", 4.25j), + (4, "Str", "string"), + (5, "Bytes", b"bytes"), + (6, "NameConstant", True), + (7, "NameConstant", None), + (8, "Ellipsis", ...), + ], + ) + self.assertEqual( + [str(w.message) for w in wlog], + [ + "visit_Num is deprecated; add visit_Constant", + "Attribute n is deprecated and will be removed in Python 3.14; use value instead", + "visit_Num is deprecated; add visit_Constant", + "Attribute n is deprecated and will be removed in Python 3.14; use value instead", + "visit_Num is deprecated; add visit_Constant", + "Attribute n is deprecated and will be removed in Python 3.14; use value instead", + "visit_Str is deprecated; add visit_Constant", + "Attribute s is deprecated and will be removed in Python 3.14; use value instead", + "visit_Bytes is deprecated; add visit_Constant", + "Attribute s is deprecated and will be removed in Python 3.14; use value instead", + "visit_NameConstant is deprecated; add visit_Constant", + "visit_NameConstant is deprecated; add visit_Constant", + "visit_Ellipsis is deprecated; add visit_Constant", + ], + ) + + +class NodeVisitorTests(BaseNodeVisitorCases, unittest.TestCase): + visitor_class = ast.NodeVisitor + + +class NodeTransformerTests(ASTTestMixin, BaseNodeVisitorCases, unittest.TestCase): + visitor_class = ast.NodeTransformer + + def assertASTTransformation(self, tranformer_class, initial_code, expected_code): + initial_ast = ast.parse(dedent(initial_code)) + expected_ast = ast.parse(dedent(expected_code)) + + tranformer = tranformer_class() + result_ast = ast.fix_missing_locations(tranformer.visit(initial_ast)) + + self.assertASTEqual(result_ast, expected_ast) + + def test_node_remove_single(self): + code = "def func(arg) -> SomeType: ..." + expected = "def func(arg): ..." + + # Since `FunctionDef.returns` is defined as a single value, we test + # the `if isinstance(old_value, AST):` branch here. + class SomeTypeRemover(ast.NodeTransformer): + def visit_Name(self, node: ast.Name): + self.generic_visit(node) + if node.id == "SomeType": + return None + return node + + self.assertASTTransformation(SomeTypeRemover, code, expected) + + def test_node_remove_from_list(self): + code = """ + def func(arg): + print(arg) + yield arg + """ + expected = """ + def func(arg): + print(arg) + """ + + # Since `FunctionDef.body` is defined as a list, we test + # the `if isinstance(old_value, list):` branch here. + class YieldRemover(ast.NodeTransformer): + def visit_Expr(self, node: ast.Expr): + self.generic_visit(node) + if isinstance(node.value, ast.Yield): + return None # Remove `yield` from a function + return node + + self.assertASTTransformation(YieldRemover, code, expected) + + def test_node_return_list(self): + code = """ + class DSL(Base, kw1=True): ... + """ + expected = """ + class DSL(Base, kw1=True, kw2=True, kw3=False): ... + """ + + class ExtendKeywords(ast.NodeTransformer): + def visit_keyword(self, node: ast.keyword): + self.generic_visit(node) + if node.arg == "kw1": + return [ + node, + ast.keyword("kw2", ast.Constant(True)), + ast.keyword("kw3", ast.Constant(False)), + ] + return node + + self.assertASTTransformation(ExtendKeywords, code, expected) + + def test_node_mutate(self): + code = """ + def func(arg): + print(arg) + """ + expected = """ + def func(arg): + log(arg) + """ + + class PrintToLog(ast.NodeTransformer): + def visit_Call(self, node: ast.Call): + self.generic_visit(node) + if isinstance(node.func, ast.Name) and node.func.id == "print": + node.func.id = "log" + return node + + self.assertASTTransformation(PrintToLog, code, expected) + + def test_node_replace(self): + code = """ + def func(arg): + print(arg) + """ + expected = """ + def func(arg): + logger.log(arg, debug=True) + """ + + class PrintToLog(ast.NodeTransformer): + def visit_Call(self, node: ast.Call): + self.generic_visit(node) + if isinstance(node.func, ast.Name) and node.func.id == "print": + return ast.Call( + func=ast.Attribute( + ast.Name("logger", ctx=ast.Load()), + attr="log", + ctx=ast.Load(), + ), + args=node.args, + keywords=[ast.keyword("debug", ast.Constant(True))], + ) + return node + + self.assertASTTransformation(PrintToLog, code, expected) + + +@support.cpython_only +class ModuleStateTests(unittest.TestCase): + # bpo-41194, bpo-41261, bpo-41631: The _ast module uses a global state. + + def check_ast_module(self): + # Check that the _ast module still works as expected + code = "x + 1" + filename = "" + mode = "eval" + + # Create _ast.AST subclasses instances + ast_tree = compile(code, filename, mode, flags=ast.PyCF_ONLY_AST) + + # Call PyAST_Check() + code = compile(ast_tree, filename, mode) + self.assertIsInstance(code, types.CodeType) + + def test_reload_module(self): + # bpo-41194: Importing the _ast module twice must not crash. + with support.swap_item(sys.modules, "_ast", None): + del sys.modules["_ast"] + import _ast as ast1 + + del sys.modules["_ast"] + import _ast as ast2 + + self.check_ast_module() + + # Unloading the two _ast module instances must not crash. + del ast1 + del ast2 + support.gc_collect() + + self.check_ast_module() + + def test_sys_modules(self): + # bpo-41631: Test reproducing a Mercurial crash when PyAST_Check() + # imported the _ast module internally. + lazy_mod = object() + + def my_import(name, *args, **kw): + sys.modules[name] = lazy_mod + return lazy_mod + + with support.swap_item(sys.modules, "_ast", None): + del sys.modules["_ast"] + + with support.swap_attr(builtins, "__import__", my_import): + # Test that compile() does not import the _ast module + self.check_ast_module() + self.assertNotIn("_ast", sys.modules) + + # Sanity check of the test itself + import _ast + + self.assertIs(_ast, lazy_mod) + + def test_subinterpreter(self): + # bpo-41631: Importing and using the _ast module in a subinterpreter + # must not crash. + code = dedent(""" + import _ast + import ast + import gc + import sys + import types + + # Create _ast.AST subclasses instances and call PyAST_Check() + ast_tree = compile('x+1', '', 'eval', + flags=ast.PyCF_ONLY_AST) + code = compile(ast_tree, 'string', 'eval') + if not isinstance(code, types.CodeType): + raise AssertionError + + # Unloading the _ast module must not crash. + del ast, _ast + del sys.modules['ast'], sys.modules['_ast'] + gc.collect() + """) + res = support.run_in_subinterp(code) + self.assertEqual(res, 0) + + +class ASTMainTests(unittest.TestCase): + # Tests `ast.main()` function. + + def test_cli_file_input(self): + code = "print(1, 2, 3)" + expected = ast.dump(ast.parse(code), indent=3) + + with os_helper.temp_dir() as tmp_dir: + filename = os.path.join(tmp_dir, "test_module.py") + with open(filename, "w", encoding="utf-8") as f: + f.write(code) + res, _ = script_helper.run_python_until_end("-m", "ast", filename) + + self.assertEqual(res.err, b"") + self.assertEqual(expected.splitlines(), res.out.decode("utf8").splitlines()) + self.assertEqual(res.rc, 0) diff --git a/Lib/test/test_ast/utils.py b/Lib/test/test_ast/utils.py new file mode 100644 index 00000000..145e89ee --- /dev/null +++ b/Lib/test/test_ast/utils.py @@ -0,0 +1,15 @@ +def to_tuple(t): + if t is None or isinstance(t, (str, int, complex, float, bytes)) or t is Ellipsis: + return t + elif isinstance(t, list): + return [to_tuple(e) for e in t] + result = [t.__class__.__name__] + if hasattr(t, 'lineno') and hasattr(t, 'col_offset'): + result.append((t.lineno, t.col_offset)) + if hasattr(t, 'end_lineno') and hasattr(t, 'end_col_offset'): + result[-1] += (t.end_lineno, t.end_col_offset) + if t._fields is None: + return tuple(result) + for f in t._fields: + result.append(to_tuple(getattr(t, f))) + return tuple(result) diff --git a/Lib/test/test_asyncio/test_eager_task_factory.py b/Lib/test/test_asyncio/test_eager_task_factory.py index 34688873..e2a54dd8 100644 --- a/Lib/test/test_asyncio/test_eager_task_factory.py +++ b/Lib/test/test_asyncio/test_eager_task_factory.py @@ -218,6 +218,56 @@ async def run(): self.run_coro(run()) + def test_staggered_race_with_eager_tasks(self): + # See https://github.com/python/cpython/issues/124309 + + async def fail(): + await asyncio.sleep(0) + raise ValueError("no good") + + async def blocked(): + fut = asyncio.Future() + await fut + + async def run(): + winner, index, excs = await asyncio.staggered.staggered_race( + [ + lambda: blocked(), + lambda: asyncio.sleep(1, result="sleep1"), + lambda: fail() + ], + delay=0.25 + ) + self.assertEqual(winner, 'sleep1') + self.assertEqual(index, 1) + self.assertIsNone(excs[index]) + self.assertIsInstance(excs[0], asyncio.CancelledError) + self.assertIsInstance(excs[2], ValueError) + + self.run_coro(run()) + + def test_staggered_race_with_eager_tasks_no_delay(self): + # See https://github.com/python/cpython/issues/124309 + async def fail(): + raise ValueError("no good") + + async def run(): + winner, index, excs = await asyncio.staggered.staggered_race( + [ + lambda: fail(), + lambda: asyncio.sleep(1, result="sleep1"), + lambda: asyncio.sleep(0, result="sleep0"), + ], + delay=None + ) + self.assertEqual(winner, 'sleep1') + self.assertEqual(index, 1) + self.assertIsNone(excs[index]) + self.assertIsInstance(excs[0], ValueError) + self.assertEqual(len(excs), 2) + + self.run_coro(run()) + class PyEagerTaskFactoryLoopTests(EagerTaskFactoryLoopTests, test_utils.TestCase): Task = tasks._PyTask @@ -246,6 +296,18 @@ class DummyLoop: _, out, err = assert_python_ok("-c", code) self.assertFalse(err) + def test_issue122332(self): + async def coro(): + pass + + async def run(): + task = self.loop.create_task(coro()) + await task + self.assertIsNone(task.get_coro()) + + self.run_coro(run()) + + class AsyncTaskCounter: def __init__(self, loop, *, task_class, eager): self.suspense_count = 0 diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py index f2558037..abf425f5 100644 --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -2351,7 +2351,7 @@ def test_handle_repr(self): h = asyncio.Handle(cb, (), self.loop) cb_regex = r'' - cb_regex = fr'functools.partialmethod\({cb_regex}, , \)\(\)' + cb_regex = fr'functools.partialmethod\({cb_regex}\)\(\)' regex = fr'^$' self.assertRegex(repr(h), regex) diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py index 2184b209..8be6dcac 100644 --- a/Lib/test/test_asyncio/test_futures.py +++ b/Lib/test/test_asyncio/test_futures.py @@ -31,6 +31,25 @@ def last_cb(): pass +class ReachableCode(Exception): + """Exception to raise to indicate that some code was reached. + + Use this exception if using mocks is not a good alternative. + """ + + +class SimpleEvilEventLoop(asyncio.base_events.BaseEventLoop): + """Base class for UAF and other evil stuff requiring an evil event loop.""" + + def get_debug(self): # to suppress tracebacks + return False + + def __del__(self): + # Automatically close the evil event loop to avoid warnings. + if not self.is_closed() and not self.is_running(): + self.close() + + class DuckFuture: # Class that does not inherit from Future but aims to be duck-type # compatible with it. @@ -270,10 +289,6 @@ def test_exception(self): f = self._new_future(loop=self.loop) self.assertRaises(asyncio.InvalidStateError, f.exception) - # StopIteration cannot be raised into a Future - CPython issue26221 - self.assertRaisesRegex(TypeError, "StopIteration .* cannot be raised", - f.set_exception, StopIteration) - f.set_exception(exc) self.assertFalse(f.cancelled()) self.assertTrue(f.done()) @@ -283,6 +298,25 @@ def test_exception(self): self.assertRaises(asyncio.InvalidStateError, f.set_exception, None) self.assertFalse(f.cancel()) + def test_stop_iteration_exception(self, stop_iteration_class=StopIteration): + exc = stop_iteration_class() + f = self._new_future(loop=self.loop) + f.set_exception(exc) + self.assertFalse(f.cancelled()) + self.assertTrue(f.done()) + self.assertRaises(RuntimeError, f.result) + exc = f.exception() + cause = exc.__cause__ + self.assertIsInstance(exc, RuntimeError) + self.assertRegex(str(exc), 'StopIteration .* cannot be raised') + self.assertIsInstance(cause, stop_iteration_class) + + def test_stop_iteration_subclass_exception(self): + class MyStopIteration(StopIteration): + pass + + self.test_stop_iteration_exception(MyStopIteration) + def test_exception_class(self): f = self._new_future(loop=self.loop) f.set_exception(RuntimeError) @@ -625,6 +659,28 @@ def __del__(self): fut = self._new_future(loop=self.loop) fut.set_result(Evil()) + def test_future_cancelled_result_refcycles(self): + f = self._new_future(loop=self.loop) + f.cancel() + exc = None + try: + f.result() + except asyncio.CancelledError as e: + exc = e + self.assertIsNotNone(exc) + self.assertListEqual(gc.get_referrers(exc), []) + + def test_future_cancelled_exception_refcycles(self): + f = self._new_future(loop=self.loop) + f.cancel() + exc = None + try: + f.exception() + except asyncio.CancelledError as e: + exc = e + self.assertIsNotNone(exc) + self.assertListEqual(gc.get_referrers(exc), []) + @unittest.skipUnless(hasattr(futures, '_CFuture'), 'requires the C _asyncio module') @@ -641,6 +697,32 @@ def test_future_del_segfault(self): with self.assertRaises(AttributeError): del fut._log_traceback + def test_future_iter_get_referents_segfault(self): + # See https://github.com/python/cpython/issues/122695 + import _asyncio + it = iter(self._new_future(loop=self.loop)) + del it + evil = gc.get_referents(_asyncio) + gc.collect() + + def test_callbacks_copy(self): + # See https://github.com/python/cpython/issues/125789 + # In C implementation, the `_callbacks` attribute + # always returns a new list to avoid mutations of internal state + + fut = self._new_future(loop=self.loop) + f1 = lambda _: 1 + f2 = lambda _: 2 + fut.add_done_callback(f1) + fut.add_done_callback(f2) + callbacks = fut._callbacks + self.assertIsNot(callbacks, fut._callbacks) + fut.remove_done_callback(f1) + callbacks = fut._callbacks + self.assertIsNot(callbacks, fut._callbacks) + fut.remove_done_callback(f2) + self.assertIsNone(fut._callbacks) + @unittest.skipUnless(hasattr(futures, '_CFuture'), 'requires the C _asyncio module') @@ -873,6 +955,107 @@ def __eq__(self, other): fut.remove_done_callback(evil()) + def test_evil_call_soon_list_mutation(self): + # see: https://github.com/python/cpython/issues/125969 + called_on_fut_callback0 = False + + pad = lambda: ... + + def evil_call_soon(*args, **kwargs): + nonlocal called_on_fut_callback0 + if called_on_fut_callback0: + # Called when handling fut->fut_callbacks[0] + # and mutates the length fut->fut_callbacks. + fut.remove_done_callback(int) + fut.remove_done_callback(pad) + else: + called_on_fut_callback0 = True + + fake_event_loop = SimpleEvilEventLoop() + fake_event_loop.call_soon = evil_call_soon + + with mock.patch.object(self, 'loop', fake_event_loop): + fut = self._new_future() + self.assertIs(fut.get_loop(), fake_event_loop) + + fut.add_done_callback(str) # sets fut->fut_callback0 + fut.add_done_callback(int) # sets fut->fut_callbacks[0] + fut.add_done_callback(pad) # sets fut->fut_callbacks[1] + fut.add_done_callback(pad) # sets fut->fut_callbacks[2] + fut.set_result("boom") + + # When there are no more callbacks, the Python implementation + # returns an empty list but the C implementation returns None. + self.assertIn(fut._callbacks, (None, [])) + + def test_use_after_free_on_fut_callback_0_with_evil__eq__(self): + # Special thanks to Nico-Posada for the original PoC. + # See https://github.com/python/cpython/issues/125966. + + fut = self._new_future() + + class cb_pad: + def __eq__(self, other): + return True + + class evil(cb_pad): + def __eq__(self, other): + fut.remove_done_callback(None) + return NotImplemented + + fut.add_done_callback(cb_pad()) + fut.remove_done_callback(evil()) + + def test_use_after_free_on_fut_callback_0_with_evil__getattribute__(self): + # see: https://github.com/python/cpython/issues/125984 + + class EvilEventLoop(SimpleEvilEventLoop): + def call_soon(self, *args, **kwargs): + super().call_soon(*args, **kwargs) + raise ReachableCode + + def __getattribute__(self, name): + nonlocal fut_callback_0 + if name == 'call_soon': + fut.remove_done_callback(fut_callback_0) + del fut_callback_0 + return object.__getattribute__(self, name) + + evil_loop = EvilEventLoop() + with mock.patch.object(self, 'loop', evil_loop): + fut = self._new_future() + self.assertIs(fut.get_loop(), evil_loop) + + fut_callback_0 = lambda: ... + fut.add_done_callback(fut_callback_0) + self.assertRaises(ReachableCode, fut.set_result, "boom") + + def test_use_after_free_on_fut_context_0_with_evil__getattribute__(self): + # see: https://github.com/python/cpython/issues/125984 + + class EvilEventLoop(SimpleEvilEventLoop): + def call_soon(self, *args, **kwargs): + super().call_soon(*args, **kwargs) + raise ReachableCode + + def __getattribute__(self, name): + if name == 'call_soon': + # resets the future's event loop + fut.__init__(loop=SimpleEvilEventLoop()) + return object.__getattribute__(self, name) + + evil_loop = EvilEventLoop() + with mock.patch.object(self, 'loop', evil_loop): + fut = self._new_future() + self.assertIs(fut.get_loop(), evil_loop) + + fut_callback_0 = mock.Mock() + fut_context_0 = mock.Mock() + fut.add_done_callback(fut_callback_0, context=fut_context_0) + del fut_context_0 + del fut_callback_0 + self.assertRaises(ReachableCode, fut.set_result, "boom") + @unittest.skipUnless(hasattr(futures, '_CFuture'), 'requires the C _asyncio module') diff --git a/Lib/test/test_asyncio/test_sendfile.py b/Lib/test/test_asyncio/test_sendfile.py index d33ff197..2509d438 100644 --- a/Lib/test/test_asyncio/test_sendfile.py +++ b/Lib/test/test_asyncio/test_sendfile.py @@ -93,13 +93,10 @@ async def wait_closed(self): class SendfileBase: - # 256 KiB plus small unaligned to buffer chunk - # Newer versions of Windows seems to have increased its internal - # buffer and tries to send as much of the data as it can as it - # has some form of buffering for this which is less than 256KiB - # on newer server versions and Windows 11. - # So DATA should be larger than 256 KiB to make this test reliable. - DATA = b"x" * (1024 * 256 + 1) + # Linux >= 6.10 seems buffering up to 17 pages of data. + # So DATA should be large enough to make this test reliable even with a + # 64 KiB page configuration. + DATA = b"x" * (1024 * 17 * 64 + 1) # Reduce socket buffer size to test on relative small data sets. BUF_SIZE = 4 * 1024 # 4 KiB diff --git a/Lib/test/test_asyncio/test_sslproto.py b/Lib/test/test_asyncio/test_sslproto.py index f5f0afea..761904c5 100644 --- a/Lib/test/test_asyncio/test_sslproto.py +++ b/Lib/test/test_asyncio/test_sslproto.py @@ -109,6 +109,54 @@ def test_connection_lost(self): test_utils.run_briefly(self.loop) self.assertIsInstance(waiter.exception(), ConnectionAbortedError) + def test_connection_lost_when_busy(self): + # gh-118950: SSLProtocol.connection_lost not being called when OSError + # is thrown on asyncio.write. + sock = mock.Mock() + sock.fileno = mock.Mock(return_value=12345) + sock.send = mock.Mock(side_effect=BrokenPipeError) + + # construct StreamWriter chain that contains loop dependant logic this emulates + # what _make_ssl_transport() does in BaseSelectorEventLoop + reader = asyncio.StreamReader(limit=2 ** 16, loop=self.loop) + protocol = asyncio.StreamReaderProtocol(reader, loop=self.loop) + ssl_proto = self.ssl_protocol(proto=protocol) + + # emulate reading decompressed data + sslobj = mock.Mock() + sslobj.read.side_effect = ssl.SSLWantReadError + sslobj.write.side_effect = ssl.SSLWantReadError + ssl_proto._sslobj = sslobj + + # emulate outgoing data + data = b'An interesting message' + + outgoing = mock.Mock() + outgoing.read = mock.Mock(return_value=data) + outgoing.pending = len(data) + ssl_proto._outgoing = outgoing + + # use correct socket transport to initialize the SSLProtocol + self.loop._make_socket_transport(sock, ssl_proto) + + transport = ssl_proto._app_transport + writer = asyncio.StreamWriter(transport, protocol, reader, self.loop) + + async def main(): + # writes data to transport + async def write(): + writer.write(data) + await writer.drain() + + # try to write for the first time + await write() + # try to write for the second time, this raises as the connection_lost + # callback should be done with error + with self.assertRaises(ConnectionResetError): + await write() + + self.loop.run_until_complete(main()) + def test_close_during_handshake(self): # bpo-29743 Closing transport during handshake process leaks socket waiter = self.loop.create_future() diff --git a/Lib/test/test_asyncio/test_staggered.py b/Lib/test/test_asyncio/test_staggered.py new file mode 100644 index 00000000..74941f70 --- /dev/null +++ b/Lib/test/test_asyncio/test_staggered.py @@ -0,0 +1,124 @@ +import asyncio +import unittest +from asyncio.staggered import staggered_race + +from test import support + +support.requires_working_socket(module=True) + + +def tearDownModule(): + asyncio.set_event_loop_policy(None) + + +class StaggeredTests(unittest.IsolatedAsyncioTestCase): + async def test_empty(self): + winner, index, excs = await staggered_race( + [], + delay=None, + ) + + self.assertIs(winner, None) + self.assertIs(index, None) + self.assertEqual(excs, []) + + async def test_one_successful(self): + async def coro(index): + return f'Res: {index}' + + winner, index, excs = await staggered_race( + [ + lambda: coro(0), + lambda: coro(1), + ], + delay=None, + ) + + self.assertEqual(winner, 'Res: 0') + self.assertEqual(index, 0) + self.assertEqual(excs, [None]) + + async def test_first_error_second_successful(self): + async def coro(index): + if index == 0: + raise ValueError(index) + return f'Res: {index}' + + winner, index, excs = await staggered_race( + [ + lambda: coro(0), + lambda: coro(1), + ], + delay=None, + ) + + self.assertEqual(winner, 'Res: 1') + self.assertEqual(index, 1) + self.assertEqual(len(excs), 2) + self.assertIsInstance(excs[0], ValueError) + self.assertIs(excs[1], None) + + async def test_first_timeout_second_successful(self): + async def coro(index): + if index == 0: + await asyncio.sleep(10) # much bigger than delay + return f'Res: {index}' + + winner, index, excs = await staggered_race( + [ + lambda: coro(0), + lambda: coro(1), + ], + delay=0.1, + ) + + self.assertEqual(winner, 'Res: 1') + self.assertEqual(index, 1) + self.assertEqual(len(excs), 2) + self.assertIsInstance(excs[0], asyncio.CancelledError) + self.assertIs(excs[1], None) + + async def test_none_successful(self): + async def coro(index): + raise ValueError(index) + + winner, index, excs = await staggered_race( + [ + lambda: coro(0), + lambda: coro(1), + ], + delay=None, + ) + + self.assertIs(winner, None) + self.assertIs(index, None) + self.assertEqual(len(excs), 2) + self.assertIsInstance(excs[0], ValueError) + self.assertIsInstance(excs[1], ValueError) + + + async def test_multiple_winners(self): + event = asyncio.Event() + + async def coro(index): + await event.wait() + return index + + async def do_set(): + event.set() + await asyncio.Event().wait() + + winner, index, excs = await staggered_race( + [ + lambda: coro(0), + lambda: coro(1), + do_set, + ], + delay=0.1, + ) + self.assertIs(winner, 0) + self.assertIs(index, 0) + self.assertEqual(len(excs), 3) + self.assertIsNone(excs[0], None) + self.assertIsInstance(excs[1], asyncio.CancelledError) + self.assertIsInstance(excs[2], asyncio.CancelledError) diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py index 3c8cc5f3..686fef83 100644 --- a/Lib/test/test_asyncio/test_streams.py +++ b/Lib/test/test_asyncio/test_streams.py @@ -1166,6 +1166,24 @@ async def handle_echo(reader, writer): messages = self._basetest_unhandled_exceptions(handle_echo) self.assertEqual(messages, []) + def test_open_connection_happy_eyeball_refcycles(self): + port = socket_helper.find_unused_port() + async def main(): + exc = None + try: + await asyncio.open_connection( + host="localhost", + port=port, + happy_eyeballs_delay=0.25, + ) + except* OSError as excs: + # can't use assertRaises because that clears frames + exc = excs.exceptions[0] + self.assertIsNotNone(exc) + self.assertListEqual(gc.get_referrers(exc), []) + + asyncio.run(main()) + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_asyncio/test_taskgroups.py b/Lib/test/test_asyncio/test_taskgroups.py index 7a18362b..236bfaac 100644 --- a/Lib/test/test_asyncio/test_taskgroups.py +++ b/Lib/test/test_asyncio/test_taskgroups.py @@ -1,7 +1,7 @@ # Adapted with permission from the EdgeDB project; # license: PSFL. - +import gc import asyncio import contextvars import contextlib @@ -10,7 +10,6 @@ from test.test_asyncio.utils import await_without_task - # To prevent a warning "test altered the execution environment" def tearDownModule(): asyncio.set_event_loop_policy(None) @@ -824,6 +823,95 @@ async def test_taskgroup_without_parent_task(self): # We still have to await coro to avoid a warning await coro + async def test_exception_refcycles_direct(self): + """Test that TaskGroup doesn't keep a reference to the raised ExceptionGroup""" + tg = asyncio.TaskGroup() + exc = None + + class _Done(Exception): + pass + + try: + async with tg: + raise _Done + except ExceptionGroup as e: + exc = e + + self.assertIsNotNone(exc) + self.assertListEqual(gc.get_referrers(exc), []) + + + async def test_exception_refcycles_errors(self): + """Test that TaskGroup deletes self._errors, and __aexit__ args""" + tg = asyncio.TaskGroup() + exc = None + + class _Done(Exception): + pass + + try: + async with tg: + raise _Done + except* _Done as excs: + exc = excs.exceptions[0] + + self.assertIsInstance(exc, _Done) + self.assertListEqual(gc.get_referrers(exc), []) + + + async def test_exception_refcycles_parent_task(self): + """Test that TaskGroup deletes self._parent_task""" + tg = asyncio.TaskGroup() + exc = None + + class _Done(Exception): + pass + + async def coro_fn(): + async with tg: + raise _Done + + try: + async with asyncio.TaskGroup() as tg2: + tg2.create_task(coro_fn()) + except* _Done as excs: + exc = excs.exceptions[0].exceptions[0] + + self.assertIsInstance(exc, _Done) + self.assertListEqual(gc.get_referrers(exc), []) + + async def test_exception_refcycles_propagate_cancellation_error(self): + """Test that TaskGroup deletes propagate_cancellation_error""" + tg = asyncio.TaskGroup() + exc = None + + try: + async with asyncio.timeout(-1): + async with tg: + await asyncio.sleep(0) + except TimeoutError as e: + exc = e.__cause__ + + self.assertIsInstance(exc, asyncio.CancelledError) + self.assertListEqual(gc.get_referrers(exc), []) + + async def test_exception_refcycles_base_error(self): + """Test that TaskGroup deletes self._base_error""" + class MyKeyboardInterrupt(KeyboardInterrupt): + pass + + tg = asyncio.TaskGroup() + exc = None + + try: + async with tg: + raise MyKeyboardInterrupt + except MyKeyboardInterrupt as e: + exc = e + + self.assertIsNotNone(exc) + self.assertListEqual(gc.get_referrers(exc), []) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index 6e8a51ce..792ab4fb 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -2489,6 +2489,28 @@ def test_get_context(self): finally: loop.close() + def test_proper_refcounts(self): + # see: https://github.com/python/cpython/issues/126083 + class Break: + def __str__(self): + raise RuntimeError("break") + + obj = object() + initial_refcount = sys.getrefcount(obj) + + coro = coroutine_function() + loop = asyncio.new_event_loop() + task = asyncio.Task.__new__(asyncio.Task) + + for _ in range(5): + with self.assertRaisesRegex(RuntimeError, 'break'): + task.__init__(coro, loop=loop, context=obj, name=Break()) + + coro.close() + del task + + self.assertEqual(sys.getrefcount(obj), initial_refcount) + def add_subclass_tests(cls): BaseTask = cls.Task diff --git a/Lib/test/test_audit.py b/Lib/test/test_audit.py index 9e3e0374..9076448c 100644 --- a/Lib/test/test_audit.py +++ b/Lib/test/test_audit.py @@ -140,6 +140,7 @@ def test_gc(self): ) + @support.requires_resource('network') def test_http(self): import_helper.import_module("http.client") returncode, events, stderr = self.run_python("test_http_client") diff --git a/Lib/test/test_bdb.py b/Lib/test/test_bdb.py index 568c88e3..33e28592 100644 --- a/Lib/test/test_bdb.py +++ b/Lib/test/test_bdb.py @@ -1203,6 +1203,19 @@ def main(): with TracerRun(self) as tracer: tracer.runcall(tfunc_import) + def test_next_to_botframe(self): + # gh-125422 + # Check that next command won't go to the bottom frame. + code = """ + lno = 2 + """ + self.expect_set = [ + ('line', 2, ''), ('step', ), + ('return', 2, ''), ('next', ), + ] + with TracerRun(self) as tracer: + tracer.run(compile(textwrap.dedent(code), '', 'exec')) + class TestRegressions(unittest.TestCase): def test_format_stack_entry_no_lineno(self): diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py index aafbb8a9..5f3e8b0f 100644 --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -3906,6 +3906,8 @@ def test_memoryview_check_released(self): self.assertRaises(ValueError, memoryview, m) # memoryview.cast() self.assertRaises(ValueError, m.cast, 'c') + # memoryview.__iter__() + self.assertRaises(ValueError, m.__iter__) # getbuffer() self.assertRaises(ValueError, ndarray, m) # memoryview.tolist() @@ -4440,6 +4442,21 @@ def test_pybuffer_size_from_format(self): self.assertEqual(_testcapi.PyBuffer_SizeFromFormat(format), struct.calcsize(format)) + @support.cpython_only + def test_flags_overflow(self): + # gh-126594: Check for integer overlow on large flags + try: + from _testcapi import INT_MIN, INT_MAX + except ImportError: + INT_MIN = -(2 ** 31) + INT_MAX = 2 ** 31 - 1 + + obj = b'abc' + for flags in (INT_MIN - 1, INT_MAX + 1): + with self.subTest(flags=flags): + with self.assertRaises(OverflowError): + obj.__buffer__(flags) + class TestPythonBufferProtocol(unittest.TestCase): def test_basic(self): diff --git a/Lib/test/test_bz2.py b/Lib/test/test_bz2.py index 772f0eac..cb730a1a 100644 --- a/Lib/test/test_bz2.py +++ b/Lib/test/test_bz2.py @@ -476,7 +476,6 @@ def testReadlinesNoNewline(self): self.assertEqual(xlines, [b'Test']) def testContextProtocol(self): - f = None with BZ2File(self.filename, "wb") as f: f.write(b"xxx") f = BZ2File(self.filename, "rb") diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py index 24e472b5..0712559b 100644 --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -456,6 +456,11 @@ def test_formatmonth(self): calendar.TextCalendar().formatmonth(0, 2), result_0_02_text ) + def test_formatmonth_with_invalid_month(self): + with self.assertRaises(calendar.IllegalMonthError): + calendar.TextCalendar().formatmonth(2017, 13) + with self.assertRaises(calendar.IllegalMonthError): + calendar.TextCalendar().formatmonth(2017, -1) def test_formatmonthname_with_year(self): self.assertEqual( @@ -972,7 +977,7 @@ def test__all__(self): not_exported = { 'mdays', 'January', 'February', 'EPOCH', 'different_locale', 'c', 'prweek', 'week', 'format', - 'formatstring', 'main', 'monthlen', 'prevmonth', 'nextmonth'} + 'formatstring', 'main', 'monthlen', 'prevmonth', 'nextmonth', ""} support.check__all__(self, calendar, not_exported=not_exported) @@ -1000,6 +1005,13 @@ def test_formatmonth(self): self.assertIn('class="text-center month"', self.cal.formatmonth(2017, 5)) + def test_formatmonth_with_invalid_month(self): + with self.assertRaises(calendar.IllegalMonthError): + self.cal.formatmonth(2017, 13) + with self.assertRaises(calendar.IllegalMonthError): + self.cal.formatmonth(2017, -1) + + def test_formatweek(self): weeks = self.cal.monthdays2calendar(2017, 5) self.assertIn('class="wed text-nowrap"', self.cal.formatweek(weeks[0])) diff --git a/Lib/test/test_capi/test_bytes.py b/Lib/test/test_capi/test_bytes.py index bb5d724f..c692ee82 100644 --- a/Lib/test/test_capi/test_bytes.py +++ b/Lib/test/test_capi/test_bytes.py @@ -52,6 +52,8 @@ def test_fromstringandsize(self): self.assertEqual(fromstringandsize(b'abc'), b'abc') self.assertEqual(fromstringandsize(b'abc', 2), b'ab') self.assertEqual(fromstringandsize(b'abc\0def'), b'abc\0def') + self.assertEqual(fromstringandsize(b'a'), b'a') + self.assertEqual(fromstringandsize(b'a', 1), b'a') self.assertEqual(fromstringandsize(b'', 0), b'') self.assertEqual(fromstringandsize(NULL, 0), b'') self.assertEqual(len(fromstringandsize(NULL, 3)), 3) diff --git a/Lib/test/test_capi/test_getargs.py b/Lib/test/test_capi/test_getargs.py index 69bd0f4c..132ba350 100644 --- a/Lib/test/test_capi/test_getargs.py +++ b/Lib/test/test_capi/test_getargs.py @@ -6,6 +6,7 @@ from test.support import import_helper from test.support import script_helper from test.support import warnings_helper +from test.support.testcase import FloatsAreIdenticalMixin # Skip this test if the _testcapi module isn't available. _testcapi = import_helper.import_module('_testcapi') from _testcapi import getargs_keywords, getargs_keyword_only @@ -436,11 +437,7 @@ def test_K(self): self.assertEqual(VERY_LARGE & ULLONG_MAX, getargs_K(VERY_LARGE)) -class Float_TestCase(unittest.TestCase): - def assertEqualWithSign(self, actual, expected): - self.assertEqual(actual, expected) - self.assertEqual(math.copysign(1, actual), math.copysign(1, expected)) - +class Float_TestCase(unittest.TestCase, FloatsAreIdenticalMixin): def test_f(self): from _testcapi import getargs_f self.assertEqual(getargs_f(4.25), 4.25) @@ -462,10 +459,10 @@ def test_f(self): self.assertEqual(getargs_f(DBL_MAX), INF) self.assertEqual(getargs_f(-DBL_MAX), -INF) if FLT_MIN > DBL_MIN: - self.assertEqualWithSign(getargs_f(DBL_MIN), 0.0) - self.assertEqualWithSign(getargs_f(-DBL_MIN), -0.0) - self.assertEqualWithSign(getargs_f(0.0), 0.0) - self.assertEqualWithSign(getargs_f(-0.0), -0.0) + self.assertFloatsAreIdentical(getargs_f(DBL_MIN), 0.0) + self.assertFloatsAreIdentical(getargs_f(-DBL_MIN), -0.0) + self.assertFloatsAreIdentical(getargs_f(0.0), 0.0) + self.assertFloatsAreIdentical(getargs_f(-0.0), -0.0) r = getargs_f(NAN) self.assertNotEqual(r, r) @@ -494,8 +491,8 @@ def test_d(self): self.assertEqual(getargs_d(x), x) self.assertRaises(OverflowError, getargs_d, 1< C integer -> object) + values = (0, 1, 1234, max_val) + if min_val < 0: + values += (-1, min_val) + for value in values: + with self.subTest(value=value): + self.assertEqual(func(value), value) + self.assertEqual(func(IntSubclass(value)), value) + if use_index: + self.assertEqual(func(Index(value)), value) + + if use_index: + self.assertEqual(func(MyIndexAndInt()), 10) + else: + self.assertRaises(TypeError, func, Index(42)) + self.assertRaises(TypeError, func, MyIndexAndInt()) + + if mask: + self.assertEqual(func(min_val - 1), max_val) + self.assertEqual(func(max_val + 1), min_val) + self.assertEqual(func(-1 << 1000), 0) + self.assertEqual(func(1 << 1000), 0) + else: + self.assertRaises(negative_value_error, func, min_val - 1) + self.assertRaises(negative_value_error, func, -1 << 1000) + self.assertRaises(OverflowError, func, max_val + 1) + self.assertRaises(OverflowError, func, 1 << 1000) + self.assertRaises(TypeError, func, 1.0) + self.assertRaises(TypeError, func, b'2') + self.assertRaises(TypeError, func, '3') + self.assertRaises(SystemError, func, NULL) + + def check_long_asintandoverflow(self, func, min_val, max_val): + # round trip (object -> C integer -> object) + for value in (min_val, max_val, -1, 0, 1, 1234): + with self.subTest(value=value): + self.assertEqual(func(value), (value, 0)) + self.assertEqual(func(IntSubclass(value)), (value, 0)) + self.assertEqual(func(Index(value)), (value, 0)) + + self.assertEqual(func(MyIndexAndInt()), (10, 0)) + + self.assertEqual(func(min_val - 1), (-1, -1)) + self.assertEqual(func(max_val + 1), (-1, +1)) + + # CRASHES func(1.0) + # CRASHES func(NULL) + def test_long_aslong(self): # Test PyLong_AsLong() and PyLong_FromLong() aslong = _testcapi.pylong_aslong from _testcapi import LONG_MIN, LONG_MAX - # round trip (object -> long -> object) - for value in (LONG_MIN, LONG_MAX, -1, 0, 1, 1234): - with self.subTest(value=value): - self.assertEqual(aslong(value), value) - - self.assertEqual(aslong(IntSubclass(42)), 42) - self.assertEqual(aslong(Index(42)), 42) - self.assertEqual(aslong(MyIndexAndInt()), 10) - - self.assertRaises(OverflowError, aslong, LONG_MIN - 1) - self.assertRaises(OverflowError, aslong, LONG_MAX + 1) - self.assertRaises(TypeError, aslong, 1.0) - self.assertRaises(TypeError, aslong, b'2') - self.assertRaises(TypeError, aslong, '3') - self.assertRaises(SystemError, aslong, NULL) + self.check_long_asint(aslong, LONG_MIN, LONG_MAX) def test_long_aslongandoverflow(self): # Test PyLong_AsLongAndOverflow() aslongandoverflow = _testcapi.pylong_aslongandoverflow from _testcapi import LONG_MIN, LONG_MAX - # round trip (object -> long -> object) - for value in (LONG_MIN, LONG_MAX, -1, 0, 1, 1234): - with self.subTest(value=value): - self.assertEqual(aslongandoverflow(value), (value, 0)) - - self.assertEqual(aslongandoverflow(IntSubclass(42)), (42, 0)) - self.assertEqual(aslongandoverflow(Index(42)), (42, 0)) - self.assertEqual(aslongandoverflow(MyIndexAndInt()), (10, 0)) - - self.assertEqual(aslongandoverflow(LONG_MIN - 1), (-1, -1)) - self.assertEqual(aslongandoverflow(LONG_MAX + 1), (-1, 1)) - # CRASHES aslongandoverflow(1.0) - # CRASHES aslongandoverflow(NULL) + self.check_long_asintandoverflow(aslongandoverflow, LONG_MIN, LONG_MAX) def test_long_asunsignedlong(self): # Test PyLong_AsUnsignedLong() and PyLong_FromUnsignedLong() asunsignedlong = _testcapi.pylong_asunsignedlong from _testcapi import ULONG_MAX - # round trip (object -> unsigned long -> object) - for value in (ULONG_MAX, 0, 1, 1234): - with self.subTest(value=value): - self.assertEqual(asunsignedlong(value), value) - - self.assertEqual(asunsignedlong(IntSubclass(42)), 42) - self.assertRaises(TypeError, asunsignedlong, Index(42)) - self.assertRaises(TypeError, asunsignedlong, MyIndexAndInt()) - - self.assertRaises(OverflowError, asunsignedlong, -1) - self.assertRaises(OverflowError, asunsignedlong, ULONG_MAX + 1) - self.assertRaises(TypeError, asunsignedlong, 1.0) - self.assertRaises(TypeError, asunsignedlong, b'2') - self.assertRaises(TypeError, asunsignedlong, '3') - self.assertRaises(SystemError, asunsignedlong, NULL) + self.check_long_asint(asunsignedlong, 0, ULONG_MAX, + use_index=False) def test_long_asunsignedlongmask(self): # Test PyLong_AsUnsignedLongMask() asunsignedlongmask = _testcapi.pylong_asunsignedlongmask from _testcapi import ULONG_MAX - # round trip (object -> unsigned long -> object) - for value in (ULONG_MAX, 0, 1, 1234): - with self.subTest(value=value): - self.assertEqual(asunsignedlongmask(value), value) - - self.assertEqual(asunsignedlongmask(IntSubclass(42)), 42) - self.assertEqual(asunsignedlongmask(Index(42)), 42) - self.assertEqual(asunsignedlongmask(MyIndexAndInt()), 10) - - self.assertEqual(asunsignedlongmask(-1), ULONG_MAX) - self.assertEqual(asunsignedlongmask(ULONG_MAX + 1), 0) - self.assertRaises(TypeError, asunsignedlongmask, 1.0) - self.assertRaises(TypeError, asunsignedlongmask, b'2') - self.assertRaises(TypeError, asunsignedlongmask, '3') - self.assertRaises(SystemError, asunsignedlongmask, NULL) + self.check_long_asint(asunsignedlongmask, 0, ULONG_MAX, mask=True) def test_long_aslonglong(self): # Test PyLong_AsLongLong() and PyLong_FromLongLong() aslonglong = _testcapi.pylong_aslonglong from _testcapi import LLONG_MIN, LLONG_MAX - # round trip (object -> long long -> object) - for value in (LLONG_MIN, LLONG_MAX, -1, 0, 1, 1234): - with self.subTest(value=value): - self.assertEqual(aslonglong(value), value) - - self.assertEqual(aslonglong(IntSubclass(42)), 42) - self.assertEqual(aslonglong(Index(42)), 42) - self.assertEqual(aslonglong(MyIndexAndInt()), 10) - - self.assertRaises(OverflowError, aslonglong, LLONG_MIN - 1) - self.assertRaises(OverflowError, aslonglong, LLONG_MAX + 1) - self.assertRaises(TypeError, aslonglong, 1.0) - self.assertRaises(TypeError, aslonglong, b'2') - self.assertRaises(TypeError, aslonglong, '3') - self.assertRaises(SystemError, aslonglong, NULL) + self.check_long_asint(aslonglong, LLONG_MIN, LLONG_MAX) def test_long_aslonglongandoverflow(self): # Test PyLong_AsLongLongAndOverflow() aslonglongandoverflow = _testcapi.pylong_aslonglongandoverflow from _testcapi import LLONG_MIN, LLONG_MAX - # round trip (object -> long long -> object) - for value in (LLONG_MIN, LLONG_MAX, -1, 0, 1, 1234): - with self.subTest(value=value): - self.assertEqual(aslonglongandoverflow(value), (value, 0)) - - self.assertEqual(aslonglongandoverflow(IntSubclass(42)), (42, 0)) - self.assertEqual(aslonglongandoverflow(Index(42)), (42, 0)) - self.assertEqual(aslonglongandoverflow(MyIndexAndInt()), (10, 0)) - - self.assertEqual(aslonglongandoverflow(LLONG_MIN - 1), (-1, -1)) - self.assertEqual(aslonglongandoverflow(LLONG_MAX + 1), (-1, 1)) - # CRASHES aslonglongandoverflow(1.0) - # CRASHES aslonglongandoverflow(NULL) + self.check_long_asintandoverflow(aslonglongandoverflow, LLONG_MIN, LLONG_MAX) def test_long_asunsignedlonglong(self): # Test PyLong_AsUnsignedLongLong() and PyLong_FromUnsignedLongLong() asunsignedlonglong = _testcapi.pylong_asunsignedlonglong from _testcapi import ULLONG_MAX - # round trip (object -> unsigned long long -> object) - for value in (ULLONG_MAX, 0, 1, 1234): - with self.subTest(value=value): - self.assertEqual(asunsignedlonglong(value), value) - - self.assertEqual(asunsignedlonglong(IntSubclass(42)), 42) - self.assertRaises(TypeError, asunsignedlonglong, Index(42)) - self.assertRaises(TypeError, asunsignedlonglong, MyIndexAndInt()) - - self.assertRaises(OverflowError, asunsignedlonglong, -1) - self.assertRaises(OverflowError, asunsignedlonglong, ULLONG_MAX + 1) - self.assertRaises(TypeError, asunsignedlonglong, 1.0) - self.assertRaises(TypeError, asunsignedlonglong, b'2') - self.assertRaises(TypeError, asunsignedlonglong, '3') - self.assertRaises(SystemError, asunsignedlonglong, NULL) + self.check_long_asint(asunsignedlonglong, 0, ULLONG_MAX, use_index=False) def test_long_asunsignedlonglongmask(self): # Test PyLong_AsUnsignedLongLongMask() asunsignedlonglongmask = _testcapi.pylong_asunsignedlonglongmask from _testcapi import ULLONG_MAX - # round trip (object -> unsigned long long -> object) - for value in (ULLONG_MAX, 0, 1, 1234): - with self.subTest(value=value): - self.assertEqual(asunsignedlonglongmask(value), value) - - self.assertEqual(asunsignedlonglongmask(IntSubclass(42)), 42) - self.assertEqual(asunsignedlonglongmask(Index(42)), 42) - self.assertEqual(asunsignedlonglongmask(MyIndexAndInt()), 10) - - self.assertEqual(asunsignedlonglongmask(-1), ULLONG_MAX) - self.assertEqual(asunsignedlonglongmask(ULLONG_MAX + 1), 0) - self.assertRaises(TypeError, asunsignedlonglongmask, 1.0) - self.assertRaises(TypeError, asunsignedlonglongmask, b'2') - self.assertRaises(TypeError, asunsignedlonglongmask, '3') - self.assertRaises(SystemError, asunsignedlonglongmask, NULL) + self.check_long_asint(asunsignedlonglongmask, 0, ULLONG_MAX, mask=True) def test_long_as_ssize_t(self): # Test PyLong_AsSsize_t() and PyLong_FromSsize_t() as_ssize_t = _testcapi.pylong_as_ssize_t from _testcapi import PY_SSIZE_T_MIN, PY_SSIZE_T_MAX - # round trip (object -> Py_ssize_t -> object) - for value in (PY_SSIZE_T_MIN, PY_SSIZE_T_MAX, -1, 0, 1, 1234): - with self.subTest(value=value): - self.assertEqual(as_ssize_t(value), value) - - self.assertEqual(as_ssize_t(IntSubclass(42)), 42) - self.assertRaises(TypeError, as_ssize_t, Index(42)) - self.assertRaises(TypeError, as_ssize_t, MyIndexAndInt()) - - self.assertRaises(OverflowError, as_ssize_t, PY_SSIZE_T_MIN - 1) - self.assertRaises(OverflowError, as_ssize_t, PY_SSIZE_T_MAX + 1) - self.assertRaises(TypeError, as_ssize_t, 1.0) - self.assertRaises(TypeError, as_ssize_t, b'2') - self.assertRaises(TypeError, as_ssize_t, '3') - self.assertRaises(SystemError, as_ssize_t, NULL) + self.check_long_asint(as_ssize_t, PY_SSIZE_T_MIN, PY_SSIZE_T_MAX, + use_index=False) def test_long_as_size_t(self): # Test PyLong_AsSize_t() and PyLong_FromSize_t() as_size_t = _testcapi.pylong_as_size_t from _testcapi import SIZE_MAX - # round trip (object -> size_t -> object) - for value in (SIZE_MAX, 0, 1, 1234): - with self.subTest(value=value): - self.assertEqual(as_size_t(value), value) - - self.assertEqual(as_size_t(IntSubclass(42)), 42) - self.assertRaises(TypeError, as_size_t, Index(42)) - self.assertRaises(TypeError, as_size_t, MyIndexAndInt()) - - self.assertRaises(OverflowError, as_size_t, -1) - self.assertRaises(OverflowError, as_size_t, SIZE_MAX + 1) - self.assertRaises(TypeError, as_size_t, 1.0) - self.assertRaises(TypeError, as_size_t, b'2') - self.assertRaises(TypeError, as_size_t, '3') - self.assertRaises(SystemError, as_size_t, NULL) + self.check_long_asint(as_size_t, 0, SIZE_MAX, use_index=False) def test_long_asdouble(self): # Test PyLong_AsDouble() @@ -407,21 +325,7 @@ def test_long_aspid(self): bits = 8 * SIZEOF_PID_T PID_T_MIN = -2**(bits-1) PID_T_MAX = 2**(bits-1) - 1 - # round trip (object -> long -> object) - for value in (PID_T_MIN, PID_T_MAX, -1, 0, 1, 1234): - with self.subTest(value=value): - self.assertEqual(aspid(value), value) - - self.assertEqual(aspid(IntSubclass(42)), 42) - self.assertEqual(aspid(Index(42)), 42) - self.assertEqual(aspid(MyIndexAndInt()), 10) - - self.assertRaises(OverflowError, aspid, PID_T_MIN - 1) - self.assertRaises(OverflowError, aspid, PID_T_MAX + 1) - self.assertRaises(TypeError, aspid, 1.0) - self.assertRaises(TypeError, aspid, b'2') - self.assertRaises(TypeError, aspid, '3') - self.assertRaises(SystemError, aspid, NULL) + self.check_long_asint(aspid, PID_T_MIN, PID_T_MAX) if __name__ == "__main__": diff --git a/Lib/test/test_capi/test_number.py b/Lib/test/test_capi/test_number.py new file mode 100644 index 00000000..3c1f0f24 --- /dev/null +++ b/Lib/test/test_capi/test_number.py @@ -0,0 +1,335 @@ +import itertools +import operator +import sys +import unittest +import warnings + +from test.support import cpython_only, import_helper + +_testcapi = import_helper.import_module('_testcapi') +from _testcapi import PY_SSIZE_T_MAX, PY_SSIZE_T_MIN + +try: + from _testbuffer import ndarray +except ImportError: + ndarray = None + +NULL = None + +class BadDescr: + def __get__(self, obj, objtype=None): + raise RuntimeError + +class WithDunder: + def _meth(self, *args): + if self.val: + return self.val + if self.exc: + raise self.exc + @classmethod + def with_val(cls, val): + obj = super().__new__(cls) + obj.val = val + obj.exc = None + setattr(cls, cls.methname, cls._meth) + return obj + + @classmethod + def with_exc(cls, exc): + obj = super().__new__(cls) + obj.val = None + obj.exc = exc + setattr(cls, cls.methname, cls._meth) + return obj + +class HasBadAttr: + def __new__(cls): + obj = super().__new__(cls) + setattr(cls, cls.methname, BadDescr()) + return obj + + +class IndexLike(WithDunder): + methname = '__index__' + +class IntLike(WithDunder): + methname = '__int__' + +class FloatLike(WithDunder): + methname = '__float__' + + +def subclassof(base): + return type(base.__name__ + 'Subclass', (base,), {}) + + +class SomeError(Exception): + pass + +class OtherError(Exception): + pass + + +class CAPITest(unittest.TestCase): + def test_check(self): + # Test PyNumber_Check() + check = _testcapi.number_check + + self.assertTrue(check(1)) + self.assertTrue(check(IndexLike.with_val(1))) + self.assertTrue(check(IntLike.with_val(99))) + self.assertTrue(check(0.5)) + self.assertTrue(check(FloatLike.with_val(4.25))) + self.assertTrue(check(1+2j)) + + self.assertFalse(check([])) + self.assertFalse(check("abc")) + self.assertFalse(check(object())) + self.assertFalse(check(NULL)) + + def test_unary_ops(self): + methmap = {'__neg__': _testcapi.number_negative, # PyNumber_Negative() + '__pos__': _testcapi.number_positive, # PyNumber_Positive() + '__abs__': _testcapi.number_absolute, # PyNumber_Absolute() + '__invert__': _testcapi.number_invert} # PyNumber_Invert() + + for name, func in methmap.items(): + # Generic object, has no tp_as_number structure + self.assertRaises(TypeError, func, object()) + + # C-API function accepts NULL + self.assertRaises(SystemError, func, NULL) + + # Behave as corresponding unary operation + op = getattr(operator, name) + for x in [0, 42, -1, 3.14, 1+2j]: + try: + op(x) + except TypeError: + self.assertRaises(TypeError, func, x) + else: + self.assertEqual(func(x), op(x)) + + def test_binary_ops(self): + methmap = {'__add__': _testcapi.number_add, # PyNumber_Add() + '__sub__': _testcapi.number_subtract, # PyNumber_Subtract() + '__mul__': _testcapi.number_multiply, # PyNumber_Multiply() + '__matmul__': _testcapi.number_matrixmultiply, # PyNumber_MatrixMultiply() + '__floordiv__': _testcapi.number_floordivide, # PyNumber_FloorDivide() + '__truediv__': _testcapi.number_truedivide, # PyNumber_TrueDivide() + '__mod__': _testcapi.number_remainder, # PyNumber_Remainder() + '__divmod__': _testcapi.number_divmod, # PyNumber_Divmod() + '__lshift__': _testcapi.number_lshift, # PyNumber_Lshift() + '__rshift__': _testcapi.number_rshift, # PyNumber_Rshift() + '__and__': _testcapi.number_and, # PyNumber_And() + '__xor__': _testcapi.number_xor, # PyNumber_Xor() + '__or__': _testcapi.number_or, # PyNumber_Or() + '__pow__': _testcapi.number_power, # PyNumber_Power() + '__iadd__': _testcapi.number_inplaceadd, # PyNumber_InPlaceAdd() + '__isub__': _testcapi.number_inplacesubtract, # PyNumber_InPlaceSubtract() + '__imul__': _testcapi.number_inplacemultiply, # PyNumber_InPlaceMultiply() + '__imatmul__': _testcapi.number_inplacematrixmultiply, # PyNumber_InPlaceMatrixMultiply() + '__ifloordiv__': _testcapi.number_inplacefloordivide, # PyNumber_InPlaceFloorDivide() + '__itruediv__': _testcapi.number_inplacetruedivide, # PyNumber_InPlaceTrueDivide() + '__imod__': _testcapi.number_inplaceremainder, # PyNumber_InPlaceRemainder() + '__ilshift__': _testcapi.number_inplacelshift, # PyNumber_InPlaceLshift() + '__irshift__': _testcapi.number_inplacershift, # PyNumber_InPlaceRshift() + '__iand__': _testcapi.number_inplaceand, # PyNumber_InPlaceAnd() + '__ixor__': _testcapi.number_inplacexor, # PyNumber_InPlaceXor() + '__ior__': _testcapi.number_inplaceor, # PyNumber_InPlaceOr() + '__ipow__': _testcapi.number_inplacepower, # PyNumber_InPlacePower() + } + + for name, func in methmap.items(): + cases = [0, 42, 3.14, -1, 123, 1+2j] + + # Generic object, has no tp_as_number structure + for x in cases: + self.assertRaises(TypeError, func, object(), x) + self.assertRaises(TypeError, func, x, object()) + + # Behave as corresponding binary operation + op = getattr(operator, name, divmod) + for x, y in itertools.combinations(cases, 2): + try: + op(x, y) + except (TypeError, ValueError, ZeroDivisionError) as exc: + self.assertRaises(exc.__class__, func, x, y) + else: + self.assertEqual(func(x, y), op(x, y)) + + # CRASHES func(NULL, object()) + # CRASHES func(object(), NULL) + + @unittest.skipIf(ndarray is None, "needs _testbuffer") + def test_misc_add(self): + # PyNumber_Add(), PyNumber_InPlaceAdd() + add = _testcapi.number_add + inplaceadd = _testcapi.number_inplaceadd + + # test sq_concat/sq_inplace_concat slots + a, b, r = [1, 2], [3, 4], [1, 2, 3, 4] + self.assertEqual(add(a, b), r) + self.assertEqual(a, [1, 2]) + self.assertRaises(TypeError, add, ndarray([1], (1,)), 2) + a, b, r = [1, 2], [3, 4], [1, 2, 3, 4] + self.assertEqual(inplaceadd(a, b), r) + self.assertEqual(a, r) + self.assertRaises(TypeError, inplaceadd, ndarray([1], (1,)), 2) + + @unittest.skipIf(ndarray is None, "needs _testbuffer") + def test_misc_multiply(self): + # PyNumber_Multiply(), PyNumber_InPlaceMultiply() + multiply = _testcapi.number_multiply + inplacemultiply = _testcapi.number_inplacemultiply + + # test sq_repeat/sq_inplace_repeat slots + a, b, r = [1], 2, [1, 1] + self.assertEqual(multiply(a, b), r) + self.assertEqual((a, b), ([1], 2)) + self.assertEqual(multiply(b, a), r) + self.assertEqual((a, b), ([1], 2)) + self.assertEqual(multiply([1], -1), []) + self.assertRaises(TypeError, multiply, ndarray([1], (1,)), 2) + self.assertRaises(TypeError, multiply, [1], 0.5) + self.assertRaises(OverflowError, multiply, [1], PY_SSIZE_T_MAX + 1) + self.assertRaises(MemoryError, multiply, [1, 2], PY_SSIZE_T_MAX//2 + 1) + a, b, r = [1], 2, [1, 1] + self.assertEqual(inplacemultiply(a, b), r) + self.assertEqual((a, b), (r, 2)) + a = [1] + self.assertEqual(inplacemultiply(b, a), r) + self.assertEqual((a, b), ([1], 2)) + self.assertRaises(TypeError, inplacemultiply, ndarray([1], (1,)), 2) + self.assertRaises(OverflowError, inplacemultiply, [1], PY_SSIZE_T_MAX + 1) + self.assertRaises(MemoryError, inplacemultiply, [1, 2], PY_SSIZE_T_MAX//2 + 1) + + def test_misc_power(self): + # PyNumber_Power() + power = _testcapi.number_power + + class HasPow(WithDunder): + methname = '__pow__' + + # ternary op + self.assertEqual(power(4, 11, 5), pow(4, 11, 5)) + self.assertRaises(TypeError, power, 4, 11, 1.25) + self.assertRaises(TypeError, power, 4, 11, HasPow.with_val(NotImplemented)) + self.assertRaises(TypeError, power, 4, 11, object()) + + @cpython_only + def test_rshift_print(self): + # This tests correct syntax hint for py2 redirection (>>). + rshift = _testcapi.number_rshift + + with self.assertRaises(TypeError) as context: + rshift(print, 42) + self.assertIn('Did you mean "print(, ' + 'file=)"?', str(context.exception)) + with self.assertRaises(TypeError) as context: + rshift(max, sys.stderr) + self.assertNotIn('Did you mean ', str(context.exception)) + with self.assertRaises(TypeError) as context: + rshift(1, "spam") + + def test_long(self): + # Test PyNumber_Long() + long = _testcapi.number_long + + self.assertEqual(long(42), 42) + self.assertEqual(long(1.25), 1) + self.assertEqual(long("42"), 42) + self.assertEqual(long(b"42"), 42) + self.assertEqual(long(bytearray(b"42")), 42) + self.assertEqual(long(memoryview(b"42")), 42) + self.assertEqual(long(IndexLike.with_val(99)), 99) + self.assertEqual(long(IntLike.with_val(99)), 99) + + self.assertRaises(TypeError, long, IntLike.with_val(1.0)) + with warnings.catch_warnings(): + warnings.simplefilter("error", DeprecationWarning) + self.assertRaises(DeprecationWarning, long, IntLike.with_val(True)) + with self.assertWarns(DeprecationWarning): + self.assertEqual(long(IntLike.with_val(True)), 1) + self.assertRaises(RuntimeError, long, IntLike.with_exc(RuntimeError)) + + self.assertRaises(TypeError, long, 1j) + self.assertRaises(TypeError, long, object()) + self.assertRaises(SystemError, long, NULL) + + def test_float(self): + # Test PyNumber_Float() + float_ = _testcapi.number_float + + self.assertEqual(float_(1.25), 1.25) + self.assertEqual(float_(123), 123.) + self.assertEqual(float_("1.25"), 1.25) + + self.assertEqual(float_(FloatLike.with_val(4.25)), 4.25) + self.assertEqual(float_(IndexLike.with_val(99)), 99.0) + self.assertEqual(float_(IndexLike.with_val(-1)), -1.0) + + self.assertRaises(TypeError, float_, FloatLike.with_val(687)) + with warnings.catch_warnings(): + warnings.simplefilter("error", DeprecationWarning) + self.assertRaises(DeprecationWarning, float_, FloatLike.with_val(subclassof(float)(4.25))) + with self.assertWarns(DeprecationWarning): + self.assertEqual(float_(FloatLike.with_val(subclassof(float)(4.25))), 4.25) + self.assertRaises(RuntimeError, float_, FloatLike.with_exc(RuntimeError)) + + self.assertRaises(TypeError, float_, IndexLike.with_val(1.25)) + self.assertRaises(OverflowError, float_, IndexLike.with_val(2**2000)) + + self.assertRaises(TypeError, float_, 1j) + self.assertRaises(TypeError, float_, object()) + self.assertRaises(SystemError, float_, NULL) + + def test_index(self): + # Test PyNumber_Index() + index = _testcapi.number_index + + self.assertEqual(index(11), 11) + + with warnings.catch_warnings(): + warnings.simplefilter("error", DeprecationWarning) + self.assertRaises(DeprecationWarning, index, IndexLike.with_val(True)) + with self.assertWarns(DeprecationWarning): + self.assertEqual(index(IndexLike.with_val(True)), 1) + self.assertRaises(TypeError, index, IndexLike.with_val(1.0)) + self.assertRaises(RuntimeError, index, IndexLike.with_exc(RuntimeError)) + + self.assertRaises(TypeError, index, 1.25) + self.assertRaises(TypeError, index, "42") + self.assertRaises(TypeError, index, object()) + self.assertRaises(SystemError, index, NULL) + + def test_tobase(self): + # Test PyNumber_ToBase() + tobase = _testcapi.number_tobase + + self.assertEqual(tobase(10, 2), bin(10)) + self.assertEqual(tobase(11, 8), oct(11)) + self.assertEqual(tobase(16, 10), str(16)) + self.assertEqual(tobase(13, 16), hex(13)) + + self.assertRaises(SystemError, tobase, NULL, 2) + self.assertRaises(SystemError, tobase, 2, 3) + self.assertRaises(TypeError, tobase, 1.25, 2) + self.assertRaises(TypeError, tobase, "42", 2) + + def test_asssizet(self): + # Test PyNumber_AsSsize_t() + asssizet = _testcapi.number_asssizet + + for n in [*range(-6, 7), PY_SSIZE_T_MIN, PY_SSIZE_T_MAX]: + self.assertEqual(asssizet(n, OverflowError), n) + self.assertEqual(asssizet(PY_SSIZE_T_MAX+10, NULL), PY_SSIZE_T_MAX) + self.assertEqual(asssizet(PY_SSIZE_T_MIN-10, NULL), PY_SSIZE_T_MIN) + + self.assertRaises(OverflowError, asssizet, PY_SSIZE_T_MAX + 10, OverflowError) + self.assertRaises(RuntimeError, asssizet, PY_SSIZE_T_MAX + 10, RuntimeError) + self.assertRaises(SystemError, asssizet, NULL, TypeError) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_capi/test_set.py b/Lib/test/test_capi/test_set.py index e9165e7e..5131e674 100644 --- a/Lib/test/test_capi/test_set.py +++ b/Lib/test/test_capi/test_set.py @@ -213,3 +213,7 @@ def test_clear(self): clear(object()) self.assertImmutable(clear) # CRASHES: clear(NULL) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_capi/test_tuple.py b/Lib/test/test_capi/test_tuple.py new file mode 100644 index 00000000..baf0d172 --- /dev/null +++ b/Lib/test/test_capi/test_tuple.py @@ -0,0 +1,261 @@ +import unittest +import sys +from collections import namedtuple +from test.support import import_helper + +_testcapi = import_helper.import_module('_testcapi') +_testlimitedcapi = _testcapi + +NULL = None +PY_SSIZE_T_MIN = _testcapi.PY_SSIZE_T_MIN +PY_SSIZE_T_MAX = _testcapi.PY_SSIZE_T_MAX + +class TupleSubclass(tuple): + pass + + +class CAPITest(unittest.TestCase): + def test_check(self): + # Test PyTuple_Check() + check = _testlimitedcapi.tuple_check + + self.assertTrue(check((1, 2))) + self.assertTrue(check(())) + self.assertTrue(check(TupleSubclass((1, 2)))) + self.assertFalse(check({1: 2})) + self.assertFalse(check([1, 2])) + self.assertFalse(check(42)) + self.assertFalse(check(object())) + + # CRASHES check(NULL) + + def test_tuple_checkexact(self): + # Test PyTuple_CheckExact() + check = _testlimitedcapi.tuple_checkexact + + self.assertTrue(check((1, 2))) + self.assertTrue(check(())) + self.assertFalse(check(TupleSubclass((1, 2)))) + self.assertFalse(check({1: 2})) + self.assertFalse(check([1, 2])) + self.assertFalse(check(42)) + self.assertFalse(check(object())) + + # CRASHES check(NULL) + + def test_tuple_new(self): + # Test PyTuple_New() + tuple_new = _testlimitedcapi.tuple_new + size = _testlimitedcapi.tuple_size + checknull = _testcapi._check_tuple_item_is_NULL + + tup1 = tuple_new(0) + self.assertEqual(tup1, ()) + self.assertEqual(size(tup1), 0) + self.assertIs(type(tup1), tuple) + tup2 = tuple_new(1) + self.assertIs(type(tup2), tuple) + self.assertEqual(size(tup2), 1) + self.assertIsNot(tup2, tup1) + self.assertTrue(checknull(tup2, 0)) + + self.assertRaises(SystemError, tuple_new, -1) + self.assertRaises(SystemError, tuple_new, PY_SSIZE_T_MIN) + self.assertRaises(MemoryError, tuple_new, PY_SSIZE_T_MAX) + + def test_tuple_pack(self): + # Test PyTuple_Pack() + pack = _testlimitedcapi.tuple_pack + + self.assertEqual(pack(0), ()) + self.assertEqual(pack(1, [1]), ([1],)) + self.assertEqual(pack(2, [1], [2]), ([1], [2])) + + self.assertRaises(SystemError, pack, PY_SSIZE_T_MIN) + self.assertRaises(SystemError, pack, -1) + self.assertRaises(MemoryError, pack, PY_SSIZE_T_MAX) + + # CRASHES pack(1, NULL) + # CRASHES pack(2, [1]) + + def test_tuple_size(self): + # Test PyTuple_Size() + size = _testlimitedcapi.tuple_size + + self.assertEqual(size(()), 0) + self.assertEqual(size((1, 2)), 2) + self.assertEqual(size(TupleSubclass((1, 2))), 2) + + self.assertRaises(SystemError, size, []) + self.assertRaises(SystemError, size, 42) + self.assertRaises(SystemError, size, object()) + + # CRASHES size(NULL) + + def test_tuple_get_size(self): + # Test PyTuple_GET_SIZE() + size = _testcapi.tuple_get_size + + self.assertEqual(size(()), 0) + self.assertEqual(size((1, 2)), 2) + self.assertEqual(size(TupleSubclass((1, 2))), 2) + + def test_tuple_getitem(self): + # Test PyTuple_GetItem() + getitem = _testlimitedcapi.tuple_getitem + + tup = ([1], [2], [3]) + self.assertEqual(getitem(tup, 0), [1]) + self.assertEqual(getitem(tup, 2), [3]) + + tup2 = TupleSubclass(([1], [2], [3])) + self.assertEqual(getitem(tup2, 0), [1]) + self.assertEqual(getitem(tup2, 2), [3]) + + self.assertRaises(IndexError, getitem, tup, PY_SSIZE_T_MIN) + self.assertRaises(IndexError, getitem, tup, -1) + self.assertRaises(IndexError, getitem, tup, len(tup)) + self.assertRaises(IndexError, getitem, tup, PY_SSIZE_T_MAX) + self.assertRaises(SystemError, getitem, [1, 2, 3], 1) + self.assertRaises(SystemError, getitem, 42, 1) + + # CRASHES getitem(NULL, 0) + + def test_tuple_get_item(self): + # Test PyTuple_GET_ITEM() + get_item = _testcapi.tuple_get_item + + tup = ([1], [2], [3]) + self.assertEqual(get_item(tup, 0), [1]) + self.assertEqual(get_item(tup, 2), [3]) + + tup2 = TupleSubclass(([1], [2], [3])) + self.assertEqual(get_item(tup2, 0), [1]) + self.assertEqual(get_item(tup2, 2), [3]) + + # CRASHES get_item(NULL, 0) + + def test_tuple_getslice(self): + # Test PyTuple_GetSlice() + getslice = _testlimitedcapi.tuple_getslice + + # empty + tup = ([1], [2], [3]) + self.assertEqual(getslice(tup, PY_SSIZE_T_MIN, 0), ()) + self.assertEqual(getslice(tup, -1, 0), ()) + self.assertEqual(getslice(tup, 3, PY_SSIZE_T_MAX), ()) + self.assertEqual(getslice(tup, 1, 1), ()) + self.assertEqual(getslice(tup, 2, 1), ()) + tup = TupleSubclass(([1], [2], [3])) + self.assertEqual(getslice(tup, PY_SSIZE_T_MIN, 0), ()) + self.assertEqual(getslice(tup, -1, 0), ()) + self.assertEqual(getslice(tup, 3, PY_SSIZE_T_MAX), ()) + self.assertEqual(getslice(tup, 1, 1), ()) + self.assertEqual(getslice(tup, 2, 1), ()) + + # slice + tup = ([1], [2], [3], [4]) + self.assertEqual(getslice(tup, 1, 3), ([2], [3])) + tup = TupleSubclass(([1], [2], [3], [4])) + self.assertEqual(getslice(tup, 1, 3), ([2], [3])) + + # whole + tup = ([1], [2], [3]) + self.assertEqual(getslice(tup, 0, 3), tup) + self.assertEqual(getslice(tup, 0, 100), tup) + self.assertEqual(getslice(tup, -100, 100), tup) + tup = TupleSubclass(([1], [2], [3])) + self.assertEqual(getslice(tup, 0, 3), tup) + self.assertEqual(getslice(tup, 0, 100), tup) + self.assertEqual(getslice(tup, -100, 100), tup) + + self.assertRaises(SystemError, getslice, [[1], [2], [3]], 0, 0) + self.assertRaises(SystemError, getslice, 42, 0, 0) + + # CRASHES getslice(NULL, 0, 0) + + def test_tuple_setitem(self): + # Test PyTuple_SetItem() + setitem = _testlimitedcapi.tuple_setitem + checknull = _testcapi._check_tuple_item_is_NULL + + tup = ([1], [2]) + self.assertEqual(setitem(tup, 0, []), ([], [2])) + self.assertEqual(setitem(tup, 1, []), ([1], [])) + + tup2 = setitem(tup, 1, NULL) + self.assertTrue(checknull(tup2, 1)) + + tup2 = TupleSubclass(([1], [2])) + self.assertRaises(SystemError, setitem, tup2, 0, []) + + self.assertRaises(IndexError, setitem, tup, PY_SSIZE_T_MIN, []) + self.assertRaises(IndexError, setitem, tup, -1, []) + self.assertRaises(IndexError, setitem, tup, len(tup), []) + self.assertRaises(IndexError, setitem, tup, PY_SSIZE_T_MAX, []) + self.assertRaises(SystemError, setitem, [1], 0, []) + self.assertRaises(SystemError, setitem, 42, 0, []) + + # CRASHES setitem(NULL, 0, []) + + def test_tuple_set_item(self): + # Test PyTuple_SET_ITEM() + set_item = _testcapi.tuple_set_item + checknull = _testcapi._check_tuple_item_is_NULL + + tup = ([1], [2]) + self.assertEqual(set_item(tup, 0, []), ([], [2])) + self.assertEqual(set_item(tup, 1, []), ([1], [])) + + tup2 = set_item(tup, 1, NULL) + self.assertTrue(checknull(tup2, 1)) + + tup2 = TupleSubclass(([1], [2])) + self.assertIs(set_item(tup2, 0, []), tup2) + self.assertEqual(tup2, ([], [2])) + + # CRASHES set_item(tup, -1, []) + # CRASHES set_item(tup, len(tup), []) + # CRASHES set_item([1], 0, []) + # CRASHES set_item(NULL, 0, []) + + def test__tuple_resize(self): + # Test _PyTuple_Resize() + resize = _testcapi._tuple_resize + checknull = _testcapi._check_tuple_item_is_NULL + + a = () + b = resize(a, 0, False) + self.assertEqual(len(a), 0) + self.assertEqual(len(b), 0) + b = resize(a, 2, False) + self.assertEqual(len(a), 0) + self.assertEqual(len(b), 2) + self.assertTrue(checknull(b, 0)) + self.assertTrue(checknull(b, 1)) + + a = ([1], [2], [3]) + b = resize(a, 3) + self.assertEqual(b, a) + b = resize(a, 2) + self.assertEqual(b, a[:2]) + b = resize(a, 5) + self.assertEqual(len(b), 5) + self.assertEqual(b[:3], a) + self.assertTrue(checknull(b, 3)) + self.assertTrue(checknull(b, 4)) + + a = () + self.assertRaises(MemoryError, resize, a, PY_SSIZE_T_MAX) + self.assertRaises(SystemError, resize, a, -1) + self.assertRaises(SystemError, resize, a, PY_SSIZE_T_MIN) + # refcount > 1 + a = (1, 2, 3) + self.assertRaises(SystemError, resize, a, 3, False) + self.assertRaises(SystemError, resize, a, 0, False) + # non-tuple + self.assertRaises(SystemError, resize, [1, 2, 3], 0, False) + self.assertRaises(SystemError, resize, NULL, 0, False) + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py index 7a159760..28d3c0db 100644 --- a/Lib/test/test_class.py +++ b/Lib/test/test_class.py @@ -503,6 +503,56 @@ def __eq__(self, other): return 1 self.assertRaises(TypeError, hash, C2()) + def testPredefinedAttrs(self): + o = object() + + class Custom: + pass + + c = Custom() + + methods = ( + '__class__', '__delattr__', '__dir__', '__eq__', '__format__', + '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', + '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', + '__new__', '__reduce__', '__reduce_ex__', '__repr__', + '__setattr__', '__sizeof__', '__str__', '__subclasshook__' + ) + for name in methods: + with self.subTest(name): + self.assertTrue(callable(getattr(object, name, None))) + self.assertTrue(callable(getattr(o, name, None))) + self.assertTrue(callable(getattr(Custom, name, None))) + self.assertTrue(callable(getattr(c, name, None))) + + not_defined = [ + '__abs__', '__aenter__', '__aexit__', '__aiter__', '__anext__', + '__await__', '__bool__', '__bytes__', '__ceil__', + '__complex__', '__contains__', '__del__', '__delete__', + '__delitem__', '__divmod__', '__enter__', '__exit__', + '__float__', '__floor__', '__get__', '__getattr__', '__getitem__', + '__index__', '__int__', '__invert__', '__iter__', '__len__', + '__length_hint__', '__missing__', '__neg__', '__next__', + '__objclass__', '__pos__', '__rdivmod__', '__reversed__', + '__round__', '__set__', '__setitem__', '__trunc__' + ] + augment = ( + 'add', 'and', 'floordiv', 'lshift', 'matmul', 'mod', 'mul', 'pow', + 'rshift', 'sub', 'truediv', 'xor' + ) + not_defined.extend(map("__{}__".format, augment)) + not_defined.extend(map("__r{}__".format, augment)) + not_defined.extend(map("__i{}__".format, augment)) + for name in not_defined: + with self.subTest(name): + self.assertFalse(hasattr(object, name)) + self.assertFalse(hasattr(o, name)) + self.assertFalse(hasattr(Custom, name)) + self.assertFalse(hasattr(c, name)) + + # __call__() is defined on the metaclass but not the class + self.assertFalse(hasattr(o, "__call__")) + self.assertFalse(hasattr(c, "__call__")) def testSFBug532646(self): # Test for SF bug 532646 diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index c114a62c..e5f653ee 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -1502,7 +1502,7 @@ def test_cli_force(self): # Verify by checking the checksum. checksum = ( "/*[clinic end generated code: " - "output=2124c291eb067d76 input=9543a8d2da235301]*/\n" + "output=99dd9b13ffdc660d input=9543a8d2da235301]*/\n" ) with open(fn, encoding='utf-8') as f: generated = f.read() @@ -2093,11 +2093,27 @@ def test_vararg(self): self.assertEqual(ac_tester.vararg(1, 2, 3, 4), (1, (2, 3, 4))) def test_vararg_with_default(self): - with self.assertRaises(TypeError): - ac_tester.vararg_with_default() - self.assertEqual(ac_tester.vararg_with_default(1, b=False), (1, (), False)) - self.assertEqual(ac_tester.vararg_with_default(1, 2, 3, 4), (1, (2, 3, 4), False)) - self.assertEqual(ac_tester.vararg_with_default(1, 2, 3, 4, b=True), (1, (2, 3, 4), True)) + fn = ac_tester.vararg_with_default + self.assertRaises(TypeError, fn) + self.assertRaises(TypeError, fn, 1, a=2) + self.assertEqual(fn(1, b=2), (1, (), True)) + self.assertEqual(fn(1, 2, 3, 4), (1, (2, 3, 4), False)) + self.assertEqual(fn(1, 2, 3, 4, b=5), (1, (2, 3, 4), True)) + self.assertEqual(fn(a=1), (1, (), False)) + self.assertEqual(fn(a=1, b=2), (1, (), True)) + + def test_vararg_with_default2(self): + fn = ac_tester.vararg_with_default2 + self.assertRaises(TypeError, fn) + self.assertRaises(TypeError, fn, 1, a=2) + self.assertEqual(fn(1, b=2), (1, (), 2, None)) + self.assertEqual(fn(1, b=2, c=3), (1, (), 2, 3)) + self.assertEqual(fn(1, 2, 3), (1, (2, 3), None, None)) + self.assertEqual(fn(1, 2, 3, b=4), (1, (2, 3), 4, None)) + self.assertEqual(fn(1, 2, 3, b=4, c=5), (1, (2, 3), 4, 5)) + self.assertEqual(fn(a=1), (1, (), None, None)) + self.assertEqual(fn(a=1, b=2), (1, (), 2, None)) + self.assertEqual(fn(a=1, b=2, c=3), (1, (), 2, 3)) def test_vararg_with_only_defaults(self): self.assertEqual(ac_tester.vararg_with_only_defaults(), ((), None)) diff --git a/Lib/test/test_cmath.py b/Lib/test/test_cmath.py index 57f80d5d..a96a5780 100644 --- a/Lib/test/test_cmath.py +++ b/Lib/test/test_cmath.py @@ -1,4 +1,5 @@ from test.support import requires_IEEE_754, cpython_only, import_helper +from test.support.testcase import ComplexesAreIdenticalMixin from test.test_math import parse_testfile, test_file import test.test_math as test_math import unittest @@ -49,7 +50,7 @@ (INF, NAN) ]] -class CMathTests(unittest.TestCase): +class CMathTests(ComplexesAreIdenticalMixin, unittest.TestCase): # list of all functions in cmath test_functions = [getattr(cmath, fname) for fname in [ 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atanh', @@ -65,39 +66,6 @@ def setUp(self): def tearDown(self): self.test_values.close() - def assertFloatIdentical(self, x, y): - """Fail unless floats x and y are identical, in the sense that: - (1) both x and y are nans, or - (2) both x and y are infinities, with the same sign, or - (3) both x and y are zeros, with the same sign, or - (4) x and y are both finite and nonzero, and x == y - - """ - msg = 'floats {!r} and {!r} are not identical' - - if math.isnan(x) or math.isnan(y): - if math.isnan(x) and math.isnan(y): - return - elif x == y: - if x != 0.0: - return - # both zero; check that signs match - elif math.copysign(1.0, x) == math.copysign(1.0, y): - return - else: - msg += ': zeros have different signs' - self.fail(msg.format(x, y)) - - def assertComplexIdentical(self, x, y): - """Fail unless complex numbers x and y have equal values and signs. - - In particular, if x and y both have real (or imaginary) part - zero, but the zeros have different signs, this test will fail. - - """ - self.assertFloatIdentical(x.real, y.real) - self.assertFloatIdentical(x.imag, y.imag) - def rAssertAlmostEqual(self, a, b, rel_err = 2e-15, abs_err = 5e-323, msg=None): """Fail if the two floating-point numbers are not almost equal. @@ -555,7 +523,7 @@ def test_isinf(self): @requires_IEEE_754 def testTanhSign(self): for z in complex_zeros: - self.assertComplexIdentical(cmath.tanh(z), z) + self.assertComplexesAreIdentical(cmath.tanh(z), z) # The algorithm used for atan and atanh makes use of the system # log1p function; If that system function doesn't respect the sign @@ -564,12 +532,12 @@ def testTanhSign(self): @requires_IEEE_754 def testAtanSign(self): for z in complex_zeros: - self.assertComplexIdentical(cmath.atan(z), z) + self.assertComplexesAreIdentical(cmath.atan(z), z) @requires_IEEE_754 def testAtanhSign(self): for z in complex_zeros: - self.assertComplexIdentical(cmath.atanh(z), z) + self.assertComplexesAreIdentical(cmath.atanh(z), z) class IsCloseTests(test_math.IsCloseTests): diff --git a/Lib/test/test_code_module.py b/Lib/test/test_code_module.py index 226bc3a8..06a1ba49 100644 --- a/Lib/test/test_code_module.py +++ b/Lib/test/test_code_module.py @@ -1,5 +1,6 @@ "Test InteractiveConsole and InteractiveInterpreter from code module" import sys +import traceback import unittest from textwrap import dedent from contextlib import ExitStack @@ -11,6 +12,7 @@ class TestInteractiveConsole(unittest.TestCase): + maxDiff = None def setUp(self): self.console = code.InteractiveConsole() @@ -58,21 +60,151 @@ def test_console_stderr(self): raise AssertionError("no console stdout") def test_syntax_error(self): - self.infunc.side_effect = ["undefined", EOFError('Finished')] + self.infunc.side_effect = ["def f():", + " x = ?", + "", + EOFError('Finished')] self.console.interact() - for call in self.stderr.method_calls: - if 'NameError' in ''.join(call[1]): - break - else: - raise AssertionError("No syntax error from console") + output = ''.join(''.join(call[1]) for call in self.stderr.method_calls) + output = output[output.index('(InteractiveConsole)'):] + output = output[:output.index('\nnow exiting')] + self.assertEqual(output.splitlines()[1:], [ + ' File "", line 2', + ' x = ?', + ' ^', + 'SyntaxError: invalid syntax']) + self.assertIs(self.sysmod.last_type, SyntaxError) + self.assertIs(type(self.sysmod.last_value), SyntaxError) + self.assertIsNone(self.sysmod.last_traceback) + self.assertIsNone(self.sysmod.last_value.__traceback__) + self.assertIs(self.sysmod.last_exc, self.sysmod.last_value) + + def test_indentation_error(self): + self.infunc.side_effect = [" 1", EOFError('Finished')] + self.console.interact() + output = ''.join(''.join(call[1]) for call in self.stderr.method_calls) + output = output[output.index('(InteractiveConsole)'):] + output = output[:output.index('\nnow exiting')] + self.assertEqual(output.splitlines()[1:], [ + ' File "", line 1', + ' 1', + 'IndentationError: unexpected indent']) + self.assertIs(self.sysmod.last_type, IndentationError) + self.assertIs(type(self.sysmod.last_value), IndentationError) + self.assertIsNone(self.sysmod.last_traceback) + self.assertIsNone(self.sysmod.last_value.__traceback__) + self.assertIs(self.sysmod.last_exc, self.sysmod.last_value) + + def test_unicode_error(self): + self.infunc.side_effect = ["'\ud800'", EOFError('Finished')] + self.console.interact() + output = ''.join(''.join(call[1]) for call in self.stderr.method_calls) + output = output[output.index('(InteractiveConsole)'):] + output = output[output.index('\n') + 1:] + self.assertTrue(output.startswith('UnicodeEncodeError: '), output) + self.assertIs(self.sysmod.last_type, UnicodeEncodeError) + self.assertIs(type(self.sysmod.last_value), UnicodeEncodeError) + self.assertIsNone(self.sysmod.last_traceback) + self.assertIsNone(self.sysmod.last_value.__traceback__) + self.assertIs(self.sysmod.last_exc, self.sysmod.last_value) def test_sysexcepthook(self): - self.infunc.side_effect = ["raise ValueError('')", + self.infunc.side_effect = ["def f():", + " raise ValueError('BOOM!')", + "", + "f()", + EOFError('Finished')] + hook = mock.Mock() + self.sysmod.excepthook = hook + self.console.interact() + hook.assert_called() + hook.assert_called_with(self.sysmod.last_type, + self.sysmod.last_value, + self.sysmod.last_traceback) + self.assertIs(self.sysmod.last_type, ValueError) + self.assertIs(type(self.sysmod.last_value), ValueError) + self.assertIs(self.sysmod.last_traceback, self.sysmod.last_value.__traceback__) + self.assertIs(self.sysmod.last_exc, self.sysmod.last_value) + self.assertEqual(traceback.format_exception(self.sysmod.last_exc), [ + 'Traceback (most recent call last):\n', + ' File "", line 1, in \n', + ' File "", line 2, in f\n', + 'ValueError: BOOM!\n']) + + def test_sysexcepthook_syntax_error(self): + self.infunc.side_effect = ["def f():", + " x = ?", + "", EOFError('Finished')] hook = mock.Mock() self.sysmod.excepthook = hook self.console.interact() - self.assertTrue(hook.called) + hook.assert_called() + hook.assert_called_with(self.sysmod.last_type, + self.sysmod.last_value, + self.sysmod.last_traceback) + self.assertIs(self.sysmod.last_type, SyntaxError) + self.assertIs(type(self.sysmod.last_value), SyntaxError) + self.assertIsNone(self.sysmod.last_traceback) + self.assertIsNone(self.sysmod.last_value.__traceback__) + self.assertIs(self.sysmod.last_exc, self.sysmod.last_value) + self.assertEqual(traceback.format_exception(self.sysmod.last_exc), [ + ' File "", line 2\n', + ' x = ?\n', + ' ^\n', + 'SyntaxError: invalid syntax\n']) + + def test_sysexcepthook_indentation_error(self): + self.infunc.side_effect = [" 1", EOFError('Finished')] + hook = mock.Mock() + self.sysmod.excepthook = hook + self.console.interact() + hook.assert_called() + hook.assert_called_with(self.sysmod.last_type, + self.sysmod.last_value, + self.sysmod.last_traceback) + self.assertIs(self.sysmod.last_type, IndentationError) + self.assertIs(type(self.sysmod.last_value), IndentationError) + self.assertIsNone(self.sysmod.last_traceback) + self.assertIsNone(self.sysmod.last_value.__traceback__) + self.assertIs(self.sysmod.last_exc, self.sysmod.last_value) + self.assertEqual(traceback.format_exception(self.sysmod.last_exc), [ + ' File "", line 1\n', + ' 1\n', + 'IndentationError: unexpected indent\n']) + + def test_sysexcepthook_crashing_doesnt_close_repl(self): + self.infunc.side_effect = ["1/0", "a = 123", "print(a)", EOFError('Finished')] + self.sysmod.excepthook = 1 + self.console.interact() + self.assertEqual(['write', ('123', ), {}], self.stdout.method_calls[0]) + error = "".join(call.args[0] for call in self.stderr.method_calls if call[0] == 'write') + self.assertIn("Error in sys.excepthook:", error) + self.assertEqual(error.count("'int' object is not callable"), 1) + self.assertIn("Original exception was:", error) + self.assertIn("division by zero", error) + + def test_sysexcepthook_raising_BaseException(self): + self.infunc.side_effect = ["1/0", "a = 123", "print(a)", EOFError('Finished')] + s = "not so fast" + def raise_base(*args, **kwargs): + raise BaseException(s) + self.sysmod.excepthook = raise_base + self.console.interact() + self.assertEqual(['write', ('123', ), {}], self.stdout.method_calls[0]) + error = "".join(call.args[0] for call in self.stderr.method_calls if call[0] == 'write') + self.assertIn("Error in sys.excepthook:", error) + self.assertEqual(error.count("not so fast"), 1) + self.assertIn("Original exception was:", error) + self.assertIn("division by zero", error) + + def test_sysexcepthook_raising_SystemExit_gets_through(self): + self.infunc.side_effect = ["1/0"] + def raise_base(*args, **kwargs): + raise SystemExit + self.sysmod.excepthook = raise_base + with self.assertRaises(SystemExit): + self.console.interact() def test_banner(self): # with banner @@ -131,6 +263,11 @@ def test_cause_tb(self): ValueError """) self.assertIn(expected, output) + self.assertIs(self.sysmod.last_type, ValueError) + self.assertIs(type(self.sysmod.last_value), ValueError) + self.assertIs(self.sysmod.last_traceback, self.sysmod.last_value.__traceback__) + self.assertIsNotNone(self.sysmod.last_traceback) + self.assertIs(self.sysmod.last_exc, self.sysmod.last_value) def test_context_tb(self): self.infunc.side_effect = ["try: ham\nexcept: eggs\n", @@ -149,6 +286,11 @@ def test_context_tb(self): NameError: name 'eggs' is not defined """) self.assertIn(expected, output) + self.assertIs(self.sysmod.last_type, NameError) + self.assertIs(type(self.sysmod.last_value), NameError) + self.assertIs(self.sysmod.last_traceback, self.sysmod.last_value.__traceback__) + self.assertIsNotNone(self.sysmod.last_traceback) + self.assertIs(self.sysmod.last_exc, self.sysmod.last_value) if __name__ == "__main__": diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py index 5dc5b1ac..f683f069 100644 --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -2,7 +2,6 @@ import contextlib import copy import io -import locale import pickle import sys import unittest @@ -1700,16 +1699,10 @@ def test_getwriter(self): self.assertRaises(TypeError, codecs.getwriter) self.assertRaises(LookupError, codecs.getwriter, "__spam__") + @support.run_with_locale('LC_CTYPE', 'tr_TR') def test_lookup_issue1813(self): # Issue #1813: under Turkish locales, lookup of some codecs failed # because 'I' is lowercased as "ı" (dotless i) - oldlocale = locale.setlocale(locale.LC_CTYPE) - self.addCleanup(locale.setlocale, locale.LC_CTYPE, oldlocale) - try: - locale.setlocale(locale.LC_CTYPE, 'tr_TR') - except locale.Error: - # Unsupported locale on this system - self.skipTest('test needs Turkish locale') c = codecs.lookup('ASCII') self.assertEqual(c.name, 'ascii') diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 6ed7fe2b..85de2fa2 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -10,7 +10,7 @@ import textwrap import warnings from test import support -from test.support import (script_helper, requires_debug_ranges, +from test.support import (script_helper, requires_debug_ranges, run_code, requires_specialization, C_RECURSION_LIMIT) from test.support.os_helper import FakePath @@ -1065,7 +1065,7 @@ def return_genexp(): x in y) - genexp_lines = [0, 2, 0] + genexp_lines = [0, 4, 2, 0, 4] genexp_code = return_genexp.__code__.co_consts[1] code_lines = self.get_code_lines(genexp_code) @@ -1431,7 +1431,7 @@ def test_multiline_generator_expression(self): self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD', line=1, end_line=2, column=1, end_column=8, occurrence=1) self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_CONST', - line=1, end_line=6, column=0, end_column=32, occurrence=1) + line=4, end_line=4, column=7, end_column=14, occurrence=1) def test_multiline_async_generator_expression(self): snippet = textwrap.dedent("""\ @@ -1829,6 +1829,66 @@ def test_load_super_attr(self): code, "LOAD_GLOBAL", line=3, end_line=3, column=4, end_column=9 ) + def test_lambda_return_position(self): + snippets = [ + "f = lambda: x", + "f = lambda: 42", + "f = lambda: 1 + 2", + "f = lambda: a + b", + ] + for snippet in snippets: + with self.subTest(snippet=snippet): + lamb = run_code(snippet)["f"] + positions = lamb.__code__.co_positions() + # assert that all positions are within the lambda + for i, pos in enumerate(positions): + with self.subTest(i=i, pos=pos): + start_line, end_line, start_col, end_col = pos + if i == 0 and start_col == end_col == 0: + # ignore the RESUME in the beginning + continue + self.assertEqual(start_line, 1) + self.assertEqual(end_line, 1) + code_start = snippet.find(":") + 2 + code_end = len(snippet) + self.assertGreaterEqual(start_col, code_start) + self.assertLessEqual(end_col, code_end) + self.assertGreaterEqual(end_col, start_col) + self.assertLessEqual(end_col, code_end) + + def test_return_in_with_positions(self): + # See gh-98442 + def f(): + with xyz: + 1 + 2 + 3 + 4 + return R + + # All instructions should have locations on a single line + for instr in dis.get_instructions(f): + start_line, end_line, _, _ = instr.positions + self.assertEqual(start_line, end_line) + + # Expect three load None instructions for the no-exception __exit__ call, + # and one RETURN_VALUE. + # They should all have the locations of the context manager ('xyz'). + + load_none = [instr for instr in dis.get_instructions(f) if + instr.opname == 'LOAD_CONST' and instr.argval is None] + return_value = [instr for instr in dis.get_instructions(f) if + instr.opname == 'RETURN_VALUE'] + + self.assertEqual(len(load_none), 3) + self.assertEqual(len(return_value), 1) + for instr in load_none + return_value: + start_line, end_line, start_col, end_col = instr.positions + self.assertEqual(start_line, f.__code__.co_firstlineno + 1) + self.assertEqual(end_line, f.__code__.co_firstlineno + 1) + self.assertEqual(start_col, 17) + self.assertEqual(end_col, 20) + class TestExpressionStackSize(unittest.TestCase): # These tests check that the computed stack size for a code object diff --git a/Lib/test/test_compiler_codegen.py b/Lib/test/test_compiler_codegen.py index ea57df9c..a1794980 100644 --- a/Lib/test/test_compiler_codegen.py +++ b/Lib/test/test_compiler_codegen.py @@ -39,6 +39,7 @@ def test_for_loop(self): ('GET_ITER', None, 1), loop_lbl := self.Label(), ('FOR_ITER', exit_lbl := self.Label(), 1), + ('NOP', None, 1, 1), ('STORE_NAME', 1, 1), ('PUSH_NULL', None, 2), ('LOAD_NAME', 2, 2), diff --git a/Lib/test/test_complex.py b/Lib/test/test_complex.py index 3385955d..f12e1c8b 100644 --- a/Lib/test/test_complex.py +++ b/Lib/test/test_complex.py @@ -1,6 +1,7 @@ import unittest import sys from test import support +from test.support.testcase import ComplexesAreIdenticalMixin from test.test_grammar import (VALID_UNDERSCORE_LITERALS, INVALID_UNDERSCORE_LITERALS) @@ -41,7 +42,7 @@ def __init__(self, value): def __complex__(self): return self.value -class ComplexTest(unittest.TestCase): +class ComplexTest(ComplexesAreIdenticalMixin, unittest.TestCase): def assertAlmostEqual(self, a, b): if isinstance(a, complex): @@ -70,29 +71,6 @@ def assertCloseAbs(self, x, y, eps=1e-9): # check that relative difference < eps self.assertTrue(abs((x-y)/y) < eps) - def assertFloatsAreIdentical(self, x, y): - """assert that floats x and y are identical, in the sense that: - (1) both x and y are nans, or - (2) both x and y are infinities, with the same sign, or - (3) both x and y are zeros, with the same sign, or - (4) x and y are both finite and nonzero, and x == y - - """ - msg = 'floats {!r} and {!r} are not identical' - - if isnan(x) or isnan(y): - if isnan(x) and isnan(y): - return - elif x == y: - if x != 0.0: - return - # both zero; check that signs match - elif copysign(1.0, x) == copysign(1.0, y): - return - else: - msg += ': zeros have different signs' - self.fail(msg.format(x, y)) - def assertClose(self, x, y, eps=1e-9): """Return true iff complexes x and y "are close".""" self.assertCloseAbs(x.real, y.real, eps) @@ -322,6 +300,11 @@ def test_pow(self): except OverflowError: pass + # gh-113841: possible undefined division by 0 in _Py_c_pow() + x, y = 9j, 33j**3 + with self.assertRaises(OverflowError): + x**y + def test_pow_with_small_integer_exponents(self): # Check that small integer exponents are handled identically # regardless of their type. @@ -618,7 +601,7 @@ def test_underscores(self): def test_hash(self): for x in range(-30, 30): self.assertEqual(hash(x), hash(complex(x, 0))) - x /= 3.0 # now check against floating point + x /= 3.0 # now check against floating-point self.assertEqual(hash(x), hash(complex(x, 0.))) self.assertNotEqual(hash(2000005 - 1j), -1) @@ -728,8 +711,7 @@ def test_repr_roundtrip(self): for y in vals: z = complex(x, y) roundtrip = complex(repr(z)) - self.assertFloatsAreIdentical(z.real, roundtrip.real) - self.assertFloatsAreIdentical(z.imag, roundtrip.imag) + self.assertComplexesAreIdentical(z, roundtrip) # if we predefine some constants, then eval(repr(z)) should # also work, except that it might change the sign of zeros diff --git a/Lib/test/test_concurrent_futures/test_deadlock.py b/Lib/test/test_concurrent_futures/test_deadlock.py index 1db4cd00..e8cd8f67 100644 --- a/Lib/test/test_concurrent_futures/test_deadlock.py +++ b/Lib/test/test_concurrent_futures/test_deadlock.py @@ -145,7 +145,7 @@ def test_exit_at_task_unpickle(self): self._check_crash(BrokenProcessPool, id, ExitAtUnpickle()) def test_error_at_task_unpickle(self): - # gh-109832: Restore stderr overriden by _raise_error_ignore_stderr() + # gh-109832: Restore stderr overridden by _raise_error_ignore_stderr() self.addCleanup(setattr, sys, 'stderr', sys.stderr) # Check problem occurring while unpickling a task on workers @@ -183,7 +183,7 @@ def test_error_during_result_pickle_on_worker(self): self._check_crash(PicklingError, _return_instance, ErrorAtPickle) def test_error_during_result_unpickle_in_result_handler(self): - # gh-109832: Restore stderr overriden by _raise_error_ignore_stderr() + # gh-109832: Restore stderr overridden by _raise_error_ignore_stderr() self.addCleanup(setattr, sys, 'stderr', sys.stderr) # Check problem occurring while unpickling a task in diff --git a/Lib/test/test_concurrent_futures/test_thread_pool.py b/Lib/test/test_concurrent_futures/test_thread_pool.py index 812f989d..6e4a4b7c 100644 --- a/Lib/test/test_concurrent_futures/test_thread_pool.py +++ b/Lib/test/test_concurrent_futures/test_thread_pool.py @@ -64,6 +64,25 @@ def submit(pool): with futures.ProcessPoolExecutor(1, mp_context=mp.get_context('fork')) as workers: workers.submit(tuple) + @support.requires_fork() + @unittest.skipUnless(hasattr(os, 'register_at_fork'), 'need os.register_at_fork') + def test_process_fork_from_a_threadpool(self): + # bpo-43944: clear concurrent.futures.thread._threads_queues after fork, + # otherwise child process will try to join parent thread + def fork_process_and_return_exitcode(): + # Ignore the warning about fork with threads. + with self.assertWarnsRegex(DeprecationWarning, + r"use of fork\(\) may lead to deadlocks in the child"): + p = mp.get_context('fork').Process(target=lambda: 1) + p.start() + p.join() + return p.exitcode + + with futures.ThreadPoolExecutor(1) as pool: + process_exitcode = pool.submit(fork_process_and_return_exitcode).result() + + self.assertEqual(process_exitcode, 0) + def test_executor_map_current_future_cancel(self): stop_event = threading.Event() log = [] diff --git a/Lib/test/test_contextlib.py b/Lib/test/test_contextlib.py index a50a4ed7..b03ce497 100644 --- a/Lib/test/test_contextlib.py +++ b/Lib/test/test_contextlib.py @@ -434,12 +434,10 @@ class FileContextTestCase(unittest.TestCase): def testWithOpen(self): tfn = tempfile.mktemp() try: - f = None with open(tfn, "w", encoding="utf-8") as f: self.assertFalse(f.closed) f.write("Booh\n") self.assertTrue(f.closed) - f = None with self.assertRaises(ZeroDivisionError): with open(tfn, "r", encoding="utf-8") as f: self.assertFalse(f.closed) diff --git a/Lib/test/test_cprofile.py b/Lib/test/test_cprofile.py index 27e8a767..3b7fd034 100644 --- a/Lib/test/test_cprofile.py +++ b/Lib/test/test_cprofile.py @@ -30,6 +30,59 @@ def test_bad_counter_during_dealloc(self): self.assertEqual(cm.unraisable.exc_type, TypeError) + def test_crash_with_not_enough_args(self): + # gh-126220 + import _lsprof + + for profile in [_lsprof.Profiler(), cProfile.Profile()]: + for method in [ + "_pystart_callback", + "_pyreturn_callback", + "_ccall_callback", + "_creturn_callback", + ]: + with self.subTest(profile=profile, method=method): + method_obj = getattr(profile, method) + with self.assertRaises(TypeError): + method_obj() # should not crash + + def test_evil_external_timer(self): + # gh-120289 + # Disabling profiler in external timer should not crash + import _lsprof + class EvilTimer(): + def __init__(self, disable_count): + self.count = 0 + self.disable_count = disable_count + + def __call__(self): + self.count += 1 + if self.count == self.disable_count: + profiler_with_evil_timer.disable() + return self.count + + # this will trigger external timer to disable profiler at + # call event - in initContext in _lsprof.c + with support.catch_unraisable_exception() as cm: + profiler_with_evil_timer = _lsprof.Profiler(EvilTimer(1)) + profiler_with_evil_timer.enable() + # Make a call to trigger timer + (lambda: None)() + profiler_with_evil_timer.disable() + profiler_with_evil_timer.clear() + self.assertEqual(cm.unraisable.exc_type, RuntimeError) + + # this will trigger external timer to disable profiler at + # return event - in Stop in _lsprof.c + with support.catch_unraisable_exception() as cm: + profiler_with_evil_timer = _lsprof.Profiler(EvilTimer(2)) + profiler_with_evil_timer.enable() + # Make a call to trigger timer + (lambda: None)() + profiler_with_evil_timer.disable() + profiler_with_evil_timer.clear() + self.assertEqual(cm.unraisable.exc_type, RuntimeError) + def test_profile_enable_disable(self): prof = self.profilerclass() # Make sure we clean ourselves up if the test fails for some reason. @@ -83,8 +136,8 @@ def test_throw(self): for func, (cc, nc, _, _, _) in pr.stats.items(): if func[2] == "": - self.assertEqual(cc, 1) - self.assertEqual(nc, 1) + self.assertEqual(cc, 2) + self.assertEqual(nc, 2) class TestCommandLine(unittest.TestCase): diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py index adb89d0d..47ff707f 100644 --- a/Lib/test/test_csv.py +++ b/Lib/test/test_csv.py @@ -425,6 +425,8 @@ def test_read_quoting(self): quoting=csv.QUOTE_NONNUMERIC) self._read_test(['1,@,3,@,5'], [['1', ',3,', '5']], quotechar='@') self._read_test(['1,\0,3,\0,5'], [['1', ',3,', '5']], quotechar='\0') + self._read_test(['1\\.5,\\.5,.5'], [[1.5, 0.5, 0.5]], + quoting=csv.QUOTE_NONNUMERIC, escapechar='\\') def test_read_skipinitialspace(self): self._read_test(['no space, space, spaces,\ttab'], @@ -1069,6 +1071,12 @@ class mydialect(csv.Dialect): mydialect.quoting = None self.assertRaises(csv.Error, mydialect) + mydialect.quoting = 42 + with self.assertRaises(csv.Error) as cm: + mydialect() + self.assertEqual(str(cm.exception), + 'bad "quoting" value') + mydialect.doublequote = True mydialect.quoting = csv.QUOTE_ALL mydialect.quotechar = '"' diff --git a/Lib/test/test_ctypes/_support.py b/Lib/test/test_ctypes/_support.py new file mode 100644 index 00000000..e4c2b338 --- /dev/null +++ b/Lib/test/test_ctypes/_support.py @@ -0,0 +1,24 @@ +# Some classes and types are not export to _ctypes module directly. + +import ctypes +from _ctypes import Structure, Union, _Pointer, Array, _SimpleCData, CFuncPtr + + +_CData = Structure.__base__ +assert _CData.__name__ == "_CData" + +class _X(Structure): + _fields_ = [("x", ctypes.c_int)] +CField = type(_X.x) + +# metaclasses +PyCStructType = type(Structure) +UnionType = type(Union) +PyCPointerType = type(_Pointer) +PyCArrayType = type(Array) +PyCSimpleType = type(_SimpleCData) +PyCFuncPtrType = type(CFuncPtr) + +# type flags +Py_TPFLAGS_DISALLOW_INSTANTIATION = 1 << 7 +Py_TPFLAGS_IMMUTABLETYPE = 1 << 8 diff --git a/Lib/test/test_ctypes/test_arrays.py b/Lib/test/test_ctypes/test_arrays.py index 78aead26..4f5a66e3 100644 --- a/Lib/test/test_ctypes/test_arrays.py +++ b/Lib/test/test_ctypes/test_arrays.py @@ -212,7 +212,7 @@ def test_empty_element_struct(self): class EmptyStruct(Structure): _fields_ = [] - obj = (EmptyStruct * 2)() # bpo37188: Floating point exception + obj = (EmptyStruct * 2)() # bpo37188: Floating-point exception self.assertEqual(sizeof(obj), 0) def test_empty_element_array(self): @@ -220,7 +220,7 @@ class EmptyArray(Array): _type_ = c_int _length_ = 0 - obj = (EmptyArray * 2)() # bpo37188: Floating point exception + obj = (EmptyArray * 2)() # bpo37188: Floating-point exception self.assertEqual(sizeof(obj), 0) def test_bpo36504_signed_int_overflow(self): diff --git a/Lib/test/test_ctypes/test_c_simple_type_meta.py b/Lib/test/test_ctypes/test_c_simple_type_meta.py new file mode 100644 index 00000000..eb77d6d7 --- /dev/null +++ b/Lib/test/test_ctypes/test_c_simple_type_meta.py @@ -0,0 +1,152 @@ +import unittest +import ctypes +from ctypes import POINTER, c_void_p + +from ._support import PyCSimpleType + + +class PyCSimpleTypeAsMetaclassTest(unittest.TestCase): + def tearDown(self): + # to not leak references, we must clean _pointer_type_cache + ctypes._reset_cache() + + def test_creating_pointer_in_dunder_new_1(self): + # Test metaclass whose instances are C types; when the type is + # created it automatically creates a pointer type for itself. + # The pointer type is also an instance of the metaclass. + # Such an implementation is used in `IUnknown` of the `comtypes` + # project. See gh-124520. + + class ct_meta(type): + def __new__(cls, name, bases, namespace): + self = super().__new__(cls, name, bases, namespace) + + # Avoid recursion: don't set up a pointer to + # a pointer (to a pointer...) + if bases == (c_void_p,): + # When creating PtrBase itself, the name + # is not yet available + return self + if issubclass(self, PtrBase): + return self + + if bases == (object,): + ptr_bases = (self, PtrBase) + else: + ptr_bases = (self, POINTER(bases[0])) + p = p_meta(f"POINTER({self.__name__})", ptr_bases, {}) + ctypes._pointer_type_cache[self] = p + return self + + class p_meta(PyCSimpleType, ct_meta): + pass + + class PtrBase(c_void_p, metaclass=p_meta): + pass + + class CtBase(object, metaclass=ct_meta): + pass + + class Sub(CtBase): + pass + + class Sub2(Sub): + pass + + self.assertIsInstance(POINTER(Sub2), p_meta) + self.assertTrue(issubclass(POINTER(Sub2), Sub2)) + self.assertTrue(issubclass(POINTER(Sub2), POINTER(Sub))) + self.assertTrue(issubclass(POINTER(Sub), POINTER(CtBase))) + + def test_creating_pointer_in_dunder_new_2(self): + # A simpler variant of the above, used in `CoClass` of the `comtypes` + # project. + + class ct_meta(type): + def __new__(cls, name, bases, namespace): + self = super().__new__(cls, name, bases, namespace) + if isinstance(self, p_meta): + return self + p = p_meta(f"POINTER({self.__name__})", (self, c_void_p), {}) + ctypes._pointer_type_cache[self] = p + return self + + class p_meta(PyCSimpleType, ct_meta): + pass + + class Core(object): + pass + + class CtBase(Core, metaclass=ct_meta): + pass + + class Sub(CtBase): + pass + + self.assertIsInstance(POINTER(Sub), p_meta) + self.assertTrue(issubclass(POINTER(Sub), Sub)) + + def test_creating_pointer_in_dunder_init_1(self): + class ct_meta(type): + def __init__(self, name, bases, namespace): + super().__init__(name, bases, namespace) + + # Avoid recursion. + # (See test_creating_pointer_in_dunder_new_1) + if bases == (c_void_p,): + return + if issubclass(self, PtrBase): + return + if bases == (object,): + ptr_bases = (self, PtrBase) + else: + ptr_bases = (self, POINTER(bases[0])) + p = p_meta(f"POINTER({self.__name__})", ptr_bases, {}) + ctypes._pointer_type_cache[self] = p + + class p_meta(PyCSimpleType, ct_meta): + pass + + class PtrBase(c_void_p, metaclass=p_meta): + pass + + class CtBase(object, metaclass=ct_meta): + pass + + class Sub(CtBase): + pass + + class Sub2(Sub): + pass + + self.assertIsInstance(POINTER(Sub2), p_meta) + self.assertTrue(issubclass(POINTER(Sub2), Sub2)) + self.assertTrue(issubclass(POINTER(Sub2), POINTER(Sub))) + self.assertTrue(issubclass(POINTER(Sub), POINTER(CtBase))) + + def test_creating_pointer_in_dunder_init_2(self): + class ct_meta(type): + def __init__(self, name, bases, namespace): + super().__init__(name, bases, namespace) + + # Avoid recursion. + # (See test_creating_pointer_in_dunder_new_2) + if isinstance(self, p_meta): + return + p = p_meta(f"POINTER({self.__name__})", (self, c_void_p), {}) + ctypes._pointer_type_cache[self] = p + + class p_meta(PyCSimpleType, ct_meta): + pass + + class Core(object): + pass + + class CtBase(Core, metaclass=ct_meta): + pass + + class Sub(CtBase): + pass + + self.assertIsInstance(POINTER(Sub), p_meta) + self.assertTrue(issubclass(POINTER(Sub), Sub)) diff --git a/Lib/test/test_ctypes/test_win32_com_foreign_func.py b/Lib/test/test_ctypes/test_win32_com_foreign_func.py new file mode 100644 index 00000000..8d217fc1 --- /dev/null +++ b/Lib/test/test_ctypes/test_win32_com_foreign_func.py @@ -0,0 +1,286 @@ +import ctypes +import gc +import sys +import unittest +from ctypes import POINTER, byref, c_void_p +from ctypes.wintypes import BYTE, DWORD, WORD + +if sys.platform != "win32": + raise unittest.SkipTest("Windows-specific test") + + +from _ctypes import COMError, CopyComPointer +from ctypes import HRESULT + + +COINIT_APARTMENTTHREADED = 0x2 +CLSCTX_SERVER = 5 +S_OK = 0 +OUT = 2 +TRUE = 1 +E_NOINTERFACE = -2147467262 + + +class GUID(ctypes.Structure): + # https://learn.microsoft.com/en-us/windows/win32/api/guiddef/ns-guiddef-guid + _fields_ = [ + ("Data1", DWORD), + ("Data2", WORD), + ("Data3", WORD), + ("Data4", BYTE * 8), + ] + + +def create_proto_com_method(name, index, restype, *argtypes): + proto = ctypes.WINFUNCTYPE(restype, *argtypes) + + def make_method(*args): + foreign_func = proto(index, name, *args) + + def call(self, *args, **kwargs): + return foreign_func(self, *args, **kwargs) + + return call + + return make_method + + +def create_guid(name): + guid = GUID() + # https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-clsidfromstring + ole32.CLSIDFromString(name, byref(guid)) + return guid + + +def is_equal_guid(guid1, guid2): + # https://learn.microsoft.com/en-us/windows/win32/api/objbase/nf-objbase-isequalguid + return ole32.IsEqualGUID(byref(guid1), byref(guid2)) + + +ole32 = ctypes.oledll.ole32 + +IID_IUnknown = create_guid("{00000000-0000-0000-C000-000000000046}") +IID_IStream = create_guid("{0000000C-0000-0000-C000-000000000046}") +IID_IPersist = create_guid("{0000010C-0000-0000-C000-000000000046}") +CLSID_ShellLink = create_guid("{00021401-0000-0000-C000-000000000046}") + +# https://learn.microsoft.com/en-us/windows/win32/api/unknwn/nf-unknwn-iunknown-queryinterface(refiid_void) +proto_query_interface = create_proto_com_method( + "QueryInterface", 0, HRESULT, POINTER(GUID), POINTER(c_void_p) +) +# https://learn.microsoft.com/en-us/windows/win32/api/unknwn/nf-unknwn-iunknown-addref +proto_add_ref = create_proto_com_method("AddRef", 1, ctypes.c_long) +# https://learn.microsoft.com/en-us/windows/win32/api/unknwn/nf-unknwn-iunknown-release +proto_release = create_proto_com_method("Release", 2, ctypes.c_long) +# https://learn.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-ipersist-getclassid +proto_get_class_id = create_proto_com_method( + "GetClassID", 3, HRESULT, POINTER(GUID) +) + + +def create_shelllink_persist(typ): + ppst = typ() + # https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-cocreateinstance + ole32.CoCreateInstance( + byref(CLSID_ShellLink), + None, + CLSCTX_SERVER, + byref(IID_IPersist), + byref(ppst), + ) + return ppst + + +class ForeignFunctionsThatWillCallComMethodsTests(unittest.TestCase): + def setUp(self): + # https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-coinitializeex + ole32.CoInitializeEx(None, COINIT_APARTMENTTHREADED) + + def tearDown(self): + # https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-couninitialize + ole32.CoUninitialize() + gc.collect() + + def test_without_paramflags_and_iid(self): + class IUnknown(c_void_p): + QueryInterface = proto_query_interface() + AddRef = proto_add_ref() + Release = proto_release() + + class IPersist(IUnknown): + GetClassID = proto_get_class_id() + + ppst = create_shelllink_persist(IPersist) + + clsid = GUID() + hr_getclsid = ppst.GetClassID(byref(clsid)) + self.assertEqual(S_OK, hr_getclsid) + self.assertEqual(TRUE, is_equal_guid(CLSID_ShellLink, clsid)) + + self.assertEqual(2, ppst.AddRef()) + self.assertEqual(3, ppst.AddRef()) + + punk = IUnknown() + hr_qi = ppst.QueryInterface(IID_IUnknown, punk) + self.assertEqual(S_OK, hr_qi) + self.assertEqual(3, punk.Release()) + + with self.assertRaises(OSError) as e: + punk.QueryInterface(IID_IStream, IUnknown()) + self.assertEqual(E_NOINTERFACE, e.exception.winerror) + + self.assertEqual(2, ppst.Release()) + self.assertEqual(1, ppst.Release()) + self.assertEqual(0, ppst.Release()) + + def test_with_paramflags_and_without_iid(self): + class IUnknown(c_void_p): + QueryInterface = proto_query_interface(None) + AddRef = proto_add_ref() + Release = proto_release() + + class IPersist(IUnknown): + GetClassID = proto_get_class_id(((OUT, "pClassID"),)) + + ppst = create_shelllink_persist(IPersist) + + clsid = ppst.GetClassID() + self.assertEqual(TRUE, is_equal_guid(CLSID_ShellLink, clsid)) + + punk = IUnknown() + hr_qi = ppst.QueryInterface(IID_IUnknown, punk) + self.assertEqual(S_OK, hr_qi) + self.assertEqual(1, punk.Release()) + + with self.assertRaises(OSError) as e: + ppst.QueryInterface(IID_IStream, IUnknown()) + self.assertEqual(E_NOINTERFACE, e.exception.winerror) + + self.assertEqual(0, ppst.Release()) + + def test_with_paramflags_and_iid(self): + class IUnknown(c_void_p): + QueryInterface = proto_query_interface(None, IID_IUnknown) + AddRef = proto_add_ref() + Release = proto_release() + + class IPersist(IUnknown): + GetClassID = proto_get_class_id(((OUT, "pClassID"),), IID_IPersist) + + ppst = create_shelllink_persist(IPersist) + + clsid = ppst.GetClassID() + self.assertEqual(TRUE, is_equal_guid(CLSID_ShellLink, clsid)) + + punk = IUnknown() + hr_qi = ppst.QueryInterface(IID_IUnknown, punk) + self.assertEqual(S_OK, hr_qi) + self.assertEqual(1, punk.Release()) + + with self.assertRaises(COMError) as e: + ppst.QueryInterface(IID_IStream, IUnknown()) + self.assertEqual(E_NOINTERFACE, e.exception.hresult) + + self.assertEqual(0, ppst.Release()) + + +class CopyComPointerTests(unittest.TestCase): + def setUp(self): + ole32.CoInitializeEx(None, COINIT_APARTMENTTHREADED) + + class IUnknown(c_void_p): + QueryInterface = proto_query_interface(None, IID_IUnknown) + AddRef = proto_add_ref() + Release = proto_release() + + class IPersist(IUnknown): + GetClassID = proto_get_class_id(((OUT, "pClassID"),), IID_IPersist) + + self.IUnknown = IUnknown + self.IPersist = IPersist + + def tearDown(self): + ole32.CoUninitialize() + gc.collect() + + def test_both_are_null(self): + src = self.IPersist() + dst = self.IPersist() + + hr = CopyComPointer(src, byref(dst)) + + self.assertEqual(S_OK, hr) + + self.assertIsNone(src.value) + self.assertIsNone(dst.value) + + def test_src_is_nonnull_and_dest_is_null(self): + # The reference count of the COM pointer created by `CoCreateInstance` + # is initially 1. + src = create_shelllink_persist(self.IPersist) + dst = self.IPersist() + + # `CopyComPointer` calls `AddRef` explicitly in the C implementation. + # The refcount of `src` is incremented from 1 to 2 here. + hr = CopyComPointer(src, byref(dst)) + + self.assertEqual(S_OK, hr) + self.assertEqual(src.value, dst.value) + + # This indicates that the refcount was 2 before the `Release` call. + self.assertEqual(1, src.Release()) + + clsid = dst.GetClassID() + self.assertEqual(TRUE, is_equal_guid(CLSID_ShellLink, clsid)) + + self.assertEqual(0, dst.Release()) + + def test_src_is_null_and_dest_is_nonnull(self): + src = self.IPersist() + dst_orig = create_shelllink_persist(self.IPersist) + dst = self.IPersist() + CopyComPointer(dst_orig, byref(dst)) + self.assertEqual(1, dst_orig.Release()) + + clsid = dst.GetClassID() + self.assertEqual(TRUE, is_equal_guid(CLSID_ShellLink, clsid)) + + # This does NOT affects the refcount of `dst_orig`. + hr = CopyComPointer(src, byref(dst)) + + self.assertEqual(S_OK, hr) + self.assertIsNone(dst.value) + + with self.assertRaises(ValueError): + dst.GetClassID() # NULL COM pointer access + + # This indicates that the refcount was 1 before the `Release` call. + self.assertEqual(0, dst_orig.Release()) + + def test_both_are_nonnull(self): + src = create_shelllink_persist(self.IPersist) + dst_orig = create_shelllink_persist(self.IPersist) + dst = self.IPersist() + CopyComPointer(dst_orig, byref(dst)) + self.assertEqual(1, dst_orig.Release()) + + self.assertEqual(dst.value, dst_orig.value) + self.assertNotEqual(src.value, dst.value) + + hr = CopyComPointer(src, byref(dst)) + + self.assertEqual(S_OK, hr) + self.assertEqual(src.value, dst.value) + self.assertNotEqual(dst.value, dst_orig.value) + + self.assertEqual(1, src.Release()) + + clsid = dst.GetClassID() + self.assertEqual(TRUE, is_equal_guid(CLSID_ShellLink, clsid)) + + self.assertEqual(0, dst.Release()) + self.assertEqual(0, dst_orig.Release()) + + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index 83d10dd8..cc3aa561 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -1081,6 +1081,14 @@ def test_resize_term(self): self.assertEqual(curses.LINES, lines) self.assertEqual(curses.COLS, cols) + with self.assertRaises(OverflowError): + curses.resize_term(35000, 1) + with self.assertRaises(OverflowError): + curses.resize_term(1, 35000) + # GH-120378: Overflow failure in resize_term() causes refresh to fail + tmp = curses.initscr() + tmp.erase() + @requires_curses_func('resizeterm') def test_resizeterm(self): curses.update_lines_cols() @@ -1095,6 +1103,14 @@ def test_resizeterm(self): self.assertEqual(curses.LINES, lines) self.assertEqual(curses.COLS, cols) + with self.assertRaises(OverflowError): + curses.resizeterm(35000, 1) + with self.assertRaises(OverflowError): + curses.resizeterm(1, 35000) + # GH-120378: Overflow failure in resizeterm() causes refresh to fail + tmp = curses.initscr() + tmp.erase() + def test_ungetch(self): curses.ungetch(b'A') self.assertEqual(self.stdscr.getkey(), 'A') diff --git a/Lib/test/test_dataclasses/__init__.py b/Lib/test/test_dataclasses/__init__.py index e15b3457..8421cf97 100644 --- a/Lib/test/test_dataclasses/__init__.py +++ b/Lib/test/test_dataclasses/__init__.py @@ -17,6 +17,7 @@ from typing import ClassVar, Any, List, Union, Tuple, Dict, Generic, TypeVar, Optional, Protocol, DefaultDict from typing import get_type_hints from collections import deque, OrderedDict, namedtuple, defaultdict +from copy import deepcopy from functools import total_ordering import typing # Needed for the string "typing.ClassVar[int]" to work as an annotation. @@ -3071,6 +3072,48 @@ class C: with self.assertRaisesRegex(TypeError, 'unhashable type'): hash(C({})) + def test_frozen_deepcopy_without_slots(self): + # see: https://github.com/python/cpython/issues/89683 + @dataclass(frozen=True, slots=False) + class C: + s: str + + c = C('hello') + self.assertEqual(deepcopy(c), c) + + def test_frozen_deepcopy_with_slots(self): + # see: https://github.com/python/cpython/issues/89683 + with self.subTest('generated __slots__'): + @dataclass(frozen=True, slots=True) + class C: + s: str + + c = C('hello') + self.assertEqual(deepcopy(c), c) + + with self.subTest('user-defined __slots__ and no __{get,set}state__'): + @dataclass(frozen=True, slots=False) + class C: + __slots__ = ('s',) + s: str + + # with user-defined slots, __getstate__ and __setstate__ are not + # automatically added, hence the error + err = r"^cannot\ assign\ to\ field\ 's'$" + self.assertRaisesRegex(FrozenInstanceError, err, deepcopy, C('')) + + with self.subTest('user-defined __slots__ and __{get,set}state__'): + @dataclass(frozen=True, slots=False) + class C: + __slots__ = ('s',) + __getstate__ = dataclasses._dataclass_getstate + __setstate__ = dataclasses._dataclass_setstate + + s: str + + c = C('hello') + self.assertEqual(deepcopy(c), c) + class TestSlots(unittest.TestCase): def test_simple(self): @@ -3560,6 +3603,57 @@ class A(WithDictSlot): ... self.assertEqual(A().__dict__, {}) A() + @support.cpython_only + def test_dataclass_slot_dict_ctype(self): + # https://github.com/python/cpython/issues/123935 + from test.support import import_helper + # Skips test if `_testcapi` is not present: + _testcapi = import_helper.import_module('_testcapi') + + @dataclass(slots=True) + class HasDictOffset(_testcapi.HeapCTypeWithDict): + __dict__: dict = {} + self.assertNotEqual(_testcapi.HeapCTypeWithDict.__dictoffset__, 0) + self.assertEqual(HasDictOffset.__slots__, ()) + + @dataclass(slots=True) + class DoesNotHaveDictOffset(_testcapi.HeapCTypeWithWeakref): + __dict__: dict = {} + self.assertEqual(_testcapi.HeapCTypeWithWeakref.__dictoffset__, 0) + self.assertEqual(DoesNotHaveDictOffset.__slots__, ('__dict__',)) + + @support.cpython_only + def test_slots_with_wrong_init_subclass(self): + # TODO: This test is for a kinda-buggy behavior. + # Ideally, it should be fixed and `__init_subclass__` + # should be fully supported in the future versions. + # See https://github.com/python/cpython/issues/91126 + class WrongSuper: + def __init_subclass__(cls, arg): + pass + + with self.assertRaisesRegex( + TypeError, + "missing 1 required positional argument: 'arg'", + ): + @dataclass(slots=True) + class WithWrongSuper(WrongSuper, arg=1): + pass + + class CorrectSuper: + args = [] + def __init_subclass__(cls, arg="default"): + cls.args.append(arg) + + @dataclass(slots=True) + class WithCorrectSuper(CorrectSuper): + pass + + # __init_subclass__ is called twice: once for `WithCorrectSuper` + # and once for `WithCorrectSuper__slots__` new class + # that we create internally. + self.assertEqual(CorrectSuper.args, ["default", "default"]) + class TestDescriptors(unittest.TestCase): def test_set_name(self): diff --git a/Lib/test/test_datetime.py b/Lib/test/test_datetime.py index 3859733a..005187f1 100644 --- a/Lib/test/test_datetime.py +++ b/Lib/test/test_datetime.py @@ -1,5 +1,6 @@ import unittest import sys +import functools from test.support.import_helper import import_fresh_module @@ -39,21 +40,26 @@ def load_tests(loader, tests, pattern): for cls in test_classes: cls.__name__ += suffix cls.__qualname__ += suffix - @classmethod - def setUpClass(cls_, module=module): - cls_._save_sys_modules = sys.modules.copy() - sys.modules[TESTS] = module - sys.modules['datetime'] = module.datetime_module - if hasattr(module, '_pydatetime'): - sys.modules['_pydatetime'] = module._pydatetime - sys.modules['_strptime'] = module._strptime - @classmethod - def tearDownClass(cls_): - sys.modules.clear() - sys.modules.update(cls_._save_sys_modules) - cls.setUpClass = setUpClass - cls.tearDownClass = tearDownClass - tests.addTests(loader.loadTestsFromTestCase(cls)) + + @functools.wraps(cls, updated=()) + class Wrapper(cls): + @classmethod + def setUpClass(cls_, module=module): + cls_._save_sys_modules = sys.modules.copy() + sys.modules[TESTS] = module + sys.modules['datetime'] = module.datetime_module + if hasattr(module, '_pydatetime'): + sys.modules['_pydatetime'] = module._pydatetime + sys.modules['_strptime'] = module._strptime + super().setUpClass() + + @classmethod + def tearDownClass(cls_): + super().tearDownClass() + sys.modules.clear() + sys.modules.update(cls_._save_sys_modules) + + tests.addTests(loader.loadTestsFromTestCase(Wrapper)) return tests diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py index 36d4157c..2ec12439 100644 --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -1242,7 +1242,7 @@ def get_fmt(x, override=None, fmt='n'): self.assertEqual(get_fmt(Decimal('-1.5'), dotsep_wide, '020n'), '-0\u00b4000\u00b4000\u00b4000\u00b4001\u00bf5') - @run_with_locale('LC_ALL', 'ps_AF') + @run_with_locale('LC_ALL', 'ps_AF', '') def test_wide_char_separator_decimal_point(self): # locale with wide char separator and decimal point Decimal = self.decimal.Decimal @@ -2060,7 +2060,9 @@ def test_tonum_methods(self): #to quantize, which is already extensively tested test_triples = [ ('123.456', -4, '0E+4'), + ('-123.456', -4, '-0E+4'), ('123.456', -3, '0E+3'), + ('-123.456', -3, '-0E+3'), ('123.456', -2, '1E+2'), ('123.456', -1, '1.2E+2'), ('123.456', 0, '123'), diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py index fbc6ce82..dfe17d47 100644 --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -1476,6 +1476,24 @@ def test_dict_items_result_gc_reversed(self): gc.collect() self.assertTrue(gc.is_tracked(next(it))) + def test_store_evilattr(self): + class EvilAttr: + def __init__(self, d): + self.d = d + + def __del__(self): + if 'attr' in self.d: + del self.d['attr'] + gc.collect() + + class Obj: + pass + + obj = Obj() + obj.__dict__ = {} + for _ in range(10): + obj.attr = EvilAttr(obj.__dict__) + def test_str_nonstr(self): # cpython uses a different lookup function if the dict only contains # `str` keys. Make sure the unoptimized path is used when a non-`str` diff --git a/Lib/test/test_dictcomps.py b/Lib/test/test_dictcomps.py index 472e3dfa..26b56dac 100644 --- a/Lib/test/test_dictcomps.py +++ b/Lib/test/test_dictcomps.py @@ -1,5 +1,8 @@ +import traceback import unittest +from test.support import BrokenIter + # For scope testing. g = "Global variable" @@ -127,6 +130,41 @@ def test_star_expression(self): self.assertEqual({i: i*i for i in [*range(4)]}, expected) self.assertEqual({i: i*i for i in (*range(4),)}, expected) + def test_exception_locations(self): + # The location of an exception raised from __init__ or + # __next__ should should be the iterator expression + def init_raises(): + try: + {x:x for x in BrokenIter(init_raises=True)} + except Exception as e: + return e + + def next_raises(): + try: + {x:x for x in BrokenIter(next_raises=True)} + except Exception as e: + return e + + def iter_raises(): + try: + {x:x for x in BrokenIter(iter_raises=True)} + except Exception as e: + return e + + for func, expected in [(init_raises, "BrokenIter(init_raises=True)"), + (next_raises, "BrokenIter(next_raises=True)"), + (iter_raises, "BrokenIter(iter_raises=True)"), + ]: + with self.subTest(func): + exc = func() + f = traceback.extract_tb(exc.__traceback__)[0] + indent = 16 + co = func.__code__ + self.assertEqual(f.lineno, co.co_firstlineno + 2) + self.assertEqual(f.end_lineno, co.co_firstlineno + 2) + self.assertEqual(f.line[f.colno - indent : f.end_colno - indent], + expected) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py index fc8d8797..ef8aa0d5 100644 --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -16,6 +16,7 @@ import email import email.policy +import email.utils from email.charset import Charset from email.generator import Generator, DecodedGenerator, BytesGenerator @@ -3352,15 +3353,137 @@ def test_getaddresses_comma_in_name(self): ], ) + def test_parsing_errors(self): + """Test for parsing errors from CVE-2023-27043 and CVE-2019-16056""" + alice = 'alice@example.org' + bob = 'bob@example.com' + empty = ('', '') + + # Test utils.getaddresses() and utils.parseaddr() on malformed email + # addresses: default behavior (strict=True) rejects malformed address, + # and strict=False which tolerates malformed address. + for invalid_separator, expected_non_strict in ( + ('(', [(f'<{bob}>', alice)]), + (')', [('', alice), empty, ('', bob)]), + ('<', [('', alice), empty, ('', bob), empty]), + ('>', [('', alice), empty, ('', bob)]), + ('[', [('', f'{alice}[<{bob}>]')]), + (']', [('', alice), empty, ('', bob)]), + ('@', [empty, empty, ('', bob)]), + (';', [('', alice), empty, ('', bob)]), + (':', [('', alice), ('', bob)]), + ('.', [('', alice + '.'), ('', bob)]), + ('"', [('', alice), ('', f'<{bob}>')]), + ): + address = f'{alice}{invalid_separator}<{bob}>' + with self.subTest(address=address): + self.assertEqual(utils.getaddresses([address]), + [empty]) + self.assertEqual(utils.getaddresses([address], strict=False), + expected_non_strict) + + self.assertEqual(utils.parseaddr([address]), + empty) + self.assertEqual(utils.parseaddr([address], strict=False), + ('', address)) + + # Comma (',') is treated differently depending on strict parameter. + # Comma without quotes. + address = f'{alice},<{bob}>' + self.assertEqual(utils.getaddresses([address]), + [('', alice), ('', bob)]) + self.assertEqual(utils.getaddresses([address], strict=False), + [('', alice), ('', bob)]) + self.assertEqual(utils.parseaddr([address]), + empty) + self.assertEqual(utils.parseaddr([address], strict=False), + ('', address)) + + # Real name between quotes containing comma. + address = '"Alice, alice@example.org" ' + expected_strict = ('Alice, alice@example.org', 'bob@example.com') + self.assertEqual(utils.getaddresses([address]), [expected_strict]) + self.assertEqual(utils.getaddresses([address], strict=False), [expected_strict]) + self.assertEqual(utils.parseaddr([address]), expected_strict) + self.assertEqual(utils.parseaddr([address], strict=False), + ('', address)) + + # Valid parenthesis in comments. + address = 'alice@example.org (Alice)' + expected_strict = ('Alice', 'alice@example.org') + self.assertEqual(utils.getaddresses([address]), [expected_strict]) + self.assertEqual(utils.getaddresses([address], strict=False), [expected_strict]) + self.assertEqual(utils.parseaddr([address]), expected_strict) + self.assertEqual(utils.parseaddr([address], strict=False), + ('', address)) + + # Invalid parenthesis in comments. + address = 'alice@example.org )Alice(' + self.assertEqual(utils.getaddresses([address]), [empty]) + self.assertEqual(utils.getaddresses([address], strict=False), + [('', 'alice@example.org'), ('', ''), ('', 'Alice')]) + self.assertEqual(utils.parseaddr([address]), empty) + self.assertEqual(utils.parseaddr([address], strict=False), + ('', address)) + + # Two addresses with quotes separated by comma. + address = '"Jane Doe" , "John Doe" ' + self.assertEqual(utils.getaddresses([address]), + [('Jane Doe', 'jane@example.net'), + ('John Doe', 'john@example.net')]) + self.assertEqual(utils.getaddresses([address], strict=False), + [('Jane Doe', 'jane@example.net'), + ('John Doe', 'john@example.net')]) + self.assertEqual(utils.parseaddr([address]), empty) + self.assertEqual(utils.parseaddr([address], strict=False), + ('', address)) + + # Test email.utils.supports_strict_parsing attribute + self.assertEqual(email.utils.supports_strict_parsing, True) + def test_getaddresses_nasty(self): - eq = self.assertEqual - eq(utils.getaddresses(['foo: ;']), [('', '')]) - eq(utils.getaddresses( - ['[]*-- =~$']), - [('', ''), ('', ''), ('', '*--')]) - eq(utils.getaddresses( - ['foo: ;', '"Jason R. Mastaler" ']), - [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')]) + for addresses, expected in ( + (['"Sürname, Firstname" '], + [('Sürname, Firstname', 'to@example.com')]), + + (['foo: ;'], + [('', '')]), + + (['foo: ;', '"Jason R. Mastaler" '], + [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')]), + + ([r'Pete(A nice \) chap) '], + [('Pete (A nice ) chap his account his host)', 'pete@silly.test')]), + + (['(Empty list)(start)Undisclosed recipients :(nobody(I know))'], + [('', '')]), + + (['Mary <@machine.tld:mary@example.net>, , jdoe@test . example'], + [('Mary', 'mary@example.net'), ('', ''), ('', 'jdoe@test.example')]), + + (['John Doe '], + [('John Doe (comment)', 'jdoe@machine.example')]), + + (['"Mary Smith: Personal Account" '], + [('Mary Smith: Personal Account', 'smith@home.example')]), + + (['Undisclosed recipients:;'], + [('', '')]), + + ([r', "Giant; \"Big\" Box" '], + [('', 'boss@nil.test'), ('Giant; "Big" Box', 'bob@example.net')]), + ): + with self.subTest(addresses=addresses): + self.assertEqual(utils.getaddresses(addresses), + expected) + self.assertEqual(utils.getaddresses(addresses, strict=False), + expected) + + addresses = ['[]*-- =~$'] + self.assertEqual(utils.getaddresses(addresses), + [('', '')]) + self.assertEqual(utils.getaddresses(addresses, strict=False), + [('', ''), ('', ''), ('', '*--')]) def test_getaddresses_embedded_comment(self): """Test proper handling of a nested comment""" @@ -3551,6 +3674,54 @@ def test_mime_classes_policy_argument(self): m = cls(*constructor, policy=email.policy.default) self.assertIs(m.policy, email.policy.default) + def test_iter_escaped_chars(self): + self.assertEqual(list(utils._iter_escaped_chars(r'a\\b\"c\\"d')), + [(0, 'a'), + (2, '\\\\'), + (3, 'b'), + (5, '\\"'), + (6, 'c'), + (8, '\\\\'), + (9, '"'), + (10, 'd')]) + self.assertEqual(list(utils._iter_escaped_chars('a\\')), + [(0, 'a'), (1, '\\')]) + + def test_strip_quoted_realnames(self): + def check(addr, expected): + self.assertEqual(utils._strip_quoted_realnames(addr), expected) + + check('"Jane Doe" , "John Doe" ', + ' , ') + check(r'"Jane \"Doe\"." ', + ' ') + + # special cases + check(r'before"name"after', 'beforeafter') + check(r'before"name"', 'before') + check(r'b"name"', 'b') # single char + check(r'"name"after', 'after') + check(r'"name"a', 'a') # single char + check(r'"name"', '') + + # no change + for addr in ( + 'Jane Doe , John Doe ', + 'lone " quote', + ): + self.assertEqual(utils._strip_quoted_realnames(addr), addr) + + + def test_check_parenthesis(self): + addr = 'alice@example.net' + self.assertTrue(utils._check_parenthesis(f'{addr} (Alice)')) + self.assertFalse(utils._check_parenthesis(f'{addr} )Alice(')) + self.assertFalse(utils._check_parenthesis(f'{addr} (Alice))')) + self.assertFalse(utils._check_parenthesis(f'{addr} ((Alice)')) + + # Ignore real name between quotes + self.assertTrue(utils._check_parenthesis(f'")Alice((" {addr}')) + # Test the iterator/generators class TestIterators(TestEmailBase): diff --git a/Lib/test/test_email/test_generator.py b/Lib/test/test_email/test_generator.py index bfff1051..c75a842c 100644 --- a/Lib/test/test_email/test_generator.py +++ b/Lib/test/test_email/test_generator.py @@ -6,6 +6,7 @@ from email.generator import Generator, BytesGenerator from email.headerregistry import Address from email import policy +import email.errors from test.test_email import TestEmailBase, parameterize @@ -249,6 +250,44 @@ def test_rfc2231_wrapping_switches_to_default_len_if_too_narrow(self): g.flatten(msg) self.assertEqual(s.getvalue(), self.typ(expected)) + def test_keep_encoded_newlines(self): + msg = self.msgmaker(self.typ(textwrap.dedent("""\ + To: nobody + Subject: Bad subject=?UTF-8?Q?=0A?=Bcc: injection@example.com + + None + """))) + expected = textwrap.dedent("""\ + To: nobody + Subject: Bad subject=?UTF-8?Q?=0A?=Bcc: injection@example.com + + None + """) + s = self.ioclass() + g = self.genclass(s, policy=self.policy.clone(max_line_length=80)) + g.flatten(msg) + self.assertEqual(s.getvalue(), self.typ(expected)) + + def test_keep_long_encoded_newlines(self): + msg = self.msgmaker(self.typ(textwrap.dedent("""\ + To: nobody + Subject: Bad subject=?UTF-8?Q?=0A?=Bcc: injection@example.com + + None + """))) + expected = textwrap.dedent("""\ + To: nobody + Subject: Bad subject + =?utf-8?q?=0A?=Bcc: + injection@example.com + + None + """) + s = self.ioclass() + g = self.genclass(s, policy=self.policy.clone(max_line_length=30)) + g.flatten(msg) + self.assertEqual(s.getvalue(), self.typ(expected)) + class TestGenerator(TestGeneratorBase, TestEmailBase): @@ -273,6 +312,29 @@ def test_flatten_unicode_linesep(self): g.flatten(msg) self.assertEqual(s.getvalue(), self.typ(expected)) + def test_verify_generated_headers(self): + """gh-121650: by default the generator prevents header injection""" + class LiteralHeader(str): + name = 'Header' + def fold(self, **kwargs): + return self + + for text in ( + 'Value\r\nBad Injection\r\n', + 'NoNewLine' + ): + with self.subTest(text=text): + message = message_from_string( + "Header: Value\r\n\r\nBody", + policy=self.policy, + ) + + del message['Header'] + message['Header'] = LiteralHeader(text) + + with self.assertRaises(email.errors.HeaderWriteError): + message.as_string() + class TestBytesGenerator(TestGeneratorBase, TestEmailBase): @@ -294,6 +356,19 @@ def test_defaults_handle_spaces_between_encoded_words_when_folded(self): g.flatten(msg) self.assertEqual(s.getvalue(), expected) + def test_defaults_handle_spaces_when_encoded_words_is_folded_in_middle(self): + source = ('A very long long long long long long long long long long long long ' + 'long long long long long long long long long long long súmmäry') + expected = ('Subject: A very long long long long long long long long long long long long\n' + ' long long long long long long long long long long long =?utf-8?q?s=C3=BAmm?=\n' + ' =?utf-8?q?=C3=A4ry?=\n\n').encode('ascii') + msg = EmailMessage() + msg['Subject'] = source + s = io.BytesIO() + g = BytesGenerator(s) + g.flatten(msg) + self.assertEqual(s.getvalue(), expected) + def test_defaults_handle_spaces_at_start_of_subject(self): source = " Уведомление" expected = b"Subject: =?utf-8?b?0KPQstC10LTQvtC80LvQtdC90LjQtQ==?=\n\n" diff --git a/Lib/test/test_email/test_message.py b/Lib/test/test_email/test_message.py index 034f7626..96979db2 100644 --- a/Lib/test/test_email/test_message.py +++ b/Lib/test/test_email/test_message.py @@ -1,6 +1,6 @@ -import unittest import textwrap -from email import policy, message_from_string +import unittest +from email import message_from_bytes, message_from_string, policy from email.message import EmailMessage, MIMEPart from test.test_email import TestEmailBase, parameterize @@ -958,6 +958,52 @@ def test_folding_with_utf8_encoding_8(self): b'123456789-123456789\n 123456789 Hello ' b'=?utf-8?q?W=C3=B6rld!?= 123456789 123456789\n\n') + def test_folding_with_short_nospace_1(self): + # bpo-36520 + # + # Fold a line that contains a long whitespace after + # the fold point. + + m = EmailMessage(policy.default) + m['Message-ID'] = '123456789' * 3 + parsed_msg = message_from_bytes(m.as_bytes(), policy=policy.default) + self.assertEqual(parsed_msg['Message-ID'], m['Message-ID']) + + def test_folding_with_long_nospace_default_policy_1(self): + # Fixed: https://github.com/python/cpython/issues/124452 + # + # When the value is too long, it should be converted back + # to its original form without any modifications. + + m = EmailMessage(policy.default) + message = '123456789' * 10 + m['Message-ID'] = message + self.assertEqual(m.as_bytes(), + f'Message-ID:\n {message}\n\n'.encode()) + parsed_msg = message_from_bytes(m.as_bytes(), policy=policy.default) + self.assertEqual(parsed_msg['Message-ID'], m['Message-ID']) + + def test_folding_with_long_nospace_compat32_policy_1(self): + m = EmailMessage(policy.compat32) + message = '123456789' * 10 + m['Message-ID'] = message + parsed_msg = message_from_bytes(m.as_bytes(), policy=policy.default) + self.assertEqual(parsed_msg['Message-ID'], m['Message-ID']) + + def test_folding_with_long_nospace_smtp_policy_1(self): + m = EmailMessage(policy.SMTP) + message = '123456789' * 10 + m['Message-ID'] = message + parsed_msg = message_from_bytes(m.as_bytes(), policy=policy.default) + self.assertEqual(parsed_msg['Message-ID'], m['Message-ID']) + + def test_folding_with_long_nospace_http_policy_1(self): + m = EmailMessage(policy.HTTP) + message = '123456789' * 10 + m['Message-ID'] = message + parsed_msg = message_from_bytes(m.as_bytes(), policy=policy.default) + self.assertEqual(parsed_msg['Message-ID'], m['Message-ID']) + def test_get_body_malformed(self): """test for bpo-42892""" msg = textwrap.dedent("""\ diff --git a/Lib/test/test_email/test_policy.py b/Lib/test/test_email/test_policy.py index c6b9c80e..baa35fd6 100644 --- a/Lib/test/test_email/test_policy.py +++ b/Lib/test/test_email/test_policy.py @@ -26,6 +26,7 @@ class PolicyAPITests(unittest.TestCase): 'raise_on_defect': False, 'mangle_from_': True, 'message_factory': None, + 'verify_generated_headers': True, } # These default values are the ones set on email.policy.default. # If any of these defaults change, the docs must be updated. @@ -294,6 +295,31 @@ def test_short_maxlen_error(self): with self.assertRaises(email.errors.HeaderParseError): policy.fold("Subject", subject) + def test_verify_generated_headers(self): + """Turning protection off allows header injection""" + policy = email.policy.default.clone(verify_generated_headers=False) + for text in ( + 'Header: Value\r\nBad: Injection\r\n', + 'Header: NoNewLine' + ): + with self.subTest(text=text): + message = email.message_from_string( + "Header: Value\r\n\r\nBody", + policy=policy, + ) + class LiteralHeader(str): + name = 'Header' + def fold(self, **kwargs): + return self + + del message['Header'] + message['Header'] = LiteralHeader(text) + + self.assertEqual( + message.as_string(), + f"{text}\nBody", + ) + # XXX: Need subclassing tests. # For adding subclassed objects, make sure the usual rules apply (subclass # wins), but that the order still works (right overrides left). diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index 24617ab2..13713cf3 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -5,6 +5,7 @@ from collections import namedtuple import contextlib +import io import json import os import os.path @@ -389,6 +390,70 @@ def test_ucnhash_capi_reset(self): out, err = self.run_embedded_interpreter("test_repeated_init_exec", code) self.assertEqual(out, '9\n' * INIT_LOOPS) + def test_static_types_inherited_slots(self): + script = textwrap.dedent(""" + import test.support + + results = {} + def add(cls, slot, own): + value = getattr(cls, slot) + try: + subresults = results[cls.__name__] + except KeyError: + subresults = results[cls.__name__] = {} + subresults[slot] = [repr(value), own] + + for cls in test.support.iter_builtin_types(): + for slot, own in test.support.iter_slot_wrappers(cls): + add(cls, slot, own) + """) + + ns = {} + exec(script, ns, ns) + all_expected = ns['results'] + del ns + + script += textwrap.dedent(""" + import json + import sys + text = json.dumps(results) + print(text, file=sys.stderr) + """) + out, err = self.run_embedded_interpreter( + "test_repeated_init_exec", script, script) + results = err.split('--- Loop #')[1:] + results = [res.rpartition(' ---\n')[-1] for res in results] + + self.maxDiff = None + for i, text in enumerate(results, start=1): + result = json.loads(text) + for classname, expected in all_expected.items(): + with self.subTest(loop=i, cls=classname): + slots = result.pop(classname) + self.assertEqual(slots, expected) + self.assertEqual(result, {}) + self.assertEqual(out, '') + + def test_getargs_reset_static_parser(self): + # Test _PyArg_Parser initializations via _PyArg_UnpackKeywords() + # https://github.com/python/cpython/issues/122334 + code = textwrap.dedent(""" + try: + import _ssl + except ModuleNotFoundError: + _ssl = None + if _ssl is not None: + _ssl.txt2obj(txt='1.3') + print('1') + + import _queue + _queue.SimpleQueue().put_nowait(item=None) + print('2') + """) + out, err = self.run_embedded_interpreter("test_repeated_init_exec", code) + self.assertEqual(out, '1\n2\n' * INIT_LOOPS) + + class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): maxDiff = 4096 UTF8_MODE_ERRORS = ('surrogatepass' if MS_WINDOWS else 'surrogateescape') diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index ccba0f91..2e50ae0f 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -1455,6 +1455,27 @@ class SpamEnum(Enum): spam = nonmember(SpamEnumIsInner) self.assertTrue(SpamEnum.spam is SpamEnumIsInner) + def test_using_members_as_nonmember(self): + class Example(Flag): + A = 1 + B = 2 + ALL = nonmember(A | B) + + self.assertEqual(Example.A.value, 1) + self.assertEqual(Example.B.value, 2) + self.assertEqual(Example.ALL, 3) + self.assertIs(type(Example.ALL), int) + + class Example(Flag): + A = auto() + B = auto() + ALL = nonmember(A | B) + + self.assertEqual(Example.A.value, 1) + self.assertEqual(Example.B.value, 2) + self.assertEqual(Example.ALL, 3) + self.assertIs(type(Example.ALL), int) + def test_nested_classes_in_enum_with_member(self): """Support locally-defined nested classes.""" class Outer(Enum): @@ -1831,6 +1852,25 @@ def test_wrong_inheritance_order(self): class Wrong(Enum, str): NotHere = 'error before this point' + def test_raise_custom_error_on_creation(self): + class InvalidRgbColorError(ValueError): + def __init__(self, r, g, b): + self.r = r + self.g = g + self.b = b + super().__init__(f'({r}, {g}, {b}) is not a valid RGB color') + + with self.assertRaises(InvalidRgbColorError): + class RgbColor(Enum): + RED = (255, 0, 0) + GREEN = (0, 255, 0) + BLUE = (0, 0, 255) + INVALID = (256, 0, 0) + + def __init__(self, r, g, b): + if not all(0 <= val <= 255 for val in (r, g, b)): + raise InvalidRgbColorError(r, g, b) + def test_intenum_transitivity(self): class number(IntEnum): one = 1 @@ -5136,7 +5176,7 @@ def test_convert_value_lookup_priority(self): filter=lambda x: x.startswith('CONVERT_TEST_')) # We don't want the reverse lookup value to vary when there are # multiple possible names for a given value. It should always - # report the first lexigraphical name in that case. + # report the first lexicographical name in that case. self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A') def test_convert_int(self): diff --git a/Lib/test/test_eof.py b/Lib/test/test_eof.py index be4fd73b..e3773834 100644 --- a/Lib/test/test_eof.py +++ b/Lib/test/test_eof.py @@ -1,6 +1,7 @@ """test script for a few new invalid token catches""" import sys +from codecs import BOM_UTF8 from test import support from test.support import os_helper from test.support import script_helper @@ -11,67 +12,158 @@ class EOFTestCase(unittest.TestCase): def test_EOF_single_quote(self): expect = "unterminated string literal (detected at line 1) (, line 1)" for quote in ("'", "\""): - try: + with self.assertRaises(SyntaxError) as cm: eval(f"""{quote}this is a test\ """) - except SyntaxError as msg: - self.assertEqual(str(msg), expect) - self.assertEqual(msg.offset, 1) - else: - raise support.TestFailed + self.assertEqual(str(cm.exception), expect) + self.assertEqual(cm.exception.offset, 1) def test_EOFS(self): - expect = ("unterminated triple-quoted string literal (detected at line 1) (, line 1)") - try: - eval("""'''this is a test""") - except SyntaxError as msg: - self.assertEqual(str(msg), expect) - self.assertEqual(msg.offset, 1) - else: - raise support.TestFailed + expect = ("unterminated triple-quoted string literal (detected at line 3) (, line 1)") + with self.assertRaises(SyntaxError) as cm: + eval("""ä = '''thîs is \na \ntest""") + self.assertEqual(str(cm.exception), expect) + self.assertEqual(cm.exception.text, "ä = '''thîs is ") + self.assertEqual(cm.exception.offset, 5) + + with self.assertRaises(SyntaxError) as cm: + eval("""ä = '''thîs is \na \ntest""".encode()) + self.assertEqual(str(cm.exception), expect) + self.assertEqual(cm.exception.text, "ä = '''thîs is ") + self.assertEqual(cm.exception.offset, 5) + + with self.assertRaises(SyntaxError) as cm: + eval(BOM_UTF8 + """ä = '''thîs is \na \ntest""".encode()) + self.assertEqual(str(cm.exception), expect) + self.assertEqual(cm.exception.text, "ä = '''thîs is ") + self.assertEqual(cm.exception.offset, 5) + + with self.assertRaises(SyntaxError) as cm: + eval("""# coding: latin1\nä = '''thîs is \na \ntest""".encode('latin1')) + self.assertEqual(str(cm.exception), "unterminated triple-quoted string literal (detected at line 4) (, line 2)") + self.assertEqual(cm.exception.text, "ä = '''thîs is ") + self.assertEqual(cm.exception.offset, 5) def test_EOFS_with_file(self): expect = ("(, line 1)") with os_helper.temp_dir() as temp_dir: - file_name = script_helper.make_script(temp_dir, 'foo', """'''this is \na \ntest""") - rc, out, err = script_helper.assert_python_failure(file_name) - self.assertIn(b'unterminated triple-quoted string literal (detected at line 3)', err) + file_name = script_helper.make_script(temp_dir, 'foo', + """ä = '''thîs is \na \ntest""") + rc, out, err = script_helper.assert_python_failure('-X', 'utf8', file_name) + err = err.decode().splitlines() + self.assertEqual(err[-3:], [ + " ä = '''thîs is ", + ' ^', + 'SyntaxError: unterminated triple-quoted string literal (detected at line 3)']) + + file_name = script_helper.make_script(temp_dir, 'foo', + """ä = '''thîs is \na \ntest""".encode()) + rc, out, err = script_helper.assert_python_failure('-X', 'utf8', file_name) + err = err.decode().splitlines() + self.assertEqual(err[-3:], [ + " ä = '''thîs is ", + ' ^', + 'SyntaxError: unterminated triple-quoted string literal (detected at line 3)']) + + file_name = script_helper.make_script(temp_dir, 'foo', + BOM_UTF8 + """ä = '''thîs is \na \ntest""".encode()) + rc, out, err = script_helper.assert_python_failure('-X', 'utf8', file_name) + err = err.decode().splitlines() + self.assertEqual(err[-3:], [ + " ä = '''thîs is ", + ' ^', + 'SyntaxError: unterminated triple-quoted string literal (detected at line 3)']) + + file_name = script_helper.make_script(temp_dir, 'foo', + """# coding: latin1\nä = '''thîs is \na \ntest""".encode('latin1')) + rc, out, err = script_helper.assert_python_failure('-X', 'utf8', file_name) + err = err.decode().splitlines() + self.assertEqual(err[-3:], [ + " ä = '''thîs is ", + ' ^', + 'SyntaxError: unterminated triple-quoted string literal (detected at line 4)']) @warnings_helper.ignore_warnings(category=SyntaxWarning) def test_eof_with_line_continuation(self): expect = "unexpected EOF while parsing (, line 1)" - try: + with self.assertRaises(SyntaxError) as cm: compile('"\\Xhh" \\', '', 'exec') - except SyntaxError as msg: - self.assertEqual(str(msg), expect) - else: - raise support.TestFailed + self.assertEqual(str(cm.exception), expect) def test_line_continuation_EOF(self): """A continuation at the end of input must be an error; bpo2180.""" expect = 'unexpected EOF while parsing (, line 1)' - with self.assertRaises(SyntaxError) as excinfo: - exec('x = 5\\') - self.assertEqual(str(excinfo.exception), expect) - with self.assertRaises(SyntaxError) as excinfo: + with self.assertRaises(SyntaxError) as cm: + exec('ä = 5\\') + self.assertEqual(str(cm.exception), expect) + self.assertEqual(cm.exception.text, 'ä = 5\\\n') + self.assertEqual(cm.exception.offset, 7) + + with self.assertRaises(SyntaxError) as cm: + exec('ä = 5\\'.encode()) + self.assertEqual(str(cm.exception), expect) + self.assertEqual(cm.exception.text, 'ä = 5\\\n') + self.assertEqual(cm.exception.offset, 7) + + with self.assertRaises(SyntaxError) as cm: + exec('# coding:latin1\nä = 5\\'.encode('latin1')) + self.assertEqual(str(cm.exception), + 'unexpected EOF while parsing (, line 2)') + self.assertEqual(cm.exception.text, 'ä = 5\\\n') + self.assertEqual(cm.exception.offset, 7) + + with self.assertRaises(SyntaxError) as cm: + exec(BOM_UTF8 + 'ä = 5\\'.encode()) + self.assertEqual(str(cm.exception), expect) + self.assertEqual(cm.exception.text, 'ä = 5\\\n') + self.assertEqual(cm.exception.offset, 7) + + with self.assertRaises(SyntaxError) as cm: exec('\\') - self.assertEqual(str(excinfo.exception), expect) + self.assertEqual(str(cm.exception), expect) @unittest.skipIf(not sys.executable, "sys.executable required") def test_line_continuation_EOF_from_file_bpo2180(self): """Ensure tok_nextc() does not add too many ending newlines.""" with os_helper.temp_dir() as temp_dir: file_name = script_helper.make_script(temp_dir, 'foo', '\\') - rc, out, err = script_helper.assert_python_failure(file_name) - self.assertIn(b'unexpected EOF while parsing', err) - self.assertIn(b'line 1', err) - self.assertIn(b'\\', err) - - file_name = script_helper.make_script(temp_dir, 'foo', 'y = 6\\') - rc, out, err = script_helper.assert_python_failure(file_name) - self.assertIn(b'unexpected EOF while parsing', err) - self.assertIn(b'line 1', err) - self.assertIn(b'y = 6\\', err) + rc, out, err = script_helper.assert_python_failure('-X', 'utf8', file_name) + err = err.decode().splitlines() + self.assertEqual(err[-2:], [ + ' \\', + 'SyntaxError: unexpected EOF while parsing']) + self.assertEqual(err[-3][-8:], ', line 1', err) + + file_name = script_helper.make_script(temp_dir, 'foo', 'ä = 6\\') + rc, out, err = script_helper.assert_python_failure('-X', 'utf8', file_name) + err = err.decode().splitlines() + self.assertEqual(err[-3:], [ + ' ä = 6\\', + ' ^', + 'SyntaxError: unexpected EOF while parsing']) + self.assertEqual(err[-4][-8:], ', line 1', err) + + file_name = script_helper.make_script(temp_dir, 'foo', + '# coding:latin1\n' + 'ä = 7\\'.encode('latin1')) + rc, out, err = script_helper.assert_python_failure('-X', 'utf8', file_name) + err = err.decode().splitlines() + self.assertEqual(err[-3:], [ + ' ä = 7\\', + ' ^', + 'SyntaxError: unexpected EOF while parsing']) + self.assertEqual(err[-4][-8:], ', line 2', err) + + file_name = script_helper.make_script(temp_dir, 'foo', + BOM_UTF8 + 'ä = 8\\'.encode()) + rc, out, err = script_helper.assert_python_failure('-X', 'utf8', file_name) + err = err.decode().splitlines() + self.assertEqual(err[-3:], [ + ' ä = 8\\', + ' ^', + 'SyntaxError: unexpected EOF while parsing']) + self.assertEqual(err[-4][-8:], ', line 1', err) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index b738ec6a..72c86eec 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -7,6 +7,8 @@ import pickle import weakref import errno +from codecs import BOM_UTF8 +from itertools import product from textwrap import dedent from test.support import (captured_stderr, check_impl_detail, @@ -314,8 +316,8 @@ def baz(): check('def f():\n global x\n nonlocal x', 2, 3) # Errors thrown by future.c - check('from __future__ import doesnt_exist', 1, 1) - check('from __future__ import braces', 1, 1) + check('from __future__ import doesnt_exist', 1, 24) + check('from __future__ import braces', 1, 24) check('x=1\nfrom __future__ import division', 2, 1) check('foo(1=2)', 1, 5) check('def f():\n x, y: int', 2, 3) @@ -1332,6 +1334,29 @@ def test_unicode_errors_no_object(self): for klass in klasses: self.assertEqual(str(klass.__new__(klass)), "") + def test_unicode_error_str_does_not_crash(self): + # Test that str(UnicodeError(...)) does not crash. + # See https://github.com/python/cpython/issues/123378. + + for start, end, objlen in product( + range(-5, 5), + range(-5, 5), + range(7), + ): + obj = 'a' * objlen + with self.subTest('encode', objlen=objlen, start=start, end=end): + exc = UnicodeEncodeError('utf-8', obj, start, end, '') + self.assertIsInstance(str(exc), str) + + with self.subTest('translate', objlen=objlen, start=start, end=end): + exc = UnicodeTranslateError(obj, start, end, '') + self.assertIsInstance(str(exc), str) + + encoded = obj.encode() + with self.subTest('decode', objlen=objlen, start=start, end=end): + exc = UnicodeDecodeError('utf-8', encoded, start, end, '') + self.assertIsInstance(str(exc), str) + @no_tracing def test_badisinstance(self): # Bug #2542: if issubclass(e, MyException) raises an exception, @@ -1820,6 +1845,8 @@ def f(): except self.failureException: with support.captured_stderr() as err: sys.__excepthook__(*sys.exc_info()) + else: + self.fail("assertRaisesRegex should have failed.") self.assertIn("aab", err.getvalue()) @@ -1969,7 +1996,115 @@ def test_copy_pickle(self): self.assertEqual(exc.name, orig.name) self.assertEqual(exc.path, orig.path) + +def run_script(source): + if isinstance(source, str): + with open(TESTFN, 'w', encoding='utf-8') as testfile: + testfile.write(dedent(source)) + else: + with open(TESTFN, 'wb') as testfile: + testfile.write(source) + _rc, _out, err = script_helper.assert_python_failure('-Wd', '-X', 'utf8', TESTFN) + return err.decode('utf-8').splitlines() + +class AssertionErrorTests(unittest.TestCase): + def tearDown(self): + unlink(TESTFN) + + def test_assertion_error_location(self): + cases = [ + ('assert None', + [ + ' assert None', + ' ^^^^', + 'AssertionError', + ], + ), + ('assert 0', + [ + ' assert 0', + ' ^', + 'AssertionError', + ], + ), + ('assert 1 > 2', + [ + ' assert 1 > 2', + ' ^^^^^', + 'AssertionError', + ], + ), + ('assert 1 > 2 and 3 > 2', + [ + ' assert 1 > 2 and 3 > 2', + ' ^^^^^^^^^^^^^^^', + 'AssertionError', + ], + ), + ('assert 1 > 2, "messäge"', + [ + ' assert 1 > 2, "messäge"', + ' ^^^^^', + 'AssertionError: messäge', + ], + ), + ('assert 1 > 2, "messäge"'.encode(), + [ + ' assert 1 > 2, "messäge"', + ' ^^^^^', + 'AssertionError: messäge', + ], + ), + ('# coding: latin1\nassert 1 > 2, "messäge"'.encode('latin1'), + [ + ' assert 1 > 2, "messäge"', + ' ^^^^^', + 'AssertionError: messäge', + ], + ), + + # Multiline: + (""" + assert ( + 1 > 2) + """, + [ + ' 1 > 2)', + ' ^^^^^', + 'AssertionError', + ], + ), + (""" + assert ( + 1 > 2), "Message" + """, + [ + ' 1 > 2), "Message"', + ' ^^^^^', + 'AssertionError: Message', + ], + ), + (""" + assert ( + 1 > 2), \\ + "Message" + """, + [ + ' 1 > 2), \\', + ' ^^^^^', + 'AssertionError: Message', + ], + ), + ] + for source, expected in cases: + with self.subTest(source=source): + result = run_script(source) + self.assertEqual(result[-3:], expected) + + class SyntaxErrorTests(unittest.TestCase): + maxDiff = None + def test_range_of_offsets(self): cases = [ # Basic range from 2->7 @@ -2061,45 +2196,103 @@ def test_range_of_offsets(self): the_exception = exc def test_encodings(self): + self.addCleanup(unlink, TESTFN) source = ( '# -*- coding: cp437 -*-\n' '"┬ó┬ó┬ó┬ó┬ó┬ó" + f(4, x for x in range(1))\n' ) - try: - with open(TESTFN, 'w', encoding='cp437') as testfile: - testfile.write(source) - rc, out, err = script_helper.assert_python_failure('-Wd', '-X', 'utf8', TESTFN) - err = err.decode('utf-8').splitlines() - - self.assertEqual(err[-3], ' "┬ó┬ó┬ó┬ó┬ó┬ó" + f(4, x for x in range(1))') - self.assertEqual(err[-2], ' ^^^^^^^^^^^^^^^^^^^') - finally: - unlink(TESTFN) + err = run_script(source.encode('cp437')) + self.assertEqual(err[-3], ' "┬ó┬ó┬ó┬ó┬ó┬ó" + f(4, x for x in range(1))') + self.assertEqual(err[-2], ' ^^^^^^^^^^^^^^^^^^^') # Check backwards tokenizer errors source = '# -*- coding: ascii -*-\n\n(\n' - try: - with open(TESTFN, 'w', encoding='ascii') as testfile: - testfile.write(source) - rc, out, err = script_helper.assert_python_failure('-Wd', '-X', 'utf8', TESTFN) - err = err.decode('utf-8').splitlines() - - self.assertEqual(err[-3], ' (') - self.assertEqual(err[-2], ' ^') - finally: - unlink(TESTFN) + err = run_script(source) + self.assertEqual(err[-3], ' (') + self.assertEqual(err[-2], ' ^') def test_non_utf8(self): # Check non utf-8 characters - try: - with open(TESTFN, 'bw') as testfile: - testfile.write(b"\x89") - rc, out, err = script_helper.assert_python_failure('-Wd', '-X', 'utf8', TESTFN) - err = err.decode('utf-8').splitlines() + self.addCleanup(unlink, TESTFN) + err = run_script(b"\x89") + self.assertIn("SyntaxError: Non-UTF-8 code starting with '\\x89' in file", err[-1]) - self.assertIn("SyntaxError: Non-UTF-8 code starting with '\\x89' in file", err[-1]) - finally: - unlink(TESTFN) + def test_string_source(self): + def try_compile(source): + with self.assertRaises(SyntaxError) as cm: + compile(source, '', 'exec') + return cm.exception + + exc = try_compile('return "ä"') + self.assertEqual(str(exc), "'return' outside function (, line 1)") + self.assertIsNone(exc.text) + self.assertEqual(exc.offset, 1) + self.assertEqual(exc.end_offset, 12) + + exc = try_compile('return "ä"'.encode()) + self.assertEqual(str(exc), "'return' outside function (, line 1)") + self.assertIsNone(exc.text) + self.assertEqual(exc.offset, 1) + self.assertEqual(exc.end_offset, 12) + + exc = try_compile(BOM_UTF8 + 'return "ä"'.encode()) + self.assertEqual(str(exc), "'return' outside function (, line 1)") + self.assertIsNone(exc.text) + self.assertEqual(exc.offset, 1) + self.assertEqual(exc.end_offset, 12) + + exc = try_compile('# coding: latin1\nreturn "ä"'.encode('latin1')) + self.assertEqual(str(exc), "'return' outside function (, line 2)") + self.assertIsNone(exc.text) + self.assertEqual(exc.offset, 1) + self.assertEqual(exc.end_offset, 12) + + exc = try_compile('return "ä" #' + 'ä'*1000) + self.assertEqual(str(exc), "'return' outside function (, line 1)") + self.assertIsNone(exc.text) + self.assertEqual(exc.offset, 1) + self.assertEqual(exc.end_offset, 12) + + exc = try_compile('return "ä" # ' + 'ä'*1000) + self.assertEqual(str(exc), "'return' outside function (, line 1)") + self.assertIsNone(exc.text) + self.assertEqual(exc.offset, 1) + self.assertEqual(exc.end_offset, 12) + + def test_file_source(self): + self.addCleanup(unlink, TESTFN) + err = run_script('return "ä"') + # NOTE: Offset is calculated incorrectly for non-ASCII strings. + self.assertEqual(err[-3::2], [ + ' return "ä"', + "SyntaxError: 'return' outside function"]) + + err = run_script('return "ä"'.encode()) + self.assertEqual(err[-3::2], [ + ' return "ä"', + "SyntaxError: 'return' outside function"]) + + err = run_script(BOM_UTF8 + 'return "ä"'.encode()) + self.assertEqual(err[-3::2], [ + ' return "ä"', + "SyntaxError: 'return' outside function"]) + + err = run_script('# coding: latin1\nreturn "ä"'.encode('latin1')) + self.assertEqual(err[-3::2], [ + ' return "ä"', + "SyntaxError: 'return' outside function"]) + + err = run_script('return "ä" #' + 'ä'*1000) + self.assertEqual(err[-2:], [ + ' ^^^^^^^^^^^', + "SyntaxError: 'return' outside function"]) + self.assertEqual(err[-3][:100], ' return "ä" #' + 'ä'*84) + + err = run_script('return "ä" # ' + 'ä'*1000) + self.assertEqual(err[-2:], [ + ' ^^^^^^^^^^^', + "SyntaxError: 'return' outside function"]) + self.assertEqual(err[-3][:100], ' return "ä" # ' + 'ä'*83) def test_attributes_new_constructor(self): args = ("bad.py", 1, 2, "abcdefg", 1, 100) diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py index d0473500..dc817d93 100644 --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -236,7 +236,7 @@ def test_sigfpe(self): faulthandler._sigfpe() """, 3, - 'Floating point exception') + 'Floating-point exception') @unittest.skipIf(_testcapi is None, 'need _testcapi') @unittest.skipUnless(hasattr(signal, 'SIGBUS'), 'need signal.SIGBUS') diff --git a/Lib/test/test_filecmp.py b/Lib/test/test_filecmp.py index 9b5ac12b..41d6059f 100644 --- a/Lib/test/test_filecmp.py +++ b/Lib/test/test_filecmp.py @@ -111,6 +111,39 @@ def test_cmpfiles(self): (['file'], ['file2'], []), "Comparing mismatched directories fails") + def test_cmpfiles_invalid_names(self): + # See https://github.com/python/cpython/issues/122400. + for file, desc in [ + ('\x00', 'NUL bytes filename'), + (__file__ + '\x00', 'filename with embedded NUL bytes'), + ("\uD834\uDD1E.py", 'surrogate codes (MUSICAL SYMBOL G CLEF)'), + ('a' * 1_000_000, 'very long filename'), + ]: + for other_dir in [self.dir, self.dir_same, self.dir_diff]: + with self.subTest(f'cmpfiles: {desc}', other_dir=other_dir): + res = filecmp.cmpfiles(self.dir, other_dir, [file]) + self.assertTupleEqual(res, ([], [], [file])) + + def test_dircmp_invalid_names(self): + for bad_dir, desc in [ + ('\x00', 'NUL bytes dirname'), + (f'Top{os.sep}Mid\x00', 'dirname with embedded NUL bytes'), + ("\uD834\uDD1E", 'surrogate codes (MUSICAL SYMBOL G CLEF)'), + ('a' * 1_000_000, 'very long dirname'), + ]: + d1 = filecmp.dircmp(self.dir, bad_dir) + d2 = filecmp.dircmp(bad_dir, self.dir) + for target in [ + # attributes where os.listdir() raises OSError or ValueError + 'left_list', 'right_list', + 'left_only', 'right_only', 'common', + ]: + with self.subTest(f'dircmp(ok, bad): {desc}', target=target): + with self.assertRaises((OSError, ValueError)): + getattr(d1, target) + with self.subTest(f'dircmp(bad, ok): {desc}', target=target): + with self.assertRaises((OSError, ValueError)): + getattr(d2, target) def _assert_lists(self, actual, expected): """Assert that two lists are equal, up to ordering.""" diff --git a/Lib/test/test_float.py b/Lib/test/test_float.py index 32aaf3a8..0c1adabd 100644 --- a/Lib/test/test_float.py +++ b/Lib/test/test_float.py @@ -8,6 +8,7 @@ import unittest from test import support +from test.support.testcase import FloatsAreIdenticalMixin from test.test_grammar import (VALID_UNDERSCORE_LITERALS, INVALID_UNDERSCORE_LITERALS) from math import isinf, isnan, copysign, ldexp @@ -152,7 +153,7 @@ def check(s): # non-UTF-8 byte string check(b'123\xa0') - @support.run_with_locale('LC_NUMERIC', 'fr_FR', 'de_DE') + @support.run_with_locale('LC_NUMERIC', 'fr_FR', 'de_DE', '') def test_float_with_comma(self): # set locale to something that doesn't use '.' for the decimal point # float must not accept the locale specific decimal point but @@ -828,7 +829,7 @@ def test_short_repr(self): self.assertEqual(repr(float(negs)), str(float(negs))) @support.requires_IEEE_754 -class RoundTestCase(unittest.TestCase): +class RoundTestCase(unittest.TestCase, FloatsAreIdenticalMixin): def test_inf_nan(self): self.assertRaises(OverflowError, round, INF) @@ -858,10 +859,10 @@ def test_large_n(self): def test_small_n(self): for n in [-308, -309, -400, 1-2**31, -2**31, -2**31-1, -2**100]: - self.assertEqual(round(123.456, n), 0.0) - self.assertEqual(round(-123.456, n), -0.0) - self.assertEqual(round(1e300, n), 0.0) - self.assertEqual(round(1e-320, n), 0.0) + self.assertFloatsAreIdentical(round(123.456, n), 0.0) + self.assertFloatsAreIdentical(round(-123.456, n), -0.0) + self.assertFloatsAreIdentical(round(1e300, n), 0.0) + self.assertFloatsAreIdentical(round(1e-320, n), 0.0) def test_overflow(self): self.assertRaises(OverflowError, round, 1.6e308, -308) @@ -1052,21 +1053,14 @@ def test_nan_signs(self): fromHex = float.fromhex toHex = float.hex -class HexFloatTestCase(unittest.TestCase): +class HexFloatTestCase(FloatsAreIdenticalMixin, unittest.TestCase): MAX = fromHex('0x.fffffffffffff8p+1024') # max normal MIN = fromHex('0x1p-1022') # min normal TINY = fromHex('0x0.0000000000001p-1022') # min subnormal EPS = fromHex('0x0.0000000000001p0') # diff between 1.0 and next float up def identical(self, x, y): - # check that floats x and y are identical, or that both - # are NaNs - if isnan(x) or isnan(y): - if isnan(x) == isnan(y): - return - elif x == y and (x != 0.0 or copysign(1.0, x) == copysign(1.0, y)): - return - self.fail('%r not identical to %r' % (x, y)) + self.assertFloatsAreIdentical(x, y) def test_ends(self): self.identical(self.MIN, ldexp(1.0, -1022)) diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py index 6fa49dbc..5998ee55 100644 --- a/Lib/test/test_format.py +++ b/Lib/test/test_format.py @@ -35,7 +35,7 @@ def testformat(formatstr, args, output=None, limit=None, overflowok=False): # when 'limit' is specified, it determines how many characters # must match exactly; lengths must always match. # ex: limit=5, '12345678' matches '12345___' - # (mainly for floating point format tests for which an exact match + # (mainly for floating-point format tests for which an exact match # can't be guaranteed due to rounding and representation errors) elif output and limit is not None and ( len(result)!=len(output) or result[:limit]!=output[:limit]): diff --git a/Lib/test/test_fractions.py b/Lib/test/test_fractions.py index bbfb1b27..f4e763fe 100644 --- a/Lib/test/test_fractions.py +++ b/Lib/test/test_fractions.py @@ -97,7 +97,7 @@ def typed_approx_eq(a, b): class Symbolic: """Simple non-numeric class for testing mixed arithmetic. - It is not Integral, Rational, Real or Complex, and cannot be conveted + It is not Integral, Rational, Real or Complex, and cannot be converted to int, float or complex. but it supports some arithmetic operations. """ def __init__(self, value): @@ -922,21 +922,21 @@ def testMixedPower(self): self.assertTypedEquals(Root(4) ** F(2, 1), Root(4, F(1))) self.assertTypedEquals(Root(4) ** F(-2, 1), Root(4, -F(1))) self.assertTypedEquals(Root(4) ** F(-2, 3), Root(4, -3.0)) - self.assertEqual(F(3, 2) ** SymbolicReal('X'), SymbolicReal('1.5 ** X')) + self.assertEqual(F(3, 2) ** SymbolicReal('X'), SymbolicReal('3/2 ** X')) self.assertEqual(SymbolicReal('X') ** F(3, 2), SymbolicReal('X ** 1.5')) - self.assertTypedEquals(F(3, 2) ** Rect(2, 0), Polar(2.25, 0.0)) - self.assertTypedEquals(F(1, 1) ** Rect(2, 3), Polar(1.0, 0.0)) + self.assertTypedEquals(F(3, 2) ** Rect(2, 0), Polar(F(9,4), 0.0)) + self.assertTypedEquals(F(1, 1) ** Rect(2, 3), Polar(F(1), 0.0)) self.assertTypedEquals(F(3, 2) ** RectComplex(2, 0), Polar(2.25, 0.0)) self.assertTypedEquals(F(1, 1) ** RectComplex(2, 3), Polar(1.0, 0.0)) self.assertTypedEquals(Polar(4, 2) ** F(3, 2), Polar(8.0, 3.0)) self.assertTypedEquals(Polar(4, 2) ** F(3, 1), Polar(64, 6)) self.assertTypedEquals(Polar(4, 2) ** F(-3, 1), Polar(0.015625, -6)) self.assertTypedEquals(Polar(4, 2) ** F(-3, 2), Polar(0.125, -3.0)) - self.assertEqual(F(3, 2) ** SymbolicComplex('X'), SymbolicComplex('1.5 ** X')) + self.assertEqual(F(3, 2) ** SymbolicComplex('X'), SymbolicComplex('3/2 ** X')) self.assertEqual(SymbolicComplex('X') ** F(3, 2), SymbolicComplex('X ** 1.5')) - self.assertEqual(F(3, 2) ** Symbolic('X'), Symbolic('1.5 ** X')) + self.assertEqual(F(3, 2) ** Symbolic('X'), Symbolic('3/2 ** X')) self.assertEqual(Symbolic('X') ** F(3, 2), Symbolic('X ** 1.5')) def testMixingWithDecimal(self): diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index fb364e9c..da1ab4ef 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -8,6 +8,7 @@ # Unicode identifiers in tests is allowed by PEP 3131. import ast +import datetime import os import re import types @@ -18,7 +19,7 @@ from test.support.os_helper import temp_cwd from test.support.script_helper import assert_python_failure, assert_python_ok -a_global = 'global variable' +a_global = "global variable" # You could argue that I'm too strict in looking for specific error # values with assertRaisesRegex, but without it it's way too easy to @@ -27,6 +28,7 @@ # worthwhile tradeoff. When I switched to this method, I found many # examples where I wasn't testing what I thought I was. + class TestCase(unittest.TestCase): def assertAllRaise(self, exception_type, regex, error_strings): for str in error_strings: @@ -38,43 +40,45 @@ def test__format__lookup(self): # Make sure __format__ is looked up on the type, not the instance. class X: def __format__(self, spec): - return 'class' + return "class" x = X() # Add a bound __format__ method to the 'y' instance, but not # the 'x' instance. y = X() - y.__format__ = types.MethodType(lambda self, spec: 'instance', y) + y.__format__ = types.MethodType(lambda self, spec: "instance", y) - self.assertEqual(f'{y}', format(y)) - self.assertEqual(f'{y}', 'class') + self.assertEqual(f"{y}", format(y)) + self.assertEqual(f"{y}", "class") self.assertEqual(format(x), format(y)) # __format__ is not called this way, but still make sure it # returns what we expect (so we can make sure we're bypassing # it). - self.assertEqual(x.__format__(''), 'class') - self.assertEqual(y.__format__(''), 'instance') + self.assertEqual(x.__format__(""), "class") + self.assertEqual(y.__format__(""), "instance") # This is how __format__ is actually called. - self.assertEqual(type(x).__format__(x, ''), 'class') - self.assertEqual(type(y).__format__(y, ''), 'class') + self.assertEqual(type(x).__format__(x, ""), "class") + self.assertEqual(type(y).__format__(y, ""), "class") def test_ast(self): # Inspired by http://bugs.python.org/issue24975 class X: def __init__(self): self.called = False + def __call__(self): self.called = True return 4 + x = X() expr = """ a = 10 f'{a * x()}'""" t = ast.parse(expr) - c = compile(t, '', 'exec') + c = compile(t, "", "exec") # Make sure x was not called. self.assertFalse(x.called) @@ -280,7 +284,6 @@ def test_ast_line_numbers_duplicate_expression(self): self.assertEqual(binop.right.col_offset, 27) def test_ast_numbers_fstring_with_formatting(self): - t = ast.parse('f"Here is that pesky {xxx:.3f} again"') self.assertEqual(len(t.body), 1) self.assertEqual(t.body[0].lineno, 1) @@ -436,24 +439,12 @@ def test_ast_line_numbers_with_parentheses(self): x, y = t.body # Check the single quoted string offsets first. - offsets = [ - (elt.col_offset, elt.end_col_offset) - for elt in x.value.elts - ] - self.assertTrue(all( - offset == (4, 10) - for offset in offsets - )) + offsets = [(elt.col_offset, elt.end_col_offset) for elt in x.value.elts] + self.assertTrue(all(offset == (4, 10) for offset in offsets)) # Check the triple quoted string offsets. - offsets = [ - (elt.col_offset, elt.end_col_offset) - for elt in y.value.elts - ] - self.assertTrue(all( - offset == (4, 14) - for offset in offsets - )) + offsets = [(elt.col_offset, elt.end_col_offset) for elt in y.value.elts] + self.assertTrue(all(offset == (4, 14) for offset in offsets)) expr = """ x = ( @@ -516,463 +507,573 @@ def test_ast_fstring_empty_format_spec(self): def test_docstring(self): def f(): - f'''Not a docstring''' + f"""Not a docstring""" + self.assertIsNone(f.__doc__) + def g(): - '''Not a docstring''' \ - f'' + """Not a docstring""" f"" + self.assertIsNone(g.__doc__) def test_literal_eval(self): - with self.assertRaisesRegex(ValueError, 'malformed node or string'): + with self.assertRaisesRegex(ValueError, "malformed node or string"): ast.literal_eval("f'x'") def test_ast_compile_time_concat(self): - x = [''] + x = [""] expr = """x[0] = 'foo' f'{3}'""" t = ast.parse(expr) - c = compile(t, '', 'exec') + c = compile(t, "", "exec") exec(c) - self.assertEqual(x[0], 'foo3') + self.assertEqual(x[0], "foo3") def test_compile_time_concat_errors(self): - self.assertAllRaise(SyntaxError, - 'cannot mix bytes and nonbytes literals', - [r"""f'' b''""", - r"""b'' f''""", - ]) + self.assertAllRaise( + SyntaxError, + "cannot mix bytes and nonbytes literals", + [ + r"""f'' b''""", + r"""b'' f''""", + ], + ) def test_literal(self): - self.assertEqual(f'', '') - self.assertEqual(f'a', 'a') - self.assertEqual(f' ', ' ') + self.assertEqual(f"", "") + self.assertEqual(f"a", "a") + self.assertEqual(f" ", " ") def test_unterminated_string(self): - self.assertAllRaise(SyntaxError, 'unterminated string', - [r"""f'{"x'""", - r"""f'{"x}'""", - r"""f'{("x'""", - r"""f'{("x}'""", - ]) + self.assertAllRaise( + SyntaxError, + "unterminated string", + [ + r"""f'{"x'""", + r"""f'{"x}'""", + r"""f'{("x'""", + r"""f'{("x}'""", + ], + ) @unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI") def test_mismatched_parens(self): - self.assertAllRaise(SyntaxError, r"closing parenthesis '\}' " - r"does not match opening parenthesis '\('", - ["f'{((}'", - ]) - self.assertAllRaise(SyntaxError, r"closing parenthesis '\)' " - r"does not match opening parenthesis '\['", - ["f'{a[4)}'", - ]) - self.assertAllRaise(SyntaxError, r"closing parenthesis '\]' " - r"does not match opening parenthesis '\('", - ["f'{a(4]}'", - ]) - self.assertAllRaise(SyntaxError, r"closing parenthesis '\}' " - r"does not match opening parenthesis '\['", - ["f'{a[4}'", - ]) - self.assertAllRaise(SyntaxError, r"closing parenthesis '\}' " - r"does not match opening parenthesis '\('", - ["f'{a(4}'", - ]) - self.assertRaises(SyntaxError, eval, "f'{" + "("*500 + "}'") + self.assertAllRaise( + SyntaxError, + r"closing parenthesis '\}' " r"does not match opening parenthesis '\('", + [ + "f'{((}'", + ], + ) + self.assertAllRaise( + SyntaxError, + r"closing parenthesis '\)' " r"does not match opening parenthesis '\['", + [ + "f'{a[4)}'", + ], + ) + self.assertAllRaise( + SyntaxError, + r"closing parenthesis '\]' " r"does not match opening parenthesis '\('", + [ + "f'{a(4]}'", + ], + ) + self.assertAllRaise( + SyntaxError, + r"closing parenthesis '\}' " r"does not match opening parenthesis '\['", + [ + "f'{a[4}'", + ], + ) + self.assertAllRaise( + SyntaxError, + r"closing parenthesis '\}' " r"does not match opening parenthesis '\('", + [ + "f'{a(4}'", + ], + ) + self.assertRaises(SyntaxError, eval, "f'{" + "(" * 500 + "}'") @unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI") def test_fstring_nested_too_deeply(self): - self.assertAllRaise(SyntaxError, - "f-string: expressions nested too deeply", - ['f"{1+2:{1+2:{1+1:{1}}}}"']) + self.assertAllRaise( + SyntaxError, + "f-string: expressions nested too deeply", + ['f"{1+2:{1+2:{1+1:{1}}}}"'], + ) def create_nested_fstring(n): if n == 0: return "1+1" - prev = create_nested_fstring(n-1) + prev = create_nested_fstring(n - 1) return f'f"{{{prev}}}"' - self.assertAllRaise(SyntaxError, - "too many nested f-strings", - [create_nested_fstring(160)]) + self.assertAllRaise( + SyntaxError, "too many nested f-strings", [create_nested_fstring(160)] + ) def test_syntax_error_in_nested_fstring(self): # See gh-104016 for more information on this crash - self.assertAllRaise(SyntaxError, - "invalid syntax", - ['f"{1 1:' + ('{f"1:' * 199)]) + self.assertAllRaise( + SyntaxError, "invalid syntax", ['f"{1 1:' + ('{f"1:' * 199)] + ) def test_double_braces(self): - self.assertEqual(f'{{', '{') - self.assertEqual(f'a{{', 'a{') - self.assertEqual(f'{{b', '{b') - self.assertEqual(f'a{{b', 'a{b') - self.assertEqual(f'}}', '}') - self.assertEqual(f'a}}', 'a}') - self.assertEqual(f'}}b', '}b') - self.assertEqual(f'a}}b', 'a}b') - self.assertEqual(f'{{}}', '{}') - self.assertEqual(f'a{{}}', 'a{}') - self.assertEqual(f'{{b}}', '{b}') - self.assertEqual(f'{{}}c', '{}c') - self.assertEqual(f'a{{b}}', 'a{b}') - self.assertEqual(f'a{{}}c', 'a{}c') - self.assertEqual(f'{{b}}c', '{b}c') - self.assertEqual(f'a{{b}}c', 'a{b}c') - - self.assertEqual(f'{{{10}', '{10') - self.assertEqual(f'}}{10}', '}10') - self.assertEqual(f'}}{{{10}', '}{10') - self.assertEqual(f'}}a{{{10}', '}a{10') - - self.assertEqual(f'{10}{{', '10{') - self.assertEqual(f'{10}}}', '10}') - self.assertEqual(f'{10}}}{{', '10}{') - self.assertEqual(f'{10}}}a{{' '}', '10}a{}') + self.assertEqual(f"{{", "{") + self.assertEqual(f"a{{", "a{") + self.assertEqual(f"{{b", "{b") + self.assertEqual(f"a{{b", "a{b") + self.assertEqual(f"}}", "}") + self.assertEqual(f"a}}", "a}") + self.assertEqual(f"}}b", "}b") + self.assertEqual(f"a}}b", "a}b") + self.assertEqual(f"{{}}", "{}") + self.assertEqual(f"a{{}}", "a{}") + self.assertEqual(f"{{b}}", "{b}") + self.assertEqual(f"{{}}c", "{}c") + self.assertEqual(f"a{{b}}", "a{b}") + self.assertEqual(f"a{{}}c", "a{}c") + self.assertEqual(f"{{b}}c", "{b}c") + self.assertEqual(f"a{{b}}c", "a{b}c") + + self.assertEqual(f"{{{10}", "{10") + self.assertEqual(f"}}{10}", "}10") + self.assertEqual(f"}}{{{10}", "}{10") + self.assertEqual(f"}}a{{{10}", "}a{10") + + self.assertEqual(f"{10}{{", "10{") + self.assertEqual(f"{10}}}", "10}") + self.assertEqual(f"{10}}}{{", "10}{") + self.assertEqual(f"{10}}}a{{" "}", "10}a{}") # Inside of strings, don't interpret doubled brackets. - self.assertEqual(f'{"{{}}"}', '{{}}') + self.assertEqual(f'{"{{}}"}', "{{}}") - self.assertAllRaise(TypeError, 'unhashable type', - ["f'{ {{}} }'", # dict in a set - ]) + self.assertAllRaise( + TypeError, + "unhashable type", + [ + "f'{ {{}} }'", # dict in a set + ], + ) def test_compile_time_concat(self): - x = 'def' - self.assertEqual('abc' f'## {x}ghi', 'abc## defghi') - self.assertEqual('abc' f'{x}' 'ghi', 'abcdefghi') - self.assertEqual('abc' f'{x}' 'gh' f'i{x:4}', 'abcdefghidef ') - self.assertEqual('{x}' f'{x}', '{x}def') - self.assertEqual('{x' f'{x}', '{xdef') - self.assertEqual('{x}' f'{x}', '{x}def') - self.assertEqual('{{x}}' f'{x}', '{{x}}def') - self.assertEqual('{{x' f'{x}', '{{xdef') - self.assertEqual('x}}' f'{x}', 'x}}def') - self.assertEqual(f'{x}' 'x}}', 'defx}}') - self.assertEqual(f'{x}' '', 'def') - self.assertEqual('' f'{x}' '', 'def') - self.assertEqual('' f'{x}', 'def') - self.assertEqual(f'{x}' '2', 'def2') - self.assertEqual('1' f'{x}' '2', '1def2') - self.assertEqual('1' f'{x}', '1def') - self.assertEqual(f'{x}' f'-{x}', 'def-def') - self.assertEqual('' f'', '') - self.assertEqual('' f'' '', '') - self.assertEqual('' f'' '' f'', '') - self.assertEqual(f'', '') - self.assertEqual(f'' '', '') - self.assertEqual(f'' '' f'', '') - self.assertEqual(f'' '' f'' '', '') + x = "def" + self.assertEqual("abc" f"## {x}ghi", "abc## defghi") + self.assertEqual("abc" f"{x}" "ghi", "abcdefghi") + self.assertEqual("abc" f"{x}" "gh" f"i{x:4}", "abcdefghidef ") + self.assertEqual("{x}" f"{x}", "{x}def") + self.assertEqual("{x" f"{x}", "{xdef") + self.assertEqual("{x}" f"{x}", "{x}def") + self.assertEqual("{{x}}" f"{x}", "{{x}}def") + self.assertEqual("{{x" f"{x}", "{{xdef") + self.assertEqual("x}}" f"{x}", "x}}def") + self.assertEqual(f"{x}" "x}}", "defx}}") + self.assertEqual(f"{x}" "", "def") + self.assertEqual("" f"{x}" "", "def") + self.assertEqual("" f"{x}", "def") + self.assertEqual(f"{x}" "2", "def2") + self.assertEqual("1" f"{x}" "2", "1def2") + self.assertEqual("1" f"{x}", "1def") + self.assertEqual(f"{x}" f"-{x}", "def-def") + self.assertEqual("" f"", "") + self.assertEqual("" f"" "", "") + self.assertEqual("" f"" "" f"", "") + self.assertEqual(f"", "") + self.assertEqual(f"" "", "") + self.assertEqual(f"" "" f"", "") + self.assertEqual(f"" "" f"" "", "") # This is not really [f'{'] + [f'}'] since we treat the inside # of braces as a purely new context, so it is actually f'{ and # then eval(' f') (a valid expression) and then }' which would # constitute a valid f-string. - self.assertEqual(f'{' f'}', ' f') + self.assertEqual(f'{' f'}', " f") - self.assertAllRaise(SyntaxError, "expecting '}'", - ['''f'{3' f"}"''', # can't concat to get a valid f-string - ]) + self.assertAllRaise( + SyntaxError, + "expecting '}'", + [ + '''f'{3' f"}"''', # can't concat to get a valid f-string + ], + ) def test_comments(self): # These aren't comments, since they're in strings. - d = {'#': 'hash'} - self.assertEqual(f'{"#"}', '#') - self.assertEqual(f'{d["#"]}', 'hash') - - self.assertAllRaise(SyntaxError, "'{' was never closed", - ["f'{1#}'", # error because everything after '#' is a comment - "f'{#}'", - "f'one: {1#}'", - "f'{1# one} {2 this is a comment still#}'", - ]) - self.assertAllRaise(SyntaxError, r"f-string: unmatched '\)'", - ["f'{)#}'", # When wrapped in parens, this becomes - # '()#)'. Make sure that doesn't compile. - ]) - self.assertEqual(f'''A complex trick: { + d = {"#": "hash"} + self.assertEqual(f'{"#"}', "#") + self.assertEqual(f'{d["#"]}', "hash") + + self.assertAllRaise( + SyntaxError, + "'{' was never closed", + [ + "f'{1#}'", # error because everything after '#' is a comment + "f'{#}'", + "f'one: {1#}'", + "f'{1# one} {2 this is a comment still#}'", + ], + ) + self.assertAllRaise( + SyntaxError, + r"f-string: unmatched '\)'", + [ + "f'{)#}'", # When wrapped in parens, this becomes + # '()#)'. Make sure that doesn't compile. + ], + ) + self.assertEqual( + f"""A complex trick: { 2 # two -}''', 'A complex trick: 2') - self.assertEqual(f''' +}""", + "A complex trick: 2", + ) + self.assertEqual( + f""" { -40 # fourty +40 # forty + # plus 2 # two -}''', '\n42') - self.assertEqual(f''' +}""", + "\n42", + ) + self.assertEqual( + f""" { -40 # fourty +40 # forty + # plus 2 # two -}''', '\n42') +}""", + "\n42", + ) - self.assertEqual(f''' + self.assertEqual( + f""" # this is not a comment { # the following operation it's 3 # this is a number -* 2}''', '\n# this is not a comment\n6') - self.assertEqual(f''' +* 2}""", + "\n# this is not a comment\n6", + ) + self.assertEqual( + f""" {# f'a {comment}' 86 # constant # nothing more -}''', '\n86') - - self.assertAllRaise(SyntaxError, r"f-string: valid expression required before '}'", - ["""f''' +}""", + "\n86", + ) + + self.assertAllRaise( + SyntaxError, + r"f-string: valid expression required before '}'", + [ + """f''' { # only a comment }''' -""", # this is equivalent to f'{}' - ]) +""", # this is equivalent to f'{}' + ], + ) def test_many_expressions(self): # Create a string with many expressions in it. Note that # because we have a space in here as a literal, we're actually # going to use twice as many ast nodes: one for each literal # plus one for each expression. - def build_fstr(n, extra=''): - return "f'" + ('{x} ' * n) + extra + "'" + def build_fstr(n, extra=""): + return "f'" + ("{x} " * n) + extra + "'" - x = 'X' + x = "X" width = 1 # Test around 256. for i in range(250, 260): - self.assertEqual(eval(build_fstr(i)), (x+' ')*i) + self.assertEqual(eval(build_fstr(i)), (x + " ") * i) # Test concatenating 2 largs fstrings. - self.assertEqual(eval(build_fstr(255)*256), (x+' ')*(255*256)) + self.assertEqual(eval(build_fstr(255) * 256), (x + " ") * (255 * 256)) - s = build_fstr(253, '{x:{width}} ') - self.assertEqual(eval(s), (x+' ')*254) + s = build_fstr(253, "{x:{width}} ") + self.assertEqual(eval(s), (x + " ") * 254) # Test lots of expressions and constants, concatenated. s = "f'{1}' 'x' 'y'" * 1024 - self.assertEqual(eval(s), '1xy' * 1024) + self.assertEqual(eval(s), "1xy" * 1024) def test_format_specifier_expressions(self): width = 10 precision = 4 - value = decimal.Decimal('12.34567') - self.assertEqual(f'result: {value:{width}.{precision}}', 'result: 12.35') - self.assertEqual(f'result: {value:{width!r}.{precision}}', 'result: 12.35') - self.assertEqual(f'result: {value:{width:0}.{precision:1}}', 'result: 12.35') - self.assertEqual(f'result: {value:{1}{0:0}.{precision:1}}', 'result: 12.35') - self.assertEqual(f'result: {value:{ 1}{ 0:0}.{ precision:1}}', 'result: 12.35') - self.assertEqual(f'{10:#{1}0x}', ' 0xa') - self.assertEqual(f'{10:{"#"}1{0}{"x"}}', ' 0xa') - self.assertEqual(f'{-10:-{"#"}1{0}x}', ' -0xa') - self.assertEqual(f'{-10:{"-"}#{1}0{"x"}}', ' -0xa') - self.assertEqual(f'{10:#{3 != {4:5} and width}x}', ' 0xa') - self.assertEqual(f'result: {value:{width:{0}}.{precision:1}}', 'result: 12.35') - - self.assertAllRaise(SyntaxError, "f-string: expecting ':' or '}'", - ["""f'{"s"!r{":10"}}'""", - # This looks like a nested format spec. - ]) - - self.assertAllRaise(SyntaxError, - "f-string: expecting a valid expression after '{'", - [# Invalid syntax inside a nested spec. - "f'{4:{/5}}'", - ]) - - self.assertAllRaise(SyntaxError, 'f-string: invalid conversion character', - [# No expansion inside conversion or for - # the : or ! itself. - """f'{"s"!{"r"}}'""", - ]) + value = decimal.Decimal("12.34567") + self.assertEqual(f"result: {value:{width}.{precision}}", "result: 12.35") + self.assertEqual(f"result: {value:{width!r}.{precision}}", "result: 12.35") + self.assertEqual( + f"result: {value:{width:0}.{precision:1}}", "result: 12.35" + ) + self.assertEqual( + f"result: {value:{1}{0:0}.{precision:1}}", "result: 12.35" + ) + self.assertEqual( + f"result: {value:{ 1}{ 0:0}.{ precision:1}}", "result: 12.35" + ) + self.assertEqual(f"{10:#{1}0x}", " 0xa") + self.assertEqual(f'{10:{"#"}1{0}{"x"}}', " 0xa") + self.assertEqual(f'{-10:-{"#"}1{0}x}', " -0xa") + self.assertEqual(f'{-10:{"-"}#{1}0{"x"}}', " -0xa") + self.assertEqual(f"{10:#{3 != {4:5} and width}x}", " 0xa") + self.assertEqual( + f"result: {value:{width:{0}}.{precision:1}}", "result: 12.35" + ) + + self.assertAllRaise( + SyntaxError, + "f-string: expecting ':' or '}'", + [ + """f'{"s"!r{":10"}}'""", + # This looks like a nested format spec. + ], + ) + + self.assertAllRaise( + SyntaxError, + "f-string: expecting a valid expression after '{'", + [ # Invalid syntax inside a nested spec. + "f'{4:{/5}}'", + ], + ) + + self.assertAllRaise( + SyntaxError, + "f-string: invalid conversion character", + [ # No expansion inside conversion or for + # the : or ! itself. + """f'{"s"!{"r"}}'""", + ], + ) def test_custom_format_specifier(self): class CustomFormat: def __format__(self, format_spec): return format_spec - self.assertEqual(f'{CustomFormat():\n}', '\n') - self.assertEqual(f'{CustomFormat():\u2603}', '☃') + self.assertEqual(f"{CustomFormat():\n}", "\n") + self.assertEqual(f"{CustomFormat():\u2603}", "☃") with self.assertWarns(SyntaxWarning): - exec(r'f"{F():¯\_(ツ)_/¯}"', {'F': CustomFormat}) + exec(r'f"{F():¯\_(ツ)_/¯}"', {"F": CustomFormat}) def test_side_effect_order(self): class X: def __init__(self): self.i = 0 + def __format__(self, spec): self.i += 1 return str(self.i) x = X() - self.assertEqual(f'{x} {x}', '1 2') + self.assertEqual(f"{x} {x}", "1 2") def test_missing_expression(self): - self.assertAllRaise(SyntaxError, - "f-string: valid expression required before '}'", - ["f'{}'", - "f'{ }'" - "f' {} '", - "f'{10:{ }}'", - "f' { } '", - - # The Python parser ignores also the following - # whitespace characters in additional to a space. - "f'''{\t\f\r\n}'''", - ]) - - self.assertAllRaise(SyntaxError, - "f-string: valid expression required before '!'", - ["f'{!r}'", - "f'{ !r}'", - "f'{!}'", - "f'''{\t\f\r\n!a}'''", - - # Catch empty expression before the - # missing closing brace. - "f'{!'", - "f'{!s:'", - - # Catch empty expression before the - # invalid conversion. - "f'{!x}'", - "f'{ !xr}'", - "f'{!x:}'", - "f'{!x:a}'", - "f'{ !xr:}'", - "f'{ !xr:a}'", - ]) - - self.assertAllRaise(SyntaxError, - "f-string: valid expression required before ':'", - ["f'{:}'", - "f'{ :!}'", - "f'{:2}'", - "f'''{\t\f\r\n:a}'''", - "f'{:'", - ]) - - self.assertAllRaise(SyntaxError, - "f-string: valid expression required before '='", - ["f'{=}'", - "f'{ =}'", - "f'{ =:}'", - "f'{ =!}'", - "f'''{\t\f\r\n=}'''", - "f'{='", - ]) + self.assertAllRaise( + SyntaxError, + "f-string: valid expression required before '}'", + [ + "f'{}'", + "f'{ }'" "f' {} '", + "f'{10:{ }}'", + "f' { } '", + # The Python parser ignores also the following + # whitespace characters in additional to a space. + "f'''{\t\f\r\n}'''", + ], + ) + + self.assertAllRaise( + SyntaxError, + "f-string: valid expression required before '!'", + [ + "f'{!r}'", + "f'{ !r}'", + "f'{!}'", + "f'''{\t\f\r\n!a}'''", + # Catch empty expression before the + # missing closing brace. + "f'{!'", + "f'{!s:'", + # Catch empty expression before the + # invalid conversion. + "f'{!x}'", + "f'{ !xr}'", + "f'{!x:}'", + "f'{!x:a}'", + "f'{ !xr:}'", + "f'{ !xr:a}'", + ], + ) + + self.assertAllRaise( + SyntaxError, + "f-string: valid expression required before ':'", + [ + "f'{:}'", + "f'{ :!}'", + "f'{:2}'", + "f'''{\t\f\r\n:a}'''", + "f'{:'", + "F'{[F'{:'}[F'{:'}]]]", + ], + ) + + self.assertAllRaise( + SyntaxError, + "f-string: valid expression required before '='", + [ + "f'{=}'", + "f'{ =}'", + "f'{ =:}'", + "f'{ =!}'", + "f'''{\t\f\r\n=}'''", + "f'{='", + ], + ) # Different error message is raised for other whitespace characters. - self.assertAllRaise(SyntaxError, r"invalid non-printable character U\+00A0", - ["f'''{\xa0}'''", - "\xa0", - ]) + self.assertAllRaise( + SyntaxError, + r"invalid non-printable character U\+00A0", + [ + "f'''{\xa0}'''", + "\xa0", + ], + ) def test_parens_in_expressions(self): - self.assertEqual(f'{3,}', '(3,)') - - self.assertAllRaise(SyntaxError, - "f-string: expecting a valid expression after '{'", - ["f'{,}'", - ]) - - self.assertAllRaise(SyntaxError, r"f-string: unmatched '\)'", - ["f'{3)+(4}'", - ]) + self.assertEqual(f"{3,}", "(3,)") + + self.assertAllRaise( + SyntaxError, + "f-string: expecting a valid expression after '{'", + [ + "f'{,}'", + ], + ) + + self.assertAllRaise( + SyntaxError, + r"f-string: unmatched '\)'", + [ + "f'{3)+(4}'", + ], + ) def test_newlines_before_syntax_error(self): - self.assertAllRaise(SyntaxError, - "f-string: expecting a valid expression after '{'", - ["f'{.}'", "\nf'{.}'", "\n\nf'{.}'"]) + self.assertAllRaise( + SyntaxError, + "f-string: expecting a valid expression after '{'", + ["f'{.}'", "\nf'{.}'", "\n\nf'{.}'"], + ) def test_backslashes_in_string_part(self): - self.assertEqual(f'\t', '\t') - self.assertEqual(r'\t', '\\t') - self.assertEqual(rf'\t', '\\t') - self.assertEqual(f'{2}\t', '2\t') - self.assertEqual(f'{2}\t{3}', '2\t3') - self.assertEqual(f'\t{3}', '\t3') - - self.assertEqual(f'\u0394', '\u0394') - self.assertEqual(r'\u0394', '\\u0394') - self.assertEqual(rf'\u0394', '\\u0394') - self.assertEqual(f'{2}\u0394', '2\u0394') - self.assertEqual(f'{2}\u0394{3}', '2\u03943') - self.assertEqual(f'\u0394{3}', '\u03943') - - self.assertEqual(f'\U00000394', '\u0394') - self.assertEqual(r'\U00000394', '\\U00000394') - self.assertEqual(rf'\U00000394', '\\U00000394') - self.assertEqual(f'{2}\U00000394', '2\u0394') - self.assertEqual(f'{2}\U00000394{3}', '2\u03943') - self.assertEqual(f'\U00000394{3}', '\u03943') - - self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}', '\u0394') - self.assertEqual(f'{2}\N{GREEK CAPITAL LETTER DELTA}', '2\u0394') - self.assertEqual(f'{2}\N{GREEK CAPITAL LETTER DELTA}{3}', '2\u03943') - self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}{3}', '\u03943') - self.assertEqual(f'2\N{GREEK CAPITAL LETTER DELTA}', '2\u0394') - self.assertEqual(f'2\N{GREEK CAPITAL LETTER DELTA}3', '2\u03943') - self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}3', '\u03943') - - self.assertEqual(f'\x20', ' ') - self.assertEqual(r'\x20', '\\x20') - self.assertEqual(rf'\x20', '\\x20') - self.assertEqual(f'{2}\x20', '2 ') - self.assertEqual(f'{2}\x20{3}', '2 3') - self.assertEqual(f'\x20{3}', ' 3') - - self.assertEqual(f'2\x20', '2 ') - self.assertEqual(f'2\x203', '2 3') - self.assertEqual(f'\x203', ' 3') + self.assertEqual(f"\t", "\t") + self.assertEqual(r"\t", "\\t") + self.assertEqual(rf"\t", "\\t") + self.assertEqual(f"{2}\t", "2\t") + self.assertEqual(f"{2}\t{3}", "2\t3") + self.assertEqual(f"\t{3}", "\t3") + + self.assertEqual(f"\u0394", "\u0394") + self.assertEqual(r"\u0394", "\\u0394") + self.assertEqual(rf"\u0394", "\\u0394") + self.assertEqual(f"{2}\u0394", "2\u0394") + self.assertEqual(f"{2}\u0394{3}", "2\u03943") + self.assertEqual(f"\u0394{3}", "\u03943") + + self.assertEqual(f"\U00000394", "\u0394") + self.assertEqual(r"\U00000394", "\\U00000394") + self.assertEqual(rf"\U00000394", "\\U00000394") + self.assertEqual(f"{2}\U00000394", "2\u0394") + self.assertEqual(f"{2}\U00000394{3}", "2\u03943") + self.assertEqual(f"\U00000394{3}", "\u03943") + + self.assertEqual(f"\N{GREEK CAPITAL LETTER DELTA}", "\u0394") + self.assertEqual(f"{2}\N{GREEK CAPITAL LETTER DELTA}", "2\u0394") + self.assertEqual(f"{2}\N{GREEK CAPITAL LETTER DELTA}{3}", "2\u03943") + self.assertEqual(f"\N{GREEK CAPITAL LETTER DELTA}{3}", "\u03943") + self.assertEqual(f"2\N{GREEK CAPITAL LETTER DELTA}", "2\u0394") + self.assertEqual(f"2\N{GREEK CAPITAL LETTER DELTA}3", "2\u03943") + self.assertEqual(f"\N{GREEK CAPITAL LETTER DELTA}3", "\u03943") + + self.assertEqual(f"\x20", " ") + self.assertEqual(r"\x20", "\\x20") + self.assertEqual(rf"\x20", "\\x20") + self.assertEqual(f"{2}\x20", "2 ") + self.assertEqual(f"{2}\x20{3}", "2 3") + self.assertEqual(f"\x20{3}", " 3") + + self.assertEqual(f"2\x20", "2 ") + self.assertEqual(f"2\x203", "2 3") + self.assertEqual(f"\x203", " 3") with self.assertWarns(SyntaxWarning): # invalid escape sequence value = eval(r"f'\{6*7}'") - self.assertEqual(value, '\\42') + self.assertEqual(value, "\\42") with self.assertWarns(SyntaxWarning): # invalid escape sequence value = eval(r"f'\g'") - self.assertEqual(value, '\\g') - self.assertEqual(f'\\{6*7}', '\\42') - self.assertEqual(fr'\{6*7}', '\\42') + self.assertEqual(value, "\\g") + self.assertEqual(f"\\{6*7}", "\\42") + self.assertEqual(rf"\{6*7}", "\\42") - AMPERSAND = 'spam' + AMPERSAND = "spam" # Get the right unicode character (&), or pick up local variable # depending on the number of backslashes. - self.assertEqual(f'\N{AMPERSAND}', '&') - self.assertEqual(f'\\N{AMPERSAND}', '\\Nspam') - self.assertEqual(fr'\N{AMPERSAND}', '\\Nspam') - self.assertEqual(f'\\\N{AMPERSAND}', '\\&') + self.assertEqual(f"\N{AMPERSAND}", "&") + self.assertEqual(f"\\N{AMPERSAND}", "\\Nspam") + self.assertEqual(rf"\N{AMPERSAND}", "\\Nspam") + self.assertEqual(f"\\\N{AMPERSAND}", "\\&") def test_misformed_unicode_character_name(self): # These test are needed because unicode names are parsed # differently inside f-strings. - self.assertAllRaise(SyntaxError, r"\(unicode error\) 'unicodeescape' codec can't decode bytes in position .*: malformed \\N character escape", - [r"f'\N'", - r"f'\N '", - r"f'\N '", # See bpo-46503. - r"f'\N{'", - r"f'\N{GREEK CAPITAL LETTER DELTA'", - - # Here are the non-f-string versions, - # which should give the same errors. - r"'\N'", - r"'\N '", - r"'\N '", - r"'\N{'", - r"'\N{GREEK CAPITAL LETTER DELTA'", - ]) + self.assertAllRaise( + SyntaxError, + r"\(unicode error\) 'unicodeescape' codec can't decode bytes in position .*: malformed \\N character escape", + [ + r"f'\N'", + r"f'\N '", + r"f'\N '", # See bpo-46503. + r"f'\N{'", + r"f'\N{GREEK CAPITAL LETTER DELTA'", + # Here are the non-f-string versions, + # which should give the same errors. + r"'\N'", + r"'\N '", + r"'\N '", + r"'\N{'", + r"'\N{GREEK CAPITAL LETTER DELTA'", + ], + ) def test_backslashes_in_expression_part(self): - self.assertEqual(f"{( + self.assertEqual( + f"{( 1 + 2 - )}", "3") - - self.assertEqual("\N{LEFT CURLY BRACKET}", '{') - self.assertEqual(f'{"\N{LEFT CURLY BRACKET}"}', '{') - self.assertEqual(rf'{"\N{LEFT CURLY BRACKET}"}', '{') - - self.assertAllRaise(SyntaxError, - "f-string: valid expression required before '}'", - ["f'{\n}'", - ]) + )}", + "3", + ) + + self.assertEqual("\N{LEFT CURLY BRACKET}", "{") + self.assertEqual(f'{"\N{LEFT CURLY BRACKET}"}', "{") + self.assertEqual(rf'{"\N{LEFT CURLY BRACKET}"}', "{") + + self.assertAllRaise( + SyntaxError, + "f-string: valid expression required before '}'", + [ + "f'{\n}'", + ], + ) def test_invalid_backslashes_inside_fstring_context(self): # All of these variations are invalid python syntax, @@ -990,23 +1091,27 @@ def test_invalid_backslashes_inside_fstring_context(self): r"\\"[0], ] ] - self.assertAllRaise(SyntaxError, 'unexpected character after line continuation', - cases) + self.assertAllRaise( + SyntaxError, "unexpected character after line continuation", cases + ) def test_no_escapes_for_braces(self): """ Only literal curly braces begin an expression. """ # \x7b is '{'. - self.assertEqual(f'\x7b1+1}}', '{1+1}') - self.assertEqual(f'\x7b1+1', '{1+1') - self.assertEqual(f'\u007b1+1', '{1+1') - self.assertEqual(f'\N{LEFT CURLY BRACKET}1+1\N{RIGHT CURLY BRACKET}', '{1+1}') + self.assertEqual(f"\x7b1+1}}", "{1+1}") + self.assertEqual(f"\x7b1+1", "{1+1") + self.assertEqual(f"\u007b1+1", "{1+1") + self.assertEqual(f"\N{LEFT CURLY BRACKET}1+1\N{RIGHT CURLY BRACKET}", "{1+1}") def test_newlines_in_expressions(self): - self.assertEqual(f'{0}', '0') - self.assertEqual(rf'''{3+ -4}''', '7') + self.assertEqual(f"{0}", "0") + self.assertEqual( + rf"""{3+ +4}""", + "7", + ) def test_lambda(self): x = 5 @@ -1017,57 +1122,61 @@ def test_lambda(self): # lambda doesn't work without parens, because the colon # makes the parser think it's a format_spec # emit warning if we can match a format_spec - self.assertAllRaise(SyntaxError, - "f-string: lambda expressions are not allowed " - "without parentheses", - ["f'{lambda x:x}'", - "f'{lambda :x}'", - "f'{lambda *arg, :x}'", - "f'{1, lambda:x}'", - "f'{lambda x:}'", - "f'{lambda :}'", - ]) + self.assertAllRaise( + SyntaxError, + "f-string: lambda expressions are not allowed " "without parentheses", + [ + "f'{lambda x:x}'", + "f'{lambda :x}'", + "f'{lambda *arg, :x}'", + "f'{1, lambda:x}'", + "f'{lambda x:}'", + "f'{lambda :}'", + ], + ) # Ensure the detection of invalid lambdas doesn't trigger detection # for valid lambdas in the second error pass with self.assertRaisesRegex(SyntaxError, "invalid syntax"): compile("lambda name_3=f'{name_4}': {name_3}\n1 $ 1", "", "exec") # but don't emit the paren warning in general cases - with self.assertRaisesRegex(SyntaxError, "f-string: expecting a valid expression after '{'"): + with self.assertRaisesRegex( + SyntaxError, "f-string: expecting a valid expression after '{'" + ): eval("f'{+ lambda:None}'") def test_valid_prefixes(self): - self.assertEqual(F'{1}', "1") - self.assertEqual(FR'{2}', "2") - self.assertEqual(fR'{3}', "3") + self.assertEqual(f"{1}", "1") + self.assertEqual(Rf"{2}", "2") + self.assertEqual(Rf"{3}", "3") def test_roundtrip_raw_quotes(self): - self.assertEqual(fr"\'", "\\'") - self.assertEqual(fr'\"', '\\"') - self.assertEqual(fr'\"\'', '\\"\\\'') - self.assertEqual(fr'\'\"', '\\\'\\"') - self.assertEqual(fr'\"\'\"', '\\"\\\'\\"') - self.assertEqual(fr'\'\"\'', '\\\'\\"\\\'') - self.assertEqual(fr'\"\'\"\'', '\\"\\\'\\"\\\'') + self.assertEqual(rf"\'", "\\'") + self.assertEqual(rf"\"", '\\"') + self.assertEqual(rf"\"\'", "\\\"\\'") + self.assertEqual(rf"\'\"", "\\'\\\"") + self.assertEqual(rf"\"\'\"", '\\"\\\'\\"') + self.assertEqual(rf"\'\"\'", "\\'\\\"\\'") + self.assertEqual(rf"\"\'\"\'", "\\\"\\'\\\"\\'") def test_fstring_backslash_before_double_bracket(self): deprecated_cases = [ - (r"f'\{{\}}'", '\\{\\}'), - (r"f'\{{'", '\\{'), - (r"f'\{{{1+1}'", '\\{2'), - (r"f'\}}{1+1}'", '\\}2'), - (r"f'{1+1}\}}'", '2\\}') + (r"f'\{{\}}'", "\\{\\}"), + (r"f'\{{'", "\\{"), + (r"f'\{{{1+1}'", "\\{2"), + (r"f'\}}{1+1}'", "\\}2"), + (r"f'{1+1}\}}'", "2\\}"), ] for case, expected_result in deprecated_cases: with self.subTest(case=case, expected_result=expected_result): with self.assertWarns(SyntaxWarning): result = eval(case) self.assertEqual(result, expected_result) - self.assertEqual(fr'\{{\}}', '\\{\\}') - self.assertEqual(fr'\{{', '\\{') - self.assertEqual(fr'\{{{1+1}', '\\{2') - self.assertEqual(fr'\}}{1+1}', '\\}2') - self.assertEqual(fr'{1+1}\}}', '2\\}') + self.assertEqual(rf"\{{\}}", "\\{\\}") + self.assertEqual(rf"\{{", "\\{") + self.assertEqual(rf"\{{{1+1}", "\\{2") + self.assertEqual(rf"\}}{1+1}", "\\}2") + self.assertEqual(rf"{1+1}\}}", "2\\}") def test_fstring_backslash_before_double_bracket_warns_once(self): with self.assertWarns(SyntaxWarning) as w: @@ -1076,18 +1185,18 @@ def test_fstring_backslash_before_double_bracket_warns_once(self): self.assertEqual(w.warnings[0].category, SyntaxWarning) def test_fstring_backslash_prefix_raw(self): - self.assertEqual(f'\\', '\\') - self.assertEqual(f'\\\\', '\\\\') - self.assertEqual(fr'\\', r'\\') - self.assertEqual(fr'\\\\', r'\\\\') - self.assertEqual(rf'\\', r'\\') - self.assertEqual(rf'\\\\', r'\\\\') - self.assertEqual(Rf'\\', R'\\') - self.assertEqual(Rf'\\\\', R'\\\\') - self.assertEqual(fR'\\', R'\\') - self.assertEqual(fR'\\\\', R'\\\\') - self.assertEqual(FR'\\', R'\\') - self.assertEqual(FR'\\\\', R'\\\\') + self.assertEqual(f"\\", "\\") + self.assertEqual(f"\\\\", "\\\\") + self.assertEqual(rf"\\", r"\\") + self.assertEqual(rf"\\\\", r"\\\\") + self.assertEqual(rf"\\", r"\\") + self.assertEqual(rf"\\\\", r"\\\\") + self.assertEqual(Rf"\\", R"\\") + self.assertEqual(Rf"\\\\", R"\\\\") + self.assertEqual(Rf"\\", R"\\") + self.assertEqual(Rf"\\\\", R"\\\\") + self.assertEqual(Rf"\\", R"\\") + self.assertEqual(Rf"\\\\", R"\\\\") def test_fstring_format_spec_greedy_matching(self): self.assertEqual(f"{1:}}}", "1}") @@ -1097,8 +1206,8 @@ def test_yield(self): # Not terribly useful, but make sure the yield turns # a function into a generator def fn(y): - f'y:{yield y*2}' - f'{yield}' + f"y:{yield y*2}" + f"{yield}" g = fn(4) self.assertEqual(next(g), 8) @@ -1106,15 +1215,15 @@ def fn(y): def test_yield_send(self): def fn(x): - yield f'x:{yield (lambda i: x * i)}' + yield f"x:{yield (lambda i: x * i)}" g = fn(10) the_lambda = next(g) self.assertEqual(the_lambda(4), 40) - self.assertEqual(g.send('string'), 'x:string') + self.assertEqual(g.send("string"), "x:string") def test_expressions_with_triple_quoted_strings(self): - self.assertEqual(f"{'''x'''}", 'x') + self.assertEqual(f"{'''x'''}", "x") self.assertEqual(f"{'''eric's'''}", "eric's") # Test concatenation within an expression @@ -1127,263 +1236,302 @@ def test_expressions_with_triple_quoted_strings(self): def test_multiple_vars(self): x = 98 - y = 'abc' - self.assertEqual(f'{x}{y}', '98abc') + y = "abc" + self.assertEqual(f"{x}{y}", "98abc") - self.assertEqual(f'X{x}{y}', 'X98abc') - self.assertEqual(f'{x}X{y}', '98Xabc') - self.assertEqual(f'{x}{y}X', '98abcX') + self.assertEqual(f"X{x}{y}", "X98abc") + self.assertEqual(f"{x}X{y}", "98Xabc") + self.assertEqual(f"{x}{y}X", "98abcX") - self.assertEqual(f'X{x}Y{y}', 'X98Yabc') - self.assertEqual(f'X{x}{y}Y', 'X98abcY') - self.assertEqual(f'{x}X{y}Y', '98XabcY') + self.assertEqual(f"X{x}Y{y}", "X98Yabc") + self.assertEqual(f"X{x}{y}Y", "X98abcY") + self.assertEqual(f"{x}X{y}Y", "98XabcY") - self.assertEqual(f'X{x}Y{y}Z', 'X98YabcZ') + self.assertEqual(f"X{x}Y{y}Z", "X98YabcZ") def test_closure(self): def outer(x): def inner(): - return f'x:{x}' + return f"x:{x}" + return inner - self.assertEqual(outer('987')(), 'x:987') - self.assertEqual(outer(7)(), 'x:7') + self.assertEqual(outer("987")(), "x:987") + self.assertEqual(outer(7)(), "x:7") def test_arguments(self): y = 2 + def f(x, width): - return f'x={x*y:{width}}' + return f"x={x*y:{width}}" - self.assertEqual(f('foo', 10), 'x=foofoo ') - x = 'bar' - self.assertEqual(f(10, 10), 'x= 20') + self.assertEqual(f("foo", 10), "x=foofoo ") + x = "bar" + self.assertEqual(f(10, 10), "x= 20") def test_locals(self): value = 123 - self.assertEqual(f'v:{value}', 'v:123') + self.assertEqual(f"v:{value}", "v:123") def test_missing_variable(self): with self.assertRaises(NameError): - f'v:{value}' + f"v:{value}" def test_missing_format_spec(self): class O: def __format__(self, spec): if not spec: - return '*' + return "*" return spec - self.assertEqual(f'{O():x}', 'x') - self.assertEqual(f'{O()}', '*') - self.assertEqual(f'{O():}', '*') + self.assertEqual(f"{O():x}", "x") + self.assertEqual(f"{O()}", "*") + self.assertEqual(f"{O():}", "*") - self.assertEqual(f'{3:}', '3') - self.assertEqual(f'{3!s:}', '3') + self.assertEqual(f"{3:}", "3") + self.assertEqual(f"{3!s:}", "3") def test_global(self): - self.assertEqual(f'g:{a_global}', 'g:global variable') - self.assertEqual(f'g:{a_global!r}', "g:'global variable'") + self.assertEqual(f"g:{a_global}", "g:global variable") + self.assertEqual(f"g:{a_global!r}", "g:'global variable'") - a_local = 'local variable' - self.assertEqual(f'g:{a_global} l:{a_local}', - 'g:global variable l:local variable') - self.assertEqual(f'g:{a_global!r}', - "g:'global variable'") - self.assertEqual(f'g:{a_global} l:{a_local!r}', - "g:global variable l:'local variable'") + a_local = "local variable" + self.assertEqual( + f"g:{a_global} l:{a_local}", "g:global variable l:local variable" + ) + self.assertEqual(f"g:{a_global!r}", "g:'global variable'") + self.assertEqual( + f"g:{a_global} l:{a_local!r}", "g:global variable l:'local variable'" + ) - self.assertIn("module 'unittest' from", f'{unittest}') + self.assertIn("module 'unittest' from", f"{unittest}") def test_shadowed_global(self): - a_global = 'really a local' - self.assertEqual(f'g:{a_global}', 'g:really a local') - self.assertEqual(f'g:{a_global!r}', "g:'really a local'") - - a_local = 'local variable' - self.assertEqual(f'g:{a_global} l:{a_local}', - 'g:really a local l:local variable') - self.assertEqual(f'g:{a_global!r}', - "g:'really a local'") - self.assertEqual(f'g:{a_global} l:{a_local!r}', - "g:really a local l:'local variable'") + a_global = "really a local" + self.assertEqual(f"g:{a_global}", "g:really a local") + self.assertEqual(f"g:{a_global!r}", "g:'really a local'") + + a_local = "local variable" + self.assertEqual( + f"g:{a_global} l:{a_local}", "g:really a local l:local variable" + ) + self.assertEqual(f"g:{a_global!r}", "g:'really a local'") + self.assertEqual( + f"g:{a_global} l:{a_local!r}", "g:really a local l:'local variable'" + ) def test_call(self): def foo(x): - return 'x=' + str(x) + return "x=" + str(x) - self.assertEqual(f'{foo(10)}', 'x=10') + self.assertEqual(f"{foo(10)}", "x=10") def test_nested_fstrings(self): y = 5 - self.assertEqual(f'{f"{0}"*3}', '000') - self.assertEqual(f'{f"{y}"*3}', '555') + self.assertEqual(f'{f"{0}"*3}', "000") + self.assertEqual(f'{f"{y}"*3}', "555") def test_invalid_string_prefixes(self): - single_quote_cases = ["fu''", - "uf''", - "Fu''", - "fU''", - "Uf''", - "uF''", - "ufr''", - "urf''", - "fur''", - "fru''", - "rfu''", - "ruf''", - "FUR''", - "Fur''", - "fb''", - "fB''", - "Fb''", - "FB''", - "bf''", - "bF''", - "Bf''", - "BF''",] + single_quote_cases = [ + "fu''", + "uf''", + "Fu''", + "fU''", + "Uf''", + "uF''", + "ufr''", + "urf''", + "fur''", + "fru''", + "rfu''", + "ruf''", + "FUR''", + "Fur''", + "fb''", + "fB''", + "Fb''", + "FB''", + "bf''", + "bF''", + "Bf''", + "BF''", + ] double_quote_cases = [case.replace("'", '"') for case in single_quote_cases] - self.assertAllRaise(SyntaxError, 'invalid syntax', - single_quote_cases + double_quote_cases) + self.assertAllRaise( + SyntaxError, "invalid syntax", single_quote_cases + double_quote_cases + ) def test_leading_trailing_spaces(self): - self.assertEqual(f'{ 3}', '3') - self.assertEqual(f'{ 3}', '3') - self.assertEqual(f'{3 }', '3') - self.assertEqual(f'{3 }', '3') + self.assertEqual(f"{ 3}", "3") + self.assertEqual(f"{ 3}", "3") + self.assertEqual(f"{3 }", "3") + self.assertEqual(f"{3 }", "3") - self.assertEqual(f'expr={ {x: y for x, y in [(1, 2), ]}}', - 'expr={1: 2}') - self.assertEqual(f'expr={ {x: y for x, y in [(1, 2), ]} }', - 'expr={1: 2}') + self.assertEqual(f"expr={ {x: y for x, y in [(1, 2), ]}}", "expr={1: 2}") + self.assertEqual(f"expr={ {x: y for x, y in [(1, 2), ]} }", "expr={1: 2}") def test_not_equal(self): # There's a special test for this because there's a special # case in the f-string parser to look for != as not ending an # expression. Normally it would, while looking for !s or !r. - self.assertEqual(f'{3!=4}', 'True') - self.assertEqual(f'{3!=4:}', 'True') - self.assertEqual(f'{3!=4!s}', 'True') - self.assertEqual(f'{3!=4!s:.3}', 'Tru') + self.assertEqual(f"{3!=4}", "True") + self.assertEqual(f"{3!=4:}", "True") + self.assertEqual(f"{3!=4!s}", "True") + self.assertEqual(f"{3!=4!s:.3}", "Tru") def test_equal_equal(self): # Because an expression ending in = has special meaning, # there's a special test for ==. Make sure it works. - self.assertEqual(f'{0==1}', 'False') + self.assertEqual(f"{0==1}", "False") def test_conversions(self): - self.assertEqual(f'{3.14:10.10}', ' 3.14') - self.assertEqual(f'{3.14!s:10.10}', '3.14 ') - self.assertEqual(f'{3.14!r:10.10}', '3.14 ') - self.assertEqual(f'{3.14!a:10.10}', '3.14 ') + self.assertEqual(f"{3.14:10.10}", " 3.14") + self.assertEqual(f"{3.14!s:10.10}", "3.14 ") + self.assertEqual(f"{3.14!r:10.10}", "3.14 ") + self.assertEqual(f"{3.14!a:10.10}", "3.14 ") - self.assertEqual(f'{"a"}', 'a') + self.assertEqual(f'{"a"}', "a") self.assertEqual(f'{"a"!r}', "'a'") self.assertEqual(f'{"a"!a}', "'a'") # Conversions can have trailing whitespace after them since it # does not provide any significance self.assertEqual(f"{3!s }", "3") - self.assertEqual(f'{3.14!s :10.10}', '3.14 ') + self.assertEqual(f"{3.14!s :10.10}", "3.14 ") # Not a conversion. self.assertEqual(f'{"a!r"}', "a!r") # Not a conversion, but show that ! is allowed in a format spec. - self.assertEqual(f'{3.14:!<10.10}', '3.14!!!!!!') - - self.assertAllRaise(SyntaxError, "f-string: expecting '}'", - ["f'{3!'", - "f'{3!s'", - "f'{3!g'", - ]) - - self.assertAllRaise(SyntaxError, 'f-string: missing conversion character', - ["f'{3!}'", - "f'{3!:'", - "f'{3!:}'", - ]) - - for conv_identifier in 'g', 'A', 'G', 'ä', 'ɐ': - self.assertAllRaise(SyntaxError, - "f-string: invalid conversion character %r: " - "expected 's', 'r', or 'a'" % conv_identifier, - ["f'{3!" + conv_identifier + "}'"]) - - for conv_non_identifier in '3', '!': - self.assertAllRaise(SyntaxError, - "f-string: invalid conversion character", - ["f'{3!" + conv_non_identifier + "}'"]) - - for conv in ' s', ' s ': - self.assertAllRaise(SyntaxError, - "f-string: conversion type must come right after the" - " exclamanation mark", - ["f'{3!" + conv + "}'"]) - - self.assertAllRaise(SyntaxError, - "f-string: invalid conversion character 'ss': " - "expected 's', 'r', or 'a'", - ["f'{3!ss}'", - "f'{3!ss:}'", - "f'{3!ss:s}'", - ]) + self.assertEqual(f"{3.14:!<10.10}", "3.14!!!!!!") + + self.assertAllRaise( + SyntaxError, + "f-string: expecting '}'", + [ + "f'{3!'", + "f'{3!s'", + "f'{3!g'", + ], + ) + + self.assertAllRaise( + SyntaxError, + "f-string: missing conversion character", + [ + "f'{3!}'", + "f'{3!:'", + "f'{3!:}'", + ], + ) + + for conv_identifier in "g", "A", "G", "ä", "ɐ": + self.assertAllRaise( + SyntaxError, + "f-string: invalid conversion character %r: " + "expected 's', 'r', or 'a'" % conv_identifier, + ["f'{3!" + conv_identifier + "}'"], + ) + + for conv_non_identifier in "3", "!": + self.assertAllRaise( + SyntaxError, + "f-string: invalid conversion character", + ["f'{3!" + conv_non_identifier + "}'"], + ) + + for conv in " s", " s ": + self.assertAllRaise( + SyntaxError, + "f-string: conversion type must come right after the" + " exclamanation mark", + ["f'{3!" + conv + "}'"], + ) + + self.assertAllRaise( + SyntaxError, + "f-string: invalid conversion character 'ss': " "expected 's', 'r', or 'a'", + [ + "f'{3!ss}'", + "f'{3!ss:}'", + "f'{3!ss:s}'", + ], + ) def test_assignment(self): - self.assertAllRaise(SyntaxError, r'invalid syntax', - ["f'' = 3", - "f'{0}' = x", - "f'{x}' = x", - ]) + self.assertAllRaise( + SyntaxError, + r"invalid syntax", + [ + "f'' = 3", + "f'{0}' = x", + "f'{x}' = x", + ], + ) def test_del(self): - self.assertAllRaise(SyntaxError, 'invalid syntax', - ["del f''", - "del '' f''", - ]) + self.assertAllRaise( + SyntaxError, + "invalid syntax", + [ + "del f''", + "del '' f''", + ], + ) def test_mismatched_braces(self): - self.assertAllRaise(SyntaxError, "f-string: single '}' is not allowed", - ["f'{{}'", - "f'{{}}}'", - "f'}'", - "f'x}'", - "f'x}x'", - r"f'\u007b}'", - - # Can't have { or } in a format spec. - "f'{3:}>10}'", - "f'{3:}}>10}'", - ]) - - self.assertAllRaise(SyntaxError, "f-string: expecting '}'", - ["f'{3'", - "f'{3!'", - "f'{3:'", - "f'{3!s'", - "f'{3!s:'", - "f'{3!s:3'", - "f'x{'", - "f'x{x'", - "f'{x'", - "f'{3:s'", - "f'{{{'", - "f'{{}}{'", - "f'{'", - "f'{i='", # See gh-93418. - ]) - - self.assertAllRaise(SyntaxError, - "f-string: expecting a valid expression after '{'", - ["f'{3:{{>10}'", - ]) + self.assertAllRaise( + SyntaxError, + "f-string: single '}' is not allowed", + [ + "f'{{}'", + "f'{{}}}'", + "f'}'", + "f'x}'", + "f'x}x'", + r"f'\u007b}'", + # Can't have { or } in a format spec. + "f'{3:}>10}'", + "f'{3:}}>10}'", + ], + ) + + self.assertAllRaise( + SyntaxError, + "f-string: expecting '}'", + [ + "f'{3'", + "f'{3!'", + "f'{3:'", + "f'{3!s'", + "f'{3!s:'", + "f'{3!s:3'", + "f'x{'", + "f'x{x'", + "f'{x'", + "f'{3:s'", + "f'{{{'", + "f'{{}}{'", + "f'{'", + "f'{i='", # See gh-93418. + ], + ) + + self.assertAllRaise( + SyntaxError, + "f-string: expecting a valid expression after '{'", + [ + "f'{3:{{>10}'", + ], + ) # But these are just normal strings. - self.assertEqual(f'{"{"}', '{') - self.assertEqual(f'{"}"}', '}') - self.assertEqual(f'{3:{"}"}>10}', '}}}}}}}}}3') - self.assertEqual(f'{2:{"{"}>10}', '{{{{{{{{{2') + self.assertEqual(f'{"{"}', "{") + self.assertEqual(f'{"}"}', "}") + self.assertEqual(f'{3:{"}"}>10}', "}}}}}}}}}3") + self.assertEqual(f'{2:{"{"}>10}', "{{{{{{{{{2") def test_if_conditional(self): # There's special logic in compile.c to test if the @@ -1392,7 +1540,7 @@ def test_if_conditional(self): def test_fstring(x, expected): flag = 0 - if f'{x}': + if f"{x}": flag = 1 else: flag = 2 @@ -1400,7 +1548,7 @@ def test_fstring(x, expected): def test_concat_empty(x, expected): flag = 0 - if '' f'{x}': + if "" f"{x}": flag = 1 else: flag = 2 @@ -1408,137 +1556,149 @@ def test_concat_empty(x, expected): def test_concat_non_empty(x, expected): flag = 0 - if ' ' f'{x}': + if " " f"{x}": flag = 1 else: flag = 2 self.assertEqual(flag, expected) - test_fstring('', 2) - test_fstring(' ', 1) + test_fstring("", 2) + test_fstring(" ", 1) - test_concat_empty('', 2) - test_concat_empty(' ', 1) + test_concat_empty("", 2) + test_concat_empty(" ", 1) - test_concat_non_empty('', 1) - test_concat_non_empty(' ', 1) + test_concat_non_empty("", 1) + test_concat_non_empty(" ", 1) def test_empty_format_specifier(self): - x = 'test' - self.assertEqual(f'{x}', 'test') - self.assertEqual(f'{x:}', 'test') - self.assertEqual(f'{x!s:}', 'test') - self.assertEqual(f'{x!r:}', "'test'") + x = "test" + self.assertEqual(f"{x}", "test") + self.assertEqual(f"{x:}", "test") + self.assertEqual(f"{x!s:}", "test") + self.assertEqual(f"{x!r:}", "'test'") def test_str_format_differences(self): - d = {'a': 'string', - 0: 'integer', - } + d = { + "a": "string", + 0: "integer", + } a = 0 - self.assertEqual(f'{d[0]}', 'integer') - self.assertEqual(f'{d["a"]}', 'string') - self.assertEqual(f'{d[a]}', 'integer') - self.assertEqual('{d[a]}'.format(d=d), 'string') - self.assertEqual('{d[0]}'.format(d=d), 'integer') + self.assertEqual(f"{d[0]}", "integer") + self.assertEqual(f'{d["a"]}', "string") + self.assertEqual(f"{d[a]}", "integer") + self.assertEqual("{d[a]}".format(d=d), "string") + self.assertEqual("{d[0]}".format(d=d), "integer") def test_errors(self): # see issue 26287 - self.assertAllRaise(TypeError, 'unsupported', - [r"f'{(lambda: 0):x}'", - r"f'{(0,):x}'", - ]) - self.assertAllRaise(ValueError, 'Unknown format code', - [r"f'{1000:j}'", - r"f'{1000:j}'", - ]) + self.assertAllRaise( + TypeError, + "unsupported", + [ + r"f'{(lambda: 0):x}'", + r"f'{(0,):x}'", + ], + ) + self.assertAllRaise( + ValueError, + "Unknown format code", + [ + r"f'{1000:j}'", + r"f'{1000:j}'", + ], + ) def test_filename_in_syntaxerror(self): # see issue 38964 with temp_cwd() as cwd: - file_path = os.path.join(cwd, 't.py') - with open(file_path, 'w', encoding="utf-8") as f: - f.write('f"{a b}"') # This generates a SyntaxError - _, _, stderr = assert_python_failure(file_path, - PYTHONIOENCODING='ascii') - self.assertIn(file_path.encode('ascii', 'backslashreplace'), stderr) + file_path = os.path.join(cwd, "t.py") + with open(file_path, "w", encoding="utf-8") as f: + f.write('f"{a b}"') # This generates a SyntaxError + _, _, stderr = assert_python_failure(file_path, PYTHONIOENCODING="ascii") + self.assertIn(file_path.encode("ascii", "backslashreplace"), stderr) def test_loop(self): for i in range(1000): - self.assertEqual(f'i:{i}', 'i:' + str(i)) + self.assertEqual(f"i:{i}", "i:" + str(i)) def test_dict(self): - d = {'"': 'dquote', - "'": 'squote', - 'foo': 'bar', - } - self.assertEqual(f'''{d["'"]}''', 'squote') - self.assertEqual(f"""{d['"']}""", 'dquote') + d = { + '"': "dquote", + "'": "squote", + "foo": "bar", + } + self.assertEqual(f"""{d["'"]}""", "squote") + self.assertEqual(f"""{d['"']}""", "dquote") - self.assertEqual(f'{d["foo"]}', 'bar') - self.assertEqual(f"{d['foo']}", 'bar') + self.assertEqual(f'{d["foo"]}', "bar") + self.assertEqual(f"{d['foo']}", "bar") def test_backslash_char(self): # Check eval of a backslash followed by a control char. # See bpo-30682: this used to raise an assert in pydebug mode. - self.assertEqual(eval('f"\\\n"'), '') - self.assertEqual(eval('f"\\\r"'), '') + self.assertEqual(eval('f"\\\n"'), "") + self.assertEqual(eval('f"\\\r"'), "") def test_debug_conversion(self): - x = 'A string' - self.assertEqual(f'{x=}', 'x=' + repr(x)) - self.assertEqual(f'{x =}', 'x =' + repr(x)) - self.assertEqual(f'{x=!s}', 'x=' + str(x)) - self.assertEqual(f'{x=!r}', 'x=' + repr(x)) - self.assertEqual(f'{x=!a}', 'x=' + ascii(x)) + x = "A string" + self.assertEqual(f"{x=}", "x=" + repr(x)) + self.assertEqual(f"{x =}", "x =" + repr(x)) + self.assertEqual(f"{x=!s}", "x=" + str(x)) + self.assertEqual(f"{x=!r}", "x=" + repr(x)) + self.assertEqual(f"{x=!a}", "x=" + ascii(x)) x = 2.71828 - self.assertEqual(f'{x=:.2f}', 'x=' + format(x, '.2f')) - self.assertEqual(f'{x=:}', 'x=' + format(x, '')) - self.assertEqual(f'{x=!r:^20}', 'x=' + format(repr(x), '^20')) - self.assertEqual(f'{x=!s:^20}', 'x=' + format(str(x), '^20')) - self.assertEqual(f'{x=!a:^20}', 'x=' + format(ascii(x), '^20')) + self.assertEqual(f"{x=:.2f}", "x=" + format(x, ".2f")) + self.assertEqual(f"{x=:}", "x=" + format(x, "")) + self.assertEqual(f"{x=!r:^20}", "x=" + format(repr(x), "^20")) + self.assertEqual(f"{x=!s:^20}", "x=" + format(str(x), "^20")) + self.assertEqual(f"{x=!a:^20}", "x=" + format(ascii(x), "^20")) x = 9 - self.assertEqual(f'{3*x+15=}', '3*x+15=42') + self.assertEqual(f"{3*x+15=}", "3*x+15=42") # There is code in ast.c that deals with non-ascii expression values. So, # use a unicode identifier to trigger that. tenπ = 31.4 - self.assertEqual(f'{tenπ=:.2f}', 'tenπ=31.40') + self.assertEqual(f"{tenπ=:.2f}", "tenπ=31.40") # Also test with Unicode in non-identifiers. - self.assertEqual(f'{"Σ"=}', '"Σ"=\'Σ\'') + self.assertEqual(f'{"Σ"=}', "\"Σ\"='Σ'") # Make sure nested fstrings still work. - self.assertEqual(f'{f"{3.1415=:.1f}":*^20}', '*****3.1415=3.1*****') + self.assertEqual(f'{f"{3.1415=:.1f}":*^20}', "*****3.1415=3.1*****") # Make sure text before and after an expression with = works # correctly. - pi = 'π' - self.assertEqual(f'alpha α {pi=} ω omega', "alpha α pi='π' ω omega") + pi = "π" + self.assertEqual(f"alpha α {pi=} ω omega", "alpha α pi='π' ω omega") # Check multi-line expressions. - self.assertEqual(f'''{ + self.assertEqual( + f"""{ 3 -=}''', '\n3\n=3') +=}""", + "\n3\n=3", + ) # Since = is handled specially, make sure all existing uses of # it still work. - self.assertEqual(f'{0==1}', 'False') - self.assertEqual(f'{0!=1}', 'True') - self.assertEqual(f'{0<=1}', 'True') - self.assertEqual(f'{0>=1}', 'False') - self.assertEqual(f'{(x:="5")}', '5') - self.assertEqual(x, '5') - self.assertEqual(f'{(x:=5)}', '5') + self.assertEqual(f"{0==1}", "False") + self.assertEqual(f"{0!=1}", "True") + self.assertEqual(f"{0<=1}", "True") + self.assertEqual(f"{0>=1}", "False") + self.assertEqual(f'{(x:="5")}', "5") + self.assertEqual(x, "5") + self.assertEqual(f"{(x:=5)}", "5") self.assertEqual(x, 5) - self.assertEqual(f'{"="}', '=') + self.assertEqual(f'{"="}', "=") x = 20 # This isn't an assignment expression, it's 'x', with a format # spec of '=10'. See test_walrus: you need to use parens. - self.assertEqual(f'{x:=10}', ' 20') + self.assertEqual(f"{x:=10}", " 20") # Test named function parameters, to make sure '=' parsing works # there. @@ -1547,40 +1707,53 @@ def f(a): oldx = x x = a return oldx + x = 0 - self.assertEqual(f'{f(a="3=")}', '0') - self.assertEqual(x, '3=') - self.assertEqual(f'{f(a=4)}', '3=') + self.assertEqual(f'{f(a="3=")}', "0") + self.assertEqual(x, "3=") + self.assertEqual(f"{f(a=4)}", "3=") self.assertEqual(x, 4) + # Check debug expressions in format spec + y = 20 + self.assertEqual(f"{2:{y=}}", "yyyyyyyyyyyyyyyyyyy2") + self.assertEqual( + f"{datetime.datetime.now():h1{y=}h2{y=}h3{y=}}", "h1y=20h2y=20h3y=20" + ) + # Make sure __format__ is being called. class C: def __format__(self, s): - return f'FORMAT-{s}' + return f"FORMAT-{s}" + def __repr__(self): - return 'REPR' + return "REPR" - self.assertEqual(f'{C()=}', 'C()=REPR') - self.assertEqual(f'{C()=!r}', 'C()=REPR') - self.assertEqual(f'{C()=:}', 'C()=FORMAT-') - self.assertEqual(f'{C()=: }', 'C()=FORMAT- ') - self.assertEqual(f'{C()=:x}', 'C()=FORMAT-x') - self.assertEqual(f'{C()=!r:*^20}', 'C()=********REPR********') + self.assertEqual(f"{C()=}", "C()=REPR") + self.assertEqual(f"{C()=!r}", "C()=REPR") + self.assertEqual(f"{C()=:}", "C()=FORMAT-") + self.assertEqual(f"{C()=: }", "C()=FORMAT- ") + self.assertEqual(f"{C()=:x}", "C()=FORMAT-x") + self.assertEqual(f"{C()=!r:*^20}", "C()=********REPR********") + self.assertEqual(f"{C():{20=}}", "FORMAT-20=20") self.assertRaises(SyntaxError, eval, "f'{C=]'") # Make sure leading and following text works. - x = 'foo' - self.assertEqual(f'X{x=}Y', 'Xx='+repr(x)+'Y') + x = "foo" + self.assertEqual(f"X{x=}Y", "Xx=" + repr(x) + "Y") # Make sure whitespace around the = works. - self.assertEqual(f'X{x =}Y', 'Xx ='+repr(x)+'Y') - self.assertEqual(f'X{x= }Y', 'Xx= '+repr(x)+'Y') - self.assertEqual(f'X{x = }Y', 'Xx = '+repr(x)+'Y') + self.assertEqual(f"X{x =}Y", "Xx =" + repr(x) + "Y") + self.assertEqual(f"X{x= }Y", "Xx= " + repr(x) + "Y") + self.assertEqual(f"X{x = }Y", "Xx = " + repr(x) + "Y") self.assertEqual(f"sadsd {1 + 1 = :{1 + 1:1d}f}", "sadsd 1 + 1 = 2.000000") - self.assertEqual(f"{1+2 = # my comment - }", '1+2 = \n 3') + self.assertEqual( + f"{1+2 = # my comment + }", + "1+2 = \n 3", + ) # These next lines contains tabs. Backslash escapes don't # work in f-strings. @@ -1588,56 +1761,59 @@ def __repr__(self): # this will be to dynamically created and exec the f-strings. But # that's such a hassle I'll save it for another day. For now, convert # the tabs to spaces just to shut up patchcheck. - #self.assertEqual(f'X{x =}Y', 'Xx\t='+repr(x)+'Y') - #self.assertEqual(f'X{x = }Y', 'Xx\t=\t'+repr(x)+'Y') + # self.assertEqual(f'X{x =}Y', 'Xx\t='+repr(x)+'Y') + # self.assertEqual(f'X{x = }Y', 'Xx\t=\t'+repr(x)+'Y') def test_walrus(self): x = 20 # This isn't an assignment expression, it's 'x', with a format # spec of '=10'. - self.assertEqual(f'{x:=10}', ' 20') + self.assertEqual(f"{x:=10}", " 20") # This is an assignment expression, which requires parens. - self.assertEqual(f'{(x:=10)}', '10') + self.assertEqual(f"{(x:=10)}", "10") self.assertEqual(x, 10) def test_invalid_syntax_error_message(self): - with self.assertRaisesRegex(SyntaxError, - "f-string: expecting '=', or '!', or ':', or '}'"): + with self.assertRaisesRegex( + SyntaxError, "f-string: expecting '=', or '!', or ':', or '}'" + ): compile("f'{a $ b}'", "?", "exec") def test_with_two_commas_in_format_specifier(self): error_msg = re.escape("Cannot specify ',' with ','.") with self.assertRaisesRegex(ValueError, error_msg): - f'{1:,,}' + f"{1:,,}" def test_with_two_underscore_in_format_specifier(self): error_msg = re.escape("Cannot specify '_' with '_'.") with self.assertRaisesRegex(ValueError, error_msg): - f'{1:__}' + f"{1:__}" def test_with_a_commas_and_an_underscore_in_format_specifier(self): error_msg = re.escape("Cannot specify both ',' and '_'.") with self.assertRaisesRegex(ValueError, error_msg): - f'{1:,_}' + f"{1:,_}" def test_with_an_underscore_and_a_comma_in_format_specifier(self): error_msg = re.escape("Cannot specify both ',' and '_'.") with self.assertRaisesRegex(ValueError, error_msg): - f'{1:_,}' + f"{1:_,}" def test_syntax_error_for_starred_expressions(self): with self.assertRaisesRegex(SyntaxError, "can't use starred expression here"): compile("f'{*a}'", "?", "exec") - with self.assertRaisesRegex(SyntaxError, - "f-string: expecting a valid expression after '{'"): + with self.assertRaisesRegex( + SyntaxError, "f-string: expecting a valid expression after '{'" + ): compile("f'{**a}'", "?", "exec") def test_not_closing_quotes(self): self.assertAllRaise(SyntaxError, "unterminated f-string literal", ['f"', "f'"]) - self.assertAllRaise(SyntaxError, "unterminated triple-quoted f-string literal", - ['f"""', "f'''"]) + self.assertAllRaise( + SyntaxError, "unterminated triple-quoted f-string literal", ['f"""', "f'''"] + ) # Ensure that the errors are reported at the correct line number. data = '''\ x = 1 + 1 @@ -1653,42 +1829,52 @@ def test_not_closing_quotes(self): except SyntaxError as e: self.assertEqual(e.text, 'z = f"""') self.assertEqual(e.lineno, 3) + def test_syntax_error_after_debug(self): - self.assertAllRaise(SyntaxError, "f-string: expecting a valid expression after '{'", - [ - "f'{1=}{;'", - "f'{1=}{+;'", - "f'{1=}{2}{;'", - "f'{1=}{3}{;'", - ]) - self.assertAllRaise(SyntaxError, "f-string: expecting '=', or '!', or ':', or '}'", - [ - "f'{1=}{1;'", - "f'{1=}{1;}'", - ]) + self.assertAllRaise( + SyntaxError, + "f-string: expecting a valid expression after '{'", + [ + "f'{1=}{;'", + "f'{1=}{+;'", + "f'{1=}{2}{;'", + "f'{1=}{3}{;'", + ], + ) + self.assertAllRaise( + SyntaxError, + "f-string: expecting '=', or '!', or ':', or '}'", + [ + "f'{1=}{1;'", + "f'{1=}{1;}'", + ], + ) def test_debug_in_file(self): with temp_cwd(): - script = 'script.py' - with open('script.py', 'w') as f: + script = "script.py" + with open("script.py", "w") as f: f.write(f"""\ print(f'''{{ 3 =}}''')""") _, stdout, _ = assert_python_ok(script) - self.assertEqual(stdout.decode('utf-8').strip().replace('\r\n', '\n').replace('\r', '\n'), - "3\n=3") + self.assertEqual( + stdout.decode("utf-8").strip().replace("\r\n", "\n").replace("\r", "\n"), + "3\n=3", + ) def test_syntax_warning_infinite_recursion_in_file(self): with temp_cwd(): - script = 'script.py' - with open(script, 'w') as f: + script = "script.py" + with open(script, "w") as f: f.write(r"print(f'\{1}')") _, stdout, stderr = assert_python_ok(script) - self.assertIn(rb'\1', stdout) + self.assertIn(rb"\1", stdout) self.assertEqual(len(stderr.strip().splitlines()), 2) -if __name__ == '__main__': + +if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_funcattrs.py b/Lib/test/test_funcattrs.py index 35b473d5..7ab1b0b5 100644 --- a/Lib/test/test_funcattrs.py +++ b/Lib/test/test_funcattrs.py @@ -76,7 +76,12 @@ def test___globals__(self): (AttributeError, TypeError)) def test___builtins__(self): - self.assertIs(self.b.__builtins__, __builtins__) + if __name__ == "__main__": + builtins_dict = __builtins__.__dict__ + else: + builtins_dict = __builtins__ + + self.assertIs(self.b.__builtins__, builtins_dict) self.cannot_set_attr(self.b, '__builtins__', 2, (AttributeError, TypeError)) @@ -86,7 +91,7 @@ def func(s): return len(s) ns = {} func2 = type(func)(func.__code__, ns) self.assertIs(func2.__globals__, ns) - self.assertIs(func2.__builtins__, __builtins__) + self.assertIs(func2.__builtins__, builtins_dict) # Make sure that the function actually works. self.assertEqual(func2("abc"), 3) diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py index 7f1b80a5..ff71fd53 100644 --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -564,6 +564,14 @@ class B: method = functools.partialmethod(func=capture, a=1) def test_repr(self): + self.assertEqual(repr(vars(self.A)['nothing']), + 'functools.partialmethod({})'.format(capture)) + self.assertEqual(repr(vars(self.A)['positional']), + 'functools.partialmethod({}, 1)'.format(capture)) + self.assertEqual(repr(vars(self.A)['keywords']), + 'functools.partialmethod({}, a=2)'.format(capture)) + self.assertEqual(repr(vars(self.A)['spec_keywords']), + 'functools.partialmethod({}, self=1, func=2)'.format(capture)) self.assertEqual(repr(vars(self.A)['both']), 'functools.partialmethod({}, 3, b=4)'.format(capture)) diff --git a/Lib/test/test_future_stmt/test_future.py b/Lib/test/test_future_stmt/test_future.py index 5a85e08e..a06e0510 100644 --- a/Lib/test/test_future_stmt/test_future.py +++ b/Lib/test/test_future_stmt/test_future.py @@ -55,7 +55,7 @@ def test_future_multiple_features(self): def test_badfuture3(self): with self.assertRaises(SyntaxError) as cm: from test.test_future_stmt import badsyntax_future3 - self.check_syntax_error(cm.exception, "badsyntax_future3", 3) + self.check_syntax_error(cm.exception, "badsyntax_future3", 3, 24) def test_badfuture4(self): with self.assertRaises(SyntaxError) as cm: @@ -80,12 +80,12 @@ def test_badfuture7(self): def test_badfuture8(self): with self.assertRaises(SyntaxError) as cm: from test.test_future_stmt import badsyntax_future8 - self.check_syntax_error(cm.exception, "badsyntax_future8", 3) + self.check_syntax_error(cm.exception, "badsyntax_future8", 3, 24) def test_badfuture9(self): with self.assertRaises(SyntaxError) as cm: from test.test_future_stmt import badsyntax_future9 - self.check_syntax_error(cm.exception, "badsyntax_future9", 3) + self.check_syntax_error(cm.exception, "badsyntax_future9", 3, 39) def test_badfuture10(self): with self.assertRaises(SyntaxError) as cm: diff --git a/Lib/test/test_gdb/__init__.py b/Lib/test/test_gdb/__init__.py index 99557739..0dd72178 100644 --- a/Lib/test/test_gdb/__init__.py +++ b/Lib/test/test_gdb/__init__.py @@ -24,6 +24,9 @@ if support.check_cflags_pgo(): raise unittest.SkipTest("test_gdb is not reliable on PGO builds") +if support.check_bolt_optimized(): + raise unittest.SkipTest("test_gdb is not reliable on BOLT optimized builds") + def load_tests(*args): return support.load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index e0da9152..ea6eada0 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -6,6 +6,7 @@ import unittest import weakref import inspect +import types from test import support @@ -89,9 +90,12 @@ def gen(): self.assertEqual(gc.garbage, old_garbage) def test_lambda_generator(self): - # Issue #23192: Test that a lambda returning a generator behaves + # bpo-23192, gh-119897: Test that a lambda returning a generator behaves # like the equivalent function f = lambda: (yield 1) + self.assertIsInstance(f(), types.GeneratorType) + self.assertEqual(next(f()), 1) + def g(): return (yield 1) # test 'yield from' @@ -450,26 +454,6 @@ def g(): self.assertIsInstance(cm.exception.value, StopIteration) self.assertEqual(cm.exception.value.value, 2) - def test_close_releases_frame_locals(self): - # See gh-118272 - - class Foo: - pass - - f = Foo() - f_wr = weakref.ref(f) - - def genfn(): - a = f - yield - - g = genfn() - next(g) - del f - g.close() - support.gc_collect() - self.assertIsNone(f_wr()) - class GeneratorThrowTest(unittest.TestCase): @@ -2161,6 +2145,16 @@ def printsolution(self, x): ... SyntaxError: 'yield' outside function +>>> f=lambda: (yield from (1,2)), (yield from (3,4)) +Traceback (most recent call last): + ... +SyntaxError: 'yield from' outside function + +>>> yield from [1,2] +Traceback (most recent call last): + ... +SyntaxError: 'yield from' outside function + >>> def f(): x = yield = y Traceback (most recent call last): ... diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py index bdfc5bfe..3eefb722 100644 --- a/Lib/test/test_genericpath.py +++ b/Lib/test/test_genericpath.py @@ -158,6 +158,11 @@ def test_exists(self): self.assertIs(self.pathmodule.lexists(filename + '\x00'), False) self.assertIs(self.pathmodule.lexists(bfilename + b'\x00'), False) + # Keyword arguments are accepted + self.assertIs(self.pathmodule.exists(path=filename), True) + if self.pathmodule is not genericpath: + self.assertIs(self.pathmodule.lexists(path=filename), True) + @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") @unittest.skipIf(is_emscripten, "Emscripten pipe fds have no stat") def test_exists_fd(self): diff --git a/Lib/test/test_getopt.py b/Lib/test/test_getopt.py index c8b3442d..2b7d0c4c 100644 --- a/Lib/test/test_getopt.py +++ b/Lib/test/test_getopt.py @@ -1,11 +1,12 @@ # test_getopt.py # David Goodger 2000-08-19 -from test.support.os_helper import EnvironmentVarGuard import doctest -import unittest - import getopt +import sys +import unittest +from test.support.i18n_helper import TestTranslationsBase, update_translation_snapshots +from test.support.os_helper import EnvironmentVarGuard sentinel = object() @@ -173,10 +174,20 @@ def test_libref_examples(): ['a1', 'a2'] """ + +class TestTranslations(TestTranslationsBase): + def test_translations(self): + self.assertMsgidsEqual(getopt) + + def load_tests(loader, tests, pattern): tests.addTest(doctest.DocTestSuite()) return tests -if __name__ == "__main__": +if __name__ == '__main__': + # To regenerate translation snapshots + if len(sys.argv) > 1 and sys.argv[1] == '--snapshot-update': + update_translation_snapshots(getopt) + sys.exit(0) unittest.main() diff --git a/Lib/test/test_getpath.py b/Lib/test/test_getpath.py index b9cbe1d9..3b613a56 100644 --- a/Lib/test/test_getpath.py +++ b/Lib/test/test_getpath.py @@ -557,7 +557,7 @@ def test_framework_macos(self): ns.add_known_dir("/Library/Frameworks/Python.framework/Versions/9.8/lib/python9.8/lib-dynload") ns.add_known_file("/Library/Frameworks/Python.framework/Versions/9.8/lib/python9.8/os.py") - # This is definitely not the stdlib (see discusion in bpo-46890) + # This is definitely not the stdlib (see discussion in bpo-46890) #ns.add_known_file("/Library/Frameworks/lib/python98.zip") expected = dict( @@ -605,7 +605,7 @@ def test_alt_framework_macos(self): ns.add_known_dir("/Library/Frameworks/DebugPython.framework/Versions/9.8/lib/python9.8/lib-dynload") ns.add_known_xfile("/Library/Frameworks/DebugPython.framework/Versions/9.8/lib/python9.8/os.py") - # This is definitely not the stdlib (see discusion in bpo-46890) + # This is definitely not the stdlib (see discussion in bpo-46890) #ns.add_known_xfile("/Library/lib/python98.zip") expected = dict( executable="/Library/Frameworks/DebugPython.framework/Versions/9.8/bin/python9.8", diff --git a/Lib/test/test_http_cookies.py b/Lib/test/test_http_cookies.py index 925c8697..8879902a 100644 --- a/Lib/test/test_http_cookies.py +++ b/Lib/test/test_http_cookies.py @@ -5,6 +5,7 @@ import doctest from http import cookies import pickle +from test import support class CookieTests(unittest.TestCase): @@ -58,6 +59,43 @@ def test_basic(self): for k, v in sorted(case['dict'].items()): self.assertEqual(C[k].value, v) + def test_unquote(self): + cases = [ + (r'a="b=\""', 'b="'), + (r'a="b=\\"', 'b=\\'), + (r'a="b=\="', 'b=='), + (r'a="b=\n"', 'b=n'), + (r'a="b=\042"', 'b="'), + (r'a="b=\134"', 'b=\\'), + (r'a="b=\377"', 'b=\xff'), + (r'a="b=\400"', 'b=400'), + (r'a="b=\42"', 'b=42'), + (r'a="b=\\042"', 'b=\\042'), + (r'a="b=\\134"', 'b=\\134'), + (r'a="b=\\\""', 'b=\\"'), + (r'a="b=\\\042"', 'b=\\"'), + (r'a="b=\134\""', 'b=\\"'), + (r'a="b=\134\042"', 'b=\\"'), + ] + for encoded, decoded in cases: + with self.subTest(encoded): + C = cookies.SimpleCookie() + C.load(encoded) + self.assertEqual(C['a'].value, decoded) + + @support.requires_resource('cpu') + def test_unquote_large(self): + n = 10**6 + for encoded in r'\\', r'\134': + with self.subTest(encoded): + data = 'a="b=' + encoded*n + ';"' + C = cookies.SimpleCookie() + C.load(data) + value = C['a'].value + self.assertEqual(value[:3], 'b=\\') + self.assertEqual(value[-2:], '\\;') + self.assertEqual(len(value), n + 3) + def test_load(self): C = cookies.SimpleCookie() C.load('Customer="WILE_E_COYOTE"; Version=1; Path=/acme') diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index 69f995f4..1d701281 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -57,7 +57,7 @@ def timevalues(self): timezone(timedelta(0, 2 * 60 * 60))), '"18-May-2033 05:33:20 +0200"'] - @run_with_locale('LC_ALL', 'de_DE', 'fr_FR') + @run_with_locale('LC_ALL', 'de_DE', 'fr_FR', '') # DST rules included to work around quirk where the Gnu C library may not # otherwise restore the previous time zone @run_with_tz('STD-1DST,M3.2.0,M11.1.0') diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index c6accc41..81b2f33a 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -787,6 +787,19 @@ def test_issue105979(self): self.assertIn("Frozen object named 'x' is invalid", str(cm.exception)) + def test_create_dynamic_null(self): + with self.assertRaisesRegex(ValueError, 'embedded null character'): + class Spec: + name = "a\x00b" + origin = "abc" + _imp.create_dynamic(Spec()) + + with self.assertRaisesRegex(ValueError, 'embedded null character'): + class Spec2: + name = "abc" + origin = "a\x00b" + _imp.create_dynamic(Spec2()) + @skip_if_dont_write_bytecode class FilePermissionTests(unittest.TestCase): diff --git a/Lib/test/test_importlib/fixtures.py b/Lib/test/test_importlib/fixtures.py index 73e5da2b..9339d68f 100644 --- a/Lib/test/test_importlib/fixtures.py +++ b/Lib/test/test_importlib/fixtures.py @@ -245,6 +245,44 @@ def setUp(self): build_files(EggInfoPkgPipInstalledNoToplevel.files, prefix=self.site_dir) +class EggInfoPkgPipInstalledExternalDataFiles(OnSysPath, SiteDir): + files: FilesSpec = { + "egg_with_module_pkg.egg-info": { + "PKG-INFO": "Name: egg_with_module-pkg", + # SOURCES.txt is made from the source archive, and contains files + # (setup.py) that are not present after installation. + "SOURCES.txt": """ + egg_with_module.py + setup.py + egg_with_module.json + egg_with_module_pkg.egg-info/PKG-INFO + egg_with_module_pkg.egg-info/SOURCES.txt + egg_with_module_pkg.egg-info/top_level.txt + """, + # installed-files.txt is written by pip, and is a strictly more + # accurate source than SOURCES.txt as to the installed contents of + # the package. + "installed-files.txt": """ + ../../../etc/jupyter/jupyter_notebook_config.d/relative.json + /etc/jupyter/jupyter_notebook_config.d/absolute.json + ../egg_with_module.py + PKG-INFO + SOURCES.txt + top_level.txt + """, + # missing top_level.txt (to trigger fallback to installed-files.txt) + }, + "egg_with_module.py": """ + def main(): + print("hello world") + """, + } + + def setUp(self): + super().setUp() + build_files(EggInfoPkgPipInstalledExternalDataFiles.files, prefix=self.site_dir) + + class EggInfoPkgPipInstalledNoModules(OnSysPath, SiteDir): files: FilesSpec = { "egg_with_no_modules_pkg.egg-info": { diff --git a/Lib/test/test_importlib/resources/test_files.py b/Lib/test/test_importlib/resources/test_files.py index 26c8b04e..038aac0a 100644 --- a/Lib/test/test_importlib/resources/test_files.py +++ b/Lib/test/test_importlib/resources/test_files.py @@ -108,6 +108,42 @@ def test_implicit_files(self): _path.build(spec, self.site_dir) assert importlib.import_module('somepkg').val == 'resources are the best' + def test_implicit_files_zip_submodule(self): + """ + Special test for gh-121735 for Python 3.12. + """ + import os + import zipfile + + def create_zip_from_directory(source_dir, zip_filename): + with zipfile.ZipFile(zip_filename, 'w') as zipf: + for root, _, files in os.walk(source_dir): + for file in files: + file_path = os.path.join(root, file) + # Ensure files are at the root + arcname = os.path.relpath(file_path, source_dir) + zipf.write(file_path, arcname) + + set_val = textwrap.dedent( + """ + import importlib.resources as res + val = res.files().joinpath('res.txt').read_text(encoding='utf-8') + """ + ) + spec = { + 'somepkg': { + '__init__.py': set_val, + 'submod.py': set_val, + 'res.txt': 'resources are the best', + }, + } + build_dir = self.fixtures.enter_context(os_helper.temp_dir()) + _path.build(spec, build_dir) + zip_file = os.path.join(self.site_dir, 'thepkg.zip') + create_zip_from_directory(build_dir, zip_file) + self.fixtures.enter_context(import_helper.DirsOnSysPath(zip_file)) + assert importlib.import_module('somepkg.submod').val == 'resources are the best' + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_importlib/test_api.py b/Lib/test/test_importlib/test_api.py index ecf2c47c..ef01a3f6 100644 --- a/Lib/test/test_importlib/test_api.py +++ b/Lib/test/test_importlib/test_api.py @@ -8,6 +8,8 @@ import sys from test.support import import_helper from test.support import os_helper +from test import support +import traceback import types import unittest import warnings @@ -354,6 +356,20 @@ def test_module_missing_spec(self): with self.assertRaises(ModuleNotFoundError): self.init.reload(module) + def test_reload_traceback_with_non_str(self): + # gh-125519 + with support.captured_stdout() as stdout: + try: + self.init.reload("typing") + except TypeError as exc: + traceback.print_exception(exc, file=stdout) + else: + self.fail("Expected TypeError to be raised") + printed_traceback = stdout.getvalue() + self.assertIn("TypeError", printed_traceback) + self.assertNotIn("AttributeError", printed_traceback) + self.assertNotIn("module.__spec__.name", printed_traceback) + (Frozen_ReloadTests, Source_ReloadTests diff --git a/Lib/test/test_importlib/test_metadata_api.py b/Lib/test/test_importlib/test_metadata_api.py index 33c6e85e..29b261ba 100644 --- a/Lib/test/test_importlib/test_metadata_api.py +++ b/Lib/test/test_importlib/test_metadata_api.py @@ -29,6 +29,7 @@ class APITests( fixtures.EggInfoPkg, fixtures.EggInfoPkgPipInstalledNoToplevel, fixtures.EggInfoPkgPipInstalledNoModules, + fixtures.EggInfoPkgPipInstalledExternalDataFiles, fixtures.EggInfoPkgSourcesFallback, fixtures.DistInfoPkg, fixtures.DistInfoPkgWithDot, diff --git a/Lib/test/test_importlib/test_util.py b/Lib/test/test_importlib/test_util.py index e018af2e..553e2087 100644 --- a/Lib/test/test_importlib/test_util.py +++ b/Lib/test/test_importlib/test_util.py @@ -6,12 +6,14 @@ importlib_util = util.import_importlib('importlib.util') import importlib.util +from importlib import _bootstrap_external import os import pathlib import re import string import sys from test import support +from test.support import os_helper import textwrap import types import unittest @@ -758,5 +760,35 @@ def test_complete_multi_phase_init_module(self): self.run_with_own_gil(script) +class MiscTests(unittest.TestCase): + def test_atomic_write_should_notice_incomplete_writes(self): + import _pyio + + oldwrite = os.write + seen_write = False + + truncate_at_length = 100 + + # Emulate an os.write that only writes partial data. + def write(fd, data): + nonlocal seen_write + seen_write = True + return oldwrite(fd, data[:truncate_at_length]) + + # Need to patch _io to be _pyio, so that io.FileIO is affected by the + # os.write patch. + with (support.swap_attr(_bootstrap_external, '_io', _pyio), + support.swap_attr(os, 'write', write)): + with self.assertRaises(OSError): + # Make sure we write something longer than the point where we + # truncate. + content = b'x' * (truncate_at_length * 2) + _bootstrap_external._write_atomic(os_helper.TESTFN, content) + assert seen_write + + with self.assertRaises(OSError): + os.stat(support.os_helper.TESTFN) # Check that the file did not get written. + + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_inspect/inspect_stringized_annotations_pep695.py b/Lib/test/test_inspect/inspect_stringized_annotations_pep695.py new file mode 100644 index 00000000..39bfe2ed --- /dev/null +++ b/Lib/test/test_inspect/inspect_stringized_annotations_pep695.py @@ -0,0 +1,87 @@ +from __future__ import annotations +from typing import Callable, Unpack + + +class A[T, *Ts, **P]: + x: T + y: tuple[*Ts] + z: Callable[P, str] + + +class B[T, *Ts, **P]: + T = int + Ts = str + P = bytes + x: T + y: Ts + z: P + + +Eggs = int +Spam = str + + +class C[Eggs, **Spam]: + x: Eggs + y: Spam + + +def generic_function[T, *Ts, **P]( + x: T, *y: Unpack[Ts], z: P.args, zz: P.kwargs +) -> None: ... + + +def generic_function_2[Eggs, **Spam](x: Eggs, y: Spam): pass + + +class D: + Foo = int + Bar = str + + def generic_method[Foo, **Bar]( + self, x: Foo, y: Bar + ) -> None: ... + + def generic_method_2[Eggs, **Spam](self, x: Eggs, y: Spam): pass + + +# Eggs is `int` in globals, a TypeVar in type_params, and `str` in locals: +class E[Eggs]: + Eggs = str + x: Eggs + + + +def nested(): + from types import SimpleNamespace + from inspect import get_annotations + + Eggs = bytes + Spam = memoryview + + + class F[Eggs, **Spam]: + x: Eggs + y: Spam + + def generic_method[Eggs, **Spam](self, x: Eggs, y: Spam): pass + + + def generic_function[Eggs, **Spam](x: Eggs, y: Spam): pass + + + # Eggs is `int` in globals, `bytes` in the function scope, + # a TypeVar in the type_params, and `str` in locals: + class G[Eggs]: + Eggs = str + x: Eggs + + + return SimpleNamespace( + F=F, + F_annotations=get_annotations(F, eval_str=True), + F_meth_annotations=get_annotations(F.generic_method, eval_str=True), + G_annotations=get_annotations(G, eval_str=True), + generic_func=generic_function, + generic_func_annotations=get_annotations(generic_function, eval_str=True) + ) diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index 4a6d2b3e..7d3153db 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -17,6 +17,7 @@ import sys import types import textwrap +from typing import Unpack import unicodedata import unittest import unittest.mock @@ -40,6 +41,7 @@ from test.test_inspect import inspect_stock_annotations from test.test_inspect import inspect_stringized_annotations from test.test_inspect import inspect_stringized_annotations_2 +from test.test_inspect import inspect_stringized_annotations_pep695 # Functions tested in this suite: @@ -199,6 +201,7 @@ def test_iscoroutine(self): inspect.iscoroutinefunction( functools.partial(functools.partial( gen_coroutine_function_example)))) + self.assertFalse(inspect.iscoroutinefunction(inspect)) self.assertFalse(inspect.iscoroutine(gen_coro)) self.assertTrue( @@ -1361,6 +1364,56 @@ def f(self): self.assertIn(('f', b.f), inspect.getmembers(b)) self.assertIn(('f', b.f), inspect.getmembers(b, inspect.ismethod)) + def test_getmembers_custom_dir(self): + class CorrectDir: + def __init__(self, attr): + self.attr = attr + def method(self): + return self.attr + 1 + def __dir__(self): + return ['attr', 'method'] + + cd = CorrectDir(5) + self.assertEqual(inspect.getmembers(cd), [ + ('attr', 5), + ('method', cd.method), + ]) + self.assertEqual(inspect.getmembers(cd, inspect.ismethod), [ + ('method', cd.method), + ]) + + def test_getmembers_custom_broken_dir(self): + # inspect.getmembers calls `dir()` on the passed object inside. + # if `__dir__` mentions some non-existent attribute, + # we still need to return others correctly. + class BrokenDir: + existing = 1 + def method(self): + return self.existing + 1 + def __dir__(self): + return ['method', 'missing', 'existing'] + + bd = BrokenDir() + self.assertEqual(inspect.getmembers(bd), [ + ('existing', 1), + ('method', bd.method), + ]) + self.assertEqual(inspect.getmembers(bd, inspect.ismethod), [ + ('method', bd.method), + ]) + + def test_getmembers_custom_duplicated_dir(self): + # Duplicates in `__dir__` must not fail and return just one result. + class DuplicatedDir: + attr = 1 + def __dir__(self): + return ['attr', 'attr'] + + dd = DuplicatedDir() + self.assertEqual(inspect.getmembers(dd), [ + ('attr', 1), + ]) + def test_getmembers_VirtualAttribute(self): class M(type): def __getattr__(cls, name): @@ -1504,6 +1557,117 @@ def wrapper(a, b): self.assertEqual(inspect.get_annotations(isa.MyClassWithLocalAnnotations), {'x': 'mytype'}) self.assertEqual(inspect.get_annotations(isa.MyClassWithLocalAnnotations, eval_str=True), {'x': int}) + def test_pep695_generic_class_with_future_annotations(self): + ann_module695 = inspect_stringized_annotations_pep695 + A_annotations = inspect.get_annotations(ann_module695.A, eval_str=True) + A_type_params = ann_module695.A.__type_params__ + self.assertIs(A_annotations["x"], A_type_params[0]) + self.assertEqual(A_annotations["y"].__args__[0], Unpack[A_type_params[1]]) + self.assertIs(A_annotations["z"].__args__[0], A_type_params[2]) + + def test_pep695_generic_class_with_future_annotations_and_local_shadowing(self): + B_annotations = inspect.get_annotations( + inspect_stringized_annotations_pep695.B, eval_str=True + ) + self.assertEqual(B_annotations, {"x": int, "y": str, "z": bytes}) + + def test_pep695_generic_class_with_future_annotations_name_clash_with_global_vars(self): + ann_module695 = inspect_stringized_annotations_pep695 + C_annotations = inspect.get_annotations(ann_module695.C, eval_str=True) + self.assertEqual( + set(C_annotations.values()), + set(ann_module695.C.__type_params__) + ) + + def test_pep_695_generic_function_with_future_annotations(self): + ann_module695 = inspect_stringized_annotations_pep695 + generic_func_annotations = inspect.get_annotations( + ann_module695.generic_function, eval_str=True + ) + func_t_params = ann_module695.generic_function.__type_params__ + self.assertEqual( + generic_func_annotations.keys(), {"x", "y", "z", "zz", "return"} + ) + self.assertIs(generic_func_annotations["x"], func_t_params[0]) + self.assertEqual(generic_func_annotations["y"], Unpack[func_t_params[1]]) + self.assertIs(generic_func_annotations["z"].__origin__, func_t_params[2]) + self.assertIs(generic_func_annotations["zz"].__origin__, func_t_params[2]) + + def test_pep_695_generic_function_with_future_annotations_name_clash_with_global_vars(self): + self.assertEqual( + set( + inspect.get_annotations( + inspect_stringized_annotations_pep695.generic_function_2, + eval_str=True + ).values() + ), + set( + inspect_stringized_annotations_pep695.generic_function_2.__type_params__ + ) + ) + + def test_pep_695_generic_method_with_future_annotations(self): + ann_module695 = inspect_stringized_annotations_pep695 + generic_method_annotations = inspect.get_annotations( + ann_module695.D.generic_method, eval_str=True + ) + params = { + param.__name__: param + for param in ann_module695.D.generic_method.__type_params__ + } + self.assertEqual( + generic_method_annotations, + {"x": params["Foo"], "y": params["Bar"], "return": None} + ) + + def test_pep_695_generic_method_with_future_annotations_name_clash_with_global_vars(self): + self.assertEqual( + set( + inspect.get_annotations( + inspect_stringized_annotations_pep695.D.generic_method_2, + eval_str=True + ).values() + ), + set( + inspect_stringized_annotations_pep695.D.generic_method_2.__type_params__ + ) + ) + + def test_pep_695_generic_method_with_future_annotations_name_clash_with_global_and_local_vars(self): + self.assertEqual( + inspect.get_annotations( + inspect_stringized_annotations_pep695.E, eval_str=True + ), + {"x": str}, + ) + + def test_pep_695_generics_with_future_annotations_nested_in_function(self): + results = inspect_stringized_annotations_pep695.nested() + + self.assertEqual( + set(results.F_annotations.values()), + set(results.F.__type_params__) + ) + self.assertEqual( + set(results.F_meth_annotations.values()), + set(results.F.generic_method.__type_params__) + ) + self.assertNotEqual( + set(results.F_meth_annotations.values()), + set(results.F.__type_params__) + ) + self.assertEqual( + set(results.F_meth_annotations.values()).intersection(results.F.__type_params__), + set() + ) + + self.assertEqual(results.G_annotations, {"x": str}) + + self.assertEqual( + set(results.generic_func_annotations.values()), + set(results.generic_func.__type_params__) + ) + class TestFormatAnnotation(unittest.TestCase): def test_typing_replacement(self): @@ -1616,6 +1780,19 @@ def g(local_ref): builtin_vars, unbound_names) self.assertEqual(inspect.getclosurevars(C().f(_arg)), expected) + def test_attribute_same_name_as_global_var(self): + class C: + _global_ref = object() + def f(): + print(C._global_ref, _global_ref) + nonlocal_vars = {"C": C} + global_vars = {"_global_ref": _global_ref} + builtin_vars = {"print": print} + unbound_names = {"_global_ref"} + expected = inspect.ClosureVars(nonlocal_vars, global_vars, + builtin_vars, unbound_names) + self.assertEqual(inspect.getclosurevars(f), expected) + def test_nonlocal_vars(self): # More complex tests of nonlocal resolution def _nonlocal_vars(f): diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index daa40a6b..d85040a3 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -645,11 +645,9 @@ def test_large_file_ops(self): def test_with_open(self): for bufsize in (0, 100): - f = None with self.open(os_helper.TESTFN, "wb", bufsize) as f: f.write(b"xxx") self.assertEqual(f.closed, True) - f = None try: with self.open(os_helper.TESTFN, "wb", bufsize) as f: 1/0 @@ -1156,6 +1154,21 @@ def test_disallow_instantiation(self): _io = self._io support.check_disallow_instantiation(self, _io._BytesIOBuffer) + def test_stringio_setstate(self): + # gh-127182: Calling __setstate__() with invalid arguments must not crash + obj = self._io.StringIO() + with self.assertRaisesRegex( + TypeError, + 'initial_value must be str or None, not int', + ): + obj.__setstate__((1, '', 0, {})) + + obj.__setstate__((None, '', 0, {})) # should not crash + self.assertEqual(obj.getvalue(), '') + + obj.__setstate__(('', '', 0, {})) + self.assertEqual(obj.getvalue(), '') + class PyIOTest(IOTest): pass @@ -4066,6 +4079,28 @@ def write(self, data): t.write("x"*chunk_size) self.assertEqual([b"abcdef", b"ghi", b"x"*chunk_size], buf._write_stack) + def test_issue119506(self): + chunk_size = 8192 + + class MockIO(self.MockRawIO): + written = False + def write(self, data): + if not self.written: + self.written = True + t.write("middle") + return super().write(data) + + buf = MockIO() + t = self.TextIOWrapper(buf) + t.write("abc") + t.write("def") + # writing data which size >= chunk_size cause flushing buffer before write. + t.write("g" * chunk_size) + t.flush() + + self.assertEqual([b"abcdef", b"middle", b"g"*chunk_size], + buf._write_stack) + class PyTextIOWrapperTest(TextIOWrapperTest): io = pyio diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index e5cbf602..3c8a928b 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -2408,6 +2408,8 @@ def testReservedIpv6(self): self.assertTrue(ipaddress.ip_address('2001:30::').is_global) self.assertFalse(ipaddress.ip_address('2001:40::').is_global) self.assertFalse(ipaddress.ip_address('2002::').is_global) + # gh-124217: conform with RFC 9637 + self.assertFalse(ipaddress.ip_address('3fff::').is_global) # some generic IETF reserved addresses self.assertEqual(True, ipaddress.ip_address('100::').is_reserved) @@ -2421,6 +2423,30 @@ def testIpv4Mapped(self): self.assertEqual(ipaddress.ip_address('::ffff:c0a8:101').ipv4_mapped, ipaddress.ip_address('192.168.1.1')) + def testIpv4MappedProperties(self): + # Test that an IPv4 mapped IPv6 address has + # the same properties as an IPv4 address. + for addr4 in ( + "178.62.3.251", # global + "169.254.169.254", # link local + "127.0.0.1", # loopback + "224.0.0.1", # multicast + "192.168.0.1", # private + "0.0.0.0", # unspecified + "100.64.0.1", # public and not global + ): + with self.subTest(addr4): + ipv4 = ipaddress.IPv4Address(addr4) + ipv6 = ipaddress.IPv6Address(f"::ffff:{addr4}") + + self.assertEqual(ipv4.is_global, ipv6.is_global) + self.assertEqual(ipv4.is_private, ipv6.is_private) + self.assertEqual(ipv4.is_reserved, ipv6.is_reserved) + self.assertEqual(ipv4.is_multicast, ipv6.is_multicast) + self.assertEqual(ipv4.is_unspecified, ipv6.is_unspecified) + self.assertEqual(ipv4.is_link_local, ipv6.is_link_local) + self.assertEqual(ipv4.is_loopback, ipv6.is_loopback) + def testIpv4MappedPrivateCheck(self): self.assertEqual( True, ipaddress.ip_address('::ffff:192.168.1.1').is_private) diff --git a/Lib/test/test_iter.py b/Lib/test/test_iter.py index 9606d5be..1b9f3cf7 100644 --- a/Lib/test/test_iter.py +++ b/Lib/test/test_iter.py @@ -5,11 +5,13 @@ from test.support import cpython_only from test.support.os_helper import TESTFN, unlink from test.support import check_free_after_iterating, ALWAYS_EQ, NEVER_EQ +from test.support import BrokenIter import pickle import collections.abc import functools import contextlib import builtins +import traceback # Test result of triple loop (too big to inline) TRIPLETS = [(0, 0, 0), (0, 0, 1), (0, 0, 2), @@ -1143,6 +1145,46 @@ def test_error_iter(self): self.assertRaises(TypeError, iter, typ()) self.assertRaises(ZeroDivisionError, iter, BadIterableClass()) + def test_exception_locations(self): + # The location of an exception raised from __init__ or + # __next__ should should be the iterator expression + + def init_raises(): + try: + for x in BrokenIter(init_raises=True): + pass + except Exception as e: + return e + + def next_raises(): + try: + for x in BrokenIter(next_raises=True): + pass + except Exception as e: + return e + + def iter_raises(): + try: + for x in BrokenIter(iter_raises=True): + pass + except Exception as e: + return e + + for func, expected in [(init_raises, "BrokenIter(init_raises=True)"), + (next_raises, "BrokenIter(next_raises=True)"), + (iter_raises, "BrokenIter(iter_raises=True)"), + ]: + with self.subTest(func): + exc = func() + f = traceback.extract_tb(exc.__traceback__)[0] + indent = 16 + co = func.__code__ + self.assertEqual(f.lineno, co.co_firstlineno + 2) + self.assertEqual(f.end_lineno, co.co_firstlineno + 2) + self.assertEqual(f.line[f.colno - indent : f.end_colno - indent], + expected) + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index 3d20e70f..5b01f93b 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -599,6 +599,8 @@ def test_count(self): self.assertEqual(take(2, zip('abc',count(-3))), [('a', -3), ('b', -2)]) self.assertRaises(TypeError, count, 2, 3, 4) self.assertRaises(TypeError, count, 'a') + self.assertEqual(take(3, count(maxsize)), + [maxsize, maxsize + 1, maxsize + 2]) self.assertEqual(take(10, count(maxsize-5)), list(range(maxsize-5, maxsize+5))) self.assertEqual(take(10, count(-maxsize-5)), @@ -621,6 +623,15 @@ def test_count(self): self.assertEqual(next(c), -8) self.assertEqual(repr(count(10.25)), 'count(10.25)') self.assertEqual(repr(count(10.0)), 'count(10.0)') + + self.assertEqual(repr(count(maxsize)), f'count({maxsize})') + c = count(maxsize - 1) + self.assertEqual(repr(c), f'count({maxsize - 1})') + next(c) # c is now at masize + self.assertEqual(repr(c), f'count({maxsize})') + next(c) + self.assertEqual(repr(c), f'count({maxsize + 1})') + self.assertEqual(type(next(count(10.0))), float) for i in (-sys.maxsize-5, -sys.maxsize+5 ,-10, -1, 0, 10, sys.maxsize-5, sys.maxsize+5): # Test repr @@ -654,6 +665,12 @@ def test_count_with_stride(self): self.assertEqual(take(20, count(-maxsize-15, 3)), take(20, range(-maxsize-15,-maxsize+100, 3))) self.assertEqual(take(3, count(10, maxsize+5)), list(range(10, 10+3*(maxsize+5), maxsize+5))) + self.assertEqual(take(3, count(maxsize, 2)), + [maxsize, maxsize + 2, maxsize + 4]) + self.assertEqual(take(3, count(maxsize, maxsize)), + [maxsize, 2 * maxsize, 3 * maxsize]) + self.assertEqual(take(3, count(-maxsize, maxsize)), + [-maxsize, 0, maxsize]) self.assertEqual(take(3, count(2, 1.25)), [2, 3.25, 4.5]) self.assertEqual(take(3, count(2, 3.25-4j)), [2, 5.25-4j, 8.5-8j]) self.assertEqual(take(3, count(Decimal('1.1'), Decimal('.1'))), @@ -695,6 +712,20 @@ def test_count_with_stride(self): for proto in range(pickle.HIGHEST_PROTOCOL + 1): self.pickletest(proto, count(i, j)) + c = count(maxsize -2, 2) + self.assertEqual(repr(c), f'count({maxsize - 2}, 2)') + next(c) # c is now at masize + self.assertEqual(repr(c), f'count({maxsize}, 2)') + next(c) + self.assertEqual(repr(c), f'count({maxsize + 2}, 2)') + + c = count(maxsize + 1, -1) + self.assertEqual(repr(c), f'count({maxsize + 1}, -1)') + next(c) # c is now at masize + self.assertEqual(repr(c), f'count({maxsize}, -1)') + next(c) + self.assertEqual(repr(c), f'count({maxsize - 1}, -1)') + def test_cycle(self): self.assertEqual(take(10, cycle('abc')), list('abcabcabca')) self.assertEqual(list(cycle('')), []) @@ -1612,10 +1643,11 @@ def test_tee(self): self.assertEqual(len(result), n) self.assertEqual([list(x) for x in result], [list('abc')]*n) - # tee pass-through to copyable iterator + # tee objects are independent (see bug gh-123884) a, b = tee('abc') c, d = tee(a) - self.assertTrue(a is c) + e, f = tee(c) + self.assertTrue(len({a, b, c, d, e, f}) == 6) # test tee_new t1, t2 = tee('abc') @@ -2029,6 +2061,172 @@ def test_islice_recipe(self): self.assertEqual(next(c), 3) + def test_tee_recipe(self): + + # Begin tee() recipe ########################################### + + def tee(iterable, n=2): + if n < 0: + raise ValueError + if n == 0: + return () + iterator = _tee(iterable) + result = [iterator] + for _ in range(n - 1): + result.append(_tee(iterator)) + return tuple(result) + + class _tee: + + def __init__(self, iterable): + it = iter(iterable) + if isinstance(it, _tee): + self.iterator = it.iterator + self.link = it.link + else: + self.iterator = it + self.link = [None, None] + + def __iter__(self): + return self + + def __next__(self): + link = self.link + if link[1] is None: + link[0] = next(self.iterator) + link[1] = [None, None] + value, self.link = link + return value + + # End tee() recipe ############################################# + + n = 200 + + a, b = tee([]) # test empty iterator + self.assertEqual(list(a), []) + self.assertEqual(list(b), []) + + a, b = tee(irange(n)) # test 100% interleaved + self.assertEqual(lzip(a,b), lzip(range(n), range(n))) + + a, b = tee(irange(n)) # test 0% interleaved + self.assertEqual(list(a), list(range(n))) + self.assertEqual(list(b), list(range(n))) + + a, b = tee(irange(n)) # test dealloc of leading iterator + for i in range(100): + self.assertEqual(next(a), i) + del a + self.assertEqual(list(b), list(range(n))) + + a, b = tee(irange(n)) # test dealloc of trailing iterator + for i in range(100): + self.assertEqual(next(a), i) + del b + self.assertEqual(list(a), list(range(100, n))) + + for j in range(5): # test randomly interleaved + order = [0]*n + [1]*n + random.shuffle(order) + lists = ([], []) + its = tee(irange(n)) + for i in order: + value = next(its[i]) + lists[i].append(value) + self.assertEqual(lists[0], list(range(n))) + self.assertEqual(lists[1], list(range(n))) + + # test argument format checking + self.assertRaises(TypeError, tee) + self.assertRaises(TypeError, tee, 3) + self.assertRaises(TypeError, tee, [1,2], 'x') + self.assertRaises(TypeError, tee, [1,2], 3, 'x') + + # tee object should be instantiable + a, b = tee('abc') + c = type(a)('def') + self.assertEqual(list(c), list('def')) + + # test long-lagged and multi-way split + a, b, c = tee(range(2000), 3) + for i in range(100): + self.assertEqual(next(a), i) + self.assertEqual(list(b), list(range(2000))) + self.assertEqual([next(c), next(c)], list(range(2))) + self.assertEqual(list(a), list(range(100,2000))) + self.assertEqual(list(c), list(range(2,2000))) + + # test invalid values of n + self.assertRaises(TypeError, tee, 'abc', 'invalid') + self.assertRaises(ValueError, tee, [], -1) + + for n in range(5): + result = tee('abc', n) + self.assertEqual(type(result), tuple) + self.assertEqual(len(result), n) + self.assertEqual([list(x) for x in result], [list('abc')]*n) + + # tee objects are independent (see bug gh-123884) + a, b = tee('abc') + c, d = tee(a) + e, f = tee(c) + self.assertTrue(len({a, b, c, d, e, f}) == 6) + + # test tee_new + t1, t2 = tee('abc') + tnew = type(t1) + self.assertRaises(TypeError, tnew) + self.assertRaises(TypeError, tnew, 10) + t3 = tnew(t1) + self.assertTrue(list(t1) == list(t2) == list(t3) == list('abc')) + + # test that tee objects are weak referencable + a, b = tee(range(10)) + p = weakref.proxy(a) + self.assertEqual(getattr(p, '__class__'), type(b)) + del a + gc.collect() # For PyPy or other GCs. + self.assertRaises(ReferenceError, getattr, p, '__class__') + + ans = list('abc') + long_ans = list(range(10000)) + + # Tests not applicable to the tee() recipe + if False: + # check copy + a, b = tee('abc') + self.assertEqual(list(copy.copy(a)), ans) + self.assertEqual(list(copy.copy(b)), ans) + a, b = tee(list(range(10000))) + self.assertEqual(list(copy.copy(a)), long_ans) + self.assertEqual(list(copy.copy(b)), long_ans) + + # check partially consumed copy + a, b = tee('abc') + take(2, a) + take(1, b) + self.assertEqual(list(copy.copy(a)), ans[2:]) + self.assertEqual(list(copy.copy(b)), ans[1:]) + self.assertEqual(list(a), ans[2:]) + self.assertEqual(list(b), ans[1:]) + a, b = tee(range(10000)) + take(100, a) + take(60, b) + self.assertEqual(list(copy.copy(a)), long_ans[100:]) + self.assertEqual(list(copy.copy(b)), long_ans[60:]) + self.assertEqual(list(a), long_ans[100:]) + self.assertEqual(list(b), long_ans[60:]) + + # Issue 13454: Crash when deleting backward iterator from tee() + forward, backward = tee(repeat(None, 2000)) # 20000000 + try: + any(forward) # exhaust the iterator + del backward + except: + del forward, backward + raise + + class TestGC(unittest.TestCase): def makecycle(self, iterator, container): diff --git a/Lib/test/test_json/test_decode.py b/Lib/test/test_json/test_decode.py index 79fb239b..2250af96 100644 --- a/Lib/test/test_json/test_decode.py +++ b/Lib/test/test_json/test_decode.py @@ -16,6 +16,12 @@ def test_float(self): self.assertIsInstance(rval, float) self.assertEqual(rval, 1.0) + def test_nonascii_digits_rejected(self): + # JSON specifies only ascii digits, see gh-125687 + for num in ["1\uff10", "0.\uff10", "0e\uff10"]: + with self.assertRaises(self.JSONDecodeError): + self.loads(num) + def test_bytes(self): self.assertEqual(self.loads(b"1"), 1) diff --git a/Lib/test/test_json/test_scanstring.py b/Lib/test/test_json/test_scanstring.py index 2d3ee8a8..cca556a3 100644 --- a/Lib/test/test_json/test_scanstring.py +++ b/Lib/test/test_json/test_scanstring.py @@ -116,6 +116,11 @@ def test_bad_escapes(self): '"\\u012z"', '"\\u0x12"', '"\\u0X12"', + '"\\u{0}"'.format("\uff10" * 4), + '"\\u 123"', + '"\\u-123"', + '"\\u+123"', + '"\\u1_23"', '"\\ud834\\"', '"\\ud834\\u"', '"\\ud834\\ud"', @@ -127,6 +132,11 @@ def test_bad_escapes(self): '"\\ud834\\udd2z"', '"\\ud834\\u0x20"', '"\\ud834\\u0X20"', + '"\\ud834\\u{0}"'.format("\uff10" * 4), + '"\\ud834\\u 123"', + '"\\ud834\\u-123"', + '"\\ud834\\u+123"', + '"\\ud834\\u1_23"', ] for s in bad_escapes: with self.assertRaises(self.JSONDecodeError, msg=s): diff --git a/Lib/test/test_largefile.py b/Lib/test/test_largefile.py index 3b0930fe..282400c6 100644 --- a/Lib/test/test_largefile.py +++ b/Lib/test/test_largefile.py @@ -142,6 +142,9 @@ def test_truncate(self): f.truncate(1) self.assertEqual(f.tell(), 0) # else pointer moved f.seek(0) + # Verify readall on a truncated file is well behaved. read() + # without a size can be unbounded, this should get just the byte + # that remains. self.assertEqual(len(f.read()), 1) # else wasn't truncated def test_seekable(self): @@ -152,6 +155,22 @@ def test_seekable(self): f.seek(pos) self.assertTrue(f.seekable()) + @bigmemtest(size=size, memuse=2, dry_run=False) + def test_seek_readall(self, _size): + # Seek which doesn't change position should readall successfully. + with self.open(TESTFN, 'rb') as f: + self.assertEqual(f.seek(0, os.SEEK_CUR), 0) + self.assertEqual(len(f.read()), size + 1) + + # Seek which changes (or might change) position should readall + # successfully. + with self.open(TESTFN, 'rb') as f: + self.assertEqual(f.seek(20, os.SEEK_SET), 20) + self.assertEqual(len(f.read()), size - 19) + + with self.open(TESTFN, 'rb') as f: + self.assertEqual(f.seek(-3, os.SEEK_END), size - 2) + self.assertEqual(len(f.read()), 3) def skip_no_disk_space(path, required): def decorator(fun): diff --git a/Lib/test/test_linecache.py b/Lib/test/test_linecache.py index e42df3d9..008f8c8f 100644 --- a/Lib/test/test_linecache.py +++ b/Lib/test/test_linecache.py @@ -276,6 +276,37 @@ def test_loader(self): self.assertEqual(linecache.getlines(filename, module_globals), ['source for x.y.z\n']) + def test_invalid_names(self): + for name, desc in [ + ('\x00', 'NUL bytes filename'), + (__file__ + '\x00', 'filename with embedded NUL bytes'), + # A filename with surrogate codes. A UnicodeEncodeError is raised + # by os.stat() upon querying, which is a subclass of ValueError. + ("\uD834\uDD1E.py", 'surrogate codes (MUSICAL SYMBOL G CLEF)'), + # For POSIX platforms, an OSError will be raised but for Windows + # platforms, a ValueError is raised due to the path_t converter. + # See: https://github.com/python/cpython/issues/122170 + ('a' * 1_000_000, 'very long filename'), + ]: + with self.subTest(f'updatecache: {desc}'): + linecache.clearcache() + lines = linecache.updatecache(name) + self.assertListEqual(lines, []) + self.assertNotIn(name, linecache.cache) + + # hack into the cache (it shouldn't be allowed + # but we never know what people do...) + for key, fullname in [(name, 'ok'), ('key', name), (name, name)]: + with self.subTest(f'checkcache: {desc}', + key=key, fullname=fullname): + linecache.clearcache() + linecache.cache[key] = (0, 1234, [], fullname) + linecache.checkcache(key) + self.assertNotIn(key, linecache.cache) + + # just to be sure that we did not mess with cache + linecache.clearcache() + class LineCacheInvalidationTests(unittest.TestCase): def setUp(self): diff --git a/Lib/test/test_list.py b/Lib/test/test_list.py index 2969c6e2..77264ed7 100644 --- a/Lib/test/test_list.py +++ b/Lib/test/test_list.py @@ -229,6 +229,31 @@ def __eq__(self, other): list4 = [1] self.assertFalse(list3 == list4) + def test_lt_operator_modifying_operand(self): + # See gh-120298 + class evil: + def __lt__(self, other): + other.clear() + return NotImplemented + + a = [[evil()]] + with self.assertRaises(TypeError): + a[0] < a + + def test_list_index_modifing_operand(self): + # See gh-120384 + class evil: + def __init__(self, lst): + self.lst = lst + def __iter__(self): + yield from self.lst + self.lst.clear() + + lst = list(range(5)) + operand = evil(lst) + with self.assertRaises(ValueError): + lst[::-1] = operand + @cpython_only def test_preallocation(self): iterable = [0] * 10 diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py index df1debf3..2065afd4 100644 --- a/Lib/test/test_listcomps.py +++ b/Lib/test/test_listcomps.py @@ -1,8 +1,11 @@ import doctest import textwrap +import traceback import types import unittest +from test.support import BrokenIter + doctests = """ ########### Tests borrowed from or inspired by test_genexps.py ############ @@ -168,6 +171,31 @@ def test_references___class__(self): """ self._check_in_scopes(code, raises=NameError) + def test_references___class___defined(self): + code = """ + __class__ = 2 + res = [__class__ for x in [1]] + """ + self._check_in_scopes( + code, outputs={"res": [2]}, scopes=["module", "function"]) + self._check_in_scopes(code, raises=NameError, scopes=["class"]) + + def test_references___class___enclosing(self): + code = """ + __class__ = 2 + class C: + res = [__class__ for x in [1]] + res = C.res + """ + self._check_in_scopes(code, raises=NameError) + + def test_super_and_class_cell_in_sibling_comps(self): + code = """ + [super for _ in [1]] + [__class__ for _ in [1]] + """ + self._check_in_scopes(code, raises=NameError) + def test_inner_cell_shadows_outer(self): code = """ items = [(lambda: i) for i in range(5)] @@ -681,6 +709,42 @@ def test_multiple_comprehension_name_reuse(self): self._check_in_scopes(code, {"x": 2, "y": [3]}, ns={"x": 3}, scopes=["class"]) self._check_in_scopes(code, {"x": 2, "y": [2]}, ns={"x": 3}, scopes=["function", "module"]) + def test_exception_locations(self): + # The location of an exception raised from __init__ or + # __next__ should should be the iterator expression + + def init_raises(): + try: + [x for x in BrokenIter(init_raises=True)] + except Exception as e: + return e + + def next_raises(): + try: + [x for x in BrokenIter(next_raises=True)] + except Exception as e: + return e + + def iter_raises(): + try: + [x for x in BrokenIter(iter_raises=True)] + except Exception as e: + return e + + for func, expected in [(init_raises, "BrokenIter(init_raises=True)"), + (next_raises, "BrokenIter(next_raises=True)"), + (iter_raises, "BrokenIter(iter_raises=True)"), + ]: + with self.subTest(func): + exc = func() + f = traceback.extract_tb(exc.__traceback__)[0] + indent = 16 + co = func.__code__ + self.assertEqual(f.lineno, co.co_firstlineno + 2) + self.assertEqual(f.end_lineno, co.co_firstlineno + 2) + self.assertEqual(f.line[f.colno - indent : f.end_colno - indent], + expected) + __test__ = {'doctests' : doctests} def load_tests(loader, tests, pattern): diff --git a/Lib/test/test_locale.py b/Lib/test/test_locale.py index b0d79985..cde80a4e 100644 --- a/Lib/test/test_locale.py +++ b/Lib/test/test_locale.py @@ -353,6 +353,8 @@ def setUp(self): is_emscripten or is_wasi, "musl libc issue on Emscripten/WASI, bpo-46390" ) + @unittest.skipIf(sys.platform.startswith("netbsd"), + "gh-124108: NetBSD doesn't support UTF-8 for LC_COLLATE") def test_strcoll_with_diacritic(self): self.assertLess(locale.strcoll('à', 'b'), 0) @@ -362,6 +364,8 @@ def test_strcoll_with_diacritic(self): is_emscripten or is_wasi, "musl libc issue on Emscripten/WASI, bpo-46390" ) + @unittest.skipIf(sys.platform.startswith("netbsd"), + "gh-124108: NetBSD doesn't support UTF-8 for LC_COLLATE") def test_strxfrm_with_diacritic(self): self.assertLess(locale.strxfrm('à'), locale.strxfrm('b')) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 6dd1b6f8..5112c2e7 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -60,6 +60,7 @@ import weakref from http.server import HTTPServer, BaseHTTPRequestHandler +from unittest.mock import patch from urllib.parse import urlparse, parse_qs from socketserver import (ThreadingUDPServer, DatagramRequestHandler, ThreadingTCPServer, StreamRequestHandler) @@ -2381,6 +2382,32 @@ class CustomListener(logging.handlers.QueueListener): class CustomQueue(queue.Queue): pass +class CustomQueueProtocol: + def __init__(self, maxsize=0): + self.queue = queue.Queue(maxsize) + + def __getattr__(self, attribute): + queue = object.__getattribute__(self, 'queue') + return getattr(queue, attribute) + +class CustomQueueFakeProtocol(CustomQueueProtocol): + # An object implementing the minimial Queue API for + # the logging module but with incorrect signatures. + # + # The object will be considered a valid queue class since we + # do not check the signatures (only callability of methods) + # but will NOT be usable in production since a TypeError will + # be raised due to the extra argument in 'put_nowait'. + def put_nowait(self): + pass + +class CustomQueueWrongProtocol(CustomQueueProtocol): + put_nowait = None + +class MinimalQueueProtocol: + def put_nowait(self, x): pass + def get(self): pass + def queueMaker(): return queue.Queue() @@ -3866,19 +3893,18 @@ def do_queuehandler_configuration(self, qspec, lspec): self.addCleanup(os.remove, fn) @threading_helper.requires_working_threading() + @support.requires_subprocess() def test_config_queue_handler(self): - q = CustomQueue() - dq = { - '()': __name__ + '.CustomQueue', - 'maxsize': 10 - } + qs = [CustomQueue(), CustomQueueProtocol()] + dqs = [{'()': f'{__name__}.{cls}', 'maxsize': 10} + for cls in ['CustomQueue', 'CustomQueueProtocol']] dl = { '()': __name__ + '.listenerMaker', 'arg1': None, 'arg2': None, 'respect_handler_level': True } - qvalues = (None, __name__ + '.queueMaker', __name__ + '.CustomQueue', dq, q) + qvalues = (None, __name__ + '.queueMaker', __name__ + '.CustomQueue', *dqs, *qs) lvalues = (None, __name__ + '.CustomListener', dl, CustomListener) for qspec, lspec in itertools.product(qvalues, lvalues): self.do_queuehandler_configuration(qspec, lspec) @@ -3894,12 +3920,115 @@ def test_config_queue_handler(self): msg = str(ctx.exception) self.assertEqual(msg, "Unable to configure handler 'ah'") + def _apply_simple_queue_listener_configuration(self, qspec): + self.apply_config({ + "version": 1, + "handlers": { + "queue_listener": { + "class": "logging.handlers.QueueHandler", + "queue": qspec, + }, + }, + }) + + @threading_helper.requires_working_threading() + @support.requires_subprocess() + @patch("multiprocessing.Manager") + def test_config_queue_handler_does_not_create_multiprocessing_manager(self, manager): + # gh-120868, gh-121723, gh-124653 + + for qspec in [ + {"()": "queue.Queue", "maxsize": -1}, + queue.Queue(), + # queue.SimpleQueue does not inherit from queue.Queue + queue.SimpleQueue(), + # CustomQueueFakeProtocol passes the checks but will not be usable + # since the signatures are incompatible. Checking the Queue API + # without testing the type of the actual queue is a trade-off + # between usability and the work we need to do in order to safely + # check that the queue object correctly implements the API. + CustomQueueFakeProtocol(), + MinimalQueueProtocol(), + ]: + with self.subTest(qspec=qspec): + self._apply_simple_queue_listener_configuration(qspec) + manager.assert_not_called() + + @patch("multiprocessing.Manager") + def test_config_queue_handler_invalid_config_does_not_create_multiprocessing_manager(self, manager): + # gh-120868, gh-121723 + + for qspec in [object(), CustomQueueWrongProtocol()]: + with self.subTest(qspec=qspec), self.assertRaises(ValueError): + self._apply_simple_queue_listener_configuration(qspec) + manager.assert_not_called() + + @skip_if_tsan_fork + @support.requires_subprocess() + @unittest.skipUnless(support.Py_DEBUG, "requires a debug build for testing" + " assertions in multiprocessing") + def test_config_reject_simple_queue_handler_multiprocessing_context(self): + # multiprocessing.SimpleQueue does not implement 'put_nowait' + # and thus cannot be used as a queue-like object (gh-124653) + + import multiprocessing + + if support.MS_WINDOWS: + start_methods = ['spawn'] + else: + start_methods = ['spawn', 'fork', 'forkserver'] + + for start_method in start_methods: + with self.subTest(start_method=start_method): + ctx = multiprocessing.get_context(start_method) + qspec = ctx.SimpleQueue() + with self.assertRaises(ValueError): + self._apply_simple_queue_listener_configuration(qspec) + + @skip_if_tsan_fork + @support.requires_subprocess() + @unittest.skipUnless(support.Py_DEBUG, "requires a debug build for testing" + "assertions in multiprocessing") + def test_config_queue_handler_multiprocessing_context(self): + # regression test for gh-121723 + if support.MS_WINDOWS: + start_methods = ['spawn'] + else: + start_methods = ['spawn', 'fork', 'forkserver'] + for start_method in start_methods: + with self.subTest(start_method=start_method): + ctx = multiprocessing.get_context(start_method) + with ctx.Manager() as manager: + q = manager.Queue() + records = [] + # use 1 process and 1 task per child to put 1 record + with ctx.Pool(1, initializer=self._mpinit_issue121723, + initargs=(q, "text"), maxtasksperchild=1): + records.append(q.get(timeout=60)) + self.assertTrue(q.empty()) + self.assertEqual(len(records), 1) + + @staticmethod + def _mpinit_issue121723(qspec, message_to_log): + # static method for pickling support + logging.config.dictConfig({ + 'version': 1, + 'disable_existing_loggers': True, + 'handlers': { + 'log_to_parent': { + 'class': 'logging.handlers.QueueHandler', + 'queue': qspec + } + }, + 'root': {'handlers': ['log_to_parent'], 'level': 'DEBUG'} + }) + # log a message (this creates a record put in the queue) + logging.getLogger().info(message_to_log) + + @support.requires_subprocess() def test_multiprocessing_queues(self): # See gh-119819 - # will skip test if it's not available - import_helper.import_module('_multiprocessing') - cd = copy.deepcopy(self.config_queue_handler) from multiprocessing import Queue as MQ, Manager as MM q1 = MQ() # this can't be pickled @@ -5956,13 +6085,28 @@ def test_emit_after_closing_in_write_mode(self): self.assertEqual(fp.read().strip(), '1') class RotatingFileHandlerTest(BaseFileTest): - @unittest.skipIf(support.is_wasi, "WASI does not have /dev/null.") def test_should_not_rollover(self): - # If maxbytes is zero rollover never occurs + # If file is empty rollover never occurs + rh = logging.handlers.RotatingFileHandler( + self.fn, encoding="utf-8", maxBytes=1) + self.assertFalse(rh.shouldRollover(None)) + rh.close() + + # If maxBytes is zero rollover never occurs + rh = logging.handlers.RotatingFileHandler( + self.fn, encoding="utf-8", maxBytes=0) + self.assertFalse(rh.shouldRollover(None)) + rh.close() + + with open(self.fn, 'wb') as f: + f.write(b'\n') rh = logging.handlers.RotatingFileHandler( self.fn, encoding="utf-8", maxBytes=0) self.assertFalse(rh.shouldRollover(None)) rh.close() + + @unittest.skipIf(support.is_wasi, "WASI does not have /dev/null.") + def test_should_not_rollover_non_file(self): # bpo-45401 - test with special file # We set maxBytes to 1 so that rollover would normally happen, except # for the check for regular files @@ -5972,18 +6116,47 @@ def test_should_not_rollover(self): rh.close() def test_should_rollover(self): - rh = logging.handlers.RotatingFileHandler(self.fn, encoding="utf-8", maxBytes=1) + with open(self.fn, 'wb') as f: + f.write(b'\n') + rh = logging.handlers.RotatingFileHandler(self.fn, encoding="utf-8", maxBytes=2) self.assertTrue(rh.shouldRollover(self.next_rec())) rh.close() def test_file_created(self): # checks that the file is created and assumes it was created # by us + os.unlink(self.fn) rh = logging.handlers.RotatingFileHandler(self.fn, encoding="utf-8") rh.emit(self.next_rec()) self.assertLogFile(self.fn) rh.close() + def test_max_bytes(self, delay=False): + kwargs = {'delay': delay} if delay else {} + os.unlink(self.fn) + rh = logging.handlers.RotatingFileHandler( + self.fn, encoding="utf-8", backupCount=2, maxBytes=100, **kwargs) + self.assertIs(os.path.exists(self.fn), not delay) + small = logging.makeLogRecord({'msg': 'a'}) + large = logging.makeLogRecord({'msg': 'b'*100}) + self.assertFalse(rh.shouldRollover(small)) + self.assertFalse(rh.shouldRollover(large)) + rh.emit(small) + self.assertLogFile(self.fn) + self.assertFalse(os.path.exists(self.fn + ".1")) + self.assertFalse(rh.shouldRollover(small)) + self.assertTrue(rh.shouldRollover(large)) + rh.emit(large) + self.assertTrue(os.path.exists(self.fn)) + self.assertLogFile(self.fn + ".1") + self.assertFalse(os.path.exists(self.fn + ".2")) + self.assertTrue(rh.shouldRollover(small)) + self.assertTrue(rh.shouldRollover(large)) + rh.close() + + def test_max_bytes_delay(self): + self.test_max_bytes(delay=True) + def test_rollover_filenames(self): def namer(name): return name + ".test" @@ -5992,11 +6165,15 @@ def namer(name): rh.namer = namer rh.emit(self.next_rec()) self.assertLogFile(self.fn) + self.assertFalse(os.path.exists(namer(self.fn + ".1"))) rh.emit(self.next_rec()) self.assertLogFile(namer(self.fn + ".1")) + self.assertFalse(os.path.exists(namer(self.fn + ".2"))) rh.emit(self.next_rec()) self.assertLogFile(namer(self.fn + ".2")) self.assertFalse(os.path.exists(namer(self.fn + ".3"))) + rh.emit(self.next_rec()) + self.assertFalse(os.path.exists(namer(self.fn + ".3"))) rh.close() def test_namer_rotator_inheritance(self): diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index 0b015580..600946ee 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -187,6 +187,9 @@ def result_check(expected, got, ulp_tol=5, abs_tol=0.0): # Check exactly equal (applies also to strings representing exceptions) if got == expected: + if not got and not expected: + if math.copysign(1, got) != math.copysign(1, expected): + return f"expected {expected}, got {got} (zero has wrong sign)" return None failure = "not equal" @@ -809,11 +812,13 @@ def testHypot(self): # Test allowable types (those with __float__) self.assertEqual(hypot(12.0, 5.0), 13.0) self.assertEqual(hypot(12, 5), 13) - self.assertEqual(hypot(1, -1), math.sqrt(2)) - self.assertEqual(hypot(1, FloatLike(-1.)), math.sqrt(2)) + self.assertEqual(hypot(0.75, -1), 1.25) + self.assertEqual(hypot(-1, 0.75), 1.25) + self.assertEqual(hypot(0.75, FloatLike(-1.)), 1.25) + self.assertEqual(hypot(FloatLike(-1.), 0.75), 1.25) self.assertEqual(hypot(Decimal(12), Decimal(5)), 13) self.assertEqual(hypot(Fraction(12, 32), Fraction(5, 32)), Fraction(13, 32)) - self.assertEqual(hypot(bool(1), bool(0), bool(1), bool(1)), math.sqrt(3)) + self.assertEqual(hypot(True, False, True, True, True), 2.0) # Test corner cases self.assertEqual(hypot(0.0, 0.0), 0.0) # Max input is zero @@ -969,9 +974,9 @@ def testDist(self): self.assertEqual(dist((D(14), D(1)), (D(2), D(-4))), D(13)) self.assertEqual(dist((F(14, 32), F(1, 32)), (F(2, 32), F(-4, 32))), F(13, 32)) - self.assertEqual(dist((True, True, False, True, False), - (True, False, True, True, False)), - sqrt(2.0)) + self.assertEqual(dist((True, True, False, False, True, True), + (True, False, True, False, False, False)), + 2.0) # Test corner cases self.assertEqual(dist((13.25, 12.5, -3.25), @@ -1397,7 +1402,7 @@ def __repr__(self): return f'Flt({int(self)})' def baseline_sumprod(p, q): - """This defines the target behavior including expections and special values. + """This defines the target behavior including exceptions and special values. However, it is subject to rounding errors, so float inputs should be exactly representable with only a few bits. """ @@ -1881,7 +1886,7 @@ def testTan(self): try: self.assertTrue(math.isnan(math.tan(INF))) self.assertTrue(math.isnan(math.tan(NINF))) - except: + except ValueError: self.assertRaises(ValueError, math.tan, INF) self.assertRaises(ValueError, math.tan, NINF) self.assertTrue(math.isnan(math.tan(NAN))) @@ -2051,6 +2056,13 @@ def test_testfile(self): except OverflowError: result = 'OverflowError' + # C99+ says for math.h's sqrt: If the argument is +∞ or ±0, it is + # returned, unmodified. On another hand, for csqrt: If z is ±0+0i, + # the result is +0+0i. Lets correct zero sign of er to follow + # first convention. + if id in ['sqrt0002', 'sqrt0003', 'sqrt1001', 'sqrt1023']: + er = math.copysign(er, ar) + # Default tolerances ulp_tol, abs_tol = 5, 0.0 diff --git a/Lib/test/test_memoryview.py b/Lib/test/test_memoryview.py index 0eb2a367..2d4bf5f1 100644 --- a/Lib/test/test_memoryview.py +++ b/Lib/test/test_memoryview.py @@ -18,6 +18,10 @@ from test.support import import_helper +class MyObject: + pass + + class AbstractMemoryTests: source_bytes = b"abcdef" @@ -228,8 +232,6 @@ def __init__(self, base): self.m = memoryview(base) class MySource(tp): pass - class MyObject: - pass # Create a reference cycle through a memoryview object. # This exercises mbuf_clear(). @@ -656,5 +658,26 @@ def __bool__(self): m[0] = MyBool() self.assertEqual(ba[:8], b'\0'*8) + def test_buffer_reference_loop(self): + m = memoryview(b'abc').__buffer__(0) + o = MyObject() + o.m = m + o.o = o + wr = weakref.ref(o) + del m, o + gc.collect() + self.assertIsNone(wr()) + + def test_picklebuffer_reference_loop(self): + pb = pickle.PickleBuffer(memoryview(b'abc')) + o = MyObject() + o.pb = pb + o.o = o + wr = weakref.ref(o) + del pb, o + gc.collect() + self.assertIsNone(wr()) + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py index 9c6715b2..4924db98 100644 --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -743,6 +743,9 @@ def test_abspath(self): tester('ntpath.abspath("C:\\spam. . .")', "C:\\spam") tester('ntpath.abspath("C:/nul")', "\\\\.\\nul") tester('ntpath.abspath("C:\\nul")', "\\\\.\\nul") + self.assertTrue(ntpath.isabs(ntpath.abspath("C:spam"))) + self.assertEqual(ntpath.abspath("C:\x00"), ntpath.join(ntpath.abspath("C:"), "\x00")) + self.assertEqual(ntpath.abspath("\x00:spam"), "\x00:\\spam") tester('ntpath.abspath("//..")', "\\\\") tester('ntpath.abspath("//../")', "\\\\..\\") tester('ntpath.abspath("//../..")', "\\\\..\\") diff --git a/Lib/test/test_optparse.py b/Lib/test/test_optparse.py index 28b27446..8655a053 100644 --- a/Lib/test/test_optparse.py +++ b/Lib/test/test_optparse.py @@ -15,7 +15,7 @@ from io import StringIO from test import support from test.support import os_helper - +from test.support.i18n_helper import TestTranslationsBase, update_translation_snapshots import optparse from optparse import make_option, Option, \ @@ -1656,5 +1656,14 @@ def test__all__(self): support.check__all__(self, optparse, not_exported=not_exported) +class TestTranslations(TestTranslationsBase): + def test_translations(self): + self.assertMsgidsEqual(optparse) + + if __name__ == '__main__': + # To regenerate translation snapshots + if len(sys.argv) > 1 and sys.argv[1] == '--snapshot-update': + update_translation_snapshots(optparse) + sys.exit(0) unittest.main() diff --git a/Lib/test/test_ordered_dict.py b/Lib/test/test_ordered_dict.py index 4571b23d..9f131a91 100644 --- a/Lib/test/test_ordered_dict.py +++ b/Lib/test/test_ordered_dict.py @@ -2,7 +2,9 @@ import contextlib import copy import gc +import operator import pickle +import re from random import randrange, shuffle import struct import sys @@ -739,11 +741,44 @@ def test_ordered_dict_items_result_gc(self): # when it's mutated and returned from __next__: self.assertTrue(gc.is_tracked(next(it))) + +class _TriggerSideEffectOnEqual: + count = 0 # number of calls to __eq__ + trigger = 1 # count value when to trigger side effect + + def __eq__(self, other): + if self.__class__.count == self.__class__.trigger: + self.side_effect() + self.__class__.count += 1 + return True + + def __hash__(self): + # all instances represent the same key + return -1 + + def side_effect(self): + raise NotImplementedError + class PurePythonOrderedDictTests(OrderedDictTests, unittest.TestCase): module = py_coll OrderedDict = py_coll.OrderedDict + def test_issue119004_attribute_error(self): + class Key(_TriggerSideEffectOnEqual): + def side_effect(self): + del dict1[TODEL] + + TODEL = Key() + dict1 = self.OrderedDict(dict.fromkeys((0, TODEL, 4.2))) + dict2 = self.OrderedDict(dict.fromkeys((0, Key(), 4.2))) + # This causes an AttributeError due to the linked list being changed + msg = re.escape("'NoneType' object has no attribute 'key'") + self.assertRaisesRegex(AttributeError, msg, operator.eq, dict1, dict2) + self.assertEqual(Key.count, 2) + self.assertDictEqual(dict1, dict.fromkeys((0, 4.2))) + self.assertDictEqual(dict2, dict.fromkeys((0, Key(), 4.2))) + class CPythonBuiltinDictTests(unittest.TestCase): """Builtin dict preserves insertion order. @@ -764,8 +799,85 @@ class CPythonBuiltinDictTests(unittest.TestCase): del method +class CPythonOrderedDictSideEffects: + + def check_runtime_error_issue119004(self, dict1, dict2): + msg = re.escape("OrderedDict mutated during iteration") + self.assertRaisesRegex(RuntimeError, msg, operator.eq, dict1, dict2) + + def test_issue119004_change_size_by_clear(self): + class Key(_TriggerSideEffectOnEqual): + def side_effect(self): + dict1.clear() + + dict1 = self.OrderedDict(dict.fromkeys((0, Key(), 4.2))) + dict2 = self.OrderedDict(dict.fromkeys((0, Key(), 4.2))) + self.check_runtime_error_issue119004(dict1, dict2) + self.assertEqual(Key.count, 2) + self.assertDictEqual(dict1, {}) + self.assertDictEqual(dict2, dict.fromkeys((0, Key(), 4.2))) + + def test_issue119004_change_size_by_delete_key(self): + class Key(_TriggerSideEffectOnEqual): + def side_effect(self): + del dict1[TODEL] + + TODEL = Key() + dict1 = self.OrderedDict(dict.fromkeys((0, TODEL, 4.2))) + dict2 = self.OrderedDict(dict.fromkeys((0, Key(), 4.2))) + self.check_runtime_error_issue119004(dict1, dict2) + self.assertEqual(Key.count, 2) + self.assertDictEqual(dict1, dict.fromkeys((0, 4.2))) + self.assertDictEqual(dict2, dict.fromkeys((0, Key(), 4.2))) + + def test_issue119004_change_linked_list_by_clear(self): + class Key(_TriggerSideEffectOnEqual): + def side_effect(self): + dict1.clear() + dict1['a'] = dict1['b'] = 'c' + + dict1 = self.OrderedDict(dict.fromkeys((0, Key(), 4.2))) + dict2 = self.OrderedDict(dict.fromkeys((0, Key(), 4.2))) + self.check_runtime_error_issue119004(dict1, dict2) + self.assertEqual(Key.count, 2) + self.assertDictEqual(dict1, dict.fromkeys(('a', 'b'), 'c')) + self.assertDictEqual(dict2, dict.fromkeys((0, Key(), 4.2))) + + def test_issue119004_change_linked_list_by_delete_key(self): + class Key(_TriggerSideEffectOnEqual): + def side_effect(self): + del dict1[TODEL] + dict1['a'] = 'c' + + TODEL = Key() + dict1 = self.OrderedDict(dict.fromkeys((0, TODEL, 4.2))) + dict2 = self.OrderedDict(dict.fromkeys((0, Key(), 4.2))) + self.check_runtime_error_issue119004(dict1, dict2) + self.assertEqual(Key.count, 2) + self.assertDictEqual(dict1, {0: None, 'a': 'c', 4.2: None}) + self.assertDictEqual(dict2, dict.fromkeys((0, Key(), 4.2))) + + def test_issue119004_change_size_by_delete_key_in_dict_eq(self): + class Key(_TriggerSideEffectOnEqual): + trigger = 0 + def side_effect(self): + del dict1[TODEL] + + TODEL = Key() + dict1 = self.OrderedDict(dict.fromkeys((0, TODEL, 4.2))) + dict2 = self.OrderedDict(dict.fromkeys((0, Key(), 4.2))) + self.assertEqual(Key.count, 0) + # the side effect is in dict.__eq__ and modifies the length + self.assertNotEqual(dict1, dict2) + self.assertEqual(Key.count, 2) + self.assertDictEqual(dict1, dict.fromkeys((0, 4.2))) + self.assertDictEqual(dict2, dict.fromkeys((0, Key(), 4.2))) + + @unittest.skipUnless(c_coll, 'requires the C version of the collections module') -class CPythonOrderedDictTests(OrderedDictTests, unittest.TestCase): +class CPythonOrderedDictTests(OrderedDictTests, + CPythonOrderedDictSideEffects, + unittest.TestCase): module = c_coll OrderedDict = c_coll.OrderedDict diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 88037059..1d6d92e0 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -824,7 +824,7 @@ def ns_to_sec(ns): return (ns * 1e-9) + 0.5e-9 def test_utime_by_indexed(self): - # pass times as floating point seconds as the second indexed parameter + # pass times as floating-point seconds as the second indexed parameter def set_time(filename, ns): atime_ns, mtime_ns = ns atime = self.ns_to_sec(atime_ns) @@ -1823,9 +1823,10 @@ def test_win32_mkdir_700(self): os.mkdir(path, mode=0o700) out = subprocess.check_output(["cacls.exe", path, "/s"], encoding="oem") os.rmdir(path) + out = out.strip().rsplit(" ", 1)[1] self.assertEqual( - out.strip(), - f'{path} "D:P(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;FA;;;OW)"', + out, + '"D:P(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;FA;;;OW)"', ) def tearDown(self): @@ -3095,7 +3096,8 @@ class Win32NtTests(unittest.TestCase): def test_getfinalpathname_handles(self): nt = import_helper.import_module('nt') ctypes = import_helper.import_module('ctypes') - import ctypes.wintypes + # Ruff false positive -- it thinks we're redefining `ctypes` here + import ctypes.wintypes # noqa: F811 kernel = ctypes.WinDLL('Kernel32.dll', use_last_error=True) kernel.GetCurrentProcess.restype = ctypes.wintypes.HANDLE @@ -3885,10 +3887,10 @@ def _check_xattrs_str(self, s, getxattr, setxattr, removexattr, listxattr, **kwa xattr.remove("user.test") self.assertEqual(set(listxattr(fn)), xattr) self.assertEqual(getxattr(fn, s("user.test2"), **kwargs), b"foo") - setxattr(fn, s("user.test"), b"a"*1024, **kwargs) - self.assertEqual(getxattr(fn, s("user.test"), **kwargs), b"a"*1024) + setxattr(fn, s("user.test"), b"a"*256, **kwargs) + self.assertEqual(getxattr(fn, s("user.test"), **kwargs), b"a"*256) removexattr(fn, s("user.test"), **kwargs) - many = sorted("user.test{}".format(i) for i in range(100)) + many = sorted("user.test{}".format(i) for i in range(32)) for thing in many: setxattr(fn, thing, b"x", **kwargs) self.assertEqual(set(listxattr(fn)), set(init_xattr) | set(many)) diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index ca604df7..4437f878 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -831,6 +831,14 @@ class PureWindowsPathTest(_BasePurePathTest, unittest.TestCase): ], }) + def test_constructor_nested_foreign_flavour(self): + # See GH-125069. + p1 = pathlib.PurePosixPath('b/c:\\d') + p2 = pathlib.PurePosixPath('b/', 'c:\\d') + self.assertEqual(p1, p2) + self.assertEqual(self.cls(p1), self.cls('b/c:/d')) + self.assertEqual(self.cls(p2), self.cls('b/c:/d')) + def test_drive_root_parts(self): check = self._check_drive_root_parts # First part is anchored. diff --git a/Lib/test/test_patma.py b/Lib/test/test_patma.py index 3dbd19df..6fe5360b 100644 --- a/Lib/test/test_patma.py +++ b/Lib/test/test_patma.py @@ -1,6 +1,7 @@ import array import collections import dataclasses +import dis import enum import inspect import sys @@ -3083,6 +3084,24 @@ class Keys: self.assertIs(y, None) self.assertIs(z, None) +class TestSourceLocations(unittest.TestCase): + def test_jump_threading(self): + # See gh-123048 + def f(): + x = 0 + v = 1 + match v: + case 1: + if x < 0: + x = 1 + case 2: + if x < 0: + x = 1 + x += 1 + + for inst in dis.get_instructions(f): + if inst.opcode in dis.hasjrel or inst.opcode in dis.hasjabs: + self.assertIsNotNone(inst.positions.lineno, "jump without location") class TestTracing(unittest.TestCase): diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 24324a37..bd61de0a 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -352,6 +352,42 @@ def test_pdb_breakpoint_commands(): 4 """ +def test_pdb_breakpoint_on_annotated_function_def(): + """Test breakpoints on function definitions with annotation. + + >>> def foo[T](): + ... return 0 + + >>> def bar() -> int: + ... return 0 + + >>> def foobar[T]() -> int: + ... return 0 + + >>> reset_Breakpoint() + + >>> def test_function(): + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... pass + + >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE + ... 'break foo', + ... 'break bar', + ... 'break foobar', + ... 'continue', + ... ]): + ... test_function() + > (3)test_function() + -> pass + (Pdb) break foo + Breakpoint 1 at :1 + (Pdb) break bar + Breakpoint 2 at :1 + (Pdb) break foobar + Breakpoint 3 at :1 + (Pdb) continue + """ + def test_pdb_breakpoints_preserved_across_interactive_sessions(): """Breakpoints are remembered between interactive sessions @@ -446,6 +482,38 @@ def test_pdb_pp_repr_exc(): (Pdb) continue """ +def test_pdb_empty_line(): + """Test that empty line repeats the last command. + + >>> def test_function(): + ... x = 1 + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... pass + ... y = 2 + + >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE + ... 'p x', + ... '', # Should repeat p x + ... 'n ;; p 0 ;; p x', # Fill cmdqueue with multiple commands + ... '', # Should still repeat p x + ... 'continue', + ... ]): + ... test_function() + > (4)test_function() + -> pass + (Pdb) p x + 1 + (Pdb) + 1 + (Pdb) n ;; p 0 ;; p x + 0 + 1 + > (5)test_function() + -> y = 2 + (Pdb) + 1 + (Pdb) continue + """ def do_nothing(): pass @@ -2251,6 +2319,20 @@ def test_issue26053(self): self.assertRegex(res, "Restarting .* with arguments:\na b c") self.assertRegex(res, "Restarting .* with arguments:\nd e f") + def test_step_into_botframe(self): + # gh-125422 + # pdb should not be able to step into the botframe (bdb.py) + script = "x = 1" + commands = """ + step + step + step + quit + """ + stdout, _ = self.run_pdb_script(script, commands) + self.assertIn("The program finished", stdout) + self.assertNotIn("bdb.py", stdout) + def test_pdbrc_basic(self): script = textwrap.dedent(""" a = 1 @@ -2708,6 +2790,16 @@ def _create_fake_frozen_module(): # verify that pdb found the source of the "frozen" function self.assertIn('x = "Sentinel string for gh-93696"', stdout, "Sentinel statement not found") + def test_empty_file(self): + script = '' + commands = 'q\n' + # We check that pdb stopped at line 0, but anything reasonable + # is acceptable here, as long as it does not halt + stdout, _ = self.run_pdb_script(script, commands) + self.assertIn('main.py(0)', stdout) + stdout, _ = self.run_pdb_module(script, commands) + self.assertIn('__main__.py(0)', stdout) + def test_non_utf8_encoding(self): script_dir = os.path.join(os.path.dirname(__file__), 'encoded_modules') for filename in os.listdir(script_dir): diff --git a/Lib/test/test_pickle.py b/Lib/test/test_pickle.py index 1a55da39..32fb3590 100644 --- a/Lib/test/test_pickle.py +++ b/Lib/test/test_pickle.py @@ -16,6 +16,7 @@ from test.pickletester import AbstractHookTests from test.pickletester import AbstractUnpickleTests +from test.pickletester import AbstractPicklingErrorTests from test.pickletester import AbstractPickleTests from test.pickletester import AbstractPickleModuleTests from test.pickletester import AbstractPersistentPicklerTests @@ -55,6 +56,18 @@ def loads(self, buf, **kwds): return u.load() +class PyPicklingErrorTests(AbstractPicklingErrorTests, unittest.TestCase): + + pickler = pickle._Pickler + + def dumps(self, arg, proto=None, **kwargs): + f = io.BytesIO() + p = self.pickler(f, proto, **kwargs) + p.dump(arg) + f.seek(0) + return bytes(f.read()) + + class PyPicklerTests(AbstractPickleTests, unittest.TestCase): pickler = pickle._Pickler @@ -88,6 +101,8 @@ def loads(self, buf, **kwds): return pickle.loads(buf, **kwds) test_framed_write_sizes_with_delayed_writer = None + test_find_class = None + test_custom_find_class = None class PersistentPicklerUnpicklerMixin(object): @@ -245,6 +260,9 @@ class CUnpicklerTests(PyUnpicklerTests): bad_stack_errors = (pickle.UnpicklingError,) truncated_errors = (pickle.UnpicklingError,) + class CPicklingErrorTests(PyPicklingErrorTests): + pickler = _pickle.Pickler + class CPicklerTests(PyPicklerTests): pickler = _pickle.Pickler unpickler = _pickle.Unpickler diff --git a/Lib/test/test_pickletools.py b/Lib/test/test_pickletools.py index d37af79e..5cb9ce43 100644 --- a/Lib/test/test_pickletools.py +++ b/Lib/test/test_pickletools.py @@ -1,3 +1,4 @@ +import io import pickle import pickletools from test import support @@ -62,6 +63,397 @@ def test_optimize_binput_and_memoize(self): self.assertNotIn(pickle.BINPUT, pickled2) +class SimpleReader: + def __init__(self, data): + self.data = data + self.pos = 0 + + def read(self, n): + data = self.data[self.pos: self.pos + n] + self.pos += n + return data + + def readline(self): + nl = self.data.find(b'\n', self.pos) + 1 + if not nl: + nl = len(self.data) + data = self.data[self.pos: nl] + self.pos = nl + return data + + +class GenopsTests(unittest.TestCase): + def test_genops(self): + it = pickletools.genops(b'(I123\nK\x12J\x12\x34\x56\x78t.') + self.assertEqual([(item[0].name,) + item[1:] for item in it], [ + ('MARK', None, 0), + ('INT', 123, 1), + ('BININT1', 0x12, 6), + ('BININT', 0x78563412, 8), + ('TUPLE', None, 13), + ('STOP', None, 14), + ]) + + def test_from_file(self): + f = io.BytesIO(b'prefix(I123\nK\x12J\x12\x34\x56\x78t.suffix') + self.assertEqual(f.read(6), b'prefix') + it = pickletools.genops(f) + self.assertEqual([(item[0].name,) + item[1:] for item in it], [ + ('MARK', None, 6), + ('INT', 123, 7), + ('BININT1', 0x12, 12), + ('BININT', 0x78563412, 14), + ('TUPLE', None, 19), + ('STOP', None, 20), + ]) + self.assertEqual(f.read(), b'suffix') + + def test_without_pos(self): + f = SimpleReader(b'(I123\nK\x12J\x12\x34\x56\x78t.') + it = pickletools.genops(f) + self.assertEqual([(item[0].name,) + item[1:] for item in it], [ + ('MARK', None, None), + ('INT', 123, None), + ('BININT1', 0x12, None), + ('BININT', 0x78563412, None), + ('TUPLE', None, None), + ('STOP', None, None), + ]) + + def test_no_stop(self): + it = pickletools.genops(b'N') + item = next(it) + self.assertEqual(item[0].name, 'NONE') + with self.assertRaisesRegex(ValueError, + 'pickle exhausted before seeing STOP'): + next(it) + + def test_truncated_data(self): + it = pickletools.genops(b'I123') + with self.assertRaisesRegex(ValueError, + 'no newline found when trying to read stringnl'): + next(it) + it = pickletools.genops(b'J\x12\x34') + with self.assertRaisesRegex(ValueError, + 'not enough data in stream to read int4'): + next(it) + + def test_unknown_opcode(self): + it = pickletools.genops(b'N\xff') + item = next(it) + self.assertEqual(item[0].name, 'NONE') + with self.assertRaisesRegex(ValueError, + r"at position 1, opcode b'\\xff' unknown"): + next(it) + + def test_unknown_opcode_without_pos(self): + f = SimpleReader(b'N\xff') + it = pickletools.genops(f) + item = next(it) + self.assertEqual(item[0].name, 'NONE') + with self.assertRaisesRegex(ValueError, + r"at position , opcode b'\\xff' unknown"): + next(it) + + +class DisTests(unittest.TestCase): + maxDiff = None + + def check_dis(self, data, expected, **kwargs): + out = io.StringIO() + pickletools.dis(data, out=out, **kwargs) + self.assertEqual(out.getvalue(), expected) + + def check_dis_error(self, data, expected, expected_error, **kwargs): + out = io.StringIO() + with self.assertRaisesRegex(ValueError, expected_error): + pickletools.dis(data, out=out, **kwargs) + self.assertEqual(out.getvalue(), expected) + + def test_mark(self): + self.check_dis(b'(N(tl.', '''\ + 0: ( MARK + 1: N NONE + 2: ( MARK + 3: t TUPLE (MARK at 2) + 4: l LIST (MARK at 0) + 5: . STOP +highest protocol among opcodes = 0 +''') + + def test_indentlevel(self): + self.check_dis(b'(N(tl.', '''\ + 0: ( MARK + 1: N NONE + 2: ( MARK + 3: t TUPLE (MARK at 2) + 4: l LIST (MARK at 0) + 5: . STOP +highest protocol among opcodes = 0 +''', indentlevel=2) + + def test_mark_without_pos(self): + self.check_dis(SimpleReader(b'(N(tl.'), '''\ +( MARK +N NONE +( MARK +t TUPLE (MARK at unknown opcode offset) +l LIST (MARK at unknown opcode offset) +. STOP +highest protocol among opcodes = 0 +''') + + def test_no_mark(self): + self.check_dis_error(b'Nt.', '''\ + 0: N NONE + 1: t TUPLE no MARK exists on stack +''', 'no MARK exists on stack') + + def test_put(self): + self.check_dis(b'Np0\nq\x01r\x02\x00\x00\x00\x94.', '''\ + 0: N NONE + 1: p PUT 0 + 4: q BINPUT 1 + 6: r LONG_BINPUT 2 + 11: \\x94 MEMOIZE (as 3) + 12: . STOP +highest protocol among opcodes = 4 +''') + + def test_put_redefined(self): + self.check_dis_error(b'Np1\np1\n.', '''\ + 0: N NONE + 1: p PUT 1 + 4: p PUT 1 +''', 'memo key 1 already defined') + self.check_dis_error(b'Np1\nq\x01.', '''\ + 0: N NONE + 1: p PUT 1 + 4: q BINPUT 1 +''', 'memo key 1 already defined') + self.check_dis_error(b'Np1\nr\x01\x00\x00\x00.', '''\ + 0: N NONE + 1: p PUT 1 + 4: r LONG_BINPUT 1 +''', 'memo key 1 already defined') + self.check_dis_error(b'Np1\n\x94.', '''\ + 0: N NONE + 1: p PUT 1 + 4: \\x94 MEMOIZE (as 1) +''', 'memo key None already defined') + + def test_put_empty_stack(self): + self.check_dis_error(b'p0\n', '''\ + 0: p PUT 0 +''', "stack is empty -- can't store into memo") + + def test_put_markobject(self): + self.check_dis_error(b'(p0\n', '''\ + 0: ( MARK + 1: p PUT 0 +''', "can't store markobject in the memo") + + def test_get(self): + self.check_dis(b'(Np1\ng1\nh\x01j\x01\x00\x00\x00t.', '''\ + 0: ( MARK + 1: N NONE + 2: p PUT 1 + 5: g GET 1 + 8: h BINGET 1 + 10: j LONG_BINGET 1 + 15: t TUPLE (MARK at 0) + 16: . STOP +highest protocol among opcodes = 1 +''') + + def test_get_without_put(self): + self.check_dis_error(b'g1\n.', '''\ + 0: g GET 1 +''', 'memo key 1 has never been stored into') + self.check_dis_error(b'h\x01.', '''\ + 0: h BINGET 1 +''', 'memo key 1 has never been stored into') + self.check_dis_error(b'j\x01\x00\x00\x00.', '''\ + 0: j LONG_BINGET 1 +''', 'memo key 1 has never been stored into') + + def test_memo(self): + memo = {} + self.check_dis(b'Np1\n.', '''\ + 0: N NONE + 1: p PUT 1 + 4: . STOP +highest protocol among opcodes = 0 +''', memo=memo) + self.check_dis(b'g1\n.', '''\ + 0: g GET 1 + 3: . STOP +highest protocol among opcodes = 0 +''', memo=memo) + + def test_mark_pop(self): + self.check_dis(b'(N00N.', '''\ + 0: ( MARK + 1: N NONE + 2: 0 POP + 3: 0 POP (MARK at 0) + 4: N NONE + 5: . STOP +highest protocol among opcodes = 0 +''') + + def test_too_small_stack(self): + self.check_dis_error(b'a', '''\ + 0: a APPEND +''', 'tries to pop 2 items from stack with only 0 items') + self.check_dis_error(b']a', '''\ + 0: ] EMPTY_LIST + 1: a APPEND +''', 'tries to pop 2 items from stack with only 1 items') + + def test_no_stop(self): + self.check_dis_error(b'N', '''\ + 0: N NONE +''', 'pickle exhausted before seeing STOP') + + def test_truncated_data(self): + self.check_dis_error(b'NI123', '''\ + 0: N NONE +''', 'no newline found when trying to read stringnl') + self.check_dis_error(b'NJ\x12\x34', '''\ + 0: N NONE +''', 'not enough data in stream to read int4') + + def test_unknown_opcode(self): + self.check_dis_error(b'N\xff', '''\ + 0: N NONE +''', r"at position 1, opcode b'\\xff' unknown") + + def test_stop_not_empty_stack(self): + self.check_dis_error(b']N.', '''\ + 0: ] EMPTY_LIST + 1: N NONE + 2: . STOP +highest protocol among opcodes = 1 +''', r'stack not empty after STOP: \[list\]') + + def test_annotate(self): + self.check_dis(b'(Nt.', '''\ + 0: ( MARK Push markobject onto the stack. + 1: N NONE Push None on the stack. + 2: t TUPLE (MARK at 0) Build a tuple out of the topmost stack slice, after markobject. + 3: . STOP Stop the unpickling machine. +highest protocol among opcodes = 0 +''', annotate=1) + self.check_dis(b'(Nt.', '''\ + 0: ( MARK Push markobject onto the stack. + 1: N NONE Push None on the stack. + 2: t TUPLE (MARK at 0) Build a tuple out of the topmost stack slice, after markobject. + 3: . STOP Stop the unpickling machine. +highest protocol among opcodes = 0 +''', annotate=20) + self.check_dis(b'(((((((ttttttt.', '''\ + 0: ( MARK Push markobject onto the stack. + 1: ( MARK Push markobject onto the stack. + 2: ( MARK Push markobject onto the stack. + 3: ( MARK Push markobject onto the stack. + 4: ( MARK Push markobject onto the stack. + 5: ( MARK Push markobject onto the stack. + 6: ( MARK Push markobject onto the stack. + 7: t TUPLE (MARK at 6) Build a tuple out of the topmost stack slice, after markobject. + 8: t TUPLE (MARK at 5) Build a tuple out of the topmost stack slice, after markobject. + 9: t TUPLE (MARK at 4) Build a tuple out of the topmost stack slice, after markobject. + 10: t TUPLE (MARK at 3) Build a tuple out of the topmost stack slice, after markobject. + 11: t TUPLE (MARK at 2) Build a tuple out of the topmost stack slice, after markobject. + 12: t TUPLE (MARK at 1) Build a tuple out of the topmost stack slice, after markobject. + 13: t TUPLE (MARK at 0) Build a tuple out of the topmost stack slice, after markobject. + 14: . STOP Stop the unpickling machine. +highest protocol among opcodes = 0 +''', annotate=20) + + def test_string(self): + self.check_dis(b"S'abc'\n.", '''\ + 0: S STRING 'abc' + 7: . STOP +highest protocol among opcodes = 0 +''') + self.check_dis(b'S"abc"\n.', '''\ + 0: S STRING 'abc' + 7: . STOP +highest protocol among opcodes = 0 +''') + self.check_dis(b"S'\xc3\xb5'\n.", '''\ + 0: S STRING '\\xc3\\xb5' + 6: . STOP +highest protocol among opcodes = 0 +''') + + def test_string_without_quotes(self): + self.check_dis_error(b"Sabc'\n.", '', + 'no string quotes around b"abc\'"') + self.check_dis_error(b'Sabc"\n.', '', + "no string quotes around b'abc\"'") + self.check_dis_error(b"S'abc\n.", '', + '''strinq quote b"'" not found at both ends of b"'abc"''') + self.check_dis_error(b'S"abc\n.', '', + r"""strinq quote b'"' not found at both ends of b'"abc'""") + self.check_dis_error(b"S'abc\"\n.", '', + r"""strinq quote b"'" not found at both ends of b'\\'abc"'""") + self.check_dis_error(b"S\"abc'\n.", '', + r"""strinq quote b'"' not found at both ends of b'"abc\\''""") + + def test_binstring(self): + self.check_dis(b"T\x03\x00\x00\x00abc.", '''\ + 0: T BINSTRING 'abc' + 8: . STOP +highest protocol among opcodes = 1 +''') + self.check_dis(b"T\x02\x00\x00\x00\xc3\xb5.", '''\ + 0: T BINSTRING '\\xc3\\xb5' + 7: . STOP +highest protocol among opcodes = 1 +''') + + def test_short_binstring(self): + self.check_dis(b"U\x03abc.", '''\ + 0: U SHORT_BINSTRING 'abc' + 5: . STOP +highest protocol among opcodes = 1 +''') + self.check_dis(b"U\x02\xc3\xb5.", '''\ + 0: U SHORT_BINSTRING '\\xc3\\xb5' + 4: . STOP +highest protocol among opcodes = 1 +''') + + def test_global(self): + self.check_dis(b"cmodule\nname\n.", '''\ + 0: c GLOBAL 'module name' + 13: . STOP +highest protocol among opcodes = 0 +''') + self.check_dis(b"cm\xc3\xb6dule\nn\xc3\xa4me\n.", '''\ + 0: c GLOBAL 'm\xf6dule n\xe4me' + 15: . STOP +highest protocol among opcodes = 0 +''') + + def test_inst(self): + self.check_dis(b"(imodule\nname\n.", '''\ + 0: ( MARK + 1: i INST 'module name' (MARK at 0) + 14: . STOP +highest protocol among opcodes = 0 +''') + + def test_persid(self): + self.check_dis(b"Pabc\n.", '''\ + 0: P PERSID 'abc' + 5: . STOP +highest protocol among opcodes = 0 +''') + + class MiscTestCase(unittest.TestCase): def test__all__(self): not_exported = { diff --git a/Lib/test/test_pkgutil.py b/Lib/test/test_pkgutil.py index d095f440..ca692755 100644 --- a/Lib/test/test_pkgutil.py +++ b/Lib/test/test_pkgutil.py @@ -522,7 +522,43 @@ def test_mixed_namespace(self): del sys.modules['foo.bar'] del sys.modules['foo.baz'] - # XXX: test .pkg files + + def test_extend_path_argument_types(self): + pkgname = 'foo' + dirname_0 = self.create_init(pkgname) + + # If the input path is not a list it is returned unchanged + self.assertEqual('notalist', pkgutil.extend_path('notalist', 'foo')) + self.assertEqual(('not', 'a', 'list'), pkgutil.extend_path(('not', 'a', 'list'), 'foo')) + self.assertEqual(123, pkgutil.extend_path(123, 'foo')) + self.assertEqual(None, pkgutil.extend_path(None, 'foo')) + + # Cleanup + shutil.rmtree(dirname_0) + del sys.path[0] + + + def test_extend_path_pkg_files(self): + pkgname = 'foo' + dirname_0 = self.create_init(pkgname) + + with open(os.path.join(dirname_0, 'bar.pkg'), 'w') as pkg_file: + pkg_file.write('\n'.join([ + 'baz', + '/foo/bar/baz', + '', + '#comment' + ])) + + extended_paths = pkgutil.extend_path(sys.path, 'bar') + + self.assertEqual(extended_paths[:-2], sys.path) + self.assertEqual(extended_paths[-2], 'baz') + self.assertEqual(extended_paths[-1], '/foo/bar/baz') + + # Cleanup + shutil.rmtree(dirname_0) + del sys.path[0] class NestedNamespacePackageTest(unittest.TestCase): @@ -588,8 +624,11 @@ def test_get_loader_handles_missing_spec_attribute(self): mod = type(sys)(name) del mod.__spec__ with CleanImport(name): - sys.modules[name] = mod - loader = pkgutil.get_loader(name) + try: + sys.modules[name] = mod + loader = pkgutil.get_loader(name) + finally: + sys.modules.pop(name, None) self.assertIsNone(loader) @ignore_warnings(category=DeprecationWarning) @@ -598,8 +637,11 @@ def test_get_loader_handles_spec_attribute_none(self): mod = type(sys)(name) mod.__spec__ = None with CleanImport(name): - sys.modules[name] = mod - loader = pkgutil.get_loader(name) + try: + sys.modules[name] = mod + loader = pkgutil.get_loader(name) + finally: + sys.modules.pop(name, None) self.assertIsNone(loader) @ignore_warnings(category=DeprecationWarning) diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index 7ed45acf..e225b891 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -6,12 +6,14 @@ from test.support import warnings_helper from test.support.script_helper import assert_python_ok +import copy import errno import sys import signal import time import os import platform +import pickle import stat import tempfile import unittest @@ -411,8 +413,10 @@ def test_posix_fallocate(self): # issue33655: Also ignore EINVAL on *BSD since ZFS is also # often used there. if inst.errno == errno.EINVAL and sys.platform.startswith( - ('sunos', 'freebsd', 'netbsd', 'openbsd', 'gnukfreebsd')): + ('sunos', 'freebsd', 'openbsd', 'gnukfreebsd')): raise unittest.SkipTest("test may fail on ZFS filesystems") + elif inst.errno == errno.EOPNOTSUPP and sys.platform.startswith("netbsd"): + raise unittest.SkipTest("test may fail on FFS filesystems") else: raise finally: @@ -1306,6 +1310,19 @@ def test_get_and_set_scheduler_and_param(self): param = posix.sched_param(sched_priority=-large) self.assertRaises(OverflowError, posix.sched_setparam, 0, param) + @requires_sched + def test_sched_param(self): + param = posix.sched_param(1) + for proto in range(pickle.HIGHEST_PROTOCOL+1): + newparam = pickle.loads(pickle.dumps(param, proto)) + self.assertEqual(newparam, param) + newparam = copy.copy(param) + self.assertIsNot(newparam, param) + self.assertEqual(newparam, param) + newparam = copy.deepcopy(param) + self.assertIsNot(newparam, param) + self.assertEqual(newparam, param) + @unittest.skipUnless(hasattr(posix, "sched_rr_get_interval"), "no function") def test_sched_rr_get_interval(self): try: diff --git a/Lib/test/test_posixpath.py b/Lib/test/test_posixpath.py index 932d8a35..cc4fd2f4 100644 --- a/Lib/test/test_posixpath.py +++ b/Lib/test/test_posixpath.py @@ -347,13 +347,19 @@ def test_expanduser_pwd(self): "no home directory on VxWorks") def test_expanduser_pwd2(self): pwd = import_helper.import_module('pwd') - for e in pwd.getpwall(): - name = e.pw_name - home = e.pw_dir + for all_entry in pwd.getpwall(): + name = all_entry.pw_name + + # gh-121200: pw_dir can be different between getpwall() and + # getpwnam(), so use getpwnam() pw_dir as expanduser() does. + entry = pwd.getpwnam(name) + home = entry.pw_dir home = home.rstrip('/') or '/' - self.assertEqual(posixpath.expanduser('~' + name), home) - self.assertEqual(posixpath.expanduser(os.fsencode('~' + name)), - os.fsencode(home)) + + with self.subTest(all_entry=all_entry, entry=entry): + self.assertEqual(posixpath.expanduser('~' + name), home) + self.assertEqual(posixpath.expanduser(os.fsencode('~' + name)), + os.fsencode(home)) NORMPATH_CASES = [ ("", "."), diff --git a/Lib/test/test_property.py b/Lib/test/test_property.py index 4de2bb37..4d632cd8 100644 --- a/Lib/test/test_property.py +++ b/Lib/test/test_property.py @@ -406,7 +406,7 @@ def getter3(self): self.assertEqual(p2.__doc__, "doc-A") # Case-3: with no user-provided doc new getter doc - # takes precendence + # takes precedence p = property(getter2, None, None, None) p2 = p.getter(getter3) @@ -431,6 +431,40 @@ def getter3(self): self.assertEqual(p.__doc__, "user") self.assertEqual(p2.__doc__, "user") + @unittest.skipIf(sys.flags.optimize >= 2, + "Docstrings are omitted with -O2 and above") + def test_prefer_explicit_doc(self): + # Issue 25757: subclasses of property lose docstring + self.assertEqual(property(doc="explicit doc").__doc__, "explicit doc") + self.assertEqual(PropertySub(doc="explicit doc").__doc__, "explicit doc") + + class Foo: + spam = PropertySub(doc="spam explicit doc") + + @spam.getter + def spam(self): + """ignored as doc already set""" + return 1 + + def _stuff_getter(self): + """ignored as doc set directly""" + stuff = PropertySub(doc="stuff doc argument", fget=_stuff_getter) + + #self.assertEqual(Foo.spam.__doc__, "spam explicit doc") + self.assertEqual(Foo.stuff.__doc__, "stuff doc argument") + + def test_property_no_doc_on_getter(self): + # If a property's getter has no __doc__ then the property's doc should + # be None; test that this is consistent with subclasses as well; see + # GH-2487 + class NoDoc: + @property + def __doc__(self): + raise AttributeError + + self.assertEqual(property(NoDoc()).__doc__, None) + self.assertEqual(PropertySub(NoDoc()).__doc__, None) + @unittest.skipIf(sys.flags.optimize >= 2, "Docstrings are omitted with -O2 and above") def test_property_setter_copies_getter_docstring(self): diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py index 23453e34..5415fa08 100644 --- a/Lib/test/test_pyclbr.py +++ b/Lib/test/test_pyclbr.py @@ -78,7 +78,8 @@ def ismethod(oclass, obj, name): objname = obj.__name__ if objname.startswith("__") and not objname.endswith("__"): - objname = "_%s%s" % (oclass.__name__, objname) + if stripped_typename := oclass.__name__.lstrip('_'): + objname = f"_{stripped_typename}{objname}" return objname == name # Make sure the toplevel functions and classes are the same. @@ -111,12 +112,16 @@ def ismethod(oclass, obj, name): for m in py_item.__dict__.keys(): if ismethod(py_item, getattr(py_item, m), m): actualMethods.append(m) - foundMethods = [] - for m in value.methods.keys(): - if m[:2] == '__' and m[-2:] != '__': - foundMethods.append('_'+name+m) - else: - foundMethods.append(m) + + if stripped_typename := name.lstrip('_'): + foundMethods = [] + for m in value.methods.keys(): + if m.startswith('__') and not m.endswith('__'): + foundMethods.append(f"_{stripped_typename}{m}") + else: + foundMethods.append(m) + else: + foundMethods = list(value.methods.keys()) try: self.assertListEq(foundMethods, actualMethods, ignore) @@ -150,8 +155,9 @@ def test_easy(self): "DocTestCase", '_DocTestSuite')) self.checkModule('difflib', ignore=("Match",)) - def test_decorators(self): - self.checkModule('test.pyclbr_input', ignore=['om']) + def test_cases(self): + # see test.pyclbr_input for the rationale behind the ignored symbols + self.checkModule('test.pyclbr_input', ignore=['om', 'f']) def test_nested(self): mb = pyclbr diff --git a/Lib/test/test_pydoc/test_pydoc.py b/Lib/test/test_pydoc/test_pydoc.py index a35257c8..6e80b543 100644 --- a/Lib/test/test_pydoc/test_pydoc.py +++ b/Lib/test/test_pydoc/test_pydoc.py @@ -15,6 +15,7 @@ import types import typing import unittest +import unittest.mock import urllib.parse import xml.etree import xml.etree.ElementTree @@ -377,6 +378,11 @@ def html2text(html): class PydocBaseTest(unittest.TestCase): + def tearDown(self): + # Self-testing. Mocking only works if sys.modules['pydoc'] and pydoc + # are the same. But some pydoc functions reload the module and change + # sys.modules, so check that it was restored. + self.assertIs(sys.modules['pydoc'], pydoc) def _restricted_walk_packages(self, walk_packages, path=None): """ @@ -408,6 +414,8 @@ def call_url_handler(self, url, expected_title): class PydocDocTest(unittest.TestCase): maxDiff = None + def tearDown(self): + self.assertIs(sys.modules['pydoc'], pydoc) @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(), 'trace function introduces __locals__ unexpectedly') @@ -656,16 +664,13 @@ def test_fail_help_output_redirect(self): @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(), 'trace function introduces __locals__ unexpectedly') + @unittest.mock.patch('pydoc.pager') @requires_docstrings - def test_help_output_redirect(self): + def test_help_output_redirect(self, pager_mock): # issue 940286, if output is set in Helper, then all output from # Helper.help should be redirected - getpager_old = pydoc.getpager - getpager_new = lambda: (lambda x: x) self.maxDiff = None - buf = StringIO() - helper = pydoc.Helper(output=buf) unused, doc_loc = get_pydoc_text(pydoc_mod) module = "test.test_pydoc.pydoc_mod" help_header = """ @@ -675,21 +680,112 @@ def test_help_output_redirect(self): help_header = textwrap.dedent(help_header) expected_help_pattern = help_header + expected_text_pattern - pydoc.getpager = getpager_new - try: + with captured_output('stdout') as output, \ + captured_output('stderr') as err, \ + StringIO() as buf: + helper = pydoc.Helper(output=buf) + helper.help(module) + result = buf.getvalue().strip() + expected_text = expected_help_pattern % ( + (doc_loc,) + + expected_text_data_docstrings + + (inspect.getabsfile(pydoc_mod),)) + self.assertEqual('', output.getvalue()) + self.assertEqual('', err.getvalue()) + self.assertEqual(expected_text, result) + + pager_mock.assert_not_called() + + @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(), + 'trace function introduces __locals__ unexpectedly') + @requires_docstrings + @unittest.mock.patch('pydoc.pager') + def test_help_output_redirect_various_requests(self, pager_mock): + # issue 940286, if output is set in Helper, then all output from + # Helper.help should be redirected + + def run_pydoc_for_request(request, expected_text_part): + """Helper function to run pydoc with its output redirected""" with captured_output('stdout') as output, \ - captured_output('stderr') as err: - helper.help(module) + captured_output('stderr') as err, \ + StringIO() as buf: + helper = pydoc.Helper(output=buf) + helper.help(request) result = buf.getvalue().strip() - expected_text = expected_help_pattern % ( - (doc_loc,) + - expected_text_data_docstrings + - (inspect.getabsfile(pydoc_mod),)) - self.assertEqual('', output.getvalue()) - self.assertEqual('', err.getvalue()) - self.assertEqual(expected_text, result) - finally: - pydoc.getpager = getpager_old + self.assertEqual('', output.getvalue(), msg=f'failed on request "{request}"') + self.assertEqual('', err.getvalue(), msg=f'failed on request "{request}"') + self.assertIn(expected_text_part, result, msg=f'failed on request "{request}"') + pager_mock.assert_not_called() + + self.maxDiff = None + + # test for "keywords" + run_pydoc_for_request('keywords', 'Here is a list of the Python keywords.') + # test for "symbols" + run_pydoc_for_request('symbols', 'Here is a list of the punctuation symbols') + # test for "topics" + run_pydoc_for_request('topics', 'Here is a list of available topics.') + # test for "modules" skipped, see test_modules() + # test for symbol "%" + run_pydoc_for_request('%', 'The power operator') + # test for special True, False, None keywords + run_pydoc_for_request('True', 'class bool(int)') + run_pydoc_for_request('False', 'class bool(int)') + run_pydoc_for_request('None', 'class NoneType(object)') + # test for keyword "assert" + run_pydoc_for_request('assert', 'The "assert" statement') + # test for topic "TYPES" + run_pydoc_for_request('TYPES', 'The standard type hierarchy') + # test for "pydoc.Helper.help" + run_pydoc_for_request('pydoc.Helper.help', 'Help on function help in pydoc.Helper:') + # test for pydoc.Helper.help + run_pydoc_for_request(pydoc.Helper.help, 'Help on function help in module pydoc:') + # test for pydoc.Helper() instance skipped because it is always meant to be interactive + + def test_showtopic(self): + with captured_stdout() as showtopic_io: + helper = pydoc.Helper() + helper.showtopic('with') + helptext = showtopic_io.getvalue() + self.assertIn('The "with" statement', helptext) + + def test_fail_showtopic(self): + with captured_stdout() as showtopic_io: + helper = pydoc.Helper() + helper.showtopic('abd') + expected = "no documentation found for 'abd'" + self.assertEqual(expected, showtopic_io.getvalue().strip()) + + @unittest.mock.patch('pydoc.pager') + def test_fail_showtopic_output_redirect(self, pager_mock): + with StringIO() as buf: + helper = pydoc.Helper(output=buf) + helper.showtopic("abd") + expected = "no documentation found for 'abd'" + self.assertEqual(expected, buf.getvalue().strip()) + + pager_mock.assert_not_called() + + @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(), + 'trace function introduces __locals__ unexpectedly') + @requires_docstrings + @unittest.mock.patch('pydoc.pager') + def test_showtopic_output_redirect(self, pager_mock): + # issue 940286, if output is set in Helper, then all output from + # Helper.showtopic should be redirected + self.maxDiff = None + + with captured_output('stdout') as output, \ + captured_output('stderr') as err, \ + StringIO() as buf: + helper = pydoc.Helper(output=buf) + helper.showtopic('with') + result = buf.getvalue().strip() + self.assertEqual('', output.getvalue()) + self.assertEqual('', err.getvalue()) + self.assertIn('The "with" statement', result) + + pager_mock.assert_not_called() def test_lambda_with_return_annotation(self): func = lambda a, b, c: 1 @@ -1062,15 +1158,20 @@ def test_modules_search_builtin(self): self.assertTrue(result.startswith(expected)) def test_importfile(self): - loaded_pydoc = pydoc.importfile(pydoc.__file__) + try: + loaded_pydoc = pydoc.importfile(pydoc.__file__) - self.assertIsNot(loaded_pydoc, pydoc) - self.assertEqual(loaded_pydoc.__name__, 'pydoc') - self.assertEqual(loaded_pydoc.__file__, pydoc.__file__) - self.assertEqual(loaded_pydoc.__spec__, pydoc.__spec__) + self.assertIsNot(loaded_pydoc, pydoc) + self.assertEqual(loaded_pydoc.__name__, 'pydoc') + self.assertEqual(loaded_pydoc.__file__, pydoc.__file__) + self.assertEqual(loaded_pydoc.__spec__, pydoc.__spec__) + finally: + sys.modules['pydoc'] = pydoc class TestDescriptions(unittest.TestCase): + def tearDown(self): + self.assertIs(sys.modules['pydoc'], pydoc) def test_module(self): # Check that pydocfodder module can be described @@ -1416,6 +1517,8 @@ def a_fn_with_https_link(): class PydocFodderTest(unittest.TestCase): + def tearDown(self): + self.assertIs(sys.modules['pydoc'], pydoc) def getsection(self, text, beginline, endline): lines = text.splitlines() @@ -1543,6 +1646,8 @@ def test_html_doc_routines_in_module(self): ) class PydocServerTest(unittest.TestCase): """Tests for pydoc._start_server""" + def tearDown(self): + self.assertIs(sys.modules['pydoc'], pydoc) def test_server(self): # Minimal test that starts the server, checks that it works, then stops @@ -1605,9 +1710,14 @@ def test_url_requests(self): ("foobar", "Pydoc: Error - foobar"), ] - with self.restrict_walk_packages(): - for url, title in requests: - self.call_url_handler(url, title) + self.assertIs(sys.modules['pydoc'], pydoc) + try: + with self.restrict_walk_packages(): + for url, title in requests: + self.call_url_handler(url, title) + finally: + # Some requests reload the module and change sys.modules. + sys.modules['pydoc'] = pydoc class TestHelper(unittest.TestCase): @@ -1617,6 +1727,9 @@ def test_keywords(self): class PydocWithMetaClasses(unittest.TestCase): + def tearDown(self): + self.assertIs(sys.modules['pydoc'], pydoc) + @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(), 'trace function introduces __locals__ unexpectedly') @requires_docstrings diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index e279412e..fbab4953 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -820,31 +820,137 @@ def test_named_unicode_escapes(self): self.checkPatternError(br'\N{LESS-THAN SIGN}', r'bad escape \N', 0) self.checkPatternError(br'[\N{LESS-THAN SIGN}]', r'bad escape \N', 1) - def test_string_boundaries(self): + def test_word_boundaries(self): # See http://bugs.python.org/issue10713 - self.assertEqual(re.search(r"\b(abc)\b", "abc").group(1), - "abc") + self.assertEqual(re.search(r"\b(abc)\b", "abc").group(1), "abc") + self.assertEqual(re.search(r"\b(abc)\b", "abc", re.ASCII).group(1), "abc") + self.assertEqual(re.search(br"\b(abc)\b", b"abc").group(1), b"abc") + self.assertEqual(re.search(br"\b(abc)\b", b"abc", re.LOCALE).group(1), b"abc") + self.assertEqual(re.search(r"\b(ьюя)\b", "ьюя").group(1), "ьюя") + self.assertIsNone(re.search(r"\b(ьюя)\b", "ьюя", re.ASCII)) + # There's a word boundary between a word and a non-word. + self.assertTrue(re.match(r".\b", "a=")) + self.assertTrue(re.match(r".\b", "a=", re.ASCII)) + self.assertTrue(re.match(br".\b", b"a=")) + self.assertTrue(re.match(br".\b", b"a=", re.LOCALE)) + self.assertTrue(re.match(r".\b", "я=")) + self.assertIsNone(re.match(r".\b", "я=", re.ASCII)) + # There's a word boundary between a non-word and a word. + self.assertTrue(re.match(r".\b", "=a")) + self.assertTrue(re.match(r".\b", "=a", re.ASCII)) + self.assertTrue(re.match(br".\b", b"=a")) + self.assertTrue(re.match(br".\b", b"=a", re.LOCALE)) + self.assertTrue(re.match(r".\b", "=я")) + self.assertIsNone(re.match(r".\b", "=я", re.ASCII)) + # There is no word boundary inside a word. + self.assertIsNone(re.match(r".\b", "ab")) + self.assertIsNone(re.match(r".\b", "ab", re.ASCII)) + self.assertIsNone(re.match(br".\b", b"ab")) + self.assertIsNone(re.match(br".\b", b"ab", re.LOCALE)) + self.assertIsNone(re.match(r".\b", "юя")) + self.assertIsNone(re.match(r".\b", "юя", re.ASCII)) + # There is no word boundary between a non-word characters. + self.assertIsNone(re.match(r".\b", "=-")) + self.assertIsNone(re.match(r".\b", "=-", re.ASCII)) + self.assertIsNone(re.match(br".\b", b"=-")) + self.assertIsNone(re.match(br".\b", b"=-", re.LOCALE)) + # There is no non-boundary match between a word and a non-word. + self.assertIsNone(re.match(r".\B", "a=")) + self.assertIsNone(re.match(r".\B", "a=", re.ASCII)) + self.assertIsNone(re.match(br".\B", b"a=")) + self.assertIsNone(re.match(br".\B", b"a=", re.LOCALE)) + self.assertIsNone(re.match(r".\B", "я=")) + self.assertTrue(re.match(r".\B", "я=", re.ASCII)) + # There is no non-boundary match between a non-word and a word. + self.assertIsNone(re.match(r".\B", "=a")) + self.assertIsNone(re.match(r".\B", "=a", re.ASCII)) + self.assertIsNone(re.match(br".\B", b"=a")) + self.assertIsNone(re.match(br".\B", b"=a", re.LOCALE)) + self.assertIsNone(re.match(r".\B", "=я")) + self.assertTrue(re.match(r".\B", "=я", re.ASCII)) + # There's a non-boundary match inside a word. + self.assertTrue(re.match(r".\B", "ab")) + self.assertTrue(re.match(r".\B", "ab", re.ASCII)) + self.assertTrue(re.match(br".\B", b"ab")) + self.assertTrue(re.match(br".\B", b"ab", re.LOCALE)) + self.assertTrue(re.match(r".\B", "юя")) + self.assertTrue(re.match(r".\B", "юя", re.ASCII)) + # There's a non-boundary match between a non-word characters. + self.assertTrue(re.match(r".\B", "=-")) + self.assertTrue(re.match(r".\B", "=-", re.ASCII)) + self.assertTrue(re.match(br".\B", b"=-")) + self.assertTrue(re.match(br".\B", b"=-", re.LOCALE)) # There's a word boundary at the start of a string. self.assertTrue(re.match(r"\b", "abc")) + self.assertTrue(re.match(r"\b", "abc", re.ASCII)) + self.assertTrue(re.match(br"\b", b"abc")) + self.assertTrue(re.match(br"\b", b"abc", re.LOCALE)) + self.assertTrue(re.match(r"\b", "ьюя")) + self.assertIsNone(re.match(r"\b", "ьюя", re.ASCII)) + # There's a word boundary at the end of a string. + self.assertTrue(re.fullmatch(r".+\b", "abc")) + self.assertTrue(re.fullmatch(r".+\b", "abc", re.ASCII)) + self.assertTrue(re.fullmatch(br".+\b", b"abc")) + self.assertTrue(re.fullmatch(br".+\b", b"abc", re.LOCALE)) + self.assertTrue(re.fullmatch(r".+\b", "ьюя")) + self.assertIsNone(re.search(r"\b", "ьюя", re.ASCII)) # A non-empty string includes a non-boundary zero-length match. - self.assertTrue(re.search(r"\B", "abc")) + self.assertEqual(re.search(r"\B", "abc").span(), (1, 1)) + self.assertEqual(re.search(r"\B", "abc", re.ASCII).span(), (1, 1)) + self.assertEqual(re.search(br"\B", b"abc").span(), (1, 1)) + self.assertEqual(re.search(br"\B", b"abc", re.LOCALE).span(), (1, 1)) + self.assertEqual(re.search(r"\B", "ьюя").span(), (1, 1)) + self.assertEqual(re.search(r"\B", "ьюя", re.ASCII).span(), (0, 0)) # There is no non-boundary match at the start of a string. - self.assertFalse(re.match(r"\B", "abc")) + self.assertIsNone(re.match(r"\B", "abc")) + self.assertIsNone(re.match(r"\B", "abc", re.ASCII)) + self.assertIsNone(re.match(br"\B", b"abc")) + self.assertIsNone(re.match(br"\B", b"abc", re.LOCALE)) + self.assertIsNone(re.match(r"\B", "ьюя")) + self.assertTrue(re.match(r"\B", "ьюя", re.ASCII)) + # There is no non-boundary match at the end of a string. + self.assertIsNone(re.fullmatch(r".+\B", "abc")) + self.assertIsNone(re.fullmatch(r".+\B", "abc", re.ASCII)) + self.assertIsNone(re.fullmatch(br".+\B", b"abc")) + self.assertIsNone(re.fullmatch(br".+\B", b"abc", re.LOCALE)) + self.assertIsNone(re.fullmatch(r".+\B", "ьюя")) + self.assertTrue(re.fullmatch(r".+\B", "ьюя", re.ASCII)) # However, an empty string contains no word boundaries, and also no # non-boundaries. - self.assertIsNone(re.search(r"\B", "")) + self.assertIsNone(re.search(r"\b", "")) + self.assertIsNone(re.search(r"\b", "", re.ASCII)) + self.assertIsNone(re.search(br"\b", b"")) + self.assertIsNone(re.search(br"\b", b"", re.LOCALE)) # This one is questionable and different from the perlre behaviour, # but describes current behavior. - self.assertIsNone(re.search(r"\b", "")) + self.assertIsNone(re.search(r"\B", "")) + self.assertIsNone(re.search(r"\B", "", re.ASCII)) + self.assertIsNone(re.search(br"\B", b"")) + self.assertIsNone(re.search(br"\B", b"", re.LOCALE)) # A single word-character string has two boundaries, but no # non-boundary gaps. self.assertEqual(len(re.findall(r"\b", "a")), 2) + self.assertEqual(len(re.findall(r"\b", "a", re.ASCII)), 2) + self.assertEqual(len(re.findall(br"\b", b"a")), 2) + self.assertEqual(len(re.findall(br"\b", b"a", re.LOCALE)), 2) self.assertEqual(len(re.findall(r"\B", "a")), 0) + self.assertEqual(len(re.findall(r"\B", "a", re.ASCII)), 0) + self.assertEqual(len(re.findall(br"\B", b"a")), 0) + self.assertEqual(len(re.findall(br"\B", b"a", re.LOCALE)), 0) # If there are no words, there are no boundaries self.assertEqual(len(re.findall(r"\b", " ")), 0) + self.assertEqual(len(re.findall(r"\b", " ", re.ASCII)), 0) + self.assertEqual(len(re.findall(br"\b", b" ")), 0) + self.assertEqual(len(re.findall(br"\b", b" ", re.LOCALE)), 0) self.assertEqual(len(re.findall(r"\b", " ")), 0) + self.assertEqual(len(re.findall(r"\b", " ", re.ASCII)), 0) + self.assertEqual(len(re.findall(br"\b", b" ")), 0) + self.assertEqual(len(re.findall(br"\b", b" ", re.LOCALE)), 0) # Can match around the whitespace. self.assertEqual(len(re.findall(r"\B", " ")), 2) + self.assertEqual(len(re.findall(r"\B", " ", re.ASCII)), 2) + self.assertEqual(len(re.findall(br"\B", b" ")), 2) + self.assertEqual(len(re.findall(br"\B", b" ", re.LOCALE)), 2) def test_bigcharset(self): self.assertEqual(re.match("([\u2222\u2223])", @@ -967,6 +1073,39 @@ def test_ignore_case_set(self): self.assertTrue(re.match(br'[19a]', b'a', re.I)) self.assertTrue(re.match(br'[19a]', b'A', re.I)) self.assertTrue(re.match(br'[19A]', b'a', re.I)) + self.assertTrue(re.match(r'[19\xc7]', '\xc7', re.I)) + self.assertTrue(re.match(r'[19\xc7]', '\xe7', re.I)) + self.assertTrue(re.match(r'[19\xe7]', '\xc7', re.I)) + self.assertTrue(re.match(r'[19\xe7]', '\xe7', re.I)) + self.assertTrue(re.match(r'[19\u0400]', '\u0400', re.I)) + self.assertTrue(re.match(r'[19\u0400]', '\u0450', re.I)) + self.assertTrue(re.match(r'[19\u0450]', '\u0400', re.I)) + self.assertTrue(re.match(r'[19\u0450]', '\u0450', re.I)) + self.assertTrue(re.match(r'[19\U00010400]', '\U00010400', re.I)) + self.assertTrue(re.match(r'[19\U00010400]', '\U00010428', re.I)) + self.assertTrue(re.match(r'[19\U00010428]', '\U00010400', re.I)) + self.assertTrue(re.match(r'[19\U00010428]', '\U00010428', re.I)) + + self.assertTrue(re.match(br'[19A]', b'A', re.I)) + self.assertTrue(re.match(br'[19a]', b'a', re.I)) + self.assertTrue(re.match(br'[19a]', b'A', re.I)) + self.assertTrue(re.match(br'[19A]', b'a', re.I)) + self.assertTrue(re.match(r'[19A]', 'A', re.I|re.A)) + self.assertTrue(re.match(r'[19a]', 'a', re.I|re.A)) + self.assertTrue(re.match(r'[19a]', 'A', re.I|re.A)) + self.assertTrue(re.match(r'[19A]', 'a', re.I|re.A)) + self.assertTrue(re.match(r'[19\xc7]', '\xc7', re.I|re.A)) + self.assertIsNone(re.match(r'[19\xc7]', '\xe7', re.I|re.A)) + self.assertIsNone(re.match(r'[19\xe7]', '\xc7', re.I|re.A)) + self.assertTrue(re.match(r'[19\xe7]', '\xe7', re.I|re.A)) + self.assertTrue(re.match(r'[19\u0400]', '\u0400', re.I|re.A)) + self.assertIsNone(re.match(r'[19\u0400]', '\u0450', re.I|re.A)) + self.assertIsNone(re.match(r'[19\u0450]', '\u0400', re.I|re.A)) + self.assertTrue(re.match(r'[19\u0450]', '\u0450', re.I|re.A)) + self.assertTrue(re.match(r'[19\U00010400]', '\U00010400', re.I|re.A)) + self.assertIsNone(re.match(r'[19\U00010400]', '\U00010428', re.I|re.A)) + self.assertIsNone(re.match(r'[19\U00010428]', '\U00010400', re.I|re.A)) + self.assertTrue(re.match(r'[19\U00010428]', '\U00010428', re.I|re.A)) # Two different characters have the same lowercase. assert 'K'.lower() == '\u212a'.lower() == 'k' # 'K' @@ -1003,8 +1142,10 @@ def test_ignore_case_range(self): self.assertTrue(re.match(br'[9-a]', b'_', re.I)) self.assertIsNone(re.match(br'[9-A]', b'_', re.I)) self.assertTrue(re.match(r'[\xc0-\xde]', '\xd7', re.I)) + self.assertTrue(re.match(r'[\xc0-\xde]', '\xe7', re.I)) self.assertIsNone(re.match(r'[\xc0-\xde]', '\xf7', re.I)) self.assertTrue(re.match(r'[\xe0-\xfe]', '\xf7', re.I)) + self.assertTrue(re.match(r'[\xe0-\xfe]', '\xc7', re.I)) self.assertIsNone(re.match(r'[\xe0-\xfe]', '\xd7', re.I)) self.assertTrue(re.match(r'[\u0430-\u045f]', '\u0450', re.I)) self.assertTrue(re.match(r'[\u0430-\u045f]', '\u0400', re.I)) @@ -1015,6 +1156,26 @@ def test_ignore_case_range(self): self.assertTrue(re.match(r'[\U00010400-\U00010427]', '\U00010428', re.I)) self.assertTrue(re.match(r'[\U00010400-\U00010427]', '\U00010400', re.I)) + self.assertTrue(re.match(r'[\xc0-\xde]', '\xd7', re.I|re.A)) + self.assertIsNone(re.match(r'[\xc0-\xde]', '\xe7', re.I|re.A)) + self.assertTrue(re.match(r'[\xe0-\xfe]', '\xf7', re.I|re.A)) + self.assertIsNone(re.match(r'[\xe0-\xfe]', '\xc7', re.I|re.A)) + self.assertTrue(re.match(r'[\u0430-\u045f]', '\u0450', re.I|re.A)) + self.assertIsNone(re.match(r'[\u0430-\u045f]', '\u0400', re.I|re.A)) + self.assertIsNone(re.match(r'[\u0400-\u042f]', '\u0450', re.I|re.A)) + self.assertTrue(re.match(r'[\u0400-\u042f]', '\u0400', re.I|re.A)) + self.assertTrue(re.match(r'[\U00010428-\U0001044f]', '\U00010428', re.I|re.A)) + self.assertIsNone(re.match(r'[\U00010428-\U0001044f]', '\U00010400', re.I|re.A)) + self.assertIsNone(re.match(r'[\U00010400-\U00010427]', '\U00010428', re.I|re.A)) + self.assertTrue(re.match(r'[\U00010400-\U00010427]', '\U00010400', re.I|re.A)) + + self.assertTrue(re.match(r'[N-\x7f]', 'A', re.I|re.A)) + self.assertTrue(re.match(r'[n-\x7f]', 'Z', re.I|re.A)) + self.assertTrue(re.match(r'[N-\uffff]', 'A', re.I|re.A)) + self.assertTrue(re.match(r'[n-\uffff]', 'Z', re.I|re.A)) + self.assertTrue(re.match(r'[N-\U00010000]', 'A', re.I|re.A)) + self.assertTrue(re.match(r'[n-\U00010000]', 'Z', re.I|re.A)) + # Two different characters have the same lowercase. assert 'K'.lower() == '\u212a'.lower() == 'k' # 'K' self.assertTrue(re.match(r'[J-M]', '\u212a', re.I)) @@ -1052,47 +1213,76 @@ def test_not_literal(self): def test_possible_set_operations(self): s = bytes(range(128)).decode() - with self.assertWarns(FutureWarning): + with self.assertWarnsRegex(FutureWarning, 'Possible set difference') as w: p = re.compile(r'[0-9--1]') + self.assertEqual(w.filename, __file__) self.assertEqual(p.findall(s), list('-./0123456789')) + with self.assertWarnsRegex(FutureWarning, 'Possible set difference') as w: + self.assertEqual(re.findall(r'[0-9--2]', s), list('-./0123456789')) + self.assertEqual(w.filename, __file__) + self.assertEqual(re.findall(r'[--1]', s), list('-./01')) - with self.assertWarns(FutureWarning): + + with self.assertWarnsRegex(FutureWarning, 'Possible set difference') as w: p = re.compile(r'[%--1]') + self.assertEqual(w.filename, __file__) self.assertEqual(p.findall(s), list("%&'()*+,-1")) - with self.assertWarns(FutureWarning): + + with self.assertWarnsRegex(FutureWarning, 'Possible set difference ') as w: p = re.compile(r'[%--]') + self.assertEqual(w.filename, __file__) self.assertEqual(p.findall(s), list("%&'()*+,-")) - with self.assertWarns(FutureWarning): + with self.assertWarnsRegex(FutureWarning, 'Possible set intersection ') as w: p = re.compile(r'[0-9&&1]') + self.assertEqual(w.filename, __file__) self.assertEqual(p.findall(s), list('&0123456789')) - with self.assertWarns(FutureWarning): + with self.assertWarnsRegex(FutureWarning, 'Possible set intersection ') as w: + self.assertEqual(re.findall(r'[0-8&&1]', s), list('&012345678')) + self.assertEqual(w.filename, __file__) + + with self.assertWarnsRegex(FutureWarning, 'Possible set intersection ') as w: p = re.compile(r'[\d&&1]') + self.assertEqual(w.filename, __file__) self.assertEqual(p.findall(s), list('&0123456789')) + self.assertEqual(re.findall(r'[&&1]', s), list('&1')) - with self.assertWarns(FutureWarning): + with self.assertWarnsRegex(FutureWarning, 'Possible set union ') as w: p = re.compile(r'[0-9||a]') + self.assertEqual(w.filename, __file__) self.assertEqual(p.findall(s), list('0123456789a|')) - with self.assertWarns(FutureWarning): + + with self.assertWarnsRegex(FutureWarning, 'Possible set union ') as w: p = re.compile(r'[\d||a]') + self.assertEqual(w.filename, __file__) self.assertEqual(p.findall(s), list('0123456789a|')) + self.assertEqual(re.findall(r'[||1]', s), list('1|')) - with self.assertWarns(FutureWarning): + with self.assertWarnsRegex(FutureWarning, 'Possible set symmetric difference ') as w: p = re.compile(r'[0-9~~1]') + self.assertEqual(w.filename, __file__) self.assertEqual(p.findall(s), list('0123456789~')) - with self.assertWarns(FutureWarning): + + with self.assertWarnsRegex(FutureWarning, 'Possible set symmetric difference ') as w: p = re.compile(r'[\d~~1]') + self.assertEqual(w.filename, __file__) self.assertEqual(p.findall(s), list('0123456789~')) + self.assertEqual(re.findall(r'[~~1]', s), list('1~')) - with self.assertWarns(FutureWarning): + with self.assertWarnsRegex(FutureWarning, 'Possible nested set ') as w: p = re.compile(r'[[0-9]|]') + self.assertEqual(w.filename, __file__) self.assertEqual(p.findall(s), list('0123456789[]')) + with self.assertWarnsRegex(FutureWarning, 'Possible nested set ') as w: + self.assertEqual(re.findall(r'[[0-8]|]', s), list('012345678[]')) + self.assertEqual(w.filename, __file__) - with self.assertWarns(FutureWarning): + with self.assertWarnsRegex(FutureWarning, 'Possible nested set ') as w: p = re.compile(r'[[:digit:]|]') + self.assertEqual(w.filename, __file__) self.assertEqual(p.findall(s), list(':[]dgit')) def test_search_coverage(self): @@ -2411,6 +2601,12 @@ def test_bug_gh106052(self): self.assertEqual(re.match("(?>(?:ab?c){1,3})", "aca").span(), (0, 2)) self.assertEqual(re.match("(?:ab?c){1,3}+", "aca").span(), (0, 2)) + def test_bug_gh101955(self): + # Possessive quantifier with nested alternative with capture groups + self.assertEqual(re.match('((x)|y|z)*+', 'xyz').groups(), ('z', 'x')) + self.assertEqual(re.match('((x)|y|z){3}+', 'xyz').groups(), ('z', 'x')) + self.assertEqual(re.match('((x)|y|z){3,}+', 'xyz').groups(), ('z', 'x')) + @unittest.skipIf(multiprocessing is None, 'test requires multiprocessing') def test_regression_gh94675(self): pattern = re.compile(r'(?<=[({}])(((//[^\n]*)?[\n])([\000-\040])*)*' @@ -2431,6 +2627,50 @@ def test_regression_gh94675(self): p.terminate() p.join() + def test_fail(self): + self.assertEqual(re.search(r'12(?!)|3', '123')[0], '3') + + def test_character_set_any(self): + # The union of complementary character sets matches any character + # and is equivalent to "(?s:.)". + s = '1x\n' + for p in r'[\s\S]', r'[\d\D]', r'[\w\W]', r'[\S\s]', r'\s|\S': + with self.subTest(pattern=p): + self.assertEqual(re.findall(p, s), list(s)) + self.assertEqual(re.fullmatch('(?:' + p + ')+', s).group(), s) + + def test_character_set_none(self): + # Negation of the union of complementary character sets does not match + # any character. + s = '1x\n' + for p in r'[^\s\S]', r'[^\d\D]', r'[^\w\W]', r'[^\S\s]': + with self.subTest(pattern=p): + self.assertIsNone(re.search(p, s)) + self.assertIsNone(re.search('(?s:.)' + p, s)) + + def check_interrupt(self, pattern, string, maxcount): + class Interrupt(Exception): + pass + p = re.compile(pattern) + for n in range(maxcount): + try: + p._fail_after(n, Interrupt) + p.match(string) + return n + except Interrupt: + pass + finally: + p._fail_after(-1, None) + + @unittest.skipUnless(hasattr(re.Pattern, '_fail_after'), 'requires debug build') + def test_memory_leaks(self): + self.check_interrupt(r'(.)*:', 'abc:', 100) + self.check_interrupt(r'([^:])*?:', 'abc:', 100) + self.check_interrupt(r'([^:])*+:', 'abc:', 100) + self.check_interrupt(r'(.){2,4}:', 'abc:', 100) + self.check_interrupt(r'([^:]){2,4}?:', 'abc:', 100) + self.check_interrupt(r'([^:]){2,4}+:', 'abc:', 100) + def get_debug_out(pat): with captured_stdout() as out: diff --git a/Lib/test/test_readline.py b/Lib/test/test_readline.py index 6c2726d3..fab124ae 100644 --- a/Lib/test/test_readline.py +++ b/Lib/test/test_readline.py @@ -12,6 +12,7 @@ from test.support.os_helper import unlink, temp_dir, TESTFN from test.support.pty_helper import run_pty from test.support.script_helper import assert_python_ok +from test.support.threading_helper import requires_working_threading # Skip tests if there is no readline module readline = import_module('readline') @@ -132,6 +133,32 @@ def test_nonascii_history(self): self.assertEqual(readline.get_history_item(1), "entrée 1") self.assertEqual(readline.get_history_item(2), "entrée 22") + def test_write_read_limited_history(self): + previous_length = readline.get_history_length() + self.addCleanup(readline.set_history_length, previous_length) + + readline.clear_history() + readline.add_history("first line") + readline.add_history("second line") + readline.add_history("third line") + + readline.set_history_length(2) + self.assertEqual(readline.get_history_length(), 2) + readline.write_history_file(TESTFN) + self.addCleanup(os.remove, TESTFN) + + readline.clear_history() + self.assertEqual(readline.get_current_history_length(), 0) + self.assertEqual(readline.get_history_length(), 2) + + readline.read_history_file(TESTFN) + self.assertEqual(readline.get_history_item(1), "second line") + self.assertEqual(readline.get_history_item(2), "third line") + self.assertEqual(readline.get_history_item(3), None) + + # Readline seems to report an additional history element. + self.assertIn(readline.get_current_history_length(), (2, 3)) + class TestReadline(unittest.TestCase): @@ -320,6 +347,50 @@ def test_history_size(self): self.assertEqual(len(lines), history_size) self.assertEqual(lines[-1].strip(), b"last input") + @requires_working_threading() + def test_gh123321_threadsafe(self): + """gh-123321: readline should be thread-safe and not crash""" + script = textwrap.dedent(r""" + import threading + from test.support.threading_helper import join_thread + + def func(): + input() + + thread1 = threading.Thread(target=func) + thread2 = threading.Thread(target=func) + thread1.start() + thread2.start() + join_thread(thread1) + join_thread(thread2) + print("done") + """) + + output = run_pty(script, input=b"input1\rinput2\r") + + self.assertIn(b"done", output) + + + def test_write_read_limited_history(self): + previous_length = readline.get_history_length() + self.addCleanup(readline.set_history_length, previous_length) + + readline.add_history("first line") + readline.add_history("second line") + readline.add_history("third line") + + readline.set_history_length(2) + self.assertEqual(readline.get_history_length(), 2) + readline.write_history_file(TESTFN) + self.addCleanup(os.remove, TESTFN) + + readline.read_history_file(TESTFN) + # Without clear_history() there's no good way to test if + # the correct entries are present (we're combining history limiting and + # possible deduplication with arbitrary previous content). + # So, we've only tested that the read did not fail. + # See TestHistoryManipulation for the full test. + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index 8135a3fd..75196ac0 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -21,6 +21,8 @@ import tempfile import textwrap import unittest +from xml.etree import ElementTree + from test import support from test.support import os_helper from test.libregrtest import cmdline @@ -2221,6 +2223,44 @@ def test_pass(self): self.check_executed_tests(output, testname, stats=1, parallel=True) self.assertNotIn('SPAM SPAM SPAM', output) + def test_xml(self): + code = textwrap.dedent(r""" + import unittest + from test import support + + class VerboseTests(unittest.TestCase): + def test_failed(self): + print("abc \x1b def") + self.fail() + """) + testname = self.create_test(code=code) + + # Run sequentially + filename = os_helper.TESTFN + self.addCleanup(os_helper.unlink, filename) + + output = self.run_tests(testname, "--junit-xml", filename, + exitcode=EXITCODE_BAD_TEST) + self.check_executed_tests(output, testname, + failed=testname, + stats=TestStats(1, 1, 0)) + + # Test generated XML + with open(filename, encoding="utf8") as fp: + content = fp.read() + + testsuite = ElementTree.fromstring(content) + self.assertEqual(int(testsuite.get('tests')), 1) + self.assertEqual(int(testsuite.get('errors')), 0) + self.assertEqual(int(testsuite.get('failures')), 1) + + testcase = testsuite[0][0] + self.assertEqual(testcase.get('status'), 'run') + self.assertEqual(testcase.get('result'), 'completed') + self.assertGreater(float(testcase.get('time')), 0) + for out in testcase.iter('system-out'): + self.assertEqual(out.text, r"abc \x1b def") + class TestUtils(unittest.TestCase): def test_format_duration(self): @@ -2403,6 +2443,25 @@ def id(self): self.assertTrue(match_test(test_chdir)) self.assertFalse(match_test(test_copy)) + def test_sanitize_xml(self): + sanitize_xml = utils.sanitize_xml + + # escape invalid XML characters + self.assertEqual(sanitize_xml('abc \x1b\x1f def'), + r'abc \x1b\x1f def') + self.assertEqual(sanitize_xml('nul:\x00, bell:\x07'), + r'nul:\x00, bell:\x07') + self.assertEqual(sanitize_xml('surrogate:\uDC80'), + r'surrogate:\udc80') + self.assertEqual(sanitize_xml('illegal \uFFFE and \uFFFF'), + r'illegal \ufffe and \uffff') + + # no escape for valid XML characters + self.assertEqual(sanitize_xml('a\n\tb'), + 'a\n\tb') + self.assertEqual(sanitize_xml('valid t\xe9xt \u20ac'), + 'valid t\xe9xt \u20ac') + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_repl.py b/Lib/test/test_repl.py index ddb4aa68..f2f18a25 100644 --- a/Lib/test/test_repl.py +++ b/Lib/test/test_repl.py @@ -146,5 +146,42 @@ def f(): self.assertEqual(traceback_lines, expected_lines) +class TestAsyncioREPLContextVars(unittest.TestCase): + def test_toplevel_contextvars_sync(self): + user_input = dedent("""\ + from contextvars import ContextVar + var = ContextVar("var", default="failed") + var.set("ok") + """) + p = spawn_repl("-m", "asyncio") + p.stdin.write(user_input) + user_input2 = dedent(""" + print(f"toplevel contextvar test: {var.get()}") + """) + p.stdin.write(user_input2) + output = kill_python(p) + self.assertEqual(p.returncode, 0) + expected = "toplevel contextvar test: ok" + self.assertIn(expected, output, expected) + + def test_toplevel_contextvars_async(self): + user_input = dedent("""\ + from contextvars import ContextVar + var = ContextVar('var', default='failed') + """) + p = spawn_repl("-m", "asyncio") + p.stdin.write(user_input+"\n") + user_input2 = "async def set_var(): var.set('ok')\n" + p.stdin.write(user_input2+"\n") + user_input3 = "await set_var()\n" + p.stdin.write(user_input3+"\n") + user_input4 = "print(f'toplevel contextvar test: {var.get()}')\n" + p.stdin.write(user_input4+"\n") + output = kill_python(p) + self.assertEqual(p.returncode, 0) + expected = "toplevel contextvar test: ok" + self.assertIn(expected, output, expected) + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_reprlib.py b/Lib/test/test_reprlib.py index 4a896db2..e2a67ef3 100644 --- a/Lib/test/test_reprlib.py +++ b/Lib/test/test_reprlib.py @@ -580,6 +580,50 @@ def test_invalid_indent(self): with self.assertRaisesRegex(expected_error, expected_msg): r.repr(test_object) + def test_shadowed_stdlib_array(self): + # Issue #113570: repr() should not be fooled by an array + class array: + def __repr__(self): + return "not array.array" + + self.assertEqual(r(array()), "not array.array") + + def test_shadowed_builtin(self): + # Issue #113570: repr() should not be fooled + # by a shadowed builtin function + class list: + def __repr__(self): + return "not builtins.list" + + self.assertEqual(r(list()), "not builtins.list") + + def test_custom_repr(self): + class MyRepr(Repr): + + def repr_TextIOWrapper(self, obj, level): + if obj.name in {'', '', ''}: + return obj.name + return repr(obj) + + aRepr = MyRepr() + self.assertEqual(aRepr.repr(sys.stdin), "") + + def test_custom_repr_class_with_spaces(self): + class TypeWithSpaces: + pass + + t = TypeWithSpaces() + type(t).__name__ = "type with spaces" + self.assertEqual(type(t).__name__, "type with spaces") + + class MyRepr(Repr): + def repr_type_with_spaces(self, obj, level): + return "Type With Spaces" + + + aRepr = MyRepr() + self.assertEqual(aRepr.repr(t), "Type With Spaces") + def write_file(path, text): with open(path, 'w', encoding='ASCII') as fp: fp.write(text) diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py index 9c849410..3f68962a 100644 --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -660,8 +660,10 @@ def test_basic_script_with_pathlike_object(self): with temp_dir() as script_dir: mod_name = 'script' script_name = FakePath(self._make_test_script(script_dir, mod_name)) - self._check_script(script_name, "", script_name, - script_name, expect_spec=False) + self._check_script(script_name, "", + os.fsdecode(script_name), + os.fsdecode(script_name), + expect_spec=False) def test_basic_script_no_suffix(self): with temp_dir() as script_dir: diff --git a/Lib/test/test_scope.py b/Lib/test/test_scope.py index 6e46dfa9..24a366ef 100644 --- a/Lib/test/test_scope.py +++ b/Lib/test/test_scope.py @@ -810,6 +810,30 @@ def dig(self): gc_collect() # For PyPy or other GCs. self.assertIsNone(ref()) + def test_multiple_nesting(self): + # Regression test for https://github.com/python/cpython/issues/121863 + class MultiplyNested: + def f1(self): + __arg = 1 + class D: + def g(self, __arg): + return __arg + return D().g(_MultiplyNested__arg=2) + + def f2(self): + __arg = 1 + class D: + def g(self, __arg): + return __arg + return D().g + + inst = MultiplyNested() + with self.assertRaises(TypeError): + inst.f1() + + closure = inst.f2() + with self.assertRaises(TypeError): + closure(_MultiplyNested__arg=2) if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_setcomps.py b/Lib/test/test_setcomps.py index 976fa885..0bb02ef1 100644 --- a/Lib/test/test_setcomps.py +++ b/Lib/test/test_setcomps.py @@ -1,6 +1,9 @@ import doctest +import traceback import unittest +from test.support import BrokenIter + doctests = """ ########### Tests mostly copied from test_listcomps.py ############ @@ -148,6 +151,42 @@ """ +class SetComprehensionTest(unittest.TestCase): + def test_exception_locations(self): + # The location of an exception raised from __init__ or + # __next__ should should be the iterator expression + + def init_raises(): + try: + {x for x in BrokenIter(init_raises=True)} + except Exception as e: + return e + + def next_raises(): + try: + {x for x in BrokenIter(next_raises=True)} + except Exception as e: + return e + + def iter_raises(): + try: + {x for x in BrokenIter(iter_raises=True)} + except Exception as e: + return e + + for func, expected in [(init_raises, "BrokenIter(init_raises=True)"), + (next_raises, "BrokenIter(next_raises=True)"), + (iter_raises, "BrokenIter(iter_raises=True)"), + ]: + with self.subTest(func): + exc = func() + f = traceback.extract_tb(exc.__traceback__)[0] + indent = 16 + co = func.__code__ + self.assertEqual(f.lineno, co.co_firstlineno + 2) + self.assertEqual(f.end_lineno, co.co_firstlineno + 2) + self.assertEqual(f.line[f.colno - indent : f.end_colno - indent], + expected) __test__ = {'doctests' : doctests} diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index 7bc5d12e..c553ea09 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -71,18 +71,17 @@ def wrap(*args, **kwargs): os.rename = builtin_rename return wrap -def write_file(path, content, binary=False): +def create_file(path, content=b''): """Write *content* to a file located at *path*. If *path* is a tuple instead of a string, os.path.join will be used to - make a path. If *binary* is true, the file will be opened in binary - mode. + make a path. """ if isinstance(path, tuple): path = os.path.join(*path) - mode = 'wb' if binary else 'w' - encoding = None if binary else "utf-8" - with open(path, mode, encoding=encoding) as fp: + if isinstance(content, str): + content = content.encode() + with open(path, 'xb') as fp: fp.write(content) def write_test_file(path, size): @@ -191,7 +190,7 @@ def test_rmtree_works_on_bytes(self): tmp = self.mkdtemp() victim = os.path.join(tmp, 'killme') os.mkdir(victim) - write_file(os.path.join(victim, 'somefile'), 'foo') + create_file(os.path.join(victim, 'somefile'), 'foo') victim = os.fsencode(victim) self.assertIsInstance(victim, bytes) shutil.rmtree(victim) @@ -243,7 +242,7 @@ def test_rmtree_works_on_symlinks(self): for d in dir1, dir2, dir3: os.mkdir(d) file1 = os.path.join(tmp, 'file1') - write_file(file1, 'foo') + create_file(file1, 'foo') link1 = os.path.join(dir1, 'link1') os.symlink(dir2, link1) link2 = os.path.join(dir1, 'link2') @@ -305,7 +304,7 @@ def test_rmtree_works_on_junctions(self): for d in dir1, dir2, dir3: os.mkdir(d) file1 = os.path.join(tmp, 'file1') - write_file(file1, 'foo') + create_file(file1, 'foo') link1 = os.path.join(dir1, 'link1') _winapi.CreateJunction(dir2, link1) link2 = os.path.join(dir1, 'link2') @@ -327,8 +326,8 @@ def test_rmtree_errors_onerror(self): # existing file tmpdir = self.mkdtemp() - write_file((tmpdir, "tstfile"), "") filename = os.path.join(tmpdir, "tstfile") + create_file(filename) with self.assertRaises(NotADirectoryError) as cm: shutil.rmtree(filename) self.assertEqual(cm.exception.filename, filename) @@ -359,8 +358,8 @@ def test_rmtree_errors_onexc(self): # existing file tmpdir = self.mkdtemp() - write_file((tmpdir, "tstfile"), "") filename = os.path.join(tmpdir, "tstfile") + create_file(filename) with self.assertRaises(NotADirectoryError) as cm: shutil.rmtree(filename) self.assertEqual(cm.exception.filename, filename) @@ -549,7 +548,7 @@ def raiser(fn, *args, **kwargs): os.lstat = raiser os.mkdir(TESTFN) - write_file((TESTFN, 'foo'), 'foo') + create_file((TESTFN, 'foo'), 'foo') shutil.rmtree(TESTFN) finally: os.lstat = orig_lstat @@ -622,7 +621,7 @@ def test_rmtree_with_dir_fd(self): self.addCleanup(os.close, dir_fd) os.mkdir(fullname) os.mkdir(os.path.join(fullname, 'subdir')) - write_file(os.path.join(fullname, 'subdir', 'somefile'), 'foo') + create_file(os.path.join(fullname, 'subdir', 'somefile'), 'foo') self.assertTrue(os.path.exists(fullname)) shutil.rmtree(victim, dir_fd=dir_fd) self.assertFalse(os.path.exists(fullname)) @@ -662,7 +661,7 @@ def test_rmtree_on_junction(self): src = os.path.join(TESTFN, 'cheese') dst = os.path.join(TESTFN, 'shop') os.mkdir(src) - open(os.path.join(src, 'spam'), 'wb').close() + create_file(os.path.join(src, 'spam')) _winapi.CreateJunction(src, dst) self.assertRaises(OSError, shutil.rmtree, dst) shutil.rmtree(dst, ignore_errors=True) @@ -704,9 +703,9 @@ def test_copytree_simple(self): dst_dir = os.path.join(self.mkdtemp(), 'destination') self.addCleanup(shutil.rmtree, src_dir) self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir)) - write_file((src_dir, 'test.txt'), '123') + create_file((src_dir, 'test.txt'), '123') os.mkdir(os.path.join(src_dir, 'test_dir')) - write_file((src_dir, 'test_dir', 'test.txt'), '456') + create_file((src_dir, 'test_dir', 'test.txt'), '456') shutil.copytree(src_dir, dst_dir) self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt'))) @@ -724,11 +723,11 @@ def test_copytree_dirs_exist_ok(self): self.addCleanup(shutil.rmtree, src_dir) self.addCleanup(shutil.rmtree, dst_dir) - write_file((src_dir, 'nonexisting.txt'), '123') + create_file((src_dir, 'nonexisting.txt'), '123') os.mkdir(os.path.join(src_dir, 'existing_dir')) os.mkdir(os.path.join(dst_dir, 'existing_dir')) - write_file((dst_dir, 'existing_dir', 'existing.txt'), 'will be replaced') - write_file((src_dir, 'existing_dir', 'existing.txt'), 'has been replaced') + create_file((dst_dir, 'existing_dir', 'existing.txt'), 'will be replaced') + create_file((src_dir, 'existing_dir', 'existing.txt'), 'has been replaced') shutil.copytree(src_dir, dst_dir, dirs_exist_ok=True) self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'nonexisting.txt'))) @@ -751,7 +750,7 @@ def test_copytree_symlinks(self): sub_dir = os.path.join(src_dir, 'sub') os.mkdir(src_dir) os.mkdir(sub_dir) - write_file((src_dir, 'file.txt'), 'foo') + create_file((src_dir, 'file.txt'), 'foo') src_link = os.path.join(sub_dir, 'link') dst_link = os.path.join(dst_dir, 'sub/link') os.symlink(os.path.join(src_dir, 'file.txt'), @@ -782,16 +781,16 @@ def test_copytree_with_exclude(self): src_dir = self.mkdtemp() try: dst_dir = join(self.mkdtemp(), 'destination') - write_file((src_dir, 'test.txt'), '123') - write_file((src_dir, 'test.tmp'), '123') + create_file((src_dir, 'test.txt'), '123') + create_file((src_dir, 'test.tmp'), '123') os.mkdir(join(src_dir, 'test_dir')) - write_file((src_dir, 'test_dir', 'test.txt'), '456') + create_file((src_dir, 'test_dir', 'test.txt'), '456') os.mkdir(join(src_dir, 'test_dir2')) - write_file((src_dir, 'test_dir2', 'test.txt'), '456') + create_file((src_dir, 'test_dir2', 'test.txt'), '456') os.mkdir(join(src_dir, 'test_dir2', 'subdir')) os.mkdir(join(src_dir, 'test_dir2', 'subdir2')) - write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456') - write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456') + create_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456') + create_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456') # testing glob-like patterns try: @@ -850,7 +849,7 @@ def test_copytree_arg_types_of_ignore(self): os.mkdir(join(src_dir)) os.mkdir(join(src_dir, 'test_dir')) os.mkdir(os.path.join(src_dir, 'test_dir', 'subdir')) - write_file((src_dir, 'test_dir', 'subdir', 'test.txt'), '456') + create_file((src_dir, 'test_dir', 'subdir', 'test.txt'), '456') invokations = [] @@ -890,9 +889,9 @@ def test_copytree_retains_permissions(self): self.addCleanup(shutil.rmtree, tmp_dir) os.chmod(src_dir, 0o777) - write_file((src_dir, 'permissive.txt'), '123') + create_file((src_dir, 'permissive.txt'), '123') os.chmod(os.path.join(src_dir, 'permissive.txt'), 0o777) - write_file((src_dir, 'restrictive.txt'), '456') + create_file((src_dir, 'restrictive.txt'), '456') os.chmod(os.path.join(src_dir, 'restrictive.txt'), 0o600) restrictive_subdir = tempfile.mkdtemp(dir=src_dir) self.addCleanup(os_helper.rmtree, restrictive_subdir) @@ -935,8 +934,7 @@ def custom_cpfun(a, b): flag = [] src = self.mkdtemp() dst = tempfile.mktemp(dir=self.mkdtemp()) - with open(os.path.join(src, 'foo'), 'w', encoding='utf-8') as f: - f.close() + create_file(os.path.join(src, 'foo')) shutil.copytree(src, dst, copy_function=custom_cpfun) self.assertEqual(len(flag), 1) @@ -971,9 +969,9 @@ def test_copytree_named_pipe(self): def test_copytree_special_func(self): src_dir = self.mkdtemp() dst_dir = os.path.join(self.mkdtemp(), 'destination') - write_file((src_dir, 'test.txt'), '123') + create_file((src_dir, 'test.txt'), '123') os.mkdir(os.path.join(src_dir, 'test_dir')) - write_file((src_dir, 'test_dir', 'test.txt'), '456') + create_file((src_dir, 'test_dir', 'test.txt'), '456') copied = [] def _copy(src, dst): @@ -986,7 +984,7 @@ def _copy(src, dst): def test_copytree_dangling_symlinks(self): src_dir = self.mkdtemp() valid_file = os.path.join(src_dir, 'test.txt') - write_file(valid_file, 'abc') + create_file(valid_file, 'abc') dir_a = os.path.join(src_dir, 'dir_a') os.mkdir(dir_a) for d in src_dir, dir_a: @@ -1014,8 +1012,7 @@ def test_copytree_symlink_dir(self): src_dir = self.mkdtemp() dst_dir = os.path.join(self.mkdtemp(), 'destination') os.mkdir(os.path.join(src_dir, 'real_dir')) - with open(os.path.join(src_dir, 'real_dir', 'test.txt'), 'wb'): - pass + create_file(os.path.join(src_dir, 'real_dir', 'test.txt')) os.symlink(os.path.join(src_dir, 'real_dir'), os.path.join(src_dir, 'link_to_dir'), target_is_directory=True) @@ -1035,7 +1032,7 @@ def test_copytree_return_value(self): dst_dir = src_dir + "dest" self.addCleanup(shutil.rmtree, dst_dir, True) src = os.path.join(src_dir, 'foo') - write_file(src, 'foo') + create_file(src, 'foo') rv = shutil.copytree(src_dir, dst_dir) self.assertEqual(['foo'], os.listdir(rv)) @@ -1047,7 +1044,7 @@ def test_copytree_subdirectory(self): dst_dir = os.path.join(src_dir, "somevendor", "1.0") os.makedirs(src_dir) src = os.path.join(src_dir, 'pol') - write_file(src, 'pol') + create_file(src, 'pol') rv = shutil.copytree(src_dir, dst_dir) self.assertEqual(['pol'], os.listdir(rv)) @@ -1062,8 +1059,8 @@ def test_copymode_follow_symlinks(self): dst = os.path.join(tmp_dir, 'bar') src_link = os.path.join(tmp_dir, 'baz') dst_link = os.path.join(tmp_dir, 'quux') - write_file(src, 'foo') - write_file(dst, 'foo') + create_file(src, 'foo') + create_file(dst, 'foo') os.symlink(src, src_link) os.symlink(dst, dst_link) os.chmod(src, stat.S_IRWXU|stat.S_IRWXG) @@ -1095,8 +1092,8 @@ def test_copymode_symlink_to_symlink(self): dst = os.path.join(tmp_dir, 'bar') src_link = os.path.join(tmp_dir, 'baz') dst_link = os.path.join(tmp_dir, 'quux') - write_file(src, 'foo') - write_file(dst, 'foo') + create_file(src, 'foo') + create_file(dst, 'foo') os.symlink(src, src_link) os.symlink(dst, dst_link) os.chmod(src, stat.S_IRWXU|stat.S_IRWXG) @@ -1126,8 +1123,8 @@ def test_copymode_symlink_to_symlink_wo_lchmod(self): dst = os.path.join(tmp_dir, 'bar') src_link = os.path.join(tmp_dir, 'baz') dst_link = os.path.join(tmp_dir, 'quux') - write_file(src, 'foo') - write_file(dst, 'foo') + create_file(src, 'foo') + create_file(dst, 'foo') os.symlink(src, src_link) os.symlink(dst, dst_link) shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail @@ -1141,11 +1138,11 @@ def test_copystat_symlinks(self): dst = os.path.join(tmp_dir, 'bar') src_link = os.path.join(tmp_dir, 'baz') dst_link = os.path.join(tmp_dir, 'qux') - write_file(src, 'foo') + create_file(src, 'foo') src_stat = os.stat(src) os.utime(src, (src_stat.st_atime, src_stat.st_mtime - 42.0)) # ensure different mtimes - write_file(dst, 'bar') + create_file(dst, 'bar') self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime) os.symlink(src, src_link) os.symlink(dst, dst_link) @@ -1185,8 +1182,8 @@ def test_copystat_handles_harmless_chflags_errors(self): tmpdir = self.mkdtemp() file1 = os.path.join(tmpdir, 'file1') file2 = os.path.join(tmpdir, 'file2') - write_file(file1, 'xxx') - write_file(file2, 'xxx') + create_file(file1, 'xxx') + create_file(file2, 'xxx') def make_chflags_raiser(err): ex = OSError() @@ -1212,9 +1209,9 @@ def _chflags_raiser(path, flags, *, follow_symlinks=True): def test_copyxattr(self): tmp_dir = self.mkdtemp() src = os.path.join(tmp_dir, 'foo') - write_file(src, 'foo') + create_file(src, 'foo') dst = os.path.join(tmp_dir, 'bar') - write_file(dst, 'bar') + create_file(dst, 'bar') # no xattr == no problem shutil._copyxattr(src, dst) @@ -1228,7 +1225,7 @@ def test_copyxattr(self): os.getxattr(dst, 'user.foo')) # check errors don't affect other attrs os.remove(dst) - write_file(dst, 'bar') + create_file(dst, 'bar') os_error = OSError(errno.EPERM, 'EPERM') def _raise_on_user_foo(fname, attr, val, **kwargs): @@ -1258,15 +1255,15 @@ def _raise_on_src(fname, *, follow_symlinks=True): # test that shutil.copystat copies xattrs src = os.path.join(tmp_dir, 'the_original') srcro = os.path.join(tmp_dir, 'the_original_ro') - write_file(src, src) - write_file(srcro, srcro) + create_file(src, src) + create_file(srcro, srcro) os.setxattr(src, 'user.the_value', b'fiddly') os.setxattr(srcro, 'user.the_value', b'fiddly') os.chmod(srcro, 0o444) dst = os.path.join(tmp_dir, 'the_copy') dstro = os.path.join(tmp_dir, 'the_copy_ro') - write_file(dst, dst) - write_file(dstro, dstro) + create_file(dst, dst) + create_file(dstro, dstro) shutil.copystat(src, dst) shutil.copystat(srcro, dstro) self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly') @@ -1282,13 +1279,13 @@ def test_copyxattr_symlinks(self): tmp_dir = self.mkdtemp() src = os.path.join(tmp_dir, 'foo') src_link = os.path.join(tmp_dir, 'baz') - write_file(src, 'foo') + create_file(src, 'foo') os.symlink(src, src_link) os.setxattr(src, 'trusted.foo', b'42') os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False) dst = os.path.join(tmp_dir, 'bar') dst_link = os.path.join(tmp_dir, 'qux') - write_file(dst, 'bar') + create_file(dst, 'bar') os.symlink(dst, dst_link) shutil._copyxattr(src_link, dst_link, follow_symlinks=False) self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43') @@ -1301,7 +1298,7 @@ def test_copyxattr_symlinks(self): def _copy_file(self, method): fname = 'test.txt' tmpdir = self.mkdtemp() - write_file((tmpdir, fname), 'xxx') + create_file((tmpdir, fname), 'xxx') file1 = os.path.join(tmpdir, fname) tmpdir2 = self.mkdtemp() method(file1, tmpdir2) @@ -1320,7 +1317,7 @@ def test_copy_symlinks(self): src = os.path.join(tmp_dir, 'foo') dst = os.path.join(tmp_dir, 'bar') src_link = os.path.join(tmp_dir, 'baz') - write_file(src, 'foo') + create_file(src, 'foo') os.symlink(src, src_link) if hasattr(os, 'lchmod'): os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO) @@ -1362,7 +1359,7 @@ def test_copy2_symlinks(self): src = os.path.join(tmp_dir, 'foo') dst = os.path.join(tmp_dir, 'bar') src_link = os.path.join(tmp_dir, 'baz') - write_file(src, 'foo') + create_file(src, 'foo') os.symlink(src, src_link) if hasattr(os, 'lchmod'): os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO) @@ -1396,7 +1393,7 @@ def test_copy2_xattr(self): tmp_dir = self.mkdtemp() src = os.path.join(tmp_dir, 'foo') dst = os.path.join(tmp_dir, 'bar') - write_file(src, 'foo') + create_file(src, 'foo') os.setxattr(src, 'user.foo', b'42') shutil.copy2(src, dst) self.assertEqual( @@ -1410,7 +1407,7 @@ def test_copy_return_value(self): src_dir = self.mkdtemp() dst_dir = self.mkdtemp() src = os.path.join(src_dir, 'foo') - write_file(src, 'foo') + create_file(src, 'foo') rv = fn(src, dst_dir) self.assertEqual(rv, os.path.join(dst_dir, 'foo')) rv = fn(src, os.path.join(dst_dir, 'bar')) @@ -1427,7 +1424,7 @@ def _test_copy_dir(self, copy_func): src_file = os.path.join(src_dir, 'foo') dir2 = self.mkdtemp() dst = os.path.join(src_dir, 'does_not_exist/') - write_file(src_file, 'foo') + create_file(src_file, 'foo') if sys.platform == "win32": err = PermissionError else: @@ -1447,7 +1444,7 @@ def test_copyfile_symlinks(self): dst = os.path.join(tmp_dir, 'dst') dst_link = os.path.join(tmp_dir, 'dst_link') link = os.path.join(tmp_dir, 'link') - write_file(src, 'foo') + create_file(src, 'foo') os.symlink(src, link) # don't follow shutil.copyfile(link, dst_link, follow_symlinks=False) @@ -1464,8 +1461,7 @@ def test_dont_copy_file_onto_link_to_itself(self): src = os.path.join(TESTFN, 'cheese') dst = os.path.join(TESTFN, 'shop') try: - with open(src, 'w', encoding='utf-8') as f: - f.write('cheddar') + create_file(src, 'cheddar') try: os.link(src, dst) except PermissionError as e: @@ -1484,8 +1480,7 @@ def test_dont_copy_file_onto_symlink_to_itself(self): src = os.path.join(TESTFN, 'cheese') dst = os.path.join(TESTFN, 'shop') try: - with open(src, 'w', encoding='utf-8') as f: - f.write('cheddar') + create_file(src, 'cheddar') # Using `src` here would mean we end up with a symlink pointing # to TESTFN/TESTFN/cheese, while it should point at # TESTFN/cheese. @@ -1520,7 +1515,7 @@ def test_copyfile_return_value(self): dst_dir = self.mkdtemp() dst_file = os.path.join(dst_dir, 'bar') src_file = os.path.join(src_dir, 'foo') - write_file(src_file, 'foo') + create_file(src_file, 'foo') rv = shutil.copyfile(src_file, dst_file) self.assertTrue(os.path.exists(rv)) self.assertEqual(read_file(src_file), read_file(dst_file)) @@ -1530,7 +1525,7 @@ def test_copyfile_same_file(self): # are the same. src_dir = self.mkdtemp() src_file = os.path.join(src_dir, 'foo') - write_file(src_file, 'foo') + create_file(src_file, 'foo') self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file) # But Error should work too, to stay backward compatible. self.assertRaises(Error, shutil.copyfile, src_file, src_file) @@ -1547,7 +1542,7 @@ def test_copyfile_nonexistent_dir(self): src_dir = self.mkdtemp() src_file = os.path.join(src_dir, 'foo') dst = os.path.join(src_dir, 'does_not_exist/') - write_file(src_file, 'foo') + create_file(src_file, 'foo') self.assertRaises(FileNotFoundError, shutil.copyfile, src_file, dst) def test_copyfile_copy_dir(self): @@ -1558,7 +1553,7 @@ def test_copyfile_copy_dir(self): src_file = os.path.join(src_dir, 'foo') dir2 = self.mkdtemp() dst = os.path.join(src_dir, 'does_not_exist/') - write_file(src_file, 'foo') + create_file(src_file, 'foo') if sys.platform == "win32": err = PermissionError else: @@ -1584,13 +1579,13 @@ def _create_files(self, base_dir='dist'): root_dir = self.mkdtemp() dist = os.path.join(root_dir, base_dir) os.makedirs(dist, exist_ok=True) - write_file((dist, 'file1'), 'xxx') - write_file((dist, 'file2'), 'xxx') + create_file((dist, 'file1'), 'xxx') + create_file((dist, 'file2'), 'xxx') os.mkdir(os.path.join(dist, 'sub')) - write_file((dist, 'sub', 'file3'), 'xxx') + create_file((dist, 'sub', 'file3'), 'xxx') os.mkdir(os.path.join(dist, 'sub2')) if base_dir: - write_file((root_dir, 'outer'), 'xxx') + create_file((root_dir, 'outer'), 'xxx') return root_dir, base_dir @support.requires_zlib() @@ -2170,7 +2165,7 @@ def test_disk_usage(self): def test_chown(self): dirname = self.mkdtemp() filename = tempfile.mktemp(dir=dirname) - write_file(filename, 'testing chown function') + create_file(filename, 'testing chown function') with self.assertRaises(ValueError): shutil.chown(filename) @@ -2231,37 +2226,41 @@ def check_chown(path, uid=None, gid=None): class TestWhich(BaseTest, unittest.TestCase): def setUp(self): - self.temp_dir = self.mkdtemp(prefix="Tmp") + temp_dir = self.mkdtemp(prefix="Tmp") + base_dir = os.path.join(temp_dir, TESTFN + '-basedir') + os.mkdir(base_dir) + self.dir = os.path.join(base_dir, TESTFN + '-dir') + os.mkdir(self.dir) + self.other_dir = os.path.join(base_dir, TESTFN + '-dir2') + os.mkdir(self.other_dir) # Give the temp_file an ".exe" suffix for all. # It's needed on Windows and not harmful on other platforms. - self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir, - prefix="Tmp", - suffix=".Exe") - os.chmod(self.temp_file.name, stat.S_IXUSR) - self.addCleanup(self.temp_file.close) - self.dir, self.file = os.path.split(self.temp_file.name) + self.file = TESTFN + '.Exe' + self.filepath = os.path.join(self.dir, self.file) + self.create_file(self.filepath) self.env_path = self.dir self.curdir = os.curdir self.ext = ".EXE" - def to_text_type(self, s): - ''' - In this class we're testing with str, so convert s to a str - ''' - if isinstance(s, bytes): - return s.decode() - return s + to_text_type = staticmethod(os.fsdecode) + + def create_file(self, path): + create_file(path) + os.chmod(path, 0o755) + + def assertNormEqual(self, actual, expected): + self.assertEqual(os.path.normcase(actual), os.path.normcase(expected)) def test_basic(self): # Given an EXE in a directory, it should be returned. rv = shutil.which(self.file, path=self.dir) - self.assertEqual(rv, self.temp_file.name) + self.assertEqual(rv, self.filepath) def test_absolute_cmd(self): # When given the fully qualified path to an executable that exists, # it should be returned. - rv = shutil.which(self.temp_file.name, path=self.temp_dir) - self.assertEqual(rv, self.temp_file.name) + rv = shutil.which(self.filepath, path=self.other_dir) + self.assertEqual(rv, self.filepath) def test_relative_cmd(self): # When given the relative path with a directory part to an executable @@ -2269,7 +2268,7 @@ def test_relative_cmd(self): base_dir, tail_dir = os.path.split(self.dir) relpath = os.path.join(tail_dir, self.file) with os_helper.change_cwd(path=base_dir): - rv = shutil.which(relpath, path=self.temp_dir) + rv = shutil.which(relpath, path=self.other_dir) self.assertEqual(rv, relpath) # But it shouldn't be searched in PATH directories (issue #16957). with os_helper.change_cwd(path=self.dir): @@ -2280,9 +2279,8 @@ def test_relative_cmd(self): "test is for non win32") def test_cwd_non_win32(self): # Issue #16957 - base_dir = os.path.dirname(self.dir) with os_helper.change_cwd(path=self.dir): - rv = shutil.which(self.file, path=base_dir) + rv = shutil.which(self.file, path=self.other_dir) # non-win32: shouldn't match in the current directory. self.assertIsNone(rv) @@ -2292,57 +2290,32 @@ def test_cwd_win32(self): base_dir = os.path.dirname(self.dir) with os_helper.change_cwd(path=self.dir): with unittest.mock.patch('shutil._win_path_needs_curdir', return_value=True): - rv = shutil.which(self.file, path=base_dir) + rv = shutil.which(self.file, path=self.other_dir) # Current directory implicitly on PATH self.assertEqual(rv, os.path.join(self.curdir, self.file)) with unittest.mock.patch('shutil._win_path_needs_curdir', return_value=False): - rv = shutil.which(self.file, path=base_dir) + rv = shutil.which(self.file, path=self.other_dir) # Current directory not on PATH self.assertIsNone(rv) @unittest.skipUnless(sys.platform == "win32", "test is for win32") def test_cwd_win32_added_before_all_other_path(self): - base_dir = pathlib.Path(os.fsdecode(self.dir)) - - elsewhere_in_path_dir = base_dir / 'dir1' - elsewhere_in_path_dir.mkdir() - match_elsewhere_in_path = elsewhere_in_path_dir / 'hello.exe' - match_elsewhere_in_path.touch() - - exe_in_cwd = base_dir / 'hello.exe' - exe_in_cwd.touch() - - with os_helper.change_cwd(path=base_dir): - with unittest.mock.patch('shutil._win_path_needs_curdir', return_value=True): - rv = shutil.which('hello.exe', path=elsewhere_in_path_dir) - - self.assertEqual(os.path.abspath(rv), os.path.abspath(exe_in_cwd)) - - @unittest.skipUnless(sys.platform == "win32", - "test is for win32") - def test_pathext_match_before_path_full_match(self): - base_dir = pathlib.Path(os.fsdecode(self.dir)) - dir1 = base_dir / 'dir1' - dir2 = base_dir / 'dir2' - dir1.mkdir() - dir2.mkdir() - - pathext_match = dir1 / 'hello.com.exe' - path_match = dir2 / 'hello.com' - pathext_match.touch() - path_match.touch() - - test_path = os.pathsep.join([str(dir1), str(dir2)]) - assert os.path.basename(shutil.which( - 'hello.com', path=test_path, mode = os.F_OK - )).lower() == 'hello.com.exe' + other_file_path = os.path.join(self.other_dir, self.file) + self.create_file(other_file_path) + with unittest.mock.patch('shutil._win_path_needs_curdir', return_value=True): + with os_helper.change_cwd(path=self.dir): + rv = shutil.which(self.file, path=self.other_dir) + self.assertEqual(rv, os.path.join(self.curdir, self.file)) + with os_helper.change_cwd(path=self.other_dir): + rv = shutil.which(self.file, path=self.dir) + self.assertEqual(rv, os.path.join(self.curdir, self.file)) @os_helper.skip_if_dac_override def test_non_matching_mode(self): # Set the file read-only and ask for writeable files. - os.chmod(self.temp_file.name, stat.S_IREAD) - if os.access(self.temp_file.name, os.W_OK): + os.chmod(self.filepath, stat.S_IREAD) + if os.access(self.filepath, os.W_OK): self.skipTest("can't set the file read-only") rv = shutil.which(self.file, path=self.dir, mode=os.W_OK) self.assertIsNone(rv) @@ -2364,13 +2337,13 @@ def test_pathext_checking(self): # Ask for the file without the ".exe" extension, then ensure that # it gets found properly with the extension. rv = shutil.which(self.file[:-4], path=self.dir) - self.assertEqual(rv, self.temp_file.name[:-4] + self.ext) + self.assertEqual(rv, self.filepath[:-4] + self.ext) def test_environ_path(self): with os_helper.EnvironmentVarGuard() as env: env['PATH'] = self.env_path rv = shutil.which(self.file) - self.assertEqual(rv, self.temp_file.name) + self.assertEqual(rv, self.filepath) def test_environ_path_empty(self): # PATH='': no match @@ -2384,12 +2357,9 @@ def test_environ_path_empty(self): self.assertIsNone(rv) def test_environ_path_cwd(self): - expected_cwd = os.path.basename(self.temp_file.name) + expected_cwd = self.file if sys.platform == "win32": - curdir = os.curdir - if isinstance(expected_cwd, bytes): - curdir = os.fsencode(curdir) - expected_cwd = os.path.join(curdir, expected_cwd) + expected_cwd = os.path.join(self.curdir, expected_cwd) # PATH=':': explicitly looks in the current directory with os_helper.EnvironmentVarGuard() as env: @@ -2414,14 +2384,14 @@ def test_environ_path_missing(self): create=True), \ support.swap_attr(os, 'defpath', self.dir): rv = shutil.which(self.file) - self.assertEqual(rv, self.temp_file.name) + self.assertEqual(rv, self.filepath) # with confstr with unittest.mock.patch('os.confstr', return_value=self.dir, \ create=True), \ support.swap_attr(os, 'defpath', ''): rv = shutil.which(self.file) - self.assertEqual(rv, self.temp_file.name) + self.assertEqual(rv, self.filepath) def test_empty_path(self): base_dir = os.path.dirname(self.dir) @@ -2439,50 +2409,88 @@ def test_empty_path_no_PATH(self): @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows') def test_pathext(self): - ext = self.to_text_type(".xyz") - temp_filexyz = tempfile.NamedTemporaryFile(dir=self.temp_dir, - prefix=self.to_text_type("Tmp2"), suffix=ext) - os.chmod(temp_filexyz.name, stat.S_IXUSR) - self.addCleanup(temp_filexyz.close) - - # strip path and extension - program = os.path.basename(temp_filexyz.name) - program = os.path.splitext(program)[0] - + ext = '.xyz' + cmd = self.to_text_type(TESTFN2) + cmdext = cmd + self.to_text_type(ext) + filepath = os.path.join(self.dir, cmdext) + self.create_file(filepath) with os_helper.EnvironmentVarGuard() as env: - env['PATHEXT'] = ext if isinstance(ext, str) else ext.decode() - rv = shutil.which(program, path=self.temp_dir) - self.assertEqual(rv, temp_filexyz.name) + env['PATHEXT'] = ext + self.assertEqual(shutil.which(cmd, path=self.dir), filepath) + self.assertEqual(shutil.which(cmdext, path=self.dir), filepath) # Issue 40592: See https://bugs.python.org/issue40592 @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows') def test_pathext_with_empty_str(self): - ext = self.to_text_type(".xyz") - temp_filexyz = tempfile.NamedTemporaryFile(dir=self.temp_dir, - prefix=self.to_text_type("Tmp2"), suffix=ext) - self.addCleanup(temp_filexyz.close) + ext = '.xyz' + cmd = self.to_text_type(TESTFN2) + cmdext = cmd + self.to_text_type(ext) + filepath = os.path.join(self.dir, cmdext) + self.create_file(filepath) + with os_helper.EnvironmentVarGuard() as env: + env['PATHEXT'] = ext + ';' # note the ; + self.assertEqual(shutil.which(cmd, path=self.dir), filepath) + self.assertEqual(shutil.which(cmdext, path=self.dir), filepath) - # strip path and extension - program = os.path.basename(temp_filexyz.name) - program = os.path.splitext(program)[0] + @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows') + def test_pathext_with_multidot_extension(self): + ext = '.foo.bar' + cmd = self.to_text_type(TESTFN2) + cmdext = cmd + self.to_text_type(ext) + filepath = os.path.join(self.dir, cmdext) + self.create_file(filepath) + with os_helper.EnvironmentVarGuard() as env: + env['PATHEXT'] = ext + self.assertEqual(shutil.which(cmd, path=self.dir), filepath) + self.assertEqual(shutil.which(cmdext, path=self.dir), filepath) + @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows') + def test_pathext_with_null_extension(self): + cmd = self.to_text_type(TESTFN2) + cmddot = cmd + self.to_text_type('.') + filepath = os.path.join(self.dir, cmd) + self.create_file(filepath) with os_helper.EnvironmentVarGuard() as env: - env['PATHEXT'] = f"{ext if isinstance(ext, str) else ext.decode()};" # note the ; - rv = shutil.which(program, path=self.temp_dir) - self.assertEqual(rv, temp_filexyz.name) + env['PATHEXT'] = '.xyz' + self.assertIsNone(shutil.which(cmd, path=self.dir)) + self.assertIsNone(shutil.which(cmddot, path=self.dir)) + env['PATHEXT'] = '.xyz;.' # note the . + self.assertEqual(shutil.which(cmd, path=self.dir), filepath) + self.assertEqual(shutil.which(cmddot, path=self.dir), + filepath + self.to_text_type('.')) + env['PATHEXT'] = '.xyz;..' # multiple dots + self.assertEqual(shutil.which(cmd, path=self.dir), filepath) + self.assertEqual(shutil.which(cmddot, path=self.dir), + filepath + self.to_text_type('.')) + + @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows') + def test_pathext_extension_ends_with_dot(self): + ext = '.xyz' + cmd = self.to_text_type(TESTFN2) + cmdext = cmd + self.to_text_type(ext) + dot = self.to_text_type('.') + filepath = os.path.join(self.dir, cmdext) + self.create_file(filepath) + with os_helper.EnvironmentVarGuard() as env: + env['PATHEXT'] = ext + '.' + self.assertEqual(shutil.which(cmd, path=self.dir), filepath) # cmd.exe hangs here + self.assertEqual(shutil.which(cmdext, path=self.dir), filepath) + self.assertIsNone(shutil.which(cmd + dot, path=self.dir)) + self.assertIsNone(shutil.which(cmdext + dot, path=self.dir)) # See GH-75586 @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows') def test_pathext_applied_on_files_in_path(self): + ext = '.xyz' + cmd = self.to_text_type(TESTFN2) + cmdext = cmd + self.to_text_type(ext) + filepath = os.path.join(self.dir, cmdext) + self.create_file(filepath) with os_helper.EnvironmentVarGuard() as env: - env["PATH"] = self.temp_dir if isinstance(self.temp_dir, str) else self.temp_dir.decode() - env["PATHEXT"] = ".test" - - test_path = os.path.join(self.temp_dir, self.to_text_type("test_program.test")) - open(test_path, 'w').close() - os.chmod(test_path, 0o755) - - self.assertEqual(shutil.which(self.to_text_type("test_program")), test_path) + env["PATH"] = os.fsdecode(self.dir) + env["PATHEXT"] = ext + self.assertEqual(shutil.which(cmd), filepath) + self.assertEqual(shutil.which(cmdext), filepath) # See GH-75586 @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows') @@ -2498,49 +2506,107 @@ def test_win_path_needs_curdir(self): self.assertFalse(shutil._win_path_needs_curdir('dontcare', os.X_OK)) need_curdir_mock.assert_called_once_with('dontcare') - # See GH-109590 @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows') - def test_pathext_preferred_for_execute(self): - with os_helper.EnvironmentVarGuard() as env: - env["PATH"] = self.temp_dir if isinstance(self.temp_dir, str) else self.temp_dir.decode() - env["PATHEXT"] = ".test" - - exe = os.path.join(self.temp_dir, self.to_text_type("test.exe")) - open(exe, 'w').close() - os.chmod(exe, 0o755) + def test_same_dir_with_pathext_extension(self): + cmd = self.file # with .exe extension + # full match + self.assertNormEqual(shutil.which(cmd, path=self.dir), self.filepath) + self.assertNormEqual(shutil.which(cmd, path=self.dir, mode=os.F_OK), + self.filepath) + + cmd2 = cmd + self.to_text_type('.com') # with .exe.com extension + other_file_path = os.path.join(self.dir, cmd2) + self.create_file(other_file_path) + + # full match + self.assertNormEqual(shutil.which(cmd, path=self.dir), self.filepath) + self.assertNormEqual(shutil.which(cmd, path=self.dir, mode=os.F_OK), + self.filepath) + self.assertNormEqual(shutil.which(cmd2, path=self.dir), other_file_path) + self.assertNormEqual(shutil.which(cmd2, path=self.dir, mode=os.F_OK), + other_file_path) - # default behavior allows a direct match if nothing in PATHEXT matches - self.assertEqual(shutil.which(self.to_text_type("test.exe")), exe) - - dot_test = os.path.join(self.temp_dir, self.to_text_type("test.exe.test")) - open(dot_test, 'w').close() - os.chmod(dot_test, 0o755) - - # now we have a PATHEXT match, so it take precedence - self.assertEqual(shutil.which(self.to_text_type("test.exe")), dot_test) - - # but if we don't use os.X_OK we don't change the order based off PATHEXT - # and therefore get the direct match. - self.assertEqual(shutil.which(self.to_text_type("test.exe"), mode=os.F_OK), exe) - - # See GH-109590 @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows') - def test_pathext_given_extension_preferred(self): - with os_helper.EnvironmentVarGuard() as env: - env["PATH"] = self.temp_dir if isinstance(self.temp_dir, str) else self.temp_dir.decode() - env["PATHEXT"] = ".exe2;.exe" + def test_same_dir_without_pathext_extension(self): + cmd = self.file[:-4] # without .exe extension + # pathext match + self.assertNormEqual(shutil.which(cmd, path=self.dir), self.filepath) + self.assertNormEqual(shutil.which(cmd, path=self.dir, mode=os.F_OK), + self.filepath) + + # without extension + other_file_path = os.path.join(self.dir, cmd) + self.create_file(other_file_path) + + # pathext match if mode contains X_OK + self.assertNormEqual(shutil.which(cmd, path=self.dir), self.filepath) + # full match + self.assertNormEqual(shutil.which(cmd, path=self.dir, mode=os.F_OK), + other_file_path) + self.assertNormEqual(shutil.which(self.file, path=self.dir), self.filepath) + self.assertNormEqual(shutil.which(self.file, path=self.dir, mode=os.F_OK), + self.filepath) - exe = os.path.join(self.temp_dir, self.to_text_type("test.exe")) - open(exe, 'w').close() - os.chmod(exe, 0o755) - - exe2 = os.path.join(self.temp_dir, self.to_text_type("test.exe2")) - open(exe2, 'w').close() - os.chmod(exe2, 0o755) + @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows') + def test_dir_order_with_pathext_extension(self): + cmd = self.file # with .exe extension + search_path = os.pathsep.join([os.fsdecode(self.other_dir), + os.fsdecode(self.dir)]) + # full match in the second directory + self.assertNormEqual(shutil.which(cmd, path=search_path), self.filepath) + self.assertNormEqual(shutil.which(cmd, path=search_path, mode=os.F_OK), + self.filepath) + + cmd2 = cmd + self.to_text_type('.com') # with .exe.com extension + other_file_path = os.path.join(self.other_dir, cmd2) + self.create_file(other_file_path) + + # pathext match in the first directory + self.assertNormEqual(shutil.which(cmd, path=search_path), other_file_path) + self.assertNormEqual(shutil.which(cmd, path=search_path, mode=os.F_OK), + other_file_path) + # full match in the first directory + self.assertNormEqual(shutil.which(cmd2, path=search_path), other_file_path) + self.assertNormEqual(shutil.which(cmd2, path=search_path, mode=os.F_OK), + other_file_path) + + # full match in the first directory + search_path = os.pathsep.join([os.fsdecode(self.dir), + os.fsdecode(self.other_dir)]) + self.assertEqual(shutil.which(cmd, path=search_path), self.filepath) + self.assertEqual(shutil.which(cmd, path=search_path, mode=os.F_OK), + self.filepath) - # even though .exe2 is preferred in PATHEXT, we matched directly to test.exe - self.assertEqual(shutil.which(self.to_text_type("test.exe")), exe) - self.assertEqual(shutil.which(self.to_text_type("test")), exe2) + @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows') + def test_dir_order_without_pathext_extension(self): + cmd = self.file[:-4] # without .exe extension + search_path = os.pathsep.join([os.fsdecode(self.other_dir), + os.fsdecode(self.dir)]) + # pathext match in the second directory + self.assertNormEqual(shutil.which(cmd, path=search_path), self.filepath) + self.assertNormEqual(shutil.which(cmd, path=search_path, mode=os.F_OK), + self.filepath) + + # without extension + other_file_path = os.path.join(self.other_dir, cmd) + self.create_file(other_file_path) + + # pathext match in the second directory + self.assertNormEqual(shutil.which(cmd, path=search_path), self.filepath) + # full match in the first directory + self.assertNormEqual(shutil.which(cmd, path=search_path, mode=os.F_OK), + other_file_path) + # full match in the second directory + self.assertNormEqual(shutil.which(self.file, path=search_path), self.filepath) + self.assertNormEqual(shutil.which(self.file, path=search_path, mode=os.F_OK), + self.filepath) + + # pathext match in the first directory + search_path = os.pathsep.join([os.fsdecode(self.dir), + os.fsdecode(self.other_dir)]) + self.assertNormEqual(shutil.which(cmd, path=search_path), self.filepath) + self.assertNormEqual(shutil.which(cmd, path=search_path, mode=os.F_OK), + self.filepath) class TestWhichBytes(TestWhich): @@ -2548,18 +2614,12 @@ def setUp(self): TestWhich.setUp(self) self.dir = os.fsencode(self.dir) self.file = os.fsencode(self.file) - self.temp_file.name = os.fsencode(self.temp_file.name) - self.temp_dir = os.fsencode(self.temp_dir) + self.filepath = os.fsencode(self.filepath) + self.other_dir = os.fsencode(self.other_dir) self.curdir = os.fsencode(self.curdir) self.ext = os.fsencode(self.ext) - def to_text_type(self, s): - ''' - In this class we're testing with bytes, so convert s to a bytes - ''' - if isinstance(s, str): - return s.encode() - return s + to_text_type = staticmethod(os.fsencode) class TestMove(BaseTest, unittest.TestCase): @@ -2570,8 +2630,7 @@ def setUp(self): self.dst_dir = self.mkdtemp() self.src_file = os.path.join(self.src_dir, filename) self.dst_file = os.path.join(self.dst_dir, filename) - with open(self.src_file, "wb") as f: - f.write(b"spam") + create_file(self.src_file, b"spam") def _check_move_file(self, src, dst, real_dst): with open(src, "rb") as f: @@ -2649,8 +2708,7 @@ def test_move_dir_altsep_to_dir(self): def test_existing_file_inside_dest_dir(self): # A file with the same name inside the destination dir already exists. - with open(self.dst_file, "wb"): - pass + create_file(self.dst_file) self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir) def test_dont_move_dir_in_itself(self): @@ -3065,8 +3123,7 @@ def test_empty_file(self): dstname = TESTFN + 'dst' self.addCleanup(lambda: os_helper.unlink(srcname)) self.addCleanup(lambda: os_helper.unlink(dstname)) - with open(srcname, "wb"): - pass + create_file(srcname) with open(srcname, "rb") as src: with open(dstname, "wb") as dst: @@ -3189,7 +3246,7 @@ def test_blocksize_arg(self): self.assertEqual(blocksize, os.path.getsize(TESTFN)) # ...unless we're dealing with a small file. os_helper.unlink(TESTFN2) - write_file(TESTFN2, b"hello", binary=True) + create_file(TESTFN2, b"hello") self.addCleanup(os_helper.unlink, TESTFN2 + '3') self.assertRaises(ZeroDivisionError, shutil.copyfile, TESTFN2, TESTFN2 + '3') diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py index c7b9549d..a45527d7 100644 --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -122,6 +122,8 @@ def __repr__(self): self.assertEqual(signal.getsignal(signal.SIGHUP), hup) self.assertEqual(0, argument.repr_count) + @unittest.skipIf(sys.platform.startswith("netbsd"), + "gh-124083: strsignal is not supported on NetBSD") def test_strsignal(self): self.assertIn("Interrupt", signal.strsignal(signal.SIGINT)) self.assertIn("Terminated", signal.strsignal(signal.SIGTERM)) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index cda95649..b40ad28f 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -558,19 +558,27 @@ class SocketPairTest(unittest.TestCase, ThreadableTest): def __init__(self, methodName='runTest'): unittest.TestCase.__init__(self, methodName=methodName) ThreadableTest.__init__(self) + self.cli = None + self.serv = None + + def socketpair(self): + # To be overridden by some child classes. + return socket.socketpair() def setUp(self): - self.serv, self.cli = socket.socketpair() + self.serv, self.cli = self.socketpair() def tearDown(self): - self.serv.close() + if self.serv: + self.serv.close() self.serv = None def clientSetUp(self): pass def clientTearDown(self): - self.cli.close() + if self.cli: + self.cli.close() self.cli = None ThreadableTest.clientTearDown(self) @@ -1623,7 +1631,7 @@ def test_getaddrinfo_int_port_overflow(self): try: socket.getaddrinfo(None, ULONG_MAX + 1, type=socket.SOCK_STREAM) except OverflowError: - # Platforms differ as to what values consitute a getaddrinfo() error + # Platforms differ as to what values constitute a getaddrinfo() error # return. Some fail for LONG_MAX+1, others ULONG_MAX+1, and Windows # silently accepts such huge "port" aka "service" numeric values. self.fail("Either no error or socket.gaierror expected.") @@ -4786,6 +4794,112 @@ def _testSend(self): self.assertEqual(msg, MSG) +class PurePythonSocketPairTest(SocketPairTest): + # Explicitly use socketpair AF_INET or AF_INET6 to ensure that is the + # code path we're using regardless platform is the pure python one where + # `_socket.socketpair` does not exist. (AF_INET does not work with + # _socket.socketpair on many platforms). + def socketpair(self): + # called by super().setUp(). + try: + return socket.socketpair(socket.AF_INET6) + except OSError: + return socket.socketpair(socket.AF_INET) + + # Local imports in this class make for easy security fix backporting. + + def setUp(self): + if hasattr(_socket, "socketpair"): + self._orig_sp = socket.socketpair + # This forces the version using the non-OS provided socketpair + # emulation via an AF_INET socket in Lib/socket.py. + socket.socketpair = socket._fallback_socketpair + else: + # This platform already uses the non-OS provided version. + self._orig_sp = None + super().setUp() + + def tearDown(self): + super().tearDown() + if self._orig_sp is not None: + # Restore the default socket.socketpair definition. + socket.socketpair = self._orig_sp + + def test_recv(self): + msg = self.serv.recv(1024) + self.assertEqual(msg, MSG) + + def _test_recv(self): + self.cli.send(MSG) + + def test_send(self): + self.serv.send(MSG) + + def _test_send(self): + msg = self.cli.recv(1024) + self.assertEqual(msg, MSG) + + def test_ipv4(self): + cli, srv = socket.socketpair(socket.AF_INET) + cli.close() + srv.close() + + def _test_ipv4(self): + pass + + @unittest.skipIf(not hasattr(_socket, 'IPPROTO_IPV6') or + not hasattr(_socket, 'IPV6_V6ONLY'), + "IPV6_V6ONLY option not supported") + @unittest.skipUnless(socket_helper.IPV6_ENABLED, 'IPv6 required for this test') + def test_ipv6(self): + cli, srv = socket.socketpair(socket.AF_INET6) + cli.close() + srv.close() + + def _test_ipv6(self): + pass + + def test_injected_authentication_failure(self): + orig_getsockname = socket.socket.getsockname + inject_sock = None + + def inject_getsocketname(self): + nonlocal inject_sock + sockname = orig_getsockname(self) + # Connect to the listening socket ahead of the + # client socket. + if inject_sock is None: + inject_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + inject_sock.setblocking(False) + try: + inject_sock.connect(sockname[:2]) + except (BlockingIOError, InterruptedError): + pass + inject_sock.setblocking(True) + return sockname + + sock1 = sock2 = None + try: + socket.socket.getsockname = inject_getsocketname + with self.assertRaises(OSError): + sock1, sock2 = socket.socketpair() + finally: + socket.socket.getsockname = orig_getsockname + if inject_sock: + inject_sock.close() + if sock1: # This cleanup isn't needed on a successful test. + sock1.close() + if sock2: + sock2.close() + + def _test_injected_authentication_failure(self): + # No-op. Exists for base class threading infrastructure to call. + # We could refactor this test into its own lesser class along with the + # setUp and tearDown code to construct an ideal; it is simpler to keep + # it here and live with extra overhead one this _one_ failure test. + pass + + class NonBlockingTCPTests(ThreadedTCPSocketTest): def __init__(self, methodName='runTest'): @@ -4945,6 +5059,36 @@ def _testRecv(self): # send data: recv() will no longer block self.cli.sendall(MSG) + @support.cpython_only + def testLargeTimeout(self): + # gh-126876: Check that a timeout larger than INT_MAX is replaced with + # INT_MAX in the poll() code path. The following assertion must not + # fail: assert(INT_MIN <= ms && ms <= INT_MAX). + import _testcapi + large_timeout = _testcapi.INT_MAX + 1 + + # test recv() with large timeout + conn, addr = self.serv.accept() + self.addCleanup(conn.close) + try: + conn.settimeout(large_timeout) + except OverflowError: + # On Windows, settimeout() fails with OverflowError, whereas + # we want to test recv(). Just give up silently. + return + msg = conn.recv(len(MSG)) + + def _testLargeTimeout(self): + # test sendall() with large timeout + import _testcapi + large_timeout = _testcapi.INT_MAX + 1 + self.cli.connect((HOST, self.port)) + try: + self.cli.settimeout(large_timeout) + except OverflowError: + return + self.cli.sendall(MSG) + class FileObjectClassTestCase(SocketConnectedTest): """Unit tests for the object returned by socket.makefile() @@ -5147,6 +5291,8 @@ def _testMakefileClose(self): self.write_file.write(self.write_msg) self.write_file.flush() + @unittest.skipUnless(hasattr(sys, 'getrefcount'), + 'test needs sys.getrefcount()') def testMakefileCloseSocketDestroy(self): refcount_before = sys.getrefcount(self.cli_conn) self.read_file.close() diff --git a/Lib/test/test_sqlite3/test_regression.py b/Lib/test/test_sqlite3/test_regression.py index 7e8221e7..6ea47872 100644 --- a/Lib/test/test_sqlite3/test_regression.py +++ b/Lib/test/test_sqlite3/test_regression.py @@ -442,6 +442,7 @@ def test_table_lock_cursor_dealloc(self): con.commit() cur = con.execute("select t from t") del cur + support.gc_collect() con.execute("drop table t") con.commit() @@ -457,6 +458,7 @@ def dup(v): con.create_function("dup", 1, dup) cur = con.execute("select dup(t) from t") del cur + support.gc_collect() con.execute("drop table t") con.commit() diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 9b59ddd8..aaddb759 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -2300,7 +2300,6 @@ def wrap_conn(self): # See also http://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/ if e.errno != errno.EPROTOTYPE and sys.platform != "darwin": self.running = False - self.server.stop() self.close() return False else: @@ -2435,10 +2434,6 @@ def run(self): self.close() self.running = False - # normally, we'd just stop here, but for the test - # harness, we want to stop the server - self.server.stop() - def __init__(self, certificate=None, ssl_version=None, certreqs=None, cacerts=None, chatty=True, connectionchatty=False, starttls_server=False, @@ -2472,21 +2467,33 @@ def __init__(self, certificate=None, ssl_version=None, self.conn_errors = [] threading.Thread.__init__(self) self.daemon = True + self._in_context = False def __enter__(self): + if self._in_context: + raise ValueError('Re-entering ThreadedEchoServer context') + self._in_context = True self.start(threading.Event()) self.flag.wait() return self def __exit__(self, *args): + assert self._in_context + self._in_context = False self.stop() self.join() def start(self, flag=None): + if not self._in_context: + raise ValueError( + 'ThreadedEchoServer must be used as a context manager') self.flag = flag threading.Thread.start(self) def run(self): + if not self._in_context: + raise ValueError( + 'ThreadedEchoServer must be used as a context manager') self.sock.settimeout(1.0) self.sock.listen(5) self.active = True @@ -4817,7 +4824,7 @@ def non_linux_skip_if_other_okay_error(self, err): return # Expect the full test setup to always work on Linux. if (isinstance(err, ConnectionResetError) or (isinstance(err, OSError) and err.errno == errno.EINVAL) or - re.search('wrong.version.number', getattr(err, "reason", ""), re.I)): + re.search('wrong.version.number', str(getattr(err, "reason", "")), re.I)): # On Windows the TCP RST leads to a ConnectionResetError # (ECONNRESET) which Linux doesn't appear to surface to userspace. # If wrap_socket() winds up on the "if connected:" path and doing diff --git a/Lib/test/test_statistics.py b/Lib/test/test_statistics.py index 0080d996..d0e13bfb 100644 --- a/Lib/test/test_statistics.py +++ b/Lib/test/test_statistics.py @@ -1074,7 +1074,7 @@ def test_no_inplace_modifications(self): def test_order_doesnt_matter(self): # Test that the order of data points doesn't change the result. - # CAUTION: due to floating point rounding errors, the result actually + # CAUTION: due to floating-point rounding errors, the result actually # may depend on the order. Consider this test representing an ideal. # To avoid this test failing, only test with exact values such as ints # or Fractions. diff --git a/Lib/test/test_string_literals.py b/Lib/test/test_string_literals.py index 371e8193..c7c6f684 100644 --- a/Lib/test/test_string_literals.py +++ b/Lib/test/test_string_literals.py @@ -131,7 +131,7 @@ def test_eval_str_invalid_escape(self): self.assertEqual(exc.lineno, 1) self.assertEqual(exc.offset, 1) - # Check that the warning is raised ony once if there are syntax errors + # Check that the warning is raised only once if there are syntax errors with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always', category=SyntaxWarning) diff --git a/Lib/test/test_strptime.py b/Lib/test/test_strptime.py index 05c8afc9..94b16635 100644 --- a/Lib/test/test_strptime.py +++ b/Lib/test/test_strptime.py @@ -5,13 +5,21 @@ import locale import re import os +import platform import sys from test import support -from test.support import skip_if_buggy_ucrt_strfptime +from test.support import skip_if_buggy_ucrt_strfptime, run_with_locales from datetime import date as datetime_date import _strptime +libc_ver = platform.libc_ver() +if libc_ver[0] == 'glibc': + glibc_ver = tuple(map(int, libc_ver[1].split('.'))) +else: + glibc_ver = None + + class getlang_Tests(unittest.TestCase): """Test _getlang""" def test_basic(self): @@ -206,8 +214,8 @@ class StrptimeTests(unittest.TestCase): """Tests for _strptime.strptime.""" def setUp(self): - """Create testing time tuple.""" - self.time_tuple = time.gmtime() + """Create testing time tuples.""" + self.time_tuple = time.localtime() def test_ValueError(self): # Make sure ValueError is raised when match fails or format is bad @@ -282,59 +290,73 @@ def test_strptime_exception_context(self): # additional check for IndexError branch (issue #19545) with self.assertRaises(ValueError) as e: _strptime._strptime_time('19', '%Y %') - self.assertIs(e.exception.__suppress_context__, True) + self.assertIsNone(e.exception.__context__) def test_unconverteddata(self): # Check ValueError is raised when there is unconverted data self.assertRaises(ValueError, _strptime._strptime_time, "10 12", "%m") - def helper(self, directive, position): + def roundtrip(self, fmt, position, time_tuple=None): """Helper fxn in testing.""" - strf_output = time.strftime("%" + directive, self.time_tuple) - strp_output = _strptime._strptime_time(strf_output, "%" + directive) - self.assertTrue(strp_output[position] == self.time_tuple[position], - "testing of '%s' directive failed; '%s' -> %s != %s" % - (directive, strf_output, strp_output[position], - self.time_tuple[position])) + if time_tuple is None: + time_tuple = self.time_tuple + strf_output = time.strftime(fmt, time_tuple) + strp_output = _strptime._strptime_time(strf_output, fmt) + self.assertEqual(strp_output[position], time_tuple[position], + "testing of %r format failed; %r -> %r != %r" % + (fmt, strf_output, strp_output[position], + time_tuple[position])) + if support.verbose >= 3: + print("testing of %r format: %r -> %r" % + (fmt, strf_output, strp_output[position])) def test_year(self): # Test that the year is handled properly - for directive in ('y', 'Y'): - self.helper(directive, 0) + self.roundtrip('%Y', 0) + self.roundtrip('%y', 0) + self.roundtrip('%Y', 0, (1900, 1, 1, 0, 0, 0, 0, 1, 0)) + # Must also make sure %y values are correct for bounds set by Open Group - for century, bounds in ((1900, ('69', '99')), (2000, ('00', '68'))): - for bound in bounds: - strp_output = _strptime._strptime_time(bound, '%y') - expected_result = century + int(bound) - self.assertTrue(strp_output[0] == expected_result, - "'y' test failed; passed in '%s' " - "and returned '%s'" % (bound, strp_output[0])) + strptime = _strptime._strptime_time + self.assertEqual(strptime('00', '%y')[0], 2000) + self.assertEqual(strptime('68', '%y')[0], 2068) + self.assertEqual(strptime('69', '%y')[0], 1969) + self.assertEqual(strptime('99', '%y')[0], 1999) def test_month(self): # Test for month directives - for directive in ('B', 'b', 'm'): - self.helper(directive, 1) + self.roundtrip('%m', 1) + + @run_with_locales('LC_TIME', 'C', 'en_US', 'fr_FR', 'de_DE', 'ja_JP', 'he_IL', '') + def test_month_locale(self): + # Test for month directives + self.roundtrip('%B', 1) + self.roundtrip('%b', 1) + for m in range(1, 13): + self.roundtrip('%B', 1, (1900, m, 1, 0, 0, 0, 0, 1, 0)) + self.roundtrip('%b', 1, (1900, m, 1, 0, 0, 0, 0, 1, 0)) def test_day(self): # Test for day directives - self.helper('d', 2) + self.roundtrip('%d %Y', 2) def test_hour(self): # Test hour directives - self.helper('H', 3) - strf_output = time.strftime("%I %p", self.time_tuple) - strp_output = _strptime._strptime_time(strf_output, "%I %p") - self.assertTrue(strp_output[3] == self.time_tuple[3], - "testing of '%%I %%p' directive failed; '%s' -> %s != %s" % - (strf_output, strp_output[3], self.time_tuple[3])) + self.roundtrip('%H', 3) + + # NB: Only works on locales with AM/PM + @run_with_locales('LC_TIME', 'C', 'en_US', 'ja_JP') + def test_hour_locale(self): + # Test hour directives + self.roundtrip('%I %p', 3) def test_minute(self): # Test minute directives - self.helper('M', 4) + self.roundtrip('%M', 4) def test_second(self): # Test second directives - self.helper('S', 5) + self.roundtrip('%S', 5) def test_fraction(self): # Test microseconds @@ -345,12 +367,18 @@ def test_fraction(self): def test_weekday(self): # Test weekday directives - for directive in ('A', 'a', 'w', 'u'): - self.helper(directive,6) + self.roundtrip('%w', 6) + self.roundtrip('%u', 6) + + @run_with_locales('LC_TIME', 'C', 'en_US', 'fr_FR', 'de_DE', 'ja_JP', '') + def test_weekday_locale(self): + # Test weekday directives + self.roundtrip('%A', 6) + self.roundtrip('%a', 6) def test_julian(self): # Test julian directives - self.helper('j', 7) + self.roundtrip('%j', 7) def test_offset(self): one_hour = 60 * 60 @@ -447,20 +475,121 @@ def test_bad_timezone(self): "time.daylight set to %s and passing in %s" % (time.tzname, tz_value, time.daylight, tz_name)) - def test_date_time(self): + # NB: Does not roundtrip in some locales due to the ambiguity of + # the date and time representation (bugs in locales?): + # * Seconds are not included: bem_ZM, bokmal, ff_SN, nb_NO, nn_NO, + # no_NO, norwegian, nynorsk. + # * Hours are in 12-hour notation without AM/PM indication: hy_AM, + # id_ID, ms_MY. + # * Year is not included: ha_NG. + # * Use non-Gregorian calendar: lo_LA, thai, th_TH. + # On Windows: ar_IN, ar_SA, fa_IR, ps_AF. + # + # BUG: Generates regexp that does not match the current date and time + # for lzh_TW. + @run_with_locales('LC_TIME', 'C', 'en_US', 'fr_FR', 'de_DE', 'ja_JP', + 'he_IL', 'eu_ES', 'ar_AE', 'mfe_MU', 'yo_NG', + 'csb_PL', 'br_FR', 'gez_ET', 'brx_IN', + 'my_MM', 'or_IN', 'shn_MM', 'az_IR') + def test_date_time_locale(self): # Test %c directive - for position in range(6): - self.helper('c', position) - - def test_date(self): + loc = locale.getlocale(locale.LC_TIME)[0] + if glibc_ver and glibc_ver < (2, 31) and loc == 'br_FR': + self.skipTest('%c in locale br_FR does not include time') + now = time.time() + self.roundtrip('%c', slice(0, 6), time.localtime(now)) + # 1 hour 20 minutes 30 seconds ago + self.roundtrip('%c', slice(0, 6), time.localtime(now - 4830)) + # 12 hours ago + self.roundtrip('%c', slice(0, 6), time.localtime(now - 12*3600)) + # different days of the week + for i in range(1, 7): + self.roundtrip('%c', slice(0, 6), time.localtime(now - i*24*3600)) + # different months + for i in range(1, 12): + self.roundtrip('%c', slice(0, 6), time.localtime(now - i*30*24*3600)) + # different year + self.roundtrip('%c', slice(0, 6), time.localtime(now - 366*24*3600)) + + # NB: Dates before 1969 do not roundtrip on some locales: + # az_IR, bo_CN, bo_IN, dz_BT, eu_ES, eu_FR, fa_IR, or_IN. + @support.run_with_tz('STD-1DST,M4.1.0,M10.1.0') + @run_with_locales('LC_TIME', 'C', 'en_US', 'fr_FR', 'de_DE', 'ja_JP', + 'he_IL', 'ar_AE', 'mfe_MU', 'yo_NG', + 'csb_PL', 'br_FR', 'gez_ET', 'brx_IN', + 'my_MM', 'shn_MM') + def test_date_time_locale2(self): + # Test %c directive + loc = locale.getlocale(locale.LC_TIME)[0] + if sys.platform.startswith('sunos'): + if loc in ('ar_AE',): + self.skipTest(f'locale {loc!r} may not work on this platform') + self.roundtrip('%c', slice(0, 6), (1900, 1, 1, 0, 0, 0, 0, 1, 0)) + self.roundtrip('%c', slice(0, 6), (1800, 1, 1, 0, 0, 0, 0, 1, 0)) + + # NB: Does not roundtrip because use non-Gregorian calendar: + # lo_LA, thai, th_TH. On Windows: ar_IN, ar_SA, fa_IR, ps_AF. + # BUG: Generates regexp that does not match the current date + # for lzh_TW. + @run_with_locales('LC_TIME', 'C', 'en_US', 'fr_FR', 'de_DE', 'ja_JP', + 'he_IL', 'eu_ES', 'ar_AE', + 'az_IR', 'my_MM', 'or_IN', 'shn_MM') + def test_date_locale(self): # Test %x directive - for position in range(0,3): - self.helper('x', position) - - def test_time(self): + now = time.time() + self.roundtrip('%x', slice(0, 3), time.localtime(now)) + # different days of the week + for i in range(1, 7): + self.roundtrip('%x', slice(0, 3), time.localtime(now - i*24*3600)) + # different months + for i in range(1, 12): + self.roundtrip('%x', slice(0, 3), time.localtime(now - i*30*24*3600)) + # different year + self.roundtrip('%x', slice(0, 3), time.localtime(now - 366*24*3600)) + + # NB: Dates before 1969 do not roundtrip on many locales, including C. + @unittest.skipIf( + support.is_emscripten or support.is_wasi, + "musl libc issue on Emscripten, bpo-46390" + ) + @run_with_locales('LC_TIME', 'en_US', 'fr_FR', 'de_DE', 'ja_JP', + 'eu_ES', 'ar_AE', 'my_MM', 'shn_MM') + def test_date_locale2(self): + # Test %x directive + loc = locale.getlocale(locale.LC_TIME)[0] + if sys.platform.startswith('sunos'): + if loc in ('en_US', 'de_DE', 'ar_AE'): + self.skipTest(f'locale {loc!r} may not work on this platform') + self.roundtrip('%x', slice(0, 3), (1900, 1, 1, 0, 0, 0, 0, 1, 0)) + self.roundtrip('%x', slice(0, 3), (1800, 1, 1, 0, 0, 0, 0, 1, 0)) + + # NB: Does not roundtrip in some locales due to the ambiguity of + # the time representation (bugs in locales?): + # * Seconds are not included: bokmal, ff_SN, nb_NO, nn_NO, no_NO, + # norwegian, nynorsk. + # * Hours are in 12-hour notation without AM/PM indication: hy_AM, + # ms_MY, sm_WS. + # BUG: Generates regexp that does not match the current time for lzh_TW. + @run_with_locales('LC_TIME', 'C', 'en_US', 'fr_FR', 'de_DE', 'ja_JP', + 'aa_ET', 'am_ET', 'az_IR', 'byn_ER', 'fa_IR', 'gez_ET', + 'my_MM', 'om_ET', 'or_IN', 'shn_MM', 'sid_ET', 'so_SO', + 'ti_ET', 'tig_ER', 'wal_ET') + def test_time_locale(self): # Test %X directive - for position in range(3,6): - self.helper('X', position) + loc = locale.getlocale(locale.LC_TIME)[0] + pos = slice(3, 6) + if glibc_ver and glibc_ver < (2, 29) and loc in { + 'aa_ET', 'am_ET', 'byn_ER', 'gez_ET', 'om_ET', + 'sid_ET', 'so_SO', 'ti_ET', 'tig_ER', 'wal_ET'}: + # Hours are in 12-hour notation without AM/PM indication. + # Ignore hours. + pos = slice(4, 6) + now = time.time() + self.roundtrip('%X', pos, time.localtime(now)) + # 1 hour 20 minutes 30 seconds ago + self.roundtrip('%X', pos, time.localtime(now - 4830)) + # 12 hours ago + self.roundtrip('%X', pos, time.localtime(now - 12*3600)) def test_percent(self): # Make sure % signs are handled properly @@ -710,13 +839,8 @@ def test_new_localetime(self): def test_TimeRE_recreation_locale(self): # The TimeRE instance should be recreated upon changing the locale. - locale_info = locale.getlocale(locale.LC_TIME) - try: - locale.setlocale(locale.LC_TIME, ('en_US', 'UTF8')) - except locale.Error: - self.skipTest('test needs en_US.UTF8 locale') - try: - _strptime._strptime_time('10', '%d') + with support.run_with_locale('LC_TIME', 'en_US.UTF8'): + _strptime._strptime_time('10 2004', '%d %Y') # Get id of current cache object. first_time_re = _strptime._TimeRE_cache try: @@ -732,10 +856,6 @@ def test_TimeRE_recreation_locale(self): # to the resetting to the original locale. except locale.Error: self.skipTest('test needs de_DE.UTF8 locale') - # Make sure we don't trample on the locale setting once we leave the - # test. - finally: - locale.setlocale(locale.LC_TIME, locale_info) @support.run_with_tz('STD-1DST,M4.1.0,M10.1.0') def test_TimeRE_recreation_timezone(self): diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index 8d4b13a6..c683e5dd 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -96,6 +96,13 @@ def test_new_features(self): ('10s', b'helloworld', b'helloworld', b'helloworld', 0), ('11s', b'helloworld', b'helloworld\0', b'helloworld\0', 1), ('20s', b'helloworld', b'helloworld'+10*b'\0', b'helloworld'+10*b'\0', 1), + ('0p', b'helloworld', b'', b'', 1), + ('1p', b'helloworld', b'\x00', b'\x00', 1), + ('2p', b'helloworld', b'\x01h', b'\x01h', 1), + ('10p', b'helloworld', b'\x09helloworl', b'\x09helloworl', 1), + ('11p', b'helloworld', b'\x0Ahelloworld', b'\x0Ahelloworld', 0), + ('12p', b'helloworld', b'\x0Ahelloworld\0', b'\x0Ahelloworld\0', 1), + ('20p', b'helloworld', b'\x0Ahelloworld'+9*b'\0', b'\x0Ahelloworld'+9*b'\0', 1), ('b', 7, b'\7', b'\7', 0), ('b', -7, b'\371', b'\371', 0), ('B', 7, b'\7', b'\7', 0), @@ -339,6 +346,7 @@ def assertStructError(func, *args, **kwargs): def test_p_code(self): # Test p ("Pascal string") code. for code, input, expected, expectedback in [ + ('0p', b'abc', b'', b''), ('p', b'abc', b'\x00', b''), ('1p', b'abc', b'\x00', b''), ('2p', b'abc', b'\x01a', b'a'), @@ -521,6 +529,9 @@ def __bool__(self): for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']: self.assertTrue(struct.unpack('>?', c)[0]) + self.assertTrue(struct.unpack('', 'utf-8', + '{{', '', '\n', '_', 'x', '\0', '\N{CEDILLA}', '\xff', + ): + with self.subTest(s=s): + t = sys.intern(s) - print('------------------------') - interp = interpreters.create() - interp.run(textwrap.dedent(f''' - import sys - t = sys.intern({s!r}) - assert id(t) == {id(t)}, (id(t), {id(t)}) - ''')) + interp = interpreters.create() + interp.run(textwrap.dedent(f''' + import sys + + # set `s`, avoid parser interning & constant folding + s = str({s.encode()!r}, 'utf-8') + + t = sys.intern(s) + assert id(t) == {id(t)}, (id(t), {id(t)}) + ''')) + + @support.cpython_only + @requires_subinterpreters + def test_subinterp_intern_singleton(self): + # Implementation detail: singletons are used for 0- and 1-character + # latin1 strings. + for s in '', '\n', '_', 'x', '\0', '\N{CEDILLA}', '\xff': + with self.subTest(s=s): + interp = interpreters.create() + interp.run(textwrap.dedent(f''' + import sys + + # set `s`, avoid parser interning & constant folding + s = str({s.encode()!r}, 'utf-8') + + assert id(s) == {id(s)} + t = sys.intern(s) + assert id(t) == id(s), (id(t), id(s)) + ''')) def test_sys_flags(self): self.assertTrue(sys.flags) diff --git a/Lib/test/test_sys_setprofile.py b/Lib/test/test_sys_setprofile.py index bb8adc8b..f7703696 100644 --- a/Lib/test/test_sys_setprofile.py +++ b/Lib/test/test_sys_setprofile.py @@ -265,6 +265,10 @@ def g(p): f_ident = ident(f) g_ident = ident(g) self.check_events(g, [(1, 'call', g_ident), + (2, 'call', f_ident), + (2, 'return', f_ident), + # once more; the generator is being garbage collected + # and it will do a PY_THROW (2, 'call', f_ident), (2, 'return', f_ident), (1, 'return', g_ident), @@ -474,6 +478,20 @@ def f(): sys.setprofile(lambda *args: None) f() + def test_method_with_c_function(self): + # gh-122029 + # When we have a PyMethodObject whose im_func is a C function, we + # should record both the call and the return. f = classmethod(repr) + # is just a way to create a PyMethodObject with a C function. + class A: + f = classmethod(repr) + events = [] + sys.setprofile(lambda frame, event, args: events.append(event)) + A().f() + sys.setprofile(None) + # The last c_call is the call to sys.setprofile + self.assertEqual(events, ['c_call', 'c_return', 'c_call']) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index 196fd60d..35985b34 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -1634,15 +1634,15 @@ def func(): EXPECTED_EVENTS = [ (0, 'call'), (2, 'line'), - (1, 'line'), (-3, 'call'), (-2, 'line'), (-2, 'return'), - (4, 'line'), (1, 'line'), + (4, 'line'), + (2, 'line'), (-2, 'call'), (-2, 'return'), - (1, 'return'), + (2, 'return'), ] # C level events should be the same as expected and the same as Python level. diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py index 1137c203..3468d0ce 100644 --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py @@ -3,6 +3,8 @@ import os import subprocess import shutil +import json +import textwrap from copy import copy from test.support import ( @@ -11,6 +13,7 @@ from test.support.import_helper import import_module from test.support.os_helper import (TESTFN, unlink, skip_unless_symlink, change_cwd) +from test.support.venv import VirtualEnvironment import sysconfig from sysconfig import (get_paths, get_platform, get_config_vars, @@ -90,6 +93,12 @@ def _cleanup_testfn(self): elif os.path.isdir(path): shutil.rmtree(path) + def venv(self, **venv_create_args): + return VirtualEnvironment.from_tmpdir( + prefix=f'{self.id()}-venv-', + **venv_create_args, + ) + def test_get_path_names(self): self.assertEqual(get_path_names(), sysconfig._SCHEME_KEYS) @@ -511,6 +520,72 @@ def test_osx_ext_suffix(self): suffix = sysconfig.get_config_var('EXT_SUFFIX') self.assertTrue(suffix.endswith('-darwin.so'), suffix) + @requires_subprocess() + def test_config_vars_depend_on_site_initialization(self): + script = textwrap.dedent(""" + import sysconfig + + config_vars = sysconfig.get_config_vars() + + import json + print(json.dumps(config_vars, indent=2)) + """) + + with self.venv() as venv: + site_config_vars = json.loads(venv.run('-c', script).stdout) + no_site_config_vars = json.loads(venv.run('-S', '-c', script).stdout) + + self.assertNotEqual(site_config_vars, no_site_config_vars) + # With the site initialization, the virtual environment should be enabled. + self.assertEqual(site_config_vars['base'], venv.prefix) + self.assertEqual(site_config_vars['platbase'], venv.prefix) + #self.assertEqual(site_config_vars['prefix'], venv.prefix) # # FIXME: prefix gets overwriten by _init_posix + # Without the site initialization, the virtual environment should be disabled. + self.assertEqual(no_site_config_vars['base'], site_config_vars['installed_base']) + self.assertEqual(no_site_config_vars['platbase'], site_config_vars['installed_platbase']) + + @requires_subprocess() + def test_config_vars_recalculation_after_site_initialization(self): + script = textwrap.dedent(""" + import sysconfig + + before = sysconfig.get_config_vars() + + import site + site.main() + + after = sysconfig.get_config_vars() + + import json + print(json.dumps({'before': before, 'after': after}, indent=2)) + """) + + with self.venv() as venv: + config_vars = json.loads(venv.run('-S', '-c', script).stdout) + + self.assertNotEqual(config_vars['before'], config_vars['after']) + self.assertEqual(config_vars['after']['base'], venv.prefix) + #self.assertEqual(config_vars['after']['prefix'], venv.prefix) # FIXME: prefix gets overwriten by _init_posix + #self.assertEqual(config_vars['after']['exec_prefix'], venv.prefix) # FIXME: exec_prefix gets overwriten by _init_posix + + @requires_subprocess() + def test_paths_depend_on_site_initialization(self): + script = textwrap.dedent(""" + import sysconfig + + paths = sysconfig.get_paths() + + import json + print(json.dumps(paths, indent=2)) + """) + + with self.venv() as venv: + site_paths = json.loads(venv.run('-c', script).stdout) + no_site_paths = json.loads(venv.run('-S', '-c', script).stdout) + + self.assertNotEqual(site_paths, no_site_paths) + + class MakefileTests(unittest.TestCase): @unittest.skipIf(sys.platform.startswith('win'), diff --git a/Lib/test/test_tabnanny.py b/Lib/test/test_tabnanny.py index cc122caf..30dcb3e3 100644 --- a/Lib/test/test_tabnanny.py +++ b/Lib/test/test_tabnanny.py @@ -315,7 +315,7 @@ def validate_cmd(self, *args, stdout="", stderr="", partial=False, expect_failur def test_with_errored_file(self): """Should displays error when errored python file is given.""" with TemporaryPyFile(SOURCE_CODES["wrong_indented"]) as file_path: - stderr = f"{file_path!r}: Token Error: " + stderr = f"{file_path!r}: Indentation Error: " stderr += ('unindent does not match any outer indentation level' ' (, line 3)') self.validate_cmd(file_path, stderr=stderr, expect_failure=True) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index 3fbd25e7..e28d0311 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -1237,6 +1237,48 @@ def test_pax_number_fields(self): finally: tar.close() + def test_pax_header_bad_formats(self): + # The fields from the pax header have priority over the + # TarInfo. + pax_header_replacements = ( + b" foo=bar\n", + b"0 \n", + b"1 \n", + b"2 \n", + b"3 =\n", + b"4 =a\n", + b"1000000 foo=bar\n", + b"0 foo=bar\n", + b"-12 foo=bar\n", + b"000000000000000000000000036 foo=bar\n", + ) + pax_headers = {"foo": "bar"} + + for replacement in pax_header_replacements: + with self.subTest(header=replacement): + tar = tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT, + encoding="iso8859-1") + try: + t = tarfile.TarInfo() + t.name = "pax" # non-ASCII + t.uid = 1 + t.pax_headers = pax_headers + tar.addfile(t) + finally: + tar.close() + + with open(tmpname, "rb") as f: + data = f.read() + self.assertIn(b"11 foo=bar\n", data) + data = data.replace(b"11 foo=bar\n", replacement) + + with open(tmpname, "wb") as f: + f.truncate() + f.write(data) + + with self.assertRaisesRegex(tarfile.ReadError, r"method tar: ReadError\('invalid header'\)"): + tarfile.open(tmpname, encoding="iso8859-1") + class WriteTestBase(TarTest): # Put all write tests in here that are supposed to be tested diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py index ebdb58f9..743ff85d 100644 --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -51,7 +51,7 @@ def test_eval_null_in_result(self): def test_eval_surrogates_in_result(self): tcl = self.interp - self.assertIn(tcl.eval(r'set a "<\ud83d\udcbb>"'), '<\U0001f4bb>') + self.assertEqual(tcl.eval(r'set a "<\ud83d\udcbb>"'), '<\U0001f4bb>') def testEvalException(self): tcl = self.interp @@ -61,11 +61,30 @@ def testEvalException2(self): tcl = self.interp self.assertRaises(TclError,tcl.eval,'this is wrong') + def test_eval_returns_tcl_obj(self): + tcl = self.interp.tk + tcl.eval(r'set a "\u20ac \ud83d\udcbb \0 \udcab"; regexp -about $a') + a = tcl.eval('set a') + expected = '\u20ac \U0001f4bb \0 \udced\udcb2\udcab' + self.assertEqual(a, expected) + def testCall(self): tcl = self.interp tcl.call('set','a','1') self.assertEqual(tcl.call('set','a'),'1') + def test_call_passing_null(self): + tcl = self.interp + tcl.call('set', 'a', 'a\0b') # ASCII-only + self.assertEqual(tcl.getvar('a'), 'a\x00b') + self.assertEqual(tcl.call('set', 'a'), 'a\x00b') + self.assertEqual(tcl.eval('set a'), 'a\x00b') + + tcl.call('set', 'a', '\u20ac\0') # non-ASCII + self.assertEqual(tcl.getvar('a'), '\u20ac\x00') + self.assertEqual(tcl.call('set', 'a'), '\u20ac\x00') + self.assertEqual(tcl.eval('set a'), '\u20ac\x00') + def testCallException(self): tcl = self.interp self.assertRaises(TclError,tcl.call,'set','a') @@ -74,11 +93,35 @@ def testCallException2(self): tcl = self.interp self.assertRaises(TclError,tcl.call,'this','is','wrong') + def test_call_returns_tcl_obj(self): + tcl = self.interp.tk + tcl.eval(r'set a "\u20ac \ud83d\udcbb \0 \udcab"; regexp -about $a') + a = tcl.call('set', 'a') + expected = '\u20ac \U0001f4bb \0 \udced\udcb2\udcab' + if self.wantobjects: + self.assertEqual(str(a), expected) + self.assertEqual(a.string, expected) + self.assertEqual(a.typename, 'regexp') + else: + self.assertEqual(a, expected) + def testSetVar(self): tcl = self.interp tcl.setvar('a','1') self.assertEqual(tcl.eval('set a'),'1') + def test_setvar_passing_null(self): + tcl = self.interp + tcl.setvar('a', 'a\0b') # ASCII-only + self.assertEqual(tcl.getvar('a'), 'a\x00b') + self.assertEqual(tcl.call('set', 'a'), 'a\x00b') + self.assertEqual(tcl.eval('set a'), 'a\x00b') + + tcl.setvar('a', '\u20ac\0') # non-ASCII + self.assertEqual(tcl.getvar('a'), '\u20ac\x00') + self.assertEqual(tcl.call('set', 'a'), '\u20ac\x00') + self.assertEqual(tcl.eval('set a'), '\u20ac\x00') + def testSetVarArray(self): tcl = self.interp tcl.setvar('a(1)','1') @@ -102,6 +145,18 @@ def testGetVarArrayException(self): tcl = self.interp self.assertRaises(TclError,tcl.getvar,'a(1)') + def test_getvar_returns_tcl_obj(self): + tcl = self.interp.tk + tcl.eval(r'set a "\u20ac \ud83d\udcbb \0 \udcab"; regexp -about $a') + a = tcl.getvar('a') + expected = '\u20ac \U0001f4bb \0 \udced\udcb2\udcab' + if self.wantobjects: + self.assertEqual(str(a), expected) + self.assertEqual(a.string, expected) + self.assertEqual(a.typename, 'regexp') + else: + self.assertEqual(a, expected) + def testUnsetVar(self): tcl = self.interp tcl.setvar('a',1) @@ -219,10 +274,18 @@ def test_evalfile_surrogates_in_result(self): with open(filename, 'wb') as f: f.write(b""" set a "<\xed\xa0\xbd\xed\xb2\xbb>" + """) + if tcl_version >= (9, 0): + self.assertRaises(TclError, tcl.evalfile, filename) + else: + tcl.evalfile(filename) + self.assertEqual(tcl.eval('set a'), '<\U0001f4bb>') + + with open(filename, 'wb') as f: + f.write(b""" set b "<\\ud83d\\udcbb>" """) tcl.evalfile(filename) - self.assertEqual(tcl.eval('set a'), '<\U0001f4bb>') self.assertEqual(tcl.eval('set b'), '<\U0001f4bb>') def testEvalFileException(self): @@ -530,6 +593,24 @@ def float_eq(actual, expected): check((1, (2,), (3, 4), '5 6', ()), '1 2 {3 4} {5 6} {}') check([1, [2,], [3, 4], '5 6', []], '1 2 {3 4} {5 6} {}') + def test_passing_tcl_obj(self): + tcl = self.interp.tk + a = None + def testfunc(arg): + nonlocal a + a = arg + self.interp.createcommand('testfunc', testfunc) + self.addCleanup(self.interp.tk.deletecommand, 'testfunc') + tcl.eval(r'set a "\u20ac \ud83d\udcbb \0 \udcab"; regexp -about $a') + tcl.eval(r'testfunc $a') + expected = '\u20ac \U0001f4bb \0 \udced\udcb2\udcab' + if self.wantobjects >= 2: + self.assertEqual(str(a), expected) + self.assertEqual(a.string, expected) + self.assertEqual(a.typename, 'regexp') + else: + self.assertEqual(a, expected) + def test_splitlist(self): splitlist = self.interp.tk.splitlist call = self.interp.tk.call @@ -654,6 +735,7 @@ def test_new_tcl_obj(self): support.check_disallow_instantiation(self, _tkinter.TkttType) support.check_disallow_instantiation(self, _tkinter.TkappType) + class BigmemTclTest(unittest.TestCase): def setUp(self): diff --git a/Lib/test/test_termios.py b/Lib/test/test_termios.py index 58698ffa..11928f04 100644 --- a/Lib/test/test_termios.py +++ b/Lib/test/test_termios.py @@ -94,7 +94,7 @@ def test_tcsendbreak(self): try: termios.tcsendbreak(self.fd, 1) except termios.error as exc: - if exc.args[0] == errno.ENOTTY and sys.platform.startswith('freebsd'): + if exc.args[0] == errno.ENOTTY and sys.platform.startswith(('freebsd', "netbsd")): self.skipTest('termios.tcsendbreak() is not supported ' 'with pseudo-terminals (?) on this platform') raise diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index 2e4b860b..75a56f78 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -1150,6 +1150,41 @@ def __del__(self): self.assertEqual(out.strip(), b"OK") self.assertIn(b"can't create new thread at interpreter shutdown", err) + def test_start_new_thread_failed(self): + # gh-109746: if Python fails to start newly created thread + # due to failure of underlying PyThread_start_new_thread() call, + # its state should be removed from interpreter' thread states list + # to avoid its double cleanup + try: + from resource import setrlimit, RLIMIT_NPROC + except ImportError as err: + self.skipTest(err) # RLIMIT_NPROC is specific to Linux and BSD + code = """if 1: + import resource + import _thread + + def f(): + print("shouldn't be printed") + + limits = resource.getrlimit(resource.RLIMIT_NPROC) + [_, hard] = limits + resource.setrlimit(resource.RLIMIT_NPROC, (0, hard)) + + try: + _thread.start_new_thread(f, ()) + except RuntimeError: + print('ok') + else: + print('!skip!') + """ + _, out, err = assert_python_ok("-u", "-c", code) + out = out.strip() + if b'!skip!' in out: + self.skipTest('RLIMIT_NPROC had no effect; probably superuser') + self.assertEqual(out, b'ok') + self.assertEqual(err, b'') + + class ThreadJoinOnShutdown(BaseTestCase): def _run_and_join(self, script): diff --git a/Lib/test/test_threading_local.py b/Lib/test/test_threading_local.py index f0b829a9..3a58afd8 100644 --- a/Lib/test/test_threading_local.py +++ b/Lib/test/test_threading_local.py @@ -208,6 +208,21 @@ def test_threading_local_clear_race(self): _testcapi.join_temporary_c_thread() + @support.cpython_only + def test_error(self): + class Loop(self._local): + attr = 1 + + # Trick the "if name == '__dict__':" test of __setattr__() + # to always be true + class NameCompareTrue: + def __eq__(self, other): + return True + + loop = Loop() + with self.assertRaisesRegex(AttributeError, 'Loop.*read-only'): + loop.__setattr__(NameCompareTrue(), 2) + class ThreadLocalTest(unittest.TestCase, BaseLocalTest): _local = _thread._local diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py index 02cc3f43..9463adda 100644 --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -2,7 +2,6 @@ from test.support import warnings_helper import decimal import enum -import locale import math import platform import sys @@ -15,7 +14,7 @@ except ImportError: _testcapi = None -from test.support import skip_if_buggy_ucrt_strfptime +from test.support import skip_if_buggy_ucrt_strfptime, SuppressCrashReport # Max year is only limited by the size of C int. SIZEOF_INT = sysconfig.get_config_var('SIZEOF_INT') or 4 @@ -178,8 +177,44 @@ def test_strftime(self): self.fail('conversion specifier: %r failed.' % format) self.assertRaises(TypeError, time.strftime, b'%S', tt) - # embedded null character - self.assertRaises(ValueError, time.strftime, '%S\0', tt) + + def test_strftime_invalid_format(self): + tt = time.gmtime(self.t) + with SuppressCrashReport(): + for i in range(1, 128): + format = ' %' + chr(i) + with self.subTest(format=format): + try: + time.strftime(format, tt) + except ValueError as exc: + self.assertEqual(str(exc), 'Invalid format string') + + def test_strftime_special(self): + tt = time.gmtime(self.t) + s1 = time.strftime('%c', tt) + s2 = time.strftime('%B', tt) + # gh-52551, gh-78662: Unicode strings should pass through strftime, + # independently from locale. + self.assertEqual(time.strftime('\U0001f40d', tt), '\U0001f40d') + self.assertEqual(time.strftime('\U0001f4bb%c\U0001f40d%B', tt), f'\U0001f4bb{s1}\U0001f40d{s2}') + self.assertEqual(time.strftime('%c\U0001f4bb%B\U0001f40d', tt), f'{s1}\U0001f4bb{s2}\U0001f40d') + # Lone surrogates should pass through. + self.assertEqual(time.strftime('\ud83d', tt), '\ud83d') + self.assertEqual(time.strftime('\udc0d', tt), '\udc0d') + self.assertEqual(time.strftime('\ud83d%c\udc0d%B', tt), f'\ud83d{s1}\udc0d{s2}') + self.assertEqual(time.strftime('%c\ud83d%B\udc0d', tt), f'{s1}\ud83d{s2}\udc0d') + self.assertEqual(time.strftime('%c\udc0d%B\ud83d', tt), f'{s1}\udc0d{s2}\ud83d') + # Surrogate pairs should not recombine. + self.assertEqual(time.strftime('\ud83d\udc0d', tt), '\ud83d\udc0d') + self.assertEqual(time.strftime('%c\ud83d\udc0d%B', tt), f'{s1}\ud83d\udc0d{s2}') + # Surrogate-escaped bytes should not recombine. + self.assertEqual(time.strftime('\udcf0\udc9f\udc90\udc8d', tt), '\udcf0\udc9f\udc90\udc8d') + self.assertEqual(time.strftime('%c\udcf0\udc9f\udc90\udc8d%B', tt), f'{s1}\udcf0\udc9f\udc90\udc8d{s2}') + # gh-124531: The null character should not terminate the format string. + self.assertEqual(time.strftime('\0', tt), '\0') + self.assertEqual(time.strftime('\0'*1000, tt), '\0'*1000) + self.assertEqual(time.strftime('\0%c\0%B', tt), f'\0{s1}\0{s2}') + self.assertEqual(time.strftime('%c\0%B\0', tt), f'{s1}\0{s2}\0') def _bounds_checking(self, func): # Make sure that strftime() checks the bounds of the various parts @@ -293,7 +328,7 @@ def test_strptime_exception_context(self): # additional check for IndexError branch (issue #19545) with self.assertRaises(ValueError) as e: time.strptime('19', '%Y %') - self.assertIs(e.exception.__suppress_context__, True) + self.assertIsNone(e.exception.__context__) def test_asctime(self): time.asctime(time.gmtime(self.t)) @@ -588,17 +623,8 @@ def test_get_clock_info(self): class TestLocale(unittest.TestCase): - def setUp(self): - self.oldloc = locale.setlocale(locale.LC_ALL) - - def tearDown(self): - locale.setlocale(locale.LC_ALL, self.oldloc) - + @support.run_with_locale('LC_ALL', 'fr_FR', '') def test_bug_3061(self): - try: - tmp = locale.setlocale(locale.LC_ALL, "fr_FR") - except locale.Error: - self.skipTest('could not set locale.LC_ALL to fr_FR') # This should not cause an exception time.strftime("%B", (2009,2,1,0,0,0,0,0,0)) diff --git a/Lib/test/test_tkinter/test_geometry_managers.py b/Lib/test/test_tkinter/test_geometry_managers.py index 59fe592b..1be474b3 100644 --- a/Lib/test/test_tkinter/test_geometry_managers.py +++ b/Lib/test/test_tkinter/test_geometry_managers.py @@ -10,6 +10,11 @@ requires('gui') +EXPECTED_FLOAT_ERRMSG = 'expected floating-point number but got "{}"' +EXPECTED_FLOAT_OR_EMPTY_ERRMSG = 'expected floating-point number (or "" )?but got "{}"' +EXPECTED_SCREEN_DISTANCE_ERRMSG = '(bad|expected) screen distance (but got )?"{}"' +EXPECTED_SCREEN_DISTANCE_OR_EMPTY_ERRMSG = '(bad|expected) screen distance (or "" but got )?"{}"' + class PackTest(AbstractWidgetTest, unittest.TestCase): test_keys = None @@ -317,7 +322,8 @@ def test_place_configure_x(self): self.assertEqual(f2.place_info()['x'], '-10') self.root.update() self.assertEqual(f2.winfo_x(), 190) - with self.assertRaisesRegex(TclError, 'bad screen distance "spam"'): + with self.assertRaisesRegex(TclError, + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('spam')): f2.place_configure(in_=f, x='spam') def test_place_configure_y(self): @@ -334,7 +340,8 @@ def test_place_configure_y(self): self.assertEqual(f2.place_info()['y'], '-10') self.root.update() self.assertEqual(f2.winfo_y(), 110) - with self.assertRaisesRegex(TclError, 'bad screen distance "spam"'): + with self.assertRaisesRegex(TclError, + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('spam')): f2.place_configure(in_=f, y='spam') def test_place_configure_relx(self): @@ -351,8 +358,7 @@ def test_place_configure_relx(self): self.assertEqual(f2.place_info()['relx'], '1') self.root.update() self.assertEqual(f2.winfo_x(), 200) - with self.assertRaisesRegex(TclError, 'expected floating-point number ' - 'but got "spam"'): + with self.assertRaisesRegex(TclError, EXPECTED_FLOAT_ERRMSG.format('spam')): f2.place_configure(in_=f, relx='spam') def test_place_configure_rely(self): @@ -369,8 +375,7 @@ def test_place_configure_rely(self): self.assertEqual(f2.place_info()['rely'], '1') self.root.update() self.assertEqual(f2.winfo_y(), 120) - with self.assertRaisesRegex(TclError, 'expected floating-point number ' - 'but got "spam"'): + with self.assertRaisesRegex(TclError, EXPECTED_FLOAT_ERRMSG.format('spam')): f2.place_configure(in_=f, rely='spam') def test_place_configure_anchor(self): @@ -391,7 +396,8 @@ def test_place_configure_width(self): f2.place_configure(width='') self.root.update() self.assertEqual(f2.winfo_width(), 30) - with self.assertRaisesRegex(TclError, 'bad screen distance "abcd"'): + with self.assertRaisesRegex(TclError, + EXPECTED_SCREEN_DISTANCE_OR_EMPTY_ERRMSG.format('abcd')): f2.place_configure(width='abcd') def test_place_configure_height(self): @@ -402,7 +408,8 @@ def test_place_configure_height(self): f2.place_configure(height='') self.root.update() self.assertEqual(f2.winfo_height(), 60) - with self.assertRaisesRegex(TclError, 'bad screen distance "abcd"'): + with self.assertRaisesRegex(TclError, + EXPECTED_SCREEN_DISTANCE_OR_EMPTY_ERRMSG.format('abcd')): f2.place_configure(height='abcd') def test_place_configure_relwidth(self): @@ -413,8 +420,7 @@ def test_place_configure_relwidth(self): f2.place_configure(relwidth='') self.root.update() self.assertEqual(f2.winfo_width(), 30) - with self.assertRaisesRegex(TclError, 'expected floating-point number ' - 'but got "abcd"'): + with self.assertRaisesRegex(TclError, EXPECTED_FLOAT_OR_EMPTY_ERRMSG.format('abcd')): f2.place_configure(relwidth='abcd') def test_place_configure_relheight(self): @@ -425,8 +431,7 @@ def test_place_configure_relheight(self): f2.place_configure(relheight='') self.root.update() self.assertEqual(f2.winfo_height(), 60) - with self.assertRaisesRegex(TclError, 'expected floating-point number ' - 'but got "abcd"'): + with self.assertRaisesRegex(TclError, EXPECTED_FLOAT_OR_EMPTY_ERRMSG.format('abcd')): f2.place_configure(relheight='abcd') def test_place_configure_bordermode(self): @@ -629,7 +634,8 @@ def test_grid_columnconfigure(self): self.assertEqual(self.root.grid_columnconfigure(0, 'weight'), 4) def test_grid_columnconfigure_minsize(self): - with self.assertRaisesRegex(TclError, 'bad screen distance "foo"'): + with self.assertRaisesRegex(TclError, + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('foo')): self.root.grid_columnconfigure(0, minsize='foo') self.root.grid_columnconfigure(0, minsize=10) self.assertEqual(self.root.grid_columnconfigure(0, 'minsize'), 10) @@ -646,7 +652,8 @@ def test_grid_columnconfigure_weight(self): self.assertEqual(self.root.grid_columnconfigure(0)['weight'], 3) def test_grid_columnconfigure_pad(self): - with self.assertRaisesRegex(TclError, 'bad screen distance "foo"'): + with self.assertRaisesRegex(TclError, + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('foo')): self.root.grid_columnconfigure(0, pad='foo') with self.assertRaisesRegex(TclError, 'invalid arg "-pad": ' 'should be non-negative'): @@ -683,7 +690,8 @@ def test_grid_rowconfigure(self): self.assertEqual(self.root.grid_rowconfigure(0, 'weight'), 4) def test_grid_rowconfigure_minsize(self): - with self.assertRaisesRegex(TclError, 'bad screen distance "foo"'): + with self.assertRaisesRegex(TclError, + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('foo')): self.root.grid_rowconfigure(0, minsize='foo') self.root.grid_rowconfigure(0, minsize=10) self.assertEqual(self.root.grid_rowconfigure(0, 'minsize'), 10) @@ -700,7 +708,8 @@ def test_grid_rowconfigure_weight(self): self.assertEqual(self.root.grid_rowconfigure(0)['weight'], 3) def test_grid_rowconfigure_pad(self): - with self.assertRaisesRegex(TclError, 'bad screen distance "foo"'): + with self.assertRaisesRegex(TclError, + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('foo')): self.root.grid_rowconfigure(0, pad='foo') with self.assertRaisesRegex(TclError, 'invalid arg "-pad": ' 'should be non-negative'): @@ -818,9 +827,11 @@ def test_grid_location(self): self.root.grid_location(0) with self.assertRaises(TypeError): self.root.grid_location(0, 0, 0) - with self.assertRaisesRegex(TclError, 'bad screen distance "x"'): + with self.assertRaisesRegex(TclError, + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('x')): self.root.grid_location('x', 'y') - with self.assertRaisesRegex(TclError, 'bad screen distance "y"'): + with self.assertRaisesRegex(TclError, + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('y')): self.root.grid_location('1c', 'y') t = self.root # de-maximize diff --git a/Lib/test/test_tkinter/test_misc.py b/Lib/test/test_tkinter/test_misc.py index fc128600..81866993 100644 --- a/Lib/test/test_tkinter/test_misc.py +++ b/Lib/test/test_tkinter/test_misc.py @@ -382,6 +382,15 @@ def test_info_patchlevel(self): self.assertEqual(vi.micro, 0) self.assertTrue(str(vi).startswith(f'{vi.major}.{vi.minor}')) + def test_embedded_null(self): + widget = tkinter.Entry(self.root) + widget.insert(0, 'abc\0def') # ASCII-only + widget.selection_range(0, 'end') + self.assertEqual(widget.selection_get(), 'abc\x00def') + widget.insert(0, '\u20ac\0') # non-ASCII + widget.selection_range(0, 'end') + self.assertEqual(widget.selection_get(), '\u20ac\0abc\x00def') + class EventTest(AbstractTkTest, unittest.TestCase): diff --git a/Lib/test/test_tkinter/test_variables.py b/Lib/test/test_tkinter/test_variables.py index c1d232e2..def7aec0 100644 --- a/Lib/test/test_tkinter/test_variables.py +++ b/Lib/test/test_tkinter/test_variables.py @@ -6,7 +6,7 @@ from tkinter import (Variable, StringVar, IntVar, DoubleVar, BooleanVar, Tcl, TclError) from test.support import ALWAYS_EQ -from test.test_tkinter.support import AbstractDefaultRootTest +from test.test_tkinter.support import AbstractDefaultRootTest, tcl_version class Var(Variable): @@ -112,6 +112,8 @@ def test_initialize(self): self.assertTrue(v.side_effect) def test_trace_old(self): + if tcl_version >= (9, 0): + self.skipTest('requires Tcl version < 9.0') # Old interface v = Variable(self.root) vname = str(v) diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index 24604b27..b020e1be 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -4,7 +4,7 @@ import os from test.support import requires -from test.test_tkinter.support import (requires_tk, +from test.test_tkinter.support import (requires_tk, tk_version, get_tk_patchlevel, widget_eq, AbstractDefaultRootTest) from test.test_tkinter.widget_tests import ( @@ -14,6 +14,9 @@ requires('gui') +EXPECTED_SCREEN_DISTANCE_ERRMSG = '(bad|expected) screen distance (but got )?"{}"' +EXPECTED_SCREEN_DISTANCE_OR_EMPTY_ERRMSG = '(bad|expected) screen distance (or "" but got )?"{}"' + def float_round(x): return float(round(x)) @@ -58,11 +61,11 @@ def test_configure_visual(self): @add_standard_options(StandardOptionsTests) class ToplevelTest(AbstractToplevelTest, unittest.TestCase): OPTIONS = ( - 'background', 'borderwidth', + 'background', 'backgroundimage', 'borderwidth', 'class', 'colormap', 'container', 'cursor', 'height', 'highlightbackground', 'highlightcolor', 'highlightthickness', 'menu', 'padx', 'pady', 'relief', 'screen', - 'takefocus', 'use', 'visual', 'width', + 'takefocus', 'tile', 'use', 'visual', 'width', ) def create(self, **kwargs): @@ -101,10 +104,10 @@ def test_configure_use(self): @add_standard_options(StandardOptionsTests) class FrameTest(AbstractToplevelTest, unittest.TestCase): OPTIONS = ( - 'background', 'borderwidth', + 'background', 'backgroundimage', 'borderwidth', 'class', 'colormap', 'container', 'cursor', 'height', 'highlightbackground', 'highlightcolor', 'highlightthickness', - 'padx', 'pady', 'relief', 'takefocus', 'visual', 'width', + 'padx', 'pady', 'relief', 'takefocus', 'tile', 'visual', 'width', ) def create(self, **kwargs): @@ -141,11 +144,9 @@ def test_configure_labelwidget(self): class AbstractLabelTest(AbstractWidgetTest, IntegerSizeTests): _conv_pixels = False - - def test_configure_highlightthickness(self): - widget = self.create() - self.checkPixelsParam(widget, 'highlightthickness', - 0, 1.3, 2.6, 6, -2, '10p') + _clip_highlightthickness = tk_version >= (8, 7) + _clip_pad = tk_version >= (8, 7) + _clip_borderwidth = tk_version >= (8, 7) @add_standard_options(StandardOptionsTests) @@ -277,6 +278,9 @@ class MenubuttonTest(AbstractLabelTest, unittest.TestCase): 'underline', 'width', 'wraplength', ) _conv_pixels = round + _clip_highlightthickness = True + _clip_pad = True + _clip_borderwidth = False def create(self, **kwargs): return tkinter.Menubutton(self.root, **kwargs) @@ -290,9 +294,6 @@ def test_configure_height(self): widget = self.create() self.checkIntegerParam(widget, 'height', 100, -100, 0, conv=str) - test_configure_highlightthickness = \ - StandardOptionsTests.test_configure_highlightthickness - def test_configure_image(self): widget = self.create() image = tkinter.PhotoImage(master=self.root, name='image1') @@ -313,16 +314,6 @@ def test_configure_menu(self): self.checkParam(widget, 'menu', menu, eq=widget_eq) menu.destroy() - def test_configure_padx(self): - widget = self.create() - self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, '12m') - self.checkParam(widget, 'padx', -2, expected=0) - - def test_configure_pady(self): - widget = self.create() - self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, '12m') - self.checkParam(widget, 'pady', -2, expected=0) - def test_configure_width(self): widget = self.create() self.checkIntegerParam(widget, 'width', 402, -402, 0, conv=str) @@ -347,7 +338,8 @@ class EntryTest(AbstractWidgetTest, unittest.TestCase): 'highlightbackground', 'highlightcolor', 'highlightthickness', 'insertbackground', 'insertborderwidth', 'insertofftime', 'insertontime', 'insertwidth', - 'invalidcommand', 'justify', 'readonlybackground', 'relief', + 'invalidcommand', 'justify', 'placeholder', 'placeholderforeground', + 'readonlybackground', 'relief', 'selectbackground', 'selectborderwidth', 'selectforeground', 'show', 'state', 'takefocus', 'textvariable', 'validate', 'validatecommand', 'width', 'xscrollcommand', @@ -441,8 +433,8 @@ class SpinboxTest(EntryTest, unittest.TestCase): 'increment', 'insertbackground', 'insertborderwidth', 'insertofftime', 'insertontime', 'insertwidth', - 'invalidcommand', 'justify', 'relief', 'readonlybackground', - 'repeatdelay', 'repeatinterval', + 'invalidcommand', 'justify', 'placeholder', 'placeholderforeground', + 'relief', 'readonlybackground', 'repeatdelay', 'repeatinterval', 'selectbackground', 'selectborderwidth', 'selectforeground', 'state', 'takefocus', 'textvariable', 'to', 'validate', 'validatecommand', 'values', @@ -489,8 +481,12 @@ def test_configure_from(self): widget = self.create() self.checkParam(widget, 'to', 100.0) self.checkFloatParam(widget, 'from', -10, 10.2, 11.7) - self.checkInvalidParam(widget, 'from', 200, - errmsg='-to value must be greater than -from value') + if tk_version >= (8, 7): + self.checkFloatParam(widget, 'from', 200, expected=100) + else: + self.checkInvalidParam( + widget, 'from', 200, + errmsg='-to value must be greater than -from value') def test_configure_increment(self): widget = self.create() @@ -500,8 +496,12 @@ def test_configure_to(self): widget = self.create() self.checkParam(widget, 'from', -100.0) self.checkFloatParam(widget, 'to', -10, 10.2, 11.7) - self.checkInvalidParam(widget, 'to', -200, - errmsg='-to value must be greater than -from value') + if tk_version >= (8, 7): + self.checkFloatParam(widget, 'to', -200, expected=-100) + else: + self.checkInvalidParam( + widget, 'to', -200, + errmsg='-to value must be greater than -from value') def test_configure_values(self): # XXX @@ -666,7 +666,7 @@ def test_configure_tabs(self): self.checkParam(widget, 'tabs', '2c left 4c 6c center', expected=('2c', 'left', '4c', '6c', 'center')) self.checkInvalidParam(widget, 'tabs', 'spam', - errmsg='bad screen distance "spam"') + errmsg=EXPECTED_SCREEN_DISTANCE_ERRMSG.format('spam')) def test_configure_tabstyle(self): widget = self.create() @@ -860,24 +860,27 @@ def test_create_line(self): def test_create_polygon(self): c = self.create() - i1 = c.create_polygon(20, 30, 40, 50, 60, 10) + tk87 = tk_version >= (8, 7) + # In Tk < 8.7 polygons are filled, but has no outline by default. + # This affects its size, so always explicitly specify outline. + i1 = c.create_polygon(20, 30, 40, 50, 60, 10, outline='red') self.assertEqual(c.coords(i1), [20.0, 30.0, 40.0, 50.0, 60.0, 10.0]) - self.assertEqual(c.bbox(i1), (19, 9, 61, 51)) + self.assertEqual(c.bbox(i1), (18, 8, 62, 52)) self.assertEqual(c.itemcget(i1, 'joinstyle'), 'round') self.assertEqual(c.itemcget(i1, 'smooth'), '0') self.assertEqual(c.itemcget(i1, 'splinestep'), '12') - i2 = c.create_polygon([21, 31, 41, 51, 61, 11]) + i2 = c.create_polygon([21, 31, 41, 51, 61, 11], outline='red') self.assertEqual(c.coords(i2), [21.0, 31.0, 41.0, 51.0, 61.0, 11.0]) - self.assertEqual(c.bbox(i2), (20, 10, 62, 52)) + self.assertEqual(c.bbox(i2), (19, 9, 63, 53)) - i3 = c.create_polygon((22, 32), (42, 52), (62, 12)) + i3 = c.create_polygon((22, 32), (42, 52), (62, 12), outline='red') self.assertEqual(c.coords(i3), [22.0, 32.0, 42.0, 52.0, 62.0, 12.0]) - self.assertEqual(c.bbox(i3), (21, 11, 63, 53)) + self.assertEqual(c.bbox(i3), (20, 10, 64, 54)) - i4 = c.create_polygon([(23, 33), (43, 53), (63, 13)]) + i4 = c.create_polygon([(23, 33), (43, 53), (63, 13)], outline='red') self.assertEqual(c.coords(i4), [23.0, 33.0, 43.0, 53.0, 63.0, 13.0]) - self.assertEqual(c.bbox(i4), (22, 12, 64, 54)) + self.assertEqual(c.bbox(i4), (21, 11, 65, 55)) self.assertRaises(TclError, c.create_polygon, 20, 30, 60) self.assertRaises(TclError, c.create_polygon, [20, 30, 60]) @@ -1174,18 +1177,16 @@ class ScrollbarTest(AbstractWidgetTest, unittest.TestCase): def create(self, **kwargs): return tkinter.Scrollbar(self.root, **kwargs) - def test_configure_activerelief(self): - widget = self.create() - self.checkReliefParam(widget, 'activerelief') - def test_configure_elementborderwidth(self): widget = self.create() - self.checkPixelsParam(widget, 'elementborderwidth', 4.3, 5.6, -2, '1m') + self.checkPixelsParam(widget, 'elementborderwidth', 4.3, 5.6, '1m') + expected = self._default_pixels if tk_version >= (8, 7) else -2 + self.checkParam(widget, 'elementborderwidth', -2, expected=expected) def test_configure_orient(self): widget = self.create() self.checkEnumParam(widget, 'orient', 'vertical', 'horizontal', - errmsg='bad orientation "{}": must be vertical or horizontal') + fullname='orientation', allow_empty=True) def test_activate(self): sb = self.create() @@ -1256,7 +1257,8 @@ def test_configure_proxyborderwidth(self): @requires_tk(8, 6, 5) def test_configure_proxyrelief(self): widget = self.create() - self.checkReliefParam(widget, 'proxyrelief') + self.checkReliefParam(widget, 'proxyrelief', + allow_empty=(tk_version >= (8, 7))) def test_configure_sashcursor(self): widget = self.create() @@ -1329,7 +1331,7 @@ def test_paneconfigure_height(self): p, b, c = self.create2() self.check_paneconfigure(p, b, 'height', 10, 10) self.check_paneconfigure_bad(p, b, 'height', - 'bad screen distance "badValue"') + EXPECTED_SCREEN_DISTANCE_OR_EMPTY_ERRMSG.format('badValue')) def test_paneconfigure_hide(self): p, b, c = self.create2() @@ -1341,19 +1343,19 @@ def test_paneconfigure_minsize(self): p, b, c = self.create2() self.check_paneconfigure(p, b, 'minsize', 10, 10) self.check_paneconfigure_bad(p, b, 'minsize', - 'bad screen distance "badValue"') + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('badValue')) def test_paneconfigure_padx(self): p, b, c = self.create2() self.check_paneconfigure(p, b, 'padx', 1.3, 1) self.check_paneconfigure_bad(p, b, 'padx', - 'bad screen distance "badValue"') + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('badValue')) def test_paneconfigure_pady(self): p, b, c = self.create2() self.check_paneconfigure(p, b, 'pady', 1.3, 1) self.check_paneconfigure_bad(p, b, 'pady', - 'bad screen distance "badValue"') + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('badValue')) def test_paneconfigure_sticky(self): p, b, c = self.create2() @@ -1374,13 +1376,14 @@ def test_paneconfigure_width(self): p, b, c = self.create2() self.check_paneconfigure(p, b, 'width', 10, 10) self.check_paneconfigure_bad(p, b, 'width', - 'bad screen distance "badValue"') + EXPECTED_SCREEN_DISTANCE_OR_EMPTY_ERRMSG.format('badValue')) @add_standard_options(StandardOptionsTests) class MenuTest(AbstractWidgetTest, unittest.TestCase): OPTIONS = ( 'activebackground', 'activeborderwidth', 'activeforeground', + 'activerelief', 'background', 'borderwidth', 'cursor', 'disabledforeground', 'font', 'foreground', 'postcommand', 'relief', 'selectcolor', 'takefocus', @@ -1396,6 +1399,8 @@ def test_indexcommand_none(self): i = widget.index('none') self.assertIsNone(i) + test_configure_activerelief = requires_tk(8, 7)(StandardOptionsTests.test_configure_activerelief) + def test_configure_postcommand(self): widget = self.create() self.checkCommandParam(widget, 'postcommand') @@ -1414,14 +1419,10 @@ def test_configure_title(self): def test_configure_type(self): widget = self.create() - opts = ('normal, tearoff, or menubar' - if widget.info_patchlevel() < (8, 7) else - 'menubar, normal, or tearoff') - self.checkEnumParam( - widget, 'type', - 'normal', 'tearoff', 'menubar', - errmsg='bad type "{}": must be ' + opts, - ) + values = ('normal', 'tearoff', 'menubar') + self.checkEnumParam(widget, 'type', *values, + allow_empty=tk_version < (8, 7), + sort=tk_version >= (8, 7)) def test_entryconfigure(self): m1 = self.create() @@ -1467,6 +1468,10 @@ class MessageTest(AbstractWidgetTest, unittest.TestCase): 'takefocus', 'text', 'textvariable', 'width', ) _conv_pad_pixels = False + if tk_version >= (8, 7): + _conv_pixels = False + _clip_pad = tk_version >= (8, 7) + _clip_borderwidth = tk_version >= (8, 7) def create(self, **kwargs): return tkinter.Message(self.root, **kwargs) @@ -1475,6 +1480,26 @@ def test_configure_aspect(self): widget = self.create() self.checkIntegerParam(widget, 'aspect', 250, 0, -300) + def test_configure_padx(self): + widget = self.create() + self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, '12m', + conv=self._conv_pad_pixels) + expected = self._default_pixels if self._clip_pad else -2 + self.checkParam(widget, 'padx', -2, expected=expected) + + def test_configure_pady(self): + widget = self.create() + self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, '12m', + conv=self._conv_pad_pixels) + expected = self._default_pixels if self._clip_pad else -2 + self.checkParam(widget, 'pady', -2, expected=expected) + + def test_configure_width(self): + widget = self.create() + self.checkPixelsParam(widget, 'width', 402, 403.4, 404.6, 0, '5i') + expected = 0 if tk_version >= (8, 7) else -402 + self.checkParam(widget, 'width', -402, expected=expected) + class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): diff --git a/Lib/test/test_tkinter/widget_tests.py b/Lib/test/test_tkinter/widget_tests.py index 514b42be..3b75dc7b 100644 --- a/Lib/test/test_tkinter/widget_tests.py +++ b/Lib/test/test_tkinter/widget_tests.py @@ -1,7 +1,8 @@ # Common tests for test_tkinter/test_widgets.py and test_ttk/test_widgets.py +import re import tkinter -from test.test_tkinter.support import (AbstractTkTest, tk_version, +from test.test_tkinter.support import (AbstractTkTest, requires_tk, tk_version, pixels_conv, tcl_obj_eq) import test.support @@ -9,9 +10,14 @@ _sentinel = object() class AbstractWidgetTest(AbstractTkTest): + _default_pixels = '' if tk_version >= (9, 0) else -1 if tk_version >= (8, 7) else '' _conv_pixels = round _conv_pad_pixels = None _stringify = False + _clip_highlightthickness = True + _clip_pad = False + _clip_borderwidth = False + _allow_empty_justify = False @property def scaling(self): @@ -56,16 +62,13 @@ def checkParam(self, widget, name, value, *, expected=_sentinel, def checkInvalidParam(self, widget, name, value, errmsg=None): orig = widget[name] if errmsg is not None: - errmsg = errmsg.format(value) - with self.assertRaises(tkinter.TclError) as cm: + errmsg = errmsg.format(re.escape(str(value))) + errmsg = fr'\A{errmsg}\Z' + with self.assertRaisesRegex(tkinter.TclError, errmsg or ''): widget[name] = value - if errmsg is not None: - self.assertEqual(str(cm.exception), errmsg) self.assertEqual(widget[name], orig) - with self.assertRaises(tkinter.TclError) as cm: + with self.assertRaisesRegex(tkinter.TclError, errmsg or ''): widget.configure({name: value}) - if errmsg is not None: - self.assertEqual(str(cm.exception), errmsg) self.assertEqual(widget[name], orig) def checkParams(self, widget, name, *values, **kwargs): @@ -74,30 +77,26 @@ def checkParams(self, widget, name, *values, **kwargs): def checkIntegerParam(self, widget, name, *values, **kwargs): self.checkParams(widget, name, *values, **kwargs) - self.checkInvalidParam(widget, name, '', - errmsg='expected integer but got ""') - self.checkInvalidParam(widget, name, '10p', - errmsg='expected integer but got "10p"') - self.checkInvalidParam(widget, name, 3.2, - errmsg='expected integer but got "3.2"') + errmsg = 'expected integer but got "{}"' + self.checkInvalidParam(widget, name, '', errmsg=errmsg) + self.checkInvalidParam(widget, name, '10p', errmsg=errmsg) + self.checkInvalidParam(widget, name, 3.2, errmsg=errmsg) def checkFloatParam(self, widget, name, *values, conv=float, **kwargs): for value in values: self.checkParam(widget, name, value, conv=conv, **kwargs) - self.checkInvalidParam(widget, name, '', - errmsg='expected floating-point number but got ""') - self.checkInvalidParam(widget, name, 'spam', - errmsg='expected floating-point number but got "spam"') + errmsg = 'expected floating-point number but got "{}"' + self.checkInvalidParam(widget, name, '', errmsg=errmsg) + self.checkInvalidParam(widget, name, 'spam', errmsg=errmsg) def checkBooleanParam(self, widget, name): for value in (False, 0, 'false', 'no', 'off'): self.checkParam(widget, name, value, expected=0) for value in (True, 1, 'true', 'yes', 'on'): self.checkParam(widget, name, value, expected=1) - self.checkInvalidParam(widget, name, '', - errmsg='expected boolean value but got ""') - self.checkInvalidParam(widget, name, 'spam', - errmsg='expected boolean value but got "spam"') + errmsg = 'expected boolean value but got "{}"' + self.checkInvalidParam(widget, name, '', errmsg=errmsg) + self.checkInvalidParam(widget, name, 'spam', errmsg=errmsg) def checkColorParam(self, widget, name, *, allow_empty=None, **kwargs): self.checkParams(widget, name, @@ -120,16 +119,24 @@ def command(*args): self.assertTrue(widget[name]) self.checkParams(widget, name, '') - def checkEnumParam(self, widget, name, *values, errmsg=None, **kwargs): + def checkEnumParam(self, widget, name, *values, + errmsg=None, allow_empty=False, fullname=None, + sort=False, **kwargs): self.checkParams(widget, name, *values, **kwargs) if errmsg is None: + if sort: + if values[-1]: + values = tuple(sorted(values)) + else: + values = tuple(sorted(values[:-1])) + ('',) errmsg2 = ' %s "{}": must be %s%s or %s' % ( - name, + fullname or name, ', '.join(values[:-1]), ',' if len(values) > 2 else '', - values[-1]) - self.checkInvalidParam(widget, name, '', - errmsg='ambiguous' + errmsg2) + values[-1] or '""') + if '' not in values and not allow_empty: + self.checkInvalidParam(widget, name, '', + errmsg='ambiguous' + errmsg2) errmsg = 'bad' + errmsg2 self.checkInvalidParam(widget, name, 'spam', errmsg=errmsg) @@ -146,20 +153,21 @@ def checkPixelsParam(self, widget, name, *values, conv1 = round self.checkParam(widget, name, value, expected=expected, conv=conv1, **kwargs) - self.checkInvalidParam(widget, name, '6x', - errmsg='bad screen distance "6x"') - self.checkInvalidParam(widget, name, 'spam', - errmsg='bad screen distance "spam"') + errmsg = '(bad|expected) screen distance ((or "" )?but got )?"{}"' + self.checkInvalidParam(widget, name, '6x', errmsg=errmsg) + self.checkInvalidParam(widget, name, 'spam', errmsg=errmsg) - def checkReliefParam(self, widget, name): - self.checkParams(widget, name, - 'flat', 'groove', 'raised', 'ridge', 'solid', 'sunken') - errmsg='bad relief "spam": must be '\ - 'flat, groove, raised, ridge, solid, or sunken' + def checkReliefParam(self, widget, name, *, allow_empty=False): + values = ('flat', 'groove', 'raised', 'ridge', 'solid', 'sunken') + if allow_empty: + values += ('',) + self.checkParams(widget, name, *values) + errmsg = 'bad relief "{}": must be %s, or %s' % ( + ', '.join(values[:-1]), + values[-1] or '""') if tk_version < (8, 6): errmsg = None - self.checkInvalidParam(widget, name, 'spam', - errmsg=errmsg) + self.checkInvalidParam(widget, name, 'spam', errmsg=errmsg) def checkImageParam(self, widget, name): image = tkinter.PhotoImage(master=self.root, name='image1') @@ -193,6 +201,7 @@ def test_keys(self): aliases = { 'bd': 'borderwidth', 'bg': 'background', + 'bgimg': 'backgroundimage', 'fg': 'foreground', 'invcmd': 'invalidcommand', 'vcmd': 'validatecommand', @@ -235,6 +244,10 @@ def test_configure_activeforeground(self): widget = self.create() self.checkColorParam(widget, 'activeforeground') + def test_configure_activerelief(self): + widget = self.create() + self.checkReliefParam(widget, 'activerelief') + def test_configure_anchor(self): widget = self.create() self.checkEnumParam(widget, 'anchor', @@ -246,6 +259,11 @@ def test_configure_background(self): if 'bg' in self.OPTIONS: self.checkColorParam(widget, 'bg') + @requires_tk(8, 7) + def test_configure_backgroundimage(self): + widget = self.create() + self.checkImageParam(widget, 'backgroundimage') + def test_configure_bitmap(self): widget = self.create() self.checkParam(widget, 'bitmap', 'questhead') @@ -262,9 +280,14 @@ def test_configure_bitmap(self): def test_configure_borderwidth(self): widget = self.create() self.checkPixelsParam(widget, 'borderwidth', - 0, 1.3, 2.6, 6, -2, '10p') + 0, 1.3, 2.6, 6, '10p') + expected = 0 if self._clip_borderwidth else -2 + self.checkParam(widget, 'borderwidth', -2, expected=expected, + conv=self._conv_pixels) if 'bd' in self.OPTIONS: - self.checkPixelsParam(widget, 'bd', 0, 1.3, 2.6, 6, -2, '10p') + self.checkPixelsParam(widget, 'bd', 0, 1.3, 2.6, 6, '10p') + self.checkParam(widget, 'bd', -2, expected=expected, + conv=self._conv_pixels) def test_configure_compound(self): widget = self.create() @@ -287,8 +310,10 @@ def test_configure_font(self): widget = self.create() self.checkParam(widget, 'font', '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') - self.checkInvalidParam(widget, 'font', '', - errmsg='font "" doesn\'t exist') + is_ttk = widget.__class__.__module__ == 'tkinter.ttk' + if not is_ttk: + self.checkInvalidParam(widget, 'font', '', + errmsg='font "" doesn\'t exist') def test_configure_foreground(self): widget = self.create() @@ -308,7 +333,8 @@ def test_configure_highlightthickness(self): widget = self.create() self.checkPixelsParam(widget, 'highlightthickness', 0, 1.3, 2.6, 6, '10p') - self.checkParam(widget, 'highlightthickness', -2, expected=0, + expected = 0 if self._clip_highlightthickness else -2 + self.checkParam(widget, 'highlightthickness', -2, expected=expected, conv=self._conv_pixels) def test_configure_image(self): @@ -342,12 +368,11 @@ def test_configure_jump(self): def test_configure_justify(self): widget = self.create() - self.checkEnumParam(widget, 'justify', 'left', 'right', 'center', - errmsg='bad justification "{}": must be ' - 'left, right, or center') - self.checkInvalidParam(widget, 'justify', '', - errmsg='ambiguous justification "": must be ' - 'left, right, or center') + values = ('left', 'right', 'center') + if self._allow_empty_justify: + values += ('',) + self.checkEnumParam(widget, 'justify', *values, + fullname='justification') def test_configure_orient(self): widget = self.create() @@ -356,13 +381,29 @@ def test_configure_orient(self): def test_configure_padx(self): widget = self.create() - self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, -2, '12m', + self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, '12m', conv=self._conv_pad_pixels) + expected = 0 if self._clip_pad else -2 + self.checkParam(widget, 'padx', -2, expected=expected, + conv=self._conv_pad_pixels) def test_configure_pady(self): widget = self.create() - self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, -2, '12m', + self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, '12m', conv=self._conv_pad_pixels) + expected = 0 if self._clip_pad else -2 + self.checkParam(widget, 'pady', -2, expected=expected, + conv=self._conv_pad_pixels) + + @requires_tk(8, 7) + def test_configure_placeholder(self): + widget = self.create() + self.checkParam(widget, 'placeholder', 'xxx') + + @requires_tk(8, 7) + def test_configure_placeholderforeground(self): + widget = self.create() + self.checkColorParam(widget, 'placeholderforeground') def test_configure_relief(self): widget = self.create() @@ -409,13 +450,35 @@ def test_configure_textvariable(self): var = tkinter.StringVar(self.root) self.checkVariableParam(widget, 'textvariable', var) + @requires_tk(8, 7) + def test_configure_tile(self): + widget = self.create() + self.checkBooleanParam(widget, 'tile') + def test_configure_troughcolor(self): widget = self.create() self.checkColorParam(widget, 'troughcolor') def test_configure_underline(self): widget = self.create() - self.checkIntegerParam(widget, 'underline', 0, 1, 10) + self.checkParams(widget, 'underline', 0, 1, 10) + if tk_version >= (8, 7): + is_ttk = widget.__class__.__module__ == 'tkinter.ttk' + self.checkParam(widget, 'underline', '', + expected='' if is_ttk else self._default_pixels) + self.checkParam(widget, 'underline', '5+2', + expected='5+2' if is_ttk else 7) + self.checkParam(widget, 'underline', '5-2', + expected='5-2' if is_ttk else 3) + self.checkParam(widget, 'underline', 'end', expected='end') + self.checkParam(widget, 'underline', 'end-2', expected='end-2') + errmsg = (r'bad index "{}": must be integer\?\[\+-\]integer\?, ' + r'end\?\[\+-\]integer\?, or ""') + else: + errmsg = 'expected integer but got "{}"' + self.checkInvalidParam(widget, 'underline', '', errmsg=errmsg) + self.checkInvalidParam(widget, 'underline', '10p', errmsg=errmsg) + self.checkInvalidParam(widget, 'underline', 3.2, errmsg=errmsg) def test_configure_wraplength(self): widget = self.create() @@ -445,7 +508,8 @@ def test_configure_offrelief(self): def test_configure_overrelief(self): widget = self.create() - self.checkReliefParam(widget, 'overrelief') + self.checkReliefParam(widget, 'overrelief', + allow_empty=(tk_version >= (8, 7))) def test_configure_selectcolor(self): widget = self.create() diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index c52b58b4..2c4e7b96 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -233,7 +233,7 @@ def test_long(self): """) def test_float(self): - # Floating point numbers + # Floating-point numbers self.check_tokenize("x = 3.14159", """\ NAME 'x' (1, 0) (1, 1) OP '=' (1, 2) (1, 3) @@ -1204,6 +1204,31 @@ def test_closing_parenthesis_from_different_line(self): NAME 'x' (1, 3) (1, 4) """) + def test_multiline_non_ascii_fstring(self): + self.check_tokenize("""\ +a = f''' + Autorzy, którzy tą jednostkę mają wpisani jako AKTUALNA -- czyli'''""", """\ + NAME 'a' (1, 0) (1, 1) + OP '=' (1, 2) (1, 3) + FSTRING_START "f\'\'\'" (1, 4) (1, 8) + FSTRING_MIDDLE '\\n Autorzy, którzy tą jednostkę mają wpisani jako AKTUALNA -- czyli' (1, 8) (2, 68) + FSTRING_END "\'\'\'" (2, 68) (2, 71) + """) + + def test_multiline_non_ascii_fstring_with_expr(self): + self.check_tokenize("""\ +f''' + 🔗 This is a test {test_arg1}🔗 +🔗'''""", """\ + FSTRING_START "f\'\'\'" (1, 0) (1, 4) + FSTRING_MIDDLE '\\n 🔗 This is a test ' (1, 4) (2, 21) + OP '{' (2, 21) (2, 22) + NAME 'test_arg1' (2, 22) (2, 31) + OP '}' (2, 31) (2, 32) + FSTRING_MIDDLE '🔗\\n🔗' (2, 32) (3, 1) + FSTRING_END "\'\'\'" (3, 1) (3, 4) + """) + class GenerateTokensTest(TokenizeTest): def check_tokenize(self, s, expected): # Format the tokens in s in a table format. @@ -1891,6 +1916,26 @@ def test_roundtrip(self): self.check_roundtrip(r"f'\\\\N{{'") self.check_roundtrip(r"f'\\\\\\N{{'") self.check_roundtrip(r"f'\\\\\\\\N{{'") + + self.check_roundtrip(r"f'\n{{foo}}'") + self.check_roundtrip(r"f'\\n{{foo}}'") + self.check_roundtrip(r"f'\\\n{{foo}}'") + self.check_roundtrip(r"f'\\\\n{{foo}}'") + + self.check_roundtrip(r"f'\t{{foo}}'") + self.check_roundtrip(r"f'\\t{{foo}}'") + self.check_roundtrip(r"f'\\\t{{foo}}'") + self.check_roundtrip(r"f'\\\\t{{foo}}'") + + self.check_roundtrip(r"rf'\t{{foo}}'") + self.check_roundtrip(r"rf'\\t{{foo}}'") + self.check_roundtrip(r"rf'\\\t{{foo}}'") + self.check_roundtrip(r"rf'\\\\t{{foo}}'") + + self.check_roundtrip(r"rf'\{{foo}}'") + self.check_roundtrip(r"f'\\{{foo}}'") + self.check_roundtrip(r"rf'\\\{{foo}}'") + self.check_roundtrip(r"f'\\\\{{foo}}'") cases = [ """ if 1: diff --git a/Lib/test/test_tools/i18n_data/docstrings.pot b/Lib/test/test_tools/i18n_data/docstrings.pot new file mode 100644 index 00000000..5af1d414 --- /dev/null +++ b/Lib/test/test_tools/i18n_data/docstrings.pot @@ -0,0 +1,40 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2000-01-01 00:00+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: pygettext.py 1.5\n" + + +#: docstrings.py:7 +#, docstring +msgid "" +msgstr "" + +#: docstrings.py:18 +#, docstring +msgid "" +"multiline\n" +" docstring\n" +" " +msgstr "" + +#: docstrings.py:25 +#, docstring +msgid "docstring1" +msgstr "" + +#: docstrings.py:30 +#, docstring +msgid "Hello, {}!" +msgstr "" + diff --git a/Lib/test/test_tools/i18n_data/docstrings.py b/Lib/test/test_tools/i18n_data/docstrings.py new file mode 100644 index 00000000..85d7f159 --- /dev/null +++ b/Lib/test/test_tools/i18n_data/docstrings.py @@ -0,0 +1,41 @@ +# Test docstring extraction +from gettext import gettext as _ + + +# Empty docstring +def test(x): + """""" + + +# Leading empty line +def test2(x): + + """docstring""" # XXX This should be extracted but isn't. + + +# XXX Multiline docstrings should be cleaned with `inspect.cleandoc`. +def test3(x): + """multiline + docstring + """ + + +# Multiple docstrings - only the first should be extracted +def test4(x): + """docstring1""" + """docstring2""" + + +def test5(x): + """Hello, {}!""".format("world!") # XXX This should not be extracted. + + +# Nested docstrings +def test6(x): + def inner(y): + """nested docstring""" # XXX This should be extracted but isn't. + + +class Outer: + class Inner: + "nested class docstring" # XXX This should be extracted but isn't. diff --git a/Lib/test/test_tools/i18n_data/fileloc.pot b/Lib/test/test_tools/i18n_data/fileloc.pot new file mode 100644 index 00000000..dbd28687 --- /dev/null +++ b/Lib/test/test_tools/i18n_data/fileloc.pot @@ -0,0 +1,35 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2000-01-01 00:00+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: pygettext.py 1.5\n" + + +#: fileloc.py:5 fileloc.py:6 +msgid "foo" +msgstr "" + +#: fileloc.py:9 +msgid "bar" +msgstr "" + +#: fileloc.py:14 fileloc.py:18 +#, docstring +msgid "docstring" +msgstr "" + +#: fileloc.py:22 fileloc.py:26 +#, docstring +msgid "baz" +msgstr "" + diff --git a/Lib/test/test_tools/i18n_data/fileloc.py b/Lib/test/test_tools/i18n_data/fileloc.py new file mode 100644 index 00000000..c5d4d059 --- /dev/null +++ b/Lib/test/test_tools/i18n_data/fileloc.py @@ -0,0 +1,26 @@ +# Test file locations +from gettext import gettext as _ + +# Duplicate strings +_('foo') +_('foo') + +# Duplicate strings on the same line should only add one location to the output +_('bar'), _('bar') + + +# Duplicate docstrings +class A: + """docstring""" + + +def f(): + """docstring""" + + +# Duplicate message and docstring +_('baz') + + +def g(): + """baz""" diff --git a/Lib/test/test_tools/i18n_data/messages.pot b/Lib/test/test_tools/i18n_data/messages.pot new file mode 100644 index 00000000..ddfbd183 --- /dev/null +++ b/Lib/test/test_tools/i18n_data/messages.pot @@ -0,0 +1,67 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2000-01-01 00:00+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: pygettext.py 1.5\n" + + +#: messages.py:5 +msgid "" +msgstr "" + +#: messages.py:8 messages.py:9 +msgid "parentheses" +msgstr "" + +#: messages.py:12 +msgid "Hello, world!" +msgstr "" + +#: messages.py:15 +msgid "" +"Hello,\n" +" multiline!\n" +msgstr "" + +#: messages.py:29 +msgid "Hello, {}!" +msgstr "" + +#: messages.py:33 +msgid "1" +msgstr "" + +#: messages.py:33 +msgid "2" +msgstr "" + +#: messages.py:34 messages.py:35 +msgid "A" +msgstr "" + +#: messages.py:34 messages.py:35 +msgid "B" +msgstr "" + +#: messages.py:36 +msgid "set" +msgstr "" + +#: messages.py:42 +msgid "nested string" +msgstr "" + +#: messages.py:47 +msgid "baz" +msgstr "" + diff --git a/Lib/test/test_tools/i18n_data/messages.py b/Lib/test/test_tools/i18n_data/messages.py new file mode 100644 index 00000000..f220294b --- /dev/null +++ b/Lib/test/test_tools/i18n_data/messages.py @@ -0,0 +1,64 @@ +# Test message extraction +from gettext import gettext as _ + +# Empty string +_("") + +# Extra parentheses +(_("parentheses")) +((_("parentheses"))) + +# Multiline strings +_("Hello, " + "world!") + +_("""Hello, + multiline! +""") + +# Invalid arguments +_() +_(None) +_(1) +_(False) +_(x="kwargs are not allowed") +_("foo", "bar") +_("something", x="something else") + +# .format() +_("Hello, {}!").format("world") # valid +_("Hello, {}!".format("world")) # invalid + +# Nested structures +_("1"), _("2") +arr = [_("A"), _("B")] +obj = {'a': _("A"), 'b': _("B")} +{{{_('set')}}} + + +# Nested functions and classes +def test(): + _("nested string") # XXX This should be extracted but isn't. + [_("nested string")] + + +class Foo: + def bar(self): + return _("baz") + + +def bar(x=_('default value')): # XXX This should be extracted but isn't. + pass + + +def baz(x=[_('default value')]): # XXX This should be extracted but isn't. + pass + + +# Shadowing _() +def _(x): + pass + + +def _(x="don't extract me"): + pass diff --git a/Lib/test/test_tools/test_i18n.py b/Lib/test/test_tools/test_i18n.py index c083a044..6f71f097 100644 --- a/Lib/test/test_tools/test_i18n.py +++ b/Lib/test/test_tools/test_i18n.py @@ -1,9 +1,11 @@ """Tests to cover the Tools/i18n package""" import os +import re import sys import unittest from textwrap import dedent +from pathlib import Path from test.support.script_helper import assert_python_ok from test.test_tools import skip_if_missing, toolsdir @@ -12,20 +14,47 @@ skip_if_missing() +DATA_DIR = Path(__file__).resolve().parent / 'i18n_data' + + +def normalize_POT_file(pot): + """Normalize the POT creation timestamp, charset and + file locations to make the POT file easier to compare. + + """ + # Normalize the creation date. + date_pattern = re.compile(r'"POT-Creation-Date: .+?\\n"') + header = r'"POT-Creation-Date: 2000-01-01 00:00+0000\\n"' + pot = re.sub(date_pattern, header, pot) + + # Normalize charset to UTF-8 (currently there's no way to specify the output charset). + charset_pattern = re.compile(r'"Content-Type: text/plain; charset=.+?\\n"') + charset = r'"Content-Type: text/plain; charset=UTF-8\\n"' + pot = re.sub(charset_pattern, charset, pot) + + # Normalize file location path separators in case this test is + # running on Windows (which uses '\'). + fileloc_pattern = re.compile(r'#:.+') + + def replace(match): + return match[0].replace(os.sep, "/") + pot = re.sub(fileloc_pattern, replace, pot) + return pot + class Test_pygettext(unittest.TestCase): """Tests for the pygettext.py tool""" - script = os.path.join(toolsdir,'i18n', 'pygettext.py') + script = Path(toolsdir, 'i18n', 'pygettext.py') def get_header(self, data): """ utility: return the header of a .po file as a dictionary """ headers = {} for line in data.split('\n'): - if not line or line.startswith(('#', 'msgid','msgstr')): + if not line or line.startswith(('#', 'msgid', 'msgstr')): continue line = line.strip('"') - key, val = line.split(':',1) + key, val = line.split(':', 1) headers[key] = val.strip() return headers @@ -53,23 +82,34 @@ def get_msgids(self, data): return msgids - def extract_docstrings_from_str(self, module_content): - """ utility: return all msgids extracted from module_content """ - filename = 'test_docstrings.py' - with temp_cwd(None) as cwd: + def assert_POT_equal(self, expected, actual): + """Check if two POT files are equal""" + self.maxDiff = None + self.assertEqual(normalize_POT_file(expected), normalize_POT_file(actual)) + + def extract_from_str(self, module_content, *, args=(), strict=True): + """Return all msgids extracted from module_content.""" + filename = 'test.py' + with temp_cwd(None): with open(filename, 'w', encoding='utf-8') as fp: fp.write(module_content) - assert_python_ok(self.script, '-D', filename) + res = assert_python_ok('-Xutf8', self.script, *args, filename) + if strict: + self.assertEqual(res.err, b'') with open('messages.pot', encoding='utf-8') as fp: data = fp.read() return self.get_msgids(data) + def extract_docstrings_from_str(self, module_content): + """Return all docstrings extracted from module_content.""" + return self.extract_from_str(module_content, args=('--docstrings',), strict=False) + def test_header(self): """Make sure the required fields are in the header, according to: http://www.gnu.org/software/gettext/manual/gettext.html#Header-Entry """ with temp_cwd(None) as cwd: - assert_python_ok(self.script) + assert_python_ok('-Xutf8', self.script) with open('messages.pot', encoding='utf-8') as fp: data = fp.read() header = self.get_header(data) @@ -96,7 +136,7 @@ def test_POT_Creation_Date(self): """ Match the date format from xgettext for POT-Creation-Date """ from datetime import datetime with temp_cwd(None) as cwd: - assert_python_ok(self.script) + assert_python_ok('-Xutf8', self.script) with open('messages.pot', encoding='utf-8') as fp: data = fp.read() header = self.get_header(data) @@ -310,6 +350,37 @@ def test_calls_in_fstring_with_partially_wrong_expression(self): self.assertNotIn('foo', msgids) self.assertIn('bar', msgids) + def test_function_and_class_names(self): + """Test that function and class names are not mistakenly extracted.""" + msgids = self.extract_from_str(dedent('''\ + def _(x): + pass + + def _(x="foo"): + pass + + async def _(x): + pass + + class _(object): + pass + ''')) + self.assertEqual(msgids, ['']) + + def test_pygettext_output(self): + """Test that the pygettext output exactly matches snapshots.""" + for input_file in DATA_DIR.glob('*.py'): + output_file = input_file.with_suffix('.pot') + with self.subTest(input_file=f'i18n_data/{input_file}'): + contents = input_file.read_text(encoding='utf-8') + with temp_cwd(None): + Path(input_file.name).write_text(contents) + assert_python_ok('-Xutf8', self.script, '--docstrings', input_file.name) + output = Path('messages.pot').read_text(encoding='utf-8') + + expected = output_file.read_text(encoding='utf-8') + self.assert_POT_equal(expected, output) + def test_files_list(self): """Make sure the directories are inspected for source files bpo-31920 @@ -318,21 +389,41 @@ def test_files_list(self): text2 = 'Text to translate2' text3 = 'Text to ignore' with temp_cwd(None), temp_dir(None) as sdir: - os.mkdir(os.path.join(sdir, 'pypkg')) - with open(os.path.join(sdir, 'pypkg', 'pymod.py'), 'w', - encoding='utf-8') as sfile: - sfile.write(f'_({text1!r})') - os.mkdir(os.path.join(sdir, 'pkg.py')) - with open(os.path.join(sdir, 'pkg.py', 'pymod2.py'), 'w', - encoding='utf-8') as sfile: - sfile.write(f'_({text2!r})') - os.mkdir(os.path.join(sdir, 'CVS')) - with open(os.path.join(sdir, 'CVS', 'pymod3.py'), 'w', - encoding='utf-8') as sfile: - sfile.write(f'_({text3!r})') - assert_python_ok(self.script, sdir) - with open('messages.pot', encoding='utf-8') as fp: - data = fp.read() + pymod = Path(sdir, 'pypkg', 'pymod.py') + pymod.parent.mkdir() + pymod.write_text(f'_({text1!r})', encoding='utf-8') + + pymod2 = Path(sdir, 'pkg.py', 'pymod2.py') + pymod2.parent.mkdir() + pymod2.write_text(f'_({text2!r})', encoding='utf-8') + + pymod3 = Path(sdir, 'CVS', 'pymod3.py') + pymod3.parent.mkdir() + pymod3.write_text(f'_({text3!r})', encoding='utf-8') + + assert_python_ok('-Xutf8', self.script, sdir) + data = Path('messages.pot').read_text(encoding='utf-8') self.assertIn(f'msgid "{text1}"', data) self.assertIn(f'msgid "{text2}"', data) self.assertNotIn(text3, data) + + +def update_POT_snapshots(): + for input_file in DATA_DIR.glob('*.py'): + output_file = input_file.with_suffix('.pot') + contents = input_file.read_bytes() + with temp_cwd(None): + Path(input_file.name).write_bytes(contents) + assert_python_ok('-Xutf8', Test_pygettext.script, '--docstrings', input_file.name) + output = Path('messages.pot').read_text(encoding='utf-8') + + output = normalize_POT_file(output) + output_file.write_text(output, encoding='utf-8') + + +if __name__ == '__main__': + # To regenerate POT files + if len(sys.argv) > 1 and sys.argv[1] == '--snapshot-update': + update_POT_snapshots() + sys.exit(0) + unittest.main() diff --git a/Lib/test/test_tools/test_makefile.py b/Lib/test/test_tools/test_makefile.py index e253bd00..f1f0cd87 100644 --- a/Lib/test/test_tools/test_makefile.py +++ b/Lib/test/test_tools/test_makefile.py @@ -51,7 +51,10 @@ def test_makefile_test_folders(self): if not dirs and not files: continue # Skip dirs with hidden-only files: - if files and all(filename.startswith('.') for filename in files): + if files and all( + filename.startswith('.') or filename == '__pycache__' + for filename in files + ): continue relpath = os.path.relpath(dirpath, support.STDLIB_DIR) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index d12b559c..119143e4 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -138,7 +138,7 @@ def test_no_caret_with_no_debug_ranges_flag_python_traceback(self): import traceback try: x = 1 / 0 - except: + except ZeroDivisionError: traceback.print_exc() """) try: @@ -386,9 +386,10 @@ class PurePythonExceptionFormattingMixin: def get_exception(self, callable, slice_start=0, slice_end=-1): try: callable() - self.fail("No exception thrown.") - except: + except BaseException: return traceback.format_exc().splitlines()[slice_start:slice_end] + else: + self.fail("No exception thrown.") callable_line = get_exception.__code__.co_firstlineno + 2 @@ -1490,7 +1491,7 @@ def test_context_suppression(self): try: try: raise Exception - except: + except Exception: raise ZeroDivisionError from None except ZeroDivisionError as _: e = _ @@ -1838,9 +1839,9 @@ def exc(): try: try: raise EG("eg1", [ValueError(1), TypeError(2)]) - except: + except EG: raise EG("eg2", [ValueError(3), TypeError(4)]) - except: + except EG: raise ImportError(5) expected = ( @@ -1889,7 +1890,7 @@ def exc(): except Exception as e: exc = e raise EG("eg", [VE(1), exc, VE(4)]) - except: + except EG: raise EG("top", [VE(5)]) expected = (f' + Exception Group Traceback (most recent call last):\n' @@ -2642,7 +2643,7 @@ def test_long_context_chain(self): def f(): try: 1/0 - except: + except ZeroDivisionError: f() try: @@ -2731,7 +2732,7 @@ def test_comparison_params_variations(self): def raise_exc(): try: raise ValueError('bad value') - except: + except ValueError: raise def raise_with_locals(): diff --git a/Lib/test/test_ttk/test_style.py b/Lib/test/test_ttk/test_style.py index 2b131862..5de29a39 100644 --- a/Lib/test/test_ttk/test_style.py +++ b/Lib/test/test_ttk/test_style.py @@ -227,13 +227,13 @@ def test_element_create_image(self): foreground='blue', background='yellow') img3 = tkinter.BitmapImage(master=self.root, file=imgfile, foreground='white', background='black') - style.element_create('Button.button', 'image', + style.element_create('TestButton.button', 'image', img1, ('pressed', img2), ('active', img3), border=(2, 4), sticky='we') - self.assertIn('Button.button', style.element_names()) + self.assertIn('TestButton.button', style.element_names()) - style.layout('Button', [('Button.button', {'sticky': 'news'})]) - b = ttk.Button(self.root, style='Button') + style.layout('TestButton', [('TestButton.button', {'sticky': 'news'})]) + b = ttk.Button(self.root, style='TestButton') b.pack(expand=True, fill='both') self.assertEqual(b.winfo_reqwidth(), 16) self.assertEqual(b.winfo_reqheight(), 16) diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index 308bbba1..ceba95c9 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -5,8 +5,9 @@ import sys from test.test_ttk_textonly import MockTclObj -from test.test_tkinter.support import (AbstractTkTest, tk_version, get_tk_patchlevel, - simulate_mouse_click, AbstractDefaultRootTest) +from test.test_tkinter.support import ( + AbstractTkTest, requires_tk, tk_version, get_tk_patchlevel, + simulate_mouse_click, AbstractDefaultRootTest) from test.test_tkinter.widget_tests import (add_standard_options, AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests) @@ -44,6 +45,10 @@ def padding_conv(value): self.checkParam(widget, 'padding', ('5p', '6p', '7p', '8p')) self.checkParam(widget, 'padding', (), expected='') + def test_configure_state(self): + widget = self.create() + self.checkParams(widget, 'state', 'active', 'disabled', 'readonly') + def test_configure_style(self): widget = self.create() self.assertEqual(widget['style'], '') @@ -57,6 +62,11 @@ def test_configure_style(self): self.assertEqual(widget2['class'], 'Foo') # XXX + def test_configure_relief(self): + widget = self.create() + self.checkReliefParam(widget, 'relief', + allow_empty=(tk_version >= (8, 7))) + class WidgetTest(AbstractTkTest, unittest.TestCase): """Tests methods available in every ttk widget.""" @@ -157,6 +167,7 @@ def test_configure_labelwidget(self): class AbstractLabelTest(AbstractWidgetTest): + _allow_empty_justify = True def checkImageParam(self, widget, name): image = tkinter.PhotoImage(master=self.root, name='image1') @@ -172,17 +183,13 @@ def checkImageParam(self, widget, name): errmsg='image "spam" doesn\'t exist') def test_configure_compound(self): - options = 'none text image center top bottom left right'.split() - errmsg = ( - 'bad compound "{}": must be' - f' {", ".join(options[:-1])}, or {options[-1]}' - ) + values = ('none', 'text', 'image', 'center', 'top', 'bottom', 'left', 'right') + if tk_version >= (8, 7): + values += ('',) widget = self.create() - self.checkEnumParam(widget, 'compound', *options, errmsg=errmsg) + self.checkEnumParam(widget, 'compound', *values, allow_empty=True) - def test_configure_state(self): - widget = self.create() - self.checkParams(widget, 'state', 'active', 'disabled', 'normal') + test_configure_justify = requires_tk(8, 7)(StandardOptionsTests.test_configure_justify) def test_configure_width(self): widget = self.create() @@ -199,21 +206,19 @@ class LabelTest(AbstractLabelTest, unittest.TestCase): 'underline', 'width', 'wraplength', ) _conv_pixels = False + _allow_empty_justify = tk_version >= (8, 7) def create(self, **kwargs): return ttk.Label(self.root, **kwargs) - def test_configure_font(self): - widget = self.create() - self.checkParam(widget, 'font', - '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') + test_configure_justify = StandardOptionsTests.test_configure_justify @add_standard_options(StandardTtkOptionsTests) class ButtonTest(AbstractLabelTest, unittest.TestCase): OPTIONS = ( 'class', 'command', 'compound', 'cursor', 'default', - 'image', 'padding', 'state', 'style', + 'image', 'justify', 'padding', 'state', 'style', 'takefocus', 'text', 'textvariable', 'underline', 'width', ) @@ -223,7 +228,9 @@ def create(self, **kwargs): def test_configure_default(self): widget = self.create() - self.checkEnumParam(widget, 'default', 'normal', 'active', 'disabled') + values = ('normal', 'active', 'disabled') + self.checkEnumParam(widget, 'default', *values, + sort=tk_version >= (8, 7)) def test_invoke(self): success = [] @@ -236,7 +243,7 @@ def test_invoke(self): class CheckbuttonTest(AbstractLabelTest, unittest.TestCase): OPTIONS = ( 'class', 'command', 'compound', 'cursor', - 'image', + 'image', 'justify', 'offvalue', 'onvalue', 'padding', 'state', 'style', 'takefocus', 'text', 'textvariable', @@ -275,7 +282,10 @@ def cb_test(): cbtn['command'] = '' res = cbtn.invoke() - self.assertFalse(str(res)) + if tk_version >= (8, 7) and self.wantobjects: + self.assertEqual(res, ()) + else: + self.assertEqual(str(res), '') self.assertLessEqual(len(success), 1) self.assertEqual(cbtn['offvalue'], cbtn.tk.globalgetvar(cbtn['variable'])) @@ -322,10 +332,12 @@ class EntryTest(AbstractWidgetTest, unittest.TestCase): 'background', 'class', 'cursor', 'exportselection', 'font', 'foreground', 'invalidcommand', 'justify', + 'placeholder', 'placeholderforeground', 'show', 'state', 'style', 'takefocus', 'textvariable', 'validate', 'validatecommand', 'width', 'xscrollcommand', ) - IDENTIFY_AS = 'Entry.field' if sys.platform == 'darwin' else 'textarea' + # bpo-27313: macOS Tk/Tcl may or may not report 'Entry.field'. + IDENTIFY_AS = {'Entry.field', 'textarea'} def setUp(self): super().setUp() @@ -344,11 +356,6 @@ def test_configure_show(self): self.checkParam(widget, 'show', '') self.checkParam(widget, 'show', ' ') - def test_configure_state(self): - widget = self.create() - self.checkParams(widget, 'state', - 'disabled', 'normal', 'readonly') - def test_configure_validate(self): widget = self.create() self.checkEnumParam(widget, 'validate', @@ -367,8 +374,7 @@ def test_identify(self): self.entry.pack() self.entry.update() - # bpo-27313: macOS Cocoa widget differs from X, allow either - self.assertEqual(self.entry.identify(5, 5), self.IDENTIFY_AS) + self.assertIn(self.entry.identify(5, 5), self.IDENTIFY_AS) self.assertEqual(self.entry.identify(-1, -1), "") self.assertRaises(tkinter.TclError, self.entry.identify, None, 5) @@ -449,12 +455,13 @@ class ComboboxTest(EntryTest, unittest.TestCase): OPTIONS = ( 'background', 'class', 'cursor', 'exportselection', 'font', 'foreground', 'height', 'invalidcommand', - 'justify', 'postcommand', 'show', 'state', 'style', + 'justify', 'placeholder', 'placeholderforeground', 'postcommand', + 'show', 'state', 'style', 'takefocus', 'textvariable', 'validate', 'validatecommand', 'values', 'width', 'xscrollcommand', ) - IDENTIFY_AS = 'Combobox.button' if sys.platform == 'darwin' else 'textarea' + IDENTIFY_AS = {'Combobox.button', 'textarea'} def setUp(self): super().setUp() @@ -513,7 +520,7 @@ def check_get_current(getval, currval): self.assertEqual(self.combo.get(), getval) self.assertEqual(self.combo.current(), currval) - self.assertEqual(self.combo['values'], '') + self.assertIn(self.combo['values'], ((), '')) check_get_current('', -1) self.checkParam(self.combo, 'values', 'mon tue wed thur', @@ -638,8 +645,14 @@ def test_insert(self): child2 = ttk.Label(self.root) child3 = ttk.Label(self.root) - self.assertRaises(tkinter.TclError, self.paned.insert, 0, child) + if tk_version >= (8, 7): + self.paned.insert(0, child) + self.assertEqual(self.paned.panes(), (str(child),)) + self.paned.forget(0) + else: + self.assertRaises(tkinter.TclError, self.paned.insert, 0, child) + self.assertEqual(self.paned.panes(), ()) self.paned.insert('end', child2) self.paned.insert(0, child) self.assertEqual(self.paned.panes(), (str(child), str(child2))) @@ -703,7 +716,7 @@ def test_sashpos(self): class RadiobuttonTest(AbstractLabelTest, unittest.TestCase): OPTIONS = ( 'class', 'command', 'compound', 'cursor', - 'image', + 'image', 'justify', 'padding', 'state', 'style', 'takefocus', 'text', 'textvariable', 'underline', 'value', 'variable', 'width', @@ -742,7 +755,10 @@ def cb_test(): cbtn2['command'] = '' res = cbtn2.invoke() - self.assertEqual(str(res), '') + if tk_version >= (8, 7) and self.wantobjects: + self.assertEqual(res, ()) + else: + self.assertEqual(str(res), '') self.assertLessEqual(len(success), 1) self.assertEqual(conv(cbtn2['value']), myvar.get()) self.assertEqual(myvar.get(), @@ -754,7 +770,7 @@ def cb_test(): class MenubuttonTest(AbstractLabelTest, unittest.TestCase): OPTIONS = ( 'class', 'compound', 'cursor', 'direction', - 'image', 'menu', 'padding', 'state', 'style', + 'image', 'justify', 'menu', 'padding', 'state', 'style', 'takefocus', 'text', 'textvariable', 'underline', 'width', ) @@ -762,10 +778,11 @@ class MenubuttonTest(AbstractLabelTest, unittest.TestCase): def create(self, **kwargs): return ttk.Menubutton(self.root, **kwargs) - def test_direction(self): + def test_configure_direction(self): widget = self.create() - self.checkEnumParam(widget, 'direction', - 'above', 'below', 'left', 'right', 'flush') + values = ('above', 'below', 'left', 'right', 'flush') + self.checkEnumParam(widget, 'direction', *values, + sort=tk_version >= (8, 7)) def test_configure_menu(self): widget = self.create() @@ -778,7 +795,7 @@ def test_configure_menu(self): class ScaleTest(AbstractWidgetTest, unittest.TestCase): OPTIONS = ( 'class', 'command', 'cursor', 'from', 'length', - 'orient', 'style', 'takefocus', 'to', 'value', 'variable', + 'orient', 'state', 'style', 'takefocus', 'to', 'value', 'variable', ) _conv_pixels = False default_orient = 'horizontal' @@ -800,6 +817,8 @@ def test_configure_length(self): widget = self.create() self.checkPixelsParam(widget, 'length', 130, 131.2, 135.6, '5i') + test_configure_state = requires_tk(8, 6, 9)(StandardTtkOptionsTests.test_configure_state) + def test_configure_to(self): widget = self.create() self.checkFloatParam(widget, 'to', 300, 14.9, 15.1, -10, conv=False) @@ -883,16 +902,28 @@ def test_set(self): @add_standard_options(StandardTtkOptionsTests) class ProgressbarTest(AbstractWidgetTest, unittest.TestCase): OPTIONS = ( - 'class', 'cursor', 'orient', 'length', - 'mode', 'maximum', 'phase', + 'anchor', 'class', 'cursor', 'font', 'foreground', 'justify', + 'orient', 'length', + 'mode', 'maximum', 'phase', 'text', 'wraplength', 'style', 'takefocus', 'value', 'variable', ) _conv_pixels = False + _allow_empty_justify = True default_orient = 'horizontal' def create(self, **kwargs): return ttk.Progressbar(self.root, **kwargs) + @requires_tk(8, 7) + def test_configure_anchor(self): + widget = self.create() + self.checkEnumParam(widget, 'anchor', + 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'center', '') + + test_configure_font = requires_tk(8, 7)(StandardOptionsTests.test_configure_font) + test_configure_foreground = requires_tk(8, 7)(StandardOptionsTests.test_configure_foreground) + test_configure_justify = requires_tk(8, 7)(StandardTtkOptionsTests.test_configure_justify) + def test_configure_length(self): widget = self.create() self.checkPixelsParam(widget, 'length', 100.1, 56.7, '2i') @@ -909,11 +940,15 @@ def test_configure_phase(self): # XXX pass + test_configure_text = requires_tk(8, 7)(StandardOptionsTests.test_configure_text) + def test_configure_value(self): widget = self.create() self.checkFloatParam(widget, 'value', 150.2, 77.7, 0, -10, conv=False) + test_configure_wraplength = requires_tk(8, 7)(StandardOptionsTests.test_configure_wraplength) + @unittest.skipIf(sys.platform == 'darwin', 'ttk.Scrollbar is special on MacOSX') @@ -928,11 +963,13 @@ def create(self, **kwargs): return ttk.Scrollbar(self.root, **kwargs) -@add_standard_options(IntegerSizeTests, StandardTtkOptionsTests) +@add_standard_options(StandardTtkOptionsTests) class NotebookTest(AbstractWidgetTest, unittest.TestCase): OPTIONS = ( 'class', 'cursor', 'height', 'padding', 'style', 'takefocus', 'width', ) + if tk_version >= (8, 7): + _conv_pixels = False def setUp(self): super().setUp() @@ -945,6 +982,20 @@ def setUp(self): def create(self, **kwargs): return ttk.Notebook(self.root, **kwargs) + def test_configure_height(self): + widget = self.create() + if get_tk_patchlevel(self.root) < (8, 6, 15): + self.checkIntegerParam(widget, 'height', 402, -402, 0) + else: + self.checkPixelsParam(widget, 'height', '10c', 402, -402, 0, conv=False) + + def test_configure_width(self): + widget = self.create() + if get_tk_patchlevel(self.root) < (8, 6, 15): + self.checkIntegerParam(widget, 'width', 402, -402, 0) + else: + self.checkPixelsParam(widget, 'width', '10c', 402, -402, 0, conv=False) + def test_tab_identifiers(self): self.nb.forget(0) self.nb.hide(self.child2) @@ -1051,7 +1102,11 @@ def test_insert(self): self.nb.insert(self.child1, child3) self.assertEqual(self.nb.tabs(), (str(child3), ) + tabs) self.nb.forget(child3) - self.assertRaises(tkinter.TclError, self.nb.insert, 2, child3) + if tk_version >= (8, 7): + self.nb.insert(2, child3) + self.assertEqual(self.nb.tabs(), (*tabs, str(child3))) + else: + self.assertRaises(tkinter.TclError, self.nb.insert, 2, child3) self.assertRaises(tkinter.TclError, self.nb.insert, -1, child3) # bad inserts @@ -1143,11 +1198,13 @@ class SpinboxTest(EntryTest, unittest.TestCase): OPTIONS = ( 'background', 'class', 'command', 'cursor', 'exportselection', 'font', 'foreground', 'format', 'from', 'increment', - 'invalidcommand', 'justify', 'show', 'state', 'style', + 'invalidcommand', 'justify', + 'placeholder', 'placeholderforeground', + 'show', 'state', 'style', 'takefocus', 'textvariable', 'to', 'validate', 'validatecommand', 'values', 'width', 'wrap', 'xscrollcommand', ) - IDENTIFY_AS = 'Spinbox.field' if sys.platform == 'darwin' else 'textarea' + IDENTIFY_AS = {'Spinbox.field', 'textarea'} def setUp(self): super().setUp() @@ -1317,8 +1374,9 @@ def test_configure_values(self): class TreeviewTest(AbstractWidgetTest, unittest.TestCase): OPTIONS = ( 'class', 'columns', 'cursor', 'displaycolumns', - 'height', 'padding', 'selectmode', 'show', - 'style', 'takefocus', 'xscrollcommand', 'yscrollcommand', + 'height', 'padding', 'selectmode', 'selecttype', 'show', 'striped', + 'style', 'takefocus', 'titlecolumns', 'titleitems', + 'xscrollcommand', 'yscrollcommand', ) def setUp(self): @@ -1333,7 +1391,8 @@ def test_configure_columns(self): self.checkParam(widget, 'columns', 'a b c', expected=('a', 'b', 'c')) self.checkParam(widget, 'columns', ('a', 'b', 'c')) - self.checkParam(widget, 'columns', '') + self.checkParam(widget, 'columns', '', + expected=() if tk_version >= (8, 7) else '') def test_configure_displaycolumns(self): widget = self.create() @@ -1345,11 +1404,12 @@ def test_configure_displaycolumns(self): expected=('#all',)) self.checkParam(widget, 'displaycolumns', (2, 1, 0)) self.checkInvalidParam(widget, 'displaycolumns', ('a', 'b', 'd'), - errmsg='Invalid column index d') + errmsg='Invalid column index "?d"?') + errmsg = 'Column index "?{}"? out of bounds' self.checkInvalidParam(widget, 'displaycolumns', (1, 2, 3), - errmsg='Column index 3 out of bounds') + errmsg=errmsg.format(3)) self.checkInvalidParam(widget, 'displaycolumns', (1, -2), - errmsg='Column index -2 out of bounds') + errmsg=errmsg.format(-2)) def test_configure_height(self): widget = self.create() @@ -1361,6 +1421,11 @@ def test_configure_selectmode(self): self.checkEnumParam(widget, 'selectmode', 'none', 'browse', 'extended') + @requires_tk(8, 7) + def test_configure_selecttype(self): + widget = self.create() + self.checkEnumParam(widget, 'selecttype', 'item', 'cell') + def test_configure_show(self): widget = self.create() self.checkParam(widget, 'show', 'tree headings', @@ -1370,6 +1435,23 @@ def test_configure_show(self): self.checkParam(widget, 'show', 'tree', expected=('tree',)) self.checkParam(widget, 'show', 'headings', expected=('headings',)) + @requires_tk(8, 7) + def test_configure_striped(self): + widget = self.create() + self.checkBooleanParam(widget, 'striped') + + @requires_tk(8, 7) + def test_configure_titlecolumns(self): + widget = self.create() + self.checkIntegerParam(widget, 'titlecolumns', 0, 1, 5) + self.checkInvalidParam(widget, 'titlecolumns', -2) + + @requires_tk(8, 7) + def test_configure_titleitems(self): + widget = self.create() + self.checkIntegerParam(widget, 'titleitems', 0, 1, 5) + self.checkInvalidParam(widget, 'titleitems', -2) + def test_bbox(self): self.tv.pack() self.assertEqual(self.tv.bbox(''), '') diff --git a/Lib/test/test_type_aliases.py b/Lib/test/test_type_aliases.py index f8b395fd..4c17933e 100644 --- a/Lib/test/test_type_aliases.py +++ b/Lib/test/test_type_aliases.py @@ -212,6 +212,19 @@ def test_generic(self): self.assertEqual(TA.__value__, list[T]) self.assertEqual(TA.__type_params__, (T,)) self.assertEqual(TA.__module__, __name__) + self.assertIs(type(TA[int]), types.GenericAlias) + + def test_not_generic(self): + TA = TypeAliasType("TA", list[int], type_params=()) + self.assertEqual(TA.__name__, "TA") + self.assertEqual(TA.__value__, list[int]) + self.assertEqual(TA.__type_params__, ()) + self.assertEqual(TA.__module__, __name__) + with self.assertRaisesRegex( + TypeError, + "Only generic type aliases are subscriptable", + ): + TA[int] def test_keywords(self): TA = TypeAliasType(name="TA", value=int) diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py index eae91690..51055dd9 100644 --- a/Lib/test/test_type_params.py +++ b/Lib/test/test_type_params.py @@ -882,6 +882,7 @@ class C[T](Base, a=1, b=2, **kwargs): T, = C.__type_params__ self.assertEqual(T.__name__, "T") self.assertEqual(C.kwargs, {"a": 1, "b": 2, "c": 3}) + self.assertEqual(C.__bases__, (Base, Generic)) bases = (Base,) class C2[T](*bases, **kwargs): @@ -890,6 +891,22 @@ class C2[T](*bases, **kwargs): T, = C2.__type_params__ self.assertEqual(T.__name__, "T") self.assertEqual(C2.kwargs, {"c": 3}) + self.assertEqual(C2.__bases__, (Base, Generic)) + + def test_starargs_base(self): + class C1[T](*()): pass + + T, = C1.__type_params__ + self.assertEqual(T.__name__, "T") + self.assertEqual(C1.__bases__, (Generic,)) + + class Base: pass + bases = [Base] + class C2[T](*bases): pass + + T, = C2.__type_params__ + self.assertEqual(T.__name__, "T") + self.assertEqual(C2.__bases__, (Base, Generic)) class TypeParamsTraditionalTypeVarsTest(unittest.TestCase): diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index 5ffe4085..9b2a5728 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -1,6 +1,10 @@ # Python test set -- part 6, built-in types -from test.support import run_with_locale, cpython_only, MISSING_C_DOCSTRINGS +from test.support import ( + run_with_locale, cpython_only, iter_builtin_types, iter_slot_wrappers, + MISSING_C_DOCSTRINGS, +) +from test.test_import import no_rerun import collections.abc from collections import namedtuple import copy @@ -9,6 +13,7 @@ import pickle import locale import sys +import textwrap import types import unittest.mock import weakref @@ -392,7 +397,7 @@ def test(i, format_spec, result): test(123456, "1=20", '11111111111111123456') test(123456, "*=20", '**************123456') - @run_with_locale('LC_NUMERIC', 'en_US.UTF8') + @run_with_locale('LC_NUMERIC', 'en_US.UTF8', '') def test_float__format__locale(self): # test locale support for __format__ code 'n' @@ -401,7 +406,7 @@ def test_float__format__locale(self): self.assertEqual(locale.format_string('%g', x, grouping=True), format(x, 'n')) self.assertEqual(locale.format_string('%.10g', x, grouping=True), format(x, '.10n')) - @run_with_locale('LC_NUMERIC', 'en_US.UTF8') + @run_with_locale('LC_NUMERIC', 'en_US.UTF8', '') def test_int__format__locale(self): # test locale support for __format__ code 'n' for integers @@ -2252,5 +2257,51 @@ def coro(): 'close', 'throw'})) +class SubinterpreterTests(unittest.TestCase): + + @classmethod + def setUpClass(cls): + global interpreters + try: + from test.support import interpreters + except ModuleNotFoundError: + raise unittest.SkipTest('subinterpreters required') + + @cpython_only + @no_rerun('channels (and queues) might have a refleak; see gh-122199') + def test_static_types_inherited_slots(self): + rch, sch = interpreters.create_channel() + + slots = [] + script = '' + for cls in iter_builtin_types(): + for slot, own in iter_slot_wrappers(cls): + slots.append((cls, slot, own)) + attr = f'{cls.__name__}.{slot}' + script += textwrap.dedent(f""" + sch.send_nowait('{attr}: ' + repr({attr})) + """) + + exec(script) + all_expected = [] + for cls, slot, _ in slots: + result = rch.recv() + assert result.startswith(f'{cls.__name__}.{slot}: '), (cls, slot, result) + all_expected.append(result) + + interp = interpreters.create() + interp.run(textwrap.dedent(f""" + from test.support import interpreters + sch = interpreters.SendChannel({sch.id}) + """)) + interp.run(script) + + for i, (cls, slot, _) in enumerate(slots): + with self.subTest(cls=cls, slot=slot): + expected = all_expected[i] + result = rch.recv() + self.assertEqual(result, expected) + + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 4cf8d498..0e533757 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -579,6 +579,41 @@ def test_constructor(self): self.assertEqual(T.__name__, "T") self.assertEqual(T.__constraints__, ()) self.assertIs(T.__bound__, None) + self.assertIs(T.__covariant__, False) + self.assertIs(T.__contravariant__, False) + self.assertIs(T.__infer_variance__, False) + + T = TypeVar(name="T", bound=type) + self.assertEqual(T.__name__, "T") + self.assertEqual(T.__constraints__, ()) + self.assertIs(T.__bound__, type) + self.assertIs(T.__covariant__, False) + self.assertIs(T.__contravariant__, False) + self.assertIs(T.__infer_variance__, False) + + T = TypeVar(name="T", covariant=True) + self.assertEqual(T.__name__, "T") + self.assertEqual(T.__constraints__, ()) + self.assertIs(T.__bound__, None) + self.assertIs(T.__covariant__, True) + self.assertIs(T.__contravariant__, False) + self.assertIs(T.__infer_variance__, False) + + T = TypeVar(name="T", contravariant=True) + self.assertEqual(T.__name__, "T") + self.assertEqual(T.__constraints__, ()) + self.assertIs(T.__bound__, None) + self.assertIs(T.__covariant__, False) + self.assertIs(T.__contravariant__, True) + self.assertIs(T.__infer_variance__, False) + + T = TypeVar(name="T", infer_variance=True) + self.assertEqual(T.__name__, "T") + self.assertEqual(T.__constraints__, ()) + self.assertIs(T.__bound__, None) + self.assertIs(T.__covariant__, False) + self.assertIs(T.__contravariant__, False) + self.assertIs(T.__infer_variance__, True) def template_replace(templates: list[str], replacements: dict[str, list[str]]) -> list[tuple[str]]: @@ -3963,6 +3998,9 @@ class CustomProtocol(TestCase, Protocol): class CustomContextManager(typing.ContextManager, Protocol): pass + class CustomAsyncIterator(typing.AsyncIterator, Protocol): + pass + def test_non_runtime_protocol_isinstance_check(self): class P(Protocol): x: int @@ -4531,20 +4569,30 @@ def f(x: X): ... {'x': list[list[ForwardRef('X')]]} ) - def test_pep695_generic_with_future_annotations(self): + def test_pep695_generic_class_with_future_annotations(self): + original_globals = dict(ann_module695.__dict__) + hints_for_A = get_type_hints(ann_module695.A) A_type_params = ann_module695.A.__type_params__ self.assertIs(hints_for_A["x"], A_type_params[0]) self.assertEqual(hints_for_A["y"].__args__[0], Unpack[A_type_params[1]]) self.assertIs(hints_for_A["z"].__args__[0], A_type_params[2]) + # should not have changed as a result of the get_type_hints() calls! + self.assertEqual(ann_module695.__dict__, original_globals) + + def test_pep695_generic_class_with_future_annotations_and_local_shadowing(self): hints_for_B = get_type_hints(ann_module695.B) - self.assertEqual(hints_for_B.keys(), {"x", "y", "z"}) + self.assertEqual(hints_for_B, {"x": int, "y": str, "z": bytes}) + + def test_pep695_generic_class_with_future_annotations_name_clash_with_global_vars(self): + hints_for_C = get_type_hints(ann_module695.C) self.assertEqual( - set(hints_for_B.values()) ^ set(ann_module695.B.__type_params__), - set() + set(hints_for_C.values()), + set(ann_module695.C.__type_params__) ) + def test_pep_695_generic_function_with_future_annotations(self): hints_for_generic_function = get_type_hints(ann_module695.generic_function) func_t_params = ann_module695.generic_function.__type_params__ self.assertEqual( @@ -4555,6 +4603,54 @@ def test_pep695_generic_with_future_annotations(self): self.assertIs(hints_for_generic_function["z"].__origin__, func_t_params[2]) self.assertIs(hints_for_generic_function["zz"].__origin__, func_t_params[2]) + def test_pep_695_generic_function_with_future_annotations_name_clash_with_global_vars(self): + self.assertEqual( + set(get_type_hints(ann_module695.generic_function_2).values()), + set(ann_module695.generic_function_2.__type_params__) + ) + + def test_pep_695_generic_method_with_future_annotations(self): + hints_for_generic_method = get_type_hints(ann_module695.D.generic_method) + params = { + param.__name__: param + for param in ann_module695.D.generic_method.__type_params__ + } + self.assertEqual( + hints_for_generic_method, + {"x": params["Foo"], "y": params["Bar"], "return": types.NoneType} + ) + + def test_pep_695_generic_method_with_future_annotations_name_clash_with_global_vars(self): + self.assertEqual( + set(get_type_hints(ann_module695.D.generic_method_2).values()), + set(ann_module695.D.generic_method_2.__type_params__) + ) + + def test_pep_695_generics_with_future_annotations_nested_in_function(self): + results = ann_module695.nested() + + self.assertEqual( + set(results.hints_for_E.values()), + set(results.E.__type_params__) + ) + self.assertEqual( + set(results.hints_for_E_meth.values()), + set(results.E.generic_method.__type_params__) + ) + self.assertNotEqual( + set(results.hints_for_E_meth.values()), + set(results.E.__type_params__) + ) + self.assertEqual( + set(results.hints_for_E_meth.values()).intersection(results.E.__type_params__), + set() + ) + + self.assertEqual( + set(results.hints_for_generic_func.values()), + set(results.generic_func.__type_params__) + ) + def test_extended_generic_rules_subclassing(self): class T1(Tuple[T, KT]): ... class T2(Tuple[T, ...]): ... diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index e43be357..19556eec 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -1676,7 +1676,7 @@ def test_startswith_endswith_errors(self): self.assertIn('str', exc) self.assertIn('tuple', exc) - @support.run_with_locale('LC_ALL', 'de_DE', 'fr_FR') + @support.run_with_locale('LC_ALL', 'de_DE', 'fr_FR', '') def test_format_float(self): # should not format with a comma, but always with C locale self.assertEqual('1.0', '%.1f' % 1.0) diff --git a/Lib/test/test_unittest/test_case.py b/Lib/test/test_unittest/test_case.py index ed5eb560..82a442a0 100644 --- a/Lib/test/test_unittest/test_case.py +++ b/Lib/test/test_unittest/test_case.py @@ -1132,6 +1132,8 @@ def testAssertMultiLineEqual(self): # need to remove the first line of the error message error = str(e).split('\n', 1)[1] self.assertEqual(sample_text_error, error) + else: + self.fail(f'{self.failureException} not raised') def testAssertEqualSingleLine(self): sample_text = "laden swallows fly slowly" @@ -1148,6 +1150,8 @@ def testAssertEqualSingleLine(self): # need to remove the first line of the error message error = str(e).split('\n', 1)[1] self.assertEqual(sample_text_error, error) + else: + self.fail(f'{self.failureException} not raised') def testAssertEqualwithEmptyString(self): '''Verify when there is an empty string involved, the diff output @@ -1165,6 +1169,8 @@ def testAssertEqualwithEmptyString(self): # need to remove the first line of the error message error = str(e).split('\n', 1)[1] self.assertEqual(sample_text_error, error) + else: + self.fail(f'{self.failureException} not raised') def testAssertEqualMultipleLinesMissingNewlineTerminator(self): '''Verifying format of diff output from assertEqual involving strings @@ -1185,6 +1191,8 @@ def testAssertEqualMultipleLinesMissingNewlineTerminator(self): # need to remove the first line of the error message error = str(e).split('\n', 1)[1] self.assertEqual(sample_text_error, error) + else: + self.fail(f'{self.failureException} not raised') def testAssertEqualMultipleLinesMismatchedNewlinesTerminators(self): '''Verifying format of diff output from assertEqual involving strings @@ -1208,6 +1216,8 @@ def testAssertEqualMultipleLinesMismatchedNewlinesTerminators(self): # need to remove the first line of the error message error = str(e).split('\n', 1)[1] self.assertEqual(sample_text_error, error) + else: + self.fail(f'{self.failureException} not raised') def testEqualityBytesWarning(self): if sys.flags.bytes_warning: diff --git a/Lib/test/test_unittest/test_util.py b/Lib/test/test_unittest/test_util.py new file mode 100644 index 00000000..d590a333 --- /dev/null +++ b/Lib/test/test_unittest/test_util.py @@ -0,0 +1,33 @@ +import unittest +from unittest.util import safe_repr, sorted_list_difference, unorderable_list_difference + + +class TestUtil(unittest.TestCase): + def test_safe_repr(self): + class RaisingRepr: + def __repr__(self): + raise ValueError("Invalid repr()") + + class LongRepr: + def __repr__(self): + return 'x' * 100 + + safe_repr(RaisingRepr()) + self.assertEqual(safe_repr('foo'), "'foo'") + self.assertEqual(safe_repr(LongRepr(), short=True), 'x'*80 + ' [truncated]...') + + def test_sorted_list_difference(self): + self.assertEqual(sorted_list_difference([], []), ([], [])) + self.assertEqual(sorted_list_difference([1, 2], [2, 3]), ([1], [3])) + self.assertEqual(sorted_list_difference([1, 2], [1, 3]), ([2], [3])) + self.assertEqual(sorted_list_difference([1, 1, 1], [1, 2, 3]), ([], [2, 3])) + self.assertEqual(sorted_list_difference([4], [1, 2, 3, 4]), ([], [1, 2, 3])) + self.assertEqual(sorted_list_difference([1, 1], [2]), ([1], [2])) + self.assertEqual(sorted_list_difference([2], [1, 1]), ([2], [1])) + self.assertEqual(sorted_list_difference([1, 2], [1, 1]), ([2], [])) + + def test_unorderable_list_difference(self): + self.assertEqual(unorderable_list_difference([], []), ([], [])) + self.assertEqual(unorderable_list_difference([1, 2], []), ([2, 1], [])) + self.assertEqual(unorderable_list_difference([], [1, 2]), ([], [1, 2])) + self.assertEqual(unorderable_list_difference([1, 2], [1, 3]), ([2], [3])) diff --git a/Lib/test/test_unittest/testmock/support.py b/Lib/test/test_unittest/testmock/support.py index 49986d65..6c535b79 100644 --- a/Lib/test/test_unittest/testmock/support.py +++ b/Lib/test/test_unittest/testmock/support.py @@ -14,3 +14,14 @@ def wibble(self): pass class X(object): pass + +# A standin for weurkzeug.local.LocalProxy - issue 119600 +def _inaccessible(*args, **kwargs): + raise AttributeError + + +class OpaqueProxy: + __getattribute__ = _inaccessible + + +g = OpaqueProxy() diff --git a/Lib/test/test_unittest/testmock/testhelpers.py b/Lib/test/test_unittest/testmock/testhelpers.py index 74785a83..c9c20f00 100644 --- a/Lib/test/test_unittest/testmock/testhelpers.py +++ b/Lib/test/test_unittest/testmock/testhelpers.py @@ -1127,6 +1127,14 @@ def test_propertymock_side_effect(self): p.assert_called_once_with() + def test_propertymock_attach(self): + m = Mock() + p = PropertyMock() + type(m).foo = p + m.attach_mock(p, 'foo') + self.assertEqual(m.mock_calls, []) + + class TestCallablePredicate(unittest.TestCase): def test_type(self): diff --git a/Lib/test/test_unittest/testmock/testmagicmethods.py b/Lib/test/test_unittest/testmock/testmagicmethods.py index a4feae7e..a8b52ce4 100644 --- a/Lib/test/test_unittest/testmock/testmagicmethods.py +++ b/Lib/test/test_unittest/testmock/testmagicmethods.py @@ -331,6 +331,45 @@ def test_magic_methods_fspath(self): self.assertEqual(os.fspath(mock), expected_path) mock.__fspath__.assert_called_once() + def test_magic_mock_does_not_reset_magic_returns(self): + # https://github.com/python/cpython/issues/123934 + for reset in (True, False): + with self.subTest(reset=reset): + mm = MagicMock() + self.assertIs(type(mm.__str__()), str) + mm.__str__.assert_called_once() + + self.assertIs(type(mm.__hash__()), int) + mm.__hash__.assert_called_once() + + for _ in range(3): + # Repeat reset several times to be sure: + mm.reset_mock(return_value=reset) + + self.assertIs(type(mm.__str__()), str) + mm.__str__.assert_called_once() + + self.assertIs(type(mm.__hash__()), int) + mm.__hash__.assert_called_once() + + def test_magic_mock_resets_manual_mocks(self): + mm = MagicMock() + mm.__iter__ = MagicMock(return_value=iter([1])) + mm.custom = MagicMock(return_value=2) + self.assertEqual(list(iter(mm)), [1]) + self.assertEqual(mm.custom(), 2) + + mm.reset_mock(return_value=True) + self.assertEqual(list(iter(mm)), []) + self.assertIsInstance(mm.custom(), MagicMock) + + def test_magic_mock_resets_manual_mocks_empty_iter(self): + mm = MagicMock() + mm.__iter__.return_value = [] + self.assertEqual(list(iter(mm)), []) + + mm.reset_mock(return_value=True) + self.assertEqual(list(iter(mm)), []) def test_magic_methods_and_spec(self): class Iterable(object): diff --git a/Lib/test/test_unittest/testmock/testmock.py b/Lib/test/test_unittest/testmock/testmock.py index 165e2c04..1eb1a1bf 100644 --- a/Lib/test/test_unittest/testmock/testmock.py +++ b/Lib/test/test_unittest/testmock/testmock.py @@ -118,6 +118,11 @@ def test_create_autospec_should_be_configurable_by_kwargs(self): # pass kwargs with respect to the parent mock. self.assertEqual(class_mock().return_value.meth.side_effect, None) + def test_create_autospec_correctly_handles_name(self): + class X: ... + mock = create_autospec(X, spec_set=True, name="Y") + self.assertEqual(mock._mock_name, "Y") + def test_repr(self): mock = Mock(name='foo') self.assertIn('foo', repr(mock)) diff --git a/Lib/test/test_unittest/testmock/testpatch.py b/Lib/test/test_unittest/testmock/testpatch.py index be75fda7..037c021e 100644 --- a/Lib/test/test_unittest/testmock/testpatch.py +++ b/Lib/test/test_unittest/testmock/testpatch.py @@ -745,6 +745,54 @@ def test_stop_idempotent(self): self.assertIsNone(patcher.stop()) + def test_exit_idempotent(self): + patcher = patch(foo_name, 'bar', 3) + with patcher: + patcher.stop() + + + def test_second_start_failure(self): + patcher = patch(foo_name, 'bar', 3) + patcher.start() + try: + self.assertRaises(RuntimeError, patcher.start) + finally: + patcher.stop() + + + def test_second_enter_failure(self): + patcher = patch(foo_name, 'bar', 3) + with patcher: + self.assertRaises(RuntimeError, patcher.start) + + + def test_second_start_after_stop(self): + patcher = patch(foo_name, 'bar', 3) + patcher.start() + patcher.stop() + patcher.start() + patcher.stop() + + + def test_property_setters(self): + mock_object = Mock() + mock_bar = mock_object.bar + patcher = patch.object(mock_object, 'bar', 'x') + with patcher: + self.assertEqual(patcher.is_local, False) + self.assertIs(patcher.target, mock_object) + self.assertEqual(patcher.temp_original, mock_bar) + patcher.is_local = True + patcher.target = mock_bar + patcher.temp_original = mock_object + self.assertEqual(patcher.is_local, True) + self.assertIs(patcher.target, mock_bar) + self.assertEqual(patcher.temp_original, mock_object) + # if changes are left intact, they may lead to disruption as shown below (it might be what someone needs though) + self.assertEqual(mock_bar.bar, mock_object) + self.assertEqual(mock_object.bar, 'x') + + def test_patchobject_start_stop(self): original = something patcher = patch.object(PTModule, 'something', 'foo') @@ -1098,7 +1146,7 @@ def test_new_callable_patch(self): self.assertIsNot(m1, m2) for mock in m1, m2: - self.assertNotCallable(m1) + self.assertNotCallable(mock) def test_new_callable_patch_object(self): @@ -1111,7 +1159,7 @@ def test_new_callable_patch_object(self): self.assertIsNot(m1, m2) for mock in m1, m2: - self.assertNotCallable(m1) + self.assertNotCallable(mock) def test_new_callable_keyword_arguments(self): @@ -2045,6 +2093,13 @@ def test(): pass with self.assertRaises(TypeError): test() + def test_patch_proxy_object(self): + @patch("test.test_unittest.testmock.support.g", new_callable=MagicMock()) + def test(_): + pass + + test() + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_unpack_ex.py b/Lib/test/test_unpack_ex.py index c201d08f..9e2d54bd 100644 --- a/Lib/test/test_unpack_ex.py +++ b/Lib/test/test_unpack_ex.py @@ -26,6 +26,12 @@ >>> a == [7, 8, 9] True +Unpack nested implied tuple + + >>> [*[*a]] = [[7,8,9]] + >>> a == [[7,8,9]] + True + Unpack string... fun! >>> a, *b = 'one' diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py index 2df74f5e..0710950e 100644 --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -19,7 +19,6 @@ ssl = None import sys import tempfile -from nturl2path import url2pathname, pathname2url from base64 import b64encode import collections @@ -719,10 +718,6 @@ def tearDown(self): def constructLocalFileUrl(self, filePath): filePath = os.path.abspath(filePath) - try: - filePath.encode("utf-8") - except UnicodeEncodeError: - raise unittest.SkipTest("filePath is not encodable to utf8") return "file://%s" % urllib.request.pathname2url(filePath) def createNewTempFile(self, data=b""): @@ -1529,39 +1524,119 @@ def test_quoting(self): (expect, result)) @unittest.skipUnless(sys.platform == 'win32', - 'test specific to the nturl2path functions.') - def test_prefixes(self): + 'test specific to Windows pathnames.') + def test_pathname2url_win(self): # Test special prefixes are correctly handled in pathname2url() - given = '\\\\?\\C:\\dir' - expect = '///C:/dir' - result = urllib.request.pathname2url(given) - self.assertEqual(expect, result, - "pathname2url() failed; %s != %s" % - (expect, result)) - given = '\\\\?\\unc\\server\\share\\dir' - expect = '/server/share/dir' - result = urllib.request.pathname2url(given) - self.assertEqual(expect, result, - "pathname2url() failed; %s != %s" % - (expect, result)) - + fn = urllib.request.pathname2url + self.assertEqual(fn('\\\\?\\C:\\dir'), '///C:/dir') + self.assertEqual(fn('\\\\?\\unc\\server\\share\\dir'), '//server/share/dir') + self.assertEqual(fn("C:"), '///C:') + self.assertEqual(fn("C:\\"), '///C:/') + self.assertEqual(fn('C:\\a\\b.c'), '///C:/a/b.c') + self.assertEqual(fn('C:\\a\\b.c\\'), '///C:/a/b.c/') + self.assertEqual(fn('C:\\a\\\\b.c'), '///C:/a//b.c') + self.assertEqual(fn('C:\\a\\b%#c'), '///C:/a/b%25%23c') + self.assertEqual(fn('C:\\a\\b\xe9'), '///C:/a/b%C3%A9') + self.assertEqual(fn('C:\\foo\\bar\\spam.foo'), "///C:/foo/bar/spam.foo") + # Long drive letter + self.assertRaises(IOError, fn, "XX:\\") + # No drive letter + self.assertEqual(fn("\\folder\\test\\"), '/folder/test/') + self.assertEqual(fn("\\\\folder\\test\\"), '//folder/test/') + self.assertEqual(fn("\\\\\\folder\\test\\"), '///folder/test/') + self.assertEqual(fn('\\\\some\\share\\'), '//some/share/') + self.assertEqual(fn('\\\\some\\share\\a\\b.c'), '//some/share/a/b.c') + self.assertEqual(fn('\\\\some\\share\\a\\b%#c\xe9'), '//some/share/a/b%25%23c%C3%A9') + # Alternate path separator + self.assertEqual(fn('C:/a/b.c'), '///C:/a/b.c') + self.assertEqual(fn('//some/share/a/b.c'), '//some/share/a/b.c') + self.assertEqual(fn('//?/C:/dir'), '///C:/dir') + self.assertEqual(fn('//?/unc/server/share/dir'), '//server/share/dir') + # Round-tripping + urls = ['///C:', + '/folder/test/', + '///C:/foo/bar/spam.foo'] + for url in urls: + self.assertEqual(fn(urllib.request.url2pathname(url)), url) + + @unittest.skipIf(sys.platform == 'win32', + 'test specific to POSIX pathnames') + def test_pathname2url_posix(self): + fn = urllib.request.pathname2url + self.assertEqual(fn('/'), '/') + self.assertEqual(fn('/a/b.c'), '/a/b.c') + self.assertEqual(fn('//a/b.c'), '////a/b.c') + self.assertEqual(fn('///a/b.c'), '/////a/b.c') + self.assertEqual(fn('////a/b.c'), '//////a/b.c') + self.assertEqual(fn('/a/b%#c'), '/a/b%25%23c') + + @unittest.skipUnless(os_helper.FS_NONASCII, 'need os_helper.FS_NONASCII') + def test_pathname2url_nonascii(self): + encoding = sys.getfilesystemencoding() + errors = sys.getfilesystemencodeerrors() + url = urllib.parse.quote(os_helper.FS_NONASCII, encoding=encoding, errors=errors) + self.assertEqual(urllib.request.pathname2url(os_helper.FS_NONASCII), url) @unittest.skipUnless(sys.platform == 'win32', - 'test specific to the urllib.url2path function.') - def test_ntpath(self): - given = ('/C:/', '///C:/', '/C|//') - expect = 'C:\\' - for url in given: - result = urllib.request.url2pathname(url) - self.assertEqual(expect, result, - 'urllib.request..url2pathname() failed; %s != %s' % - (expect, result)) - given = '///C|/path' - expect = 'C:\\path' - result = urllib.request.url2pathname(given) - self.assertEqual(expect, result, - 'urllib.request.url2pathname() failed; %s != %s' % - (expect, result)) + 'test specific to Windows pathnames.') + def test_url2pathname_win(self): + fn = urllib.request.url2pathname + self.assertEqual(fn('/C:/'), 'C:\\') + self.assertEqual(fn("///C|"), 'C:') + self.assertEqual(fn("///C:"), 'C:') + self.assertEqual(fn('///C:/'), 'C:\\') + self.assertEqual(fn('/C|//'), 'C:\\\\') + self.assertEqual(fn('///C|/path'), 'C:\\path') + # No DOS drive + self.assertEqual(fn("///C/test/"), '\\C\\test\\') + self.assertEqual(fn("////C/test/"), '\\\\C\\test\\') + # DOS drive paths + self.assertEqual(fn('C:/path/to/file'), 'C:\\path\\to\\file') + self.assertEqual(fn('C:/path/to/file/'), 'C:\\path\\to\\file\\') + self.assertEqual(fn('C:/path/to//file'), 'C:\\path\\to\\\\file') + self.assertEqual(fn('C|/path/to/file'), 'C:\\path\\to\\file') + self.assertEqual(fn('/C|/path/to/file'), 'C:\\path\\to\\file') + self.assertEqual(fn('///C|/path/to/file'), 'C:\\path\\to\\file') + self.assertEqual(fn("///C|/foo/bar/spam.foo"), 'C:\\foo\\bar\\spam.foo') + # Non-ASCII drive letter + self.assertRaises(IOError, fn, "///\u00e8|/") + # UNC paths + self.assertEqual(fn('//server/path/to/file'), '\\\\server\\path\\to\\file') + self.assertEqual(fn('////server/path/to/file'), '\\\\server\\path\\to\\file') + self.assertEqual(fn('/////server/path/to/file'), '\\\\server\\path\\to\\file') + # Localhost paths + self.assertEqual(fn('//localhost/C:/path/to/file'), 'C:\\path\\to\\file') + self.assertEqual(fn('//localhost/C|/path/to/file'), 'C:\\path\\to\\file') + self.assertEqual(fn('//localhost/path/to/file'), '\\path\\to\\file') + self.assertEqual(fn('//localhost//server/path/to/file'), '\\\\server\\path\\to\\file') + # Percent-encoded forward slashes are preserved for backwards compatibility + self.assertEqual(fn('C:/foo%2fbar'), 'C:\\foo/bar') + self.assertEqual(fn('//server/share/foo%2fbar'), '\\\\server\\share\\foo/bar') + # Round-tripping + paths = ['C:', + r'\C\test\\', + r'C:\foo\bar\spam.foo'] + for path in paths: + self.assertEqual(fn(urllib.request.pathname2url(path)), path) + + @unittest.skipIf(sys.platform == 'win32', + 'test specific to POSIX pathnames') + def test_url2pathname_posix(self): + fn = urllib.request.url2pathname + self.assertEqual(fn('/foo/bar'), '/foo/bar') + self.assertEqual(fn('//foo/bar'), '//foo/bar') + self.assertEqual(fn('///foo/bar'), '/foo/bar') + self.assertEqual(fn('////foo/bar'), '//foo/bar') + self.assertEqual(fn('//localhost/foo/bar'), '/foo/bar') + + @unittest.skipUnless(os_helper.FS_NONASCII, 'need os_helper.FS_NONASCII') + def test_url2pathname_nonascii(self): + encoding = sys.getfilesystemencoding() + errors = sys.getfilesystemencodeerrors() + url = os_helper.FS_NONASCII + self.assertEqual(urllib.request.url2pathname(url), os_helper.FS_NONASCII) + url = urllib.parse.quote(url, encoding=encoding, errors=errors) + self.assertEqual(urllib.request.url2pathname(url), os_helper.FS_NONASCII) class Utility_Tests(unittest.TestCase): """Testcase to test the various utility functions in the urllib.""" @@ -1645,60 +1720,5 @@ def test_with_method_arg(self): self.assertEqual(request.get_method(), 'HEAD') -class URL2PathNameTests(unittest.TestCase): - - def test_converting_drive_letter(self): - self.assertEqual(url2pathname("///C|"), 'C:') - self.assertEqual(url2pathname("///C:"), 'C:') - self.assertEqual(url2pathname("///C|/"), 'C:\\') - - def test_converting_when_no_drive_letter(self): - # cannot end a raw string in \ - self.assertEqual(url2pathname("///C/test/"), r'\\\C\test' '\\') - self.assertEqual(url2pathname("////C/test/"), r'\\C\test' '\\') - - def test_simple_compare(self): - self.assertEqual(url2pathname("///C|/foo/bar/spam.foo"), - r'C:\foo\bar\spam.foo') - - def test_non_ascii_drive_letter(self): - self.assertRaises(IOError, url2pathname, "///\u00e8|/") - - def test_roundtrip_url2pathname(self): - list_of_paths = ['C:', - r'\\\C\test\\', - r'C:\foo\bar\spam.foo' - ] - for path in list_of_paths: - self.assertEqual(url2pathname(pathname2url(path)), path) - -class PathName2URLTests(unittest.TestCase): - - def test_converting_drive_letter(self): - self.assertEqual(pathname2url("C:"), '///C:') - self.assertEqual(pathname2url("C:\\"), '///C:') - - def test_converting_when_no_drive_letter(self): - self.assertEqual(pathname2url(r"\\\folder\test" "\\"), - '/////folder/test/') - self.assertEqual(pathname2url(r"\\folder\test" "\\"), - '////folder/test/') - self.assertEqual(pathname2url(r"\folder\test" "\\"), - '/folder/test/') - - def test_simple_compare(self): - self.assertEqual(pathname2url(r'C:\foo\bar\spam.foo'), - "///C:/foo/bar/spam.foo" ) - - def test_long_drive_letter(self): - self.assertRaises(IOError, pathname2url, "XX:\\") - - def test_roundtrip_pathname2url(self): - list_of_paths = ['///C:', - '/////folder/test/', - '///C:/foo/bar/spam.foo'] - for path in list_of_paths: - self.assertEqual(pathname2url(url2pathname(path)), path) - if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py index 69cf1dc7..12b1053a 100644 --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -716,10 +716,6 @@ def test_processors(self): def sanepathname2url(path): - try: - path.encode("utf-8") - except UnicodeEncodeError: - raise unittest.SkipTest("path is not encodable to utf8") urlpath = urllib.request.pathname2url(path) if os.name == "nt" and urlpath.startswith("///"): urlpath = urlpath[2:] diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py index 4faad733..818e7e93 100644 --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -207,6 +207,9 @@ def test_roundtrips(self): ('scheme://///path/to/file', ('scheme', '', '///path/to/file', '', '', ''), ('scheme', '', '///path/to/file', '', '')), + ('file:tmp/junk.txt', + ('file', '', 'tmp/junk.txt', '', '', ''), + ('file', '', 'tmp/junk.txt', '', '')), ('file:///tmp/junk.txt', ('file', '', '/tmp/junk.txt', '', '', ''), ('file', '', '/tmp/junk.txt', '', '')), @@ -216,6 +219,18 @@ def test_roundtrips(self): ('file://///tmp/junk.txt', ('file', '', '///tmp/junk.txt', '', '', ''), ('file', '', '///tmp/junk.txt', '', '')), + ('http:tmp/junk.txt', + ('http', '', 'tmp/junk.txt', '', '', ''), + ('http', '', 'tmp/junk.txt', '', '')), + ('http://example.com/tmp/junk.txt', + ('http', 'example.com', '/tmp/junk.txt', '', '', ''), + ('http', 'example.com', '/tmp/junk.txt', '', '')), + ('http:///example.com/tmp/junk.txt', + ('http', '', '/example.com/tmp/junk.txt', '', '', ''), + ('http', '', '/example.com/tmp/junk.txt', '', '')), + ('http:////example.com/tmp/junk.txt', + ('http', '', '//example.com/tmp/junk.txt', '', '', ''), + ('http', '', '//example.com/tmp/junk.txt', '', '')), ('imap://mail.python.org/mbox1', ('imap', 'mail.python.org', '/mbox1', '', '', ''), ('imap', 'mail.python.org', '/mbox1', '', '')), @@ -260,7 +275,8 @@ def _encode(t): ('', '', 'schème:path/to/file', '', '')), ] for url, parsed, split in str_cases + bytes_cases: - self.checkRoundtrips(url, parsed, split) + with self.subTest(url): + self.checkRoundtrips(url, parsed, split) def test_roundtrips_normalization(self): str_cases = [ @@ -292,7 +308,8 @@ def _encode(t): tuple(x.encode('ascii') for x in t[3])) bytes_cases = [_encode(x) for x in str_cases] for url, url2, parsed, split in str_cases + bytes_cases: - self.checkRoundtrips(url, parsed, split, url2) + with self.subTest(url): + self.checkRoundtrips(url, parsed, split, url2) def test_http_roundtrips(self): # urllib.parse.urlsplit treats 'http:' as an optimized special case, @@ -333,11 +350,17 @@ def _encode(t): self.checkRoundtrips(url, parsed, split) def checkJoin(self, base, relurl, expected): - str_components = (base, relurl, expected) - self.assertEqual(urllib.parse.urljoin(base, relurl), expected) - bytes_components = baseb, relurlb, expectedb = [ - x.encode('ascii') for x in str_components] - self.assertEqual(urllib.parse.urljoin(baseb, relurlb), expectedb) + with self.subTest(base=base, relurl=relurl): + self.assertEqual(urllib.parse.urljoin(base, relurl), expected) + baseb = base.encode('ascii') + relurlb = relurl.encode('ascii') + expectedb = expected.encode('ascii') + self.assertEqual(urllib.parse.urljoin(baseb, relurlb), expectedb) + + relurl = urllib.parse.urlunsplit(urllib.parse.urlsplit(relurl)) + self.assertEqual(urllib.parse.urljoin(base, relurl), expected) + relurlb = urllib.parse.urlunsplit(urllib.parse.urlsplit(relurlb)) + self.assertEqual(urllib.parse.urljoin(baseb, relurlb), expectedb) def test_unparse_parse(self): str_cases = ['Python', './Python','x-newscheme://foo.com/stuff','x://y','x:/y','x:/','/',] diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index feaf9784..8254a701 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -17,6 +17,7 @@ import sys import sysconfig import tempfile +import shlex from test.support import (captured_stdout, captured_stderr, skip_if_broken_multiprocessing_synchronize, verbose, requires_subprocess, is_emscripten, is_wasi, @@ -97,6 +98,10 @@ def get_text_file_contents(self, *args, encoding='utf-8'): result = f.read() return result + def assertEndsWith(self, string, tail): + if not string.endswith(tail): + self.fail(f"String {string!r} does not end with {tail!r}") + class BasicTest(BaseTest): """Test venv module functionality.""" @@ -446,6 +451,82 @@ def test_executable_symlinks(self): 'import sys; print(sys.executable)']) self.assertEqual(out.strip(), envpy.encode()) + # gh-124651: test quoted strings + @unittest.skipIf(os.name == 'nt', 'contains invalid characters on Windows') + def test_special_chars_bash(self): + """ + Test that the template strings are quoted properly (bash) + """ + rmtree(self.env_dir) + bash = shutil.which('bash') + if bash is None: + self.skipTest('bash required for this test') + env_name = '"\';&&$e|\'"' + env_dir = os.path.join(os.path.realpath(self.env_dir), env_name) + builder = venv.EnvBuilder(clear=True) + builder.create(env_dir) + activate = os.path.join(env_dir, self.bindir, 'activate') + test_script = os.path.join(self.env_dir, 'test_special_chars.sh') + with open(test_script, "w") as f: + f.write(f'source {shlex.quote(activate)}\n' + 'python -c \'import sys; print(sys.executable)\'\n' + 'python -c \'import os; print(os.environ["VIRTUAL_ENV"])\'\n' + 'deactivate\n') + out, err = check_output([bash, test_script]) + lines = out.splitlines() + self.assertTrue(env_name.encode() in lines[0]) + self.assertEndsWith(lines[1], env_name.encode()) + + # gh-124651: test quoted strings + @unittest.skipIf(os.name == 'nt', 'contains invalid characters on Windows') + def test_special_chars_csh(self): + """ + Test that the template strings are quoted properly (csh) + """ + rmtree(self.env_dir) + csh = shutil.which('tcsh') or shutil.which('csh') + if csh is None: + self.skipTest('csh required for this test') + env_name = '"\';&&$e|\'"' + env_dir = os.path.join(os.path.realpath(self.env_dir), env_name) + builder = venv.EnvBuilder(clear=True) + builder.create(env_dir) + activate = os.path.join(env_dir, self.bindir, 'activate.csh') + test_script = os.path.join(self.env_dir, 'test_special_chars.csh') + with open(test_script, "w") as f: + f.write(f'source {shlex.quote(activate)}\n' + 'python -c \'import sys; print(sys.executable)\'\n' + 'python -c \'import os; print(os.environ["VIRTUAL_ENV"])\'\n' + 'deactivate\n') + out, err = check_output([csh, test_script]) + lines = out.splitlines() + self.assertTrue(env_name.encode() in lines[0]) + self.assertEndsWith(lines[1], env_name.encode()) + + # gh-124651: test quoted strings on Windows + @unittest.skipUnless(os.name == 'nt', 'only relevant on Windows') + def test_special_chars_windows(self): + """ + Test that the template strings are quoted properly on Windows + """ + rmtree(self.env_dir) + env_name = "'&&^$e" + env_dir = os.path.join(os.path.realpath(self.env_dir), env_name) + builder = venv.EnvBuilder(clear=True) + builder.create(env_dir) + activate = os.path.join(env_dir, self.bindir, 'activate.bat') + test_batch = os.path.join(self.env_dir, 'test_special_chars.bat') + with open(test_batch, "w") as f: + f.write('@echo off\n' + f'"{activate}" & ' + f'{self.exe} -c "import sys; print(sys.executable)" & ' + f'{self.exe} -c "import os; print(os.environ[\'VIRTUAL_ENV\'])" & ' + 'deactivate') + out, err = check_output([test_batch]) + lines = out.splitlines() + self.assertTrue(env_name.encode() in lines[0]) + self.assertEndsWith(lines[1], env_name.encode()) + @unittest.skipUnless(os.name == 'nt', 'only relevant on Windows') def test_unicode_in_batch_file(self): """ @@ -782,6 +863,14 @@ def do_test_with_pip(self, system_site_packages): err = re.sub("^(WARNING: )?The directory .* or its parent directory " "is not owned or is not writable by the current user.*$", "", err, flags=re.MULTILINE) + # Ignore warning about missing optional module: + try: + import ssl + except ImportError: + err = re.sub( + "^WARNING: Disabling truststore since ssl support is missing$", + "", + err, flags=re.MULTILINE) self.assertEqual(err.rstrip(), "") # Being fairly specific regarding the expected behaviour for the # initial bundling phase in Python 3.4. If the output changes in diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py index 83237f5f..a86750ab 100644 --- a/Lib/test/test_warnings/__init__.py +++ b/Lib/test/test_warnings/__init__.py @@ -1,10 +1,12 @@ from contextlib import contextmanager import linecache import os +import importlib from io import StringIO import re import sys import textwrap +import types import unittest from test import support from test.support import import_helper @@ -610,6 +612,97 @@ class NonWarningSubclass: self.module.warn('good warning category', MyWarningClass) self.assertIsInstance(cm.warning, Warning) + def check_module_globals(self, module_globals): + with original_warnings.catch_warnings(module=self.module, record=True) as w: + self.module.filterwarnings('default') + self.module.warn_explicit( + 'eggs', UserWarning, 'bar', 1, + module_globals=module_globals) + self.assertEqual(len(w), 1) + self.assertEqual(w[0].category, UserWarning) + self.assertEqual(str(w[0].message), 'eggs') + + def check_module_globals_error(self, module_globals, errmsg, errtype=ValueError): + if self.module is py_warnings: + self.check_module_globals(module_globals) + return + with original_warnings.catch_warnings(module=self.module, record=True) as w: + self.module.filterwarnings('always') + with self.assertRaisesRegex(errtype, re.escape(errmsg)): + self.module.warn_explicit( + 'eggs', UserWarning, 'bar', 1, + module_globals=module_globals) + self.assertEqual(len(w), 0) + + def check_module_globals_deprecated(self, module_globals, msg): + if self.module is py_warnings: + self.check_module_globals(module_globals) + return + with original_warnings.catch_warnings(module=self.module, record=True) as w: + self.module.filterwarnings('always') + self.module.warn_explicit( + 'eggs', UserWarning, 'bar', 1, + module_globals=module_globals) + self.assertEqual(len(w), 2) + self.assertEqual(w[0].category, DeprecationWarning) + self.assertEqual(str(w[0].message), msg) + self.assertEqual(w[1].category, UserWarning) + self.assertEqual(str(w[1].message), 'eggs') + + def test_gh86298_no_loader_and_no_spec(self): + self.check_module_globals({'__name__': 'bar'}) + + def test_gh86298_loader_is_none_and_no_spec(self): + self.check_module_globals({'__name__': 'bar', '__loader__': None}) + + def test_gh86298_no_loader_and_spec_is_none(self): + self.check_module_globals_error( + {'__name__': 'bar', '__spec__': None}, + 'Module globals is missing a __spec__.loader') + + def test_gh86298_loader_is_none_and_spec_is_none(self): + self.check_module_globals_error( + {'__name__': 'bar', '__loader__': None, '__spec__': None}, + 'Module globals is missing a __spec__.loader') + + def test_gh86298_loader_is_none_and_spec_loader_is_none(self): + self.check_module_globals_error( + {'__name__': 'bar', '__loader__': None, + '__spec__': types.SimpleNamespace(loader=None)}, + 'Module globals is missing a __spec__.loader') + + def test_gh86298_no_spec(self): + self.check_module_globals_deprecated( + {'__name__': 'bar', '__loader__': object()}, + 'Module globals is missing a __spec__.loader') + + def test_gh86298_spec_is_none(self): + self.check_module_globals_deprecated( + {'__name__': 'bar', '__loader__': object(), '__spec__': None}, + 'Module globals is missing a __spec__.loader') + + def test_gh86298_no_spec_loader(self): + self.check_module_globals_deprecated( + {'__name__': 'bar', '__loader__': object(), + '__spec__': types.SimpleNamespace()}, + 'Module globals is missing a __spec__.loader') + + def test_gh86298_loader_and_spec_loader_disagree(self): + self.check_module_globals_deprecated( + {'__name__': 'bar', '__loader__': object(), + '__spec__': types.SimpleNamespace(loader=object())}, + 'Module globals; __loader__ != __spec__.loader') + + def test_gh86298_no_loader_and_no_spec_loader(self): + self.check_module_globals_error( + {'__name__': 'bar', '__spec__': types.SimpleNamespace()}, + 'Module globals is missing a __spec__.loader', AttributeError) + + def test_gh86298_no_loader_with_spec_loader_okay(self): + self.check_module_globals( + {'__name__': 'bar', + '__spec__': types.SimpleNamespace(loader=object())}) + class CWarnTests(WarnTests, unittest.TestCase): module = c_warnings @@ -858,37 +951,46 @@ def test_issue31285(self): # warn_explicit() should neither raise a SystemError nor cause an # assertion failure, in case the return value of get_source() has a # bad splitlines() method. - def get_bad_loader(splitlines_ret_val): + get_source_called = [] + def get_module_globals(*, splitlines_ret_val): + class BadSource(str): + def splitlines(self): + return splitlines_ret_val + class BadLoader: def get_source(self, fullname): - class BadSource(str): - def splitlines(self): - return splitlines_ret_val + get_source_called.append(splitlines_ret_val) return BadSource('spam') - return BadLoader() + + loader = BadLoader() + spec = importlib.machinery.ModuleSpec('foobar', loader) + return {'__loader__': loader, + '__spec__': spec, + '__name__': 'foobar'} + wmod = self.module with original_warnings.catch_warnings(module=wmod): wmod.filterwarnings('default', category=UserWarning) + linecache.clearcache() with support.captured_stderr() as stderr: wmod.warn_explicit( 'foo', UserWarning, 'bar', 1, - module_globals={'__loader__': get_bad_loader(42), - '__name__': 'foobar'}) + module_globals=get_module_globals(splitlines_ret_val=42)) self.assertIn('UserWarning: foo', stderr.getvalue()) + self.assertEqual(get_source_called, [42]) - show = wmod._showwarnmsg - try: + linecache.clearcache() + with support.swap_attr(wmod, '_showwarnmsg', None): del wmod._showwarnmsg with support.captured_stderr() as stderr: wmod.warn_explicit( 'eggs', UserWarning, 'bar', 1, - module_globals={'__loader__': get_bad_loader([42]), - '__name__': 'foobar'}) + module_globals=get_module_globals(splitlines_ret_val=[42])) self.assertIn('UserWarning: eggs', stderr.getvalue()) - finally: - wmod._showwarnmsg = show + self.assertEqual(get_source_called, [42, [42]]) + linecache.clearcache() @support.cpython_only def test_issue31411(self): diff --git a/Lib/test/test_winconsoleio.py b/Lib/test/test_winconsoleio.py index cf8b1058..459d2192 100644 --- a/Lib/test/test_winconsoleio.py +++ b/Lib/test/test_winconsoleio.py @@ -126,6 +126,29 @@ def test_write_empty_data(self): with ConIO('CONOUT$', 'w') as f: self.assertEqual(f.write(b''), 0) + @requires_resource('console') + def test_write(self): + testcases = [] + with ConIO('CONOUT$', 'w') as f: + for a in [ + b'', + b'abc', + b'\xc2\xa7\xe2\x98\x83\xf0\x9f\x90\x8d', + b'\xff'*10, + ]: + for b in b'\xc2\xa7', b'\xe2\x98\x83', b'\xf0\x9f\x90\x8d': + testcases.append(a + b) + for i in range(1, len(b)): + data = a + b[:i] + testcases.append(data + b'z') + testcases.append(data + b'\xff') + # incomplete multibyte sequence + with self.subTest(data=data): + self.assertEqual(f.write(data), len(a)) + for data in testcases: + with self.subTest(data=data): + self.assertEqual(f.write(data), len(data)) + def assertStdinRoundTrip(self, text): stdin = open('CONIN$', 'r') old_stdin = sys.stdin diff --git a/Lib/test/test_with.py b/Lib/test/test_with.py index d8190232..839cdec6 100644 --- a/Lib/test/test_with.py +++ b/Lib/test/test_with.py @@ -5,6 +5,7 @@ __email__ = "mbland at acm dot org" import sys +import traceback import unittest from collections import deque from contextlib import _GeneratorContextManager, contextmanager, nullcontext @@ -170,7 +171,10 @@ def __exit__(self, *args): def shouldThrow(): ct = EnterThrows() self.foo = None - with ct as self.foo: + # Ruff complains that we're redefining `self.foo` here, + # but the whole point of the test is to check that `self.foo` + # is *not* redefined (because `__enter__` raises) + with ct as self.foo: # ruff: noqa: F811 pass self.assertRaises(RuntimeError, shouldThrow) self.assertEqual(self.foo, None) @@ -251,7 +255,6 @@ def testInlineGeneratorBoundSyntax(self): self.assertAfterWithGeneratorInvariantsNoError(foo) def testInlineGeneratorBoundToExistingVariable(self): - foo = None with mock_contextmanager_generator() as foo: self.assertInWithGeneratorInvariants(foo) self.assertAfterWithGeneratorInvariantsNoError(foo) @@ -749,5 +752,48 @@ def testEnterReturnsTuple(self): self.assertEqual(10, b1) self.assertEqual(20, b2) + def testExceptionLocation(self): + # The location of an exception raised from + # __init__, __enter__ or __exit__ of a context + # manager should be just the context manager expression, + # pinpointing the precise context manager in case there + # is more than one. + + def init_raises(): + try: + with self.Dummy(), self.InitRaises() as cm, self.Dummy() as d: + pass + except Exception as e: + return e + + def enter_raises(): + try: + with self.EnterRaises(), self.Dummy() as d: + pass + except Exception as e: + return e + + def exit_raises(): + try: + with self.ExitRaises(), self.Dummy() as d: + pass + except Exception as e: + return e + + for func, expected in [(init_raises, "self.InitRaises()"), + (enter_raises, "self.EnterRaises()"), + (exit_raises, "self.ExitRaises()"), + ]: + with self.subTest(func): + exc = func() + f = traceback.extract_tb(exc.__traceback__)[0] + indent = 16 + co = func.__code__ + self.assertEqual(f.lineno, co.co_firstlineno + 2) + self.assertEqual(f.end_lineno, co.co_firstlineno + 2) + self.assertEqual(f.line[f.colno - indent : f.end_colno - indent], + expected) + + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py index 9c382d14..f8c2e5cc 100644 --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -2343,6 +2343,22 @@ def test_39495_treebuilder_start(self): self.assertRaises(TypeError, ET.TreeBuilder().start, "tag") self.assertRaises(TypeError, ET.TreeBuilder().start, "tag", None) + def test_issue123213_correct_extend_exception(self): + # Does not hide the internal exception when extending the element + self.assertRaises(ZeroDivisionError, ET.Element('tag').extend, + (1/0 for i in range(2))) + + # Still raises the TypeError when extending with a non-iterable + self.assertRaises(TypeError, ET.Element('tag').extend, None) + + # Preserves the TypeError message when extending with a generator + def f(): + raise TypeError("mymessage") + + self.assertRaisesRegex( + TypeError, 'mymessage', + ET.Element('tag').extend, (f() for i in range(2))) + # -------------------------------------------------------------------- @@ -3669,6 +3685,22 @@ def test_setslice_negative_steps(self): e[1::-sys.maxsize<<64] = [ET.Element('d')] self.assertEqual(self._subelem_tags(e), ['a0', 'd', 'a2', 'a3']) + def test_issue123213_setslice_exception(self): + e = ET.Element('tag') + # Does not hide the internal exception when assigning to the element + with self.assertRaises(ZeroDivisionError): + e[:1] = (1/0 for i in range(2)) + + # Still raises the TypeError when assigning with a non-iterable + with self.assertRaises(TypeError): + e[:1] = None + + # Preserve the original TypeError message when assigning. + def f(): + raise TypeError("mymessage") + + with self.assertRaisesRegex(TypeError, 'mymessage'): + e[:1] = (f() for i in range(2)) class IOTest(unittest.TestCase): def test_encoding(self): @@ -4009,7 +4041,7 @@ class BoolTest(unittest.TestCase): def test_warning(self): e = ET.fromstring('') msg = ( - r"Testing an element's truth value will raise an exception in " + r"Testing an element's truth value will always return True in " r"future versions. " r"Use specific 'len\(elem\)' or 'elem is not None' test instead.") with self.assertWarnsRegex(DeprecationWarning, msg): diff --git a/Lib/test/test_zipfile/_path/test_path.py b/Lib/test/test_zipfile/_path/test_path.py index 06d5aab6..616c4e8c 100644 --- a/Lib/test/test_zipfile/_path/test_path.py +++ b/Lib/test/test_zipfile/_path/test_path.py @@ -4,6 +4,7 @@ import pathlib import pickle import sys +import time import unittest import zipfile @@ -472,6 +473,18 @@ def test_glob_recursive(self, alpharep): assert list(root.glob("**/*.txt")) == list(root.rglob("*.txt")) + @pass_alpharep + def test_glob_dirs(self, alpharep): + root = zipfile.Path(alpharep) + assert list(root.glob('b')) == [zipfile.Path(alpharep, "b/")] + assert list(root.glob('b*')) == [zipfile.Path(alpharep, "b/")] + + @pass_alpharep + def test_glob_subdir(self, alpharep): + root = zipfile.Path(alpharep) + assert list(root.glob('g/h')) == [zipfile.Path(alpharep, "g/h/")] + assert list(root.glob('g*/h*')) == [zipfile.Path(alpharep, "g/h/")] + @pass_alpharep def test_glob_subdirs(self, alpharep): root = zipfile.Path(alpharep) @@ -577,3 +590,87 @@ def test_getinfo_missing(self, alpharep): zipfile.Path(alpharep) with self.assertRaises(KeyError): alpharep.getinfo('does-not-exist') + + def test_malformed_paths(self): + """ + Path should handle malformed paths gracefully. + + Paths with leading slashes are not visible. + + Paths with dots are treated like regular files. + """ + data = io.BytesIO() + zf = zipfile.ZipFile(data, "w") + zf.writestr("/one-slash.txt", b"content") + zf.writestr("//two-slash.txt", b"content") + zf.writestr("../parent.txt", b"content") + zf.filename = '' + root = zipfile.Path(zf) + assert list(map(str, root.iterdir())) == ['../'] + assert root.joinpath('..').joinpath('parent.txt').read_bytes() == b'content' + + def test_unsupported_names(self): + """ + Path segments with special characters are readable. + + On some platforms or file systems, characters like + ``:`` and ``?`` are not allowed, but they are valid + in the zip file. + """ + data = io.BytesIO() + zf = zipfile.ZipFile(data, "w") + zf.writestr("path?", b"content") + zf.writestr("V: NMS.flac", b"fLaC...") + zf.filename = '' + root = zipfile.Path(zf) + contents = root.iterdir() + assert next(contents).name == 'path?' + assert next(contents).name == 'V: NMS.flac' + assert root.joinpath('V: NMS.flac').read_bytes() == b"fLaC..." + + def test_backslash_not_separator(self): + """ + In a zip file, backslashes are not separators. + """ + data = io.BytesIO() + zf = zipfile.ZipFile(data, "w") + zf.writestr(DirtyZipInfo.for_name("foo\\bar", zf), b"content") + zf.filename = '' + root = zipfile.Path(zf) + (first,) = root.iterdir() + assert not first.is_dir() + assert first.name == 'foo\\bar' + + @pass_alpharep + def test_interface(self, alpharep): + from importlib.resources.abc import Traversable + + zf = zipfile.Path(alpharep) + assert isinstance(zf, Traversable) + + +class DirtyZipInfo(zipfile.ZipInfo): + """ + Bypass name sanitization. + """ + + def __init__(self, filename, *args, **kwargs): + super().__init__(filename, *args, **kwargs) + self.filename = filename + + @classmethod + def for_name(cls, name, archive): + """ + Construct the same way that ZipFile.writestr does. + + TODO: extract this functionality and re-use + """ + self = cls(filename=name, date_time=time.localtime(time.time())[:6]) + self.compress_type = archive.compression + self.compress_level = archive.compresslevel + if self.filename.endswith('/'): # pragma: no cover + self.external_attr = 0o40775 << 16 # drwxrwxr-x + self.external_attr |= 0x10 # MS-DOS directory flag + else: + self.external_attr = 0o600 << 16 # ?rw------- + return self diff --git a/Lib/test/test_zipfile/test_core.py b/Lib/test/test_zipfile/test_core.py index 5b32f80d..86efccd2 100644 --- a/Lib/test/test_zipfile/test_core.py +++ b/Lib/test/test_zipfile/test_core.py @@ -1117,7 +1117,7 @@ def test_force_zip64(self): # Because this is hard to verify by parsing the data as a zip, the raw # bytes are checked to ensure that they line up with the zip spec. # The spec for this can be found at: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT - # The relevent sections for this test are: + # The relevant sections for this test are: # - 4.3.7 for local file header # - 4.5.3 for zip64 extra field @@ -1188,7 +1188,7 @@ def test_unseekable_zip_known_filesize(self): # in as a zip, this test looks at the raw bytes created to ensure that # the correct data has been generated. # The spec for this can be found at: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT - # The relevent sections for this test are: + # The relevant sections for this test are: # - 4.3.7 for local file header # - 4.3.9 for the data descriptor # - 4.5.3 for zip64 extra field diff --git a/Lib/test/test_zipimport.py b/Lib/test/test_zipimport.py index 14c19719..12fd9826 100644 --- a/Lib/test/test_zipimport.py +++ b/Lib/test/test_zipimport.py @@ -50,8 +50,11 @@ def module_path_to_dotted_name(path): TESTMOD = "ziptestmodule" +TESTMOD2 = "ziptestmodule2" +TESTMOD3 = "ziptestmodule3" TESTPACK = "ziptestpackage" TESTPACK2 = "ziptestpackage2" +TESTPACK3 = "ziptestpackage3" TEMP_DIR = os.path.abspath("junk95142") TEMP_ZIP = os.path.abspath("junk95142.zip") @@ -92,8 +95,10 @@ def makeTree(self, files, dirName=TEMP_DIR): # defined by files under the directory dirName. self.addCleanup(os_helper.rmtree, dirName) - for name, (mtime, data) in files.items(): - path = os.path.join(dirName, name) + for name, data in files.items(): + if isinstance(data, tuple): + mtime, data = data + path = os.path.join(dirName, *name.split('/')) if path[-1] == os.sep: if not os.path.isdir(path): os.makedirs(path) @@ -104,22 +109,18 @@ def makeTree(self, files, dirName=TEMP_DIR): with open(path, 'wb') as fp: fp.write(data) - def makeZip(self, files, zipName=TEMP_ZIP, **kw): + def makeZip(self, files, zipName=TEMP_ZIP, *, + comment=None, file_comment=None, stuff=None, prefix='', **kw): # Create a zip archive based set of modules/packages - # defined by files in the zip file zipName. If the - # key 'stuff' exists in kw it is prepended to the archive. + # defined by files in the zip file zipName. + # If stuff is not None, it is prepended to the archive. self.addCleanup(os_helper.unlink, zipName) - with ZipFile(zipName, "w") as z: - for name, (mtime, data) in files.items(): - zinfo = ZipInfo(name, time.localtime(mtime)) - zinfo.compress_type = self.compression - z.writestr(zinfo, data) - comment = kw.get("comment", None) + with ZipFile(zipName, "w", compression=self.compression) as z: + self.writeZip(z, files, file_comment=file_comment, prefix=prefix) if comment is not None: z.comment = comment - stuff = kw.get("stuff", None) if stuff is not None: # Prepend 'stuff' to the start of the zipfile with open(zipName, "rb") as f: @@ -128,20 +129,41 @@ def makeZip(self, files, zipName=TEMP_ZIP, **kw): f.write(stuff) f.write(data) - def doTest(self, expected_ext, files, *modules, **kw): + def writeZip(self, z, files, *, file_comment=None, prefix=''): + for name, data in files.items(): + if isinstance(data, tuple): + mtime, data = data + else: + mtime = NOW + name = name.replace(os.sep, '/') + zinfo = ZipInfo(prefix + name, time.localtime(mtime)) + zinfo.compress_type = self.compression + if file_comment is not None: + zinfo.comment = file_comment + if data is None: + zinfo.CRC = 0 + z.mkdir(zinfo) + else: + assert name[-1] != '/' + z.writestr(zinfo, data) + + def doTest(self, expected_ext, files, *modules, call=None, **kw): + if 'prefix' not in kw: + kw['prefix'] = 'pre/fix/' + prefix = kw['prefix'] self.makeZip(files, **kw) - sys.path.insert(0, TEMP_ZIP) + zip_path = os.path.join(TEMP_ZIP, *prefix.split('/')[:-1]) + sys.path.insert(0, zip_path) mod = importlib.import_module(".".join(modules)) - call = kw.get('call') if call is not None: call(mod) if expected_ext: file = mod.get_file() - self.assertEqual(file, os.path.join(TEMP_ZIP, + self.assertEqual(file, os.path.join(zip_path, *modules) + expected_ext) def testAFakeZlib(self): @@ -167,7 +189,7 @@ def testAFakeZlib(self): self.skipTest('zlib is a builtin module') if "zlib" in sys.modules: del sys.modules["zlib"] - files = {"zlib.py": (NOW, test_src)} + files = {"zlib.py": test_src} try: self.doTest(".py", files, "zlib") except ImportError: @@ -178,16 +200,16 @@ def testAFakeZlib(self): self.fail("expected test to raise ImportError") def testPy(self): - files = {TESTMOD + ".py": (NOW, test_src)} + files = {TESTMOD + ".py": test_src} self.doTest(".py", files, TESTMOD) def testPyc(self): - files = {TESTMOD + pyc_ext: (NOW, test_pyc)} + files = {TESTMOD + pyc_ext: test_pyc} self.doTest(pyc_ext, files, TESTMOD) def testBoth(self): - files = {TESTMOD + ".py": (NOW, test_src), - TESTMOD + pyc_ext: (NOW, test_pyc)} + files = {TESTMOD + ".py": test_src, + TESTMOD + pyc_ext: test_pyc} self.doTest(pyc_ext, files, TESTMOD) def testUncheckedHashBasedPyc(self): @@ -220,22 +242,22 @@ def check(mod): self.doTest(None, files, TESTMOD, call=check) def testEmptyPy(self): - files = {TESTMOD + ".py": (NOW, "")} + files = {TESTMOD + ".py": ""} self.doTest(None, files, TESTMOD) def testBadMagic(self): # make pyc magic word invalid, forcing loading from .py badmagic_pyc = bytearray(test_pyc) badmagic_pyc[0] ^= 0x04 # flip an arbitrary bit - files = {TESTMOD + ".py": (NOW, test_src), - TESTMOD + pyc_ext: (NOW, badmagic_pyc)} + files = {TESTMOD + ".py": test_src, + TESTMOD + pyc_ext: badmagic_pyc} self.doTest(".py", files, TESTMOD) def testBadMagic2(self): # make pyc magic word invalid, causing an ImportError badmagic_pyc = bytearray(test_pyc) badmagic_pyc[0] ^= 0x04 # flip an arbitrary bit - files = {TESTMOD + pyc_ext: (NOW, badmagic_pyc)} + files = {TESTMOD + pyc_ext: badmagic_pyc} try: self.doTest(".py", files, TESTMOD) self.fail("This should not be reached") @@ -248,22 +270,22 @@ def testBadMTime(self): # flip the second bit -- not the first as that one isn't stored in the # .py's mtime in the zip archive. badtime_pyc[11] ^= 0x02 - files = {TESTMOD + ".py": (NOW, test_src), - TESTMOD + pyc_ext: (NOW, badtime_pyc)} + files = {TESTMOD + ".py": test_src, + TESTMOD + pyc_ext: badtime_pyc} self.doTest(".py", files, TESTMOD) def test2038MTime(self): # Make sure we can handle mtimes larger than what a 32-bit signed number # can hold. twenty_thirty_eight_pyc = make_pyc(test_co, 2**32 - 1, len(test_src)) - files = {TESTMOD + ".py": (NOW, test_src), - TESTMOD + pyc_ext: (NOW, twenty_thirty_eight_pyc)} + files = {TESTMOD + ".py": test_src, + TESTMOD + pyc_ext: twenty_thirty_eight_pyc} self.doTest(".py", files, TESTMOD) def testPackage(self): packdir = TESTPACK + os.sep - files = {packdir + "__init__" + pyc_ext: (NOW, test_pyc), - packdir + TESTMOD + pyc_ext: (NOW, test_pyc)} + files = {packdir + "__init__" + pyc_ext: test_pyc, + packdir + TESTMOD + pyc_ext: test_pyc} self.doTest(pyc_ext, files, TESTPACK, TESTMOD) def testSubPackage(self): @@ -271,9 +293,9 @@ def testSubPackage(self): # archives. packdir = TESTPACK + os.sep packdir2 = packdir + TESTPACK2 + os.sep - files = {packdir + "__init__" + pyc_ext: (NOW, test_pyc), - packdir2 + "__init__" + pyc_ext: (NOW, test_pyc), - packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc)} + files = {packdir + "__init__" + pyc_ext: test_pyc, + packdir2 + "__init__" + pyc_ext: test_pyc, + packdir2 + TESTMOD + pyc_ext: test_pyc} self.doTest(pyc_ext, files, TESTPACK, TESTPACK2, TESTMOD) def testSubNamespacePackage(self): @@ -282,9 +304,9 @@ def testSubNamespacePackage(self): packdir = TESTPACK + os.sep packdir2 = packdir + TESTPACK2 + os.sep # The first two files are just directory entries (so have no data). - files = {packdir: (NOW, ""), - packdir2: (NOW, ""), - packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc)} + files = {packdir: None, + packdir2: None, + packdir2 + TESTMOD + pyc_ext: test_pyc} self.doTest(pyc_ext, files, TESTPACK, TESTPACK2, TESTMOD) def testMixedNamespacePackage(self): @@ -292,19 +314,19 @@ def testMixedNamespacePackage(self): # real filesystem and a zip archive. packdir = TESTPACK + os.sep packdir2 = packdir + TESTPACK2 + os.sep - packdir3 = packdir2 + TESTPACK + '3' + os.sep - files1 = {packdir: (NOW, ""), - packdir + TESTMOD + pyc_ext: (NOW, test_pyc), - packdir2: (NOW, ""), - packdir3: (NOW, ""), - packdir3 + TESTMOD + pyc_ext: (NOW, test_pyc), - packdir2 + TESTMOD + '3' + pyc_ext: (NOW, test_pyc), - packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc)} - files2 = {packdir: (NOW, ""), - packdir + TESTMOD + '2' + pyc_ext: (NOW, test_pyc), - packdir2: (NOW, ""), - packdir2 + TESTMOD + '2' + pyc_ext: (NOW, test_pyc), - packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc)} + packdir3 = packdir2 + TESTPACK3 + os.sep + files1 = {packdir: None, + packdir + TESTMOD + pyc_ext: test_pyc, + packdir2: None, + packdir3: None, + packdir3 + TESTMOD + pyc_ext: test_pyc, + packdir2 + TESTMOD3 + pyc_ext: test_pyc, + packdir2 + TESTMOD + pyc_ext: test_pyc} + files2 = {packdir: None, + packdir + TESTMOD2 + pyc_ext: test_pyc, + packdir2: None, + packdir2 + TESTMOD2 + pyc_ext: test_pyc, + packdir2 + TESTMOD + pyc_ext: test_pyc} zip1 = os.path.abspath("path1.zip") self.makeZip(files1, zip1) @@ -337,8 +359,8 @@ def testMixedNamespacePackage(self): mod = importlib.import_module('.'.join((TESTPACK, TESTMOD))) self.assertEqual("path1.zip", mod.__file__.split(os.sep)[-3]) - # And TESTPACK/(TESTMOD + '2') only exists in path2. - mod = importlib.import_module('.'.join((TESTPACK, TESTMOD + '2'))) + # And TESTPACK/(TESTMOD2) only exists in path2. + mod = importlib.import_module('.'.join((TESTPACK, TESTMOD2))) self.assertEqual(os.path.basename(TEMP_DIR), mod.__file__.split(os.sep)[-3]) @@ -355,13 +377,13 @@ def testMixedNamespacePackage(self): self.assertEqual(os.path.basename(TEMP_DIR), mod.__file__.split(os.sep)[-4]) - # subpkg.TESTMOD + '2' only exists in zip2. - mod = importlib.import_module('.'.join((subpkg, TESTMOD + '2'))) + # subpkg.TESTMOD2 only exists in zip2. + mod = importlib.import_module('.'.join((subpkg, TESTMOD2))) self.assertEqual(os.path.basename(TEMP_DIR), mod.__file__.split(os.sep)[-4]) - # Finally subpkg.TESTMOD + '3' only exists in zip1. - mod = importlib.import_module('.'.join((subpkg, TESTMOD + '3'))) + # Finally subpkg.TESTMOD3 only exists in zip1. + mod = importlib.import_module('.'.join((subpkg, TESTMOD3))) self.assertEqual('path1.zip', mod.__file__.split(os.sep)[-4]) def testNamespacePackage(self): @@ -369,22 +391,22 @@ def testNamespacePackage(self): # archives. packdir = TESTPACK + os.sep packdir2 = packdir + TESTPACK2 + os.sep - packdir3 = packdir2 + TESTPACK + '3' + os.sep - files1 = {packdir: (NOW, ""), - packdir + TESTMOD + pyc_ext: (NOW, test_pyc), - packdir2: (NOW, ""), - packdir3: (NOW, ""), - packdir3 + TESTMOD + pyc_ext: (NOW, test_pyc), - packdir2 + TESTMOD + '3' + pyc_ext: (NOW, test_pyc), - packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc)} + packdir3 = packdir2 + TESTPACK3 + os.sep + files1 = {packdir: None, + packdir + TESTMOD + pyc_ext: test_pyc, + packdir2: None, + packdir3: None, + packdir3 + TESTMOD + pyc_ext: test_pyc, + packdir2 + TESTMOD3 + pyc_ext: test_pyc, + packdir2 + TESTMOD + pyc_ext: test_pyc} zip1 = os.path.abspath("path1.zip") self.makeZip(files1, zip1) - files2 = {packdir: (NOW, ""), - packdir + TESTMOD + '2' + pyc_ext: (NOW, test_pyc), - packdir2: (NOW, ""), - packdir2 + TESTMOD + '2' + pyc_ext: (NOW, test_pyc), - packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc)} + files2 = {packdir: None, + packdir + TESTMOD2 + pyc_ext: test_pyc, + packdir2: None, + packdir2 + TESTMOD2 + pyc_ext: test_pyc, + packdir2 + TESTMOD + pyc_ext: test_pyc} zip2 = os.path.abspath("path2.zip") self.makeZip(files2, zip2) @@ -413,8 +435,8 @@ def testNamespacePackage(self): mod = importlib.import_module('.'.join((TESTPACK, TESTMOD))) self.assertEqual("path1.zip", mod.__file__.split(os.sep)[-3]) - # And TESTPACK/(TESTMOD + '2') only exists in path2. - mod = importlib.import_module('.'.join((TESTPACK, TESTMOD + '2'))) + # And TESTPACK/(TESTMOD2) only exists in path2. + mod = importlib.import_module('.'.join((TESTPACK, TESTMOD2))) self.assertEqual("path2.zip", mod.__file__.split(os.sep)[-3]) # One level deeper... @@ -429,29 +451,22 @@ def testNamespacePackage(self): mod = importlib.import_module('.'.join((subpkg, TESTMOD))) self.assertEqual('path2.zip', mod.__file__.split(os.sep)[-4]) - # subpkg.TESTMOD + '2' only exists in zip2. - mod = importlib.import_module('.'.join((subpkg, TESTMOD + '2'))) + # subpkg.TESTMOD2 only exists in zip2. + mod = importlib.import_module('.'.join((subpkg, TESTMOD2))) self.assertEqual('path2.zip', mod.__file__.split(os.sep)[-4]) - # Finally subpkg.TESTMOD + '3' only exists in zip1. - mod = importlib.import_module('.'.join((subpkg, TESTMOD + '3'))) + # Finally subpkg.TESTMOD3 only exists in zip1. + mod = importlib.import_module('.'.join((subpkg, TESTMOD3))) self.assertEqual('path1.zip', mod.__file__.split(os.sep)[-4]) def testZipImporterMethods(self): packdir = TESTPACK + os.sep packdir2 = packdir + TESTPACK2 + os.sep - files = {packdir + "__init__" + pyc_ext: (NOW, test_pyc), - packdir2 + "__init__" + pyc_ext: (NOW, test_pyc), - packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc), - "spam" + pyc_ext: (NOW, test_pyc)} - - self.addCleanup(os_helper.unlink, TEMP_ZIP) - with ZipFile(TEMP_ZIP, "w") as z: - for name, (mtime, data) in files.items(): - zinfo = ZipInfo(name, time.localtime(mtime)) - zinfo.compress_type = self.compression - zinfo.comment = b"spam" - z.writestr(zinfo, data) + files = {packdir + "__init__" + pyc_ext: test_pyc, + packdir2 + "__init__" + pyc_ext: test_pyc, + packdir2 + TESTMOD + pyc_ext: test_pyc, + "spam" + pyc_ext: test_pyc} + self.makeZip(files, file_comment=b"spam") zi = zipimport.zipimporter(TEMP_ZIP) self.assertEqual(zi.archive, TEMP_ZIP) @@ -507,17 +522,11 @@ def testZipImporterMethods(self): def testInvalidateCaches(self): packdir = TESTPACK + os.sep packdir2 = packdir + TESTPACK2 + os.sep - files = {packdir + "__init__" + pyc_ext: (NOW, test_pyc), - packdir2 + "__init__" + pyc_ext: (NOW, test_pyc), - packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc), - "spam" + pyc_ext: (NOW, test_pyc)} - self.addCleanup(os_helper.unlink, TEMP_ZIP) - with ZipFile(TEMP_ZIP, "w") as z: - for name, (mtime, data) in files.items(): - zinfo = ZipInfo(name, time.localtime(mtime)) - zinfo.compress_type = self.compression - zinfo.comment = b"spam" - z.writestr(zinfo, data) + files = {packdir + "__init__" + pyc_ext: test_pyc, + packdir2 + "__init__" + pyc_ext: test_pyc, + packdir2 + TESTMOD + pyc_ext: test_pyc, + "spam" + pyc_ext: test_pyc} + self.makeZip(files, file_comment=b"spam") zi = zipimport.zipimporter(TEMP_ZIP) self.assertEqual(zi._files.keys(), files.keys()) @@ -525,14 +534,10 @@ def testInvalidateCaches(self): zi.invalidate_caches() self.assertEqual(zi._files.keys(), files.keys()) # Add a new file to the ZIP archive - newfile = {"spam2" + pyc_ext: (NOW, test_pyc)} + newfile = {"spam2" + pyc_ext: test_pyc} files.update(newfile) - with ZipFile(TEMP_ZIP, "a") as z: - for name, (mtime, data) in newfile.items(): - zinfo = ZipInfo(name, time.localtime(mtime)) - zinfo.compress_type = self.compression - zinfo.comment = b"spam" - z.writestr(zinfo, data) + with ZipFile(TEMP_ZIP, "a", compression=self.compression) as z: + self.writeZip(z, newfile, file_comment=b"spam") # Check that we can detect the new file after invalidating the cache zi.invalidate_caches() self.assertEqual(zi._files.keys(), files.keys()) @@ -549,16 +554,9 @@ def testInvalidateCaches(self): def testZipImporterMethodsInSubDirectory(self): packdir = TESTPACK + os.sep packdir2 = packdir + TESTPACK2 + os.sep - files = {packdir2 + "__init__" + pyc_ext: (NOW, test_pyc), - packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc)} - - self.addCleanup(os_helper.unlink, TEMP_ZIP) - with ZipFile(TEMP_ZIP, "w") as z: - for name, (mtime, data) in files.items(): - zinfo = ZipInfo(name, time.localtime(mtime)) - zinfo.compress_type = self.compression - zinfo.comment = b"eggs" - z.writestr(zinfo, data) + files = {packdir2 + "__init__" + pyc_ext: test_pyc, + packdir2 + TESTMOD + pyc_ext: test_pyc} + self.makeZip(files, file_comment=b"eggs") zi = zipimport.zipimporter(TEMP_ZIP + os.sep + packdir) self.assertEqual(zi.archive, TEMP_ZIP) @@ -623,9 +621,9 @@ def get_file(): if __loader__.get_data("some.data") != b"some data": raise AssertionError("bad data")\n""" pyc = make_pyc(compile(src, "", "exec"), NOW, len(src)) - files = {TESTMOD + pyc_ext: (NOW, pyc), - "some.data": (NOW, "some data")} - self.doTest(pyc_ext, files, TESTMOD) + files = {TESTMOD + pyc_ext: pyc, + "some.data": "some data"} + self.doTest(pyc_ext, files, TESTMOD, prefix='') def testDefaultOptimizationLevel(self): # zipimport should use the default optimization level (#28131) @@ -633,7 +631,7 @@ def testDefaultOptimizationLevel(self): def test(val): assert(val) return val\n""" - files = {TESTMOD + '.py': (NOW, src)} + files = {TESTMOD + '.py': src} self.makeZip(files) sys.path.insert(0, TEMP_ZIP) mod = importlib.import_module(TESTMOD) @@ -646,7 +644,7 @@ def test(val): def testImport_WithStuff(self): # try importing from a zipfile which contains additional # stuff at the beginning of the file - files = {TESTMOD + ".py": (NOW, test_src)} + files = {TESTMOD + ".py": test_src} self.doTest(".py", files, TESTMOD, stuff=b"Some Stuff"*31) @@ -654,18 +652,18 @@ def assertModuleSource(self, module): self.assertEqual(inspect.getsource(module), test_src) def testGetSource(self): - files = {TESTMOD + ".py": (NOW, test_src)} + files = {TESTMOD + ".py": test_src} self.doTest(".py", files, TESTMOD, call=self.assertModuleSource) def testGetCompiledSource(self): pyc = make_pyc(compile(test_src, "", "exec"), NOW, len(test_src)) - files = {TESTMOD + ".py": (NOW, test_src), - TESTMOD + pyc_ext: (NOW, pyc)} + files = {TESTMOD + ".py": test_src, + TESTMOD + pyc_ext: pyc} self.doTest(pyc_ext, files, TESTMOD, call=self.assertModuleSource) def runDoctest(self, callback): - files = {TESTMOD + ".py": (NOW, test_src), - "xyz.txt": (NOW, ">>> log.append(True)\n")} + files = {TESTMOD + ".py": test_src, + "xyz.txt": ">>> log.append(True)\n"} self.doTest(".py", files, TESTMOD, call=callback) def doDoctestFile(self, module): @@ -717,29 +715,21 @@ def doTraceback(self, module): raise AssertionError("This ought to be impossible") def testTraceback(self): - files = {TESTMOD + ".py": (NOW, raise_src)} + files = {TESTMOD + ".py": raise_src} self.doTest(None, files, TESTMOD, call=self.doTraceback) @unittest.skipIf(os_helper.TESTFN_UNENCODABLE is None, "need an unencodable filename") def testUnencodable(self): filename = os_helper.TESTFN_UNENCODABLE + ".zip" - self.addCleanup(os_helper.unlink, filename) - with ZipFile(filename, "w") as z: - zinfo = ZipInfo(TESTMOD + ".py", time.localtime(NOW)) - zinfo.compress_type = self.compression - z.writestr(zinfo, test_src) + self.makeZip({TESTMOD + ".py": test_src}, filename) spec = zipimport.zipimporter(filename).find_spec(TESTMOD) mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) def testBytesPath(self): filename = os_helper.TESTFN + ".zip" - self.addCleanup(os_helper.unlink, filename) - with ZipFile(filename, "w") as z: - zinfo = ZipInfo(TESTMOD + ".py", time.localtime(NOW)) - zinfo.compress_type = self.compression - z.writestr(zinfo, test_src) + self.makeZip({TESTMOD + ".py": test_src}, filename) zipimport.zipimporter(filename) with self.assertRaises(TypeError): @@ -750,15 +740,15 @@ def testBytesPath(self): zipimport.zipimporter(memoryview(os.fsencode(filename))) def testComment(self): - files = {TESTMOD + ".py": (NOW, test_src)} + files = {TESTMOD + ".py": test_src} self.doTest(".py", files, TESTMOD, comment=b"comment") def testBeginningCruftAndComment(self): - files = {TESTMOD + ".py": (NOW, test_src)} + files = {TESTMOD + ".py": test_src} self.doTest(".py", files, TESTMOD, stuff=b"cruft" * 64, comment=b"hi") def testLargestPossibleComment(self): - files = {TESTMOD + ".py": (NOW, test_src)} + files = {TESTMOD + ".py": test_src} self.doTest(".py", files, TESTMOD, comment=b"c" * ((1 << 16) - 1)) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py index 0a13986a..9611a0d2 100644 --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -7,7 +7,7 @@ import pickle import random import sys -from test.support import bigmemtest, _1G, _4G, skip_on_s390x +from test.support import bigmemtest, _1G, _4G, is_s390x zlib = import_helper.import_module('zlib') @@ -34,8 +34,9 @@ def _zlib_runtime_version_tuple(zlib_version=zlib.ZLIB_RUNTIME_VERSION): ZLIB_RUNTIME_VERSION_TUPLE = _zlib_runtime_version_tuple() -# bpo-46623: On s390x, when a hardware accelerator is used, using different -# ways to compress data with zlib can produce different compressed data. +# bpo-46623: When a hardware accelerator is used (currently only on s390x), +# using different ways to compress data with zlib can produce different +# compressed data. # Simplified test_pair() code: # # def func1(data): @@ -58,8 +59,10 @@ def _zlib_runtime_version_tuple(zlib_version=zlib.ZLIB_RUNTIME_VERSION): # # zlib.decompress(func1(data)) == zlib.decompress(func2(data)) == data # -# Make the assumption that s390x always has an accelerator to simplify the skip -# condition. +# To simplify the skip condition, make the assumption that s390x always has an +# accelerator, and nothing else has it. +HW_ACCELERATED = is_s390x + class VersionTestCase(unittest.TestCase): @@ -224,12 +227,14 @@ def test_keywords(self): bufsize=zlib.DEF_BUF_SIZE), HAMLET_SCENE) - @skip_on_s390x def test_speech128(self): # compress more data data = HAMLET_SCENE * 128 x = zlib.compress(data) - self.assertEqual(zlib.compress(bytearray(data)), x) + # With hardware acceleration, the compressed bytes + # might not be identical. + if not HW_ACCELERATED: + self.assertEqual(zlib.compress(bytearray(data)), x) for ob in x, bytearray(x): self.assertEqual(zlib.decompress(ob), data) @@ -276,7 +281,6 @@ def test_64bit_compress(self, size): class CompressObjectTestCase(BaseCompressTestCase, unittest.TestCase): # Test compression object - @skip_on_s390x def test_pair(self): # straightforward compress/decompress objects datasrc = HAMLET_SCENE * 128 @@ -287,7 +291,10 @@ def test_pair(self): x1 = co.compress(data) x2 = co.flush() self.assertRaises(zlib.error, co.flush) # second flush should not work - self.assertEqual(x1 + x2, datazip) + # With hardware acceleration, the compressed bytes might not + # be identical. + if not HW_ACCELERATED: + self.assertEqual(x1 + x2, datazip) for v1, v2 in ((x1, x2), (bytearray(x1), bytearray(x2))): dco = zlib.decompressobj() y1 = dco.decompress(v1 + v2) @@ -499,20 +506,16 @@ def test_flushes(self): for sync in sync_opt: for level in range(10): - try: + with self.subTest(sync=sync, level=level): 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)) - del obj + self.assertEqual(zlib.decompress(b''.join([a,b,c,d])), + data, ("Decompress failed: flush " + "mode=%i, level=%i") % (sync, level)) + del obj @unittest.skipUnless(hasattr(zlib, 'Z_SYNC_FLUSH'), 'requires zlib.Z_SYNC_FLUSH') diff --git a/Lib/test/translationdata/argparse/msgids.txt b/Lib/test/translationdata/argparse/msgids.txt new file mode 100644 index 00000000..a1b4f94d --- /dev/null +++ b/Lib/test/translationdata/argparse/msgids.txt @@ -0,0 +1,36 @@ + (default: %(default)s) +%(heading)s: +%(prog)s: error: %(message)s\n +%r is not callable +'required' is an invalid argument for positionals +.__call__() not defined +ambiguous option: %(option)s could match %(matches)s +argument "-" with mode %r +argument %(argument_name)s: %(message)s +can't open '%(filename)s': %(error)s +cannot have multiple subparser arguments +cannot merge actions - two groups are named %r +conflicting subparser alias: %s +conflicting subparser: %s +dest= is required for options like %r +expected at least one argument +expected at most one argument +expected one argument +ignored explicit argument %r +invalid %(type)s value: %(value)r +invalid choice: %(value)r (choose from %(choices)s) +invalid conflict_resolution value: %r +invalid option string %(option)r: must start with a character %(prefix_chars)r +mutually exclusive arguments must be optional +not allowed with argument %s +one of the arguments %s is required +options +positional arguments +show program's version number and exit +show this help message and exit +subcommands +the following arguments are required: %s +unexpected option string: %s +unknown parser %(parser_name)r (choices: %(choices)s) +unrecognized arguments: %s +usage: \ No newline at end of file diff --git a/Lib/test/translationdata/getopt/msgids.txt b/Lib/test/translationdata/getopt/msgids.txt new file mode 100644 index 00000000..1ffab1f3 --- /dev/null +++ b/Lib/test/translationdata/getopt/msgids.txt @@ -0,0 +1,6 @@ +option -%s not recognized +option -%s requires argument +option --%s must not have an argument +option --%s not a unique prefix +option --%s not recognized +option --%s requires argument \ No newline at end of file diff --git a/Lib/test/translationdata/optparse/msgids.txt b/Lib/test/translationdata/optparse/msgids.txt new file mode 100644 index 00000000..ac5317c7 --- /dev/null +++ b/Lib/test/translationdata/optparse/msgids.txt @@ -0,0 +1,14 @@ +%prog [options] +%s option does not take a value +Options +Usage +Usage: %s\n +ambiguous option: %s (%s?) +complex +floating-point +integer +no such option: %s +option %s: invalid %s value: %r +option %s: invalid choice: %r (choose from %s) +show program's version number and exit +show this help message and exit \ No newline at end of file diff --git a/Lib/test/typinganndata/ann_module695.py b/Lib/test/typinganndata/ann_module695.py index 2ede9fe3..b6f3b06b 100644 --- a/Lib/test/typinganndata/ann_module695.py +++ b/Lib/test/typinganndata/ann_module695.py @@ -17,6 +17,56 @@ class B[T, *Ts, **P]: z: P +Eggs = int +Spam = str + + +class C[Eggs, **Spam]: + x: Eggs + y: Spam + + def generic_function[T, *Ts, **P]( x: T, *y: *Ts, z: P.args, zz: P.kwargs ) -> None: ... + + +def generic_function_2[Eggs, **Spam](x: Eggs, y: Spam): pass + + +class D: + Foo = int + Bar = str + + def generic_method[Foo, **Bar]( + self, x: Foo, y: Bar + ) -> None: ... + + def generic_method_2[Eggs, **Spam](self, x: Eggs, y: Spam): pass + + +def nested(): + from types import SimpleNamespace + from typing import get_type_hints + + Eggs = bytes + Spam = memoryview + + + class E[Eggs, **Spam]: + x: Eggs + y: Spam + + def generic_method[Eggs, **Spam](self, x: Eggs, y: Spam): pass + + + def generic_function[Eggs, **Spam](x: Eggs, y: Spam): pass + + + return SimpleNamespace( + E=E, + hints_for_E=get_type_hints(E), + hints_for_E_meth=get_type_hints(E.generic_method), + generic_func=generic_function, + hints_for_generic_func=get_type_hints(generic_function) + ) diff --git a/Lib/threading.py b/Lib/threading.py index 98cb43c6..0bba85d0 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -332,7 +332,7 @@ def wait(self, timeout=None): awakened or timed out, it re-acquires the lock and returns. When the timeout argument is present and not None, it should be a - floating point number specifying a timeout for the operation in seconds + floating-point number specifying a timeout for the operation in seconds (or fractions thereof). When the underlying lock is an RLock, it is not released using its @@ -642,7 +642,7 @@ def wait(self, timeout=None): the optional timeout occurs. When the timeout argument is present and not None, it should be a - floating point number specifying a timeout for the operation in seconds + floating-point number specifying a timeout for the operation in seconds (or fractions thereof). This method returns the internal flag on exit, so it will always return @@ -685,6 +685,8 @@ def __init__(self, parties, action=None, timeout=None): default for all subsequent 'wait()' calls. """ + if parties < 1: + raise ValueError("parties must be > 0") self._cond = Condition(Lock()) self._action = action self._timeout = timeout @@ -1120,7 +1122,7 @@ def join(self, timeout=None): or until the optional timeout occurs. When the timeout argument is present and not None, it should be a - floating point number specifying a timeout for the operation in seconds + floating-point number specifying a timeout for the operation in seconds (or fractions thereof). As join() always returns None, you must call is_alive() after join() to decide whether a timeout happened -- if the thread is still alive, the join() call timed out. diff --git a/Lib/tkinter/simpledialog.py b/Lib/tkinter/simpledialog.py index 538bbfc3..2c1417f7 100644 --- a/Lib/tkinter/simpledialog.py +++ b/Lib/tkinter/simpledialog.py @@ -357,7 +357,7 @@ def askinteger(title, prompt, **kw): class _QueryFloat(_QueryDialog): - errormessage = "Not a floating point value." + errormessage = "Not a floating-point value." def getresult(self): return self.getdouble(self.entry.get()) diff --git a/Lib/tkinter/ttk.py b/Lib/tkinter/ttk.py index efeabb7a..5d1c9d77 100644 --- a/Lib/tkinter/ttk.py +++ b/Lib/tkinter/ttk.py @@ -683,7 +683,10 @@ def current(self, newindex=None): returns the index of the current value in the list of values or -1 if the current value does not appear in the list.""" if newindex is None: - return self.tk.getint(self.tk.call(self._w, "current")) + res = self.tk.call(self._w, "current") + if res == '': + return -1 + return self.tk.getint(res) return self.tk.call(self._w, "current", newindex) @@ -1515,7 +1518,7 @@ def __init__(self, master=None, variable=None, from_=0, to=10, **kw): self.label.place(anchor='n' if label_side == 'top' else 's') # update the label as scale or variable changes - self.__tracecb = self._variable.trace_variable('w', self._adjust) + self.__tracecb = self._variable.trace_add('write', self._adjust) self.bind('', self._adjust) self.bind('', self._adjust) @@ -1523,7 +1526,7 @@ def __init__(self, master=None, variable=None, from_=0, to=10, **kw): def destroy(self): """Destroy this widget and possibly its associated variable.""" try: - self._variable.trace_vdelete('w', self.__tracecb) + self._variable.trace_remove('write', self.__tracecb) except AttributeError: pass else: diff --git a/Lib/token.py b/Lib/token.py index 487f6edd..e26d36bd 100644 --- a/Lib/token.py +++ b/Lib/token.py @@ -1,7 +1,8 @@ """Token constants.""" # Auto-generated by Tools/build/generate_token.py -__all__ = ['tok_name', 'ISTERMINAL', 'ISNONTERMINAL', 'ISEOF'] +__all__ = ['tok_name', 'ISTERMINAL', 'ISNONTERMINAL', 'ISEOF', + 'EXACT_TOKEN_TYPES'] ENDMARKER = 0 NAME = 1 diff --git a/Lib/tokenize.py b/Lib/tokenize.py index 7af7a5cc..b2dff8e6 100644 --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -202,7 +202,7 @@ def escape_brackets(self, token): characters[-2::-1] ) ) - if n_backslashes % 2 == 0: + if n_backslashes % 2 == 0 or characters[-1] != "N": characters.append(character) else: consume_until_next_bracket = True diff --git a/Lib/turtle.py b/Lib/turtle.py index 811c5dfa..92ac58f8 100644 --- a/Lib/turtle.py +++ b/Lib/turtle.py @@ -1719,7 +1719,7 @@ def xcor(self): >>> reset() >>> turtle.left(60) >>> turtle.forward(100) - >>> print turtle.xcor() + >>> print(turtle.xcor()) 50.0 """ return self._position[0] @@ -1733,7 +1733,7 @@ def ycor(self): >>> reset() >>> turtle.left(60) >>> turtle.forward(100) - >>> print turtle.ycor() + >>> print(turtle.ycor()) 86.6025403784 """ return self._position[1] @@ -2336,7 +2336,7 @@ def isvisible(self): Example (for a Turtle instance named turtle): >>> turtle.hideturtle() - >>> print turtle.isvisible(): + >>> print(turtle.isvisible()) False """ return self._shown diff --git a/Lib/turtledemo/clock.py b/Lib/turtledemo/clock.py index 9f8585bd..318f1260 100755 --- a/Lib/turtledemo/clock.py +++ b/Lib/turtledemo/clock.py @@ -1,8 +1,7 @@ #!/usr/bin/env python3 -# -*- coding: cp1252 -*- """ turtle-example-suite: - tdemo_clock.py + turtledemo/clock.py Enhanced clock-program, showing date and time @@ -13,6 +12,9 @@ from turtle import * from datetime import datetime +dtfont = "TkFixedFont", 14, "bold" +current_day = None + def jump(distanz, winkel=0): penup() right(winkel) @@ -53,11 +55,23 @@ def clockface(radius): jump(-radius) rt(6) +def display_date_time(): + global current_day + writer.clear() + now = datetime.now() + current_day = now.day + writer.home() + writer.forward(distance=65) + writer.write(wochentag(now), align="center", font=dtfont) + writer.back(distance=150) + writer.write(datum(now), align="center", font=dtfont) + writer.forward(distance=85) + def setup(): global second_hand, minute_hand, hour_hand, writer mode("logo") make_hand_shape("second_hand", 125, 25) - make_hand_shape("minute_hand", 130, 25) + make_hand_shape("minute_hand", 115, 25) make_hand_shape("hour_hand", 90, 25) clockface(160) second_hand = Turtle() @@ -75,10 +89,10 @@ def setup(): hand.speed(0) ht() writer = Turtle() - #writer.mode("logo") writer.ht() writer.pu() writer.bk(85) + display_date_time() def wochentag(t): wochentag = ["Monday", "Tuesday", "Wednesday", @@ -100,18 +114,11 @@ def tick(): stunde = t.hour + minute/60.0 try: tracer(False) # Terminator can occur here - writer.clear() - writer.home() - writer.forward(65) - writer.write(wochentag(t), - align="center", font=("Courier", 14, "bold")) - writer.back(150) - writer.write(datum(t), - align="center", font=("Courier", 14, "bold")) - writer.forward(85) second_hand.setheading(6*sekunde) # or here minute_hand.setheading(6*minute) hour_hand.setheading(30*stunde) + if t.day != current_day: + display_date_time() tracer(True) ontimer(tick, 100) except Terminator: diff --git a/Lib/turtledemo/sorting_animate.py b/Lib/turtledemo/sorting_animate.py index d25a0ab6..1c6aae80 100755 --- a/Lib/turtledemo/sorting_animate.py +++ b/Lib/turtledemo/sorting_animate.py @@ -7,7 +7,7 @@ Sorts a shelf of 10 blocks using insertion sort, selection sort and quicksort. -Shelfs are implemented using builtin lists. +Shelves are implemented using builtin lists. Blocks are turtles with shape "square", but stretched to rectangles by shapesize() diff --git a/Lib/typing.py b/Lib/typing.py index 882dc4da..a271416d 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -927,15 +927,24 @@ def _evaluate(self, globalns, localns, type_params=None, *, recursive_guard): globalns = getattr( sys.modules.get(self.__forward_module__, None), '__dict__', globalns ) + + # type parameters require some special handling, + # as they exist in their own scope + # but `eval()` does not have a dedicated parameter for that scope. + # For classes, names in type parameter scopes should override + # names in the global scope (which here are called `localns`!), + # but should in turn be overridden by names in the class scope + # (which here are called `globalns`!) if type_params: - # "Inject" type parameters into the local namespace - # (unless they are shadowed by assignments *in* the local namespace), - # as a way of emulating annotation scopes when calling `eval()` - locals_to_pass = {param.__name__: param for param in type_params} | localns - else: - locals_to_pass = localns + globalns, localns = dict(globalns), dict(localns) + for param in type_params: + param_name = param.__name__ + if not self.__forward_is_class__ or param_name not in globalns: + globalns[param_name] = param + localns.pop(param_name, None) + type_ = _type_check( - eval(self.__forward_code__, globalns, locals_to_pass), + eval(self.__forward_code__, globalns, localns), "Forward references must evaluate to types.", is_argument=self.__forward_is_argument__, allow_special_forms=self.__forward_is_class__, @@ -1806,7 +1815,8 @@ def _allow_reckless_class_checks(depth=2): _PROTO_ALLOWLIST = { 'collections.abc': [ 'Callable', 'Awaitable', 'Iterable', 'Iterator', 'AsyncIterable', - 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', 'Buffer', + 'AsyncIterator', 'Hashable', 'Sized', 'Container', 'Collection', + 'Reversible', 'Buffer', ], 'contextlib': ['AbstractContextManager', 'AbstractAsyncContextManager'], } diff --git a/Lib/unittest/async_case.py b/Lib/unittest/async_case.py index bd2a4711..2abfb790 100644 --- a/Lib/unittest/async_case.py +++ b/Lib/unittest/async_case.py @@ -5,6 +5,7 @@ from .case import TestCase +__unittest = True class IsolatedAsyncioTestCase(TestCase): # Names intentionally have a long prefix diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 486e0c63..c4ce8f8a 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -598,7 +598,9 @@ def __set_side_effect(self, value): side_effect = property(__get_side_effect, __set_side_effect) - def reset_mock(self, visited=None,*, return_value=False, side_effect=False): + def reset_mock(self, visited=None, *, + return_value: bool = False, + side_effect: bool = False): "Restore the mock object to its initial state." if visited is None: visited = [] @@ -800,6 +802,9 @@ def __setattr__(self, name, value): mock_name = f'{self._extract_mock_name()}.{name}' raise AttributeError(f'Cannot set {mock_name}') + if isinstance(value, PropertyMock): + self.__dict__[name] = value + return return object.__setattr__(self, name, value) @@ -1324,6 +1329,7 @@ def __init__( self.autospec = autospec self.kwargs = kwargs self.additional_patchers = [] + self.is_started = False def copy(self): @@ -1436,6 +1442,9 @@ def get_original(self): def __enter__(self): """Perform the patch.""" + if self.is_started: + raise RuntimeError("Patch is already started") + new, spec, spec_set = self.new, self.spec, self.spec_set autospec, kwargs = self.autospec, self.kwargs new_callable = self.new_callable @@ -1478,13 +1487,12 @@ def __enter__(self): if isinstance(original, type): # If we're patching out a class and there is a spec inherit = True - if spec is None and _is_async_obj(original): - Klass = AsyncMock - else: - Klass = MagicMock - _kwargs = {} + + # Determine the Klass to use if new_callable is not None: Klass = new_callable + elif spec is None and _is_async_obj(original): + Klass = AsyncMock elif spec is not None or spec_set is not None: this_spec = spec if spec_set is not None: @@ -1497,7 +1505,12 @@ def __enter__(self): Klass = AsyncMock elif not_callable: Klass = NonCallableMagicMock + else: + Klass = MagicMock + else: + Klass = MagicMock + _kwargs = {} if spec is not None: _kwargs['spec'] = spec if spec_set is not None: @@ -1563,6 +1576,7 @@ def __enter__(self): self.temp_original = original self.is_local = local self._exit_stack = contextlib.ExitStack() + self.is_started = True try: setattr(self.target, self.attribute, new_attr) if self.attribute_name is not None: @@ -1582,6 +1596,9 @@ def __enter__(self): def __exit__(self, *exc_info): """Undo the patch.""" + if not self.is_started: + return + if self.is_local and self.temp_original is not DEFAULT: setattr(self.target, self.attribute, self.temp_original) else: @@ -1598,6 +1615,7 @@ def __exit__(self, *exc_info): del self.target exit_stack = self._exit_stack del self._exit_stack + self.is_started = False return exit_stack.__exit__(*exc_info) @@ -2182,6 +2200,17 @@ def mock_add_spec(self, spec, spec_set=False): self._mock_add_spec(spec, spec_set) self._mock_set_magics() + def reset_mock(self, /, *args, return_value: bool = False, **kwargs): + if ( + return_value + and self._mock_name + and _is_magic(self._mock_name) + ): + # Don't reset return values for magic methods, + # otherwise `m.__str__` will start + # to return `MagicMock` instances, instead of `str` instances. + return_value = False + super().reset_mock(*args, return_value=return_value, **kwargs) class MagicProxy(Base): @@ -2718,6 +2747,12 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None, if not unsafe: _check_spec_arg_typos(kwargs) + _name = kwargs.pop('name', _name) + _new_name = _name + if _parent is None: + # for a top level object no _new_name should be set + _new_name = '' + _kwargs.update(kwargs) Klass = MagicMock @@ -2735,13 +2770,6 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None, elif is_type and instance and not _instance_callable(spec): Klass = NonCallableMagicMock - _name = _kwargs.pop('name', _name) - - _new_name = _name - if _parent is None: - # for a top level object no _new_name should be set - _new_name = '' - mock = Klass(parent=_parent, _new_parent=_parent, _new_name=_new_name, name=_name, **_kwargs) diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py index 3932bb99..24815952 100644 --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -525,9 +525,13 @@ def urlunsplit(components): empty query; the RFC states that these are equivalent).""" scheme, netloc, url, query, fragment, _coerce_result = ( _coerce_args(*components)) - if netloc or (scheme and scheme in uses_netloc) or url[:2] == '//': + if netloc: if url and url[:1] != '/': url = '/' + url - url = '//' + (netloc or '') + url + url = '//' + netloc + url + elif url[:2] == '//': + url = '//' + url + elif scheme and scheme in uses_netloc and (not url or url[:1] == '/'): + url = '//' + url if scheme: url = scheme + ':' + url if query: diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py index 7228a355..9a559f44 100644 --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -1681,12 +1681,27 @@ def data_open(self, req): def url2pathname(pathname): """OS-specific conversion from a relative URL of the 'file' scheme to a file system path; not recommended for general use.""" - return unquote(pathname) + if pathname[:3] == '///': + # URL has an empty authority section, so the path begins on the + # third character. + pathname = pathname[2:] + elif pathname[:12] == '//localhost/': + # Skip past 'localhost' authority. + pathname = pathname[11:] + encoding = sys.getfilesystemencoding() + errors = sys.getfilesystemencodeerrors() + return unquote(pathname, encoding=encoding, errors=errors) def pathname2url(pathname): """OS-specific conversion from a file system path to a relative URL of the 'file' scheme; not recommended for general use.""" - return quote(pathname) + if pathname[:2] == '//': + # Add explicitly empty authority to avoid interpreting the path + # as authority. + pathname = '//' + pathname + encoding = sys.getfilesystemencoding() + errors = sys.getfilesystemencodeerrors() + return quote(pathname, encoding=encoding, errors=errors) ftpcache = {} diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py index d5dec4ab..aeb522c3 100644 --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -11,6 +11,7 @@ import sys import sysconfig import types +import shlex CORE_VENV_DEPS = ('pip',) @@ -422,11 +423,41 @@ def replace_variables(self, text, context): :param context: The information for the environment creation request being processed. """ - text = text.replace('__VENV_DIR__', context.env_dir) - text = text.replace('__VENV_NAME__', context.env_name) - text = text.replace('__VENV_PROMPT__', context.prompt) - text = text.replace('__VENV_BIN_NAME__', context.bin_name) - text = text.replace('__VENV_PYTHON__', context.env_exe) + replacements = { + '__VENV_DIR__': context.env_dir, + '__VENV_NAME__': context.env_name, + '__VENV_PROMPT__': context.prompt, + '__VENV_BIN_NAME__': context.bin_name, + '__VENV_PYTHON__': context.env_exe, + } + + def quote_ps1(s): + """ + This should satisfy PowerShell quoting rules [1], unless the quoted + string is passed directly to Windows native commands [2]. + [1]: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules + [2]: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_parsing#passing-arguments-that-contain-quote-characters + """ + s = s.replace("'", "''") + return f"'{s}'" + + def quote_bat(s): + return s + + # gh-124651: need to quote the template strings properly + quote = shlex.quote + script_path = context.script_path + if script_path.endswith('.ps1'): + quote = quote_ps1 + elif script_path.endswith('.bat'): + quote = quote_bat + else: + # fallbacks to POSIX shell compliant quote + quote = shlex.quote + + replacements = {key: quote(s) for key, s in replacements.items()} + for key, quoted in replacements.items(): + text = text.replace(key, quoted) return text def install_scripts(self, context, path): @@ -466,6 +497,7 @@ def install_scripts(self, context, path): with open(srcfile, 'rb') as f: data = f.read() if not srcfile.endswith(('.exe', '.pdb')): + context.script_path = srcfile try: data = data.decode('utf-8') data = self.replace_variables(data, context) diff --git a/Lib/venv/scripts/common/activate b/Lib/venv/scripts/common/activate index d5914e0c..74825877 100644 --- a/Lib/venv/scripts/common/activate +++ b/Lib/venv/scripts/common/activate @@ -14,8 +14,9 @@ deactivate () { unset _OLD_VIRTUAL_PYTHONHOME fi - # Call hash to forget past commands. Without forgetting - # past commands the $PATH changes we made may not be respected + # Call hash to forget past locations. Without forgetting + # past locations the $PATH changes we made may not be respected. + # See "man bash" for more details. hash is usually a builtin of your shell hash -r 2> /dev/null if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then @@ -39,14 +40,14 @@ deactivate nondestructive if [ "${OSTYPE:-}" = "cygwin" ] || [ "${OSTYPE:-}" = "msys" ] ; then # transform D:\path\to\venv to /d/path/to/venv on MSYS # and to /cygdrive/d/path/to/venv on Cygwin - export VIRTUAL_ENV=$(cygpath "__VENV_DIR__") + export VIRTUAL_ENV=$(cygpath __VENV_DIR__) else # use the path as-is - export VIRTUAL_ENV="__VENV_DIR__" + export VIRTUAL_ENV=__VENV_DIR__ fi _OLD_VIRTUAL_PATH="$PATH" -PATH="$VIRTUAL_ENV/__VENV_BIN_NAME__:$PATH" +PATH="$VIRTUAL_ENV/"__VENV_BIN_NAME__":$PATH" export PATH # unset PYTHONHOME if set @@ -59,9 +60,9 @@ fi if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then _OLD_VIRTUAL_PS1="${PS1:-}" - PS1="__VENV_PROMPT__${PS1:-}" + PS1=__VENV_PROMPT__"${PS1:-}" export PS1 - VIRTUAL_ENV_PROMPT="__VENV_PROMPT__" + VIRTUAL_ENV_PROMPT=__VENV_PROMPT__ export VIRTUAL_ENV_PROMPT fi diff --git a/Lib/venv/scripts/nt/activate.bat b/Lib/venv/scripts/nt/activate.bat index 5daa45af..c2c6dd29 100644 --- a/Lib/venv/scripts/nt/activate.bat +++ b/Lib/venv/scripts/nt/activate.bat @@ -8,7 +8,7 @@ if defined _OLD_CODEPAGE ( "%SystemRoot%\System32\chcp.com" 65001 > nul ) -set VIRTUAL_ENV=__VENV_DIR__ +set "VIRTUAL_ENV=__VENV_DIR__" if not defined PROMPT set PROMPT=$P$G @@ -24,8 +24,8 @@ set PYTHONHOME= if defined _OLD_VIRTUAL_PATH set PATH=%_OLD_VIRTUAL_PATH% if not defined _OLD_VIRTUAL_PATH set _OLD_VIRTUAL_PATH=%PATH% -set PATH=%VIRTUAL_ENV%\__VENV_BIN_NAME__;%PATH% -set VIRTUAL_ENV_PROMPT=__VENV_PROMPT__ +set "PATH=%VIRTUAL_ENV%\__VENV_BIN_NAME__;%PATH%" +set "VIRTUAL_ENV_PROMPT=__VENV_PROMPT__" :END if defined _OLD_CODEPAGE ( diff --git a/Lib/venv/scripts/posix/activate.csh b/Lib/venv/scripts/posix/activate.csh index 5e8d66fa..08f79296 100644 --- a/Lib/venv/scripts/posix/activate.csh +++ b/Lib/venv/scripts/posix/activate.csh @@ -9,17 +9,17 @@ alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PA # Unset irrelevant variables. deactivate nondestructive -setenv VIRTUAL_ENV "__VENV_DIR__" +setenv VIRTUAL_ENV __VENV_DIR__ set _OLD_VIRTUAL_PATH="$PATH" -setenv PATH "$VIRTUAL_ENV/__VENV_BIN_NAME__:$PATH" +setenv PATH "$VIRTUAL_ENV/"__VENV_BIN_NAME__":$PATH" set _OLD_VIRTUAL_PROMPT="$prompt" if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then - set prompt = "__VENV_PROMPT__$prompt" - setenv VIRTUAL_ENV_PROMPT "__VENV_PROMPT__" + set prompt = __VENV_PROMPT__"$prompt" + setenv VIRTUAL_ENV_PROMPT __VENV_PROMPT__ endif alias pydoc python -m pydoc diff --git a/Lib/venv/scripts/posix/activate.fish b/Lib/venv/scripts/posix/activate.fish index 91ad6442..508cab0d 100644 --- a/Lib/venv/scripts/posix/activate.fish +++ b/Lib/venv/scripts/posix/activate.fish @@ -33,10 +33,10 @@ end # Unset irrelevant variables. deactivate nondestructive -set -gx VIRTUAL_ENV "__VENV_DIR__" +set -gx VIRTUAL_ENV __VENV_DIR__ set -gx _OLD_VIRTUAL_PATH $PATH -set -gx PATH "$VIRTUAL_ENV/__VENV_BIN_NAME__" $PATH +set -gx PATH "$VIRTUAL_ENV/"__VENV_BIN_NAME__ $PATH # Unset PYTHONHOME if set. if set -q PYTHONHOME @@ -56,7 +56,7 @@ if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" set -l old_status $status # Output the venv prompt; color taken from the blue of the Python logo. - printf "%s%s%s" (set_color 4B8BBE) "__VENV_PROMPT__" (set_color normal) + printf "%s%s%s" (set_color 4B8BBE) __VENV_PROMPT__ (set_color normal) # Restore the return status of the previous command. echo "exit $old_status" | . @@ -65,5 +65,5 @@ if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" end set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" - set -gx VIRTUAL_ENV_PROMPT "__VENV_PROMPT__" + set -gx VIRTUAL_ENV_PROMPT __VENV_PROMPT__ end diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py index ba6711e4..13b9e85f 100755 --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -30,7 +30,7 @@ def register(name, klass, instance=None, *, preferred=False): # Preferred browsers go to the front of the list. # Need to match to the default browser returned by xdg-settings, which # may be of the form e.g. "firefox.desktop". - if preferred or (_os_preferred_browser and name in _os_preferred_browser): + if preferred or (_os_preferred_browser and f'{name}.desktop' == _os_preferred_browser): _tryorder.insert(0, name) else: _tryorder.append(name) @@ -77,6 +77,9 @@ def open(url, new=0, autoraise=True): - 1: a new browser window. - 2: a new browser page ("tab"). If possible, autoraise raises the window (the default) or not. + + If opening the browser succeeds, return True. + If there is a problem, return False. """ if _tryorder is None: with _lock: diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py index fd2cc870..c657b52d 100644 --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -201,7 +201,7 @@ def __len__(self): def __bool__(self): warnings.warn( - "Testing an element's truth value will raise an exception in " + "Testing an element's truth value will always return True in " "future versions. " "Use specific 'len(elem)' or 'elem is not None' test instead.", DeprecationWarning, stacklevel=2 diff --git a/Lib/zipfile/__init__.py b/Lib/zipfile/__init__.py index 91358156..cf71c6db 100644 --- a/Lib/zipfile/__init__.py +++ b/Lib/zipfile/__init__.py @@ -295,7 +295,7 @@ def _EndRecData(fpin): fpin.seek(-sizeEndCentDir, 2) except OSError: return None - data = fpin.read() + data = fpin.read(sizeEndCentDir) if (len(data) == sizeEndCentDir and data[0:4] == stringEndArchive and data[-2:] == b"\000\000"): @@ -315,9 +315,9 @@ def _EndRecData(fpin): # record signature. The comment is the last item in the ZIP file and may be # up to 64K long. It is assumed that the "end of central directory" magic # number does not appear in the comment. - maxCommentStart = max(filesize - (1 << 16) - sizeEndCentDir, 0) + maxCommentStart = max(filesize - ZIP_MAX_COMMENT - sizeEndCentDir, 0) fpin.seek(maxCommentStart, 0) - data = fpin.read() + data = fpin.read(ZIP_MAX_COMMENT + sizeEndCentDir) start = data.rfind(stringEndArchive) if start >= 0: # found the magic number; attempt to unpack and interpret diff --git a/Lib/zipfile/_path/__init__.py b/Lib/zipfile/_path/__init__.py index 78c41356..645cfafd 100644 --- a/Lib/zipfile/_path/__init__.py +++ b/Lib/zipfile/_path/__init__.py @@ -1,3 +1,12 @@ +""" +A Path-like interface for zipfiles. + +This codebase is shared between zipfile.Path in the stdlib +and zipp in PyPI. See +https://github.com/python/importlib_metadata/wiki/Development-Methodology +for more detail. +""" + import io import posixpath import zipfile @@ -34,7 +43,7 @@ def _parents(path): def _ancestry(path): """ Given a path with elements separated by - posixpath.sep, generate all elements of that path + posixpath.sep, generate all elements of that path. >>> list(_ancestry('b/d')) ['b/d', 'b'] @@ -46,9 +55,14 @@ def _ancestry(path): ['b'] >>> list(_ancestry('')) [] + + Multiple separators are treated like a single. + + >>> list(_ancestry('//b//d///f//')) + ['//b//d///f', '//b//d', '//b'] """ path = path.rstrip(posixpath.sep) - while path and path != posixpath.sep: + while path.rstrip(posixpath.sep): yield path path, tail = posixpath.split(path) @@ -174,7 +188,10 @@ def _extract_text_encoding(encoding=None, *args, **kwargs): class Path: """ - A pathlib-compatible interface for zip files. + A :class:`importlib.resources.abc.Traversable` interface for zip files. + + Implements many of the features users enjoy from + :class:`pathlib.Path`. Consider a zip file with this structure:: @@ -286,7 +303,7 @@ def open(self, mode='r', *args, pwd=None, **kwargs): if self.is_dir(): raise IsADirectoryError(self) zip_mode = mode[0] - if not self.exists() and zip_mode == 'r': + if zip_mode == 'r' and not self.exists(): raise FileNotFoundError(self) stream = self.root.open(self.at, zip_mode, pwd=pwd) if 'b' in mode: diff --git a/Lib/zipfile/_path/glob.py b/Lib/zipfile/_path/glob.py index 4a2e665e..d5213533 100644 --- a/Lib/zipfile/_path/glob.py +++ b/Lib/zipfile/_path/glob.py @@ -2,6 +2,19 @@ def translate(pattern): + return match_dirs(translate_core(pattern)) + + +def match_dirs(pattern): + """ + Ensure that zipfile.Path directory names are matched. + + zipfile.Path directory names always end in a slash. + """ + return rf'{pattern}[/]?' + + +def translate_core(pattern): r""" Given a glob pattern, produce a regex that matches it. diff --git a/Lib/zipimport.py b/Lib/zipimport.py index a7333a4c..7669abd6 100644 --- a/Lib/zipimport.py +++ b/Lib/zipimport.py @@ -254,17 +254,9 @@ def load_module(self, fullname): def get_resource_reader(self, fullname): - """Return the ResourceReader for a package in a zip file. - - If 'fullname' is a package within the zip file, return the - 'ResourceReader' object for the package. Otherwise return None. - """ - try: - if not self.is_package(fullname): - return None - except ZipImportError: - return None + """Return the ResourceReader for a module in a zip file.""" from importlib.readers import ZipReader + return ZipReader(self, fullname) diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index d24cb76f..90f2b685 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -246,9 +246,9 @@ def library_recipes(): result.extend([ dict( - name="OpenSSL 3.0.13", - url="https://www.openssl.org/source/openssl-3.0.13.tar.gz", - checksum='88525753f79d3bec27d2fa7c66aa0b92b3aa9498dafd93d7cfa4b3780cdae313', + name="OpenSSL 3.0.15", + url="https://github.com/openssl/openssl/releases/download/openssl-3.0.15/openssl-3.0.15.tar.gz", + checksum='23c666d0edf20f14249b3d8f0368acaee9ab585b09e1de82107c66e1f3ec9533', buildrecipe=build_universal_openssl, configure=None, install=None, @@ -264,10 +264,10 @@ def library_recipes(): tk_patches = ['backport_gh71383_fix.patch', 'tk868_on_10_8_10_9.patch', 'backport_gh110950_fix.patch'] else: - tcl_tk_ver='8.6.14' - tcl_checksum='5880225babf7954c58d4fb0f5cf6279104ce1cd6aa9b71e9a6322540e1c4de66' + tcl_tk_ver='8.6.15' + tcl_checksum='861e159753f2e2fbd6ec1484103715b0be56be3357522b858d3cbb5f893ffef1' - tk_checksum='8ffdb720f47a6ca6107eac2dd877e30b0ef7fac14f3a84ebbd0b3612cee41a94' + tk_checksum='550969f35379f952b3020f3ab7b9dd5bfd11c1ef7c9b7c6a75f5c49aca793fec' tk_patches = [] diff --git a/Mac/BuildScript/resources/ReadMe.rtf b/Mac/BuildScript/resources/ReadMe.rtf index 384840cd..a5d47e31 100644 --- a/Mac/BuildScript/resources/ReadMe.rtf +++ b/Mac/BuildScript/resources/ReadMe.rtf @@ -1,4 +1,4 @@ -{\rtf1\ansi\ansicpg1252\cocoartf2709 +{\rtf1\ansi\ansicpg1252\cocoartf2761 \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;\f2\fswiss\fcharset0 Helvetica-Oblique; \f3\fmodern\fcharset0 CourierNewPSMT;\f4\fmodern\fcharset0 Courier;} {\colortbl;\red255\green255\blue255;} @@ -11,8 +11,9 @@ \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 \f1\b \cf0 \ul \ulc0 Certificate verification and OpenSSL\ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 -\f0\b0 \ulnone \ +\f0\b0 \cf0 \ulnone \ This package includes its own private copy of OpenSSL 3.0. The trust certificates in system and user keychains managed by the \f2\i Keychain Access \f0\i0 application and the @@ -31,18 +32,21 @@ The bundled \f3 pip \f0 has its own default certificate store for verifying download connections.\ \ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 -\f1\b \ul Install Options\ +\f1\b \cf0 \ul Install Options\ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 -\f0\b0 \ulnone \ +\f0\b0 \cf0 \ulnone \ You can control some aspects of what is installed by this package. To see the options, click on the \f4 Customize \f0 button in the \f4 Installation Type \f0 step of the macOS installer app. Click on a package name in the list shown to see more information about that option,\ \ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 -\f1\b \ul Using IDLE or other Tk applications +\f1\b \cf0 \ul Using IDLE or other Tk applications \f0\b0 \ulnone \ \ This package includes its own private version of Tcl/Tk 8.6. It does not use any system-supplied or third-party supplied versions of Tcl/Tk.\ @@ -60,19 +64,30 @@ Due to new security checks on macOS 10.15 Catalina, when launching IDLE macOS ma \f0\b0 button to proceed.\ \ -\f1\b \ul Apple Silicon Mac support\ +\f1\b \ul Minimum supported macOS version is now macOS 10.13\ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 -\f0\b0 \ulnone \ -On Apple Silicon Macs, it is possible to run Python either with native ARM64 code or under Intel 64 emulation using Rosetta2. This option might be useful for testing or if binary wheels are not yet available with native ARM64 binaries. To easily force Python to run in emulation mode, invoke it from a command line shell with the +\f0\b0 \cf0 \ulnone \ +As of Python 3.12.6, as previously announced, this installer now supports running on macOS 10.13 High Sierra and newer systems. If you have a need for running Python 3.12 on older macOS systems, pre-built versions for these systems may be available from third-party distributors (such as MacPorts) or Python can be built from source ({\field{\*\fldinst{HYPERLINK "https://www.python.org/downloads/source/"}}{\fldrslt https://www.python.org/downloads/source/}}).\ + \ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 + +\f1\b \cf0 \ul Apple Silicon Mac support\ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 + +\f0\b0 \cf0 \ulnone \ +On Apple Silicon Macs, it is possible to run Python either with native ARM64 code or under Intel 64 emulation using Rosetta 2. This option might be useful for testing or if binary wheels are not yet available with native ARM64 binaries. To easily force Python to run in emulation mode, invoke it from a command line shell with the \f4 python3-intel64 \f0 command instead of just \f4 python3 \f0 .\ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 -\f1\b \ul \ +\f1\b \cf0 \ul \ Other changes\ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 -\f0\b0 \ulnone \ +\f0\b0 \cf0 \ulnone \ For other changes in this release, see the \f2\i What's new \f0\i0 section in the {\field{\*\fldinst{HYPERLINK "https://www.python.org/doc/"}}{\fldrslt Documentation Set}} for this release and its diff --git a/Mac/BuildScript/resources/install_certificates.command b/Mac/BuildScript/resources/install_certificates.command index 19b4adac..b10e18e1 100755 --- a/Mac/BuildScript/resources/install_certificates.command +++ b/Mac/BuildScript/resources/install_certificates.command @@ -10,22 +10,52 @@ import os import os.path +import platform import ssl import stat import subprocess import sys -STAT_0o775 = ( stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR - | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP - | stat.S_IROTH | stat.S_IXOTH ) +STAT_0o775 = ( + stat.S_IRUSR + | stat.S_IWUSR + | stat.S_IXUSR + | stat.S_IRGRP + | stat.S_IWGRP + | stat.S_IXGRP + | stat.S_IROTH + | stat.S_IXOTH +) + def main(): - openssl_dir, openssl_cafile = os.path.split( - ssl.get_default_verify_paths().openssl_cafile) + pip_call = [sys.executable, "-E", "-s", "-m", "pip"] + macos_release = tuple([int(n) for n in platform.mac_ver()[0].split(".")[0:2]]) + old_macos = macos_release < (10, 13) + if old_macos: + pip_version_string = subprocess.check_output(pip_call + ["-V"]).decode().strip() + # Silence warning to user to upgrade pip + pip_call.append("--disable-pip-version-check") + pip_version = tuple( + [int(n) for n in pip_version_string.split()[1].split(".")[0:2]] + ) + if pip_version >= (24, 2): + print( + f" -- WARNING: this version of pip may not work on this older version of macOS.\n" + f" found {pip_version_string}\n" + f" (See https://github.com/pypa/pip/issues/12901 for more information.)\n" + f" Attempting to revert to an older version of pip.\n" + f" -- pip install --use-deprecated=legacy-certs pip==24.1.2\n" + ) + subprocess.check_call( + pip_call + ["install", "--use-deprecated=legacy-certs", "pip==24.1.2"] + ) + openssl_dir, openssl_cafile = os.path.split( + ssl.get_default_verify_paths().openssl_cafile + ) print(" -- pip install --upgrade certifi") - subprocess.check_call([sys.executable, - "-E", "-s", "-m", "pip", "install", "--upgrade", "certifi"]) + subprocess.check_call(pip_call + ["install", "--upgrade", "certifi"]) import certifi @@ -42,7 +72,16 @@ def main(): print(" -- setting permissions") os.chmod(openssl_cafile, STAT_0o775) print(" -- update complete") + if old_macos: + print( + f" -- WARNING: Future releases of this Python installer may not support this older macOS version.\n" + ) -if __name__ == '__main__': - main() + +if __name__ == "__main__": + try: + main() + except subprocess.SubprocessError: + print(" -- WARNING: Install Certificates failed") + sys.exit(1) EOF diff --git a/Makefile.pre.in b/Makefile.pre.in index 4a957fb0..083f4c75 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -167,7 +167,7 @@ SHLIB_SUFFIX= @SHLIB_SUFFIX@ EXT_SUFFIX= @EXT_SUFFIX@ LDSHARED= @LDSHARED@ $(PY_LDFLAGS) BLDSHARED= @BLDSHARED@ $(PY_CORE_LDFLAGS) -LDCXXSHARED= @LDCXXSHARED@ +LDCXXSHARED= @LDCXXSHARED@ $(PY_LDFLAGS) DESTSHARED= $(BINLIBDEST)/lib-dynload # List of exported symbols for AIX @@ -2120,6 +2120,7 @@ LIBSUBDIRS= asyncio \ __phello__ TESTSUBDIRS= idlelib/idle_test \ test \ + test/test_ast \ test/audiodata \ test/certdata \ test/certdata/capath \ @@ -2234,6 +2235,7 @@ TESTSUBDIRS= idlelib/idle_test \ test/test_tomllib/data/valid/dates-and-times \ test/test_tomllib/data/valid/multiline-basic-str \ test/test_tools \ + test/test_tools/i18n_data \ test/test_ttk \ test/test_unittest \ test/test_unittest/testmock \ @@ -2245,6 +2247,10 @@ TESTSUBDIRS= idlelib/idle_test \ test/test_zoneinfo/data \ test/tokenizedata \ test/tracedmodules \ + test/translationdata \ + test/translationdata/argparse \ + test/translationdata/getopt \ + test/translationdata/optparse \ test/typinganndata \ test/wheeldata \ test/xmltestdata \ diff --git a/Misc/ACKS b/Misc/ACKS index 88bac0a8..0f8b79f2 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -516,6 +516,7 @@ Michael Ernst Ben Escoto Andy Eskilsson André Espaze +Lucas Esposito Stefan Esser Nicolas Estibals Jonathan Eunice @@ -722,6 +723,7 @@ Larry Hastings Tim Hatch Zac Hatfield-Dodds Shane Hathaway +Akinori Hattori Michael Haubenwallner Janko Hauser Flavian Hautbois @@ -744,6 +746,7 @@ Kasun Herath Chris Herborth Ivan Herman Jürgen Hermann +Joshua Jay Herman Gary Herron Ernie Hershey Thomas Herve @@ -1086,6 +1089,7 @@ Ivan Levkivskyi Ben Lewis William Lewis Akira Li +Jiahao Li Robert Li Xuanji Li Zekun Li @@ -1135,6 +1139,7 @@ Mark Lutz Taras Lyapun Jim Lynch Mikael Lyngvig +Ilya Lyubavski Jeff MacDonald John Machin Andrew I MacIntyre @@ -1303,6 +1308,7 @@ Hrvoje Nikšić Gregory Nofi Jesse Noller Bill Noon +Janek Nouvertné Stefan Norberg Tim Northover Joe Norton @@ -1633,6 +1639,7 @@ Scott Schram Robin Schreiber Chad J. Schroeder Simon-Martin Schroeder +Brian Schubert Christian Schubert Sam Schulenburg Andreas Schwab @@ -1787,6 +1794,7 @@ Reuben Sumner Eryk Sun Sanjay Sundaresan Marek Šuppa +Danica J. Sutherland Hisao Suzuki Kalle Svensson Andrew Svetlov diff --git a/Misc/HISTORY b/Misc/HISTORY index 3cf3a0bf..08b53c02 100644 --- a/Misc/HISTORY +++ b/Misc/HISTORY @@ -3952,7 +3952,7 @@ Library - Issue #18626: the inspect module now offers a basic command line introspection interface (Initial patch by Claudiu Popa) -- Issue #3015: Fixed tkinter with wantobject=False. Any Tcl command call +- Issue #3015: Fixed tkinter with ``wantobjects=False``. Any Tcl command call returned empty string. - Issue #19037: The mailbox module now makes all changes to maildir files @@ -5590,7 +5590,7 @@ Library - Issue #16248: Disable code execution from the user's home directory by tkinter when the -E flag is passed to Python. Patch by Zachary Ware. -- Issue #13390: New function :func:`sys.getallocatedblocks()` returns the +- Issue #13390: New function :func:`sys.getallocatedblocks` returns the number of memory blocks currently allocated. - Issue #16628: Fix a memory leak in ctypes.resize(). @@ -6157,7 +6157,7 @@ Tests starting with a ".". Patch by Sebastian Kreft. - Issue #13390: The ``-R`` option to regrtest now also checks for memory - allocation leaks, using :func:`sys.getallocatedblocks()`. + allocation leaks, using :func:`sys.getallocatedblocks`. - Issue #16559: Add more tests for the json module, including some from the official test suite at json.org. Patch by Serhiy Storchaka. diff --git a/Misc/NEWS b/Misc/NEWS index db250160..ce9de61c 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,6 +2,1023 @@ Python News +++++++++++ +What's New in Python 3.12.8 final? +================================== + +*Release date: 2024-12-03* + +macOS +----- + +- gh-124448: Update bundled Tcl/Tk in macOS installer to 8.6.15. + +Windows +------- + +- gh-126911: Update credits command output. + +- gh-125315: Avoid crashing in :mod:`platform` due to slow WMI calls on some + Windows machines. + +- gh-125550: Enable the :ref:`launcher` to detect Python 3.14 installs from + the Windows Store. + +- gh-124448: Updated bundled Tcl/Tk to 8.6.15. + +Tools/Demos +----------- + +- gh-126807: Fix extraction warnings in :program:`pygettext.py` caused by + mistaking function definitions for function calls. + +Tests +----- + +- gh-126909: Fix test_os extended attribute tests to work on filesystems + with 1 KiB xattr size limit. + +- gh-125041: Re-enable skipped tests for :mod:`zlib` on the s390x + architecture: only skip checks of the compressed bytes, which can be + different between zlib's software implementation and the + hardware-accelerated implementation. + +- gh-124295: Add translation tests to the :mod:`argparse` module. + +Security +-------- + +- gh-126623: Upgrade libexpat to 2.6.4 + +Library +------- + +- gh-127303: Publicly expose :data:`~token.EXACT_TOKEN_TYPES` in + :attr:`!token.__all__`. + +- gh-123967: Fix faulthandler for trampoline frames. If the top-most frame + is a trampoline frame, skip it. Patch by Victor Stinner. + +- gh-127182: Fix :meth:`!io.StringIO.__setstate__` crash, when :const:`None` + was passed as the first value. + +- gh-127217: Fix :func:`urllib.request.pathname2url` for paths starting with + multiple slashes on Posix. + +- gh-127035: Fix :mod:`shutil.which` on Windows. Now it looks at direct + match if and only if the command ends with a PATHEXT extension or X_OK is + not in mode. Support extensionless files if "." is in PATHEXT. Support + PATHEXT extensions that end with a dot. + +- gh-127078: Fix issue where :func:`urllib.request.url2pathname` failed to + discard an extra slash before a UNC drive in the URL path on Windows. + +- gh-126766: Fix issue where :func:`urllib.request.url2pathname` failed to + discard any 'localhost' authority present in the URL. + +- gh-126997: Fix support of STRING and GLOBAL opcodes with non-ASCII + arguments in :mod:`pickletools`. :func:`pickletools.dis` now outputs + non-ASCII bytes in STRING, BINSTRING and SHORT_BINSTRING arguments as + escaped (``\xXX``). + +- gh-126618: Fix the representation of :class:`itertools.count` objects when + the count value is :data:`sys.maxsize`. + +- gh-85168: Fix issue where :func:`urllib.request.url2pathname` and + :func:`~urllib.request.pathname2url` always used UTF-8 when quoting and + unquoting file URIs. They now use the :term:`filesystem encoding and error + handler`. + +- gh-67877: Fix memory leaks when :mod:`regular expression ` matching + terminates abruptly, either because of a signal or because memory + allocation fails. + +- gh-126789: Fixed the values of :py:func:`sysconfig.get_config_vars`, + :py:func:`sysconfig.get_paths`, and their siblings when the :py:mod:`site` + initialization happens after :py:mod:`sysconfig` has built a cache for + :py:func:`sysconfig.get_config_vars`. + +- gh-126188: Update bundled pip to 24.3.1 + +- gh-126766: Fix issue where :func:`urllib.request.url2pathname` failed to + discard two leading slashes introducing an empty authority section. + +- gh-126727: ``locale.nl_langinfo(locale.ERA)`` now returns multiple era + description segments separated by semicolons. Previously it only returned + the first segment on platforms with Glibc. + +- gh-126699: Allow :class:`collections.abc.AsyncIterator` to be a base for + Protocols. + +- gh-104745: Limit starting a patcher (from :func:`unittest.mock.patch` or + :func:`unittest.mock.patch.object`) more than once without stopping it + +- gh-126595: Fix a crash when instantiating :class:`itertools.count` with an + initial count of :data:`sys.maxsize` on debug builds. Patch by Bénédikt + Tran. + +- gh-120423: Fix issue where :func:`urllib.request.pathname2url` mishandled + Windows paths with embedded forward slashes. + +- gh-126565: Improve performances of :meth:`zipfile.Path.open` for + non-reading modes. + +- gh-126505: Fix bugs in compiling case-insensitive :mod:`regular + expressions ` with character classes containing non-BMP characters: + upper-case non-BMP character did was ignored and the ASCII flag was + ignored when matching a character range whose upper bound is beyond the + BMP region. + +- gh-117378: Fixed the :mod:`multiprocessing` ``"forkserver"`` start method + forkserver process to correctly inherit the parent's :data:`sys.path` + during the importing of :func:`multiprocessing.set_forkserver_preload` + modules in the same manner as :data:`sys.path` is configured in workers + before executing work items. + + This bug caused some forkserver module preloading to silently fail to + preload. This manifested as a performance degration in child processes + when the ``sys.path`` was required due to additional repeated work in + every worker. + + It could also have a side effect of ``""`` remaining in :data:`sys.path` + during forkserver preload imports instead of the absolute path from + :func:`os.getcwd` at multiprocessing import time used in the worker + ``sys.path``. + + The ``sys.path`` differences between phases in the child process could + potentially have caused preload to import incorrect things from the wrong + location. We are unaware of that actually having happened in practice. + +- gh-125679: The :class:`multiprocessing.Lock` and + :class:`multiprocessing.RLock` ``repr`` values no longer say "unknown" on + macOS. + +- gh-126476: Raise :class:`calendar.IllegalMonthError` (now a subclass of + :class:`IndexError`) for :func:`calendar.month` when the input month is + not correct. + +- gh-126489: The Python implementation of :mod:`pickle` no longer calls + :meth:`pickle.Pickler.persistent_id` for the result of + :meth:`!persistent_id`. + +- gh-126303: Fix pickling and copying of :class:`os.sched_param` objects. + +- gh-126138: Fix a use-after-free crash on :class:`asyncio.Task` objects + whose underlying coroutine yields an object that implements an evil + :meth:`~object.__getattribute__`. Patch by Nico Posada. + +- gh-126220: Fix crash in :class:`!cProfile.Profile` and + :class:`!_lsprof.Profiler` when their callbacks were directly called with + 0 arguments. + +- gh-126212: Fix issue where :func:`urllib.request.pathname2url` and + :func:`~urllib.request.url2pathname` removed slashes from Windows DOS + drive paths and URLs. + +- gh-126205: Fix issue where :func:`urllib.request.pathname2url` generated + URLs beginning with four slashes (rather than two) when given a Windows + UNC path. + +- gh-126105: Fix a crash in :mod:`ast` when the :attr:`ast.AST._fields` + attribute is deleted. + +- gh-126106: Fixes a possible ``NULL`` pointer dereference in :mod:`ssl`. + +- gh-126080: Fix a use-after-free crash on :class:`asyncio.Task` objects for + which the underlying event loop implements an evil + :meth:`~object.__getattribute__`. Reported by Nico-Posada. Patch by + Bénédikt Tran. + +- gh-126083: Fixed a reference leak in :class:`asyncio.Task` objects when + reinitializing the same object with a non-``None`` context. Patch by Nico + Posada. + +- gh-125984: Fix use-after-free crashes on :class:`asyncio.Future` objects + for which the underlying event loop implements an evil + :meth:`~object.__getattribute__`. Reported by Nico-Posada. Patch by + Bénédikt Tran. + +- gh-125969: Fix an out-of-bounds crash when an evil + :meth:`asyncio.loop.call_soon` mutates the length of the internal + callbacks list. Patch by Bénédikt Tran. + +- gh-125966: Fix a use-after-free crash in + :meth:`asyncio.Future.remove_done_callback`. Patch by Bénédikt Tran. + +- gh-125789: Fix possible crash when mutating list of callbacks returned by + :attr:`!asyncio.Future._callbacks`. It now always returns a new copy in C + implementation :mod:`!_asyncio`. Patch by Kumar Aditya. + +- gh-124452: Fix an issue in + :meth:`email.policy.EmailPolicy.header_source_parse` and + :meth:`email.policy.Compat32.header_source_parse` that introduced spurious + leading whitespaces into header values when the header includes a newline + character after the header name delimiter (``:``) and before the value. + +- gh-125884: Fixed the bug for :mod:`pdb` where it can't set breakpoints on + functions with certain annotations. + +- gh-125355: Fix several bugs in + :meth:`argparse.ArgumentParser.parse_intermixed_args`. + + * The parser no longer changes temporarily during parsing. + * Default values are not processed twice. + * Required mutually exclusive groups containing positional arguments are now supported. + * The missing arguments report now includes the names of all required optional and positional arguments. + * Unknown options can be intermixed with positional arguments in parse_known_intermixed_args(). + +- gh-125682: Reject non-ASCII digits in the Python implementation of + :func:`json.loads` conforming to the JSON specification. + +- gh-125660: Reject invalid unicode escapes for Python implementation of + :func:`json.loads`. + +- gh-125259: Fix the notes removal logic for errors thrown in enum + initialization. + +- gh-125519: Improve traceback if :func:`importlib.reload` is called with an + object that is not a module. Patch by Alex Waygood. + +- gh-125451: Fix deadlock when + :class:`concurrent.futures.ProcessPoolExecutor` shuts down concurrently + with an error when feeding a job to a worker process. + +- gh-125422: Fixed the bug where :mod:`pdb` and :mod:`bdb` can step into the + bottom caller frame. + +- gh-100141: Fixed the bug where :mod:`pdb` will be stuck in an infinite + loop when debugging an empty file. + +- gh-53203: Fix :func:`time.strptime` for ``%c``, ``%x`` and ``%X`` formats + in many locales that use non-ASCII digits, like Persian, Burmese, Odia and + Shan. + +- gh-125254: Fix a bug where ArgumentError includes the incorrect ambiguous + option in :mod:`argparse`. + +- gh-61011: Fix inheritance of nested mutually exclusive groups from parent + parser in :class:`argparse.ArgumentParser`. Previously, all nested + mutually exclusive groups lost their connection to the group containing + them and were displayed as belonging directly to the parser. + +- gh-52551: Fix encoding issues in :func:`time.strftime`, the + :meth:`~datetime.datetime.strftime` method of the :mod:`datetime` classes + :class:`~datetime.datetime`, :class:`~datetime.date` and + :class:`~datetime.time` and formatting of these classes. Characters not + encodable in the current locale are now acceptable in the format string. + Surrogate pairs and sequence of surrogatescape-encoded bytes are no longer + recombinated. Embedded null character no longer terminates the format + string. + +- gh-125118: Don't copy arbitrary values to :c:expr:`_Bool` in the + :mod:`struct` module. + +- gh-125069: Fix an issue where providing a :class:`pathlib.PurePath` object + as an initializer argument to a second :class:`~pathlib.PurePath` object + with a different flavour resulted in arguments to the former object's + initializer being joined by the latter object's flavour. + +- gh-124969: Fix ``locale.nl_langinfo(locale.ALT_DIGITS)`` on platforms with + glibc. Now it returns a string consisting of up to 100 semicolon-separated + symbols (an empty string in most locales) on all Posix platforms. + Previously it only returned the first symbol or an empty string. + +- gh-124958: Fix refcycles in exceptions raised from + :class:`asyncio.TaskGroup` and the python implementation of + :class:`asyncio.Future` + +- gh-53203: Fix :func:`time.strptime` for ``%c`` and ``%x`` formats in many + locales: Arabic, Bislama, Breton, Bodo, Kashubian, Chuvash, Estonian, + French, Irish, Ge'ez, Gurajati, Manx Gaelic, Hebrew, Hindi, Chhattisgarhi, + Haitian Kreyol, Japanese, Kannada, Korean, Marathi, Malay, Norwegian, + Nynorsk, Punjabi, Rajasthani, Tok Pisin, Yoruba, Yue Chinese, Yau/Nungon + and Chinese. + +- gh-124917: Allow calling :func:`os.path.exists` and + :func:`os.path.lexists` with keyword arguments on Windows. Fixes a + regression in 3.12.4. + +- gh-124653: Fix detection of the minimal Queue API needed by the + :mod:`logging` module. Patch by Bénédikt Tran. + +- gh-124858: Fix reference cycles left in tracebacks in + :func:`asyncio.open_connection` when used with ``happy_eyeballs_delay`` + +- gh-124390: Fixed :exc:`AssertionError` when using + :func:`!asyncio.staggered.staggered_race` with + :attr:`asyncio.eager_task_factory`. + +- gh-124651: Properly quote template strings in :mod:`venv` activation + scripts. + +- gh-124594: All :mod:`asyncio` REPL prompts run in the same :class:`context + `. Contributed by Bartosz Sławecki. + +- gh-120378: Fix a crash related to an integer overflow in + :func:`curses.resizeterm` and :func:`curses.resize_term`. + +- gh-123884: Fixed bug in itertools.tee() handling of other tee inputs (a + tee in a tee). The output now has the promised *n* independent new + iterators. Formerly, the first iterator was identical (not independent) + to the input iterator. This would sometimes give surprising results. + +- gh-123978: Remove broken :func:`time.thread_time` and + :func:`time.thread_time_ns` on NetBSD. + +- gh-124008: Fix possible crash (in debug build), incorrect output or + returning incorrect value from raw binary ``write()`` when writing to + console on Windows. + +- gh-123370: Fix the canvas not clearing after running turtledemo clock. + +- gh-120754: Update unbounded ``read`` calls in :mod:`zipfile` to specify an + explicit ``size`` putting a limit on how much data they may read. This + also updates handling around ZIP max comment size to match the standard + instead of reading comments that are one byte too long. + +- gh-70764: Fixed an issue where :func:`inspect.getclosurevars` would + incorrectly classify an attribute name as a global variable when the name + exists both as an attribute name and a global variable. + +- gh-119826: Always return an absolute path for :func:`os.path.abspath` on + Windows. + +- gh-117766: Always use :func:`str` to print ``choices`` in :mod:`argparse`. + +- gh-101955: Fix SystemError when match regular expression pattern + containing some combination of possessive quantifier, alternative and + capture group. + +- gh-88110: Fixed :class:`multiprocessing.Process` reporting a ``.exitcode`` + of 1 even on success when using the ``"fork"`` start method while using a + :class:`concurrent.futures.ThreadPoolExecutor`. + +- gh-71936: Fix a race condition in :class:`multiprocessing.pool.Pool`. + +- bpo-46128: Strip :class:`unittest.IsolatedAsyncioTestCase` stack frames + from reported stacktraces. + +- bpo-14074: Fix :mod:`argparse` metavar processing to allow positional + arguments to have a tuple metavar. + +IDLE +---- + +- gh-122392: Increase currently inadequate vertical spacing for the IDLE + browsers (path, module, and stack) on high-resolution monitors. + +Documentation +------------- + +- gh-125277: Require Sphinx 7.2.6 or later to build the Python + documentation. Patch by Adam Turner. + +- gh-125018: The :mod:`importlib.metadata` documentation now includes + semantic cross-reference targets for the significant documented APIs. This + means intersphinx references like :func:`importlib.metadata.version` will + now work as expected. + +- gh-121277: Writers of CPython's documentation can now use ``next`` as the + version for the ``versionchanged``, ``versionadded``, ``deprecated`` + directives. + +- gh-60712: Include the :class:`object` type in the lists of documented + types. Change by Furkan Onder and Martin Panter. + +Core and Builtins +----------------- + +- gh-113841: Fix possible undefined behavior division by zero in + :class:`complex`'s :c:func:`_Py_c_pow`. + +- gh-126341: Now :exc:`ValueError` is raised instead of :exc:`SystemError` + when trying to iterate over a released :class:`memoryview` object. + +- gh-126066: Fix :mod:`importlib` to not write an incomplete .pyc files when + a ulimit or some other operating system mechanism is preventing the write + to go through fully. + +- gh-126139: Provide better error location when attempting to use a + :term:`future statement <__future__>` with an unknown future feature. + +- gh-125008: Fix :func:`tokenize.untokenize` producing invalid syntax for + double braces preceded by certain escape characters. + +- gh-123378: Fix a crash in the :meth:`~object.__str__` method of + :exc:`UnicodeError` objects when the :attr:`UnicodeError.start` and + :attr:`UnicodeError.end` values are invalid or out-of-range. Patch by + Bénédikt Tran. + +- gh-116510: Fix a crash caused by immortal interned strings being shared + between sub-interpreters that use basic single-phase init. In that case, + the string can be used by an interpreter that outlives the interpreter + that created and interned it. For interpreters that share obmalloc state, + also share the interned dict with the main interpreter. + +- gh-118950: Fix bug where SSLProtocol.connection_lost wasn't getting called + when OSError was thrown on writing to socket. + +- gh-113570: Fixed a bug in ``reprlib.repr`` where it incorrectly called the + repr method on shadowed Python built-in types. + +- gh-109746: If :func:`!_thread.start_new_thread` fails to start a new + thread, it deletes its state from interpreter and thus avoids its repeated + cleanup on finalization. + +C API +----- + +- gh-113601: Removed debug build assertions related to interning strings, + which were falsely triggered by stable ABI extensions. + +Build +----- + +- gh-89640: Hard-code float word ordering as little endian on WASM. + +- gh-89640: Improve detection of float word ordering on Linux when link-time + optimizations are enabled. + + +What's New in Python 3.12.7 final? +================================== + +*Release date: 2024-10-01* + +Windows +------- + +- gh-123915: Ensure that ``Tools\msi\buildrelease.bat`` uses different + directories for AMD64 and ARM64 builds. + +- gh-117505: Fixes an issue with the Windows installer not running ensurepip + in a fully isolated environment. This could cause unexpected interactions + with the user site-packages. + +Tests +----- + +- gh-124378: Updated ``test_ttk`` to pass with Tcl/Tk 8.6.15. + +Security +-------- + +- gh-122792: Changed IPv4-mapped ``ipaddress.IPv6Address`` to consistently + use the mapped IPv4 address value for deciding properties. Properties + which have their behavior fixed are ``is_multicast``, ``is_reserved``, + ``is_link_local``, ``is_global``, and ``is_unspecified``. + +Library +------- + +- gh-116850: Fix :mod:`argparse` for namespaces with not directly writable + dict (e.g. classes). + +- gh-58573: Fix conflicts between abbreviated long options in the parent + parser and subparsers in :mod:`argparse`. + +- gh-61181: Fix support of :ref:`choices` with string value in + :mod:`argparse`. Substrings of the specified string no longer considered + valid values. + +- gh-80259: Fix :mod:`argparse` support of positional arguments with + ``nargs='?'``, ``default=argparse.SUPPRESS`` and specified ``type``. + +- gh-124498: Fix :class:`typing.TypeAliasType` not to be generic, when + ``type_params`` is an empty tuple. + +- gh-124345: :mod:`argparse` vim supports abbreviated single-dash long + options separated by ``=`` from its value. + +- gh-104860: Fix disallowing abbreviation of single-dash long options in + :mod:`argparse` with ``allow_abbrev=False``. + +- gh-63143: Fix parsing mutually exclusive arguments in :mod:`argparse`. + Arguments with the value identical to the default value (e.g. booleans, + small integers, empty or 1-character strings) are no longer considered + "not present". + +- gh-72795: Positional arguments with :ref:`nargs` equal to ``'*'`` or + :data:`!argparse.REMAINDER` are no longer required. This allows to use + positional argument with ``nargs='*'`` and without ``default`` in mutually + exclusive group and improves error message about required arguments. + +- gh-59317: Fix parsing positional argument with :ref:`nargs` equal to + ``'?'`` or ``'*'`` if it is preceded by an option and another positional + argument. + +- gh-53780: :mod:`argparse` now ignores the first ``"--"`` (double dash) + between an option and command. + +- gh-124217: Add RFC 9637 reserved IPv6 block ``3fff::/20`` in + :mod:`ipaddress` module. + +- gh-124248: Fixed potential crash when using :mod:`struct` to process + zero-width 'Pascal string' fields (``0p``). + +- gh-81691: Fix handling of multiple ``"--"`` (double dashes) in + :mod:`argparse`. Only the first one has now been removed, all subsequent + ones are now taken literally. + +- gh-87041: Fix a bug in :mod:`argparse` where lengthy subparser argument + help is incorrectly indented. + +- gh-124171: Add workaround for broken :c:func:`!fmod()` implementations on + Windows, that loose zero sign (e.g. ``fmod(-10, 1)`` returns ``0.0``). + Patch by Sergey B Kirpichev. + +- gh-123934: Fix :class:`unittest.mock.MagicMock` reseting magic methods + return values after ``.reset_mock(return_value=True)`` was called. + +- gh-123935: Fix parent slots detection for dataclasses that inherit from + classes with ``__dictoffset__``. + +- gh-123892: Add ``"_wmi"`` to :data:`sys.stdlib_module_names`. Patch by + Victor Stinner. + +- gh-116810: Resolve a memory leak introduced in CPython 3.10's :mod:`ssl` + when the :attr:`ssl.SSLSocket.session` property was accessed. Speeds up + read and write access to said property by no longer unnecessarily cloning + session objects via serialization. + +- gh-121735: When working with zip archives, importlib.resources now + properly honors module-adjacent references (e.g. ``files(pkg.mod)`` and + not just ``files(pkg)``). + +- gh-119004: Fix a crash in :ref:`OrderedDict.__eq__ + ` when operands are mutated during the + check. Patch by Bénédikt Tran. + +- bpo-44864: Do not translate user-provided strings in + :class:`argparse.ArgumentParser`. + +IDLE +---- + +- gh-112938: Fix uninteruptable hang when Shell gets rapid continuous + output. + +Core and Builtins +----------------- + +- gh-116510: Fix a bug that can cause a crash when sub-interpreters use + "basic" single-phase extension modules. Shared objects could refer to + PyGC_Head nodes that had been freed as part of interpreter cleanup. + +- gh-124188: Fix reading and decoding a line from the source file witn + non-UTF-8 encoding for syntax errors raised in the compiler. + +- gh-77894: Fix possible crash in the garbage collector when it tries to + break a reference loop containing a :class:`memoryview` object. Now a + :class:`!memoryview` object can only be cleared if there are no buffers + that refer it. + +- gh-98442: Fix too wide source locations of the cleanup instructions of a + with statement. + +- gh-113993: Strings interned with :func:`sys.intern` are again + garbage-collected when no longer used, as per the documentation. Strings + interned with the C function :c:func:`PyUnicode_InternInPlace` are still + immortal. Internals of the string interning mechanism have been changed. + This may affect performance and identities of :class:`str` objects. + +C API +----- + +- gh-113993: :c:func:`PyUnicode_InternInPlace` no longer prevents its + argument from being garbage collected. + + Several functions that take ``char *`` are now documented as possibly + preventing string objects from being garbage collected; refer to their + documentation for details: :c:func:`PyUnicode_InternFromString`, + :c:func:`PyDict_SetItemString`, :c:func:`PyObject_SetAttrString`, + :c:func:`PyObject_DelAttrString`, :c:func:`PyUnicode_InternFromString`, + and ``PyModule_Add*`` convenience functions. + +Build +----- + +- gh-124487: Windows builds now use Windows 8.1 as their API baseline + (installation already required Windows 8.1). + +- gh-123917: Fix the check for the ``crypt()`` function in the configure + script. Patch by Paul Smith and Victor Stinner. + + +What's New in Python 3.12.6 final? +================================== + +*Release date: 2024-09-06* + +macOS +----- + +- gh-123418: Updated macOS installer build to use OpenSSL 3.0.15. + +Windows +------- + +- gh-123418: Updated Windows build to use OpenSSL 3.0.15. + +- gh-100256: :mod:`mimetypes` no longer fails when it encounters an + inaccessible registry key. + +- gh-79846: Makes :code:`ssl.create_default_context()` ignore invalid + certificates in the Windows certificate store + +Tools/Demos +----------- + +- gh-123418: Update GitHub CI workflows to use OpenSSL 3.0.15 and + multissltests to use 3.0.15, 3.1.7, and 3.2.3. + +Tests +----- + +- gh-101525: Skip ``test_gdb`` if the binary is relocated by BOLT. Patch by + Donghee Na. + +Security +-------- + +- gh-123678: Upgrade libexpat to 2.6.3 + +- gh-121285: Remove backtracking from tarfile header parsing for + ``hdrcharset``, PAX, and GNU sparse headers. + +Library +------- + +- gh-123270: Applied a more surgical fix for malformed payloads in + :class:`zipfile.Path` causing infinite loops (gh-122905) without breaking + contents using legitimate characters. + +- gh-123213: :meth:`xml.etree.ElementTree.Element.extend` and + :class:`~xml.etree.ElementTree.Element` assignment no longer hide the + internal exception if an erronous generator is passed. Patch by Bar Harel. + +- gh-85110: Preserve relative path in URL without netloc in + :func:`urllib.parse.urlunsplit` and :func:`urllib.parse.urlunparse`. + +- gh-123067: Fix quadratic complexity in parsing ``"``-quoted cookie values + with backslashes by :mod:`http.cookies`. + +- gh-122903: ``zipfile.Path.glob`` now correctly matches directories instead + of silently omitting them. + +- gh-122905: :class:`zipfile.Path` objects now sanitize names from the + zipfile. + +- gh-122695: Fixed double-free when using :func:`gc.get_referents` with a + freed :class:`asyncio.Future` iterator. + +- gh-116263: :class:`logging.handlers.RotatingFileHandler` no longer rolls + over empty log files. + +- gh-118814: Fix the :class:`typing.TypeVar` constructor when name is passed + by keyword. + +- gh-122478: Remove internal frames from tracebacks shown in + :class:`code.InteractiveInterpreter` with non-default + :func:`sys.excepthook`. Save correct tracebacks in + :attr:`sys.last_traceback` and update ``__traceback__`` attribute of + :attr:`sys.last_value` and :attr:`sys.last_exc`. + +- gh-113785: :mod:`csv` now correctly parses numeric fields (when used with + :const:`csv.QUOTE_NONNUMERIC`) which start with an escape character. + +- gh-112182: :meth:`!asyncio.futures.Future.set_exception` now transforms + :exc:`StopIteration` into :exc:`RuntimeError` instead of hanging or other + misbehavior. Patch contributed by Jamie Phan. + +- gh-108172: ``webbrowser`` honors OS preferred browser on Linux when its + desktop entry name contains the text of a known browser name. + +- gh-102988: :func:`email.utils.getaddresses` and + :func:`email.utils.parseaddr` now return ``('', '')`` 2-tuples in more + situations where invalid email addresses are encountered instead of + potentially inaccurate values. Add optional *strict* parameter to these + two functions: use ``strict=False`` to get the old behavior, accept + malformed inputs. ``getattr(email.utils, 'supports_strict_parsing', + False)`` can be use to check if the *strict* paramater is available. Patch + by Thomas Dwyer and Victor Stinner to improve the CVE-2023-27043 fix. + +- gh-99437: :func:`runpy.run_path` now decodes path-like objects, making + sure __file__ and sys.argv[0] of the module being run are always strings. + +IDLE +---- + +- gh-120083: Add explicit black IDLE Hovertip foreground color needed for + recent macOS. Fixes Sonoma showing unreadable white on pale yellow. Patch + by John Riggles. + +Core and Builtins +----------------- + +- gh-123321: Prevent Parser/myreadline race condition from segfaulting on + multi-threaded use. Patch by Bar Harel and Amit Wienner. + +- gh-122982: Extend the deprecation period for bool inversion (``~``) by two + years. + +- gh-123229: Fix valgrind warning by initializing the f-string buffers to 0 + in the tokenizer. Patch by Pablo Galindo + +- gh-123142: Fix too-wide source location in exception tracebacks coming + from broken iterables in comprehensions. + +- gh-123048: Fix a bug where pattern matching code could emit a + :opcode:`JUMP_FORWARD` with no source location. + +- gh-123083: Fix a potential use-after-free in ``STORE_ATTR_WITH_HINT``. + +- gh-122527: Fix a crash that occurred when a ``PyStructSequence`` was + deallocated after its type's dictionary was cleared by the GC. The type's + :c:member:`~PyTypeObject.tp_basicsize` now accounts for non-sequence + fields that aren't included in the :c:macro:`Py_SIZE` of the sequence. + +- gh-93691: Fix source locations of instructions generated for with + statements. + +Build +----- + +- gh-123297: Propagate the value of ``LDFLAGS`` to ``LDCXXSHARED`` in + :mod:`sysconfig`. Patch by Pablo Galindo + + +What's New in Python 3.12.5 final? +================================== + +*Release date: 2024-08-06* + +Windows +------- + +- gh-122573: The Windows build of CPython now requires 3.10 or newer. + +Tests +----- + +- gh-59022: Add tests for :func:`pkgutil.extend_path`. Patch by Andreas + Stocker. + +- gh-99242: :func:`os.getloadavg` may throw :exc:`OSError` when running + regression tests under certain conditions (e.g. chroot). This error is now + caught and ignored, since reporting load average is optional. + +- gh-121084: Fix test_typing random leaks. Clear typing ABC caches when + running tests for refleaks (``-R`` option): call ``_abc_caches_clear()`` + on typing abstract classes and their subclasses. Patch by Victor Stinner. + +- gh-121160: Add a test for :func:`readline.set_history_length`. Note that + this test may fail on readline libraries. + +- gh-121200: Fix ``test_expanduser_pwd2()`` of ``test_posixpath``. Call + ``getpwnam()`` to get ``pw_dir``, since it can be different than + ``getpwall()`` ``pw_dir``. Patch by Victor Stinner. + +- gh-121188: When creating the JUnit XML file, regrtest now escapes + characters which are invalid in XML, such as the chr(27) control character + used in ANSI escape sequences. Patch by Victor Stinner. + +Security +-------- + +- gh-121957: Fixed missing audit events around interactive use of Python, + now also properly firing for ``python -i``, as well as for ``python -m + asyncio``. The event in question is ``cpython.run_stdin``. + +- gh-122133: Authenticate the socket connection for the + ``socket.socketpair()`` fallback on platforms where ``AF_UNIX`` is not + available like Windows. + + Patch by Gregory P. Smith and Seth Larson + . Reported by Ellie + +Library +------- + +- gh-122744: Bump the version of pip bundled in ensurepip to version 24.2. + +- gh-122334: Fix crash when importing :mod:`ssl` after the main interpreter + restarts. + +- gh-87320: In :class:`code.InteractiveInterpreter`, handle exceptions + caused by calling a non-default :func:`sys.excepthook`. Before, the + exception bubbled up to the caller, ending the REPL. + +- gh-122400: Handle :exc:`ValueError`\s raised by :func:`os.stat` in + :class:`filecmp.dircmp` and :func:`filecmp.cmpfiles`. Patch by Bénédikt + Tran. + +- gh-122311: Fix some error messages in :mod:`pickle`. + +- gh-121650: :mod:`email` headers with embedded newlines are now quoted on + output. The :mod:`~email.generator` will now refuse to serialize (write) + headers that are unsafely folded or delimited; see + :attr:`~email.policy.Policy.verify_generated_headers`. (Contributed by Bas + Bloemsaat and Petr Viktorin in :gh:`121650`.) + +- gh-122332: Fixed segfault with :meth:`asyncio.Task.get_coro` when using an + eager task factory. + +- gh-122170: Handle :exc:`ValueError`\s raised by :func:`os.stat` in + :mod:`linecache`. Patch by Bénédikt Tran. + +- gh-121723: Make :func:`logging.config.dictConfig` accept any object + implementing the Queue public API. See the :ref:`queue configuration + ` section for details. Patch by Bénédikt Tran. + +- gh-82951: Serializing objects with complex ``__qualname__`` (such as + unbound methods and nested classes) by name no longer involves serializing + parent objects by value in pickle protocols < 4. + +- gh-120930: Fixed a bug introduced by gh-92081 that added an incorrect + extra blank to encoded words occurring in wrapped headers. + +- gh-121474: Fix missing sanity check for ``parties`` arg in + :class:`threading.Barrier` constructor. Patch by Clinton Christian + (pygeek). + +- gh-121025: Improve the :meth:`~object.__repr__` of + :class:`functools.partialmethod`. Patch by Bénédikt Tran. + +- gh-121018: Fixed issues where :meth:`!argparse.ArgumentParser.parse_args` + did not honor ``exit_on_error=False``. Based on patch by Ben Hsing. + +- gh-119614: Fix truncation of strings with embedded null characters in some + internal operations in :mod:`tkinter`. + +- gh-120910: When reading installed files from an egg, use + ``relative_to(walk_up=True)`` to honor files installed outside of the + installation root. + +- gh-101830: Accessing the :mod:`tkinter` object's string representation no + longer converts the underlying Tcl object to a string on Windows. + +- gh-120811: Fix possible memory leak in :meth:`contextvars.Context.run`. + +- gh-120769: Make empty line in :mod:`pdb` repeats the last command even + when the command is from ``cmdqueue``. + +- gh-120732: Fix ``name`` passing to :class:`unittest.mock.Mock` object when + using :func:`unittest.mock.create_autospec`. + +- gh-120495: Fix incorrect exception handling in Tab Nanny. Patch by + Wulian233. + +- gh-120343: Fix column offset reporting for tokens that come after + multiline f-strings in the :mod:`tokenize` module. + +- gh-119600: Fix :func:`unittest.mock.patch` to not read attributes of the + target when ``new_callable`` is set. Patch by Robert Collins. + +- gh-120289: Fixed the use-after-free issue in :mod:`cProfile` by + disallowing ``disable()`` and ``clear()`` in external timers. + +- gh-114053: Fix edge-case bug where :func:`typing.get_type_hints` would + produce incorrect results if type parameters in a class scope were + overridden by assignments in a class scope and ``from __future__ import + annotations`` semantics were enabled. Patch by Alex Waygood. + +- gh-114053: Fix erroneous :exc:`NameError` when calling + :func:`inspect.get_annotations` with ``eval_str=True``` on a class that + made use of :pep:`695` type parameters in a module that had ``from + __future__ import annotations`` at the top of the file. Patch by Alex + Waygood. + +- gh-120268: Prohibit passing ``None`` to pure-Python + :meth:`datetime.date.fromtimestamp` to achieve consistency with + C-extension implementation. + +- gh-120244: Fix memory leak in :func:`re.sub` when the replacement string + contains backreferences. + +- gh-120211: Fix :mod:`tkinter.ttk` with Tcl/Tk 9.0. + +- gh-71587: Fix crash in C version of :meth:`datetime.datetime.strptime` + when called again on the restarted interpreter. + +- gh-117983: Defer the ``threading`` import in ``importlib.util`` until lazy + loading is used. + +- gh-119698: Fix :meth:`symtable.Class.get_methods` and document its + behaviour. Patch by Bénédikt Tran. + +- gh-120121: Add :exc:`concurrent.futures.InvalidStateError` to module's + ``__all__``. + +- gh-112672: Support building :mod:`tkinter` with Tcl 9.0. + +- gh-65454: :func:`unittest.mock.Mock.attach_mock` no longer triggers a call + to a ``PropertyMock`` being attached. + +- gh-81936: :meth:`!help` and :meth:`!showtopic` methods now respect a + configured *output* argument to :class:`!pydoc.Helper` and not use the + pager in such cases. Patch by Enrico Tröger. + +- gh-119577: The :exc:`DeprecationWarning` emitted when testing the truth + value of an :class:`xml.etree.ElementTree.Element` now describes + unconditionally returning ``True`` in a future version rather than raising + an exception in Python 3.14. + +- gh-119506: Fix :meth:`!io.TextIOWrapper.write` method breaks internal + buffer when the method is called again during flushing internal buffer. + +- gh-119189: When using the ``**`` operator or :func:`pow` with + :class:`~fractions.Fraction` as the base and an exponent that is not + rational, a float, or a complex, the fraction is no longer converted to a + float. + +- gh-105623: Fix performance degradation in + :class:`logging.handlers.RotatingFileHandler`. Patch by Craig Robson. + +- bpo-39324: Add mime type mapping for .md <-> text/markdown + +IDLE +---- + +- gh-122482: Change About IDLE to direct users to discuss.python.org instead + of the now unused idle-dev email and mailing list. + +- gh-78889: Stop Shell freezes by blocking user access to non-method + sys.stdout.shell attributes, which are all private. + +- gh-120104: Fix padding in config and search dialog windows in IDLE. + +Documentation +------------- + +- gh-121749: Fix documentation for :c:func:`PyModule_AddObjectRef`. + +- gh-120012: Clarify the behaviours of :meth:`multiprocessing.Queue.empty` + and :meth:`multiprocessing.SimpleQueue.empty` on closed queues. Patch by + Bénédikt Tran. + +Core and Builtins +----------------- + +- gh-122208: Dictionary watchers now only deliver the PyDict_EVENT_ADDED + event when the insertion is in a known good state to succeed. + +- gh-122300: Preserve AST nodes for f-string with single-element format + specifiers. Patch by Pablo Galindo + +- gh-122029: Emit ``c_call`` events in :func:`sys.setprofile` when a + ``PyMethodObject`` pointing to a ``PyCFunction`` is called. + +- gh-122026: Fix a bug that caused the tokenizer to not correctly identify + mismatched parentheses inside f-strings in some situations. Patch by Pablo + Galindo + +- gh-121657: Improve the :exc:`SyntaxError` message if the user tries to use + :keyword:`yield from ` outside a function. + +- gh-117482: Unexpected slot wrappers are no longer created for builtin + static types in subinterpreters. + +- gh-121439: Allow tuples of length 20 in the freelist to be reused. + +- gh-121130: Fix f-strings with debug expressions in format specifiers. + Patch by Pablo Galindo + +- gh-120722: Correctly set the bytecode position on return instructions + within lambdas. Patch by Jelle Zijlstra. + +- gh-120384: Fix an array out of bounds crash in ``list_ass_subscript``, + which could be invoked via some specificly tailored input: including + concurrent modification of a list object, where one thread assigns a slice + and another clears it. + +- gh-120380: Fix Python implementation of :class:`pickle.Pickler` for + :class:`bytes` and :class:`bytearray` objects when using protocol version + 5. Patch by Bénédikt Tran. + +- gh-93691: Fix source locations of instructions generated for the iterator + of a for statement. + +- gh-120198: Fix a crash when multiple threads read and write to the same + ``__class__`` of an object concurrently. + +- gh-120298: Fix use-after free in ``list_richcompare_impl`` which can be + invoked via some specificly tailored evil input. + +- gh-119666: Fix a compiler crash in the case where two comprehensions in + class scope both reference ``__class__``. + +- bpo-24766: Fix handling of ``doc`` argument to subclasses of ``property``. + +Build +----- + +- gh-120671: Fix failing configure tests due to a missing space when + appending to CFLAGS. + +- gh-115983: Skip building test modules that must be built as shared under + WASI. + + What's New in Python 3.12.4 final? ================================== @@ -10,136 +1027,134 @@ What's New in Python 3.12.4 final? Security -------- -- gh-issue-118486: :func:`os.mkdir` on Windows now accepts *mode* of - ``0o700`` to restrict the new directory to the current user. This fixes +- gh-118486: :func:`os.mkdir` on Windows now accepts *mode* of ``0o700`` to + restrict the new directory to the current user. This fixes :cve:`2024-4030` affecting :func:`tempfile.mkdtemp` in scenarios where the base temporary directory is more permissive than the default. -- gh-issue-116741: Update bundled libexpat to 2.6.2 +- gh-116741: Update bundled libexpat to 2.6.2 -- gh-issue-117233: Detect BLAKE2, SHA3, Shake, & truncated SHA512 support in - the OpenSSL-ish libcrypto library at build time. This allows - :mod:`hashlib` to be used with libraries that do not to support every - algorithm that upstream OpenSSL does. +- gh-117233: Detect BLAKE2, SHA3, Shake, & truncated SHA512 support in the + OpenSSL-ish libcrypto library at build time. This allows :mod:`hashlib` + to be used with libraries that do not to support every algorithm that + upstream OpenSSL does. Core and Builtins ----------------- -- gh-issue-119821: Fix execution of :ref:`annotation scopes - ` within classes when ``globals`` is set to a non-dict. - Patch by Jelle Zijlstra. - -- gh-issue-118263: Speed up :func:`os.path.normpath` with a direct C call. - -- gh-issue-119311: Fix bug where names are unexpectedly mangled in the bases - of generic classes. +- gh-119821: Fix execution of :ref:`annotation scopes ` + within classes when ``globals`` is set to a non-dict. Patch by Jelle + Zijlstra. -- gh-issue-119395: Fix bug where names appearing after a generic class are - mangled as if they are in the generic class. +- gh-119311: Fix bug where names are unexpectedly mangled in the bases of + generic classes. -- gh-issue-118507: Fix :func:`os.path.isfile` on Windows for pipes. +- gh-119395: Fix bug where names appearing after a generic class are mangled + as if they are in the generic class. -- gh-issue-119213: Non-builtin modules built with argument clinic were - crashing if used in a subinterpreter before the main interpreter. The - objects that were causing the problem by leaking between interpreters - carelessly have been fixed. +- gh-119213: Non-builtin modules built with argument clinic were crashing if + used in a subinterpreter before the main interpreter. The objects that + were causing the problem by leaking between interpreters carelessly have + been fixed. -- gh-issue-119011: Fixes ``type.__type_params__`` to return an empty tuple - instead of a descriptor. +- gh-119011: Fixes ``type.__type_params__`` to return an empty tuple instead + of a descriptor. -- gh-issue-118997: Fix _Py_ClearImmortal() assertion: use _Py_IsImmortal() - to tolerate reference count lower than _Py_IMMORTAL_REFCNT. Fix the - assertion for the stable ABI, when a C extension is built with Python 3.11 - or lower. Patch by Victor Stinner. +- gh-118997: Fix _Py_ClearImmortal() assertion: use _Py_IsImmortal() to + tolerate reference count lower than _Py_IMMORTAL_REFCNT. Fix the assertion + for the stable ABI, when a C extension is built with Python 3.11 or lower. + Patch by Victor Stinner. -- gh-issue-118513: Fix incorrect :exc:`UnboundLocalError` when two - comprehensions in the same function both reference the same name, and in - one comprehension the name is bound while in the other it's an implicit +- gh-118513: Fix incorrect :exc:`UnboundLocalError` when two comprehensions + in the same function both reference the same name, and in one + comprehension the name is bound while in the other it's an implicit global. -- gh-issue-118164: Break a loop between the Python implementation of the +- gh-118164: Break a loop between the Python implementation of the :mod:`decimal` module and the Python code for integer to string conversion. Also optimize integer to string conversion for values in the range from 9_000 to 135_000 decimal digits. -- gh-issue-118272: Fix bug where ``generator.close`` does not free the - generator frame's locals. +- gh-118272: Fix bug where ``generator.close`` does not free the generator + frame's locals. -- gh-issue-116767: Fix crash in compiler on 'async with' that has many - context managers. +- gh-116767: Fix crash in compiler on 'async with' that has many context + managers. -- gh-issue-117894: Prevent ``agen.aclose()`` objects being re-used after +- gh-117894: Prevent ``agen.aclose()`` objects being re-used after ``.throw()``. -- gh-issue-117881: prevent concurrent access to an async generator via +- gh-117881: prevent concurrent access to an async generator via athrow().throw() or asend().throw() -- gh-issue-115874: Fixed a possible segfault during garbage collection of +- gh-115874: Fixed a possible segfault during garbage collection of ``_asyncio.FutureIter`` objects Library ------- -- gh-issue-119819: Fix regression to allow logging configuration with +- gh-119819: Fix regression to allow logging configuration with multiprocessing queue types. -- gh-issue-89727: Fix issue with :func:`shutil.rmtree` where a +- gh-89727: Fix issue with :func:`shutil.rmtree` where a :exc:`RecursionError` is raised on deep directory trees. -- gh-issue-89727: Partially fix issue with :func:`shutil.rmtree` where a +- gh-89727: Partially fix issue with :func:`shutil.rmtree` where a :exc:`RecursionError` is raised on deep directory trees. A recursion error is no longer raised when :data:`!rmtree.avoids_symlink_attacks` is false. -- gh-issue-119118: Fix performance regression in the :mod:`tokenize` module - by caching the ``line`` token attribute and calculating the column offset +- gh-119118: Fix performance regression in the :mod:`tokenize` module by + caching the ``line`` token attribute and calculating the column offset more efficiently. -- gh-issue-89727: Fix issue with :func:`os.fwalk` where a - :exc:`RecursionError` was raised on deep directory trees by adjusting the - implementation to be iterative instead of recursive. +- gh-89727: Fix issue with :func:`os.fwalk` where a :exc:`RecursionError` + was raised on deep directory trees by adjusting the implementation to be + iterative instead of recursive. -- gh-issue-113892: Now, the method ``sock_connect`` of +- gh-118263: Speed up :func:`os.path.normpath` with a direct C call. + +- gh-113892: Now, the method ``sock_connect`` of :class:`asyncio.ProactorEventLoop` raises a :exc:`ValueError` if given socket is not in non-blocking mode, as well as in other loop implementations. -- gh-issue-119174: Fix high DPI causes turtledemo(turtle-graphics examples) +- gh-118507: Fix :func:`os.path.isfile` on Windows for pipes. + +- gh-119174: Fix high DPI causes turtledemo(turtle-graphics examples) windows blurry Patch by Wulian233 and Terry Jan Reedy -- gh-issue-118643: Fix an AttributeError in the :mod:`email` module when - re-fold a long address list. Also fix more cases of incorrect encoding of - the address separator in the address list. +- gh-118643: Fix an AttributeError in the :mod:`email` module when re-fold a + long address list. Also fix more cases of incorrect encoding of the + address separator in the address list. -- gh-issue-58933: Make :mod:`pdb` return to caller frame correctly when +- gh-58933: Make :mod:`pdb` return to caller frame correctly when ``f_trace`` of the caller frame is not set -- gh-issue-118868: Fixed issue where kwargs were no longer passed to the - logging handler QueueHandler +- gh-118868: Fixed issue where kwargs were no longer passed to the logging + handler QueueHandler -- gh-issue-118164: The Python implementation of the ``decimal`` module could +- gh-118164: The Python implementation of the ``decimal`` module could appear to hang in relatively small power cases (like ``2**117``) if context precision was set to a very high value. A different method to check for exactly representable results is used now that doesn't rely on computing ``10**precision`` (which could be effectively too large to compute). -- gh-issue-118404: Fix :func:`inspect.signature` for non-comparable - callables. +- gh-118404: Fix :func:`inspect.signature` for non-comparable callables. -- gh-issue-118314: Fix an edge case in :func:`binascii.a2b_base64` strict - mode, where excessive padding is not detected when no padding is - necessary. +- gh-118314: Fix an edge case in :func:`binascii.a2b_base64` strict mode, + where excessive padding is not detected when no padding is necessary. -- gh-issue-118042: Fix an unraisable exception in +- gh-118042: Fix an unraisable exception in :meth:`!telnetlib.Telnet.__del__` when the ``__init__()`` method was not called. -- gh-issue-118221: Fix a bug where :func:`!sqlite3.iterdump` could fail if a +- gh-118221: Fix a bug where :func:`!sqlite3.iterdump` could fail if a custom :attr:`row factory ` was used. Patch by Erlend Aasland. -- gh-issue-118013: Fix regression introduced in gh-103193 that meant that - calling :func:`inspect.getattr_static` on an instance would cause a strong +- gh-118013: Fix regression introduced in gh-103193 that meant that calling + :func:`inspect.getattr_static` on an instance would cause a strong reference to that instance's class to persist in an internal cache in the :mod:`inspect` module. This caused unexpected memory consumption if the class was dynamically created, the class held strong references to other @@ -149,61 +1164,61 @@ Library function should still be significantly faster than it was in Python 3.11. Patch by Alex Waygood. -- gh-issue-90848: Fixed :func:`unittest.mock.create_autospec` to configure - parent mock with keyword arguments. +- gh-90848: Fixed :func:`unittest.mock.create_autospec` to configure parent + mock with keyword arguments. -- gh-issue-118168: Fix incorrect argument substitution when - :data:`typing.Unpack` is used with the builtin :class:`tuple`. - :data:`!typing.Unpack` now raises :exc:`TypeError` when used with certain - invalid types. Patch by Jelle Zijlstra. +- gh-118168: Fix incorrect argument substitution when :data:`typing.Unpack` + is used with the builtin :class:`tuple`. :data:`!typing.Unpack` now raises + :exc:`TypeError` when used with certain invalid types. Patch by Jelle + Zijlstra. -- gh-issue-118033: Fix :func:`dataclasses.dataclass` not creating a +- gh-118033: Fix :func:`dataclasses.dataclass` not creating a ``__weakref__`` slot when subclassing :class:`typing.Generic`. -- gh-issue-117535: Do not try to get the source line for made up file name - "sys" in :mod:`warnings`. +- gh-117535: Do not try to get the source line for made up file name "sys" + in :mod:`warnings`. -- gh-issue-114053: Fix erroneous :exc:`NameError` when calling +- gh-114053: Fix erroneous :exc:`NameError` when calling :func:`typing.get_type_hints` on a class that made use of :pep:`695` type parameters in a module that had ``from __future__ import annotations`` at the top of the file. Patch by Alex Waygood. -- gh-issue-117995: Don't raise :exc:`DeprecationWarning` when a - :term:`sequence` of parameters is used to bind indexed, nameless - placeholders. See also :gh:`100668`. +- gh-117995: Don't raise :exc:`DeprecationWarning` when a :term:`sequence` + of parameters is used to bind indexed, nameless placeholders. See also + :gh:`100668`. -- gh-issue-80361: Fix TypeError in :func:`email.message.Message.get_payload` - when the charset is :rfc:`2231` encoded. +- gh-80361: Fix TypeError in :func:`email.message.Message.get_payload` when + the charset is :rfc:`2231` encoded. -- gh-issue-86650: Fix IndexError when parse some emails with invalid - Message-ID (including one-off addresses generated by Microsoft Outlook). +- gh-86650: Fix IndexError when parse some emails with invalid Message-ID + (including one-off addresses generated by Microsoft Outlook). -- gh-issue-117691: Improve the error messages emitted by :mod:`tarfile` +- gh-117691: Improve the error messages emitted by :mod:`tarfile` deprecation warnings relating to PEP 706. If a ``filter`` argument is not provided to ``extract()`` or ``extractall``, the deprecation warning now points to the line in the user's code where the relevant function was called. Patch by Alex Waygood. -- gh-issue-77102: :mod:`site` module now parses ``.pth`` file with UTF-8 - first, and :term:`locale encoding` if ``UnicodeDecodeError`` happened. It +- gh-77102: :mod:`site` module now parses ``.pth`` file with UTF-8 first, + and :term:`locale encoding` if ``UnicodeDecodeError`` happened. It supported only locale encoding before. -- gh-issue-117692: Fixes a bug when :class:`doctest.DocTestFinder` was - failing on wrapped ``builtin_function_or_method``. +- gh-117692: Fixes a bug when :class:`doctest.DocTestFinder` was failing on + wrapped ``builtin_function_or_method``. -- gh-issue-117566: :meth:`ipaddress.IPv6Address.is_loopback` will now return +- gh-117566: :meth:`ipaddress.IPv6Address.is_loopback` will now return ``True`` for IPv4-mapped loopback addresses, i.e. addresses in the ``::ffff:127.0.0.0/104`` address space. -- gh-issue-117503: Fix support of non-ASCII user names in bytes paths in +- gh-117503: Fix support of non-ASCII user names in bytes paths in :func:`os.path.expanduser` on Posix. -- gh-issue-117313: Only treat ``'\n'``, ``'\r'`` and ``'\r\n'`` as line - separators in re-folding the :mod:`email` messages. Preserve control - characters ``'\v'``, ``'\f'``, ``'\x1c'``, ``'\x1d'`` and ``'\x1e'`` and - Unicode line separators ``'\x85'``, ``'\u2028'`` and ``'\u2029'`` as is. +- gh-117313: Only treat ``'\n'``, ``'\r'`` and ``'\r\n'`` as line separators + in re-folding the :mod:`email` messages. Preserve control characters + ``'\v'``, ``'\f'``, ``'\x1c'``, ``'\x1d'`` and ``'\x1e'`` and Unicode line + separators ``'\x85'``, ``'\u2028'`` and ``'\u2029'`` as is. -- gh-issue-113171: Fixed various false positives and false negatives in +- gh-113171: Fixed various false positives and false negatives in * :attr:`ipaddress.IPv4Address.is_private` (see these docs for details) * :attr:`ipaddress.IPv4Address.is_global` @@ -213,19 +1228,19 @@ Library Also in the corresponding :class:`ipaddress.IPv4Network` and :class:`ipaddress.IPv6Network` attributes. -- gh-issue-103956: Fix lack of newline characters in :mod:`trace` module - output when line tracing is enabled but source code line for current frame - is not available. +- gh-103956: Fix lack of newline characters in :mod:`trace` module output + when line tracing is enabled but source code line for current frame is not + available. -- gh-issue-92081: Fix missing spaces in email headers when the spaces are - mixed with encoded 8-bit characters. +- gh-92081: Fix missing spaces in email headers when the spaces are mixed + with encoded 8-bit characters. -- gh-issue-103194: Prepare Tkinter for C API changes in Tcl 8.7/9.0 to avoid +- gh-103194: Prepare Tkinter for C API changes in Tcl 8.7/9.0 to avoid :class:`_tkinter.Tcl_Obj` being unexpectedly returned instead of :class:`bool`, :class:`str`, :class:`bytearray`, or :class:`int`. -- gh-issue-87106: Fixed handling in :meth:`inspect.Signature.bind` of - keyword arguments having the same name as positional-only arguments when a +- gh-87106: Fixed handling in :meth:`inspect.Signature.bind` of keyword + arguments having the same name as positional-only arguments when a variadic keyword argument (e.g. ``**kwargs``) is present. - bpo-45767: Fix integer conversion in :func:`os.major`, :func:`os.minor`, @@ -238,7 +1253,7 @@ Library - bpo-30988: Fix parsing of emails with invalid address headers having a leading or trailing dot. Patch by tsufeki. -- gh-issue-67693: Fix :func:`urllib.parse.urlunparse` and +- gh-67693: Fix :func:`urllib.parse.urlunparse` and :func:`urllib.parse.urlunsplit` for URIs with path starting with multiple slashes and no authority. Based on patch by Ashwin Ramaswami. @@ -249,45 +1264,44 @@ Library Documentation ------------- -- gh-issue-117928: The minimum Sphinx version required for the documentation - is now 6.2.1. +- gh-117928: The minimum Sphinx version required for the documentation is + now 6.2.1. -- gh-issue-91565: Changes to documentation files and config outputs to - reflect the new location for reporting bugs - i.e. GitHub rather than - bugs.python.org. +- gh-91565: Changes to documentation files and config outputs to reflect the + new location for reporting bugs - i.e. GitHub rather than bugs.python.org. Tests ----- -- gh-issue-119050: regrtest test runner: Add XML support to the refleak - checker (-R option). Patch by Victor Stinner. +- gh-119050: regrtest test runner: Add XML support to the refleak checker + (-R option). Patch by Victor Stinner. Windows ------- -- gh-issue-119690: Adds Unicode support and fixes audit events for +- gh-119690: Adds Unicode support and fixes audit events for ``_winapi.CreateNamedPipe``. -- gh-issue-119070: Fixes ``py.exe`` handling of shebangs like ``/usr/bin/env +- gh-119070: Fixes ``py.exe`` handling of shebangs like ``/usr/bin/env python3.12``, which were previously interpreted as ``python3.exe`` instead of ``python3.12.exe``. -- gh-issue-118347: Fixes launcher updates not being installed. +- gh-118347: Fixes launcher updates not being installed. -- gh-issue-115009: Update Windows installer to use SQLite 3.45.3. +- gh-115009: Update Windows installer to use SQLite 3.45.3. -- gh-issue-90329: Suppress the warning displayed on virtual environment - creation when the requested and created paths differ only by a short (8.3 - style) name. Warnings will continue to be shown if a junction or symlink - in the path caused the venv to be created in a different location than - originally requested. +- gh-90329: Suppress the warning displayed on virtual environment creation + when the requested and created paths differ only by a short (8.3 style) + name. Warnings will continue to be shown if a junction or symlink in the + path caused the venv to be created in a different location than originally + requested. macOS ----- -- gh-issue-115009: Update macOS installer to use SQLite 3.45.3. +- gh-115009: Update macOS installer to use SQLite 3.45.3. -- gh-issue-116145: Update macOS installer to Tcl/Tk 8.6.14. +- gh-116145: Update macOS installer to Tcl/Tk 8.6.14. IDLE ---- @@ -297,14 +1311,14 @@ IDLE C API ----- -- gh-issue-119585: Fix crash when a thread state that was created by +- gh-119585: Fix crash when a thread state that was created by :c:func:`PyGILState_Ensure` calls a destructor that during :c:func:`PyThreadState_Clear` that calls back into :c:func:`PyGILState_Ensure` and :c:func:`PyGILState_Release`. This might occur when in the free-threaded build or when using thread-local variables whose destructors call :c:func:`PyGILState_Ensure`. -- gh-issue-117534: Improve validation logic in the C implementation of +- gh-117534: Improve validation logic in the C implementation of :meth:`datetime.fromisoformat` to better handle invalid years. Patch by Vlad Efanov. @@ -317,7 +1331,7 @@ What's New in Python 3.12.3 final? Security -------- -- gh-issue-115398: Allow controlling Expat >=2.6.0 reparse deferral +- gh-115398: Allow controlling Expat >=2.6.0 reparse deferral (:cve:`2023-52425`) by adding five new methods: * :meth:`xml.etree.ElementTree.XMLParser.flush` @@ -326,12 +1340,12 @@ Security * :meth:`xml.parsers.expat.xmlparser.SetReparseDeferralEnabled` * :meth:`xml.sax.expatreader.ExpatParser.flush` -- gh-issue-115399: Update bundled libexpat to 2.6.0 +- gh-115399: Update bundled libexpat to 2.6.0 -- gh-issue-115243: Fix possible crashes in :meth:`collections.deque.index` - when the deque is concurrently modified. +- gh-115243: Fix possible crashes in :meth:`collections.deque.index` when + the deque is concurrently modified. -- gh-issue-114572: :meth:`ssl.SSLContext.cert_store_stats` and +- gh-114572: :meth:`ssl.SSLContext.cert_store_stats` and :meth:`ssl.SSLContext.get_ca_certs` now correctly lock access to the certificate store, when the :class:`ssl.SSLContext` is shared across multiple threads. @@ -339,126 +1353,125 @@ Security Core and Builtins ----------------- -- gh-issue-109120: Added handle of incorrect star expressions, e.g ``f(3, - *)``. Patch by Grigoryev Semyon +- gh-109120: Added handle of incorrect star expressions, e.g ``f(3, *)``. + Patch by Grigoryev Semyon -- gh-issue-99108: Updated the :mod:`hashlib` built-in `HACL\* project`_ C - code from upstream that we use for many implementations when they are not +- gh-99108: Updated the :mod:`hashlib` built-in `HACL\* project`_ C code + from upstream that we use for many implementations when they are not present via OpenSSL in a given build. This also avoids the rare potential for a C symbol name one definition rule linking issue. .. _HACL\* project: https://github.com/hacl-star/hacl-star -- gh-issue-116735: For ``INSTRUMENTED_CALL_FUNCTION_EX``, set ``arg0`` to +- gh-116735: For ``INSTRUMENTED_CALL_FUNCTION_EX``, set ``arg0`` to ``sys.monitoring.MISSING`` instead of ``None`` for :monitoring-event:`CALL` event. -- gh-issue-113964: Starting new threads and process creation through +- gh-113964: Starting new threads and process creation through :func:`os.fork` are now only prevented once all non-daemon threads exit. -- gh-issue-116604: Respect the status of the garbage collector when indirect - calls are made via :c:func:`PyErr_CheckSignals` and the evaluation - breaker. Patch by Pablo Galindo +- gh-116604: Respect the status of the garbage collector when indirect calls + are made via :c:func:`PyErr_CheckSignals` and the evaluation breaker. + Patch by Pablo Galindo -- gh-issue-116626: Ensure ``INSTRUMENTED_CALL_FUNCTION_EX`` always emits +- gh-116626: Ensure ``INSTRUMENTED_CALL_FUNCTION_EX`` always emits :monitoring-event:`CALL` -- gh-issue-116296: Fix possible refleak in :meth:`!object.__reduce__` - internal error handling. +- gh-116296: Fix possible refleak in :meth:`!object.__reduce__` internal + error handling. -- gh-issue-116034: Fix location of the error on a failed assertion. +- gh-116034: Fix location of the error on a failed assertion. -- gh-issue-115823: Properly calculate error ranges in the parser when - raising :exc:`SyntaxError` exceptions caused by invalid byte sequences. - Patch by Pablo Galindo +- gh-115823: Properly calculate error ranges in the parser when raising + :exc:`SyntaxError` exceptions caused by invalid byte sequences. Patch by + Pablo Galindo -- gh-issue-112087: For an empty reverse iterator for list will be reduced to +- gh-112087: For an empty reverse iterator for list will be reduced to :func:`reversed`. Patch by Donghee Na. -- gh-issue-115154: Fix a bug that was causing the - :func:`tokenize.untokenize` function to handle unicode named literals - incorrectly. Patch by Pablo Galindo +- gh-115154: Fix a bug that was causing the :func:`tokenize.untokenize` + function to handle unicode named literals incorrectly. Patch by Pablo + Galindo -- gh-issue-114828: Fix compilation crashes in uncommon code examples using +- gh-114828: Fix compilation crashes in uncommon code examples using :func:`super` inside a comprehension in a class body. -- gh-issue-115011: Setters for members with an unsigned integer type now - support the same range of valid values for objects that has a +- gh-115011: Setters for members with an unsigned integer type now support + the same range of valid values for objects that has a :meth:`~object.__index__` method as for :class:`int`. -- gh-issue-112215: Change the C recursion limits to more closely reflect the +- gh-112215: Change the C recursion limits to more closely reflect the underlying platform limits. -- gh-issue-96497: Fix incorrect resolution of mangled class variables used - in assignment expressions in comprehensions. +- gh-96497: Fix incorrect resolution of mangled class variables used in + assignment expressions in comprehensions. Library ------- -- gh-issue-117467: Preserve mailbox ownership when rewriting in +- gh-117467: Preserve mailbox ownership when rewriting in :func:`mailbox.mbox.flush`. Patch by Tony Mountifield. -- gh-issue-117310: Fixed an unlikely early & extra ``Py_DECREF`` triggered - crash in :mod:`ssl` when creating a new ``_ssl._SSLContext`` if CPython - was built implausibly such that the default cipher list is empty **or** - the SSL library it was linked against reports a failure from its C +- gh-117310: Fixed an unlikely early & extra ``Py_DECREF`` triggered crash + in :mod:`ssl` when creating a new ``_ssl._SSLContext`` if CPython was + built implausibly such that the default cipher list is empty **or** the + SSL library it was linked against reports a failure from its C ``SSL_CTX_set_cipher_list()`` API. -- gh-issue-117178: Fix regression in lazy loading of self-referential - modules, introduced in gh-114781. +- gh-117178: Fix regression in lazy loading of self-referential modules, + introduced in gh-114781. -- gh-issue-117084: Fix :mod:`zipfile` extraction for directory entries with - the name containing backslashes on Windows. +- gh-117084: Fix :mod:`zipfile` extraction for directory entries with the + name containing backslashes on Windows. -- gh-issue-117110: Fix a bug that prevents subclasses of :class:`typing.Any` - to be instantiated with arguments. Patch by Chris Fu. +- gh-117110: Fix a bug that prevents subclasses of :class:`typing.Any` to be + instantiated with arguments. Patch by Chris Fu. -- gh-issue-90872: On Windows, :meth:`subprocess.Popen.wait` no longer calls +- gh-90872: On Windows, :meth:`subprocess.Popen.wait` no longer calls ``WaitForSingleObject()`` with a negative timeout: pass ``0`` ms if the timeout is negative. Patch by Victor Stinner. -- gh-issue-116957: configparser: Don't leave ConfigParser values in an - invalid state (stored as a list instead of a str) after an earlier read - raised DuplicateSectionError or DuplicateOptionError. +- gh-116957: configparser: Don't leave ConfigParser values in an invalid + state (stored as a list instead of a str) after an earlier read raised + DuplicateSectionError or DuplicateOptionError. -- gh-issue-90095: Ignore empty lines and comments in ``.pdbrc`` +- gh-90095: Ignore empty lines and comments in ``.pdbrc`` -- gh-issue-116764: Restore support of ``None`` and other false values in +- gh-116764: Restore support of ``None`` and other false values in :mod:`urllib.parse` functions :func:`~urllib.parse.parse_qs` and :func:`~urllib.parse.parse_qsl`. Also, they now raise a TypeError for non-zero integers and non-empty sequences. -- gh-issue-116811: In ``PathFinder.invalidate_caches``, delegate to +- gh-116811: In ``PathFinder.invalidate_caches``, delegate to ``MetadataPathFinder.invalidate_caches``. -- gh-issue-116600: Fix :func:`repr` for global :class:`~enum.Flag` members. +- gh-116600: Fix :func:`repr` for global :class:`~enum.Flag` members. -- gh-issue-116484: Change automatically generated - :class:`tkinter.Checkbutton` widget names to avoid collisions with - automatically generated :class:`tkinter.ttk.Checkbutton` widget names - within the same parent widget. +- gh-116484: Change automatically generated :class:`tkinter.Checkbutton` + widget names to avoid collisions with automatically generated + :class:`tkinter.ttk.Checkbutton` widget names within the same parent + widget. -- gh-issue-116401: Fix blocking :func:`os.fwalk` and :func:`shutil.rmtree` - on opening named pipe. +- gh-116401: Fix blocking :func:`os.fwalk` and :func:`shutil.rmtree` on + opening named pipe. -- gh-issue-116143: Fix a race in pydoc ``_start_server``, eliminating a - window in which ``_start_server`` can return a thread that is "serving" - but without a ``docserver`` set. +- gh-116143: Fix a race in pydoc ``_start_server``, eliminating a window in + which ``_start_server`` can return a thread that is "serving" but without + a ``docserver`` set. -- gh-issue-116325: :mod:`typing`: raise :exc:`SyntaxError` instead of +- gh-116325: :mod:`typing`: raise :exc:`SyntaxError` instead of :exc:`AttributeError` on forward references as empty strings. -- gh-issue-90535: Fix support of *interval* values > 1 in +- gh-90535: Fix support of *interval* values > 1 in :class:`logging.TimedRotatingFileHandler` for ``when='MIDNIGHT'`` and ``when='Wx'``. -- gh-issue-115978: Disable preadv(), readv(), pwritev(), and writev() on - WASI. +- gh-115978: Disable preadv(), readv(), pwritev(), and writev() on WASI. Under wasmtime for WASI 0.2, these functions don't pass test_posix (https://github.com/bytecodealliance/wasmtime/issues/7830). -- gh-issue-88352: Fix the computation of the next rollover time in the +- gh-88352: Fix the computation of the next rollover time in the :class:`logging.TimedRotatingFileHandler` handler. :meth:`!computeRollover` now always returns a timestamp larger than the specified time and works correctly during the DST change. @@ -466,105 +1479,104 @@ Library saving from data loss when run at midnight or during repeated time at the DST change. -- gh-issue-87115: Set ``__main__.__spec__`` to ``None`` when running a - script with :mod:`pdb` +- gh-87115: Set ``__main__.__spec__`` to ``None`` when running a script with + :mod:`pdb` -- gh-issue-76511: Fix UnicodeEncodeError in :meth:`email.Message.as_string` - that results when a message that claims to be in the ascii character set +- gh-76511: Fix UnicodeEncodeError in :meth:`email.Message.as_string` that + results when a message that claims to be in the ascii character set actually has non-ascii characters. Non-ascii characters are now replaced with the U+FFFD replacement character, like in the ``replace`` error handler. -- gh-issue-116040: [Enum] fix by-value calls when second value is falsey; - e.g. Cardinal(1, 0) +- gh-116040: [Enum] fix by-value calls when second value is falsey; e.g. + Cardinal(1, 0) -- gh-issue-75988: Fixed :func:`unittest.mock.create_autospec` to pass the - call through to the wrapped object to return the real result. +- gh-75988: Fixed :func:`unittest.mock.create_autospec` to pass the call + through to the wrapped object to return the real result. -- gh-issue-115881: Fix issue where :func:`ast.parse` would incorrectly flag +- gh-115881: Fix issue where :func:`ast.parse` would incorrectly flag conditional context managers (such as ``with (x() if y else z()): ...``) as invalid syntax if ``feature_version=(3, 8)`` was passed. This reverts changes to the grammar made as part of gh-94949. -- gh-issue-115886: Fix silent truncation of the name with an embedded null +- gh-115886: Fix silent truncation of the name with an embedded null character in :class:`multiprocessing.shared_memory.SharedMemory`. -- gh-issue-115809: Improve algorithm for computing which rolled-over log - files to delete in :class:`logging.TimedRotatingFileHandler`. It is now - reliable for handlers without ``namer`` and with arbitrary deterministic - ``namer`` that leaves the datetime part in the file name unmodified. +- gh-115809: Improve algorithm for computing which rolled-over log files to + delete in :class:`logging.TimedRotatingFileHandler`. It is now reliable + for handlers without ``namer`` and with arbitrary deterministic ``namer`` + that leaves the datetime part in the file name unmodified. -- gh-issue-74668: :mod:`urllib.parse` functions - :func:`~urllib.parse.parse_qs` and :func:`~urllib.parse.parse_qsl` now - support bytes arguments containing raw and percent-encoded non-ASCII data. +- gh-74668: :mod:`urllib.parse` functions :func:`~urllib.parse.parse_qs` and + :func:`~urllib.parse.parse_qsl` now support bytes arguments containing raw + and percent-encoded non-ASCII data. -- gh-issue-67044: :func:`csv.writer` now always quotes or escapes ``'\r'`` - and ``'\n'``, regardless of *lineterminator* value. +- gh-67044: :func:`csv.writer` now always quotes or escapes ``'\r'`` and + ``'\n'``, regardless of *lineterminator* value. -- gh-issue-115712: :func:`csv.writer()` now quotes empty fields if delimiter - is a space and skipinitialspace is true and raises exception if quoting is - not possible. +- gh-115712: :func:`csv.writer` now quotes empty fields if delimiter is a + space and skipinitialspace is true and raises exception if quoting is not + possible. -- gh-issue-112364: Fixed :func:`ast.unparse` to handle format_spec with - ``"``, ``'`` or ``\\``. Patched by Frank Hoffmann. +- gh-112364: Fixed :func:`ast.unparse` to handle format_spec with ``"``, + ``'`` or ``\\``. Patched by Frank Hoffmann. -- gh-issue-111358: Fix a bug in +- gh-111358: Fix a bug in :meth:`asyncio.BaseEventLoop.shutdown_default_executor` to ensure the timeout passed to the coroutine behaves as expected. -- gh-issue-115618: Fix improper decreasing the reference count for ``None`` +- gh-115618: Fix improper decreasing the reference count for ``None`` argument in :class:`property` methods :meth:`~property.getter`, :meth:`~property.setter` and :meth:`~property.deleter`. -- gh-issue-115570: A :exc:`DeprecationWarning` is no longer omitted on - access to the ``__doc__`` attributes of the deprecated ``typing.io`` and +- gh-115570: A :exc:`DeprecationWarning` is no longer omitted on access to + the ``__doc__`` attributes of the deprecated ``typing.io`` and ``typing.re`` pseudo-modules. -- gh-issue-112006: Fix :func:`inspect.unwrap` for types with the - ``__wrapper__`` data descriptor. +- gh-112006: Fix :func:`inspect.unwrap` for types with the ``__wrapper__`` + data descriptor. -- gh-issue-101293: Support callables with the ``__call__()`` method and - types with ``__new__()`` and ``__init__()`` methods set to class methods, - static methods, bound methods, partial functions, and other types of - methods and descriptors in :meth:`inspect.Signature.from_callable`. +- gh-101293: Support callables with the ``__call__()`` method and types with + ``__new__()`` and ``__init__()`` methods set to class methods, static + methods, bound methods, partial functions, and other types of methods and + descriptors in :meth:`inspect.Signature.from_callable`. -- gh-issue-115392: Fix a bug in :mod:`doctest` where incorrect line numbers - would be reported for decorated functions. +- gh-115392: Fix a bug in :mod:`doctest` where incorrect line numbers would + be reported for decorated functions. -- gh-issue-114563: Fix several :func:`format()` bugs when using the C - implementation of :class:`~decimal.Decimal`: * memory leak in some rare - cases when using the ``z`` format option (coerce negative 0) * incorrect - output when applying the ``z`` format option to type ``F`` (fixed-point - with capital ``NAN`` / ``INF``) * incorrect output when applying the ``#`` - format option (alternate form) +- gh-114563: Fix several :func:`format` bugs when using the C implementation + of :class:`~decimal.Decimal`: * memory leak in some rare cases when using + the ``z`` format option (coerce negative 0) * incorrect output when + applying the ``z`` format option to type ``F`` (fixed-point with capital + ``NAN`` / ``INF``) * incorrect output when applying the ``#`` format + option (alternate form) -- gh-issue-115197: ``urllib.request`` no longer resolves the hostname before +- gh-115197: ``urllib.request`` no longer resolves the hostname before checking it against the system's proxy bypass list on macOS and Windows. -- gh-issue-115165: Most exceptions are now ignored when attempting to set - the ``__orig_class__`` attribute on objects returned when calling +- gh-115165: Most exceptions are now ignored when attempting to set the + ``__orig_class__`` attribute on objects returned when calling :mod:`typing` generic aliases (including generic aliases created using :data:`typing.Annotated`). Previously only :exc:`AttributeError` was ignored. Patch by Dave Shawley. -- gh-issue-115133: Fix tests for - :class:`~xml.etree.ElementTree.XMLPullParser` with Expat 2.6.0. +- gh-115133: Fix tests for :class:`~xml.etree.ElementTree.XMLPullParser` + with Expat 2.6.0. -- gh-issue-115059: :meth:`io.BufferedRandom.read1` now flushes the - underlying write buffer. +- gh-115059: :meth:`io.BufferedRandom.read1` now flushes the underlying + write buffer. -- gh-issue-79382: Trailing ``**`` no longer allows to match files and - non-existing paths in recursive :func:`~glob.glob`. +- gh-79382: Trailing ``**`` no longer allows to match files and non-existing + paths in recursive :func:`~glob.glob`. -- gh-issue-114071: Support tuple subclasses using auto() for enum member - value. +- gh-114071: Support tuple subclasses using auto() for enum member value. -- gh-issue-114763: Protect modules loaded with - :class:`importlib.util.LazyLoader` from race conditions when multiple - threads try to access attributes before the loading is complete. +- gh-114763: Protect modules loaded with :class:`importlib.util.LazyLoader` + from race conditions when multiple threads try to access attributes before + the loading is complete. -- gh-issue-97959: Fix rendering class methods, bound methods, method and - function aliases in :mod:`pydoc`. Class methods no longer have "method of +- gh-97959: Fix rendering class methods, bound methods, method and function + aliases in :mod:`pydoc`. Class methods no longer have "method of builtins.type instance" note. Corresponding notes are now added for class and unbound methods. Method and function aliases now have references to the module or the class where the origin was defined if it differs from @@ -572,46 +1584,45 @@ Library Methods of builtin classes are now supported as well as methods of Python classes. -- gh-issue-112281: Allow creating :ref:`union of types` for +- gh-112281: Allow creating :ref:`union of types` for :class:`typing.Annotated` with unhashable metadata. -- gh-issue-111775: Fix - :meth:`importlib.resources.simple.ResourceHandle.open` for text mode, - added missed ``stream`` argument. +- gh-111775: Fix :meth:`importlib.resources.simple.ResourceHandle.open` for + text mode, added missed ``stream`` argument. -- gh-issue-90095: Make .pdbrc and -c work with any valid pdb commands. +- gh-90095: Make .pdbrc and -c work with any valid pdb commands. -- gh-issue-107155: Fix incorrect output of ``help(x)`` where ``x`` is a +- gh-107155: Fix incorrect output of ``help(x)`` where ``x`` is a :keyword:`lambda` function, which has an ``__annotations__`` dictionary attribute with a ``"return"`` key. -- gh-issue-105866: Fixed ``_get_slots`` bug which caused error when defining +- gh-105866: Fixed ``_get_slots`` bug which caused error when defining dataclasses with slots and a weakref_slot. -- gh-issue-60346: Fix ArgumentParser inconsistent with parse_known_args. +- gh-60346: Fix ArgumentParser inconsistent with parse_known_args. -- gh-issue-100985: Update HTTPSConnection to consistently wrap IPv6 - Addresses when using a proxy. +- gh-100985: Update HTTPSConnection to consistently wrap IPv6 Addresses when + using a proxy. -- gh-issue-100884: email: fix misfolding of comma in address-lists over - multiple lines in combination with unicode encoding. +- gh-100884: email: fix misfolding of comma in address-lists over multiple + lines in combination with unicode encoding. -- gh-issue-95782: Fix :func:`io.BufferedReader.tell`, - :func:`io.BufferedReader.seek`, :func:`_pyio.BufferedReader.tell`, +- gh-95782: Fix :func:`io.BufferedReader.tell`, + :func:`io.BufferedReader.seek`, :func:`!_pyio.BufferedReader.tell`, :func:`io.BufferedRandom.tell`, :func:`io.BufferedRandom.seek` and - :func:`_pyio.BufferedRandom.tell` being able to return negative offsets. + :func:`!_pyio.BufferedRandom.tell` being able to return negative offsets. -- gh-issue-96310: Fix a traceback in :mod:`argparse` when all options in a +- gh-96310: Fix a traceback in :mod:`argparse` when all options in a mutually exclusive group are suppressed. -- gh-issue-93205: Fixed a bug in +- gh-93205: Fixed a bug in :class:`logging.handlers.TimedRotatingFileHandler` where multiple rotating handler instances pointing to files with the same name but different extensions would conflict and not delete the correct files. - bpo-44865: Add missing call to localization function in :mod:`argparse`. -- bpo-43952: Fix :meth:`multiprocessing.connection.Listener.accept()` to +- bpo-43952: Fix :meth:`multiprocessing.connection.Listener.accept` to accept empty bytes as authkey. Not accepting empty bytes as key causes it to hang indefinitely. @@ -619,9 +1630,9 @@ Library allows getting source code for the ``__main__`` module when a custom loader is used. -- gh-issue-66543: Make :func:`mimetypes.guess_type` properly parsing of URLs - with only a host name, URLs containing fragment or query, and filenames - with only a UNC sharepoint on Windows. Based on patch by Dong-hee Na. +- gh-66543: Make :func:`mimetypes.guess_type` properly parsing of URLs with + only a host name, URLs containing fragment or query, and filenames with + only a UNC sharepoint on Windows. Based on patch by Dong-hee Na. - bpo-33775: Add 'default' and 'version' help text for localization in argparse. @@ -629,112 +1640,110 @@ Library Documentation ------------- -- gh-issue-115399: Document :cve:`2023-52425` of Expat <2.6.0 under "XML +- gh-115399: Document :cve:`2023-52425` of Expat <2.6.0 under "XML vulnerabilities". -- gh-issue-115233: Fix an example for :class:`~logging.LoggerAdapter` in the +- gh-115233: Fix an example for :class:`~logging.LoggerAdapter` in the Logging Cookbook. Tests ----- -- gh-issue-83434: Disable JUnit XML output (``--junit-xml=FILE`` command - line option) in regrtest when hunting for reference leaks (``-R`` option). +- gh-83434: Disable JUnit XML output (``--junit-xml=FILE`` command line + option) in regrtest when hunting for reference leaks (``-R`` option). Patch by Victor Stinner. -- gh-issue-117187: Fix XML tests for vanilla Expat <2.6.0. +- gh-117187: Fix XML tests for vanilla Expat <2.6.0. -- gh-issue-116333: Tests of TLS related things (error codes, etc) were - updated to be more lenient about specific error message strings and - behaviors as seen in the BoringSSL and AWS-LC forks of OpenSSL. +- gh-116333: Tests of TLS related things (error codes, etc) were updated to + be more lenient about specific error message strings and behaviors as seen + in the BoringSSL and AWS-LC forks of OpenSSL. -- gh-issue-115979: Update test_importlib so that it passes under WASI SDK - 21. +- gh-115979: Update test_importlib so that it passes under WASI SDK 21. -- gh-issue-112536: Add --tsan to test.regrtest for running TSAN tests in +- gh-112536: Add --tsan to test.regrtest for running TSAN tests in reasonable execution times. Patch by Donghee Na. -- gh-issue-116307: Added import helper ``isolated_modules`` as - ``CleanImport`` does not remove modules imported during the context. Use - it in importlib.resources tests to avoid leaving ``mod`` around to impede +- gh-116307: Added import helper ``isolated_modules`` as ``CleanImport`` + does not remove modules imported during the context. Use it in + importlib.resources tests to avoid leaving ``mod`` around to impede importlib.metadata tests. -- gh-issue-115720: Leak tests (``-R``, ``--huntrleaks``) now show a summary - of the number of leaks found in each iteration. +- gh-115720: Leak tests (``-R``, ``--huntrleaks``) now show a summary of the + number of leaks found in each iteration. -- gh-issue-115122: Add ``--bisect`` option to regrtest test runner: run - failed tests with ``test.bisect_cmd`` to identify failing tests. Patch by - Victor Stinner. +- gh-115122: Add ``--bisect`` option to regrtest test runner: run failed + tests with ``test.bisect_cmd`` to identify failing tests. Patch by Victor + Stinner. -- gh-issue-115596: Fix ``ProgramPriorityTests`` in ``test_os`` permanently +- gh-115596: Fix ``ProgramPriorityTests`` in ``test_os`` permanently changing the process priority. Build ----- -- gh-issue-116313: Get WASI builds to work under wasmtime 18 w/ WASI - 0.2/preview2 primitives. +- gh-116313: Get WASI builds to work under wasmtime 18 w/ WASI 0.2/preview2 + primitives. -- gh-issue-116117: Backport ``libb2``'s PR #42 to fix compiling CPython on - 32-bit Windows with ``clang-cl``. +- gh-116117: Backport ``libb2``'s PR #42 to fix compiling CPython on 32-bit + Windows with ``clang-cl``. -- gh-issue-115167: Avoid vendoring ``vcruntime140_threads.dll`` when - building with Visual Studio 2022 version 17.8. +- gh-115167: Avoid vendoring ``vcruntime140_threads.dll`` when building with + Visual Studio 2022 version 17.8. -- gh-issue-112536: Add support for thread sanitizer (TSAN) +- gh-112536: Add support for thread sanitizer (TSAN) Windows ------- -- gh-issue-117267: Ensure ``DirEntry.stat().st_ctime`` behaves consistently - with :func:`os.stat` during the deprecation period of ``st_ctime`` by +- gh-117267: Ensure ``DirEntry.stat().st_ctime`` behaves consistently with + :func:`os.stat` during the deprecation period of ``st_ctime`` by containing the same value as ``st_birthtime``. After the deprecation period, ``st_ctime`` will be the metadata change time (or unavailable through ``DirEntry``), and only ``st_birthtime`` will contain the creation time. -- gh-issue-116773: Fix instances of ``<_overlapped.Overlapped object at - 0xXXX> still has pending operation at deallocation, the process may - crash``. +- gh-116773: Fix instances of ``<_overlapped.Overlapped object at 0xXXX> + still has pending operation at deallocation, the process may crash``. -- gh-issue-91227: Fix the asyncio ProactorEventLoop implementation so that - sending a datagram to an address that is not listening does not prevent - receiving any more datagrams. +- gh-91227: Fix the asyncio ProactorEventLoop implementation so that sending + a datagram to an address that is not listening does not prevent receiving + any more datagrams. -- gh-issue-115554: The installer now has more strict rules about updating - the :ref:`launcher`. In general, most users only have a single launcher +- gh-115554: The installer now has more strict rules about updating the + :ref:`launcher`. In general, most users only have a single launcher installed and will see no difference. When multiple launchers have been installed, the option to install the launcher is disabled until all but one have been removed. Downgrading the launcher (which was never allowed) is now more obviously blocked. -- gh-issue-115543: :ref:`launcher` can now detect Python 3.13 when installed - from the Microsoft Store, and will install Python 3.12 by default when +- gh-115543: :ref:`launcher` can now detect Python 3.13 when installed from + the Microsoft Store, and will install Python 3.12 by default when :envvar:`PYLAUNCHER_ALLOW_INSTALL` is set. -- gh-issue-115049: Fixes ``py.exe`` launcher failing when run as users - without user profiles. +- gh-115049: Fixes ``py.exe`` launcher failing when run as users without + user profiles. -- gh-issue-115009: Update Windows installer to use SQLite 3.45.1. +- gh-115009: Update Windows installer to use SQLite 3.45.1. IDLE ---- -- gh-issue-88516: On macOS show a proxy icon in the title bar of editor - windows to match platform behaviour. +- gh-88516: On macOS show a proxy icon in the title bar of editor windows to + match platform behaviour. Tools/Demos ----------- -- gh-issue-113516: Don't set ``LDSHARED`` when building for WASI. +- gh-113516: Don't set ``LDSHARED`` when building for WASI. C API ----- -- gh-issue-117021: Fix integer overflow in :c:func:`PyLong_AsPid` on - non-Windows 64-bit platforms. +- gh-117021: Fix integer overflow in :c:func:`PyLong_AsPid` on non-Windows + 64-bit platforms. -- gh-issue-116869: Make the C API compatible with +- gh-116869: Make the C API compatible with ``-Werror=declaration-after-statement`` compiler flag again. Patch by Victor Stinner. @@ -747,123 +1756,118 @@ What's New in Python 3.12.2 final? Security -------- -- gh-issue-113659: Skip ``.pth`` files with names starting with a dot or - hidden file attribute. +- gh-113659: Skip ``.pth`` files with names starting with a dot or hidden + file attribute. Core and Builtins ----------------- -- gh-issue-114887: Changed socket type validation in +- gh-114887: Changed socket type validation in :meth:`~asyncio.loop.create_datagram_endpoint` to accept all non-stream sockets. This fixes a regression in compatibility with raw sockets. -- gh-issue-114388: Fix a :exc:`RuntimeWarning` emitted when assign an - integer-like value that is not an instance of :class:`int` to an attribute - that corresponds to a C struct member of :ref:`type ` - T_UINT and T_ULONG. Fix a double :exc:`RuntimeWarning` emitted when assign - a negative integer value to an attribute that corresponds to a C struct +- gh-114388: Fix a :exc:`RuntimeWarning` emitted when assign an integer-like + value that is not an instance of :class:`int` to an attribute that + corresponds to a C struct member of :ref:`type ` T_UINT + and T_ULONG. Fix a double :exc:`RuntimeWarning` emitted when assign a + negative integer value to an attribute that corresponds to a C struct member of type T_UINT. -- gh-issue-113703: Fix a regression in the :mod:`codeop` module that was - causing it to incorrectly identify incomplete f-strings. Patch by Pablo - Galindo +- gh-113703: Fix a regression in the :mod:`codeop` module that was causing + it to incorrectly identify incomplete f-strings. Patch by Pablo Galindo -- gh-issue-89811: Check for a valid ``tp_version_tag`` before performing - bytecode specializations that rely on this value being usable. +- gh-89811: Check for a valid ``tp_version_tag`` before performing bytecode + specializations that rely on this value being usable. -- gh-issue-113602: Fix an error that was causing the parser to try to - overwrite existing errors and crashing in the process. Patch by Pablo - Galindo +- gh-113602: Fix an error that was causing the parser to try to overwrite + existing errors and crashing in the process. Patch by Pablo Galindo -- gh-issue-113297: Fix segfault in the compiler on with statement with 19 - context managers. +- gh-113297: Fix segfault in the compiler on with statement with 19 context + managers. -- gh-issue-106905: Use per AST-parser state rather than global state to - track recursion depth within the AST parser to prevent potential race - condition due to simultaneous parsing. +- gh-106905: Use per AST-parser state rather than global state to track + recursion depth within the AST parser to prevent potential race condition + due to simultaneous parsing. The issue primarily showed up in 3.11 by multithreaded users of :func:`ast.parse`. In 3.12 a change to when garbage collection can be triggered prevented the race condition from occurring. -- gh-issue-112943: Correctly compute end column offsets for multiline tokens - in the :mod:`tokenize` module. Patch by Pablo Galindo +- gh-112943: Correctly compute end column offsets for multiline tokens in + the :mod:`tokenize` module. Patch by Pablo Galindo -- gh-issue-112716: Fix SystemError in the ``import`` statement and in +- gh-112716: Fix SystemError in the ``import`` statement and in ``__reduce__()`` methods of builtin types when ``__builtins__`` is not a dict. -- gh-issue-94606: Fix UnicodeEncodeError when - :func:`email.message.get_payload` reads a message with a Unicode surrogate - character and the message content is not well-formed for surrogateescape - encoding. Patch by Sidney Markowitz. +- gh-94606: Fix UnicodeEncodeError when :func:`email.message.get_payload` + reads a message with a Unicode surrogate character and the message content + is not well-formed for surrogateescape encoding. Patch by Sidney + Markowitz. Library ------- -- gh-issue-114965: Update bundled pip to 24.0 +- gh-114965: Update bundled pip to 24.0 -- gh-issue-114959: :mod:`tarfile` no longer ignores errors when trying to - extract a directory on top of a file. +- gh-114959: :mod:`tarfile` no longer ignores errors when trying to extract + a directory on top of a file. -- gh-issue-109475: Fix support of explicit option value "--" in - :mod:`argparse` (e.g. ``--option=--``). +- gh-109475: Fix support of explicit option value "--" in :mod:`argparse` + (e.g. ``--option=--``). -- gh-issue-110190: Fix ctypes structs with array on Windows ARM64 platform - by setting ``MAX_STRUCT_SIZE`` to 32 in stgdict. Patch by Diego Russo +- gh-110190: Fix ctypes structs with array on Windows ARM64 platform by + setting ``MAX_STRUCT_SIZE`` to 32 in stgdict. Patch by Diego Russo -- gh-issue-113280: Fix a leak of open socket in rare cases when error - occurred in :class:`ssl.SSLSocket` creation. +- gh-113280: Fix a leak of open socket in rare cases when error occurred in + :class:`ssl.SSLSocket` creation. -- gh-issue-77749: :meth:`email.policy.EmailPolicy.fold` now always encodes +- gh-77749: :meth:`email.policy.EmailPolicy.fold` now always encodes non-ASCII characters in headers if :attr:`~email.policy.EmailPolicy.utf8` is false. -- gh-issue-114492: Make the result of :func:`termios.tcgetattr` reproducible - on Alpine Linux. Previously it could leave a random garbage in some - fields. +- gh-114492: Make the result of :func:`termios.tcgetattr` reproducible on + Alpine Linux. Previously it could leave a random garbage in some fields. -- gh-issue-113267: Revert changes in :gh:`106584` which made calls of +- gh-113267: Revert changes in :gh:`106584` which made calls of ``TestResult`` methods ``startTest()`` and ``stopTest()`` unbalanced. -- gh-issue-75128: Ignore an :exc:`OSError` in +- gh-75128: Ignore an :exc:`OSError` in :meth:`asyncio.BaseEventLoop.create_server` when IPv6 is available but the interface cannot actually support it. -- gh-issue-114257: Dismiss the :exc:`FileNotFound` error in +- gh-114257: Dismiss the :exc:`FileNotFound` error in :func:`ctypes.util.find_library` and just return ``None`` on Linux. -- gh-issue-114328: The :func:`tty.setcbreak` and new - :func:`tty.cfmakecbreak` no longer clears the terminal input ICRLF flag. - This fixes a regression introduced in 3.12 that no longer matched how OSes - define cbreak mode in their ``stty(1)`` manual pages. +- gh-114328: The :func:`tty.setcbreak` and new :func:`tty.cfmakecbreak` no + longer clears the terminal input ICRLF flag. This fixes a regression + introduced in 3.12 that no longer matched how OSes define cbreak mode in + their ``stty(1)`` manual pages. -- gh-issue-101438: Avoid reference cycle in ElementTree.iterparse. The - iterator returned by ``ElementTree.iterparse`` may hold on to a file - descriptor. The reference cycle prevented prompt clean-up of the file - descriptor if the returned iterator was not exhausted. +- gh-101438: Avoid reference cycle in ElementTree.iterparse. The iterator + returned by ``ElementTree.iterparse`` may hold on to a file descriptor. + The reference cycle prevented prompt clean-up of the file descriptor if + the returned iterator was not exhausted. -- gh-issue-104522: :exc:`OSError` raised when run a subprocess now only has +- gh-104522: :exc:`OSError` raised when run a subprocess now only has *filename* attribute set to *cwd* if the error was caused by a failed attempt to change the current directory. -- gh-issue-114149: Enum: correctly handle tuple subclasses in custom - ``__new__``. +- gh-114149: Enum: correctly handle tuple subclasses in custom ``__new__``. -- gh-issue-109534: Fix a reference leak in +- gh-109534: Fix a reference leak in :class:`asyncio.selector_events.BaseSelectorEventLoop` when SSL handshakes fail. Patch contributed by Jamie Phan. -- gh-issue-114077: Fix possible :exc:`OverflowError` in +- gh-114077: Fix possible :exc:`OverflowError` in :meth:`socket.socket.sendfile` when pass *count* larger than 2 GiB on 32-bit platform. -- gh-issue-114014: Fixed a bug in :class:`fractions.Fraction` where an - invalid string using ``d`` in the decimals part creates a different error - compared to other invalid letters/characters. Patch by Jeremiah Gabriel - Pascual. +- gh-114014: Fixed a bug in :class:`fractions.Fraction` where an invalid + string using ``d`` in the decimals part creates a different error compared + to other invalid letters/characters. Patch by Jeremiah Gabriel Pascual. -- gh-issue-113951: Fix the behavior of ``tag_unbind()`` methods of +- gh-113951: Fix the behavior of ``tag_unbind()`` methods of :class:`tkinter.Text` and :class:`tkinter.Canvas` classes with three arguments. Previously, ``widget.tag_unbind(tag, sequence, funcid)`` destroyed the current binding for *sequence*, leaving *sequence* unbound, @@ -872,144 +1876,144 @@ Library command. It leaves *sequence* unbound only if *funcid* was the last bound command. -- gh-issue-113877: Fix :mod:`tkinter` method ``winfo_pathname()`` on 64-bit +- gh-113877: Fix :mod:`tkinter` method ``winfo_pathname()`` on 64-bit Windows. -- gh-issue-113661: unittest runner: Don't exit 5 if tests were skipped. The +- gh-113661: unittest runner: Don't exit 5 if tests were skipped. The intention of exiting 5 was to detect issues where the test suite wasn't discovered at all. If we skipped tests, it was correctly discovered. -- gh-issue-113781: Silence unraisable AttributeError when warnings are - emitted during Python finalization. +- gh-113781: Silence unraisable AttributeError when warnings are emitted + during Python finalization. -- gh-issue-112932: Restore the ability for :mod:`zipfile` to ``extractall`` - from zip files with a "/" directory entry in them as is commonly added to - zips by some wiki or bug tracker data exporters. +- gh-112932: Restore the ability for :mod:`zipfile` to ``extractall`` from + zip files with a "/" directory entry in them as is commonly added to zips + by some wiki or bug tracker data exporters. -- gh-issue-113594: Fix :exc:`UnicodeEncodeError` in :mod:`email` when - re-fold lines that contain unknown-8bit encoded part followed by - non-unknown-8bit encoded part. +- gh-113594: Fix :exc:`UnicodeEncodeError` in :mod:`email` when re-fold + lines that contain unknown-8bit encoded part followed by non-unknown-8bit + encoded part. -- gh-issue-113538: In :meth:`asyncio.StreamReaderProtocol.connection_made`, - there is callback that logs an error if the task wrapping the "connected +- gh-113538: In :meth:`asyncio.StreamReaderProtocol.connection_made`, there + is callback that logs an error if the task wrapping the "connected callback" fails. This callback would itself fail if the task was cancelled. Prevent this by checking whether the task was cancelled first. If so, close the transport but don't log an error. -- gh-issue-85567: Fix resource warnings for unclosed files in :mod:`pickle` - and :mod:`pickletools` command line interfaces. +- gh-85567: Fix resource warnings for unclosed files in :mod:`pickle` and + :mod:`pickletools` command line interfaces. -- gh-issue-101225: Increase the backlog for +- gh-101225: Increase the backlog for :class:`multiprocessing.connection.Listener` objects created by :mod:`multiprocessing.manager` and :mod:`multiprocessing.resource_sharer` to significantly reduce the risk of getting a connection refused error when creating a :class:`multiprocessing.connection.Connection` to them. -- gh-issue-113543: Make sure that ``webbrowser.MacOSXOSAScript`` sends +- gh-113543: Make sure that ``webbrowser.MacOSXOSAScript`` sends ``webbrowser.open`` audit event. -- gh-issue-113028: When a second reference to a string appears in the input - to :mod:`pickle`, and the Python implementation is in use, we are - guaranteed that a single copy gets pickled and a single object is shared - when reloaded. Previously, in protocol 0, when a string contained certain +- gh-113028: When a second reference to a string appears in the input to + :mod:`pickle`, and the Python implementation is in use, we are guaranteed + that a single copy gets pickled and a single object is shared when + reloaded. Previously, in protocol 0, when a string contained certain characters (e.g. newline) it resulted in duplicate objects. -- gh-issue-113421: Fix multiprocessing logger for ``%(filename)s``. +- gh-113421: Fix multiprocessing logger for ``%(filename)s``. -- gh-issue-111784: Fix segfaults in the ``_elementtree`` module. Fix first +- gh-111784: Fix segfaults in the ``_elementtree`` module. Fix first segfault during deallocation of ``_elementtree.XMLParser`` instances by keeping strong reference to ``pyexpat`` module in module state for capsule lifetime. Fix second segfault which happens in the same deallocation process by keeping strong reference to ``_elementtree`` module in ``XMLParser`` structure for ``_elementtree`` module lifetime. -- gh-issue-113407: Fix import of :mod:`unittest.mock` when CPython is built +- gh-113407: Fix import of :mod:`unittest.mock` when CPython is built without docstrings. -- gh-issue-113320: Fix regression in Python 3.12 where - :class:`~typing.Protocol` classes that were not marked as - :func:`runtime-checkable ` would be - unnecessarily introspected, potentially causing exceptions to be raised if - the protocol had problematic members. Patch by Alex Waygood. +- gh-113320: Fix regression in Python 3.12 where :class:`~typing.Protocol` + classes that were not marked as :func:`runtime-checkable + ` would be unnecessarily introspected, + potentially causing exceptions to be raised if the protocol had + problematic members. Patch by Alex Waygood. -- gh-issue-113358: Fix rendering tracebacks for exceptions with a broken +- gh-113358: Fix rendering tracebacks for exceptions with a broken ``__getattr__``. -- gh-issue-113214: Fix an ``AttributeError`` during asyncio SSL protocol - aborts in SSL-over-SSL scenarios. +- gh-113214: Fix an ``AttributeError`` during asyncio SSL protocol aborts in + SSL-over-SSL scenarios. -- gh-issue-113246: Update bundled pip to 23.3.2. +- gh-113246: Update bundled pip to 23.3.2. -- gh-issue-113199: Make ``http.client.HTTPResponse.read1`` and +- gh-113199: Make ``http.client.HTTPResponse.read1`` and ``http.client.HTTPResponse.readline`` close IO after reading all data when content length is known. Patch by Illia Volochii. -- gh-issue-113188: Fix :func:`shutil.copymode` and :func:`shutil.copystat` - on Windows. Previously they worked differenly if *dst* is a symbolic link: +- gh-113188: Fix :func:`shutil.copymode` and :func:`shutil.copystat` on + Windows. Previously they worked differenly if *dst* is a symbolic link: they modified the permission bits of *dst* itself rather than the file it points to if *follow_symlinks* is true or *src* is not a symbolic link, and did not modify the permission bits if *follow_symlinks* is false and *src* is a symbolic link. -- gh-issue-61648: Detect line numbers of properties in doctests. +- gh-61648: Detect line numbers of properties in doctests. -- gh-issue-112559: :func:`signal.signal` and :func:`signal.getsignal` no - longer call ``repr`` on callable handlers. :func:`asyncio.run` and +- gh-112559: :func:`signal.signal` and :func:`signal.getsignal` no longer + call ``repr`` on callable handlers. :func:`asyncio.run` and :meth:`asyncio.Runner.run` no longer call ``repr`` on the task results. Patch by Yilei Yang. -- gh-issue-110190: Fix ctypes structs with array on PPC64LE platform by - setting ``MAX_STRUCT_SIZE`` to 64 in stgdict. Patch by Diego Russo. +- gh-110190: Fix ctypes structs with array on PPC64LE platform by setting + ``MAX_STRUCT_SIZE`` to 64 in stgdict. Patch by Diego Russo. -- gh-issue-79429: Ignore FileNotFoundError when remove a temporary directory - in the multiprocessing finalizer. +- gh-79429: Ignore FileNotFoundError when remove a temporary directory in + the multiprocessing finalizer. -- gh-issue-81194: Fix a crash in :func:`socket.if_indextoname` with specific - value (UINT_MAX). Fix an integer overflow in :func:`socket.if_indextoname` - on 64-bit non-Windows platforms. +- gh-81194: Fix a crash in :func:`socket.if_indextoname` with specific value + (UINT_MAX). Fix an integer overflow in :func:`socket.if_indextoname` on + 64-bit non-Windows platforms. -- gh-issue-112343: Improve handling of pdb convenience variables to avoid +- gh-112343: Improve handling of pdb convenience variables to avoid replacing string contents. -- gh-issue-111615: Fix a regression caused by a fix to gh-93162 whereby you +- gh-111615: Fix a regression caused by a fix to gh-93162 whereby you couldn't configure a :class:`QueueHandler` without specifying handlers. -- gh-issue-111049: Fix crash during garbage collection of the - :class:`io.BytesIO` buffer object. +- gh-111049: Fix crash during garbage collection of the :class:`io.BytesIO` + buffer object. -- gh-issue-110345: Show the Tcl/Tk patchlevel (rather than version) in +- gh-110345: Show the Tcl/Tk patchlevel (rather than version) in :meth:`tkinter._test`. -- gh-issue-109858: Protect :mod:`zipfile` from "quoted-overlap" zipbomb. It - now raises BadZipFile when try to read an entry that overlaps with other - entry or central directory. +- gh-109858: Protect :mod:`zipfile` from "quoted-overlap" zipbomb. It now + raises BadZipFile when try to read an entry that overlaps with other entry + or central directory. -- gh-issue-114440: On Windows, closing the connection writer when cleaning - up a broken :class:`multiprocessing.Queue` queue is now done for all - queues, rather than only in :mod:`concurrent.futures` manager thread. This - can prevent a deadlock when a ``multiprocessing`` worker process - terminates without cleaning up. This completes the backport of patches by - Victor Stinner and Serhiy Storchaka. +- gh-114440: On Windows, closing the connection writer when cleaning up a + broken :class:`multiprocessing.Queue` queue is now done for all queues, + rather than only in :mod:`concurrent.futures` manager thread. This can + prevent a deadlock when a ``multiprocessing`` worker process terminates + without cleaning up. This completes the backport of patches by Victor + Stinner and Serhiy Storchaka. -- gh-issue-38807: Fix race condition in :mod:`trace`. Instead of checking if - a directory exists and creating it, directly call :func:`os.makedirs` with +- gh-38807: Fix race condition in :mod:`trace`. Instead of checking if a + directory exists and creating it, directly call :func:`os.makedirs` with the kwarg ``exist_ok=True``. -- gh-issue-75705: Set unixfrom envelope in :class:`mailbox.mbox` and +- gh-75705: Set unixfrom envelope in :class:`mailbox.mbox` and :class:`mailbox.MMDF`. -- gh-issue-106233: Fix stacklevel in ``InvalidTZPathWarning`` during +- gh-106233: Fix stacklevel in ``InvalidTZPathWarning`` during :mod:`zoneinfo` module import. -- gh-issue-105102: Allow :class:`ctypes.Union` to be nested in +- gh-105102: Allow :class:`ctypes.Union` to be nested in :class:`ctypes.Structure` when the system endianness is the opposite of the classes. -- gh-issue-104282: Fix null pointer dereference in +- gh-104282: Fix null pointer dereference in :func:`lzma._decode_filter_properties` due to improper handling of BCJ filters with properties of zero length. Patch by Radislav Chugunov. -- gh-issue-102512: When :func:`os.fork` is called from a foreign thread (aka +- gh-102512: When :func:`os.fork` is called from a foreign thread (aka ``_DummyThread``), the type of the thread in a child process is changed to ``_MainThread``. Also changed its name and daemonic status, it can be now joined. @@ -1033,22 +2037,22 @@ Library Documentation ------------- -- gh-issue-110746: Improved markup for valid options/values for methods +- gh-110746: Improved markup for valid options/values for methods ttk.treeview.column and ttk.treeview.heading, and for Layouts. -- gh-issue-95649: Document that the :mod:`asyncio` module contains code - taken from `v0.16.0 of the uvloop project +- gh-95649: Document that the :mod:`asyncio` module contains code taken from + `v0.16.0 of the uvloop project `_, as well as the required MIT licensing information. Tests ----- -- gh-issue-109980: Fix ``test_tarfile_vs_tar`` in ``test_shutil`` for macOS, - where system tar can include more information in the archive than +- gh-109980: Fix ``test_tarfile_vs_tar`` in ``test_shutil`` for macOS, where + system tar can include more information in the archive than :mod:`shutil.make_archive`. -- gh-issue-105089: Fix +- gh-105089: Fix ``test.test_zipfile.test_core.TestWithDirectory.test_create_directory_with_write`` test in AIX by doing a bitwise AND of 0xFFFF on mode , so that it will be in sync with ``zinfo.external_attr`` @@ -1058,13 +2062,12 @@ Tests Build ----- -- gh-issue-112305: Fixed the ``check-clean-src`` step performed on out of - tree builds to detect errant ``$(srcdir)/Python/frozen_modules/*.h`` files - and recommend appropriate source tree cleanup steps to get a working build +- gh-112305: Fixed the ``check-clean-src`` step performed on out of tree + builds to detect errant ``$(srcdir)/Python/frozen_modules/*.h`` files and + recommend appropriate source tree cleanup steps to get a working build again. -- gh-issue-112867: Fix the build for the case that - WITH_PYMALLOC_RADIX_TREE=0 set. +- gh-112867: Fix the build for the case that WITH_PYMALLOC_RADIX_TREE=0 set. - bpo-11102: The :func:`os.major`, :func:`os.makedev`, and :func:`os.minor` functions are now available on HP-UX v3. @@ -1074,30 +2077,30 @@ Build Windows ------- -- gh-issue-109991: Update Windows build to use OpenSSL 3.0.13. +- gh-109991: Update Windows build to use OpenSSL 3.0.13. -- gh-issue-111239: Update Windows builds to use zlib v1.3.1. +- gh-111239: Update Windows builds to use zlib v1.3.1. -- gh-issue-100107: The ``py.exe`` launcher will no longer attempt to run the +- gh-100107: The ``py.exe`` launcher will no longer attempt to run the Microsoft Store redirector when launching a script containing a ``/usr/bin/env`` shebang -- gh-issue-114096: Process privileges that are activated for creating - directory junctions are now restored afterwards, avoiding behaviour - changes in other parts of the program. +- gh-114096: Process privileges that are activated for creating directory + junctions are now restored afterwards, avoiding behaviour changes in other + parts of the program. -- gh-issue-111877: :func:`os.stat` calls were returning incorrect time - values for files that could not be accessed directly. +- gh-111877: :func:`os.stat` calls were returning incorrect time values for + files that could not be accessed directly. -- gh-issue-113009: :mod:`multiprocessing`: On Windows, fix a race condition - in ``Process.terminate()``: no longer set the ``returncode`` attribute to +- gh-113009: :mod:`multiprocessing`: On Windows, fix a race condition in + ``Process.terminate()``: no longer set the ``returncode`` attribute to always call ``WaitForSingleObject()`` in ``Process.wait()``. Previously, sometimes the process was still running after ``TerminateProcess()`` even if ``GetExitCodeProcess()`` is not ``STILL_ACTIVE``. Patch by Victor Stinner. -- gh-issue-87868: Correctly sort and remove duplicate environment variables - in :py:func:`!_winapi.CreateProcess`. +- gh-87868: Correctly sort and remove duplicate environment variables in + :py:func:`!_winapi.CreateProcess`. - bpo-37308: Fix mojibake in :class:`mmap.mmap` when using a non-ASCII *tagname* argument on Windows. @@ -1105,57 +2108,56 @@ Windows macOS ----- -- gh-issue-115009: Update macOS installer to use SQLite 3.45.1. +- gh-115009: Update macOS installer to use SQLite 3.45.1. -- gh-issue-109991: Update macOS installer to use OpenSSL 3.0.13. +- gh-109991: Update macOS installer to use OpenSSL 3.0.13. -- gh-issue-110459: Running ``configure ... --with-openssl-rpath=X/Y/Z`` no - longer fails to detect OpenSSL on macOS. +- gh-110459: Running ``configure ... --with-openssl-rpath=X/Y/Z`` no longer + fails to detect OpenSSL on macOS. -- gh-issue-74573: Document that :mod:`dbm.ndbm` can silently corrupt DBM - files on updates when exceeding undocumented platform limits, and can - crash (segmentation fault) when reading such a corrupted file. (FB8919203) +- gh-74573: Document that :mod:`dbm.ndbm` can silently corrupt DBM files on + updates when exceeding undocumented platform limits, and can crash + (segmentation fault) when reading such a corrupted file. (FB8919203) -- gh-issue-65701: The :program:`freeze` tool doesn't work with framework - builds of Python. Document this and bail out early when running the tool - with such a build. +- gh-65701: The :program:`freeze` tool doesn't work with framework builds of + Python. Document this and bail out early when running the tool with such a + build. -- gh-issue-108269: Set ``CFBundleAllowMixedLocalizations`` to true in the +- gh-108269: Set ``CFBundleAllowMixedLocalizations`` to true in the Info.plist for the framework, embedded Python.app and IDLE.app with framework installs on macOS. This allows applications to pick up the user's preferred locale when that's different from english. -- gh-issue-102362: Make sure the result of :func:`sysconfig.get_plaform` - includes at least a major and minor versions, even if - ``MACOSX_DEPLOYMENT_TARGET`` is set to only a major version during build - to match the format expected by pip. +- gh-102362: Make sure the result of :func:`sysconfig.get_plaform` includes + at least a major and minor versions, even if ``MACOSX_DEPLOYMENT_TARGET`` + is set to only a major version during build to match the format expected + by pip. -- gh-issue-110017: Disable a signal handling stress test on macOS due to a - bug in macOS (FB13453490). +- gh-110017: Disable a signal handling stress test on macOS due to a bug in + macOS (FB13453490). -- gh-issue-110820: Make sure the preprocessor definitions for +- gh-110820: Make sure the preprocessor definitions for ``ALIGNOF_MAX_ALIGN_T``, ``SIZEOF_LONG_DOUBLE`` and ``HAVE_GCC_ASM_FOR_X64`` are correct for Universal 2 builds on macOS. IDLE ---- -- gh-issue-96905: In idlelib code, stop redefining built-ins 'dict' and - 'object'. +- gh-96905: In idlelib code, stop redefining built-ins 'dict' and 'object'. -- gh-issue-72284: Improve the lists of features, editor key bindings, and - shell key bingings in the IDLE doc. +- gh-72284: Improve the lists of features, editor key bindings, and shell + key bingings in the IDLE doc. -- gh-issue-113903: Fix rare failure of test.test_idle, in test_configdialog. +- gh-113903: Fix rare failure of test.test_idle, in test_configdialog. -- gh-issue-113729: Fix the "Help -> IDLE Doc" menu bug in 3.11.7 and 3.12.1. +- gh-113729: Fix the "Help -> IDLE Doc" menu bug in 3.11.7 and 3.12.1. -- gh-issue-113269: Fix test_editor hang on macOS Catalina. +- gh-113269: Fix test_editor hang on macOS Catalina. -- gh-issue-112898: Fix processing unsaved files when quitting IDLE on macOS. +- gh-112898: Fix processing unsaved files when quitting IDLE on macOS. -- gh-issue-103820: Revise IDLE bindings so that events from mouse button 4/5 - on non-X11 windowing systems (i.e. Win32 and Aqua) are not mistaken for +- gh-103820: Revise IDLE bindings so that events from mouse button 4/5 on + non-X11 windowing systems (i.e. Win32 and Aqua) are not mistaken for scrolling. - bpo-13586: Enter the selected text when opening the "Replace" dialog. @@ -1163,14 +2165,14 @@ IDLE Tools/Demos ----------- -- gh-issue-109991: Update GitHub CI workflows to use OpenSSL 3.0.13 and +- gh-109991: Update GitHub CI workflows to use OpenSSL 3.0.13 and multissltests to use 1.1.1w, 3.0.13, 3.1.5, and 3.2.1. -- gh-issue-115015: Fix a bug in Argument Clinic that generated incorrect - code for methods with no parameters that use the :ref:`METH_METHOD | - METH_FASTCALL | METH_KEYWORDS ` - calling convention. Only the positional parameter count was checked; any - keyword argument passed would be silently accepted. +- gh-115015: Fix a bug in Argument Clinic that generated incorrect code for + methods with no parameters that use the :ref:`METH_METHOD | METH_FASTCALL + | METH_KEYWORDS ` calling + convention. Only the positional parameter count was checked; any keyword + argument passed would be silently accepted. What's New in Python 3.12.1 final? @@ -1181,150 +2183,148 @@ What's New in Python 3.12.1 final? Core and Builtins ----------------- -- gh-issue-112125: Fix None.__ne__(None) returning NotImplemented instead of - False +- gh-112125: Fix None.__ne__(None) returning NotImplemented instead of False -- gh-issue-112625: Fixes a bug where a bytearray object could be cleared - while iterating over an argument in the ``bytearray.join()`` method that - could result in reading memory after it was freed. +- gh-112625: Fixes a bug where a bytearray object could be cleared while + iterating over an argument in the ``bytearray.join()`` method that could + result in reading memory after it was freed. -- gh-issue-105967: Workaround a bug in Apple's macOS platform zlib library - where :func:`zlib.crc32` and :func:`binascii.crc32` could produce - incorrect results on multi-gigabyte inputs. Including when using - :mod:`zipfile` on zips containing large data. +- gh-105967: Workaround a bug in Apple's macOS platform zlib library where + :func:`zlib.crc32` and :func:`binascii.crc32` could produce incorrect + results on multi-gigabyte inputs. Including when using :mod:`zipfile` on + zips containing large data. -- gh-issue-112356: Stopped erroneously deleting a ``LOAD_NULL`` bytecode +- gh-112356: Stopped erroneously deleting a ``LOAD_NULL`` bytecode instruction when optimized twice. -- gh-issue-111058: Change coro.cr_frame/gen.gi_frame to return ``None`` - after the coroutine/generator has been closed. This fixes a bug where +- gh-111058: Change coro.cr_frame/gen.gi_frame to return ``None`` after the + coroutine/generator has been closed. This fixes a bug where :func:`~inspect.getcoroutinestate` and :func:`~inspect.getgeneratorstate` return the wrong state for a closed coroutine/generator. -- gh-issue-112388: Fix an error that was causing the parser to try to - overwrite tokenizer errors. Patch by pablo Galindo +- gh-112388: Fix an error that was causing the parser to try to overwrite + tokenizer errors. Patch by pablo Galindo -- gh-issue-112387: Fix error positions for decoded strings with backwards - tokenize errors. Patch by Pablo Galindo +- gh-112387: Fix error positions for decoded strings with backwards tokenize + errors. Patch by Pablo Galindo -- gh-issue-112367: Avoid undefined behaviour when using the perf trampolines - by not freeing the code arenas until shutdown. Patch by Pablo Galindo +- gh-112367: Avoid undefined behaviour when using the perf trampolines by + not freeing the code arenas until shutdown. Patch by Pablo Galindo -- gh-issue-112243: Don't include comments in f-string debug expressions. - Patch by Pablo Galindo +- gh-112243: Don't include comments in f-string debug expressions. Patch by + Pablo Galindo -- gh-issue-112266: Change docstrings of :attr:`~object.__dict__` and +- gh-112266: Change docstrings of :attr:`~object.__dict__` and :attr:`~object.__weakref__`. -- gh-issue-111654: Fix runtime crash when some error happens in opcode +- gh-111654: Fix runtime crash when some error happens in opcode ``LOAD_FROM_DICT_OR_DEREF``. -- gh-issue-109181: Speed up :obj:`Traceback` object creation by lazily - compute the line number. Patch by Pablo Galindo +- gh-109181: Speed up :obj:`Traceback` object creation by lazily compute the + line number. Patch by Pablo Galindo -- gh-issue-102388: Fix a bug where ``iso2022_jp_3`` and ``iso2022_jp_2004`` - codecs read out of bounds +- gh-102388: Fix a bug where ``iso2022_jp_3`` and ``iso2022_jp_2004`` codecs + read out of bounds -- gh-issue-111366: Fix an issue in the :mod:`codeop` that was causing +- gh-111366: Fix an issue in the :mod:`codeop` that was causing :exc:`SyntaxError` exceptions raised in the presence of invalid syntax to not contain precise error messages. Patch by Pablo Galindo -- gh-issue-111380: Fix a bug that was causing :exc:`SyntaxWarning` to appear - twice when parsing if invalid syntax is encountered later. Patch by Pablo +- gh-111380: Fix a bug that was causing :exc:`SyntaxWarning` to appear twice + when parsing if invalid syntax is encountered later. Patch by Pablo galindo -- gh-issue-94438: Fix a regression that prevented jumping across ``is None`` - and ``is not None`` when debugging. Patch by Savannah Ostrowski. +- gh-94438: Fix a regression that prevented jumping across ``is None`` and + ``is not None`` when debugging. Patch by Savannah Ostrowski. -- gh-issue-110938: Fix error messages for indented blocks with functions and +- gh-110938: Fix error messages for indented blocks with functions and classes with generic type parameters. Patch by Pablo Galindo -- gh-issue-109894: Fixed crash due to improperly initialized static +- gh-109894: Fixed crash due to improperly initialized static :exc:`MemoryError` in subinterpreter. -- gh-issue-110782: Fix crash when :class:`typing.TypeVar` is constructed - with a keyword argument. Patch by Jelle Zijlstra. +- gh-110782: Fix crash when :class:`typing.TypeVar` is constructed with a + keyword argument. Patch by Jelle Zijlstra. -- gh-issue-110696: Fix incorrect error message for invalid argument - unpacking. Patch by Pablo Galindo +- gh-110696: Fix incorrect error message for invalid argument unpacking. + Patch by Pablo Galindo -- gh-issue-110543: Fix regression in Python 3.12 where +- gh-110543: Fix regression in Python 3.12 where :meth:`types.CodeType.replace` would produce a broken code object if called on a module or class code object that contains a comprehension. Patch by Jelle Zijlstra. -- gh-issue-110514: Add ``PY_THROW`` to :func:`sys.setprofile` events +- gh-110514: Add ``PY_THROW`` to :func:`sys.setprofile` events -- gh-issue-110455: Guard ``assert(tstate->thread_id > 0)`` with ``#ifndef +- gh-110455: Guard ``assert(tstate->thread_id > 0)`` with ``#ifndef HAVE_PTHREAD_STUBS``. This allows for for pydebug builds to work under WASI which (currently) lacks thread support. -- gh-issue-110259: Correctly identify the format spec in f-strings (with - single or triple quotes) that have multiple lines in the expression part - and include a formatting spec. Patch by Pablo Galindo +- gh-110259: Correctly identify the format spec in f-strings (with single or + triple quotes) that have multiple lines in the expression part and include + a formatting spec. Patch by Pablo Galindo -- gh-issue-110237: Fix missing error checks for calls to ``PyList_Append`` - in ``_PyEval_MatchClass``. +- gh-110237: Fix missing error checks for calls to ``PyList_Append`` in + ``_PyEval_MatchClass``. -- gh-issue-109889: Fix the compiler's redundant NOP detection algorithm to - skip over NOPs with no line number when looking for the next instruction's +- gh-109889: Fix the compiler's redundant NOP detection algorithm to skip + over NOPs with no line number when looking for the next instruction's lineno. -- gh-issue-109853: ``sys.path[0]`` is now set correctly for subinterpreters. +- gh-109853: ``sys.path[0]`` is now set correctly for subinterpreters. -- gh-issue-105716: Subinterpreters now correctly handle the case where they - have threads running in the background. Before, such threads would - interfere with cleaning up and destroying them, as well as prevent running - another script. +- gh-105716: Subinterpreters now correctly handle the case where they have + threads running in the background. Before, such threads would interfere + with cleaning up and destroying them, as well as prevent running another + script. -- gh-issue-109793: The main thread no longer exits prematurely when a +- gh-109793: The main thread no longer exits prematurely when a subinterpreter is cleaned up during runtime finalization. The bug was a problem particularly because, when triggered, the Python process would always return with a 0 exitcode, even if it failed. -- gh-issue-109596: Fix some tokens in the grammar that were incorrectly - marked as soft keywords. Also fix some repeated rule names and ensure that - repeated rules are not allowed. Patch by Pablo Galindo +- gh-109596: Fix some tokens in the grammar that were incorrectly marked as + soft keywords. Also fix some repeated rule names and ensure that repeated + rules are not allowed. Patch by Pablo Galindo -- gh-issue-109351: Fix crash when compiling an invalid AST involving a named +- gh-109351: Fix crash when compiling an invalid AST involving a named (walrus) expression. -- gh-issue-109216: Fix possible memory leak in :opcode:`BUILD_MAP`. +- gh-109216: Fix possible memory leak in :opcode:`BUILD_MAP`. -- gh-issue-109207: Fix a SystemError in ``__repr__`` of symtable entry - object. +- gh-109207: Fix a SystemError in ``__repr__`` of symtable entry object. -- gh-issue-109179: Fix bug where the C traceback display drops notes from +- gh-109179: Fix bug where the C traceback display drops notes from :exc:`SyntaxError`. -- gh-issue-109052: Use the base opcode when comparing code objects to avoid +- gh-109052: Use the base opcode when comparing code objects to avoid interference from instrumentation -- gh-issue-88943: Improve syntax error for non-ASCII character that follows - a numerical literal. It now points on the invalid non-ASCII character, not +- gh-88943: Improve syntax error for non-ASCII character that follows a + numerical literal. It now points on the invalid non-ASCII character, not on the valid numerical literal. -- gh-issue-106931: Statically allocated string objects are now interned - globally instead of per-interpreter. This fixes a situation where such a - string would only be interned in a single interpreter. Normal string - objects are unaffected. +- gh-106931: Statically allocated string objects are now interned globally + instead of per-interpreter. This fixes a situation where such a string + would only be interned in a single interpreter. Normal string objects are + unaffected. Library ------- -- gh-issue-79325: Fix an infinite recursion error in +- gh-79325: Fix an infinite recursion error in :func:`tempfile.TemporaryDirectory` cleanup on Windows. -- gh-issue-112645: Remove deprecation error on passing ``onerror`` to +- gh-112645: Remove deprecation error on passing ``onerror`` to :func:`shutil.rmtree`. -- gh-issue-112618: Fix a caching bug relating to :data:`typing.Annotated`. +- gh-112618: Fix a caching bug relating to :data:`typing.Annotated`. ``Annotated[str, True]`` is no longer identical to ``Annotated[str, 1]``. -- gh-issue-112334: Fixed a performance regression in 3.12's - :mod:`subprocess` on Linux where it would no longer use the fast-path - ``vfork()`` system call when it should have due to a logic bug, instead - always falling back to the safe but slower ``fork()``. +- gh-112334: Fixed a performance regression in 3.12's :mod:`subprocess` on + Linux where it would no longer use the fast-path ``vfork()`` system call + when it should have due to a logic bug, instead always falling back to the + safe but slower ``fork()``. Also fixed a related 3.12 security regression: If a value of ``extra_groups=[]`` was passed to :mod:`subprocess.Popen` or related APIs, @@ -1335,248 +2335,239 @@ Library This was identified via code inspection in the process of fixing the first bug. -- gh-issue-110190: Fix ctypes structs with array on Arm platform by setting +- gh-110190: Fix ctypes structs with array on Arm platform by setting ``MAX_STRUCT_SIZE`` to 32 in stgdict. Patch by Diego Russo. -- gh-issue-112578: Fix a spurious :exc:`RuntimeWarning` when executing the +- gh-112578: Fix a spurious :exc:`RuntimeWarning` when executing the :mod:`zipfile` module. -- gh-issue-112509: Fix edge cases that could cause a key to be present in - both the ``__required_keys__`` and ``__optional_keys__`` attributes of a +- gh-112509: Fix edge cases that could cause a key to be present in both the + ``__required_keys__`` and ``__optional_keys__`` attributes of a :class:`typing.TypedDict`. Patch by Jelle Zijlstra. -- gh-issue-112414: Fix regression in Python 3.12 where calling :func:`repr` - on a module that had been imported using a custom :term:`loader` could - fail with :exc:`AttributeError`. Patch by Alex Waygood. +- gh-112414: Fix regression in Python 3.12 where calling :func:`repr` on a + module that had been imported using a custom :term:`loader` could fail + with :exc:`AttributeError`. Patch by Alex Waygood. -- gh-issue-112358: Revert change to :class:`struct.Struct` initialization - that broke some cases of subclassing. +- gh-112358: Revert change to :class:`struct.Struct` initialization that + broke some cases of subclassing. -- gh-issue-94722: Fix bug where comparison between instances of +- gh-94722: Fix bug where comparison between instances of :class:`~doctest.DocTest` fails if one of them has ``None`` as its lineno. -- gh-issue-112105: Make :func:`readline.set_completer_delims` work with - libedit +- gh-112105: Make :func:`readline.set_completer_delims` work with libedit -- gh-issue-111942: Fix SystemError in the TextIOWrapper constructor with +- gh-111942: Fix SystemError in the TextIOWrapper constructor with non-encodable "errors" argument in non-debug mode. -- gh-issue-109538: Issue warning message instead of having - :class:`RuntimeError` be displayed when event loop has already been closed - at :meth:`StreamWriter.__del__`. +- gh-109538: Issue warning message instead of having :class:`RuntimeError` + be displayed when event loop has already been closed at + :meth:`StreamWriter.__del__`. -- gh-issue-111942: Fix crashes in :meth:`io.TextIOWrapper.reconfigure` when - pass invalid arguments, e.g. non-string encoding. +- gh-111942: Fix crashes in :meth:`io.TextIOWrapper.reconfigure` when pass + invalid arguments, e.g. non-string encoding. -- gh-issue-111460: :mod:`curses`: restore wide character support (including +- gh-111460: :mod:`curses`: restore wide character support (including :func:`curses.unget_wch` and :meth:`~curses.window.get_wch`) on macOS, which was unavailable due to a regression in Python 3.12. -- gh-issue-103791: :class:`contextlib.suppress` now supports suppressing +- gh-103791: :class:`contextlib.suppress` now supports suppressing exceptions raised as part of a :exc:`BaseExceptionGroup`, in addition to the recent support for :exc:`ExceptionGroup`. -- gh-issue-111804: Remove posix.fallocate() under WASI as the underlying +- gh-111804: Remove posix.fallocate() under WASI as the underlying posix_fallocate() is not available in WASI preview2. -- gh-issue-111841: Fix truncating arguments on an embedded null character in +- gh-111841: Fix truncating arguments on an embedded null character in :meth:`os.putenv` and :meth:`os.unsetenv` on Windows. -- gh-issue-111541: Fix :mod:`doctest` for :exc:`SyntaxError` not-builtin +- gh-111541: Fix :mod:`doctest` for :exc:`SyntaxError` not-builtin subclasses. -- gh-issue-110894: Call loop exception handler for exceptions in +- gh-110894: Call loop exception handler for exceptions in ``client_connected_cb`` of :func:`asyncio.start_server` so that applications can handle it. Patch by Kumar Aditya. -- gh-issue-111531: Fix reference leaks in ``bind_class()`` and - ``bind_all()`` methods of :mod:`tkinter` widgets. +- gh-111531: Fix reference leaks in ``bind_class()`` and ``bind_all()`` + methods of :mod:`tkinter` widgets. -- gh-issue-111356: Added :func:`io.text_encoding()`, - :data:`io.DEFAULT_BUFFER_SIZE`, and :class:`io.IncrementalNewlineDecoder` - to ``io.__all__``. +- gh-111356: Added :func:`io.text_encoding`, :data:`io.DEFAULT_BUFFER_SIZE`, + and :class:`io.IncrementalNewlineDecoder` to ``io.__all__``. -- gh-issue-111342: Fixed typo in :func:`math.sumprod`. +- gh-111342: Fixed typo in :func:`math.sumprod`. -- gh-issue-68166: Remove mention of not supported "vsapi" element type in +- gh-68166: Remove mention of not supported "vsapi" element type in :meth:`tkinter.ttk.Style.element_create`. Add tests for ``element_create()`` and other ``ttk.Style`` methods. Add examples for ``element_create()`` in the documentation. -- gh-issue-75666: Fix the behavior of :mod:`tkinter` widget's ``unbind()`` - method with two arguments. Previously, ``widget.unbind(sequence, funcid)`` +- gh-75666: Fix the behavior of :mod:`tkinter` widget's ``unbind()`` method + with two arguments. Previously, ``widget.unbind(sequence, funcid)`` destroyed the current binding for *sequence*, leaving *sequence* unbound, and deleted the *funcid* command. Now it removes only *funcid* from the binding for *sequence*, keeping other commands, and deletes the *funcid* command. It leaves *sequence* unbound only if *funcid* was the last bound command. -- gh-issue-79033: Another attempt at fixing - :func:`asyncio.Server.wait_closed()`. It now blocks until both conditions - are true: the server is closed, *and* there are no more active - connections. (This means that in some cases where in 3.12.0 this function - would *incorrectly* have returned immediately, it will now block; in - particular, when there are no active connections but the server hasn't - been closed yet.) +- gh-79033: Another attempt at fixing :func:`asyncio.Server.wait_closed`. It + now blocks until both conditions are true: the server is closed, *and* + there are no more active connections. (This means that in some cases where + in 3.12.0 this function would *incorrectly* have returned immediately, it + will now block; in particular, when there are no active connections but + the server hasn't been closed yet.) -- gh-issue-111295: Fix :mod:`time` not checking for errors when - initializing. +- gh-111295: Fix :mod:`time` not checking for errors when initializing. -- gh-issue-111253: Add error checking during :mod:`!_socket` module init. +- gh-111253: Add error checking during :mod:`!_socket` module init. -- gh-issue-111251: Fix :mod:`_blake2` not checking for errors when - initializing. +- gh-111251: Fix :mod:`_blake2` not checking for errors when initializing. -- gh-issue-111174: Fix crash in :meth:`io.BytesIO.getbuffer` called - repeatedly for empty BytesIO. +- gh-111174: Fix crash in :meth:`io.BytesIO.getbuffer` called repeatedly for + empty BytesIO. -- gh-issue-111187: Postpone removal version for locale.getdefaultlocale() to +- gh-111187: Postpone removal version for locale.getdefaultlocale() to Python 3.15. -- gh-issue-111159: Fix :mod:`doctest` output comparison for exceptions with - notes. +- gh-111159: Fix :mod:`doctest` output comparison for exceptions with notes. -- gh-issue-110910: Fix invalid state handling in :class:`asyncio.TaskGroup` - and :class:`asyncio.Timeout`. They now raise proper RuntimeError if they - are improperly used and are left in consistent state after this. +- gh-110910: Fix invalid state handling in :class:`asyncio.TaskGroup` and + :class:`asyncio.Timeout`. They now raise proper RuntimeError if they are + improperly used and are left in consistent state after this. -- gh-issue-111092: Make turtledemo run without default root enabled. +- gh-111092: Make turtledemo run without default root enabled. -- gh-issue-110488: Fix a couple of issues in - :meth:`pathlib.PurePath.with_name`: a single dot was incorrectly - considered a valid name, and in :class:`PureWindowsPath`, a name with an - NTFS alternate data stream, like ``a:b``, was incorrectly considered - invalid. +- gh-110488: Fix a couple of issues in :meth:`pathlib.PurePath.with_name`: a + single dot was incorrectly considered a valid name, and in + :class:`PureWindowsPath`, a name with an NTFS alternate data stream, like + ``a:b``, was incorrectly considered invalid. -- gh-issue-110392: Fix :func:`tty.setraw` and :func:`tty.setcbreak`: - previously they returned partially modified list of the original tty - attributes. :func:`tty.cfmakeraw` and :func:`tty.cfmakecbreak` now make a - copy of the list of special characters before modifying it. +- gh-110392: Fix :func:`tty.setraw` and :func:`tty.setcbreak`: previously + they returned partially modified list of the original tty attributes. + :func:`tty.cfmakeraw` and :func:`tty.cfmakecbreak` now make a copy of the + list of special characters before modifying it. -- gh-issue-110590: Fix a bug in :meth:`!_sre.compile` where :exc:`TypeError` - would be overwritten by :exc:`OverflowError` when the *code* argument was - a list of non-ints. +- gh-110590: Fix a bug in :meth:`!_sre.compile` where :exc:`TypeError` would + be overwritten by :exc:`OverflowError` when the *code* argument was a list + of non-ints. -- gh-issue-65052: Prevent :mod:`pdb` from crashing when trying to display +- gh-65052: Prevent :mod:`pdb` from crashing when trying to display undisplayable objects -- gh-issue-110519: Deprecation warning about non-integer number in - :mod:`gettext` now alwais refers to the line in the user code where - gettext function or method is used. Previously it could refer to a line in - ``gettext`` code. +- gh-110519: Deprecation warning about non-integer number in :mod:`gettext` + now alwais refers to the line in the user code where gettext function or + method is used. Previously it could refer to a line in ``gettext`` code. -- gh-issue-110395: Ensure that :func:`select.kqueue` objects correctly - appear as closed in forked children, to prevent operations on an invalid - file descriptor. +- gh-110395: Ensure that :func:`select.kqueue` objects correctly appear as + closed in forked children, to prevent operations on an invalid file + descriptor. -- gh-issue-110378: :func:`~contextlib.contextmanager` and +- gh-110378: :func:`~contextlib.contextmanager` and :func:`~contextlib.asynccontextmanager` context managers now close an invalid underlying generator object that yields more then one value. -- gh-issue-110365: Fix :func:`termios.tcsetattr` bug that was overwritting +- gh-110365: Fix :func:`termios.tcsetattr` bug that was overwritting existing errors during parsing integers from ``term`` list. -- gh-issue-109653: Fix a Python 3.12 regression in the import time of +- gh-109653: Fix a Python 3.12 regression in the import time of :mod:`random`. Patch by Alex Waygood. -- gh-issue-110196: Add ``__reduce__`` method to :class:`IPv6Address` in - order to keep ``scope_id`` +- gh-110196: Add ``__reduce__`` method to :class:`IPv6Address` in order to + keep ``scope_id`` -- gh-issue-110036: On Windows, multiprocessing ``Popen.terminate()`` now - catchs :exc:`PermissionError` and get the process exit code. If the - process is still running, raise again the :exc:`PermissionError`. - Otherwise, the process terminated as expected: store its exit code. Patch - by Victor Stinner. +- gh-110036: On Windows, multiprocessing ``Popen.terminate()`` now catchs + :exc:`PermissionError` and get the process exit code. If the process is + still running, raise again the :exc:`PermissionError`. Otherwise, the + process terminated as expected: store its exit code. Patch by Victor + Stinner. -- gh-issue-110038: Fixed an issue that caused :meth:`KqueueSelector.select` - to not return all the ready events in some cases when a file descriptor is +- gh-110038: Fixed an issue that caused :meth:`KqueueSelector.select` to not + return all the ready events in some cases when a file descriptor is registered for both read and write. -- gh-issue-109631: :mod:`re` functions such as :func:`re.findall`, +- gh-109631: :mod:`re` functions such as :func:`re.findall`, :func:`re.split`, :func:`re.search` and :func:`re.sub` which perform short repeated matches can now be interrupted by user. -- gh-issue-109747: Improve errors for unsupported look-behind patterns. Now +- gh-109747: Improve errors for unsupported look-behind patterns. Now re.error is raised instead of OverflowError or RuntimeError for too large width of look-behind pattern. -- gh-issue-109818: Fix :func:`reprlib.recursive_repr` not copying +- gh-109818: Fix :func:`reprlib.recursive_repr` not copying ``__type_params__`` from decorated function. -- gh-issue-109047: :mod:`concurrent.futures`: The *executor manager thread* - now catches exceptions when adding an item to the *call queue*. During - Python finalization, creating a new thread can now raise - :exc:`RuntimeError`. Catch the exception and call ``terminate_broken()`` - in this case. Patch by Victor Stinner. +- gh-109047: :mod:`concurrent.futures`: The *executor manager thread* now + catches exceptions when adding an item to the *call queue*. During Python + finalization, creating a new thread can now raise :exc:`RuntimeError`. + Catch the exception and call ``terminate_broken()`` in this case. Patch by + Victor Stinner. -- gh-issue-109782: Ensure the signature of :func:`os.path.isdir` is - identical on all platforms. Patch by Amin Alaee. +- gh-109782: Ensure the signature of :func:`os.path.isdir` is identical on + all platforms. Patch by Amin Alaee. -- gh-issue-109590: :func:`shutil.which` will prefer files with an extension - in ``PATHEXT`` if the given mode includes ``os.X_OK`` on win32. If no +- gh-109590: :func:`shutil.which` will prefer files with an extension in + ``PATHEXT`` if the given mode includes ``os.X_OK`` on win32. If no ``PATHEXT`` match is found, a file without an extension in ``PATHEXT`` can be returned. This change will have :func:`shutil.which` act more similarly to previous behavior in Python 3.11. -- gh-issue-109786: Fix possible reference leaks and crash when re-enter the +- gh-109786: Fix possible reference leaks and crash when re-enter the ``__next__()`` method of :class:`itertools.pairwise`. -- gh-issue-109593: Avoid deadlocking on a reentrant call to the - multiprocessing resource tracker. Such a reentrant call, though unlikely, - can happen if a GC pass invokes the finalizer for a multiprocessing object - such as SemLock. +- gh-109593: Avoid deadlocking on a reentrant call to the multiprocessing + resource tracker. Such a reentrant call, though unlikely, can happen if a + GC pass invokes the finalizer for a multiprocessing object such as + SemLock. -- gh-issue-109613: Fix :func:`os.stat` and :meth:`os.DirEntry.stat`: check - for exceptions. Previously, on Python built in debug mode, these functions +- gh-109613: Fix :func:`os.stat` and :meth:`os.DirEntry.stat`: check for + exceptions. Previously, on Python built in debug mode, these functions could trigger a fatal Python error (and abort the process) when a function succeeded with an exception set. Patch by Victor Stinner. -- gh-issue-109375: The :mod:`pdb` ``alias`` command now prevents registering +- gh-109375: The :mod:`pdb` ``alias`` command now prevents registering aliases without arguments. -- gh-issue-107219: Fix a race condition in ``concurrent.futures``. When a - process in the process pool was terminated abruptly (while the future was - running or pending), close the connection write end. If the call queue is - blocked on sending bytes to a worker process, closing the connection write - end interrupts the send, so the queue can be closed. Patch by Victor - Stinner. +- gh-107219: Fix a race condition in ``concurrent.futures``. When a process + in the process pool was terminated abruptly (while the future was running + or pending), close the connection write end. If the call queue is blocked + on sending bytes to a worker process, closing the connection write end + interrupts the send, so the queue can be closed. Patch by Victor Stinner. -- gh-issue-50644: Attempts to pickle or create a shallow or deep copy of +- gh-50644: Attempts to pickle or create a shallow or deep copy of :mod:`codecs` streams now raise a TypeError. Previously, copying failed with a RecursionError, while pickling produced wrong results that eventually caused unpickling to fail with a RecursionError. -- gh-issue-108987: Fix :func:`_thread.start_new_thread` race condition. If a +- gh-108987: Fix :func:`_thread.start_new_thread` race condition. If a thread is created during Python finalization, the newly spawned thread now exits immediately instead of trying to access freed memory and lead to a crash. Patch by Victor Stinner. -- gh-issue-108791: Improved error handling in :mod:`pdb` command line - interface, making it produce more concise error messages. +- gh-108791: Improved error handling in :mod:`pdb` command line interface, + making it produce more concise error messages. -- gh-issue-105829: Fix concurrent.futures.ProcessPoolExecutor deadlock +- gh-105829: Fix concurrent.futures.ProcessPoolExecutor deadlock -- gh-issue-106584: Fix exit code for ``unittest`` if all tests are skipped. - Patch by Egor Eliseev. +- gh-106584: Fix exit code for ``unittest`` if all tests are skipped. Patch + by Egor Eliseev. -- gh-issue-102956: Fix returning of empty byte strings after seek in zipfile +- gh-102956: Fix returning of empty byte strings after seek in zipfile module -- gh-issue-84867: :class:`unittest.TestLoader` no longer loads test cases - from exact :class:`unittest.TestCase` and - :class:`unittest.FunctionTestCase` classes. +- gh-84867: :class:`unittest.TestLoader` no longer loads test cases from + exact :class:`unittest.TestCase` and :class:`unittest.FunctionTestCase` + classes. -- gh-issue-91133: Fix a bug in :class:`tempfile.TemporaryDirectory` cleanup, - which now no longer dereferences symlinks when working around file system +- gh-91133: Fix a bug in :class:`tempfile.TemporaryDirectory` cleanup, which + now no longer dereferences symlinks when working around file system permission errors. -- gh-issue-73561: Omit the interface scope from an IPv6 address when used as - Host header by :mod:`http.client`. +- gh-73561: Omit the interface scope from an IPv6 address when used as Host + header by :mod:`http.client`. -- gh-issue-86826: :mod:`zipinfo` now supports the full range of values in - the TZ string determined by RFC 8536 and detects all invalid formats. Both - Python and C implementations now raise exceptions of the same type on - invalid data. +- gh-86826: :mod:`zipinfo` now supports the full range of values in the TZ + string determined by RFC 8536 and detects all invalid formats. Both Python + and C implementations now raise exceptions of the same type on invalid + data. - bpo-43153: On Windows, ``tempfile.TemporaryDirectory`` previously masked a ``PermissionError`` with ``NotADirectoryError`` during directory cleanup. @@ -1598,164 +2589,163 @@ Library Documentation ------------- -- gh-issue-111699: Relocate ``smtpd`` deprecation notice to its own section - rather than under ``locale`` in What's New in Python 3.12 document +- gh-111699: Relocate ``smtpd`` deprecation notice to its own section rather + than under ``locale`` in What's New in Python 3.12 document -- gh-issue-108826: :mod:`dis` module command-line interface is now mentioned - in documentation. +- gh-108826: :mod:`dis` module command-line interface is now mentioned in + documentation. Tests ----- -- gh-issue-112769: The tests now correctly compare zlib version when +- gh-112769: The tests now correctly compare zlib version when :const:`zlib.ZLIB_RUNTIME_VERSION` contains non-integer suffixes. For example zlib-ng defines the version as ``1.3.0.zlib-ng``. -- gh-issue-110367: Make regrtest ``--verbose3`` option compatible with +- gh-110367: Make regrtest ``--verbose3`` option compatible with ``--huntrleaks -jN`` options. The ``./python -m test -j1 -R 3:3 --verbose3`` command now works as expected. Patch by Victor Stinner. -- gh-issue-111165: Remove no longer used functions ``run_unittest()`` and +- gh-111165: Remove no longer used functions ``run_unittest()`` and ``run_doctest()`` from the :mod:`test.support` module. -- gh-issue-110932: Fix regrtest if the ``SOURCE_DATE_EPOCH`` environment - variable is defined: use the variable value as the random seed. Patch by - Victor Stinner. +- gh-110932: Fix regrtest if the ``SOURCE_DATE_EPOCH`` environment variable + is defined: use the variable value as the random seed. Patch by Victor + Stinner. -- gh-issue-110995: test_gdb: Fix detection of gdb built without Python - scripting support. Patch by Victor Stinner. +- gh-110995: test_gdb: Fix detection of gdb built without Python scripting + support. Patch by Victor Stinner. -- gh-issue-110918: Test case matching patterns specified by options - ``--match``, ``--ignore``, ``--matchfile`` and ``--ignorefile`` are now - tested in the order of specification, and the last match determines - whether the test case be run or ignored. +- gh-110918: Test case matching patterns specified by options ``--match``, + ``--ignore``, ``--matchfile`` and ``--ignorefile`` are now tested in the + order of specification, and the last match determines whether the test + case be run or ignored. -- gh-issue-110647: Fix test_stress_modifying_handlers() of test_signal. - Patch by Victor Stinner. +- gh-110647: Fix test_stress_modifying_handlers() of test_signal. Patch by + Victor Stinner. -- gh-issue-103053: Fix test_tools.test_freeze on FreeBSD: run "make - distclean" instead of "make clean" in the copied source directory to - remove also the "python" program. Patch by Victor Stinner. +- gh-103053: Fix test_tools.test_freeze on FreeBSD: run "make distclean" + instead of "make clean" in the copied source directory to remove also the + "python" program. Patch by Victor Stinner. -- gh-issue-110167: Fix a deadlock in test_socket when server fails with a - timeout but the client is still running in its thread. Don't hold a lock - to call cleanup functions in doCleanups(). One of the cleanup function - waits until the client completes, whereas the client could deadlock if it - called addCleanup() in such situation. Patch by Victor Stinner. +- gh-110167: Fix a deadlock in test_socket when server fails with a timeout + but the client is still running in its thread. Don't hold a lock to call + cleanup functions in doCleanups(). One of the cleanup function waits until + the client completes, whereas the client could deadlock if it called + addCleanup() in such situation. Patch by Victor Stinner. -- gh-issue-110388: Add tests for :mod:`tty`. +- gh-110388: Add tests for :mod:`tty`. -- gh-issue-81002: Add tests for :mod:`termios`. +- gh-81002: Add tests for :mod:`termios`. -- gh-issue-110267: Add tests for pickling and copying PyStructSequence - objects. Patched by Xuehai Pan. +- gh-110267: Add tests for pickling and copying PyStructSequence objects. + Patched by Xuehai Pan. -- gh-issue-110031: Skip test_threading tests using thread+fork if Python is - built with Address Sanitizer (ASAN). Patch by Victor Stinner. +- gh-110031: Skip test_threading tests using thread+fork if Python is built + with Address Sanitizer (ASAN). Patch by Victor Stinner. -- gh-issue-110088: Fix test_asyncio timeouts: don't measure the maximum - duration, a test should not measure a CI performance. Only measure the - minimum duration when a task has a timeout or delay. Add ``CLOCK_RES`` to +- gh-110088: Fix test_asyncio timeouts: don't measure the maximum duration, + a test should not measure a CI performance. Only measure the minimum + duration when a task has a timeout or delay. Add ``CLOCK_RES`` to ``test_asyncio.utils``. Patch by Victor Stinner. -- gh-issue-109974: Fix race conditions in test_threading lock tests. Wait - until a condition is met rather than using :func:`time.sleep` with a - hardcoded number of seconds. Patch by Victor Stinner. +- gh-109974: Fix race conditions in test_threading lock tests. Wait until a + condition is met rather than using :func:`time.sleep` with a hardcoded + number of seconds. Patch by Victor Stinner. -- gh-issue-110033: Fix ``test_interprocess_signal()`` of ``test_signal``. - Make sure that the ``subprocess.Popen`` object is deleted before the test +- gh-110033: Fix ``test_interprocess_signal()`` of ``test_signal``. Make + sure that the ``subprocess.Popen`` object is deleted before the test raising an exception in a signal handler. Otherwise, ``Popen.__del__()`` can get the exception which is logged as ``Exception ignored in: ...`` and the test fails. Patch by Victor Stinner. -- gh-issue-109594: Fix test_timeout() of test_concurrent_futures.test_wait. - Remove the future which may or may not complete depending if it takes - longer than the timeout ot not. Keep the second future which does not - complete before wait() timeout. Patch by Victor Stinner. +- gh-109594: Fix test_timeout() of test_concurrent_futures.test_wait. Remove + the future which may or may not complete depending if it takes longer than + the timeout ot not. Keep the second future which does not complete before + wait() timeout. Patch by Victor Stinner. -- gh-issue-109972: Split test_gdb.py file into a test_gdb package made of - multiple tests, so tests can now be run in parallel. Patch by Victor - Stinner. +- gh-109972: Split test_gdb.py file into a test_gdb package made of multiple + tests, so tests can now be run in parallel. Patch by Victor Stinner. -- gh-issue-103053: Skip test_freeze_simple_script() of - test_tools.test_freeze if Python is built with ``./configure - --enable-optimizations``, which means with Profile Guided Optimization - (PGO): it just makes the test too slow. The freeze tool is tested by many - other CIs with other (faster) compiler flags. Patch by Victor Stinner. +- gh-103053: Skip test_freeze_simple_script() of test_tools.test_freeze if + Python is built with ``./configure --enable-optimizations``, which means + with Profile Guided Optimization (PGO): it just makes the test too slow. + The freeze tool is tested by many other CIs with other (faster) compiler + flags. Patch by Victor Stinner. -- gh-issue-109580: Skip ``test_perf_profiler`` if Python is built with ASAN, - MSAN or UBSAN sanitizer. Python does crash randomly in this test on such - build. Patch by Victor Stinner. +- gh-109580: Skip ``test_perf_profiler`` if Python is built with ASAN, MSAN + or UBSAN sanitizer. Python does crash randomly in this test on such build. + Patch by Victor Stinner. -- gh-issue-104736: Fix test_gdb on Python built with LLVM clang 16 on Linux +- gh-104736: Fix test_gdb on Python built with LLVM clang 16 on Linux ppc64le (ex: Fedora 38). Search patterns in gdb "bt" command output to detect when gdb fails to retrieve the traceback. For example, skip a test if ``Backtrace stopped: frame did not save the PC`` is found. Patch by Victor Stinner. -- gh-issue-108927: Fixed order dependence in running tests in the same - process when a test that has submodules (e.g. test_importlib) follows a - test that imports its submodule (e.g. test_importlib.util) and precedes a - test (e.g. test_unittest or test_compileall) that uses that submodule. +- gh-108927: Fixed order dependence in running tests in the same process + when a test that has submodules (e.g. test_importlib) follows a test that + imports its submodule (e.g. test_importlib.util) and precedes a test (e.g. + test_unittest or test_compileall) that uses that submodule. Build ----- -- gh-issue-112088: Add ``Tools/build/regen-configure.sh`` script to - regenerate the ``configure`` with an Ubuntu container image. The +- gh-112088: Add ``Tools/build/regen-configure.sh`` script to regenerate the + ``configure`` with an Ubuntu container image. The ``quay.io/tiran/cpython_autoconf:271`` container image (`tiran/cpython_autoconf `_) is no longer used. Patch by Victor Stinner. -- gh-issue-111046: For wasi-threads, memory is now exported to fix - compatibility issues with some wasm runtimes. +- gh-111046: For wasi-threads, memory is now exported to fix compatibility + issues with some wasm runtimes. -- gh-issue-103053: "make check-clean-src" now also checks if the "python" - program is found in the source directory: fail with an error if it does - exist. Patch by Victor Stinner. +- gh-103053: "make check-clean-src" now also checks if the "python" program + is found in the source directory: fail with an error if it does exist. + Patch by Victor Stinner. -- gh-issue-109191: Fix compile error when building with recent versions of +- gh-109191: Fix compile error when building with recent versions of libedit. Windows ------- -- gh-issue-111856: Fixes :func:`~os.fstat` on file systems that do not - support file ID requests. This includes FAT32 and exFAT. +- gh-111856: Fixes :func:`~os.fstat` on file systems that do not support + file ID requests. This includes FAT32 and exFAT. -- gh-issue-111293: Fix :data:`os.DirEntry.inode` dropping higher 64 bits of - a file id on some filesystems on Windows. +- gh-111293: Fix :data:`os.DirEntry.inode` dropping higher 64 bits of a file + id on some filesystems on Windows. -- gh-issue-110913: WindowsConsoleIO now correctly chunks large buffers - without splitting up UTF-8 sequences. +- gh-110913: WindowsConsoleIO now correctly chunks large buffers without + splitting up UTF-8 sequences. -- gh-issue-110437: Allows overriding the source of VC redistributables so - that releases can be guaranteed to never downgrade between updates. +- gh-110437: Allows overriding the source of VC redistributables so that + releases can be guaranteed to never downgrade between updates. -- gh-issue-109286: Update Windows installer to use SQLite 3.43.1. +- gh-109286: Update Windows installer to use SQLite 3.43.1. macOS ----- -- gh-issue-109981: Use ``/dev/fd`` on macOS to determine the number of open - files in ``test.support.os_helper.fd_count`` to avoid a crash with - "guarded" file descriptors when probing for open files. +- gh-109981: Use ``/dev/fd`` on macOS to determine the number of open files + in ``test.support.os_helper.fd_count`` to avoid a crash with "guarded" + file descriptors when probing for open files. -- gh-issue-110950: Update macOS installer to include an upstream Tcl/Tk fix - for the ``Secure coding is not enabled for restorable state!`` warning +- gh-110950: Update macOS installer to include an upstream Tcl/Tk fix for + the ``Secure coding is not enabled for restorable state!`` warning encountered in Tkinter on macOS 14 Sonoma. -- gh-issue-111015: Ensure that IDLE.app and Python Launcher.app are - installed with appropriate permissions on macOS builds. +- gh-111015: Ensure that IDLE.app and Python Launcher.app are installed with + appropriate permissions on macOS builds. -- gh-issue-109286: Update macOS installer to use SQLite 3.43.1. +- gh-109286: Update macOS installer to use SQLite 3.43.1. -- gh-issue-71383: Update macOS installer to include an upstream Tcl/Tk fix - for the ``ttk::ThemeChanged`` error encountered in Tkinter. +- gh-71383: Update macOS installer to include an upstream Tcl/Tk fix for the + ``ttk::ThemeChanged`` error encountered in Tkinter. -- gh-issue-92603: Update macOS installer to include a fix accepted by - upstream Tcl/Tk for a crash encountered after the first :meth:`tkinter.Tk` - instance is destroyed. +- gh-92603: Update macOS installer to include a fix accepted by upstream + Tcl/Tk for a crash encountered after the first :meth:`tkinter.Tk` instance + is destroyed. IDLE ---- @@ -1768,15 +2758,15 @@ IDLE C API ----- -- gh-issue-106560: Fix redundant declarations in the public C API. Declare +- gh-106560: Fix redundant declarations in the public C API. Declare PyBool_Type and PyLong_Type only once. Patch by Victor Stinner. -- gh-issue-112438: Fix support of format units "es", "et", "es#", and "et#" - in nested tuples in :c:func:`PyArg_ParseTuple`-like functions. +- gh-112438: Fix support of format units "es", "et", "es#", and "et#" in + nested tuples in :c:func:`PyArg_ParseTuple`-like functions. -- gh-issue-109521: :c:func:`PyImport_GetImporter` now sets RuntimeError if - it fails to get :data:`sys.path_hooks` or :data:`sys.path_importer_cache` - or they are not list and dict correspondingly. Previously it could return +- gh-109521: :c:func:`PyImport_GetImporter` now sets RuntimeError if it + fails to get :data:`sys.path_hooks` or :data:`sys.path_importer_cache` or + they are not list and dict correspondingly. Previously it could return NULL without setting error in obscure cases, crash or raise SystemError if these attributes have wrong type. @@ -1789,41 +2779,41 @@ What's New in Python 3.12.0 final? Core and Builtins ----------------- -- gh-issue-109823: Fix bug where compiler does not adjust labels when - removing an empty basic block which is a jump target. +- gh-109823: Fix bug where compiler does not adjust labels when removing an + empty basic block which is a jump target. -- gh-issue-109719: Fix missing jump target labels when compiler reorders - cold/warm blocks. +- gh-109719: Fix missing jump target labels when compiler reorders cold/warm + blocks. -- gh-issue-109627: Fix bug where the compiler does not assign a new jump - target label to a duplicated small exit block. +- gh-109627: Fix bug where the compiler does not assign a new jump target + label to a duplicated small exit block. Library ------- -- gh-issue-110045: Update the :mod:`symtable` module to support the new - scopes introduced by :pep:`695`. +- gh-110045: Update the :mod:`symtable` module to support the new scopes + introduced by :pep:`695`. Documentation ------------- -- gh-issue-109209: The minimum Sphinx version required for the documentation - is now 4.2. +- gh-109209: The minimum Sphinx version required for the documentation is + now 4.2. Windows ------- -- gh-issue-109991: Update Windows build to use OpenSSL 3.0.11. +- gh-109991: Update Windows build to use OpenSSL 3.0.11. macOS ----- -- gh-issue-109991: Update macOS installer to use OpenSSL 3.0.11. +- gh-109991: Update macOS installer to use OpenSSL 3.0.11. Tools/Demos ----------- -- gh-issue-109991: Update GitHub CI workflows to use OpenSSL 3.0.11 and +- gh-109991: Update GitHub CI workflows to use OpenSSL 3.0.11 and multissltests to use 1.1.1w, 3.0.11, and 3.1.3. @@ -1835,146 +2825,142 @@ What's New in Python 3.12.0 release candidate 3? Core and Builtins ----------------- -- gh-issue-109496: On a Python built in debug mode, :c:func:`Py_DECREF()` - now calls ``_Py_NegativeRefcount()`` if the object is a dangling pointer - to deallocated memory: memory filled with ``0xDD`` "dead byte" by the - debug hook on memory allocators. The fix is to check the reference count +- gh-109496: On a Python built in debug mode, :c:func:`Py_DECREF()` now + calls ``_Py_NegativeRefcount()`` if the object is a dangling pointer to + deallocated memory: memory filled with ``0xDD`` "dead byte" by the debug + hook on memory allocators. The fix is to check the reference count *before* checking for ``_Py_IsImmortal()``. Patch by Victor Stinner. -- gh-issue-109371: Deopted instructions correctly for tool initialization - and modified the incorrect assertion in instrumentation, when a previous - tool already sets INSTRUCTION events +- gh-109371: Deopted instructions correctly for tool initialization and + modified the incorrect assertion in instrumentation, when a previous tool + already sets INSTRUCTION events -- gh-issue-105658: Fix bug where the line trace of an except block ending - with a conditional includes an excess event with the line of the - conditional expression. +- gh-105658: Fix bug where the line trace of an except block ending with a + conditional includes an excess event with the line of the conditional + expression. -- gh-issue-109219: Fix compiling type param scopes that use a name which is - also free in an inner scope. +- gh-109219: Fix compiling type param scopes that use a name which is also + free in an inner scope. -- gh-issue-109341: Fix crash when compiling an invalid AST involving a +- gh-109341: Fix crash when compiling an invalid AST involving a :class:`ast.TypeAlias`. -- gh-issue-109195: Fix source location for the ``LOAD_*`` instruction - preceding a ``LOAD_SUPER_ATTR`` to load the ``super`` global (or shadowing - variable) so that it encompasses only the name ``super`` and not the - following parentheses. +- gh-109195: Fix source location for the ``LOAD_*`` instruction preceding a + ``LOAD_SUPER_ATTR`` to load the ``super`` global (or shadowing variable) + so that it encompasses only the name ``super`` and not the following + parentheses. -- gh-issue-109118: Disallow nested scopes (lambdas, generator expressions, - and comprehensions) within PEP 695 annotation scopes that are nested - within classes. +- gh-109118: Disallow nested scopes (lambdas, generator expressions, and + comprehensions) within PEP 695 annotation scopes that are nested within + classes. -- gh-issue-109114: Relax the detection of the error message for invalid - lambdas inside f-strings to not search for arbitrary replacement fields to - avoid false positives. Patch by Pablo Galindo +- gh-109114: Relax the detection of the error message for invalid lambdas + inside f-strings to not search for arbitrary replacement fields to avoid + false positives. Patch by Pablo Galindo -- gh-issue-109118: Fix interpreter crash when a NameError is raised inside - the type parameters of a generic class. +- gh-109118: Fix interpreter crash when a NameError is raised inside the + type parameters of a generic class. -- gh-issue-108976: Fix crash that occurs after de-instrumenting a code - object in a monitoring callback. +- gh-108976: Fix crash that occurs after de-instrumenting a code object in a + monitoring callback. -- gh-issue-108732: Make iteration variables of module- and class-scoped +- gh-108732: Make iteration variables of module- and class-scoped comprehensions visible to pdb and other tools that use ``frame.f_locals`` again. -- gh-issue-108959: Fix caret placement for error locations for subscript and +- gh-108959: Fix caret placement for error locations for subscript and binary operations that involve non-semantic parentheses and spaces. Patch by Pablo Galindo Library ------- -- gh-issue-108682: Enum: require ``names=()`` or ``type=...`` to create an - empty enum using the functional syntax. +- gh-108682: Enum: require ``names=()`` or ``type=...`` to create an empty + enum using the functional syntax. -- gh-issue-108843: Fix an issue in :func:`ast.unparse` when unparsing - f-strings containing many quote types. +- gh-108843: Fix an issue in :func:`ast.unparse` when unparsing f-strings + containing many quote types. Documentation ------------- -- gh-issue-102823: Document the return type of ``x // y`` when ``x`` and - ``y`` have type :class:`float`. +- gh-102823: Document the return type of ``x // y`` when ``x`` and ``y`` + have type :class:`float`. Tests ----- -- gh-issue-109396: Fix ``test_socket.test_hmac_sha1()`` in FIPS mode. Use a - longer key: FIPS mode requires at least of at least 112 bits. The previous - key was only 32 bits. Patch by Victor Stinner. +- gh-109396: Fix ``test_socket.test_hmac_sha1()`` in FIPS mode. Use a longer + key: FIPS mode requires at least of at least 112 bits. The previous key + was only 32 bits. Patch by Victor Stinner. -- gh-issue-104736: Fix test_gdb on Python built with LLVM clang 16 on Linux +- gh-104736: Fix test_gdb on Python built with LLVM clang 16 on Linux ppc64le (ex: Fedora 38). Search patterns in gdb "bt" command output to detect when gdb fails to retrieve the traceback. For example, skip a test if ``Backtrace stopped: frame did not save the PC`` is found. Patch by Victor Stinner. -- gh-issue-109237: Fix ``test_site.test_underpth_basic()`` when the working +- gh-109237: Fix ``test_site.test_underpth_basic()`` when the working directory contains at least one non-ASCII character: encode the ``._pth`` file to UTF-8 and enable the UTF-8 Mode to use UTF-8 for the child process stdout. Patch by Victor Stinner. -- gh-issue-109230: Fix ``test_pyexpat.test_exception()``: it can now be run - from a directory different than Python source code directory. Before, the - test failed in this case. Skip the test if Modules/pyexpat.c source is - not available. Skip also the test on Python implementations other than +- gh-109230: Fix ``test_pyexpat.test_exception()``: it can now be run from a + directory different than Python source code directory. Before, the test + failed in this case. Skip the test if Modules/pyexpat.c source is not + available. Skip also the test on Python implementations other than CPython. Patch by Victor Stinner. -- gh-issue-109015: Fix test_asyncio, test_imaplib and test_socket tests on - FreeBSD if the TCP blackhole is enabled (``sysctl - net.inet.tcp.blackhole``). Skip the few tests which failed with - ``ETIMEDOUT`` which such non standard configuration. Currently, the - `FreeBSD GCP image enables TCP and UDP blackhole - `_ (``sysctl +- gh-109015: Fix test_asyncio, test_imaplib and test_socket tests on FreeBSD + if the TCP blackhole is enabled (``sysctl net.inet.tcp.blackhole``). Skip + the few tests which failed with ``ETIMEDOUT`` which such non standard + configuration. Currently, the `FreeBSD GCP image enables TCP and UDP + blackhole `_ (``sysctl net.inet.tcp.blackhole=2`` and ``sysctl net.inet.udp.blackhole=1``). Patch by Victor Stinner. -- gh-issue-91960: Skip ``test_gdb`` if gdb is unable to retrieve Python - frame objects: if a frame is ````. When Python is built - with "clang -Og", gdb can fail to retrive the *frame* parameter of +- gh-91960: Skip ``test_gdb`` if gdb is unable to retrieve Python frame + objects: if a frame is ````. When Python is built with + "clang -Og", gdb can fail to retrive the *frame* parameter of ``_PyEval_EvalFrameDefault()``. In this case, tests like ``py_bt()`` are likely to fail. Without getting access to Python frames, ``python-gdb.py`` is mostly clueless on retrieving the Python traceback. Moreover, ``test_gdb`` is no longer skipped on macOS if Python is built with Clang. Patch by Victor Stinner. -- gh-issue-108962: Skip ``test_tempfile.test_flags()`` if ``chflags()`` - fails with "OSError: [Errno 45] Operation not supported" (ex: on FreeBSD - 13). Patch by Victor Stinner. +- gh-108962: Skip ``test_tempfile.test_flags()`` if ``chflags()`` fails with + "OSError: [Errno 45] Operation not supported" (ex: on FreeBSD 13). Patch + by Victor Stinner. -- gh-issue-108851: Fix ``test_tomllib`` recursion tests for WASI buildbots: - reduce the recursion limit and compute the maximum nested array/dict - depending on the current available recursion limit. Patch by Victor - Stinner. +- gh-108851: Fix ``test_tomllib`` recursion tests for WASI buildbots: reduce + the recursion limit and compute the maximum nested array/dict depending on + the current available recursion limit. Patch by Victor Stinner. -- gh-issue-108851: Add ``get_recursion_available()`` and - ``get_recursion_depth()`` functions to the :mod:`test.support` module. - Patch by Victor Stinner. +- gh-108851: Add ``get_recursion_available()`` and ``get_recursion_depth()`` + functions to the :mod:`test.support` module. Patch by Victor Stinner. -- gh-issue-108834: Add ``--fail-rerun option`` option to regrtest: if a test +- gh-108834: Add ``--fail-rerun option`` option to regrtest: if a test failed when then passed when rerun in verbose mode, exit the process with exit code 2 (error), instead of exit code 0 (success). Patch by Victor Stinner. -- gh-issue-108834: Rename regrtest ``--verbose2`` option (``-w``) to - ``--rerun``. Keep ``--verbose2`` as a deprecated alias. Patch by Victor - Stinner. +- gh-108834: Rename regrtest ``--verbose2`` option (``-w``) to ``--rerun``. + Keep ``--verbose2`` as a deprecated alias. Patch by Victor Stinner. -- gh-issue-108834: When regrtest reruns failed tests in verbose mode - (``./python -m test --rerun``), tests are now rerun in fresh worker - processes rather than being executed in the main process. If a test does - crash or is killed by a timeout, the main process can detect and handle - the killed worker process. Tests are rerun in parallel if the ``-jN`` - option is used to run tests in parallel. Patch by Victor Stinner. +- gh-108834: When regrtest reruns failed tests in verbose mode (``./python + -m test --rerun``), tests are now rerun in fresh worker processes rather + than being executed in the main process. If a test does crash or is killed + by a timeout, the main process can detect and handle the killed worker + process. Tests are rerun in parallel if the ``-jN`` option is used to run + tests in parallel. Patch by Victor Stinner. -- gh-issue-103186: Suppress and assert expected RuntimeWarnings in +- gh-103186: Suppress and assert expected RuntimeWarnings in test_sys_settrace.py Build ----- -- gh-issue-108740: Fix a race condition in ``make regen-all``. The +- gh-108740: Fix a race condition in ``make regen-all``. The ``deepfreeze.c`` source and files generated by Argument Clinic are now generated or updated before generating "global objects". Previously, some identifiers may miss depending on the order in which these files were @@ -1989,131 +2975,128 @@ What's New in Python 3.12.0 release candidate 2? Security -------- -- gh-issue-108310: Fixed an issue where instances of :class:`ssl.SSLSocket` - were vulnerable to a bypass of the TLS handshake and included protections - (like certificate verification) and treating sent unencrypted data as if - it were post-handshake TLS encrypted data. Security issue reported as +- gh-108310: Fixed an issue where instances of :class:`ssl.SSLSocket` were + vulnerable to a bypass of the TLS handshake and included protections (like + certificate verification) and treating sent unencrypted data as if it were + post-handshake TLS encrypted data. Security issue reported as :cve:`2023-40217` by Aapo Oksman. Patch by Gregory P. Smith. -- gh-issue-107774: PEP 669 specifies that - ``sys.monitoring.register_callback`` will generate an audit event. - Pre-releases of Python 3.12 did not generate the audit event. This is now - fixed. +- gh-107774: PEP 669 specifies that ``sys.monitoring.register_callback`` + will generate an audit event. Pre-releases of Python 3.12 did not generate + the audit event. This is now fixed. Core and Builtins ----------------- -- gh-issue-108520: Fix - :meth:`multiprocessing.synchronize.SemLock.__setstate__` to properly - initialize :attr:`multiprocessing.synchronize.SemLock._is_fork_ctx`. This - fixes a regression when passing a SemLock accross nested processes. +- gh-108520: Fix :meth:`multiprocessing.synchronize.SemLock.__setstate__` to + properly initialize + :attr:`multiprocessing.synchronize.SemLock._is_fork_ctx`. This fixes a + regression when passing a SemLock accross nested processes. Rename :attr:`multiprocessing.synchronize.SemLock.is_fork_ctx` to :attr:`multiprocessing.synchronize.SemLock._is_fork_ctx` to avoid exposing it as public API. -- gh-issue-108654: Restore locals shadowed by an inlined comprehension if - the comprehension raises an exception. +- gh-108654: Restore locals shadowed by an inlined comprehension if the + comprehension raises an exception. -- gh-issue-108487: Change an assert that would cause a spurious crash in a - devious case that should only trigger deoptimization. +- gh-108487: Change an assert that would cause a spurious crash in a devious + case that should only trigger deoptimization. -- gh-issue-106176: Use a ``WeakValueDictionary`` to track the lists - containing the modules each thread is currently importing. This helps - avoid a reference leak from keeping the list around longer than necessary. - Weakrefs are used as GC can't interrupt the cleanup. +- gh-106176: Use a ``WeakValueDictionary`` to track the lists containing the + modules each thread is currently importing. This helps avoid a reference + leak from keeping the list around longer than necessary. Weakrefs are used + as GC can't interrupt the cleanup. -- gh-issue-107901: Fix missing line number on :opcode:`JUMP_BACKWARD` at the - end of a for loop. +- gh-107901: Fix missing line number on :opcode:`JUMP_BACKWARD` at the end + of a for loop. -- gh-issue-108390: Raise an exception when setting a non-local event - (``RAISE``, ``EXCEPTION_HANDLED``, etc.) in - ``sys.monitoring.set_local_events``. +- gh-108390: Raise an exception when setting a non-local event (``RAISE``, + ``EXCEPTION_HANDLED``, etc.) in ``sys.monitoring.set_local_events``. Fixes crash when tracing in recursive calls to Python classes. -- gh-issue-91051: Fix abort / segfault when using all eight type watcher - slots, on platforms where ``char`` is signed by default. +- gh-91051: Fix abort / segfault when using all eight type watcher slots, on + platforms where ``char`` is signed by default. -- gh-issue-107724: In pre-release versions of 3.12, up to rc1, the - sys.monitoring callback function for the ``PY_THROW`` event was missing - the third, exception argument. That is now fixed. +- gh-107724: In pre-release versions of 3.12, up to rc1, the sys.monitoring + callback function for the ``PY_THROW`` event was missing the third, + exception argument. That is now fixed. -- gh-issue-107080: Trace refs builds (``--with-trace-refs``) were crashing - when used with isolated subinterpreters. The problematic global state has - been isolated to each interpreter. Other fixing the crashes, this change - does not affect users. +- gh-107080: Trace refs builds (``--with-trace-refs``) were crashing when + used with isolated subinterpreters. The problematic global state has been + isolated to each interpreter. Other fixing the crashes, this change does + not affect users. -- gh-issue-77377: Ensure that multiprocessing synchronization objects - created in a fork context are not sent to a different process created in a - spawn context. This changes a segfault into an actionable RuntimeError in - the parent process. +- gh-77377: Ensure that multiprocessing synchronization objects created in a + fork context are not sent to a different process created in a spawn + context. This changes a segfault into an actionable RuntimeError in the + parent process. Library ------- -- gh-issue-108469: :func:`ast.unparse` now supports new :term:`f-string` - syntax introduced in Python 3.12. Note that the :term:`f-string` quotes - are reselected for simplicity under the new syntax. (Patch by Steven Sun) +- gh-108469: :func:`ast.unparse` now supports new :term:`f-string` syntax + introduced in Python 3.12. Note that the :term:`f-string` quotes are + reselected for simplicity under the new syntax. (Patch by Steven Sun) -- gh-issue-108682: Enum: raise :exc:`TypeError` if ``super().__new__()`` is - called from a custom ``__new__``. +- gh-108682: Enum: raise :exc:`TypeError` if ``super().__new__()`` is called + from a custom ``__new__``. -- gh-issue-108295: Fix crashes related to use of weakrefs on +- gh-108295: Fix crashes related to use of weakrefs on :data:`typing.TypeVar`. -- gh-issue-64662: Fix support for virtual tables in +- gh-64662: Fix support for virtual tables in :meth:`sqlite3.Connection.iterdump`. Patch by Aviv Palivoda. -- gh-issue-108111: Fix a regression introduced in GH-101251 for 3.12, - resulting in an incorrect offset calculation in - :meth:`gzip.GzipFile.seek`. +- gh-108111: Fix a regression introduced in GH-101251 for 3.12, resulting in + an incorrect offset calculation in :meth:`gzip.GzipFile.seek`. -- gh-issue-105736: Harmonized the pure Python version of +- gh-105736: Harmonized the pure Python version of :class:`~collections.OrderedDict` with the C version. Now, both versions set up their internal state in ``__new__``. Formerly, the pure Python version did the set up in ``__init__``. -- gh-issue-108083: Fix bugs in the constructor of :mod:`sqlite3.Connection` - and :meth:`sqlite3.Connection.close` where exceptions could be leaked. - Patch by Erlend E. Aasland. +- gh-108083: Fix bugs in the constructor of :mod:`sqlite3.Connection` and + :meth:`sqlite3.Connection.close` where exceptions could be leaked. Patch + by Erlend E. Aasland. -- gh-issue-107963: Fix :func:`multiprocessing.set_forkserver_preload` to - check the given list of modules names. Patch by Donghee Na. +- gh-107963: Fix :func:`multiprocessing.set_forkserver_preload` to check the + given list of modules names. Patch by Donghee Na. -- gh-issue-106242: Fixes :func:`os.path.normpath` to handle embedded null +- gh-106242: Fixes :func:`os.path.normpath` to handle embedded null characters without truncating the path. -- gh-issue-107913: Fix possible losses of ``errno`` and ``winerror`` values - in :exc:`OSError` exceptions if they were cleared or modified by the - cleanup code before creating the exception object. +- gh-107913: Fix possible losses of ``errno`` and ``winerror`` values in + :exc:`OSError` exceptions if they were cleared or modified by the cleanup + code before creating the exception object. -- gh-issue-107845: :func:`tarfile.data_filter` now takes the location of - symlinks into account when determining their target, so it will no longer - reject some valid tarballs with ``LinkOutsideDestinationError``. +- gh-107845: :func:`tarfile.data_filter` now takes the location of symlinks + into account when determining their target, so it will no longer reject + some valid tarballs with ``LinkOutsideDestinationError``. -- gh-issue-107805: Fix signatures of module-level generated functions in +- gh-107805: Fix signatures of module-level generated functions in :mod:`turtle`. -- gh-issue-107715: Fix :meth:`doctest.DocTestFinder.find` in presence of - class names with special characters. Patch by Gertjan van Zwieten. +- gh-107715: Fix :meth:`doctest.DocTestFinder.find` in presence of class + names with special characters. Patch by Gertjan van Zwieten. -- gh-issue-100814: Passing a callable object as an option value to a Tkinter - image now raises the expected TclError instead of an AttributeError. +- gh-100814: Passing a callable object as an option value to a Tkinter image + now raises the expected TclError instead of an AttributeError. -- gh-issue-106684: Close :class:`asyncio.StreamWriter` when it is not closed - by application leading to memory leaks. Patch by Kumar Aditya. +- gh-106684: Close :class:`asyncio.StreamWriter` when it is not closed by + application leading to memory leaks. Patch by Kumar Aditya. -- gh-issue-107396: tarfiles; Fixed use before assignment of self.exception - for gzip decompression +- gh-107396: tarfiles; Fixed use before assignment of self.exception for + gzip decompression -- gh-issue-106052: :mod:`re` module: fix the matching of possessive - quantifiers in the case of a subpattern containing backtracking. +- gh-106052: :mod:`re` module: fix the matching of possessive quantifiers in + the case of a subpattern containing backtracking. -- gh-issue-100061: Fix a bug that causes wrong matches for regular - expressions with possessive qualifier. +- gh-100061: Fix a bug that causes wrong matches for regular expressions + with possessive qualifier. -- gh-issue-99203: Restore following CPython <= 3.10.5 behavior of +- gh-99203: Restore following CPython <= 3.10.5 behavior of :func:`shutil.make_archive`: do not create an empty archive if ``root_dir`` is not a directory, and, in that case, raise :class:`FileNotFoundError` or :class:`NotADirectoryError` regardless of @@ -2123,82 +3106,82 @@ Library Documentation ------------- -- gh-issue-105052: Update ``timeit`` doc to specify that time in seconds is - just the default. +- gh-105052: Update ``timeit`` doc to specify that time in seconds is just + the default. Tests ----- -- gh-issue-89392: Removed support of ``test_main()`` function in tests. They - now always use normal unittest test runner. +- gh-89392: Removed support of ``test_main()`` function in tests. They now + always use normal unittest test runner. -- gh-issue-108388: Convert test_concurrent_futures to a package of 7 - sub-tests. Patch by Victor Stinner. +- gh-108388: Convert test_concurrent_futures to a package of 7 sub-tests. + Patch by Victor Stinner. -- gh-issue-108388: Split test_multiprocessing_fork, +- gh-108388: Split test_multiprocessing_fork, test_multiprocessing_forkserver and test_multiprocessing_spawn into test packages. Each package is made of 4 sub-tests: processes, threads, manager and misc. It allows running more tests in parallel and so reduce the total test duration. Patch by Victor Stinner. -- gh-issue-105776: Fix test_cppext when the C compiler command ``-std=c11`` +- gh-105776: Fix test_cppext when the C compiler command ``-std=c11`` option: remove ``-std=`` options from the compiler command. Patch by Victor Stinner. -- gh-issue-107178: Add the C API test for functions in the Mapping Protocol, - the Sequence Protocol and some functions in the Object Protocol. +- gh-107178: Add the C API test for functions in the Mapping Protocol, the + Sequence Protocol and some functions in the Object Protocol. Build ----- -- gh-issue-63760: Fix Solaris build: no longer redefine the - ``gethostname()`` function. Solaris defines the function since 2005. Patch - by Victor Stinner, original patch by Jakub Kulík. +- gh-63760: Fix Solaris build: no longer redefine the ``gethostname()`` + function. Solaris defines the function since 2005. Patch by Victor + Stinner, original patch by Jakub Kulík. -- gh-issue-107814: When calling ``find_python.bat`` with ``-q`` it did not +- gh-107814: When calling ``find_python.bat`` with ``-q`` it did not properly silence the output of nuget. That is now fixed. Windows ------- -- gh-issue-107565: Update Windows build to use OpenSSL 3.0.10. +- gh-107565: Update Windows build to use OpenSSL 3.0.10. -- gh-issue-106242: Fixes :func:`~os.path.realpath` to behave consistently - when passed a path containing an embedded null character on Windows. In - strict mode, it now raises :exc:`OSError` instead of the unexpected +- gh-106242: Fixes :func:`~os.path.realpath` to behave consistently when + passed a path containing an embedded null character on Windows. In strict + mode, it now raises :exc:`OSError` instead of the unexpected :exc:`ValueError`, and in non-strict mode will make the path absolute. -- gh-issue-106844: Fix integer overflow and truncating by the null character - in :func:`!_winapi.LCMapStringEx` which affects :func:`ntpath.normcase`. +- gh-106844: Fix integer overflow and truncating by the null character in + :func:`!_winapi.LCMapStringEx` which affects :func:`ntpath.normcase`. macOS ----- -- gh-issue-107565: Update macOS installer to use OpenSSL 3.0.10. +- gh-107565: Update macOS installer to use OpenSSL 3.0.10. Tools/Demos ----------- -- gh-issue-107565: Update multissltests and GitHub CI workflows to use - OpenSSL 1.1.1v, 3.0.10, and 3.1.2. +- gh-107565: Update multissltests and GitHub CI workflows to use OpenSSL + 1.1.1v, 3.0.10, and 3.1.2. -- gh-issue-95065: Argument Clinic now supports overriding automatically - generated signature by using directive ``@text_signature``. +- gh-95065: Argument Clinic now supports overriding automatically generated + signature by using directive ``@text_signature``. C API ----- -- gh-issue-107916: C API functions :c:func:`PyErr_SetFromErrnoWithFilename`, +- gh-107916: C API functions :c:func:`PyErr_SetFromErrnoWithFilename`, :c:func:`PyErr_SetExcFromWindowsErrWithFilename` and :c:func:`PyErr_SetFromWindowsErrWithFilename` save now the error code before calling :c:func:`PyUnicode_DecodeFSDefault`. -- gh-issue-107915: Such C API functions as ``PyErr_SetString()``, +- gh-107915: Such C API functions as ``PyErr_SetString()``, ``PyErr_Format()``, ``PyErr_SetFromErrnoWithFilename()`` and many others no longer crash or ignore errors if it failed to format the error message or decode the filename. Instead, they keep a corresponding error. -- gh-issue-107810: Improve :exc:`DeprecationWarning` for uses of +- gh-107810: Improve :exc:`DeprecationWarning` for uses of :c:type:`PyType_Spec` with metaclasses that have custom ``tp_new``. @@ -2210,130 +3193,128 @@ What's New in Python 3.12.0 release candidate 1? Security -------- -- gh-issue-102988: Reverted the :mod:`email.utils` security improvement - change released in 3.12beta4 that unintentionally caused +- gh-102988: Reverted the :mod:`email.utils` security improvement change + released in 3.12beta4 that unintentionally caused :mod:`email.utils.getaddresses` to fail to parse email addresses with a comma in the quoted name field. See :gh:`106669`. -- gh-issue-102509: Start initializing ``ob_digit`` during creation of +- gh-102509: Start initializing ``ob_digit`` during creation of :c:type:`PyLongObject` objects. Patch by Illia Volochii. Core and Builtins ----------------- -- gh-issue-107263: Increase C recursion limit for functions other than the - main interpreter from 800 to 1500. This should allow functions like +- gh-107263: Increase C recursion limit for functions other than the main + interpreter from 800 to 1500. This should allow functions like ``list.__repr__`` and ``json.dumps`` to handle all the inputs that they could prior to 3.12 -- gh-issue-104432: Fix potential unaligned memory access on C APIs involving +- gh-104432: Fix potential unaligned memory access on C APIs involving returned sequences of ``char *`` pointers within the :mod:`grp` and :mod:`socket` modules. These were revealed using a ``-fsaniziter=alignment`` build on ARM macOS. Patch by Christopher Chavez. -- gh-issue-106898: Add the exception as the third argument to ``PY_UNIND`` +- gh-106898: Add the exception as the third argument to ``PY_UNIND`` callbacks in ``sys.monitoring``. This makes the ``PY_UNWIND`` callback consistent with the other exception hanlding callbacks. -- gh-issue-106895: Raise a ``ValueError`` when a monitoring callback funtion +- gh-106895: Raise a ``ValueError`` when a monitoring callback funtion returns ``DISABLE`` for events that cannot be disabled locally. -- gh-issue-106897: Add a ``RERAISE`` event to ``sys.monitoring``, which - occurs when an exception is reraised, either explicitly by a plain - ``raise`` statement, or implicitly in an ``except`` or ``finally`` block. +- gh-106897: Add a ``RERAISE`` event to ``sys.monitoring``, which occurs + when an exception is reraised, either explicitly by a plain ``raise`` + statement, or implicitly in an ``except`` or ``finally`` block. -- gh-issue-104621: Unsupported modules now always fail to be imported. +- gh-104621: Unsupported modules now always fail to be imported. -- gh-issue-106917: Fix classmethod-style :func:`super` method calls (i.e., - where the second argument to :func:`super`, or the implied second argument - drawn from ``self/cls`` in the case of zero-arg super, is a type) when the +- gh-106917: Fix classmethod-style :func:`super` method calls (i.e., where + the second argument to :func:`super`, or the implied second argument drawn + from ``self/cls`` in the case of zero-arg super, is a type) when the target of the call is not a classmethod. -- gh-issue-105699: Python no longer crashes due an infrequent race when +- gh-105699: Python no longer crashes due an infrequent race when initialzing per-interpreter interned strings. The crash would manifest when the interpreter was finalized. -- gh-issue-105699: Python no longer crashes due to an infrequent race in - setting ``Py_FileSystemDefaultEncoding`` and - ``Py_FileSystemDefaultEncodeErrors`` (both deprecated), when - simultaneously initializing two isolated subinterpreters. Now they are - only set during runtime initialization. +- gh-105699: Python no longer crashes due to an infrequent race in setting + ``Py_FileSystemDefaultEncoding`` and ``Py_FileSystemDefaultEncodeErrors`` + (both deprecated), when simultaneously initializing two isolated + subinterpreters. Now they are only set during runtime initialization. -- gh-issue-106092: Fix a segmentation fault caused by a use-after-free bug - in ``frame_dealloc`` when the trashcan delays the deallocation of a +- gh-106092: Fix a segmentation fault caused by a use-after-free bug in + ``frame_dealloc`` when the trashcan delays the deallocation of a ``PyFrameObject``. -- gh-issue-106719: No longer suppress arbitrary errors in the - ``__annotations__`` getter and setter in the type and module types. +- gh-106719: No longer suppress arbitrary errors in the ``__annotations__`` + getter and setter in the type and module types. -- gh-issue-106723: Propagate ``frozen_modules`` to multiprocessing spawned - process interpreters. +- gh-106723: Propagate ``frozen_modules`` to multiprocessing spawned process + interpreters. -- gh-issue-105235: Prevent out-of-bounds memory access during - ``mmap.find()`` calls. +- gh-105235: Prevent out-of-bounds memory access during ``mmap.find()`` + calls. Library ------- -- gh-issue-107077: Seems that in some conditions, OpenSSL will return +- gh-107077: Seems that in some conditions, OpenSSL will return ``SSL_ERROR_SYSCALL`` instead of ``SSL_ERROR_SSL`` when a certification verification has failed, but the error parameters will still contain ``ERR_LIB_SSL`` and ``SSL_R_CERTIFICATE_VERIFY_FAILED``. We are now detecting this situation and raising the appropiate ``ssl.SSLCertVerificationError``. Patch by Pablo Galindo -- gh-issue-107576: Fix :func:`types.get_original_bases` to only return +- gh-107576: Fix :func:`types.get_original_bases` to only return :attr:`!__orig_bases__` if it is present on ``cls`` directly. Patch by James Hilton-Balfe. -- gh-issue-46376: Prevent memory leak and use-after-free when using pointers - to pointers with ctypes +- gh-46376: Prevent memory leak and use-after-free when using pointers to + pointers with ctypes -- gh-issue-62519: Make :func:`gettext.pgettext` search plural definitions - when translation is not found. +- gh-62519: Make :func:`gettext.pgettext` search plural definitions when + translation is not found. -- gh-issue-83006: Document behavior of :func:`shutil.disk_usage` for - non-mounted filesystems on Unix. +- gh-83006: Document behavior of :func:`shutil.disk_usage` for non-mounted + filesystems on Unix. -- gh-issue-106186: Do not report ``MultipartInvariantViolationDefect`` - defect when the :class:`email.parser.Parser` class is used to parse emails - with ``headersonly=True``. +- gh-106186: Do not report ``MultipartInvariantViolationDefect`` defect when + the :class:`email.parser.Parser` class is used to parse emails with + ``headersonly=True``. -- gh-issue-105002: Fix invalid result from :meth:`PurePath.relative_to` - method when attempting to walk a "``..``" segment in *other* with - *walk_up* enabled. A :exc:`ValueError` exception is now raised in this - case. +- gh-105002: Fix invalid result from :meth:`PurePath.relative_to` method + when attempting to walk a "``..``" segment in *other* with *walk_up* + enabled. A :exc:`ValueError` exception is now raised in this case. -- gh-issue-106831: Fix potential missing ``NULL`` check of - ``d2i_SSL_SESSION`` result in ``_ssl.c``. +- gh-106831: Fix potential missing ``NULL`` check of ``d2i_SSL_SESSION`` + result in ``_ssl.c``. -- gh-issue-106774: Update the bundled copy of pip to version 23.2.1. +- gh-106774: Update the bundled copy of pip to version 23.2.1. -- gh-issue-106752: Fixed several bugs in zipfile.Path, including: in +- gh-106752: Fixed several bugs in zipfile.Path, including: in ``Path.match``, Windows separators are no longer honored (and never were meant to be); Fixed ``name``/``suffix``/``suffixes``/``stem`` operations when no filename is present and the Path is not at the root of the zipfile; Reworked glob for performance and more correct matching behavior. -- gh-issue-106602: Add __copy__ and __deepcopy__ in :mod:`enum` +- gh-106602: Add __copy__ and __deepcopy__ in :mod:`enum` -- gh-issue-106530: Revert a change to :func:`colorsys.rgb_to_hls` that - caused division by zero for certain almost-white inputs. Patch by Terry - Jan Reedy. +- gh-106530: Revert a change to :func:`colorsys.rgb_to_hls` that caused + division by zero for certain almost-white inputs. Patch by Terry Jan + Reedy. -- gh-issue-106403: Instances of :class:`typing.TypeVar`, +- gh-106403: Instances of :class:`typing.TypeVar`, :class:`typing.ParamSpec`, :class:`typing.ParamSpecArgs`, :class:`typing.ParamSpecKwargs`, and :class:`typing.TypeVarTuple` once again support weak references, fixing a regression introduced in Python 3.12.0 beta 1. Patch by Jelle Zijlstra. -- gh-issue-106350: Detect possible memory allocation failure in the - libtommath function :c:func:`mp_init` used by the ``_tkinter`` module. +- gh-106350: Detect possible memory allocation failure in the libtommath + function :c:func:`mp_init` used by the ``_tkinter`` module. -- gh-issue-106263: Fix crash when calling ``repr`` with a manually - constructed SignalDict object. Patch by Charlie Zhao. +- gh-106263: Fix crash when calling ``repr`` with a manually constructed + SignalDict object. Patch by Charlie Zhao. -- gh-issue-105626: Change the default return value of +- gh-105626: Change the default return value of :meth:`http.client.HTTPConnection.get_proxy_response_headers` to be ``None`` and not ``{}``. @@ -2343,74 +3324,72 @@ Library Documentation ------------- -- gh-issue-107305: Add documentation for :c:type:`PyInterpreterConfig` and +- gh-107305: Add documentation for :c:type:`PyInterpreterConfig` and :c:func:`Py_NewInterpreterFromConfig`. Also clarify some of the nearby docs relative to per-interpreter GIL. -- gh-issue-107008: Document the :mod:`curses` module variables +- gh-107008: Document the :mod:`curses` module variables :const:`~curses.LINES` and :const:`~curses.COLS`. -- gh-issue-106948: Add a number of standard external names to - ``nitpick_ignore``. +- gh-106948: Add a number of standard external names to ``nitpick_ignore``. -- gh-issue-54738: Add documentation on how to localize the :mod:`argparse` - module. +- gh-54738: Add documentation on how to localize the :mod:`argparse` module. Tests ----- -- gh-issue-107237: ``test_logging``: Fix ``test_udp_reconnection()`` by - increasing the timeout from 100 ms to 5 minutes (LONG_TIMEOUT). Patch by - Victor Stinner. +- gh-107237: ``test_logging``: Fix ``test_udp_reconnection()`` by increasing + the timeout from 100 ms to 5 minutes (LONG_TIMEOUT). Patch by Victor + Stinner. -- gh-issue-106714: test_capi: Fix test_no_FatalError_infinite_loop() to no - longer write a coredump, by using test.support.SuppressCrashReport. Patch - by Victor Stinner. +- gh-106714: test_capi: Fix test_no_FatalError_infinite_loop() to no longer + write a coredump, by using test.support.SuppressCrashReport. Patch by + Victor Stinner. -- gh-issue-104090: Avoid creating a reference to the test object in +- gh-104090: Avoid creating a reference to the test object in :meth:`~unittest.TestResult.collectedDurations`. -- gh-issue-106752: Moved tests for ``zipfile.Path`` into +- gh-106752: Moved tests for ``zipfile.Path`` into ``Lib/test/test_zipfile/_path``. Made ``zipfile._path`` a package. Build ----- -- gh-issue-106881: Check for ``linux/limits.h`` before including it in +- gh-106881: Check for ``linux/limits.h`` before including it in ``Modules/posixmodule.c``. -- gh-issue-106962: Detect MPI compilers in :file:`configure`. +- gh-106962: Detect MPI compilers in :file:`configure`. -- gh-issue-101538: Add experimental wasi-threads support. Patch by Takashi +- gh-101538: Add experimental wasi-threads support. Patch by Takashi Yamamoto. Windows ------- -- gh-issue-99079: Update Windows build to use OpenSSL 3.0.9 +- gh-99079: Update Windows build to use OpenSSL 3.0.9 macOS ----- -- gh-issue-99079: Update macOS installer to use OpenSSL 3.0.9. +- gh-99079: Update macOS installer to use OpenSSL 3.0.9. Tools/Demos ----------- -- gh-issue-106970: Fix bugs in the Argument Clinic ``destination - clear`` command; the destination buffers would never be cleared, and the +- gh-106970: Fix bugs in the Argument Clinic ``destination clear`` + command; the destination buffers would never be cleared, and the ``destination`` directive parser would simply continue to the fault handler after processing the command. Patch by Erlend E. Aasland. -- gh-issue-103186: ``freeze`` now fetches ``CONFIG_ARGS`` from the original +- gh-103186: ``freeze`` now fetches ``CONFIG_ARGS`` from the original CPython instance the Makefile uses to call utility scripts. Patch by Ijtaba Hussain. C API ----- -- gh-issue-107226: :c:func:`PyModule_AddObjectRef` is now only available in - the limited API version 3.10 or later. +- gh-107226: :c:func:`PyModule_AddObjectRef` is now only available in the + limited API version 3.10 or later. What's New in Python 3.12.0 beta 4? @@ -2421,122 +3400,114 @@ What's New in Python 3.12.0 beta 4? Security -------- -- gh-issue-102988: :cve:`2023-27043`: Prevent :func:`email.utils.parseaddr` - and :func:`email.utils.getaddresses` from returning the realname portion - of an invalid RFC2822 email header in the email address portion of the - 2-tuple returned after being parsed by - :class:`email._parseaddr.AddressList`. +- gh-102988: :cve:`2023-27043`: Prevent :func:`email.utils.parseaddr` and + :func:`email.utils.getaddresses` from returning the realname portion of an + invalid RFC2822 email header in the email address portion of the 2-tuple + returned after being parsed by :class:`email._parseaddr.AddressList`. Core and Builtins ----------------- -- gh-issue-106396: When the format specification of an f-string expression - is empty, the parser now generates an empty :class:`ast.JoinedStr` node - for it instead of an one-element :class:`ast.JoinedStr` with an empty - string :class:`ast.Constant`. +- gh-106396: When the format specification of an f-string expression is + empty, the parser now generates an empty :class:`ast.JoinedStr` node for + it instead of an one-element :class:`ast.JoinedStr` with an empty string + :class:`ast.Constant`. -- gh-issue-106145: Make ``end_lineno`` and ``end_col_offset`` required on +- gh-106145: Make ``end_lineno`` and ``end_col_offset`` required on ``type_param`` ast nodes. -- gh-issue-105979: Fix crash in :func:`!_imp.get_frozen_object` due to - improper exception handling. +- gh-105979: Fix crash in :func:`!_imp.get_frozen_object` due to improper + exception handling. -- gh-issue-98931: Ensure custom :exc:`SyntaxError` error messages are raised - for invalid imports with multiple targets. Patch by Pablo Galindo +- gh-98931: Ensure custom :exc:`SyntaxError` error messages are raised for + invalid imports with multiple targets. Patch by Pablo Galindo -- gh-issue-105908: Fixed bug where :gh:`99111` breaks future import +- gh-105908: Fixed bug where :gh:`99111` breaks future import ``barry_as_FLUFL`` in the Python REPL. -- gh-issue-105340: Include the comprehension iteration variable in - ``locals()`` inside a module- or class-scope comprehension. +- gh-105340: Include the comprehension iteration variable in ``locals()`` + inside a module- or class-scope comprehension. -- gh-issue-105486: Change the repr of ``ParamSpec`` list of args in +- gh-105486: Change the repr of ``ParamSpec`` list of args in ``types.GenericAlias``. -- gh-issue-101006: Improve error handling when read :mod:`marshal` data. +- gh-101006: Improve error handling when read :mod:`marshal` data. Library ------- -- gh-issue-106524: Fix crash in :func:`!_sre.template` with templates - containing invalid group indices. +- gh-106524: Fix crash in :func:`!_sre.template` with templates containing + invalid group indices. -- gh-issue-106510: Improve debug output for atomic groups in regular - expressions. +- gh-106510: Improve debug output for atomic groups in regular expressions. -- gh-issue-106503: Fix ref cycle in - :class:`!asyncio._SelectorSocketTransport` by removing ``_write_ready`` in - ``close``. +- gh-106503: Fix ref cycle in :class:`!asyncio._SelectorSocketTransport` by + removing ``_write_ready`` in ``close``. -- gh-issue-105497: Fix flag mask inversion when unnamed flags exist. +- gh-105497: Fix flag mask inversion when unnamed flags exist. -- gh-issue-90876: Prevent :mod:`multiprocessing.spawn` from failing to - *import* in environments where ``sys.executable`` is ``None``. This - regressed in 3.11 with the addition of support for path-like objects in - multiprocessing. +- gh-90876: Prevent :mod:`multiprocessing.spawn` from failing to *import* in + environments where ``sys.executable`` is ``None``. This regressed in 3.11 + with the addition of support for path-like objects in multiprocessing. -- gh-issue-106292: Check for an instance-dict cached value in the - :meth:`__get__` method of :func:`functools.cached_property`. This better - matches the pre-3.12 behavior and improves compatibility for users - subclassing :func:`functools.cached_property` and adding a :meth:`__set__` - method. +- gh-106292: Check for an instance-dict cached value in the :meth:`__get__` + method of :func:`functools.cached_property`. This better matches the + pre-3.12 behavior and improves compatibility for users subclassing + :func:`functools.cached_property` and adding a :meth:`__set__` method. -- gh-issue-106330: Fix incorrect matching of empty paths in +- gh-106330: Fix incorrect matching of empty paths in :meth:`pathlib.PurePath.match`. This bug was introduced in Python 3.12.0 beta 1. -- gh-issue-102541: Make pydoc.doc catch bad module ImportError when output - stream is not None. +- gh-102541: Make pydoc.doc catch bad module ImportError when output stream + is not None. -- gh-issue-106152: Added PY_THROW event hook for :mod:`cProfile` for - generators +- gh-106152: Added PY_THROW event hook for :mod:`cProfile` for generators -- gh-issue-106075: Added ``asyncio.taskgroups.__all__`` to - ``asyncio.__all__`` for export in star imports. +- gh-106075: Added ``asyncio.taskgroups.__all__`` to ``asyncio.__all__`` for + export in star imports. -- gh-issue-105987: Fix crash due to improper reference counting in - :mod:`asyncio` eager task factory internal routines. +- gh-105987: Fix crash due to improper reference counting in :mod:`asyncio` + eager task factory internal routines. -- gh-issue-105974: Fix bug where a :class:`typing.Protocol` class that had - one or more non-callable members would raise :exc:`TypeError` when +- gh-105974: Fix bug where a :class:`typing.Protocol` class that had one or + more non-callable members would raise :exc:`TypeError` when :func:`issubclass` was called against it, even if it defined a custom ``__subclasshook__`` method. The behaviour in Python 3.11 and lower -- which has now been restored -- was not to raise :exc:`TypeError` in these situations if a custom ``__subclasshook__`` method was defined. Patch by Alex Waygood. -- gh-issue-96145: Reverted addition of ``json.AttrDict``. +- gh-96145: Reverted addition of ``json.AttrDict``. -- gh-issue-105497: Fix flag inversion when alias/mask members exist. +- gh-105497: Fix flag inversion when alias/mask members exist. -- gh-issue-104554: Add RTSPS scheme support in urllib.parse +- gh-104554: Add RTSPS scheme support in urllib.parse -- gh-issue-94777: Fix hanging :mod:`multiprocessing` ``ProcessPoolExecutor`` - when a child process crashes while data is being written in the call - queue. +- gh-94777: Fix hanging :mod:`multiprocessing` ``ProcessPoolExecutor`` when + a child process crashes while data is being written in the call queue. Documentation ------------- -- gh-issue-106232: Make timeit doc command lines compatible with Windows by - using double quotes for arguments. This works on linux and macOS also. +- gh-106232: Make timeit doc command lines compatible with Windows by using + double quotes for arguments. This works on linux and macOS also. Tests ----- -- gh-issue-101634: When running the Python test suite with ``-jN`` option, - if a worker stdout cannot be decoded from the locale encoding report a - failed testn so the exitcode is non-zero. Patch by Victor Stinner. +- gh-101634: When running the Python test suite with ``-jN`` option, if a + worker stdout cannot be decoded from the locale encoding report a failed + testn so the exitcode is non-zero. Patch by Victor Stinner. Build ----- -- gh-issue-106118: Fix compilation for platforms without :data:`!O_CLOEXEC`. - The issue was introduced with Python 3.12b1 in :gh:`103295`. Patch by - Erlend Aasland. +- gh-106118: Fix compilation for platforms without :data:`!O_CLOEXEC`. The + issue was introduced with Python 3.12b1 in :gh:`103295`. Patch by Erlend + Aasland. -- gh-issue-104692: Include ``commoninstall`` as a prerequisite for - ``bininstall`` +- gh-104692: Include ``commoninstall`` as a prerequisite for ``bininstall`` This ensures that ``commoninstall`` is completed before ``bininstall`` is started when parallel builds are used (``make -j install``), and so the @@ -2546,14 +3517,14 @@ Build Tools/Demos ----------- -- gh-issue-106359: Argument Clinic now explicitly forbids "kwarg splats" in +- gh-106359: Argument Clinic now explicitly forbids "kwarg splats" in function calls used as annotations. C API ----- -- gh-issue-105227: The new :c:func:`PyType_GetDict` provides the dictionary - for the given type object that is normally exposed by ``cls.__dict__``. +- gh-105227: The new :c:func:`PyType_GetDict` provides the dictionary for + the given type object that is normally exposed by ``cls.__dict__``. Normally it's sufficient to use :c:member:`~PyTypeObject.tp_dict`, but for the static builtin types :c:member:`!tp_dict` is now always ``NULL``. :c:func:`!PyType_GetDict()` provides the correct dict object instead. @@ -2567,53 +3538,51 @@ What's New in Python 3.12.0 beta 3? Core and Builtins ----------------- -- gh-issue-105840: Fix possible crashes when specializing function calls - with too many ``__defaults__``. +- gh-105840: Fix possible crashes when specializing function calls with too + many ``__defaults__``. -- gh-issue-105831: Fix an f-string bug, where using a debug expression (the - ``=`` sign) that appears in the last line of a file results to the debug - buffer that holds the expression text being one character too small. +- gh-105831: Fix an f-string bug, where using a debug expression (the ``=`` + sign) that appears in the last line of a file results to the debug buffer + that holds the expression text being one character too small. -- gh-issue-105800: Correctly issue :exc:`SyntaxWarning` in f-strings if - invalid sequences are used. Patch by Pablo Galindo +- gh-105800: Correctly issue :exc:`SyntaxWarning` in f-strings if invalid + sequences are used. Patch by Pablo Galindo -- gh-issue-105587: The runtime can't guarantee that immortal objects will - not be mutated by Extensions. Thus, this modifies - _PyStaticObject_CheckRefcnt to warn instead of asserting. +- gh-105587: The runtime can't guarantee that immortal objects will not be + mutated by Extensions. Thus, this modifies _PyStaticObject_CheckRefcnt to + warn instead of asserting. -- gh-issue-105564: Don't include artificil newlines in the ``line`` - attribute of tokens in the APIs of the :mod:`tokenize` module. Patch by - Pablo Galindo +- gh-105564: Don't include artificil newlines in the ``line`` attribute of + tokens in the APIs of the :mod:`tokenize` module. Patch by Pablo Galindo -- gh-issue-105549: Tokenize separately ``NUMBER`` and ``NAME`` tokens that - are not ambiguous. Patch by Pablo Galindo. +- gh-105549: Tokenize separately ``NUMBER`` and ``NAME`` tokens that are not + ambiguous. Patch by Pablo Galindo. -- gh-issue-105588: Fix an issue that could result in crashes when compiling +- gh-105588: Fix an issue that could result in crashes when compiling malformed :mod:`ast` nodes. -- gh-issue-105375: Fix bugs in the :mod:`builtins` module where exceptions - could end up being overwritten. - -- gh-issue-105375: Fix bug in the compiler where an exception could end up - being overwritten. +- gh-105375: Fix bugs in the :mod:`builtins` module where exceptions could + end up being overwritten. -- gh-issue-105375: Improve error handling in - :c:func:`PyUnicode_BuildEncodingMap` where an exception could end up being +- gh-105375: Fix bug in the compiler where an exception could end up being overwritten. -- gh-issue-105435: Fix spurious newline character if file ends on a comment +- gh-105375: Improve error handling in :c:func:`PyUnicode_BuildEncodingMap` + where an exception could end up being overwritten. + +- gh-105435: Fix spurious newline character if file ends on a comment without a newline. Patch by Pablo Galindo -- gh-issue-105390: Correctly raise :exc:`tokenize.TokenError` exceptions - instead of :exc:`SyntaxError` for tokenize errors such as incomplete - input. Patch by Pablo Galindo +- gh-105390: Correctly raise :exc:`tokenize.TokenError` exceptions instead + of :exc:`SyntaxError` for tokenize errors such as incomplete input. Patch + by Pablo Galindo -- gh-issue-104812: The "pending call" machinery now works for all - interpreters, not just the main interpreter, and runs in all threads, not - just the main thread. Some calls are still only done in the main thread, - ergo in the main interpreter. This change does not affect signal handling - nor the existing public C-API (``Py_AddPendingCall()``), which both still - only target the main thread. The new functionality is meant strictly for +- gh-104812: The "pending call" machinery now works for all interpreters, + not just the main interpreter, and runs in all threads, not just the main + thread. Some calls are still only done in the main thread, ergo in the + main interpreter. This change does not affect signal handling nor the + existing public C-API (``Py_AddPendingCall()``), which both still only + target the main thread. The new functionality is meant strictly for internal use for now, since consequences of its use are not well understood yet outside some very restricted cases. This change brings the capability in line with the intention when the state was made @@ -2622,109 +3591,105 @@ Core and Builtins Library ------- -- gh-issue-105808: Fix a regression introduced in GH-101251 for 3.12, - causing :meth:`gzip.GzipFile.flush` to not flush the compressor (nor pass - along the ``zip_mode`` argument). +- gh-105808: Fix a regression introduced in GH-101251 for 3.12, causing + :meth:`gzip.GzipFile.flush` to not flush the compressor (nor pass along + the ``zip_mode`` argument). -- gh-issue-104799: Enable :func:`ast.unparse` to unparse function and class +- gh-104799: Enable :func:`ast.unparse` to unparse function and class definitions created without the new ``type_params`` field from :pep:`695`. Patch by Jelle Zijlstra. -- gh-issue-105745: Fix ``webbrowser.Konqueror.open`` method. +- gh-105745: Fix ``webbrowser.Konqueror.open`` method. -- gh-issue-105375: Fix a bug in :c:func:`!_Unpickler_SetInputStream` where - an exception could end up being overwritten in case of failure. +- gh-105375: Fix a bug in :c:func:`!_Unpickler_SetInputStream` where an + exception could end up being overwritten in case of failure. -- gh-issue-105375: Fix bugs in :mod:`sys` where exceptions could end up - being overwritten because of deferred error handling. +- gh-105375: Fix bugs in :mod:`sys` where exceptions could end up being + overwritten because of deferred error handling. -- gh-issue-105605: Harden :mod:`pyexpat` error handling during module +- gh-105605: Harden :mod:`pyexpat` error handling during module initialisation to prevent exceptions from possibly being overwritten, and objects from being dereferenced twice. -- gh-issue-105375: Fix bug in :mod:`decimal` where an exception could end up - being overwritten. +- gh-105375: Fix bug in :mod:`decimal` where an exception could end up being + overwritten. -- gh-issue-105375: Fix bugs in :mod:`!_datetime` where exceptions could be +- gh-105375: Fix bugs in :mod:`!_datetime` where exceptions could be overwritten in case of module initialisation failure. -- gh-issue-105375: Fix bugs in :mod:`!_ssl` initialisation which could lead - to leaked references and overwritten exceptions. +- gh-105375: Fix bugs in :mod:`!_ssl` initialisation which could lead to + leaked references and overwritten exceptions. -- gh-issue-105375: Fix a bug in :class:`array.array` where an exception - could end up being overwritten. +- gh-105375: Fix a bug in :class:`array.array` where an exception could end + up being overwritten. -- gh-issue-105375: Fix bugs in :mod:`_ctypes` where exceptions could end up - being overwritten. - -- gh-issue-105375: Fix a bug in the :mod:`posix` module where an exception - could be overwritten. +- gh-105375: Fix bugs in :mod:`_ctypes` where exceptions could end up being + overwritten. -- gh-issue-105375: Fix bugs in :mod:`!_elementtree` where exceptions could +- gh-105375: Fix a bug in the :mod:`posix` module where an exception could be overwritten. -- gh-issue-105375: Fix bugs in :mod:`zoneinfo` where exceptions could be +- gh-105375: Fix bugs in :mod:`!_elementtree` where exceptions could be overwritten. -- gh-issue-105375: Fix bugs in :mod:`errno` where exceptions could be +- gh-105375: Fix bugs in :mod:`zoneinfo` where exceptions could be overwritten. -- gh-issue-105375: Fix bugs in :mod:`pickle` where exceptions could be +- gh-105375: Fix bugs in :mod:`errno` where exceptions could be overwritten. + +- gh-105375: Fix bugs in :mod:`pickle` where exceptions could be overwritten. -- gh-issue-105375: Fix a bug in :mod:`sqlite3` where an exception could be +- gh-105375: Fix a bug in :mod:`sqlite3` where an exception could be overwritten in the :meth:`collation ` callback. -- gh-issue-105332: Revert pickling method from by-name back to by-value. +- gh-105332: Revert pickling method from by-name back to by-value. -- gh-issue-104310: In the beta 1 release we added a utility function for - extension module authors, to use when testing their module for support in - multiple interpreters or under a per-interpreter GIL. The name of that - function has changed from ``allowing_all_extensions`` to +- gh-104310: In the beta 1 release we added a utility function for extension + module authors, to use when testing their module for support in multiple + interpreters or under a per-interpreter GIL. The name of that function + has changed from ``allowing_all_extensions`` to ``_incompatible_extension_module_restrictions``. The default for the "disable_check" argument has change from ``True`` to ``False``, to better match the new function name. -- gh-issue-104996: Improve performance of :class:`pathlib.PurePath` - initialisation by deferring joining of paths when multiple arguments are - given. +- gh-104996: Improve performance of :class:`pathlib.PurePath` initialisation + by deferring joining of paths when multiple arguments are given. -- gh-issue-102541: Hide traceback in :func:`help` prompt, when import - failed. +- gh-102541: Hide traceback in :func:`help` prompt, when import failed. Tests ----- -- gh-issue-105084: When the Python build is configured - ``--with-wheel-pkg-dir``, tests requiring the ``setuptools`` and ``wheel`` - wheels will search for the wheels in ``WHEEL_PKG_DIR``. +- gh-105084: When the Python build is configured ``--with-wheel-pkg-dir``, + tests requiring the ``setuptools`` and ``wheel`` wheels will search for + the wheels in ``WHEEL_PKG_DIR``. Windows ------- -- gh-issue-105436: Ensure that an empty environment block is terminated by - two null characters, as is required by Windows. +- gh-105436: Ensure that an empty environment block is terminated by two + null characters, as is required by Windows. C API ----- -- gh-issue-105375: Fix a bug in :c:func:`PyErr_WarnExplicit` where an - exception could end up being overwritten if the API failed internally. +- gh-105375: Fix a bug in :c:func:`PyErr_WarnExplicit` where an exception + could end up being overwritten if the API failed internally. -- gh-issue-105603: We've renamed the new (in 3.12) - ``PyInterpreterConfig.own_gil`` to ``PyInterpreterConfig.gil`` and changed - the meaning of the value from "bool" to an integer with supported values - of ``PyInterpreterConfig_DEFAULT_GIL``, - ``PyInterpreterConfig_SHARED_GIL``, and ``PyInterpreterConfig_OWN_GIL``. - The default is "shared". +- gh-105603: We've renamed the new (in 3.12) ``PyInterpreterConfig.own_gil`` + to ``PyInterpreterConfig.gil`` and changed the meaning of the value from + "bool" to an integer with supported values of + ``PyInterpreterConfig_DEFAULT_GIL``, ``PyInterpreterConfig_SHARED_GIL``, + and ``PyInterpreterConfig_OWN_GIL``. The default is "shared". -- gh-issue-105387: In the limited C API version 3.12, :c:func:`Py_INCREF` - and :c:func:`Py_DECREF` functions are now implemented as opaque function - calls to hide implementation details. Patch by Victor Stinner. +- gh-105387: In the limited C API version 3.12, :c:func:`Py_INCREF` and + :c:func:`Py_DECREF` functions are now implemented as opaque function calls + to hide implementation details. Patch by Victor Stinner. -- gh-issue-103968: :c:func:`PyType_FromMetaclass` now allows metaclasses - with ``tp_new`` set to ``NULL``. +- gh-103968: :c:func:`PyType_FromMetaclass` now allows metaclasses with + ``tp_new`` set to ``NULL``. What's New in Python 3.12.0 beta 2? @@ -2735,67 +3700,66 @@ What's New in Python 3.12.0 beta 2? Security -------- -- gh-issue-103142: The version of OpenSSL used in our binary builds has been +- gh-103142: The version of OpenSSL used in our binary builds has been upgraded to 1.1.1u to address several CVEs. -- gh-issue-99108: Refresh our new HACL* built-in :mod:`hashlib` code from +- gh-99108: Refresh our new HACL* built-in :mod:`hashlib` code from upstream. Built-in SHA2 should be faster and an issue with SHA3 on 32-bit platforms is fixed. Core and Builtins ----------------- -- gh-issue-105259: Don't include newline character for trailing ``NEWLINE`` - tokens emitted in the :mod:`tokenize` module. Patch by Pablo Galindo +- gh-105259: Don't include newline character for trailing ``NEWLINE`` tokens + emitted in the :mod:`tokenize` module. Patch by Pablo Galindo -- gh-issue-105324: Fix the main function of the :mod:`tokenize` module when +- gh-105324: Fix the main function of the :mod:`tokenize` module when reading from ``sys.stdin``. Patch by Pablo Galindo -- gh-issue-98963: Restore the ability for a subclass of :class:`property` to +- gh-98963: Restore the ability for a subclass of :class:`property` to define ``__slots__`` or otherwise be dict-less by ignoring failures to set a docstring on such a class. This behavior had regressed in 3.12beta1. An :exc:`AttributeError` where there had not previously been one was disruptive to existing code. -- gh-issue-105194: Do not escape with backslashes f-string format - specifiers. Patch by Pablo Galindo +- gh-105194: Do not escape with backslashes f-string format specifiers. + Patch by Pablo Galindo -- gh-issue-105162: Fixed bug in generator.close()/throw() where an inner - iterator would be ignored when the outer iterator was instrumented. +- gh-105162: Fixed bug in generator.close()/throw() where an inner iterator + would be ignored when the outer iterator was instrumented. -- gh-issue-105164: Ensure annotations are set up correctly if the only - annotation in a block is within a :keyword:`match` block. Patch by Jelle - Zijlstra. +- gh-105164: Ensure annotations are set up correctly if the only annotation + in a block is within a :keyword:`match` block. Patch by Jelle Zijlstra. -- gh-issue-104799: Attributes of :mod:`ast` nodes that are lists now default - to the empty list if omitted. This means that some code that previously +- gh-104799: Attributes of :mod:`ast` nodes that are lists now default to + the empty list if omitted. This means that some code that previously raised :exc:`TypeError` when the AST node was used will now proceed with the empty list instead. Patch by Jelle Zijlstra. -- gh-issue-105035: Fix :func:`super` calls on types with custom +- gh-105035: Fix :func:`super` calls on types with custom :attr:`tp_getattro` implementation (e.g. meta-types.) -- gh-issue-105017: Show CRLF lines in the tokenize string attribute in both - NL and NEWLINE tokens. Patch by Marta Gómez. +- gh-105017: Show CRLF lines in the tokenize string attribute in both NL and + NEWLINE tokens. Patch by Marta Gómez. -- gh-issue-105013: Fix handling of multiline parenthesized lambdas in +- gh-105013: Fix handling of multiline parenthesized lambdas in :func:`inspect.getsource`. Patch by Pablo Galindo -- gh-issue-105017: Do not include an additional final ``NL`` token when - parsing files having CRLF lines. Patch by Marta Gómez. +- gh-105017: Do not include an additional final ``NL`` token when parsing + files having CRLF lines. Patch by Marta Gómez. -- gh-issue-104976: Ensure that trailing ``DEDENT`` - :class:`tokenize.TokenInfo` objects emitted by the :mod:`tokenize` module - are reported as in Python 3.11. Patch by Pablo Galindo +- gh-104976: Ensure that trailing ``DEDENT`` :class:`tokenize.TokenInfo` + objects emitted by the :mod:`tokenize` module are reported as in Python + 3.11. Patch by Pablo Galindo -- gh-issue-104972: Ensure that the ``line`` attribute in +- gh-104972: Ensure that the ``line`` attribute in :class:`tokenize.TokenInfo` objects in the :mod:`tokenize` module are always correct. Patch by Pablo Galindo -- gh-issue-104955: Fix signature for the new - :meth:`~object.__release_buffer__` slot. Patch by Jelle Zijlstra. +- gh-104955: Fix signature for the new :meth:`~object.__release_buffer__` + slot. Patch by Jelle Zijlstra. -- gh-issue-104690: Starting new threads and process creation through +- gh-104690: Starting new threads and process creation through :func:`os.fork` during interpreter shutdown (such as from :mod:`atexit` handlers) is no longer supported. It can lead to race condition between the main Python runtime thread freeing thread states while internal @@ -2803,152 +3767,150 @@ Core and Builtins created threads. Or forked children trying to use the mid-shutdown runtime and thread state in the child process. -- gh-issue-104879: Fix crash when accessing the ``__module__`` attribute of - type aliases defined outside a module. Patch by Jelle Zijlstra. +- gh-104879: Fix crash when accessing the ``__module__`` attribute of type + aliases defined outside a module. Patch by Jelle Zijlstra. -- gh-issue-104825: Tokens emitted by the :mod:`tokenize` module do not - include an implicit ``\n`` character in the ``line`` attribute anymore. - Patch by Pablo Galindo +- gh-104825: Tokens emitted by the :mod:`tokenize` module do not include an + implicit ``\n`` character in the ``line`` attribute anymore. Patch by + Pablo Galindo Library ------- -- gh-issue-105280: Fix bug where ``isinstance([], collections.abc.Mapping)`` - could evaluate to ``True`` if garbage collection happened at the wrong - time. The bug was caused by changes to the implementation of +- gh-105280: Fix bug where ``isinstance([], collections.abc.Mapping)`` could + evaluate to ``True`` if garbage collection happened at the wrong time. The + bug was caused by changes to the implementation of :class:`typing.Protocol` in Python 3.12. -- gh-issue-105239: Fix longstanding bug where ``issubclass(object, +- gh-105239: Fix longstanding bug where ``issubclass(object, typing.Protocol)`` would evaluate to ``True`` in some edge cases. Patch by Alex Waygood. -- gh-issue-105080: Fixed inconsistent signature on derived classes for +- gh-105080: Fixed inconsistent signature on derived classes for :func:`inspect.signature` -- gh-issue-105144: Fix a recent regression in the :mod:`typing` module. The +- gh-105144: Fix a recent regression in the :mod:`typing` module. The regression meant that doing ``class Foo(X, typing.Protocol)``, where ``X`` was a class that had :class:`abc.ABCMeta` as its metaclass, would then cause subsequent ``isinstance(1, X)`` calls to erroneously raise :exc:`TypeError`. Patch by Alex Waygood. -- gh-issue-105113: Improve performance of :meth:`pathlib.PurePath.match` by +- gh-105113: Improve performance of :meth:`pathlib.PurePath.match` by compiling an :class:`re.Pattern` object for the entire pattern. -- gh-issue-101588: Deprecate undocumented copy/deepcopy/pickle support for +- gh-101588: Deprecate undocumented copy/deepcopy/pickle support for itertools. -- gh-issue-103631: Fix - ``pathlib.PurePosixPath(pathlib.PureWindowsPath(...))`` not converting - path separators to restore 3.11 compatible behavior. +- gh-103631: Fix ``pathlib.PurePosixPath(pathlib.PureWindowsPath(...))`` not + converting path separators to restore 3.11 compatible behavior. -- gh-issue-104947: Make comparisons between :class:`pathlib.PureWindowsPath` +- gh-104947: Make comparisons between :class:`pathlib.PureWindowsPath` objects consistent across Windows and Posix to match 3.11 behavior. -- gh-issue-104935: Fix bugs with the interaction between +- gh-104935: Fix bugs with the interaction between :func:`typing.runtime_checkable` and :class:`typing.Generic` that were introduced by the :pep:`695` implementation. Patch by Jelle Zijlstra. -- gh-issue-104874: Document the ``__name__`` and ``__supertype__`` - attributes of :class:`typing.NewType`. Patch by Jelle Zijlstra. +- gh-104874: Document the ``__name__`` and ``__supertype__`` attributes of + :class:`typing.NewType`. Patch by Jelle Zijlstra. -- gh-issue-104799: Adjust the location of the (see :pep:`695`) - ``type_params`` field on :class:`ast.ClassDef`, - :class:`ast.AsyncFunctionDef`, and :class:`ast.FunctionDef` to better - preserve backward compatibility. Patch by Jelle Zijlstra +- gh-104799: Adjust the location of the (see :pep:`695`) ``type_params`` + field on :class:`ast.ClassDef`, :class:`ast.AsyncFunctionDef`, and + :class:`ast.FunctionDef` to better preserve backward compatibility. Patch + by Jelle Zijlstra -- gh-issue-104797: Allow :class:`typing.Protocol` classes to inherit from +- gh-104797: Allow :class:`typing.Protocol` classes to inherit from :class:`collections.abc.Buffer`. Patch by Jelle Zijlstra. -- gh-issue-104372: On Linux where :mod:`subprocess` can use the ``vfork()`` +- gh-104372: On Linux where :mod:`subprocess` can use the ``vfork()`` syscall for faster spawning, prevent the parent process from blocking other threads by dropping the GIL while it waits for the vfork'ed child process ``exec()`` outcome. This prevents spawning a binary from a slow filesystem from blocking the rest of the application. -- gh-issue-99108: We now release the GIL around built-in :mod:`hashlib` +- gh-99108: We now release the GIL around built-in :mod:`hashlib` computations of reasonable size for the SHA families and MD5 hash functions, matching what our OpenSSL backed hash computations already does. -- gh-issue-104399: Prepare the ``_tkinter`` module for building with Tcl 9.0 - and future libtommath by replacing usage of deprecated functions +- gh-104399: Prepare the ``_tkinter`` module for building with Tcl 9.0 and + future libtommath by replacing usage of deprecated functions :c:func:`mp_to_unsigned_bin_n` and :c:func:`mp_unsigned_bin_size` when necessary. -- gh-issue-102024: Reduce calls of ``_idle_semaphore.release()`` in +- gh-102024: Reduce calls of ``_idle_semaphore.release()`` in :func:`concurrent.futures.thread._worker`. Documentation ------------- -- gh-issue-89455: Add missing documentation for the ``max_group_depth`` and +- gh-89455: Add missing documentation for the ``max_group_depth`` and ``max_group_width`` parameters and the ``exceptions`` attribute of the :class:`traceback.TracebackException` class. -- gh-issue-89412: Add missing documentation for the ``end_lineno`` and +- gh-89412: Add missing documentation for the ``end_lineno`` and ``end_offset`` attributes of the :class:`traceback.TracebackException` class. -- gh-issue-104943: Remove mentions of old Python versions in +- gh-104943: Remove mentions of old Python versions in :class:`typing.NamedTuple`. Build ----- -- gh-issue-90005: Fix a regression in :file:`configure` where we could end - up unintentionally linking with ``libbsd``. +- gh-90005: Fix a regression in :file:`configure` where we could end up + unintentionally linking with ``libbsd``. -- gh-issue-89886: Autoconf 2.71 and aclocal 1.16.4 is now required to - regenerate :file:`!configure`. +- gh-89886: Autoconf 2.71 and aclocal 1.16.4 is now required to regenerate + :file:`!configure`. Windows ------- -- gh-issue-105146: Updated the links at the end of the installer to point to +- gh-105146: Updated the links at the end of the installer to point to Discourse rather than the mailing lists. -- gh-issue-103646: When installed from the Microsoft Store, ``pip`` no - longer defaults to per-user installs. However, as the install directory is +- gh-103646: When installed from the Microsoft Store, ``pip`` no longer + defaults to per-user installs. However, as the install directory is unwritable, it should automatically decide to do a per-user install anyway. This should resolve issues when ``pip`` is passed an option that conflicts with ``--user``. -- gh-issue-88745: Improve performance of :func:`shutil.copy2` by using the +- gh-88745: Improve performance of :func:`shutil.copy2` by using the operating system's ``CopyFile2`` function. This may result in subtle changes to metadata copied along with some files, bringing them in line with normal OS behavior. -- gh-issue-104820: Fixes :func:`~os.stat` and related functions on file - systems that do not support file ID requests. This includes FAT32 and - exFAT. +- gh-104820: Fixes :func:`~os.stat` and related functions on file systems + that do not support file ID requests. This includes FAT32 and exFAT. -- gh-issue-104803: Add :func:`os.path.isdevdrive` to detect whether a path - is on a Windows Dev Drive. Returns ``False`` on platforms that do not - support Dev Drive, and is absent on non-Windows platforms. +- gh-104803: Add :func:`os.path.isdevdrive` to detect whether a path is on a + Windows Dev Drive. Returns ``False`` on platforms that do not support Dev + Drive, and is absent on non-Windows platforms. macOS ----- -- gh-issue-103142: Update macOS installer to use OpenSSL 1.1.1u. +- gh-103142: Update macOS installer to use OpenSSL 1.1.1u. IDLE ---- -- gh-issue-104719: Remove IDLE's modification of tokenize.tabsize and test - other uses of tokenize data and methods. +- gh-104719: Remove IDLE's modification of tokenize.tabsize and test other + uses of tokenize data and methods. C API ----- -- gh-issue-105115: ``PyTypeObject.tp_bases`` (and ``tp_mro``) for builtin - static types are now shared by all interpreters, whereas in 3.12-beta1 - they were stored on ``PyInterpreterState``. Also note that now the tuples - are immortal objects. +- gh-105115: ``PyTypeObject.tp_bases`` (and ``tp_mro``) for builtin static + types are now shared by all interpreters, whereas in 3.12-beta1 they were + stored on ``PyInterpreterState``. Also note that now the tuples are + immortal objects. -- gh-issue-105071: Add ``PyUnstable_Exc_PrepReraiseStar`` to the unstable C - api to expose the implementation of :keyword:`except* `. +- gh-105071: Add ``PyUnstable_Exc_PrepReraiseStar`` to the unstable C api to + expose the implementation of :keyword:`except* `. -- gh-issue-104668: Don't call :c:var:`PyOS_InputHook` or +- gh-104668: Don't call :c:var:`PyOS_InputHook` or :c:var:`PyOS_ReadlineFunctionPointer` in subinterpreters, since it's generally difficult to avoid using global state in their registered callbacks. This also avoids situations where extensions may find @@ -2964,125 +3926,122 @@ What's New in Python 3.12.0 beta 1? Security -------- -- gh-issue-99889: Fixed a security in flaw in :func:`uu.decode` that could - allow for directory traversal based on the input if no ``out_file`` was +- gh-99889: Fixed a security in flaw in :func:`uu.decode` that could allow + for directory traversal based on the input if no ``out_file`` was specified. -- gh-issue-104049: Do not expose the local on-disk location in directory - indexes produced by :class:`http.client.SimpleHTTPRequestHandler`. +- gh-104049: Do not expose the local on-disk location in directory indexes + produced by :class:`http.client.SimpleHTTPRequestHandler`. -- gh-issue-99108: Upgrade built-in :mod:`hashlib` SHA3 implementation to a +- gh-99108: Upgrade built-in :mod:`hashlib` SHA3 implementation to a verified implementation from the ``HACL*`` project. Used when OpenSSL is not present or lacks SHA3. -- gh-issue-102153: :func:`urllib.parse.urlsplit` now strips leading C0 - control and space characters following the specification for URLs defined - by WHATWG in response to :cve:`2023-24329`. Patch by Illia Volochii. +- gh-102153: :func:`urllib.parse.urlsplit` now strips leading C0 control and + space characters following the specification for URLs defined by WHATWG in + response to :cve:`2023-24329`. Patch by Illia Volochii. Core and Builtins ----------------- -- gh-issue-102856: Implement PEP 701 changes in the :mod:`tokenize` module. - Patch by Marta Gómez Macías and Pablo Galindo Salgado +- gh-102856: Implement PEP 701 changes in the :mod:`tokenize` module. Patch + by Marta Gómez Macías and Pablo Galindo Salgado -- gh-issue-104615: Fix wrong ordering of assignments in code like ``a, a = - x, y``. Contributed by Carl Meyer. +- gh-104615: Fix wrong ordering of assignments in code like ``a, a = x, y``. + Contributed by Carl Meyer. -- gh-issue-104572: Improve syntax error message for invalid constructs in +- gh-104572: Improve syntax error message for invalid constructs in :pep:`695` contexts and in annotations when ``from __future__ import annotations`` is active. -- gh-issue-104482: Fix three error handling bugs in ast.c's validation of - pattern matching statements. +- gh-104482: Fix three error handling bugs in ast.c's validation of pattern + matching statements. -- gh-issue-102818: Do not add a frame to the traceback in the - ``sys.setprofile`` and ``sys.settrace`` trampoline functions. This ensures - that frames are not duplicated if an exception is raised in the callback - function, and ensures that frames are not omitted if a C callback is used - and that does not add the frame. +- gh-102818: Do not add a frame to the traceback in the ``sys.setprofile`` + and ``sys.settrace`` trampoline functions. This ensures that frames are + not duplicated if an exception is raised in the callback function, and + ensures that frames are not omitted if a C callback is used and that does + not add the frame. -- gh-issue-104405: Fix an issue where some :term:`bytecode` instructions - could ignore :pep:`523` when "inlining" calls. +- gh-104405: Fix an issue where some :term:`bytecode` instructions could + ignore :pep:`523` when "inlining" calls. -- gh-issue-103082: Change behavior of ``sys.monitoring.events.LINE`` events - in ``sys.monitoring``: Line events now occur when a new line is reached +- gh-103082: Change behavior of ``sys.monitoring.events.LINE`` events in + ``sys.monitoring``: Line events now occur when a new line is reached dynamically, instead of using a static approximation, as before. This makes the behavior very similar to that of "line" events in ``sys.settrace``. This should ease porting of tools from 3.11 to 3.12. -- gh-issue-104263: Fix ``float("nan")`` to produce a quiet NaN on platforms - (like MIPS) where the meaning of the signalling / quiet bit is inverted - from its usual meaning. Also introduce a new macro ``Py_INFINITY`` - matching C99's ``INFINITY``, and refactor internals to rely on C99's - ``NAN`` and ``INFINITY`` macros instead of hard-coding bit patterns for - infinities and NaNs. Thanks Sebastian Berg. - -- gh-issue-99113: Multi-phase init extension modules may now indicate that - they support running in subinterpreters that have their own GIL. This is - done by using ``Py_MOD_PER_INTERPRETER_GIL_SUPPORTED`` as the value for - the ``Py_mod_multiple_interpreters`` module def slot. Otherwise the - module, by default, cannot be imported in such subinterpreters. (This - does not affect the main interpreter or subinterpreters that do not have - their own GIL.) In addition to the isolation that multi-phase init - already normally requires, support for per-interpreter GIL involves one - additional constraint: thread-safety. If the module has external (linked) +- gh-104263: Fix ``float("nan")`` to produce a quiet NaN on platforms (like + MIPS) where the meaning of the signalling / quiet bit is inverted from its + usual meaning. Also introduce a new macro ``Py_INFINITY`` matching C99's + ``INFINITY``, and refactor internals to rely on C99's ``NAN`` and + ``INFINITY`` macros instead of hard-coding bit patterns for infinities and + NaNs. Thanks Sebastian Berg. + +- gh-99113: Multi-phase init extension modules may now indicate that they + support running in subinterpreters that have their own GIL. This is done + by using ``Py_MOD_PER_INTERPRETER_GIL_SUPPORTED`` as the value for the + ``Py_mod_multiple_interpreters`` module def slot. Otherwise the module, + by default, cannot be imported in such subinterpreters. (This does not + affect the main interpreter or subinterpreters that do not have their own + GIL.) In addition to the isolation that multi-phase init already normally + requires, support for per-interpreter GIL involves one additional + constraint: thread-safety. If the module has external (linked) dependencies and those libraries have any state that isn't thread-safe then the module must do the additional work to add thread-safety. This should be an uncommon case. -- gh-issue-99113: The GIL is now (optionally) per-interpreter. This is the +- gh-99113: The GIL is now (optionally) per-interpreter. This is the fundamental change for PEP 684. This is all made possible by virtue of the isolated state of each interpreter in the process. The behavior of the main interpreter remains unchanged. Likewise, interpreters created using ``Py_NewInterpreter()`` are not affected. To get an interpreter with its own GIL, call ``Py_NewInterpreterFromConfig()``. -- gh-issue-104108: Multi-phase init extension modules may now indicate - whether or not they actually support multiple interpreters. By default - such modules are expected to support use in multiple interpreters. In the - uncommon case that one does not, it may use the new +- gh-104108: Multi-phase init extension modules may now indicate whether or + not they actually support multiple interpreters. By default such modules + are expected to support use in multiple interpreters. In the uncommon + case that one does not, it may use the new ``Py_mod_multiple_interpreters`` module def slot. A value of ``0`` means the module does not support them. ``1`` means it does. The default is ``1``. -- gh-issue-104142: Fix an issue where :class:`list` or :class:`tuple` - repetition could fail to respect :pep:`683`. +- gh-104142: Fix an issue where :class:`list` or :class:`tuple` repetition + could fail to respect :pep:`683`. -- gh-issue-104078: Improve the performance of - :c:func:`PyObject_HasAttrString` +- gh-104078: Improve the performance of :c:func:`PyObject_HasAttrString` -- gh-issue-104066: Improve the performance of :func:`hasattr` for module - objects with a missing attribute. +- gh-104066: Improve the performance of :func:`hasattr` for module objects + with a missing attribute. -- gh-issue-104028: Reduce object creation while calling callback function - from gc. Patch by Donghee Na. +- gh-104028: Reduce object creation while calling callback function from gc. + Patch by Donghee Na. -- gh-issue-104018: Disallow the "z" format specifier in %-format of bytes - objects. +- gh-104018: Disallow the "z" format specifier in %-format of bytes objects. -- gh-issue-102213: Fix performance loss when accessing an object's - attributes with ``__getattr__`` defined. +- gh-102213: Fix performance loss when accessing an object's attributes with + ``__getattr__`` defined. -- gh-issue-103895: Improve handling of edge cases in showing +- gh-103895: Improve handling of edge cases in showing ``Exception.__notes__``. Ensures that the messages always end with a newline and that string/bytes are not exploded over multiple lines. Patch by Carey Metcalfe. -- gh-issue-103907: Don't modify the refcounts of known immortal objects +- gh-103907: Don't modify the refcounts of known immortal objects (:const:`True`, :const:`False`, and :const:`None`) in the main interpreter loop. -- gh-issue-103899: Provide a helpful hint in the :exc:`TypeError` message - when accidentally calling a :term:`module` object that has a callable - attribute of the same name (such as :func:`dis.dis` or - :class:`datetime.datetime`). +- gh-103899: Provide a helpful hint in the :exc:`TypeError` message when + accidentally calling a :term:`module` object that has a callable attribute + of the same name (such as :func:`dis.dis` or :class:`datetime.datetime`). -- gh-issue-103845: Remove both line and instruction instrumentation before - adding new ones for monitoring, to avoid newly added instrumentation being +- gh-103845: Remove both line and instruction instrumentation before adding + new ones for monitoring, to avoid newly added instrumentation being removed immediately. -- gh-issue-103763: Implement :pep:`695`, adding syntactic support for - generic classes, generic functions, and type aliases. +- gh-103763: Implement :pep:`695`, adding syntactic support for generic + classes, generic functions, and type aliases. A new ``type X = ...`` syntax is added for type aliases, which resolves at runtime to an instance of the new class ``typing.TypeAliasType``. The @@ -3105,91 +4064,90 @@ Core and Builtins Patch by Eric Traut, Larry Hastings, and Jelle Zijlstra. -- gh-issue-103801: Adds three minor linting fixes to the wasm module caught - that were caught by ruff. +- gh-103801: Adds three minor linting fixes to the wasm module caught that + were caught by ruff. -- gh-issue-103793: Optimized asyncio Task creation by deferring expensive - string formatting (task name generation) from Task creation to the first - time ``get_name`` is called. This makes asyncio benchmarks up to 5% - faster. +- gh-103793: Optimized asyncio Task creation by deferring expensive string + formatting (task name generation) from Task creation to the first time + ``get_name`` is called. This makes asyncio benchmarks up to 5% faster. -- gh-issue-102310: Change the error range for invalid bytes literals. +- gh-102310: Change the error range for invalid bytes literals. -- gh-issue-103590: Do not wrap a single exception raised from a - ``try-except*`` construct in an :exc:`ExceptionGroup`. +- gh-103590: Do not wrap a single exception raised from a ``try-except*`` + construct in an :exc:`ExceptionGroup`. -- gh-issue-103650: Change the perf map format to remove the '0x' prefix from - the addresses +- gh-103650: Change the perf map format to remove the '0x' prefix from the + addresses -- gh-issue-102856: Implement the required C tokenizer changes for PEP 701. - Patch by Pablo Galindo Salgado, Lysandros Nikolaou, Batuhan Taskaya, Marta - Gómez Macías and sunmy2019. +- gh-102856: Implement the required C tokenizer changes for PEP 701. Patch + by Pablo Galindo Salgado, Lysandros Nikolaou, Batuhan Taskaya, Marta Gómez + Macías and sunmy2019. -- gh-issue-100530: Clarify the error message raised when the called part of - a class pattern isn't actually a class. +- gh-100530: Clarify the error message raised when the called part of a + class pattern isn't actually a class. -- gh-issue-101517: Fix bug in line numbers of instructions emitted for +- gh-101517: Fix bug in line numbers of instructions emitted for :keyword:`except* `. -- gh-issue-103492: Clarify :exc:`SyntaxWarning` with literal ``is`` - comparison by specifying which literal is problematic, since comparisons - using ``is`` with e.g. ``None`` and bool literals are idiomatic. +- gh-103492: Clarify :exc:`SyntaxWarning` with literal ``is`` comparison by + specifying which literal is problematic, since comparisons using ``is`` + with e.g. ``None`` and bool literals are idiomatic. -- gh-issue-87729: Add :opcode:`LOAD_SUPER_ATTR` (and a specialization for +- gh-87729: Add :opcode:`LOAD_SUPER_ATTR` (and a specialization for ``super().method()``) to speed up ``super().method()`` and ``super().attr``. This makes ``super().method()`` roughly 2.3x faster and brings it within 20% of the performance of a simple method call. Patch by Vladimir Matveev and Carl Meyer. -- gh-issue-103488: Change the internal offset distinguishing yield and - return target addresses, so that the instruction pointer is correct for - exception handling and other stack unwinding. +- gh-103488: Change the internal offset distinguishing yield and return + target addresses, so that the instruction pointer is correct for exception + handling and other stack unwinding. -- gh-issue-82012: The bitwise inversion operator (``~``) on bool is - deprecated. It returns the bitwise inversion of the underlying ``int`` - representation such that ``bool(~True) == True``, which can be confusing. - Use ``not`` for logical negation of bools. In the rare case that you - really need the bitwise inversion of the underlying ``int``, convert to - int explicitly ``~int(x)``. +- gh-82012: The bitwise inversion operator (``~``) on bool is deprecated. It + returns the bitwise inversion of the underlying ``int`` representation + such that ``bool(~True) == True``, which can be confusing. Use ``not`` for + logical negation of bools. In the rare case that you really need the + bitwise inversion of the underlying ``int``, convert to int explicitly + ``~int(x)``. -- gh-issue-77757: Exceptions raised in a typeobject's ``__set_name__`` - method are no longer wrapped by a :exc:`RuntimeError`. Context information - is added to the exception as a :pep:`678` note. +- gh-77757: Exceptions raised in a typeobject's ``__set_name__`` method are + no longer wrapped by a :exc:`RuntimeError`. Context information is added + to the exception as a :pep:`678` note. -- gh-issue-103333: :exc:`AttributeError` now retains the ``name`` attribute - when pickled and unpickled. +- gh-103333: :exc:`AttributeError` now retains the ``name`` attribute when + pickled and unpickled. -- gh-issue-103242: Migrate :meth:`~ssl.SSLContext.set_ecdh_curve` method not - to use deprecated OpenSSL APIs. Patch by Donghee Na. +- gh-103242: Migrate :meth:`~ssl.SSLContext.set_ecdh_curve` method not to + use deprecated OpenSSL APIs. Patch by Donghee Na. -- gh-issue-103323: We've replaced our use of ``_PyRuntime.tstate_current`` - with a thread-local variable. This is a fairly low-level implementation - detail, and there should be no change in behavior. +- gh-103323: We've replaced our use of ``_PyRuntime.tstate_current`` with a + thread-local variable. This is a fairly low-level implementation detail, + and there should be no change in behavior. -- gh-issue-84436: The implementation of PEP-683 which adds Immortal Objects - by using a fixed reference count that skips reference counting to make +- gh-84436: The implementation of PEP-683 which adds Immortal Objects by + using a fixed reference count that skips reference counting to make objects truly immutable. -- gh-issue-102700: Allow built-in modules to be submodules. This allows - submodules to be statically linked into a CPython binary. +- gh-102700: Allow built-in modules to be submodules. This allows submodules + to be statically linked into a CPython binary. -- gh-issue-103082: Implement :pep:`669` Low Impact Monitoring for CPython. +- gh-103082: Implement :pep:`669` Low Impact Monitoring for CPython. -- gh-issue-88691: Reduce the number of inline :opcode:`CACHE` entries for +- gh-88691: Reduce the number of inline :opcode:`CACHE` entries for :opcode:`CALL`. -- gh-issue-102500: Make the buffer protocol accessible in Python code using - the new ``__buffer__`` and ``__release_buffer__`` magic methods. See +- gh-102500: Make the buffer protocol accessible in Python code using the + new ``__buffer__`` and ``__release_buffer__`` magic methods. See :pep:`688` for details. Patch by Jelle Zijlstra. -- gh-issue-97933: :pep:`709`: inline list, dict and set comprehensions to - improve performance and reduce bytecode size. +- gh-97933: :pep:`709`: inline list, dict and set comprehensions to improve + performance and reduce bytecode size. -- gh-issue-99184: Bypass instance attribute access of ``__name__`` in - ``repr`` of :class:`weakref.ref`. +- gh-99184: Bypass instance attribute access of ``__name__`` in ``repr`` of + :class:`weakref.ref`. -- gh-issue-98003: Complex function calls are now faster and consume no C - stack space. +- gh-98003: Complex function calls are now faster and consume no C stack + space. - bpo-39610: ``len()`` for 0-dimensional :class:`memoryview` objects (such as ``memoryview(ctypes.c_uint8(42))``) now raises a :exc:`TypeError`. @@ -3202,18 +4160,18 @@ Core and Builtins Library ------- -- gh-issue-104600: :func:`functools.update_wrapper` now sets the +- gh-104600: :func:`functools.update_wrapper` now sets the ``__type_params__`` attribute (added by :pep:`695`). -- gh-issue-104340: When an ``asyncio`` pipe protocol loses its connection - due to an error, and the caller doesn't await ``wait_closed()`` on the +- gh-104340: When an ``asyncio`` pipe protocol loses its connection due to + an error, and the caller doesn't await ``wait_closed()`` on the corresponding ``StreamWriter``, don't log a warning about an exception that was never retrieved. After all, according to the ``StreamWriter.close()`` docs, the ``wait_closed()`` call is optional ("not mandatory"). -- gh-issue-104555: Fix issue where an :func:`issubclass` check comparing a - class ``X`` against a :func:`runtime-checkable protocol +- gh-104555: Fix issue where an :func:`issubclass` check comparing a class + ``X`` against a :func:`runtime-checkable protocol ` ``Y`` with non-callable members would not cause :exc:`TypeError` to be raised if an :func:`isinstance` call had previously been made comparing an instance of ``X`` to ``Y``. This issue @@ -3221,198 +4179,196 @@ Library 3.12 due to some unrelated changes that were made to runtime-checkable protocols. Patch by Alex Waygood. -- gh-issue-104372: Refactored the ``_posixsubprocess`` internals to avoid - Python C API usage between fork and exec when marking ``pass_fds=`` file +- gh-104372: Refactored the ``_posixsubprocess`` internals to avoid Python C + API usage between fork and exec when marking ``pass_fds=`` file descriptors inheritable. -- gh-issue-104484: Added *case_sensitive* argument to +- gh-104484: Added *case_sensitive* argument to :meth:`pathlib.PurePath.match` -- gh-issue-75367: Fix data descriptor detection in +- gh-75367: Fix data descriptor detection in :func:`inspect.getattr_static`. -- gh-issue-104536: Fix a race condition in the internal +- gh-104536: Fix a race condition in the internal :mod:`multiprocessing.process` cleanup logic that could manifest as an unintended ``AttributeError`` when calling ``process.close()``. -- gh-issue-103857: Update datetime deprecations' stracktrace to point to the +- gh-103857: Update datetime deprecations' stracktrace to point to the calling line -- gh-issue-101520: Move the core functionality of the ``tracemalloc`` module - in the ``Python/`` folder, leaving just the module wrapper in - ``Modules/``. +- gh-101520: Move the core functionality of the ``tracemalloc`` module in + the ``Python/`` folder, leaving just the module wrapper in ``Modules/``. -- gh-issue-104392: Remove undocumented and unused ``_paramspec_tvars`` - attribute from some classes in :mod:`typing`. +- gh-104392: Remove undocumented and unused ``_paramspec_tvars`` attribute + from some classes in :mod:`typing`. -- gh-issue-102613: Fix issue where :meth:`pathlib.Path.glob` raised +- gh-102613: Fix issue where :meth:`pathlib.Path.glob` raised :exc:`RecursionError` when walking deep directory trees. -- gh-issue-103000: Improve performance of :func:`dataclasses.asdict` for the +- gh-103000: Improve performance of :func:`dataclasses.asdict` for the common case where *dict_factory* is ``dict``. Patch by David C Ellis. -- gh-issue-104301: Allow leading whitespace in disambiguated statements in +- gh-104301: Allow leading whitespace in disambiguated statements in :mod:`pdb`. -- gh-issue-104139: Teach :func:`urllib.parse.unsplit` to retain the ``"//"`` - when assembling ``itms-services://?action=generate-bugs`` style `Apple - Platform Deployment +- gh-104139: Teach :func:`urllib.parse.unsplit` to retain the ``"//"`` when + assembling ``itms-services://?action=generate-bugs`` style `Apple Platform + Deployment `_ URLs. -- gh-issue-104307: :func:`socket.getnameinfo` now releases the GIL while +- gh-104307: :func:`socket.getnameinfo` now releases the GIL while contacting the DNS server -- gh-issue-104310: Users may now use - ``importlib.util.allowing_all_extensions()`` (a context manager) to - temporarily disable the strict compatibility checks for importing - extension modules in subinterpreters. +- gh-104310: Users may now use ``importlib.util.allowing_all_extensions()`` + (a context manager) to temporarily disable the strict compatibility checks + for importing extension modules in subinterpreters. -- gh-issue-87695: Fix issue where :meth:`pathlib.Path.glob` raised - :exc:`OSError` when it encountered a symlink to an overly long path. +- gh-87695: Fix issue where :meth:`pathlib.Path.glob` raised :exc:`OSError` + when it encountered a symlink to an overly long path. -- gh-issue-104265: Prevent possible crash by disallowing instantiation of - the :class:`!_csv.Reader` and :class:`!_csv.Writer` types. The regression - was introduced in 3.10.0a4 with PR 23224 (:issue:`14935`). Patch by - Radislav Chugunov. +- gh-104265: Prevent possible crash by disallowing instantiation of the + :class:`!_csv.Reader` and :class:`!_csv.Writer` types. The regression was + introduced in 3.10.0a4 with PR 23224 (:issue:`14935`). Patch by Radislav + Chugunov. -- gh-issue-102613: Improve performance of :meth:`pathlib.Path.glob` when - expanding recursive wildcards ("``**``") by merging adjacent wildcards and +- gh-102613: Improve performance of :meth:`pathlib.Path.glob` when expanding + recursive wildcards ("``**``") by merging adjacent wildcards and de-duplicating results only when necessary. -- gh-issue-65772: Remove unneeded comments and code in turtle.py. +- gh-65772: Remove unneeded comments and code in turtle.py. -- gh-issue-90208: Fixed issue where :meth:`pathlib.Path.glob` returned - incomplete results when it encountered a :exc:`PermissionError`. This - method now suppresses all :exc:`OSError` exceptions, except those raised - from calling :meth:`~pathlib.Path.is_dir` on the top-level path. +- gh-90208: Fixed issue where :meth:`pathlib.Path.glob` returned incomplete + results when it encountered a :exc:`PermissionError`. This method now + suppresses all :exc:`OSError` exceptions, except those raised from calling + :meth:`~pathlib.Path.is_dir` on the top-level path. -- gh-issue-104144: Optimize :class:`asyncio.TaskGroup` when using +- gh-104144: Optimize :class:`asyncio.TaskGroup` when using :func:`asyncio.eager_task_factory`. Skip scheduling a done callback if a TaskGroup task completes eagerly. -- gh-issue-104144: Optimize :func:`asyncio.gather` when using +- gh-104144: Optimize :func:`asyncio.gather` when using :func:`asyncio.eager_task_factory` to complete eagerly if all fututres completed eagerly. Avoid scheduling done callbacks for futures that complete eagerly. -- gh-issue-104114: Fix issue where :meth:`pathlib.Path.glob` returns paths - using the case of non-wildcard segments for corresponding path segments, - rather than the real filesystem case. +- gh-104114: Fix issue where :meth:`pathlib.Path.glob` returns paths using + the case of non-wildcard segments for corresponding path segments, rather + than the real filesystem case. -- gh-issue-104104: Improve performance of :meth:`pathlib.Path.glob` by using +- gh-104104: Improve performance of :meth:`pathlib.Path.glob` by using :const:`re.IGNORECASE` to implement case-insensitive matching. -- gh-issue-104102: Improve performance of :meth:`pathlib.Path.glob` when +- gh-104102: Improve performance of :meth:`pathlib.Path.glob` when evaluating patterns that contain ``'../'`` segments. -- gh-issue-103822: Update the return type of ``weekday`` to the newly added - Day attribute +- gh-103822: Update the return type of ``weekday`` to the newly added Day + attribute -- gh-issue-103629: Update the ``repr`` of :class:`typing.Unpack` according - to :pep:`692`. +- gh-103629: Update the ``repr`` of :class:`typing.Unpack` according to + :pep:`692`. -- gh-issue-103963: Make :mod:`dis` display the names of the args for +- gh-103963: Make :mod:`dis` display the names of the args for :opcode:`!CALL_INTRINSIC_*`. -- gh-issue-104035: Do not ignore user-defined ``__getstate__`` and +- gh-104035: Do not ignore user-defined ``__getstate__`` and ``__setstate__`` methods for slotted frozen dataclasses. -- gh-issue-103987: In :mod:`mmap`, fix several bugs that could lead to - access to memory-mapped files after they have been invalidated. +- gh-103987: In :mod:`mmap`, fix several bugs that could lead to access to + memory-mapped files after they have been invalidated. -- gh-issue-103977: Improve import time of :mod:`platform` module. +- gh-103977: Improve import time of :mod:`platform` module. -- gh-issue-88773: Added :func:`turtle.teleport` to the :mod:`turtle` module - to move a turtle to a new point without tracing a line, visible or - invisible. Patch by Liam Gersten. +- gh-88773: Added :func:`turtle.teleport` to the :mod:`turtle` module to + move a turtle to a new point without tracing a line, visible or invisible. + Patch by Liam Gersten. -- gh-issue-103935: Use :func:`io.open_code` for files to be executed instead - of raw :func:`open` +- gh-103935: Use :func:`io.open_code` for files to be executed instead of + raw :func:`open` -- gh-issue-68968: Fixed garbled output of - :meth:`~unittest.TestCase.assertEqual` when an input lacks final newline. +- gh-68968: Fixed garbled output of :meth:`~unittest.TestCase.assertEqual` + when an input lacks final newline. -- gh-issue-100370: Fix potential :exc:`OverflowError` in +- gh-100370: Fix potential :exc:`OverflowError` in :meth:`sqlite3.Connection.blobopen` for 32-bit builds. Patch by Erlend E. Aasland. -- gh-issue-102628: Substitute CTRL-D with CTRL-Z in :mod:`sqlite3` CLI - banner when running on Windows. +- gh-102628: Substitute CTRL-D with CTRL-Z in :mod:`sqlite3` CLI banner when + running on Windows. -- gh-issue-103636: Module-level attributes ``January`` and ``February`` are +- gh-103636: Module-level attributes ``January`` and ``February`` are deprecated from :mod:`calendar`. -- gh-issue-103583: Isolate :mod:`!_multibytecodec` and codecs extension - modules. Patches by Erlend E. Aasland. +- gh-103583: Isolate :mod:`!_multibytecodec` and codecs extension modules. + Patches by Erlend E. Aasland. -- gh-issue-103848: Add checks to ensure that ``[`` bracketed ``]`` hosts - found by :func:`urllib.parse.urlsplit` are of IPv6 or IPvFuture format. +- gh-103848: Add checks to ensure that ``[`` bracketed ``]`` hosts found by + :func:`urllib.parse.urlsplit` are of IPv6 or IPvFuture format. -- gh-issue-103872: Update the bundled copy of pip to version 23.1.2. +- gh-103872: Update the bundled copy of pip to version 23.1.2. -- gh-issue-99944: Make :mod:`dis` display the value of oparg of +- gh-99944: Make :mod:`dis` display the value of oparg of :opcode:`KW_NAMES`. -- gh-issue-74940: The C.UTF-8 locale is no longer converted to en_US.UTF-8, +- gh-74940: The C.UTF-8 locale is no longer converted to en_US.UTF-8, enabling the use of UTF-8 encoding on systems which have no locales installed. -- gh-issue-103861: Fix ``zipfile.Zipfile`` creating invalid zip files when +- gh-103861: Fix ``zipfile.Zipfile`` creating invalid zip files when ``force_zip64`` was used to add files to them. Patch by Carey Metcalfe. -- gh-issue-103857: Deprecated :meth:`datetime.datetime.utcnow` and +- gh-103857: Deprecated :meth:`datetime.datetime.utcnow` and :meth:`datetime.datetime.utcfromtimestamp`. (Patch by Paul Ganssle) -- gh-issue-103839: Avoid compilation error due to tommath.h not being found - when building Tkinter against Tcl 8.7 built with bundled libtommath. +- gh-103839: Avoid compilation error due to tommath.h not being found when + building Tkinter against Tcl 8.7 built with bundled libtommath. -- gh-issue-103791: :class:`contextlib.suppress` now supports suppressing +- gh-103791: :class:`contextlib.suppress` now supports suppressing exceptions raised as part of an :exc:`ExceptionGroup`. If other exceptions exist on the group, they are re-raised in a group that does not contain the suppressed exceptions. -- gh-issue-90750: Use :meth:`datetime.datetime.fromisocalendar` in the +- gh-90750: Use :meth:`datetime.datetime.fromisocalendar` in the implementation of :meth:`datetime.datetime.strptime`, which should now accept only valid ISO dates. (Patch by Paul Ganssle) -- gh-issue-103685: Prepare :meth:`tkinter.Menu.index` for Tk 8.7 so that it - does not raise ``TclError: expected integer but got ""`` when it should - return ``None``. +- gh-103685: Prepare :meth:`tkinter.Menu.index` for Tk 8.7 so that it does + not raise ``TclError: expected integer but got ""`` when it should return + ``None``. -- gh-issue-81403: :class:`urllib.request.CacheFTPHandler` no longer raises +- gh-81403: :class:`urllib.request.CacheFTPHandler` no longer raises :class:`URLError` if a cached FTP instance is reused. ftplib's endtransfer method calls voidresp to drain the connection to handle FTP instance reuse properly. -- gh-issue-103699: Add ``__orig_bases__`` to non-generic TypedDicts, - call-based TypedDicts, and call-based NamedTuples. Other TypedDicts and - NamedTuples already had the attribute. +- gh-103699: Add ``__orig_bases__`` to non-generic TypedDicts, call-based + TypedDicts, and call-based NamedTuples. Other TypedDicts and NamedTuples + already had the attribute. -- gh-issue-103693: Add convenience variable feature to :mod:`pdb` +- gh-103693: Add convenience variable feature to :mod:`pdb` -- gh-issue-92248: Deprecate ``type``, ``choices``, and ``metavar`` - parameters of ``argparse.BooleanOptionalAction``. +- gh-92248: Deprecate ``type``, ``choices``, and ``metavar`` parameters of + ``argparse.BooleanOptionalAction``. -- gh-issue-89415: Add :mod:`socket` constants for source-specific multicast. - Patch by Reese Hyde. +- gh-89415: Add :mod:`socket` constants for source-specific multicast. Patch + by Reese Hyde. -- gh-issue-103673: :mod:`socketserver` gains ``ForkingUnixStreamServer`` and +- gh-103673: :mod:`socketserver` gains ``ForkingUnixStreamServer`` and ``ForkingUnixDatagramServer`` classes. Patch by Jay Berry. -- gh-issue-103636: Added Enum for months and days in the calendar module. +- gh-103636: Added Enum for months and days in the calendar module. -- gh-issue-84976: Create a new ``Lib/_pydatetime.py`` file that defines the - Python version of the ``datetime`` module, and make ``datetime`` import - the contents of the new library only if the C implementation is missing. +- gh-84976: Create a new ``Lib/_pydatetime.py`` file that defines the Python + version of the ``datetime`` module, and make ``datetime`` import the + contents of the new library only if the C implementation is missing. Currently, the full Python implementation is defined and then deleted if the C implementation is not available, slowing down ``import datetime`` unnecessarily. -- gh-issue-103596: Attributes/methods are no longer shadowed by same-named - enum members, although they may be shadowed by enum.property's. +- gh-103596: Attributes/methods are no longer shadowed by same-named enum + members, although they may be shadowed by enum.property's. -- gh-issue-103584: Updated ``importlib.metadata`` with changes from +- gh-103584: Updated ``importlib.metadata`` with changes from ``importlib_metadata`` 5.2 through 6.5.0, including: Support ``installed-files.txt`` for ``Distribution.files`` when present. ``PackageMetadata`` now stipulates an additional ``get`` method allowing @@ -3425,64 +4381,63 @@ Library expectation that ``PackageMetadata.__getitem__`` will return ``None`` for missing keys. In the future, it will raise a ``KeyError``. -- gh-issue-103578: Fixed a bug where :mod:`pdb` crashes when reading source - file with different encoding by replacing :func:`io.open` with +- gh-103578: Fixed a bug where :mod:`pdb` crashes when reading source file + with different encoding by replacing :func:`io.open` with :func:`io.open_code`. The new method would also call into the hook set by :c:func:`PyFile_SetOpenCodeHook`. -- gh-issue-103556: Now creating :class:`inspect.Signature` objects with +- gh-103556: Now creating :class:`inspect.Signature` objects with positional-only parameter with a default followed by a positional-or-keyword parameter without one is impossible. -- gh-issue-103559: Update the bundled copy of pip to version 23.1.1. +- gh-103559: Update the bundled copy of pip to version 23.1.1. -- gh-issue-103548: Improve performance of :meth:`pathlib.Path.absolute` and +- gh-103548: Improve performance of :meth:`pathlib.Path.absolute` and :meth:`~pathlib.Path.cwd` by joining paths only when necessary. Also improve performance of :meth:`pathlib.PurePath.is_absolute` on Posix by skipping path parsing and normalization. -- gh-issue-103538: Remove ``_tkinter`` module code guarded by definition of - the ``TK_AQUA`` macro which was only needed for Tk 8.4.7 or earlier and - was never actually defined by any build system or documented for manual - use. +- gh-103538: Remove ``_tkinter`` module code guarded by definition of the + ``TK_AQUA`` macro which was only needed for Tk 8.4.7 or earlier and was + never actually defined by any build system or documented for manual use. -- gh-issue-103533: Update :mod:`cProfile` to use PEP 669 API +- gh-103533: Update :mod:`cProfile` to use PEP 669 API -- gh-issue-103525: Fix misleading exception message when mixed ``str`` and +- gh-103525: Fix misleading exception message when mixed ``str`` and ``bytes`` arguments are supplied to :class:`pathlib.PurePath` and :class:`~pathlib.Path`. -- gh-issue-103489: Add :meth:`~sqlite3.Connection.getconfig` and +- gh-103489: Add :meth:`~sqlite3.Connection.getconfig` and :meth:`~sqlite3.Connection.setconfig` to :class:`~sqlite3.Connection` to make configuration changes to a database connection. Patch by Erlend E. Aasland. -- gh-issue-103365: Set default Flag boundary to ``STRICT`` and fix bitwise +- gh-103365: Set default Flag boundary to ``STRICT`` and fix bitwise operations. -- gh-issue-103472: Avoid a potential :exc:`ResourceWarning` in +- gh-103472: Avoid a potential :exc:`ResourceWarning` in :class:`http.client.HTTPConnection` by closing the proxy / tunnel's CONNECT response explicitly. -- gh-issue-103462: Fixed an issue with using +- gh-103462: Fixed an issue with using :meth:`~asyncio.WriteTransport.writelines` in :mod:`asyncio` to send very large payloads that exceed the amount of data that can be written in one call to :meth:`socket.socket.send` or :meth:`socket.socket.sendmsg`, resulting in the remaining buffer being left unwritten. -- gh-issue-103449: Fix a bug in doc string generation in +- gh-103449: Fix a bug in doc string generation in :func:`dataclasses.dataclass`. -- gh-issue-103092: Isolate :mod:`!_collections` (apply :pep:`687`). Patch by +- gh-103092: Isolate :mod:`!_collections` (apply :pep:`687`). Patch by Erlend E. Aasland. -- gh-issue-103357: Added support for :class:`logging.Formatter` ``defaults`` +- gh-103357: Added support for :class:`logging.Formatter` ``defaults`` parameter to :func:`logging.config.dictConfig` and :func:`logging.config.fileConfig`. Patch by Bar Harel. -- gh-issue-103092: Adapt the :mod:`winreg` extension module to :pep:`687`. +- gh-103092: Adapt the :mod:`winreg` extension module to :pep:`687`. -- gh-issue-74690: The performance of :func:`isinstance` checks against +- gh-74690: The performance of :func:`isinstance` checks against :func:`runtime-checkable protocols ` has been considerably improved for protocols that only have a few members. To achieve this improvement, several internal implementation details of the @@ -3491,165 +4446,164 @@ Library ``typing._is_callable_members_only``, and ``typing._get_protocol_attrs``. Patches by Alex Waygood. -- gh-issue-74690: The members of a runtime-checkable protocol are now - considered "frozen" at runtime as soon as the class has been created. See +- gh-74690: The members of a runtime-checkable protocol are now considered + "frozen" at runtime as soon as the class has been created. See :ref:`"What's new in Python 3.12" ` for more details. -- gh-issue-103256: Fixed a bug that caused :mod:`hmac` to raise an exception - when the requested hash algorithm was not available in OpenSSL despite - being available separately as part of ``hashlib`` itself. It now falls - back properly to the built-in. This could happen when, for example, your +- gh-103256: Fixed a bug that caused :mod:`hmac` to raise an exception when + the requested hash algorithm was not available in OpenSSL despite being + available separately as part of ``hashlib`` itself. It now falls back + properly to the built-in. This could happen when, for example, your OpenSSL does not include SHA3 support and you want to compute ``hmac.digest(b'K', b'M', 'sha3_256')``. -- gh-issue-102778: Support ``sys.last_exc`` in :mod:`idlelib`. +- gh-102778: Support ``sys.last_exc`` in :mod:`idlelib`. -- gh-issue-103285: Improve performance of :func:`ast.get_source_segment`. +- gh-103285: Improve performance of :func:`ast.get_source_segment`. -- gh-issue-103225: Fix a bug in :mod:`pdb` when displaying line numbers of +- gh-103225: Fix a bug in :mod:`pdb` when displaying line numbers of module-level source code. -- gh-issue-103092: Adapt the :mod:`msvcrt` extension module to :pep:`687`. +- gh-103092: Adapt the :mod:`msvcrt` extension module to :pep:`687`. -- gh-issue-103092: Adapt the :mod:`winsound` extension module to :pep:`687`. +- gh-103092: Adapt the :mod:`winsound` extension module to :pep:`687`. -- gh-issue-93910: Remove deprecation of enum ``member.member`` access. +- gh-93910: Remove deprecation of enum ``member.member`` access. -- gh-issue-102978: Fixes :func:`unittest.mock.patch` not enforcing function +- gh-102978: Fixes :func:`unittest.mock.patch` not enforcing function signatures for methods decorated with ``@classmethod`` or ``@staticmethod`` when patch is called with ``autospec=True``. -- gh-issue-103092: Isolate :mod:`!_socket` (apply :pep:`687`). Patch by - Erlend E. Aasland. +- gh-103092: Isolate :mod:`!_socket` (apply :pep:`687`). Patch by Erlend E. + Aasland. -- gh-issue-100479: Add :meth:`pathlib.PurePath.with_segments`, which creates - a path object from arguments. This method is called whenever a derivative +- gh-100479: Add :meth:`pathlib.PurePath.with_segments`, which creates a + path object from arguments. This method is called whenever a derivative path is created, such as from :attr:`pathlib.PurePath.parent`. Subclasses may override this method to share information between path objects. -- gh-issue-103220: Fix issue where :func:`os.path.join` added a slash when - joining onto an incomplete UNC drive with a trailing slash on Windows. +- gh-103220: Fix issue where :func:`os.path.join` added a slash when joining + onto an incomplete UNC drive with a trailing slash on Windows. -- gh-issue-103204: Fixes :mod:`http.server` accepting HTTP requests with - HTTP version numbers preceded by '+', or '-', or with digit-separating '_' +- gh-103204: Fixes :mod:`http.server` accepting HTTP requests with HTTP + version numbers preceded by '+', or '-', or with digit-separating '_' characters. The length of the version numbers is also constrained. -- gh-issue-75586: Fix various Windows-specific issues with ``shutil.which``. +- gh-75586: Fix various Windows-specific issues with ``shutil.which``. -- gh-issue-103193: Improve performance of :func:`inspect.getattr_static`. - Patch by Alex Waygood. +- gh-103193: Improve performance of :func:`inspect.getattr_static`. Patch by + Alex Waygood. -- gh-issue-103176: :func:`sys._current_exceptions` now returns a mapping - from thread-id to an exception instance, rather than to a ``(typ, exc, - tb)`` tuple. +- gh-103176: :func:`sys._current_exceptions` now returns a mapping from + thread-id to an exception instance, rather than to a ``(typ, exc, tb)`` + tuple. -- gh-issue-103143: Polish the help messages and docstrings of :mod:`pdb`. +- gh-103143: Polish the help messages and docstrings of :mod:`pdb`. -- gh-issue-103015: Add *entrypoint* keyword-only parameter to +- gh-103015: Add *entrypoint* keyword-only parameter to :meth:`sqlite3.Connection.load_extension`, for overriding the SQLite extension entry point. Patch by Erlend E. Aasland. -- gh-issue-103000: Improve performance of :func:`dataclasses.astuple` and +- gh-103000: Improve performance of :func:`dataclasses.astuple` and :func:`dataclasses.asdict` in cases where the contents are common Python types. -- gh-issue-102953: The extraction methods in :mod:`tarfile`, and +- gh-102953: The extraction methods in :mod:`tarfile`, and :func:`shutil.unpack_archive`, have a new a *filter* argument that allows limiting tar features than may be surprising or dangerous, such as creating files outside the destination directory. See :ref:`tarfile-extraction-filter` for details. -- gh-issue-97696: Implemented an eager task factory in asyncio. When used as - a task factory on an event loop, it performs eager execution of - coroutines. Coroutines that are able to complete synchronously (e.g. - return or raise without blocking) are returned immediately as a finished - task, and the task is never scheduled to the event loop. If the coroutine - blocks, the (pending) task is scheduled and returned. +- gh-97696: Implemented an eager task factory in asyncio. When used as a + task factory on an event loop, it performs eager execution of coroutines. + Coroutines that are able to complete synchronously (e.g. return or raise + without blocking) are returned immediately as a finished task, and the + task is never scheduled to the event loop. If the coroutine blocks, the + (pending) task is scheduled and returned. -- gh-issue-81079: Add *case_sensitive* keyword-only argument to +- gh-81079: Add *case_sensitive* keyword-only argument to :meth:`pathlib.Path.glob` and :meth:`~pathlib.Path.rglob`. -- gh-issue-101819: Isolate the :mod:`io` extension module by applying - :pep:`687`. Patch by Kumar Aditya, Victor Stinner, and Erlend E. Aasland. +- gh-101819: Isolate the :mod:`io` extension module by applying :pep:`687`. + Patch by Kumar Aditya, Victor Stinner, and Erlend E. Aasland. -- gh-issue-91896: Deprecate :class:`collections.abc.ByteString` +- gh-91896: Deprecate :class:`collections.abc.ByteString` -- gh-issue-101362: Speed up :class:`pathlib.Path` construction by omitting - the path anchor from the internal list of path parts. +- gh-101362: Speed up :class:`pathlib.Path` construction by omitting the + path anchor from the internal list of path parts. -- gh-issue-102114: Functions in the :mod:`dis` module that accept a source - code string as argument now print a more concise traceback when the string +- gh-102114: Functions in the :mod:`dis` module that accept a source code + string as argument now print a more concise traceback when the string contains a syntax or indentation error. -- gh-issue-62432: The :mod:`unittest` runner will now exit with status code - 5 if no tests were run. It is common for test runner misconfiguration to - fail to find any tests, this should be an error. +- gh-62432: The :mod:`unittest` runner will now exit with status code 5 if + no tests were run. It is common for test runner misconfiguration to fail + to find any tests, this should be an error. -- gh-issue-78079: Fix incorrect normalization of UNC device path roots, and +- gh-78079: Fix incorrect normalization of UNC device path roots, and partial UNC share path roots, in :class:`pathlib.PurePath`. Pathlib no longer appends a trailing slash to such paths. -- gh-issue-85984: Add :func:`tty.cfmakeraw` and :func:`tty.cfmakecbreak` to +- gh-85984: Add :func:`tty.cfmakeraw` and :func:`tty.cfmakecbreak` to :mod:`tty` and modernize, the behavior of :func:`tty.setraw` and :func:`tty.setcbreak` to use POSIX.1-2017 Chapter 11 "General Terminal Interface" flag masks by default. -- gh-issue-101688: Implement :func:`types.get_original_bases` to provide - further introspection for types. +- gh-101688: Implement :func:`types.get_original_bases` to provide further + introspection for types. -- gh-issue-101640: :class:`argparse.ArgumentParser` now catches errors when +- gh-101640: :class:`argparse.ArgumentParser` now catches errors when writing messages, such as when :data:`sys.stderr` is ``None``. Patch by Oleg Iarygin. -- gh-issue-83861: Fix datetime.astimezone method return value when invoked - on a naive datetime instance that represents local time falling in a - timezone transition gap. PEP 495 requires that instances with fold=1 - produce earlier times than those with fold=0 in this case. +- gh-83861: Fix datetime.astimezone method return value when invoked on a + naive datetime instance that represents local time falling in a timezone + transition gap. PEP 495 requires that instances with fold=1 produce + earlier times than those with fold=0 in this case. -- gh-issue-89550: Decrease execution time of some :mod:`gzip` file writes by - 15% by adding more appropriate buffering. +- gh-89550: Decrease execution time of some :mod:`gzip` file writes by 15% + by adding more appropriate buffering. -- gh-issue-95299: Remove the bundled setuptools wheel from ``ensurepip``, - and stop installing setuptools in environments created by ``venv``. +- gh-95299: Remove the bundled setuptools wheel from ``ensurepip``, and stop + installing setuptools in environments created by ``venv``. -- gh-issue-99353: Respect the :class:`http.client.HTTPConnection` - ``.debuglevel`` flag in :class:`urllib.request.AbstractHTTPHandler` when - its constructor parameter ``debuglevel`` is not set. And do the same for - ``*HTTPS*``. +- gh-99353: Respect the :class:`http.client.HTTPConnection` ``.debuglevel`` + flag in :class:`urllib.request.AbstractHTTPHandler` when its constructor + parameter ``debuglevel`` is not set. And do the same for ``*HTTPS*``. -- gh-issue-98040: Remove the long-deprecated ``imp`` module. +- gh-98040: Remove the long-deprecated ``imp`` module. -- gh-issue-97850: Deprecate :func:`pkgutil.find_loader` and +- gh-97850: Deprecate :func:`pkgutil.find_loader` and :func:`pkgutil.get_loader` in favor of :func:`importlib.util.find_spec`. -- gh-issue-94473: Flatten arguments in :meth:`tkinter.Canvas.coords`. It now +- gh-94473: Flatten arguments in :meth:`tkinter.Canvas.coords`. It now accepts not only ``x1, y1, x2, y2, ...`` and ``[x1, y1, x2, y2, ...]``, but also ``(x1, y1), (x2, y2), ...`` and ``[(x1, y1), (x2, y2), ...]``. -- gh-issue-98040: Remove more deprecated importlib APIs: ``find_loader()``, +- gh-98040: Remove more deprecated importlib APIs: ``find_loader()``, ``find_module()``, ``importlib.abc.Finder``, ``pkgutil.ImpImporter``, ``pkgutil.ImpLoader``. -- gh-issue-96522: Fix potential deadlock in pty.spawn() +- gh-96522: Fix potential deadlock in pty.spawn() -- gh-issue-96534: Support divert(4) added in FreeBSD 14. +- gh-96534: Support divert(4) added in FreeBSD 14. -- gh-issue-87474: Fix potential file descriptor leaks in +- gh-87474: Fix potential file descriptor leaks in :class:`subprocess.Popen`. -- gh-issue-94906: Support multiple steps in :func:`math.nextafter`. Patch by +- gh-94906: Support multiple steps in :func:`math.nextafter`. Patch by Shantanu Jain and Matthias Gorgens. -- gh-issue-51574: Make :func:`tempfile.mkdtemp` return absolute paths when - its *dir* parameter is relative. +- gh-51574: Make :func:`tempfile.mkdtemp` return absolute paths when its + *dir* parameter is relative. -- gh-issue-94518: Convert private :meth:`_posixsubprocess.fork_exec` to use +- gh-94518: Convert private :meth:`!_posixsubprocess.fork_exec` to use Argument Clinic. -- gh-issue-92184: When creating zip files using :mod:`zipfile`, - ``os.altsep``, if not ``None``, will always be treated as a path separator - even when it is not ``/``. Patch by Carey Metcalfe. +- gh-92184: When creating zip files using :mod:`zipfile`, ``os.altsep``, if + not ``None``, will always be treated as a path separator even when it is + not ``/``. Patch by Carey Metcalfe. - bpo-46797: Deprecation warnings are now emitted for :class:`!ast.Num`, :class:`!ast.Bytes`, :class:`!ast.Str`, :class:`!ast.NameConstant` and @@ -3686,76 +4640,76 @@ Library Documentation ------------- -- gh-issue-67056: Document that the effect of registering or unregistering - an :mod:`atexit` cleanup function from within a registered cleanup - function is undefined. +- gh-67056: Document that the effect of registering or unregistering an + :mod:`atexit` cleanup function from within a registered cleanup function + is undefined. -- gh-issue-103629: Mention the new way of typing ``**kwargs`` with - ``Unpack`` and ``TypedDict`` introduced in :pep:`692`. +- gh-103629: Mention the new way of typing ``**kwargs`` with ``Unpack`` and + ``TypedDict`` introduced in :pep:`692`. -- gh-issue-48241: Clarifying documentation about the url parameter to +- gh-48241: Clarifying documentation about the url parameter to urllib.request.urlopen and urllib.request.Request needing to be encoded properly. -- gh-issue-86094: Add support for Unicode Path Extra Field in ZipFile. Patch - by Yeojin Kim and Andrea Giudiceandrea +- gh-86094: Add support for Unicode Path Extra Field in ZipFile. Patch by + Yeojin Kim and Andrea Giudiceandrea -- gh-issue-99202: Fix extension type from documentation for compiling in - C++20 mode +- gh-99202: Fix extension type from documentation for compiling in C++20 + mode Tests ----- -- gh-issue-104494: Update ``test_pack_configure_in`` and +- gh-104494: Update ``test_pack_configure_in`` and ``test_place_configure_in`` for changes to error message formatting in Tk 8.7. -- gh-issue-104461: Run test_configure_screen on X11 only, since the - ``DISPLAY`` environment variable and ``-screen`` option for toplevels are - not useful on Tk for Win32 or Aqua. +- gh-104461: Run test_configure_screen on X11 only, since the ``DISPLAY`` + environment variable and ``-screen`` option for toplevels are not useful + on Tk for Win32 or Aqua. -- gh-issue-86275: Added property-based tests to the :mod:`zoneinfo` tests, - along with stubs for the ``hypothesis`` interface. (Patch by Paul Ganssle) +- gh-86275: Added property-based tests to the :mod:`zoneinfo` tests, along + with stubs for the ``hypothesis`` interface. (Patch by Paul Ganssle) -- gh-issue-103329: Regression tests for the behaviour of +- gh-103329: Regression tests for the behaviour of ``unittest.mock.PropertyMock`` were added. -- gh-issue-102795: fix use of poll in test_epoll's test_control_and_wait +- gh-102795: fix use of poll in test_epoll's test_control_and_wait -- gh-issue-75729: Fix the :func:`os.spawn* ` tests failing on - Windows when the working directory or interpreter path contains spaces. +- gh-75729: Fix the :func:`os.spawn* ` tests failing on Windows + when the working directory or interpreter path contains spaces. Build ----- -- gh-issue-101282: BOLT optimization is now applied to the libpython shared +- gh-101282: BOLT optimization is now applied to the libpython shared library if building a shared library. BOLT instrumentation and application settings can now be influenced via the ``BOLT_INSTRUMENT_FLAGS`` and ``BOLT_APPLY_FLAGS`` configure variables. -- gh-issue-99017: ``PYTHON_FOR_REGEN`` now require Python 3.10 or newer. +- gh-99017: ``PYTHON_FOR_REGEN`` now require Python 3.10 or newer. -- gh-issue-104490: Define ``.PHONY`` / virtual make targets consistently and +- gh-104490: Define ``.PHONY`` / virtual make targets consistently and properly. -- gh-issue-104106: Add gcc fallback of mkfifoat/mknodat for macOS. Patch by +- gh-104106: Add gcc fallback of mkfifoat/mknodat for macOS. Patch by Donghee Na. -- gh-issue-103532: The ``TKINTER_PROTECT_LOADTK`` macro is no longer defined - or used in the ``_tkinter`` module. It was previously only defined when +- gh-103532: The ``TKINTER_PROTECT_LOADTK`` macro is no longer defined or + used in the ``_tkinter`` module. It was previously only defined when building against Tk 8.4.13 and older, but Tk older than 8.5.12 has been unsupported since gh-issue-91152. -- gh-issue-99069: Extended workaround defining ``static_assert`` when - missing from the libc headers to all clang and gcc builds. In particular, - this fixes building on macOS <= 10.10. +- gh-99069: Extended workaround defining ``static_assert`` when missing from + the libc headers to all clang and gcc builds. In particular, this fixes + building on macOS <= 10.10. -- gh-issue-100220: Changed the default value of the ``SHELL`` Makefile - variable from ``/bin/sh`` to ``/bin/sh -e`` to ensure that complex recipes +- gh-100220: Changed the default value of the ``SHELL`` Makefile variable + from ``/bin/sh`` to ``/bin/sh -e`` to ensure that complex recipes correctly fail after an error. Previously, ``make install`` could fail to install some files and yet return a successful result. -- gh-issue-90656: Add platform triplets for 64-bit LoongArch: +- gh-90656: Add platform triplets for 64-bit LoongArch: * loongarch64-linux-gnusf * loongarch64-linux-gnuf32 @@ -3766,112 +4720,110 @@ Build Windows ------- -- gh-issue-104623: Update Windows installer to use SQLite 3.42.0. +- gh-104623: Update Windows installer to use SQLite 3.42.0. -- gh-issue-82814: Fix a potential ``[Errno 13] Permission denied`` when - using :func:`shutil.copystat` within Windows Subsystem for Linux (WSL) on - a mounted filesystem by adding ``errno.EACCES`` to the list of ignored +- gh-82814: Fix a potential ``[Errno 13] Permission denied`` when using + :func:`shutil.copystat` within Windows Subsystem for Linux (WSL) on a + mounted filesystem by adding ``errno.EACCES`` to the list of ignored errors within the internal implementation. -- gh-issue-103088: Fix virtual environment :file:`activate` script having +- gh-103088: Fix virtual environment :file:`activate` script having incorrect line endings for Cygwin. -- gh-issue-103088: Fixes venvs not working in bash on Windows across - different disks +- gh-103088: Fixes venvs not working in bash on Windows across different + disks -- gh-issue-102997: Update Windows installer to use SQLite 3.41.2. +- gh-102997: Update Windows installer to use SQLite 3.41.2. -- gh-issue-88013: Fixed a bug where :exc:`TypeError` was raised when calling +- gh-88013: Fixed a bug where :exc:`TypeError` was raised when calling :func:`ntpath.realpath` with a bytes parameter in some cases. macOS ----- -- gh-issue-99834: Update macOS installer to Tcl/Tk 8.6.13. +- gh-99834: Update macOS installer to Tcl/Tk 8.6.13. -- gh-issue-104623: Update macOS installer to SQLite 3.42.0. +- gh-104623: Update macOS installer to SQLite 3.42.0. -- gh-issue-103545: Add ``os.PRIO_DARWIN_THREAD``, - ``os.PRIO_DARWIN_PROCESS``, ``os.PRIO_DARWIN_BG`` and - ``os.PRIO_DARWIN_NONUI``. These can be used with ``os.setpriority`` to run - the process at a lower priority and make use of the efficiency cores on - Apple Silicon systems. +- gh-103545: Add ``os.PRIO_DARWIN_THREAD``, ``os.PRIO_DARWIN_PROCESS``, + ``os.PRIO_DARWIN_BG`` and ``os.PRIO_DARWIN_NONUI``. These can be used with + ``os.setpriority`` to run the process at a lower priority and make use of + the efficiency cores on Apple Silicon systems. -- gh-issue-104180: Support reading SOCKS proxy configuration from macOS - System Configuration. Patch by Sam Schott. +- gh-104180: Support reading SOCKS proxy configuration from macOS System + Configuration. Patch by Sam Schott. -- gh-issue-60436: update curses textbox to additionally handle backspace - using the ``curses.ascii.DEL`` key press. +- gh-60436: update curses textbox to additionally handle backspace using the + ``curses.ascii.DEL`` key press. -- gh-issue-102997: Update macOS installer to SQLite 3.41.2. +- gh-102997: Update macOS installer to SQLite 3.41.2. IDLE ---- -- gh-issue-104499: Fix completions for Tk Aqua 8.7 (currently blank). +- gh-104499: Fix completions for Tk Aqua 8.7 (currently blank). -- gh-issue-104496: About prints both tcl and tk versions if different - (expected someday). +- gh-104496: About prints both tcl and tk versions if different (expected + someday). -- gh-issue-88496: Fix IDLE test hang on macOS. +- gh-88496: Fix IDLE test hang on macOS. Tools/Demos ----------- -- gh-issue-104389: Argument Clinic C converters now accept the ``unused`` - keyword, for wrapping a parameter with :c:macro:`Py_UNUSED`. Patch by - Erlend E. Aasland. +- gh-104389: Argument Clinic C converters now accept the ``unused`` keyword, + for wrapping a parameter with :c:macro:`Py_UNUSED`. Patch by Erlend E. + Aasland. C API ----- -- gh-issue-101291: Added unstable C API for extracting the value of - "compact" integers: :c:func:`PyUnstable_Long_IsCompact` and +- gh-101291: Added unstable C API for extracting the value of "compact" + integers: :c:func:`PyUnstable_Long_IsCompact` and :c:func:`PyUnstable_Long_CompactValue`. -- gh-issue-104109: We've added ``Py_NewInterpreterFromConfig()`` and +- gh-104109: We've added ``Py_NewInterpreterFromConfig()`` and ``PyInterpreterConfig`` to the public C-API (but not the stable ABI; not yet at least). The new function may be used to create a new interpreter with various features configured. The function was added to support PEP 684 (per-interpreter GIL). -- gh-issue-103968: :c:func:`PyType_FromSpec` and its variants now allow - creating classes whose metaclass overrides - :c:member:`~PyTypeObject.tp_new`. The ``tp_new`` is ignored. This behavior - is deprecated and will be disallowed in 3.14+. The new - :c:func:`PyType_FromMetaclass` already disallows it. +- gh-103968: :c:func:`PyType_FromSpec` and its variants now allow creating + classes whose metaclass overrides :c:member:`~PyTypeObject.tp_new`. The + ``tp_new`` is ignored. This behavior is deprecated and will be disallowed + in 3.14+. The new :c:func:`PyType_FromMetaclass` already disallows it. -- gh-issue-103743: Add :c:func:`PyUnstable_Object_GC_NewWithExtraData` - function that can be used to allocate additional memory after an object - for data not managed by Python. +- gh-103743: Add :c:func:`PyUnstable_Object_GC_NewWithExtraData` function + that can be used to allocate additional memory after an object for data + not managed by Python. -- gh-issue-103295: Introduced :c:func:`PyUnstable_WritePerfMapEntry`, +- gh-103295: Introduced :c:func:`PyUnstable_WritePerfMapEntry`, :c:func:`PyUnstable_PerfMapState_Init` and :c:func:`PyUnstable_PerfMapState_Fini`. These allow extension modules (JIT compilers in particular) to write to perf-map files in a thread safe manner. The :doc:`../howto/perf_profiling` also uses these APIs to write entries in the perf-map file. -- gh-issue-103509: Added C API for extending types whose instance memory - layout is opaque: :c:member:`PyType_Spec.basicsize` can now be zero or - negative, :c:func:`PyObject_GetTypeData` can be used to get - subclass-specific data, and :c:macro:`Py_TPFLAGS_ITEMS_AT_END` can be used - to safely extend variable-size objects. See :pep:`697` for details. +- gh-103509: Added C API for extending types whose instance memory layout is + opaque: :c:member:`PyType_Spec.basicsize` can now be zero or negative, + :c:func:`PyObject_GetTypeData` can be used to get subclass-specific data, + and :c:macro:`Py_TPFLAGS_ITEMS_AT_END` can be used to safely extend + variable-size objects. See :pep:`697` for details. -- gh-issue-103091: Add a new C-API function to eagerly assign a version tag - to a PyTypeObject: ``PyUnstable_Type_AssignVersionTag()``. +- gh-103091: Add a new C-API function to eagerly assign a version tag to a + PyTypeObject: ``PyUnstable_Type_AssignVersionTag()``. -- gh-issue-101408: :c:macro:`PyObject_GC_Resize` should calculate preheader - size if needed. Patch by Donghee Na. +- gh-101408: :c:macro:`PyObject_GC_Resize` should calculate preheader size + if needed. Patch by Donghee Na. -- gh-issue-98836: Add support of more formatting options (left aligning, - octals, uppercase hexadecimals, :c:type:`intmax_t`, :c:type:`ptrdiff_t`, +- gh-98836: Add support of more formatting options (left aligning, octals, + uppercase hexadecimals, :c:type:`intmax_t`, :c:type:`ptrdiff_t`, :c:type:`wchar_t` C strings, variable width and precision) in :c:func:`PyUnicode_FromFormat` and :c:func:`PyUnicode_FromFormatV`. -- gh-issue-96803: Add unstable C-API functions to get the code object, lasti - and line number from the internal ``_PyInterpreterFrame`` in the limited - API. The functions are: +- gh-96803: Add unstable C-API functions to get the code object, lasti and + line number from the internal ``_PyInterpreterFrame`` in the limited API. + The functions are: * ``PyCodeObject * PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame)`` * ``int PyUnstable_InterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame)`` @@ -3886,75 +4838,72 @@ What's New in Python 3.12.0 alpha 7? Core and Builtins ----------------- -- gh-issue-102192: Deprecated ``_PyErr_ChainExceptions`` in favour of +- gh-102192: Deprecated ``_PyErr_ChainExceptions`` in favour of ``_PyErr_ChainExceptions1``. -- gh-issue-89987: Reduce the number of inline :opcode:`CACHE` entries for +- gh-89987: Reduce the number of inline :opcode:`CACHE` entries for :opcode:`BINARY_SUBSCR`. -- gh-issue-102859: Removed :opcode:`!JUMP_IF_FALSE_OR_POP` and +- gh-102859: Removed :opcode:`!JUMP_IF_FALSE_OR_POP` and :opcode:`!JUMP_IF_TRUE_OR_POP` instructions. -- gh-issue-101975: Fixed ``stacktop`` value on tracing entries to avoid - corruption on garbage collection. +- gh-101975: Fixed ``stacktop`` value on tracing entries to avoid corruption + on garbage collection. -- gh-issue-102778: Add :data:`sys.last_exc` and deprecate - :data:`sys.last_type`, :data:`sys.last_value` and - :data:`sys.last_traceback`, which hold the same information in its legacy - form. +- gh-102778: Add :data:`sys.last_exc` and deprecate :data:`sys.last_type`, + :data:`sys.last_value` and :data:`sys.last_traceback`, which hold the same + information in its legacy form. -- gh-issue-100982: Replace all occurrences of ``COMPARE_AND_BRANCH`` with +- gh-100982: Replace all occurrences of ``COMPARE_AND_BRANCH`` with :opcode:`COMPARE_OP`. -- gh-issue-102701: Fix overflow when creating very large dict. +- gh-102701: Fix overflow when creating very large dict. -- gh-issue-102755: Add :c:func:`PyErr_DisplayException` which takes just an +- gh-102755: Add :c:func:`PyErr_DisplayException` which takes just an exception instance, to replace the legacy :c:func:`PyErr_Display` which takes the ``(typ, exc, tb)`` triplet. -- gh-issue-102594: Add note to exception raised in ``PyErr_SetObject`` when +- gh-102594: Add note to exception raised in ``PyErr_SetObject`` when normalization fails. -- gh-issue-90997: Shrink the number of inline :opcode:`CACHE` entries used - by :opcode:`LOAD_GLOBAL`. +- gh-90997: Shrink the number of inline :opcode:`CACHE` entries used by + :opcode:`LOAD_GLOBAL`. -- gh-issue-102491: Improve import time of ``platform`` by removing - IronPython version parsing. The IronPython version parsing was not - functional (see https://github.com/IronLanguages/ironpython3/issues/1667). +- gh-102491: Improve import time of ``platform`` by removing IronPython + version parsing. The IronPython version parsing was not functional (see + https://github.com/IronLanguages/ironpython3/issues/1667). -- gh-issue-101291: Rearrage bits in first field (after header) of - PyLongObject. * Bits 0 and 1: 1 - sign. I.e. 0 for positive numbers, 1 for - zero and 2 for negative numbers. * Bit 2 reserved (probably for the - immortal bit) * Bits 3+ the unsigned size. +- gh-101291: Rearrage bits in first field (after header) of PyLongObject. * + Bits 0 and 1: 1 - sign. I.e. 0 for positive numbers, 1 for zero and 2 for + negative numbers. * Bit 2 reserved (probably for the immortal bit) * Bits + 3+ the unsigned size. This makes a few operations slightly more efficient, and will enable a more compact and faster 2s-complement representation of most ints in future. -- gh-issue-102397: Fix segfault from race condition in signal handling - during garbage collection. Patch by Kumar Aditya. +- gh-102397: Fix segfault from race condition in signal handling during + garbage collection. Patch by Kumar Aditya. -- gh-issue-102406: :mod:`codecs` encoding/decoding errors now get the - context information (which operation and which codecs) attached as - :pep:`678` notes instead of through chaining a new instance of the - exception. +- gh-102406: :mod:`codecs` encoding/decoding errors now get the context + information (which operation and which codecs) attached as :pep:`678` + notes instead of through chaining a new instance of the exception. -- gh-issue-102281: Fix potential nullptr dereference and use of - uninitialized memory in fileutils. Patch by Max Bachmann. +- gh-102281: Fix potential nullptr dereference and use of uninitialized + memory in fileutils. Patch by Max Bachmann. -- gh-issue-102300: Reuse operands with refcount of 1 in float - specializations of BINARY_OP. +- gh-102300: Reuse operands with refcount of 1 in float specializations of + BINARY_OP. -- gh-issue-102213: Fix performance loss when accessing an object's - attributes with ``__getattr__`` defined. +- gh-102213: Fix performance loss when accessing an object's attributes with + ``__getattr__`` defined. -- gh-issue-102255: Improve build support for the Xbox. Patch by Max - Bachmann. +- gh-102255: Improve build support for the Xbox. Patch by Max Bachmann. -- gh-issue-102027: Fix SSE2 and SSE3 detection in ``_blake2`` internal - module. Patch by Max Bachmann. +- gh-102027: Fix SSE2 and SSE3 detection in ``_blake2`` internal module. + Patch by Max Bachmann. -- gh-issue-101865: Deprecate ``co_lnotab`` in code objects, schedule it for +- gh-101865: Deprecate ``co_lnotab`` in code objects, schedule it for removal in Python 3.14 - bpo-1635741: Adapt :mod:`!_pickle` to :pep:`687`. Patch by Mohamed Koubaa @@ -3963,23 +4912,21 @@ Core and Builtins Library ------- -- gh-issue-103085: Pure python :func:`locale.getencoding()` will not warn +- gh-103085: Pure python :func:`locale.getencoding` will not warn deprecation. -- gh-issue-103068: It's no longer possible to register conditional - breakpoints in :class:`~pdb.Pdb` that raise :exc:`SyntaxError`. Patch by - Tian Gao. +- gh-103068: It's no longer possible to register conditional breakpoints in + :class:`~pdb.Pdb` that raise :exc:`SyntaxError`. Patch by Tian Gao. -- gh-issue-102549: Don't ignore exceptions in member type creation. +- gh-102549: Don't ignore exceptions in member type creation. -- gh-issue-103056: Ensure final ``_generate_next_value_`` is a - ``staticmethod``. +- gh-103056: Ensure final ``_generate_next_value_`` is a ``staticmethod``. -- gh-issue-103046: Display current line label correctly in :mod:`dis` when +- gh-103046: Display current line label correctly in :mod:`dis` when ``show_caches`` is False and ``lasti`` points to a CACHE entry. -- gh-issue-102433: :func:`isinstance` checks against - :func:`runtime-checkable protocols ` now use +- gh-102433: :func:`isinstance` checks against :func:`runtime-checkable + protocols ` now use :func:`inspect.getattr_static` rather than :func:`hasattr` to lookup whether attributes exist. This means that descriptors and :meth:`~object.__getattr__` methods are no longer unexpectedly evaluated @@ -3989,109 +4936,107 @@ Library instances of that protocol on Python 3.12+, and vice versa. Most users are unlikely to be affected by this change. Patch by Alex Waygood. -- gh-issue-103023: It's no longer possible to register expressions to - display in :class:`~pdb.Pdb` that raise :exc:`SyntaxError`. Patch by Tian - Gao. +- gh-103023: It's no longer possible to register expressions to display in + :class:`~pdb.Pdb` that raise :exc:`SyntaxError`. Patch by Tian Gao. -- gh-issue-102947: Improve traceback when :func:`dataclasses.fields` is - called on a non-dataclass. Patch by Alex Waygood +- gh-102947: Improve traceback when :func:`dataclasses.fields` is called on + a non-dataclass. Patch by Alex Waygood -- gh-issue-102780: The :class:`asyncio.Timeout` context manager now works - reliably even when performing cleanup due to task cancellation. - Previously it could raise a :exc:`~asyncio.CancelledError` instead of an +- gh-102780: The :class:`asyncio.Timeout` context manager now works reliably + even when performing cleanup due to task cancellation. Previously it + could raise a :exc:`~asyncio.CancelledError` instead of an :exc:`~asyncio.TimeoutError` in such cases. -- gh-issue-102871: Remove support for obsolete browsers from - :mod:`webbrowser`. Removed browsers include Grail, Mosaic, Netscape, - Galeon, Skipstone, Iceape, Firebird, and Firefox versions 35 and below. +- gh-102871: Remove support for obsolete browsers from :mod:`webbrowser`. + Removed browsers include Grail, Mosaic, Netscape, Galeon, Skipstone, + Iceape, Firebird, and Firefox versions 35 and below. -- gh-issue-102839: Improve performance of :func:`math.log` arguments - handling by removing the argument clinic. +- gh-102839: Improve performance of :func:`math.log` arguments handling by + removing the argument clinic. -- gh-issue-102828: Add the ``onexc`` arg to :func:`shutil.rmtree`, which is - like ``onerror`` but expects an exception instance rather than an exc_info +- gh-102828: Add the ``onexc`` arg to :func:`shutil.rmtree`, which is like + ``onerror`` but expects an exception instance rather than an exc_info tuple. Deprecate ``onerror``. -- gh-issue-88965: typing: Fix a bug relating to substitution in custom - classes generic over a :class:`~typing.ParamSpec`. Previously, if the +- gh-88965: typing: Fix a bug relating to substitution in custom classes + generic over a :class:`~typing.ParamSpec`. Previously, if the ``ParamSpec`` was substituted with a parameters list that itself contained a :class:`~typing.TypeVar`, the ``TypeVar`` in the parameters list could not be subsequently substituted. This is now fixed. Patch by Nikita Sobolev. -- gh-issue-76846: Fix issue where ``__new__()`` and ``__init__()`` methods - of :class:`pathlib.PurePath` and :class:`~pathlib.Path` subclasses were - not called in some circumstances. +- gh-76846: Fix issue where ``__new__()`` and ``__init__()`` methods of + :class:`pathlib.PurePath` and :class:`~pathlib.Path` subclasses were not + called in some circumstances. -- gh-issue-78530: :func:`asyncio.wait` now accepts generators yielding - tasks. Patch by Kumar Aditya. +- gh-78530: :func:`asyncio.wait` now accepts generators yielding tasks. + Patch by Kumar Aditya. -- gh-issue-102748: :func:`asyncio.iscoroutine` now returns ``False`` for +- gh-102748: :func:`asyncio.iscoroutine` now returns ``False`` for generators as :mod:`asyncio` does not support legacy generator-based coroutines. Patch by Kumar Aditya. -- gh-issue-102670: Optimized fmean(), correlation(), covariance(), and +- gh-102670: Optimized fmean(), correlation(), covariance(), and linear_regression() using the new math.sumprod() function. -- gh-issue-102615: Typing: Improve the ``repr`` of generic aliases for - classes generic over a :class:`~typing.ParamSpec`. (Use square brackets to +- gh-102615: Typing: Improve the ``repr`` of generic aliases for classes + generic over a :class:`~typing.ParamSpec`. (Use square brackets to represent a parameter list.) -- gh-issue-100112: :meth:`asyncio.Task.get_coro` now always returns a - coroutine when wrapping an awaitable object. Patch by Kumar Aditya. +- gh-100112: :meth:`asyncio.Task.get_coro` now always returns a coroutine + when wrapping an awaitable object. Patch by Kumar Aditya. -- gh-issue-102578: Speed up setting or deleting mutable attributes on +- gh-102578: Speed up setting or deleting mutable attributes on non-dataclass subclasses of frozen dataclasses. Due to the implementation of ``__setattr__`` and ``__delattr__`` for frozen dataclasses, this previously had a time complexity of *O*\ (*n*). It now has a time complexity of *O*\ (1). -- gh-issue-102519: Add :func:`os.listdrives`, :func:`os.listvolumes` and +- gh-102519: Add :func:`os.listdrives`, :func:`os.listvolumes` and :func:`os.listmounts` functions on Windows for enumerating drives, volumes and mount points -- gh-issue-74468: Attribute name of the extracted :mod:`tarfile` file object - now holds filename of itself rather than of the archive it is contained - in. Patch by Oleg Iarygin. +- gh-74468: Attribute name of the extracted :mod:`tarfile` file object now + holds filename of itself rather than of the archive it is contained in. + Patch by Oleg Iarygin. -- gh-issue-102378: Private helper method +- gh-102378: Private helper method ``inspect._signature_strip_non_python_syntax`` will no longer strip ``/`` from the input string. -- gh-issue-79940: Add :func:`inspect.getasyncgenstate` and +- gh-79940: Add :func:`inspect.getasyncgenstate` and :func:`inspect.getasyncgenlocals`. Patch by Thomas Krennwallner. -- gh-issue-102103: Add ``module`` argument to - :func:`dataclasses.make_dataclass` and make classes produced by it - pickleable. +- gh-102103: Add ``module`` argument to :func:`dataclasses.make_dataclass` + and make classes produced by it pickleable. -- gh-issue-102069: Fix ``__weakref__`` descriptor generation for custom +- gh-102069: Fix ``__weakref__`` descriptor generation for custom dataclasses. -- gh-issue-102038: Skip a ``stat`` in :mod:`site` if we have already found a +- gh-102038: Skip a ``stat`` in :mod:`site` if we have already found a ``pyvenv.cfg`` -- gh-issue-98886: Fix issues when defining dataclasses that have fields with +- gh-98886: Fix issues when defining dataclasses that have fields with specific underscore names that aren't clearly reserved by :mod:`dataclasses`. -- gh-issue-101673: Fix a :mod:`pdb` bug where ``ll`` clears the changes to - local variables. +- gh-101673: Fix a :mod:`pdb` bug where ``ll`` clears the changes to local + variables. -- gh-issue-101313: Added -h and --help arguments to the webbrowser CLI +- gh-101313: Added -h and --help arguments to the webbrowser CLI -- gh-issue-100372: :meth:`ssl.SSLContext.load_verify_locations` no longer +- gh-100372: :meth:`ssl.SSLContext.load_verify_locations` no longer incorrectly accepts some cases of trailing data when parsing DER. -- gh-issue-89727: Fix pathlib.Path.walk RecursionError on deep directory - trees by rewriting it using iteration instead of recursion. +- gh-89727: Fix pathlib.Path.walk RecursionError on deep directory trees by + rewriting it using iteration instead of recursion. -- gh-issue-100131: Added an optional ``delete`` keyword argument to +- gh-100131: Added an optional ``delete`` keyword argument to :class:`tempfile.TemporaryDirectory`. -- gh-issue-48330: Added ``--durations`` command line option, showing the N - slowest test cases. :class:`unittest.TextTestRunner` and +- gh-48330: Added ``--durations`` command line option, showing the N slowest + test cases. :class:`unittest.TextTestRunner` and :class:`unittest.TextTestResult` constructors accept a new *durations* keyword argument. Subclasses should take this into account or accept ``**kwargs``. Added :meth:`unittest.TestResult.addDuration` method and @@ -4099,28 +5044,27 @@ Library (Contributed by Giampaolo Rodola) -- gh-issue-98169: Fix :func:`dataclasses.astuple` crash when +- gh-98169: Fix :func:`dataclasses.astuple` crash when :class:`collections.defaultdict` is present in the attributes. -- gh-issue-96931: Fix incorrect results from - :meth:`ssl.SSLSocket.shared_ciphers` +- gh-96931: Fix incorrect results from :meth:`ssl.SSLSocket.shared_ciphers` -- gh-issue-95495: When built against OpenSSL 3.0, the :mod:`ssl` module had - a bug where it reported unauthenticated EOFs (i.e. without close_notify) - as a clean TLS-level EOF. It now raises :exc:`~ssl.SSLEOFError`, matching - the behavior in previous versions of OpenSSL. The +- gh-95495: When built against OpenSSL 3.0, the :mod:`ssl` module had a bug + where it reported unauthenticated EOFs (i.e. without close_notify) as a + clean TLS-level EOF. It now raises :exc:`~ssl.SSLEOFError`, matching the + behavior in previous versions of OpenSSL. The :attr:`~ssl.SSLContext.options` attribute on :class:`~ssl.SSLContext` also no longer includes :const:`~ssl.OP_IGNORE_UNEXPECTED_EOF` by default. This option may be set to specify the previous OpenSSL 3.0 behavior. -- gh-issue-94684: Now :func:`uuid.uuid3` and :func:`uuid.uuid5` functions - support :class:`bytes` objects as their *name* argument. +- gh-94684: Now :func:`uuid.uuid3` and :func:`uuid.uuid5` functions support + :class:`bytes` objects as their *name* argument. -- gh-issue-94440: Fix a :mod:`concurrent.futures.process` bug where +- gh-94440: Fix a :mod:`concurrent.futures.process` bug where ``ProcessPoolExecutor`` shutdown could hang after a future has been quickly submitted and canceled. -- gh-issue-72346: Added deprecation warning to *isdst* parameter of +- gh-72346: Added deprecation warning to *isdst* parameter of :func:`email.utils.localtime`. - bpo-36305: Fix handling of Windows filenames that resemble drives, such as @@ -4129,46 +5073,46 @@ Library Documentation ------------- -- gh-issue-103112: Add docstring to :meth:`http.client.HTTPResponse.read` to - fix ``pydoc`` output. +- gh-103112: Add docstring to :meth:`http.client.HTTPResponse.read` to fix + ``pydoc`` output. Tests ----- -- gh-issue-102980: Improve test coverage on :mod:`pdb`. +- gh-102980: Improve test coverage on :mod:`pdb`. -- gh-issue-102537: Adjust the error handling strategy in +- gh-102537: Adjust the error handling strategy in ``test_zoneinfo.TzPathTest.python_tzpath_context``. Patch by Paul Ganssle. -- gh-issue-101377: Improved test_locale_calendar_formatweekday of calendar. +- gh-101377: Improved test_locale_calendar_formatweekday of calendar. Build ----- -- gh-issue-102973: Add a dev container (along with accompanying Dockerfile) - for development purposes. +- gh-102973: Add a dev container (along with accompanying Dockerfile) for + development purposes. -- gh-issue-102711: Fix ``-Wstrict-prototypes`` compiler warnings. +- gh-102711: Fix ``-Wstrict-prototypes`` compiler warnings. Windows ------- -- gh-issue-102690: Update :mod:`webbrowser` to fall back to Microsoft Edge - instead of Internet Explorer. +- gh-102690: Update :mod:`webbrowser` to fall back to Microsoft Edge instead + of Internet Explorer. -- gh-issue-99726: Improves correctness of stat results for Windows, and uses +- gh-99726: Improves correctness of stat results for Windows, and uses faster API when available Tools/Demos ----------- -- gh-issue-102809: ``Misc/gdbinit`` was removed. +- gh-102809: ``Misc/gdbinit`` was removed. C API ----- -- gh-issue-102013: Add a new (unstable) C-API function for iterating over - GC'able objects using a callback: ``PyUnstable_VisitObjects``. +- gh-102013: Add a new (unstable) C-API function for iterating over GC'able + objects using a callback: ``PyUnstable_VisitObjects``. What's New in Python 3.12.0 alpha 6? @@ -4179,221 +5123,216 @@ What's New in Python 3.12.0 alpha 6? Security -------- -- gh-issue-99108: Replace builtin hashlib implementations of MD5 and SHA1 - with verified ones from the HACL* project. +- gh-99108: Replace builtin hashlib implementations of MD5 and SHA1 with + verified ones from the HACL* project. -- gh-issue-101727: Updated the OpenSSL version used in Windows and macOS - binary release builds to 1.1.1t to address :cve:`2023-0286`, - :cve:`2022-4303`, and :cve:`2022-4303` per `the OpenSSL 2023-02-07 - security advisory `_. +- gh-101727: Updated the OpenSSL version used in Windows and macOS binary + release builds to 1.1.1t to address :cve:`2023-0286`, :cve:`2022-4303`, + and :cve:`2022-4303` per `the OpenSSL 2023-02-07 security advisory + `_. -- gh-issue-99108: Replace the builtin :mod:`hashlib` implementations of - SHA2-384 and SHA2-512 originally from LibTomCrypt with formally verified, +- gh-99108: Replace the builtin :mod:`hashlib` implementations of SHA2-384 + and SHA2-512 originally from LibTomCrypt with formally verified, side-channel resistant code from the `HACL* `_ project. The builtins remain a fallback only used when OpenSSL does not provide them. -- gh-issue-101283: :class:`subprocess.Popen` now uses a safer approach to - find ``cmd.exe`` when launching with ``shell=True``. Patch by Eryk Sun, - based on a patch by Oleg Iarygin. +- gh-101283: :class:`subprocess.Popen` now uses a safer approach to find + ``cmd.exe`` when launching with ``shell=True``. Patch by Eryk Sun, based + on a patch by Oleg Iarygin. Core and Builtins ----------------- -- gh-issue-102493: Fix regression in semantics of normalisation in +- gh-102493: Fix regression in semantics of normalisation in ``PyErr_SetObject``. -- gh-issue-102416: Do not memoize incorrectly automatically generated loop - rules in the parser. Patch by Pablo Galindo. +- gh-102416: Do not memoize incorrectly automatically generated loop rules + in the parser. Patch by Pablo Galindo. -- gh-issue-102356: Fix a bug that caused a crash when deallocating deeply - nested filter objects. Patch by Marta Gómez Macías. +- gh-102356: Fix a bug that caused a crash when deallocating deeply nested + filter objects. Patch by Marta Gómez Macías. -- gh-issue-102336: Cleanup Windows 7 specific special handling. Patch by Max +- gh-102336: Cleanup Windows 7 specific special handling. Patch by Max Bachmann. -- gh-issue-102250: Fixed a segfault occurring when the interpreter calls a +- gh-102250: Fixed a segfault occurring when the interpreter calls a ``__bool__`` method that raises. -- gh-issue-102126: Fix deadlock at shutdown when clearing thread states if - any finalizer tries to acquire the runtime head lock. Patch by Kumar - Aditya. +- gh-102126: Fix deadlock at shutdown when clearing thread states if any + finalizer tries to acquire the runtime head lock. Patch by Kumar Aditya. -- gh-issue-102027: Use ``GetCurrentProcessId`` on Windows when ``getpid`` is +- gh-102027: Use ``GetCurrentProcessId`` on Windows when ``getpid`` is unavailable. Patch by Max Bachmann. -- gh-issue-102056: Fix error handling bugs in interpreter's exception - printing code, which could cause a crash on infinite recursion. +- gh-102056: Fix error handling bugs in interpreter's exception printing + code, which could cause a crash on infinite recursion. -- gh-issue-100982: Restrict the scope of the :opcode:`FOR_ITER_RANGE` - instruction to the scope of the original :opcode:`FOR_ITER` instruction, - to allow instrumentation. +- gh-100982: Restrict the scope of the :opcode:`FOR_ITER_RANGE` instruction + to the scope of the original :opcode:`FOR_ITER` instruction, to allow + instrumentation. -- gh-issue-101967: Fix possible segfault in - ``positional_only_passed_as_keyword`` function, when new list created. +- gh-101967: Fix possible segfault in ``positional_only_passed_as_keyword`` + function, when new list created. -- gh-issue-101952: Fix possible segfault in ``BUILD_SET`` opcode, when new - set created. +- gh-101952: Fix possible segfault in ``BUILD_SET`` opcode, when new set + created. -- gh-issue-74895: :mod:`socket.getaddrinfo` no longer raises +- gh-74895: :mod:`socket.getaddrinfo` no longer raises :class:`OverflowError` for :class:`int` **port** values outside of the C long range. Out of range values are left up to the underlying string based C library API to report. A :class:`socket.gaierror` ``SAI_SERVICE`` may occur instead, or no error at all as not all platform C libraries generate an error. -- gh-issue-101799: Add :opcode:`CALL_INTRINSIC_2` and use it instead of +- gh-101799: Add :opcode:`CALL_INTRINSIC_2` and use it instead of :opcode:`!PREP_RERAISE_STAR`. -- gh-issue-101857: Fix xattr support detection on Linux systems by widening - the check to linux, not just glibc. This fixes support for musl. +- gh-101857: Fix xattr support detection on Linux systems by widening the + check to linux, not just glibc. This fixes support for musl. -- gh-issue-84783: Make the slice object hashable. Patch by Will Bradshaw and +- gh-84783: Make the slice object hashable. Patch by Will Bradshaw and Furkan Onder. -- gh-issue-87849: Change the ``SEND`` instruction to leave the receiver on - the stack. This allows the specialized form of ``SEND`` to skip the chain - of C calls and jump directly to the ``RESUME`` in the generator or - coroutine. +- gh-87849: Change the ``SEND`` instruction to leave the receiver on the + stack. This allows the specialized form of ``SEND`` to skip the chain of C + calls and jump directly to the ``RESUME`` in the generator or coroutine. -- gh-issue-101765: Fix SystemError / segmentation fault in iter - ``__reduce__`` when internal access of ``builtins.__dict__`` keys mutates - the iter object. +- gh-101765: Fix SystemError / segmentation fault in iter ``__reduce__`` + when internal access of ``builtins.__dict__`` keys mutates the iter + object. -- gh-issue-101430: Update :mod:`tracemalloc` to handle presize of object - properly. Patch by Donghee Na. +- gh-101430: Update :mod:`tracemalloc` to handle presize of object properly. + Patch by Donghee Na. -- gh-issue-101696: Invalidate type version tag in ``_PyStaticType_Dealloc`` - for static types, avoiding bug where a false cache hit could crash the +- gh-101696: Invalidate type version tag in ``_PyStaticType_Dealloc`` for + static types, avoiding bug where a false cache hit could crash the interpreter. Patch by Kumar Aditya. -- gh-issue-101632: Adds a new :opcode:`RETURN_CONST` instruction. +- gh-101632: Adds a new :opcode:`RETURN_CONST` instruction. -- gh-issue-100719: Remove gi_code field from generator (and coroutine and - async generator) objects as it is redundant. The frame already includes a +- gh-100719: Remove gi_code field from generator (and coroutine and async + generator) objects as it is redundant. The frame already includes a reference to the code object. -- gh-issue-98627: When an interpreter is configured to check (and only - then), importing an extension module will now fail when the extension does - not support multiple interpreters (i.e. doesn't implement PEP 489 - multi-phase init). This does not apply to the main interpreter, nor to - subinterpreters created with ``Py_NewInterpreter()``. +- gh-98627: When an interpreter is configured to check (and only then), + importing an extension module will now fail when the extension does not + support multiple interpreters (i.e. doesn't implement PEP 489 multi-phase + init). This does not apply to the main interpreter, nor to subinterpreters + created with ``Py_NewInterpreter()``. Library ------- -- gh-issue-102302: Micro-optimise hashing of :class:`inspect.Parameter`, - reducing the time it takes to hash an instance by around 40%. +- gh-102302: Micro-optimise hashing of :class:`inspect.Parameter`, reducing + the time it takes to hash an instance by around 40%. -- gh-issue-101979: Fix a bug where parentheses in the ``metavar`` argument - to :meth:`argparse.ArgumentParser.add_argument` were dropped. Patch by - Yeojin Kim. +- gh-101979: Fix a bug where parentheses in the ``metavar`` argument to + :meth:`argparse.ArgumentParser.add_argument` were dropped. Patch by Yeojin + Kim. -- gh-issue-91038: :meth:`platform.platform` now has boolean default - arguments. +- gh-91038: :meth:`platform.platform` now has boolean default arguments. -- gh-issue-81652: Add :const:`mmap.MAP_ALIGNED_SUPER` FreeBSD and +- gh-81652: Add :const:`mmap.MAP_ALIGNED_SUPER` FreeBSD and :const:`mmap.MAP_CONCEAL` OpenBSD constants to :mod:`mmap`. Patch by Yeojin Kim. -- gh-issue-102179: Fix :func:`os.dup2` error message for negative fds. +- gh-102179: Fix :func:`os.dup2` error message for negative fds. -- gh-issue-101961: For the binary mode, :func:`fileinput.hookcompressed` - doesn't set the ``encoding`` value even if the value is ``None``. Patch by - Gihwan Kim. +- gh-101961: For the binary mode, :func:`fileinput.hookcompressed` doesn't + set the ``encoding`` value even if the value is ``None``. Patch by Gihwan + Kim. -- gh-issue-101936: The default value of ``fp`` becomes :class:`io.BytesIO` - if :exc:`~urllib.error.HTTPError` is initialized without a designated - ``fp`` parameter. Patch by Long Vo. +- gh-101936: The default value of ``fp`` becomes :class:`io.BytesIO` if + :exc:`~urllib.error.HTTPError` is initialized without a designated ``fp`` + parameter. Patch by Long Vo. -- gh-issue-101566: In zipfile, sync Path with `zipp 3.14 +- gh-101566: In zipfile, sync Path with `zipp 3.14 `_, including fix for extractall on the underlying zipfile after being wrapped in ``Path``. -- gh-issue-97930: Apply changes from `importlib_resources 5.12 +- gh-97930: Apply changes from `importlib_resources 5.12 `_, including fix for ``MultiplexedPath`` to support directories in multiple namespaces (python/importlib_resources#265). -- gh-issue-101997: Upgrade pip wheel bundled with ensurepip (pip 23.0.1) +- gh-101997: Upgrade pip wheel bundled with ensurepip (pip 23.0.1) -- gh-issue-99108: The built-in extension modules for :mod:`hashlib` SHA2 +- gh-99108: The built-in extension modules for :mod:`hashlib` SHA2 algorithms, used when OpenSSL does not provide them, now live in a single internal ``_sha2`` module instead of separate ``_sha256`` and ``_sha512`` modules. -- gh-issue-101892: Callable iterators no longer raise :class:`SystemError` - when the callable object exhausts the iterator but forgets to either - return a sentinel value or raise :class:`StopIteration`. +- gh-101892: Callable iterators no longer raise :class:`SystemError` when + the callable object exhausts the iterator but forgets to either return a + sentinel value or raise :class:`StopIteration`. -- gh-issue-87634: Remove locking behavior from - :func:`functools.cached_property`. +- gh-87634: Remove locking behavior from :func:`functools.cached_property`. -- gh-issue-97786: Fix potential undefined behaviour in corner cases of +- gh-97786: Fix potential undefined behaviour in corner cases of floating-point-to-time conversions. -- gh-issue-101517: Fixed bug where :mod:`bdb` looks up the source line with +- gh-101517: Fixed bug where :mod:`bdb` looks up the source line with :mod:`linecache` with a ``lineno=None``, which causes it to fail with an unhandled exception. -- gh-issue-101773: Optimize :class:`fractions.Fraction` for small - components. The private argument ``_normalize`` of the - :class:`fractions.Fraction` constructor has been removed. +- gh-101773: Optimize :class:`fractions.Fraction` for small components. The + private argument ``_normalize`` of the :class:`fractions.Fraction` + constructor has been removed. -- gh-issue-101693: In :meth:`sqlite3.Cursor.execute`, - :exc:`DeprecationWarning` is now emitted when :ref:`named placeholders - ` are used together with parameters supplied as a - :term:`sequence` instead of as a :class:`dict`. Starting from Python 3.14, - using named placeholders with parameters supplied as a sequence will raise - a :exc:`~sqlite3.ProgrammingError`. Patch by Erlend E. Aasland. +- gh-101693: In :meth:`sqlite3.Cursor.execute`, :exc:`DeprecationWarning` is + now emitted when :ref:`named placeholders ` are used + together with parameters supplied as a :term:`sequence` instead of as a + :class:`dict`. Starting from Python 3.14, using named placeholders with + parameters supplied as a sequence will raise a + :exc:`~sqlite3.ProgrammingError`. Patch by Erlend E. Aasland. -- gh-issue-101446: Change repr of :class:`collections.OrderedDict` to use - regular dictionary formatting instead of pairs of keys and values. +- gh-101446: Change repr of :class:`collections.OrderedDict` to use regular + dictionary formatting instead of pairs of keys and values. -- gh-issue-101362: Speed up :class:`pathlib.PurePath` construction by - handling arguments more uniformly. When a :class:`pathlib.Path` argument - is supplied, we use its string representation rather than joining its - parts with :func:`os.path.join`. +- gh-101362: Speed up :class:`pathlib.PurePath` construction by handling + arguments more uniformly. When a :class:`pathlib.Path` argument is + supplied, we use its string representation rather than joining its parts + with :func:`os.path.join`. -- gh-issue-101362: Speed up :class:`pathlib.PurePath` construction by - calling :func:`os.path.join` only when two or more arguments are given. +- gh-101362: Speed up :class:`pathlib.PurePath` construction by calling + :func:`os.path.join` only when two or more arguments are given. -- gh-issue-101362: Speed up :class:`pathlib.Path` construction by running - the path flavour compatibility check only when pathlib is imported. +- gh-101362: Speed up :class:`pathlib.Path` construction by running the path + flavour compatibility check only when pathlib is imported. -- gh-issue-85984: Refactored the implementation of :func:`pty.fork` to use +- gh-85984: Refactored the implementation of :func:`pty.fork` to use :func:`os.login_tty`. A :exc:`DeprecationWarning` is now raised by ``pty.master_open()`` and ``pty.slave_open()``. They were undocumented and deprecated long long ago in the docstring in favor of :func:`pty.openpty`. -- gh-issue-101561: Add a new decorator :func:`typing.override`. See - :pep:`698` for details. Patch by Steven Troxler. +- gh-101561: Add a new decorator :func:`typing.override`. See :pep:`698` for + details. Patch by Steven Troxler. -- gh-issue-63301: Set exit code when :mod:`tabnanny` CLI exits on error. +- gh-63301: Set exit code when :mod:`tabnanny` CLI exits on error. -- gh-issue-101360: Fix anchor matching in - :meth:`pathlib.PureWindowsPath.match`. Path and pattern anchors are now - matched with :mod:`fnmatch`, just like other path parts. This allows - patterns such as ``"*:/Users/*"`` to be matched. +- gh-101360: Fix anchor matching in :meth:`pathlib.PureWindowsPath.match`. + Path and pattern anchors are now matched with :mod:`fnmatch`, just like + other path parts. This allows patterns such as ``"*:/Users/*"`` to be + matched. -- gh-issue-101277: Remove global state from :mod:`itertools` module - (:pep:`687`). Patches by Erlend E. Aasland. +- gh-101277: Remove global state from :mod:`itertools` module (:pep:`687`). + Patches by Erlend E. Aasland. -- gh-issue-100809: Fix handling of drive-relative paths (like 'C:' and - 'C:foo') in :meth:`pathlib.Path.absolute`. This method now uses the OS API - to retrieve the correct current working directory for the drive. +- gh-100809: Fix handling of drive-relative paths (like 'C:' and 'C:foo') in + :meth:`pathlib.Path.absolute`. This method now uses the OS API to retrieve + the correct current working directory for the drive. -- gh-issue-99138: Apply :pep:`687` to :mod:`zoneinfo`. Patch by Erlend E. - Aasland. +- gh-99138: Apply :pep:`687` to :mod:`zoneinfo`. Patch by Erlend E. Aasland. -- gh-issue-96764: :func:`asyncio.wait_for` now uses :func:`asyncio.timeout` - as its underlying implementation. Patch by Kumar Aditya. +- gh-96764: :func:`asyncio.wait_for` now uses :func:`asyncio.timeout` as its + underlying implementation. Patch by Kumar Aditya. -- gh-issue-88233: Correctly preserve "extra" fields in ``zipfile`` - regardless of their ordering relative to a zip64 "extra." +- gh-88233: Correctly preserve "extra" fields in ``zipfile`` regardless of + their ordering relative to a zip64 "extra." - bpo-23224: Fix segfaults when creating :class:`lzma.LZMADecompressor` and :class:`bz2.BZ2Decompressor` objects without calling ``__init__()``, and @@ -4405,21 +5344,21 @@ Library Documentation ------------- -- gh-issue-85417: Update :mod:`cmath` documentation to clarify behaviour on - branch cuts. +- gh-85417: Update :mod:`cmath` documentation to clarify behaviour on branch + cuts. -- gh-issue-97725: Fix :meth:`asyncio.Task.print_stack` description for +- gh-97725: Fix :meth:`asyncio.Task.print_stack` description for ``file=None``. Patch by Oleg Iarygin. Tests ----- -- gh-issue-102019: Fix deadlock on shutdown if - ``test_current_{exception,frames}`` fails. Patch by Jacob Bower. +- gh-102019: Fix deadlock on shutdown if ``test_current_{exception,frames}`` + fails. Patch by Jacob Bower. -- gh-issue-85984: Utilize new "winsize" functions from termios in pty tests. +- gh-85984: Utilize new "winsize" functions from termios in pty tests. -- gh-issue-89792: ``test_tools`` now copies up to 10x less source data to a +- gh-89792: ``test_tools`` now copies up to 10x less source data to a temporary directory during the ``freeze`` test by ignoring git metadata and other artifacts. It also limits its python build parallelism based on os.cpu_count instead of hard coding it as 8 cores. @@ -4427,62 +5366,61 @@ Tests Build ----- -- gh-issue-99942: On Android, in a static build, python-config in embed mode - no longer incorrectly reports a library to link to. +- gh-99942: On Android, in a static build, python-config in embed mode no + longer incorrectly reports a library to link to. -- gh-issue-99942: On Android, python.pc now correctly reports the library to - link to, the same as python-config.sh. +- gh-99942: On Android, python.pc now correctly reports the library to link + to, the same as python-config.sh. -- gh-issue-100221: Fix creating install directories in ``make - sharedinstall`` if they exist outside ``DESTDIR`` already. +- gh-100221: Fix creating install directories in ``make sharedinstall`` if + they exist outside ``DESTDIR`` already. -- gh-issue-96821: Explicitly mark C extension modules that need defined - signed integer overflow, and add a configure option +- gh-96821: Explicitly mark C extension modules that need defined signed + integer overflow, and add a configure option :option:`--with-strict-overflow`. Patch by Matthias Görgens and Shantanu Jain. Windows ------- -- gh-issue-102344: Implement ``winreg.QueryValue`` using ``QueryValueEx`` - and ``winreg.SetValue`` using ``SetValueEx``. Patch by Max Bachmann. +- gh-102344: Implement ``winreg.QueryValue`` using ``QueryValueEx`` and + ``winreg.SetValue`` using ``SetValueEx``. Patch by Max Bachmann. -- gh-issue-101881: Handle read and write operations on non-blocking pipes - properly on Windows. +- gh-101881: Handle read and write operations on non-blocking pipes properly + on Windows. -- gh-issue-101881: Add support for the os.get_blocking() and - os.set_blocking() functions on Windows. +- gh-101881: Add support for the os.get_blocking() and os.set_blocking() + functions on Windows. -- gh-issue-101849: Ensures installer will correctly upgrade existing - ``py.exe`` launcher installs. +- gh-101849: Ensures installer will correctly upgrade existing ``py.exe`` + launcher installs. -- gh-issue-101763: Updates copy of libffi bundled with Windows installs to - 3.4.4. +- gh-101763: Updates copy of libffi bundled with Windows installs to 3.4.4. -- gh-issue-101759: Update Windows installer to SQLite 3.40.1. +- gh-101759: Update Windows installer to SQLite 3.40.1. -- gh-issue-101614: Correctly handle extensions built against debug binaries - that reference ``python3_d.dll``. +- gh-101614: Correctly handle extensions built against debug binaries that + reference ``python3_d.dll``. -- gh-issue-101196: The functions ``os.path.isdir``, ``os.path.isfile``, +- gh-101196: The functions ``os.path.isdir``, ``os.path.isfile``, ``os.path.islink`` and ``os.path.exists`` are now 13% to 28% faster on Windows, by making fewer Win32 API calls. macOS ----- -- gh-issue-101759: Update macOS installer to SQLite 3.40.1. +- gh-101759: Update macOS installer to SQLite 3.40.1. C API ----- -- gh-issue-101907: Removes use of non-standard C++ extension in public - header files. +- gh-101907: Removes use of non-standard C++ extension in public header + files. -- gh-issue-99293: Document that the Py_TPFLAGS_VALID_VERSION_TAG is an - internal feature, should not be used, and will be removed. +- gh-99293: Document that the Py_TPFLAGS_VALID_VERSION_TAG is an internal + feature, should not be used, and will be removed. -- gh-issue-101578: Add :c:func:`PyErr_GetRaisedException` and +- gh-101578: Add :c:func:`PyErr_GetRaisedException` and :c:func:`PyErr_SetRaisedException` for saving and restoring the current exception. These functions return and accept a single exception object, rather than the triple arguments of the now-deprecated @@ -4493,7 +5431,7 @@ C API convenience functions for retrieving and modifying the :attr:`~BaseException.args` passed to the exception's constructor. -- gh-issue-91744: Introduced the *Unstable C API tier*, marking APi that is +- gh-91744: Introduced the *Unstable C API tier*, marking APi that is allowed to change in minor releases without a deprecation period. See :pep:`689` for details. @@ -4506,8 +5444,8 @@ What's New in Python 3.12.0 alpha 5? Security -------- -- gh-issue-99108: Replace the builtin :mod:`hashlib` implementations of - SHA2-224 and SHA2-256 originally from LibTomCrypt with formally verified, +- gh-99108: Replace the builtin :mod:`hashlib` implementations of SHA2-224 + and SHA2-256 originally from LibTomCrypt with formally verified, side-channel resistant code from the `HACL* `_ project. The builtins remain a fallback only used when OpenSSL does not provide them. @@ -4515,64 +5453,63 @@ Security Core and Builtins ----------------- -- gh-issue-92173: Fix the ``defs`` and ``kwdefs`` arguments to +- gh-92173: Fix the ``defs`` and ``kwdefs`` arguments to :c:func:`PyEval_EvalCodeEx` and a reference leak in that function. -- gh-issue-59956: The GILState API is now partially compatible with +- gh-59956: The GILState API is now partially compatible with subinterpreters. Previously, ``PyThreadState_GET()`` and ``PyGILState_GetThisThreadState()`` would get out of sync, causing inconsistent behavior and crashes. -- gh-issue-101400: Fix wrong lineno in exception message on - :keyword:`continue` or :keyword:`break` which are not in a loop. Patch by - Donghee Na. +- gh-101400: Fix wrong lineno in exception message on :keyword:`continue` or + :keyword:`break` which are not in a loop. Patch by Donghee Na. -- gh-issue-101372: Fix :func:`~unicodedata.is_normalized` to properly handle - the UCD 3.2.0 cases. Patch by Donghee Na. +- gh-101372: Fix :func:`~unicodedata.is_normalized` to properly handle the + UCD 3.2.0 cases. Patch by Donghee Na. -- gh-issue-101266: Fix :func:`sys.getsizeof` reporting for :class:`int` +- gh-101266: Fix :func:`sys.getsizeof` reporting for :class:`int` subclasses. -- gh-issue-101291: Refactor the ``PyLongObject`` struct into a normal Python +- gh-101291: Refactor the ``PyLongObject`` struct into a normal Python object header and a ``PyLongValue`` struct. -- gh-issue-101046: Fix a possible memory leak in the parser when raising +- gh-101046: Fix a possible memory leak in the parser when raising :exc:`MemoryError`. Patch by Pablo Galindo -- gh-issue-101037: Fix potential memory underallocation issue for instances - of :class:`int` subclasses with value zero. +- gh-101037: Fix potential memory underallocation issue for instances of + :class:`int` subclasses with value zero. -- gh-issue-100762: Record the (virtual) exception block depth in the oparg - of :opcode:`YIELD_VALUE`. Use this to avoid the expensive ``throw()`` when +- gh-100762: Record the (virtual) exception block depth in the oparg of + :opcode:`YIELD_VALUE`. Use this to avoid the expensive ``throw()`` when closing generators (and coroutines) that can be closed trivially. -- gh-issue-100982: Adds a new :opcode:`COMPARE_AND_BRANCH` instruction. This - is a bit more efficient when performing a comparison immediately followed - by a branch, and restores the design intent of PEP 659 that - specializations are local to a single instruction. +- gh-100982: Adds a new :opcode:`COMPARE_AND_BRANCH` instruction. This is a + bit more efficient when performing a comparison immediately followed by a + branch, and restores the design intent of PEP 659 that specializations are + local to a single instruction. -- gh-issue-100942: Fixed segfault in property.getter/setter/deleter that - occurred when a property subclass overrode the ``__new__`` method to - return a non-property instance. +- gh-100942: Fixed segfault in property.getter/setter/deleter that occurred + when a property subclass overrode the ``__new__`` method to return a + non-property instance. -- gh-issue-100923: Remove the ``mask`` cache entry for the - :opcode:`COMPARE_OP` instruction and embed the mask into the oparg. +- gh-100923: Remove the ``mask`` cache entry for the :opcode:`COMPARE_OP` + instruction and embed the mask into the oparg. -- gh-issue-100892: Fix race while iterating over thread states in clearing +- gh-100892: Fix race while iterating over thread states in clearing :class:`threading.local`. Patch by Kumar Aditya. -- gh-issue-91351: Fix a case where re-entrant imports could corrupt the - import deadlock detection code and cause a :exc:`KeyError` to be raised - out of :mod:`importlib/_bootstrap`. In addition to the straightforward - cases, this could also happen when garbage collection leads to a warning - being emitted -- as happens when it collects an open socket or file) +- gh-91351: Fix a case where re-entrant imports could corrupt the import + deadlock detection code and cause a :exc:`KeyError` to be raised out of + :mod:`importlib/_bootstrap`. In addition to the straightforward cases, + this could also happen when garbage collection leads to a warning being + emitted -- as happens when it collects an open socket or file) -- gh-issue-100726: Optimize construction of ``range`` object for medium size +- gh-100726: Optimize construction of ``range`` object for medium size integers. -- gh-issue-100712: Added option to build cpython with specialization - disabled, by setting ``ENABLE_SPECIALIZATION=False`` in :mod:`opcode`, - followed by ``make regen-all``. +- gh-100712: Added option to build cpython with specialization disabled, by + setting ``ENABLE_SPECIALIZATION=False`` in :mod:`opcode`, followed by + ``make regen-all``. - bpo-32780: Inter-field padding is now inserted into the PEP3118 format strings obtained from :class:`ctypes.Structure` objects, reflecting their @@ -4581,63 +5518,63 @@ Core and Builtins Library ------- -- gh-issue-101541: [Enum] - fix psuedo-flag creation +- gh-101541: [Enum] - fix psuedo-flag creation -- gh-issue-101570: Upgrade pip wheel bundled with ensurepip (pip 23.0) +- gh-101570: Upgrade pip wheel bundled with ensurepip (pip 23.0) -- gh-issue-101323: Fix a bug where errors where not thrown by +- gh-101323: Fix a bug where errors where not thrown by zlib._ZlibDecompressor if encountered during decompressing. -- gh-issue-101317: Add *ssl_shutdown_timeout* parameter for +- gh-101317: Add *ssl_shutdown_timeout* parameter for :meth:`asyncio.StreamWriter.start_tls`. -- gh-issue-101326: Fix regression when passing ``None`` as second or third +- gh-101326: Fix regression when passing ``None`` as second or third argument to ``FutureIter.throw``. -- gh-issue-92123: Adapt the ``_elementtree`` extension module to multi-phase - init (:pep:`489`). Patches by Erlend E. Aasland. +- gh-92123: Adapt the ``_elementtree`` extension module to multi-phase init + (:pep:`489`). Patches by Erlend E. Aasland. -- gh-issue-100795: Avoid potential unexpected ``freeaddrinfo`` call (double - free) in :mod:`socket` when when a libc ``getaddrinfo()`` implementation - leaves garbage in an output pointer when returning an error. Original - patch by Sergey G. Brester. +- gh-100795: Avoid potential unexpected ``freeaddrinfo`` call (double free) + in :mod:`socket` when when a libc ``getaddrinfo()`` implementation leaves + garbage in an output pointer when returning an error. Original patch by + Sergey G. Brester. -- gh-issue-101143: Remove unused references to :class:`~asyncio.TimerHandle` - in ``asyncio.base_events.BaseEventLoop._add_callback``. +- gh-101143: Remove unused references to :class:`~asyncio.TimerHandle` in + ``asyncio.base_events.BaseEventLoop._add_callback``. -- gh-issue-101144: Make :func:`zipfile.Path.open` and +- gh-101144: Make :func:`zipfile.Path.open` and :func:`zipfile.Path.read_text` also accept ``encoding`` as a positional argument. This was the behavior in Python 3.9 and earlier. 3.10 introduced a regression where supplying it as a positional argument would lead to a :exc:`TypeError`. -- gh-issue-94518: Group-related variables of ``_posixsubprocess`` module are +- gh-94518: Group-related variables of ``_posixsubprocess`` module are renamed to stress that supplimentary group affinity is added to a fork, not replace the inherited ones. Patch by Oleg Iarygin. -- gh-issue-101015: Fix :func:`typing.get_type_hints` on ``'*tuple[...]'`` - and ``*tuple[...]``. It must not drop the ``Unpack`` part. +- gh-101015: Fix :func:`typing.get_type_hints` on ``'*tuple[...]'`` and + ``*tuple[...]``. It must not drop the ``Unpack`` part. -- gh-issue-101000: Add :func:`os.path.splitroot()`, which splits a path into - a 3-item tuple ``(drive, root, tail)``. This new function is used by +- gh-101000: Add :func:`os.path.splitroot`, which splits a path into a + 3-item tuple ``(drive, root, tail)``. This new function is used by :mod:`pathlib` to improve the performance of path construction by up to a third. -- gh-issue-100573: Fix a Windows :mod:`asyncio` bug with named pipes where a +- gh-100573: Fix a Windows :mod:`asyncio` bug with named pipes where a client doing ``os.stat()`` on the pipe would cause an error in the server that disabled serving future requests. -- gh-issue-39615: :func:`warnings.warn` now has the ability to skip stack - frames based on code filename prefix rather than only a numeric - ``stacklevel`` via the new ``skip_file_prefixes`` keyword argument. +- gh-39615: :func:`warnings.warn` now has the ability to skip stack frames + based on code filename prefix rather than only a numeric ``stacklevel`` + via the new ``skip_file_prefixes`` keyword argument. -- gh-issue-100750: pass encoding kwarg to subprocess in platform +- gh-100750: pass encoding kwarg to subprocess in platform -- gh-issue-100160: Emit a deprecation warning in +- gh-100160: Emit a deprecation warning in :meth:`asyncio.DefaultEventLoopPolicy.get_event_loop` if there is no current event loop set and it decides to create one. -- gh-issue-96290: Fix handling of partial and invalid UNC drives in +- gh-96290: Fix handling of partial and invalid UNC drives in ``ntpath.splitdrive()``, and in ``ntpath.normpath()`` on non-Windows systems. Paths such as '\\server' and '\\' are now considered by ``splitdrive()`` to contain only a drive, and consequently are not @@ -4645,28 +5582,27 @@ Library ``normpath()`` on Windows systems is unaffected, as native OS APIs are used. Patch by Eryk Sun, with contributions by Barney Gale. -- gh-issue-99952: Fix a reference undercounting issue in - :class:`ctypes.Structure` with ``from_param()`` results larger than a C - pointer. +- gh-99952: Fix a reference undercounting issue in :class:`ctypes.Structure` + with ``from_param()`` results larger than a C pointer. -- gh-issue-67790: Add float-style formatting support for +- gh-67790: Add float-style formatting support for :class:`fractions.Fraction` instances. -- gh-issue-99266: Preserve more detailed error messages in :mod:`ctypes`. +- gh-99266: Preserve more detailed error messages in :mod:`ctypes`. -- gh-issue-86682: Ensure runtime-created collections have the correct module - name using the newly added (internal) :func:`sys._getframemodulename`. +- gh-86682: Ensure runtime-created collections have the correct module name + using the newly added (internal) :func:`sys._getframemodulename`. -- gh-issue-88597: :mod:`uuid` now has a command line interface. Try ``python - -m uuid -h``. +- gh-88597: :mod:`uuid` now has a command line interface. Try ``python -m + uuid -h``. -- gh-issue-60580: :data:`ctypes.wintypes.BYTE` definition changed from +- gh-60580: :data:`ctypes.wintypes.BYTE` definition changed from :data:`~ctypes.c_byte` to :data:`~ctypes.c_ubyte` to match Windows SDK. Patch by Anatoly Techtonik and Oleg Iarygin. -- gh-issue-94518: ``_posixsubprocess`` now initializes all UID and GID - variables using a reserved ``-1`` value instead of a separate flag. Patch - by Oleg Iarygin. +- gh-94518: ``_posixsubprocess`` now initializes all UID and GID variables + using a reserved ``-1`` value instead of a separate flag. Patch by Oleg + Iarygin. - bpo-38941: The :mod:`xml.etree.ElementTree` module now emits :exc:`DeprecationWarning` when testing the truth value of an @@ -4679,7 +5615,7 @@ Library - bpo-29847: Fix a bug where :class:`pathlib.Path` accepted and ignored keyword arguments. Patch provided by Yurii Karabas. -- gh-issue-77772: :class:`ctypes.CDLL`, :class:`ctypes.OleDLL`, +- gh-77772: :class:`ctypes.CDLL`, :class:`ctypes.OleDLL`, :class:`ctypes.WinDLL`, and :class:`ctypes.PyDLL` now accept :term:`path-like objects ` as their ``name`` argument. Patch by Robert Hoelzl. @@ -4687,75 +5623,74 @@ Library Documentation ------------- -- gh-issue-88324: Reword :mod:`subprocess` to emphasize default behavior of +- gh-88324: Reword :mod:`subprocess` to emphasize default behavior of *stdin*, *stdout*, and *stderr* arguments. Remove inaccurate statement about child file handle inheritance. Tests ----- -- gh-issue-101334: ``test_tarfile`` has been updated to pass when run as a - high UID. +- gh-101334: ``test_tarfile`` has been updated to pass when run as a high + UID. Build ----- -- gh-issue-101282: Update BOLT configuration not to use deprecated usage of +- gh-101282: Update BOLT configuration not to use deprecated usage of ``--split functions``. Patch by Donghee Na. -- gh-issue-101522: Allow overriding Windows dependencies versions and paths - using MSBuild properties. +- gh-101522: Allow overriding Windows dependencies versions and paths using + MSBuild properties. -- gh-issue-77532: Minor fixes to allow building with - ``PlatformToolset=ClangCL`` on Windows. +- gh-77532: Minor fixes to allow building with ``PlatformToolset=ClangCL`` + on Windows. -- gh-issue-101152: In accordance with :PEP:`699`, the ``ma_version_tag`` - field in :c:type:`PyDictObject` is deprecated for extension modules. - Accessing this field will generate a compiler warning at compile time. - This field will be removed in Python 3.14. +- gh-101152: In accordance with :PEP:`699`, the ``ma_version_tag`` field in + :c:type:`PyDictObject` is deprecated for extension modules. Accessing this + field will generate a compiler warning at compile time. This field will be + removed in Python 3.14. -- gh-issue-100340: Allows -Wno-int-conversion for wasm-sdk 17 and onwards, - thus enables building WASI builds once against the latest sdk. +- gh-100340: Allows -Wno-int-conversion for wasm-sdk 17 and onwards, thus + enables building WASI builds once against the latest sdk. -- gh-issue-101060: Conditionally add ``-fno-reorder-blocks-and-partition`` - in configure. Effectively fixes ``--enable-bolt`` when using Clang, as - this appears to be a GCC-only flag. +- gh-101060: Conditionally add ``-fno-reorder-blocks-and-partition`` in + configure. Effectively fixes ``--enable-bolt`` when using Clang, as this + appears to be a GCC-only flag. -- gh-issue-98705: ``__bool__`` is defined in AIX system header files which - breaks the build in AIX, so undefine it. +- gh-98705: ``__bool__`` is defined in AIX system header files which breaks + the build in AIX, so undefine it. -- gh-issue-98636: Fix a regression in detecting ``gdbm_compat`` library for - the ``_gdbm`` module build. +- gh-98636: Fix a regression in detecting ``gdbm_compat`` library for the + ``_gdbm`` module build. -- gh-issue-96305: ``_aix_support`` now uses a simple code to get platform - details rather than the now non-existent ``_bootsubprocess`` during - bootstrap. +- gh-96305: ``_aix_support`` now uses a simple code to get platform details + rather than the now non-existent ``_bootsubprocess`` during bootstrap. Windows ------- -- gh-issue-101543: Ensure the install path in the registry is only used when - the standard library hasn't been located in any other way. +- gh-101543: Ensure the install path in the registry is only used when the + standard library hasn't been located in any other way. -- gh-issue-101467: The ``py.exe`` launcher now correctly filters when only a +- gh-101467: The ``py.exe`` launcher now correctly filters when only a single runtime is installed. It also correctly handles prefix matches on tags so that ``-3.1`` does not match ``3.11``, but would still match ``3.1-32``. -- gh-issue-99834: Updates bundled copy of Tcl/Tk to 8.6.13.0 +- gh-99834: Updates bundled copy of Tcl/Tk to 8.6.13.0 -- gh-issue-101135: Restore ability to launch older 32-bit versions from the +- gh-101135: Restore ability to launch older 32-bit versions from the :file:`py.exe` launcher when both 32-bit and 64-bit installs of the same version are available. -- gh-issue-82052: Fixed an issue where writing more than 32K of Unicode - output to the console screen in one go can result in mojibake. +- gh-82052: Fixed an issue where writing more than 32K of Unicode output to + the console screen in one go can result in mojibake. -- gh-issue-100320: Ensures the ``PythonPath`` registry key from an install - is used when launching from a different copy of Python that relies on an - existing install to provide a copy of its modules and standard library. +- gh-100320: Ensures the ``PythonPath`` registry key from an install is used + when launching from a different copy of Python that relies on an existing + install to provide a copy of its modules and standard library. -- gh-issue-100247: Restores support for the :file:`py.exe` launcher finding +- gh-100247: Restores support for the :file:`py.exe` launcher finding shebang commands in its configuration file using the full command name. @@ -4767,114 +5702,107 @@ What's New in Python 3.12.0 alpha 4? Core and Builtins ----------------- -- gh-issue-100776: Fix misleading default value in :func:`input`'s +- gh-100776: Fix misleading default value in :func:`input`'s ``__text_signature__``. -- gh-issue-99005: Remove :opcode:`!UNARY_POSITIVE`, - :opcode:`!ASYNC_GEN_WRAP` and :opcode:`!LIST_TO_TUPLE`, replacing them - with intrinsics. +- gh-99005: Remove :opcode:`!UNARY_POSITIVE`, :opcode:`!ASYNC_GEN_WRAP` and + :opcode:`!LIST_TO_TUPLE`, replacing them with intrinsics. -- gh-issue-99005: Add new :opcode:`CALL_INTRINSIC_1` instruction. Remove +- gh-99005: Add new :opcode:`CALL_INTRINSIC_1` instruction. Remove :opcode:`IMPORT_STAR`, :opcode:`PRINT_EXPR` and :opcode:`STOPITERATION_ERROR`, replacing them with the :opcode:`CALL_INTRINSIC_1` instruction. -- gh-issue-100288: Remove the LOAD_ATTR_METHOD_WITH_DICT specialized - instruction. Stats show it is not useful. +- gh-100288: Remove the LOAD_ATTR_METHOD_WITH_DICT specialized instruction. + Stats show it is not useful. -- gh-issue-100720: Added ``_PyFrame_NumSlotsForCodeObject``, which returns - the number of slots needed in a frame for a given code object. +- gh-100720: Added ``_PyFrame_NumSlotsForCodeObject``, which returns the + number of slots needed in a frame for a given code object. -- gh-issue-100719: Removed the co_nplaincellvars field from the code object, - as it is redundant. +- gh-100719: Removed the co_nplaincellvars field from the code object, as it + is redundant. -- gh-issue-100637: Fix :func:`int.__sizeof__` calculation to include the - 1-element ``ob_digit`` array for ``0`` and ``False``. +- gh-100637: Fix :func:`int.__sizeof__` calculation to include the 1-element + ``ob_digit`` array for ``0`` and ``False``. -- gh-issue-100649: Update the native_thread_id field of PyThreadState after - fork. +- gh-100649: Update the native_thread_id field of PyThreadState after fork. -- gh-issue-100126: Fix an issue where "incomplete" frames could be briefly - visible to C code while other frames are being torn down, possibly - resulting in corruption or hard crashes of the interpreter while running - finalizers. +- gh-100126: Fix an issue where "incomplete" frames could be briefly visible + to C code while other frames are being torn down, possibly resulting in + corruption or hard crashes of the interpreter while running finalizers. -- gh-issue-87447: Fix :exc:`SyntaxError` on comprehension rebind checking - with names that are not actually redefined. +- gh-87447: Fix :exc:`SyntaxError` on comprehension rebind checking with + names that are not actually redefined. Now reassigning ``b`` in ``[(b := 1) for a, b.prop in some_iter]`` is allowed. Reassigning ``a`` is still disallowed as per :pep:`572`. -- gh-issue-100268: Add :meth:`int.is_integer` to improve duck type - compatibility between :class:`int` and :class:`float`. +- gh-100268: Add :meth:`int.is_integer` to improve duck type compatibility + between :class:`int` and :class:`float`. -- gh-issue-100425: Improve the accuracy of ``sum()`` with compensated - summation. +- gh-100425: Improve the accuracy of ``sum()`` with compensated summation. -- gh-issue-100374: Fix incorrect result and delay in :func:`socket.getfqdn`. - Patch by Dominic Socular. +- gh-100374: Fix incorrect result and delay in :func:`socket.getfqdn`. Patch + by Dominic Socular. -- gh-issue-100357: Convert ``vars``, ``dir``, ``next``, ``getattr``, and - ``iter`` to argument clinic. +- gh-100357: Convert ``vars``, ``dir``, ``next``, ``getattr``, and ``iter`` + to argument clinic. -- gh-issue-100117: Improve the output of :meth:`codeobject.co_lines` by - emitting only one entry for each line range. +- gh-100117: Improve the output of :meth:`codeobject.co_lines` by emitting + only one entry for each line range. -- gh-issue-90043: Handle NaNs when specializing :opcode:`COMPARE_OP` for +- gh-90043: Handle NaNs when specializing :opcode:`COMPARE_OP` for :class:`float` values. -- gh-issue-100222: Redefine the ``_Py_CODEUNIT`` typedef as a union to - describe its layout to the C compiler, avoiding type punning and improving - clarity. +- gh-100222: Redefine the ``_Py_CODEUNIT`` typedef as a union to describe + its layout to the C compiler, avoiding type punning and improving clarity. -- gh-issue-99955: Internal compiler functions (in compile.c) now - consistently return -1 on error and 0 on success. +- gh-99955: Internal compiler functions (in compile.c) now consistently + return -1 on error and 0 on success. -- gh-issue-100188: The ``BINARY_SUBSCR_LIST_INT`` and - ``BINARY_SUBSCR_TUPLE_INT`` instructions are no longer used for negative - integers because those instructions always miss when encountering negative - integers. +- gh-100188: The ``BINARY_SUBSCR_LIST_INT`` and ``BINARY_SUBSCR_TUPLE_INT`` + instructions are no longer used for negative integers because those + instructions always miss when encountering negative integers. -- gh-issue-99110: Initialize frame->previous in frameobject.c to fix a +- gh-99110: Initialize frame->previous in frameobject.c to fix a segmentation fault when accessing frames created by :c:func:`PyFrame_New`. -- gh-issue-94155: Improved the hashing algorithm for code objects, - mitigating some hash collisions. +- gh-94155: Improved the hashing algorithm for code objects, mitigating some + hash collisions. -- gh-issue-99540: ``None`` now hashes to a constant value. This is not a +- gh-99540: ``None`` now hashes to a constant value. This is not a requirements change. -- gh-issue-100143: When built with ``--enable-pystats``, stats collection is - now off by default. To enable it early at startup, pass the ``-Xpystats`` +- gh-100143: When built with ``--enable-pystats``, stats collection is now + off by default. To enable it early at startup, pass the ``-Xpystats`` flag. Stats are now always dumped, even if switched off. -- gh-issue-100146: Improve ``BUILD_LIST`` opcode so that it works similarly - to the ``BUILD_TUPLE`` opcode, by stealing references from the stack - rather than repeatedly using stack operations to set list elements. - Implementation details are in a new private API - :c:func:`_PyList_FromArraySteal`. +- gh-100146: Improve ``BUILD_LIST`` opcode so that it works similarly to the + ``BUILD_TUPLE`` opcode, by stealing references from the stack rather than + repeatedly using stack operations to set list elements. Implementation + details are in a new private API :c:func:`!_PyList_FromArraySteal`. -- gh-issue-100110: Specialize ``FOR_ITER`` for tuples. +- gh-100110: Specialize ``FOR_ITER`` for tuples. -- gh-issue-100050: Honor existing errors obtained when searching for - mismatching parentheses in the tokenizer. Patch by Pablo Galindo +- gh-100050: Honor existing errors obtained when searching for mismatching + parentheses in the tokenizer. Patch by Pablo Galindo -- gh-issue-92216: Improve the performance of :func:`hasattr` for type - objects with a missing attribute. +- gh-92216: Improve the performance of :func:`hasattr` for type objects with + a missing attribute. -- gh-issue-99582: Freeze :mod:`zipimport` module into ``_bootstrap_python``. +- gh-99582: Freeze :mod:`zipimport` module into ``_bootstrap_python``. -- gh-issue-99554: Pack debugging location tables more efficiently during - bytecode compilation. +- gh-99554: Pack debugging location tables more efficiently during bytecode + compilation. -- gh-issue-98522: Add an internal version number to code objects, to give - better versioning of inner functions and comprehensions, and thus better +- gh-98522: Add an internal version number to code objects, to give better + versioning of inner functions and comprehensions, and thus better specialization of those functions. This change is invisible to both Python and C extensions. -- gh-issue-94603: Improve performance of ``list.pop`` for small lists. +- gh-94603: Improve performance of ``list.pop`` for small lists. -- gh-issue-89051: Add :const:`ssl.OP_LEGACY_SERVER_CONNECT` +- gh-89051: Add :const:`ssl.OP_LEGACY_SERVER_CONNECT` - bpo-32782: ``ctypes`` arrays of length 0 now report a correct itemsize when a ``memoryview`` is constructed from them, rather than always giving @@ -4883,178 +5811,171 @@ Core and Builtins Library ------- -- gh-issue-100833: Speed up :func:`math.fsum` by removing defensive - ``volatile`` qualifiers. +- gh-100833: Speed up :func:`math.fsum` by removing defensive ``volatile`` + qualifiers. -- gh-issue-100805: Modify :func:`random.choice` implementation to once again - work with NumPy arrays. +- gh-100805: Modify :func:`random.choice` implementation to once again work + with NumPy arrays. -- gh-issue-100813: Add :const:`socket.IP_PKTINFO` constant. +- gh-100813: Add :const:`socket.IP_PKTINFO` constant. -- gh-issue-100792: Make :meth:`email.message.Message.__contains__` twice as - fast. +- gh-100792: Make :meth:`email.message.Message.__contains__` twice as fast. -- gh-issue-91851: Microoptimizations for - :meth:`fractions.Fraction.__round__`, :meth:`fractions.Fraction.__ceil__` - and :meth:`fractions.Fraction.__floor__`. +- gh-91851: Microoptimizations for :meth:`fractions.Fraction.__round__`, + :meth:`fractions.Fraction.__ceil__` and + :meth:`fractions.Fraction.__floor__`. -- gh-issue-90104: Avoid RecursionError on ``repr`` if a dataclass field - definition has a cyclic reference. +- gh-90104: Avoid RecursionError on ``repr`` if a dataclass field definition + has a cyclic reference. -- gh-issue-100689: Fix crash in :mod:`pyexpat` by statically allocating +- gh-100689: Fix crash in :mod:`pyexpat` by statically allocating ``PyExpat_CAPI`` capsule. -- gh-issue-100740: Fix ``unittest.mock.Mock`` not respecting the spec for +- gh-100740: Fix ``unittest.mock.Mock`` not respecting the spec for attribute names prefixed with ``assert``. -- gh-issue-91219: Change ``SimpleHTTPRequestHandler`` to support subclassing - to provide a different set of index file names instead of using - ``__init__`` parameters. +- gh-91219: Change ``SimpleHTTPRequestHandler`` to support subclassing to + provide a different set of index file names instead of using ``__init__`` + parameters. -- gh-issue-100690: ``Mock`` objects which are not unsafe will now raise an +- gh-100690: ``Mock`` objects which are not unsafe will now raise an ``AttributeError`` when accessing an attribute that matches the name of an assertion but without the prefix ``assert_``, e.g. accessing ``called_once`` instead of ``assert_called_once``. This is in addition to this already happening for accessing attributes with prefixes ``assert``, ``assret``, ``asert``, ``aseert``, and ``assrt``. -- gh-issue-89727: Simplify and optimize :func:`os.walk` by using +- gh-89727: Simplify and optimize :func:`os.walk` by using :func:`isinstance` checks to check the top of the stack. -- gh-issue-100485: Add math.sumprod() to compute the sum of products. +- gh-100485: Add math.sumprod() to compute the sum of products. -- gh-issue-86508: Fix :func:`asyncio.open_connection` to skip binding to - local addresses of different family. Patch by Kumar Aditya. +- gh-86508: Fix :func:`asyncio.open_connection` to skip binding to local + addresses of different family. Patch by Kumar Aditya. -- gh-issue-97930: ``importlib.resources.files`` now accepts a module as an - anchor instead of only accepting packages. If a module is passed, - resources are resolved adjacent to that module (in the same package or at - the package root). The parameter was renamed from ``package`` to - ``anchor`` with a compatibility shim for those passing by keyword. - Additionally, the new ``anchor`` parameter is now optional and will - default to the caller's module. +- gh-97930: ``importlib.resources.files`` now accepts a module as an anchor + instead of only accepting packages. If a module is passed, resources are + resolved adjacent to that module (in the same package or at the package + root). The parameter was renamed from ``package`` to ``anchor`` with a + compatibility shim for those passing by keyword. Additionally, the new + ``anchor`` parameter is now optional and will default to the caller's + module. -- gh-issue-100585: Fixed a bug where importlib.resources.as_file was leaving - file pointers open +- gh-100585: Fixed a bug where importlib.resources.as_file was leaving file + pointers open -- gh-issue-100562: Improve performance of :meth:`pathlib.Path.absolute` by - nearly 2x. This comes at the cost of a performance regression in +- gh-100562: Improve performance of :meth:`pathlib.Path.absolute` by nearly + 2x. This comes at the cost of a performance regression in :meth:`pathlib.Path.cwd`, which is generally used less frequently in user code. -- gh-issue-100519: Small simplification of - :func:`http.cookiejar.eff_request_host` that improves readability and - better matches the RFC wording. +- gh-100519: Small simplification of :func:`http.cookiejar.eff_request_host` + that improves readability and better matches the RFC wording. -- gh-issue-100287: Fix the interaction of :func:`unittest.mock.seal` with +- gh-100287: Fix the interaction of :func:`unittest.mock.seal` with :class:`unittest.mock.AsyncMock`. -- gh-issue-100488: Add :meth:`Fraction.is_integer` to check whether a +- gh-100488: Add :meth:`Fraction.is_integer` to check whether a :class:`fractions.Fraction` is an integer. This improves duck type compatibility with :class:`float` and :class:`int`. -- gh-issue-100474: :mod:`http.server` now checks that an index page is - actually a regular file before trying to serve it. This avoids issues - with directories named ``index.html``. +- gh-100474: :mod:`http.server` now checks that an index page is actually a + regular file before trying to serve it. This avoids issues with + directories named ``index.html``. -- gh-issue-100363: Speed up :func:`asyncio.get_running_loop` by removing - redundant ``getpid`` checks. Patch by Kumar Aditya. +- gh-100363: Speed up :func:`asyncio.get_running_loop` by removing redundant + ``getpid`` checks. Patch by Kumar Aditya. -- gh-issue-78878: Fix crash when creating an instance of - :class:`!_ctypes.CField`. +- gh-78878: Fix crash when creating an instance of :class:`!_ctypes.CField`. -- gh-issue-100348: Fix ref cycle in - :class:`!asyncio._SelectorSocketTransport` by removing ``_read_ready_cb`` - in ``close``. +- gh-100348: Fix ref cycle in :class:`!asyncio._SelectorSocketTransport` by + removing ``_read_ready_cb`` in ``close``. -- gh-issue-100344: Provide C implementation for :func:`asyncio.current_task` - for a 4x-6x speedup. +- gh-100344: Provide C implementation for :func:`asyncio.current_task` for a + 4x-6x speedup. -- gh-issue-100272: Fix JSON serialization of OrderedDict. It now preserves - the order of keys. +- gh-100272: Fix JSON serialization of OrderedDict. It now preserves the + order of keys. -- gh-issue-83076: Instantiation of ``Mock()`` and ``AsyncMock()`` is now - 3.8x faster. +- gh-83076: Instantiation of ``Mock()`` and ``AsyncMock()`` is now 3.8x + faster. -- gh-issue-100234: Set a default value of 1.0 for the ``lambd`` parameter in +- gh-100234: Set a default value of 1.0 for the ``lambd`` parameter in random.expovariate(). -- gh-issue-100228: A :exc:`DeprecationWarning` may be raised when - :func:`os.fork()` or :func:`os.forkpty()` is called from multi-threaded - processes. Forking with threads is unsafe and can cause deadlocks, - crashes and subtle problems. Lack of a warning does not indicate that the - fork call was actually safe, as Python may not be aware of all threads. +- gh-100228: A :exc:`DeprecationWarning` may be raised when :func:`os.fork` + or :func:`os.forkpty` is called from multi-threaded processes. Forking + with threads is unsafe and can cause deadlocks, crashes and subtle + problems. Lack of a warning does not indicate that the fork call was + actually safe, as Python may not be aware of all threads. -- gh-issue-100039: Improve signatures for enums and flags. +- gh-100039: Improve signatures for enums and flags. -- gh-issue-100133: Fix regression in :mod:`asyncio` where a subprocess would +- gh-100133: Fix regression in :mod:`asyncio` where a subprocess would sometimes lose data received from pipe. - bpo-44592: Fixes inconsistent handling of case sensitivity of *extrasaction* arg in :class:`csv.DictWriter`. -- gh-issue-100098: Fix ``tuple`` subclasses being cast to ``tuple`` when - used as enum values. +- gh-100098: Fix ``tuple`` subclasses being cast to ``tuple`` when used as + enum values. -- gh-issue-85432: Rename the *fmt* parameter of the pure-Python - implementation of :meth:`datetime.time.strftime` to *format*. Rename the - *t* parameter of :meth:`datetime.datetime.fromtimestamp` to *timestamp*. - These changes mean the parameter names in the pure-Python implementation - now match the parameter names in the C implementation. Patch by Alex - Waygood. +- gh-85432: Rename the *fmt* parameter of the pure-Python implementation of + :meth:`datetime.time.strftime` to *format*. Rename the *t* parameter of + :meth:`datetime.datetime.fromtimestamp` to *timestamp*. These changes mean + the parameter names in the pure-Python implementation now match the + parameter names in the C implementation. Patch by Alex Waygood. -- gh-issue-98778: Update :exc:`~urllib.error.HTTPError` to be initialized +- gh-98778: Update :exc:`~urllib.error.HTTPError` to be initialized properly, even if the ``fp`` is ``None``. Patch by Donghee Na. -- gh-issue-99925: Unify error messages in JSON serialization between +- gh-99925: Unify error messages in JSON serialization between ``json.dumps(float('nan'), allow_nan=False)`` and ``json.dumps(float('nan'), allow_nan=False, indent=)``. Now both include the representation of the value that could not be serialized. -- gh-issue-89727: Fix issue with :func:`os.walk` where a - :exc:`RecursionError` would occur on deep directory structures by - adjusting the implementation of :func:`os.walk` to be iterative instead of - recursive. +- gh-89727: Fix issue with :func:`os.walk` where a :exc:`RecursionError` + would occur on deep directory structures by adjusting the implementation + of :func:`os.walk` to be iterative instead of recursive. -- gh-issue-94943: Add :ref:`enum-dataclass-support` to the - :class:`~enum.Enum` :meth:`~enum.Enum.__repr__`. When inheriting from a +- gh-94943: Add :ref:`enum-dataclass-support` to the :class:`~enum.Enum` + :meth:`~enum.Enum.__repr__`. When inheriting from a :class:`~dataclasses.dataclass`, only show the field names in the value section of the member :func:`repr`, and not the dataclass' class name. -- gh-issue-83035: Fix :func:`inspect.getsource` handling of decorator calls - with nested parentheses. +- gh-83035: Fix :func:`inspect.getsource` handling of decorator calls with + nested parentheses. -- gh-issue-99576: Fix ``.save()`` method for ``LWPCookieJar`` and +- gh-99576: Fix ``.save()`` method for ``LWPCookieJar`` and ``MozillaCookieJar``: saved file was not truncated on repeated save. -- gh-issue-94912: Add :func:`inspect.markcoroutinefunction` decorator which +- gh-94912: Add :func:`inspect.markcoroutinefunction` decorator which manually marks a function as a coroutine for the benefit of :func:`iscoroutinefunction`. -- gh-issue-99509: Add :pep:`585` support for +- gh-99509: Add :pep:`585` support for :class:`multiprocessing.queues.Queue`. -- gh-issue-99482: Remove ``Jython`` partial compatibility code from several - stdlib modules. +- gh-99482: Remove ``Jython`` partial compatibility code from several stdlib + modules. -- gh-issue-99433: Fix :mod:`doctest` failure on - :class:`types.MethodWrapperType` in modules. +- gh-99433: Fix :mod:`doctest` failure on :class:`types.MethodWrapperType` + in modules. -- gh-issue-85267: Several improvements to :func:`inspect.signature`'s - handling of ``__text_signature``. - Fixes a case where - :func:`inspect.signature` dropped parameters - Fixes a case where - :func:`inspect.signature` raised :exc:`tokenize.TokenError` - Allows - :func:`inspect.signature` to understand defaults involving binary - operations of constants - :func:`inspect.signature` is documented as only - raising :exc:`TypeError` or :exc:`ValueError`, but sometimes raised - :exc:`RuntimeError`. These cases now raise :exc:`ValueError` - Removed a - dead code path +- gh-85267: Several improvements to :func:`inspect.signature`'s handling of + ``__text_signature``. - Fixes a case where :func:`inspect.signature` + dropped parameters - Fixes a case where :func:`inspect.signature` raised + :exc:`tokenize.TokenError` - Allows :func:`inspect.signature` to + understand defaults involving binary operations of constants - + :func:`inspect.signature` is documented as only raising :exc:`TypeError` + or :exc:`ValueError`, but sometimes raised :exc:`RuntimeError`. These + cases now raise :exc:`ValueError` - Removed a dead code path -- gh-issue-91166: :mod:`asyncio` is optimized to avoid excessive copying - when writing to socket and use :meth:`~socket.socket.sendmsg` if the - platform supports it. Patch by Kumar Aditya. +- gh-91166: :mod:`asyncio` is optimized to avoid excessive copying when + writing to socket and use :meth:`~socket.socket.sendmsg` if the platform + supports it. Patch by Kumar Aditya. -- gh-issue-98030: Add missing TCP socket options from Linux: ``TCP_MD5SIG``, +- gh-98030: Add missing TCP socket options from Linux: ``TCP_MD5SIG``, ``TCP_THIN_LINEAR_TIMEOUTS``, ``TCP_THIN_DUPACK``, ``TCP_REPAIR``, ``TCP_REPAIR_QUEUE``, ``TCP_QUEUE_SEQ``, ``TCP_REPAIR_OPTIONS``, ``TCP_TIMESTAMP``, ``TCP_CC_INFO``, ``TCP_SAVE_SYN``, ``TCP_SAVED_SYN``, @@ -5062,28 +5983,28 @@ Library ``TCP_MD5SIG_EXT``, ``TCP_FASTOPEN_KEY``, ``TCP_FASTOPEN_NO_COOKIE``, ``TCP_ZEROCOPY_RECEIVE``, ``TCP_INQ``, ``TCP_TX_DELAY``. -- gh-issue-88500: Reduced the memory usage of :func:`urllib.parse.unquote` - and :func:`urllib.parse.unquote_to_bytes` on large values. +- gh-88500: Reduced the memory usage of :func:`urllib.parse.unquote` and + :func:`urllib.parse.unquote_to_bytes` on large values. -- gh-issue-96127: ``inspect.signature`` was raising ``TypeError`` on call - with mock objects. Now it correctly returns ``(*args, **kwargs)`` as - inferred signature. +- gh-96127: ``inspect.signature`` was raising ``TypeError`` on call with + mock objects. Now it correctly returns ``(*args, **kwargs)`` as inferred + signature. -- gh-issue-95882: Fix a 3.11 regression in +- gh-95882: Fix a 3.11 regression in :func:`~contextlib.asynccontextmanager`, which caused it to propagate exceptions with incorrect tracebacks and fix a 3.11 regression in :func:`~contextlib.contextmanager`, which caused it to propagate exceptions with incorrect tracebacks for :exc:`StopIteration`. -- gh-issue-78707: Deprecate passing more than one positional argument to +- gh-78707: Deprecate passing more than one positional argument to :meth:`pathlib.PurePath.relative_to` and :meth:`~pathlib.PurePath.is_relative_to`. -- gh-issue-92122: Fix reStructuredText syntax errors in docstrings in the +- gh-92122: Fix reStructuredText syntax errors in docstrings in the :mod:`enum` module. -- gh-issue-91851: Optimize the :class:`~fractions.Fraction` arithmetics for - small components. +- gh-91851: Optimize the :class:`~fractions.Fraction` arithmetics for small + components. - bpo-24132: Make :class:`pathlib.PurePath` and :class:`~pathlib.Path` subclassable (private to start). Previously, attempting to instantiate a @@ -5101,10 +6022,10 @@ Library Documentation ------------- -- gh-issue-100616: Document existing ``attr`` parameter to +- gh-100616: Document existing ``attr`` parameter to :func:`curses.window.vline` function in :mod:`curses`. -- gh-issue-100472: Remove claim in documentation that the ``stripdir``, +- gh-100472: Remove claim in documentation that the ``stripdir``, ``prependdir`` and ``limit_sl_dest`` parameters of :func:`compileall.compile_dir` and :func:`compileall.compile_file` could be :class:`bytes`. @@ -5115,19 +6036,19 @@ Documentation Tests ----- -- gh-issue-100454: Start running SSL tests with OpenSSL 3.1.0-beta1. +- gh-100454: Start running SSL tests with OpenSSL 3.1.0-beta1. -- gh-issue-100086: The Python test runner (libregrtest) now logs Python - build information like "debug" vs "release" build, or LTO and PGO - optimizations. Patch by Victor Stinner. +- gh-100086: The Python test runner (libregrtest) now logs Python build + information like "debug" vs "release" build, or LTO and PGO optimizations. + Patch by Victor Stinner. -- gh-issue-93018: Make two tests forgiving towards host system libexpat with +- gh-93018: Make two tests forgiving towards host system libexpat with backported security fixes applied. Build ----- -- gh-issue-100540: Removed the ``--with-system-ffi`` ``configure`` option; +- gh-100540: Removed the ``--with-system-ffi`` ``configure`` option; ``libffi`` must now always be supplied by the system on all non-Windows platforms. The option has had no effect on non-Darwin platforms for several releases, and in 3.11 only had the non-obvious effect of invoking @@ -5136,8 +6057,8 @@ Build first check for the OS ``libffi`` and then fall back to the same processing as other platforms if it is not found. -- gh-issue-88267: Avoid exporting Python symbols in linked Windows - applications when the core is built as static. +- gh-88267: Avoid exporting Python symbols in linked Windows applications + when the core is built as static. - bpo-41916: Allow override of ac_cv_cxx_thread so that cross compiled python can set -pthread for CXX. @@ -5145,17 +6066,17 @@ Build Windows ------- -- gh-issue-100180: Update Windows installer to OpenSSL 1.1.1s +- gh-100180: Update Windows installer to OpenSSL 1.1.1s -- gh-issue-99191: Use ``_MSVC_LANG >= 202002L`` instead of less-precise - ``_MSC_VER >=1929`` to more accurately test for C++20 support in +- gh-99191: Use ``_MSVC_LANG >= 202002L`` instead of less-precise ``_MSC_VER + >=1929`` to more accurately test for C++20 support in :file:`PC/_wmimodule.cpp`. -- gh-issue-79218: Define ``MS_WIN64`` for Mingw-w64 64bit, fix cython - compilation failure. +- gh-79218: Define ``MS_WIN64`` for Mingw-w64 64bit, fix cython compilation + failure. -- gh-issue-99941: Ensure that :func:`asyncio.Protocol.data_received` - receives an immutable :class:`bytes` object (as documented), instead of +- gh-99941: Ensure that :func:`asyncio.Protocol.data_received` receives an + immutable :class:`bytes` object (as documented), instead of :class:`bytearray`. - bpo-43984: :meth:`winreg.SetValueEx` now leaves the target value untouched @@ -5168,9 +6089,9 @@ Windows macOS ----- -- gh-issue-100180: Update macOS installer to OpenSSL 1.1.1s +- gh-100180: Update macOS installer to OpenSSL 1.1.1s -- gh-issue-100540: Removed obsolete ``dlfcn.h`` shim from the ``_ctypes`` +- gh-100540: Removed obsolete ``dlfcn.h`` shim from the ``_ctypes`` extension module, which has not been necessary since Mac OS X 10.2. Tools/Demos @@ -5179,19 +6100,19 @@ Tools/Demos - bpo-45256: Fix a bug that caused an :exc:`AttributeError` to be raised in ``python-gdb.py`` when ``py-locals`` is used without a frame. -- gh-issue-100342: Add missing ``NULL`` check for possible allocation - failure in ``*args`` parsing in Argument Clinic. +- gh-100342: Add missing ``NULL`` check for possible allocation failure in + ``*args`` parsing in Argument Clinic. C API ----- -- gh-issue-99947: Raising SystemError on import will now have its cause be - set to the original unexpected exception. +- gh-99947: Raising SystemError on import will now have its cause be set to + the original unexpected exception. -- gh-issue-99240: In argument parsing, after deallocating newly allocated - memory, reset its pointer to NULL. +- gh-99240: In argument parsing, after deallocating newly allocated memory, + reset its pointer to NULL. -- gh-issue-98724: The :c:macro:`Py_CLEAR`, :c:macro:`Py_SETREF` and +- gh-98724: The :c:macro:`Py_CLEAR`, :c:macro:`Py_SETREF` and :c:macro:`Py_XSETREF` macros now only evaluate their arguments once. If an argument has side effects, these side effects are no longer duplicated. Patch by Victor Stinner. @@ -5205,75 +6126,74 @@ What's New in Python 3.12.0 alpha 3? Security -------- -- gh-issue-100001: ``python -m http.server`` no longer allows terminal - control characters sent within a garbage request to be printed to the - stderr server log. +- gh-100001: ``python -m http.server`` no longer allows terminal control + characters sent within a garbage request to be printed to the stderr + server log. This is done by changing the :mod:`http.server` :class:`BaseHTTPRequestHandler` ``.log_message`` method to replace control characters with a :samp:`\\x{HH}` hex escape before printing. -- gh-issue-87604: Avoid publishing list of active per-interpreter audit - hooks via the :mod:`gc` module +- gh-87604: Avoid publishing list of active per-interpreter audit hooks via + the :mod:`gc` module Core and Builtins ----------------- -- gh-issue-99891: Fix a bug in the tokenizer that could cause infinite - recursion when showing syntax warnings that happen in the first line of - the source. Patch by Pablo Galindo +- gh-99891: Fix a bug in the tokenizer that could cause infinite recursion + when showing syntax warnings that happen in the first line of the source. + Patch by Pablo Galindo -- gh-issue-91054: Add :c:func:`PyCode_AddWatcher` and +- gh-91054: Add :c:func:`PyCode_AddWatcher` and :c:func:`PyCode_ClearWatcher` APIs to register callbacks to receive notification on creation and destruction of code objects. -- gh-issue-99729: Fix an issue that could cause frames to be visible to - Python code as they are being torn down, possibly leading to memory - corruption or hard crashes of the interpreter. +- gh-99729: Fix an issue that could cause frames to be visible to Python + code as they are being torn down, possibly leading to memory corruption or + hard crashes of the interpreter. -- gh-issue-99708: Fix bug where compiler crashes on an if expression with an - empty body block. +- gh-99708: Fix bug where compiler crashes on an if expression with an empty + body block. -- gh-issue-99578: Fix a reference bug in :func:`_imp.create_builtin()` after - the creation of the first sub-interpreter for modules ``builtins`` and +- gh-99578: Fix a reference bug in :func:`!_imp.create_builtin` after the + creation of the first sub-interpreter for modules ``builtins`` and ``sys``. Patch by Victor Stinner. -- gh-issue-99581: Fixed a bug that was causing a buffer overflow if the - tokenizer copies a line missing the newline character from a file that is - as long as the available tokenizer buffer. Patch by Pablo galindo +- gh-99581: Fixed a bug that was causing a buffer overflow if the tokenizer + copies a line missing the newline character from a file that is as long as + the available tokenizer buffer. Patch by Pablo galindo -- gh-issue-99553: Fix bug where an :exc:`ExceptionGroup` subclass can wrap a +- gh-99553: Fix bug where an :exc:`ExceptionGroup` subclass can wrap a :exc:`BaseException`. -- gh-issue-99547: Add a function to os.path to check if a path is a - junction: isjunction. Add similar functionality to pathlib.Path as - is_junction. +- gh-99547: Add a function to os.path to check if a path is a junction: + isjunction. Add similar functionality to pathlib.Path as is_junction. -- gh-issue-99370: Fix zip path for venv created from a non-installed python - on POSIX platforms. +- gh-99370: Fix zip path for venv created from a non-installed python on + POSIX platforms. -- gh-issue-99377: Add audit events for thread creation and clear operations. +- gh-99377: Add audit events for thread creation and clear operations. -- gh-issue-98686: Remove the ``BINARY_OP_GENERIC`` and - ``COMPARE_OP_GENERIC`` "specializations". +- gh-98686: Remove the ``BINARY_OP_GENERIC`` and ``COMPARE_OP_GENERIC`` + "specializations". -- gh-issue-99298: Remove the remaining error paths for attribute - specializations, and refuse to specialize attribute accesses on types that - haven't had :c:func:`PyType_Ready` called on them yet. +- gh-99298: Remove the remaining error paths for attribute specializations, + and refuse to specialize attribute accesses on types that haven't had + :c:func:`PyType_Ready` called on them yet. -- gh-issue-99127: Allow some features of :mod:`syslog` to the main - interpreter only. Patch by Donghee Na. +- gh-99127: Allow some features of :mod:`syslog` to the main interpreter + only. Patch by Donghee Na. -- gh-issue-91053: Optimizing interpreters and JIT compilers may need to - invalidate internal metadata when functions are modified. This change adds - the ability to provide a callback that will be invoked each time a - function is created, modified, or destroyed. +- gh-91053: Optimizing interpreters and JIT compilers may need to invalidate + internal metadata when functions are modified. This change adds the + ability to provide a callback that will be invoked each time a function is + created, modified, or destroyed. -- gh-issue-90994: Improve error messages when there's a syntax error with - call arguments. The following three cases are covered: - No value is - assigned to a named argument, eg ``foo(a=)``. - A value is assigned to a - star argument, eg ``foo(*args=[0])``. - A value is assigned to a - double-star keyword argument, eg ``foo(**kwarg={'a': 0})``. +- gh-90994: Improve error messages when there's a syntax error with call + arguments. The following three cases are covered: - No value is assigned + to a named argument, eg ``foo(a=)``. - A value is assigned to a star + argument, eg ``foo(*args=[0])``. - A value is assigned to a double-star + keyword argument, eg ``foo(**kwarg={'a': 0})``. - bpo-45026: Optimize the :class:`range` object iterator. It is now smaller, faster iteration of ranges containing large numbers. Smaller pickles, @@ -5289,74 +6209,72 @@ Core and Builtins Library ------- -- gh-issue-100001: Also \ escape \s in the http.server +- gh-100001: Also \ escape \s in the http.server BaseHTTPRequestHandler.log_message so that it is technically possible to parse the line and reconstruct what the original data was. Without this a \xHH is ambiguious as to if it is a hex replacement we put in or the characters r"\x" came through in the original request line. -- gh-issue-99957: Add ``frozen_default`` parameter to +- gh-99957: Add ``frozen_default`` parameter to :func:`typing.dataclass_transform`. -- gh-issue-79033: Fix :func:`asyncio.Server.wait_closed` to actually do what - the docs promise -- wait for all existing connections to complete, after +- gh-79033: Fix :func:`asyncio.Server.wait_closed` to actually do what the + docs promise -- wait for all existing connections to complete, after closing the server. -- gh-issue-51524: Fix bug when calling trace.CoverageResults with valid - infile. +- gh-51524: Fix bug when calling trace.CoverageResults with valid infile. -- gh-issue-99645: Fix a bug in handling class cleanups in +- gh-99645: Fix a bug in handling class cleanups in :class:`unittest.TestCase`. Now ``addClassCleanup()`` uses separate lists for different ``TestCase`` subclasses, and ``doClassCleanups()`` only cleans up the particular class. -- gh-issue-99508: Fix ``TypeError`` in - ``Lib/importlib/_bootstrap_external.py`` while calling - ``_imp.source_hash()``. +- gh-99508: Fix ``TypeError`` in ``Lib/importlib/_bootstrap_external.py`` + while calling ``_imp.source_hash()``. -- gh-issue-66285: Fix :mod:`asyncio` to not share event loop and signal - wakeupfd in forked processes. Patch by Kumar Aditya. +- gh-66285: Fix :mod:`asyncio` to not share event loop and signal wakeupfd + in forked processes. Patch by Kumar Aditya. -- gh-issue-97001: Release the GIL when calling termios APIs to avoid - blocking threads. +- gh-97001: Release the GIL when calling termios APIs to avoid blocking + threads. -- gh-issue-92647: Use final status of an enum to determine lookup or - creation branch of functional API. +- gh-92647: Use final status of an enum to determine lookup or creation + branch of functional API. -- gh-issue-99388: Add *loop_factory* parameter to :func:`asyncio.run` to - allow specifying a custom event loop factory. Patch by Kumar Aditya. +- gh-99388: Add *loop_factory* parameter to :func:`asyncio.run` to allow + specifying a custom event loop factory. Patch by Kumar Aditya. -- gh-issue-99341: Fix :func:`ast.increment_lineno` to also cover +- gh-99341: Fix :func:`ast.increment_lineno` to also cover :class:`ast.TypeIgnore` when changing line numbers. -- gh-issue-99382: Check the number of arguments in substitution in user - generics containing a :class:`~typing.TypeVarTuple` and one or more +- gh-99382: Check the number of arguments in substitution in user generics + containing a :class:`~typing.TypeVarTuple` and one or more :class:`~typing.TypeVar`. -- gh-issue-99379: Fix substitution of :class:`~typing.ParamSpec` followed by +- gh-99379: Fix substitution of :class:`~typing.ParamSpec` followed by :class:`~typing.TypeVarTuple` in generic aliases. -- gh-issue-99344: Fix substitution of :class:`~typing.TypeVarTuple` and +- gh-99344: Fix substitution of :class:`~typing.TypeVarTuple` and :class:`~typing.ParamSpec` together in user generics. -- gh-issue-99284: Remove ``_use_broken_old_ctypes_structure_semantics_`` old +- gh-99284: Remove ``_use_broken_old_ctypes_structure_semantics_`` old untested and undocumented hack from :mod:`ctypes`. -- gh-issue-99201: Fix :exc:`IndexError` when initializing the config - variables on Windows if ``HAVE_DYNAMIC_LOADING`` is not set. +- gh-99201: Fix :exc:`IndexError` when initializing the config variables on + Windows if ``HAVE_DYNAMIC_LOADING`` is not set. -- gh-issue-99240: Fix double-free bug in Argument Clinic ``str_converter`` - by extracting memory clean up to a new ``post_parsing`` section. +- gh-99240: Fix double-free bug in Argument Clinic ``str_converter`` by + extracting memory clean up to a new ``post_parsing`` section. -- gh-issue-64490: Fix refcount error when arguments are packed to tuple in +- gh-64490: Fix refcount error when arguments are packed to tuple in Argument Clinic. -- gh-issue-99029: :meth:`pathlib.PurePath.relative_to()` now treats naked - Windows drive paths as relative. This brings its behaviour in line with - other parts of pathlib. +- gh-99029: :meth:`pathlib.PurePath.relative_to` now treats naked Windows + drive paths as relative. This brings its behaviour in line with other + parts of pathlib. -- gh-issue-98253: The implementation of the typing module is now more - resilient to reference leaks in binary extension modules. +- gh-98253: The implementation of the typing module is now more resilient to + reference leaks in binary extension modules. Previously, a reference leak in a typed C API-based extension module could leak internals of the typing module, which could in turn introduce leaks @@ -5366,12 +6284,12 @@ Library the implementation was therefore changed to reduce harm by providing better isolation. -- gh-issue-98458: Fix infinite loop in unittest when a self-referencing - chained exception is raised +- gh-98458: Fix infinite loop in unittest when a self-referencing chained + exception is raised -- gh-issue-93453: :func:`asyncio.get_event_loop` and many other - :mod:`asyncio` functions like :func:`asyncio.ensure_future`, - :func:`asyncio.shield` or :func:`asyncio.gather`, and also the +- gh-93453: :func:`asyncio.get_event_loop` and many other :mod:`asyncio` + functions like :func:`asyncio.ensure_future`, :func:`asyncio.shield` or + :func:`asyncio.gather`, and also the :meth:`~asyncio.BaseDefaultEventLoopPolicy.get_event_loop` method of :class:`asyncio.BaseDefaultEventLoopPolicy` now raise a :exc:`RuntimeError` if called when there is no running event loop and the @@ -5379,33 +6297,32 @@ Library a new current event loop. :exc:`DeprecationWarning` is no longer emitted if there is no running event loop but the current event loop was set. -- gh-issue-97966: On ``uname_result``, restored expectation that ``_fields`` - and ``_asdict`` would include all six properties including ``processor``. +- gh-97966: On ``uname_result``, restored expectation that ``_fields`` and + ``_asdict`` would include all six properties including ``processor``. -- gh-issue-98248: Provide informative error messages in :func:`struct.pack` - when its integral arguments are not in range. +- gh-98248: Provide informative error messages in :func:`struct.pack` when + its integral arguments are not in range. -- gh-issue-98108: ``zipfile.Path`` is now pickleable if its initialization +- gh-98108: ``zipfile.Path`` is now pickleable if its initialization parameters were pickleable (e.g. for file system paths). -- gh-issue-98098: Created packages from zipfile and test_zipfile modules, +- gh-98098: Created packages from zipfile and test_zipfile modules, separating ``zipfile.Path`` functionality. -- gh-issue-82836: Fix :attr:`~ipaddress.IPv4Address.is_private` properties - in the :mod:`ipaddress` module. Previously non-private networks - (0.0.0.0/0) would return ``True`` from this method; now they correctly - return ``False``. +- gh-82836: Fix :attr:`~ipaddress.IPv4Address.is_private` properties in the + :mod:`ipaddress` module. Previously non-private networks (0.0.0.0/0) would + return ``True`` from this method; now they correctly return ``False``. -- gh-issue-96828: Add an :const:`~ssl.OP_ENABLE_KTLS` option for enabling - the use of the kernel TLS (kTLS). Patch by Illia Volochii. +- gh-96828: Add an :const:`~ssl.OP_ENABLE_KTLS` option for enabling the use + of the kernel TLS (kTLS). Patch by Illia Volochii. -- gh-issue-88863: To avoid apparent memory leaks when +- gh-88863: To avoid apparent memory leaks when :func:`asyncio.open_connection` raises, break reference cycles generated by local exception and future instances (which has exception instance as its member var). Patch by Dong Uk, Kang. -- gh-issue-91078: :meth:`TarFile.next` now returns ``None`` when called on - an empty tarfile. +- gh-91078: :meth:`TarFile.next` now returns ``None`` when called on an + empty tarfile. - bpo-47220: Document the optional *callback* parameter of :class:`WeakMethod`. Patch by Géry Ogam. @@ -5423,18 +6340,18 @@ Library Documentation ------------- -- gh-issue-99931: Use `sphinxext-opengraph +- gh-99931: Use `sphinxext-opengraph `__ to generate `OpenGraph metadata `__. -- gh-issue-89682: Reworded docstring of the default ``__contains__`` to - clarify that it returns a :class:`bool`. +- gh-89682: Reworded docstring of the default ``__contains__`` to clarify + that it returns a :class:`bool`. -- gh-issue-88330: Improved the description of what a resource is in +- gh-88330: Improved the description of what a resource is in importlib.resources docs. -- gh-issue-92892: Document that calling variadic functions with ctypes - requires special care on macOS/arm64 (and possibly other platforms). +- gh-92892: Document that calling variadic functions with ctypes requires + special care on macOS/arm64 (and possibly other platforms). - bpo-41825: Restructured the documentation for the :func:`os.wait* ` family of functions, and improved the docs for @@ -5444,56 +6361,56 @@ Documentation Tests ----- -- gh-issue-99892: Skip test_normalization() of test_unicodedata if it fails - to download NormalizationTest.txt file from pythontest.net. Patch by - Victor Stinner. +- gh-99892: Skip test_normalization() of test_unicodedata if it fails to + download NormalizationTest.txt file from pythontest.net. Patch by Victor + Stinner. -- gh-issue-99934: Correct test_marsh on (32 bit) x86: test_deterministic - sets was failing. +- gh-99934: Correct test_marsh on (32 bit) x86: test_deterministic sets was + failing. -- gh-issue-99741: We've implemented multi-phase init (PEP 489/630/687) for - the internal (for testing) _xxsubinterpreters module. +- gh-99741: We've implemented multi-phase init (PEP 489/630/687) for the + internal (for testing) _xxsubinterpreters module. -- gh-issue-99659: Optional big memory tests in ``test_sqlite3`` now catch - the correct :exc:`sqlite.DataError` exception type in case of too large +- gh-99659: Optional big memory tests in ``test_sqlite3`` now catch the + correct :exc:`sqlite.DataError` exception type in case of too large strings and/or blobs passed. -- gh-issue-99593: Cover the Unicode C API with tests. +- gh-99593: Cover the Unicode C API with tests. -- gh-issue-96002: Add functional test for Argument Clinic. +- gh-96002: Add functional test for Argument Clinic. Build ----- -- gh-issue-99086: Fix ``-Wimplicit-int``, ``-Wstrict-prototypes``, and +- gh-99086: Fix ``-Wimplicit-int``, ``-Wstrict-prototypes``, and ``-Wimplicit-function-declaration`` compiler warnings in :program:`configure` checks. -- gh-issue-99337: Fix a compilation issue with GCC 12 on macOS. +- gh-99337: Fix a compilation issue with GCC 12 on macOS. -- gh-issue-99289: Add a ``COMPILEALL_OPTS`` variable in Makefile to override +- gh-99289: Add a ``COMPILEALL_OPTS`` variable in Makefile to override :mod:`compileall` options (default: ``-j0``) in ``make install``. Also merged the ``compileall`` commands into a single command building .pyc files for the all optimization levels (0, 1, 2) at once. Patch by Victor Stinner. -- gh-issue-98872: Fix a possible fd leak in ``Programs/_freeze_module.c`` +- gh-98872: Fix a possible fd leak in ``Programs/_freeze_module.c`` introduced in Python 3.11. -- gh-issue-88226: Always define ``TARGET_*`` labels in ``Python/ceval.c``, - even if ``USE_COMPUTED_GOTOS`` is disabled. This allows breakpoints to be - set at those labels in (for instance) ``gdb``. +- gh-88226: Always define ``TARGET_*`` labels in ``Python/ceval.c``, even if + ``USE_COMPUTED_GOTOS`` is disabled. This allows breakpoints to be set at + those labels in (for instance) ``gdb``. Windows ------- -- gh-issue-99345: Use faster initialization functions to detect install - location for Windows Store package +- gh-99345: Use faster initialization functions to detect install location + for Windows Store package -- gh-issue-98629: Fix initialization of :data:`sys.version` and ``sys._git`` - on Windows +- gh-98629: Fix initialization of :data:`sys.version` and ``sys._git`` on + Windows -- gh-issue-99442: Fix handling in :ref:`launcher` when ``argv[0]`` does not +- gh-99442: Fix handling in :ref:`launcher` when ``argv[0]`` does not include a file extension. - bpo-40882: Fix a memory leak in @@ -5502,15 +6419,15 @@ Windows macOS ----- -- gh-issue-87235: On macOS ``python3 /dev/fd/9 9` with - unhashable exceptions. +- gh-99181: Fix failure in :keyword:`except* ` with unhashable + exceptions. -- gh-issue-99204: Fix calculation of :data:`sys._base_executable` when - inside a POSIX virtual environment using copies of the python binary when - the base installation does not provide the executable name used by the - venv. Calculation will fall back to alternative names ("python", +- gh-99204: Fix calculation of :data:`sys._base_executable` when inside a + POSIX virtual environment using copies of the python binary when the base + installation does not provide the executable name used by the venv. + Calculation will fall back to alternative names ("python", "python."). -- gh-issue-96055: Update :mod:`faulthandler` to emit an error message with - the proper unexpected signal number. Patch by Donghee Na. +- gh-96055: Update :mod:`faulthandler` to emit an error message with the + proper unexpected signal number. Patch by Donghee Na. -- gh-issue-99153: Fix location of :exc:`SyntaxError` for a :keyword:`try` - block with both :keyword:`except` and :keyword:`except* `. +- gh-99153: Fix location of :exc:`SyntaxError` for a :keyword:`try` block + with both :keyword:`except` and :keyword:`except* `. -- gh-issue-98686: Merge the adaptive opcode logic into each instruction's +- gh-98686: Merge the adaptive opcode logic into each instruction's unquickened variant, and merge the logic in ``EXTENDED_ARG_QUICK`` into :opcode:`EXTENDED_ARG`. With these changes, the quickening that happens at code object creation is now only responsible for initializing warmup counters and inserting superinstructions. -- gh-issue-99103: Fix the error reporting positions of specialized traceback +- gh-99103: Fix the error reporting positions of specialized traceback anchors when the source line contains Unicode characters. -- gh-issue-99139: Improve the error suggestion for :exc:`NameError` - exceptions for instances. Now if a :exc:`NameError` is raised in a method - and the instance has an attribute that's exactly equal to the name in the +- gh-99139: Improve the error suggestion for :exc:`NameError` exceptions for + instances. Now if a :exc:`NameError` is raised in a method and the + instance has an attribute that's exactly equal to the name in the exception, the suggestion will include ``self.`` instead of the closest match in the method scope. Patch by Pablo Galindo -- gh-issue-98401: Octal escapes with value larger than ``0o377`` (ex: - ``"\477"``), deprecated in Python 3.11, now produce a - :exc:`SyntaxWarning`, instead of :exc:`DeprecationWarning`. In a future - Python version they will be eventually a :exc:`SyntaxError`. Patch by - Victor Stinner. +- gh-98401: Octal escapes with value larger than ``0o377`` (ex: ``"\477"``), + deprecated in Python 3.11, now produce a :exc:`SyntaxWarning`, instead of + :exc:`DeprecationWarning`. In a future Python version they will be + eventually a :exc:`SyntaxError`. Patch by Victor Stinner. -- gh-issue-98401: A backslash-character pair that is not a valid escape - sequence now generates a :exc:`SyntaxWarning`, instead of +- gh-98401: A backslash-character pair that is not a valid escape sequence + now generates a :exc:`SyntaxWarning`, instead of :exc:`DeprecationWarning`. For example, ``re.compile("\d+\.\d+")`` now emits a :exc:`SyntaxWarning` (``"\d"`` is an invalid escape sequence), use raw strings for regular expression: ``re.compile(r"\d+\.\d+")``. In a future Python version, :exc:`SyntaxError` will eventually be raised, instead of :exc:`SyntaxWarning`. Patch by Victor Stinner. -- gh-issue-96793: Handle StopIteration and StopAsyncIteration raised in - generator or coroutines in the bytecode, rather than in wrapping C code. +- gh-96793: Handle StopIteration and StopAsyncIteration raised in generator + or coroutines in the bytecode, rather than in wrapping C code. -- gh-issue-98931: Improve the :exc:`SyntaxError` error message when the user - types ``import x from y`` instead of ``from y import x``. Patch by Pablo - Galindo +- gh-98931: Improve the :exc:`SyntaxError` error message when the user types + ``import x from y`` instead of ``from y import x``. Patch by Pablo Galindo -- gh-issue-98852: Fix subscription of type aliases containing bare generic - types or types like :class:`~typing.TypeVar`: for example ``tuple[A, - T][int]`` and ``tuple[TypeVar, T][int]``, where ``A`` is a generic type, - and ``T`` is a type variable. +- gh-98852: Fix subscription of type aliases containing bare generic types + or types like :class:`~typing.TypeVar`: for example ``tuple[A, T][int]`` + and ``tuple[TypeVar, T][int]``, where ``A`` is a generic type, and ``T`` + is a type variable. -- gh-issue-98925: Lower the recursion depth for marshal on WASI to support +- gh-98925: Lower the recursion depth for marshal on WASI to support (in-development) wasmtime 2.0. -- gh-issue-98783: Fix multiple crashes in debug mode when ``str`` subclasses - are used instead of ``str`` itself. +- gh-98783: Fix multiple crashes in debug mode when ``str`` subclasses are + used instead of ``str`` itself. -- gh-issue-98811: Use complete source locations to simplify detection of +- gh-98811: Use complete source locations to simplify detection of ``__future__`` imports which are not at the beginning of the file. Also corrects the offset in the exception raised in one case, which was off by one and impeded highlighting. -- gh-issue-96793: Add specialization of :opcode:`FOR_ITER` for generators. - Saves multiple layers of dispatch and checking to get from the +- gh-96793: Add specialization of :opcode:`FOR_ITER` for generators. Saves + multiple layers of dispatch and checking to get from the :opcode:`FOR_ITER` instruction in the caller to the :opcode:`RESUME` in the generator. -- gh-issue-98762: Fix source locations of :keyword:`match` sub-patterns. +- gh-98762: Fix source locations of :keyword:`match` sub-patterns. -- gh-issue-98586: Added the methods :c:func:`PyObject_Vectorcall` and +- gh-98586: Added the methods :c:func:`PyObject_Vectorcall` and :c:func:`PyObject_VectorcallMethod` to the :ref:`Limited API ` along with the auxiliary macro constant :c:macro:`PY_VECTORCALL_ARGUMENTS_OFFSET`. @@ -5667,17 +6581,17 @@ Core and Builtins vector calls from binary extension modules that avoid argument boxing/unboxing overheads. -- gh-issue-99257: Fix an issue where member descriptors (such as those for +- gh-99257: Fix an issue where member descriptors (such as those for :attr:`~object.__slots__`) could behave incorrectly or crash instead of raising a :exc:`TypeError` when accessed via an instance of an invalid type. -- gh-issue-93143: Rather than changing :attr:`~types.CodeType.co_code`, the +- gh-93143: Rather than changing :attr:`~types.CodeType.co_code`, the interpreter will now display a :exc:`RuntimeWarning` and assign :const:`None` to any fast locals that are left unbound after jumps or :keyword:`del` statements executed while tracing. -- gh-issue-96421: When calling into Python code from C code, through +- gh-96421: When calling into Python code from C code, through :c:func:`PyEval_EvalFrameEx` or a related C-API function, a shim frame in inserted into the call stack. This occurs in the ``_PyEval_EvalFrameDefault()`` function. The extra frame should be @@ -5690,156 +6604,153 @@ Core and Builtins :opcode:`RETURN_VALUE`, :opcode:`YIELD_VALUE`, and :opcode:`RETURN_GENERATOR`, which now clear the frame. -- gh-issue-98415: Fix detection of MAC addresses for :mod:`uuid` on certain - OSs. Patch by Chaim Sanders +- gh-98415: Fix detection of MAC addresses for :mod:`uuid` on certain OSs. + Patch by Chaim Sanders -- gh-issue-98686: Quicken all code objects, and specialize adaptive bytecode +- gh-98686: Quicken all code objects, and specialize adaptive bytecode instructions more aggressively. -- gh-issue-92119: Print exception class name instead of its string - representation when raising errors from :mod:`ctypes` calls. +- gh-92119: Print exception class name instead of its string representation + when raising errors from :mod:`ctypes` calls. -- gh-issue-91058: :exc:`ImportError` raised from failed ``from - import `` now include suggestions for the value of ```` based - on the available names in ````. Patch by Pablo Galindo +- gh-91058: :exc:`ImportError` raised from failed ``from import + `` now include suggestions for the value of ```` based on the + available names in ````. Patch by Pablo Galindo -- gh-issue-96793: The :opcode:`FOR_ITER` now leaves the iterator on the - stack on termination of the loop. This is to assist specialization of - loops for generators. +- gh-96793: The :opcode:`FOR_ITER` now leaves the iterator on the stack on + termination of the loop. This is to assist specialization of loops for + generators. -- gh-issue-90716: Add _pylong.py module. It includes asymptotically faster +- gh-90716: Add _pylong.py module. It includes asymptotically faster algorithms that can be used for operations on integers with many digits. It is used by longobject.c to speed up some operations. -- gh-issue-95389: Expose :const:`~socket.ETH_P_ALL` and some of the +- gh-95389: Expose :const:`~socket.ETH_P_ALL` and some of the :ref:`ETHERTYPE_* constants ` in :mod:`socket`. Patch by Noam Cohen. -- gh-issue-93696: Allow :mod:`pdb` to locate source for frozen modules in - the standard library. +- gh-93696: Allow :mod:`pdb` to locate source for frozen modules in the + standard library. Library ------- -- gh-issue-99418: Fix bug in :func:`urllib.parse.urlparse` that causes URL - schemes that begin with a digit, a plus sign, or a minus sign to be parsed +- gh-99418: Fix bug in :func:`urllib.parse.urlparse` that causes URL schemes + that begin with a digit, a plus sign, or a minus sign to be parsed incorrectly. -- gh-issue-94597: Deprecate :class:`asyncio.AbstractChildWatcher` to be - removed in Python 3.14. Patch by Kumar Aditya. +- gh-94597: Deprecate :class:`asyncio.AbstractChildWatcher` to be removed in + Python 3.14. Patch by Kumar Aditya. -- gh-issue-99305: Improve performance of :func:`secrets.token_hex`. +- gh-99305: Improve performance of :func:`secrets.token_hex`. -- gh-issue-74044: Fixed bug where :func:`inspect.signature` reported - incorrect arguments for decorated methods. +- gh-74044: Fixed bug where :func:`inspect.signature` reported incorrect + arguments for decorated methods. -- gh-issue-99275: Fix ``SystemError`` in :mod:`ctypes` when exception was - not set during ``__initsubclass__``. +- gh-99275: Fix ``SystemError`` in :mod:`ctypes` when exception was not set + during ``__initsubclass__``. -- gh-issue-99277: Remove older version of +- gh-99277: Remove older version of ``_SSLProtocolTransport.get_write_buffer_limits`` in :mod:`!asyncio.sslproto` -- gh-issue-99248: fix negative numbers failing in verify() +- gh-99248: fix negative numbers failing in verify() -- gh-issue-99155: Fix :class:`statistics.NormalDist` pickle with ``0`` and - ``1`` protocols. +- gh-99155: Fix :class:`statistics.NormalDist` pickle with ``0`` and ``1`` + protocols. -- gh-issue-93464: ``enum.auto()`` is now correctly activated when combined - with other assignment values. E.g. ``ONE = auto(), 'some text'`` will now +- gh-93464: ``enum.auto()`` is now correctly activated when combined with + other assignment values. E.g. ``ONE = auto(), 'some text'`` will now evaluate as ``(1, 'some text')``. -- gh-issue-99134: Update the bundled copy of pip to version 22.3.1. +- gh-99134: Update the bundled copy of pip to version 22.3.1. -- gh-issue-92584: Remove the ``distutils`` package. It was deprecated in - Python 3.10 by :pep:`632` "Deprecate distutils module". For projects still - using ``distutils`` and cannot be updated to something else, the - ``setuptools`` project can be installed: it still provides ``distutils``. - Patch by Victor Stinner. +- gh-92584: Remove the ``distutils`` package. It was deprecated in Python + 3.10 by :pep:`632` "Deprecate distutils module". For projects still using + ``distutils`` and cannot be updated to something else, the ``setuptools`` + project can be installed: it still provides ``distutils``. Patch by Victor + Stinner. -- gh-issue-98999: Now :mod:`_pyio` is consistent with :mod:`_io` in raising +- gh-98999: Now :mod:`!_pyio` is consistent with :mod:`!_io` in raising ``ValueError`` when executing methods over closed buffers. -- gh-issue-83004: Clean up refleak on failed module initialisation in - :mod:`_zoneinfo` +- gh-83004: Clean up refleak on failed module initialisation in + :mod:`!_zoneinfo` -- gh-issue-83004: Clean up refleaks on failed module initialisation in - :mod:`_pickle` +- gh-83004: Clean up refleaks on failed module initialisation in + :mod:`!_pickle` -- gh-issue-83004: Clean up refleak on failed module initialisation in - :mod:`_io`. +- gh-83004: Clean up refleak on failed module initialisation in :mod:`!_io`. -- gh-issue-98897: Fix memory leak in :func:`math.dist` when both points - don't have the same dimension. Patch by Kumar Aditya. +- gh-98897: Fix memory leak in :func:`math.dist` when both points don't have + the same dimension. Patch by Kumar Aditya. -- gh-issue-98878: Use the frame bound builtins when offering a name - suggestion in :mod:`traceback` to prevent crashing when ``__builtins__`` - is not a dict. +- gh-98878: Use the frame bound builtins when offering a name suggestion in + :mod:`traceback` to prevent crashing when ``__builtins__`` is not a dict. -- gh-issue-98139: In :mod:`importlib._bootstrap`, enhance namespace package - repr to ````. +- gh-98139: In :mod:`importlib._bootstrap`, enhance namespace package repr + to ````. -- gh-issue-90352: Fix ``_SelectorDatagramTransport`` to inherit from +- gh-90352: Fix ``_SelectorDatagramTransport`` to inherit from :class:`~asyncio.DatagramTransport` in :mod:`asyncio`. Patch by Kumar Aditya. -- gh-issue-98793: Fix argument typechecks in :func:`!_overlapped.WSAConnect` - and :func:`!_overlapped.Overlapped.WSASendTo` functions. +- gh-98793: Fix argument typechecks in :func:`!_overlapped.WSAConnect` and + :func:`!_overlapped.Overlapped.WSASendTo` functions. -- gh-issue-98744: Prevent crashing in :mod:`traceback` when retrieving the +- gh-98744: Prevent crashing in :mod:`traceback` when retrieving the byte-offset for some source files that contain certain unicode characters. -- gh-issue-98740: Fix internal error in the :mod:`re` module which in very - rare circumstances prevented compilation of a regular expression - containing a :ref:`conditional expression ` - without the "else" branch. +- gh-98740: Fix internal error in the :mod:`re` module which in very rare + circumstances prevented compilation of a regular expression containing a + :ref:`conditional expression ` without the + "else" branch. -- gh-issue-98703: Fix :meth:`asyncio.StreamWriter.drain` to call +- gh-98703: Fix :meth:`asyncio.StreamWriter.drain` to call ``protocol.connection_lost`` callback only once on Windows. -- gh-issue-98624: Add a mutex to unittest.mock.NonCallableMock to protect +- gh-98624: Add a mutex to unittest.mock.NonCallableMock to protect concurrent access to mock attributes. -- gh-issue-98658: The :class:`array.array` class now supports subscripting, - making it a :term:`generic type`. +- gh-98658: The :class:`array.array` class now supports subscripting, making + it a :term:`generic type`. -- gh-issue-98284: Improved :class:`TypeError` message for undefined abstract +- gh-98284: Improved :class:`TypeError` message for undefined abstract methods of a :class:`abc.ABC` instance. The names of the missing methods are surrounded by single-quotes to highlight them. -- gh-issue-96151: Allow ``BUILTINS`` to be a valid field name for frozen +- gh-96151: Allow ``BUILTINS`` to be a valid field name for frozen dataclasses. -- gh-issue-98086: Make sure ``patch.dict()`` can be applied on async - functions. +- gh-98086: Make sure ``patch.dict()`` can be applied on async functions. -- gh-issue-72719: Remove modules :mod:`!asyncore` and :mod:`!asynchat`, - which were deprecated by :pep:`594`. +- gh-72719: Remove modules :mod:`!asyncore` and :mod:`!asynchat`, which were + deprecated by :pep:`594`. -- gh-issue-96192: Fix handling of ``bytes`` :term:`path-like objects - ` in :func:`os.ismount()`. +- gh-96192: Fix handling of ``bytes`` :term:`path-like objects ` in :func:`os.ismount`. -- gh-issue-94172: :mod:`ftplib`: Remove the ``FTP_TLS.ssl_version`` class +- gh-94172: :mod:`ftplib`: Remove the ``FTP_TLS.ssl_version`` class attribute: use the *context* parameter instead. Patch by Victor Stinner -- gh-issue-94172: Remove the *keyfile* and *certfile* parameters from the +- gh-94172: Remove the *keyfile* and *certfile* parameters from the :mod:`ftplib`, :mod:`imaplib`, :mod:`poplib` and :mod:`smtplib` modules, and the *key_file*, *cert_file* and *check_hostname* parameters from the :mod:`http.client` module, all deprecated since Python 3.6. Use the *context* parameter (*ssl_context* in :mod:`imaplib`) instead. Patch by Victor Stinner. -- gh-issue-83638: Add the :attr:`~sqlite3.Connection.autocommit` attribute - to :class:`sqlite3.Connection` and the *autocommit* parameter to +- gh-83638: Add the :attr:`~sqlite3.Connection.autocommit` attribute to + :class:`sqlite3.Connection` and the *autocommit* parameter to :func:`sqlite3.connect` to control :pep:`249`-compliant :ref:`transaction handling `. Patch by Erlend E. Aasland. -- gh-issue-92452: Fixed a race condition that could cause +- gh-92452: Fixed a race condition that could cause :func:`sysconfig.get_config_var` to incorrectly return :const:`None` in multi-threaded programs. -- gh-issue-91803: Fix an error when using a method of objects mocked with +- gh-91803: Fix an error when using a method of objects mocked with :func:`unittest.mock.create_autospec` after it was sealed with :func:`unittest.mock.seal` function. @@ -5854,26 +6765,25 @@ Library Documentation ------------- -- gh-issue-98832: Changes wording of docstring for - :func:`pathlib.Path.iterdir`. +- gh-98832: Changes wording of docstring for :func:`pathlib.Path.iterdir`. -- gh-issue-97966: Update uname docs to clarify the special nature of the - platform attribute and to indicate when it became late-bound. +- gh-97966: Update uname docs to clarify the special nature of the platform + attribute and to indicate when it became late-bound. Tests ----- -- gh-issue-98903: The Python test suite now fails with exit code 4 if no - tests ran. It should help detecting typos in test names and test methods. +- gh-98903: The Python test suite now fails with exit code 4 if no tests + ran. It should help detecting typos in test names and test methods. -- gh-issue-98713: Fix a bug in the :mod:`typing` tests where a test relying - on CPython-specific implementation details was not decorated with +- gh-98713: Fix a bug in the :mod:`typing` tests where a test relying on + CPython-specific implementation details was not decorated with ``@cpython_only`` and was not skipped on other implementations. -- gh-issue-87390: Add tests for star-unpacking with PEP 646, and some other +- gh-87390: Add tests for star-unpacking with PEP 646, and some other miscellaneous PEP 646 tests. -- gh-issue-96853: Added explicit coverage of ``Py_Initialize`` (and hence +- gh-96853: Added explicit coverage of ``Py_Initialize`` (and hence ``Py_InitializeEx``) back to the embedding tests (all other embedding tests migrated to ``Py_InitializeFromConfig`` in Python 3.11) @@ -5883,22 +6793,21 @@ Tests Build ----- -- gh-issue-99086: Fix ``-Wimplicit-int`` compiler warning in - :program:`configure` check for ``PTHREAD_SCOPE_SYSTEM``. +- gh-99086: Fix ``-Wimplicit-int`` compiler warning in :program:`configure` + check for ``PTHREAD_SCOPE_SYSTEM``. -- gh-issue-99016: Fix build with ``PYTHON_FOR_REGEN=python3.8``. +- gh-99016: Fix build with ``PYTHON_FOR_REGEN=python3.8``. -- gh-issue-97731: Specify the full path to the source location for ``make +- gh-97731: Specify the full path to the source location for ``make docclean`` (needed for cross-builds). -- gh-issue-98949: Drop unused build dependency on ``readelf``. +- gh-98949: Drop unused build dependency on ``readelf``. -- gh-issue-98989: Use ``python3.11``, if available, for regeneration and - freezing. +- gh-98989: Use ``python3.11``, if available, for regeneration and freezing. -- gh-issue-98831: Add new tooling, in ``Tools/cases_generator``, to generate - the interpreter switch statement from a list of opcode definitions. This - only affects adding, modifying or removing instruction definitions. The +- gh-98831: Add new tooling, in ``Tools/cases_generator``, to generate the + interpreter switch statement from a list of opcode definitions. This only + affects adding, modifying or removing instruction definitions. The instruction definitions now live in ``Python/bytecodes.c``, in the form of a `custom DSL (under development) `__. @@ -5906,15 +6815,13 @@ Build which is then included by ``Python/ceval.c`` to provide most of the cases of the main interpreter switch. -- gh-issue-98817: Remove PCbuild/lib.pyproj: it's not used for anything, is - only a minor convenience for Visual Studio users (who probably mostly - don't even know about it), and it takes a lot of maintenance effort to - keep updated. +- gh-98817: Remove PCbuild/lib.pyproj: it's not used for anything, is only a + minor convenience for Visual Studio users (who probably mostly don't even + know about it), and it takes a lot of maintenance effort to keep updated. -- gh-issue-98776: Fix ``make regen-test-levenshtein`` for out-of-tree - builds. +- gh-98776: Fix ``make regen-test-levenshtein`` for out-of-tree builds. -- gh-issue-98707: Don't use vendored ``libmpdec`` headers if +- gh-98707: Don't use vendored ``libmpdec`` headers if :option:`--with-system-libmpdec` is passed to :program:`configure`. Don't use vendored ``libexpat`` headers if :option:`--with-system-expat` is passed to :program:`configure`. @@ -5922,64 +6829,63 @@ Build Windows ------- -- gh-issue-98689: Update Windows builds to zlib v1.2.13. v1.2.12 has +- gh-98689: Update Windows builds to zlib v1.2.13. v1.2.12 has :cve:`2022-37434`, but the vulnerable ``inflateGetHeader`` API is not used by Python. -- gh-issue-98790: Assumes that a missing ``DLLs`` directory means that - standard extension modules are in the executable's directory. +- gh-98790: Assumes that a missing ``DLLs`` directory means that standard + extension modules are in the executable's directory. -- gh-issue-98745: Update :file:`py.exe` launcher to install 3.11 by default - and 3.12 on request. +- gh-98745: Update :file:`py.exe` launcher to install 3.11 by default and + 3.12 on request. -- gh-issue-98692: Fix the :ref:`launcher` ignoring unrecognized shebang - lines instead of treating them as local paths +- gh-98692: Fix the :ref:`launcher` ignoring unrecognized shebang lines + instead of treating them as local paths -- gh-issue-94328: Update Windows installer to use SQLite 3.39.4. +- gh-94328: Update Windows installer to use SQLite 3.39.4. macOS ----- -- gh-issue-94328: Update macOS installer to SQLite 3.39.4. +- gh-94328: Update macOS installer to SQLite 3.39.4. C API ----- -- gh-issue-98724: The :c:macro:`Py_CLEAR`, :c:macro:`Py_SETREF` and +- gh-98724: The :c:macro:`Py_CLEAR`, :c:macro:`Py_SETREF` and :c:macro:`Py_XSETREF` macros now only evaluate their argument once. If the argument has side effects, these side effects are no longer duplicated. Patch by Victor Stinner. -- gh-issue-98978: Fix use-after-free in ``Py_SetPythonHome(NULL)``, +- gh-98978: Fix use-after-free in ``Py_SetPythonHome(NULL)``, ``Py_SetProgramName(NULL)`` and ``_Py_SetProgramFullPath(NULL)`` function calls. Issue reported by Benedikt Reinartz. Patch by Victor Stinner. -- gh-issue-98410: Add ``getbufferproc`` and ``releasebufferproc`` to the - stable API. +- gh-98410: Add ``getbufferproc`` and ``releasebufferproc`` to the stable + API. -- gh-issue-98610: Some configurable capabilities of sub-interpreters have - changed. They always allow subprocesses (:mod:`subprocess`) now, whereas - before subprocesses could be optionally disallowed for a sub-interpreter. - Instead :func:`os.exec` can now be disallowed. Disallowing daemon threads - is now supported. Disallowing all threads is still allowed, but is never - done by default. Note that the optional restrictions are only available - through ``_Py_NewInterpreterFromConfig()``, which isn't a public API. They - do not affect the main interpreter, nor :c:func:`Py_NewInterpreter`. +- gh-98610: Some configurable capabilities of sub-interpreters have changed. + They always allow subprocesses (:mod:`subprocess`) now, whereas before + subprocesses could be optionally disallowed for a sub-interpreter. Instead + :func:`os.exec` can now be disallowed. Disallowing daemon threads is now + supported. Disallowing all threads is still allowed, but is never done by + default. Note that the optional restrictions are only available through + ``_Py_NewInterpreterFromConfig()``, which isn't a public API. They do not + affect the main interpreter, nor :c:func:`Py_NewInterpreter`. -- gh-issue-98608: A ``_PyInterpreterConfig`` has been added and +- gh-98608: A ``_PyInterpreterConfig`` has been added and ``_Py_NewInterpreter()`` has been renamed to ``_Py_NewInterpreterFromConfig()``. The "isolated_subinterpreters" argument is now a granular config that captures the previous behavior. Note that this is all "private" API. -- gh-issue-96853: ``Py_InitializeEx`` now correctly calls ``PyConfig_Clear`` - after initializing the interpreter (the omission didn't cause a memory - leak only because none of the dynamically allocated config fields are - populated by the wrapper function) +- gh-96853: ``Py_InitializeEx`` now correctly calls ``PyConfig_Clear`` after + initializing the interpreter (the omission didn't cause a memory leak only + because none of the dynamically allocated config fields are populated by + the wrapper function) -- gh-issue-91248: Add :c:func:`PyFrame_GetVar` and - :c:func:`PyFrame_GetVarString` functions to get a frame variable by its - name. Patch by Victor Stinner. +- gh-91248: Add :c:func:`PyFrame_GetVar` and :c:func:`PyFrame_GetVarString` + functions to get a frame variable by its name. Patch by Victor Stinner. What's New in Python 3.12.0 alpha 1? @@ -5990,12 +6896,12 @@ What's New in Python 3.12.0 alpha 1? Security -------- -- gh-issue-97616: Fix multiplying a list by an integer (``list *= int``): - detect the integer overflow when the new allocated length is close to the - maximum size. Issue reported by Jordan Limor. Patch by Victor Stinner. +- gh-97616: Fix multiplying a list by an integer (``list *= int``): detect + the integer overflow when the new allocated length is close to the maximum + size. Issue reported by Jordan Limor. Patch by Victor Stinner. -- gh-issue-97514: On Linux the :mod:`multiprocessing` module returns to - using filesystem backed unix domain sockets for communication with the +- gh-97514: On Linux the :mod:`multiprocessing` module returns to using + filesystem backed unix domain sockets for communication with the *forkserver* process instead of the Linux abstract socket namespace. Only code that chooses to use the :ref:`"forkserver" start method ` is affected. @@ -6010,213 +6916,209 @@ Security This prevents Linux :cve:`2022-42919`. -- gh-issue-87389: :mod:`http.server`: Fix an open redirection vulnerability - in the HTTP server when an URI path starts with ``//``. Vulnerability +- gh-87389: :mod:`http.server`: Fix an open redirection vulnerability in the + HTTP server when an URI path starts with ``//``. Vulnerability discovered, and initial fix proposed, by Hamza Avvan. -- gh-issue-79096: LWPCookieJar and MozillaCookieJar create files with file - mode 600 instead of 644 (Microsoft Windows is not affected) +- gh-79096: LWPCookieJar and MozillaCookieJar create files with file mode + 600 instead of 644 (Microsoft Windows is not affected) -- gh-issue-92888: Fix ``memoryview`` use after free when accessing the - backing buffer in certain cases. +- gh-92888: Fix ``memoryview`` use after free when accessing the backing + buffer in certain cases. -- gh-issue-68966: The deprecated mailcap module now refuses to inject unsafe - text (filenames, MIME types, parameters) into shell commands. Instead of - using such text, it will warn and act as if a match was not found (or for - test commands, as if the test failed). +- gh-68966: The deprecated mailcap module now refuses to inject unsafe text + (filenames, MIME types, parameters) into shell commands. Instead of using + such text, it will warn and act as if a match was not found (or for test + commands, as if the test failed). Core and Builtins ----------------- -- gh-issue-98374: Suppress ImportError for invalid query for help() command. - Patch by Donghee Na. +- gh-98374: Suppress ImportError for invalid query for help() command. Patch + by Donghee Na. -- gh-issue-98461: Fix source location in bytecode for list, set and dict +- gh-98461: Fix source location in bytecode for list, set and dict comprehensions as well as generator expressions. -- gh-issue-98354: Added unicode check for ``name`` attribute of ``spec`` - argument passed in :func:`_imp.create_builtin` function. +- gh-98354: Added unicode check for ``name`` attribute of ``spec`` argument + passed in :func:`!_imp.create_builtin` function. -- gh-issue-98398: Fix source location of 'assert' bytecodes. +- gh-98398: Fix source location of 'assert' bytecodes. -- gh-issue-98390: Fix location of sub-expressions of boolean expressions, by +- gh-98390: Fix location of sub-expressions of boolean expressions, by reducing their scope to that of the sub-expression. -- gh-issue-98254: Modules from the standard library are now potentially - suggested as part of the error messages displayed by the interpreter when - an :exc:`NameError` is raised to the top level. Patch by Pablo Galindo +- gh-98254: Modules from the standard library are now potentially suggested + as part of the error messages displayed by the interpreter when an + :exc:`NameError` is raised to the top level. Patch by Pablo Galindo -- gh-issue-97997: Add running column offset to the tokenizer state to avoid +- gh-97997: Add running column offset to the tokenizer state to avoid calculating AST column information with pointer arithmetic. -- gh-issue-97973: Modify the tokenizer to return all necessary information - the parser needs to set location information in the AST nodes, so that the +- gh-97973: Modify the tokenizer to return all necessary information the + parser needs to set location information in the AST nodes, so that the parser does not have to calculate those doing pointer arithmetic. -- gh-issue-96078: :func:`os.sched_yield` now release the GIL while calling +- gh-96078: :func:`os.sched_yield` now release the GIL while calling sched_yield(2). Patch by Donghee Na. -- gh-issue-97955: Migrate :mod:`zoneinfo` to Argument Clinic. +- gh-97955: Migrate :mod:`zoneinfo` to Argument Clinic. -- gh-issue-97912: The compiler now avoids quadratic behavior when finding - which instructions should use the :opcode:`LOAD_FAST_CHECK` opcode. +- gh-97912: The compiler now avoids quadratic behavior when finding which + instructions should use the :opcode:`LOAD_FAST_CHECK` opcode. -- gh-issue-97002: Fix an issue where several frame objects could be backed - by the same interpreter frame, possibly leading to corrupted memory and - hard crashes of the interpreter. +- gh-97002: Fix an issue where several frame objects could be backed by the + same interpreter frame, possibly leading to corrupted memory and hard + crashes of the interpreter. -- gh-issue-97943: Bugfix: :c:func:`PyFunction_GetAnnotations` should return - a borrowed reference. It was returning a new reference. +- gh-97943: Bugfix: :c:func:`PyFunction_GetAnnotations` should return a + borrowed reference. It was returning a new reference. -- gh-issue-97922: The Garbage Collector now runs only on the eval breaker +- gh-97922: The Garbage Collector now runs only on the eval breaker mechanism of the Python bytecode evaluation loop instead on object allocations. The GC can also run when :c:func:`PyErr_CheckSignals` is called so C extensions that need to run for a long time without executing any Python code also have a chance to execute the GC periodically. -- gh-issue-65961: When ``__package__`` is different than - ``__spec__.parent``, raise a ``DeprecationWarning`` instead of - ``ImportWarning``. +- gh-65961: When ``__package__`` is different than ``__spec__.parent``, + raise a ``DeprecationWarning`` instead of ``ImportWarning``. Also remove ``importlib.util.set_package()`` which was scheduled for removal. -- gh-issue-97850: Long deprecated, ``module_repr()`` should now be - completely eradicated. +- gh-97850: Long deprecated, ``module_repr()`` should now be completely + eradicated. -- gh-issue-86298: In cases where ``warnings.warn_explicit()`` consults the +- gh-86298: In cases where ``warnings.warn_explicit()`` consults the module's loader, an ``DeprecationWarning`` is issued when ``m.__loader__`` differs from ``m.__spec__.loader``. -- gh-issue-97779: Ensure that all Python frame objects are backed by - "complete" frames. +- gh-97779: Ensure that all Python frame objects are backed by "complete" + frames. -- gh-issue-91052: Add API for subscribing to modification events on selected +- gh-91052: Add API for subscribing to modification events on selected dictionaries. -- gh-issue-97752: Fix possible data corruption or crashes when accessing the +- gh-97752: Fix possible data corruption or crashes when accessing the ``f_back`` member of newly-created generator or coroutine frames. -- gh-issue-97591: Fixed a missing incref/decref pair in +- gh-97591: Fixed a missing incref/decref pair in ``Exception.__setstate__()``. Patch by Ofey Chan. -- gh-issue-97670: Remove the :func:`sys.getdxp` function and the +- gh-97670: Remove the :func:`sys.getdxp` function and the ``Tools/scripts/analyze_dxp.py`` script. DXP stands for "dynamic execution pairs". They were related to ``DYNAMIC_EXECUTION_PROFILE`` and ``DXPAIRS`` macros which have been removed in Python 3.11. Python can now be built with :option:`./configure --enable-pystats <--enable-pystats>` to gather statistics on Python opcodes. Patch by Victor Stinner. -- gh-issue-94526: Fix the Python path configuration used to initialized +- gh-94526: Fix the Python path configuration used to initialized :data:`sys.path` at Python startup. Paths are no longer encoded to UTF-8/strict to avoid encoding errors if it contains surrogate characters (bytes paths are decoded with the surrogateescape error handler). Patch by Victor Stinner. -- gh-issue-96670: The parser now raises :exc:`SyntaxError` when parsing - source code containing null bytes. Patch by Pablo Galindo +- gh-96670: The parser now raises :exc:`SyntaxError` when parsing source + code containing null bytes. Patch by Pablo Galindo -- gh-issue-96975: Fix a crash occurring when :c:func:`PyEval_GetFrame` is - called while the topmost Python frame is in a partially-initialized state. +- gh-96975: Fix a crash occurring when :c:func:`PyEval_GetFrame` is called + while the topmost Python frame is in a partially-initialized state. -- gh-issue-96848: Fix command line parsing: reject :option:`-X - int_max_str_digits <-X>` option with no value (invalid) when the +- gh-96848: Fix command line parsing: reject :option:`-X int_max_str_digits + <-X>` option with no value (invalid) when the :envvar:`PYTHONINTMAXSTRDIGITS` environment variable is set to a valid limit. Patch by Victor Stinner. -- gh-issue-95921: Fix overly-broad source position information for chained +- gh-95921: Fix overly-broad source position information for chained comparisons used as branching conditions. -- gh-issue-96821: Fix undefined behaviour in ``audioop.c``. +- gh-96821: Fix undefined behaviour in ``audioop.c``. -- gh-issue-96821: Fix undefined behaviour in ``_testcapimodule.c``. +- gh-96821: Fix undefined behaviour in ``_testcapimodule.c``. -- gh-issue-95778: When :exc:`ValueError` is raised if an integer is larger - than the limit, mention the :func:`sys.set_int_max_str_digits` function in - the error message. Patch by Victor Stinner. +- gh-95778: When :exc:`ValueError` is raised if an integer is larger than + the limit, mention the :func:`sys.set_int_max_str_digits` function in the + error message. Patch by Victor Stinner. -- gh-issue-96387: At Python exit, sometimes a thread holding the GIL can - wait forever for a thread (usually a daemon thread) which requested to - drop the GIL, whereas the thread already exited. To fix the race - condition, the thread which requested the GIL drop now resets its request - before exiting. Issue discovered and analyzed by Mingliang ZHAO. Patch by - Victor Stinner. +- gh-96387: At Python exit, sometimes a thread holding the GIL can wait + forever for a thread (usually a daemon thread) which requested to drop the + GIL, whereas the thread already exited. To fix the race condition, the + thread which requested the GIL drop now resets its request before exiting. + Issue discovered and analyzed by Mingliang ZHAO. Patch by Victor Stinner. -- gh-issue-96864: Fix a possible assertion failure, fatal error, or +- gh-96864: Fix a possible assertion failure, fatal error, or :exc:`SystemError` if a line tracing event raises an exception while opcode tracing is enabled. -- gh-issue-95778: The ``PyLong_FromString`` function was refactored to make - it more maintainable and extensible. +- gh-95778: The ``PyLong_FromString`` function was refactored to make it + more maintainable and extensible. -- gh-issue-96678: Fix undefined behaviour in C code of null pointer - arithmetic. +- gh-96678: Fix undefined behaviour in C code of null pointer arithmetic. -- gh-issue-96754: Make sure that all frame objects created are created from - valid interpreter frames. Prevents the possibility of invalid frames in +- gh-96754: Make sure that all frame objects created are created from valid + interpreter frames. Prevents the possibility of invalid frames in backtraces and signal handlers. -- gh-issue-90997: Improve the performance of reading and writing inline - bytecode caches on some platforms. +- gh-90997: Improve the performance of reading and writing inline bytecode + caches on some platforms. -- gh-issue-96751: Remove dead code from ``CALL_FUNCTION_EX`` opcode. +- gh-96751: Remove dead code from ``CALL_FUNCTION_EX`` opcode. -- gh-issue-90751: :class:`memoryview` now supports half-floats. Patch by - Donghee Na and Antoine Pitrou. +- gh-90751: :class:`memoryview` now supports half-floats. Patch by Donghee + Na and Antoine Pitrou. -- gh-issue-96678: Fix case of undefined behavior in ceval.c +- gh-96678: Fix case of undefined behavior in ceval.c -- gh-issue-64373: Convert :mod:`_functools` to argument clinic. +- gh-64373: Convert :mod:`!_functools` to argument clinic. -- gh-issue-96641: Do not expose ``KeyWrapper`` in :mod:`_functools`. +- gh-96641: Do not expose ``KeyWrapper`` in :mod:`!_functools`. -- gh-issue-96636: Ensure that tracing, ``sys.setrace()``, is turned on +- gh-96636: Ensure that tracing, ``sys.setrace()``, is turned on immediately. In pre-release versions of 3.11, some tracing events might have been lost when turning on tracing in a ``__del__`` method or interrupt. -- gh-issue-96572: Fix use after free in trace refs build mode. Patch by - Kumar Aditya. +- gh-96572: Fix use after free in trace refs build mode. Patch by Kumar + Aditya. -- gh-issue-96611: When loading a file with invalid UTF-8 inside a multi-line +- gh-96611: When loading a file with invalid UTF-8 inside a multi-line string, a correct SyntaxError is emitted. -- gh-issue-96612: Make sure that incomplete frames do not show up in - tracemalloc traces. +- gh-96612: Make sure that incomplete frames do not show up in tracemalloc + traces. -- gh-issue-90230: Fix compiler warnings and test failures when building with +- gh-90230: Fix compiler warnings and test failures when building with ``--enable-pystats``. -- gh-issue-96587: Correctly raise ``SyntaxError`` on exception groups - (:pep:`654`) on python versions prior to 3.11 +- gh-96587: Correctly raise ``SyntaxError`` on exception groups (:pep:`654`) + on python versions prior to 3.11 -- gh-issue-96569: Remove two cases of undefined behavior, by adding NULL - checks. +- gh-96569: Remove two cases of undefined behavior, by adding NULL checks. -- gh-issue-96582: Fix possible ``NULL`` pointer dereference in +- gh-96582: Fix possible ``NULL`` pointer dereference in ``_PyThread_CurrentFrames``. Patch by Kumar Aditya. -- gh-issue-91079: Separate Python recursion checking from C recursion - checking which reduces the chance of C stack overflow and allows the - recursion limit to be increased safely. +- gh-91079: Separate Python recursion checking from C recursion checking + which reduces the chance of C stack overflow and allows the recursion + limit to be increased safely. -- gh-issue-93911: Fix an issue that could prevent :opcode:`LOAD_ATTR` from +- gh-93911: Fix an issue that could prevent :opcode:`LOAD_ATTR` from specializing properly when accessing properties. -- gh-issue-96348: Emit a DeprecationWarning when :meth:`~generator.throw`, +- gh-96348: Emit a DeprecationWarning when :meth:`~generator.throw`, :meth:`~coroutine.throw` or :meth:`~agen.athrow` are called with more than one argument. -- gh-issue-95196: Disable incorrect pickling of the C implemented - classmethod descriptors. +- gh-95196: Disable incorrect pickling of the C implemented classmethod + descriptors. -- gh-issue-96364: Fix text signatures of ``list.__getitem__`` and +- gh-96364: Fix text signatures of ``list.__getitem__`` and ``dict.__getitem__``. -- gh-issue-96352: Fix :exc:`AttributeError` missing ``name`` and ``obj`` +- gh-96352: Fix :exc:`AttributeError` missing ``name`` and ``obj`` attributes in :meth:`object.__getattribute__`. Patch by Philip Georgi. -- gh-issue-93554: Change the jump opcodes so that all conditional jumps are +- gh-93554: Change the jump opcodes so that all conditional jumps are forward jumps. Backward jumps are converted by the assembler into a conditional forward jump whose target is the fallthrough block (and with a reversed condition), followed by an unconditional backward jump. For @@ -6234,20 +7136,20 @@ Core and Builtins The corresponding opcodes without direction are no longer pseudo-instructions, and they implement the forward conditional jumps. -- gh-issue-96268: Loading a file with invalid UTF-8 will now report the - broken character at the correct location. +- gh-96268: Loading a file with invalid UTF-8 will now report the broken + character at the correct location. -- gh-issue-96237: The internal field ``_PyInterpreterFrame.f_func`` is - renamed to ``_PyInterpreterFrame.f_funcobj`` and may be any object. The - ``f_globals`` and ``f_builtin`` fields may hold junk values. +- gh-96237: The internal field ``_PyInterpreterFrame.f_func`` is renamed to + ``_PyInterpreterFrame.f_funcobj`` and may be any object. The ``f_globals`` + and ``f_builtin`` fields may hold junk values. It is safest to treat the ``_PyInterpreterFrame`` struct as opaque. -- gh-issue-96187: Fixed a bug that caused ``_PyCode_GetExtra`` to return - garbage for negative indexes. Patch by Pablo Galindo +- gh-96187: Fixed a bug that caused ``_PyCode_GetExtra`` to return garbage + for negative indexes. Patch by Pablo Galindo -- gh-issue-96143: Add a new ``-X perf`` Python command line option as well - as :func:`sys.activate_stack_trampoline` and +- gh-96143: Add a new ``-X perf`` Python command line option as well as + :func:`sys.activate_stack_trampoline` and :func:`sys.deactivate_stack_trampoline` function in the :mod:`sys` module that allows to set/unset the interpreter in a way that the Linux ``perf`` profiler can detect Python calls. The new @@ -6256,329 +7158,319 @@ Core and Builtins and Christian Heimes with contributions from Gregory P. Smith [Google] and Mark Shannon. -- gh-issue-96071: Fix a deadlock in :c:func:`PyGILState_Ensure` when - allocating new thread state. Patch by Kumar Aditya. +- gh-96071: Fix a deadlock in :c:func:`PyGILState_Ensure` when allocating + new thread state. Patch by Kumar Aditya. -- gh-issue-96046: :c:func:`PyType_Ready` now initializes ``ht_cached_keys`` - and performs additional checks to ensure that type objects are properly +- gh-96046: :c:func:`PyType_Ready` now initializes ``ht_cached_keys`` and + performs additional checks to ensure that type objects are properly configured. This avoids crashes in 3rd party packages that don't use regular API to create new types. -- gh-issue-96005: On WASI :const:`~errno.ENOTCAPABLE` is now mapped to +- gh-96005: On WASI :const:`~errno.ENOTCAPABLE` is now mapped to :exc:`PermissionError`. The :mod:`errno` modules exposes the new error number. ``getpath.py`` now ignores :exc:`PermissionError` when it cannot open landmark files ``pybuilddir.txt`` and ``pyenv.cfg``. -- gh-issue-93678: Added test a harness for direct unit tests of the - compiler's optimization stage. The ``_testinternalcapi.optimize_cfg()`` - function runs the optimiser on a sequence of instructions. The +- gh-93678: Added test a harness for direct unit tests of the compiler's + optimization stage. The ``_testinternalcapi.optimize_cfg()`` function runs + the optimiser on a sequence of instructions. The ``CfgOptimizationTestCase`` class in ``test.support`` has utilities for invoking the optimizer and checking the output. -- gh-issue-95245: Reduces the size of a "simple" Python object from 8 to 6 - words by moving the weakreflist pointer into the pre-header directly - before the object's dict/values pointer. +- gh-95245: Reduces the size of a "simple" Python object from 8 to 6 words + by moving the weakreflist pointer into the pre-header directly before the + object's dict/values pointer. -- gh-issue-90997: Compile virtual :keyword:`try`/:keyword:`except` blocks to +- gh-90997: Compile virtual :keyword:`try`/:keyword:`except` blocks to handle exceptions raised during :meth:`~generator.close` or :meth:`~generator.throw` calls through a suspended frame. -- gh-issue-95977: Optimized calling :meth:`~object.__get__` with vectorcall. - Patch by Kumar Aditya. +- gh-95977: Optimized calling :meth:`~object.__get__` with vectorcall. Patch + by Kumar Aditya. -- gh-issue-91210: Improve error message when a parameter without a default - value follows one with a default value, and show the same message, even - when the non-default/default sequence is preceded by positional-only - parameters. +- gh-91210: Improve error message when a parameter without a default value + follows one with a default value, and show the same message, even when the + non-default/default sequence is preceded by positional-only parameters. -- gh-issue-95922: Fixed bug where the compiler's - ``eliminate_empty_basic_blocks`` function ignores the last block of the - code unit. +- gh-95922: Fixed bug where the compiler's ``eliminate_empty_basic_blocks`` + function ignores the last block of the code unit. -- gh-issue-95818: Skip over incomplete frames in - :c:func:`PyThreadState_GetFrame`. +- gh-95818: Skip over incomplete frames in :c:func:`PyThreadState_GetFrame`. -- gh-issue-95876: Fix format string in - ``_PyPegen_raise_error_known_location`` that can lead to memory corruption - on some 64bit systems. The function was building a tuple with ``i`` (int) - instead of ``n`` (Py_ssize_t) for Py_ssize_t arguments. +- gh-95876: Fix format string in ``_PyPegen_raise_error_known_location`` + that can lead to memory corruption on some 64bit systems. The function was + building a tuple with ``i`` (int) instead of ``n`` (Py_ssize_t) for + Py_ssize_t arguments. -- gh-issue-95605: Fix misleading contents of error message when converting - an all-whitespace string to :class:`float`. +- gh-95605: Fix misleading contents of error message when converting an + all-whitespace string to :class:`float`. -- gh-issue-95150: Update code object hashing and equality to consider all +- gh-95150: Update code object hashing and equality to consider all debugging and exception handling tables. This fixes an issue where certain non-identical code objects could be "deduplicated" during compilation. -- gh-issue-91146: Reduce allocation size of :class:`list` from - :meth:`str.split` and :meth:`str.rsplit`. Patch by Donghee Na and Inada - Naoki. +- gh-91146: Reduce allocation size of :class:`list` from :meth:`str.split` + and :meth:`str.rsplit`. Patch by Donghee Na and Inada Naoki. -- gh-issue-87092: Create a 'jump target label' abstraction in the compiler - so that the compiler's codegen stage does not work directly with basic - blocks. This prepares the code for changes to the underlying CFG - generation mechanism. +- gh-87092: Create a 'jump target label' abstraction in the compiler so that + the compiler's codegen stage does not work directly with basic blocks. + This prepares the code for changes to the underlying CFG generation + mechanism. -- gh-issue-95355: ``_PyPegen_Parser_New`` now properly detects token memory +- gh-95355: ``_PyPegen_Parser_New`` now properly detects token memory allocation errors. Patch by Honglin Zhu. -- gh-issue-90081: Run Python code in tracer/profiler function at full speed. - Fixes slowdown in earlier versions of 3.11. +- gh-90081: Run Python code in tracer/profiler function at full speed. Fixes + slowdown in earlier versions of 3.11. -- gh-issue-95324: Emit a warning in debug mode if an object does not call +- gh-95324: Emit a warning in debug mode if an object does not call :c:func:`PyObject_GC_UnTrack` before deallocation. Patch by Pablo Galindo. -- gh-issue-95245: Merge managed dict and values pointer into a single tagged +- gh-95245: Merge managed dict and values pointer into a single tagged pointer to save one word in the pre-header. -- gh-issue-93678: Add cfg_builder struct and refactor the relevant code so - that a cfg can be constructed without an instance of the compiler struct. +- gh-93678: Add cfg_builder struct and refactor the relevant code so that a + cfg can be constructed without an instance of the compiler struct. -- gh-issue-95185: Prevented crashes in the AST constructor when compiling - some absurdly long expressions like ``"+0"*1000000``. - :exc:`RecursionError` is now raised instead. Patch by Pablo Galindo +- gh-95185: Prevented crashes in the AST constructor when compiling some + absurdly long expressions like ``"+0"*1000000``. :exc:`RecursionError` is + now raised instead. Patch by Pablo Galindo -- gh-issue-93351: :class:`ast.AST` node positions are now validated when - provided to :func:`compile` and other related functions. If invalid - positions are detected, a :exc:`ValueError` will be raised. +- gh-93351: :class:`ast.AST` node positions are now validated when provided + to :func:`compile` and other related functions. If invalid positions are + detected, a :exc:`ValueError` will be raised. -- gh-issue-94438: Fix an issue that caused extended opcode arguments and - some conditional pops to be ignored when calculating valid jump targets - for assignments to the ``f_lineno`` attribute of frame objects. In some - cases, this could cause inconsistent internal state, resulting in a hard - crash of the interpreter. +- gh-94438: Fix an issue that caused extended opcode arguments and some + conditional pops to be ignored when calculating valid jump targets for + assignments to the ``f_lineno`` attribute of frame objects. In some cases, + this could cause inconsistent internal state, resulting in a hard crash of + the interpreter. -- gh-issue-95060: Undocumented ``PyCode_Addr2Location`` function now - properly returns when ``addrq`` argument is less than zero. +- gh-95060: Undocumented ``PyCode_Addr2Location`` function now properly + returns when ``addrq`` argument is less than zero. -- gh-issue-95113: Replace all ``EXTENDED_ARG_QUICK`` instructions with basic +- gh-95113: Replace all ``EXTENDED_ARG_QUICK`` instructions with basic :opcode:`EXTENDED_ARG` instructions in unquickened code. Consumers of non-adaptive bytecode should be able to handle extended arguments the same way they were handled in CPython 3.10 and older. -- gh-issue-91409: Fix incorrect source location info caused by certain +- gh-91409: Fix incorrect source location info caused by certain optimizations in the bytecode compiler. -- gh-issue-95023: Implement :func:`os.setns` and :func:`os.unshare` for - Linux. Patch by Noam Cohen. +- gh-95023: Implement :func:`os.setns` and :func:`os.unshare` for Linux. + Patch by Noam Cohen. -- gh-issue-94036: Fix incorrect source location info for some multi-line - attribute accesses and method calls. +- gh-94036: Fix incorrect source location info for some multi-line attribute + accesses and method calls. -- gh-issue-94938: Fix error detection in some builtin functions when keyword +- gh-94938: Fix error detection in some builtin functions when keyword argument name is an instance of a str subclass with overloaded ``__eq__`` and ``__hash__``. Previously it could cause SystemError or other undesired behavior. -- gh-issue-94996: :func:`ast.parse` will no longer parse function - definitions with positional-only params when passed ``feature_version`` - less than ``(3, 8)``. Patch by Shantanu Jain. - -- gh-issue-94739: Allow jumping within, out of, and across exception - handlers in the debugger. +- gh-94996: :func:`ast.parse` will no longer parse function definitions with + positional-only params when passed ``feature_version`` less than ``(3, + 8)``. Patch by Shantanu Jain. -- gh-issue-94949: :func:`ast.parse` will no longer parse parenthesized - context managers when passed ``feature_version`` less than ``(3, 9)``. - Patch by Shantanu Jain. +- gh-94739: Allow jumping within, out of, and across exception handlers in + the debugger. -- gh-issue-94947: :func:`ast.parse` will no longer parse assignment - expressions when passed ``feature_version`` less than ``(3, 8)``. Patch by +- gh-94949: :func:`ast.parse` will no longer parse parenthesized context + managers when passed ``feature_version`` less than ``(3, 9)``. Patch by Shantanu Jain. -- gh-issue-91256: Ensures the program name is known for help text during +- gh-94947: :func:`ast.parse` will no longer parse assignment expressions + when passed ``feature_version`` less than ``(3, 8)``. Patch by Shantanu + Jain. + +- gh-91256: Ensures the program name is known for help text during interpreter startup. -- gh-issue-94869: Fix the column offsets for some expressions in multi-line +- gh-94869: Fix the column offsets for some expressions in multi-line f-strings :mod:`ast` nodes. Patch by Pablo Galindo. -- gh-issue-94893: Fix an issue where frame object manipulations could - corrupt inline bytecode caches. +- gh-94893: Fix an issue where frame object manipulations could corrupt + inline bytecode caches. -- gh-issue-94822: Fix an issue where lookups of metaclass descriptors may be +- gh-94822: Fix an issue where lookups of metaclass descriptors may be ignored when an identically-named attribute also exists on the class itself. -- gh-issue-91153: Fix an issue where a :class:`bytearray` item assignment - could crash if it's resized by the new value's :meth:`__index__` method. +- gh-91153: Fix an issue where a :class:`bytearray` item assignment could + crash if it's resized by the new value's :meth:`__index__` method. -- gh-issue-90699: Fix reference counting bug in :meth:`bool.__repr__`. Patch - by Kumar Aditya. +- gh-90699: Fix reference counting bug in :meth:`bool.__repr__`. Patch by + Kumar Aditya. -- gh-issue-94694: Fix an issue that could cause code with multi-line method +- gh-94694: Fix an issue that could cause code with multi-line method lookups to have misleading or incorrect column offset information. In some cases (when compiling a hand-built AST) this could have resulted in a hard crash of the interpreter. -- gh-issue-93252: Fix an issue that caused internal frames to outlive failed +- gh-93252: Fix an issue that caused internal frames to outlive failed Python function calls, possibly resulting in memory leaks or hard interpreter crashes. -- gh-issue-94215: Fix an issue where exceptions raised by line-tracing - events would cause frames to be left in an invalid state, possibly - resulting in a hard crash of the interpreter. +- gh-94215: Fix an issue where exceptions raised by line-tracing events + would cause frames to be left in an invalid state, possibly resulting in a + hard crash of the interpreter. -- gh-issue-92228: Disable the compiler's inline-small-exit-blocks - optimization for exit blocks that are associated with source code lines. - This fixes a bug where the debugger cannot tell where an exception handler - ends and the following code block begins. +- gh-92228: Disable the compiler's inline-small-exit-blocks optimization for + exit blocks that are associated with source code lines. This fixes a bug + where the debugger cannot tell where an exception handler ends and the + following code block begins. -- gh-issue-94485: Line number of a module's ``RESUME`` instruction is set to - 0 as specified in :pep:`626`. +- gh-94485: Line number of a module's ``RESUME`` instruction is set to 0 as + specified in :pep:`626`. -- gh-issue-94438: Account for instructions that can push NULL to the stack - when setting line number in a frame. Prevents some (unlikely) crashes. +- gh-94438: Account for instructions that can push NULL to the stack when + setting line number in a frame. Prevents some (unlikely) crashes. -- gh-issue-91719: Reload ``opcode`` when raising ``unknown opcode error`` in - the interpreter main loop, for C compilers to generate dispatching code +- gh-91719: Reload ``opcode`` when raising ``unknown opcode error`` in the + interpreter main loop, for C compilers to generate dispatching code independently. -- gh-issue-94329: Compile and run code with unpacking of extremely large - sequences (1000s of elements). Such code failed to compile. It now - compiles and runs correctly. +- gh-94329: Compile and run code with unpacking of extremely large sequences + (1000s of elements). Such code failed to compile. It now compiles and runs + correctly. -- gh-issue-94360: Fixed a tokenizer crash when reading encoded files with - syntax errors from ``stdin`` with non utf-8 encoded text. Patch by Pablo - Galindo +- gh-94360: Fixed a tokenizer crash when reading encoded files with syntax + errors from ``stdin`` with non utf-8 encoded text. Patch by Pablo Galindo -- gh-issue-88116: Fix an issue when reading line numbers from code objects - if the encoded line numbers are close to ``INT_MIN``. Patch by Pablo - Galindo +- gh-88116: Fix an issue when reading line numbers from code objects if the + encoded line numbers are close to ``INT_MIN``. Patch by Pablo Galindo -- gh-issue-94262: Don't create frame objects for incomplete frames. Prevents - the creation of generators and closures from being observable to Python - and C extensions, restoring the behavior of 3.10 and earlier. +- gh-94262: Don't create frame objects for incomplete frames. Prevents the + creation of generators and closures from being observable to Python and C + extensions, restoring the behavior of 3.10 and earlier. -- gh-issue-94192: Fix error for dictionary literals with invalid expression - as value. +- gh-94192: Fix error for dictionary literals with invalid expression as + value. -- gh-issue-87995: :class:`types.MappingProxyType` instances are now hashable - if the underlying mapping is hashable. +- gh-87995: :class:`types.MappingProxyType` instances are now hashable if + the underlying mapping is hashable. -- gh-issue-93883: Revise the display strategy of traceback enhanced error +- gh-93883: Revise the display strategy of traceback enhanced error locations. The indicators are only shown when the location doesn't span the whole line. -- gh-issue-94163: Add :opcode:`BINARY_SLICE` and :opcode:`STORE_SLICE` +- gh-94163: Add :opcode:`BINARY_SLICE` and :opcode:`STORE_SLICE` instructions for more efficient handling and better specialization of slicing operations, where the slice is explicit in the source code. -- gh-issue-94021: Fix unreachable code warning in ``Python/specialize.c``. +- gh-94021: Fix unreachable code warning in ``Python/specialize.c``. -- gh-issue-93911: Specialize ``LOAD_ATTR`` for objects with custom +- gh-93911: Specialize ``LOAD_ATTR`` for objects with custom ``__getattribute__``. -- gh-issue-93955: Improve performance of attribute lookups on objects with - custom ``__getattribute__`` and ``__getattr__``. Patch by Ken Jin. +- gh-93955: Improve performance of attribute lookups on objects with custom + ``__getattribute__`` and ``__getattr__``. Patch by Ken Jin. -- gh-issue-93911: Specialize ``LOAD_ATTR`` for ``property()`` attributes. +- gh-93911: Specialize ``LOAD_ATTR`` for ``property()`` attributes. -- gh-issue-93678: Refactor compiler optimisation code so that it no longer - needs the ``struct assembler`` and ``struct compiler`` passed around. - Instead, each function takes the CFG and other data that it actually - needs. This will make it possible to test this code directly. +- gh-93678: Refactor compiler optimisation code so that it no longer needs + the ``struct assembler`` and ``struct compiler`` passed around. Instead, + each function takes the CFG and other data that it actually needs. This + will make it possible to test this code directly. -- gh-issue-93841: When built with ``-enable-pystats``, ``sys._stats_on()``, +- gh-93841: When built with ``-enable-pystats``, ``sys._stats_on()``, ``sys._stats_off()``, ``sys._stats_clear()`` and ``sys._stats_dump()`` functions have been added to enable gathering stats for parts of programs. -- gh-issue-93516: Store offset of first traceable instruction in code object - to avoid having to recompute it for each instruction when tracing. +- gh-93516: Store offset of first traceable instruction in code object to + avoid having to recompute it for each instruction when tracing. -- gh-issue-93516: Lazily create a table mapping bytecode offsets to line - numbers to speed up calculation of line numbers when tracing. +- gh-93516: Lazily create a table mapping bytecode offsets to line numbers + to speed up calculation of line numbers when tracing. -- gh-issue-89828: :class:`types.GenericAlias` no longer relays the - ``__class__`` attribute. For example, ``isinstance(list[int], type)`` no - longer returns ``True``. +- gh-89828: :class:`types.GenericAlias` no longer relays the ``__class__`` + attribute. For example, ``isinstance(list[int], type)`` no longer returns + ``True``. -- gh-issue-93678: Refactor the compiler to reduce boilerplate and - repetition. +- gh-93678: Refactor the compiler to reduce boilerplate and repetition. -- gh-issue-93671: Fix some exponential backtrace case happening with deeply - nested sequence patterns in match statements. Patch by Pablo Galindo +- gh-93671: Fix some exponential backtrace case happening with deeply nested + sequence patterns in match statements. Patch by Pablo Galindo -- gh-issue-93662: Make sure that the end column offsets are correct in - multi-line method calls. Previously, the end column could precede the - column offset. +- gh-93662: Make sure that the end column offsets are correct in multi-line + method calls. Previously, the end column could precede the column offset. -- gh-issue-93461: :func:`importlib.invalidate_caches` now drops entries from +- gh-93461: :func:`importlib.invalidate_caches` now drops entries from :data:`sys.path_importer_cache` with a relative path as name. This solves a caching issue when a process changes its current working directory. ``FileFinder`` no longer inserts a dot in the path, e.g. ``/egg/./spam`` is now ``/egg/spam``. -- gh-issue-93621: Change order of bytecode instructions emitted for +- gh-93621: Change order of bytecode instructions emitted for :keyword:`with` and :keyword:`async with` to reduce the number of entries in the exception table. -- gh-issue-93533: Reduce the size of the inline cache for ``LOAD_METHOD`` by - 2 bytes. +- gh-93533: Reduce the size of the inline cache for ``LOAD_METHOD`` by 2 + bytes. -- gh-issue-93444: Removed redundant fields from the compiler's basicblock - struct: ``b_nofallthrough``, ``b_exit``, ``b_return``. They can be easily +- gh-93444: Removed redundant fields from the compiler's basicblock struct: + ``b_nofallthrough``, ``b_exit``, ``b_return``. They can be easily calculated from the opcode of the last instruction of the block. -- gh-issue-93429: ``LOAD_METHOD`` instruction has been removed. It was - merged back into ``LOAD_ATTR``. +- gh-93429: ``LOAD_METHOD`` instruction has been removed. It was merged back + into ``LOAD_ATTR``. -- gh-issue-93418: Fixed an assert where an f-string has an equal sign '=' +- gh-93418: Fixed an assert where an f-string has an equal sign '=' following an expression, but there's no trailing brace. For example, f"{i=". -- gh-issue-93382: Cache the result of :c:func:`PyCode_GetCode` function to - restore the *O*\ (1) lookup of the :attr:`~types.CodeType.co_code` - attribute. +- gh-93382: Cache the result of :c:func:`PyCode_GetCode` function to restore + the *O*\ (1) lookup of the :attr:`~types.CodeType.co_code` attribute. -- gh-issue-93359: Ensure that custom :mod:`ast` nodes without explicit end +- gh-93359: Ensure that custom :mod:`ast` nodes without explicit end positions can be compiled. Patch by Pablo Galindo. -- gh-issue-93356: Code for exception handlers is emitted at the end of the - code unit's bytecode. This avoids one jump when no exception is raised. +- gh-93356: Code for exception handlers is emitted at the end of the code + unit's bytecode. This avoids one jump when no exception is raised. -- gh-issue-93354: Use exponential backoff for specialization counters in the +- gh-93354: Use exponential backoff for specialization counters in the interpreter. Can reduce the number of failed specializations significantly and avoid slowdown for those parts of a program that are not suitable for specialization. -- gh-issue-93283: Improve error message for invalid syntax of conversion - character in f-string expressions. +- gh-93283: Improve error message for invalid syntax of conversion character + in f-string expressions. -- gh-issue-93345: Fix a crash in substitution of a ``TypeVar`` in nested - generic alias after ``TypeVarTuple``. +- gh-93345: Fix a crash in substitution of a ``TypeVar`` in nested generic + alias after ``TypeVarTuple``. -- gh-issue-93223: When a bytecode instruction jumps to an unconditional jump +- gh-93223: When a bytecode instruction jumps to an unconditional jump instruction, the first instruction can often be optimized to target the unconditional jump's target directly. For tracing reasons, this would previously only occur if both instructions have the same line number. This also now occurs if the unconditional jump is artificial, i.e., if it has no associated line number. -- gh-issue-84694: The ``--experimental-isolated-subinterpreters`` configure - option and ``EXPERIMENTAL_ISOLATED_SUBINTERPRETERS`` macro have been - removed. +- gh-84694: The ``--experimental-isolated-subinterpreters`` configure option + and ``EXPERIMENTAL_ISOLATED_SUBINTERPRETERS`` macro have been removed. -- gh-issue-91924: Fix ``__lltrace__`` debug feature if the stdout encoding - is not UTF-8. Patch by Victor Stinner. +- gh-91924: Fix ``__lltrace__`` debug feature if the stdout encoding is not + UTF-8. Patch by Victor Stinner. -- gh-issue-93040: Wraps unused parameters in ``Objects/obmalloc.c`` with +- gh-93040: Wraps unused parameters in ``Objects/obmalloc.c`` with ``Py_UNUSED``. -- gh-issue-93143: Avoid ``NULL`` checks for uninitialized local variables by +- gh-93143: Avoid ``NULL`` checks for uninitialized local variables by determining at compile time which variables must be initialized. -- gh-issue-93061: Backward jumps after ``async for`` loops are no longer - given dubious line numbers. +- gh-93061: Backward jumps after ``async for`` loops are no longer given + dubious line numbers. -- gh-issue-93065: Fix contextvars HAMT implementation to handle iteration - over deep trees. +- gh-93065: Fix contextvars HAMT implementation to handle iteration over + deep trees. The bug was discovered and fixed by Eli Libman. See `MagicStack/immutables#84 `_ for more details. -- gh-issue-93012: Added the new function :c:func:`PyType_FromMetaclass`, - which generalizes the existing :c:func:`PyType_FromModuleAndSpec` using an +- gh-93012: Added the new function :c:func:`PyType_FromMetaclass`, which + generalizes the existing :c:func:`PyType_FromModuleAndSpec` using an additional metaclass argument. This is useful for language binding tools, where it can be used to intercept type-related operations like subclassing or static attribute access by specifying a metaclass with custom slots. @@ -6587,63 +7479,62 @@ Core and Builtins API, which provides a path towards migrating more binding tools onto the Stable ABI. -- gh-issue-93021: Fix the :attr:`__text_signature__` for :meth:`__get__` - methods implemented in C. Patch by Jelle Zijlstra. +- gh-93021: Fix the :attr:`__text_signature__` for :meth:`__get__` methods + implemented in C. Patch by Jelle Zijlstra. -- gh-issue-89914: The operand of the ``YIELD_VALUE`` instruction is set to - the stack depth. This is done to help frame handling on ``yield`` and may +- gh-89914: The operand of the ``YIELD_VALUE`` instruction is set to the + stack depth. This is done to help frame handling on ``yield`` and may assist debuggers. -- gh-issue-92955: Fix memory leak in code object's lines and positions - iterators as they were not finalized at exit. Patch by Kumar Aditya. +- gh-92955: Fix memory leak in code object's lines and positions iterators + as they were not finalized at exit. Patch by Kumar Aditya. -- gh-issue-92930: Fixed a crash in ``_pickle.c`` from mutating collections - during ``__reduce__`` or ``persistent_id``. +- gh-92930: Fixed a crash in ``_pickle.c`` from mutating collections during + ``__reduce__`` or ``persistent_id``. -- gh-issue-90690: The PRECALL instruction has been removed. It offered only - a small advantage for specialization and is not needed in the vast - majority of cases. +- gh-90690: The PRECALL instruction has been removed. It offered only a + small advantage for specialization and is not needed in the vast majority + of cases. -- gh-issue-92914: Always round the allocated size for lists up to the - nearest even number. +- gh-92914: Always round the allocated size for lists up to the nearest even + number. -- gh-issue-92858: Improve error message for some suites with syntax error - before ':' +- gh-92858: Improve error message for some suites with syntax error before + ':' -- gh-issue-90473: Decrease default recursion limit on WASI to address - limited call stack size. +- gh-90473: Decrease default recursion limit on WASI to address limited call + stack size. -- gh-issue-92804: Fix memory leak in ``memoryview`` iterator as it was not +- gh-92804: Fix memory leak in ``memoryview`` iterator as it was not finalized at exit. Patch by Kumar Aditya. -- gh-issue-92777: Specialize ``LOAD_METHOD`` for objects with lazy - dictionaries. Patch by Ken Jin. +- gh-92777: Specialize ``LOAD_METHOD`` for objects with lazy dictionaries. + Patch by Ken Jin. -- gh-issue-92658: Add support for connecting and binding to Hyper-V sockets - on Windows Hyper-V hosts and guests. +- gh-92658: Add support for connecting and binding to Hyper-V sockets on + Windows Hyper-V hosts and guests. -- gh-issue-92236: Remove spurious "LINE" event when starting a generator or +- gh-92236: Remove spurious "LINE" event when starting a generator or coroutine, visible tracing functions implemented in C. -- gh-issue-91102: :meth:`_warnings.warn_explicit` is ported to Argument - Clinic. +- gh-91102: :meth:`!_warnings.warn_explicit` is ported to Argument Clinic. -- gh-issue-92619: Make the compiler duplicate an exit block only if none of - its instructions have a lineno (previously only the first instruction in - the block was checked, leading to unnecessarily duplicated blocks). +- gh-92619: Make the compiler duplicate an exit block only if none of its + instructions have a lineno (previously only the first instruction in the + block was checked, leading to unnecessarily duplicated blocks). -- gh-issue-88750: The deprecated debug build only ``PYTHONTHREADDEBUG`` +- gh-88750: The deprecated debug build only ``PYTHONTHREADDEBUG`` environment variable no longer does anything. -- gh-issue-92261: Fix hang when trying to iterate over a ``typing.Union``. +- gh-92261: Fix hang when trying to iterate over a ``typing.Union``. -- gh-issue-91432: Specialized the :opcode:`FOR_ITER` opcode using the PEP - 659 machinery +- gh-91432: Specialized the :opcode:`FOR_ITER` opcode using the PEP 659 + machinery -- gh-issue-91399: Removed duplicate '{0, 0, 0, 0, 0, 0}' entry in +- gh-91399: Removed duplicate '{0, 0, 0, 0, 0, 0}' entry in 'Objects/unicodetype_db.h'. -- gh-issue-91578: Updates the error message for abstract class. +- gh-91578: Updates the error message for abstract class. - bpo-47091: Improve performance of repetition of :class:`list` and :class:`tuple` by using ``memcpy`` to copy data and performing the @@ -6659,85 +7550,84 @@ Core and Builtins Library ------- -- gh-issue-89237: Fix hang on Windows in ``subprocess.wait_closed()`` in +- gh-89237: Fix hang on Windows in ``subprocess.wait_closed()`` in :mod:`asyncio` with :class:`~asyncio.ProactorEventLoop`. Patch by Kumar Aditya. -- gh-issue-97928: :meth:`tkinter.Text.count` raises now an exception for - options starting with "-" instead of silently ignoring them. +- gh-97928: :meth:`tkinter.Text.count` raises now an exception for options + starting with "-" instead of silently ignoring them. -- gh-issue-98393: The :mod:`os` module no longer accepts bytes-like paths, - like :class:`bytearray` and :class:`memoryview` types: only the exact +- gh-98393: The :mod:`os` module no longer accepts bytes-like paths, like + :class:`bytearray` and :class:`memoryview` types: only the exact :class:`bytes` type is accepted for bytes strings. Patch by Victor Stinner. -- gh-issue-98363: Added itertools.batched() to batch data into lists of a - given length with the last list possibly being shorter than the others. +- gh-98363: Added itertools.batched() to batch data into lists of a given + length with the last list possibly being shorter than the others. -- gh-issue-98331: Update the bundled copies of pip and setuptools to - versions 22.3 and 65.5.0 respectively. +- gh-98331: Update the bundled copies of pip and setuptools to versions 22.3 + and 65.5.0 respectively. -- gh-issue-98307: A :meth:`~logging.handlers.SysLogHandler.createSocket` - method was added to :class:`~logging.handlers.SysLogHandler`. +- gh-98307: A :meth:`~logging.handlers.SysLogHandler.createSocket` method + was added to :class:`~logging.handlers.SysLogHandler`. -- gh-issue-96035: Fix bug in :func:`urllib.parse.urlparse` that causes - certain port numbers containing whitespace, underscores, plus and minus - signs, or non-ASCII digits to be incorrectly accepted. +- gh-96035: Fix bug in :func:`urllib.parse.urlparse` that causes certain + port numbers containing whitespace, underscores, plus and minus signs, or + non-ASCII digits to be incorrectly accepted. -- gh-issue-98257: Make :func:`sys.setprofile` and :func:`sys.settrace` - functions reentrant. They can no long fail with: ``RuntimeError("Cannot - install a trace function while another trace function is being - installed")``. Patch by Victor Stinner. +- gh-98257: Make :func:`sys.setprofile` and :func:`sys.settrace` functions + reentrant. They can no long fail with: ``RuntimeError("Cannot install a + trace function while another trace function is being installed")``. Patch + by Victor Stinner. -- gh-issue-98251: Allow :mod:`venv` to pass along :envvar:`!PYTHON*` - variables to ``ensurepip`` and ``pip`` when they do not impact path - resolution +- gh-98251: Allow :mod:`venv` to pass along :envvar:`!PYTHON*` variables to + ``ensurepip`` and ``pip`` when they do not impact path resolution -- gh-issue-94597: Deprecated +- gh-94597: Deprecated :meth:`asyncio.AbstractEventLoopPolicy.get_child_watcher` and :meth:`asyncio.AbstractEventLoopPolicy.set_child_watcher` methods to be removed in Python 3.14. Patch by Kumar Aditya. -- gh-issue-98178: On macOS, fix a crash in :func:`syslog.syslog` in - multi-threaded applications. On macOS, the libc ``syslog()`` function is - not thread-safe, so :func:`syslog.syslog` no longer releases the GIL to - call it. Patch by Victor Stinner. +- gh-98178: On macOS, fix a crash in :func:`syslog.syslog` in multi-threaded + applications. On macOS, the libc ``syslog()`` function is not thread-safe, + so :func:`syslog.syslog` no longer releases the GIL to call it. Patch by + Victor Stinner. -- gh-issue-44098: Release the GIL when creating :class:`mmap.mmap` objects - on Unix. +- gh-44098: Release the GIL when creating :class:`mmap.mmap` objects on + Unix. -- gh-issue-87730: Wrap network errors consistently in urllib FTP support, so - the test suite doesn't fail when a network is available but the public +- gh-87730: Wrap network errors consistently in urllib FTP support, so the + test suite doesn't fail when a network is available but the public internet is not reachable. -- gh-issue-94597: The child watcher classes +- gh-94597: The child watcher classes :class:`~asyncio.MultiLoopChildWatcher`, :class:`~asyncio.FastChildWatcher` and :class:`~asyncio.SafeChildWatcher` are deprecated and will be removed in Python 3.14. Patch by Kumar Aditya. -- gh-issue-98023: Change default child watcher to +- gh-98023: Change default child watcher to :class:`~asyncio.PidfdChildWatcher` on Linux systems which supports it. Patch by Kumar Aditya. -- gh-issue-90985: Earlier in 3.11 we deprecated +- gh-90985: Earlier in 3.11 we deprecated ``asyncio.Task.cancel("message")``. We realized we were too harsh, and have undeprecated it. -- gh-issue-65961: Do not rely solely on ``__cached__`` on modules; code will - also support ``__spec__.cached``. +- gh-65961: Do not rely solely on ``__cached__`` on modules; code will also + support ``__spec__.cached``. -- gh-issue-97646: Replace deprecated ``application/javascript`` with +- gh-97646: Replace deprecated ``application/javascript`` with ``text/javascript`` in :mod:`mimetypes`. See :rfc:`9239`. Patch by Noam Cohen. -- gh-issue-97930: Apply changes from importlib_resources 5.8 and 5.9: +- gh-97930: Apply changes from importlib_resources 5.8 and 5.9: ``Traversable.joinpath`` provides a concrete implementation. ``as_file`` now supports directories of resources. -- gh-issue-97850: Remove deprecated :func:`!importlib.util.set_loader` and +- gh-97850: Remove deprecated :func:`!importlib.util.set_loader` and :func:`!importlib.util.module_for_loader` from :mod:`importlib.util`. -- gh-issue-97837: Change deprecate warning message in :mod:`unittest` from +- gh-97837: Change deprecate warning message in :mod:`unittest` from ``It is deprecated to return a value!=None`` @@ -6745,46 +7635,46 @@ Library ``It is deprecated to return a value that is not None from a test case`` -- gh-issue-97825: Fixes :exc:`AttributeError` when - :meth:`subprocess.check_output` is used with argument ``input=None`` and - either of the arguments *encoding* or *errors* are used. +- gh-97825: Fixes :exc:`AttributeError` when :meth:`subprocess.check_output` + is used with argument ``input=None`` and either of the arguments + *encoding* or *errors* are used. -- gh-issue-97008: :exc:`NameError` and :exc:`AttributeError` spelling - suggestions provided since :gh:`82711` are now also emitted by the pure - Python :mod:`traceback` module. Tests for those suggestions now exercise - both implementations to ensure they are equivalent. Patch by Carl - Friedrich Bolz-Tereick and Łukasz Langa. +- gh-97008: :exc:`NameError` and :exc:`AttributeError` spelling suggestions + provided since :gh:`82711` are now also emitted by the pure Python + :mod:`traceback` module. Tests for those suggestions now exercise both + implementations to ensure they are equivalent. Patch by Carl Friedrich + Bolz-Tereick and Łukasz Langa. -- gh-issue-97799: :mod:`dataclass` now uses :func:`inspect.get_annotations` - to examine the annotations on class objects. +- gh-97799: :mod:`dataclass` now uses :func:`inspect.get_annotations` to + examine the annotations on class objects. -- gh-issue-97781: Removed deprecated interfaces in ``importlib.metadata`` - (entry points accessed as dictionary, implicit dictionary construction of +- gh-97781: Removed deprecated interfaces in ``importlib.metadata`` (entry + points accessed as dictionary, implicit dictionary construction of sequence of ``EntryPoint`` objects, mutablility of ``EntryPoints`` result, access of entry point by index). ``entry_points`` now has a simpler, more straightforward API (returning ``EntryPoints``). -- gh-issue-96827: Avoid spurious tracebacks from :mod:`asyncio` when default +- gh-96827: Avoid spurious tracebacks from :mod:`asyncio` when default executor cleanup is delayed until after the event loop is closed (e.g. as the result of a keyboard interrupt). -- gh-issue-95534: :meth:`gzip.GzipFile.read` reads 10% faster. +- gh-95534: :meth:`gzip.GzipFile.read` reads 10% faster. -- gh-issue-97592: Avoid a crash in the C version of +- gh-97592: Avoid a crash in the C version of :meth:`asyncio.Future.remove_done_callback` when an evil argument is passed. -- gh-issue-97639: Remove ``tokenize.NL`` check from :mod:`tabnanny`. +- gh-97639: Remove ``tokenize.NL`` check from :mod:`tabnanny`. -- gh-issue-97545: Make Semaphore run faster. +- gh-97545: Make Semaphore run faster. -- gh-issue-73588: Fix generation of the default name of +- gh-73588: Fix generation of the default name of :class:`tkinter.Checkbutton`. Previously, checkbuttons in different parent widgets could have the same short name and share the same state if arguments "name" and "variable" are not specified. Now they are globally unique. -- gh-issue-96865: fix Flag to use boundary CONFORM +- gh-96865: fix Flag to use boundary CONFORM This restores previous Flag behavior of allowing flags with non-sequential values to be combined; e.g. @@ -6793,396 +7683,391 @@ Library Skip.TWO | Skip.EIGHT -> -- gh-issue-97005: Update bundled libexpat to 2.4.9 +- gh-97005: Update bundled libexpat to 2.4.9 -- gh-issue-85760: Fix race condition in :mod:`asyncio` where +- gh-85760: Fix race condition in :mod:`asyncio` where :meth:`~asyncio.SubprocessProtocol.process_exited` called before the :meth:`~asyncio.SubprocessProtocol.pipe_data_received` leading to inconsistent output. Patch by Kumar Aditya. -- gh-issue-96704: Pass the correct ``contextvars.Context`` when a - ``asyncio`` exception handler is called on behalf of a task or callback - handle. This adds a new ``Task`` method, ``get_context``, and also a new - ``Handle`` method with the same name. If this method is not found on a - task object (perhaps because it is a third-party library that does not yet - provide this method), the context prevailing at the time the exception - handler is called is used. +- gh-96704: Pass the correct ``contextvars.Context`` when a ``asyncio`` + exception handler is called on behalf of a task or callback handle. This + adds a new ``Task`` method, ``get_context``, and also a new ``Handle`` + method with the same name. If this method is not found on a task object + (perhaps because it is a third-party library that does not yet provide + this method), the context prevailing at the time the exception handler is + called is used. -- gh-issue-96819: Fixed check in :mod:`multiprocessing.resource_tracker` - that guarantees that the length of a write to a pipe is not greater than +- gh-96819: Fixed check in :mod:`multiprocessing.resource_tracker` that + guarantees that the length of a write to a pipe is not greater than ``PIPE_BUF``. -- gh-issue-95865: Reduce :func:`urllib.parse.quote_from_bytes` memory use on - large values. +- gh-95865: Reduce :func:`urllib.parse.quote_from_bytes` memory use on large + values. Contributed by Dennis Sweeney. -- gh-issue-96741: Corrected type annotation for dataclass attribute +- gh-96741: Corrected type annotation for dataclass attribute ``pstats.FunctionProfile.ncalls`` to be ``str``. -- gh-issue-96734: Update :mod:`unicodedata` database to Unicode 15.0.0. +- gh-96734: Update :mod:`unicodedata` database to Unicode 15.0.0. -- gh-issue-96735: Fix undefined behaviour in :func:`struct.unpack`. +- gh-96735: Fix undefined behaviour in :func:`struct.unpack`. -- gh-issue-46412: Improve performance of ``bool(db)`` for large ndb/gdb - databases. Previously this would call ``len(db)`` which would iterate over - all keys -- the answer (empty or not) is known after the first key. +- gh-46412: Improve performance of ``bool(db)`` for large ndb/gdb databases. + Previously this would call ``len(db)`` which would iterate over all keys + -- the answer (empty or not) is known after the first key. -- gh-issue-96652: Fix the faulthandler implementation of +- gh-96652: Fix the faulthandler implementation of ``faulthandler.register(signal, chain=True)`` if the ``sigaction()`` function is not available: don't call the previous signal handler if it's NULL. Patch by Victor Stinner. -- gh-issue-68163: Correct conversion of :class:`numbers.Rational`'s to +- gh-68163: Correct conversion of :class:`numbers.Rational`'s to :class:`float`. -- gh-issue-96538: Speed up ``bisect.bisect()`` functions by taking advantage - of type-stability. +- gh-96538: Speed up ``bisect.bisect()`` functions by taking advantage of + type-stability. -- gh-issue-96465: Fraction hashes are now cached. +- gh-96465: Fraction hashes are now cached. -- gh-issue-96079: In :mod:`typing`, fix missing field ``name`` and incorrect +- gh-96079: In :mod:`typing`, fix missing field ``name`` and incorrect ``__module__`` in _AnnotatedAlias. -- gh-issue-96415: Remove ``types._cell_factory`` from module namespace. +- gh-96415: Remove ``types._cell_factory`` from module namespace. -- gh-issue-95987: Fix ``repr`` of ``Any`` subclasses. +- gh-95987: Fix ``repr`` of ``Any`` subclasses. -- gh-issue-96388: Work around missing socket functions in +- gh-96388: Work around missing socket functions in :class:`~socket.socket`'s ``__repr__``. -- gh-issue-96385: Fix ``TypeVarTuple.__typing_prepare_subst__``. - ``TypeError`` was not raised when using more than one ``TypeVarTuple``, - like ``[*T, *V]`` in type alias substitutions. +- gh-96385: Fix ``TypeVarTuple.__typing_prepare_subst__``. ``TypeError`` was + not raised when using more than one ``TypeVarTuple``, like ``[*T, *V]`` in + type alias substitutions. -- gh-issue-96142: Add ``match_args``, ``kw_only``, ``slots``, and - ``weakref_slot`` to ``_DataclassParams``. +- gh-96142: Add ``match_args``, ``kw_only``, ``slots``, and ``weakref_slot`` + to ``_DataclassParams``. -- gh-issue-96073: In :mod:`inspect`, fix overeager replacement of - "``typing.``" in formatting annotations. +- gh-96073: In :mod:`inspect`, fix overeager replacement of "``typing.``" in + formatting annotations. -- gh-issue-89258: Added a :meth:`~logging.Logger.getChildren` method to +- gh-89258: Added a :meth:`~logging.Logger.getChildren` method to :class:`logging.Logger`, to get the immediate child loggers of a logger. -- gh-issue-96346: Use double caching for compiled RE patterns. +- gh-96346: Use double caching for compiled RE patterns. -- gh-issue-96349: Fixed a minor performance regression in +- gh-96349: Fixed a minor performance regression in :func:`threading.Event.__init__` -- gh-issue-90467: Fix :class:`asyncio.streams.StreamReaderProtocol` to keep - a strong reference to the created task, so that it's not garbage collected +- gh-90467: Fix :class:`asyncio.streams.StreamReaderProtocol` to keep a + strong reference to the created task, so that it's not garbage collected -- gh-issue-96172: Fix a bug in ``unicodedata``: ``east_asian_width`` used to +- gh-96172: Fix a bug in ``unicodedata``: ``east_asian_width`` used to return the wrong value for unassigned characters; and for yet unassigned, but reserved characters. -- gh-issue-96159: Fix a performance regression in logging +- gh-96159: Fix a performance regression in logging TimedRotatingFileHandler. Only check for special files when the rollover time has passed. -- gh-issue-96175: Fix unused ``localName`` parameter in the ``Attr`` class - in :mod:`xml.dom.minidom`. +- gh-96175: Fix unused ``localName`` parameter in the ``Attr`` class in + :mod:`xml.dom.minidom`. -- gh-issue-96145: Add AttrDict to JSON module for use with object_hook. +- gh-96145: Add AttrDict to JSON module for use with object_hook. -- gh-issue-96052: Fix handling compiler warnings (SyntaxWarning and +- gh-96052: Fix handling compiler warnings (SyntaxWarning and DeprecationWarning) in :func:`codeop.compile_command` when checking for incomplete input. Previously it emitted warnings and raised a SyntaxError. Now it always returns ``None`` for incomplete input without emitting any warnings. -- gh-issue-96125: Fix incorrect condition that causes - ``sys.thread_info.name`` to be wrong on pthread platforms. +- gh-96125: Fix incorrect condition that causes ``sys.thread_info.name`` to + be wrong on pthread platforms. -- gh-issue-96019: Fix a bug in the ``makeunicodedata.py`` script leading to - about 13 KiB of space saving in the ``unicodedata`` module, specifically - the character decomposition data. +- gh-96019: Fix a bug in the ``makeunicodedata.py`` script leading to about + 13 KiB of space saving in the ``unicodedata`` module, specifically the + character decomposition data. -- gh-issue-95463: Remove an incompatible change from :issue:`28080` that - caused a regression that ignored the utf8 in ``ZipInfo.flag_bits``. Patch - by Pablo Galindo. +- gh-95463: Remove an incompatible change from :issue:`28080` that caused a + regression that ignored the utf8 in ``ZipInfo.flag_bits``. Patch by Pablo + Galindo. -- gh-issue-69142: Add ``%:z`` strftime format code (generates tzoffset with - colons as separator), see :ref:`strftime-strptime-behavior`. +- gh-69142: Add ``%:z`` strftime format code (generates tzoffset with colons + as separator), see :ref:`strftime-strptime-behavior`. -- gh-issue-95899: Fix :class:`asyncio.Runner` to call +- gh-95899: Fix :class:`asyncio.Runner` to call :func:`asyncio.set_event_loop` only once to avoid calling :meth:`~asyncio.AbstractChildWatcher.attach_loop` multiple times on child watchers. Patch by Kumar Aditya. -- gh-issue-95736: Fix :class:`unittest.IsolatedAsyncioTestCase` to set event - loop before calling setup functions. Patch by Kumar Aditya. +- gh-95736: Fix :class:`unittest.IsolatedAsyncioTestCase` to set event loop + before calling setup functions. Patch by Kumar Aditya. -- gh-issue-95865: Speed up :func:`urllib.parse.quote_from_bytes` by - replacing a list comprehension with ``map()``. +- gh-95865: Speed up :func:`urllib.parse.quote_from_bytes` by replacing a + list comprehension with ``map()``. -- gh-issue-95861: Add support for computing Spearman's correlation - coefficient to the existing statistics.correlation() function. +- gh-95861: Add support for computing Spearman's correlation coefficient to + the existing statistics.correlation() function. -- gh-issue-95804: Fix ``logging`` shutdown handler so it respects +- gh-95804: Fix ``logging`` shutdown handler so it respects ``MemoryHandler.flushOnClose``. -- gh-issue-95704: When a task catches :exc:`asyncio.CancelledError` and - raises some other error, the other error should generally not silently be +- gh-95704: When a task catches :exc:`asyncio.CancelledError` and raises + some other error, the other error should generally not silently be suppressed. -- gh-issue-95149: The :class:`HTTPStatus ` enum offers a - couple of properties to indicate the HTTP status category e.g. +- gh-95149: The :class:`HTTPStatus ` enum offers a couple + of properties to indicate the HTTP status category e.g. ``HTTPStatus.OK.is_success``. -- gh-issue-95609: Update bundled pip to 22.2.2. +- gh-95609: Update bundled pip to 22.2.2. -- gh-issue-95289: Fix :class:`asyncio.TaskGroup` to propagate exception when +- gh-95289: Fix :class:`asyncio.TaskGroup` to propagate exception when :exc:`asyncio.CancelledError` was replaced with another exception by a context manager. Patch by Kumar Aditya and Guido van Rossum. -- gh-issue-94909: Fix incorrect joining of relative Windows paths with - drives in :class:`pathlib.PurePath` initializer. +- gh-94909: Fix incorrect joining of relative Windows paths with drives in + :class:`pathlib.PurePath` initializer. -- gh-issue-95385: Faster ``json.dumps()`` when sorting of keys is not - requested (default). +- gh-95385: Faster ``json.dumps()`` when sorting of keys is not requested + (default). -- gh-issue-83901: Improve :meth:`Signature.bind ` - error message for missing keyword-only arguments. +- gh-83901: Improve :meth:`Signature.bind ` error + message for missing keyword-only arguments. -- gh-issue-95339: Update bundled pip to 22.2.1. +- gh-95339: Update bundled pip to 22.2.1. -- gh-issue-95045: Fix GC crash when deallocating ``_lsprof.Profiler`` by +- gh-95045: Fix GC crash when deallocating ``_lsprof.Profiler`` by untracking it before calling any callbacks. Patch by Kumar Aditya. -- gh-issue-95231: Fail gracefully if :const:`~errno.EPERM` or +- gh-95231: Fail gracefully if :const:`~errno.EPERM` or :const:`~errno.ENOSYS` is raised when loading :mod:`crypt` methods. This may happen when trying to load ``MD5`` on a Linux kernel with :abbr:`FIPS (Federal Information Processing Standard)` enabled. -- gh-issue-95097: Fix :func:`asyncio.run` for :class:`asyncio.Task` +- gh-95097: Fix :func:`asyncio.run` for :class:`asyncio.Task` implementations without :meth:`~asyncio.Task.uncancel` method. Patch by Kumar Aditya. -- gh-issue-95087: Fix IndexError in parsing invalid date in the :mod:`email` +- gh-95087: Fix IndexError in parsing invalid date in the :mod:`email` module. -- gh-issue-95199: Upgrade bundled setuptools to 63.2.0. +- gh-95199: Upgrade bundled setuptools to 63.2.0. -- gh-issue-95194: Upgrade bundled pip to 22.2. +- gh-95194: Upgrade bundled pip to 22.2. -- gh-issue-93899: Fix check for existence of :const:`os.EFD_CLOEXEC`, +- gh-93899: Fix check for existence of :const:`os.EFD_CLOEXEC`, :const:`os.EFD_NONBLOCK` and :const:`os.EFD_SEMAPHORE` flags on older kernel versions where these flags are not present. Patch by Kumar Aditya. -- gh-issue-95166: Fix :meth:`concurrent.futures.Executor.map` to cancel the +- gh-95166: Fix :meth:`concurrent.futures.Executor.map` to cancel the currently waiting on future on an error - e.g. TimeoutError or KeyboardInterrupt. -- gh-issue-95132: Fix a :mod:`sqlite3` regression where ``*args`` and - ``**kwds`` were incorrectly relayed from :py:func:`~sqlite3.connect` to - the :class:`~sqlite3.Connection` factory. The regression was introduced in +- gh-95132: Fix a :mod:`sqlite3` regression where ``*args`` and ``**kwds`` + were incorrectly relayed from :py:func:`~sqlite3.connect` to the + :class:`~sqlite3.Connection` factory. The regression was introduced in 3.11a1 with PR 24421 (:gh:`85128`). Patch by Erlend E. Aasland. -- gh-issue-93157: Fix :mod:`fileinput` module didn't support ``errors`` - option when ``inplace`` is true. +- gh-93157: Fix :mod:`fileinput` module didn't support ``errors`` option + when ``inplace`` is true. -- gh-issue-91212: Fixed flickering of the turtle window when the tracer is - turned off. Patch by Shin-myoung-serp. +- gh-91212: Fixed flickering of the turtle window when the tracer is turned + off. Patch by Shin-myoung-serp. -- gh-issue-95077: Add deprecation warning for enum ``member.member`` access - (e.g. ``Color.RED.BLUE``). Remove ``EnumMeta.__getattr__``. +- gh-95077: Add deprecation warning for enum ``member.member`` access (e.g. + ``Color.RED.BLUE``). Remove ``EnumMeta.__getattr__``. -- gh-issue-95109: Ensure that timeouts scheduled with - :class:`asyncio.Timeout` that have already expired are delivered promptly. +- gh-95109: Ensure that timeouts scheduled with :class:`asyncio.Timeout` + that have already expired are delivered promptly. -- gh-issue-95105: :meth:`wsgiref.types.InputStream.__iter__` should return +- gh-95105: :meth:`wsgiref.types.InputStream.__iter__` should return ``Iterator[bytes]``, not ``Iterable[bytes]``. Patch by Shantanu Jain. -- gh-issue-95066: Replaced assert with exception in :func:`ast.parse`, when +- gh-95066: Replaced assert with exception in :func:`ast.parse`, when ``feature_version`` has an invalid major version. Patch by Shantanu Jain. -- gh-issue-77617: Add :mod:`sqlite3` :ref:`command-line interface - `. Patch by Erlend Aasland. +- gh-77617: Add :mod:`sqlite3` :ref:`command-line interface `. + Patch by Erlend Aasland. -- gh-issue-95005: Replace :c:expr:`_PyAccu` with :c:expr:`_PyUnicodeWriter` - in JSON encoder and StringIO and remove the :c:expr:`_PyAccu` - implementation. +- gh-95005: Replace :c:expr:`_PyAccu` with :c:expr:`_PyUnicodeWriter` in + JSON encoder and StringIO and remove the :c:expr:`_PyAccu` implementation. -- gh-issue-90085: Remove ``-c/--clock`` and ``-t/--time`` CLI options of +- gh-90085: Remove ``-c/--clock`` and ``-t/--time`` CLI options of :mod:`timeit`. The options had been deprecated since Python 3.3 and the functionality was removed in Python 3.7. Patch by Shantanu Jain. -- gh-issue-94857: Fix refleak in ``_io.TextIOWrapper.reconfigure``. Patch by - Kumar Aditya. +- gh-94857: Fix refleak in ``_io.TextIOWrapper.reconfigure``. Patch by Kumar + Aditya. -- gh-issue-94821: Fix binding of unix socket to empty address on Linux to - use an available address from the abstract namespace, instead of "\0". +- gh-94821: Fix binding of unix socket to empty address on Linux to use an + available address from the abstract namespace, instead of "\0". -- gh-issue-94736: Fix crash when deallocating an instance of a subclass of +- gh-94736: Fix crash when deallocating an instance of a subclass of ``_multiprocessing.SemLock``. Patch by Kumar Aditya. -- gh-issue-81620: Add random.binomialvariate(). +- gh-81620: Add random.binomialvariate(). -- gh-issue-74116: Allow :meth:`asyncio.StreamWriter.drain` to be awaited +- gh-74116: Allow :meth:`asyncio.StreamWriter.drain` to be awaited concurrently by multiple tasks. Patch by Kumar Aditya. -- gh-issue-87822: When called with ``capture_locals=True``, the - :mod:`traceback` module functions swallow exceptions raised from calls to - ``repr()`` on local variables of frames. This is in order to prioritize - the original exception over rendering errors. An indication of the - failure is printed in place of the missing value. (Patch by Simon-Martin - Schroeder). +- gh-87822: When called with ``capture_locals=True``, the :mod:`traceback` + module functions swallow exceptions raised from calls to ``repr()`` on + local variables of frames. This is in order to prioritize the original + exception over rendering errors. An indication of the failure is printed + in place of the missing value. (Patch by Simon-Martin Schroeder). -- gh-issue-88050: Fix :mod:`asyncio` subprocess transport to kill process - cleanly when process is blocked and avoid ``RuntimeError`` when loop is - closed. Patch by Kumar Aditya. +- gh-88050: Fix :mod:`asyncio` subprocess transport to kill process cleanly + when process is blocked and avoid ``RuntimeError`` when loop is closed. + Patch by Kumar Aditya. -- gh-issue-94637: :meth:`SSLContext.set_default_verify_paths` now releases - the GIL around ``SSL_CTX_set_default_verify_paths`` call. The function - call performs I/O and CPU intensive work. +- gh-94637: :meth:`SSLContext.set_default_verify_paths` now releases the GIL + around ``SSL_CTX_set_default_verify_paths`` call. The function call + performs I/O and CPU intensive work. -- gh-issue-94309: Deprecate aliases :class:`typing.Hashable` and +- gh-94309: Deprecate aliases :class:`typing.Hashable` and :class:`typing.Sized` -- gh-issue-92546: An undocumented ``python -m pprint`` benchmark is moved - into ``pprint`` suite of pyperformance. Patch by Oleg Iarygin. +- gh-92546: An undocumented ``python -m pprint`` benchmark is moved into + ``pprint`` suite of pyperformance. Patch by Oleg Iarygin. -- gh-issue-94607: Fix subclassing complex generics with type variables in +- gh-94607: Fix subclassing complex generics with type variables in :mod:`typing`. Previously an error message saying ``Some type variables ... are not listed in Generic[...]`` was shown. :mod:`typing` no longer populates ``__parameters__`` with the ``__parameters__`` of a Python class. -- gh-issue-94619: Remove the long-deprecated ``module_repr()`` from +- gh-94619: Remove the long-deprecated ``module_repr()`` from :mod:`importlib`. -- gh-issue-93910: The ability to access the other values of an enum on an - enum (e.g. ``Color.RED.BLUE``) has been restored in order to fix a - performance regression. +- gh-93910: The ability to access the other values of an enum on an enum + (e.g. ``Color.RED.BLUE``) has been restored in order to fix a performance + regression. -- gh-issue-93896: Fix :func:`asyncio.run` and +- gh-93896: Fix :func:`asyncio.run` and :class:`unittest.IsolatedAsyncioTestCase` to always the set event loop as it was done in Python 3.10 and earlier. Patch by Kumar Aditya. -- gh-issue-94343: Allow setting the attributes of ``reprlib.Repr`` during - object initialization - -- gh-issue-94382: Port static types of ``_multiprocessing`` module to heap - types. Patch by Kumar Aditya. +- gh-94343: Allow setting the attributes of ``reprlib.Repr`` during object + initialization -- gh-issue-78724: Fix crash in :class:`struct.Struct` when it was not - completely initialized by initializing it in :meth:`~object.__new__`. +- gh-94382: Port static types of ``_multiprocessing`` module to heap types. Patch by Kumar Aditya. -- gh-issue-94510: Re-entrant calls to :func:`sys.setprofile` and +- gh-78724: Fix crash in :class:`struct.Struct` when it was not completely + initialized by initializing it in :meth:`~object.__new__`. Patch by Kumar + Aditya. + +- gh-94510: Re-entrant calls to :func:`sys.setprofile` and :func:`sys.settrace` now raise :exc:`RuntimeError`. Patch by Pablo Galindo. -- gh-issue-92336: Fix bug where :meth:`linecache.getline` fails on bad files - with :exc:`UnicodeDecodeError` or :exc:`SyntaxError`. It now returns an - empty string as per the documentation. +- gh-92336: Fix bug where :meth:`linecache.getline` fails on bad files with + :exc:`UnicodeDecodeError` or :exc:`SyntaxError`. It now returns an empty + string as per the documentation. -- gh-issue-94398: Once a :class:`asyncio.TaskGroup` has started shutting - down (i.e., at least one task has failed and the task group has started +- gh-94398: Once a :class:`asyncio.TaskGroup` has started shutting down + (i.e., at least one task has failed and the task group has started cancelling the remaining tasks), it should not be possible to add new tasks to the task group. -- gh-issue-94383: :mod:`xml.etree`: Remove the - ``ElementTree.Element.copy()`` method of the pure Python implementation, - deprecated in Python 3.10, use the :func:`copy.copy` function instead. The - C implementation of :mod:`xml.etree` has no ``copy()`` method, only a - ``__copy__()`` method. Patch by Victor Stinner. +- gh-94383: :mod:`xml.etree`: Remove the ``ElementTree.Element.copy()`` + method of the pure Python implementation, deprecated in Python 3.10, use + the :func:`copy.copy` function instead. The C implementation of + :mod:`xml.etree` has no ``copy()`` method, only a ``__copy__()`` method. + Patch by Victor Stinner. -- gh-issue-94379: :mod:`zipimport`: Remove ``find_loader()`` and - ``find_module()`` methods, deprecated in Python 3.10: use the - ``find_spec()`` method instead. See :pep:`451` for the rationale. Patch by - Victor Stinner. +- gh-94379: :mod:`zipimport`: Remove ``find_loader()`` and ``find_module()`` + methods, deprecated in Python 3.10: use the ``find_spec()`` method + instead. See :pep:`451` for the rationale. Patch by Victor Stinner. -- gh-issue-94352: :func:`shlex.split`: Passing ``None`` for *s* argument now +- gh-94352: :func:`shlex.split`: Passing ``None`` for *s* argument now raises an exception, rather than reading :data:`sys.stdin`. The feature was deprecated in Python 3.9. Patch by Victor Stinner. -- gh-issue-94318: Strip trailing spaces in :mod:`pydoc` text output. +- gh-94318: Strip trailing spaces in :mod:`pydoc` text output. -- gh-issue-89988: Fix memory leak in :class:`pickle.Pickler` when looking up +- gh-89988: Fix memory leak in :class:`pickle.Pickler` when looking up :attr:`dispatch_table`. Patch by Kumar Aditya. -- gh-issue-90016: Deprecate :mod:`sqlite3` :ref:`default adapters and - converters `. Patch by Erlend E. Aasland. +- gh-90016: Deprecate :mod:`sqlite3` :ref:`default adapters and converters + `. Patch by Erlend E. Aasland. -- gh-issue-94254: Fixed types of :mod:`struct` module to be immutable. Patch - by Kumar Aditya. +- gh-94254: Fixed types of :mod:`struct` module to be immutable. Patch by + Kumar Aditya. -- gh-issue-93259: Now raise ``ValueError`` when ``None`` or an empty string - are passed to ``Distribution.from_name`` (and other callers). +- gh-93259: Now raise ``ValueError`` when ``None`` or an empty string are + passed to ``Distribution.from_name`` (and other callers). -- gh-issue-74696: :func:`shutil.make_archive` now passes the *root_dir* - argument to custom archivers which support it. +- gh-74696: :func:`shutil.make_archive` now passes the *root_dir* argument + to custom archivers which support it. -- gh-issue-94216: The :mod:`dis` module now has the opcodes for pseudo +- gh-94216: The :mod:`dis` module now has the opcodes for pseudo instructions (those which are used by the compiler during code generation but then removed or replaced by real opcodes before the final bytecode is emitted). -- gh-issue-93096: Removed undocumented ``python -m codecs``. Use ``python -m +- gh-93096: Removed undocumented ``python -m codecs``. Use ``python -m unittest test.test_codecs.EncodedFileTest`` instead. -- gh-issue-94207: Made :class:`_struct.Struct` GC-tracked in order to fix a - reference leak in the :mod:`_struct` module. +- gh-94207: Made :class:`!_struct.Struct` GC-tracked in order to fix a + reference leak in the :mod:`!_struct` module. -- gh-issue-93096: Removed undocumented ``-t`` argument of ``python -m - base64``. Use ``python -m unittest +- gh-93096: Removed undocumented ``-t`` argument of ``python -m base64``. + Use ``python -m unittest test.test_base64.LegacyBase64TestCase.test_encodebytes`` instead. -- gh-issue-94226: Remove the :func:`locale.format` function, deprecated in - Python 3.7: use :func:`locale.format_string` instead. Patch by Victor - Stinner. +- gh-94226: Remove the :func:`locale.format` function, deprecated in Python + 3.7: use :func:`locale.format_string` instead. Patch by Victor Stinner. -- gh-issue-94199: Remove the :func:`ssl.match_hostname` function. The +- gh-94199: Remove the :func:`ssl.match_hostname` function. The :func:`ssl.match_hostname` was deprecated in Python 3.7. OpenSSL performs hostname matching since Python 3.7, Python no longer uses the :func:`ssl.match_hostname` function. Patch by Victor Stinner. -- gh-issue-94214: Document the ``context`` object used in the - ``venv.EnvBuilder`` class, and add the new environment's library path to - it. +- gh-94214: Document the ``context`` object used in the ``venv.EnvBuilder`` + class, and add the new environment's library path to it. -- gh-issue-94199: Remove the :func:`ssl.wrap_socket` function, deprecated in +- gh-94199: Remove the :func:`ssl.wrap_socket` function, deprecated in Python 3.7: instead, create a :class:`ssl.SSLContext` object and call its :class:`ssl.SSLContext.wrap_socket` method. Any package that still uses :func:`ssl.wrap_socket` is broken and insecure. The function neither sends a SNI TLS extension nor validates server hostname. Code is subject to :cwe:`295` Improper Certificate Validation. Patch by Victor Stinner. -- gh-issue-94199: Remove the :func:`ssl.RAND_pseudo_bytes` function, - deprecated in Python 3.6: use :func:`os.urandom` or :func:`ssl.RAND_bytes` - instead. Patch by Victor Stinner. +- gh-94199: Remove the :func:`ssl.RAND_pseudo_bytes` function, deprecated in + Python 3.6: use :func:`os.urandom` or :func:`ssl.RAND_bytes` instead. + Patch by Victor Stinner. -- gh-issue-94199: :mod:`hashlib`: Remove the pure Python implementation of - :func:`hashlib.pbkdf2_hmac()`, deprecated in Python 3.10. Python 3.10 and +- gh-94199: :mod:`hashlib`: Remove the pure Python implementation of + :func:`hashlib.pbkdf2_hmac`, deprecated in Python 3.10. Python 3.10 and newer requires OpenSSL 1.1.1 (:pep:`644`): this OpenSSL version provides a - C implementation of :func:`~hashlib.pbkdf2_hmac()` which is faster. Patch - by Victor Stinner. + C implementation of :func:`~hashlib.pbkdf2_hmac` which is faster. Patch by + Victor Stinner. -- gh-issue-94196: :mod:`gzip`: Remove the ``filename`` attribute of +- gh-94196: :mod:`gzip`: Remove the ``filename`` attribute of :class:`gzip.GzipFile`, deprecated since Python 2.6, use the :attr:`~gzip.GzipFile.name` attribute instead. In write mode, the ``filename`` attribute added ``'.gz'`` file extension if it was not present. Patch by Victor Stinner. -- gh-issue-94182: run the :class:`asyncio.PidfdChildWatcher` on the running - loop, this allows event loops to run subprocesses when there is no default - event loop running on the main thread +- gh-94182: run the :class:`asyncio.PidfdChildWatcher` on the running loop, + this allows event loops to run subprocesses when there is no default event + loop running on the main thread -- gh-issue-94169: Remove ``io.OpenWrapper`` and ``_pyio.OpenWrapper``, - deprecated in Python 3.10: just use :func:`open` instead. The :func:`open` +- gh-94169: Remove ``io.OpenWrapper`` and ``_pyio.OpenWrapper``, deprecated + in Python 3.10: just use :func:`open` instead. The :func:`open` (:func:`io.open`) function is a built-in function. Since Python 3.10, - :func:`_pyio.open` is also a static method. Patch by Victor Stinner. + :func:`!_pyio.open` is also a static method. Patch by Victor Stinner. -- gh-issue-91742: Fix :mod:`pdb` crash after jump caused by a null pointer +- gh-91742: Fix :mod:`pdb` crash after jump caused by a null pointer dereference. Patch by Kumar Aditya. -- gh-issue-94101: Manual instantiation of :class:`ssl.SSLSession` objects is - no longer allowed as it lead to misconfigured instances that crashed the +- gh-94101: Manual instantiation of :class:`ssl.SSLSession` objects is no + longer allowed as it lead to misconfigured instances that crashed the interpreter when attributes where accessed on them. -- gh-issue-84753: :func:`inspect.iscoroutinefunction`, +- gh-84753: :func:`inspect.iscoroutinefunction`, :func:`inspect.isgeneratorfunction`, and :func:`inspect.isasyncgenfunction` now properly return ``True`` for duck-typed function-like objects like instances of @@ -7191,303 +8076,296 @@ Library This makes :func:`inspect.iscoroutinefunction` consistent with the behavior of :func:`asyncio.iscoroutinefunction`. Patch by Mehdi ABAAKOUK. -- gh-issue-94028: Fix a regression in the :mod:`sqlite3` where statement - objects were not properly cleared and reset after use in cursor iters. The +- gh-94028: Fix a regression in the :mod:`sqlite3` where statement objects + were not properly cleared and reset after use in cursor iters. The regression was introduced by PR 27884 in Python 3.11a1. Patch by Erlend E. Aasland. -- gh-issue-93973: Add keyword argument ``all_errors`` to +- gh-93973: Add keyword argument ``all_errors`` to ``asyncio.create_connection`` so that multiple connection errors can be raised as an ``ExceptionGroup``. -- gh-issue-93963: Officially deprecate from ``importlib.abc`` classes moved - to ``importlib.resources.abc``. +- gh-93963: Officially deprecate from ``importlib.abc`` classes moved to + ``importlib.resources.abc``. -- gh-issue-93858: Prevent error when activating venv in nested fish - instances. +- gh-93858: Prevent error when activating venv in nested fish instances. -- gh-issue-93820: Pickle :class:`enum.Flag` by name. +- gh-93820: Pickle :class:`enum.Flag` by name. -- gh-issue-93847: Fix repr of enum of generic aliases. +- gh-93847: Fix repr of enum of generic aliases. -- gh-issue-91404: Revert the :mod:`re` memory leak when a match is - terminated by a signal or memory allocation failure as the implemented fix - caused a major performance regression. +- gh-91404: Revert the :mod:`re` memory leak when a match is terminated by a + signal or memory allocation failure as the implemented fix caused a major + performance regression. -- gh-issue-83499: Fix double closing of file description in :mod:`tempfile`. +- gh-83499: Fix double closing of file description in :mod:`tempfile`. -- gh-issue-93820: Fixed a regression when :func:`copy.copy`-ing - :class:`enum.Flag` with multiple flag members. +- gh-93820: Fixed a regression when :func:`copy.copy`-ing :class:`enum.Flag` + with multiple flag members. -- gh-issue-79512: Fixed names and ``__module__`` value of :mod:`weakref` - classes :class:`~weakref.ReferenceType`, :class:`~weakref.ProxyType`, +- gh-79512: Fixed names and ``__module__`` value of :mod:`weakref` classes + :class:`~weakref.ReferenceType`, :class:`~weakref.ProxyType`, :class:`~weakref.CallableProxyType`. It makes them pickleable. -- gh-issue-91389: Fix an issue where :mod:`dis` utilities could report - missing or incorrect position information in the presence of ``CACHE`` - entries. +- gh-91389: Fix an issue where :mod:`dis` utilities could report missing or + incorrect position information in the presence of ``CACHE`` entries. -- gh-issue-93626: Set ``__future__.annotations`` to have a ``None`` +- gh-93626: Set ``__future__.annotations`` to have a ``None`` mandatoryRelease to indicate that it is currently 'TBD'. -- gh-issue-90473: Emscripten and WASI have no home directory and cannot - provide :pep:`370` user site directory. +- gh-90473: Emscripten and WASI have no home directory and cannot provide + :pep:`370` user site directory. -- gh-issue-90494: :func:`copy.copy` and :func:`copy.deepcopy` now always - raise a TypeError if ``__reduce__()`` returns a tuple with length 6 - instead of silently ignore the 6th item or produce incorrect result. +- gh-90494: :func:`copy.copy` and :func:`copy.deepcopy` now always raise a + TypeError if ``__reduce__()`` returns a tuple with length 6 instead of + silently ignore the 6th item or produce incorrect result. -- gh-issue-90549: Fix a multiprocessing bug where a global named resource - (such as a semaphore) could leak when a child process is spawned (as - opposed to forked). +- gh-90549: Fix a multiprocessing bug where a global named resource (such as + a semaphore) could leak when a child process is spawned (as opposed to + forked). -- gh-issue-93521: Fixed a case where dataclasses would try to add - ``__weakref__`` into the ``__slots__`` for a dataclass that specified +- gh-93521: Fixed a case where dataclasses would try to add ``__weakref__`` + into the ``__slots__`` for a dataclass that specified ``weakref_slot=True`` when it was already defined in one of its bases. This resulted in a ``TypeError`` upon the new class being created. -- gh-issue-79579: :mod:`sqlite3` now correctly detects DML queries with - leading comments. Patch by Erlend E. Aasland. +- gh-79579: :mod:`sqlite3` now correctly detects DML queries with leading + comments. Patch by Erlend E. Aasland. -- gh-issue-93421: Update :data:`sqlite3.Cursor.rowcount` when a DML - statement has run to completion. This fixes the row count for SQL queries - like ``UPDATE ... RETURNING``. Patch by Erlend E. Aasland. +- gh-93421: Update :data:`sqlite3.Cursor.rowcount` when a DML statement has + run to completion. This fixes the row count for SQL queries like ``UPDATE + ... RETURNING``. Patch by Erlend E. Aasland. -- gh-issue-93475: Expose ``FICLONE`` and ``FICLONERANGE`` constants in +- gh-93475: Expose ``FICLONE`` and ``FICLONERANGE`` constants in :mod:`fcntl`. Patch by Illia Volochii. -- gh-issue-93370: Deprecate :data:`sqlite3.version` and +- gh-93370: Deprecate :data:`sqlite3.version` and :data:`sqlite3.version_info`. -- gh-issue-91810: Suppress writing an XML declaration in open files in +- gh-91810: Suppress writing an XML declaration in open files in ``ElementTree.write()`` with ``encoding='unicode'`` and ``xml_declaration=None``. -- gh-issue-91162: Support splitting of unpacked arbitrary-length tuple over +- gh-91162: Support splitting of unpacked arbitrary-length tuple over ``TypeVar`` and ``TypeVarTuple`` parameters. For example: * ``A[T, *Ts][*tuple[int, ...]]`` -> ``A[int, *tuple[int, ...]]`` * ``A[*Ts, T][*tuple[int, ...]]`` -> ``A[*tuple[int, ...], int]`` -- gh-issue-93353: Fix the :func:`importlib.resources.as_file` context - manager to remove the temporary file if destroyed late during Python - finalization: keep a local reference to the :func:`os.remove` function. - Patch by Victor Stinner. +- gh-93353: Fix the :func:`importlib.resources.as_file` context manager to + remove the temporary file if destroyed late during Python finalization: + keep a local reference to the :func:`os.remove` function. Patch by Victor + Stinner. -- gh-issue-83658: Make :class:`multiprocessing.Pool` raise an exception if +- gh-83658: Make :class:`multiprocessing.Pool` raise an exception if ``maxtasksperchild`` is not ``None`` or a positive int. -- gh-issue-93312: Add :const:`os.PIDFD_NONBLOCK` flag to open a file - descriptor for a process with :func:`os.pidfd_open` in non-blocking mode. - Patch by Kumar Aditya. +- gh-93312: Add :const:`os.PIDFD_NONBLOCK` flag to open a file descriptor + for a process with :func:`os.pidfd_open` in non-blocking mode. Patch by + Kumar Aditya. -- gh-issue-88123: Implement ``Enum.__contains__`` that returns ``True`` or +- gh-88123: Implement ``Enum.__contains__`` that returns ``True`` or ``False`` to replace the deprecated behaviour that would sometimes raise a :exc:`TypeError`. -- gh-issue-93297: Make asyncio task groups prevent child tasks from being - GCed +- gh-93297: Make asyncio task groups prevent child tasks from being GCed -- gh-issue-85308: Changed :class:`argparse.ArgumentParser` to use +- gh-85308: Changed :class:`argparse.ArgumentParser` to use :term:`filesystem encoding and error handler` instead of default text encoding to read arguments from file (e.g. ``fromfile_prefix_chars`` option). This change affects Windows; argument file should be encoded with UTF-8 instead of ANSI Codepage. -- gh-issue-93156: Accessing the :attr:`pathlib.PurePath.parents` sequence of - an absolute path using negative index values produced incorrect results. +- gh-93156: Accessing the :attr:`pathlib.PurePath.parents` sequence of an + absolute path using negative index values produced incorrect results. -- gh-issue-93162: Add the ability for :func:`logging.config.dictConfig` to +- gh-93162: Add the ability for :func:`logging.config.dictConfig` to usefully configure :class:`~logging.handlers.QueueHandler` and :class:`~logging.handlers.QueueListener` as a pair, and add :func:`logging.getHandlerByName` and :func:`logging.getHandlerNames` APIs to allow access to handlers by name. -- gh-issue-93243: The :mod:`!smtpd` module was removed per the schedule in +- gh-93243: The :mod:`!smtpd` module was removed per the schedule in :pep:`594`. -- gh-issue-92886: Replace ``assert`` statements with ``raise - AssertionError()`` in :class:`~wsgiref.BaseHandler` so that the tested - behaviour is maintained running with optimizations ``(-O)``. +- gh-92886: Replace ``assert`` statements with ``raise AssertionError()`` in + :class:`~wsgiref.BaseHandler` so that the tested behaviour is maintained + running with optimizations ``(-O)``. -- gh-issue-90155: Fix broken :class:`asyncio.Semaphore` when acquire is - cancelled. +- gh-90155: Fix broken :class:`asyncio.Semaphore` when acquire is cancelled. -- gh-issue-90817: The :func:`locale.resetlocale` function is deprecated and - will be removed in Python 3.13. Use ``locale.setlocale(locale.LC_ALL, - "")`` instead. Patch by Victor Stinner. +- gh-90817: The :func:`locale.resetlocale` function is deprecated and will + be removed in Python 3.13. Use ``locale.setlocale(locale.LC_ALL, "")`` + instead. Patch by Victor Stinner. -- gh-issue-91513: Added ``taskName`` attribute to :mod:`logging` module for - use with :mod:`asyncio` tasks. +- gh-91513: Added ``taskName`` attribute to :mod:`logging` module for use + with :mod:`asyncio` tasks. -- gh-issue-74696: :func:`shutil.make_archive` no longer temporarily changes - the current working directory during creation of standard ``.zip`` or tar +- gh-74696: :func:`shutil.make_archive` no longer temporarily changes the + current working directory during creation of standard ``.zip`` or tar archives. -- gh-issue-92728: The :func:`re.template` function and the corresponding +- gh-92728: The :func:`re.template` function and the corresponding :const:`re.TEMPLATE` and :const:`re.T` flags are restored after they were removed in 3.11.0b1, but they are now deprecated, so they might be removed from Python 3.13. -- gh-issue-93033: Search in some strings (platform dependent i.e [U+0xFFFF, +- gh-93033: Search in some strings (platform dependent i.e [U+0xFFFF, U+0x0100] on Windows or [U+0xFFFFFFFF, U+0x00010000] on Linux 64-bit) are now up to 10 times faster. -- gh-issue-89973: Fix :exc:`re.error` raised in :mod:`fnmatch` if the - pattern contains a character range with upper bound lower than lower bound - (e.g. ``[c-a]``). Now such ranges are interpreted as empty ranges. +- gh-89973: Fix :exc:`re.error` raised in :mod:`fnmatch` if the pattern + contains a character range with upper bound lower than lower bound (e.g. + ``[c-a]``). Now such ranges are interpreted as empty ranges. -- gh-issue-93044: No longer convert the database argument of +- gh-93044: No longer convert the database argument of :func:`sqlite3.connect` to bytes before passing it to the factory. -- gh-issue-93010: In a very special case, the email package tried to append - the nonexistent ``InvalidHeaderError`` to the defect list. It should have - been ``InvalidHeaderDefect``. +- gh-93010: In a very special case, the email package tried to append the + nonexistent ``InvalidHeaderError`` to the defect list. It should have been + ``InvalidHeaderDefect``. -- gh-issue-92986: Fix :func:`ast.unparse` when ``ImportFrom.level`` is - ``None`` +- gh-92986: Fix :func:`ast.unparse` when ``ImportFrom.level`` is ``None`` -- gh-issue-92932: Now :func:`~dis.dis` and :func:`~dis.get_instructions` - handle operand values for instructions prefixed by ``EXTENDED_ARG_QUICK``. - Patch by Sam Gross and Donghee Na. +- gh-92932: Now :func:`~dis.dis` and :func:`~dis.get_instructions` handle + operand values for instructions prefixed by ``EXTENDED_ARG_QUICK``. Patch + by Sam Gross and Donghee Na. -- gh-issue-92675: Fix :func:`venv.ensure_directories` to accept +- gh-92675: Fix :func:`venv.ensure_directories` to accept :class:`pathlib.Path` arguments in addition to :class:`str` paths. Patch by David Foster. -- gh-issue-87901: Removed the ``encoding`` argument from :func:`os.popen` - that was added in 3.11b1. +- gh-87901: Removed the ``encoding`` argument from :func:`os.popen` that was + added in 3.11b1. -- gh-issue-91922: Fix function :func:`sqlite.connect` and the +- gh-91922: Fix function :func:`sqlite.connect` and the :class:`sqlite.Connection` constructor on non-UTF-8 locales. Also, they now support bytes paths non-decodable with the current FS encoding. -- gh-issue-92869: Added :class:`~ctypes.c_time_t` to :mod:`ctypes`, which - has the same size as the :c:type:`time_t` type in C. +- gh-92869: Added :class:`~ctypes.c_time_t` to :mod:`ctypes`, which has the + same size as the :c:type:`time_t` type in C. -- gh-issue-92839: Fixed crash resulting from calling bisect.insort() or +- gh-92839: Fixed crash resulting from calling bisect.insort() or bisect.insort_left() with the key argument not equal to ``None``. -- gh-issue-90473: :mod:`subprocess` now fails early on Emscripten and WASI +- gh-90473: :mod:`subprocess` now fails early on Emscripten and WASI platforms to work around missing :func:`os.pipe` on WASI. -- gh-issue-89325: Removed many old deprecated :mod:`unittest` features: +- gh-89325: Removed many old deprecated :mod:`unittest` features: :class:`~unittest.TestCase` method aliases, undocumented and broken :class:`~unittest.TestCase` method ``assertDictContainsSubset``, undocumented :meth:`TestLoader.loadTestsFromModule ` parameter *use_load_tests*, and an underscored alias of the :class:`~unittest.TextTestResult` class. -- gh-issue-92734: Allow multi-element reprs emitted by :mod:`reprlib` to be +- gh-92734: Allow multi-element reprs emitted by :mod:`reprlib` to be pretty-printed using configurable indentation. -- gh-issue-92671: Fixed :func:`ast.unparse` for empty tuples in the - assignment target context. +- gh-92671: Fixed :func:`ast.unparse` for empty tuples in the assignment + target context. -- gh-issue-91581: :meth:`~datetime.datetime.utcfromtimestamp` no longer - attempts to resolve ``fold`` in the pure Python implementation, since the - fold is never 1 in UTC. In addition to being slightly faster in the common - case, this also prevents some errors when the timestamp is close to +- gh-91581: :meth:`~datetime.datetime.utcfromtimestamp` no longer attempts + to resolve ``fold`` in the pure Python implementation, since the fold is + never 1 in UTC. In addition to being slightly faster in the common case, + this also prevents some errors when the timestamp is close to :attr:`datetime.min `. Patch by Paul Ganssle. -- gh-issue-86388: Removed randrange() functionality deprecated since Python - 3.10. Formerly, randrange(10.0) losslessly converted to randrange(10). - Now, it raises a TypeError. Also, the exception raised for non-integral - values such as randrange(10.5) or randrange('10') has been changed from +- gh-86388: Removed randrange() functionality deprecated since Python 3.10. + Formerly, randrange(10.0) losslessly converted to randrange(10). Now, it + raises a TypeError. Also, the exception raised for non-integral values + such as randrange(10.5) or randrange('10') has been changed from ValueError to TypeError. -- gh-issue-90385: Add :meth:`pathlib.Path.walk` as an alternative to +- gh-90385: Add :meth:`pathlib.Path.walk` as an alternative to :func:`os.walk`. -- gh-issue-92550: Fix :meth:`pathlib.Path.rglob` for empty pattern. +- gh-92550: Fix :meth:`pathlib.Path.rglob` for empty pattern. -- gh-issue-92591: Allow :mod:`logging` filters to return a +- gh-92591: Allow :mod:`logging` filters to return a :class:`logging.LogRecord` instance so that filters attached to :class:`logging.Handler`\ s can enrich records without side effects on other handlers. -- gh-issue-92445: Fix a bug in :mod:`argparse` where ``nargs="*"`` would - raise an error instead of returning an empty list when 0 arguments were - supplied if choice was also defined in ``parser.add_argument``. +- gh-92445: Fix a bug in :mod:`argparse` where ``nargs="*"`` would raise an + error instead of returning an empty list when 0 arguments were supplied if + choice was also defined in ``parser.add_argument``. -- gh-issue-92547: Remove undocumented :mod:`sqlite3` features deprecated in - Python 3.10: +- gh-92547: Remove undocumented :mod:`sqlite3` features deprecated in Python + 3.10: * ``sqlite3.enable_shared_cache()`` * ``sqlite3.OptimizedUnicode`` Patch by Erlend E. Aasland. -- gh-issue-92530: Fix an issue that occurred after interrupting +- gh-92530: Fix an issue that occurred after interrupting :func:`threading.Condition.notify`. -- gh-issue-92531: The statistics.median_grouped() function now always return - a float. Formerly, it did not convert the input type when for sequences of +- gh-92531: The statistics.median_grouped() function now always return a + float. Formerly, it did not convert the input type when for sequences of length one. -- gh-issue-84131: The :class:`pathlib.Path` deprecated method ``link_to`` - has been removed. Use 3.10's :meth:`~pathlib.Path.hardlink_to` method - instead as its semantics are consistent with that of +- gh-84131: The :class:`pathlib.Path` deprecated method ``link_to`` has been + removed. Use 3.10's :meth:`~pathlib.Path.hardlink_to` method instead as + its semantics are consistent with that of :meth:`~pathlib.Path.symlink_to`. -- gh-issue-89336: Removed :mod:`configparser` module APIs: the +- gh-89336: Removed :mod:`configparser` module APIs: the ``SafeConfigParser`` class alias, the ``ParsingError.filename`` property and parameter, and the ``ConfigParser.readfp`` method, all of which were deprecated since Python 3.2. -- gh-issue-92391: Add :meth:`~object.__class_getitem__` to +- gh-92391: Add :meth:`~object.__class_getitem__` to :class:`csv.DictReader` and :class:`csv.DictWriter`, allowing them to be parameterized at runtime. Patch by Marc Mueller. -- gh-issue-91968: Add ``SO_RTABLE`` and ``SO_USER_COOKIE`` constants to +- gh-91968: Add ``SO_RTABLE`` and ``SO_USER_COOKIE`` constants to :mod:`socket`. -- gh-issue-91810: :class:`~xml.etree.ElementTree.ElementTree` method +- gh-91810: :class:`~xml.etree.ElementTree.ElementTree` method :meth:`~xml.etree.ElementTree.ElementTree.write` and function :func:`~xml.etree.ElementTree.tostring` now use the text file's encoding ("UTF-8" if not available) instead of locale encoding in XML declaration when ``encoding="unicode"`` is specified. -- gh-issue-81790: :func:`os.path.splitdrive` now understands DOS device - paths with UNC links (beginning ``\\?\UNC\``). Contributed by Barney Gale. +- gh-81790: :func:`os.path.splitdrive` now understands DOS device paths with + UNC links (beginning ``\\?\UNC\``). Contributed by Barney Gale. -- gh-issue-91760: Apply more strict rules for numerical group references and - group names in regular expressions. Only sequence of ASCII digits is now +- gh-91760: Apply more strict rules for numerical group references and group + names in regular expressions. Only sequence of ASCII digits is now accepted as a numerical reference. The group name in bytes patterns and replacement strings can now only contain ASCII letters and digits and underscore. -- gh-issue-90622: Worker processes for +- gh-90622: Worker processes for :class:`concurrent.futures.ProcessPoolExecutor` are no longer spawned on demand (a feature added in 3.9) when the multiprocessing context start method is ``"fork"`` as that can lead to deadlocks in the child processes due to a fork happening while threads are running. -- gh-issue-91577: Move imports in :class:`~multiprocessing.SharedMemory` - methods to module level so that they can be executed late in python - finalization. +- gh-91577: Move imports in :class:`~multiprocessing.SharedMemory` methods + to module level so that they can be executed late in python finalization. -- gh-issue-91581: Remove an unhandled error case in the C implementation of - calls to :meth:`datetime.fromtimestamp ` - with no time zone (i.e. getting a local time from an epoch timestamp). - This should have no user-facing effect other than giving a possibly more +- gh-91581: Remove an unhandled error case in the C implementation of calls + to :meth:`datetime.fromtimestamp ` with + no time zone (i.e. getting a local time from an epoch timestamp). This + should have no user-facing effect other than giving a possibly more accurate error message when called with timestamps that fall on 10000-01-01 in the local time. Patch by Paul Ganssle. -- gh-issue-91539: Improve performance of - ``urllib.request.getproxies_environment`` when there are many environment - variables +- gh-91539: Improve performance of ``urllib.request.getproxies_environment`` + when there are many environment variables -- gh-issue-91524: Speed up the regular expression substitution (functions +- gh-91524: Speed up the regular expression substitution (functions :func:`re.sub` and :func:`re.subn` and corresponding :class:`re.Pattern` methods) for replacement strings containing group references by 2--3 times. -- gh-issue-91447: Fix findtext in the xml module to only give an empty - string when the text attribute is set to ``None``. +- gh-91447: Fix findtext in the xml module to only give an empty string when + the text attribute is set to ``None``. -- gh-issue-91456: Deprecate current default auto() behavior: In 3.13 the - default will be for for auto() to always return the largest member value +- gh-91456: Deprecate current default auto() behavior: In 3.13 the default + will be for for auto() to always return the largest member value incremented by 1, and to raise if incompatible value types are used. - bpo-47231: Fixed an issue with inconsistent trailing slashes in tarfile @@ -7500,7 +8378,7 @@ Library - bpo-41287: Fix handling of the ``doc`` argument in subclasses of :func:`property`. -- gh-issue-90005: :mod:`ctypes` dependency ``libffi`` is now detected with +- gh-90005: :mod:`ctypes` dependency ``libffi`` is now detected with ``pkg-config``. - bpo-32547: The constructors for :class:`~csv.DictWriter` and @@ -7533,8 +8411,8 @@ Library - bpo-46364: Restrict use of sockets instead of pipes for stdin of subprocesses created by :mod:`asyncio` to AIX platform only. -- bpo-28249: Set :attr:`doctest.DocTest.lineno` to ``None`` when object does - not have :attr:`__doc__`. +- bpo-28249: Set :attr:`doctest.DocTest.lineno` to ``None`` when an object + does not have :attr:`~definition.__doc__`. - bpo-46197: Fix :mod:`ensurepip` environment isolation for subprocess running ``pip``. @@ -7590,73 +8468,73 @@ Library Documentation ------------- -- gh-issue-85525: Remove extra row +- gh-85525: Remove extra row -- gh-issue-86404: Deprecated tools ``make suspicious`` and ``rstlint.py`` - are now removed. They have been replaced by :pypi:`sphinx-lint`. +- gh-86404: Deprecated tools ``make suspicious`` and ``rstlint.py`` are now + removed. They have been replaced by :pypi:`sphinx-lint`. -- gh-issue-97741: Fix ``!`` in c domain ref target syntax via a ``conf.py`` - patch, so it works as intended to disable ref target resolution. +- gh-97741: Fix ``!`` in c domain ref target syntax via a ``conf.py`` patch, + so it works as intended to disable ref target resolution. -- gh-issue-96432: Fraction literals now support whitespace around the - forward slash, ``Fraction('2 / 3')``. +- gh-96432: Fraction literals now support whitespace around the forward + slash, ``Fraction('2 / 3')``. -- gh-issue-96098: Improve discoverability of the higher level - concurrent.futures module by providing clearer links from the lower level - threading and multiprocessing modules. +- gh-96098: Improve discoverability of the higher level concurrent.futures + module by providing clearer links from the lower level threading and + multiprocessing modules. -- gh-issue-95957: What's New 3.11 now has instructions for how to provide - compiler and linker flags for Tcl/Tk and OpenSSL on RHEL 7 and CentOS 7. +- gh-95957: What's New 3.11 now has instructions for how to provide compiler + and linker flags for Tcl/Tk and OpenSSL on RHEL 7 and CentOS 7. -- gh-issue-95588: Clarified the conflicting advice given in the :mod:`ast` +- gh-95588: Clarified the conflicting advice given in the :mod:`ast` documentation about :func:`ast.literal_eval` being "safe" for use on untrusted input while at the same time warning that it can crash the process. The latter statement is true and is deemed unfixable without a large amount of work unsuitable for a bugfix. So we keep the warning and no longer claim that ``literal_eval`` is safe. -- gh-issue-91207: Fix stylesheet not working in Windows CHM htmlhelp docs - and add warning that they are deprecated. Contributed by C.A.M. Gerlach. +- gh-91207: Fix stylesheet not working in Windows CHM htmlhelp docs and add + warning that they are deprecated. Contributed by C.A.M. Gerlach. -- gh-issue-95454: Replaced incorrectly written true/false values in - documentation. Patch by Robert O'Shea +- gh-95454: Replaced incorrectly written true/false values in documentation. + Patch by Robert O'Shea -- gh-issue-95451: Update library documentation with :ref:`availability - information ` on WebAssembly platforms - ``wasm32-emscripten`` and ``wasm32-wasi``. +- gh-95451: Update library documentation with :ref:`availability information + ` on WebAssembly platforms ``wasm32-emscripten`` and + ``wasm32-wasi``. -- gh-issue-95415: Use consistent syntax for platform availability. The - directive now supports a content body and emits a warning when it - encounters an unknown platform. +- gh-95415: Use consistent syntax for platform availability. The directive + now supports a content body and emits a warning when it encounters an + unknown platform. -- gh-issue-94321: Document the :pep:`246` style protocol type +- gh-94321: Document the :pep:`246` style protocol type :class:`sqlite3.PrepareProtocol`. -- gh-issue-86128: Document a limitation in ThreadPoolExecutor where its exit +- gh-86128: Document a limitation in ThreadPoolExecutor where its exit handler is executed before any handlers in atexit. -- gh-issue-61162: Clarify :mod:`sqlite3` behavior when +- gh-61162: Clarify :mod:`sqlite3` behavior when :ref:`sqlite3-connection-context-manager`. -- gh-issue-87260: Align :mod:`sqlite3` argument specs with the actual +- gh-87260: Align :mod:`sqlite3` argument specs with the actual implementation. -- gh-issue-86986: The minimum Sphinx version required to build the - documentation is now 3.2. +- gh-86986: The minimum Sphinx version required to build the documentation + is now 3.2. -- gh-issue-88831: Augmented documentation of asyncio.create_task(). - Clarified the need to keep strong references to tasks and added a code - snippet detailing how to do this. +- gh-88831: Augmented documentation of asyncio.create_task(). Clarified the + need to keep strong references to tasks and added a code snippet detailing + how to do this. -- gh-issue-86438: Clarify that :option:`-W` and :envvar:`PYTHONWARNINGS` are +- gh-86438: Clarify that :option:`-W` and :envvar:`PYTHONWARNINGS` are matched literally and case-insensitively, rather than as regular expressions, in :mod:`warnings`. -- gh-issue-93031: Update tutorial introduction output to use 3.10+ - SyntaxError invalid range. +- gh-93031: Update tutorial introduction output to use 3.10+ SyntaxError + invalid range. -- gh-issue-92240: Added release dates for "What's New in Python 3.X" for - 3.0, 3.1, 3.2, 3.8 and 3.10 +- gh-92240: Added release dates for "What's New in Python 3.X" for 3.0, 3.1, + 3.2, 3.8 and 3.10 - bpo-47161: Document that :class:`pathlib.PurePath` does not collapse initial double slashes because they denote UNC paths. @@ -7676,125 +8554,121 @@ Documentation Tests ----- -- gh-issue-95027: On Windows, when the Python test suite is run with the - ``-jN`` option, the ANSI code page is now used as the encoding for the - stdout temporary file, rather than using UTF-8 which can lead to decoding - errors. Patch by Victor Stinner. +- gh-95027: On Windows, when the Python test suite is run with the ``-jN`` + option, the ANSI code page is now used as the encoding for the stdout + temporary file, rather than using UTF-8 which can lead to decoding errors. + Patch by Victor Stinner. -- gh-issue-96624: Fixed the failure of repeated runs of - ``test.test_unittest`` caused by side effects in - ``test_dotted_but_module_not_loaded``. +- gh-96624: Fixed the failure of repeated runs of ``test.test_unittest`` + caused by side effects in ``test_dotted_but_module_not_loaded``. -- gh-issue-95243: Mitigate the inherent race condition from using +- gh-95243: Mitigate the inherent race condition from using find_unused_port() in testSockName() by trying to find an unused port a few times before failing. Patch by Ross Burton. -- gh-issue-95573: :source:`Lib/test/test_asyncio/test_ssl.py` exposed a bug - in the macOS kernel where intense concurrent load on non-blocking sockets +- gh-95573: :source:`Lib/test/test_asyncio/test_ssl.py` exposed a bug in the + macOS kernel where intense concurrent load on non-blocking sockets occasionally causes :const:`errno.ENOBUFS` ("No buffer space available") to be emitted. FB11063974 filed with Apple, in the mean time as a workaround buffer size used in tests on macOS is decreased to avoid intermittent failures. Patch by Fantix King. -- gh-issue-95280: Fix problem with ``test_ssl`` ``test_get_ciphers`` on - systems that require perfect forward secrecy (PFS) ciphers. +- gh-95280: Fix problem with ``test_ssl`` ``test_get_ciphers`` on systems + that require perfect forward secrecy (PFS) ciphers. -- gh-issue-95212: Make multiprocessing test case - ``test_shared_memory_recreate`` parallel-safe. +- gh-95212: Make multiprocessing test case ``test_shared_memory_recreate`` + parallel-safe. -- gh-issue-95218: Move tests for importlib.resources into +- gh-95218: Move tests for importlib.resources into test_importlib.resources. -- gh-issue-93963: Updated tests to use preferred location for +- gh-93963: Updated tests to use preferred location for ``importlib.resources`` ABCs. -- gh-issue-94675: Add a regression test for :mod:`re` exponentional slowdown - when using rjsmin. +- gh-94675: Add a regression test for :mod:`re` exponentional slowdown when + using rjsmin. -- gh-issue-91330: Added more tests for :mod:`dataclasses` to cover behavior - with data descriptor-based fields. +- gh-91330: Added more tests for :mod:`dataclasses` to cover behavior with + data descriptor-based fields. -- gh-issue-94208: ``test_ssl`` is now checking for supported TLS version and +- gh-94208: ``test_ssl`` is now checking for supported TLS version and protocols in more tests. -- gh-issue-94315: Tests now check for DAC override capability instead of - relying on :func:`os.geteuid`. +- gh-94315: Tests now check for DAC override capability instead of relying + on :func:`os.geteuid`. -- gh-issue-54781: Rename test_tk to test_tkinter, and rename - test_ttk_guionly to test_ttk. Patch by Victor Stinner. +- gh-54781: Rename test_tk to test_tkinter, and rename test_ttk_guionly to + test_ttk. Patch by Victor Stinner. -- gh-issue-93839: Move ``Lib/ctypes/test/`` to ``Lib/test/test_ctypes/``. - Patch by Victor Stinner. +- gh-93839: Move ``Lib/ctypes/test/`` to ``Lib/test/test_ctypes/``. Patch by + Victor Stinner. -- gh-issue-93951: In test_bdb.StateTestCase.test_skip, avoid including - auxiliary importers. +- gh-93951: In test_bdb.StateTestCase.test_skip, avoid including auxiliary + importers. -- gh-issue-93957: Provide nicer error reporting from subprocesses in +- gh-93957: Provide nicer error reporting from subprocesses in test_venv.EnsurePipTest.test_with_pip. -- gh-issue-93884: Add test cases for :c:func:`PyNumber_ToBase` that take a - large number or a non-int object as parameter. +- gh-93884: Add test cases for :c:func:`PyNumber_ToBase` that take a large + number or a non-int object as parameter. -- gh-issue-93852: test_asyncio, test_logging, test_socket and - test_socketserver now create AF_UNIX domains in the current directory to - no longer fail with ``OSError("AF_UNIX path too long")`` if the temporary - directory (the :envvar:`TMPDIR` environment variable) is too long. Patch - by Victor Stinner. +- gh-93852: test_asyncio, test_logging, test_socket and test_socketserver + now create AF_UNIX domains in the current directory to no longer fail with + ``OSError("AF_UNIX path too long")`` if the temporary directory (the + :envvar:`TMPDIR` environment variable) is too long. Patch by Victor + Stinner. -- gh-issue-93353: regrtest now checks if a test leaks temporary files or +- gh-93353: regrtest now checks if a test leaks temporary files or directories if run with -jN option. Patch by Victor Stinner. -- gh-issue-84461: ``run_tests.py`` now handles cross compiling env vars - correctly and pass ``HOSTRUNNER`` to regression tests. +- gh-84461: ``run_tests.py`` now handles cross compiling env vars correctly + and pass ``HOSTRUNNER`` to regression tests. -- gh-issue-93616: ``test_modulefinder`` now creates a temporary directory in +- gh-93616: ``test_modulefinder`` now creates a temporary directory in ``ModuleFinderTest.setUp()`` instead of module scope. -- gh-issue-93575: Fix issue with test_unicode test_raiseMemError. The test - case now use ``test.support.calcobjsize`` to calculate size of PyUnicode +- gh-93575: Fix issue with test_unicode test_raiseMemError. The test case + now use ``test.support.calcobjsize`` to calculate size of PyUnicode structs. :func:`sys.getsizeof` may return different size when string has UTF-8 memory. -- gh-issue-90473: WASI does not have a ``chmod(2)`` syscall. - :func:`os.chmod` is now a dummy function on WASI. Skip all tests that - depend on working :func:`os.chmod`. +- gh-90473: WASI does not have a ``chmod(2)`` syscall. :func:`os.chmod` is + now a dummy function on WASI. Skip all tests that depend on working + :func:`os.chmod`. -- gh-issue-90473: Skip tests on WASI that require symlinks with absolute - paths. +- gh-90473: Skip tests on WASI that require symlinks with absolute paths. -- gh-issue-57539: Increase calendar test coverage for +- gh-57539: Increase calendar test coverage for :meth:`calendar.LocaleTextCalendar.formatweekday`. -- gh-issue-90473: Skip symlink tests on WASI. wasmtime uses ``openat2(2)`` - with ``RESOLVE_BENEATH`` flag, which prevents symlinks with absolute - paths. +- gh-90473: Skip symlink tests on WASI. wasmtime uses ``openat2(2)`` with + ``RESOLVE_BENEATH`` flag, which prevents symlinks with absolute paths. -- gh-issue-89858: Fix ``test_embed`` for out-of-tree builds. Patch by Kumar +- gh-89858: Fix ``test_embed`` for out-of-tree builds. Patch by Kumar Aditya. -- gh-issue-92886: Fixing tests that fail when running with optimizations - (``-O``) in ``test_imaplib.py``. +- gh-92886: Fixing tests that fail when running with optimizations (``-O``) + in ``test_imaplib.py``. -- gh-issue-92886: Fixing tests that fail when running with optimizations - (``-O``) in ``test_zipimport.py`` +- gh-92886: Fixing tests that fail when running with optimizations (``-O``) + in ``test_zipimport.py`` -- gh-issue-92886: Fixing tests that fail when running with optimizations - (``-O``) in ``test_py_compile.py`` +- gh-92886: Fixing tests that fail when running with optimizations (``-O``) + in ``test_py_compile.py`` -- gh-issue-92886: Fixing tests that fail when running with optimizations - (``-O``) in ``test_sys_settrace.py``. +- gh-92886: Fixing tests that fail when running with optimizations (``-O``) + in ``test_sys_settrace.py``. -- gh-issue-92886: Fixing tests that fail when running with optimizations - (``-O``) in ``_test_multiprocessing.py`` +- gh-92886: Fixing tests that fail when running with optimizations (``-O``) + in ``_test_multiprocessing.py`` -- gh-issue-92670: Skip - ``test_shutil.TestCopy.test_copyfile_nonexistent_dir`` test on AIX as the - test uses a trailing slash to force the OS consider the path as a - directory, but on AIX the trailing slash has no effect and is considered - as a file. +- gh-92670: Skip ``test_shutil.TestCopy.test_copyfile_nonexistent_dir`` test + on AIX as the test uses a trailing slash to force the OS consider the path + as a directory, but on AIX the trailing slash has no effect and is + considered as a file. -- gh-issue-92514: Remove unused ``test.support.BasicTestRunner``. Patch by - Jelle Zijlstra. +- gh-92514: Remove unused ``test.support.BasicTestRunner``. Patch by Jelle + Zijlstra. - bpo-47016: Create a GitHub Actions workflow for verifying bundled pip and setuptools. Patch by Illia Volochii and Adam Turner. @@ -7802,120 +8676,113 @@ Tests Build ----- -- gh-issue-96761: Fix the build process of clang compiler for +- gh-96761: Fix the build process of clang compiler for :program:`_bootstrap_python` if LTO optimization is applied. Patch by Matthias Görgens and Donghee Na. -- gh-issue-96883: ``wasm32-emscripten`` builds for browsers now include +- gh-96883: ``wasm32-emscripten`` builds for browsers now include :mod:`concurrent.futures` for :mod:`asyncio` and :mod:`unittest.mock`. -- gh-issue-85936: CPython now uses the ThinLTO option as the default policy - if the Clang compiler accepts the flag. Patch by Donghee Na. +- gh-85936: CPython now uses the ThinLTO option as the default policy if the + Clang compiler accepts the flag. Patch by Donghee Na. -- gh-issue-96729: Ensure that Windows releases built with +- gh-96729: Ensure that Windows releases built with ``Tools\msi\buildrelease.bat`` are upgradable to and from official Python releases. -- gh-issue-96269: Shared module targets now depend on new ``MODULE_DEPS`` +- gh-96269: Shared module targets now depend on new ``MODULE_DEPS`` variable, which includes ``EXPORTSYMS``. This fixes a build order issue on unsupported AIX platform. -- gh-issue-84461: ``wasm32-emscripten`` platform no longer builds - :mod:`resource` module, :func:`~os.getresuid`, :func:`~os.getresgid`, and - their setters. The APIs are stubs and not functional. +- gh-84461: ``wasm32-emscripten`` platform no longer builds :mod:`resource` + module, :func:`~os.getresuid`, :func:`~os.getresgid`, and their setters. + The APIs are stubs and not functional. -- gh-issue-95973: Add a new ``--with-dsymutil`` configure option to link - debug information in macOS. Patch by Pablo Galindo. +- gh-95973: Add a new ``--with-dsymutil`` configure option to link debug + information in macOS. Patch by Pablo Galindo. -- gh-issue-90536: Use the BOLT post-link optimizer to improve performance, +- gh-90536: Use the BOLT post-link optimizer to improve performance, particularly on medium-to-large applications. -- gh-issue-93744: Remove the ``configure --with-cxx-main`` build option: it - didn't work for many years. Remove the ``MAINCC`` variable from - ``configure`` and ``Makefile``. Patch by Victor Stinner. +- gh-93744: Remove the ``configure --with-cxx-main`` build option: it didn't + work for many years. Remove the ``MAINCC`` variable from ``configure`` and + ``Makefile``. Patch by Victor Stinner. -- gh-issue-94801: Fix a regression in ``configure`` script that caused some - header checks to ignore custom ``CPPFLAGS``. The regression was introduced - in :gh:`94802`. +- gh-94801: Fix a regression in ``configure`` script that caused some header + checks to ignore custom ``CPPFLAGS``. The regression was introduced in + :gh:`94802`. -- gh-issue-95145: wasm32-wasi builds no longer depend on WASIX's pthread - stubs. Python now has its own stubbed pthread API. +- gh-95145: wasm32-wasi builds no longer depend on WASIX's pthread stubs. + Python now has its own stubbed pthread API. -- gh-issue-95174: Python now detects missing ``dup`` function in WASI and - works around some missing :mod:`errno`, :mod:`select`, and :mod:`socket` +- gh-95174: Python now detects missing ``dup`` function in WASI and works + around some missing :mod:`errno`, :mod:`select`, and :mod:`socket` constants. -- gh-issue-95174: Python now skips missing :mod:`socket` functions and - methods on WASI. WASI can only create sockets from existing fd / accept - and has no netdb. +- gh-95174: Python now skips missing :mod:`socket` functions and methods on + WASI. WASI can only create sockets from existing fd / accept and has no + netdb. -- gh-issue-95085: Platforms ``wasm32-unknown-emscripten`` and +- gh-95085: Platforms ``wasm32-unknown-emscripten`` and ``wasm32-unknown-wasi`` have been promoted to :pep:`11` tier 3 platform support. -- gh-issue-94847: Fixed ``_decimal`` module build issue on GCC when - compiling with LTO and pydebug. Debug builds no longer force inlining of - functions. +- gh-94847: Fixed ``_decimal`` module build issue on GCC when compiling with + LTO and pydebug. Debug builds no longer force inlining of functions. -- gh-issue-94841: Fix the possible performance regression of +- gh-94841: Fix the possible performance regression of :c:func:`PyObject_Free` compiled with MSVC version 1932. -- gh-issue-94801: ``configure`` now uses custom flags like ``ZLIB_CFLAGS`` - and ``ZLIB_LIBS`` when searching for headers and libraries. +- gh-94801: ``configure`` now uses custom flags like ``ZLIB_CFLAGS`` and + ``ZLIB_LIBS`` when searching for headers and libraries. -- gh-issue-94773: ``deepfreeze.py`` now supports code object with frozensets - that contain incompatible, unsortable types. +- gh-94773: ``deepfreeze.py`` now supports code object with frozensets that + contain incompatible, unsortable types. -- gh-issue-94682: Build and test with OpenSSL 1.1.1q +- gh-94682: Build and test with OpenSSL 1.1.1q -- gh-issue-90005: Dependencies of :mod:`readline` and :mod:`curses` module - are now detected in ``configure`` script with ``pkg-config``. Only - ``ncurses`` / ``ncursesw`` are detected automatically. The old ``curses`` - library is not configured automatically. Workaround for missing - ``termcap`` or ``tinfo`` library has been removed. +- gh-90005: Dependencies of :mod:`readline` and :mod:`curses` module are now + detected in ``configure`` script with ``pkg-config``. Only ``ncurses`` / + ``ncursesw`` are detected automatically. The old ``curses`` library is not + configured automatically. Workaround for missing ``termcap`` or ``tinfo`` + library has been removed. -- gh-issue-90005: Fix building ``_ctypes`` extension without ``pkg-config``. +- gh-90005: Fix building ``_ctypes`` extension without ``pkg-config``. -- gh-issue-90005: ``_dbm`` module dependencies are now detected by - configure. +- gh-90005: ``_dbm`` module dependencies are now detected by configure. -- gh-issue-94404: ``makesetup`` now works around an issue with sed on macOS - and uses correct CFLAGS for object files that end up in a shared - extension. Module CFLAGS are used before PY_STDMODULE_CFLAGS to avoid - clashes with system headers. +- gh-94404: ``makesetup`` now works around an issue with sed on macOS and + uses correct CFLAGS for object files that end up in a shared extension. + Module CFLAGS are used before PY_STDMODULE_CFLAGS to avoid clashes with + system headers. -- gh-issue-93939: C extension modules are now built by ``configure`` and - ``make`` instead of ``distutils`` and ``setup.py``. +- gh-93939: C extension modules are now built by ``configure`` and ``make`` + instead of ``distutils`` and ``setup.py``. -- gh-issue-93939: The ``2to3``, ``idle``, and ``pydoc`` scripts are now - generated and installed by ``Makefile`` instead of ``setup.py``. +- gh-93939: The ``2to3``, ``idle``, and ``pydoc`` scripts are now generated + and installed by ``Makefile`` instead of ``setup.py``. -- gh-issue-94280: Updated pegen regeneration script on Windows to find and - use Python 3.9 or higher. Prior to this, pegen regeneration already - required 3.9 or higher, but the script may have used lower versions of - Python. +- gh-94280: Updated pegen regeneration script on Windows to find and use + Python 3.9 or higher. Prior to this, pegen regeneration already required + 3.9 or higher, but the script may have used lower versions of Python. -- gh-issue-93584: Address race condition in ``Makefile`` when installing a - PGO build. All ``test`` and ``install`` targets now depend on ``all`` - target. +- gh-93584: Address race condition in ``Makefile`` when installing a PGO + build. All ``test`` and ``install`` targets now depend on ``all`` target. -- gh-issue-93491: ``configure`` now detects and reports :pep:`11` support - tiers. +- gh-93491: ``configure`` now detects and reports :pep:`11` support tiers. -- gh-issue-69093: Fix ``Modules/Setup.stdlib.in`` rule for ``_sqlite3`` - extension. +- gh-69093: Fix ``Modules/Setup.stdlib.in`` rule for ``_sqlite3`` extension. -- gh-issue-93207: ``va_start()`` with two parameters, like ``va_start(args, +- gh-93207: ``va_start()`` with two parameters, like ``va_start(args, format),`` is now required to build Python. ``va_start()`` is no longer called with a single parameter. Patch by Kumar Aditya. -- gh-issue-93202: Python now always use the ``%zu`` and ``%zd`` printf - formats to format a :c:type:`size_t` or ``Py_ssize_t`` number. Building - Python 3.12 requires a C11 compiler, so these printf formats are now - always supported. Patch by Victor Stinner. +- gh-93202: Python now always use the ``%zu`` and ``%zd`` printf formats to + format a :c:type:`size_t` or ``Py_ssize_t`` number. Building Python 3.12 + requires a C11 compiler, so these printf formats are now always supported. + Patch by Victor Stinner. -- gh-issue-90473: Disable pymalloc and increase stack size on - ``wasm32-wasi``. +- gh-90473: Disable pymalloc and increase stack size on ``wasm32-wasi``. - bpo-34449: Drop invalid compiler switch ``-fPIC`` for HP aCC on HP-UX. Patch by Michael Osipov. @@ -7923,98 +8790,96 @@ Build Windows ------- -- gh-issue-98360: Fixes :mod:`multiprocessing` spawning child processes on - Windows from a virtual environment to ensure that child processes that - also use :mod:`multiprocessing` to spawn more children will recognize that - they are in a virtual environment. +- gh-98360: Fixes :mod:`multiprocessing` spawning child processes on Windows + from a virtual environment to ensure that child processes that also use + :mod:`multiprocessing` to spawn more children will recognize that they are + in a virtual environment. -- gh-issue-98414: Fix :file:`py.exe` launcher handling of - :samp:`-V:{}/` option when default preferences have been set in - environment variables or configuration files. +- gh-98414: Fix :file:`py.exe` launcher handling of :samp:`-V:{}/` + option when default preferences have been set in environment variables or + configuration files. -- gh-issue-97728: Fix possible crashes caused by the use of uninitialized +- gh-97728: Fix possible crashes caused by the use of uninitialized variables when pass invalid arguments in :func:`os.system` on Windows and in Windows-specific modules (like ``winreg``). -- gh-issue-90989: Made :ref:`launcher` install per-user by default (unless - an all users install already exists), and clarify some text in the - installer. +- gh-90989: Made :ref:`launcher` install per-user by default (unless an all + users install already exists), and clarify some text in the installer. -- gh-issue-97649: The ``Tools`` directory is no longer installed on Windows +- gh-97649: The ``Tools`` directory is no longer installed on Windows -- gh-issue-96965: Update libffi to 3.4.3 +- gh-96965: Update libffi to 3.4.3 -- gh-issue-96577: Fixes a potential buffer overrun in :mod:`msilib`. +- gh-96577: Fixes a potential buffer overrun in :mod:`msilib`. -- gh-issue-96559: Fixes the Windows launcher not using the compatible +- gh-96559: Fixes the Windows launcher not using the compatible interpretation of default tags found in configuration files when no tag was passed to the command. -- gh-issue-94781: Fix :file:`pcbuild.proj` to clean previous instances of - output files in ``Python\deepfreeze`` and ``Python\frozen_modules`` - directories on Windows. Patch by Charlie Zhao. +- gh-94781: Fix :file:`pcbuild.proj` to clean previous instances of output + files in ``Python\deepfreeze`` and ``Python\frozen_modules`` directories + on Windows. Patch by Charlie Zhao. -- gh-issue-89545: Updates :mod:`platform` code getting the Windows version - to use native Windows Management Instrumentation (WMI) queries to - determine OS version, type, and architecture. +- gh-89545: Updates :mod:`platform` code getting the Windows version to use + native Windows Management Instrumentation (WMI) queries to determine OS + version, type, and architecture. -- gh-issue-95733: Make certain requirements of the Windows Store package - optional to allow installing on earlier updates of Windows. +- gh-95733: Make certain requirements of the Windows Store package optional + to allow installing on earlier updates of Windows. -- gh-issue-95656: Enable the - :meth:`~sqlite3.Connection.enable_load_extension` :mod:`sqlite3` API. +- gh-95656: Enable the :meth:`~sqlite3.Connection.enable_load_extension` + :mod:`sqlite3` API. -- gh-issue-95587: Fixes some issues where the Windows installer would - incorrectly detect certain features of an existing install when upgrading. +- gh-95587: Fixes some issues where the Windows installer would incorrectly + detect certain features of an existing install when upgrading. -- gh-issue-94399: Restores the behaviour of :ref:`launcher` for - ``/usr/bin/env`` shebang lines, which will now search :envvar:`PATH` for - an executable matching the given command. If none is found, the usual - search process is used. +- gh-94399: Restores the behaviour of :ref:`launcher` for ``/usr/bin/env`` + shebang lines, which will now search :envvar:`PATH` for an executable + matching the given command. If none is found, the usual search process is + used. -- gh-issue-95445: Fixes the unsuccessful removal of the HTML document - directory when uninstalling with Windows msi. +- gh-95445: Fixes the unsuccessful removal of the HTML document directory + when uninstalling with Windows msi. -- gh-issue-95359: Fix :ref:`launcher` handling of :file:`py.ini` commands - (it was incorrectly expecting a ``py_`` prefix on keys) and crashes when - reading per-user configuration file. +- gh-95359: Fix :ref:`launcher` handling of :file:`py.ini` commands (it was + incorrectly expecting a ``py_`` prefix on keys) and crashes when reading + per-user configuration file. -- gh-issue-95285: Fix :ref:`launcher` handling of command lines where it is - only passed a short executable name. +- gh-95285: Fix :ref:`launcher` handling of command lines where it is only + passed a short executable name. -- gh-issue-90844: Allow virtual environments to correctly launch when they - have spaces in the path. +- gh-90844: Allow virtual environments to correctly launch when they have + spaces in the path. -- gh-issue-94772: Fix incorrect handling of shebang lines in py.exe launcher +- gh-94772: Fix incorrect handling of shebang lines in py.exe launcher -- gh-issue-94018: :mod:`zipfile` will now remove trailing spaces from path +- gh-94018: :mod:`zipfile` will now remove trailing spaces from path components when extracting files on Windows. -- gh-issue-93824: Drag and drop of files onto Python files in Windows - Explorer has been enabled for Windows ARM64. +- gh-93824: Drag and drop of files onto Python files in Windows Explorer has + been enabled for Windows ARM64. -- gh-issue-43414: :func:`os.get_terminal_size` now attempts to read the size - from any provided handle, rather than only supporting file descriptors 0, - 1 and 2. +- gh-43414: :func:`os.get_terminal_size` now attempts to read the size from + any provided handle, rather than only supporting file descriptors 0, 1 and + 2. -- gh-issue-92817: Ensures that :file:`py.exe` will prefer an active virtual +- gh-92817: Ensures that :file:`py.exe` will prefer an active virtual environment over default tags specified with environment variables or through a :file:`py.ini` file. -- gh-issue-92984: Explicitly disable incremental linking for non-Debug - builds +- gh-92984: Explicitly disable incremental linking for non-Debug builds -- gh-issue-92841: :mod:`asyncio` no longer throws ``RuntimeError: Event loop - is closed`` on interpreter exit after asynchronous socket activity. Patch - by Oleg Iarygin. +- gh-92841: :mod:`asyncio` no longer throws ``RuntimeError: Event loop is + closed`` on interpreter exit after asynchronous socket activity. Patch by + Oleg Iarygin. - bpo-46907: Update Windows installer to use SQLite 3.38.4. -- gh-issue-91061: Accept os.PathLike for the argument to winsound.PlaySound +- gh-91061: Accept os.PathLike for the argument to winsound.PlaySound - bpo-42658: Support native Windows case-insensitive path comparisons by using ``LCMapStringEx`` instead of :func:`str.lower` in - :func:`ntpath.normcase`. Add ``LCMapStringEx`` to the :mod:`_winapi` + :func:`ntpath.normcase`. Add ``LCMapStringEx`` to the :mod:`!_winapi` module. - bpo-38704: Prevent installation on unsupported Windows versions. @@ -8022,7 +8887,7 @@ Windows macOS ----- -- gh-issue-97897: The macOS 13 SDK includes support for the ``mkfifoat`` and +- gh-97897: The macOS 13 SDK includes support for the ``mkfifoat`` and ``mknodat`` system calls. Using the ``dir_fd`` option with either :func:`os.mkfifo` or :func:`os.mknod` could result in a segfault if cpython is built with the macOS 13 SDK but run on an earlier version of @@ -8032,138 +8897,132 @@ macOS IDLE ---- -- gh-issue-97527: Fix a bug in the previous bugfix that caused IDLE to not - start when run with 3.10.8, 3.12.0a1, and at least Microsoft Python - 3.10.2288.0 installed without the Lib/test package. 3.11.0 was never - affected. +- gh-97527: Fix a bug in the previous bugfix that caused IDLE to not start + when run with 3.10.8, 3.12.0a1, and at least Microsoft Python 3.10.2288.0 + installed without the Lib/test package. 3.11.0 was never affected. -- gh-issue-65802: Document handling of extensions in Save As dialogs. +- gh-65802: Document handling of extensions in Save As dialogs. -- gh-issue-95191: Include prompts when saving Shell (interactive input and +- gh-95191: Include prompts when saving Shell (interactive input and output). -- gh-issue-95511: Fix the Shell context menu copy-with-prompts bug of - copying an extra line when one selects whole lines. +- gh-95511: Fix the Shell context menu copy-with-prompts bug of copying an + extra line when one selects whole lines. -- gh-issue-95471: In the Edit menu, move ``Select All`` and add a new - separator. +- gh-95471: In the Edit menu, move ``Select All`` and add a new separator. -- gh-issue-95411: Enable using IDLE's module browser with .pyw files. +- gh-95411: Enable using IDLE's module browser with .pyw files. -- gh-issue-89610: Add .pyi as a recognized extension for IDLE on macOS. - This allows opening stub files by double clicking on them in the Finder. +- gh-89610: Add .pyi as a recognized extension for IDLE on macOS. This + allows opening stub files by double clicking on them in the Finder. Tools/Demos ----------- -- gh-issue-68686: Remove ptags and eptags scripts. +- gh-68686: Remove ptags and eptags scripts. -- gh-issue-97681: Remove the ``Tools/demo/`` directory which contained old - demo scripts. A copy can be found in the `old-demos project +- gh-97681: Remove the ``Tools/demo/`` directory which contained old demo + scripts. A copy can be found in the `old-demos project `_. Patch by Victor Stinner. -- gh-issue-97669: Remove outdated example scripts of the ``Tools/scripts/`` +- gh-97669: Remove outdated example scripts of the ``Tools/scripts/`` directory. A copy can be found in the `old-demos project `_. Patch by Victor Stinner. -- gh-issue-95853: The ``wasm_build.py`` script now pre-builds Emscripten - ports, checks for broken EMSDK versions, and warns about pkg-config env - vars. +- gh-95853: The ``wasm_build.py`` script now pre-builds Emscripten ports, + checks for broken EMSDK versions, and warns about pkg-config env vars. -- gh-issue-95853: The new tool ``Tools/wasm/wasm_builder.py`` automates - configure, compile, and test steps for building CPython on WebAssembly - platforms. +- gh-95853: The new tool ``Tools/wasm/wasm_builder.py`` automates configure, + compile, and test steps for building CPython on WebAssembly platforms. -- gh-issue-95731: Fix handling of module docstrings in +- gh-95731: Fix handling of module docstrings in :file:`Tools/i18n/pygettext.py`. -- gh-issue-93939: Add script ``Tools/scripts/check_modules.py`` to check and +- gh-93939: Add script ``Tools/scripts/check_modules.py`` to check and validate builtin and shared extension modules. The script also handles ``Modules/Setup`` and will eventually replace ``setup.py``. -- gh-issue-94538: Fix Argument Clinic output to custom file destinations. - Patch by Erlend E. Aasland. +- gh-94538: Fix Argument Clinic output to custom file destinations. Patch by + Erlend E. Aasland. -- gh-issue-94430: Allow parameters named ``module`` and ``self`` with custom - C names in Argument Clinic. Patch by Erlend E. Aasland +- gh-94430: Allow parameters named ``module`` and ``self`` with custom C + names in Argument Clinic. Patch by Erlend E. Aasland -- gh-issue-86087: The ``Tools/scripts/parseentities.py`` script used to - parse HTML4 entities has been removed. +- gh-86087: The ``Tools/scripts/parseentities.py`` script used to parse + HTML4 entities has been removed. C API ----- -- gh-issue-98393: The :c:func:`PyUnicode_FSDecoder` function no longer - accepts bytes-like paths, like :class:`bytearray` and :class:`memoryview` - types: only the exact :class:`bytes` type is accepted for bytes strings. - Patch by Victor Stinner. +- gh-98393: The :c:func:`PyUnicode_FSDecoder` function no longer accepts + bytes-like paths, like :class:`bytearray` and :class:`memoryview` types: + only the exact :class:`bytes` type is accepted for bytes strings. Patch by + Victor Stinner. -- gh-issue-91051: Add :c:func:`PyType_Watch` and related APIs to allow - callbacks on :c:func:`PyType_Modified`. +- gh-91051: Add :c:func:`PyType_Watch` and related APIs to allow callbacks + on :c:func:`PyType_Modified`. -- gh-issue-95756: Lazily create and cache ``co_`` attributes for better +- gh-95756: Lazily create and cache ``co_`` attributes for better performance for code getters. -- gh-issue-96512: Configuration for the :ref:`integer string conversion - length limitation ` now lives in the PyConfig C API - struct. +- gh-96512: Configuration for the :ref:`integer string conversion length + limitation ` now lives in the PyConfig C API struct. -- gh-issue-95589: Extensions classes that set ``tp_dictoffset`` and +- gh-95589: Extensions classes that set ``tp_dictoffset`` and ``tp_weaklistoffset`` lose the support for multiple inheritance, but are now safe. Extension classes should use :c:macro:`Py_TPFLAGS_MANAGED_DICT` and :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` instead. -- gh-issue-95781: An unrecognized format character in +- gh-95781: An unrecognized format character in :c:func:`PyUnicode_FromFormat` and :c:func:`PyUnicode_FromFormatV` now sets a :exc:`SystemError`. In previous versions it caused all the rest of the format string to be copied as-is to the result string, and any extra arguments discarded. -- gh-issue-92678: Restore the 3.10 behavior for multiple inheritance of C +- gh-92678: Restore the 3.10 behavior for multiple inheritance of C extension classes that store their dictionary at the end of the struct. -- gh-issue-92678: Support C extensions using managed dictionaries by setting - the ``Py_TPFLAGS_MANAGED_DICT`` flag. +- gh-92678: Support C extensions using managed dictionaries by setting the + ``Py_TPFLAGS_MANAGED_DICT`` flag. -- gh-issue-93274: API for implementing vectorcall +- gh-93274: API for implementing vectorcall (:c:macro:`Py_TPFLAGS_HAVE_VECTORCALL`, :c:func:`PyVectorcall_NARGS` and :c:func:`PyVectorcall_Call`) was added to the limited API and stable ABI. -- gh-issue-95504: Fix sign placement when specifying width or precision in +- gh-95504: Fix sign placement when specifying width or precision in :c:func:`PyUnicode_FromFormat` and :c:func:`PyUnicode_FromFormatV`. Patch by Philip Georgi. -- gh-issue-93012: The :c:macro:`Py_TPFLAGS_HAVE_VECTORCALL` flag is now - removed from a class when the class's :py:meth:`~object.__call__` method - is reassigned. This makes vectorcall safe to use with mutable types (i.e. +- gh-93012: The :c:macro:`Py_TPFLAGS_HAVE_VECTORCALL` flag is now removed + from a class when the class's :py:meth:`~object.__call__` method is + reassigned. This makes vectorcall safe to use with mutable types (i.e. heap types without the :const:`immutable ` flag). Mutable types that do not override :c:member:`~PyTypeObject.tp_call` now inherit the :c:macro:`Py_TPFLAGS_HAVE_VECTORCALL` flag. -- gh-issue-95388: Creating :c:macro:`immutable types - ` with mutable bases is deprecated and is - planned to be disabled in Python 3.14. +- gh-95388: Creating :c:macro:`immutable types ` + with mutable bases is deprecated and is planned to be disabled in Python + 3.14. -- gh-issue-92678: Adds unstable C-API functions - ``_PyObject_VisitManagedDict`` and ``_PyObject_ClearManagedDict`` to allow - C extensions to allow the VM to manage their object's dictionaries. +- gh-92678: Adds unstable C-API functions ``_PyObject_VisitManagedDict`` and + ``_PyObject_ClearManagedDict`` to allow C extensions to allow the VM to + manage their object's dictionaries. -- gh-issue-94936: Added :c:func:`PyCode_GetVarnames`, - :c:func:`PyCode_GetCellvars` and :c:func:`PyCode_GetFreevars` for - accessing ``co_varnames``, ``co_cellvars`` and ``co_freevars`` - respectively via the C API. +- gh-94936: Added :c:func:`PyCode_GetVarnames`, :c:func:`PyCode_GetCellvars` + and :c:func:`PyCode_GetFreevars` for accessing ``co_varnames``, + ``co_cellvars`` and ``co_freevars`` respectively via the C API. -- gh-issue-94930: Fix ``SystemError`` raised when +- gh-94930: Fix ``SystemError`` raised when :c:func:`PyArg_ParseTupleAndKeywords` is used with ``#`` in ``(...)`` but without ``PY_SSIZE_T_CLEAN`` defined. -- gh-issue-94731: Python again uses C-style casts for most casting - operations when compiled with C++. This may trigger compiler warnings, if - they are enabled with e.g. ``-Wold-style-cast`` or - ``-Wzero-as-null-pointer-constant`` options for ``g++``. +- gh-94731: Python again uses C-style casts for most casting operations when + compiled with C++. This may trigger compiler warnings, if they are enabled + with e.g. ``-Wold-style-cast`` or ``-Wzero-as-null-pointer-constant`` + options for ``g++``. -- gh-issue-93937: The following frame functions and type are now directly +- gh-93937: The following frame functions and type are now directly available with ``#include ``, it's no longer needed to add ``#include ``: @@ -8178,19 +9037,19 @@ C API Patch by Victor Stinner. -- gh-issue-91321: Fix the compatibility of the Python C API with C++ older - than C++11. Patch by Victor Stinner. +- gh-91321: Fix the compatibility of the Python C API with C++ older than + C++11. Patch by Victor Stinner. -- gh-issue-91731: Avoid defining the ``static_assert`` when compiling with - C++ 11, where this is a keyword and redefining it can lead to undefined - behavior. Patch by Pablo Galindo +- gh-91731: Avoid defining the ``static_assert`` when compiling with C++ 11, + where this is a keyword and redefining it can lead to undefined behavior. + Patch by Pablo Galindo -- gh-issue-89546: :c:func:`PyType_FromMetaclass` (and other ``PyType_From*`` +- gh-89546: :c:func:`PyType_FromMetaclass` (and other ``PyType_From*`` functions) now check that offsets and the base class's :c:member:`~PyTypeObject.tp_basicsize` fit in the new class's ``tp_basicsize``. -- gh-issue-93503: Add two new public functions to the public C-API, +- gh-93503: Add two new public functions to the public C-API, :c:func:`PyEval_SetProfileAllThreads` and :c:func:`PyEval_SetTraceAllThreads`, that allow to set tracing and profiling functions in all running threads in addition to the calling one. @@ -8199,52 +9058,50 @@ C API :func:`threading.settrace_all_threads`) that allow to do the same from Python. Patch by Pablo Galindo -- gh-issue-93442: Add C++ overloads for _Py_CAST_impl() to handle 0/NULL. - This will allow C++ extensions that pass 0 or NULL to macros using - _Py_CAST() to continue to compile. +- gh-93442: Add C++ overloads for _Py_CAST_impl() to handle 0/NULL. This + will allow C++ extensions that pass 0 or NULL to macros using _Py_CAST() + to continue to compile. -- gh-issue-93466: Slot IDs in PyType_Spec may not be repeated. The - documentation was updated to mention this. For some cases of repeated - slots, PyType_FromSpec and related functions will now raise an exception. +- gh-93466: Slot IDs in PyType_Spec may not be repeated. The documentation + was updated to mention this. For some cases of repeated slots, + PyType_FromSpec and related functions will now raise an exception. -- gh-issue-92898: Fix C++ compiler warnings when casting function arguments - to ``PyObject*``. Patch by Serge Guelton. +- gh-92898: Fix C++ compiler warnings when casting function arguments to + ``PyObject*``. Patch by Serge Guelton. -- gh-issue-93103: Deprecate global configuration variables, like +- gh-93103: Deprecate global configuration variables, like :c:var:`Py_IgnoreEnvironmentFlag`, in the documentation: the :c:func:`Py_InitializeFromConfig` API should be instead. Patch by Victor Stinner. -- gh-issue-77782: Deprecate global configuration variable like +- gh-77782: Deprecate global configuration variable like :c:var:`Py_IgnoreEnvironmentFlag`: the :c:func:`Py_InitializeFromConfig` API should be instead. Patch by Victor Stinner. -- gh-issue-92913: Ensures changes to - :c:member:`PyConfig.module_search_paths` are ignored unless - :c:member:`PyConfig.module_search_paths_set` is set +- gh-92913: Ensures changes to :c:member:`PyConfig.module_search_paths` are + ignored unless :c:member:`PyConfig.module_search_paths_set` is set -- gh-issue-92781: Avoid mixing declarations and code in the C API to fix the +- gh-92781: Avoid mixing declarations and code in the C API to fix the compiler warning: "ISO C90 forbids mixed declarations and code" [-Werror=declaration-after-statement]. Patch by Victor Stinner. -- gh-issue-92651: Remove the ``token.h`` header file. There was never any - public tokenizer C API. The ``token.h`` header file was only designed to - be used by Python internals. Patch by Victor Stinner. +- gh-92651: Remove the ``token.h`` header file. There was never any public + tokenizer C API. The ``token.h`` header file was only designed to be used + by Python internals. Patch by Victor Stinner. -- gh-issue-92536: Remove legacy Unicode APIs based on ``Py_UNICODE*``. +- gh-92536: Remove legacy Unicode APIs based on ``Py_UNICODE*``. -- gh-issue-85858: Remove the ``PyUnicode_InternImmortal()`` function and the +- gh-85858: Remove the ``PyUnicode_InternImmortal()`` function and the ``SSTATE_INTERNED_IMMORTAL`` macro. Patch by Victor Stinner. -- gh-issue-92193: Add new function :c:func:`PyFunction_SetVectorcall` to the - C API which sets the vectorcall field of a given - :c:type:`PyFunctionObject`. +- gh-92193: Add new function :c:func:`PyFunction_SetVectorcall` to the C API + which sets the vectorcall field of a given :c:type:`PyFunctionObject`. Warning: extensions using this API must preserve the behavior of the unaltered function! -- gh-issue-59121: Fixed an assert that prevented ``PyRun_InteractiveOne`` - from providing tracebacks when parsing from the provided FD. +- gh-59121: Fixed an assert that prevented ``PyRun_InteractiveOne`` from + providing tracebacks when parsing from the provided FD. - bpo-45383: The :c:func:`PyType_FromSpec` API will now find and use a metaclass based on the provided bases. An error will be raised if there is @@ -8259,19 +9116,19 @@ What's New in Python 3.11.0 beta 1? Security -------- -- gh-issue-57684: Add the :option:`-P` command line option and the +- gh-57684: Add the :option:`-P` command line option and the :envvar:`PYTHONSAFEPATH` environment variable to not prepend a potentially unsafe path to :data:`sys.path`. Patch by Victor Stinner. Core and Builtins ----------------- -- gh-issue-89519: Chaining classmethod descriptors (introduced in bpo-19072) - is deprecated. It can no longer be used to wrap other descriptors such as +- gh-89519: Chaining classmethod descriptors (introduced in bpo-19072) is + deprecated. It can no longer be used to wrap other descriptors such as property(). The core design of this feature was flawed, and it caused a number of downstream problems. -- gh-issue-92345: ``pymain_run_python()`` now imports ``readline`` and +- gh-92345: ``pymain_run_python()`` now imports ``readline`` and ``rlcompleter`` before sys.path is extended to include the current working directory of an interactive interpreter. Non-interactive interpreters are not affected. @@ -8279,123 +9136,118 @@ Core and Builtins - bpo-43857: Improve the :exc:`AttributeError` message when deleting a missing attribute. Patch by Géry Ogam. -- gh-issue-92245: Make sure that PEP 523 is respected in all cases. In - 3.11a7, specialization may have prevented Python-to-Python calls - respecting PEP 523. +- gh-92245: Make sure that PEP 523 is respected in all cases. In 3.11a7, + specialization may have prevented Python-to-Python calls respecting PEP + 523. -- gh-issue-92203: Add a closure keyword-only parameter to :func:`exec()`. It - can only be specified when exec-ing a code object that uses free - variables. When specified, it must be a tuple, with exactly the number of - cell variables referenced by the code object. closure has a default value - of ``None``, and it must be ``None`` if the code object doesn't refer to - any free variables. +- gh-92203: Add a closure keyword-only parameter to :func:`exec`. It can + only be specified when exec-ing a code object that uses free variables. + When specified, it must be a tuple, with exactly the number of cell + variables referenced by the code object. closure has a default value of + ``None``, and it must be ``None`` if the code object doesn't refer to any + free variables. -- gh-issue-91173: Disable frozen modules in debug builds. Patch by Kumar - Aditya. +- gh-91173: Disable frozen modules in debug builds. Patch by Kumar Aditya. -- gh-issue-92114: Improve error message when subscript a type with +- gh-92114: Improve error message when subscript a type with ``__class_getitem__`` set to ``None``. -- gh-issue-92112: Fix crash triggered by an evil custom ``mro()`` on a - metaclass. +- gh-92112: Fix crash triggered by an evil custom ``mro()`` on a metaclass. -- gh-issue-92063: The ``PRECALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS`` - instruction now ensures methods are called only on objects of the correct - type. +- gh-92063: The ``PRECALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS`` instruction + now ensures methods are called only on objects of the correct type. -- gh-issue-92031: Deoptimize statically allocated code objects during +- gh-92031: Deoptimize statically allocated code objects during ``Py_FINALIZE()`` so that future ``_PyCode_Quicken`` calls always start with unquickened code. -- gh-issue-92036: Fix a crash in subinterpreters related to the garbage - collector. When a subinterpreter is deleted, untrack all objects tracked - by its GC. To prevent a crash in deallocator functions expecting objects - to be tracked by the GC, leak a strong reference to these objects on - purpose, so they are never deleted and their deallocator functions are not - called. Patch by Victor Stinner. +- gh-92036: Fix a crash in subinterpreters related to the garbage collector. + When a subinterpreter is deleted, untrack all objects tracked by its GC. + To prevent a crash in deallocator functions expecting objects to be + tracked by the GC, leak a strong reference to these objects on purpose, so + they are never deleted and their deallocator functions are not called. + Patch by Victor Stinner. -- gh-issue-92032: The interpreter can now autocomplete soft keywords, as of - now ``match``, ``case``, and ``_`` (wildcard pattern) from :pep:`634`. +- gh-92032: The interpreter can now autocomplete soft keywords, as of now + ``match``, ``case``, and ``_`` (wildcard pattern) from :pep:`634`. -- gh-issue-87999: The warning emitted by the Python parser for a numeric - literal immediately followed by keyword has been changed from deprecation - warning to syntax warning. +- gh-87999: The warning emitted by the Python parser for a numeric literal + immediately followed by keyword has been changed from deprecation warning + to syntax warning. -- gh-issue-91869: Fix an issue where specialized opcodes with extended - arguments could produce incorrect tracing output or lead to assertion - failures. +- gh-91869: Fix an issue where specialized opcodes with extended arguments + could produce incorrect tracing output or lead to assertion failures. -- gh-issue-91603: Speed up :class:`types.UnionType` instantiation. Based on - patch provided by Yurii Karabas. +- gh-91603: Speed up :class:`types.UnionType` instantiation. Based on patch + provided by Yurii Karabas. -- gh-issue-89373: If Python is built in debug mode, Python now ensures that +- gh-89373: If Python is built in debug mode, Python now ensures that deallocator functions leave the current exception unchanged. Patch by Victor Stinner. -- gh-issue-91632: Fix a minor memory leak at exit: release the memory of the +- gh-91632: Fix a minor memory leak at exit: release the memory of the :class:`generic_alias_iterator` type. Patch by Donghee Na. -- gh-issue-81548: Octal escapes with value larger than ``0o377`` now produce - a :exc:`DeprecationWarning`. In a future Python version they will be a +- gh-81548: Octal escapes with value larger than ``0o377`` now produce a + :exc:`DeprecationWarning`. In a future Python version they will be a :exc:`SyntaxWarning` and eventually a :exc:`SyntaxError`. - bpo-43950: Use a single compact table for line starts, ends and column offsets. Reduces memory consumption for location info by half -- gh-issue-91102: Use Argument Clinic for :class:`EncodingMap`. Patch by - Oleg Iarygin. +- gh-91102: Use Argument Clinic for :class:`EncodingMap`. Patch by Oleg + Iarygin. -- gh-issue-91636: Fixed a crash in a garbage-collection edge-case, in which - a ``PyFunction_Type.tp_clear`` function could leave a python function - object in an inconsistent state. +- gh-91636: Fixed a crash in a garbage-collection edge-case, in which a + ``PyFunction_Type.tp_clear`` function could leave a python function object + in an inconsistent state. -- gh-issue-91603: Speed up :func:`isinstance` and :func:`issubclass` checks - for :class:`types.UnionType`. Patch by Yurii Karabas. +- gh-91603: Speed up :func:`isinstance` and :func:`issubclass` checks for + :class:`types.UnionType`. Patch by Yurii Karabas. -- gh-issue-91625: Fixed a bug in which adaptive opcodes ignored any - preceding ``EXTENDED_ARG``\ s on specialization failure. +- gh-91625: Fixed a bug in which adaptive opcodes ignored any preceding + ``EXTENDED_ARG``\ s on specialization failure. -- gh-issue-78607: The LLTRACE special build now looks for the name - ``__lltrace__`` defined in module globals, rather than the name - ``__ltrace__``, which had been introduced as a typo. +- gh-78607: The LLTRACE special build now looks for the name ``__lltrace__`` + defined in module globals, rather than the name ``__ltrace__``, which had + been introduced as a typo. -- gh-issue-91576: Speed up iteration of ascii strings by 50%. Patch by Kumar +- gh-91576: Speed up iteration of ascii strings by 50%. Patch by Kumar Aditya. -- gh-issue-89279: Improve interpreter performance on Windows by inlining a - few specific macros. +- gh-89279: Improve interpreter performance on Windows by inlining a few + specific macros. -- gh-issue-91502: Add a new :c:func:`_PyFrame_IsEntryFrame` API function, to +- gh-91502: Add a new :c:func:`!_PyFrame_IsEntryFrame` API function, to check if a :c:type:`PyFrameObject` is an entry frame. Patch by Pablo Galindo. -- gh-issue-91266: Refactor the ``bytearray`` strip methods ``strip``, - ``lstrip`` and ``rstrip`` to use a common implementation. +- gh-91266: Refactor the ``bytearray`` strip methods ``strip``, ``lstrip`` + and ``rstrip`` to use a common implementation. -- gh-issue-91479: Replaced the ``__note__`` field of :exc:`BaseException` - (added in an earlier version of 3.11) with the final design of :pep:`678`. +- gh-91479: Replaced the ``__note__`` field of :exc:`BaseException` (added + in an earlier version of 3.11) with the final design of :pep:`678`. Namely, :exc:`BaseException` gets an :meth:`add_note` method, and its ``__notes__`` field is created when necessary. -- gh-issue-46055: Speed up right shift of negative integers, by removing +- gh-46055: Speed up right shift of negative integers, by removing unnecessary creation of temporaries. Original patch by Xinhang Xu, reworked by Mark Dickinson. -- gh-issue-91462: Make the interpreter's low-level tracing (lltrace) feature +- gh-91462: Make the interpreter's low-level tracing (lltrace) feature output more readable by displaying opcode names (rather than just numbers), and by displaying stack contents before each opcode. -- gh-issue-89455: Fixed an uninitialized bool value in the traceback - printing code path that was introduced by the initial bpo-45292 exception - groups work. +- gh-89455: Fixed an uninitialized bool value in the traceback printing code + path that was introduced by the initial bpo-45292 exception groups work. -- gh-issue-91421: Fix a potential integer overflow in _Py_DecodeUTF8Ex. +- gh-91421: Fix a potential integer overflow in _Py_DecodeUTF8Ex. -- gh-issue-91428: Add ``static const char *const _PyOpcode_OpName[256] = - {...};`` to ``opcode.h`` for debug builds to assist in debugging the - Python interpreter. It is now more convenient to make various forms of - debugging output more human-readable by including opcode names rather than - just the corresponding decimal digits. +- gh-91428: Add ``static const char *const _PyOpcode_OpName[256] = {...};`` + to ``opcode.h`` for debug builds to assist in debugging the Python + interpreter. It is now more convenient to make various forms of debugging + output more human-readable by including opcode names rather than just the + corresponding decimal digits. - bpo-47120: Make :opcode:`POP_JUMP_IF_TRUE`, :opcode:`POP_JUMP_IF_FALSE`, :opcode:`POP_JUMP_IF_NONE` and :opcode:`POP_JUMP_IF_NOT_NONE` virtual, @@ -8467,76 +9319,74 @@ Core and Builtins Library ------- -- gh-issue-87901: Add the *encoding* parameter to :func:`os.popen`. +- gh-87901: Add the *encoding* parameter to :func:`os.popen`. -- gh-issue-90997: Fix an issue where :mod:`dis` utilities may interpret - populated inline cache entries as valid instructions. +- gh-90997: Fix an issue where :mod:`dis` utilities may interpret populated + inline cache entries as valid instructions. -- gh-issue-92332: Deprecate :class:`typing.Text` (removal of the class is +- gh-92332: Deprecate :class:`typing.Text` (removal of the class is currently not planned). Patch by Alex Waygood. - Deprecate nested classes in enum definitions becoming members -- in 3.13 they will be normal classes; add ``member`` and ``nonmember`` functions to allow control over results now. -- gh-issue-92356: Fixed a performance regression in ctypes function calls. +- gh-92356: Fixed a performance regression in ctypes function calls. -- gh-issue-90997: Show the actual named values stored in inline caches when +- gh-90997: Show the actual named values stored in inline caches when ``show_caches=True`` is passed to :mod:`dis` utilities. -- gh-issue-92301: Prefer ``close_range()`` to iterating over procfs for file +- gh-92301: Prefer ``close_range()`` to iterating over procfs for file descriptor closing in :mod:`subprocess` for better performance. -- gh-issue-67248: Sort the miscellaneous topics in Cmd.do_help() +- gh-67248: Sort the miscellaneous topics in Cmd.do_help() -- gh-issue-92210: Port ``socket.__init__`` to Argument Clinic. Patch by - Cinder. +- gh-92210: Port ``socket.__init__`` to Argument Clinic. Patch by Cinder. -- gh-issue-80010: Add support for generalized ISO 8601 parsing to +- gh-80010: Add support for generalized ISO 8601 parsing to :meth:`datetime.datetime.fromisoformat`, :meth:`datetime.date.fromisoformat` and :meth:`datetime.time.fromisoformat`. Patch by Paul Ganssle. -- gh-issue-92118: Fix a 3.11 regression in - :func:`~contextlib.contextmanager`, which caused it to propagate - exceptions with incorrect tracebacks. +- gh-92118: Fix a 3.11 regression in :func:`~contextlib.contextmanager`, + which caused it to propagate exceptions with incorrect tracebacks. -- gh-issue-90887: Adding ``COPYFILE_STAT``, ``COPYFILE_ACL`` and +- gh-90887: Adding ``COPYFILE_STAT``, ``COPYFILE_ACL`` and ``COPYFILE_XATTR`` constants for :func:`os.fcopyfile` available in macOs. -- gh-issue-91215: For :func:`@dataclass `, add +- gh-91215: For :func:`@dataclass `, add *weakref_slot*. The new parameter defaults to ``False``. If true, and if ``slots=True``, add a slot named ``"__weakref__"``, which will allow instances to be weakref'd. Contributed by Eric V. Smith -- gh-issue-85984: New function os.login_tty() for Unix. +- gh-85984: New function os.login_tty() for Unix. -- gh-issue-92128: Add :meth:`~object.__class_getitem__` to +- gh-92128: Add :meth:`~object.__class_getitem__` to :class:`logging.LoggerAdapter` and :class:`logging.StreamHandler`, allowing them to be parameterized at runtime. Patch by Alex Waygood. -- gh-issue-92049: Forbid pickling constants ``re._constants.SUCCESS`` etc. +- gh-92049: Forbid pickling constants ``re._constants.SUCCESS`` etc. Previously, pickling did not fail, but the result could not be unpickled. -- gh-issue-92062: :class:`inspect.Parameter` now raises :exc:`ValueError` if +- gh-92062: :class:`inspect.Parameter` now raises :exc:`ValueError` if ``name`` is a keyword, in addition to the existing check that it is an identifier. -- gh-issue-87390: Add an ``__unpacked__`` attribute to +- gh-87390: Add an ``__unpacked__`` attribute to :class:`types.GenericAlias`. Patch by Jelle Zijlstra. -- gh-issue-88089: Add support for generic :class:`typing.NamedTuple`. +- gh-88089: Add support for generic :class:`typing.NamedTuple`. -- gh-issue-91996: New http.HTTPMethod enum to represent all the available - HTTP request methods in a convenient way +- gh-91996: New http.HTTPMethod enum to represent all the available HTTP + request methods in a convenient way -- gh-issue-91984: Modified test strings in test_argparse.py to not contain +- gh-91984: Modified test strings in test_argparse.py to not contain trailing spaces before end of line. -- gh-issue-91952: Add ``encoding="locale"`` support to +- gh-91952: Add ``encoding="locale"`` support to :meth:`TextIOWrapper.reconfigure`. -- gh-issue-91954: Add *encoding* and *errors* arguments to +- gh-91954: Add *encoding* and *errors* arguments to :func:`subprocess.getoutput` and :func:`subprocess.getstatusoutput`. - bpo-47029: Always close the read end of the pipe used by @@ -8545,167 +9395,165 @@ Library collection and at :meth:`multiprocessing.Queue.close` calls. Patch by Géry Ogam. -- gh-issue-91928: Add ``datetime.UTC`` alias for ``datetime.timezone.utc``. +- gh-91928: Add ``datetime.UTC`` alias for ``datetime.timezone.utc``. Patch by Kabir Kwatra. -- gh-issue-68966: The :mod:`mailcap` module is now deprecated and will be - removed in Python 3.13. See :pep:`594` for the rationale and the - :mod:`mimetypes` module for an alternative. Patch by Victor Stinner. +- gh-68966: The :mod:`mailcap` module is now deprecated and will be removed + in Python 3.13. See :pep:`594` for the rationale and the :mod:`mimetypes` + module for an alternative. Patch by Victor Stinner. -- gh-issue-91401: Provide a way to disable :mod:`subprocess` use of - ``vfork()`` just in case it is ever needed and document the existing - mechanism for ``posix_spawn()``. +- gh-91401: Provide a way to disable :mod:`subprocess` use of ``vfork()`` + just in case it is ever needed and document the existing mechanism for + ``posix_spawn()``. -- gh-issue-64783: Fix :const:`signal.NSIG` value on FreeBSD to accept signal +- gh-64783: Fix :const:`signal.NSIG` value on FreeBSD to accept signal numbers greater than 32, like :const:`signal.SIGRTMIN` and :const:`signal.SIGRTMAX`. Patch by Victor Stinner. -- gh-issue-91910: Add missing f prefix to f-strings in error messages from - the :mod:`multiprocessing` and :mod:`asyncio` modules. +- gh-91910: Add missing f prefix to f-strings in error messages from the + :mod:`multiprocessing` and :mod:`asyncio` modules. -- gh-issue-91860: Add :func:`typing.dataclass_transform`, implementing - :pep:`681`. Patch by Jelle Zijlstra. +- gh-91860: Add :func:`typing.dataclass_transform`, implementing :pep:`681`. + Patch by Jelle Zijlstra. -- gh-issue-91832: Add ``required`` attribute to :class:`argparse.Action` - repr output. +- gh-91832: Add ``required`` attribute to :class:`argparse.Action` repr + output. -- gh-issue-91827: In the :mod:`tkinter` module add method - ``info_patchlevel()`` which returns the exact version of the Tcl library - as a named tuple similar to :data:`sys.version_info`. +- gh-91827: In the :mod:`tkinter` module add method ``info_patchlevel()`` + which returns the exact version of the Tcl library as a named tuple + similar to :data:`sys.version_info`. -- gh-issue-84461: Add :option:`--enable-wasm-pthreads` to enable pthreads - support for WASM builds. ``Emscripten/node`` no longer has threading - enabled by default. Include additional file systems. +- gh-84461: Add :option:`--enable-wasm-pthreads` to enable pthreads support + for WASM builds. ``Emscripten/node`` no longer has threading enabled by + default. Include additional file systems. -- gh-issue-91821: Fix unstable ``test_from_tuple`` test in - ``test_decimal.py``. +- gh-91821: Fix unstable ``test_from_tuple`` test in ``test_decimal.py``. -- gh-issue-91217: Deprecate the xdrlib module. +- gh-91217: Deprecate the xdrlib module. -- gh-issue-91217: Deprecate the uu module. +- gh-91217: Deprecate the uu module. -- gh-issue-91760: More strict rules will be applied for numerical group - references and group names in regular expressions. For now, a deprecation - warning is emitted for group references and group names which will be - errors in future Python versions. +- gh-91760: More strict rules will be applied for numerical group references + and group names in regular expressions. For now, a deprecation warning is + emitted for group references and group names which will be errors in + future Python versions. -- gh-issue-84461: Add provisional :data:`sys._emscripten_info` named tuple - with build-time and run-time information about Emscripten platform. +- gh-84461: Add provisional :data:`sys._emscripten_info` named tuple with + build-time and run-time information about Emscripten platform. -- gh-issue-90623: :func:`signal.raise_signal` and :func:`os.kill` now check +- gh-90623: :func:`signal.raise_signal` and :func:`os.kill` now check immediately for pending signals. Patch by Victor Stinner. -- gh-issue-91734: Fix OSS audio support on Solaris. +- gh-91734: Fix OSS audio support on Solaris. -- gh-issue-90633: Include the passed value in the exception thrown by +- gh-90633: Include the passed value in the exception thrown by :func:`typing.assert_never`. Patch by Jelle Zijlstra. -- gh-issue-91700: Compilation of regular expression containing a conditional +- gh-91700: Compilation of regular expression containing a conditional expression ``(?(group)...)`` now raises an appropriate :exc:`re.error` if the group number refers to not defined group. Previously an internal RuntimeError was raised. -- gh-issue-91231: Add an optional keyword *shutdown_timeout* parameter to - the :class:`multiprocessing.BaseManager` constructor. Kill the process if +- gh-91231: Add an optional keyword *shutdown_timeout* parameter to the + :class:`multiprocessing.BaseManager` constructor. Kill the process if terminate() takes longer than the timeout. Patch by Victor Stinner. -- gh-issue-91621: Fix :func:`typing.get_type_hints` for +- gh-91621: Fix :func:`typing.get_type_hints` for :class:`collections.abc.Callable`. Patch by Shantanu Jain. -- gh-issue-90568: Parsing ``\N`` escapes of Unicode Named Character - Sequences in a :mod:`regular expression ` raises now :exc:`re.error` - instead of ``TypeError``. +- gh-90568: Parsing ``\N`` escapes of Unicode Named Character Sequences in a + :mod:`regular expression ` raises now :exc:`re.error` instead of + ``TypeError``. -- gh-issue-91670: Remove deprecated ``SO`` config variable in - :mod:`sysconfig`. +- gh-91670: Remove deprecated ``SO`` config variable in :mod:`sysconfig`. -- gh-issue-91217: Deprecate the telnetlib module. +- gh-91217: Deprecate the telnetlib module. -- gh-issue-91217: Deprecate the sunau module. +- gh-91217: Deprecate the sunau module. -- gh-issue-91217: Deprecate the spwd module. +- gh-91217: Deprecate the spwd module. -- gh-issue-91217: Deprecate the sndhdr module, as well as inline needed +- gh-91217: Deprecate the sndhdr module, as well as inline needed functionality for ``email.mime.MIMEAudio``. -- gh-issue-91616: :mod:`re` module, fix :meth:`~re.Pattern.fullmatch` - mismatch when using Atomic Grouping or Possessive Quantifiers. +- gh-91616: :mod:`re` module, fix :meth:`~re.Pattern.fullmatch` mismatch + when using Atomic Grouping or Possessive Quantifiers. -- gh-issue-91217: Deprecate the 'pipes' module. +- gh-91217: Deprecate the 'pipes' module. -- gh-issue-91217: Deprecate the ossaudiodev module. +- gh-91217: Deprecate the ossaudiodev module. - bpo-47256: :mod:`re` module, limit the maximum capturing group to 1,073,741,823 in 64-bit build, this increases the depth of backtracking. -- gh-issue-91217: Deprecate the nis module. +- gh-91217: Deprecate the nis module. -- gh-issue-91595: Fix the comparison of character and integer inside +- gh-91595: Fix the comparison of character and integer inside :func:`Tools.gdb.libpython.write_repr`. Patch by Yu Liu. -- gh-issue-74166: Add option to raise all errors from +- gh-74166: Add option to raise all errors from :meth:`~socket.create_connection` in an :exc:`ExceptionGroup` when it fails to create a connection. The default remains to raise only the last error that had occurred when multiple addresses were tried. -- gh-issue-91487: Optimize asyncio UDP speed, over 100 times faster when +- gh-91487: Optimize asyncio UDP speed, over 100 times faster when transferring a large file. -- gh-issue-91575: Update case-insensitive matching in the :mod:`re` module - to the latest Unicode version. +- gh-91575: Update case-insensitive matching in the :mod:`re` module to the + latest Unicode version. -- gh-issue-90622: In ``concurrent.futures.process.ProcessPoolExecutor`` - disallow the "fork" multiprocessing start method when the new +- gh-90622: In ``concurrent.futures.process.ProcessPoolExecutor`` disallow + the "fork" multiprocessing start method when the new ``max_tasks_per_child`` feature is used as the mix of threads+fork can hang the child processes. Default to using the safe "spawn" start method in that circumstance if no ``mp_context`` was supplied. -- gh-issue-89022: In :mod:`sqlite3`, ``SQLITE_MISUSE`` result codes are now - mapped to :exc:`~sqlite3.InterfaceError` instead of +- gh-89022: In :mod:`sqlite3`, ``SQLITE_MISUSE`` result codes are now mapped + to :exc:`~sqlite3.InterfaceError` instead of :exc:`~sqlite3.ProgrammingError`. Also, more accurate exceptions are raised when binding parameters fail. Patch by Erlend E. Aasland. -- gh-issue-91526: Stop calling ``os.device_encoding(file.fileno())`` in +- gh-91526: Stop calling ``os.device_encoding(file.fileno())`` in :class:`TextIOWrapper`. It was complex, never documented, and didn't work for most cases. (Patch by Inada Naoki.) -- gh-issue-88116: Change the frame-related functions in the :mod:`inspect` - module to return a regular object (that is backwards compatible with the - old tuple-like interface) that include the extended :pep:`657` position +- gh-88116: Change the frame-related functions in the :mod:`inspect` module + to return a regular object (that is backwards compatible with the old + tuple-like interface) that include the extended :pep:`657` position information (end line number, column and end column). The affected functions are: :func:`inspect.getframeinfo`, :func:`inspect.getouterframes`, :func:`inspect.getinnerframes`, :func:`inspect.stack` and :func:`inspect.trace`. Patch by Pablo Galindo. -- gh-issue-69093: Add indexing and slicing support to :class:`sqlite3.Blob`. - Patch by Aviv Palivoda and Erlend E. Aasland. +- gh-69093: Add indexing and slicing support to :class:`sqlite3.Blob`. Patch + by Aviv Palivoda and Erlend E. Aasland. -- gh-issue-69093: Add :term:`context manager` support to - :class:`sqlite3.Blob`. Patch by Aviv Palivoda and Erlend E. Aasland. +- gh-69093: Add :term:`context manager` support to :class:`sqlite3.Blob`. + Patch by Aviv Palivoda and Erlend E. Aasland. -- gh-issue-91217: Deprecate nntplib. +- gh-91217: Deprecate nntplib. -- gh-issue-91217: Deprecate msilib. +- gh-91217: Deprecate msilib. -- gh-issue-91404: Improve the performance of :mod:`re` matching by using - computed gotos (or "threaded code") on supported platforms and removing - expensive pointer indirections. +- gh-91404: Improve the performance of :mod:`re` matching by using computed + gotos (or "threaded code") on supported platforms and removing expensive + pointer indirections. -- gh-issue-91217: Deprecate the imghdr module. +- gh-91217: Deprecate the imghdr module. -- gh-issue-91217: Deprecate the crypt module. +- gh-91217: Deprecate the crypt module. -- gh-issue-91276: Make space for longer opcodes in :mod:`dis` output. +- gh-91276: Make space for longer opcodes in :mod:`dis` output. - bpo-47000: Make :class:`TextIOWrapper` uses locale encoding when ``encoding="locale"`` is specified even in UTF-8 mode. -- gh-issue-91230: :func:`warnings.catch_warnings` now accepts arguments for +- gh-91230: :func:`warnings.catch_warnings` now accepts arguments for :func:`warnings.simplefilter`, providing a more concise way to locally ignore warnings or convert them to errors. -- gh-issue-91217: Deprecate the chunk module. +- gh-91217: Deprecate the chunk module. - Add the ``TCP_CONNECTION_INFO`` option (available on macOS) to :mod:`socket`. @@ -8853,17 +9701,16 @@ Library Documentation ------------- -- gh-issue-91888: Add a new ``gh`` role to the documentation to link to - GitHub issues. +- gh-91888: Add a new ``gh`` role to the documentation to link to GitHub + issues. -- gh-issue-91783: Document security issues concerning the use of the - function :meth:`shutil.unpack_archive` +- gh-91783: Document security issues concerning the use of the function + :meth:`shutil.unpack_archive` -- gh-issue-91547: Remove "Undocumented modules" page. +- gh-91547: Remove "Undocumented modules" page. -- gh-issue-91298: In ``importlib.resources.abc``, refined the documentation - of the Traversable Protocol, applying changes from importlib_resources - 5.7.1. +- gh-91298: In ``importlib.resources.abc``, refined the documentation of the + Traversable Protocol, applying changes from importlib_resources 5.7.1. - bpo-44347: Clarify the meaning of *dirs_exist_ok*, a kwarg of :func:`shutil.copytree`. @@ -8881,10 +9728,9 @@ Documentation of the :ref:`Limited API/Stable ABI `. - bpo-46962: All docstrings in code snippets are now wrapped into - :c:macro:`PyDoc_STR` to follow the guideline of `PEP 7's Documentation - Strings paragraph - `_. Patch - by Oleg Iarygin. + :c:macro:`PyDoc_STR` to follow the guideline of :pep:`PEP 7's + Documentation Strings paragraph <0007#documentation-strings>`. Patch by + Oleg Iarygin. - bpo-26792: Improve the docstrings of :func:`runpy.run_module` and :func:`runpy.run_path`. Original patch by Andrew Brezovsky. @@ -8892,21 +9738,19 @@ Documentation Tests ----- -- gh-issue-92169: Use ``warnings_helper.import_deprecated()`` to import - deprecated modules uniformly in tests. Patch by Hugo van Kemenade. +- gh-92169: Use ``warnings_helper.import_deprecated()`` to import deprecated + modules uniformly in tests. Patch by Hugo van Kemenade. -- gh-issue-84461: When multiprocessing is enabled, libregrtest can now use a +- gh-84461: When multiprocessing is enabled, libregrtest can now use a Python executable other than :code:`sys.executable` via the ``--python`` flag. -- gh-issue-91904: Fix initialization of - :envvar:`PYTHONREGRTEST_UNICODE_GUARD` which prevented running regression - tests on non-UTF-8 locale. +- gh-91904: Fix initialization of :envvar:`PYTHONREGRTEST_UNICODE_GUARD` + which prevented running regression tests on non-UTF-8 locale. -- gh-issue-91752: Added @requires_zlib to - test.test_tools.test_freeze.TestFreeze. +- gh-91752: Added @requires_zlib to test.test_tools.test_freeze.TestFreeze. -- gh-issue-91607: Fix ``test_concurrent_futures`` to test the correct +- gh-91607: Fix ``test_concurrent_futures`` to test the correct multiprocessing start method context in several cases where the test logic mixed this up. @@ -8925,12 +9769,11 @@ Tests Build ----- -- gh-issue-89452: gdbm-compat is now preferred over ndbm if both are - available on the system. This allows avoiding the problematic ndbm.h on - macOS. +- gh-89452: gdbm-compat is now preferred over ndbm if both are available on + the system. This allows avoiding the problematic ndbm.h on macOS. -- gh-issue-91731: Python is now built with ``-std=c11`` compiler option, - rather than ``-std=c99``. Patch by Victor Stinner. +- gh-91731: Python is now built with ``-std=c11`` compiler option, rather + than ``-std=c99``. Patch by Victor Stinner. - bpo-47152: Add script and make target for generating ``sre_constants.h``. @@ -8962,45 +9805,43 @@ macOS Tools/Demos ----------- -- gh-issue-91583: Fix regression in the code generated by Argument Clinic - for functions with the ``defining_class`` parameter. +- gh-91583: Fix regression in the code generated by Argument Clinic for + functions with the ``defining_class`` parameter. -- gh-issue-91575: Add script ``Tools/scripts/generate_re_casefix.py`` and - the make target ``regen-re`` for generating additional data for - case-insensitive matching according to the current Unicode version. +- gh-91575: Add script ``Tools/scripts/generate_re_casefix.py`` and the make + target ``regen-re`` for generating additional data for case-insensitive + matching according to the current Unicode version. -- gh-issue-91551: Remove the ancient Pynche color editor. It has moved to +- gh-91551: Remove the ancient Pynche color editor. It has moved to https://gitlab.com/warsaw/pynche C API ----- -- gh-issue-88279: Deprecate the C functions: :c:func:`PySys_SetArgv`, +- gh-88279: Deprecate the C functions: :c:func:`PySys_SetArgv`, :c:func:`PySys_SetArgvEx`, :c:func:`PySys_SetPath`. Patch by Victor Stinner. -- gh-issue-92154: Added the :c:func:`PyCode_GetCode` function. This function - does the equivalent of the Python code ``getattr(code_object, - 'co_code')``. +- gh-92154: Added the :c:func:`PyCode_GetCode` function. This function does + the equivalent of the Python code ``getattr(code_object, 'co_code')``. -- gh-issue-92173: Fix the ``closure`` argument to - :c:func:`PyEval_EvalCodeEx`. +- gh-92173: Fix the ``closure`` argument to :c:func:`PyEval_EvalCodeEx`. -- gh-issue-91320: Fix C++ compiler warnings about "old-style cast" (``g++ +- gh-91320: Fix C++ compiler warnings about "old-style cast" (``g++ -Wold-style-cast``) in the Python C API. Use C++ ``reinterpret_cast<>`` and ``static_cast<>`` casts when the Python C API is used in C++. Patch by Victor Stinner. -- gh-issue-80527: Mark functions as deprecated by :pep:`623`: +- gh-80527: Mark functions as deprecated by :pep:`623`: :c:func:`!PyUnicode_AS_DATA`, :c:func:`!PyUnicode_AS_UNICODE`, :c:func:`!PyUnicode_GET_DATA_SIZE`, :c:func:`!PyUnicode_GET_SIZE`. Patch by Victor Stinner. -- gh-issue-91768: :c:func:`Py_REFCNT`, :c:func:`Py_TYPE`, :c:func:`Py_SIZE` - and :c:func:`Py_IS_TYPE` functions argument type is now ``PyObject*``, - rather than ``const PyObject*``. Patch by Victor Stinner. +- gh-91768: :c:func:`Py_REFCNT`, :c:func:`Py_TYPE`, :c:func:`Py_SIZE` and + :c:func:`Py_IS_TYPE` functions argument type is now ``PyObject*``, rather + than ``const PyObject*``. Patch by Victor Stinner. -- gh-issue-91020: Add ``PyBytes_Type.tp_alloc`` to initialize +- gh-91020: Add ``PyBytes_Type.tp_alloc`` to initialize ``PyBytesObject.ob_shash`` for bytes subclasses. - bpo-40421: Add ``PyFrame_GetLasti`` C-API function to access frame @@ -9109,7 +9950,7 @@ Core and Builtins - bpo-47012: Speed up iteration of :class:`bytes` and :class:`bytearray` by 30%. Patch by Kumar Aditya. -- bpo-47009: Improved the performance of :meth:`list.append()` and list +- bpo-47009: Improved the performance of :meth:`list.append` and list comprehensions by optimizing for the common case, where no resize is needed. Patch by Dennis Sweeney. @@ -9427,7 +10268,7 @@ Library * Don't overwrite :exc:`BufferError` with :exc:`ValueError` when conversion to BLOB fails. * Raise :exc:`~sqlite3.ProgrammingError` instead of :exc:`~sqlite3.Warning` if - user tries to :meth:`~sqlite3.Cursor.execute()` more than one SQL statement. + user tries to :meth:`~sqlite3.Cursor.execute` more than one SQL statement. * Raise :exc:`~sqlite3.ProgrammingError` instead of :exc:`ValueError` if an SQL query contains null characters. @@ -9527,7 +10368,7 @@ Build script with Christian's container image ``quay.io/tiran/cpython_autoconf:269``. -- bpo-46917: Building Python now requires support of IEEE 754 floating point +- bpo-46917: Building Python now requires support of IEEE 754 floating-point numbers. Patch by Victor Stinner. - bpo-45774: ``configure`` now verifies that all SQLite C APIs needed for @@ -9997,7 +10838,7 @@ Build - bpo-46656: Building Python now requires a C11 compiler. Optional C11 features are not required. Patch by Victor Stinner. -- bpo-46656: Building Python now requires support for floating point +- bpo-46656: Building Python now requires support for floating-point Not-a-Number (NaN): remove the ``Py_NO_NAN`` macro. Patch by Victor Stinner. @@ -10247,9 +11088,9 @@ Library - bpo-46422: Use ``dis.Positions`` in ``dis.Instruction`` instead of a regular ``tuple``. -- bpo-46434: :mod:`pdb` now gracefully handles ``help`` when :attr:`__doc__` - is missing, for example when run with pregenerated optimized ``.pyc`` - files. +- bpo-46434: :mod:`pdb` now gracefully handles ``help`` when + :attr:`~module.__doc__` is missing, for example when run with pregenerated + optimized ``.pyc`` files. - bpo-43869: Python uses the same time Epoch on all platforms. Add an explicit unit test to ensure that it's the case. Patch by Victor Stinner. @@ -10544,8 +11385,8 @@ Core and Builtins ``SEND`` instruction which performs the same operation, but without the loop. -- bpo-45635: The code called from :c:func:`_PyErr_Display` was refactored to - improve error handling. It now exits immediately upon an unrecoverable +- bpo-45635: The code called from :c:func:`!_PyErr_Display` was refactored + to improve error handling. It now exits immediately upon an unrecoverable error. - bpo-46054: Fix parser error when parsing non-utf8 characters in source @@ -10897,7 +11738,7 @@ Core and Builtins - bpo-46004: Fix the :exc:`SyntaxError` location for errors involving for loops with invalid targets. Patch by Pablo Galindo -- bpo-45711: :c:func:`_PyErr_ChainStackItem` no longer normalizes +- bpo-45711: :c:func:`!_PyErr_ChainStackItem` no longer normalizes ``exc_info`` (including setting the traceback on the exception instance) because ``exc_info`` is always normalized. @@ -11375,7 +12216,7 @@ Core and Builtins Galindo. - bpo-45688: :data:`sys.stdlib_module_names` now contains the macOS-specific - module :mod:`_scproxy`. + module :mod:`!_scproxy`. - bpo-45379: Clarify :exc:`ImportError` message when we try to explicitly import a frozen module but frozen modules are disabled. @@ -11752,7 +12593,7 @@ Build - bpo-45571: ``Modules/Setup`` now use ``PY_CFLAGS_NODIST`` instead of ``PY_CFLAGS`` to compile shared modules. -- bpo-45570: :mod:`pyexpat` and :mod:`_elementtree` no longer define +- bpo-45570: :mod:`pyexpat` and :mod:`!_elementtree` no longer define obsolete macros ``HAVE_EXPAT_CONFIG_H`` and ``USE_PYEXPAT_CAPI``. ``XML_POOR_ENTROPY`` is now defined in ``expat_config.h``. @@ -12134,7 +12975,7 @@ Core and Builtins - bpo-44732: Rename ``types.Union`` to ``types.UnionType``. - bpo-44725: Expose specialization stats in python via - :func:`_opcode.get_specialization_stats`. + :func:`!_opcode.get_specialization_stats`. - bpo-44717: Improve AttributeError on circular imports of submodules. @@ -12545,7 +13386,7 @@ Library * Old alias ``_TextTestResult`` of :class:`~unittest.TextTestResult`. - bpo-38371: Remove the deprecated ``split()`` method of - :class:`_tkinter.TkappType`. Patch by Erlend E. Aasland. + :class:`!_tkinter.TkappType`. Patch by Erlend E. Aasland. - bpo-20499: Improve the speed and accuracy of statistics.pvariance(). @@ -12667,7 +13508,7 @@ Library occurs during file extraction. - bpo-44935: :mod:`subprocess` on Solaris now also uses - :func:`os.posix_spawn()` for better performance. + :func:`os.posix_spawn` for better performance. - bpo-44911: :class:`~unittest.IsolatedAsyncioTestCase` will no longer throw an exception while cancelling leaked tasks. Patch by Bar Harel. @@ -12774,10 +13615,10 @@ Library - bpo-44690: Adopt *binacii.a2b_base64*'s strict mode in *base64.b64decode*. -- bpo-42854: Fixed a bug in the :mod:`_ssl` module that was throwing - :exc:`OverflowError` when using :meth:`_ssl._SSLSocket.write` and - :meth:`_ssl._SSLSocket.read` for a big value of the ``len`` parameter. - Patch by Pablo Galindo +- bpo-42854: Fixed a bug in the :mod:`!_ssl` module that was throwing + :exc:`OverflowError` when using :meth:`!_ssl._SSLSocket.write` and + :meth:`!_ssl._SSLSocket.read` for a big value of the ``len`` parameter. + Patch by Pablo Galindo. - bpo-44686: Replace ``unittest.mock._importer`` with ``pkgutil.resolve_name``. @@ -12808,7 +13649,7 @@ Library :exc:`TypeError`, it should be :exc:`OSError` with appropriate error message. -- bpo-44608: Fix memory leak in :func:`_tkinter._flatten` if it is called +- bpo-44608: Fix memory leak in :func:`!_tkinter._flatten` if it is called with a sequence or set, but not list or tuple. - bpo-44594: Fix an edge case of :class:`ExitStack` and @@ -13439,7 +14280,7 @@ Tests - bpo-25130: Add calls of :func:`gc.collect` in tests to support PyPy. -- bpo-45011: Made tests relying on the :mod:`_asyncio` C extension module +- bpo-45011: Made tests relying on the :mod:`!_asyncio` C extension module optional to allow running on alternative Python implementations. Patch by Serhiy Storchaka. @@ -13457,7 +14298,7 @@ Tests potential harmless "malloc can't allocate region" messages spewed by test_decimal. -- bpo-44734: Fixed floating point precision issue in turtle tests. +- bpo-44734: Fixed floating-point precision issue in turtle tests. - bpo-44708: Regression tests, when run with -w, are now re-running only the affected test methods instead of re-running the entire test file. @@ -13874,7 +14715,7 @@ Core and Builtins should not normally be possible, but might occur in some unusual circumstances. -- bpo-43963: Importing the :mod:`_signal` module in a subinterpreter has no +- bpo-43963: Importing the :mod:`!_signal` module in a subinterpreter has no longer side effects. - bpo-42739: The internal representation of line number tables is changed to @@ -14100,11 +14941,11 @@ Library _pyio.open is a Python function. In Python 3.10, _pyio.open() is now a static method, and builtins.open() is now io.open(). -- bpo-43680: The Python :func:`_pyio.open` function becomes a static method +- bpo-43680: The Python :func:`!_pyio.open` function becomes a static method to behave as :func:`io.open` built-in function: don't become a bound method when stored as a class variable. It becomes possible since static methods are now callable in Python 3.10. Moreover, - :func:`_pyio.OpenWrapper` becomes a simple alias to :func:`_pyio.open`. + :func:`!_pyio.OpenWrapper` becomes a simple alias to :func:`!_pyio.open`. Patch by Victor Stinner. - bpo-41515: Fix :exc:`KeyError` raised in :func:`typing.get_type_hints` due @@ -14168,7 +15009,7 @@ Library :class:`typing.ParamSpecKwargs`, which enables a more useful ``repr()``. Patch by Jelle Zijlstra. -- bpo-43731: Add an ``encoding`` parameter :func:`logging.fileConfig()`. +- bpo-43731: Add an ``encoding`` parameter :func:`logging.fileConfig`. - bpo-43712: Add ``encoding`` and ``errors`` parameters to :func:`fileinput.input` and :class:`fileinput.FileInput`. @@ -14289,7 +15130,7 @@ Library Patch by Ma Lin. - bpo-36470: Fix dataclasses with ``InitVar``\s and - :func:`~dataclasses.replace()`. Patch by Claudiu Popa. + :func:`~dataclasses.replace`. Patch by Claudiu Popa. - bpo-40849: Expose X509_V_FLAG_PARTIAL_CHAIN ssl flag @@ -14300,11 +15141,11 @@ Library accept a *follow_symlinks* keyword-only argument for consistency with corresponding functions in the :mod:`os` module. -- bpo-39899: :func:`os.path.expanduser()` now refuses to guess Windows home +- bpo-39899: :func:`os.path.expanduser` now refuses to guess Windows home directories if the basename of current user's home directory does not match their username. - :meth:`pathlib.Path.expanduser()` and :meth:`~pathlib.Path.home()` now + :meth:`pathlib.Path.expanduser` and :meth:`~pathlib.Path.home` now consistently raise :exc:`RuntimeError` exception when a home directory cannot be resolved. Previously a :exc:`KeyError` exception could be raised on Windows when the ``"USERNAME"`` environment variable was unset. @@ -14381,7 +15222,7 @@ Windows - bpo-35306: Adds additional arguments to :func:`os.startfile` function. -- bpo-43538: Avoid raising errors from :meth:`pathlib.Path.exists()` when +- bpo-43538: Avoid raising errors from :meth:`pathlib.Path.exists` when passed an invalid filename. - bpo-38822: Fixed :func:`os.stat` failing on inaccessible directories with @@ -14539,7 +15380,7 @@ Core and Builtins internally. This reduces the number of EXTENDED_ARG instructions needed and streamlines instruction dispatch a bit. -- bpo-40645: Fix reference leak in the :mod:`_hashopenssl` extension. Patch +- bpo-40645: Fix reference leak in the :mod:`!_hashopenssl` extension. Patch by Pablo Galindo. - bpo-42134: Calls to find_module() by the import system now raise @@ -14752,8 +15593,8 @@ Library - bpo-14678: Add an invalidate_caches() method to the zipimport.zipimporter class to support importlib.invalidate_caches(). Patch by Desmond Cheong. -- bpo-42782: Fail fast in :func:`shutil.move()` to avoid creating - destination directories on failure. +- bpo-42782: Fail fast in :func:`shutil.move` to avoid creating destination + directories on failure. - bpo-40066: Enum's ``repr()`` and ``str()`` have changed: ``repr()`` is now *EnumClass.MemberName* and ``str()`` is *MemberName*. Additionally, @@ -14772,13 +15613,13 @@ Library value of type bytes, it is now handled consistently. Previously exceptions could be raised from some tempfile APIs when the directory did not already exist in this situation. Also ensures that the - :func:`tempfile.gettempdir()` and :func:`tempfile.gettempdirb()` functions + :func:`tempfile.gettempdir` and :func:`tempfile.gettempdirb` functions *always* return ``str`` and ``bytes`` respectively. - bpo-39342: Expose ``X509_V_FLAG_ALLOW_PROXY_CERTS`` as :const:`~ssl.VERIFY_ALLOW_PROXY_CERTS` to allow proxy certificate validation as explained in - https://www.openssl.org/docs/man1.1.1/man7/proxy-certificates.html. + https://docs.openssl.org/1.1.1/man7/proxy-certificates/. - bpo-31861: Add builtins.aiter and builtins.anext. Patch by Joshua Bronson (@jab), Daniel Pope (@lordmauve), and Justin Wang (@justin39). @@ -15057,7 +15898,7 @@ Library - bpo-42151: Make the pure Python implementation of :mod:`xml.etree.ElementTree` behave the same as the C implementation - (:mod:`_elementree`) regarding default attribute values (by not setting + (:mod:`!_elementree`) regarding default attribute values (by not setting ``specified_attributes=1``). - bpo-29753: In ctypes, now packed bitfields are calculated properly and the @@ -15203,7 +16044,7 @@ Core and Builtins after reassigning a slice at the start of the ``bytearray`` to a shorter byte string). -- bpo-42882: Fix the :c:func:`_PyUnicode_FromId` function +- bpo-42882: Fix the :c:func:`!_PyUnicode_FromId` function (_Py_IDENTIFIER(var) API) when :c:func:`Py_Initialize` / :c:func:`Py_Finalize` is called multiple times: preserve ``_PyRuntime.unicode_ids.next_index`` value. @@ -15493,7 +16334,7 @@ Core and Builtins - bpo-40521: Make the Unicode dictionary of interned strings compatible with subinterpreters. Patch by Victor Stinner. -- bpo-39465: Make :c:func:`_PyUnicode_FromId` function compatible with +- bpo-39465: Make :c:func:`!_PyUnicode_FromId` function compatible with subinterpreters. Each interpreter now has an array of identifier objects (interned strings decoded from UTF-8). Patch by Victor Stinner. @@ -15553,7 +16394,7 @@ Library - bpo-9694: Argparse help no longer uses the confusing phrase, "optional arguments". It uses "options" instead. -- bpo-1635741: Port the :mod:`_thread` extension module to the multiphase +- bpo-1635741: Port the :mod:`!_thread` extension module to the multiphase initialization API (:pep:`489`) and convert its static types to heap types. @@ -15675,7 +16516,7 @@ Library - bpo-31904: Fix site and sysconfig modules for VxWorks RTOS which has no home directories. -- bpo-41462: Add :func:`os.set_blocking()` support for VxWorks RTOS. +- bpo-41462: Add :func:`os.set_blocking` support for VxWorks RTOS. - bpo-40219: Lowered :class:`tkinter.ttk.LabeledScale` dummy widget to prevent hiding part of the content label. @@ -15766,8 +16607,8 @@ C API regression. Python 3.9 uses ``-fvisibility=hidden`` and the function was not exported explicitly and so not exported. -- bpo-32381: Remove the private :c:func:`_Py_fopen` function which is no - longer needed. Use :c:func:`_Py_wfopen` or :c:func:`_Py_fopen_obj` +- bpo-32381: Remove the private :c:func:`!_Py_fopen` function which is no + longer needed. Use :c:func:`!_Py_wfopen` or :c:func:`!_Py_fopen_obj` instead. Patch by Victor Stinner. - bpo-1635741: Port :mod:`resource` extension module to module state @@ -15977,7 +16818,7 @@ Library - bpo-42403: Simplify the :mod:`importlib` external bootstrap code: ``importlib._bootstrap_external`` now uses regular imports to import - builtin modules. When it is imported, the builtin :func:`__import__()` + builtin modules. When it is imported, the builtin :func:`__import__` function is already fully working and so can be used to import builtin modules like :mod:`sys`. Patch by Victor Stinner. @@ -15990,8 +16831,8 @@ Library initialization API (:pep:`489`). Patch by Victor Stinner and Mohamed Koubaa. -- bpo-37205: :func:`time.time()`, :func:`time.perf_counter()` and - :func:`time.monotonic()` functions can no longer fail with a Python fatal +- bpo-37205: :func:`time.time`, :func:`time.perf_counter` and + :func:`time.monotonic` functions can no longer fail with a Python fatal error, instead raise a regular Python exception on failure. - bpo-42328: Fixed :meth:`tkinter.ttk.Style.map`. The function accepts now @@ -16003,12 +16844,11 @@ Library (flatten, deduplicate, use type to cache key). Patch provided by Yurii Karabas. -- bpo-37205: :func:`time.perf_counter()` on Windows and - :func:`time.monotonic()` on macOS are now system-wide. Previously, they - used an offset computed at startup to reduce the precision loss caused by - the float type. Use :func:`time.perf_counter_ns()` and - :func:`time.monotonic_ns()` added in Python 3.7 to avoid this precision - loss. +- bpo-37205: :func:`time.perf_counter` on Windows and :func:`time.monotonic` + on macOS are now system-wide. Previously, they used an offset computed at + startup to reduce the precision loss caused by the float type. Use + :func:`time.perf_counter_ns` and :func:`time.monotonic_ns` added in Python + 3.7 to avoid this precision loss. - bpo-42318: Fixed support of non-BMP characters in :mod:`tkinter` on macOS. @@ -16306,7 +17146,7 @@ C API - bpo-40170: The ``Py_TRASHCAN_BEGIN`` macro no longer accesses PyTypeObject attributes, but now can get the condition by calling the new private - :c:func:`_PyTrash_cond()` function which hides implementation details. + :c:func:`!_PyTrash_cond()` function which hides implementation details. - bpo-42260: :c:func:`Py_GetPath`, :c:func:`Py_GetPrefix`, :c:func:`Py_GetExecPrefix`, :c:func:`Py_GetProgramFullPath`, @@ -16447,8 +17287,8 @@ Core and Builtins currently active in that thread at the time the function is called. - bpo-38605: Enable ``from __future__ import annotations`` (:pep:`563`) by - default. The values found in :attr:`__annotations__` dicts are now - strings, e.g. ``{"x": "int"}`` instead of ``{"x": int}``. + default. The values found in :attr:`~object.__annotations__` dicts are now + strings, for example ``{"x": "int"}`` instead of ``{"x": int}``. Library ------- @@ -16501,13 +17341,13 @@ Library values - bpo-42065: Fix an incorrectly formatted error from - :meth:`_codecs.charmap_decode` when called with a mapped value outside the - range of valid Unicode code points. PR by Max Bernstein. + :meth:`!_codecs.charmap_decode` when called with a mapped value outside + the range of valid Unicode code points. PR by Max Bernstein. - bpo-41966: Fix pickling pure Python :class:`datetime.time` subclasses. Patch by Dean Inwood. -- bpo-19270: :meth:`sched.scheduler.cancel()` will now cancel the correct +- bpo-19270: :meth:`sched.scheduler.cancel` will now cancel the correct event, if two events with same priority are scheduled for the same time. Patch by Bar Harel. @@ -16746,7 +17586,7 @@ Core and Builtins - bpo-41870: Speed up calls to ``bool()`` by using the :pep:`590` ``vectorcall`` calling convention. Patch by Donghee Na. -- bpo-1635741: Port the :mod:`_bisect` module to the multi-phase +- bpo-1635741: Port the :mod:`!_bisect` module to the multi-phase initialization API (:pep:`489`). - bpo-39934: Correctly count control blocks in 'except' in compiler. Ensures @@ -16756,32 +17596,32 @@ Core and Builtins - bpo-41780: Fix :meth:`__dir__` of :class:`types.GenericAlias`. Patch by Batuhan Taskaya. -- bpo-1635741: Port the :mod:`_lsprof` extension module to multi-phase +- bpo-1635741: Port the :mod:`!_lsprof` extension module to multi-phase initialization (:pep:`489`). - bpo-1635741: Port the :mod:`cmath` extension module to multi-phase initialization (:pep:`489`). -- bpo-1635741: Port the :mod:`_scproxy` extension module to multi-phase +- bpo-1635741: Port the :mod:`!_scproxy` extension module to multi-phase initialization (:pep:`489`). - bpo-1635741: Port the :mod:`termios` extension module to multi-phase initialization (:pep:`489`). -- bpo-1635741: Convert the :mod:`_sha256` extension module types to heap +- bpo-1635741: Convert the :mod:`!_sha256` extension module types to heap types. - bpo-41690: Fix a possible stack overflow in the parser when parsing functions and classes with a huge amount of arguments. Patch by Pablo Galindo. -- bpo-1635741: Port the :mod:`_overlapped` extension module to multi-phase +- bpo-1635741: Port the :mod:`!_overlapped` extension module to multi-phase initialization (:pep:`489`). -- bpo-1635741: Port the :mod:`_curses_panel` extension module to multi-phase - initialization (:pep:`489`). +- bpo-1635741: Port the :mod:`!_curses_panel` extension module to + multi-phase initialization (:pep:`489`). -- bpo-1635741: Port the :mod:`_opcode` extension module to multi-phase +- bpo-1635741: Port the :mod:`!_opcode` extension module to multi-phase initialization (:pep:`489`). - bpo-41681: Fixes the wrong error description in the error raised by using @@ -16807,12 +17647,12 @@ Core and Builtins implement lazy import, whereas Python expected that ``import _ast`` always return a fully initialized ``_ast`` module. -- bpo-40077: Convert :mod:`_operator` to use :c:func:`PyType_FromSpec`. +- bpo-40077: Convert :mod:`!_operator` to use :c:func:`PyType_FromSpec`. -- bpo-1653741: Port :mod:`_sha3` to multi-phase init. Convert static types +- bpo-1653741: Port :mod:`!_sha3` to multi-phase init. Convert static types to heap types. -- bpo-1635741: Port the :mod:`_blake2` extension module to the multi-phase +- bpo-1635741: Port the :mod:`!_blake2` extension module to the multi-phase initialization API (:pep:`489`). - bpo-41533: Free the stack allocated in ``va_build_stack`` if @@ -16824,7 +17664,7 @@ Core and Builtins - bpo-41525: The output of ``python --help`` contains now only ASCII characters. -- bpo-1635741: Port the :mod:`_sha1`, :mod:`_sha512`, and :mod:`_md5` +- bpo-1635741: Port the :mod:`!_sha1`, :mod:`!_sha512`, and :mod:`!_md5` extension modules to multi-phase initialization API (:pep:`489`). - bpo-41431: Optimize ``dict_merge()`` for copying dict (e.g. ``dict(d)`` @@ -16916,7 +17756,7 @@ Core and Builtins - bpo-40939: Remove the remaining files from the old parser and the :mod:`symbol` module. -- bpo-40077: Convert :mod:`_bz2` to use :c:func:`PyType_FromSpec`. +- bpo-40077: Convert :mod:`!_bz2` to use :c:func:`PyType_FromSpec`. - bpo-41006: The ``encodings.latin_1`` module is no longer imported at startup. Now it is only imported when it is the filesystem encoding or the @@ -16926,7 +17766,7 @@ Core and Builtins which raises a :exc:`ValueError` if the arguments are exhausted at different lengths. Patch by Brandt Bucher. -- bpo-1635741: Port :mod:`_gdbm` to multiphase initialization. +- bpo-1635741: Port :mod:`!_gdbm` to multiphase initialization. - bpo-40985: Fix a bug that caused the :exc:`SyntaxError` text to be empty when a file ends with a line ending in a line continuation character (i.e. @@ -16935,7 +17775,7 @@ Core and Builtins - bpo-40958: Fix a possible buffer overflow in the PEG parser when gathering information for emitting syntax errors. Patch by Pablo Galindo. -- bpo-1635741: Port :mod:`_dbm` to multiphase initialization. +- bpo-1635741: Port :mod:`!_dbm` to multiphase initialization. - bpo-40957: Fix refleak in _Py_fopen_obj() when PySys_Audit() fails @@ -17048,7 +17888,7 @@ Core and Builtins - bpo-1635741: Port :mod:`mmap` to multiphase initialization. -- bpo-1635741: Port :mod:`_lzma` to multiphase initialization. +- bpo-1635741: Port :mod:`!_lzma` to multiphase initialization. - bpo-37999: Builtin and extension functions that take integer arguments no longer accept :class:`~decimal.Decimal`\ s, :class:`~fractions.Fraction`\ @@ -17056,7 +17896,7 @@ Core and Builtins (e.g. that have the :meth:`~object.__int__` method but do not have the :meth:`~object.__index__` method). -- bpo-29882: Add :meth:`int.bit_count()`, counting the number of ones in the +- bpo-29882: Add :meth:`int.bit_count`, counting the number of ones in the binary representation of an integer. Patch by Niklas Fiekas. - bpo-36982: Use ncurses extended color functions when available to support @@ -17213,7 +18053,7 @@ Library Inputs that used to cause ZeroDivisionError now cause an OverflowError instead. -- bpo-41440: Add :func:`os.cpu_count()` support for VxWorks RTOS. +- bpo-41440: Add :func:`os.cpu_count` support for VxWorks RTOS. - bpo-41316: Fix the :mod:`tarfile` module to write only basename of TAR file to GZIP compression header. @@ -17514,7 +18354,7 @@ Library - bpo-38144: Added the *root_dir* and *dir_fd* parameters in :func:`glob.glob`. -- bpo-26543: Fix :meth:`IMAP4.noop()` when debug mode is enabled (ex: +- bpo-26543: Fix :meth:`IMAP4.noop` when debug mode is enabled (ex: ``imaplib.Debug = 3``). - bpo-12178: :func:`csv.writer` now correctly escapes *escapechar* when @@ -18055,7 +18895,7 @@ Library ``randbytes()`` now directly reuses ``getrandbits()``. - bpo-40394: Added default arguments to - :meth:`difflib.SequenceMatcher.find_longest_match()`. + :meth:`difflib.SequenceMatcher.find_longest_match`. - bpo-39995: Fix a race condition in concurrent.futures._ThreadWakeup: access to _ThreadWakeup is now protected with the shutdown lock. @@ -18276,7 +19116,7 @@ Core and Builtins The codecs machinery can no longer work on very late calls to str.encode() and str.decode(). -- bpo-40077: Fix possible refleaks in :mod:`_json`, memo of PyScannerObject +- bpo-40077: Fix possible refleaks in :mod:`!_json`, memo of PyScannerObject should be traversed. - bpo-37207: Speed up calls to ``dict()`` by using the :pep:`590` @@ -18381,8 +19221,8 @@ Library - bpo-40330: In :meth:`ShareableList.__setitem__`, check the size of a new string item after encoding it to utf-8, not before. -- bpo-40148: Added :meth:`pathlib.Path.with_stem()` to create a new Path - with the stem replaced. +- bpo-40148: Added :meth:`pathlib.Path.with_stem` to create a new Path with + the stem replaced. - bpo-40325: Deprecated support for set objects in random.sample(). @@ -18466,7 +19306,7 @@ Library _MainThread instance for _main_thread, instead of a _DummyThread instance. - bpo-40089: Add a private ``_at_fork_reinit()`` method to - :class:`_thread.Lock`, :class:`_thread.RLock`, :class:`threading.RLock` + :class:`!_thread.Lock`, :class:`!_thread.RLock`, :class:`threading.RLock` and :class:`threading.Condition` classes: reinitialize the lock at fork in the child process, reset the lock to the unlocked state. Rename also the private ``_reset_internal_locks()`` method of :class:`threading.Event` to @@ -18541,8 +19381,8 @@ Library returned as part of source of the class. Patch by Karthikeyan Singaravelan. -- bpo-33262: Deprecate passing None as an argument for - :func:`shlex.split()`'s ``s`` parameter. Patch by Zackery Spytz. +- bpo-33262: Deprecate passing None as an argument for :func:`shlex.split`'s + ``s`` parameter. Patch by Zackery Spytz. - bpo-31758: Prevent crashes when using an uninitialized ``_elementtree.XMLParser`` object. Patch by Oren Milman. @@ -18891,7 +19731,7 @@ Library preferred to avoid the case when the temporary-file-generated address is too large for an AF_UNIX socket address. Patch by Pablo Galindo. -- bpo-36287: :func:`ast.dump()` no longer outputs optional fields and +- bpo-36287: :func:`ast.dump` no longer outputs optional fields and attributes with default values. The default values for optional fields and attributes of AST nodes are now set as class attributes (e.g. ``Constant.kind`` is set to ``None``). @@ -19458,12 +20298,11 @@ Windows - bpo-39393: Improve the error message when attempting to load a DLL with unresolved dependencies. -- bpo-38883: :meth:`~pathlib.Path.home()` and - :meth:`~pathlib.Path.expanduser()` on Windows now prefer - :envvar:`USERPROFILE` and no longer use :envvar:`HOME`, which is not - normally set for regular user accounts. This makes them again behave like - :func:`os.path.expanduser`, which was changed to ignore :envvar:`HOME` in - 3.8, see :issue:`36264`. +- bpo-38883: :meth:`~pathlib.Path.home` and :meth:`~pathlib.Path.expanduser` + on Windows now prefer :envvar:`USERPROFILE` and no longer use + :envvar:`HOME`, which is not normally set for regular user accounts. This + makes them again behave like :func:`os.path.expanduser`, which was changed + to ignore :envvar:`HOME` in 3.8, see :issue:`36264`. - bpo-39185: The build.bat script has additional options for very-quiet output (-q) and very-verbose output (-vv) @@ -20331,8 +21170,8 @@ Core and Builtins - bpo-38631: Replace ``Py_FatalError()`` call with a regular :exc:`RuntimeError` exception in :meth:`float.__getformat__`. -- bpo-38639: Optimized :func:`math.floor()`, :func:`math.ceil()` and - :func:`math.trunc()` for floats. +- bpo-38639: Optimized :func:`math.floor`, :func:`math.ceil` and + :func:`math.trunc` for floats. - bpo-38640: Fixed a bug in the compiler that was causing to raise in the presence of break statements and continue statements inside always false @@ -20387,7 +21226,7 @@ Core and Builtins ``crypt_r``. - bpo-37474: On FreeBSD, Python no longer calls ``fedisableexcept()`` at - startup to control the floating point control mode. The call became + startup to control the floating-point control mode. The call became useless since FreeBSD 6: it became the default mode. - bpo-38006: Fix a bug due to the interaction of weakrefs and the cyclic @@ -20743,12 +21582,13 @@ Library - bpo-38405: Nested subclasses of :class:`typing.NamedTuple` are now pickleable. -- bpo-38332: Prevent :exc:`KeyError` thrown by :func:`_encoded_words.decode` - when given an encoded-word with invalid content-type encoding from - propagating all the way to :func:`email.message.get`. +- bpo-38332: Prevent :exc:`KeyError` thrown by + :func:`!_encoded_words.decode` when given an encoded-word with invalid + content-type encoding from propagating all the way to + :func:`email.message.get`. - bpo-38371: Deprecated the ``split()`` method in - :class:`_tkinter.TkappType` in favour of the ``splitlist()`` method which + :class:`!_tkinter.TkappType` in favour of the ``splitlist()`` method which has more consistent and predictable behavior. - bpo-38341: Add :exc:`smtplib.SMTPNotSupportedError` to the :mod:`smtplib` @@ -21289,9 +22129,9 @@ Library - bpo-37279: Fix asyncio sendfile support when sendfile sends extra data in fallback mode. -- bpo-19865: :func:`ctypes.create_unicode_buffer()` now also supports - non-BMP characters on platforms with 16-bit :c:type:`wchar_t` (for - example, Windows and AIX). +- bpo-19865: :func:`ctypes.create_unicode_buffer` now also supports non-BMP + characters on platforms with 16-bit :c:type:`wchar_t` (for example, + Windows and AIX). - bpo-37266: In a subinterpreter, spawning a daemon thread now raises an exception. Daemon threads were never supported in subinterpreters. @@ -21299,7 +22139,7 @@ Library error if a daemon thread was still running. - bpo-37210: Allow pure Python implementation of :mod:`pickle` to work even - when the C :mod:`_pickle` module is unavailable. + when the C :mod:`!_pickle` module is unavailable. - bpo-21872: Fix :mod:`lzma`: module decompresses data incompletely. When decompressing a FORMAT_ALONE format file, and it doesn't have the end @@ -21315,11 +22155,11 @@ Library tuple. - bpo-36607: Eliminate :exc:`RuntimeError` raised by - :func:`asyncio.all_tasks()` if internal tasks weak set is changed by - another thread during iteration. + :func:`asyncio.all_tasks` if internal tasks weak set is changed by another + thread during iteration. -- bpo-18748: :class:`_pyio.IOBase` destructor now does nothing if getting - the ``closed`` attribute fails to better mimic :class:`_io.IOBase` +- bpo-18748: :class:`!_pyio.IOBase` destructor now does nothing if getting + the ``closed`` attribute fails to better mimic :class:`!_io.IOBase` finalizer. - bpo-36402: Fix a race condition at Python shutdown when waiting for @@ -21470,7 +22310,7 @@ Library - bpo-30618: Add :meth:`~pathlib.Path.readlink`. Patch by Girts Folkmanis. -- bpo-32498: Made :func:`urllib.parse.unquote()` accept bytes in addition to +- bpo-32498: Made :func:`urllib.parse.unquote` accept bytes in addition to strings. Patch by Stein Karlsen. - bpo-33348: lib2to3 now recognizes expressions after ``*`` and ``**`` like @@ -21567,7 +22407,7 @@ Documentation - bpo-37478: Added possible exceptions to the description of os.chdir(). -- bpo-34903: Documented that in :meth:`datetime.datetime.strptime()`, the +- bpo-34903: Documented that in :meth:`datetime.datetime.strptime`, the leading zero in some two-digit formats is optional. Patch by Mike Gleen. - bpo-36260: Add decompression pitfalls to zipfile module documentation. @@ -21953,7 +22793,7 @@ Windows - bpo-32587: Make :const:`winreg.REG_MULTI_SZ` support zero-length strings. - bpo-28269: Replace use of :c:func:`strcasecmp` for the system function - :c:func:`_stricmp`. Patch by Minmin Gong. + :c:func:`!_stricmp`. Patch by Minmin Gong. - bpo-36590: Add native Bluetooth RFCOMM support to socket module. @@ -22192,8 +23032,9 @@ C API - bpo-36763: Add :c:func:`PyConfig_SetWideStringList` function. - bpo-37337: Add fast functions for calling methods: - :c:func:`_PyObject_VectorcallMethod`, :c:func:`_PyObject_CallMethodNoArgs` - and :c:func:`_PyObject_CallMethodOneArg`. + :c:func:`!_PyObject_VectorcallMethod`, + :c:func:`!_PyObject_CallMethodNoArgs` and + :c:func:`!_PyObject_CallMethodOneArg`. - bpo-28805: The :c:macro:`METH_FASTCALL` calling convention has been documented. @@ -22299,8 +23140,8 @@ Core and Builtins - bpo-37032: Added new ``replace()`` method to the code type (:class:`types.CodeType`). -- bpo-37007: Implement :func:`socket.if_nameindex()`, - :func:`socket.if_nametoindex()`, and :func:`socket.if_indextoname()` on +- bpo-37007: Implement :func:`socket.if_nameindex`, + :func:`socket.if_nametoindex`, and :func:`socket.if_indextoname` on Windows. - bpo-36829: :c:func:`PyErr_WriteUnraisable` now creates a traceback object @@ -22423,7 +23264,7 @@ Library - bpo-29262: Add ``get_origin()`` and ``get_args()`` introspection helpers to ``typing`` module. -- bpo-12639: :meth:`msilib.Directory.start_component()` no longer fails if +- bpo-12639: :meth:`msilib.Directory.start_component` no longer fails if *keyfile* is not ``None``. - bpo-36999: Add the ``asyncio.Task.get_coro()`` method to publicly expose @@ -22444,8 +23285,8 @@ Library - bpo-33725: On macOS, the :mod:`multiprocessing` module now uses *spawn* start method by default. -- bpo-37054: Fix destructor :class:`_pyio.BytesIO` and - :class:`_pyio.TextIOWrapper`: initialize their ``_buffer`` attribute as +- bpo-37054: Fix destructor :class:`!_pyio.BytesIO` and + :class:`!_pyio.TextIOWrapper`: initialize their ``_buffer`` attribute as soon as possible (in the class body), because it's used by ``__del__()`` which calls ``close()``. @@ -22714,7 +23555,7 @@ Library - bpo-35125: Asyncio: Remove inner callback on outer cancellation in shield -- bpo-35721: Fix :meth:`asyncio.SelectorEventLoop.subprocess_exec()` leaks +- bpo-35721: Fix :meth:`asyncio.SelectorEventLoop.subprocess_exec` leaks file descriptors if ``Popen`` fails and called with ``stdin=subprocess.PIPE``. Patch by Niklas Fiekas. @@ -23224,8 +24065,8 @@ Library - bpo-17396: :mod:`modulefinder` no longer crashes when encountering syntax errors in followed imports. Patch by Brandt Bucher. -- bpo-35934: Added :meth:`~socket.create_server()` and - :meth:`~socket.has_dualstack_ipv6()` convenience functions to automate the +- bpo-35934: Added :meth:`~socket.create_server` and + :meth:`~socket.has_dualstack_ipv6` convenience functions to automate the necessary tasks usually involved when creating a server socket, including accepting both IPv4 and IPv6 connections on the same socket. (Contributed by Giampaolo Rodola in :issue:`17561`.) @@ -23322,7 +24163,7 @@ Tests - bpo-32424: Fix typo in test_cyclic_gc() test for xml.etree.ElementTree. Patch by Gordon P. Hemsley. -- bpo-36635: Add a new :mod:`_testinternalcapi` module to test the internal +- bpo-36635: Add a new :mod:`!_testinternalcapi` module to test the internal C API. - bpo-36629: Fix ``test_imap4_host_default_value()`` of ``test_imaplib``: @@ -23509,7 +24350,7 @@ C API coerced and/or if the UTF-8 Mode is enabled by the user configuration. The LC_CTYPE coercion and UTF-8 Mode are now disabled by default to fix the mojibake issue. They must now be enabled explicitly (opt-in) using the new - :c:func:`_Py_PreInitialize` API with ``_PyPreConfig``. + :c:func:`!_Py_PreInitialize` API with ``_PyPreConfig``. - bpo-36025: Fixed an accidental change to the datetime C API where the arguments to the :c:func:`PyDate_FromTimestamp` function were incorrectly @@ -23923,7 +24764,7 @@ Library treats the mean and standard deviation of measurement data as single entity. -- bpo-35904: Added statistics.fmean() as a faster, floating point variant of +- bpo-35904: Added statistics.fmean() as a faster, floating-point variant of the existing mean() function. - bpo-35918: Removed broken ``has_key`` method from @@ -24145,7 +24986,7 @@ Core and Builtins test_faulthandler. - bpo-35560: Fix an assertion error in :func:`format` in debug build for - floating point formatting with "n" format, zero padding and small width. + floating-point formatting with "n" format, zero padding and small width. Release build is not impacted. Patch by Karthikeyan Singaravelan. - bpo-35552: Format characters ``%s`` and ``%V`` in @@ -24284,7 +25125,7 @@ Core and Builtins - bpo-30156: The C function ``property_descr_get()`` uses a "cached" tuple to optimize function calls. But this tuple can be discovered in debug mode - with :func:`sys.getobjects()`. Remove the optimization, it's not really + with :func:`sys.getobjects`. Remove the optimization, it's not really worth it and it causes 3 different crashes last years. - bpo-34762: Fix contextvars C API to use PyObject* pointer types. @@ -24924,7 +25765,7 @@ Library connection on non-Windows systems. - bpo-35062: Fix incorrect parsing of - :class:`_io.IncrementalNewlineDecoder`'s *translate* argument. + :class:`io.IncrementalNewlineDecoder`'s *translate* argument. - bpo-35065: Remove ``StreamReaderProtocol._untrack_reader``. The call to ``_untrack_reader`` is currently performed too soon, causing the protocol @@ -25038,9 +25879,9 @@ Library and also to add support by default for *wss*, the secure websocket protocol. -- 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-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-34925: 25% speedup in argument parsing for the functions in the bisect module. @@ -25162,10 +26003,10 @@ Library - bpo-34636: Speed up re scanning of many non-matching characters for \s \w and \d within bytes objects. (microoptimization) -- bpo-24412: Add :func:`~unittest.addModuleCleanup()` and - :meth:`~unittest.TestCase.addClassCleanup()` to unittest to support - cleanups for :func:`~unittest.setUpModule()` and - :meth:`~unittest.TestCase.setUpClass()`. Patch by Lisa Roach. +- bpo-24412: Add :func:`~unittest.addModuleCleanup` and + :meth:`~unittest.TestCase.addClassCleanup` to unittest to support cleanups + for :func:`~unittest.setUpModule` and + :meth:`~unittest.TestCase.setUpClass`. Patch by Lisa Roach. - bpo-34630: Don't log SSL certificate errors in asyncio code (connection error logging is skipped already). @@ -25246,8 +26087,8 @@ Library ``trace.cover`` file. - bpo-34441: Fix crash when an ``ABC``-derived class with invalid - ``__subclasses__`` is passed as the second argument to - :func:`issubclass()`. Patch by Alexey Izbyshev. + ``__subclasses__`` is passed as the second argument to :func:`issubclass`. + Patch by Alexey Izbyshev. - bpo-34427: Fix infinite loop in ``a.extend(a)`` for ``MutableSequence`` subclasses. @@ -25317,7 +26158,7 @@ Library Wright. - bpo-34270: The default asyncio task class now always has a name which can - be get or set using two new methods (:meth:`~asyncio.Task.get_name()` and + be get or set using two new methods (:meth:`~asyncio.Task.get_name` and :meth:`~asyncio.Task.set_name`) and is visible in the :func:`repr` output. An initial name can also be set using the new ``name`` keyword argument to :func:`asyncio.create_task` or the @@ -25488,12 +26329,12 @@ Library :func:`~os.path.exists`, :func:`~os.path.lexists`, :func:`~os.path.isdir`, :func:`~os.path.isfile`, :func:`~os.path.islink`, and :func:`~os.path.ismount`, and :mod:`pathlib.Path` methods that return a - boolean result like :meth:`~pathlib.Path.exists()`, - :meth:`~pathlib.Path.is_dir()`, :meth:`~pathlib.Path.is_file()`, - :meth:`~pathlib.Path.is_mount()`, :meth:`~pathlib.Path.is_symlink()`, - :meth:`~pathlib.Path.is_block_device()`, - :meth:`~pathlib.Path.is_char_device()`, :meth:`~pathlib.Path.is_fifo()`, - :meth:`~pathlib.Path.is_socket()` now return ``False`` instead of raising + boolean result like :meth:`~pathlib.Path.exists`, + :meth:`~pathlib.Path.is_dir`, :meth:`~pathlib.Path.is_file`, + :meth:`~pathlib.Path.is_mount`, :meth:`~pathlib.Path.is_symlink`, + :meth:`~pathlib.Path.is_block_device`, + :meth:`~pathlib.Path.is_char_device`, :meth:`~pathlib.Path.is_fifo`, + :meth:`~pathlib.Path.is_socket` now return ``False`` instead of raising :exc:`ValueError` or its subclasses :exc:`UnicodeEncodeError` and :exc:`UnicodeDecodeError` for paths that contain characters or bytes unrepresentable at the OS level. @@ -25860,7 +26701,7 @@ Library Python 3.0. - bpo-20104: Improved error handling and fixed a reference leak in - :func:`os.posix_spawn()`. + :func:`os.posix_spawn`. - bpo-33106: Deleting a key from a read-only dbm database raises module specific error instead of KeyError. @@ -26057,7 +26898,7 @@ Library - bpo-32792: collections.ChainMap() preserves the order of the underlying mappings. -- bpo-32775: :func:`fnmatch.translate()` no longer produces patterns which +- bpo-32775: :func:`fnmatch.translate` no longer produces patterns which contain set operations. Sets starting with '[' or containing '--', '&&', '~~' or '||' will be interpreted differently in regular expressions in future versions. Currently they emit warnings. fnmatch.translate() now @@ -26761,7 +27602,7 @@ macOS - bpo-32901: Update macOS 10.9+ installer to Tcl/Tk 8.6.8. -- bpo-31903: In :mod:`_scproxy`, drop the GIL when calling into +- bpo-31903: In :mod:`!_scproxy`, drop the GIL when calling into ``SystemConfiguration`` to avoid deadlocks. IDLE @@ -27491,7 +28332,7 @@ Library :func:`pickle.Pickler.dump`. - bpo-20104: Improved error handling and fixed a reference leak in - :func:`os.posix_spawn()`. + :func:`os.posix_spawn`. - bpo-33175: In dataclasses, Field.__set_name__ now looks up the __set_name__ special method on the class, not the instance, of the default @@ -27911,7 +28752,7 @@ Library - bpo-32792: collections.ChainMap() preserves the order of the underlying mappings. -- bpo-32775: :func:`fnmatch.translate()` no longer produces patterns which +- bpo-32775: :func:`fnmatch.translate` no longer produces patterns which contain set operations. Sets starting with '[' or containing '--', '&&', '~~' or '||' will be interpreted differently in regular expressions in future versions. Currently they emit warnings. fnmatch.translate() now @@ -28257,8 +29098,8 @@ Library - bpo-32248: Add :mod:`importlib.resources` and :class:`importlib.abc.ResourceReader` as the unified API for reading resources contained within packages. Loaders wishing to support resource - reading must implement the :meth:`get_resource_reader()` method. - File-based and zipimport-based loaders both implement these APIs. + reading must implement the :meth:`get_resource_reader` method. File-based + and zipimport-based loaders both implement these APIs. :class:`importlib.abc.ResourceLoader` is deprecated in favor of these new APIs. @@ -28525,8 +29366,8 @@ Library coroutines. Affected functions: loop.sock_sendall, loop.sock_recv, loop.sock_accept, loop.getaddrinfo, loop.getnameinfo. -- bpo-32323: :func:`urllib.parse.urlsplit()` does not convert zone-id - (scope) to lower case for scoped IPv6 addresses in hostnames now. +- bpo-32323: :func:`urllib.parse.urlsplit` does not convert zone-id (scope) + to lower case for scoped IPv6 addresses in hostnames now. - bpo-32302: Fix bdist_wininst of distutils for CRT v142: it binary compatible with CRT v140. @@ -28534,7 +29375,7 @@ Library - bpo-29711: Fix ``stop_serving`` in asyncio proactor loop kill all listening servers -- bpo-32308: :func:`re.sub()` now replaces empty matches adjacent to a +- bpo-32308: :func:`re.sub` now replaces empty matches adjacent to a previous non-empty match. - bpo-29970: Abort asyncio SSLProtocol connection if handshake not complete @@ -32147,8 +32988,8 @@ Library - bpo-32185: The SSL module no longer sends IP addresses in SNI TLS extension on platforms with OpenSSL 1.0.2+ or inet_pton. -- bpo-32323: :func:`urllib.parse.urlsplit()` does not convert zone-id - (scope) to lower case for scoped IPv6 addresses in hostnames now. +- bpo-32323: :func:`urllib.parse.urlsplit` does not convert zone-id (scope) + to lower case for scoped IPv6 addresses in hostnames now. - bpo-32302: Fix bdist_wininst of distutils for CRT v142: it binary compatible with CRT v140. @@ -36283,9 +37124,9 @@ Library exception handler to dump the traceback of all Python threads on any Windows exception, not only on UNIX signals (SIGSEGV, SIGFPE, SIGABRT). -- bpo-26530: Add C functions :c:func:`_PyTraceMalloc_Track` and - :c:func:`_PyTraceMalloc_Untrack` to track memory blocks using the - :mod:`tracemalloc` module. Add :c:func:`_PyTraceMalloc_GetTraceback` to +- bpo-26530: Add C functions :c:func:`!_PyTraceMalloc_Track` and + :c:func:`!_PyTraceMalloc_Untrack` to track memory blocks using the + :mod:`tracemalloc` module. Add :c:func:`!_PyTraceMalloc_GetTraceback` to get the traceback of an object. - bpo-26588: The _tracemalloc now supports tracing memory allocations of @@ -41823,8 +42664,8 @@ Library - bpo-21402: tkinter.ttk now works when default root window is not set. -- bpo-3015: _tkinter.create() now creates tkapp object with wantobject=1 by - default. +- bpo-3015: ``_tkinter.create()`` now creates ``tkapp`` object with + ``wantobjects=1`` by default. - bpo-10203: sqlite3.Row now truly supports sequence protocol. In particular it supports reverse() and negative indices. Original patch by @@ -42471,7 +43312,7 @@ Tests regrtest.py. - bpo-21634: Fix pystone micro-benchmark: use floor division instead of true - division to benchmark integers instead of floating point numbers. Set + division to benchmark integers instead of floating-point numbers. Set pystone version to 1.2. Patch written by Lennart Regebro. - bpo-21605: Added tests for Tkinter images. diff --git a/Misc/coverity_model.c b/Misc/coverity_model.c index 8960362a..90c72c7b 100644 --- a/Misc/coverity_model.c +++ b/Misc/coverity_model.c @@ -74,7 +74,7 @@ PyObject *PyLong_FromSsize_t(Py_ssize_t ival) /* tainted sinks * - * Coverity considers argv, environ, read() data etc as tained. + * Coverity considers argv, environ, read() data etc as tainted. */ PyObject *PyErr_SetFromErrnoWithFilename(PyObject *exc, const char *filename) diff --git a/Misc/externals.spdx.json b/Misc/externals.spdx.json index e905c2b9..4219cd4f 100644 --- a/Misc/externals.spdx.json +++ b/Misc/externals.spdx.json @@ -48,21 +48,21 @@ "checksums": [ { "algorithm": "SHA256", - "checksumValue": "e6a77c273ebb284fedd8ea19b081fce74a9455936ffd47215f7c24713e2614b2" + "checksumValue": "1550c87996a0858474a9dd179deab2c55eb73726b9a140b32865b02fd3d8a86b" } ], - "downloadLocation": "https://github.com/python/cpython-source-deps/archive/refs/tags/openssl-3.0.13.tar.gz", + "downloadLocation": "https://github.com/python/cpython-source-deps/archive/refs/tags/openssl-3.0.15.tar.gz", "externalRefs": [ { "referenceCategory": "SECURITY", - "referenceLocator": "cpe:2.3:a:openssl:openssl:3.0.13:*:*:*:*:*:*:*", + "referenceLocator": "cpe:2.3:a:openssl:openssl:3.0.15:*:*:*:*:*:*:*", "referenceType": "cpe23Type" } ], "licenseConcluded": "NOASSERTION", "name": "openssl", "primaryPackagePurpose": "SOURCE", - "versionInfo": "3.0.13" + "versionInfo": "3.0.15" }, { "SPDXID": "SPDXRef-PACKAGE-sqlite", @@ -90,42 +90,42 @@ "checksums": [ { "algorithm": "SHA256", - "checksumValue": "6e33a88f116822167734cd72b693b5d30ced130a3cae6dc2ff696042f993bb42" + "checksumValue": "4c23f0dd3efcbe6f3a22c503a68d147617bb30c4f5290f1eb3eaacf0b460440b" } ], - "downloadLocation": "https://github.com/python/cpython-source-deps/archive/refs/tags/tcl-core-8.6.13.0.tar.gz", + "downloadLocation": "https://github.com/python/cpython-source-deps/archive/refs/tags/tcl-core-8.6.15.0.tar.gz", "externalRefs": [ { "referenceCategory": "SECURITY", - "referenceLocator": "cpe:2.3:a:tcl_tk:tcl_tk:8.6.13.0:*:*:*:*:*:*:*", + "referenceLocator": "cpe:2.3:a:tcl_tk:tcl_tk:8.6.15.0:*:*:*:*:*:*:*", "referenceType": "cpe23Type" } ], "licenseConcluded": "NOASSERTION", "name": "tcl-core", "primaryPackagePurpose": "SOURCE", - "versionInfo": "8.6.13.0" + "versionInfo": "8.6.15.0" }, { "SPDXID": "SPDXRef-PACKAGE-tk", "checksums": [ { "algorithm": "SHA256", - "checksumValue": "896c1f488bdd0159091bd5cce124b756dfdffa4a5350b7fd4d7d8e48421089a4" + "checksumValue": "0ae56d39bca92865f338529557a1e56d110594184b6dc5a91339c5675751e264" } ], - "downloadLocation": "https://github.com/python/cpython-source-deps/archive/refs/tags/tk-8.6.13.0.tar.gz", + "downloadLocation": "https://github.com/python/cpython-source-deps/archive/refs/tags/tk-8.6.15.0.tar.gz", "externalRefs": [ { "referenceCategory": "SECURITY", - "referenceLocator": "cpe:2.3:a:tcl_tk:tcl_tk:8.6.13.0:*:*:*:*:*:*:*", + "referenceLocator": "cpe:2.3:a:tcl_tk:tcl_tk:8.6.15.0:*:*:*:*:*:*:*", "referenceType": "cpe23Type" } ], "licenseConcluded": "NOASSERTION", "name": "tk", "primaryPackagePurpose": "SOURCE", - "versionInfo": "8.6.13.0" + "versionInfo": "8.6.15.0" }, { "SPDXID": "SPDXRef-PACKAGE-tix", diff --git a/Misc/python.man b/Misc/python.man index 9f89c94a..abb065cd 100644 --- a/Misc/python.man +++ b/Misc/python.man @@ -251,6 +251,7 @@ emitted by a process (even those that are otherwise ignored by default): -Wdefault # Warn once per call location -Werror # Convert to exceptions -Walways # Warn every time + -Wall # Same as -Walways -Wmodule # Warn once per calling module -Wonce # Warn once per Python process -Wignore # Never warn diff --git a/Misc/sbom.spdx.json b/Misc/sbom.spdx.json index 49b25ff7..eb13ecff 100644 --- a/Misc/sbom.spdx.json +++ b/Misc/sbom.spdx.json @@ -48,11 +48,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "4076a884f0ca96873589b5c8159e2e5bfb8b829a" + "checksumValue": "373cc00d87782a736970644d863ff2ebbd0e4886" }, { "algorithm": "SHA256", - "checksumValue": "1a434bf3d2f9fb8a0b5adb79201a942788d11824c3e5b46a0b9962c0c482016c" + "checksumValue": "0f750bc336e510d14ac9a3e63fc2399f60f3f04f0061c426e86751ed5fba90e4" } ], "fileName": "Modules/expat/expat.h" @@ -62,11 +62,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "b70ce53fdc25ae482681ae2f6623c3c8edc9c1b7" + "checksumValue": "9e615c6e5c3ba00670f674a6b071bb855b0b563d" }, { "algorithm": "SHA256", - "checksumValue": "86afb425ec9999eb4f1ec9ab2fb41c58c4aa5cb9bf934b8c94264670fc5a961d" + "checksumValue": "3d90a4b65c40a3f848c36100f4d73b933a015c7b7cd85c28e4331a6b845c1ad0" } ], "fileName": "Modules/expat/expat_external.h" @@ -128,29 +128,29 @@ "fileName": "Modules/expat/nametab.h" }, { - "SPDXID": "SPDXRef-FILE-Modules-expat-pyexpatns.h", + "SPDXID": "SPDXRef-FILE-Modules-expat-refresh.sh", "checksums": [ { "algorithm": "SHA1", - "checksumValue": "f50c899172acd93fc539007bfb43315b83d407e4" + "checksumValue": "a9b0a33b8359cfe94b23972a1605daf8dcc605d9" }, { "algorithm": "SHA256", - "checksumValue": "d571b8258cfaa067a20adef553e5fcedd6671ca4a8841483496de031bd904567" + "checksumValue": "19eb541460bc2ca8b87118acd3c048f6af77affbf8719ac29aa7b6c8d70f83fd" } ], - "fileName": "Modules/expat/pyexpatns.h" + "fileName": "Modules/expat/refresh.sh" }, { "SPDXID": "SPDXRef-FILE-Modules-expat-siphash.h", "checksums": [ { "algorithm": "SHA1", - "checksumValue": "4c49b5df2bc702f663ba3b5a52d1940ec363226b" + "checksumValue": "aca27f46d9fd387b63ce7ff2e4f172cad130b39b" }, { "algorithm": "SHA256", - "checksumValue": "b5ec29f6560acc183f1ee8ab92bb3aea17b87b4c2120cd2e3f78deba7a12491e" + "checksumValue": "f537add526ecda8389503b7ef45fb52b6217e4dc171dcc3a8dc6903ff6134726" } ], "fileName": "Modules/expat/siphash.h" @@ -188,11 +188,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "fed1311be8577491b7f63085a27014eabf2caec8" + "checksumValue": "3199fbd38b6fb158f73d5c8de6b6e6e3812ef803" }, { "algorithm": "SHA256", - "checksumValue": "3dc233eca5fa1bb7387c503f8a12d840707e4374b229e05d5657db9645725040" + "checksumValue": "c1518244dd5ea397e345d00e12cc45d42f43453ed208218559c981c97a0583e2" } ], "fileName": "Modules/expat/xmlparse.c" @@ -1562,14 +1562,14 @@ "checksums": [ { "algorithm": "SHA256", - "checksumValue": "d4cf38d26e21a56654ffe4acd9cd5481164619626802328506a2869afab29ab3" + "checksumValue": "17aa6cfc5c4c219c09287abfc10bc13f0c06f30bb654b28bfe6f567ca646eb79" } ], - "downloadLocation": "https://github.com/libexpat/libexpat/releases/download/R_2_6_2/expat-2.6.2.tar.gz", + "downloadLocation": "https://github.com/libexpat/libexpat/releases/download/R_2_6_3/expat-2.6.3.tar.gz", "externalRefs": [ { "referenceCategory": "SECURITY", - "referenceLocator": "cpe:2.3:a:libexpat_project:libexpat:2.6.2:*:*:*:*:*:*:*", + "referenceLocator": "cpe:2.3:a:libexpat_project:libexpat:2.6.3:*:*:*:*:*:*:*", "referenceType": "cpe23Type" } ], @@ -1577,7 +1577,7 @@ "name": "expat", "originator": "Organization: Expat development team", "primaryPackagePurpose": "SOURCE", - "versionInfo": "2.6.2" + "versionInfo": "2.6.3" }, { "SPDXID": "SPDXRef-PACKAGE-hacl-star", @@ -1715,7 +1715,7 @@ "spdxElementId": "SPDXRef-PACKAGE-expat" }, { - "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-pyexpatns.h", + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-refresh.sh", "relationshipType": "CONTAINS", "spdxElementId": "SPDXRef-PACKAGE-expat" }, diff --git a/Misc/valgrind-python.supp b/Misc/valgrind-python.supp index c9c45ba7..f5e39d6f 100644 --- a/Misc/valgrind-python.supp +++ b/Misc/valgrind-python.supp @@ -103,6 +103,49 @@ fun:COMMENT_THIS_LINE_TO_DISABLE_LEAK_WARNING } +# +# Leaks: dlopen() called without dlclose() +# + +{ + dlopen() called without dlclose() + Memcheck:Leak + fun:malloc + fun:malloc + fun:strdup + fun:_dl_load_cache_lookup +} +{ + dlopen() called without dlclose() + Memcheck:Leak + fun:malloc + fun:malloc + fun:strdup + fun:_dl_map_object +} +{ + dlopen() called without dlclose() + Memcheck:Leak + fun:malloc + fun:* + fun:_dl_new_object +} +{ + dlopen() called without dlclose() + Memcheck:Leak + fun:calloc + fun:* + fun:_dl_new_object +} +{ + dlopen() called without dlclose() + Memcheck:Leak + fun:calloc + fun:* + fun:_dl_check_map_versions +} + + # # Non-python specific leaks # diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 05e79915..2356b708 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -430,18 +430,22 @@ future_ensure_alive(FutureObj *fut) static int future_schedule_callbacks(asyncio_state *state, FutureObj *fut) { - Py_ssize_t len; - Py_ssize_t i; - if (fut->fut_callback0 != NULL) { /* There's a 1st callback */ - int ret = call_soon(state, - fut->fut_loop, fut->fut_callback0, - (PyObject *)fut, fut->fut_context0); - - Py_CLEAR(fut->fut_callback0); - Py_CLEAR(fut->fut_context0); + // Beware: An evil call_soon could alter fut_callback0 or fut_context0. + // Since we are anyway clearing them after the call, whether call_soon + // succeeds or not, the idea is to transfer ownership so that external + // code is not able to alter them during the call. + PyObject *fut_callback0 = fut->fut_callback0; + fut->fut_callback0 = NULL; + PyObject *fut_context0 = fut->fut_context0; + fut->fut_context0 = NULL; + + int ret = call_soon(state, fut->fut_loop, fut_callback0, + (PyObject *)fut, fut_context0); + Py_CLEAR(fut_callback0); + Py_CLEAR(fut_context0); if (ret) { /* If an error occurs in pure-Python implementation, all callbacks are cleared. */ @@ -458,27 +462,25 @@ future_schedule_callbacks(asyncio_state *state, FutureObj *fut) return 0; } - len = PyList_GET_SIZE(fut->fut_callbacks); - if (len == 0) { - /* The list of callbacks was empty; clear it and return. */ - Py_CLEAR(fut->fut_callbacks); - return 0; - } - - for (i = 0; i < len; i++) { - PyObject *cb_tup = PyList_GET_ITEM(fut->fut_callbacks, i); + // Beware: An evil call_soon could change fut->fut_callbacks. + // The idea is to transfer the ownership of the callbacks list + // so that external code is not able to mutate the list during + // the iteration. + PyObject *callbacks = fut->fut_callbacks; + fut->fut_callbacks = NULL; + Py_ssize_t n = PyList_GET_SIZE(callbacks); + for (Py_ssize_t i = 0; i < n; i++) { + assert(PyList_GET_SIZE(callbacks) == n); + PyObject *cb_tup = PyList_GET_ITEM(callbacks, i); PyObject *cb = PyTuple_GET_ITEM(cb_tup, 0); PyObject *ctx = PyTuple_GET_ITEM(cb_tup, 1); if (call_soon(state, fut->fut_loop, cb, (PyObject *)fut, ctx)) { - /* If an error occurs in pure-Python implementation, - all callbacks are cleared. */ - Py_CLEAR(fut->fut_callbacks); + Py_DECREF(callbacks); return -1; } } - - Py_CLEAR(fut->fut_callbacks); + Py_DECREF(callbacks); return 0; } @@ -594,12 +596,27 @@ future_set_exception(asyncio_state *state, FutureObj *fut, PyObject *exc) PyErr_SetString(PyExc_TypeError, "invalid exception object"); return NULL; } - if (Py_IS_TYPE(exc_val, (PyTypeObject *)PyExc_StopIteration)) { + if (PyErr_GivenExceptionMatches(exc_val, PyExc_StopIteration)) { + const char *msg = "StopIteration interacts badly with " + "generators and cannot be raised into a " + "Future"; + PyObject *message = PyUnicode_FromString(msg); + if (message == NULL) { + Py_DECREF(exc_val); + return NULL; + } + PyObject *err = PyObject_CallOneArg(PyExc_RuntimeError, message); + Py_DECREF(message); + if (err == NULL) { + Py_DECREF(exc_val); + return NULL; + } + assert(PyExceptionInstance_Check(err)); + + PyException_SetCause(err, Py_NewRef(exc_val)); + PyException_SetContext(err, Py_NewRef(exc_val)); Py_DECREF(exc_val); - PyErr_SetString(PyExc_TypeError, - "StopIteration interacts badly with generators " - "and cannot be raised into a Future"); - return NULL; + exc_val = err; } assert(!fut->fut_exception); @@ -1027,7 +1044,12 @@ _asyncio_Future_remove_done_callback_impl(FutureObj *self, PyTypeObject *cls, ENSURE_FUTURE_ALIVE(state, self) if (self->fut_callback0 != NULL) { - int cmp = PyObject_RichCompareBool(self->fut_callback0, fn, Py_EQ); + // Beware: An evil PyObject_RichCompareBool could free fut_callback0 + // before a recursive call is made with that same arg. For details, see + // https://github.com/python/cpython/pull/125967#discussion_r1816593340. + PyObject *fut_callback0 = Py_NewRef(self->fut_callback0); + int cmp = PyObject_RichCompareBool(fut_callback0, fn, Py_EQ); + Py_DECREF(fut_callback0); if (cmp == -1) { return NULL; } @@ -1051,8 +1073,10 @@ _asyncio_Future_remove_done_callback_impl(FutureObj *self, PyTypeObject *cls, if (len == 1) { PyObject *cb_tup = PyList_GET_ITEM(self->fut_callbacks, 0); + Py_INCREF(cb_tup); int cmp = PyObject_RichCompareBool( PyTuple_GET_ITEM(cb_tup, 0), fn, Py_EQ); + Py_DECREF(cb_tup); if (cmp == -1) { return NULL; } @@ -1275,52 +1299,49 @@ static PyObject * FutureObj_get_callbacks(FutureObj *fut, void *Py_UNUSED(ignored)) { asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut); - Py_ssize_t i; - ENSURE_FUTURE_ALIVE(state, fut) - if (fut->fut_callback0 == NULL) { - if (fut->fut_callbacks == NULL) { - Py_RETURN_NONE; - } - - return Py_NewRef(fut->fut_callbacks); + Py_ssize_t len = 0; + if (fut->fut_callback0 != NULL) { + len++; } - - Py_ssize_t len = 1; if (fut->fut_callbacks != NULL) { len += PyList_GET_SIZE(fut->fut_callbacks); } - - PyObject *new_list = PyList_New(len); - if (new_list == NULL) { - return NULL; + if (len == 0) { + Py_RETURN_NONE; } - PyObject *tup0 = PyTuple_New(2); - if (tup0 == NULL) { - Py_DECREF(new_list); + PyObject *callbacks = PyList_New(len); + if (callbacks == NULL) { return NULL; } - Py_INCREF(fut->fut_callback0); - PyTuple_SET_ITEM(tup0, 0, fut->fut_callback0); - assert(fut->fut_context0 != NULL); - Py_INCREF(fut->fut_context0); - PyTuple_SET_ITEM(tup0, 1, (PyObject *)fut->fut_context0); - - PyList_SET_ITEM(new_list, 0, tup0); + Py_ssize_t i = 0; + if (fut->fut_callback0 != NULL) { + PyObject *tup0 = PyTuple_New(2); + if (tup0 == NULL) { + Py_DECREF(callbacks); + return NULL; + } + PyTuple_SET_ITEM(tup0, 0, Py_NewRef(fut->fut_callback0)); + assert(fut->fut_context0 != NULL); + PyTuple_SET_ITEM(tup0, 1, Py_NewRef(fut->fut_context0)); + PyList_SET_ITEM(callbacks, i, tup0); + i++; + } if (fut->fut_callbacks != NULL) { - for (i = 0; i < PyList_GET_SIZE(fut->fut_callbacks); i++) { - PyObject *cb = PyList_GET_ITEM(fut->fut_callbacks, i); + for (Py_ssize_t j = 0; j < PyList_GET_SIZE(fut->fut_callbacks); j++) { + PyObject *cb = PyList_GET_ITEM(fut->fut_callbacks, j); Py_INCREF(cb); - PyList_SET_ITEM(new_list, i + 1, cb); + PyList_SET_ITEM(callbacks, i, cb); + i++; } } - return new_list; + return callbacks; } static PyObject * @@ -2124,7 +2145,7 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop, return -1; } } else { - self->task_context = Py_NewRef(context); + Py_XSETREF(self->task_context, Py_NewRef(context)); } Py_CLEAR(self->task_fut_waiter); @@ -2509,7 +2530,11 @@ static PyObject * _asyncio_Task_get_coro_impl(TaskObj *self) /*[clinic end generated code: output=bcac27c8cc6c8073 input=d2e8606c42a7b403]*/ { - return Py_NewRef(self->task_coro); + if (self->task_coro) { + return Py_NewRef(self->task_coro); + } + + Py_RETURN_NONE; } /*[clinic input] @@ -2728,7 +2753,11 @@ task_call_step_soon(asyncio_state *state, TaskObj *task, PyObject *arg) return -1; } - int ret = call_soon(state, task->task_loop, cb, NULL, task->task_context); + // Beware: An evil call_soon could alter task_context. + // See: https://github.com/python/cpython/issues/126080. + PyObject *task_context = Py_NewRef(task->task_context); + int ret = call_soon(state, task->task_loop, cb, NULL, task_context); + Py_DECREF(task_context); Py_DECREF(cb); return ret; } @@ -2967,8 +2996,17 @@ task_step_handle_result_impl(asyncio_state *state, TaskObj *task, PyObject *resu if (task->task_must_cancel) { PyObject *r; int is_true; + + // Beware: An evil `__getattribute__` could + // prematurely delete task->task_cancel_msg before the + // task is cancelled, thereby causing a UAF crash. + // + // See https://github.com/python/cpython/issues/126138 + PyObject *task_cancel_msg = Py_NewRef(task->task_cancel_msg); r = PyObject_CallMethodOneArg(result, &_Py_ID(cancel), - task->task_cancel_msg); + task_cancel_msg); + Py_DECREF(task_cancel_msg); + if (r == NULL) { return NULL; } @@ -3060,8 +3098,17 @@ task_step_handle_result_impl(asyncio_state *state, TaskObj *task, PyObject *resu if (task->task_must_cancel) { PyObject *r; int is_true; + + // Beware: An evil `__getattribute__` could + // prematurely delete task->task_cancel_msg before the + // task is cancelled, thereby causing a UAF crash. + // + // See https://github.com/python/cpython/issues/126138 + PyObject *task_cancel_msg = Py_NewRef(task->task_cancel_msg); r = PyObject_CallMethodOneArg(result, &_Py_ID(cancel), - task->task_cancel_msg); + task_cancel_msg); + Py_DECREF(task_cancel_msg); + if (r == NULL) { return NULL; } @@ -3602,14 +3649,6 @@ module_traverse(PyObject *mod, visitproc visit, void *arg) Py_VISIT(state->iscoroutine_typecache); Py_VISIT(state->context_kwname); - - // Visit freelist. - PyObject *next = (PyObject*) state->fi_freelist; - while (next != NULL) { - PyObject *current = next; - Py_VISIT(current); - next = (PyObject*) ((futureiterobject*) current)->future; - } return 0; } diff --git a/Modules/_bisectmodule.c b/Modules/_bisectmodule.c index 0773bbd1..d79946c8 100644 --- a/Modules/_bisectmodule.c +++ b/Modules/_bisectmodule.c @@ -66,7 +66,7 @@ internal_bisect_right(PyObject *list, PyObject *item, Py_ssize_t lo, Py_ssize_t if (sq_item == NULL) { return -1; } - if (Py_EnterRecursiveCall("in _bisect.bisect_right")) { + if (Py_EnterRecursiveCall(" in _bisect.bisect_right")) { return -1; } PyTypeObject *tp = Py_TYPE(item); @@ -250,7 +250,7 @@ internal_bisect_left(PyObject *list, PyObject *item, Py_ssize_t lo, Py_ssize_t h if (sq_item == NULL) { return -1; } - if (Py_EnterRecursiveCall("in _bisect.bisect_left")) { + if (Py_EnterRecursiveCall(" in _bisect.bisect_left")) { return -1; } PyTypeObject *tp = Py_TYPE(item); diff --git a/Modules/_csv.c b/Modules/_csv.c index d63eac1b..9a7b7d27 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -701,6 +701,8 @@ parse_process_char(ReaderObj *self, _csvstate *module_state, Py_UCS4 c) } else if (c == dialect->escapechar) { /* possible escaped character */ + if (dialect->quoting == QUOTE_NONNUMERIC) + self->numeric_field = 1; self->state = ESCAPED_CHAR; } else if (c == ' ' && dialect->skipinitialspace) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index c5157560..b6d45e92 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -2164,9 +2164,15 @@ PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) Py_DECREF(result); return NULL; } - x = PyDict_SetItemString(result->tp_dict, - ml->ml_name, - meth); + PyObject *name = PyUnicode_FromString(ml->ml_name); + if (name == NULL) { + Py_DECREF(meth); + Py_DECREF(result); + return NULL; + } + PyUnicode_InternInPlace(&name); + x = PyDict_SetItem(result->tp_dict, name, meth); + Py_DECREF(name); Py_DECREF(meth); if (x == -1) { Py_DECREF(result); @@ -2263,7 +2269,7 @@ PyCSimpleType_from_param(PyObject *type, PyObject *value) return NULL; } if (as_parameter) { - if (_Py_EnterRecursiveCall("while processing _as_parameter_")) { + if (_Py_EnterRecursiveCall(" while processing _as_parameter_")) { Py_DECREF(as_parameter); Py_XDECREF(exc); return NULL; diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c index 39157865..5788b53b 100644 --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -164,7 +164,7 @@ _testfunc_array_in_struct3B_set_defaults(void) /* * Test3C struct tests the MAX_STRUCT_SIZE 32. Structs containing arrays of up - * to four floating point types are passed in registers on Arm platforms. + * to four floating-point types are passed in registers on Arm platforms. * This struct is used for within bounds test on Arm platfroms and for an * out-of-bounds tests for platfroms where MAX_STRUCT_SIZE is less than 32. * See gh-110190. @@ -188,7 +188,7 @@ _testfunc_array_in_struct3C_set_defaults(void) /* * Test3D struct tests the MAX_STRUCT_SIZE 64. Structs containing arrays of up - * to eight floating point types are passed in registers on PPC64LE platforms. + * to eight floating-point types are passed in registers on PPC64LE platforms. * This struct is used for within bounds test on PPC64LE platfroms and for an * out-of-bounds tests for platfroms where MAX_STRUCT_SIZE is less than 64. * See gh-110190. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 743b9e37..b099959e 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -4071,9 +4071,9 @@ NoArgNoReturnFunctionBody(resetty) /*[clinic input] _curses.resizeterm - nlines: int + nlines: short Height. - ncols: int + ncols: short Width. / @@ -4084,8 +4084,8 @@ window dimensions (in particular the SIGWINCH handler). [clinic start generated code]*/ static PyObject * -_curses_resizeterm_impl(PyObject *module, int nlines, int ncols) -/*[clinic end generated code: output=56d6bcc5194ad055 input=0fca02ebad5ffa82]*/ +_curses_resizeterm_impl(PyObject *module, short nlines, short ncols) +/*[clinic end generated code: output=4de3abab50c67f02 input=414e92a63e3e9899]*/ { PyObject *result; @@ -4107,9 +4107,9 @@ _curses_resizeterm_impl(PyObject *module, int nlines, int ncols) /*[clinic input] _curses.resize_term - nlines: int + nlines: short Height. - ncols: int + ncols: short Width. / @@ -4123,8 +4123,8 @@ without additional interaction with the application. [clinic start generated code]*/ static PyObject * -_curses_resize_term_impl(PyObject *module, int nlines, int ncols) -/*[clinic end generated code: output=9e26d8b9ea311ed2 input=2197edd05b049ed4]*/ +_curses_resize_term_impl(PyObject *module, short nlines, short ncols) +/*[clinic end generated code: output=46c6d749fa291dbd input=276afa43d8ea7091]*/ { PyObject *result; diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 8552e42d..8535811a 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -1501,7 +1501,7 @@ make_somezreplacement(PyObject *object, char *sep, PyObject *tzinfoarg) PyObject *tzinfo = get_tzinfo_member(object); if (tzinfo == Py_None || tzinfo == NULL) { - return PyBytes_FromStringAndSize(NULL, 0); + return PyUnicode_FromStringAndSize(NULL, 0); } assert(tzinfoarg != NULL); @@ -1512,7 +1512,7 @@ make_somezreplacement(PyObject *object, char *sep, PyObject *tzinfoarg) tzinfoarg) < 0) return NULL; - return PyBytes_FromStringAndSize(buf, strlen(buf)); + return PyUnicode_FromString(buf); } static PyObject * @@ -1569,7 +1569,7 @@ make_freplacement(PyObject *object) else sprintf(freplacement, "%06d", 0); - return PyBytes_FromStringAndSize(freplacement, strlen(freplacement)); + return PyUnicode_FromString(freplacement); } /* I sure don't want to reproduce the strftime code from the time module, @@ -1590,79 +1590,60 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple, PyObject *Zreplacement = NULL; /* py string, replacement for %Z */ PyObject *freplacement = NULL; /* py string, replacement for %f */ - const char *pin; /* pointer to next char in input format */ - Py_ssize_t flen; /* length of input format */ - char ch; /* next char in input format */ - - PyObject *newfmt = NULL; /* py string, the output format */ - char *pnew; /* pointer to available byte in output format */ - size_t totalnew; /* number bytes total in output format buffer, - exclusive of trailing \0 */ - size_t usednew; /* number bytes used so far in output format buffer */ - - const char *ptoappend; /* ptr to string to append to output buffer */ - Py_ssize_t ntoappend; /* # of bytes to append to output buffer */ - assert(object && format && timetuple); assert(PyUnicode_Check(format)); - /* Convert the input format to a C string and size */ - pin = PyUnicode_AsUTF8AndSize(format, &flen); - if (!pin) + + PyObject *strftime = _PyImport_GetModuleAttrString("time", "strftime"); + if (strftime == NULL) { return NULL; + } /* Scan the input format, looking for %z/%Z/%f escapes, building * a new format. Since computing the replacements for those codes * is expensive, don't unless they're actually used. */ - if (flen > INT_MAX - 1) { - PyErr_NoMemory(); - goto Done; - } - totalnew = flen + 1; /* realistic if no %z/%Z */ - newfmt = PyBytes_FromStringAndSize(NULL, totalnew); - if (newfmt == NULL) goto Done; - pnew = PyBytes_AsString(newfmt); - usednew = 0; - - while ((ch = *pin++) != '\0') { - if (ch != '%') { - ptoappend = pin - 1; - ntoappend = 1; + _PyUnicodeWriter writer; + _PyUnicodeWriter_Init(&writer); + writer.overallocate = 1; + + Py_ssize_t flen = PyUnicode_GET_LENGTH(format); + Py_ssize_t i = 0; + Py_ssize_t start = 0; + Py_ssize_t end = 0; + while (i != flen) { + i = PyUnicode_FindChar(format, '%', i, flen, 1); + if (i < 0) { + assert(!PyErr_Occurred()); + break; } - else if ((ch = *pin++) == '\0') { - /* Null byte follows %, copy only '%'. - * - * Back the pin up one char so that we catch the null check - * the next time through the loop.*/ - pin--; - ptoappend = pin - 1; - ntoappend = 1; + end = i; + i++; + if (i == flen) { + break; } + Py_UCS4 ch = PyUnicode_READ_CHAR(format, i); + i++; /* A % has been seen and ch is the character after it. */ - else if (ch == 'z') { + PyObject *replacement = NULL; + if (ch == 'z') { /* %z -> +HHMM */ if (zreplacement == NULL) { zreplacement = make_somezreplacement(object, "", tzinfoarg); if (zreplacement == NULL) - goto Done; + goto Error; } - assert(zreplacement != NULL); - assert(PyBytes_Check(zreplacement)); - ptoappend = PyBytes_AS_STRING(zreplacement); - ntoappend = PyBytes_GET_SIZE(zreplacement); + replacement = zreplacement; } - else if (ch == ':' && *pin == 'z' && pin++) { + else if (ch == ':' && i < flen && PyUnicode_READ_CHAR(format, i) == 'z') { /* %:z -> +HH:MM */ + i++; if (colonzreplacement == NULL) { colonzreplacement = make_somezreplacement(object, ":", tzinfoarg); if (colonzreplacement == NULL) - goto Done; + goto Error; } - assert(colonzreplacement != NULL); - assert(PyBytes_Check(colonzreplacement)); - ptoappend = PyBytes_AS_STRING(colonzreplacement); - ntoappend = PyBytes_GET_SIZE(colonzreplacement); + replacement = colonzreplacement; } else if (ch == 'Z') { /* format tzname */ @@ -1670,79 +1651,63 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple, Zreplacement = make_Zreplacement(object, tzinfoarg); if (Zreplacement == NULL) - goto Done; + goto Error; } - assert(Zreplacement != NULL); - assert(PyUnicode_Check(Zreplacement)); - ptoappend = PyUnicode_AsUTF8AndSize(Zreplacement, - &ntoappend); - if (ptoappend == NULL) - goto Done; + replacement = Zreplacement; } else if (ch == 'f') { /* format microseconds */ if (freplacement == NULL) { freplacement = make_freplacement(object); if (freplacement == NULL) - goto Done; + goto Error; } - assert(freplacement != NULL); - assert(PyBytes_Check(freplacement)); - ptoappend = PyBytes_AS_STRING(freplacement); - ntoappend = PyBytes_GET_SIZE(freplacement); + replacement = freplacement; } else { /* percent followed by something else */ - ptoappend = pin - 2; - ntoappend = 2; - } - - /* Append the ntoappend chars starting at ptoappend to - * the new format. - */ - if (ntoappend == 0) continue; - assert(ptoappend != NULL); - assert(ntoappend > 0); - while (usednew + ntoappend > totalnew) { - if (totalnew > (PY_SSIZE_T_MAX >> 1)) { /* overflow */ - PyErr_NoMemory(); - goto Done; - } - totalnew <<= 1; - if (_PyBytes_Resize(&newfmt, totalnew) < 0) - goto Done; - pnew = PyBytes_AsString(newfmt) + usednew; } - memcpy(pnew, ptoappend, ntoappend); - pnew += ntoappend; - usednew += ntoappend; - assert(usednew <= totalnew); + assert(replacement != NULL); + assert(PyUnicode_Check(replacement)); + if (_PyUnicodeWriter_WriteSubstring(&writer, format, start, end) < 0) { + goto Error; + } + start = i; + if (_PyUnicodeWriter_WriteStr(&writer, replacement) < 0) { + goto Error; + } } /* end while() */ - if (_PyBytes_Resize(&newfmt, usednew) < 0) - goto Done; - { - PyObject *format; - PyObject *strftime = _PyImport_GetModuleAttrString("time", "strftime"); - - if (strftime == NULL) + PyObject *newformat; + if (start == 0) { + _PyUnicodeWriter_Dealloc(&writer); + newformat = Py_NewRef(format); + } + else { + if (_PyUnicodeWriter_WriteSubstring(&writer, format, start, flen) < 0) { + goto Error; + } + newformat = _PyUnicodeWriter_Finish(&writer); + if (newformat == NULL) { goto Done; - format = PyUnicode_FromString(PyBytes_AS_STRING(newfmt)); - if (format != NULL) { - result = PyObject_CallFunctionObjArgs(strftime, - format, timetuple, NULL); - Py_DECREF(format); } - Py_DECREF(strftime); } + result = PyObject_CallFunctionObjArgs(strftime, + newformat, timetuple, NULL); + Py_DECREF(newformat); + Done: Py_XDECREF(freplacement); Py_XDECREF(zreplacement); Py_XDECREF(colonzreplacement); Py_XDECREF(Zreplacement); - Py_XDECREF(newfmt); + Py_XDECREF(strftime); return result; + + Error: + _PyUnicodeWriter_Dealloc(&writer); + goto Done; } /* --------------------------------------------------------------------------- @@ -5209,19 +5174,19 @@ datetime_utcfromtimestamp(PyObject *cls, PyObject *args) static PyObject * datetime_strptime(PyObject *cls, PyObject *args) { - static PyObject *module = NULL; - PyObject *string, *format; + PyObject *string, *format, *result; if (!PyArg_ParseTuple(args, "UU:strptime", &string, &format)) return NULL; + PyObject *module = PyImport_ImportModule("_strptime"); if (module == NULL) { - module = PyImport_ImportModule("_strptime"); - if (module == NULL) - return NULL; + return NULL; } - return PyObject_CallMethodObjArgs(module, &_Py_ID(_strptime_datetime), - cls, string, format, NULL); + result = PyObject_CallMethodObjArgs(module, &_Py_ID(_strptime_datetime), + cls, string, format, NULL); + Py_DECREF(module); + return result; } /* Return new datetime from date/datetime and time arguments. */ diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index fcd4be93..386f38ad 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -1213,12 +1213,8 @@ _elementtree_Element_extend_impl(ElementObject *self, PyTypeObject *cls, PyObject* seq; Py_ssize_t i; - seq = PySequence_Fast(elements, ""); + seq = PySequence_Fast(elements, "'elements' must be an iterable"); if (!seq) { - PyErr_Format( - PyExc_TypeError, - "expected sequence, not \"%.200s\"", Py_TYPE(elements)->tp_name - ); return NULL; } @@ -1504,7 +1500,7 @@ element_bool(PyObject* self_) { ElementObject* self = (ElementObject*) self_; if (PyErr_WarnEx(PyExc_DeprecationWarning, - "Testing an element's truth value will raise an exception " + "Testing an element's truth value will always return True " "in future versions. Use specific 'len(elem)' or " "'elem is not None' test instead.", 1) < 0) { @@ -1920,12 +1916,8 @@ element_ass_subscr(PyObject* self_, PyObject* item, PyObject* value) } /* A new slice is actually being assigned */ - seq = PySequence_Fast(value, ""); + seq = PySequence_Fast(value, "assignment expects an iterable"); if (!seq) { - PyErr_Format( - PyExc_TypeError, - "expected sequence, not \"%.200s\"", Py_TYPE(value)->tp_name - ); return -1; } newlen = PySequence_Fast_GET_SIZE(seq); diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index a8001d71..a6d1b839 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -734,12 +734,14 @@ functools_reduce(PyObject *self, PyObject *args) PyDoc_STRVAR(functools_reduce_doc, "reduce(function, iterable[, initial]) -> value\n\ \n\ -Apply a function of two arguments cumulatively to the items of a sequence\n\ -or iterable, from left to right, so as to reduce the iterable to a single\n\ -value. For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\ -((((1+2)+3)+4)+5). If initial is present, it is placed before the items\n\ -of the iterable in the calculation, and serves as a default when the\n\ -iterable is empty."); +Apply a function of two arguments cumulatively to the items of an iterable, from left to right.\n\ +\n\ +This effectively reduces the iterable to a single value. If initial is present,\n\ +it is placed before the items of the iterable in the calculation, and serves as\n\ +a default when the iterable is empty.\n\ +\n\ +For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])\n\ +calculates ((((1 + 2) + 3) + 4) + 5)."); /* lru_cache object **********************************************************/ diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index 3eb25704..ed9cf0da 100644 --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -193,7 +193,7 @@ write_str(stringio *self, PyObject *obj) } if (self->writenl) { PyObject *translated = PyUnicode_Replace( - decoded, &_Py_STR(newline), self->writenl, -1); + decoded, _Py_LATIN1_CHR('\n'), self->writenl, -1); Py_SETREF(decoded, translated); } if (decoded == NULL) @@ -884,23 +884,25 @@ stringio_setstate(stringio *self, PyObject *state) once by __init__. So we do not take any chance and replace object's buffer completely. */ { - PyObject *item; - Py_UCS4 *buf; - Py_ssize_t bufsize; - - item = PyTuple_GET_ITEM(state, 0); - buf = PyUnicode_AsUCS4Copy(item); - if (buf == NULL) - return NULL; - bufsize = PyUnicode_GET_LENGTH(item); + PyObject *item = PyTuple_GET_ITEM(state, 0); + if (PyUnicode_Check(item)) { + Py_UCS4 *buf = PyUnicode_AsUCS4Copy(item); + if (buf == NULL) + return NULL; + Py_ssize_t bufsize = PyUnicode_GET_LENGTH(item); - if (resize_buffer(self, bufsize) < 0) { + if (resize_buffer(self, bufsize) < 0) { + PyMem_Free(buf); + return NULL; + } + memcpy(self->buf, buf, bufsize * sizeof(Py_UCS4)); PyMem_Free(buf); - return NULL; + self->string_size = bufsize; + } + else { + assert(item == Py_None); + self->string_size = 0; } - memcpy(self->buf, buf, bufsize * sizeof(Py_UCS4)); - PyMem_Free(buf); - self->string_size = bufsize; } /* Set carefully the position value. Alternatively, we could use the seek diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 14dd19d9..4a1ba22d 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -1723,16 +1723,26 @@ _io_TextIOWrapper_write_impl(textio *self, PyObject *text) bytes_len = PyBytes_GET_SIZE(b); } - if (self->pending_bytes == NULL) { - self->pending_bytes_count = 0; - self->pending_bytes = b; - } - else if (self->pending_bytes_count + bytes_len > self->chunk_size) { - // Prevent to concatenate more than chunk_size data. - if (_textiowrapper_writeflush(self) < 0) { - Py_DECREF(b); - return NULL; + // We should avoid concatinating huge data. + // Flush the buffer before adding b to the buffer if b is not small. + // https://github.com/python/cpython/issues/87426 + if (bytes_len >= self->chunk_size) { + // _textiowrapper_writeflush() calls buffer.write(). + // self->pending_bytes can be appended during buffer->write() + // or other thread. + // We need to loop until buffer becomes empty. + // https://github.com/python/cpython/issues/118138 + // https://github.com/python/cpython/issues/119506 + while (self->pending_bytes != NULL) { + if (_textiowrapper_writeflush(self) < 0) { + Py_DECREF(b); + return NULL; + } } + } + + if (self->pending_bytes == NULL) { + assert(self->pending_bytes_count == 0); self->pending_bytes = b; } else if (!PyList_CheckExact(self->pending_bytes)) { @@ -1741,6 +1751,9 @@ _io_TextIOWrapper_write_impl(textio *self, PyObject *text) Py_DECREF(b); return NULL; } + // Since Python 3.12, allocating GC object won't trigger GC and release + // GIL. See https://github.com/python/cpython/issues/97922 + assert(!PyList_CheckExact(self->pending_bytes)); PyList_SET_ITEM(list, 0, self->pending_bytes); PyList_SET_ITEM(list, 1, b); self->pending_bytes = list; diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index c2c365e0..da4907ec 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -135,19 +135,67 @@ char _PyIO_get_console_type(PyObject *path_or_fd) { } static DWORD -_find_last_utf8_boundary(const char *buf, DWORD len) +_find_last_utf8_boundary(const unsigned char *buf, DWORD len) { - /* This function never returns 0, returns the original len instead */ - DWORD count = 1; - if (len == 0 || (buf[len - 1] & 0x80) == 0) { - return len; - } - for (;; count++) { - if (count > 3 || count >= len) { + for (DWORD count = 1; count < 4 && count <= len; count++) { + unsigned char c = buf[len - count]; + if (c < 0x80) { + /* No starting byte found. */ return len; } - if ((buf[len - count] & 0xc0) != 0x80) { - return len - count; + if (c >= 0xc0) { + if (c < 0xe0 /* 2-bytes sequence */ ? count < 2 : + c < 0xf0 /* 3-bytes sequence */ ? count < 3 : + c < 0xf8 /* 4-bytes sequence */) + { + /* Incomplete multibyte sequence. */ + return len - count; + } + /* Either complete or invalid sequence. */ + return len; + } + } + /* Either complete 4-bytes sequence or invalid sequence. */ + return len; +} + +/* Find the number of UTF-8 bytes that corresponds to the specified number of + * wchars. + * I.e. find x <= len so that MultiByteToWideChar(CP_UTF8, 0, s, x, NULL, 0) == n. + * + * WideCharToMultiByte() cannot be used for this, because the UTF-8 -> wchar + * conversion is not reversible (invalid UTF-8 byte produces \ufffd which + * will be converted back to 3-bytes UTF-8 sequence \xef\xbf\xbd). + * So we need to use binary search. + */ +static DWORD +_wchar_to_utf8_count(const unsigned char *s, DWORD len, DWORD n) +{ + DWORD start = 0; + while (1) { + DWORD mid = 0; + for (DWORD i = len / 2; i <= len; i++) { + mid = _find_last_utf8_boundary(s, i); + if (mid != 0) { + break; + } + /* The middle could split the first multibytes sequence. */ + } + if (mid == len) { + return start + len; + } + if (mid == 0) { + mid = len > 1 ? len - 1 : 1; + } + DWORD wlen = MultiByteToWideChar(CP_UTF8, 0, s, mid, NULL, 0); + if (wlen <= n) { + s += mid; + start += mid; + len -= mid; + n -= wlen; + } + else { + len = mid; } } } @@ -556,8 +604,10 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) { int err = 0, sig = 0; wchar_t *buf = (wchar_t*)PyMem_Malloc(maxlen * sizeof(wchar_t)); - if (!buf) + if (!buf) { + PyErr_NoMemory(); goto error; + } *readlen = 0; @@ -615,6 +665,7 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) { Py_UNBLOCK_THREADS if (!newbuf) { sig = -1; + PyErr_NoMemory(); break; } buf = newbuf; @@ -638,8 +689,10 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) { if (*readlen > 0 && buf[0] == L'\x1a') { PyMem_Free(buf); buf = (wchar_t *)PyMem_Malloc(sizeof(wchar_t)); - if (!buf) + if (!buf) { + PyErr_NoMemory(); goto error; + } buf[0] = L'\0'; *readlen = 0; } @@ -817,8 +870,10 @@ _io__WindowsConsoleIO_readall_impl(winconsoleio *self) bufsize = BUFSIZ; buf = (wchar_t*)PyMem_Malloc((bufsize + 1) * sizeof(wchar_t)); - if (buf == NULL) + if (buf == NULL) { + PyErr_NoMemory(); return NULL; + } while (1) { wchar_t *subbuf; @@ -840,6 +895,7 @@ _io__WindowsConsoleIO_readall_impl(winconsoleio *self) (bufsize + 1) * sizeof(wchar_t)); if (tmp == NULL) { PyMem_Free(buf); + PyErr_NoMemory(); return NULL; } buf = tmp; @@ -1015,43 +1071,49 @@ _io__WindowsConsoleIO_write_impl(winconsoleio *self, PyTypeObject *cls, len = (DWORD)b->len; Py_BEGIN_ALLOW_THREADS - wlen = MultiByteToWideChar(CP_UTF8, 0, b->buf, len, NULL, 0); - /* issue11395 there is an unspecified upper bound on how many bytes can be written at once. We cap at 32k - the caller will have to handle partial writes. Since we don't know how many input bytes are being ignored, we have to reduce and recalculate. */ - while (wlen > 32766 / sizeof(wchar_t)) { - len /= 2; + const DWORD max_wlen = 32766 / sizeof(wchar_t); + /* UTF-8 to wchar ratio is at most 3:1. */ + len = Py_MIN(len, max_wlen * 3); + while (1) { /* Fix for github issues gh-110913 and gh-82052. */ len = _find_last_utf8_boundary(b->buf, len); wlen = MultiByteToWideChar(CP_UTF8, 0, b->buf, len, NULL, 0); + if (wlen <= max_wlen) { + break; + } + len /= 2; } Py_END_ALLOW_THREADS - if (!wlen) - return PyErr_SetFromWindowsErr(0); + if (!wlen) { + return PyLong_FromLong(0); + } wbuf = (wchar_t*)PyMem_Malloc(wlen * sizeof(wchar_t)); + if (!wbuf) { + PyErr_NoMemory(); + return NULL; + } Py_BEGIN_ALLOW_THREADS wlen = MultiByteToWideChar(CP_UTF8, 0, b->buf, len, wbuf, wlen); if (wlen) { res = WriteConsoleW(handle, wbuf, wlen, &n, NULL); +#ifdef Py_DEBUG + if (res) { +#else if (res && n < wlen) { +#endif /* Wrote fewer characters than expected, which means our * len value may be wrong. So recalculate it from the - * characters that were written. As this could potentially - * result in a different value, we also validate that value. + * characters that were written. */ - len = WideCharToMultiByte(CP_UTF8, 0, wbuf, n, - NULL, 0, NULL, NULL); - if (len) { - wlen = MultiByteToWideChar(CP_UTF8, 0, b->buf, len, - NULL, 0); - assert(wlen == len); - } + len = _wchar_to_utf8_count(b->buf, len, n); } } else res = 0; diff --git a/Modules/_localemodule.c b/Modules/_localemodule.c index cbd036fd..db819437 100644 --- a/Modules/_localemodule.c +++ b/Modules/_localemodule.c @@ -62,7 +62,7 @@ module _locale [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=ed98569b726feada]*/ -/* support functions for formatting floating point numbers */ +/* support functions for formatting floating-point numbers */ /* the grouping is terminated by either 0 or CHAR_MAX */ static PyObject* @@ -595,6 +595,37 @@ static struct langinfo_constant{ {0, 0} }; +#ifdef __GLIBC__ +#if defined(ALT_DIGITS) || defined(ERA) +static PyObject * +decode_strings(const char *result, size_t max_count) +{ + /* Convert a sequence of NUL-separated C strings to a Python string + * containing semicolon separated items. */ + size_t i = 0; + size_t count = 0; + for (; count < max_count && result[i]; count++) { + i += strlen(result + i) + 1; + } + char *buf = PyMem_Malloc(i); + if (buf == NULL) { + PyErr_NoMemory(); + return NULL; + } + memcpy(buf, result, i); + /* Replace all NULs with semicolons. */ + i = 0; + while (--count) { + i += strlen(buf + i); + buf[i++] = ';'; + } + PyObject *pyresult = PyUnicode_DecodeLocale(buf, NULL); + PyMem_Free(buf); + return pyresult; +} +#endif +#endif + /*[clinic input] _locale.nl_langinfo @@ -618,7 +649,28 @@ _locale_nl_langinfo_impl(PyObject *module, int item) instead of an empty string for nl_langinfo(ERA). */ const char *result = nl_langinfo(item); result = result != NULL ? result : ""; - return PyUnicode_DecodeLocale(result, NULL); + PyObject *pyresult; +#ifdef __GLIBC__ + /* According to the POSIX specification the result must be + * a sequence of semicolon-separated strings. + * But in Glibc they are NUL-separated. */ +#ifdef ALT_DIGITS + if (item == ALT_DIGITS && *result) { + pyresult = decode_strings(result, 100); + } + else +#endif +#ifdef ERA + if (item == ERA && *result) { + pyresult = decode_strings(result, SIZE_MAX); + } + else +#endif +#endif + { + pyresult = PyUnicode_DecodeLocale(result, NULL); + } + return pyresult; } PyErr_SetString(PyExc_ValueError, "unsupported langinfo constant"); return NULL; diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index 257de438..0464e7e8 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -56,6 +56,7 @@ typedef struct { #define POF_ENABLED 0x001 #define POF_SUBCALLS 0x002 #define POF_BUILTINS 0x004 +#define POF_EXT_TIMER 0x008 #define POF_NOMEMORY 0x100 /*[clinic input] @@ -84,7 +85,14 @@ _lsprof_get_state(PyObject *module) static _PyTime_t CallExternalTimer(ProfilerObject *pObj) { - PyObject *o = _PyObject_CallNoArgs(pObj->externalTimer); + PyObject *o = NULL; + + // External timer can do arbitrary things so we need a flag to prevent + // horrible things to happen + pObj->flags |= POF_EXT_TIMER; + o = _PyObject_CallNoArgs(pObj->externalTimer); + pObj->flags &= ~POF_EXT_TIMER; + if (o == NULL) { PyErr_WriteUnraisable(pObj->externalTimer); return 0; @@ -596,6 +604,12 @@ setBuiltins(ProfilerObject *pObj, int nvalue) PyObject* pystart_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t size) { + if (size < 2) { + PyErr_Format(PyExc_TypeError, + "_pystart_callback expected 2 arguments, got %zd", + size); + return NULL; + } PyObject* code = args[0]; ptrace_enter_call((PyObject*)self, (void *)code, (PyObject *)code); @@ -604,6 +618,12 @@ PyObject* pystart_callback(ProfilerObject* self, PyObject *const *args, Py_ssize PyObject* pyreturn_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t size) { + if (size < 3) { + PyErr_Format(PyExc_TypeError, + "_pyreturn_callback expected 3 arguments, got %zd", + size); + return NULL; + } PyObject* code = args[0]; ptrace_leave_call((PyObject*)self, (void *)code); @@ -639,6 +659,12 @@ PyObject* get_cfunc_from_callable(PyObject* callable, PyObject* self_arg, PyObje PyObject* ccall_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t size) { + if (size < 4) { + PyErr_Format(PyExc_TypeError, + "_ccall_callback expected 4 arguments, got %zd", + size); + return NULL; + } if (self->flags & POF_BUILTINS) { PyObject* callable = args[2]; PyObject* self_arg = args[3]; @@ -657,6 +683,12 @@ PyObject* ccall_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t PyObject* creturn_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t size) { + if (size < 4) { + PyErr_Format(PyExc_TypeError, + "_creturn_callback expected 4 arguments, got %zd", + size); + return NULL; + } if (self->flags & POF_BUILTINS) { PyObject* callable = args[2]; PyObject* self_arg = args[3]; @@ -718,34 +750,47 @@ profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds) return NULL; } - if (PyObject_CallMethod(monitoring, "use_tool_id", "is", self->tool_id, "cProfile") == NULL) { + PyObject *check = PyObject_CallMethod(monitoring, + "use_tool_id", "is", + self->tool_id, "cProfile"); + if (check == NULL) { PyErr_Format(PyExc_ValueError, "Another profiling tool is already active"); - Py_DECREF(monitoring); - return NULL; + goto error; } + Py_DECREF(check); for (int i = 0; callback_table[i].callback_method; i++) { + int event = (1 << callback_table[i].event); PyObject* callback = PyObject_GetAttrString((PyObject*)self, callback_table[i].callback_method); if (!callback) { - Py_DECREF(monitoring); - return NULL; + goto error; } - Py_XDECREF(PyObject_CallMethod(monitoring, "register_callback", "iiO", self->tool_id, - (1 << callback_table[i].event), - callback)); + PyObject *register_result = PyObject_CallMethod(monitoring, "register_callback", + "iiO", self->tool_id, + event, callback); Py_DECREF(callback); - all_events |= (1 << callback_table[i].event); + if (register_result == NULL) { + goto error; + } + Py_DECREF(register_result); + all_events |= event; } - if (!PyObject_CallMethod(monitoring, "set_events", "ii", self->tool_id, all_events)) { - Py_DECREF(monitoring); - return NULL; + PyObject *event_result = PyObject_CallMethod(monitoring, "set_events", "ii", + self->tool_id, all_events); + if (event_result == NULL) { + goto error; } + Py_DECREF(event_result); Py_DECREF(monitoring); self->flags |= POF_ENABLED; Py_RETURN_NONE; + +error: + Py_DECREF(monitoring); + return NULL; } static void @@ -773,6 +818,11 @@ Stop collecting profiling information.\n\ static PyObject* profiler_disable(ProfilerObject *self, PyObject* noarg) { + if (self->flags & POF_EXT_TIMER) { + PyErr_SetString(PyExc_RuntimeError, + "cannot disable profiler in external timer"); + return NULL; + } if (self->flags & POF_ENABLED) { PyObject* result = NULL; PyObject* monitoring = _PyImport_GetModuleAttrString("sys", "monitoring"); @@ -826,6 +876,11 @@ Clear all profiling information collected so far.\n\ static PyObject* profiler_clear(ProfilerObject *pObj, PyObject* noarg) { + if (pObj->flags & POF_EXT_TIMER) { + PyErr_SetString(PyExc_RuntimeError, + "cannot clear profiler in external timer"); + return NULL; + } clearEntries(pObj); Py_RETURN_NONE; } @@ -834,6 +889,7 @@ static int profiler_traverse(ProfilerObject *op, visitproc visit, void *arg) { Py_VISIT(Py_TYPE(op)); + Py_VISIT(op->externalTimer); return 0; } diff --git a/Modules/_operator.c b/Modules/_operator.c index 68ccc905..720687d4 100644 --- a/Modules/_operator.c +++ b/Modules/_operator.c @@ -2,6 +2,9 @@ #include "pycore_moduleobject.h" // _PyModule_GetState() #include "structmember.h" // PyMemberDef #include "pycore_runtime.h" // _Py_ID() +#include "pycore_pystate.h" // _PyInterpreterState_GET() + + #include "clinic/_operator.c.h" typedef struct { @@ -1224,6 +1227,7 @@ attrgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return NULL; /* prepare attr while checking args */ + PyInterpreterState *interp = _PyInterpreterState_GET(); for (idx = 0; idx < nattrs; ++idx) { PyObject *item = PyTuple_GET_ITEM(args, idx); int dot_count; @@ -1251,7 +1255,7 @@ attrgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) if (dot_count == 0) { Py_INCREF(item); - PyUnicode_InternInPlace(&item); + _PyUnicode_InternMortal(interp, &item); PyTuple_SET_ITEM(attr, idx, item); } else { /* make it a tuple of non-dotted attrnames */ PyObject *attr_chain = PyTuple_New(dot_count + 1); @@ -1277,7 +1281,7 @@ attrgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) Py_DECREF(attr); return NULL; } - PyUnicode_InternInPlace(&attr_chain_item); + _PyUnicode_InternMortal(interp, &attr_chain_item); PyTuple_SET_ITEM(attr_chain, attr_chain_idx, attr_chain_item); ++attr_chain_idx; unibuff_till = unibuff_from = unibuff_till + 1; @@ -1291,7 +1295,7 @@ attrgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) Py_DECREF(attr); return NULL; } - PyUnicode_InternInPlace(&attr_chain_item); + _PyUnicode_InternMortal(interp, &attr_chain_item); PyTuple_SET_ITEM(attr_chain, attr_chain_idx, attr_chain_item); PyTuple_SET_ITEM(attr, idx, attr_chain); @@ -1587,7 +1591,8 @@ methodcaller_new(PyTypeObject *type, PyObject *args, PyObject *kwds) name = PyTuple_GET_ITEM(args, 0); Py_INCREF(name); - PyUnicode_InternInPlace(&name); + PyInterpreterState *interp = _PyInterpreterState_GET(); + _PyUnicode_InternMortal(interp, &name); mc->name = name; mc->kwds = Py_XNewRef(kwds); diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 2bf9977f..b8f701c2 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -1344,6 +1344,10 @@ _Unpickler_ReadFromFile(UnpicklerObject *self, Py_ssize_t n) else { read_size = _Unpickler_SetStringInput(self, data); Py_DECREF(data); + if (read_size < 0) { + return -1; + } + self->prefetched_idx = 0; if (n <= read_size) return n; @@ -1865,8 +1869,7 @@ get_dotted_path(PyObject *obj, PyObject *name) { PyObject *dotted_path; Py_ssize_t i, n; - _Py_DECLARE_STR(dot, "."); - dotted_path = PyUnicode_Split(name, &_Py_STR(dot), -1); + dotted_path = PyUnicode_Split(name, _Py_LATIN1_CHR('.'), -1); if (dotted_path == NULL) return NULL; n = PyList_GET_SIZE(dotted_path); @@ -1876,10 +1879,10 @@ get_dotted_path(PyObject *obj, PyObject *name) if (_PyUnicode_EqualToASCIIString(subpath, "")) { if (obj == NULL) PyErr_Format(PyExc_AttributeError, - "Can't pickle local object %R", name); + "Can't get local object %R", name); else PyErr_Format(PyExc_AttributeError, - "Can't pickle local attribute %R on %R", name, obj); + "Can't get local attribute %R on %R", name, obj); Py_DECREF(dotted_path); return NULL; } @@ -2566,7 +2569,7 @@ save_picklebuffer(PickleState *st, PicklerObject *self, PyObject *obj) { if (self->proto < 5) { PyErr_SetString(st->PicklingError, - "PickleBuffer can only pickled with protocol >= 5"); + "PickleBuffer can only be pickled with protocol >= 5"); return -1; } const Py_buffer* view = PyPickleBuffer_GetBuffer(obj); @@ -3188,6 +3191,7 @@ batch_dict(PickleState *state, PicklerObject *self, PyObject *iter) if (!PyTuple_Check(obj) || PyTuple_Size(obj) != 2) { PyErr_SetString(PyExc_TypeError, "dict items " "iterator must return 2-tuples"); + Py_DECREF(obj); return -1; } i = save(state, self, PyTuple_GET_ITEM(obj, 0), 0); @@ -3651,7 +3655,6 @@ save_global(PickleState *st, PicklerObject *self, PyObject *obj, PyObject *module = NULL; PyObject *parent = NULL; PyObject *dotted_path = NULL; - PyObject *lastname = NULL; PyObject *cls; int status = 0; @@ -3692,10 +3695,7 @@ save_global(PickleState *st, PicklerObject *self, PyObject *obj, obj, module_name); goto error; } - lastname = Py_NewRef(PyList_GET_ITEM(dotted_path, - PyList_GET_SIZE(dotted_path) - 1)); cls = get_deep_attribute(module, dotted_path, &parent); - Py_CLEAR(dotted_path); if (cls == NULL) { PyErr_Format(st->PicklingError, "Can't pickle %R: attribute lookup %S on %S failed", @@ -3728,31 +3728,23 @@ save_global(PickleState *st, PicklerObject *self, PyObject *obj, code_obj = PyDict_GetItemWithError(st->extension_registry, extension_key); Py_DECREF(extension_key); - /* The object is not registered in the extension registry. - This is the most likely code path. */ if (code_obj == NULL) { if (PyErr_Occurred()) { goto error; } + /* The object is not registered in the extension registry. + This is the most likely code path. */ goto gen_global; } - /* XXX: pickle.py doesn't check neither the type, nor the range - of the value returned by the extension_registry. It should for - consistency. */ - - /* Verify code_obj has the right type and value. */ - if (!PyLong_Check(code_obj)) { - PyErr_Format(st->PicklingError, - "Can't pickle %R: extension code %R isn't an integer", - obj, code_obj); - goto error; - } - code = PyLong_AS_LONG(code_obj); + Py_INCREF(code_obj); + code = PyLong_AsLong(code_obj); + Py_DECREF(code_obj); if (code <= 0 || code > 0x7fffffffL) { + /* Should never happen in normal circumstances, since the type and + the value of the code are checked in copyreg.add_extension(). */ if (!PyErr_Occurred()) - PyErr_Format(st->PicklingError, "Can't pickle %R: extension " - "code %ld is out of range", obj, code); + PyErr_Format(PyExc_RuntimeError, "extension code %ld is out of range", code); goto error; } @@ -3783,7 +3775,10 @@ save_global(PickleState *st, PicklerObject *self, PyObject *obj, else { gen_global: if (parent == module) { - Py_SETREF(global_name, Py_NewRef(lastname)); + Py_SETREF(global_name, + Py_NewRef(PyList_GET_ITEM(dotted_path, + PyList_GET_SIZE(dotted_path) - 1))); + Py_CLEAR(dotted_path); } if (self->proto >= 4) { const char stack_global_op = STACK_GLOBAL; @@ -3796,20 +3791,30 @@ save_global(PickleState *st, PicklerObject *self, PyObject *obj, if (_Pickler_Write(self, &stack_global_op, 1) < 0) goto error; } - else if (parent != module) { - PyObject *reduce_value = Py_BuildValue("(O(OO))", - st->getattr, parent, lastname); - if (reduce_value == NULL) - goto error; - status = save_reduce(st, self, reduce_value, NULL); - Py_DECREF(reduce_value); - if (status < 0) - goto error; - } else { /* Generate a normal global opcode if we are using a pickle protocol < 4, or if the object is not registered in the - extension registry. */ + extension registry. + + Objects with multi-part __qualname__ are represented as + getattr(getattr(..., attrname1), attrname2). */ + const char mark_op = MARK; + const char tupletwo_op = (self->proto < 2) ? TUPLE : TUPLE2; + const char reduce_op = REDUCE; + Py_ssize_t i; + if (dotted_path) { + if (PyList_GET_SIZE(dotted_path) > 1) { + Py_SETREF(global_name, Py_NewRef(PyList_GET_ITEM(dotted_path, 0))); + } + for (i = 1; i < PyList_GET_SIZE(dotted_path); i++) { + if (save(st, self, st->getattr, 0) < 0 || + (self->proto < 2 && _Pickler_Write(self, &mark_op, 1) < 0)) + { + goto error; + } + } + } + PyObject *encoded; PyObject *(*unicode_encoder)(PyObject *); @@ -3871,6 +3876,17 @@ save_global(PickleState *st, PicklerObject *self, PyObject *obj, Py_DECREF(encoded); if (_Pickler_Write(self, "\n", 1) < 0) goto error; + + if (dotted_path) { + for (i = 1; i < PyList_GET_SIZE(dotted_path); i++) { + if (save(st, self, PyList_GET_ITEM(dotted_path, i), 0) < 0 || + _Pickler_Write(self, &tupletwo_op, 1) < 0 || + _Pickler_Write(self, &reduce_op, 1) < 0) + { + goto error; + } + } + } } /* Memoize the object. */ if (memo_put(st, self, obj) < 0) @@ -3886,7 +3902,6 @@ save_global(PickleState *st, PicklerObject *self, PyObject *obj, Py_XDECREF(module); Py_XDECREF(parent); Py_XDECREF(dotted_path); - Py_XDECREF(lastname); return status; } @@ -6623,11 +6638,13 @@ load_additems(PickleState *state, UnpicklerObject *self) if (result == NULL) { Pdata_clear(self->stack, i + 1); Py_SET_SIZE(self->stack, mark); + Py_DECREF(add_func); return -1; } Py_DECREF(result); } Py_SET_SIZE(self->stack, mark); + Py_DECREF(add_func); } return 0; @@ -6703,10 +6720,13 @@ load_build(PickleState *st, UnpicklerObject *self) /* normally the keys for instance attributes are interned. we should try to do that here. */ Py_INCREF(d_key); - if (PyUnicode_CheckExact(d_key)) - PyUnicode_InternInPlace(&d_key); + if (PyUnicode_CheckExact(d_key)) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + _PyUnicode_InternMortal(interp, &d_key); + } if (PyObject_SetItem(dict, d_key, d_value) < 0) { Py_DECREF(d_key); + Py_DECREF(dict); goto error; } Py_DECREF(d_key); diff --git a/Modules/_sqlite/clinic/connection.c.h b/Modules/_sqlite/clinic/connection.c.h index 417abcc4..93e4a0f3 100644 --- a/Modules/_sqlite/clinic/connection.c.h +++ b/Modules/_sqlite/clinic/connection.c.h @@ -717,7 +717,7 @@ pysqlite_connection_set_progress_handler(pysqlite_Connection *self, PyTypeObject PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(progress_handler), &_Py_ID(n), }, + .ob_item = { &_Py_ID(progress_handler), _Py_LATIN1_CHR('n'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -1665,4 +1665,4 @@ getconfig(pysqlite_Connection *self, PyObject *arg) #ifndef DESERIALIZE_METHODDEF #define DESERIALIZE_METHODDEF #endif /* !defined(DESERIALIZE_METHODDEF) */ -/*[clinic end generated code: output=834a99827555bf1a input=a9049054013a1b77]*/ +/*[clinic end generated code: output=305d580e3eaa622d input=a9049054013a1b77]*/ diff --git a/Modules/_sre/clinic/sre.c.h b/Modules/_sre/clinic/sre.c.h index 529c634e..56a4e604 100644 --- a/Modules/_sre/clinic/sre.c.h +++ b/Modules/_sre/clinic/sre.c.h @@ -975,6 +975,44 @@ PyDoc_STRVAR(_sre_SRE_Pattern___deepcopy____doc__, #define _SRE_SRE_PATTERN___DEEPCOPY___METHODDEF \ {"__deepcopy__", (PyCFunction)_sre_SRE_Pattern___deepcopy__, METH_O, _sre_SRE_Pattern___deepcopy____doc__}, +#if defined(Py_DEBUG) + +PyDoc_STRVAR(_sre_SRE_Pattern__fail_after__doc__, +"_fail_after($self, count, exception, /)\n" +"--\n" +"\n" +"For debugging."); + +#define _SRE_SRE_PATTERN__FAIL_AFTER_METHODDEF \ + {"_fail_after", _PyCFunction_CAST(_sre_SRE_Pattern__fail_after), METH_FASTCALL, _sre_SRE_Pattern__fail_after__doc__}, + +static PyObject * +_sre_SRE_Pattern__fail_after_impl(PatternObject *self, int count, + PyObject *exception); + +static PyObject * +_sre_SRE_Pattern__fail_after(PatternObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + int count; + PyObject *exception; + + if (!_PyArg_CheckPositional("_fail_after", nargs, 2, 2)) { + goto exit; + } + count = _PyLong_AsInt(args[0]); + if (count == -1 && PyErr_Occurred()) { + goto exit; + } + exception = args[1]; + return_value = _sre_SRE_Pattern__fail_after_impl(self, count, exception); + +exit: + return return_value; +} + +#endif /* defined(Py_DEBUG) */ + PyDoc_STRVAR(_sre_compile__doc__, "compile($module, /, pattern, flags, code, groups, groupindex,\n" " indexgroup)\n" @@ -1460,4 +1498,8 @@ _sre_SRE_Scanner_search(ScannerObject *self, PyTypeObject *cls, PyObject *const } return _sre_SRE_Scanner_search_impl(self, cls); } -/*[clinic end generated code: output=045de53cfe02dee0 input=a9049054013a1b77]*/ + +#ifndef _SRE_SRE_PATTERN__FAIL_AFTER_METHODDEF + #define _SRE_SRE_PATTERN__FAIL_AFTER_METHODDEF +#endif /* !defined(_SRE_SRE_PATTERN__FAIL_AFTER_METHODDEF) */ +/*[clinic end generated code: output=2165ecf43a7c20e8 input=a9049054013a1b77]*/ diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c index 05473904..35c6058d 100644 --- a/Modules/_sre/sre.c +++ b/Modules/_sre/sre.c @@ -218,6 +218,85 @@ data_stack_grow(SRE_STATE* state, Py_ssize_t size) return 0; } +/* memory pool functions for SRE_REPEAT, this can avoid memory + leak when SRE(match) function terminates abruptly. + state->repeat_pool_used is a doubly-linked list, so that we + can remove a SRE_REPEAT node from it. + state->repeat_pool_unused is a singly-linked list, we put/get + node at the head. */ +static SRE_REPEAT * +repeat_pool_malloc(SRE_STATE *state) +{ + SRE_REPEAT *repeat; + + if (state->repeat_pool_unused) { + /* remove from unused pool (singly-linked list) */ + repeat = state->repeat_pool_unused; + state->repeat_pool_unused = repeat->pool_next; + } + else { + repeat = PyObject_Malloc(sizeof(SRE_REPEAT)); + if (!repeat) { + return NULL; + } + } + + /* add to used pool (doubly-linked list) */ + SRE_REPEAT *temp = state->repeat_pool_used; + if (temp) { + temp->pool_prev = repeat; + } + repeat->pool_prev = NULL; + repeat->pool_next = temp; + state->repeat_pool_used = repeat; + + return repeat; +} + +static void +repeat_pool_free(SRE_STATE *state, SRE_REPEAT *repeat) +{ + SRE_REPEAT *prev = repeat->pool_prev; + SRE_REPEAT *next = repeat->pool_next; + + /* remove from used pool (doubly-linked list) */ + if (prev) { + prev->pool_next = next; + } + else { + state->repeat_pool_used = next; + } + if (next) { + next->pool_prev = prev; + } + + /* add to unused pool (singly-linked list) */ + repeat->pool_next = state->repeat_pool_unused; + state->repeat_pool_unused = repeat; +} + +static void +repeat_pool_clear(SRE_STATE *state) +{ + /* clear used pool */ + SRE_REPEAT *next = state->repeat_pool_used; + state->repeat_pool_used = NULL; + while (next) { + SRE_REPEAT *temp = next; + next = temp->pool_next; + PyObject_Free(temp); + } + + /* clear unused pool */ + next = state->repeat_pool_unused; + state->repeat_pool_unused = NULL; + while (next) { + SRE_REPEAT *temp = next; + next = temp->pool_next; + PyObject_Free(temp); + } +} + /* generate 8-bit version */ #define SRE_CHAR Py_UCS1 @@ -463,6 +542,11 @@ state_init(SRE_STATE* state, PatternObject* pattern, PyObject* string, state->pos = start; state->endpos = end; +#ifdef Py_DEBUG + state->fail_after_count = pattern->fail_after_count; + state->fail_after_exc = pattern->fail_after_exc; // borrowed ref +#endif + return string; err: /* We add an explicit cast here because MSVC has a bug when @@ -485,6 +569,8 @@ state_fini(SRE_STATE* state) /* See above PyMem_Del for why we explicitly cast here. */ PyMem_Free((void*) state->mark); state->mark = NULL; + /* SRE_REPEAT pool */ + repeat_pool_clear(state); } /* calculate offset from start of string */ @@ -571,6 +657,9 @@ pattern_traverse(PatternObject *self, visitproc visit, void *arg) Py_VISIT(self->groupindex); Py_VISIT(self->indexgroup); Py_VISIT(self->pattern); +#ifdef Py_DEBUG + Py_VISIT(self->fail_after_exc); +#endif return 0; } @@ -580,6 +669,9 @@ pattern_clear(PatternObject *self) Py_CLEAR(self->groupindex); Py_CLEAR(self->indexgroup); Py_CLEAR(self->pattern); +#ifdef Py_DEBUG + Py_CLEAR(self->fail_after_exc); +#endif return 0; } @@ -642,7 +734,7 @@ _sre_SRE_Pattern_match_impl(PatternObject *self, PyTypeObject *cls, Py_ssize_t status; PyObject *match; - if (!state_init(&state, (PatternObject *)self, string, pos, endpos)) + if (!state_init(&state, self, string, pos, endpos)) return NULL; state.ptr = state.start; @@ -1330,6 +1422,29 @@ _sre_SRE_Pattern___deepcopy__(PatternObject *self, PyObject *memo) return Py_NewRef(self); } +#ifdef Py_DEBUG +/*[clinic input] +_sre.SRE_Pattern._fail_after + + count: int + exception: object + / + +For debugging. +[clinic start generated code]*/ + +static PyObject * +_sre_SRE_Pattern__fail_after_impl(PatternObject *self, int count, + PyObject *exception) +/*[clinic end generated code: output=9a6bf12135ac50c2 input=ef80a45c66c5499d]*/ +{ + self->fail_after_count = count; + Py_INCREF(exception); + Py_XSETREF(self->fail_after_exc, exception); + Py_RETURN_NONE; +} +#endif /* Py_DEBUG */ + static PyObject * pattern_repr(PatternObject *obj) { @@ -1456,6 +1571,10 @@ _sre_compile_impl(PyObject *module, PyObject *pattern, int flags, self->pattern = NULL; self->groupindex = NULL; self->indexgroup = NULL; +#ifdef Py_DEBUG + self->fail_after_count = -1; + self->fail_after_exc = NULL; +#endif self->codesize = n; @@ -1572,6 +1691,7 @@ _sre_template_impl(PyObject *module, PyObject *pattern, PyObject *template) } self->items[i].literal = Py_XNewRef(literal); } + PyObject_GC_Track(self); return (PyObject*) self; bad_template: @@ -2166,6 +2286,8 @@ match_getindex(MatchObject* self, PyObject* index) return -1; } + // Check that i*2 cannot overflow to make static analyzers happy + assert(i <= SRE_MAXGROUPS); return i; } @@ -2549,7 +2671,8 @@ pattern_new_match(_sremodulestate* module_state, if (!match) return NULL; - match->pattern = (PatternObject*)Py_NewRef(pattern); + Py_INCREF(pattern); + match->pattern = pattern; match->string = Py_NewRef(state->string); @@ -2685,7 +2808,7 @@ _sre_SRE_Scanner_match_impl(ScannerObject *self, PyTypeObject *cls) return NULL; } - match = pattern_new_match(module_state, (PatternObject*) self->pattern, + match = pattern_new_match(module_state, self->pattern, state, status); if (status == 0) @@ -2735,7 +2858,7 @@ _sre_SRE_Scanner_search_impl(ScannerObject *self, PyTypeObject *cls) return NULL; } - match = pattern_new_match(module_state, (PatternObject*) self->pattern, + match = pattern_new_match(module_state, self->pattern, state, status); if (status == 0) @@ -2771,7 +2894,8 @@ pattern_scanner(_sremodulestate *module_state, return NULL; } - scanner->pattern = Py_NewRef(self); + Py_INCREF(self); + scanner->pattern = self; PyObject_GC_Track(scanner); return (PyObject*) scanner; @@ -2965,6 +3089,7 @@ static PyMethodDef pattern_methods[] = { _SRE_SRE_PATTERN_SCANNER_METHODDEF _SRE_SRE_PATTERN___COPY___METHODDEF _SRE_SRE_PATTERN___DEEPCOPY___METHODDEF + _SRE_SRE_PATTERN__FAIL_AFTER_METHODDEF {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, {NULL, NULL} diff --git a/Modules/_sre/sre.h b/Modules/_sre/sre.h index a0f23560..b8c6f8e3 100644 --- a/Modules/_sre/sre.h +++ b/Modules/_sre/sre.h @@ -34,6 +34,11 @@ typedef struct { int flags; /* flags used when compiling pattern source */ PyObject *weakreflist; /* List of weak references */ int isbytes; /* pattern type (1 - bytes, 0 - string, -1 - None) */ +#ifdef Py_DEBUG + /* for simulation of user interruption */ + int fail_after_count; + PyObject *fail_after_exc; +#endif /* pattern code */ Py_ssize_t codesize; SRE_CODE code[1]; @@ -68,6 +73,9 @@ typedef struct SRE_REPEAT_T { const SRE_CODE* pattern; /* points to REPEAT operator arguments */ const void* last_ptr; /* helper to check for infinite loops */ struct SRE_REPEAT_T *prev; /* points to previous repeat context */ + /* for SRE_REPEAT pool */ + struct SRE_REPEAT_T *pool_prev; + struct SRE_REPEAT_T *pool_next; } SRE_REPEAT; typedef struct { @@ -94,12 +102,19 @@ typedef struct { size_t data_stack_base; /* current repeat context */ SRE_REPEAT *repeat; + /* SRE_REPEAT pool */ + SRE_REPEAT *repeat_pool_used; + SRE_REPEAT *repeat_pool_unused; unsigned int sigcount; +#ifdef Py_DEBUG + int fail_after_count; + PyObject *fail_after_exc; +#endif } SRE_STATE; typedef struct { PyObject_HEAD - PyObject* pattern; + PatternObject* pattern; SRE_STATE state; int executing; } ScannerObject; diff --git a/Modules/_sre/sre_lib.h b/Modules/_sre/sre_lib.h index 95c1ada9..9e9a0ec9 100644 --- a/Modules/_sre/sre_lib.h +++ b/Modules/_sre/sre_lib.h @@ -524,13 +524,28 @@ typedef struct { Py_ssize_t last_ctx_pos; } SRE(match_context); -#define MAYBE_CHECK_SIGNALS \ +#define _MAYBE_CHECK_SIGNALS \ do { \ if ((0 == (++sigcount & 0xfff)) && PyErr_CheckSignals()) { \ RETURN_ERROR(SRE_ERROR_INTERRUPTED); \ } \ } while (0) +#ifdef Py_DEBUG +# define MAYBE_CHECK_SIGNALS \ + do { \ + _MAYBE_CHECK_SIGNALS; \ + if (state->fail_after_count >= 0) { \ + if (state->fail_after_count-- == 0) { \ + PyErr_SetNone(state->fail_after_exc); \ + RETURN_ERROR(SRE_ERROR_INTERRUPTED); \ + } \ + } \ + } while (0) +#else +# define MAYBE_CHECK_SIGNALS _MAYBE_CHECK_SIGNALS +#endif /* Py_DEBUG */ + #ifdef HAVE_COMPUTED_GOTOS #ifndef USE_COMPUTED_GOTOS #define USE_COMPUTED_GOTOS 1 @@ -1083,12 +1098,9 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) pattern[1], pattern[2])); /* install new repeat context */ - /* TODO(https://github.com/python/cpython/issues/67877): Fix this - * potential memory leak. */ - ctx->u.rep = (SRE_REPEAT*) PyObject_Malloc(sizeof(*ctx->u.rep)); + ctx->u.rep = repeat_pool_malloc(state); if (!ctx->u.rep) { - PyErr_NoMemory(); - RETURN_FAILURE; + RETURN_ERROR(SRE_ERROR_MEMORY); } ctx->u.rep->count = -1; ctx->u.rep->pattern = pattern; @@ -1099,7 +1111,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) state->ptr = ptr; DO_JUMP(JUMP_REPEAT, jump_repeat, pattern+pattern[0]); state->repeat = ctx->u.rep->prev; - PyObject_Free(ctx->u.rep); + repeat_pool_free(state, ctx->u.rep); if (ret) { RETURN_ON_ERROR(ret); @@ -1257,6 +1269,17 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) pointer */ state->ptr = ptr; + /* Set state->repeat to non-NULL */ + ctx->u.rep = repeat_pool_malloc(state); + if (!ctx->u.rep) { + RETURN_ERROR(SRE_ERROR_MEMORY); + } + ctx->u.rep->count = -1; + ctx->u.rep->pattern = NULL; + ctx->u.rep->prev = state->repeat; + ctx->u.rep->last_ptr = NULL; + state->repeat = ctx->u.rep; + /* Initialize Count to 0 */ ctx->count = 0; @@ -1271,6 +1294,9 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) } else { state->ptr = ptr; + /* Restore state->repeat */ + state->repeat = ctx->u.rep->prev; + repeat_pool_free(state, ctx->u.rep); RETURN_FAILURE; } } @@ -1343,6 +1369,10 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) } } + /* Restore state->repeat */ + state->repeat = ctx->u.rep->prev; + repeat_pool_free(state, ctx->u.rep); + /* Evaluate Tail */ /* Jump to end of pattern indicated by skip, and then skip the SUCCESS op code that follows it. */ diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 85fbc162..7a9f2c87 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -2224,6 +2224,17 @@ PySSL_dealloc(PySSLSocket *self) PyTypeObject *tp = Py_TYPE(self); PyObject_GC_UnTrack(self); if (self->ssl) { + // If we free the SSL socket object without having called SSL_shutdown, + // OpenSSL will invalidate the linked SSL session object. While this + // behavior is strictly RFC-compliant, it makes session reuse less + // likely and it would also break compatibility with older stdlib + // versions (which used an ugly workaround of duplicating the + // SSL_SESSION object). + // Therefore, we ensure the socket is marked as shutdown in any case. + // + // See elaborate explanation at + // https://github.com/python/cpython/pull/123249#discussion_r1766164530 + SSL_set_shutdown(self->ssl, SSL_SENT_SHUTDOWN | SSL_get_shutdown(self->ssl)); SSL_free(self->ssl); } Py_XDECREF(self->Socket); @@ -2768,48 +2779,6 @@ _ssl__SSLSocket_verify_client_post_handshake_impl(PySSLSocket *self) #endif } -static SSL_SESSION* -_ssl_session_dup(SSL_SESSION *session) { - SSL_SESSION *newsession = NULL; - int slen; - unsigned char *senc = NULL, *p; - const unsigned char *const_p; - - if (session == NULL) { - PyErr_SetString(PyExc_ValueError, "Invalid session"); - goto error; - } - - /* get length */ - slen = i2d_SSL_SESSION(session, NULL); - if (slen == 0 || slen > 0xFF00) { - PyErr_SetString(PyExc_ValueError, "i2d() failed"); - goto error; - } - if ((senc = PyMem_Malloc(slen)) == NULL) { - PyErr_NoMemory(); - goto error; - } - p = senc; - if (!i2d_SSL_SESSION(session, &p)) { - PyErr_SetString(PyExc_ValueError, "i2d() failed"); - goto error; - } - const_p = senc; - newsession = d2i_SSL_SESSION(NULL, &const_p, slen); - if (newsession == NULL) { - PyErr_SetString(PyExc_ValueError, "d2i() failed"); - goto error; - } - PyMem_Free(senc); - return newsession; - error: - if (senc != NULL) { - PyMem_Free(senc); - } - return NULL; -} - static PyObject * PySSL_get_session(PySSLSocket *self, void *closure) { /* get_session can return sessions from a server-side connection, @@ -2817,15 +2786,6 @@ PySSL_get_session(PySSLSocket *self, void *closure) { PySSLSession *pysess; SSL_SESSION *session; - /* duplicate session as workaround for session bug in OpenSSL 1.1.0, - * https://github.com/openssl/openssl/issues/1550 */ - session = SSL_get0_session(self->ssl); /* borrowed reference */ - if (session == NULL) { - Py_RETURN_NONE; - } - if ((session = _ssl_session_dup(session)) == NULL) { - return NULL; - } session = SSL_get1_session(self->ssl); if (session == NULL) { Py_RETURN_NONE; @@ -2844,11 +2804,8 @@ PySSL_get_session(PySSLSocket *self, void *closure) { } static int PySSL_set_session(PySSLSocket *self, PyObject *value, - void *closure) - { + void *closure) { PySSLSession *pysess; - SSL_SESSION *session; - int result; if (!Py_IS_TYPE(value, get_state_sock(self)->PySSLSession_Type)) { PyErr_SetString(PyExc_TypeError, "Value is not a SSLSession."); @@ -2871,14 +2828,7 @@ static int PySSL_set_session(PySSLSocket *self, PyObject *value, "Cannot set session after handshake."); return -1; } - /* duplicate session */ - if ((session = _ssl_session_dup(pysess->session)) == NULL) { - return -1; - } - result = SSL_set_session(self->ssl, session); - /* free duplicate, SSL_set_session() bumps ref count */ - SSL_SESSION_free(session); - if (result == 0) { + if (SSL_set_session(self->ssl, pysess->session) == 0) { _setSSLError(get_state_sock(self), NULL, 0, __FILE__, __LINE__); return -1; } @@ -2950,7 +2900,7 @@ static PyType_Spec PySSLSocket_spec = { .name = "_ssl._SSLSocket", .basicsize = sizeof(PySSLSocket), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | - Py_TPFLAGS_HAVE_GC), + Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_DISALLOW_INSTANTIATION), .slots = PySSLSocket_slots, }; @@ -5001,14 +4951,14 @@ PySSLSession_dealloc(PySSLSession *self) static PyObject * PySSLSession_richcompare(PyObject *left, PyObject *right, int op) { - int result; - PyTypeObject *sesstype = ((PySSLSession*)left)->ctx->state->PySSLSession_Type; - if (left == NULL || right == NULL) { PyErr_BadInternalCall(); return NULL; } + int result; + PyTypeObject *sesstype = ((PySSLSession*)left)->ctx->state->PySSLSession_Type; + if (!Py_IS_TYPE(left, sesstype) || !Py_IS_TYPE(right, sesstype)) { Py_RETURN_NOTIMPLEMENTED; } diff --git a/Modules/_struct.c b/Modules/_struct.c index 55efc0c6..6532174a 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -278,7 +278,7 @@ get_size_t(_structmodulestate *state, PyObject *v, size_t *p) #define RANGE_ERROR(state, f, flag) return _range_error(state, f, flag) -/* Floating point helpers */ +/* Floating-point helpers */ static PyObject * unpack_halffloat(const char *p, /* start of 2-byte string */ @@ -483,9 +483,8 @@ nu_ulonglong(_structmodulestate *state, const char *p, const formatdef *f) static PyObject * nu_bool(_structmodulestate *state, const char *p, const formatdef *f) { - _Bool x; - memcpy((char *)&x, p, sizeof x); - return PyBool_FromLong(x != 0); + const _Bool bool_false = 0; + return PyBool_FromLong(memcmp(p, &bool_false, sizeof(_Bool))); } @@ -1662,9 +1661,16 @@ s_unpack_internal(PyStructObject *soself, const char *startfrom, if (e->format == 's') { v = PyBytes_FromStringAndSize(res, code->size); } else if (e->format == 'p') { - Py_ssize_t n = *(unsigned char*)res; - if (n >= code->size) - n = code->size - 1; + Py_ssize_t n; + if (code->size == 0) { + n = 0; + } + else { + n = *(unsigned char*)res; + if (n >= code->size) { + n = code->size - 1; + } + } v = PyBytes_FromStringAndSize(res + 1, n); } else { v = e->unpack(state, res, e); @@ -1975,8 +1981,12 @@ s_pack_internal(PyStructObject *soself, PyObject *const *args, int offset, n = PyByteArray_GET_SIZE(v); p = PyByteArray_AS_STRING(v); } - if (n > (code->size - 1)) + if (code->size == 0) { + n = 0; + } + else if (n > (code->size - 1)) { n = code->size - 1; + } if (n > 0) memcpy(res + 1, p, n); if (n > 255) diff --git a/Modules/_testcapi/numbers.c b/Modules/_testcapi/numbers.c index 6f7fa3fa..e16ff737 100644 --- a/Modules/_testcapi/numbers.c +++ b/Modules/_testcapi/numbers.c @@ -1,7 +1,168 @@ #include "parts.h" #include "util.h" + +static PyObject * +number_check(PyObject *Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyNumber_Check(obj)); +} + +#define BINARYFUNC(funcsuffix, methsuffix) \ + static PyObject * \ + number_##methsuffix(PyObject *Py_UNUSED(module), PyObject *args) \ + { \ + PyObject *o1, *o2; \ + \ + if (!PyArg_ParseTuple(args, "OO", &o1, &o2)) { \ + return NULL; \ + } \ + \ + NULLABLE(o1); \ + NULLABLE(o2); \ + return PyNumber_##funcsuffix(o1, o2); \ + }; + +BINARYFUNC(Add, add) +BINARYFUNC(Subtract, subtract) +BINARYFUNC(Multiply, multiply) +BINARYFUNC(MatrixMultiply, matrixmultiply) +BINARYFUNC(FloorDivide, floordivide) +BINARYFUNC(TrueDivide, truedivide) +BINARYFUNC(Remainder, remainder) +BINARYFUNC(Divmod, divmod) + +#define TERNARYFUNC(funcsuffix, methsuffix) \ + static PyObject * \ + number_##methsuffix(PyObject *Py_UNUSED(module), PyObject *args) \ + { \ + PyObject *o1, *o2, *o3 = Py_None; \ + \ + if (!PyArg_ParseTuple(args, "OO|O", &o1, &o2, &o3)) { \ + return NULL; \ + } \ + \ + NULLABLE(o1); \ + NULLABLE(o2); \ + return PyNumber_##funcsuffix(o1, o2, o3); \ + }; + +TERNARYFUNC(Power, power) + +#define UNARYFUNC(funcsuffix, methsuffix) \ + static PyObject * \ + number_##methsuffix(PyObject *Py_UNUSED(module), PyObject *obj) \ + { \ + NULLABLE(obj); \ + return PyNumber_##funcsuffix(obj); \ + }; + +UNARYFUNC(Negative, negative) +UNARYFUNC(Positive, positive) +UNARYFUNC(Absolute, absolute) +UNARYFUNC(Invert, invert) + +BINARYFUNC(Lshift, lshift) +BINARYFUNC(Rshift, rshift) +BINARYFUNC(And, and) +BINARYFUNC(Xor, xor) +BINARYFUNC(Or, or) + +BINARYFUNC(InPlaceAdd, inplaceadd) +BINARYFUNC(InPlaceSubtract, inplacesubtract) +BINARYFUNC(InPlaceMultiply, inplacemultiply) +BINARYFUNC(InPlaceMatrixMultiply, inplacematrixmultiply) +BINARYFUNC(InPlaceFloorDivide, inplacefloordivide) +BINARYFUNC(InPlaceTrueDivide, inplacetruedivide) +BINARYFUNC(InPlaceRemainder, inplaceremainder) + +TERNARYFUNC(InPlacePower, inplacepower) + +BINARYFUNC(InPlaceLshift, inplacelshift) +BINARYFUNC(InPlaceRshift, inplacershift) +BINARYFUNC(InPlaceAnd, inplaceand) +BINARYFUNC(InPlaceXor, inplacexor) +BINARYFUNC(InPlaceOr, inplaceor) + +UNARYFUNC(Long, long) +UNARYFUNC(Float, float) +UNARYFUNC(Index, index) + +static PyObject * +number_tobase(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *n; + int base; + + if (!PyArg_ParseTuple(args, "Oi", &n, &base)) { + return NULL; + } + + NULLABLE(n); + return PyNumber_ToBase(n, base); +} + +static PyObject * +number_asssizet(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *o, *exc; + Py_ssize_t ret; + + if (!PyArg_ParseTuple(args, "OO", &o, &exc)) { + return NULL; + } + + NULLABLE(o); + NULLABLE(exc); + ret = PyNumber_AsSsize_t(o, exc); + + if (ret == (Py_ssize_t)(-1) && PyErr_Occurred()) { + return NULL; + } + + return PyLong_FromSsize_t(ret); +} + + static PyMethodDef test_methods[] = { + {"number_check", number_check, METH_O}, + {"number_add", number_add, METH_VARARGS}, + {"number_subtract", number_subtract, METH_VARARGS}, + {"number_multiply", number_multiply, METH_VARARGS}, + {"number_matrixmultiply", number_matrixmultiply, METH_VARARGS}, + {"number_floordivide", number_floordivide, METH_VARARGS}, + {"number_truedivide", number_truedivide, METH_VARARGS}, + {"number_remainder", number_remainder, METH_VARARGS}, + {"number_divmod", number_divmod, METH_VARARGS}, + {"number_power", number_power, METH_VARARGS}, + {"number_negative", number_negative, METH_O}, + {"number_positive", number_positive, METH_O}, + {"number_absolute", number_absolute, METH_O}, + {"number_invert", number_invert, METH_O}, + {"number_lshift", number_lshift, METH_VARARGS}, + {"number_rshift", number_rshift, METH_VARARGS}, + {"number_and", number_and, METH_VARARGS}, + {"number_xor", number_xor, METH_VARARGS}, + {"number_or", number_or, METH_VARARGS}, + {"number_inplaceadd", number_inplaceadd, METH_VARARGS}, + {"number_inplacesubtract", number_inplacesubtract, METH_VARARGS}, + {"number_inplacemultiply", number_inplacemultiply, METH_VARARGS}, + {"number_inplacematrixmultiply", number_inplacematrixmultiply, METH_VARARGS}, + {"number_inplacefloordivide", number_inplacefloordivide, METH_VARARGS}, + {"number_inplacetruedivide", number_inplacetruedivide, METH_VARARGS}, + {"number_inplaceremainder", number_inplaceremainder, METH_VARARGS}, + {"number_inplacepower", number_inplacepower, METH_VARARGS}, + {"number_inplacelshift", number_inplacelshift, METH_VARARGS}, + {"number_inplacershift", number_inplacershift, METH_VARARGS}, + {"number_inplaceand", number_inplaceand, METH_VARARGS}, + {"number_inplacexor", number_inplacexor, METH_VARARGS}, + {"number_inplaceor", number_inplaceor, METH_VARARGS}, + {"number_long", number_long, METH_O}, + {"number_float", number_float, METH_O}, + {"number_index", number_index, METH_O}, + {"number_tobase", number_tobase, METH_VARARGS}, + {"number_asssizet", number_asssizet, METH_VARARGS}, {NULL}, }; diff --git a/Modules/_testcapi/tuple.c b/Modules/_testcapi/tuple.c index 95dde8c0..23ea4e1d 100644 --- a/Modules/_testcapi/tuple.c +++ b/Modules/_testcapi/tuple.c @@ -2,14 +2,240 @@ #include "util.h" +static PyObject * +tuple_get_size(PyObject *Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + RETURN_SIZE(PyTuple_GET_SIZE(obj)); +} + +static PyObject * +tuple_get_item(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj; + Py_ssize_t i; + if (!PyArg_ParseTuple(args, "On", &obj, &i)) { + return NULL; + } + NULLABLE(obj); + return Py_XNewRef(PyTuple_GET_ITEM(obj, i)); +} + +static PyObject * +tuple_copy(PyObject *tuple) +{ + Py_ssize_t size = PyTuple_GET_SIZE(tuple); + PyObject *newtuple = PyTuple_New(size); + if (!newtuple) { + return NULL; + } + for (Py_ssize_t n = 0; n < size; n++) { + PyTuple_SET_ITEM(newtuple, n, Py_XNewRef(PyTuple_GET_ITEM(tuple, n))); + } + return newtuple; +} + +static PyObject * +tuple_set_item(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj, *value, *newtuple; + Py_ssize_t i; + if (!PyArg_ParseTuple(args, "OnO", &obj, &i, &value)) { + return NULL; + } + NULLABLE(value); + if (PyTuple_CheckExact(obj)) { + newtuple = tuple_copy(obj); + if (!newtuple) { + return NULL; + } + + PyObject *val = PyTuple_GET_ITEM(newtuple, i); + PyTuple_SET_ITEM(newtuple, i, Py_XNewRef(value)); + Py_DECREF(val); + return newtuple; + } + else { + NULLABLE(obj); + + PyObject *val = PyTuple_GET_ITEM(obj, i); + PyTuple_SET_ITEM(obj, i, Py_XNewRef(value)); + Py_DECREF(val); + return Py_XNewRef(obj); + } +} + +static PyObject * +_tuple_resize(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *tup; + Py_ssize_t newsize; + int new = 1; + if (!PyArg_ParseTuple(args, "On|p", &tup, &newsize, &new)) { + return NULL; + } + if (new) { + tup = tuple_copy(tup); + if (!tup) { + return NULL; + } + } + else { + NULLABLE(tup); + Py_XINCREF(tup); + } + int r = _PyTuple_Resize(&tup, newsize); + if (r == -1) { + assert(tup == NULL); + return NULL; + } + return tup; +} + +static PyObject * +_check_tuple_item_is_NULL(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj; + Py_ssize_t i; + if (!PyArg_ParseTuple(args, "On", &obj, &i)) { + return NULL; + } + return PyLong_FromLong(PyTuple_GET_ITEM(obj, i) == NULL); +} + +static PyObject * +tuple_check(PyObject* Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyTuple_Check(obj)); +} + +static PyObject * +tuple_checkexact(PyObject* Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyTuple_CheckExact(obj)); +} + +static PyObject * +tuple_new(PyObject* Py_UNUSED(module), PyObject *len) +{ + return PyTuple_New(PyLong_AsSsize_t(len)); +} + +static PyObject * +tuple_pack(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *arg1 = NULL, *arg2 = NULL; + Py_ssize_t size; + + if (!PyArg_ParseTuple(args, "n|OO", &size, &arg1, &arg2)) { + return NULL; + } + if (arg1) { + NULLABLE(arg1); + if (arg2) { + NULLABLE(arg2); + return PyTuple_Pack(size, arg1, arg2); + } + return PyTuple_Pack(size, arg1); + } + return PyTuple_Pack(size); +} + +static PyObject * +tuple_size(PyObject *Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + RETURN_SIZE(PyTuple_Size(obj)); +} + +static PyObject * +tuple_getitem(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj; + Py_ssize_t i; + if (!PyArg_ParseTuple(args, "On", &obj, &i)) { + return NULL; + } + NULLABLE(obj); + return Py_XNewRef(PyTuple_GetItem(obj, i)); +} + +static PyObject * +tuple_getslice(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj; + Py_ssize_t ilow, ihigh; + if (!PyArg_ParseTuple(args, "Onn", &obj, &ilow, &ihigh)) { + return NULL; + } + NULLABLE(obj); + return PyTuple_GetSlice(obj, ilow, ihigh); +} + +static PyObject * +tuple_setitem(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj, *value, *newtuple = NULL; + Py_ssize_t i; + if (!PyArg_ParseTuple(args, "OnO", &obj, &i, &value)) { + return NULL; + } + NULLABLE(value); + if (PyTuple_CheckExact(obj)) { + Py_ssize_t size = PyTuple_Size(obj); + newtuple = PyTuple_New(size); + if (!newtuple) { + return NULL; + } + for (Py_ssize_t n = 0; n < size; n++) { + if (PyTuple_SetItem(newtuple, n, + Py_XNewRef(PyTuple_GetItem(obj, n))) == -1) { + Py_DECREF(newtuple); + return NULL; + } + } + + if (PyTuple_SetItem(newtuple, i, Py_XNewRef(value)) == -1) { + Py_DECREF(newtuple); + return NULL; + } + return newtuple; + } + else { + NULLABLE(obj); + + if (PyTuple_SetItem(obj, i, Py_XNewRef(value)) == -1) { + return NULL; + } + return Py_XNewRef(obj); + } +} + + static PyMethodDef test_methods[] = { + {"tuple_get_size", tuple_get_size, METH_O}, + {"tuple_get_item", tuple_get_item, METH_VARARGS}, + {"tuple_set_item", tuple_set_item, METH_VARARGS}, + {"_tuple_resize", _tuple_resize, METH_VARARGS}, + {"_check_tuple_item_is_NULL", _check_tuple_item_is_NULL, METH_VARARGS}, + /* Limited C API */ + {"tuple_check", tuple_check, METH_O}, + {"tuple_checkexact", tuple_checkexact, METH_O}, + {"tuple_new", tuple_new, METH_O}, + {"tuple_pack", tuple_pack, METH_VARARGS}, + {"tuple_size", tuple_size, METH_O}, + {"tuple_getitem", tuple_getitem, METH_VARARGS}, + {"tuple_getslice", tuple_getslice, METH_VARARGS}, + {"tuple_setitem", tuple_setitem, METH_VARARGS}, {NULL}, }; int _PyTestCapi_Init_Tuple(PyObject *m) { - if (PyModule_AddFunctions(m, test_methods) < 0){ + if (PyModule_AddFunctions(m, test_methods) < 0) { return -1; } diff --git a/Modules/_testcapi/vectorcall.c b/Modules/_testcapi/vectorcall.c index dcbc973c..bf91d0b4 100644 --- a/Modules/_testcapi/vectorcall.c +++ b/Modules/_testcapi/vectorcall.c @@ -349,6 +349,9 @@ static PyObject * MethodDescriptor2_new(PyTypeObject* type, PyObject* args, PyObject *kw) { MethodDescriptor2Object *op = PyObject_New(MethodDescriptor2Object, type); + if (op == NULL) { + return NULL; + } op->base.vectorcall = NULL; op->vectorcall = MethodDescriptor_vectorcall; return (PyObject *)op; diff --git a/Modules/_testclinic.c b/Modules/_testclinic.c index 676535f5..29cc106a 100644 --- a/Modules/_testclinic.c +++ b/Modules/_testclinic.c @@ -1034,6 +1034,25 @@ vararg_with_default_impl(PyObject *module, PyObject *a, PyObject *args, } +/*[clinic input] +vararg_with_default2 + + a: object + *args: object + b: object = None + c: object = None + +[clinic start generated code]*/ + +static PyObject * +vararg_with_default2_impl(PyObject *module, PyObject *a, PyObject *args, + PyObject *b, PyObject *c) +/*[clinic end generated code: output=a0fb7c37796e2129 input=59fb22f5f0a8925f]*/ +{ + return pack_arguments_newref(4, a, args, b, c); +} + + /*[clinic input] vararg_with_only_defaults @@ -1274,6 +1293,7 @@ static PyMethodDef tester_methods[] = { VARARG_AND_POSONLY_METHODDEF VARARG_METHODDEF VARARG_WITH_DEFAULT_METHODDEF + VARARG_WITH_DEFAULT2_METHODDEF VARARG_WITH_ONLY_DEFAULTS_METHODDEF GH_32092_OOB_METHODDEF GH_32092_KW_PASS_METHODDEF diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 365f4460..366ee618 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -961,7 +961,7 @@ local_setattro(localobject *self, PyObject *name, PyObject *v) } if (r == 1) { PyErr_Format(PyExc_AttributeError, - "'%.100s' object attribute '%U' is read-only", + "'%.100s' object attribute %R is read-only", Py_TYPE(self)->tp_name, name); return -1; } @@ -1219,6 +1219,7 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs) if (ident == PYTHREAD_INVALID_THREAD_ID) { PyErr_SetString(ThreadError, "can't start new thread"); PyThreadState_Clear(boot->tstate); + PyThreadState_Delete(boot->tstate); thread_bootstate_free(boot, 1); return NULL; } diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 8dca940b..6b5fcb8a 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -71,6 +71,12 @@ Copyright (C) 1994 Steen Lumholt. #define USE_DEPRECATED_TOMMATH_API 1 #endif +// As suggested by https://core.tcl-lang.org/tcl/wiki?name=Migrating+C+extensions+to+Tcl+9 +#ifndef TCL_SIZE_MAX +typedef int Tcl_Size; +#define TCL_SIZE_MAX INT_MAX +#endif + #if !(defined(MS_WINDOWS) || defined(__CYGWIN__)) #define HAVE_CREATEFILEHANDLER #endif @@ -491,24 +497,28 @@ unicodeFromTclString(const char *s) } static PyObject * -unicodeFromTclObj(Tcl_Obj *value) +unicodeFromTclObj(TkappObject *tkapp, Tcl_Obj *value) { - int len; + Tcl_Size len; #if USE_TCL_UNICODE - int byteorder = NATIVE_BYTEORDER; - const Tcl_UniChar *u = Tcl_GetUnicodeFromObj(value, &len); - if (sizeof(Tcl_UniChar) == 2) - return PyUnicode_DecodeUTF16((const char *)u, len * 2, - "surrogatepass", &byteorder); - else if (sizeof(Tcl_UniChar) == 4) - return PyUnicode_DecodeUTF32((const char *)u, len * 4, - "surrogatepass", &byteorder); - else - Py_UNREACHABLE(); -#else + if (value->typePtr != NULL && tkapp != NULL && + (value->typePtr == tkapp->StringType || + value->typePtr == tkapp->UTF32StringType)) + { + int byteorder = NATIVE_BYTEORDER; + const Tcl_UniChar *u = Tcl_GetUnicodeFromObj(value, &len); + if (sizeof(Tcl_UniChar) == 2) + return PyUnicode_DecodeUTF16((const char *)u, len * 2, + "surrogatepass", &byteorder); + else if (sizeof(Tcl_UniChar) == 4) + return PyUnicode_DecodeUTF32((const char *)u, len * 4, + "surrogatepass", &byteorder); + else + Py_UNREACHABLE(); + } +#endif /* USE_TCL_UNICODE */ const char *s = Tcl_GetStringFromObj(value, &len); return unicodeFromTclStringAndSize(s, len); -#endif } /*[clinic input] @@ -521,6 +531,10 @@ class _tkinter.tktimertoken "TkttObject *" "&Tktt_Type_spec" /**** Tkapp Object ****/ +#if TK_MAJOR_VERSION >= 9 +int Tcl_AppInit(Tcl_Interp *); +#endif + #ifndef WITH_APPINIT int Tcl_AppInit(Tcl_Interp *interp) @@ -786,7 +800,7 @@ static PyObject * PyTclObject_string(PyTclObject *self, void *ignored) { if (!self->string) { - self->string = unicodeFromTclObj(self->value); + self->string = unicodeFromTclObj(NULL, self->value); if (!self->string) return NULL; } @@ -800,7 +814,7 @@ PyTclObject_str(PyTclObject *self) return Py_NewRef(self->string); } /* XXX Could cache result if it is non-ASCII. */ - return unicodeFromTclObj(self->value); + return unicodeFromTclObj(NULL, self->value); } static PyObject * @@ -1010,7 +1024,9 @@ AsObj(PyObject *value) PyErr_SetString(PyExc_OverflowError, "string is too long"); return NULL; } - if (PyUnicode_IS_ASCII(value)) { + if (PyUnicode_IS_ASCII(value) && + strlen(PyUnicode_DATA(value)) == (size_t)PyUnicode_GET_LENGTH(value)) + { return Tcl_NewStringObj((const char *)PyUnicode_DATA(value), (int)size); } @@ -1025,9 +1041,6 @@ AsObj(PyObject *value) "surrogatepass", NATIVE_BYTEORDER); else Py_UNREACHABLE(); -#else - encoded = _PyUnicode_AsUTF8String(value, "surrogateescape"); -#endif if (!encoded) { return NULL; } @@ -1037,12 +1050,39 @@ AsObj(PyObject *value) PyErr_SetString(PyExc_OverflowError, "string is too long"); return NULL; } -#if USE_TCL_UNICODE result = Tcl_NewUnicodeObj((const Tcl_UniChar *)PyBytes_AS_STRING(encoded), (int)(size / sizeof(Tcl_UniChar))); #else + encoded = _PyUnicode_AsUTF8String(value, "surrogateescape"); + if (!encoded) { + return NULL; + } + size = PyBytes_GET_SIZE(encoded); + if (strlen(PyBytes_AS_STRING(encoded)) != (size_t)size) { + /* The string contains embedded null characters. + * Tcl needs a null character to be represented as \xc0\x80 in + * the Modified UTF-8 encoding. Otherwise the string can be + * truncated in some internal operations. + * + * NOTE: stringlib_replace() could be used here, but optimizing + * this obscure case isn't worth it unless stringlib_replace() + * was already exposed in the C API for other reasons. */ + Py_SETREF(encoded, + PyObject_CallMethod(encoded, "replace", "y#y#", + "\0", (Py_ssize_t)1, + "\xc0\x80", (Py_ssize_t)2)); + if (!encoded) { + return NULL; + } + size = PyBytes_GET_SIZE(encoded); + } + if (size > INT_MAX) { + Py_DECREF(encoded); + PyErr_SetString(PyExc_OverflowError, "string is too long"); + return NULL; + } result = Tcl_NewStringObj(PyBytes_AS_STRING(encoded), (int)size); -#endif +#endif /* USE_TCL_UNICODE */ Py_DECREF(encoded); return result; } @@ -1139,7 +1179,7 @@ FromObj(TkappObject *tkapp, Tcl_Obj *value) Tcl_Interp *interp = Tkapp_Interp(tkapp); if (value->typePtr == NULL) { - return unicodeFromTclObj(value); + return unicodeFromTclObj(tkapp, value); } if (value->typePtr == tkapp->BooleanType || @@ -1148,7 +1188,7 @@ FromObj(TkappObject *tkapp, Tcl_Obj *value) } if (value->typePtr == tkapp->ByteArrayType) { - int size; + Tcl_Size size; char *data = (char*)Tcl_GetByteArrayFromObj(value, &size); return PyBytes_FromStringAndSize(data, size); } @@ -1174,8 +1214,8 @@ FromObj(TkappObject *tkapp, Tcl_Obj *value) } if (value->typePtr == tkapp->ListType) { - int size; - int i, status; + Tcl_Size i, size; + int status; PyObject *elem; Tcl_Obj *tcl_elem; @@ -1204,7 +1244,7 @@ FromObj(TkappObject *tkapp, Tcl_Obj *value) if (value->typePtr == tkapp->StringType || value->typePtr == tkapp->UTF32StringType) { - return unicodeFromTclObj(value); + return unicodeFromTclObj(tkapp, value); } if (tkapp->BignumType == NULL && @@ -1231,9 +1271,9 @@ typedef struct Tkapp_CallEvent { } Tkapp_CallEvent; static void -Tkapp_CallDeallocArgs(Tcl_Obj** objv, Tcl_Obj** objStore, int objc) +Tkapp_CallDeallocArgs(Tcl_Obj** objv, Tcl_Obj** objStore, Tcl_Size objc) { - int i; + Tcl_Size i; for (i = 0; i < objc; i++) Tcl_DecrRefCount(objv[i]); if (objv != objStore) @@ -1244,7 +1284,7 @@ Tkapp_CallDeallocArgs(Tcl_Obj** objv, Tcl_Obj** objStore, int objc) interpreter thread, which may or may not be the calling thread. */ static Tcl_Obj** -Tkapp_CallArgs(PyObject *args, Tcl_Obj** objStore, int *pobjc) +Tkapp_CallArgs(PyObject *args, Tcl_Obj** objStore, Tcl_Size *pobjc) { Tcl_Obj **objv = objStore; Py_ssize_t objc = 0, i; @@ -1292,10 +1332,10 @@ Tkapp_CallArgs(PyObject *args, Tcl_Obj** objStore, int *pobjc) Tcl_IncrRefCount(objv[i]); } } - *pobjc = (int)objc; + *pobjc = (Tcl_Size)objc; return objv; finally: - Tkapp_CallDeallocArgs(objv, objStore, (int)objc); + Tkapp_CallDeallocArgs(objv, objStore, (Tcl_Size)objc); return NULL; } @@ -1304,7 +1344,7 @@ Tkapp_CallArgs(PyObject *args, Tcl_Obj** objStore, int *pobjc) static PyObject * Tkapp_UnicodeResult(TkappObject *self) { - return unicodeFromTclObj(Tcl_GetObjResult(self->interp)); + return unicodeFromTclObj(self, Tcl_GetObjResult(self->interp)); } @@ -1323,7 +1363,7 @@ Tkapp_ObjectResult(TkappObject *self) res = FromObj(self, value); Tcl_DecrRefCount(value); } else { - res = unicodeFromTclObj(value); + res = unicodeFromTclObj(self, value); } return res; } @@ -1361,7 +1401,7 @@ Tkapp_CallProc(Tkapp_CallEvent *e, int flags) { Tcl_Obj *objStore[ARGSZ]; Tcl_Obj **objv; - int objc; + Tcl_Size objc; int i; ENTER_PYTHON if (e->self->trace && !Tkapp_Trace(e->self, PyTuple_Pack(1, e->args))) { @@ -1417,7 +1457,7 @@ Tkapp_Call(PyObject *selfptr, PyObject *args) { Tcl_Obj *objStore[ARGSZ]; Tcl_Obj **objv = NULL; - int objc, i; + Tcl_Size objc; PyObject *res = NULL; TkappObject *self = (TkappObject*)selfptr; int flags = TCL_EVAL_DIRECT | TCL_EVAL_GLOBAL; @@ -1464,6 +1504,7 @@ Tkapp_Call(PyObject *selfptr, PyObject *args) { TRACE(self, ("(O)", args)); + int i; objv = Tkapp_CallArgs(args, objStore, &objc); if (!objv) return NULL; @@ -1852,7 +1893,7 @@ GetVar(TkappObject *self, PyObject *args, int flags) res = FromObj(self, tres); } else { - res = unicodeFromTclObj(tres); + res = unicodeFromTclObj(self, tres); } } LEAVE_OVERLAP_TCL @@ -2197,13 +2238,12 @@ _tkinter_tkapp_splitlist(TkappObject *self, PyObject *arg) /*[clinic end generated code: output=13b51d34386d36fb input=2b2e13351e3c0b53]*/ { char *list; - int argc; + Tcl_Size argc, i; const char **argv; PyObject *v; - int i; if (PyTclObject_Check(arg)) { - int objc; + Tcl_Size objc; Tcl_Obj **objv; if (Tcl_ListObjGetElements(Tkapp_Interp(self), ((PyTclObject*)arg)->value, @@ -2298,7 +2338,7 @@ PythonCmd(ClientData clientData, Tcl_Interp *interp, return PythonCmd_Error(interp); for (i = 0; i < (objc - 1); i++) { - PyObject *s = unicodeFromTclObj(objv[i + 1]); + PyObject *s = unicodeFromTclObj((TkappObject *)data->self, objv[i + 1]); if (!s) { Py_DECREF(args); return PythonCmd_Error(interp); diff --git a/Modules/_winapi.c b/Modules/_winapi.c index edb11818..76f18c71 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -2268,7 +2268,7 @@ _winapi__mimetypes_read_windows_registry_impl(PyObject *module, } err = RegOpenKeyExW(hkcr, ext, 0, KEY_READ, &subkey); - if (err == ERROR_FILE_NOT_FOUND) { + if (err == ERROR_FILE_NOT_FOUND || err == ERROR_ACCESS_DENIED) { err = ERROR_SUCCESS; continue; } else if (err != ERROR_SUCCESS) { diff --git a/Modules/_xxtestfuzz/README.rst b/Modules/_xxtestfuzz/README.rst index 42bd02a0..27c44f7b 100644 --- a/Modules/_xxtestfuzz/README.rst +++ b/Modules/_xxtestfuzz/README.rst @@ -20,7 +20,7 @@ Add the test name on a new line in ``fuzz_tests.txt``. In ``fuzzer.c``, add a function to be run:: - int $test_name (const char* data, size_t size) { + static int $fuzz_test_name(const char* data, size_t size) { ... return 0; } @@ -28,10 +28,12 @@ In ``fuzzer.c``, add a function to be run:: And invoke it from ``LLVMFuzzerTestOneInput``:: - #if _Py_FUZZ_YES(fuzz_builtin_float) - rv |= _run_fuzz(data, size, fuzz_builtin_float); + #if !defined(_Py_FUZZ_ONE) || defined(_Py_FUZZ_$fuzz_test_name) + rv |= _run_fuzz(data, size, $fuzz_test_name); #endif +Don't forget to replace ``$fuzz_test_name`` with your actual test name. + ``LLVMFuzzerTestOneInput`` will run in oss-fuzz, with each test in ``fuzz_tests.txt`` run separately. diff --git a/Modules/_zoneinfo.c b/Modules/_zoneinfo.c index 8fc86162..47e40125 100644 --- a/Modules/_zoneinfo.c +++ b/Modules/_zoneinfo.c @@ -954,6 +954,7 @@ ttinfo_eq(const _ttinfo *const tti0, const _ttinfo *const tti1) static int load_data(zoneinfo_state *state, PyZoneInfo_ZoneInfo *self, PyObject *file_obj) { + int rv = 0; PyObject *data_tuple = NULL; long *utcoff = NULL; @@ -1230,7 +1231,6 @@ load_data(zoneinfo_state *state, PyZoneInfo_ZoneInfo *self, PyObject *file_obj) } } - int rv = 0; goto cleanup; error: // These resources only need to be freed if we have failed, if we succeed diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 19ee83d2..d24c5989 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -2739,7 +2739,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds) PyDoc_STRVAR(module_doc, "This module defines an object type which can efficiently represent\n\ -an array of basic values: characters, integers, floating point\n\ +an array of basic values: characters, integers, floating-point\n\ numbers. Arrays are sequence types and behave very much like lists,\n\ except that the type of objects stored in them is constrained.\n"); @@ -2767,8 +2767,8 @@ The following type codes are defined:\n\ 'L' unsigned integer 4\n\ 'q' signed integer 8 (see note)\n\ 'Q' unsigned integer 8 (see note)\n\ - 'f' floating point 4\n\ - 'd' floating point 8\n\ + 'f' floating-point 4\n\ + 'd' floating-point 8\n\ \n\ NOTE: The 'u' typecode corresponds to Python's unicode character. On\n\ narrow builds this is 2-bytes on wide builds this is 4-bytes.\n\ diff --git a/Modules/clinic/_bisectmodule.c.h b/Modules/clinic/_bisectmodule.c.h index 7944f521..cfd1c984 100644 --- a/Modules/clinic/_bisectmodule.c.h +++ b/Modules/clinic/_bisectmodule.c.h @@ -43,7 +43,7 @@ _bisect_bisect_right(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(a), &_Py_ID(x), &_Py_ID(lo), &_Py_ID(hi), &_Py_ID(key), }, + .ob_item = { _Py_LATIN1_CHR('a'), _Py_LATIN1_CHR('x'), &_Py_ID(lo), &_Py_ID(hi), &_Py_ID(key), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -151,7 +151,7 @@ _bisect_insort_right(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(a), &_Py_ID(x), &_Py_ID(lo), &_Py_ID(hi), &_Py_ID(key), }, + .ob_item = { _Py_LATIN1_CHR('a'), _Py_LATIN1_CHR('x'), &_Py_ID(lo), &_Py_ID(hi), &_Py_ID(key), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -256,7 +256,7 @@ _bisect_bisect_left(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(a), &_Py_ID(x), &_Py_ID(lo), &_Py_ID(hi), &_Py_ID(key), }, + .ob_item = { _Py_LATIN1_CHR('a'), _Py_LATIN1_CHR('x'), &_Py_ID(lo), &_Py_ID(hi), &_Py_ID(key), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -364,7 +364,7 @@ _bisect_insort_left(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(a), &_Py_ID(x), &_Py_ID(lo), &_Py_ID(hi), &_Py_ID(key), }, + .ob_item = { _Py_LATIN1_CHR('a'), _Py_LATIN1_CHR('x'), &_Py_ID(lo), &_Py_ID(hi), &_Py_ID(key), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -433,4 +433,4 @@ _bisect_insort_left(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P exit: return return_value; } -/*[clinic end generated code: output=5a7fa64bf9b262f3 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=57335e39ce2bf80e input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index 9d99d41a..1d716bec 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -3688,25 +3688,55 @@ PyDoc_STRVAR(_curses_resizeterm__doc__, {"resizeterm", _PyCFunction_CAST(_curses_resizeterm), METH_FASTCALL, _curses_resizeterm__doc__}, static PyObject * -_curses_resizeterm_impl(PyObject *module, int nlines, int ncols); +_curses_resizeterm_impl(PyObject *module, short nlines, short ncols); static PyObject * _curses_resizeterm(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - int nlines; - int ncols; + short nlines; + short ncols; if (!_PyArg_CheckPositional("resizeterm", nargs, 2, 2)) { goto exit; } - nlines = _PyLong_AsInt(args[0]); - if (nlines == -1 && PyErr_Occurred()) { - goto exit; + { + long ival = PyLong_AsLong(args[0]); + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + else if (ival < SHRT_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is less than minimum"); + goto exit; + } + else if (ival > SHRT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is greater than maximum"); + goto exit; + } + else { + nlines = (short) ival; + } } - ncols = _PyLong_AsInt(args[1]); - if (ncols == -1 && PyErr_Occurred()) { - goto exit; + { + long ival = PyLong_AsLong(args[1]); + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + else if (ival < SHRT_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is less than minimum"); + goto exit; + } + else if (ival > SHRT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is greater than maximum"); + goto exit; + } + else { + ncols = (short) ival; + } } return_value = _curses_resizeterm_impl(module, nlines, ncols); @@ -3739,25 +3769,55 @@ PyDoc_STRVAR(_curses_resize_term__doc__, {"resize_term", _PyCFunction_CAST(_curses_resize_term), METH_FASTCALL, _curses_resize_term__doc__}, static PyObject * -_curses_resize_term_impl(PyObject *module, int nlines, int ncols); +_curses_resize_term_impl(PyObject *module, short nlines, short ncols); static PyObject * _curses_resize_term(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - int nlines; - int ncols; + short nlines; + short ncols; if (!_PyArg_CheckPositional("resize_term", nargs, 2, 2)) { goto exit; } - nlines = _PyLong_AsInt(args[0]); - if (nlines == -1 && PyErr_Occurred()) { - goto exit; + { + long ival = PyLong_AsLong(args[0]); + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + else if (ival < SHRT_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is less than minimum"); + goto exit; + } + else if (ival > SHRT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is greater than maximum"); + goto exit; + } + else { + nlines = (short) ival; + } } - ncols = _PyLong_AsInt(args[1]); - if (ncols == -1 && PyErr_Occurred()) { - goto exit; + { + long ival = PyLong_AsLong(args[1]); + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + else if (ival < SHRT_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is less than minimum"); + goto exit; + } + else if (ival > SHRT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is greater than maximum"); + goto exit; + } + else { + ncols = (short) ival; + } } return_value = _curses_resize_term_impl(module, nlines, ncols); @@ -4313,4 +4373,4 @@ _curses_has_extended_color_support(PyObject *module, PyObject *Py_UNUSED(ignored #ifndef _CURSES_USE_DEFAULT_COLORS_METHODDEF #define _CURSES_USE_DEFAULT_COLORS_METHODDEF #endif /* !defined(_CURSES_USE_DEFAULT_COLORS_METHODDEF) */ -/*[clinic end generated code: output=27a2364193b503c1 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=764ee4c154c6d4a8 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_hashopenssl.c.h b/Modules/clinic/_hashopenssl.c.h index fb61a444..84e23462 100644 --- a/Modules/clinic/_hashopenssl.c.h +++ b/Modules/clinic/_hashopenssl.c.h @@ -1354,7 +1354,7 @@ _hashlib_scrypt(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObj PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(password), &_Py_ID(salt), &_Py_ID(n), &_Py_ID(r), &_Py_ID(p), &_Py_ID(maxmem), &_Py_ID(dklen), }, + .ob_item = { &_Py_ID(password), &_Py_ID(salt), _Py_LATIN1_CHR('n'), _Py_LATIN1_CHR('r'), _Py_LATIN1_CHR('p'), &_Py_ID(maxmem), &_Py_ID(dklen), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -1851,4 +1851,4 @@ _hashlib_compare_digest(PyObject *module, PyObject *const *args, Py_ssize_t narg #ifndef _HASHLIB_SCRYPT_METHODDEF #define _HASHLIB_SCRYPT_METHODDEF #endif /* !defined(_HASHLIB_SCRYPT_METHODDEF) */ -/*[clinic end generated code: output=b339e255db698147 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=4734184f6555dc95 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_testclinic.c.h b/Modules/clinic/_testclinic.c.h index 3fce2624..31a366df 100644 --- a/Modules/clinic/_testclinic.c.h +++ b/Modules/clinic/_testclinic.c.h @@ -1263,7 +1263,7 @@ keywords(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kw PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(a), &_Py_ID(b), }, + .ob_item = { _Py_LATIN1_CHR('a'), _Py_LATIN1_CHR('b'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -1319,7 +1319,7 @@ keywords_kwonly(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObj PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(a), &_Py_ID(b), }, + .ob_item = { _Py_LATIN1_CHR('a'), _Py_LATIN1_CHR('b'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -1375,7 +1375,7 @@ keywords_opt(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(a), &_Py_ID(b), &_Py_ID(c), }, + .ob_item = { _Py_LATIN1_CHR('a'), _Py_LATIN1_CHR('b'), _Py_LATIN1_CHR('c'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -1444,7 +1444,7 @@ keywords_opt_kwonly(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(a), &_Py_ID(b), &_Py_ID(c), &_Py_ID(d), }, + .ob_item = { _Py_LATIN1_CHR('a'), _Py_LATIN1_CHR('b'), _Py_LATIN1_CHR('c'), _Py_LATIN1_CHR('d'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -1524,7 +1524,7 @@ keywords_kwonly_opt(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(a), &_Py_ID(b), &_Py_ID(c), }, + .ob_item = { _Py_LATIN1_CHR('a'), _Py_LATIN1_CHR('b'), _Py_LATIN1_CHR('c'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -1592,7 +1592,7 @@ posonly_keywords(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(b), }, + .ob_item = { _Py_LATIN1_CHR('b'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -1648,7 +1648,7 @@ posonly_kwonly(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(b), }, + .ob_item = { _Py_LATIN1_CHR('b'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -1705,7 +1705,7 @@ posonly_keywords_kwonly(PyObject *module, PyObject *const *args, Py_ssize_t narg PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(b), &_Py_ID(c), }, + .ob_item = { _Py_LATIN1_CHR('b'), _Py_LATIN1_CHR('c'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -1764,7 +1764,7 @@ posonly_keywords_opt(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(b), &_Py_ID(c), &_Py_ID(d), }, + .ob_item = { _Py_LATIN1_CHR('b'), _Py_LATIN1_CHR('c'), _Py_LATIN1_CHR('d'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -1835,7 +1835,7 @@ posonly_opt_keywords_opt(PyObject *module, PyObject *const *args, Py_ssize_t nar PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(c), &_Py_ID(d), }, + .ob_item = { _Py_LATIN1_CHR('c'), _Py_LATIN1_CHR('d'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -1911,7 +1911,7 @@ posonly_kwonly_opt(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(b), &_Py_ID(c), &_Py_ID(d), }, + .ob_item = { _Py_LATIN1_CHR('b'), _Py_LATIN1_CHR('c'), _Py_LATIN1_CHR('d'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -1982,7 +1982,7 @@ posonly_opt_kwonly_opt(PyObject *module, PyObject *const *args, Py_ssize_t nargs PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(c), &_Py_ID(d), }, + .ob_item = { _Py_LATIN1_CHR('c'), _Py_LATIN1_CHR('d'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2058,7 +2058,7 @@ posonly_keywords_kwonly_opt(PyObject *module, PyObject *const *args, Py_ssize_t PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(b), &_Py_ID(c), &_Py_ID(d), &_Py_ID(e), }, + .ob_item = { _Py_LATIN1_CHR('b'), _Py_LATIN1_CHR('c'), _Py_LATIN1_CHR('d'), _Py_LATIN1_CHR('e'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2133,7 +2133,7 @@ posonly_keywords_opt_kwonly_opt(PyObject *module, PyObject *const *args, Py_ssiz PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(b), &_Py_ID(c), &_Py_ID(d), &_Py_ID(e), }, + .ob_item = { _Py_LATIN1_CHR('b'), _Py_LATIN1_CHR('c'), _Py_LATIN1_CHR('d'), _Py_LATIN1_CHR('e'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2217,7 +2217,7 @@ posonly_opt_keywords_opt_kwonly_opt(PyObject *module, PyObject *const *args, Py_ PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(c), &_Py_ID(d), }, + .ob_item = { _Py_LATIN1_CHR('c'), _Py_LATIN1_CHR('d'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2296,7 +2296,7 @@ keyword_only_parameter(PyObject *module, PyObject *const *args, Py_ssize_t nargs PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(a), }, + .ob_item = { _Py_LATIN1_CHR('a'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2351,7 +2351,7 @@ posonly_vararg(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(b), }, + .ob_item = { _Py_LATIN1_CHR('b'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2446,7 +2446,7 @@ vararg(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwna PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(a), }, + .ob_item = { _Py_LATIN1_CHR('a'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2504,7 +2504,7 @@ vararg_with_default(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(a), &_Py_ID(b), }, + .ob_item = { _Py_LATIN1_CHR('a'), _Py_LATIN1_CHR('b'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2547,6 +2547,78 @@ vararg_with_default(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P return return_value; } +PyDoc_STRVAR(vararg_with_default2__doc__, +"vararg_with_default2($module, /, a, *args, b=None, c=None)\n" +"--\n" +"\n"); + +#define VARARG_WITH_DEFAULT2_METHODDEF \ + {"vararg_with_default2", _PyCFunction_CAST(vararg_with_default2), METH_FASTCALL|METH_KEYWORDS, vararg_with_default2__doc__}, + +static PyObject * +vararg_with_default2_impl(PyObject *module, PyObject *a, PyObject *args, + PyObject *b, PyObject *c); + +static PyObject * +vararg_with_default2(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 3 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { _Py_LATIN1_CHR('a'), _Py_LATIN1_CHR('b'), _Py_LATIN1_CHR('c'), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"a", "b", "c", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "vararg_with_default2", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[4]; + Py_ssize_t noptargs = Py_MIN(nargs, 1) + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *a; + PyObject *__clinic_args = NULL; + PyObject *b = Py_None; + PyObject *c = Py_None; + + args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, 1, argsbuf); + if (!args) { + goto exit; + } + a = args[0]; + __clinic_args = args[1]; + if (!noptargs) { + goto skip_optional_kwonly; + } + if (args[2]) { + b = args[2]; + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + c = args[3]; +skip_optional_kwonly: + return_value = vararg_with_default2_impl(module, a, __clinic_args, b, c); + +exit: + Py_XDECREF(__clinic_args); + return return_value; +} + PyDoc_STRVAR(vararg_with_only_defaults__doc__, "vararg_with_only_defaults($module, /, *args, b=None)\n" "--\n" @@ -2571,7 +2643,7 @@ vararg_with_only_defaults(PyObject *module, PyObject *const *args, Py_ssize_t na PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(b), }, + .ob_item = { _Py_LATIN1_CHR('b'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -3097,4 +3169,4 @@ _testclinic_TestClass_meth_method_no_params(PyObject *self, PyTypeObject *cls, P } return _testclinic_TestClass_meth_method_no_params_impl(self, cls); } -/*[clinic end generated code: output=999de26ba394ab5d input=a9049054013a1b77]*/ +/*[clinic end generated code: output=74fdd265fd402226 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_testmultiphase.c.h b/Modules/clinic/_testmultiphase.c.h index 4f2b1bcf..c63f9e32 100644 --- a/Modules/clinic/_testmultiphase.c.h +++ b/Modules/clinic/_testmultiphase.c.h @@ -88,7 +88,7 @@ _testmultiphase_StateAccessType_increment_count_clinic(StateAccessTypeObject *se PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(n), &_Py_ID(twice), }, + .ob_item = { _Py_LATIN1_CHR('n'), &_Py_ID(twice), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -162,4 +162,4 @@ _testmultiphase_StateAccessType_get_count(StateAccessTypeObject *self, PyTypeObj } return _testmultiphase_StateAccessType_get_count_impl(self, cls); } -/*[clinic end generated code: output=2193fe33d5e2b739 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=0543b54ec62be171 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/cmathmodule.c.h b/Modules/clinic/cmathmodule.c.h index 941448e7..f018d901 100644 --- a/Modules/clinic/cmathmodule.c.h +++ b/Modules/clinic/cmathmodule.c.h @@ -908,7 +908,7 @@ cmath_isclose(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObjec PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(a), &_Py_ID(b), &_Py_ID(rel_tol), &_Py_ID(abs_tol), }, + .ob_item = { _Py_LATIN1_CHR('a'), _Py_LATIN1_CHR('b'), &_Py_ID(rel_tol), &_Py_ID(abs_tol), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -982,4 +982,4 @@ cmath_isclose(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObjec exit: return return_value; } -/*[clinic end generated code: output=87f609786ef270cd input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a6c9ca48ffe871b6 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/itertoolsmodule.c.h b/Modules/clinic/itertoolsmodule.c.h index 32278bf7..51c766f0 100644 --- a/Modules/clinic/itertoolsmodule.c.h +++ b/Modules/clinic/itertoolsmodule.c.h @@ -42,7 +42,7 @@ batched_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(iterable), &_Py_ID(n), }, + .ob_item = { &_Py_ID(iterable), _Py_LATIN1_CHR('n'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -494,7 +494,7 @@ itertools_combinations(PyTypeObject *type, PyObject *args, PyObject *kwargs) PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(iterable), &_Py_ID(r), }, + .ob_item = { &_Py_ID(iterable), _Py_LATIN1_CHR('r'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -565,7 +565,7 @@ itertools_combinations_with_replacement(PyTypeObject *type, PyObject *args, PyOb PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(iterable), &_Py_ID(r), }, + .ob_item = { &_Py_ID(iterable), _Py_LATIN1_CHR('r'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -635,7 +635,7 @@ itertools_permutations(PyTypeObject *type, PyObject *args, PyObject *kwargs) PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(iterable), &_Py_ID(r), }, + .ob_item = { &_Py_ID(iterable), _Py_LATIN1_CHR('r'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -913,4 +913,4 @@ itertools_count(PyTypeObject *type, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=111cbd102c2a23c9 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=55a83cfda62afb57 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/mathmodule.c.h b/Modules/clinic/mathmodule.c.h index c16c1b08..97c16a43 100644 --- a/Modules/clinic/mathmodule.c.h +++ b/Modules/clinic/mathmodule.c.h @@ -34,9 +34,9 @@ PyDoc_STRVAR(math_fsum__doc__, "fsum($module, seq, /)\n" "--\n" "\n" -"Return an accurate floating point sum of values in the iterable seq.\n" +"Return an accurate floating-point sum of values in the iterable seq.\n" "\n" -"Assumes IEEE-754 floating point arithmetic."); +"Assumes IEEE-754 floating-point arithmetic."); #define MATH_FSUM_METHODDEF \ {"fsum", (PyCFunction)math_fsum, METH_O, math_fsum__doc__}, @@ -549,7 +549,7 @@ PyDoc_STRVAR(math_isclose__doc__, "isclose($module, /, a, b, *, rel_tol=1e-09, abs_tol=0.0)\n" "--\n" "\n" -"Determine whether two floating point numbers are close in value.\n" +"Determine whether two floating-point numbers are close in value.\n" "\n" " rel_tol\n" " maximum difference for being considered \"close\", relative to the\n" @@ -587,7 +587,7 @@ math_isclose(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(a), &_Py_ID(b), &_Py_ID(rel_tol), &_Py_ID(abs_tol), }, + .ob_item = { _Py_LATIN1_CHR('a'), _Py_LATIN1_CHR('b'), &_Py_ID(rel_tol), &_Py_ID(abs_tol), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -950,4 +950,4 @@ math_ulp(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=91a0357265a2a553 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=c1335a499389a04e input=a9049054013a1b77]*/ diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index 02cb95a6..a33461dc 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -1975,25 +1975,55 @@ os__path_splitroot(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py #if defined(MS_WINDOWS) PyDoc_STRVAR(os__path_exists__doc__, -"_path_exists($module, path, /)\n" +"_path_exists($module, /, path)\n" "--\n" "\n" "Test whether a path exists. Returns False for broken symbolic links."); #define OS__PATH_EXISTS_METHODDEF \ - {"_path_exists", (PyCFunction)os__path_exists, METH_O, os__path_exists__doc__}, + {"_path_exists", _PyCFunction_CAST(os__path_exists), METH_FASTCALL|METH_KEYWORDS, os__path_exists__doc__}, static int os__path_exists_impl(PyObject *module, path_t *path); static PyObject * -os__path_exists(PyObject *module, PyObject *arg) +os__path_exists(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(path), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"path", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "_path_exists", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; path_t path = PATH_T_INITIALIZE_P("_path_exists", "path", 0, 0, 1, 1); int _return_value; - if (!path_converter(arg, &path)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!path_converter(args[0], &path)) { goto exit; } _return_value = os__path_exists_impl(module, &path); @@ -2038,7 +2068,7 @@ os__path_isdir(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(s), }, + .ob_item = { _Py_LATIN1_CHR('s'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -5985,7 +6015,7 @@ PyDoc_STRVAR(os_times__doc__, "\n" "The object returned behaves like a named tuple with these fields:\n" " (utime, stime, cutime, cstime, elapsed_time)\n" -"All fields are floating point numbers."); +"All fields are floating-point numbers."); #define OS_TIMES_METHODDEF \ {"times", (PyCFunction)os_times, METH_NOARGS, os_times__doc__}, @@ -12002,4 +12032,4 @@ os_waitstatus_to_exitcode(PyObject *module, PyObject *const *args, Py_ssize_t na #ifndef OS_WAITSTATUS_TO_EXITCODE_METHODDEF #define OS_WAITSTATUS_TO_EXITCODE_METHODDEF #endif /* !defined(OS_WAITSTATUS_TO_EXITCODE_METHODDEF) */ -/*[clinic end generated code: output=e2cf3ab750346780 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=6d34c4564aca7725 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/selectmodule.c.h b/Modules/clinic/selectmodule.c.h index f44ca1d7..086fab5b 100644 --- a/Modules/clinic/selectmodule.c.h +++ b/Modules/clinic/selectmodule.c.h @@ -24,7 +24,7 @@ PyDoc_STRVAR(select_select__doc__, "gotten from a fileno() method call on one of those.\n" "\n" "The optional 4th argument specifies a timeout in seconds; it may be\n" -"a floating point number to specify fractions of seconds. If it is absent\n" +"a floating-point number to specify fractions of seconds. If it is absent\n" "or None, the call will never time out.\n" "\n" "The return value is a tuple of three lists corresponding to the first three\n" @@ -1309,4 +1309,4 @@ select_kqueue_control(kqueue_queue_Object *self, PyObject *const *args, Py_ssize #ifndef SELECT_KQUEUE_CONTROL_METHODDEF #define SELECT_KQUEUE_CONTROL_METHODDEF #endif /* !defined(SELECT_KQUEUE_CONTROL_METHODDEF) */ -/*[clinic end generated code: output=64516114287e894d input=a9049054013a1b77]*/ +/*[clinic end generated code: output=4d031b2402ee40e7 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/signalmodule.c.h b/Modules/clinic/signalmodule.c.h index 3b3c6ba1..7206298c 100644 --- a/Modules/clinic/signalmodule.c.h +++ b/Modules/clinic/signalmodule.c.h @@ -526,7 +526,7 @@ PyDoc_STRVAR(signal_sigtimedwait__doc__, "\n" "Like sigwaitinfo(), but with a timeout.\n" "\n" -"The timeout is specified in seconds, with floating point numbers allowed."); +"The timeout is specified in seconds, with floating-point numbers allowed."); #define SIGNAL_SIGTIMEDWAIT_METHODDEF \ {"sigtimedwait", _PyCFunction_CAST(signal_sigtimedwait), METH_FASTCALL, signal_sigtimedwait__doc__}, @@ -705,4 +705,4 @@ signal_pidfd_send_signal(PyObject *module, PyObject *const *args, Py_ssize_t nar #ifndef SIGNAL_PIDFD_SEND_SIGNAL_METHODDEF #define SIGNAL_PIDFD_SEND_SIGNAL_METHODDEF #endif /* !defined(SIGNAL_PIDFD_SEND_SIGNAL_METHODDEF) */ -/*[clinic end generated code: output=2b54dc607f6e3146 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=29cc8fb029d04c97 input=a9049054013a1b77]*/ diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h index c2770be3..523b37d8 100644 --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -130,7 +130,9 @@ enum XML_Error { /* Added in 2.3.0. */ XML_ERROR_NO_BUFFER, /* Added in 2.4.0. */ - XML_ERROR_AMPLIFICATION_LIMIT_BREACH + XML_ERROR_AMPLIFICATION_LIMIT_BREACH, + /* Added in 2.6.4. */ + XML_ERROR_NOT_STARTED, }; enum XML_Content_Type { @@ -1066,7 +1068,7 @@ XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled); */ #define XML_MAJOR_VERSION 2 #define XML_MINOR_VERSION 6 -#define XML_MICRO_VERSION 2 +#define XML_MICRO_VERSION 4 #ifdef __cplusplus } diff --git a/Modules/expat/expat_external.h b/Modules/expat/expat_external.h index 12c560e1..567872b0 100644 --- a/Modules/expat/expat_external.h +++ b/Modules/expat/expat_external.h @@ -40,6 +40,10 @@ #ifndef Expat_External_INCLUDED #define Expat_External_INCLUDED 1 +/* Namespace external symbols to allow multiple libexpat version to + co-exist. */ +#include "pyexpatns.h" + /* External API definitions */ /* Expat tries very hard to make the API boundary very specifically @@ -64,11 +68,6 @@ compiled with the cdecl calling convention as the default since system headers may assume the cdecl convention. */ - -/* Namespace external symbols to allow multiple libexpat version to - co-exist. */ -#include "pyexpatns.h" - #ifndef XMLCALL # if defined(_MSC_VER) # define XMLCALL __cdecl diff --git a/Modules/expat/refresh.sh b/Modules/expat/refresh.sh new file mode 100755 index 00000000..82a9dbc2 --- /dev/null +++ b/Modules/expat/refresh.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +# +# Use this script to update libexpat + +set -e +set -o pipefail + +if [[ "${BASH_VERSINFO[0]}" -lt 4 ]]; then + echo "A bash version >= 4 required. Got: $BASH_VERSION" >&2 + exit 1 +fi + +# Update this when updating to a new version after verifying that the changes +# the update brings in are good. These values are used for verifying the SBOM, too. +expected_libexpat_tag="R_2_6_4" +expected_libexpat_version="2.6.4" +expected_libexpat_sha256="fd03b7172b3bd7427a3e7a812063f74754f24542429b634e0db6511b53fb2278" + +expat_dir="$(realpath "$(dirname -- "${BASH_SOURCE[0]}")")" +cd ${expat_dir} + +# Step 1: download and copy files +curl --location "https://github.com/libexpat/libexpat/releases/download/${expected_libexpat_tag}/expat-${expected_libexpat_version}.tar.gz" > libexpat.tar.gz +echo "${expected_libexpat_sha256} libexpat.tar.gz" | sha256sum --check + +# Step 2: Pull files from the libexpat distribution +declare -a lib_files +lib_files=( + ascii.h + asciitab.h + expat.h + expat_external.h + iasciitab.h + internal.h + latin1tab.h + nametab.h + siphash.h + utf8tab.h + winconfig.h + xmlparse.c + xmlrole.c + xmlrole.h + xmltok.c + xmltok.h + xmltok_impl.c + xmltok_impl.h + xmltok_ns.c +) +for f in "${lib_files[@]}"; do + tar xzvf libexpat.tar.gz "expat-${expected_libexpat_version}/lib/${f}" --strip-components 2 +done +rm libexpat.tar.gz + +# Step 3: Add the namespacing include to expat_external.h +sed -i 's/#define Expat_External_INCLUDED 1/&\n\n\/* Namespace external symbols to allow multiple libexpat version to\n co-exist. \*\/\n#include "pyexpatns.h"/' expat_external.h + +echo "Updated; verify all is okay using git diff and git status." diff --git a/Modules/expat/siphash.h b/Modules/expat/siphash.h index a1ed99e6..04f6f745 100644 --- a/Modules/expat/siphash.h +++ b/Modules/expat/siphash.h @@ -126,8 +126,7 @@ | ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) \ | ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56)) -#define SIPHASH_INITIALIZER \ - { 0, 0, 0, 0, {0}, 0, 0 } +#define SIPHASH_INITIALIZER {0, 0, 0, 0, {0}, 0, 0} struct siphash { uint64_t v0, v1, v2, v3; diff --git a/Modules/expat/xmlparse.c b/Modules/expat/xmlparse.c index 2951fec7..a4e091e7 100644 --- a/Modules/expat/xmlparse.c +++ b/Modules/expat/xmlparse.c @@ -1,4 +1,4 @@ -/* 2a14271ad4d35e82bde8ba210b4edb7998794bcbae54deab114046a300f9639a (2.6.2+) +/* c5625880f4bf417c1463deee4eb92d86ff413f802048621c57e25fe483eb59e4 (2.6.4+) __ __ _ ___\ \/ /_ __ __ _| |_ / _ \\ /| '_ \ / _` | __| @@ -39,6 +39,8 @@ Copyright (c) 2022 Sean McBride Copyright (c) 2023 Owain Davies Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow + Copyright (c) 2024 Berkay Eren Ürün + Copyright (c) 2024 Hanno Böck Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -294,7 +296,7 @@ typedef struct { The name of the element is stored in both the document and API encodings. The memory buffer 'buf' is a separately-allocated memory area which stores the name. During the XML_Parse()/ - XMLParseBuffer() when the element is open, the memory for the 'raw' + XML_ParseBuffer() when the element is open, the memory for the 'raw' version of the name (in the document encoding) is shared with the document buffer. If the element is open across calls to XML_Parse()/XML_ParseBuffer(), the buffer is re-allocated to @@ -2038,6 +2040,12 @@ XML_ParseBuffer(XML_Parser parser, int len, int isFinal) { if (parser == NULL) return XML_STATUS_ERROR; + + if (len < 0) { + parser->m_errorCode = XML_ERROR_INVALID_ARGUMENT; + return XML_STATUS_ERROR; + } + switch (parser->m_parsingStatus.parsing) { case XML_SUSPENDED: parser->m_errorCode = XML_ERROR_SUSPENDED; @@ -2227,6 +2235,9 @@ XML_StopParser(XML_Parser parser, XML_Bool resumable) { if (parser == NULL) return XML_STATUS_ERROR; switch (parser->m_parsingStatus.parsing) { + case XML_INITIALIZED: + parser->m_errorCode = XML_ERROR_NOT_STARTED; + return XML_STATUS_ERROR; case XML_SUSPENDED: if (resumable) { parser->m_errorCode = XML_ERROR_SUSPENDED; @@ -2237,7 +2248,7 @@ XML_StopParser(XML_Parser parser, XML_Bool resumable) { case XML_FINISHED: parser->m_errorCode = XML_ERROR_FINISHED; return XML_STATUS_ERROR; - default: + case XML_PARSING: if (resumable) { #ifdef XML_DTD if (parser->m_isParamEntity) { @@ -2248,6 +2259,9 @@ XML_StopParser(XML_Parser parser, XML_Bool resumable) { parser->m_parsingStatus.parsing = XML_SUSPENDED; } else parser->m_parsingStatus.parsing = XML_FINISHED; + break; + default: + assert(0); } return XML_STATUS_OK; } @@ -2512,6 +2526,9 @@ XML_ErrorString(enum XML_Error code) { case XML_ERROR_AMPLIFICATION_LIMIT_BREACH: return XML_L( "limit on input amplification factor (from DTD and entities) breached"); + /* Added in 2.6.4. */ + case XML_ERROR_NOT_STARTED: + return XML_L("parser not started"); } return NULL; } @@ -5846,18 +5863,17 @@ processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) { /* Set a safe default value in case 'next' does not get set */ next = textStart; -#ifdef XML_DTD if (entity->is_param) { int tok = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next); result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd, tok, next, &next, XML_FALSE, XML_FALSE, XML_ACCOUNT_ENTITY_EXPANSION); - } else -#endif /* XML_DTD */ + } else { result = doContent(parser, parser->m_tagLevel, parser->m_internalEncoding, textStart, textEnd, &next, XML_FALSE, XML_ACCOUNT_ENTITY_EXPANSION); + } if (result == XML_ERROR_NONE) { if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) { @@ -5894,18 +5910,17 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end, /* Set a safe default value in case 'next' does not get set */ next = textStart; -#ifdef XML_DTD if (entity->is_param) { int tok = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next); result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd, tok, next, &next, XML_FALSE, XML_TRUE, XML_ACCOUNT_ENTITY_EXPANSION); - } else -#endif /* XML_DTD */ + } else { result = doContent(parser, openEntity->startTagLevel, parser->m_internalEncoding, textStart, textEnd, &next, XML_FALSE, XML_ACCOUNT_ENTITY_EXPANSION); + } if (result != XML_ERROR_NONE) return result; @@ -5932,7 +5947,6 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end, return XML_ERROR_NONE; } -#ifdef XML_DTD if (entity->is_param) { int tok; parser->m_processor = prologProcessor; @@ -5940,9 +5954,7 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end, return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr, (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE, XML_ACCOUNT_DIRECT); - } else -#endif /* XML_DTD */ - { + } else { parser->m_processor = contentProcessor; /* see externalEntityContentProcessor vs contentProcessor */ result = doContent(parser, parser->m_parentParser ? 1 : 0, @@ -7016,6 +7028,16 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, if (! newE) return 0; if (oldE->nDefaultAtts) { + /* Detect and prevent integer overflow. + * The preprocessor guard addresses the "always false" warning + * from -Wtype-limits on platforms where + * sizeof(int) < sizeof(size_t), e.g. on x86_64. */ +#if UINT_MAX >= SIZE_MAX + if ((size_t)oldE->nDefaultAtts + > ((size_t)(-1) / sizeof(DEFAULT_ATTRIBUTE))) { + return 0; + } +#endif newE->defaultAtts = ms->malloc_fcn(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE)); if (! newE->defaultAtts) { @@ -7558,6 +7580,15 @@ nextScaffoldPart(XML_Parser parser) { int next; if (! dtd->scaffIndex) { + /* Detect and prevent integer overflow. + * The preprocessor guard addresses the "always false" warning + * from -Wtype-limits on platforms where + * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ +#if UINT_MAX >= SIZE_MAX + if (parser->m_groupSize > ((size_t)(-1) / sizeof(int))) { + return -1; + } +#endif dtd->scaffIndex = (int *)MALLOC(parser, parser->m_groupSize * sizeof(int)); if (! dtd->scaffIndex) return -1; @@ -7835,7 +7866,7 @@ accountingReportDiff(XML_Parser rootParser, assert(! rootParser->m_parentParser); fprintf(stderr, - " (+" EXPAT_FMT_PTRDIFF_T("6") " bytes %s|%d, xmlparse.c:%d) %*s\"", + " (+" EXPAT_FMT_PTRDIFF_T("6") " bytes %s|%u, xmlparse.c:%d) %*s\"", bytesMore, (account == XML_ACCOUNT_DIRECT) ? "DIR" : "EXP", levelsAwayFromRootParser, source_line, 10, ""); @@ -7948,7 +7979,7 @@ entityTrackingReportStats(XML_Parser rootParser, ENTITY *entity, fprintf( stderr, - "expat: Entities(%p): Count %9d, depth %2d/%2d %*s%s%s; %s length %d (xmlparse.c:%d)\n", + "expat: Entities(%p): Count %9u, depth %2u/%2u %*s%s%s; %s length %d (xmlparse.c:%d)\n", (void *)rootParser, rootParser->m_entity_stats.countEverOpened, rootParser->m_entity_stats.currentDepth, rootParser->m_entity_stats.maximumDepthSeen, diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c index da26b7bc..96cc6d8c 100644 --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -70,7 +70,7 @@ static fault_handler_t faulthandler_handlers[] = { #ifdef SIGILL {SIGILL, 0, "Illegal instruction", }, #endif - {SIGFPE, 0, "Floating point exception", }, + {SIGFPE, 0, "Floating-point exception", }, {SIGABRT, 0, "Aborted", }, /* define SIGSEGV at the end to make it the default choice if searching the handler fails in faulthandler_fatal_error() */ diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index f8c774cb..e14d9d58 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2174,6 +2174,13 @@ _PyGC_DumpShutdownStats(PyInterpreterState *interp) } } +static void +finalize_unlink_gc_head(PyGC_Head *gc) { + PyGC_Head *prev = GC_PREV(gc); + PyGC_Head *next = GC_NEXT(gc); + _PyGCHead_SET_NEXT(prev, next); + _PyGCHead_SET_PREV(next, prev); +} void _PyGC_Fini(PyInterpreterState *interp) @@ -2182,9 +2189,25 @@ _PyGC_Fini(PyInterpreterState *interp) Py_CLEAR(gcstate->garbage); Py_CLEAR(gcstate->callbacks); - /* We expect that none of this interpreters objects are shared - with other interpreters. - See https://github.com/python/cpython/issues/90228. */ + /* Prevent a subtle bug that affects sub-interpreters that use basic + * single-phase init extensions (m_size == -1). Those extensions cause objects + * to be shared between interpreters, via the PyDict_Update(mdict, m_copy) call + * in import_find_extension(). + * + * If they are GC objects, their GC head next or prev links could refer to + * the interpreter _gc_runtime_state PyGC_Head nodes. Those nodes go away + * when the interpreter structure is freed and so pointers to them become + * invalid. If those objects are still used by another interpreter and + * UNTRACK is called on them, a crash will happen. We untrack the nodes + * here to avoid that. + * + * This bug was originally fixed when reported as gh-90228. The bug was + * re-introduced in gh-94673. + */ + for (int i = 0; i < NUM_GENERATIONS; i++) { + finalize_unlink_gc_head(&gcstate->generations[i].head); + } + finalize_unlink_gc_head(&gcstate->permanent_generation.head); } /* for debugging */ diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index d42f9dd0..12708f49 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -1137,7 +1137,7 @@ itertools_tee_impl(PyObject *module, PyObject *iterable, Py_ssize_t n) /*[clinic end generated code: output=1c64519cd859c2f0 input=c99a1472c425d66d]*/ { Py_ssize_t i; - PyObject *it, *copyable, *copyfunc, *result; + PyObject *it, *to, *result; if (n < 0) { PyErr_SetString(PyExc_ValueError, "n must be >= 0"); @@ -1154,41 +1154,24 @@ itertools_tee_impl(PyObject *module, PyObject *iterable, Py_ssize_t n) return NULL; } - if (_PyObject_LookupAttr(it, &_Py_ID(__copy__), ©func) < 0) { - Py_DECREF(it); + (void)&_Py_ID(__copy__); // Retain a reference to __copy__ + itertools_state *state = get_module_state(module); + to = tee_fromiterable(state, it); + Py_DECREF(it); + if (to == NULL) { Py_DECREF(result); return NULL; } - if (copyfunc != NULL) { - copyable = it; - } - else { - itertools_state *state = get_module_state(module); - copyable = tee_fromiterable(state, it); - Py_DECREF(it); - if (copyable == NULL) { - Py_DECREF(result); - return NULL; - } - copyfunc = PyObject_GetAttr(copyable, &_Py_ID(__copy__)); - if (copyfunc == NULL) { - Py_DECREF(copyable); - Py_DECREF(result); - return NULL; - } - } - PyTuple_SET_ITEM(result, 0, copyable); + PyTuple_SET_ITEM(result, 0, to); for (i = 1; i < n; i++) { - copyable = _PyObject_CallNoArgs(copyfunc); - if (copyable == NULL) { - Py_DECREF(copyfunc); + to = tee_copy((teeobject *)to, NULL); + if (to == NULL) { Py_DECREF(result); return NULL; } - PyTuple_SET_ITEM(result, i, copyable); + PyTuple_SET_ITEM(result, i, to); } - Py_DECREF(copyfunc); return result; } @@ -3998,7 +3981,7 @@ typedef struct { fast_mode: when cnt an integer < PY_SSIZE_T_MAX and no step is specified. - assert(cnt != PY_SSIZE_T_MAX && long_cnt == NULL && long_step==PyLong(1)); + assert(long_cnt == NULL && long_step==PyLong(1)); Advances with: cnt += 1 When count hits Y_SSIZE_T_MAX, switch to slow_mode. @@ -4085,7 +4068,7 @@ itertools_count_impl(PyTypeObject *type, PyObject *long_cnt, else cnt = PY_SSIZE_T_MAX; - assert((cnt != PY_SSIZE_T_MAX && long_cnt == NULL && fast_mode) || + assert((long_cnt == NULL && fast_mode) || (cnt == PY_SSIZE_T_MAX && long_cnt != NULL && !fast_mode)); assert(!fast_mode || (PyLong_Check(long_step) && PyLong_AS_LONG(long_step) == 1)); @@ -4157,7 +4140,7 @@ count_next(countobject *lz) static PyObject * count_repr(countobject *lz) { - if (lz->cnt != PY_SSIZE_T_MAX) + if (lz->long_cnt == NULL) return PyUnicode_FromFormat("%s(%zd)", _PyType_Name(Py_TYPE(lz)), lz->cnt); diff --git a/Modules/main.c b/Modules/main.c index 1b189b45..b602272b 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -540,6 +540,10 @@ pymain_repl(PyConfig *config, int *exitcode) return; } + if (PySys_Audit("cpython.run_stdin", NULL) < 0) { + return; + } + PyCompilerFlags cf = _PyCompilerFlags_INIT; int res = PyRun_AnyFileFlags(stdin, "", &cf); *exitcode = (res != 0); diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index bbd6bd01..d856ff6c 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -106,7 +106,7 @@ typedef struct{ double hi; double lo; } DoubleLength; static DoubleLength dl_fast_sum(double a, double b) { - /* Algorithm 1.1. Compensated summation of two floating point numbers. */ + /* Algorithm 1.1. Compensated summation of two floating-point numbers. */ assert(fabs(a) >= fabs(b)); double x = a + b; double y = (a - x) + b; @@ -1347,14 +1347,14 @@ math.fsum seq: object / -Return an accurate floating point sum of values in the iterable seq. +Return an accurate floating-point sum of values in the iterable seq. -Assumes IEEE-754 floating point arithmetic. +Assumes IEEE-754 floating-point arithmetic. [clinic start generated code]*/ static PyObject * math_fsum(PyObject *module, PyObject *seq) -/*[clinic end generated code: output=ba5c672b87fe34fc input=c51b7d8caf6f6e82]*/ +/*[clinic end generated code: output=ba5c672b87fe34fc input=4506244ded6057dc]*/ { PyObject *item, *iter, *sum = NULL; Py_ssize_t i, j, n = 0, m = NUM_PARTIALS; @@ -2343,6 +2343,15 @@ math_fmod_impl(PyObject *module, double x, double y) return PyFloat_FromDouble(x); errno = 0; r = fmod(x, y); +#ifdef _MSC_VER + /* Windows (e.g. Windows 10 with MSC v.1916) loose sign + for zero result. But C99+ says: "if y is nonzero, the result + has the same sign as x". + */ + if (r == 0.0 && y != 0.0) { + r = copysign(r, x); + } +#endif if (Py_IS_NAN(r)) { if (!Py_IS_NAN(x) && !Py_IS_NAN(y)) errno = EDOM; @@ -2411,7 +2420,7 @@ Since lo**2 is less than 1/2 ulp(csum), we have csum+lo*lo == csum. To minimize loss of information during the accumulation of fractional values, each term has a separate accumulator. This also breaks up sequential dependencies in the inner loop so the CPU can maximize -floating point throughput. [4] On an Apple M1 Max, hypot(*vec) +floating-point throughput. [4] On an Apple M1 Max, hypot(*vec) takes only 3.33 µsec when len(vec) == 1000. The square root differential correction is needed because a @@ -3093,7 +3102,7 @@ math.isclose -> bool maximum difference for being considered "close", regardless of the magnitude of the input values -Determine whether two floating point numbers are close in value. +Determine whether two floating-point numbers are close in value. Return True if a is close in value to b, and False otherwise. @@ -3108,7 +3117,7 @@ only close to themselves. static int math_isclose_impl(PyObject *module, double a, double b, double rel_tol, double abs_tol) -/*[clinic end generated code: output=b73070207511952d input=f28671871ea5bfba]*/ +/*[clinic end generated code: output=b73070207511952d input=12d41764468bfdb8]*/ { double diff = 0.0; diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 9cc53c86..d5298519 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -24,6 +24,7 @@ #include "pycore_object.h" // _PyObject_LookupSpecial() #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_signal.h" // Py_NSIG +#include "pycore_typeobject.h" // _PyType_AddMethod() #ifdef MS_WINDOWS # include @@ -5209,7 +5210,6 @@ _testFileType(path_t *path, int testedType) os._path_exists -> bool path: path_t(allow_fd=True, suppress_value_error=True) - / Test whether a path exists. Returns False for broken symbolic links. @@ -5217,7 +5217,7 @@ Test whether a path exists. Returns False for broken symbolic links. static int os__path_exists_impl(PyObject *module, path_t *path) -/*[clinic end generated code: output=8da13acf666e16ba input=29198507a6082a57]*/ +/*[clinic end generated code: output=8da13acf666e16ba input=142beabfc66783eb]*/ { return _testFileExists(path, TRUE); } @@ -7579,6 +7579,7 @@ os_register_at_fork_impl(PyObject *module, PyObject *before, } #endif /* HAVE_FORK */ +#if defined(HAVE_FORK1) || defined(HAVE_FORKPTY) || defined(HAVE_FORK) // Common code to raise a warning if we detect there is more than one thread // running in the process. Best effort, silent if unable to count threads. // Constraint: Quick. Never overcounts. Never leaves an error set. @@ -7677,6 +7678,7 @@ static void warn_about_fork_with_threads(const char* name) { PyErr_Clear(); } } +#endif // HAVE_FORK1 || HAVE_FORKPTY || HAVE_FORK #ifdef HAVE_FORK1 /*[clinic input] @@ -7865,6 +7867,16 @@ os_sched_param_impl(PyTypeObject *type, PyObject *sched_priority) return res; } +static PyObject * +os_sched_param_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return Py_BuildValue("(O(N))", Py_TYPE(self), PyStructSequence_GetItem(self, 0)); +} + +static PyMethodDef os_sched_param_reduce_method = { + "__reduce__", (PyCFunction)os_sched_param_reduce, METH_NOARGS|METH_COEXIST, NULL, +}; + PyDoc_VAR(os_sched_param__doc__); static PyStructSequence_Field sched_param_fields[] = { @@ -10054,12 +10066,12 @@ Return a collection containing process timing information. The object returned behaves like a named tuple with these fields: (utime, stime, cutime, cstime, elapsed_time) -All fields are floating point numbers. +All fields are floating-point numbers. [clinic start generated code]*/ static PyObject * os_times_impl(PyObject *module) -/*[clinic end generated code: output=35f640503557d32a input=2bf9df3d6ab2e48b]*/ +/*[clinic end generated code: output=35f640503557d32a input=8dbfe33a2dcc3df3]*/ #ifdef MS_WINDOWS { FILETIME create, exit, kernel, user; @@ -11783,6 +11795,7 @@ os_mknod_impl(PyObject *module, path_t *path, int mode, dev_t device, #endif /* defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV) */ +#ifdef HAVE_DEVICE_MACROS static PyObject * major_minor_conv(unsigned int value) { @@ -11805,7 +11818,6 @@ major_minor_check(dev_t value) return (dev_t)(unsigned int)value == value; } -#ifdef HAVE_DEVICE_MACROS /*[clinic input] os.major @@ -17000,6 +17012,12 @@ posixmodule_exec(PyObject *m) return -1; } ((PyTypeObject *)state->SchedParamType)->tp_new = os_sched_param; + if (_PyType_AddMethod((PyTypeObject *)state->SchedParamType, + &os_sched_param_reduce_method) < 0) + { + return -1; + } + PyType_Modified((PyTypeObject *)state->SchedParamType); #endif /* initialize TerminalSize_info */ diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c index 97f1db20..50788e53 100644 --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -263,7 +263,7 @@ A file descriptor is either a socket or file object, or a small integer gotten from a fileno() method call on one of those. The optional 4th argument specifies a timeout in seconds; it may be -a floating point number to specify fractions of seconds. If it is absent +a floating-point number to specify fractions of seconds. If it is absent or None, the call will never time out. The return value is a tuple of three lists corresponding to the first three @@ -278,7 +278,7 @@ descriptors can be used. static PyObject * select_select_impl(PyObject *module, PyObject *rlist, PyObject *wlist, PyObject *xlist, PyObject *timeout_obj) -/*[clinic end generated code: output=2b3cfa824f7ae4cf input=e467f5d68033de00]*/ +/*[clinic end generated code: output=2b3cfa824f7ae4cf input=1199d5e101abca4a]*/ { #ifdef SELECT_USES_HEAP pylist *rfd2obj, *wfd2obj, *efd2obj; diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index 00ea4343..4f4e6a39 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -637,7 +637,7 @@ signal_strsignal_impl(PyObject *module, int signalnum) res = "Aborted"; break; case SIGFPE: - res = "Floating point exception"; + res = "Floating-point exception"; break; case SIGSEGV: res = "Segmentation fault"; @@ -1199,13 +1199,13 @@ signal.sigtimedwait Like sigwaitinfo(), but with a timeout. -The timeout is specified in seconds, with floating point numbers allowed. +The timeout is specified in seconds, with floating-point numbers allowed. [clinic start generated code]*/ static PyObject * signal_sigtimedwait_impl(PyObject *module, sigset_t sigset, PyObject *timeout_obj) -/*[clinic end generated code: output=59c8971e8ae18a64 input=87fd39237cf0b7ba]*/ +/*[clinic end generated code: output=59c8971e8ae18a64 input=955773219c1596cd]*/ { _PyTime_t timeout; if (_PyTime_FromSecondsObject(&timeout, diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 97248792..7f2ebba9 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -816,7 +816,9 @@ internal_select(PySocketSockObject *s, int writing, _PyTime_t interval, /* s->sock_timeout is in seconds, timeout in ms */ ms = _PyTime_AsMilliseconds(interval, _PyTime_ROUND_CEILING); - assert(ms <= INT_MAX); + if (ms > INT_MAX) { + ms = INT_MAX; + } /* On some OSes, typically BSD-based ones, the timeout parameter of the poll() syscall, when negative, must be exactly INFTIM, where defined, @@ -828,6 +830,7 @@ internal_select(PySocketSockObject *s, int writing, _PyTime_t interval, ms = -1; #endif } + assert(INT_MIN <= ms && ms <= INT_MAX); Py_BEGIN_ALLOW_THREADS; n = poll(&pollfd, 1, (int)ms); diff --git a/Modules/timemodule.c b/Modules/timemodule.c index 9038c372..59078263 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -159,7 +159,7 @@ time_time(PyObject *self, PyObject *unused) PyDoc_STRVAR(time_doc, -"time() -> floating point number\n\ +"time() -> floating-point number\n\ \n\ Return the current time in seconds since the Epoch.\n\ Fractions of a second may be present if the system clock provides them."); @@ -373,7 +373,7 @@ time_clock_getres(PyObject *self, PyObject *args) } PyDoc_STRVAR(clock_getres_doc, -"clock_getres(clk_id) -> floating point number\n\ +"clock_getres(clk_id) -> floating-point number\n\ \n\ Return the resolution (precision) of the specified clock clk_id."); @@ -432,7 +432,7 @@ PyDoc_STRVAR(sleep_doc, "sleep(seconds)\n\ \n\ Delay execution for a given number of seconds. The argument may be\n\ -a floating point number for subsecond precision."); +a floating-point number for subsecond precision."); static PyStructSequence_Field struct_time_type_fields[] = { {"tm_year", "year, for example, 1993"}, @@ -795,27 +795,100 @@ the C library strftime function.\n" #endif static PyObject * -time_strftime(PyObject *module, PyObject *args) +time_strftime1(time_char **outbuf, size_t *bufsize, + time_char *format, size_t fmtlen, + struct tm *tm) { - PyObject *tup = NULL; - struct tm buf; - const time_char *fmt; + size_t buflen; +#if defined(MS_WINDOWS) && !defined(HAVE_WCSFTIME) + /* check that the format string contains only valid directives */ + for (const time_char *f = strchr(format, '%'); + f != NULL; + f = strchr(f + 2, '%')) + { + if (f[1] == '#') + ++f; /* not documented by python, */ + if (f[1] == '\0') + break; + if ((f[1] == 'y') && tm->tm_year < 0) { + PyErr_SetString(PyExc_ValueError, + "format %y requires year >= 1900 on Windows"); + return NULL; + } + } +#elif (defined(_AIX) || (defined(__sun) && defined(__SVR4))) && defined(HAVE_WCSFTIME) + for (const time_char *f = wcschr(format, '%'); + f != NULL; + f = wcschr(f + 2, '%')) + { + if (f[1] == L'\0') + break; + /* Issue #19634: On AIX, wcsftime("y", (1899, 1, 1, 0, 0, 0, 0, 0, 0)) + returns "0/" instead of "99" */ + if (f[1] == L'y' && tm->tm_year < 0) { + PyErr_SetString(PyExc_ValueError, + "format %y requires year >= 1900 on AIX"); + return NULL; + } + } +#endif + + /* I hate these functions that presume you know how big the output + * will be ahead of time... + */ + while (1) { + if (*bufsize > PY_SSIZE_T_MAX/sizeof(time_char)) { + PyErr_NoMemory(); + return NULL; + } + *outbuf = (time_char *)PyMem_Realloc(*outbuf, + *bufsize*sizeof(time_char)); + if (*outbuf == NULL) { + PyErr_NoMemory(); + return NULL; + } +#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) + errno = 0; +#endif + _Py_BEGIN_SUPPRESS_IPH + buflen = format_time(*outbuf, *bufsize, format, tm); + _Py_END_SUPPRESS_IPH +#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) + /* VisualStudio .NET 2005 does this properly */ + if (buflen == 0 && errno == EINVAL) { + PyErr_SetString(PyExc_ValueError, "Invalid format string"); + return NULL; + } +#endif + if (buflen == 0 && *bufsize < 256 * fmtlen) { + *bufsize += *bufsize; + continue; + } + /* If the buffer is 256 times as long as the format, + it's probably not failing for lack of room! + More likely, the format yields an empty result, + e.g. an empty format, or %Z when the timezone + is unknown. */ #ifdef HAVE_WCSFTIME - wchar_t *format; + return PyUnicode_FromWideChar(*outbuf, buflen); #else - PyObject *format; + return PyUnicode_DecodeLocaleAndSize(*outbuf, buflen, "surrogateescape"); #endif + } +} + +static PyObject * +time_strftime(PyObject *module, PyObject *args) +{ + PyObject *tup = NULL; + struct tm buf; PyObject *format_arg; - size_t fmtlen, buflen; - time_char *outbuf = NULL; - size_t i; - PyObject *ret = NULL; + Py_ssize_t format_size; + time_char *format, *outbuf = NULL; + size_t fmtlen, bufsize = 1024; memset((void *) &buf, '\0', sizeof(buf)); - /* Will always expect a unicode string to be passed as format. - Given that there's no str type anymore in py3k this seems safe. - */ if (!PyArg_ParseTuple(args, "U|O:strftime", &format_arg, &tup)) return NULL; @@ -848,101 +921,65 @@ time_strftime(PyObject *module, PyObject *args) else if (buf.tm_isdst > 1) buf.tm_isdst = 1; -#ifdef HAVE_WCSFTIME - format = PyUnicode_AsWideCharString(format_arg, NULL); - if (format == NULL) + format_size = PyUnicode_GET_LENGTH(format_arg); + if ((size_t)format_size > PY_SSIZE_T_MAX/sizeof(time_char) - 1) { + PyErr_NoMemory(); return NULL; - fmt = format; -#else - /* Convert the unicode string to an ascii one */ - format = PyUnicode_EncodeLocale(format_arg, "surrogateescape"); - if (format == NULL) + } + format = PyMem_Malloc((format_size + 1)*sizeof(time_char)); + if (format == NULL) { + PyErr_NoMemory(); return NULL; - fmt = PyBytes_AS_STRING(format); -#endif - -#if defined(MS_WINDOWS) && !defined(HAVE_WCSFTIME) - /* check that the format string contains only valid directives */ - for (outbuf = strchr(fmt, '%'); - outbuf != NULL; - outbuf = strchr(outbuf+2, '%')) - { - if (outbuf[1] == '#') - ++outbuf; /* not documented by python, */ - if (outbuf[1] == '\0') - break; - if ((outbuf[1] == 'y') && buf.tm_year < 0) { - PyErr_SetString(PyExc_ValueError, - "format %y requires year >= 1900 on Windows"); - Py_DECREF(format); - return NULL; - } } -#elif (defined(_AIX) || (defined(__sun) && defined(__SVR4))) && defined(HAVE_WCSFTIME) - for (outbuf = wcschr(fmt, '%'); - outbuf != NULL; - outbuf = wcschr(outbuf+2, '%')) - { - if (outbuf[1] == L'\0') - break; - /* Issue #19634: On AIX, wcsftime("y", (1899, 1, 1, 0, 0, 0, 0, 0, 0)) - returns "0/" instead of "99" */ - 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; + _PyUnicodeWriter writer; + _PyUnicodeWriter_Init(&writer); + writer.overallocate = 1; + Py_ssize_t i = 0; + while (i < format_size) { + fmtlen = 0; + for (; i < format_size; i++) { + Py_UCS4 c = PyUnicode_READ_CHAR(format_arg, i); + if (!c || c > 127) { + break; + } + format[fmtlen++] = (char)c; } - } -#endif - - fmtlen = time_strlen(fmt); - - /* I hate these functions that presume you know how big the output - * will be ahead of time... - */ - for (i = 1024; ; i += i) { - outbuf = (time_char *)PyMem_Malloc(i*sizeof(time_char)); - if (outbuf == NULL) { - PyErr_NoMemory(); - break; + if (fmtlen) { + format[fmtlen] = 0; + PyObject *unicode = time_strftime1(&outbuf, &bufsize, + format, fmtlen, &buf); + if (unicode == NULL) { + goto error; + } + if (_PyUnicodeWriter_WriteStr(&writer, unicode) < 0) { + Py_DECREF(unicode); + goto error; + } + Py_DECREF(unicode); } -#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) - errno = 0; -#endif - _Py_BEGIN_SUPPRESS_IPH - buflen = format_time(outbuf, i, fmt, &buf); - _Py_END_SUPPRESS_IPH -#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) - /* VisualStudio .NET 2005 does this properly */ - if (buflen == 0 && errno == EINVAL) { - PyErr_SetString(PyExc_ValueError, "Invalid format string"); - PyMem_Free(outbuf); - break; + + Py_ssize_t start = i; + for (; i < format_size; i++) { + Py_UCS4 c = PyUnicode_READ_CHAR(format_arg, i); + if (c == '%') { + break; + } } -#endif - if (buflen > 0 || i >= 256 * fmtlen) { - /* If the buffer is 256 times as long as the format, - it's probably not failing for lack of room! - More likely, the format yields an empty result, - e.g. an empty format, or %Z when the timezone - is unknown. */ -#ifdef HAVE_WCSFTIME - ret = PyUnicode_FromWideChar(outbuf, buflen); -#else - ret = PyUnicode_DecodeLocaleAndSize(outbuf, buflen, "surrogateescape"); -#endif - PyMem_Free(outbuf); - break; + if (start < i) { + if (_PyUnicodeWriter_WriteSubstring(&writer, format_arg, start, i) < 0) { + goto error; + } } - PyMem_Free(outbuf); } -#ifdef HAVE_WCSFTIME + + PyMem_Free(outbuf); PyMem_Free(format); -#else - Py_DECREF(format); -#endif - return ret; + return _PyUnicodeWriter_Finish(&writer); +error: + PyMem_Free(outbuf); + PyMem_Free(format); + _PyUnicodeWriter_Dealloc(&writer); + return NULL; } #undef time_char @@ -1123,7 +1160,7 @@ time_mktime(PyObject *module, PyObject *tm_tuple) } PyDoc_STRVAR(mktime_doc, -"mktime(tuple) -> floating point number\n\ +"mktime(tuple) -> floating-point number\n\ \n\ Convert a time tuple in local time to seconds since the Epoch.\n\ Note that mktime(gmtime(0)) will not generally return zero for most\n\ @@ -1292,8 +1329,14 @@ _PyTime_GetProcessTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info) #else /* clock_gettime */ +// gh-115714: Don't use CLOCK_PROCESS_CPUTIME_ID on WASI. +/* CLOCK_PROF is defined on NetBSD, but not supported. + * CLOCK_PROCESS_CPUTIME_ID is broken on NetBSD for the same reason as + * CLOCK_THREAD_CPUTIME_ID (see comment below). + */ #if defined(HAVE_CLOCK_GETTIME) \ - && (defined(CLOCK_PROCESS_CPUTIME_ID) || defined(CLOCK_PROF)) + && (defined(CLOCK_PROCESS_CPUTIME_ID) || defined(CLOCK_PROF)) \ + && !defined(__NetBSD__) struct timespec ts; if (HAVE_CLOCK_GETTIME_RUNTIME) { @@ -1499,9 +1542,16 @@ _PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info) return 0; } +/* CLOCK_THREAD_CPUTIME_ID is broken on NetBSD: the result of clock_gettime() + * includes the sleeping time, that defeats the purpose of the clock. + * Also, clock_getres() does not support it. + * https://github.com/python/cpython/issues/123978 + * https://gnats.netbsd.org/57512 + */ #elif defined(HAVE_CLOCK_GETTIME) && \ - defined(CLOCK_PROCESS_CPUTIME_ID) && \ - !defined(__EMSCRIPTEN__) && !defined(__wasi__) + defined(CLOCK_THREAD_CPUTIME_ID) && \ + !defined(__EMSCRIPTEN__) && !defined(__wasi__) && \ + !defined(__NetBSD__) #define HAVE_THREAD_TIME #if defined(__APPLE__) && defined(__has_attribute) && __has_attribute(availability) @@ -1913,7 +1963,7 @@ PyDoc_STRVAR(module_doc, \n\ There are two standard representations of time. One is the number\n\ of seconds since the Epoch, in UTC (a.k.a. GMT). It may be an integer\n\ -or a floating point number (to represent fractions of seconds).\n\ +or a floating-point number (to represent fractions of seconds).\n\ The epoch is the point where the time starts, the return value of time.gmtime(0).\n\ It is January 1, 1970, 00:00:00 (UTC) on all platforms.\n\ \n\ diff --git a/Objects/boolobject.c b/Objects/boolobject.c index f43e26f3..74e16dd2 100644 --- a/Objects/boolobject.c +++ b/Objects/boolobject.c @@ -71,8 +71,8 @@ static PyObject * bool_invert(PyObject *v) { if (PyErr_WarnEx(PyExc_DeprecationWarning, - "Bitwise inversion '~' on bool is deprecated. This " - "returns the bitwise inversion of the underlying int " + "Bitwise inversion '~' on bool is deprecated and will be removed in " + "Python 3.16. This returns the bitwise inversion of the underlying int " "object and is usually not what you expect from negating " "a bool. Use the 'not' operator for boolean negation or " "~int(x) if you really want the bitwise inversion of the " diff --git a/Objects/clinic/floatobject.c.h b/Objects/clinic/floatobject.c.h index a99fd74e..ed166538 100644 --- a/Objects/clinic/floatobject.c.h +++ b/Objects/clinic/floatobject.c.h @@ -201,7 +201,7 @@ PyDoc_STRVAR(float_new__doc__, "float(x=0, /)\n" "--\n" "\n" -"Convert a string or number to a floating point number, if possible."); +"Convert a string or number to a floating-point number, if possible."); static PyObject * float_new_impl(PyTypeObject *type, PyObject *x); @@ -260,7 +260,7 @@ PyDoc_STRVAR(float___getformat____doc__, "It exists mainly to be used in Python\'s test suite.\n" "\n" "This function returns whichever of \'unknown\', \'IEEE, big-endian\' or \'IEEE,\n" -"little-endian\' best describes the format of floating point numbers used by the\n" +"little-endian\' best describes the format of floating-point numbers used by the\n" "C type named by typestr."); #define FLOAT___GETFORMAT___METHODDEF \ @@ -325,4 +325,4 @@ float___format__(PyObject *self, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=ea329577074911b9 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=e6e3f5f833b37eba input=a9049054013a1b77]*/ diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 1be66215..7332d4fb 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -132,6 +132,7 @@ all_name_chars(PyObject *o) static int intern_strings(PyObject *tuple) { + PyInterpreterState *interp = _PyInterpreterState_GET(); Py_ssize_t i; for (i = PyTuple_GET_SIZE(tuple); --i >= 0; ) { @@ -141,7 +142,7 @@ intern_strings(PyObject *tuple) "non-string found in code slot"); return -1; } - PyUnicode_InternInPlace(&_PyTuple_ITEMS(tuple)[i]); + _PyUnicode_InternImmortal(interp, &_PyTuple_ITEMS(tuple)[i]); } return 0; } @@ -150,6 +151,7 @@ intern_strings(PyObject *tuple) static int intern_string_constants(PyObject *tuple, int *modified) { + PyInterpreterState *interp = _PyInterpreterState_GET(); for (Py_ssize_t i = PyTuple_GET_SIZE(tuple); --i >= 0; ) { PyObject *v = PyTuple_GET_ITEM(tuple, i); if (PyUnicode_CheckExact(v)) { @@ -159,7 +161,7 @@ intern_string_constants(PyObject *tuple, int *modified) if (all_name_chars(v)) { PyObject *w = v; - PyUnicode_InternInPlace(&v); + _PyUnicode_InternMortal(interp, &v); if (w != v) { PyTuple_SET_ITEM(tuple, i, v); if (modified) { diff --git a/Objects/complexobject.c b/Objects/complexobject.c index 7f7e7e6b..eff17380 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -146,7 +146,7 @@ _Py_c_pow(Py_complex a, Py_complex b) at = atan2(a.imag, a.real); phase = at*b.real; if (b.imag != 0.0) { - len /= exp(at*b.imag); + len *= exp(-at*b.imag); phase += b.imag*log(vabs); } r.real = len*cos(phase); diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 18876fd2..a6c90e7a 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -1788,22 +1788,9 @@ property_init_impl(propertyobject *self, PyObject *fget, PyObject *fset, /* if no docstring given and the getter has one, use that one */ else if (fget != NULL) { int rc = _PyObject_LookupAttr(fget, &_Py_ID(__doc__), &prop_doc); - if (rc <= 0) { + if (rc < 0) { return rc; } - if (!Py_IS_TYPE(self, &PyProperty_Type) && - prop_doc != NULL && prop_doc != Py_None) { - // This oddity preserves the long existing behavior of surfacing - // an AttributeError when using a dict-less (__slots__) property - // subclass as a decorator on a getter method with a docstring. - // See PropertySubclassTest.test_slots_docstring_copy_exception. - int err = PyObject_SetAttr( - (PyObject *)self, &_Py_ID(__doc__), prop_doc); - if (err < 0) { - Py_DECREF(prop_doc); // release our new reference. - return -1; - } - } if (prop_doc == Py_None) { prop_doc = NULL; Py_DECREF(Py_None); @@ -1831,7 +1818,9 @@ property_init_impl(propertyobject *self, PyObject *fget, PyObject *fset, Py_DECREF(prop_doc); if (err < 0) { assert(PyErr_Occurred()); - if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + if (!self->getter_doc && + PyErr_ExceptionMatches(PyExc_AttributeError)) + { PyErr_Clear(); // https://github.com/python/cpython/issues/98963#issuecomment-1574413319 // Python silently dropped this doc assignment through 3.11. diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 254cd9ad..4e965314 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1251,10 +1251,6 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp, MAINTAIN_TRACKING(mp, key, value); if (ix == DKIX_EMPTY) { - uint64_t new_version = _PyDict_NotifyEvent( - interp, PyDict_EVENT_ADDED, mp, key, value); - /* Insert into new slot. */ - mp->ma_keys->dk_version = 0; assert(old_value == NULL); if (mp->ma_keys->dk_usable <= 0) { /* Need to resize. */ @@ -1262,6 +1258,11 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp, goto Fail; } + uint64_t new_version = _PyDict_NotifyEvent( + interp, PyDict_EVENT_ADDED, mp, key, value); + /* Insert into new slot. */ + mp->ma_keys->dk_version = 0; + Py_ssize_t hashpos = find_empty_slot(mp->ma_keys, hash); dictkeys_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries); @@ -1335,9 +1336,6 @@ insert_to_emptydict(PyInterpreterState *interp, PyDictObject *mp, { assert(mp->ma_keys == Py_EMPTY_KEYS); - uint64_t new_version = _PyDict_NotifyEvent( - interp, PyDict_EVENT_ADDED, mp, key, value); - int unicode = PyUnicode_CheckExact(key); PyDictKeysObject *newkeys = new_keys_object( interp, PyDict_LOG_MINSIZE, unicode); @@ -1346,6 +1344,9 @@ insert_to_emptydict(PyInterpreterState *interp, PyDictObject *mp, Py_DECREF(value); return -1; } + uint64_t new_version = _PyDict_NotifyEvent( + interp, PyDict_EVENT_ADDED, mp, key, value); + /* We don't decref Py_EMPTY_KEYS here because it is immortal. */ mp->ma_keys = newkeys; mp->ma_values = NULL; @@ -3324,15 +3325,15 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) return NULL; if (ix == DKIX_EMPTY) { - uint64_t new_version = _PyDict_NotifyEvent( - interp, PyDict_EVENT_ADDED, mp, key, defaultobj); - mp->ma_keys->dk_version = 0; value = defaultobj; if (mp->ma_keys->dk_usable <= 0) { if (insertion_resize(interp, mp, 1) < 0) { return NULL; } } + uint64_t new_version = _PyDict_NotifyEvent( + interp, PyDict_EVENT_ADDED, mp, key, defaultobj); + mp->ma_keys->dk_version = 0; Py_ssize_t hashpos = find_empty_slot(mp->ma_keys, hash); dictkeys_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries); if (DK_IS_UNICODE(mp->ma_keys)) { @@ -3633,8 +3634,8 @@ PyDoc_STRVAR(sizeof__doc__, "D.__sizeof__() -> size of D in memory, in bytes"); PyDoc_STRVAR(update__doc__, -"D.update([E, ]**F) -> None. Update D from dict/iterable E and F.\n\ -If E is present and has a .keys() method, then does: for k in E: D[k] = E[k]\n\ +"D.update([E, ]**F) -> None. Update D from mapping/iterable E and F.\n\ +If E is present and has a .keys() method, then does: for k in E.keys(): D[k] = E[k]\n\ If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v\n\ In either case, this is followed by: for k in F: D[k] = F[k]"); @@ -3915,7 +3916,8 @@ PyDict_SetItemString(PyObject *v, const char *key, PyObject *item) kv = PyUnicode_FromString(key); if (kv == NULL) return -1; - PyUnicode_InternInPlace(&kv); /* XXX Should we really? */ + PyInterpreterState *interp = _PyInterpreterState_GET(); + _PyUnicode_InternImmortal(interp, &kv); /* XXX Should we really? */ err = PyDict_SetItem(v, kv, item); Py_DECREF(kv); return err; diff --git a/Objects/exceptions.c b/Objects/exceptions.c index e3217c92..c579563d 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -2961,46 +2961,55 @@ UnicodeEncodeError_init(PyObject *self, PyObject *args, PyObject *kwds) static PyObject * UnicodeEncodeError_str(PyObject *self) { - PyUnicodeErrorObject *uself = (PyUnicodeErrorObject *)self; + PyUnicodeErrorObject *exc = (PyUnicodeErrorObject *)self; PyObject *result = NULL; PyObject *reason_str = NULL; PyObject *encoding_str = NULL; - if (!uself->object) + if (exc->object == NULL) { /* Not properly initialized. */ return PyUnicode_FromString(""); + } /* Get reason and encoding as strings, which they might not be if they've been modified after we were constructed. */ - reason_str = PyObject_Str(uself->reason); - if (reason_str == NULL) + reason_str = PyObject_Str(exc->reason); + if (reason_str == NULL) { goto done; - encoding_str = PyObject_Str(uself->encoding); - if (encoding_str == NULL) + } + encoding_str = PyObject_Str(exc->encoding); + if (encoding_str == NULL) { goto done; + } + + Py_ssize_t len = PyUnicode_GET_LENGTH(exc->object); + Py_ssize_t start = exc->start, end = exc->end; - if (uself->start < PyUnicode_GET_LENGTH(uself->object) && uself->end == uself->start+1) { - Py_UCS4 badchar = PyUnicode_ReadChar(uself->object, uself->start); + if ((start >= 0 && start < len) && (end >= 0 && end <= len) && end == start + 1) { + Py_UCS4 badchar = PyUnicode_ReadChar(exc->object, start); const char *fmt; - if (badchar <= 0xff) + if (badchar <= 0xff) { fmt = "'%U' codec can't encode character '\\x%02x' in position %zd: %U"; - else if (badchar <= 0xffff) + } + else if (badchar <= 0xffff) { fmt = "'%U' codec can't encode character '\\u%04x' in position %zd: %U"; - else + } + else { fmt = "'%U' codec can't encode character '\\U%08x' in position %zd: %U"; + } result = PyUnicode_FromFormat( fmt, encoding_str, (int)badchar, - uself->start, + start, reason_str); } else { result = PyUnicode_FromFormat( "'%U' codec can't encode characters in position %zd-%zd: %U", encoding_str, - uself->start, - uself->end-1, + start, + end - 1, reason_str); } done: @@ -3074,41 +3083,46 @@ UnicodeDecodeError_init(PyObject *self, PyObject *args, PyObject *kwds) static PyObject * UnicodeDecodeError_str(PyObject *self) { - PyUnicodeErrorObject *uself = (PyUnicodeErrorObject *)self; + PyUnicodeErrorObject *exc = (PyUnicodeErrorObject *)self; PyObject *result = NULL; PyObject *reason_str = NULL; PyObject *encoding_str = NULL; - if (!uself->object) + if (exc->object == NULL) { /* Not properly initialized. */ return PyUnicode_FromString(""); + } /* Get reason and encoding as strings, which they might not be if they've been modified after we were constructed. */ - reason_str = PyObject_Str(uself->reason); - if (reason_str == NULL) + reason_str = PyObject_Str(exc->reason); + if (reason_str == NULL) { goto done; - encoding_str = PyObject_Str(uself->encoding); - if (encoding_str == NULL) + } + encoding_str = PyObject_Str(exc->encoding); + if (encoding_str == NULL) { goto done; + } + + Py_ssize_t len = PyBytes_GET_SIZE(exc->object); + Py_ssize_t start = exc->start, end = exc->end; - if (uself->start < PyBytes_GET_SIZE(uself->object) && uself->end == uself->start+1) { - int byte = (int)(PyBytes_AS_STRING(((PyUnicodeErrorObject *)self)->object)[uself->start]&0xff); + if ((start >= 0 && start < len) && (end >= 0 && end <= len) && end == start + 1) { + int badbyte = (int)(PyBytes_AS_STRING(exc->object)[start] & 0xff); result = PyUnicode_FromFormat( "'%U' codec can't decode byte 0x%02x in position %zd: %U", encoding_str, - byte, - uself->start, + badbyte, + start, reason_str); } else { result = PyUnicode_FromFormat( "'%U' codec can't decode bytes in position %zd-%zd: %U", encoding_str, - uself->start, - uself->end-1, - reason_str - ); + start, + end - 1, + reason_str); } done: Py_XDECREF(reason_str); @@ -3171,42 +3185,49 @@ UnicodeTranslateError_init(PyUnicodeErrorObject *self, PyObject *args, static PyObject * UnicodeTranslateError_str(PyObject *self) { - PyUnicodeErrorObject *uself = (PyUnicodeErrorObject *)self; + PyUnicodeErrorObject *exc = (PyUnicodeErrorObject *)self; PyObject *result = NULL; PyObject *reason_str = NULL; - if (!uself->object) + if (exc->object == NULL) { /* Not properly initialized. */ return PyUnicode_FromString(""); + } /* Get reason as a string, which it might not be if it's been modified after we were constructed. */ - reason_str = PyObject_Str(uself->reason); - if (reason_str == NULL) + reason_str = PyObject_Str(exc->reason); + if (reason_str == NULL) { goto done; + } + + Py_ssize_t len = PyUnicode_GET_LENGTH(exc->object); + Py_ssize_t start = exc->start, end = exc->end; - if (uself->start < PyUnicode_GET_LENGTH(uself->object) && uself->end == uself->start+1) { - Py_UCS4 badchar = PyUnicode_ReadChar(uself->object, uself->start); + if ((start >= 0 && start < len) && (end >= 0 && end <= len) && end == start + 1) { + Py_UCS4 badchar = PyUnicode_ReadChar(exc->object, start); const char *fmt; - if (badchar <= 0xff) + if (badchar <= 0xff) { fmt = "can't translate character '\\x%02x' in position %zd: %U"; - else if (badchar <= 0xffff) + } + else if (badchar <= 0xffff) { fmt = "can't translate character '\\u%04x' in position %zd: %U"; - else + } + else { fmt = "can't translate character '\\U%08x' in position %zd: %U"; + } result = PyUnicode_FromFormat( fmt, (int)badchar, - uself->start, - reason_str - ); - } else { + start, + reason_str); + } + else { result = PyUnicode_FromFormat( "can't translate characters in position %zd-%zd: %U", - uself->start, - uself->end-1, - reason_str - ); + start, + end - 1, + reason_str); } done: Py_XDECREF(reason_str); @@ -3254,7 +3275,7 @@ SimpleExtendsException(PyExc_Exception, ArithmeticError, * FloatingPointError extends ArithmeticError */ SimpleExtendsException(PyExc_ArithmeticError, FloatingPointError, - "Floating point operation failed."); + "Floating-point operation failed."); /* diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 7a882bfd..92d40e8a 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -1644,12 +1644,12 @@ float.__new__ as float_new x: object(c_default="NULL") = 0 / -Convert a string or number to a floating point number, if possible. +Convert a string or number to a floating-point number, if possible. [clinic start generated code]*/ static PyObject * float_new_impl(PyTypeObject *type, PyObject *x) -/*[clinic end generated code: output=ccf1e8dc460ba6ba input=f43661b7de03e9d8]*/ +/*[clinic end generated code: output=ccf1e8dc460ba6ba input=55909f888aa0c8a6]*/ { if (type != &PyFloat_Type) { if (x == NULL) { @@ -1745,13 +1745,13 @@ You probably don't want to use this function. It exists mainly to be used in Python's test suite. This function returns whichever of 'unknown', 'IEEE, big-endian' or 'IEEE, -little-endian' best describes the format of floating point numbers used by the +little-endian' best describes the format of floating-point numbers used by the C type named by typestr. [clinic start generated code]*/ static PyObject * float___getformat___impl(PyTypeObject *type, const char *typestr) -/*[clinic end generated code: output=2bfb987228cc9628 input=d5a52600f835ad67]*/ +/*[clinic end generated code: output=2bfb987228cc9628 input=90d5e246409a246e]*/ { float_format_type r; @@ -1937,7 +1937,7 @@ _init_global_state(void) float_format_type detected_double_format, detected_float_format; /* We attempt to determine if this machine is using IEEE - floating point formats by peering at the bits of some + floating-point formats by peering at the bits of some carefully chosen values. If it looks like we are on an IEEE platform, the float packing/unpacking routines can just copy bits, if not they resort to arithmetic & shifts diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c index 117b4e8d..7f89e683 100644 --- a/Objects/genericaliasobject.c +++ b/Objects/genericaliasobject.c @@ -564,6 +564,10 @@ ga_getitem(PyObject *self, PyObject *item) } PyObject *res = Py_GenericAlias(alias->origin, newargs); + if (res == NULL) { + Py_DECREF(newargs); + return NULL; + } ((gaobject *)res)->starred = alias->starred; Py_DECREF(newargs); diff --git a/Objects/genobject.c b/Objects/genobject.c index dc034a4b..474abe10 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -374,6 +374,7 @@ static PyObject * gen_close(PyGenObject *gen, PyObject *args) { PyObject *retval; + PyObject *yf = _PyGen_yf(gen); int err = 0; if (gen->gi_frame_state == FRAME_CREATED) { @@ -383,7 +384,6 @@ gen_close(PyGenObject *gen, PyObject *args) if (gen->gi_frame_state >= FRAME_COMPLETED) { Py_RETURN_NONE; } - PyObject *yf = _PyGen_yf(gen); if (yf) { PyFrameState state = gen->gi_frame_state; gen->gi_frame_state = FRAME_EXECUTING; @@ -396,14 +396,12 @@ gen_close(PyGenObject *gen, PyObject *args) * YIELD_VALUE if the debugger has changed the lineno. */ if (err == 0 && is_yield(frame->prev_instr)) { assert(is_resume(frame->prev_instr + 1)); - int exception_handler_depth = frame->prev_instr[0].op.arg; + int exception_handler_depth = frame->prev_instr[0].op.code; assert(exception_handler_depth > 0); /* We can safely ignore the outermost try block * as it automatically generated to handle * StopIteration. */ if (exception_handler_depth == 1) { - gen->gi_frame_state = FRAME_COMPLETED; - _PyFrame_ClearLocals((_PyInterpreterFrame *)gen->gi_iframe); Py_RETURN_NONE; } } diff --git a/Objects/listobject.c b/Objects/listobject.c index f59abe2e..d017f34b 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -2759,7 +2759,14 @@ list_richcompare(PyObject *v, PyObject *w, int op) } /* Compare the final item again using the proper operator */ - return PyObject_RichCompare(vl->ob_item[i], wl->ob_item[i], op); + PyObject *vitem = vl->ob_item[i]; + PyObject *witem = wl->ob_item[i]; + Py_INCREF(vitem); + Py_INCREF(witem); + PyObject *result = PyObject_RichCompare(vl->ob_item[i], wl->ob_item[i], op); + Py_DECREF(vitem); + Py_DECREF(witem); + return result; } /*[clinic input] @@ -2928,6 +2935,23 @@ list_subscript(PyListObject* self, PyObject* item) } } +static Py_ssize_t +adjust_slice_indexes(PyListObject *lst, + Py_ssize_t *start, Py_ssize_t *stop, + Py_ssize_t step) +{ + Py_ssize_t slicelength = PySlice_AdjustIndices(Py_SIZE(lst), start, stop, + step); + + /* Make sure s[5:2] = [..] inserts at the right place: + before 5, not before 2. */ + if ((step < 0 && *start < *stop) || + (step > 0 && *start > *stop)) + *stop = *start; + + return slicelength; +} + static int list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value) { @@ -2940,22 +2964,11 @@ list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value) return list_ass_item(self, i, value); } else if (PySlice_Check(item)) { - Py_ssize_t start, stop, step, slicelength; + Py_ssize_t start, stop, step; if (PySlice_Unpack(item, &start, &stop, &step) < 0) { return -1; } - slicelength = PySlice_AdjustIndices(Py_SIZE(self), &start, &stop, - step); - - if (step == 1) - return list_ass_slice(self, start, stop, value); - - /* Make sure s[5:2] = [..] inserts at the right place: - before 5, not before 2. */ - if ((step < 0 && start < stop) || - (step > 0 && start > stop)) - stop = start; if (value == NULL) { /* delete slice */ @@ -2964,6 +2977,12 @@ list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value) Py_ssize_t i; int res; + Py_ssize_t slicelength = adjust_slice_indexes(self, &start, &stop, + step); + + if (step == 1) + return list_ass_slice(self, start, stop, value); + if (slicelength <= 0) return 0; @@ -3039,6 +3058,15 @@ list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value) if (!seq) return -1; + Py_ssize_t slicelength = adjust_slice_indexes(self, &start, &stop, + step); + + if (step == 1) { + int res = list_ass_slice(self, start, stop, seq); + Py_DECREF(seq); + return res; + } + if (PySequence_Fast_GET_SIZE(seq) != slicelength) { PyErr_Format(PyExc_ValueError, "attempt to assign sequence of " diff --git a/Objects/longobject.c b/Objects/longobject.c index c72e1643..c366034f 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -484,11 +484,18 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) do_decref = 1; } if (_PyLong_IsCompact(v)) { -#if SIZEOF_LONG < SIZEOF_VOID_P - intptr_t tmp = _PyLong_CompactValue(v); - res = (long)tmp; - if (res != tmp) { - *overflow = tmp < 0 ? -1 : 1; +#if SIZEOF_LONG < SIZEOF_SIZE_T + Py_ssize_t tmp = _PyLong_CompactValue(v); + if (tmp < LONG_MIN) { + *overflow = -1; + res = -1; + } + else if (tmp > LONG_MAX) { + *overflow = 1; + res = -1; + } + else { + res = (long)tmp; } #else res = _PyLong_CompactValue(v); @@ -633,14 +640,15 @@ PyLong_AsUnsignedLong(PyObject *vv) v = (PyLongObject *)vv; if (_PyLong_IsNonNegativeCompact(v)) { -#if SIZEOF_LONG < SIZEOF_VOID_P - intptr_t tmp = _PyLong_CompactValue(v); +#if SIZEOF_LONG < SIZEOF_SIZE_T + size_t tmp = (size_t)_PyLong_CompactValue(v); unsigned long res = (unsigned long)tmp; if (res != tmp) { goto overflow; } + return res; #else - return _PyLong_CompactValue(v); + return (unsigned long)(size_t)_PyLong_CompactValue(v); #endif } if (_PyLong_IsNegative(v)) { @@ -686,7 +694,7 @@ PyLong_AsSize_t(PyObject *vv) v = (PyLongObject *)vv; if (_PyLong_IsNonNegativeCompact(v)) { - return _PyLong_CompactValue(v); + return (size_t)_PyLong_CompactValue(v); } if (_PyLong_IsNegative(v)) { PyErr_SetString(PyExc_OverflowError, @@ -723,7 +731,11 @@ _PyLong_AsUnsignedLongMask(PyObject *vv) } v = (PyLongObject *)vv; if (_PyLong_IsCompact(v)) { - return (unsigned long)_PyLong_CompactValue(v); +#if SIZEOF_LONG < SIZEOF_SIZE_T + return (unsigned long)(size_t)_PyLong_CompactValue(v); +#else + return (unsigned long)(long)_PyLong_CompactValue(v); +#endif } i = _PyLong_DigitCount(v); int sign = _PyLong_NonCompactSign(v); @@ -1267,7 +1279,18 @@ PyLong_AsUnsignedLongLong(PyObject *vv) v = (PyLongObject*)vv; if (_PyLong_IsNonNegativeCompact(v)) { res = 0; - bytes = _PyLong_CompactValue(v); +#if SIZEOF_LONG_LONG < SIZEOF_SIZE_T + size_t tmp = (size_t)_PyLong_CompactValue(v); + bytes = (unsigned long long)tmp; + if (bytes != tmp) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert " + "to C unsigned long long"); + res = -1; + } +#else + bytes = (unsigned long long)(size_t)_PyLong_CompactValue(v); +#endif } else { res = _PyLong_AsByteArray((PyLongObject *)vv, (unsigned char *)&bytes, @@ -1298,7 +1321,11 @@ _PyLong_AsUnsignedLongLongMask(PyObject *vv) } v = (PyLongObject *)vv; if (_PyLong_IsCompact(v)) { - return (unsigned long long)(signed long long)_PyLong_CompactValue(v); +#if SIZEOF_LONG_LONG < SIZEOF_SIZE_T + return (unsigned long long)(size_t)_PyLong_CompactValue(v); +#else + return (unsigned long long)(long long)_PyLong_CompactValue(v); +#endif } i = _PyLong_DigitCount(v); sign = _PyLong_NonCompactSign(v); @@ -1370,7 +1397,22 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow) do_decref = 1; } if (_PyLong_IsCompact(v)) { +#if SIZEOF_LONG_LONG < SIZEOF_SIZE_T + Py_ssize_t tmp = _PyLong_CompactValue(v); + if (tmp < LLONG_MIN) { + *overflow = -1; + res = -1; + } + else if (tmp > LLONG_MAX) { + *overflow = 1; + res = -1; + } + else { + res = (long long)tmp; + } +#else res = _PyLong_CompactValue(v); +#endif } else { i = _PyLong_DigitCount(v); @@ -3308,7 +3350,7 @@ long_hash(PyLongObject *v) int sign; if (_PyLong_IsCompact(v)) { - x = _PyLong_CompactValue(v); + x = (Py_uhash_t)_PyLong_CompactValue(v); if (x == (Py_uhash_t)-1) { x = (Py_uhash_t)-2; } @@ -6209,7 +6251,7 @@ PyDoc_STRVAR(long_doc, int(x, base=10) -> integer\n\ \n\ Convert a number or string to an integer, or return 0 if no arguments\n\ -are given. If x is a number, return x.__int__(). For floating point\n\ +are given. If x is a number, return x.__int__(). For floating-point\n\ numbers, this truncates towards zero.\n\ \n\ If x is not a number or if base is given, then x must be a string,\n\ diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index b0168044..9a5f9c66 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -108,8 +108,6 @@ mbuf_release(_PyManagedBufferObject *self) if (self->flags&_Py_MANAGED_BUFFER_RELEASED) return; - /* NOTE: at this point self->exports can still be > 0 if this function - is called from mbuf_clear() to break up a reference cycle. */ self->flags |= _Py_MANAGED_BUFFER_RELEASED; /* PyBuffer_Release() decrements master->obj and sets it to NULL. */ @@ -264,7 +262,7 @@ PyTypeObject _PyManagedBuffer_Type = { /* Assumptions: ndim >= 1. The macro tests for a corner case that should perhaps be explicitly forbidden in the PEP. */ #define HAVE_SUBOFFSETS_IN_LAST_DIM(view) \ - (view->suboffsets && view->suboffsets[dest->ndim-1] >= 0) + (view->suboffsets && view->suboffsets[view->ndim-1] >= 0) static inline int last_dim_is_contiguous(const Py_buffer *dest, const Py_buffer *src) @@ -1092,32 +1090,19 @@ PyBuffer_ToContiguous(void *buf, const Py_buffer *src, Py_ssize_t len, char orde /* Inform the managed buffer that this particular memoryview will not access the underlying buffer again. If no other memoryviews are registered with the managed buffer, the underlying buffer is released instantly and - marked as inaccessible for both the memoryview and the managed buffer. - - This function fails if the memoryview itself has exported buffers. */ -static int + marked as inaccessible for both the memoryview and the managed buffer. */ +static void _memory_release(PyMemoryViewObject *self) { + assert(self->exports == 0); if (self->flags & _Py_MEMORYVIEW_RELEASED) - return 0; + return; - if (self->exports == 0) { - self->flags |= _Py_MEMORYVIEW_RELEASED; - assert(self->mbuf->exports > 0); - if (--self->mbuf->exports == 0) - mbuf_release(self->mbuf); - return 0; + self->flags |= _Py_MEMORYVIEW_RELEASED; + assert(self->mbuf->exports > 0); + if (--self->mbuf->exports == 0) { + mbuf_release(self->mbuf); } - if (self->exports > 0) { - PyErr_Format(PyExc_BufferError, - "memoryview has %zd exported buffer%s", self->exports, - self->exports==1 ? "" : "s"); - return -1; - } - - PyErr_SetString(PyExc_SystemError, - "_memory_release(): negative export count"); - return -1; } /*[clinic input] @@ -1130,9 +1115,21 @@ static PyObject * memoryview_release_impl(PyMemoryViewObject *self) /*[clinic end generated code: output=d0b7e3ba95b7fcb9 input=bc71d1d51f4a52f0]*/ { - if (_memory_release(self) < 0) + if (self->exports == 0) { + _memory_release(self); + Py_RETURN_NONE; + } + + if (self->exports > 0) { + PyErr_Format(PyExc_BufferError, + "memoryview has %zd exported buffer%s", self->exports, + self->exports==1 ? "" : "s"); return NULL; - Py_RETURN_NONE; + } + + PyErr_SetString(PyExc_SystemError, + "memoryview: negative export count"); + return NULL; } static void @@ -1140,7 +1137,7 @@ memory_dealloc(PyMemoryViewObject *self) { assert(self->exports == 0); _PyObject_GC_UNTRACK(self); - (void)_memory_release(self); + _memory_release(self); Py_CLEAR(self->mbuf); if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) self); @@ -1157,8 +1154,10 @@ memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg) static int memory_clear(PyMemoryViewObject *self) { - (void)_memory_release(self); - Py_CLEAR(self->mbuf); + if (self->exports == 0) { + _memory_release(self); + Py_CLEAR(self->mbuf); + } return 0; } @@ -3323,6 +3322,7 @@ memory_iter(PyObject *seq) PyErr_BadInternalCall(); return NULL; } + CHECK_RELEASED(seq); PyMemoryViewObject *obj = (PyMemoryViewObject *)seq; int ndims = obj->view.ndim; if (ndims == 0) { diff --git a/Objects/object.c b/Objects/object.c index aac707d6..70671911 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -159,11 +159,27 @@ _PyDebug_PrintTotalRefs(void) { #ifdef Py_TRACE_REFS -#define REFCHAIN(interp) &interp->object_state.refchain +#define REFCHAIN(interp) interp->object_state.refchain + +static inline int +has_own_refchain(PyInterpreterState *interp) +{ + if (interp->feature_flags & Py_RTFLAGS_USE_MAIN_OBMALLOC) { + return (_Py_IsMainInterpreter(interp) + || _PyInterpreterState_Main() == NULL); + } + return 1; +} static inline void init_refchain(PyInterpreterState *interp) { + if (!has_own_refchain(interp)) { + // Legacy subinterpreters share a refchain with the main interpreter. + REFCHAIN(interp) = REFCHAIN(_PyInterpreterState_Main()); + return; + } + REFCHAIN(interp) = &interp->object_state._refchain_obj; PyObject *refchain = REFCHAIN(interp); refchain->_ob_prev = refchain; refchain->_ob_next = refchain; @@ -1170,7 +1186,8 @@ PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value) } Py_INCREF(name); - PyUnicode_InternInPlace(&name); + PyInterpreterState *interp = _PyInterpreterState_GET(); + _PyUnicode_InternMortal(interp, &name); if (tp->tp_setattro != NULL) { err = (*tp->tp_setattro)(v, name, value); Py_DECREF(name); @@ -2009,9 +2026,7 @@ void _PyObject_InitState(PyInterpreterState *interp) { #ifdef Py_TRACE_REFS - if (!_Py_IsMainInterpreter(interp)) { - init_refchain(interp); - } + init_refchain(interp); #endif } diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 39b0f684..cf364c13 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -789,6 +789,7 @@ _odict_clear_nodes(PyODictObject *od) _odictnode_DEALLOC(node); node = next; } + od->od_state++; } /* There isn't any memory management of nodes past this point. */ @@ -799,24 +800,40 @@ _odict_keys_equal(PyODictObject *a, PyODictObject *b) { _ODictNode *node_a, *node_b; + // keep operands' state to detect undesired mutations + const size_t state_a = a->od_state; + const size_t state_b = b->od_state; + node_a = _odict_FIRST(a); node_b = _odict_FIRST(b); while (1) { - if (node_a == NULL && node_b == NULL) + if (node_a == NULL && node_b == NULL) { /* success: hit the end of each at the same time */ return 1; - else if (node_a == NULL || node_b == NULL) + } + else if (node_a == NULL || node_b == NULL) { /* unequal length */ return 0; + } else { - int res = PyObject_RichCompareBool( - (PyObject *)_odictnode_KEY(node_a), - (PyObject *)_odictnode_KEY(node_b), - Py_EQ); - if (res < 0) + PyObject *key_a = Py_NewRef(_odictnode_KEY(node_a)); + PyObject *key_b = Py_NewRef(_odictnode_KEY(node_b)); + int res = PyObject_RichCompareBool(key_a, key_b, Py_EQ); + Py_DECREF(key_a); + Py_DECREF(key_b); + if (res < 0) { return res; - else if (res == 0) + } + else if (a->od_state != state_a || b->od_state != state_b) { + PyErr_SetString(PyExc_RuntimeError, + "OrderedDict mutated during iteration"); + return -1; + } + else if (res == 0) { + // This check comes after the check on the state + // in order for the exception to be set correctly. return 0; + } /* otherwise it must match, so move on to the next one */ node_a = _odictnode_NEXT(node_a); diff --git a/Objects/structseq.c b/Objects/structseq.c index 8b189595..246d4c76 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -41,12 +41,20 @@ get_type_attr_as_size(PyTypeObject *tp, PyObject *name) get_type_attr_as_size(tp, &_Py_ID(n_sequence_fields)) #define REAL_SIZE_TP(tp) \ get_type_attr_as_size(tp, &_Py_ID(n_fields)) -#define REAL_SIZE(op) REAL_SIZE_TP(Py_TYPE(op)) +#define REAL_SIZE(op) get_real_size((PyObject *)op) #define UNNAMED_FIELDS_TP(tp) \ get_type_attr_as_size(tp, &_Py_ID(n_unnamed_fields)) #define UNNAMED_FIELDS(op) UNNAMED_FIELDS_TP(Py_TYPE(op)) +static Py_ssize_t +get_real_size(PyObject *op) +{ + // Compute the real size from the visible size (i.e., Py_SIZE()) and the + // number of non-sequence fields accounted for in tp_basicsize. + Py_ssize_t hidden = Py_TYPE(op)->tp_basicsize - offsetof(PyStructSequence, ob_item); + return Py_SIZE(op) + hidden / sizeof(PyObject *); +} PyObject * PyStructSequence_New(PyTypeObject *type) @@ -107,6 +115,9 @@ structseq_dealloc(PyStructSequence *obj) PyObject_GC_UnTrack(obj); PyTypeObject *tp = Py_TYPE(obj); + // gh-122527: We can't use REAL_SIZE_TP() or any macros that access the + // type's dictionary here, because the dictionary may have already been + // cleared by the garbage collector. size = REAL_SIZE(obj); for (i = 0; i < size; ++i) { Py_XDECREF(obj->ob_item[i]); @@ -467,10 +478,14 @@ initialize_members(PyStructSequence_Desc *desc, static void initialize_static_fields(PyTypeObject *type, PyStructSequence_Desc *desc, - PyMemberDef *tp_members, unsigned long tp_flags) + PyMemberDef *tp_members, Py_ssize_t n_members, + unsigned long tp_flags) { type->tp_name = desc->name; - type->tp_basicsize = sizeof(PyStructSequence) - sizeof(PyObject *); + // Account for hidden members in tp_basicsize because they are not + // included in the variable size. + Py_ssize_t n_hidden = n_members - desc->n_in_sequence; + type->tp_basicsize = sizeof(PyStructSequence) + (n_hidden - 1) * sizeof(PyObject *); type->tp_itemsize = sizeof(PyObject *); type->tp_dealloc = (destructor)structseq_dealloc; type->tp_repr = (reprfunc)structseq_repr; @@ -520,7 +535,7 @@ _PyStructSequence_InitBuiltinWithFlags(PyInterpreterState *interp, if (members == NULL) { goto error; } - initialize_static_fields(type, desc, members, tp_flags); + initialize_static_fields(type, desc, members, n_members, tp_flags); _Py_SetImmortal(type); } @@ -582,7 +597,7 @@ PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc) if (members == NULL) { return -1; } - initialize_static_fields(type, desc, members, 0); + initialize_static_fields(type, desc, members, n_members, 0); if (initialize_static_type(type, desc, n_members, n_unnamed_members) < 0) { PyMem_Free(members); return -1; @@ -658,7 +673,8 @@ _PyStructSequence_NewType(PyStructSequence_Desc *desc, unsigned long tp_flags) /* The name in this PyType_Spec is statically allocated so it is */ /* expected that it'll outlive the PyType_Spec */ spec.name = desc->name; - spec.basicsize = sizeof(PyStructSequence) - sizeof(PyObject *); + Py_ssize_t hidden = n_members - desc->n_in_sequence; + spec.basicsize = (int)(sizeof(PyStructSequence) + (hidden - 1) * sizeof(PyObject *)); spec.itemsize = sizeof(PyObject *); spec.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | tp_flags; spec.slots = slots; diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 991edcc8..918654fa 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -1139,7 +1139,7 @@ maybe_freelist_pop(Py_ssize_t size) return NULL; } assert(size > 0); - if (size < PyTuple_MAXSAVESIZE) { + if (size <= PyTuple_MAXSAVESIZE) { Py_ssize_t index = size - 1; PyTupleObject *op = STATE.free_list[index]; if (op != NULL) { diff --git a/Objects/typeobject.c b/Objects/typeobject.c index bf2be42f..5bca4b4e 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -116,6 +116,7 @@ static_builtin_index_clear(PyTypeObject *self) self->tp_subclasses = NULL; } + static inline static_builtin_state * static_builtin_state_get(PyInterpreterState *interp, PyTypeObject *self) { @@ -1079,8 +1080,10 @@ type_module(PyTypeObject *type, void *context) if (s != NULL) { mod = PyUnicode_FromStringAndSize( type->tp_name, (Py_ssize_t)(s - type->tp_name)); - if (mod != NULL) - PyUnicode_InternInPlace(&mod); + if (mod != NULL) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + _PyUnicode_InternMortal(interp, &mod); + } } else { mod = Py_NewRef(&_Py_ID(builtins)); @@ -4917,7 +4920,8 @@ type_setattro(PyTypeObject *type, PyObject *name, PyObject *value) } /* bpo-40521: Interned strings are shared by all subinterpreters */ if (!PyUnicode_CHECK_INTERNED(name)) { - PyUnicode_InternInPlace(&name); + PyInterpreterState *interp = _PyInterpreterState_GET(); + _PyUnicode_InternMortal(interp, &name); if (!PyUnicode_CHECK_INTERNED(name)) { PyErr_SetString(PyExc_MemoryError, "Out of memory interning an attribute name"); @@ -5709,7 +5713,6 @@ compatible_for_assignment(PyTypeObject* oldto, PyTypeObject* newto, const char* static int object_set_class(PyObject *self, PyObject *value, void *closure) { - PyTypeObject *oldto = Py_TYPE(self); if (value == NULL) { PyErr_SetString(PyExc_TypeError, @@ -5729,6 +5732,8 @@ object_set_class(PyObject *self, PyObject *value, void *closure) return -1; } + PyTypeObject *oldto = Py_TYPE(self); + /* In versions of CPython prior to 3.5, the code in compatible_for_assignment was not set up to correctly check for memory layout / slot / etc. compatibility for non-HEAPTYPE classes, so we just @@ -6640,6 +6645,12 @@ type_add_method(PyTypeObject *type, PyMethodDef *meth) return 0; } +int +_PyType_AddMethod(PyTypeObject *type, PyMethodDef *meth) +{ + return type_add_method(type, meth); +} + /* Add the methods from tp_methods to the __dict__ in a type object */ static int @@ -7584,6 +7595,7 @@ _PyStaticType_InitBuiltin(PyInterpreterState *interp, PyTypeObject *self) if (res < 0) { static_builtin_state_clear(interp, self); } + return res; } @@ -8195,13 +8207,13 @@ wrap_buffer(PyObject *self, PyObject *args, void *wrapped) if (flags == -1 && PyErr_Occurred()) { return NULL; } - if (flags > INT_MAX) { + if (flags > INT_MAX || flags < INT_MIN) { PyErr_SetString(PyExc_OverflowError, - "buffer flags too large"); + "buffer flags out of range"); return NULL; } - return _PyMemoryView_FromBufferProc(self, Py_SAFE_DOWNCAST(flags, Py_ssize_t, int), + return _PyMemoryView_FromBufferProc(self, (int)flags, (getbufferproc)wrapped); } @@ -10076,6 +10088,84 @@ recurse_down_subclasses(PyTypeObject *type, PyObject *attr_name, return 0; } +static int +expect_manually_inherited(PyTypeObject *type, void **slot) +{ + PyObject *typeobj = (PyObject *)type; + if (slot == (void *)&type->tp_init) { + /* This is a best-effort list of builtin exception types + that have their own tp_init function. */ + if (typeobj != PyExc_BaseException + && typeobj != PyExc_BaseExceptionGroup + && typeobj != PyExc_ImportError + && typeobj != PyExc_NameError + && typeobj != PyExc_OSError + && typeobj != PyExc_StopIteration + && typeobj != PyExc_SyntaxError + && typeobj != PyExc_UnicodeDecodeError + && typeobj != PyExc_UnicodeEncodeError + + && type != &PyBool_Type + && type != &PyBytes_Type + && type != &PyMemoryView_Type + && type != &PyComplex_Type + && type != &PyEnum_Type + && type != &PyFilter_Type + && type != &PyFloat_Type + && type != &PyFrozenSet_Type + && type != &PyLong_Type + && type != &PyMap_Type + && type != &PyRange_Type + && type != &PyReversed_Type + && type != &PySlice_Type + && type != &PyTuple_Type + && type != &PyUnicode_Type + && type != &PyZip_Type) + + { + return 1; + } + } + else if (slot == (void *)&type->tp_str) { + /* This is a best-effort list of builtin exception types + that have their own tp_str function. */ + if (typeobj == PyExc_AttributeError || typeobj == PyExc_NameError) { + return 1; + } + } + else if (slot == (void *)&type->tp_getattr + || slot == (void *)&type->tp_getattro) + { + /* This is a best-effort list of builtin types + that have their own tp_getattr function. */ + if (typeobj == PyExc_BaseException + || type == &PyByteArray_Type + || type == &PyBytes_Type + || type == &PyComplex_Type + || type == &PyDict_Type + || type == &PyEnum_Type + || type == &PyFilter_Type + || type == &PyLong_Type + || type == &PyList_Type + || type == &PyMap_Type + || type == &PyMemoryView_Type + || type == &PyProperty_Type + || type == &PyRange_Type + || type == &PyReversed_Type + || type == &PySet_Type + || type == &PySlice_Type + || type == &PySuper_Type + || type == &PyTuple_Type + || type == &PyZip_Type) + { + return 1; + } + } + + /* It must be inherited (see type_ready_inherit()).. */ + return 0; +} + /* This function is called by PyType_Ready() to populate the type's dictionary with method descriptors for function slots. For each function slot (like tp_repr) that's defined in the type, one or more @@ -10120,6 +10210,26 @@ add_operators(PyTypeObject *type) ptr = slotptr(type, p->offset); if (!ptr || !*ptr) continue; + if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN + && type->tp_base != NULL) + { + /* Also ignore when the type slot has been inherited. */ + void **ptr_base = slotptr(type->tp_base, p->offset); + if (ptr_base && *ptr == *ptr_base) { + /* Ideally we would always ignore any manually inherited + slots, Which would mean inheriting the slot wrapper + using normal attribute lookup rather than keeping + a distinct copy. However, that would introduce + a slight change in behavior that could break + existing code. + + In the meantime, look the other way when the definition + explicitly inherits the slot. */ + if (!expect_manually_inherited(type, ptr)) { + continue; + } + } + } int r = PyDict_Contains(dict, p->name_strobj); if (r > 0) continue; diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index db9c2191..4f0bc096 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -1364,7 +1364,16 @@ typealias_alloc(PyObject *name, PyObject *type_params, PyObject *compute_value, return NULL; } ta->name = Py_NewRef(name); - ta->type_params = Py_IsNone(type_params) ? NULL : Py_XNewRef(type_params); + if ( + type_params == NULL + || Py_IsNone(type_params) + || (PyTuple_Check(type_params) && PyTuple_GET_SIZE(type_params) == 0) + ) { + ta->type_params = NULL; + } + else { + ta->type_params = Py_NewRef(type_params); + } ta->compute_value = Py_XNewRef(compute_value); ta->value = Py_XNewRef(value); ta->module = Py_XNewRef(module); diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index fc9379be..c885be5b 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -179,10 +179,7 @@ extern "C" { *_to++ = (to_type) *_iter++; \ } while (0) -#define LATIN1(ch) \ - (ch < 128 \ - ? (PyObject*)&_Py_SINGLETON(strings).ascii[ch] \ - : (PyObject*)&_Py_SINGLETON(strings).latin1[ch - 128]) +#define LATIN1 _Py_LATIN1_CHR #ifdef MS_WINDOWS /* On Windows, overallocate by 50% is the best factor */ @@ -225,18 +222,20 @@ static inline PyObject* unicode_new_empty(void) return Py_NewRef(empty); } -/* This dictionary holds all interned unicode strings. Note that references - to strings in this dictionary are *not* counted in the string's ob_refcnt. - When the interned string reaches a refcnt of 0 the string deallocation - function will delete the reference from this dictionary. -*/ +/* This dictionary holds per-interpreter interned strings. + * See InternalDocs/string_interning.md for details. + */ static inline PyObject *get_interned_dict(PyInterpreterState *interp) { return _Py_INTERP_CACHED_OBJECT(interp, interned_strings); } +/* This hashtable holds statically allocated interned strings. + * See InternalDocs/string_interning.md for details. + */ #define INTERNED_STRINGS _PyRuntime.cached_objects.interned_strings +/* Get number of all interned strings for the current interpreter. */ Py_ssize_t _PyUnicode_InternedSize(void) { @@ -244,6 +243,28 @@ _PyUnicode_InternedSize(void) return _Py_hashtable_len(INTERNED_STRINGS) + PyDict_GET_SIZE(dict); } +/* Get number of immortal interned strings for the current interpreter. */ +Py_ssize_t +_PyUnicode_InternedSize_Immortal(void) +{ + PyObject *dict = get_interned_dict(_PyInterpreterState_GET()); + PyObject *key, *value; + Py_ssize_t pos = 0; + Py_ssize_t count = 0; + + // It's tempting to keep a count and avoid a loop here. But, this function + // is intended for refleak tests. It spends extra work to report the true + // value, to help detect bugs in optimizations. + + while (PyDict_Next(dict, &pos, &key, &value)) { + assert(PyUnicode_CHECK_INTERNED(key) != SSTATE_INTERNED_IMMORTAL_STATIC); + if (PyUnicode_CHECK_INTERNED(key) == SSTATE_INTERNED_IMMORTAL) { + count++; + } + } + return _Py_hashtable_len(INTERNED_STRINGS) + count; +} + static Py_hash_t unicode_hash(PyObject *); static int unicode_compare_eq(PyObject *, PyObject *); @@ -266,28 +287,38 @@ hashtable_unicode_compare(const void *key1, const void *key2) } } +/* Return true if this interpreter should share the main interpreter's + intern_dict. That's important for interpreters which load basic + single-phase init extension modules (m_size == -1). There could be interned + immortal strings that are shared between interpreters, due to the + PyDict_Update(mdict, m_copy) call in import_find_extension(). + + It's not safe to deallocate those strings until all interpreters that + potentially use them are freed. By storing them in the main interpreter, we + ensure they get freed after all other interpreters are freed. +*/ +static bool +has_shared_intern_dict(PyInterpreterState *interp) +{ + PyInterpreterState *main_interp = _PyInterpreterState_Main(); + return interp != main_interp && interp->feature_flags & Py_RTFLAGS_USE_MAIN_OBMALLOC; +} + static int init_interned_dict(PyInterpreterState *interp) { - if (_Py_IsMainInterpreter(interp)) { - assert(INTERNED_STRINGS == NULL); - _Py_hashtable_allocator_t hashtable_alloc = {PyMem_RawMalloc, PyMem_RawFree}; - INTERNED_STRINGS = _Py_hashtable_new_full( - hashtable_unicode_hash, - hashtable_unicode_compare, - NULL, - NULL, - &hashtable_alloc - ); - if (INTERNED_STRINGS == NULL) { + assert(get_interned_dict(interp) == NULL); + PyObject *interned; + if (has_shared_intern_dict(interp)) { + interned = get_interned_dict(_PyInterpreterState_Main()); + Py_INCREF(interned); + } + else { + interned = PyDict_New(); + if (interned == NULL) { return -1; } } - assert(get_interned_dict(interp) == NULL); - PyObject *interned = interned = PyDict_New(); - if (interned == NULL) { - return -1; - } _Py_INTERP_CACHED_OBJECT(interp, interned_strings) = interned; return 0; } @@ -297,11 +328,62 @@ clear_interned_dict(PyInterpreterState *interp) { PyObject *interned = get_interned_dict(interp); if (interned != NULL) { - PyDict_Clear(interned); + if (!has_shared_intern_dict(interp)) { + // only clear if the dict belongs to this interpreter + PyDict_Clear(interned); + } Py_DECREF(interned); _Py_INTERP_CACHED_OBJECT(interp, interned_strings) = NULL; } - if (_Py_IsMainInterpreter(interp) && INTERNED_STRINGS != NULL) { +} + +static PyStatus +init_global_interned_strings(PyInterpreterState *interp) +{ + assert(INTERNED_STRINGS == NULL); + _Py_hashtable_allocator_t hashtable_alloc = {PyMem_RawMalloc, PyMem_RawFree}; + + INTERNED_STRINGS = _Py_hashtable_new_full( + hashtable_unicode_hash, + hashtable_unicode_compare, + // Objects stored here are immortal and statically allocated, + // so we don't need key_destroy_func & value_destroy_func: + NULL, + NULL, + &hashtable_alloc + ); + if (INTERNED_STRINGS == NULL) { + PyErr_Clear(); + return _PyStatus_ERR("failed to create global interned dict"); + } + + /* Intern statically allocated string identifiers, deepfreeze strings, + * and one-byte latin-1 strings. + * This must be done before any module initialization so that statically + * allocated string identifiers are used instead of heap allocated strings. + * Deepfreeze uses the interned identifiers if present to save space + * else generates them and they are interned to speed up dict lookups. + */ + _PyUnicode_InitStaticStrings(interp); + + for (int i = 0; i < 256; i++) { + PyObject *s = LATIN1(i); + _PyUnicode_InternStatic(interp, &s); + assert(s == LATIN1(i)); + } +#ifdef Py_DEBUG + assert(_PyUnicode_CheckConsistency(&_Py_STR(empty), 1)); + + for (int i = 0; i < 256; i++) { + assert(_PyUnicode_CheckConsistency(LATIN1(i), 1)); + } +#endif + return _PyStatus_OK(); +} + +static void clear_global_interned_strings(void) +{ + if (INTERNED_STRINGS != NULL) { _Py_hashtable_destroy(INTERNED_STRINGS); INTERNED_STRINGS = NULL; } @@ -634,6 +716,41 @@ _PyUnicode_CheckConsistency(PyObject *op, int check_content) } CHECK(PyUnicode_READ(kind, data, ascii->length) == 0); } + + /* Check interning state */ +#ifdef Py_DEBUG + // Note that we do not check `_Py_IsImmortal(op)`, since stable ABI + // extensions can make immortal strings mortal (but with a high enough + // refcount). + // The other way is extremely unlikely (worth a potential failed assertion + // in a debug build), so we do check `!_Py_IsImmortal(op)`. + switch (PyUnicode_CHECK_INTERNED(op)) { + case SSTATE_NOT_INTERNED: + if (ascii->state.statically_allocated) { + // This state is for two exceptions: + // - strings are currently checked before they're interned + // - the 256 one-latin1-character strings + // are static but use SSTATE_NOT_INTERNED + } + else { + CHECK(!_Py_IsImmortal(op)); + } + break; + case SSTATE_INTERNED_MORTAL: + CHECK(!ascii->state.statically_allocated); + CHECK(!_Py_IsImmortal(op)); + break; + case SSTATE_INTERNED_IMMORTAL: + CHECK(!ascii->state.statically_allocated); + break; + case SSTATE_INTERNED_IMMORTAL_STATIC: + CHECK(ascii->state.statically_allocated); + break; + default: + Py_UNREACHABLE(); + } +#endif + return 1; #undef CHECK @@ -1592,16 +1709,65 @@ unicode_dealloc(PyObject *unicode) _Py_FatalRefcountError("deallocating an Unicode singleton"); } #endif - /* This should never get called, but we also don't want to SEGV if - * we accidentally decref an immortal string out of existence. Since - * the string is an immortal object, just re-set the reference count. - */ - if (PyUnicode_CHECK_INTERNED(unicode) - || _PyUnicode_STATE(unicode).statically_allocated) - { + if (_PyUnicode_STATE(unicode).statically_allocated) { + /* This should never get called, but we also don't want to SEGV if + * we accidentally decref an immortal string out of existence. Since + * the string is an immortal object, just re-set the reference count. + */ +#ifdef Py_DEBUG + Py_UNREACHABLE(); +#endif _Py_SetImmortal(unicode); return; } + switch (_PyUnicode_STATE(unicode).interned) { + case SSTATE_NOT_INTERNED: + break; + case SSTATE_INTERNED_MORTAL: + /* Remove the object from the intern dict. + * Before doing so, we set the refcount to 3: the key and value + * in the interned_dict, plus one to work with. + */ + assert(Py_REFCNT(unicode) == 0); + Py_SET_REFCNT(unicode, 3); +#ifdef Py_REF_DEBUG + /* let's be pedantic with the ref total */ + _Py_IncRefTotal(_PyInterpreterState_GET()); + _Py_IncRefTotal(_PyInterpreterState_GET()); + _Py_IncRefTotal(_PyInterpreterState_GET()); +#endif + PyInterpreterState *interp = _PyInterpreterState_GET(); + PyObject *interned = get_interned_dict(interp); + assert(interned != NULL); + int r = PyDict_DelItem(interned, unicode); + if (r == -1) { + PyErr_WriteUnraisable(unicode); + // We don't know what happened to the string. It's probably + // best to leak it: + // - if it was not found, something is very wrong + // - if it was deleted, there are no more references to it + // so it can't cause trouble (except wasted memory) + // - if it wasn't deleted, it'll remain interned + _Py_SetImmortal(unicode); + _PyUnicode_STATE(unicode).interned = SSTATE_INTERNED_IMMORTAL; + return; + } + // Only our work reference should be left; remove it too. + assert(Py_REFCNT(unicode) == 1); + Py_SET_REFCNT(unicode, 0); +#ifdef Py_REF_DEBUG + /* let's be pedantic with the ref total */ + _Py_DecRefTotal(_PyInterpreterState_GET()); +#endif + break; + default: + // As with `statically_allocated` above. +#ifdef Py_REF_DEBUG + Py_UNREACHABLE(); +#endif + _Py_SetImmortal(unicode); + return; + } if (_PyUnicode_HAS_UTF8_MEMORY(unicode)) { PyObject_Free(_PyUnicode_UTF8(unicode)); } @@ -1763,7 +1929,8 @@ unicode_write_cstr(PyObject *unicode, Py_ssize_t index, static PyObject* get_latin1_char(Py_UCS1 ch) { - return Py_NewRef(LATIN1(ch)); + PyObject *o = LATIN1(ch); + return o; } static PyObject* @@ -1943,7 +2110,7 @@ _PyUnicode_FromId(_Py_Identifier *id) if (!obj) { return NULL; } - PyUnicode_InternInPlace(&obj); + _PyUnicode_InternImmortal(interp, &obj); if (index >= ids->size) { // Overallocate to reduce the number of realloc @@ -3851,6 +4018,18 @@ PyUnicode_AsUTF8(PyObject *unicode) return PyUnicode_AsUTF8AndSize(unicode, NULL); } +const char * +_PyUnicode_AsUTF8NoNUL(PyObject *unicode) +{ + Py_ssize_t size; + const char *s = PyUnicode_AsUTF8AndSize(unicode, &size); + if (s && strlen(s) != (size_t)size) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + return NULL; + } + return s; +} + /* PyUnicode_GetSize() has been deprecated since Python 3.3 because it returned length of Py_UNICODE. @@ -10728,8 +10907,10 @@ _PyUnicode_EqualToASCIIId(PyObject *left, _Py_Identifier *right) if (left == right_uni) return 1; - if (PyUnicode_CHECK_INTERNED(left)) + assert(PyUnicode_CHECK_INTERNED(right_uni)); + if (PyUnicode_CHECK_INTERNED(left)) { return 0; + } assert(_PyUnicode_HASH(right_uni) != -1); Py_hash_t hash = _PyUnicode_HASH(left); @@ -14704,28 +14885,26 @@ _PyUnicode_InitState(PyInterpreterState *interp) PyStatus _PyUnicode_InitGlobalObjects(PyInterpreterState *interp) { - // Initialize the global interned dict - if (init_interned_dict(interp)) { - PyErr_Clear(); - return _PyStatus_ERR("failed to create interned dict"); + if (_Py_IsMainInterpreter(interp)) { + PyStatus status = init_global_interned_strings(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; + } } + assert(INTERNED_STRINGS); - if (_Py_IsMainInterpreter(interp)) { - /* Intern statically allocated string identifiers and deepfreeze strings. - * This must be done before any module initialization so that statically - * allocated string identifiers are used instead of heap allocated strings. - * Deepfreeze uses the interned identifiers if present to save space - * else generates them and they are interned to speed up dict lookups. - */ - _PyUnicode_InitStaticStrings(interp); + return _PyStatus_OK(); +} -#ifdef Py_DEBUG - assert(_PyUnicode_CheckConsistency(&_Py_STR(empty), 1)); - for (int i = 0; i < 256; i++) { - assert(_PyUnicode_CheckConsistency(LATIN1(i), 1)); - } -#endif +PyStatus +_PyUnicode_InitInternDict(PyInterpreterState *interp) +{ + assert(INTERNED_STRINGS); + + if (init_interned_dict(interp)) { + PyErr_Clear(); + return _PyStatus_ERR("failed to create interned dict"); } return _PyStatus_OK(); @@ -14750,104 +14929,243 @@ _PyUnicode_InitTypes(PyInterpreterState *interp) return _PyStatus_ERR("Can't initialize unicode types"); } +static /* non-null */ PyObject* +intern_static(PyInterpreterState *interp, PyObject *s /* stolen */) +{ + // Note that this steals a reference to `s`, but in many cases that + // stolen ref is returned, requiring no decref/incref. + + assert(s != NULL); + assert(_PyUnicode_CHECK(s)); + assert(_PyUnicode_STATE(s).statically_allocated); + assert(!PyUnicode_CHECK_INTERNED(s)); + +#ifdef Py_DEBUG + /* We must not add process-global interned string if there's already a + * per-interpreter interned_dict, which might contain duplicates. + */ + PyObject *interned = get_interned_dict(interp); + assert(interned == NULL); +#endif + + /* Look in the global cache first. */ + PyObject *r = (PyObject *)_Py_hashtable_get(INTERNED_STRINGS, s); + /* We should only init each string once */ + assert(r == NULL); + /* but just in case (for the non-debug build), handle this */ + if (r != NULL && r != s) { + assert(_PyUnicode_STATE(r).interned == SSTATE_INTERNED_IMMORTAL_STATIC); + assert(_PyUnicode_CHECK(r)); + Py_DECREF(s); + return Py_NewRef(r); + } + + if (_Py_hashtable_set(INTERNED_STRINGS, s, s) < -1) { + Py_FatalError("failed to intern static string"); + } + + _PyUnicode_STATE(s).interned = SSTATE_INTERNED_IMMORTAL_STATIC; + return s; +} void -_PyUnicode_InternInPlace(PyInterpreterState *interp, PyObject **p) +_PyUnicode_InternStatic(PyInterpreterState *interp, PyObject **p) +{ + // This should only be called as part of runtime initialization + assert(!Py_IsInitialized()); + + *p = intern_static(interp, *p); + assert(*p); +} + +static void +immortalize_interned(PyObject *s) +{ + assert(PyUnicode_CHECK_INTERNED(s) == SSTATE_INTERNED_MORTAL); + assert(!_Py_IsImmortal(s)); +#ifdef Py_REF_DEBUG + /* The reference count value should be excluded from the RefTotal. + The decrements to these objects will not be registered so they + need to be accounted for in here. */ + for (Py_ssize_t i = 0; i < Py_REFCNT(s); i++) { + _Py_DecRefTotal(_PyInterpreterState_GET()); + } +#endif + _PyUnicode_STATE(s).interned = SSTATE_INTERNED_IMMORTAL; + _Py_SetImmortal(s); +} + +static /* non-null */ PyObject* +intern_common(PyInterpreterState *interp, PyObject *s /* stolen */, + bool immortalize) { - PyObject *s = *p; + // Note that this steals a reference to `s`, but in many cases that + // stolen ref is returned, requiring no decref/incref. + #ifdef Py_DEBUG assert(s != NULL); assert(_PyUnicode_CHECK(s)); #else if (s == NULL || !PyUnicode_Check(s)) { - return; + return s; } #endif /* If it's a subclass, we don't really know what putting it in the interned dict might do. */ if (!PyUnicode_CheckExact(s)) { - return; + return s; } - if (PyUnicode_CHECK_INTERNED(s)) { - return; + /* Is it already interned? */ + switch (PyUnicode_CHECK_INTERNED(s)) { + case SSTATE_NOT_INTERNED: + // no, go on + break; + case SSTATE_INTERNED_MORTAL: + // yes but we might need to make it immortal + if (immortalize) { + immortalize_interned(s); + } + return s; + default: + // all done + return s; } - /* Look in the global cache first. */ - PyObject *r = (PyObject *)_Py_hashtable_get(INTERNED_STRINGS, s); - if (r != NULL && r != s) { - Py_SETREF(*p, Py_NewRef(r)); - return; + if (_PyUnicode_STATE(s).statically_allocated) { + return intern_static(interp, s); } - /* Handle statically allocated strings. */ - if (_PyUnicode_STATE(s).statically_allocated) { - assert(_Py_IsImmortal(s)); - if (_Py_hashtable_set(INTERNED_STRINGS, s, s) == 0) { - _PyUnicode_STATE(*p).interned = SSTATE_INTERNED_IMMORTAL_STATIC; + /* If it's already immortal, intern it as such */ + if (_Py_IsImmortal(s)) { + immortalize = 1; + } + + /* if it's a short string, get the singleton */ + if (PyUnicode_GET_LENGTH(s) == 1 && + PyUnicode_KIND(s) == PyUnicode_1BYTE_KIND) { + PyObject *r = LATIN1(*(unsigned char*)PyUnicode_DATA(s)); + assert(PyUnicode_CHECK_INTERNED(r)); + Py_DECREF(s); + return r; + } +#ifdef Py_DEBUG + assert(!unicode_is_singleton(s)); +#endif + + /* Look in the global cache now. */ + { + PyObject *r = (PyObject *)_Py_hashtable_get(INTERNED_STRINGS, s); + if (r != NULL) { + assert(_PyUnicode_STATE(r).statically_allocated); + assert(r != s); // r must be statically_allocated; s is not + Py_DECREF(s); + return Py_NewRef(r); } - return; } - /* Look in the per-interpreter cache. */ + /* Do a setdefault on the per-interpreter cache. */ PyObject *interned = get_interned_dict(interp); assert(interned != NULL); - PyObject *t = PyDict_SetDefault(interned, s, s); + PyObject *t = PyDict_SetDefault(interned, s, s); // t is borrowed if (t == NULL) { PyErr_Clear(); - return; + return s; } if (t != s) { - Py_SETREF(*p, Py_NewRef(t)); - return; + // value was already present (not inserted) + Py_INCREF(t); + Py_DECREF(s); + if (immortalize && + PyUnicode_CHECK_INTERNED(t) == SSTATE_INTERNED_MORTAL) { + immortalize_interned(t); + } + return t; } - - if (_Py_IsImmortal(s)) { - // XXX Restrict this to the main interpreter? - _PyUnicode_STATE(*p).interned = SSTATE_INTERNED_IMMORTAL_STATIC; - return; + else { + // value was newly inserted } + /* NOT_INTERNED -> INTERNED_MORTAL */ + + assert(_PyUnicode_STATE(s).interned == SSTATE_NOT_INTERNED); + + if (!_Py_IsImmortal(s)) { + /* The two references in interned dict (key and value) are not counted. + unicode_dealloc() and _PyUnicode_ClearInterned() take care of this. */ + Py_SET_REFCNT(s, Py_REFCNT(s) - 2); #ifdef Py_REF_DEBUG - /* The reference count value excluding the 2 references from the - interned dictionary should be excluded from the RefTotal. The - decrements to these objects will not be registered so they - need to be accounted for in here. */ - for (Py_ssize_t i = 0; i < Py_REFCNT(s) - 2; i++) { + /* let's be pedantic with the ref total */ + _Py_DecRefTotal(_PyInterpreterState_GET()); _Py_DecRefTotal(_PyInterpreterState_GET()); +#endif + } + _PyUnicode_STATE(s).interned = SSTATE_INTERNED_MORTAL; + + /* INTERNED_MORTAL -> INTERNED_IMMORTAL (if needed) */ + +#ifdef Py_DEBUG + if (_Py_IsImmortal(s)) { + assert(immortalize); } #endif - _Py_SetImmortal(s); - _PyUnicode_STATE(*p).interned = SSTATE_INTERNED_IMMORTAL; + if (immortalize) { + immortalize_interned(s); + } + + return s; +} + +void +_PyUnicode_InternImmortal(PyInterpreterState *interp, PyObject **p) +{ + *p = intern_common(interp, *p, 1); + assert(*p); +} + +void +_PyUnicode_InternMortal(PyInterpreterState *interp, PyObject **p) +{ + *p = intern_common(interp, *p, 0); + assert(*p); +} + + +void +_PyUnicode_InternInPlace(PyInterpreterState *interp, PyObject **p) +{ + _PyUnicode_InternImmortal(interp, p); + return; } void PyUnicode_InternInPlace(PyObject **p) { PyInterpreterState *interp = _PyInterpreterState_GET(); - _PyUnicode_InternInPlace(interp, p); + _PyUnicode_InternMortal(interp, p); } -// Function kept for the stable ABI. +// Public-looking name kept for the stable ABI; user should not call this: PyAPI_FUNC(void) PyUnicode_InternImmortal(PyObject **); void PyUnicode_InternImmortal(PyObject **p) { - PyUnicode_InternInPlace(p); - // Leak a reference on purpose - Py_INCREF(*p); + PyInterpreterState *interp = _PyInterpreterState_GET(); + _PyUnicode_InternImmortal(interp, p); } PyObject * PyUnicode_InternFromString(const char *cp) { PyObject *s = PyUnicode_FromString(cp); - if (s == NULL) + if (s == NULL) { return NULL; - PyUnicode_InternInPlace(&s); + } + PyInterpreterState *interp = _PyInterpreterState_GET(); + _PyUnicode_InternMortal(interp, &s); return s; } @@ -14861,20 +15179,13 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp) } assert(PyDict_CheckExact(interned)); - /* TODO: - * Currently, the runtime is not able to guarantee that it can exit without - * allocations that carry over to a future initialization of Python within - * the same process. i.e: - * ./python -X showrefcount -c 'import itertools' - * [237 refs, 237 blocks] - * - * Therefore, this should remain disabled for until there is a strict guarantee - * that no memory will be left after `Py_Finalize`. - */ -#ifdef Py_DEBUG - /* For all non-singleton interned strings, restore the two valid references - to that instance from within the intern string dictionary and let the - normal reference counting process clean up these instances. */ + if (has_shared_intern_dict(interp)) { + // the dict doesn't belong to this interpreter, skip the debug + // checks on it and just clear the pointer to it + clear_interned_dict(interp); + return; + } + #ifdef INTERNED_STATS fprintf(stderr, "releasing %zd interned strings\n", PyDict_GET_SIZE(interned)); @@ -14888,13 +15199,32 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp) int shared = 0; switch (PyUnicode_CHECK_INTERNED(s)) { case SSTATE_INTERNED_IMMORTAL: + /* Make immortal interned strings mortal again. + * + * Currently, the runtime is not able to guarantee that it can exit + * without allocations that carry over to a future initialization + * of Python within the same process. i.e: + * ./python -X showrefcount -c 'import itertools' + * [237 refs, 237 blocks] + * + * This should remain disabled (`Py_DEBUG` only) until there is a + * strict guarantee that no memory will be left after + * `Py_Finalize`. + */ +#ifdef Py_DEBUG // Skip the Immortal Instance check and restore // the two references (key and value) ignored // by PyUnicode_InternInPlace(). s->ob_refcnt = 2; +#ifdef Py_REF_DEBUG + /* let's be pedantic with the ref total */ + _Py_IncRefTotal(_PyInterpreterState_GET()); + _Py_IncRefTotal(_PyInterpreterState_GET()); +#endif #ifdef INTERNED_STATS total_length += PyUnicode_GET_LENGTH(s); #endif +#endif // Py_DEBUG break; case SSTATE_INTERNED_IMMORTAL_STATIC: /* It is shared between interpreters, so we should unmark it @@ -14907,7 +15237,15 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp) } break; case SSTATE_INTERNED_MORTAL: - /* fall through */ + // Restore 2 references held by the interned dict; these will + // be decref'd by clear_interned_dict's PyDict_Clear. + Py_SET_REFCNT(s, Py_REFCNT(s) + 2); +#ifdef Py_REF_DEBUG + /* let's be pedantic with the ref total */ + _Py_IncRefTotal(_PyInterpreterState_GET()); + _Py_IncRefTotal(_PyInterpreterState_GET()); +#endif + break; case SSTATE_NOT_INTERNED: /* fall through */ default: @@ -14928,8 +15266,10 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp) for (Py_ssize_t i=0; i < ids->size; i++) { Py_XINCREF(ids->array[i]); } -#endif /* Py_DEBUG */ clear_interned_dict(interp); + if (_Py_IsMainInterpreter(interp)) { + clear_global_interned_strings(); + } } @@ -15140,7 +15480,7 @@ encode_wstr_utf8(wchar_t *wstr, char **str, const char *name) int res; res = _Py_EncodeUTF8Ex(wstr, str, NULL, NULL, 1, _Py_ERROR_STRICT); if (res == -2) { - PyErr_Format(PyExc_RuntimeWarning, "cannot decode %s", name); + PyErr_Format(PyExc_RuntimeError, "cannot encode %s", name); return -1; } if (res < 0) { @@ -15364,8 +15704,10 @@ _PyUnicode_Fini(PyInterpreterState *interp) { struct _Py_unicode_state *state = &interp->unicode; - // _PyUnicode_ClearInterned() must be called before _PyUnicode_Fini() - assert(get_interned_dict(interp) == NULL); + if (!has_shared_intern_dict(interp)) { + // _PyUnicode_ClearInterned() must be called before _PyUnicode_Fini() + assert(get_interned_dict(interp) == NULL); + } _PyUnicode_FiniEncodings(&state->fs_codec); diff --git a/PC/_wmimodule.cpp b/PC/_wmimodule.cpp index 22ed0527..2c24761b 100644 --- a/PC/_wmimodule.cpp +++ b/PC/_wmimodule.cpp @@ -55,12 +55,26 @@ _query_thread(LPVOID param) IWbemLocator *locator = NULL; IWbemServices *services = NULL; IEnumWbemClassObject* enumerator = NULL; + HRESULT hr = S_OK; BSTR bstrQuery = NULL; struct _query_data *data = (struct _query_data*)param; - HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + // gh-125315: Copy the query string first, so that if the main thread gives + // up on waiting we aren't left with a dangling pointer (and a likely crash) + bstrQuery = SysAllocString(data->query); + if (!bstrQuery) { + hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); + } + + if (SUCCEEDED(hr)) { + hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + } + if (FAILED(hr)) { CloseHandle(data->writePipe); + if (bstrQuery) { + SysFreeString(bstrQuery); + } return (DWORD)hr; } @@ -101,12 +115,6 @@ _query_thread(LPVOID param) NULL, EOAC_NONE ); } - if (SUCCEEDED(hr)) { - bstrQuery = SysAllocString(data->query); - if (!bstrQuery) { - hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); - } - } if (SUCCEEDED(hr)) { hr = services->ExecQuery( bstr_t("WQL"), diff --git a/PC/clinic/_testconsole.c.h b/PC/clinic/_testconsole.c.h index b2f3b4ce..9b4d196b 100644 --- a/PC/clinic/_testconsole.c.h +++ b/PC/clinic/_testconsole.c.h @@ -36,7 +36,7 @@ _testconsole_write_input(PyObject *module, PyObject *const *args, Py_ssize_t nar PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(file), &_Py_ID(s), }, + .ob_item = { &_Py_ID(file), _Py_LATIN1_CHR('s'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -140,4 +140,4 @@ _testconsole_read_output(PyObject *module, PyObject *const *args, Py_ssize_t nar #ifndef _TESTCONSOLE_READ_OUTPUT_METHODDEF #define _TESTCONSOLE_READ_OUTPUT_METHODDEF #endif /* !defined(_TESTCONSOLE_READ_OUTPUT_METHODDEF) */ -/*[clinic end generated code: output=208c72e2c873555b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=2dcfa57c20b6e058 input=a9049054013a1b77]*/ diff --git a/PC/launcher2.c b/PC/launcher2.c index f331aab3..7a78ed16 100644 --- a/PC/launcher2.c +++ b/PC/launcher2.c @@ -1938,6 +1938,7 @@ struct AppxSearchInfo { struct AppxSearchInfo APPX_SEARCH[] = { // Releases made through the Store + { L"PythonSoftwareFoundation.Python.3.14_qbz5n2kfra8p0", L"3.14", 10 }, { L"PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0", L"3.13", 10 }, { L"PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0", L"3.12", 10 }, { L"PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0", L"3.11", 10 }, @@ -1946,8 +1947,9 @@ struct AppxSearchInfo APPX_SEARCH[] = { { L"PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0", L"3.8", 10 }, // Side-loadable releases. Note that the publisher ID changes whenever we - // renew our code-signing certificate, so the newer ID has a higher - // priority (lower sortKey) + // change our code signing certificate subject, so the newer IDs have higher + // priorities (lower sortKey) + { L"PythonSoftwareFoundation.Python.3.14_3847v3x7pw1km", L"3.14", 11 }, { L"PythonSoftwareFoundation.Python.3.13_3847v3x7pw1km", L"3.13", 11 }, { L"PythonSoftwareFoundation.Python.3.12_3847v3x7pw1km", L"3.12", 11 }, { L"PythonSoftwareFoundation.Python.3.11_3847v3x7pw1km", L"3.11", 11 }, @@ -2030,7 +2032,8 @@ struct StoreSearchInfo { struct StoreSearchInfo STORE_SEARCH[] = { - { L"3", /* 3.12 */ L"9NCVDN91XZQP" }, + { L"3", /* 3.13 */ L"9PNRBTZXMB4Z" }, + { L"3.14", L"9NTRHQCBBPR8" }, { L"3.13", L"9PNRBTZXMB4Z" }, { L"3.12", L"9NCVDN91XZQP" }, { L"3.11", L"9NRWMJP3717K" }, diff --git a/PC/pyconfig.h b/PC/pyconfig.h index 3415efe2..7815bfcf 100644 --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -161,9 +161,9 @@ WIN32 is still required for the locale module. #endif /* MS_WIN64 */ /* set the version macros for the windows headers */ -/* Python 3.9+ requires Windows 8 or greater */ -#define Py_WINVER 0x0602 /* _WIN32_WINNT_WIN8 */ -#define Py_NTDDI NTDDI_WIN8 +/* Python 3.12+ requires Windows 8.1 or greater */ +#define Py_WINVER 0x0603 /* _WIN32_WINNT_WINBLUE (8.1) */ +#define Py_NTDDI NTDDI_WINBLUE /* We only set these values when building Python - we don't want to force these values on extensions, as that will affect the prototypes and diff --git a/PCbuild/find_python.bat b/PCbuild/find_python.bat index 4f54bf75..34e98494 100644 --- a/PCbuild/find_python.bat +++ b/PCbuild/find_python.bat @@ -36,13 +36,15 @@ @if "%_Py_EXTERNALS_DIR%"=="" (set _Py_EXTERNALS_DIR=%_Py_D%\..\externals) @rem If we have Python in externals, use that one -@if exist "%_Py_EXTERNALS_DIR%\pythonx86\tools\python.exe" ("%_Py_EXTERNALS_DIR%\pythonx86\tools\python.exe" -Ec "import sys; assert sys.version_info[:2] >= (3, 8)" >nul 2>nul) && (set PYTHON="%_Py_EXTERNALS_DIR%\pythonx86\tools\python.exe") && (set _Py_Python_Source=found in externals directory) && goto :found || rmdir /Q /S "%_Py_EXTERNALS_DIR%\pythonx86" +@if exist "%_Py_EXTERNALS_DIR%\pythonx86\tools\python.exe" ("%_Py_EXTERNALS_DIR%\pythonx86\tools\python.exe" -Ec "import sys; assert sys.version_info[:2] >= (3, 10)" >nul 2>nul) && (set PYTHON="%_Py_EXTERNALS_DIR%\pythonx86\tools\python.exe") && (set _Py_Python_Source=found in externals directory) && goto :found || rmdir /Q /S "%_Py_EXTERNALS_DIR%\pythonx86" @rem If HOST_PYTHON is recent enough, use that -@if NOT "%HOST_PYTHON%"=="" @%HOST_PYTHON% -Ec "import sys; assert sys.version_info[:2] >= (3, 9)" >nul 2>nul && (set PYTHON="%HOST_PYTHON%") && (set _Py_Python_Source=found as HOST_PYTHON) && goto :found +@if NOT "%HOST_PYTHON%"=="" @%HOST_PYTHON% -Ec "import sys; assert sys.version_info[:2] >= (3, 10)" >nul 2>nul && (set PYTHON="%HOST_PYTHON%") && (set _Py_Python_Source=found as HOST_PYTHON) && goto :found @rem If py.exe finds a recent enough version, use that one -@for %%p in (3.11 3.10 3.9) do @py -%%p -EV >nul 2>&1 && (set PYTHON=py -%%p) && (set _Py_Python_Source=found %%p with py.exe) && goto :found +@rem It is fine to add new versions to this list when they have released, +@rem but we do not use prerelease builds here. +@for %%p in (3.13 3.12 3.11 3.10) do @py -%%p -EV >nul 2>&1 && (set PYTHON=py -%%p) && (set _Py_Python_Source=found %%p with py.exe) && goto :found @if NOT exist "%_Py_EXTERNALS_DIR%" mkdir "%_Py_EXTERNALS_DIR%" @set _Py_NUGET=%NUGET% diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat index 3ab35202..77b4fb81 100644 --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -53,10 +53,10 @@ echo.Fetching external libraries... set libraries= set libraries=%libraries% bzip2-1.0.8 if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.4.4 -if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-3.0.13 +if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-3.0.15 set libraries=%libraries% sqlite-3.45.3.0 -if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-core-8.6.13.0 -if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-8.6.13.0 +if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-core-8.6.15.0 +if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-8.6.15.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tix-8.4.3.6 set libraries=%libraries% xz-5.2.5 set libraries=%libraries% zlib-1.3.1 @@ -77,8 +77,8 @@ echo.Fetching external binaries... set binaries= if NOT "%IncludeLibffi%"=="false" set binaries=%binaries% libffi-3.4.4 -if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-3.0.13 -if NOT "%IncludeTkinter%"=="false" set binaries=%binaries% tcltk-8.6.13.0 +if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-3.0.15 +if NOT "%IncludeTkinter%"=="false" set binaries=%binaries% tcltk-8.6.15.2 if NOT "%IncludeSSLSrc%"=="false" set binaries=%binaries% nasm-2.11.06 for %%b in (%binaries%) do ( diff --git a/PCbuild/python.props b/PCbuild/python.props index 8120c75e..7bcf1726 100644 --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -74,8 +74,8 @@ $(ExternalsDir)libffi-3.4.4\ $(libffiDir)$(ArchName)\ $(libffiOutDir)include - $(ExternalsDir)openssl-3.0.13\ - $(ExternalsDir)openssl-bin-3.0.13\$(ArchName)\ + $(ExternalsDir)openssl-3.0.15\ + $(ExternalsDir)openssl-bin-3.0.15\$(ArchName)\ $(opensslOutDir)include $(ExternalsDir)\nasm-2.11.06\ $(ExternalsDir)\zlib-1.3.1\ diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index 7340861d..f330eb12 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -193,7 +193,7 @@ _sqlite3 Homepage: https://www.sqlite.org/ _tkinter - Wraps version 8.6.6 of the Tk windowing system, which is downloaded + Wraps version 8.6.15 of the Tk windowing system, which is downloaded from our binaries repository at https://github.com/python/cpython-bin-deps. diff --git a/PCbuild/tcltk.props b/PCbuild/tcltk.props index 53392c1d..173fad74 100644 --- a/PCbuild/tcltk.props +++ b/PCbuild/tcltk.props @@ -2,7 +2,7 @@ - 8.6.13.0 + 8.6.15.2 $(TclVersion) 8.4.3.6 $([System.Version]::Parse($(TclVersion)).Major) diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index e68a9cac..be52d894 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -1,1680 +1,1611 @@ #include #include "pegen.h" -#include "tokenizer.h" +#include "pycore_runtime.h" // _PyRuntime #include "string_parser.h" -#include "pycore_runtime.h" // _PyRuntime +#include "tokenizer.h" +#include "pycore_pystate.h" // _PyInterpreterState_GET() -void * -_PyPegen_dummy_name(Parser *p, ...) -{ - return &_PyRuntime.parser.dummy_name; +void *_PyPegen_dummy_name(Parser *p, ...) { + return &_PyRuntime.parser.dummy_name; } /* Creates a single-element asdl_seq* that contains a */ -asdl_seq * -_PyPegen_singleton_seq(Parser *p, void *a) -{ - assert(a != NULL); - asdl_seq *seq = (asdl_seq*)_Py_asdl_generic_seq_new(1, p->arena); - if (!seq) { - return NULL; - } - asdl_seq_SET_UNTYPED(seq, 0, a); - return seq; +asdl_seq *_PyPegen_singleton_seq(Parser *p, void *a) { + assert(a != NULL); + asdl_seq *seq = (asdl_seq *)_Py_asdl_generic_seq_new(1, p->arena); + if (!seq) { + return NULL; + } + asdl_seq_SET_UNTYPED(seq, 0, a); + return seq; } /* Creates a copy of seq and prepends a to it */ -asdl_seq * -_PyPegen_seq_insert_in_front(Parser *p, void *a, asdl_seq *seq) -{ - assert(a != NULL); - if (!seq) { - return _PyPegen_singleton_seq(p, a); - } +asdl_seq *_PyPegen_seq_insert_in_front(Parser *p, void *a, asdl_seq *seq) { + assert(a != NULL); + if (!seq) { + return _PyPegen_singleton_seq(p, a); + } - asdl_seq *new_seq = (asdl_seq*)_Py_asdl_generic_seq_new(asdl_seq_LEN(seq) + 1, p->arena); - if (!new_seq) { - return NULL; - } + asdl_seq *new_seq = + (asdl_seq *)_Py_asdl_generic_seq_new(asdl_seq_LEN(seq) + 1, p->arena); + if (!new_seq) { + return NULL; + } - asdl_seq_SET_UNTYPED(new_seq, 0, a); - for (Py_ssize_t i = 1, l = asdl_seq_LEN(new_seq); i < l; i++) { - asdl_seq_SET_UNTYPED(new_seq, i, asdl_seq_GET_UNTYPED(seq, i - 1)); - } - return new_seq; + asdl_seq_SET_UNTYPED(new_seq, 0, a); + for (Py_ssize_t i = 1, l = asdl_seq_LEN(new_seq); i < l; i++) { + asdl_seq_SET_UNTYPED(new_seq, i, asdl_seq_GET_UNTYPED(seq, i - 1)); + } + return new_seq; } /* Creates a copy of seq and appends a to it */ -asdl_seq * -_PyPegen_seq_append_to_end(Parser *p, asdl_seq *seq, void *a) -{ - assert(a != NULL); - if (!seq) { - return _PyPegen_singleton_seq(p, a); - } - - asdl_seq *new_seq = (asdl_seq*)_Py_asdl_generic_seq_new(asdl_seq_LEN(seq) + 1, p->arena); - if (!new_seq) { - return NULL; - } - - for (Py_ssize_t i = 0, l = asdl_seq_LEN(new_seq); i + 1 < l; i++) { - asdl_seq_SET_UNTYPED(new_seq, i, asdl_seq_GET_UNTYPED(seq, i)); - } - asdl_seq_SET_UNTYPED(new_seq, asdl_seq_LEN(new_seq) - 1, a); - return new_seq; -} - -static Py_ssize_t -_get_flattened_seq_size(asdl_seq *seqs) -{ - Py_ssize_t size = 0; - for (Py_ssize_t i = 0, l = asdl_seq_LEN(seqs); i < l; i++) { - asdl_seq *inner_seq = asdl_seq_GET_UNTYPED(seqs, i); - size += asdl_seq_LEN(inner_seq); - } - return size; +asdl_seq *_PyPegen_seq_append_to_end(Parser *p, asdl_seq *seq, void *a) { + assert(a != NULL); + if (!seq) { + return _PyPegen_singleton_seq(p, a); + } + + asdl_seq *new_seq = + (asdl_seq *)_Py_asdl_generic_seq_new(asdl_seq_LEN(seq) + 1, p->arena); + if (!new_seq) { + return NULL; + } + + for (Py_ssize_t i = 0, l = asdl_seq_LEN(new_seq); i + 1 < l; i++) { + asdl_seq_SET_UNTYPED(new_seq, i, asdl_seq_GET_UNTYPED(seq, i)); + } + asdl_seq_SET_UNTYPED(new_seq, asdl_seq_LEN(new_seq) - 1, a); + return new_seq; +} + +static Py_ssize_t _get_flattened_seq_size(asdl_seq *seqs) { + Py_ssize_t size = 0; + for (Py_ssize_t i = 0, l = asdl_seq_LEN(seqs); i < l; i++) { + asdl_seq *inner_seq = asdl_seq_GET_UNTYPED(seqs, i); + size += asdl_seq_LEN(inner_seq); + } + return size; } /* Flattens an asdl_seq* of asdl_seq*s */ -asdl_seq * -_PyPegen_seq_flatten(Parser *p, asdl_seq *seqs) -{ - Py_ssize_t flattened_seq_size = _get_flattened_seq_size(seqs); - assert(flattened_seq_size > 0); - - asdl_seq *flattened_seq = (asdl_seq*)_Py_asdl_generic_seq_new(flattened_seq_size, p->arena); - if (!flattened_seq) { - return NULL; - } +asdl_seq *_PyPegen_seq_flatten(Parser *p, asdl_seq *seqs) { + Py_ssize_t flattened_seq_size = _get_flattened_seq_size(seqs); + assert(flattened_seq_size > 0); - int flattened_seq_idx = 0; - for (Py_ssize_t i = 0, l = asdl_seq_LEN(seqs); i < l; i++) { - asdl_seq *inner_seq = asdl_seq_GET_UNTYPED(seqs, i); - for (Py_ssize_t j = 0, li = asdl_seq_LEN(inner_seq); j < li; j++) { - asdl_seq_SET_UNTYPED(flattened_seq, flattened_seq_idx++, asdl_seq_GET_UNTYPED(inner_seq, j)); - } + asdl_seq *flattened_seq = + (asdl_seq *)_Py_asdl_generic_seq_new(flattened_seq_size, p->arena); + if (!flattened_seq) { + return NULL; + } + + int flattened_seq_idx = 0; + for (Py_ssize_t i = 0, l = asdl_seq_LEN(seqs); i < l; i++) { + asdl_seq *inner_seq = asdl_seq_GET_UNTYPED(seqs, i); + for (Py_ssize_t j = 0, li = asdl_seq_LEN(inner_seq); j < li; j++) { + asdl_seq_SET_UNTYPED(flattened_seq, flattened_seq_idx++, + asdl_seq_GET_UNTYPED(inner_seq, j)); } - assert(flattened_seq_idx == flattened_seq_size); + } + assert(flattened_seq_idx == flattened_seq_size); - return flattened_seq; + return flattened_seq; } -void * -_PyPegen_seq_last_item(asdl_seq *seq) -{ - Py_ssize_t len = asdl_seq_LEN(seq); - return asdl_seq_GET_UNTYPED(seq, len - 1); +void *_PyPegen_seq_last_item(asdl_seq *seq) { + Py_ssize_t len = asdl_seq_LEN(seq); + return asdl_seq_GET_UNTYPED(seq, len - 1); } -void * -_PyPegen_seq_first_item(asdl_seq *seq) -{ - return asdl_seq_GET_UNTYPED(seq, 0); +void *_PyPegen_seq_first_item(asdl_seq *seq) { + return asdl_seq_GET_UNTYPED(seq, 0); } /* Creates a new name of the form . */ -expr_ty -_PyPegen_join_names_with_dot(Parser *p, expr_ty first_name, expr_ty second_name) -{ - assert(first_name != NULL && second_name != NULL); - PyObject *first_identifier = first_name->v.Name.id; - PyObject *second_identifier = second_name->v.Name.id; - - if (PyUnicode_READY(first_identifier) == -1) { - return NULL; - } - if (PyUnicode_READY(second_identifier) == -1) { - return NULL; - } - const char *first_str = PyUnicode_AsUTF8(first_identifier); - if (!first_str) { - return NULL; - } - const char *second_str = PyUnicode_AsUTF8(second_identifier); - if (!second_str) { - return NULL; - } - Py_ssize_t len = strlen(first_str) + strlen(second_str) + 1; // +1 for the dot - - PyObject *str = PyBytes_FromStringAndSize(NULL, len); - if (!str) { - return NULL; - } - - char *s = PyBytes_AS_STRING(str); - if (!s) { - return NULL; - } - - strcpy(s, first_str); - s += strlen(first_str); - *s++ = '.'; - strcpy(s, second_str); - s += strlen(second_str); - *s = '\0'; - - PyObject *uni = PyUnicode_DecodeUTF8(PyBytes_AS_STRING(str), PyBytes_GET_SIZE(str), NULL); - Py_DECREF(str); - if (!uni) { - return NULL; - } - PyUnicode_InternInPlace(&uni); - if (_PyArena_AddPyObject(p->arena, uni) < 0) { - Py_DECREF(uni); - return NULL; - } - - return _PyAST_Name(uni, Load, EXTRA_EXPR(first_name, second_name)); +expr_ty _PyPegen_join_names_with_dot(Parser *p, expr_ty first_name, + expr_ty second_name) { + assert(first_name != NULL && second_name != NULL); + PyObject *first_identifier = first_name->v.Name.id; + PyObject *second_identifier = second_name->v.Name.id; + + if (PyUnicode_READY(first_identifier) == -1) { + return NULL; + } + if (PyUnicode_READY(second_identifier) == -1) { + return NULL; + } + const char *first_str = PyUnicode_AsUTF8(first_identifier); + if (!first_str) { + return NULL; + } + const char *second_str = PyUnicode_AsUTF8(second_identifier); + if (!second_str) { + return NULL; + } + Py_ssize_t len = strlen(first_str) + strlen(second_str) + 1; // +1 for the dot + + PyObject *str = PyBytes_FromStringAndSize(NULL, len); + if (!str) { + return NULL; + } + + char *s = PyBytes_AS_STRING(str); + if (!s) { + return NULL; + } + + strcpy(s, first_str); + s += strlen(first_str); + *s++ = '.'; + strcpy(s, second_str); + s += strlen(second_str); + *s = '\0'; + + PyObject *uni = + PyUnicode_DecodeUTF8(PyBytes_AS_STRING(str), PyBytes_GET_SIZE(str), NULL); + Py_DECREF(str); + if (!uni) { + return NULL; + } + PyInterpreterState *interp = _PyInterpreterState_GET(); + _PyUnicode_InternMortal(interp, &uni); + if (_PyArena_AddPyObject(p->arena, uni) < 0) { + Py_DECREF(uni); + return NULL; + } + + return _PyAST_Name(uni, Load, EXTRA_EXPR(first_name, second_name)); } /* Counts the total number of dots in seq's tokens */ -int -_PyPegen_seq_count_dots(asdl_seq *seq) -{ - int number_of_dots = 0; - for (Py_ssize_t i = 0, l = asdl_seq_LEN(seq); i < l; i++) { - Token *current_expr = asdl_seq_GET_UNTYPED(seq, i); - switch (current_expr->type) { - case ELLIPSIS: - number_of_dots += 3; - break; - case DOT: - number_of_dots += 1; - break; - default: - Py_UNREACHABLE(); - } +int _PyPegen_seq_count_dots(asdl_seq *seq) { + int number_of_dots = 0; + for (Py_ssize_t i = 0, l = asdl_seq_LEN(seq); i < l; i++) { + Token *current_expr = asdl_seq_GET_UNTYPED(seq, i); + switch (current_expr->type) { + case ELLIPSIS: + number_of_dots += 3; + break; + case DOT: + number_of_dots += 1; + break; + default: + Py_UNREACHABLE(); } + } - return number_of_dots; + return number_of_dots; } /* Creates an alias with '*' as the identifier name */ -alias_ty -_PyPegen_alias_for_star(Parser *p, int lineno, int col_offset, int end_lineno, - int end_col_offset, PyArena *arena) { - PyObject *str = PyUnicode_InternFromString("*"); - if (!str) { - return NULL; - } - if (_PyArena_AddPyObject(p->arena, str) < 0) { - Py_DECREF(str); - return NULL; - } - return _PyAST_alias(str, NULL, lineno, col_offset, end_lineno, end_col_offset, arena); +alias_ty _PyPegen_alias_for_star(Parser *p, int lineno, int col_offset, + int end_lineno, int end_col_offset, + PyArena *arena) { + PyObject *str = PyUnicode_InternFromString("*"); + if (!str) { + return NULL; + } + if (_PyArena_AddPyObject(p->arena, str) < 0) { + Py_DECREF(str); + return NULL; + } + return _PyAST_alias(str, NULL, lineno, col_offset, end_lineno, end_col_offset, + arena); } /* Creates a new asdl_seq* with the identifiers of all the names in seq */ -asdl_identifier_seq * -_PyPegen_map_names_to_ids(Parser *p, asdl_expr_seq *seq) -{ - Py_ssize_t len = asdl_seq_LEN(seq); - assert(len > 0); - - asdl_identifier_seq *new_seq = _Py_asdl_identifier_seq_new(len, p->arena); - if (!new_seq) { - return NULL; - } - for (Py_ssize_t i = 0; i < len; i++) { - expr_ty e = asdl_seq_GET(seq, i); - asdl_seq_SET(new_seq, i, e->v.Name.id); - } - return new_seq; +asdl_identifier_seq *_PyPegen_map_names_to_ids(Parser *p, asdl_expr_seq *seq) { + Py_ssize_t len = asdl_seq_LEN(seq); + assert(len > 0); + + asdl_identifier_seq *new_seq = _Py_asdl_identifier_seq_new(len, p->arena); + if (!new_seq) { + return NULL; + } + for (Py_ssize_t i = 0; i < len; i++) { + expr_ty e = asdl_seq_GET(seq, i); + asdl_seq_SET(new_seq, i, e->v.Name.id); + } + return new_seq; } /* Constructs a CmpopExprPair */ -CmpopExprPair * -_PyPegen_cmpop_expr_pair(Parser *p, cmpop_ty cmpop, expr_ty expr) -{ - assert(expr != NULL); - CmpopExprPair *a = _PyArena_Malloc(p->arena, sizeof(CmpopExprPair)); - if (!a) { - return NULL; - } - a->cmpop = cmpop; - a->expr = expr; - return a; +CmpopExprPair *_PyPegen_cmpop_expr_pair(Parser *p, cmpop_ty cmpop, + expr_ty expr) { + assert(expr != NULL); + CmpopExprPair *a = _PyArena_Malloc(p->arena, sizeof(CmpopExprPair)); + if (!a) { + return NULL; + } + a->cmpop = cmpop; + a->expr = expr; + return a; } -asdl_int_seq * -_PyPegen_get_cmpops(Parser *p, asdl_seq *seq) -{ - Py_ssize_t len = asdl_seq_LEN(seq); - assert(len > 0); +asdl_int_seq *_PyPegen_get_cmpops(Parser *p, asdl_seq *seq) { + Py_ssize_t len = asdl_seq_LEN(seq); + assert(len > 0); - asdl_int_seq *new_seq = _Py_asdl_int_seq_new(len, p->arena); - if (!new_seq) { - return NULL; - } - for (Py_ssize_t i = 0; i < len; i++) { - CmpopExprPair *pair = asdl_seq_GET_UNTYPED(seq, i); - asdl_seq_SET(new_seq, i, pair->cmpop); - } - return new_seq; + asdl_int_seq *new_seq = _Py_asdl_int_seq_new(len, p->arena); + if (!new_seq) { + return NULL; + } + for (Py_ssize_t i = 0; i < len; i++) { + CmpopExprPair *pair = asdl_seq_GET_UNTYPED(seq, i); + asdl_seq_SET(new_seq, i, pair->cmpop); + } + return new_seq; } -asdl_expr_seq * -_PyPegen_get_exprs(Parser *p, asdl_seq *seq) -{ - Py_ssize_t len = asdl_seq_LEN(seq); - assert(len > 0); +asdl_expr_seq *_PyPegen_get_exprs(Parser *p, asdl_seq *seq) { + Py_ssize_t len = asdl_seq_LEN(seq); + assert(len > 0); - asdl_expr_seq *new_seq = _Py_asdl_expr_seq_new(len, p->arena); - if (!new_seq) { - return NULL; - } - for (Py_ssize_t i = 0; i < len; i++) { - CmpopExprPair *pair = asdl_seq_GET_UNTYPED(seq, i); - asdl_seq_SET(new_seq, i, pair->expr); - } - return new_seq; + asdl_expr_seq *new_seq = _Py_asdl_expr_seq_new(len, p->arena); + if (!new_seq) { + return NULL; + } + for (Py_ssize_t i = 0; i < len; i++) { + CmpopExprPair *pair = asdl_seq_GET_UNTYPED(seq, i); + asdl_seq_SET(new_seq, i, pair->expr); + } + return new_seq; } -/* Creates an asdl_seq* where all the elements have been changed to have ctx as context */ -static asdl_expr_seq * -_set_seq_context(Parser *p, asdl_expr_seq *seq, expr_context_ty ctx) -{ - Py_ssize_t len = asdl_seq_LEN(seq); - if (len == 0) { - return NULL; - } +/* Creates an asdl_seq* where all the elements have been changed to have ctx as + * context */ +static asdl_expr_seq *_set_seq_context(Parser *p, asdl_expr_seq *seq, + expr_context_ty ctx) { + Py_ssize_t len = asdl_seq_LEN(seq); + if (len == 0) { + return NULL; + } - asdl_expr_seq *new_seq = _Py_asdl_expr_seq_new(len, p->arena); - if (!new_seq) { - return NULL; - } - for (Py_ssize_t i = 0; i < len; i++) { - expr_ty e = asdl_seq_GET(seq, i); - asdl_seq_SET(new_seq, i, _PyPegen_set_expr_context(p, e, ctx)); - } - return new_seq; + asdl_expr_seq *new_seq = _Py_asdl_expr_seq_new(len, p->arena); + if (!new_seq) { + return NULL; + } + for (Py_ssize_t i = 0; i < len; i++) { + expr_ty e = asdl_seq_GET(seq, i); + asdl_seq_SET(new_seq, i, _PyPegen_set_expr_context(p, e, ctx)); + } + return new_seq; } -static expr_ty -_set_name_context(Parser *p, expr_ty e, expr_context_ty ctx) -{ - return _PyAST_Name(e->v.Name.id, ctx, EXTRA_EXPR(e, e)); +static expr_ty _set_name_context(Parser *p, expr_ty e, expr_context_ty ctx) { + return _PyAST_Name(e->v.Name.id, ctx, EXTRA_EXPR(e, e)); } -static expr_ty -_set_tuple_context(Parser *p, expr_ty e, expr_context_ty ctx) -{ - return _PyAST_Tuple( - _set_seq_context(p, e->v.Tuple.elts, ctx), - ctx, - EXTRA_EXPR(e, e)); +static expr_ty _set_tuple_context(Parser *p, expr_ty e, expr_context_ty ctx) { + return _PyAST_Tuple(_set_seq_context(p, e->v.Tuple.elts, ctx), ctx, + EXTRA_EXPR(e, e)); } -static expr_ty -_set_list_context(Parser *p, expr_ty e, expr_context_ty ctx) -{ - return _PyAST_List( - _set_seq_context(p, e->v.List.elts, ctx), - ctx, - EXTRA_EXPR(e, e)); +static expr_ty _set_list_context(Parser *p, expr_ty e, expr_context_ty ctx) { + return _PyAST_List(_set_seq_context(p, e->v.List.elts, ctx), ctx, + EXTRA_EXPR(e, e)); } -static expr_ty -_set_subscript_context(Parser *p, expr_ty e, expr_context_ty ctx) -{ - return _PyAST_Subscript(e->v.Subscript.value, e->v.Subscript.slice, - ctx, EXTRA_EXPR(e, e)); +static expr_ty _set_subscript_context(Parser *p, expr_ty e, + expr_context_ty ctx) { + return _PyAST_Subscript(e->v.Subscript.value, e->v.Subscript.slice, ctx, + EXTRA_EXPR(e, e)); } -static expr_ty -_set_attribute_context(Parser *p, expr_ty e, expr_context_ty ctx) -{ - return _PyAST_Attribute(e->v.Attribute.value, e->v.Attribute.attr, - ctx, EXTRA_EXPR(e, e)); +static expr_ty _set_attribute_context(Parser *p, expr_ty e, + expr_context_ty ctx) { + return _PyAST_Attribute(e->v.Attribute.value, e->v.Attribute.attr, ctx, + EXTRA_EXPR(e, e)); } -static expr_ty -_set_starred_context(Parser *p, expr_ty e, expr_context_ty ctx) -{ - return _PyAST_Starred(_PyPegen_set_expr_context(p, e->v.Starred.value, ctx), - ctx, EXTRA_EXPR(e, e)); +static expr_ty _set_starred_context(Parser *p, expr_ty e, expr_context_ty ctx) { + return _PyAST_Starred(_PyPegen_set_expr_context(p, e->v.Starred.value, ctx), + ctx, EXTRA_EXPR(e, e)); } /* Creates an `expr_ty` equivalent to `expr` but with `ctx` as context */ -expr_ty -_PyPegen_set_expr_context(Parser *p, expr_ty expr, expr_context_ty ctx) -{ - assert(expr != NULL); - - expr_ty new = NULL; - switch (expr->kind) { - case Name_kind: - new = _set_name_context(p, expr, ctx); - break; - case Tuple_kind: - new = _set_tuple_context(p, expr, ctx); - break; - case List_kind: - new = _set_list_context(p, expr, ctx); - break; - case Subscript_kind: - new = _set_subscript_context(p, expr, ctx); - break; - case Attribute_kind: - new = _set_attribute_context(p, expr, ctx); - break; - case Starred_kind: - new = _set_starred_context(p, expr, ctx); - break; - default: - new = expr; - } - return new; -} - -/* Constructs a KeyValuePair that is used when parsing a dict's key value pairs */ -KeyValuePair * -_PyPegen_key_value_pair(Parser *p, expr_ty key, expr_ty value) -{ - KeyValuePair *a = _PyArena_Malloc(p->arena, sizeof(KeyValuePair)); - if (!a) { - return NULL; - } - a->key = key; - a->value = value; - return a; +expr_ty _PyPegen_set_expr_context(Parser *p, expr_ty expr, + expr_context_ty ctx) { + assert(expr != NULL); + + expr_ty new = NULL; + switch (expr->kind) { + case Name_kind: + new = _set_name_context(p, expr, ctx); + break; + case Tuple_kind: + new = _set_tuple_context(p, expr, ctx); + break; + case List_kind: + new = _set_list_context(p, expr, ctx); + break; + case Subscript_kind: + new = _set_subscript_context(p, expr, ctx); + break; + case Attribute_kind: + new = _set_attribute_context(p, expr, ctx); + break; + case Starred_kind: + new = _set_starred_context(p, expr, ctx); + break; + default: + new = expr; + } + return new; +} + +/* Constructs a KeyValuePair that is used when parsing a dict's key value pairs + */ +KeyValuePair *_PyPegen_key_value_pair(Parser *p, expr_ty key, expr_ty value) { + KeyValuePair *a = _PyArena_Malloc(p->arena, sizeof(KeyValuePair)); + if (!a) { + return NULL; + } + a->key = key; + a->value = value; + return a; } /* Extracts all keys from an asdl_seq* of KeyValuePair*'s */ -asdl_expr_seq * -_PyPegen_get_keys(Parser *p, asdl_seq *seq) -{ - Py_ssize_t len = asdl_seq_LEN(seq); - asdl_expr_seq *new_seq = _Py_asdl_expr_seq_new(len, p->arena); - if (!new_seq) { - return NULL; - } - for (Py_ssize_t i = 0; i < len; i++) { - KeyValuePair *pair = asdl_seq_GET_UNTYPED(seq, i); - asdl_seq_SET(new_seq, i, pair->key); - } - return new_seq; +asdl_expr_seq *_PyPegen_get_keys(Parser *p, asdl_seq *seq) { + Py_ssize_t len = asdl_seq_LEN(seq); + asdl_expr_seq *new_seq = _Py_asdl_expr_seq_new(len, p->arena); + if (!new_seq) { + return NULL; + } + for (Py_ssize_t i = 0; i < len; i++) { + KeyValuePair *pair = asdl_seq_GET_UNTYPED(seq, i); + asdl_seq_SET(new_seq, i, pair->key); + } + return new_seq; } /* Extracts all values from an asdl_seq* of KeyValuePair*'s */ -asdl_expr_seq * -_PyPegen_get_values(Parser *p, asdl_seq *seq) -{ - Py_ssize_t len = asdl_seq_LEN(seq); - asdl_expr_seq *new_seq = _Py_asdl_expr_seq_new(len, p->arena); - if (!new_seq) { - return NULL; - } - for (Py_ssize_t i = 0; i < len; i++) { - KeyValuePair *pair = asdl_seq_GET_UNTYPED(seq, i); - asdl_seq_SET(new_seq, i, pair->value); - } - return new_seq; -} - -/* Constructs a KeyPatternPair that is used when parsing mapping & class patterns */ -KeyPatternPair * -_PyPegen_key_pattern_pair(Parser *p, expr_ty key, pattern_ty pattern) -{ - KeyPatternPair *a = _PyArena_Malloc(p->arena, sizeof(KeyPatternPair)); - if (!a) { - return NULL; - } - a->key = key; - a->pattern = pattern; - return a; +asdl_expr_seq *_PyPegen_get_values(Parser *p, asdl_seq *seq) { + Py_ssize_t len = asdl_seq_LEN(seq); + asdl_expr_seq *new_seq = _Py_asdl_expr_seq_new(len, p->arena); + if (!new_seq) { + return NULL; + } + for (Py_ssize_t i = 0; i < len; i++) { + KeyValuePair *pair = asdl_seq_GET_UNTYPED(seq, i); + asdl_seq_SET(new_seq, i, pair->value); + } + return new_seq; +} + +/* Constructs a KeyPatternPair that is used when parsing mapping & class + * patterns */ +KeyPatternPair *_PyPegen_key_pattern_pair(Parser *p, expr_ty key, + pattern_ty pattern) { + KeyPatternPair *a = _PyArena_Malloc(p->arena, sizeof(KeyPatternPair)); + if (!a) { + return NULL; + } + a->key = key; + a->pattern = pattern; + return a; } /* Extracts all keys from an asdl_seq* of KeyPatternPair*'s */ -asdl_expr_seq * -_PyPegen_get_pattern_keys(Parser *p, asdl_seq *seq) -{ - Py_ssize_t len = asdl_seq_LEN(seq); - asdl_expr_seq *new_seq = _Py_asdl_expr_seq_new(len, p->arena); - if (!new_seq) { - return NULL; - } - for (Py_ssize_t i = 0; i < len; i++) { - KeyPatternPair *pair = asdl_seq_GET_UNTYPED(seq, i); - asdl_seq_SET(new_seq, i, pair->key); - } - return new_seq; +asdl_expr_seq *_PyPegen_get_pattern_keys(Parser *p, asdl_seq *seq) { + Py_ssize_t len = asdl_seq_LEN(seq); + asdl_expr_seq *new_seq = _Py_asdl_expr_seq_new(len, p->arena); + if (!new_seq) { + return NULL; + } + for (Py_ssize_t i = 0; i < len; i++) { + KeyPatternPair *pair = asdl_seq_GET_UNTYPED(seq, i); + asdl_seq_SET(new_seq, i, pair->key); + } + return new_seq; } /* Extracts all patterns from an asdl_seq* of KeyPatternPair*'s */ -asdl_pattern_seq * -_PyPegen_get_patterns(Parser *p, asdl_seq *seq) -{ - Py_ssize_t len = asdl_seq_LEN(seq); - asdl_pattern_seq *new_seq = _Py_asdl_pattern_seq_new(len, p->arena); - if (!new_seq) { - return NULL; - } - for (Py_ssize_t i = 0; i < len; i++) { - KeyPatternPair *pair = asdl_seq_GET_UNTYPED(seq, i); - asdl_seq_SET(new_seq, i, pair->pattern); - } - return new_seq; +asdl_pattern_seq *_PyPegen_get_patterns(Parser *p, asdl_seq *seq) { + Py_ssize_t len = asdl_seq_LEN(seq); + asdl_pattern_seq *new_seq = _Py_asdl_pattern_seq_new(len, p->arena); + if (!new_seq) { + return NULL; + } + for (Py_ssize_t i = 0; i < len; i++) { + KeyPatternPair *pair = asdl_seq_GET_UNTYPED(seq, i); + asdl_seq_SET(new_seq, i, pair->pattern); + } + return new_seq; } /* Constructs a NameDefaultPair */ -NameDefaultPair * -_PyPegen_name_default_pair(Parser *p, arg_ty arg, expr_ty value, Token *tc) -{ - NameDefaultPair *a = _PyArena_Malloc(p->arena, sizeof(NameDefaultPair)); - if (!a) { - return NULL; - } - a->arg = _PyPegen_add_type_comment_to_arg(p, arg, tc); - a->value = value; - return a; +NameDefaultPair *_PyPegen_name_default_pair(Parser *p, arg_ty arg, + expr_ty value, Token *tc) { + NameDefaultPair *a = _PyArena_Malloc(p->arena, sizeof(NameDefaultPair)); + if (!a) { + return NULL; + } + a->arg = _PyPegen_add_type_comment_to_arg(p, arg, tc); + a->value = value; + return a; } /* Constructs a SlashWithDefault */ -SlashWithDefault * -_PyPegen_slash_with_default(Parser *p, asdl_arg_seq *plain_names, asdl_seq *names_with_defaults) -{ - SlashWithDefault *a = _PyArena_Malloc(p->arena, sizeof(SlashWithDefault)); - if (!a) { - return NULL; - } - a->plain_names = plain_names; - a->names_with_defaults = names_with_defaults; - return a; +SlashWithDefault *_PyPegen_slash_with_default(Parser *p, + asdl_arg_seq *plain_names, + asdl_seq *names_with_defaults) { + SlashWithDefault *a = _PyArena_Malloc(p->arena, sizeof(SlashWithDefault)); + if (!a) { + return NULL; + } + a->plain_names = plain_names; + a->names_with_defaults = names_with_defaults; + return a; } /* Constructs a StarEtc */ -StarEtc * -_PyPegen_star_etc(Parser *p, arg_ty vararg, asdl_seq *kwonlyargs, arg_ty kwarg) -{ - StarEtc *a = _PyArena_Malloc(p->arena, sizeof(StarEtc)); - if (!a) { - return NULL; - } - a->vararg = vararg; - a->kwonlyargs = kwonlyargs; - a->kwarg = kwarg; - return a; -} - -asdl_seq * -_PyPegen_join_sequences(Parser *p, asdl_seq *a, asdl_seq *b) -{ - Py_ssize_t first_len = asdl_seq_LEN(a); - Py_ssize_t second_len = asdl_seq_LEN(b); - asdl_seq *new_seq = (asdl_seq*)_Py_asdl_generic_seq_new(first_len + second_len, p->arena); - if (!new_seq) { - return NULL; - } - - int k = 0; - for (Py_ssize_t i = 0; i < first_len; i++) { - asdl_seq_SET_UNTYPED(new_seq, k++, asdl_seq_GET_UNTYPED(a, i)); - } - for (Py_ssize_t i = 0; i < second_len; i++) { - asdl_seq_SET_UNTYPED(new_seq, k++, asdl_seq_GET_UNTYPED(b, i)); - } - - return new_seq; -} - -static asdl_arg_seq* -_get_names(Parser *p, asdl_seq *names_with_defaults) -{ - Py_ssize_t len = asdl_seq_LEN(names_with_defaults); - asdl_arg_seq *seq = _Py_asdl_arg_seq_new(len, p->arena); - if (!seq) { - return NULL; - } - for (Py_ssize_t i = 0; i < len; i++) { - NameDefaultPair *pair = asdl_seq_GET_UNTYPED(names_with_defaults, i); - asdl_seq_SET(seq, i, pair->arg); - } - return seq; -} - -static asdl_expr_seq * -_get_defaults(Parser *p, asdl_seq *names_with_defaults) -{ - Py_ssize_t len = asdl_seq_LEN(names_with_defaults); - asdl_expr_seq *seq = _Py_asdl_expr_seq_new(len, p->arena); - if (!seq) { - return NULL; - } - for (Py_ssize_t i = 0; i < len; i++) { - NameDefaultPair *pair = asdl_seq_GET_UNTYPED(names_with_defaults, i); - asdl_seq_SET(seq, i, pair->value); - } - return seq; -} - -static int -_make_posonlyargs(Parser *p, - asdl_arg_seq *slash_without_default, - SlashWithDefault *slash_with_default, - asdl_arg_seq **posonlyargs) { - if (slash_without_default != NULL) { - *posonlyargs = slash_without_default; - } - else if (slash_with_default != NULL) { - asdl_arg_seq *slash_with_default_names = - _get_names(p, slash_with_default->names_with_defaults); - if (!slash_with_default_names) { - return -1; - } - *posonlyargs = (asdl_arg_seq*)_PyPegen_join_sequences( - p, - (asdl_seq*)slash_with_default->plain_names, - (asdl_seq*)slash_with_default_names); - } - else { - *posonlyargs = _Py_asdl_arg_seq_new(0, p->arena); - } - return *posonlyargs == NULL ? -1 : 0; -} - -static int -_make_posargs(Parser *p, - asdl_arg_seq *plain_names, - asdl_seq *names_with_default, - asdl_arg_seq **posargs) { - if (plain_names != NULL && names_with_default != NULL) { - asdl_arg_seq *names_with_default_names = _get_names(p, names_with_default); - if (!names_with_default_names) { - return -1; - } - *posargs = (asdl_arg_seq*)_PyPegen_join_sequences( - p,(asdl_seq*)plain_names, (asdl_seq*)names_with_default_names); - } - else if (plain_names == NULL && names_with_default != NULL) { - *posargs = _get_names(p, names_with_default); - } - else if (plain_names != NULL && names_with_default == NULL) { - *posargs = plain_names; - } - else { - *posargs = _Py_asdl_arg_seq_new(0, p->arena); - } - return *posargs == NULL ? -1 : 0; -} - -static int -_make_posdefaults(Parser *p, - SlashWithDefault *slash_with_default, - asdl_seq *names_with_default, - asdl_expr_seq **posdefaults) { - if (slash_with_default != NULL && names_with_default != NULL) { - asdl_expr_seq *slash_with_default_values = - _get_defaults(p, slash_with_default->names_with_defaults); - if (!slash_with_default_values) { - return -1; - } - asdl_expr_seq *names_with_default_values = _get_defaults(p, names_with_default); - if (!names_with_default_values) { - return -1; - } - *posdefaults = (asdl_expr_seq*)_PyPegen_join_sequences( - p, - (asdl_seq*)slash_with_default_values, - (asdl_seq*)names_with_default_values); - } - else if (slash_with_default == NULL && names_with_default != NULL) { - *posdefaults = _get_defaults(p, names_with_default); - } - else if (slash_with_default != NULL && names_with_default == NULL) { - *posdefaults = _get_defaults(p, slash_with_default->names_with_defaults); - } - else { - *posdefaults = _Py_asdl_expr_seq_new(0, p->arena); - } - return *posdefaults == NULL ? -1 : 0; -} - -static int -_make_kwargs(Parser *p, StarEtc *star_etc, - asdl_arg_seq **kwonlyargs, - asdl_expr_seq **kwdefaults) { - if (star_etc != NULL && star_etc->kwonlyargs != NULL) { - *kwonlyargs = _get_names(p, star_etc->kwonlyargs); - } - else { - *kwonlyargs = _Py_asdl_arg_seq_new(0, p->arena); - } - - if (*kwonlyargs == NULL) { - return -1; - } - - if (star_etc != NULL && star_etc->kwonlyargs != NULL) { - *kwdefaults = _get_defaults(p, star_etc->kwonlyargs); - } - else { - *kwdefaults = _Py_asdl_expr_seq_new(0, p->arena); - } - - if (*kwdefaults == NULL) { - return -1; - } - - return 0; -} - -/* Constructs an arguments_ty object out of all the parsed constructs in the parameters rule */ -arguments_ty -_PyPegen_make_arguments(Parser *p, asdl_arg_seq *slash_without_default, - SlashWithDefault *slash_with_default, asdl_arg_seq *plain_names, - asdl_seq *names_with_default, StarEtc *star_etc) -{ - asdl_arg_seq *posonlyargs; - if (_make_posonlyargs(p, slash_without_default, slash_with_default, &posonlyargs) == -1) { - return NULL; - } - - asdl_arg_seq *posargs; - if (_make_posargs(p, plain_names, names_with_default, &posargs) == -1) { - return NULL; - } - - asdl_expr_seq *posdefaults; - if (_make_posdefaults(p,slash_with_default, names_with_default, &posdefaults) == -1) { - return NULL; - } - - arg_ty vararg = NULL; - if (star_etc != NULL && star_etc->vararg != NULL) { - vararg = star_etc->vararg; - } - - asdl_arg_seq *kwonlyargs; - asdl_expr_seq *kwdefaults; - if (_make_kwargs(p, star_etc, &kwonlyargs, &kwdefaults) == -1) { - return NULL; - } - - arg_ty kwarg = NULL; - if (star_etc != NULL && star_etc->kwarg != NULL) { - kwarg = star_etc->kwarg; - } - - return _PyAST_arguments(posonlyargs, posargs, vararg, kwonlyargs, - kwdefaults, kwarg, posdefaults, p->arena); -} - - -/* Constructs an empty arguments_ty object, that gets used when a function accepts no - * arguments. */ -arguments_ty -_PyPegen_empty_arguments(Parser *p) -{ - asdl_arg_seq *posonlyargs = _Py_asdl_arg_seq_new(0, p->arena); - if (!posonlyargs) { - return NULL; - } - asdl_arg_seq *posargs = _Py_asdl_arg_seq_new(0, p->arena); - if (!posargs) { - return NULL; - } - asdl_expr_seq *posdefaults = _Py_asdl_expr_seq_new(0, p->arena); - if (!posdefaults) { - return NULL; - } - asdl_arg_seq *kwonlyargs = _Py_asdl_arg_seq_new(0, p->arena); - if (!kwonlyargs) { - return NULL; - } - asdl_expr_seq *kwdefaults = _Py_asdl_expr_seq_new(0, p->arena); - if (!kwdefaults) { - return NULL; - } - - return _PyAST_arguments(posonlyargs, posargs, NULL, kwonlyargs, - kwdefaults, NULL, posdefaults, p->arena); +StarEtc *_PyPegen_star_etc(Parser *p, arg_ty vararg, asdl_seq *kwonlyargs, + arg_ty kwarg) { + StarEtc *a = _PyArena_Malloc(p->arena, sizeof(StarEtc)); + if (!a) { + return NULL; + } + a->vararg = vararg; + a->kwonlyargs = kwonlyargs; + a->kwarg = kwarg; + return a; +} + +asdl_seq *_PyPegen_join_sequences(Parser *p, asdl_seq *a, asdl_seq *b) { + Py_ssize_t first_len = asdl_seq_LEN(a); + Py_ssize_t second_len = asdl_seq_LEN(b); + asdl_seq *new_seq = + (asdl_seq *)_Py_asdl_generic_seq_new(first_len + second_len, p->arena); + if (!new_seq) { + return NULL; + } + + int k = 0; + for (Py_ssize_t i = 0; i < first_len; i++) { + asdl_seq_SET_UNTYPED(new_seq, k++, asdl_seq_GET_UNTYPED(a, i)); + } + for (Py_ssize_t i = 0; i < second_len; i++) { + asdl_seq_SET_UNTYPED(new_seq, k++, asdl_seq_GET_UNTYPED(b, i)); + } + + return new_seq; +} + +static asdl_arg_seq *_get_names(Parser *p, asdl_seq *names_with_defaults) { + Py_ssize_t len = asdl_seq_LEN(names_with_defaults); + asdl_arg_seq *seq = _Py_asdl_arg_seq_new(len, p->arena); + if (!seq) { + return NULL; + } + for (Py_ssize_t i = 0; i < len; i++) { + NameDefaultPair *pair = asdl_seq_GET_UNTYPED(names_with_defaults, i); + asdl_seq_SET(seq, i, pair->arg); + } + return seq; +} + +static asdl_expr_seq *_get_defaults(Parser *p, asdl_seq *names_with_defaults) { + Py_ssize_t len = asdl_seq_LEN(names_with_defaults); + asdl_expr_seq *seq = _Py_asdl_expr_seq_new(len, p->arena); + if (!seq) { + return NULL; + } + for (Py_ssize_t i = 0; i < len; i++) { + NameDefaultPair *pair = asdl_seq_GET_UNTYPED(names_with_defaults, i); + asdl_seq_SET(seq, i, pair->value); + } + return seq; +} + +static int _make_posonlyargs(Parser *p, asdl_arg_seq *slash_without_default, + SlashWithDefault *slash_with_default, + asdl_arg_seq **posonlyargs) { + if (slash_without_default != NULL) { + *posonlyargs = slash_without_default; + } else if (slash_with_default != NULL) { + asdl_arg_seq *slash_with_default_names = + _get_names(p, slash_with_default->names_with_defaults); + if (!slash_with_default_names) { + return -1; + } + *posonlyargs = (asdl_arg_seq *)_PyPegen_join_sequences( + p, (asdl_seq *)slash_with_default->plain_names, + (asdl_seq *)slash_with_default_names); + } else { + *posonlyargs = _Py_asdl_arg_seq_new(0, p->arena); + } + return *posonlyargs == NULL ? -1 : 0; +} + +static int _make_posargs(Parser *p, asdl_arg_seq *plain_names, + asdl_seq *names_with_default, asdl_arg_seq **posargs) { + if (plain_names != NULL && names_with_default != NULL) { + asdl_arg_seq *names_with_default_names = _get_names(p, names_with_default); + if (!names_with_default_names) { + return -1; + } + *posargs = (asdl_arg_seq *)_PyPegen_join_sequences( + p, (asdl_seq *)plain_names, (asdl_seq *)names_with_default_names); + } else if (plain_names == NULL && names_with_default != NULL) { + *posargs = _get_names(p, names_with_default); + } else if (plain_names != NULL && names_with_default == NULL) { + *posargs = plain_names; + } else { + *posargs = _Py_asdl_arg_seq_new(0, p->arena); + } + return *posargs == NULL ? -1 : 0; +} + +static int _make_posdefaults(Parser *p, SlashWithDefault *slash_with_default, + asdl_seq *names_with_default, + asdl_expr_seq **posdefaults) { + if (slash_with_default != NULL && names_with_default != NULL) { + asdl_expr_seq *slash_with_default_values = + _get_defaults(p, slash_with_default->names_with_defaults); + if (!slash_with_default_values) { + return -1; + } + asdl_expr_seq *names_with_default_values = + _get_defaults(p, names_with_default); + if (!names_with_default_values) { + return -1; + } + *posdefaults = (asdl_expr_seq *)_PyPegen_join_sequences( + p, (asdl_seq *)slash_with_default_values, + (asdl_seq *)names_with_default_values); + } else if (slash_with_default == NULL && names_with_default != NULL) { + *posdefaults = _get_defaults(p, names_with_default); + } else if (slash_with_default != NULL && names_with_default == NULL) { + *posdefaults = _get_defaults(p, slash_with_default->names_with_defaults); + } else { + *posdefaults = _Py_asdl_expr_seq_new(0, p->arena); + } + return *posdefaults == NULL ? -1 : 0; +} + +static int _make_kwargs(Parser *p, StarEtc *star_etc, asdl_arg_seq **kwonlyargs, + asdl_expr_seq **kwdefaults) { + if (star_etc != NULL && star_etc->kwonlyargs != NULL) { + *kwonlyargs = _get_names(p, star_etc->kwonlyargs); + } else { + *kwonlyargs = _Py_asdl_arg_seq_new(0, p->arena); + } + + if (*kwonlyargs == NULL) { + return -1; + } + + if (star_etc != NULL && star_etc->kwonlyargs != NULL) { + *kwdefaults = _get_defaults(p, star_etc->kwonlyargs); + } else { + *kwdefaults = _Py_asdl_expr_seq_new(0, p->arena); + } + + if (*kwdefaults == NULL) { + return -1; + } + + return 0; +} + +/* Constructs an arguments_ty object out of all the parsed constructs in the + * parameters rule */ +arguments_ty _PyPegen_make_arguments(Parser *p, + asdl_arg_seq *slash_without_default, + SlashWithDefault *slash_with_default, + asdl_arg_seq *plain_names, + asdl_seq *names_with_default, + StarEtc *star_etc) { + asdl_arg_seq *posonlyargs; + if (_make_posonlyargs(p, slash_without_default, slash_with_default, + &posonlyargs) == -1) { + return NULL; + } + + asdl_arg_seq *posargs; + if (_make_posargs(p, plain_names, names_with_default, &posargs) == -1) { + return NULL; + } + + asdl_expr_seq *posdefaults; + if (_make_posdefaults(p, slash_with_default, names_with_default, + &posdefaults) == -1) { + return NULL; + } + + arg_ty vararg = NULL; + if (star_etc != NULL && star_etc->vararg != NULL) { + vararg = star_etc->vararg; + } + + asdl_arg_seq *kwonlyargs; + asdl_expr_seq *kwdefaults; + if (_make_kwargs(p, star_etc, &kwonlyargs, &kwdefaults) == -1) { + return NULL; + } + + arg_ty kwarg = NULL; + if (star_etc != NULL && star_etc->kwarg != NULL) { + kwarg = star_etc->kwarg; + } + + return _PyAST_arguments(posonlyargs, posargs, vararg, kwonlyargs, kwdefaults, + kwarg, posdefaults, p->arena); +} + +/* Constructs an empty arguments_ty object, that gets used when a function + * accepts no arguments. */ +arguments_ty _PyPegen_empty_arguments(Parser *p) { + asdl_arg_seq *posonlyargs = _Py_asdl_arg_seq_new(0, p->arena); + if (!posonlyargs) { + return NULL; + } + asdl_arg_seq *posargs = _Py_asdl_arg_seq_new(0, p->arena); + if (!posargs) { + return NULL; + } + asdl_expr_seq *posdefaults = _Py_asdl_expr_seq_new(0, p->arena); + if (!posdefaults) { + return NULL; + } + asdl_arg_seq *kwonlyargs = _Py_asdl_arg_seq_new(0, p->arena); + if (!kwonlyargs) { + return NULL; + } + asdl_expr_seq *kwdefaults = _Py_asdl_expr_seq_new(0, p->arena); + if (!kwdefaults) { + return NULL; + } + + return _PyAST_arguments(posonlyargs, posargs, NULL, kwonlyargs, kwdefaults, + NULL, posdefaults, p->arena); } /* Encapsulates the value of an operator_ty into an AugOperator struct */ -AugOperator * -_PyPegen_augoperator(Parser *p, operator_ty kind) -{ - AugOperator *a = _PyArena_Malloc(p->arena, sizeof(AugOperator)); - if (!a) { - return NULL; - } - a->kind = kind; - return a; +AugOperator *_PyPegen_augoperator(Parser *p, operator_ty kind) { + AugOperator *a = _PyArena_Malloc(p->arena, sizeof(AugOperator)); + if (!a) { + return NULL; + } + a->kind = kind; + return a; } /* Construct a FunctionDef equivalent to function_def, but with decorators */ -stmt_ty -_PyPegen_function_def_decorators(Parser *p, asdl_expr_seq *decorators, stmt_ty function_def) -{ - assert(function_def != NULL); - if (function_def->kind == AsyncFunctionDef_kind) { - return _PyAST_AsyncFunctionDef( - function_def->v.AsyncFunctionDef.name, - function_def->v.AsyncFunctionDef.args, - function_def->v.AsyncFunctionDef.body, decorators, - function_def->v.AsyncFunctionDef.returns, - function_def->v.AsyncFunctionDef.type_comment, - function_def->v.AsyncFunctionDef.type_params, - function_def->lineno, function_def->col_offset, - function_def->end_lineno, function_def->end_col_offset, p->arena); - } - - return _PyAST_FunctionDef( - function_def->v.FunctionDef.name, - function_def->v.FunctionDef.args, - function_def->v.FunctionDef.body, decorators, - function_def->v.FunctionDef.returns, - function_def->v.FunctionDef.type_comment, - function_def->v.FunctionDef.type_params, - function_def->lineno, function_def->col_offset, - function_def->end_lineno, function_def->end_col_offset, p->arena); +stmt_ty _PyPegen_function_def_decorators(Parser *p, asdl_expr_seq *decorators, + stmt_ty function_def) { + assert(function_def != NULL); + if (function_def->kind == AsyncFunctionDef_kind) { + return _PyAST_AsyncFunctionDef( + function_def->v.AsyncFunctionDef.name, + function_def->v.AsyncFunctionDef.args, + function_def->v.AsyncFunctionDef.body, decorators, + function_def->v.AsyncFunctionDef.returns, + function_def->v.AsyncFunctionDef.type_comment, + function_def->v.AsyncFunctionDef.type_params, function_def->lineno, + function_def->col_offset, function_def->end_lineno, + function_def->end_col_offset, p->arena); + } + + return _PyAST_FunctionDef( + function_def->v.FunctionDef.name, function_def->v.FunctionDef.args, + function_def->v.FunctionDef.body, decorators, + function_def->v.FunctionDef.returns, + function_def->v.FunctionDef.type_comment, + function_def->v.FunctionDef.type_params, function_def->lineno, + function_def->col_offset, function_def->end_lineno, + function_def->end_col_offset, p->arena); } /* Construct a ClassDef equivalent to class_def, but with decorators */ -stmt_ty -_PyPegen_class_def_decorators(Parser *p, asdl_expr_seq *decorators, stmt_ty class_def) -{ - assert(class_def != NULL); - return _PyAST_ClassDef( - class_def->v.ClassDef.name, - class_def->v.ClassDef.bases, class_def->v.ClassDef.keywords, - class_def->v.ClassDef.body, decorators, - class_def->v.ClassDef.type_params, - class_def->lineno, class_def->col_offset, class_def->end_lineno, - class_def->end_col_offset, p->arena); +stmt_ty _PyPegen_class_def_decorators(Parser *p, asdl_expr_seq *decorators, + stmt_ty class_def) { + assert(class_def != NULL); + return _PyAST_ClassDef( + class_def->v.ClassDef.name, class_def->v.ClassDef.bases, + class_def->v.ClassDef.keywords, class_def->v.ClassDef.body, decorators, + class_def->v.ClassDef.type_params, class_def->lineno, + class_def->col_offset, class_def->end_lineno, class_def->end_col_offset, + p->arena); } /* Construct a KeywordOrStarred */ -KeywordOrStarred * -_PyPegen_keyword_or_starred(Parser *p, void *element, int is_keyword) -{ - KeywordOrStarred *a = _PyArena_Malloc(p->arena, sizeof(KeywordOrStarred)); - if (!a) { - return NULL; - } - a->element = element; - a->is_keyword = is_keyword; - return a; -} - -/* Get the number of starred expressions in an asdl_seq* of KeywordOrStarred*s */ -static int -_seq_number_of_starred_exprs(asdl_seq *seq) -{ - int n = 0; - for (Py_ssize_t i = 0, l = asdl_seq_LEN(seq); i < l; i++) { - KeywordOrStarred *k = asdl_seq_GET_UNTYPED(seq, i); - if (!k->is_keyword) { - n++; - } - } - return n; +KeywordOrStarred *_PyPegen_keyword_or_starred(Parser *p, void *element, + int is_keyword) { + KeywordOrStarred *a = _PyArena_Malloc(p->arena, sizeof(KeywordOrStarred)); + if (!a) { + return NULL; + } + a->element = element; + a->is_keyword = is_keyword; + return a; +} + +/* Get the number of starred expressions in an asdl_seq* of KeywordOrStarred*s + */ +static int _seq_number_of_starred_exprs(asdl_seq *seq) { + int n = 0; + for (Py_ssize_t i = 0, l = asdl_seq_LEN(seq); i < l; i++) { + KeywordOrStarred *k = asdl_seq_GET_UNTYPED(seq, i); + if (!k->is_keyword) { + n++; + } + } + return n; } /* Extract the starred expressions of an asdl_seq* of KeywordOrStarred*s */ -asdl_expr_seq * -_PyPegen_seq_extract_starred_exprs(Parser *p, asdl_seq *kwargs) -{ - int new_len = _seq_number_of_starred_exprs(kwargs); - if (new_len == 0) { - return NULL; - } - asdl_expr_seq *new_seq = _Py_asdl_expr_seq_new(new_len, p->arena); - if (!new_seq) { - return NULL; - } - - int idx = 0; - for (Py_ssize_t i = 0, len = asdl_seq_LEN(kwargs); i < len; i++) { - KeywordOrStarred *k = asdl_seq_GET_UNTYPED(kwargs, i); - if (!k->is_keyword) { - asdl_seq_SET(new_seq, idx++, k->element); - } - } - return new_seq; +asdl_expr_seq *_PyPegen_seq_extract_starred_exprs(Parser *p, asdl_seq *kwargs) { + int new_len = _seq_number_of_starred_exprs(kwargs); + if (new_len == 0) { + return NULL; + } + asdl_expr_seq *new_seq = _Py_asdl_expr_seq_new(new_len, p->arena); + if (!new_seq) { + return NULL; + } + + int idx = 0; + for (Py_ssize_t i = 0, len = asdl_seq_LEN(kwargs); i < len; i++) { + KeywordOrStarred *k = asdl_seq_GET_UNTYPED(kwargs, i); + if (!k->is_keyword) { + asdl_seq_SET(new_seq, idx++, k->element); + } + } + return new_seq; } /* Return a new asdl_seq* with only the keywords in kwargs */ -asdl_keyword_seq* -_PyPegen_seq_delete_starred_exprs(Parser *p, asdl_seq *kwargs) -{ - Py_ssize_t len = asdl_seq_LEN(kwargs); - Py_ssize_t new_len = len - _seq_number_of_starred_exprs(kwargs); - if (new_len == 0) { - return NULL; - } - asdl_keyword_seq *new_seq = _Py_asdl_keyword_seq_new(new_len, p->arena); - if (!new_seq) { - return NULL; - } - - int idx = 0; - for (Py_ssize_t i = 0; i < len; i++) { - KeywordOrStarred *k = asdl_seq_GET_UNTYPED(kwargs, i); - if (k->is_keyword) { - asdl_seq_SET(new_seq, idx++, k->element); - } - } - return new_seq; -} - -expr_ty -_PyPegen_ensure_imaginary(Parser *p, expr_ty exp) -{ - if (exp->kind != Constant_kind || !PyComplex_CheckExact(exp->v.Constant.value)) { - RAISE_SYNTAX_ERROR_KNOWN_LOCATION(exp, "imaginary number required in complex literal"); - return NULL; - } - return exp; -} - -expr_ty -_PyPegen_ensure_real(Parser *p, expr_ty exp) -{ - if (exp->kind != Constant_kind || PyComplex_CheckExact(exp->v.Constant.value)) { - RAISE_SYNTAX_ERROR_KNOWN_LOCATION(exp, "real number required in complex literal"); - return NULL; - } - return exp; -} - -mod_ty -_PyPegen_make_module(Parser *p, asdl_stmt_seq *a) { - asdl_type_ignore_seq *type_ignores = NULL; - Py_ssize_t num = p->type_ignore_comments.num_items; - if (num > 0) { - // Turn the raw (comment, lineno) pairs into TypeIgnore objects in the arena - type_ignores = _Py_asdl_type_ignore_seq_new(num, p->arena); - if (type_ignores == NULL) { - return NULL; - } - for (int i = 0; i < num; i++) { - PyObject *tag = _PyPegen_new_type_comment(p, p->type_ignore_comments.items[i].comment); - if (tag == NULL) { - return NULL; - } - type_ignore_ty ti = _PyAST_TypeIgnore(p->type_ignore_comments.items[i].lineno, - tag, p->arena); - if (ti == NULL) { - return NULL; - } - asdl_seq_SET(type_ignores, i, ti); - } - } - return _PyAST_Module(a, type_ignores, p->arena); -} - -PyObject * -_PyPegen_new_type_comment(Parser *p, const char *s) -{ - PyObject *res = PyUnicode_DecodeUTF8(s, strlen(s), NULL); - if (res == NULL) { - return NULL; - } - if (_PyArena_AddPyObject(p->arena, res) < 0) { - Py_DECREF(res); - return NULL; - } - return res; -} - -arg_ty -_PyPegen_add_type_comment_to_arg(Parser *p, arg_ty a, Token *tc) -{ - if (tc == NULL) { - return a; - } - const char *bytes = PyBytes_AsString(tc->bytes); - if (bytes == NULL) { - return NULL; - } - PyObject *tco = _PyPegen_new_type_comment(p, bytes); - if (tco == NULL) { - return NULL; - } - return _PyAST_arg(a->arg, a->annotation, tco, - a->lineno, a->col_offset, a->end_lineno, a->end_col_offset, - p->arena); +asdl_keyword_seq *_PyPegen_seq_delete_starred_exprs(Parser *p, + asdl_seq *kwargs) { + Py_ssize_t len = asdl_seq_LEN(kwargs); + Py_ssize_t new_len = len - _seq_number_of_starred_exprs(kwargs); + if (new_len == 0) { + return NULL; + } + asdl_keyword_seq *new_seq = _Py_asdl_keyword_seq_new(new_len, p->arena); + if (!new_seq) { + return NULL; + } + + int idx = 0; + for (Py_ssize_t i = 0; i < len; i++) { + KeywordOrStarred *k = asdl_seq_GET_UNTYPED(kwargs, i); + if (k->is_keyword) { + asdl_seq_SET(new_seq, idx++, k->element); + } + } + return new_seq; +} + +expr_ty _PyPegen_ensure_imaginary(Parser *p, expr_ty exp) { + if (exp->kind != Constant_kind || + !PyComplex_CheckExact(exp->v.Constant.value)) { + RAISE_SYNTAX_ERROR_KNOWN_LOCATION( + exp, "imaginary number required in complex literal"); + return NULL; + } + return exp; +} + +expr_ty _PyPegen_ensure_real(Parser *p, expr_ty exp) { + if (exp->kind != Constant_kind || + PyComplex_CheckExact(exp->v.Constant.value)) { + RAISE_SYNTAX_ERROR_KNOWN_LOCATION( + exp, "real number required in complex literal"); + return NULL; + } + return exp; +} + +mod_ty _PyPegen_make_module(Parser *p, asdl_stmt_seq *a) { + asdl_type_ignore_seq *type_ignores = NULL; + Py_ssize_t num = p->type_ignore_comments.num_items; + if (num > 0) { + // Turn the raw (comment, lineno) pairs into TypeIgnore objects in the arena + type_ignores = _Py_asdl_type_ignore_seq_new(num, p->arena); + if (type_ignores == NULL) { + return NULL; + } + for (int i = 0; i < num; i++) { + PyObject *tag = _PyPegen_new_type_comment( + p, p->type_ignore_comments.items[i].comment); + if (tag == NULL) { + return NULL; + } + type_ignore_ty ti = _PyAST_TypeIgnore( + p->type_ignore_comments.items[i].lineno, tag, p->arena); + if (ti == NULL) { + return NULL; + } + asdl_seq_SET(type_ignores, i, ti); + } + } + return _PyAST_Module(a, type_ignores, p->arena); +} + +PyObject *_PyPegen_new_type_comment(Parser *p, const char *s) { + PyObject *res = PyUnicode_DecodeUTF8(s, strlen(s), NULL); + if (res == NULL) { + return NULL; + } + if (_PyArena_AddPyObject(p->arena, res) < 0) { + Py_DECREF(res); + return NULL; + } + return res; +} + +arg_ty _PyPegen_add_type_comment_to_arg(Parser *p, arg_ty a, Token *tc) { + if (tc == NULL) { + return a; + } + const char *bytes = PyBytes_AsString(tc->bytes); + if (bytes == NULL) { + return NULL; + } + PyObject *tco = _PyPegen_new_type_comment(p, bytes); + if (tco == NULL) { + return NULL; + } + return _PyAST_arg(a->arg, a->annotation, tco, a->lineno, a->col_offset, + a->end_lineno, a->end_col_offset, p->arena); } /* Checks if the NOTEQUAL token is valid given the current parser flags 0 indicates success and nonzero indicates failure (an exception may be set) */ -int -_PyPegen_check_barry_as_flufl(Parser *p, Token* t) { - assert(t->bytes != NULL); - assert(t->type == NOTEQUAL); - - const char* tok_str = PyBytes_AS_STRING(t->bytes); - if (p->flags & PyPARSE_BARRY_AS_BDFL && strcmp(tok_str, "<>") != 0) { - RAISE_SYNTAX_ERROR("with Barry as BDFL, use '<>' instead of '!='"); - return -1; - } - if (!(p->flags & PyPARSE_BARRY_AS_BDFL)) { - return strcmp(tok_str, "!="); - } +int _PyPegen_check_barry_as_flufl(Parser *p, Token *t) { + assert(t->bytes != NULL); + assert(t->type == NOTEQUAL); + + const char *tok_str = PyBytes_AS_STRING(t->bytes); + if (p->flags & PyPARSE_BARRY_AS_BDFL && strcmp(tok_str, "<>") != 0) { + RAISE_SYNTAX_ERROR("with Barry as BDFL, use '<>' instead of '!='"); + return -1; + } + if (!(p->flags & PyPARSE_BARRY_AS_BDFL)) { + return strcmp(tok_str, "!="); + } + return 0; +} + +int _PyPegen_check_legacy_stmt(Parser *p, expr_ty name) { + if (name->kind != Name_kind) { return 0; -} - -int -_PyPegen_check_legacy_stmt(Parser *p, expr_ty name) { - if (name->kind != Name_kind) { - return 0; - } - const char* candidates[2] = {"print", "exec"}; - for (int i=0; i<2; i++) { - if (PyUnicode_CompareWithASCIIString(name->v.Name.id, candidates[i]) == 0) { - return 1; - } + } + const char *candidates[2] = {"print", "exec"}; + for (int i = 0; i < 2; i++) { + if (PyUnicode_CompareWithASCIIString(name->v.Name.id, candidates[i]) == 0) { + return 1; } - return 0; + } + return 0; } static ResultTokenWithMetadata * -result_token_with_metadata(Parser *p, void *result, PyObject *metadata) -{ - ResultTokenWithMetadata *res = _PyArena_Malloc(p->arena, sizeof(ResultTokenWithMetadata)); - if (res == NULL) { - return NULL; - } - res->metadata = metadata; - res->result = result; - return res; +result_token_with_metadata(Parser *p, void *result, PyObject *metadata) { + ResultTokenWithMetadata *res = + _PyArena_Malloc(p->arena, sizeof(ResultTokenWithMetadata)); + if (res == NULL) { + return NULL; + } + res->metadata = metadata; + res->result = result; + return res; } ResultTokenWithMetadata * -_PyPegen_check_fstring_conversion(Parser *p, Token* conv_token, expr_ty conv) -{ - if (conv_token->lineno != conv->lineno || conv_token->end_col_offset != conv->col_offset) { - return RAISE_SYNTAX_ERROR_KNOWN_RANGE( - conv_token, conv, - "f-string: conversion type must come right after the exclamanation mark" - ); - } - return result_token_with_metadata(p, conv, conv_token->metadata); +_PyPegen_check_fstring_conversion(Parser *p, Token *conv_token, expr_ty conv) { + if (conv_token->lineno != conv->lineno || + conv_token->end_col_offset != conv->col_offset) { + return RAISE_SYNTAX_ERROR_KNOWN_RANGE(conv_token, conv, + "f-string: conversion type must come " + "right after the exclamanation mark"); + } + return result_token_with_metadata(p, conv, conv_token->metadata); } +static asdl_expr_seq * +unpack_top_level_joined_strs(Parser *p, asdl_expr_seq *raw_expressions); ResultTokenWithMetadata * -_PyPegen_setup_full_format_spec(Parser *p, Token *colon, asdl_expr_seq *spec, int lineno, int col_offset, - int end_lineno, int end_col_offset, PyArena *arena) -{ - if (!spec) { - return NULL; - } - - // This is needed to keep compatibility with 3.11, where an empty format spec is parsed - // as an *empty* JoinedStr node, instead of having an empty constant in it. - if (asdl_seq_LEN(spec) == 1) { - expr_ty e = asdl_seq_GET(spec, 0); - if (e->kind == Constant_kind - && PyUnicode_Check(e->v.Constant.value) - && PyUnicode_GetLength(e->v.Constant.value) == 0) { - spec = _Py_asdl_expr_seq_new(0, arena); - } - } - - expr_ty res = _PyAST_JoinedStr(spec, lineno, col_offset, end_lineno, end_col_offset, p->arena); - if (!res) { - return NULL; - } - return result_token_with_metadata(p, res, colon->metadata); -} - -const char * -_PyPegen_get_expr_name(expr_ty e) -{ - assert(e != NULL); - switch (e->kind) { - case Attribute_kind: - return "attribute"; - case Subscript_kind: - return "subscript"; - case Starred_kind: - return "starred"; - case Name_kind: - return "name"; - case List_kind: - return "list"; - case Tuple_kind: - return "tuple"; - case Lambda_kind: - return "lambda"; - case Call_kind: - return "function call"; - case BoolOp_kind: - case BinOp_kind: - case UnaryOp_kind: - return "expression"; - case GeneratorExp_kind: - return "generator expression"; - case Yield_kind: - case YieldFrom_kind: - return "yield expression"; - case Await_kind: - return "await expression"; - case ListComp_kind: - return "list comprehension"; - case SetComp_kind: - return "set comprehension"; - case DictComp_kind: - return "dict comprehension"; - case Dict_kind: - return "dict literal"; - case Set_kind: - return "set display"; - case JoinedStr_kind: - case FormattedValue_kind: - return "f-string expression"; - case Constant_kind: { - PyObject *value = e->v.Constant.value; - if (value == Py_None) { - return "None"; - } - if (value == Py_False) { - return "False"; - } - if (value == Py_True) { - return "True"; - } - if (value == Py_Ellipsis) { - return "ellipsis"; - } - return "literal"; - } - case Compare_kind: - return "comparison"; - case IfExp_kind: - return "conditional expression"; - case NamedExpr_kind: - return "named expression"; - default: - PyErr_Format(PyExc_SystemError, - "unexpected expression in assignment %d (line %d)", - e->kind, e->lineno); - return NULL; - } -} - -expr_ty -_PyPegen_get_last_comprehension_item(comprehension_ty comprehension) { - if (comprehension->ifs == NULL || asdl_seq_LEN(comprehension->ifs) == 0) { - return comprehension->iter; - } - return PyPegen_last_item(comprehension->ifs, expr_ty); +_PyPegen_setup_full_format_spec(Parser *p, Token *colon, asdl_expr_seq *spec, + int lineno, int col_offset, int end_lineno, + int end_col_offset, PyArena *arena) { + if (!spec) { + return NULL; + } + + // This is needed to keep compatibility with 3.11, where an empty format spec + // is parsed as an *empty* JoinedStr node, instead of having an empty constant + // in it. + if (asdl_seq_LEN(spec) == 1) { + expr_ty e = asdl_seq_GET(spec, 0); + if (e->kind == Constant_kind && PyUnicode_Check(e->v.Constant.value) && + PyUnicode_GetLength(e->v.Constant.value) == 0) { + spec = _Py_asdl_expr_seq_new(0, arena); + } + } + expr_ty res; + Py_ssize_t n = asdl_seq_LEN(spec); + if (n == 0 || (n == 1 && asdl_seq_GET(spec, 0)->kind == Constant_kind)) { + res = _PyAST_JoinedStr(spec, lineno, col_offset, end_lineno, end_col_offset, + p->arena); + } else { + res = _PyPegen_concatenate_strings(p, spec, lineno, col_offset, end_lineno, + end_col_offset, arena); + } + if (!res) { + return NULL; + } + return result_token_with_metadata(p, res, colon->metadata); +} + +const char *_PyPegen_get_expr_name(expr_ty e) { + assert(e != NULL); + switch (e->kind) { + case Attribute_kind: + return "attribute"; + case Subscript_kind: + return "subscript"; + case Starred_kind: + return "starred"; + case Name_kind: + return "name"; + case List_kind: + return "list"; + case Tuple_kind: + return "tuple"; + case Lambda_kind: + return "lambda"; + case Call_kind: + return "function call"; + case BoolOp_kind: + case BinOp_kind: + case UnaryOp_kind: + return "expression"; + case GeneratorExp_kind: + return "generator expression"; + case Yield_kind: + case YieldFrom_kind: + return "yield expression"; + case Await_kind: + return "await expression"; + case ListComp_kind: + return "list comprehension"; + case SetComp_kind: + return "set comprehension"; + case DictComp_kind: + return "dict comprehension"; + case Dict_kind: + return "dict literal"; + case Set_kind: + return "set display"; + case JoinedStr_kind: + case FormattedValue_kind: + return "f-string expression"; + case Constant_kind: { + PyObject *value = e->v.Constant.value; + if (value == Py_None) { + return "None"; + } + if (value == Py_False) { + return "False"; + } + if (value == Py_True) { + return "True"; + } + if (value == Py_Ellipsis) { + return "ellipsis"; + } + return "literal"; + } + case Compare_kind: + return "comparison"; + case IfExp_kind: + return "conditional expression"; + case NamedExpr_kind: + return "named expression"; + default: + PyErr_Format(PyExc_SystemError, + "unexpected expression in assignment %d (line %d)", e->kind, + e->lineno); + return NULL; + } +} + +expr_ty _PyPegen_get_last_comprehension_item(comprehension_ty comprehension) { + if (comprehension->ifs == NULL || asdl_seq_LEN(comprehension->ifs) == 0) { + return comprehension->iter; + } + return PyPegen_last_item(comprehension->ifs, expr_ty); } expr_ty _PyPegen_collect_call_seqs(Parser *p, asdl_expr_seq *a, asdl_seq *b, - int lineno, int col_offset, int end_lineno, - int end_col_offset, PyArena *arena) { - Py_ssize_t args_len = asdl_seq_LEN(a); - Py_ssize_t total_len = args_len; - - if (b == NULL) { - return _PyAST_Call(_PyPegen_dummy_name(p), a, NULL, lineno, col_offset, - end_lineno, end_col_offset, arena); + int lineno, int col_offset, int end_lineno, + int end_col_offset, PyArena *arena) { + Py_ssize_t args_len = asdl_seq_LEN(a); + Py_ssize_t total_len = args_len; - } + if (b == NULL) { + return _PyAST_Call(_PyPegen_dummy_name(p), a, NULL, lineno, col_offset, + end_lineno, end_col_offset, arena); + } - asdl_expr_seq *starreds = _PyPegen_seq_extract_starred_exprs(p, b); - asdl_keyword_seq *keywords = _PyPegen_seq_delete_starred_exprs(p, b); + asdl_expr_seq *starreds = _PyPegen_seq_extract_starred_exprs(p, b); + asdl_keyword_seq *keywords = _PyPegen_seq_delete_starred_exprs(p, b); - if (starreds) { - total_len += asdl_seq_LEN(starreds); - } + if (starreds) { + total_len += asdl_seq_LEN(starreds); + } - asdl_expr_seq *args = _Py_asdl_expr_seq_new(total_len, arena); + asdl_expr_seq *args = _Py_asdl_expr_seq_new(total_len, arena); + if (args == NULL) { + return NULL; + } - Py_ssize_t i = 0; - for (i = 0; i < args_len; i++) { - asdl_seq_SET(args, i, asdl_seq_GET(a, i)); - } - for (; i < total_len; i++) { - asdl_seq_SET(args, i, asdl_seq_GET(starreds, i - args_len)); - } + Py_ssize_t i = 0; + for (i = 0; i < args_len; i++) { + asdl_seq_SET(args, i, asdl_seq_GET(a, i)); + } + for (; i < total_len; i++) { + asdl_seq_SET(args, i, asdl_seq_GET(starreds, i - args_len)); + } - return _PyAST_Call(_PyPegen_dummy_name(p), args, keywords, lineno, - col_offset, end_lineno, end_col_offset, arena); + return _PyAST_Call(_PyPegen_dummy_name(p), args, keywords, lineno, col_offset, + end_lineno, end_col_offset, arena); } // AST Error reporting helpers -expr_ty -_PyPegen_get_invalid_target(expr_ty e, TARGETS_TYPE targets_type) -{ - if (e == NULL) { - return NULL; - } - -#define VISIT_CONTAINER(CONTAINER, TYPE) do { \ - Py_ssize_t len = asdl_seq_LEN((CONTAINER)->v.TYPE.elts);\ - for (Py_ssize_t i = 0; i < len; i++) {\ - expr_ty other = asdl_seq_GET((CONTAINER)->v.TYPE.elts, i);\ - expr_ty child = _PyPegen_get_invalid_target(other, targets_type);\ - if (child != NULL) {\ - return child;\ - }\ - }\ - } while (0) - - // We only need to visit List and Tuple nodes recursively as those - // are the only ones that can contain valid names in targets when - // they are parsed as expressions. Any other kind of expression - // that is a container (like Sets or Dicts) is directly invalid and - // we don't need to visit it recursively. - - switch (e->kind) { - case List_kind: - VISIT_CONTAINER(e, List); - return NULL; - case Tuple_kind: - VISIT_CONTAINER(e, Tuple); - return NULL; - case Starred_kind: - if (targets_type == DEL_TARGETS) { - return e; - } - return _PyPegen_get_invalid_target(e->v.Starred.value, targets_type); - case Compare_kind: - // This is needed, because the `a in b` in `for a in b` gets parsed - // as a comparison, and so we need to search the left side of the comparison - // for invalid targets. - if (targets_type == FOR_TARGETS) { - cmpop_ty cmpop = (cmpop_ty) asdl_seq_GET(e->v.Compare.ops, 0); - if (cmpop == In) { - return _PyPegen_get_invalid_target(e->v.Compare.left, targets_type); - } - return NULL; - } - return e; - case Name_kind: - case Subscript_kind: - case Attribute_kind: - return NULL; - default: - return e; - } +expr_ty _PyPegen_get_invalid_target(expr_ty e, TARGETS_TYPE targets_type) { + if (e == NULL) { + return NULL; + } + +#define VISIT_CONTAINER(CONTAINER, TYPE) \ + do { \ + Py_ssize_t len = asdl_seq_LEN((CONTAINER)->v.TYPE.elts); \ + for (Py_ssize_t i = 0; i < len; i++) { \ + expr_ty other = asdl_seq_GET((CONTAINER)->v.TYPE.elts, i); \ + expr_ty child = _PyPegen_get_invalid_target(other, targets_type); \ + if (child != NULL) { \ + return child; \ + } \ + } \ + } while (0) + + // We only need to visit List and Tuple nodes recursively as those + // are the only ones that can contain valid names in targets when + // they are parsed as expressions. Any other kind of expression + // that is a container (like Sets or Dicts) is directly invalid and + // we don't need to visit it recursively. + + switch (e->kind) { + case List_kind: + VISIT_CONTAINER(e, List); + return NULL; + case Tuple_kind: + VISIT_CONTAINER(e, Tuple); + return NULL; + case Starred_kind: + if (targets_type == DEL_TARGETS) { + return e; + } + return _PyPegen_get_invalid_target(e->v.Starred.value, targets_type); + case Compare_kind: + // This is needed, because the `a in b` in `for a in b` gets parsed + // as a comparison, and so we need to search the left side of the comparison + // for invalid targets. + if (targets_type == FOR_TARGETS) { + cmpop_ty cmpop = (cmpop_ty)asdl_seq_GET(e->v.Compare.ops, 0); + if (cmpop == In) { + return _PyPegen_get_invalid_target(e->v.Compare.left, targets_type); + } + return NULL; + } + return e; + case Name_kind: + case Subscript_kind: + case Attribute_kind: + return NULL; + default: + return e; + } } void *_PyPegen_arguments_parsing_error(Parser *p, expr_ty e) { - int kwarg_unpacking = 0; - for (Py_ssize_t i = 0, l = asdl_seq_LEN(e->v.Call.keywords); i < l; i++) { - keyword_ty keyword = asdl_seq_GET(e->v.Call.keywords, i); - if (!keyword->arg) { - kwarg_unpacking = 1; - } - } - - const char *msg = NULL; - if (kwarg_unpacking) { - msg = "positional argument follows keyword argument unpacking"; - } else { - msg = "positional argument follows keyword argument"; - } - - return RAISE_SYNTAX_ERROR(msg); -} - -void * -_PyPegen_nonparen_genexp_in_call(Parser *p, expr_ty args, asdl_comprehension_seq *comprehensions) -{ - /* The rule that calls this function is 'args for_if_clauses'. - For the input f(L, x for x in y), L and x are in args and - the for is parsed as a for_if_clause. We have to check if - len <= 1, so that input like dict((a, b) for a, b in x) - gets successfully parsed and then we pass the last - argument (x in the above example) as the location of the - error */ - Py_ssize_t len = asdl_seq_LEN(args->v.Call.args); - if (len <= 1) { - return NULL; - } - - comprehension_ty last_comprehension = PyPegen_last_item(comprehensions, comprehension_ty); - - return RAISE_SYNTAX_ERROR_KNOWN_RANGE( - (expr_ty) asdl_seq_GET(args->v.Call.args, len - 1), - _PyPegen_get_last_comprehension_item(last_comprehension), - "Generator expression must be parenthesized" - ); + int kwarg_unpacking = 0; + for (Py_ssize_t i = 0, l = asdl_seq_LEN(e->v.Call.keywords); i < l; i++) { + keyword_ty keyword = asdl_seq_GET(e->v.Call.keywords, i); + if (!keyword->arg) { + kwarg_unpacking = 1; + } + } + + const char *msg = NULL; + if (kwarg_unpacking) { + msg = "positional argument follows keyword argument unpacking"; + } else { + msg = "positional argument follows keyword argument"; + } + + return RAISE_SYNTAX_ERROR(msg); +} + +void *_PyPegen_nonparen_genexp_in_call(Parser *p, expr_ty args, + asdl_comprehension_seq *comprehensions) { + /* The rule that calls this function is 'args for_if_clauses'. + For the input f(L, x for x in y), L and x are in args and + the for is parsed as a for_if_clause. We have to check if + len <= 1, so that input like dict((a, b) for a, b in x) + gets successfully parsed and then we pass the last + argument (x in the above example) as the location of the + error */ + Py_ssize_t len = asdl_seq_LEN(args->v.Call.args); + if (len <= 1) { + return NULL; + } + + comprehension_ty last_comprehension = + PyPegen_last_item(comprehensions, comprehension_ty); + + return RAISE_SYNTAX_ERROR_KNOWN_RANGE( + (expr_ty)asdl_seq_GET(args->v.Call.args, len - 1), + _PyPegen_get_last_comprehension_item(last_comprehension), + "Generator expression must be parenthesized"); } // Fstring stuff -static expr_ty -_PyPegen_decode_fstring_part(Parser* p, int is_raw, expr_ty constant, Token* token) { - assert(PyUnicode_CheckExact(constant->v.Constant.value)); - - const char* bstr = PyUnicode_AsUTF8(constant->v.Constant.value); - if (bstr == NULL) { - return NULL; - } - - size_t len; - if (strcmp(bstr, "{{") == 0 || strcmp(bstr, "}}") == 0) { - len = 1; - } else { - len = strlen(bstr); - } - - is_raw = is_raw || strchr(bstr, '\\') == NULL; - PyObject *str = _PyPegen_decode_string(p, is_raw, bstr, len, token); - if (str == NULL) { - _Pypegen_raise_decode_error(p); - return NULL; - } - if (_PyArena_AddPyObject(p->arena, str) < 0) { - Py_DECREF(str); - return NULL; - } - return _PyAST_Constant(str, NULL, constant->lineno, constant->col_offset, - constant->end_lineno, constant->end_col_offset, - p->arena); +static expr_ty _PyPegen_decode_fstring_part(Parser *p, int is_raw, + expr_ty constant, Token *token) { + assert(PyUnicode_CheckExact(constant->v.Constant.value)); + + const char *bstr = PyUnicode_AsUTF8(constant->v.Constant.value); + if (bstr == NULL) { + return NULL; + } + + size_t len; + if (strcmp(bstr, "{{") == 0 || strcmp(bstr, "}}") == 0) { + len = 1; + } else { + len = strlen(bstr); + } + + is_raw = is_raw || strchr(bstr, '\\') == NULL; + PyObject *str = _PyPegen_decode_string(p, is_raw, bstr, len, token); + if (str == NULL) { + _Pypegen_raise_decode_error(p); + return NULL; + } + if (_PyArena_AddPyObject(p->arena, str) < 0) { + Py_DECREF(str); + return NULL; + } + return _PyAST_Constant(str, NULL, constant->lineno, constant->col_offset, + constant->end_lineno, constant->end_col_offset, + p->arena); } static asdl_expr_seq * -unpack_top_level_joined_strs(Parser *p, asdl_expr_seq *raw_expressions) -{ - /* The parser might put multiple f-string values into an individual - * JoinedStr node at the top level due to stuff like f-string debugging - * expressions. This function flattens those and promotes them to the - * upper level. Only simplifies AST, but the compiler already takes care - * of the regular output, so this is not necessary if you are not going - * to expose the output AST to Python level. */ - - Py_ssize_t i, req_size, raw_size; - - req_size = raw_size = asdl_seq_LEN(raw_expressions); - expr_ty expr; - for (i = 0; i < raw_size; i++) { - expr = asdl_seq_GET(raw_expressions, i); - if (expr->kind == JoinedStr_kind) { - req_size += asdl_seq_LEN(expr->v.JoinedStr.values) - 1; - } - } - - asdl_expr_seq *expressions = _Py_asdl_expr_seq_new(req_size, p->arena); - - Py_ssize_t raw_index, req_index = 0; - for (raw_index = 0; raw_index < raw_size; raw_index++) { - expr = asdl_seq_GET(raw_expressions, raw_index); - if (expr->kind == JoinedStr_kind) { - asdl_expr_seq *values = expr->v.JoinedStr.values; - for (Py_ssize_t n = 0; n < asdl_seq_LEN(values); n++) { - asdl_seq_SET(expressions, req_index, asdl_seq_GET(values, n)); - req_index++; - } - } else { - asdl_seq_SET(expressions, req_index, expr); - req_index++; - } - } - return expressions; -} - -expr_ty -_PyPegen_joined_str(Parser *p, Token* a, asdl_expr_seq* raw_expressions, Token*b) { - asdl_expr_seq *expr = unpack_top_level_joined_strs(p, raw_expressions); - Py_ssize_t n_items = asdl_seq_LEN(expr); - - const char* quote_str = PyBytes_AsString(a->bytes); - if (quote_str == NULL) { - return NULL; - } - int is_raw = strpbrk(quote_str, "rR") != NULL; - - asdl_expr_seq *seq = _Py_asdl_expr_seq_new(n_items, p->arena); - if (seq == NULL) { - return NULL; - } - - Py_ssize_t index = 0; - for (Py_ssize_t i = 0; i < n_items; i++) { - expr_ty item = asdl_seq_GET(expr, i); - if (item->kind == Constant_kind) { - item = _PyPegen_decode_fstring_part(p, is_raw, item, b); - if (item == NULL) { - return NULL; - } - - /* Tokenizer emits string parts even when the underlying string - might become an empty value (e.g. FSTRING_MIDDLE with the value \\n) - so we need to check for them and simplify it here. */ - if (PyUnicode_CheckExact(item->v.Constant.value) - && PyUnicode_GET_LENGTH(item->v.Constant.value) == 0) { - continue; - } - } - asdl_seq_SET(seq, index++, item); - } - - asdl_expr_seq *resized_exprs; - if (index != n_items) { - resized_exprs = _Py_asdl_expr_seq_new(index, p->arena); - if (resized_exprs == NULL) { - return NULL; - } - for (Py_ssize_t i = 0; i < index; i++) { - asdl_seq_SET(resized_exprs, i, asdl_seq_GET(seq, i)); - } - } - else { - resized_exprs = seq; - } - - return _PyAST_JoinedStr(resized_exprs, a->lineno, a->col_offset, - b->end_lineno, b->end_col_offset, - p->arena); -} - -expr_ty _PyPegen_decoded_constant_from_token(Parser* p, Token* tok) { - Py_ssize_t bsize; - char* bstr; - if (PyBytes_AsStringAndSize(tok->bytes, &bstr, &bsize) == -1) { - return NULL; - } - PyObject* str = _PyPegen_decode_string(p, 0, bstr, bsize, tok); - if (str == NULL) { - return NULL; - } - if (_PyArena_AddPyObject(p->arena, str) < 0) { - Py_DECREF(str); - return NULL; - } - return _PyAST_Constant(str, NULL, tok->lineno, tok->col_offset, - tok->end_lineno, tok->end_col_offset, - p->arena); -} - -expr_ty _PyPegen_constant_from_token(Parser* p, Token* tok) { - char* bstr = PyBytes_AsString(tok->bytes); - if (bstr == NULL) { - return NULL; - } - PyObject* str = PyUnicode_FromString(bstr); - if (str == NULL) { - return NULL; - } - if (_PyArena_AddPyObject(p->arena, str) < 0) { - Py_DECREF(str); - return NULL; - } - return _PyAST_Constant(str, NULL, tok->lineno, tok->col_offset, - tok->end_lineno, tok->end_col_offset, - p->arena); -} - -expr_ty _PyPegen_constant_from_string(Parser* p, Token* tok) { - char* the_str = PyBytes_AsString(tok->bytes); - if (the_str == NULL) { - return NULL; - } - PyObject *s = _PyPegen_parse_string(p, tok); - if (s == NULL) { - _Pypegen_raise_decode_error(p); - return NULL; - } - if (_PyArena_AddPyObject(p->arena, s) < 0) { - Py_DECREF(s); - return NULL; - } - PyObject *kind = NULL; - if (the_str && the_str[0] == 'u') { - kind = _PyPegen_new_identifier(p, "u"); - if (kind == NULL) { - return NULL; - } - } - return _PyAST_Constant(s, kind, tok->lineno, tok->col_offset, tok->end_lineno, tok->end_col_offset, p->arena); -} - -expr_ty _PyPegen_formatted_value(Parser *p, expr_ty expression, Token *debug, ResultTokenWithMetadata *conversion, - ResultTokenWithMetadata *format, Token *closing_brace, int lineno, int col_offset, - int end_lineno, int end_col_offset, PyArena *arena) { - int conversion_val = -1; - if (conversion != NULL) { - expr_ty conversion_expr = (expr_ty) conversion->result; - assert(conversion_expr->kind == Name_kind); - Py_UCS4 first = PyUnicode_READ_CHAR(conversion_expr->v.Name.id, 0); - - if (PyUnicode_GET_LENGTH(conversion_expr->v.Name.id) > 1 || - !(first == 's' || first == 'r' || first == 'a')) { - RAISE_SYNTAX_ERROR_KNOWN_LOCATION(conversion_expr, - "f-string: invalid conversion character %R: expected 's', 'r', or 'a'", - conversion_expr->v.Name.id); - return NULL; - } - - conversion_val = Py_SAFE_DOWNCAST(first, Py_UCS4, int); - } - else if (debug && !format) { - /* If no conversion is specified, use !r for debug expressions */ - conversion_val = (int)'r'; - } - - expr_ty formatted_value = _PyAST_FormattedValue( - expression, conversion_val, format ? (expr_ty) format->result : NULL, - lineno, col_offset, end_lineno, - end_col_offset, arena - ); - - if (debug) { - /* Find the non whitespace token after the "=" */ - int debug_end_line, debug_end_offset; - PyObject *debug_metadata; - - if (conversion) { - debug_end_line = ((expr_ty) conversion->result)->lineno; - debug_end_offset = ((expr_ty) conversion->result)->col_offset; - debug_metadata = conversion->metadata; - } - else if (format) { - debug_end_line = ((expr_ty) format->result)->lineno; - debug_end_offset = ((expr_ty) format->result)->col_offset + 1; - debug_metadata = format->metadata; - } - else { - debug_end_line = end_lineno; - debug_end_offset = end_col_offset; - debug_metadata = closing_brace->metadata; - } - - expr_ty debug_text = _PyAST_Constant(debug_metadata, NULL, lineno, col_offset + 1, debug_end_line, - debug_end_offset - 1, p->arena); - if (!debug_text) { - return NULL; - } - - asdl_expr_seq *values = _Py_asdl_expr_seq_new(2, arena); - asdl_seq_SET(values, 0, debug_text); - asdl_seq_SET(values, 1, formatted_value); - return _PyAST_JoinedStr(values, lineno, col_offset, debug_end_line, debug_end_offset, p->arena); +unpack_top_level_joined_strs(Parser *p, asdl_expr_seq *raw_expressions) { + /* The parser might put multiple f-string values into an individual + * JoinedStr node at the top level due to stuff like f-string debugging + * expressions. This function flattens those and promotes them to the + * upper level. Only simplifies AST, but the compiler already takes care + * of the regular output, so this is not necessary if you are not going + * to expose the output AST to Python level. */ + + Py_ssize_t i, req_size, raw_size; + + req_size = raw_size = asdl_seq_LEN(raw_expressions); + expr_ty expr; + for (i = 0; i < raw_size; i++) { + expr = asdl_seq_GET(raw_expressions, i); + if (expr->kind == JoinedStr_kind) { + req_size += asdl_seq_LEN(expr->v.JoinedStr.values) - 1; + } + } + + asdl_expr_seq *expressions = _Py_asdl_expr_seq_new(req_size, p->arena); + if (expressions == NULL) { + return NULL; + } + + Py_ssize_t raw_index, req_index = 0; + for (raw_index = 0; raw_index < raw_size; raw_index++) { + expr = asdl_seq_GET(raw_expressions, raw_index); + if (expr->kind == JoinedStr_kind) { + asdl_expr_seq *values = expr->v.JoinedStr.values; + for (Py_ssize_t n = 0; n < asdl_seq_LEN(values); n++) { + asdl_seq_SET(expressions, req_index, asdl_seq_GET(values, n)); + req_index++; + } + } else { + asdl_seq_SET(expressions, req_index, expr); + req_index++; + } + } + return expressions; +} + +expr_ty _PyPegen_joined_str(Parser *p, Token *a, asdl_expr_seq *raw_expressions, + Token *b) { + + asdl_expr_seq *expr = unpack_top_level_joined_strs(p, raw_expressions); + Py_ssize_t n_items = asdl_seq_LEN(expr); + + const char *quote_str = PyBytes_AsString(a->bytes); + if (quote_str == NULL) { + return NULL; + } + int is_raw = strpbrk(quote_str, "rR") != NULL; + + asdl_expr_seq *seq = _Py_asdl_expr_seq_new(n_items, p->arena); + if (seq == NULL) { + return NULL; + } + + Py_ssize_t index = 0; + for (Py_ssize_t i = 0; i < n_items; i++) { + expr_ty item = asdl_seq_GET(expr, i); + if (item->kind == Constant_kind) { + item = _PyPegen_decode_fstring_part(p, is_raw, item, b); + if (item == NULL) { + return NULL; + } + + /* Tokenizer emits string parts even when the underlying string + might become an empty value (e.g. FSTRING_MIDDLE with the value \\n) + so we need to check for them and simplify it here. */ + if (PyUnicode_CheckExact(item->v.Constant.value) && + PyUnicode_GET_LENGTH(item->v.Constant.value) == 0) { + continue; + } + } + asdl_seq_SET(seq, index++, item); + } + + asdl_expr_seq *resized_exprs; + if (index != n_items) { + resized_exprs = _Py_asdl_expr_seq_new(index, p->arena); + if (resized_exprs == NULL) { + return NULL; + } + for (Py_ssize_t i = 0; i < index; i++) { + asdl_seq_SET(resized_exprs, i, asdl_seq_GET(seq, i)); + } + } else { + resized_exprs = seq; + } + + return _PyAST_JoinedStr(resized_exprs, a->lineno, a->col_offset, + b->end_lineno, b->end_col_offset, p->arena); +} + +expr_ty _PyPegen_decoded_constant_from_token(Parser *p, Token *tok) { + Py_ssize_t bsize; + char *bstr; + if (PyBytes_AsStringAndSize(tok->bytes, &bstr, &bsize) == -1) { + return NULL; + } + PyObject *str = _PyPegen_decode_string(p, 0, bstr, bsize, tok); + if (str == NULL) { + return NULL; + } + if (_PyArena_AddPyObject(p->arena, str) < 0) { + Py_DECREF(str); + return NULL; + } + return _PyAST_Constant(str, NULL, tok->lineno, tok->col_offset, + tok->end_lineno, tok->end_col_offset, p->arena); +} + +expr_ty _PyPegen_constant_from_token(Parser *p, Token *tok) { + char *bstr = PyBytes_AsString(tok->bytes); + if (bstr == NULL) { + return NULL; + } + PyObject *str = PyUnicode_FromString(bstr); + if (str == NULL) { + return NULL; + } + if (_PyArena_AddPyObject(p->arena, str) < 0) { + Py_DECREF(str); + return NULL; + } + return _PyAST_Constant(str, NULL, tok->lineno, tok->col_offset, + tok->end_lineno, tok->end_col_offset, p->arena); +} + +expr_ty _PyPegen_constant_from_string(Parser *p, Token *tok) { + char *the_str = PyBytes_AsString(tok->bytes); + if (the_str == NULL) { + return NULL; + } + PyObject *s = _PyPegen_parse_string(p, tok); + if (s == NULL) { + _Pypegen_raise_decode_error(p); + return NULL; + } + if (_PyArena_AddPyObject(p->arena, s) < 0) { + Py_DECREF(s); + return NULL; + } + PyObject *kind = NULL; + if (the_str && the_str[0] == 'u') { + kind = _PyPegen_new_identifier(p, "u"); + if (kind == NULL) { + return NULL; + } + } + return _PyAST_Constant(s, kind, tok->lineno, tok->col_offset, tok->end_lineno, + tok->end_col_offset, p->arena); +} + +expr_ty _PyPegen_formatted_value(Parser *p, expr_ty expression, Token *debug, + ResultTokenWithMetadata *conversion, + ResultTokenWithMetadata *format, + Token *closing_brace, int lineno, + int col_offset, int end_lineno, + int end_col_offset, PyArena *arena) { + int conversion_val = -1; + if (conversion != NULL) { + expr_ty conversion_expr = (expr_ty)conversion->result; + assert(conversion_expr->kind == Name_kind); + Py_UCS4 first = PyUnicode_READ_CHAR(conversion_expr->v.Name.id, 0); + + if (PyUnicode_GET_LENGTH(conversion_expr->v.Name.id) > 1 || + !(first == 's' || first == 'r' || first == 'a')) { + RAISE_SYNTAX_ERROR_KNOWN_LOCATION( + conversion_expr, + "f-string: invalid conversion character %R: expected 's', 'r', or " + "'a'", + conversion_expr->v.Name.id); + return NULL; + } + + conversion_val = Py_SAFE_DOWNCAST(first, Py_UCS4, int); + } else if (debug && !format) { + /* If no conversion is specified, use !r for debug expressions */ + conversion_val = (int)'r'; + } + + expr_ty formatted_value = _PyAST_FormattedValue( + expression, conversion_val, format ? (expr_ty)format->result : NULL, + lineno, col_offset, end_lineno, end_col_offset, arena); + + if (debug) { + /* Find the non whitespace token after the "=" */ + int debug_end_line, debug_end_offset; + PyObject *debug_metadata; + + if (conversion) { + debug_end_line = ((expr_ty)conversion->result)->lineno; + debug_end_offset = ((expr_ty)conversion->result)->col_offset; + debug_metadata = conversion->metadata; + } else if (format) { + debug_end_line = ((expr_ty)format->result)->lineno; + debug_end_offset = ((expr_ty)format->result)->col_offset + 1; + debug_metadata = format->metadata; + } else { + debug_end_line = end_lineno; + debug_end_offset = end_col_offset; + debug_metadata = closing_brace->metadata; } - else { - return formatted_value; + expr_ty debug_text = + _PyAST_Constant(debug_metadata, NULL, lineno, col_offset + 1, + debug_end_line, debug_end_offset - 1, p->arena); + if (!debug_text) { + return NULL; } -} -expr_ty -_PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *strings, - int lineno, int col_offset, int end_lineno, - int end_col_offset, PyArena *arena) -{ - Py_ssize_t len = asdl_seq_LEN(strings); - assert(len > 0); - - int f_string_found = 0; - int unicode_string_found = 0; - int bytes_found = 0; - - Py_ssize_t i = 0; - Py_ssize_t n_flattened_elements = 0; + asdl_expr_seq *values = _Py_asdl_expr_seq_new(2, arena); + if (values == NULL) { + return NULL; + } + asdl_seq_SET(values, 0, debug_text); + asdl_seq_SET(values, 1, formatted_value); + return _PyAST_JoinedStr(values, lineno, col_offset, debug_end_line, + debug_end_offset, p->arena); + } else { + return formatted_value; + } +} + +expr_ty _PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *strings, + int lineno, int col_offset, int end_lineno, + int end_col_offset, PyArena *arena) { + Py_ssize_t len = asdl_seq_LEN(strings); + assert(len > 0); + + int f_string_found = 0; + int unicode_string_found = 0; + int bytes_found = 0; + + Py_ssize_t i = 0; + Py_ssize_t n_flattened_elements = 0; + for (i = 0; i < len; i++) { + expr_ty elem = asdl_seq_GET(strings, i); + switch (elem->kind) { + case Constant_kind: + if (PyBytes_CheckExact(elem->v.Constant.value)) { + bytes_found = 1; + } else { + unicode_string_found = 1; + } + n_flattened_elements++; + break; + case JoinedStr_kind: + n_flattened_elements += asdl_seq_LEN(elem->v.JoinedStr.values); + f_string_found = 1; + break; + default: + n_flattened_elements++; + f_string_found = 1; + break; + } + } + + if ((unicode_string_found || f_string_found) && bytes_found) { + RAISE_SYNTAX_ERROR("cannot mix bytes and nonbytes literals"); + return NULL; + } + + if (bytes_found) { + PyObject *res = PyBytes_FromString(""); + + /* Bytes literals never get a kind, but just for consistency + since they are represented as Constant nodes, we'll mirror + the same behavior as unicode strings for determining the + kind. */ + PyObject *kind = asdl_seq_GET(strings, 0)->v.Constant.kind; for (i = 0; i < len; i++) { - expr_ty elem = asdl_seq_GET(strings, i); - if (elem->kind == Constant_kind) { - if (PyBytes_CheckExact(elem->v.Constant.value)) { - bytes_found = 1; - } else { - unicode_string_found = 1; + expr_ty elem = asdl_seq_GET(strings, i); + PyBytes_Concat(&res, elem->v.Constant.value); + } + if (!res || _PyArena_AddPyObject(arena, res) < 0) { + Py_XDECREF(res); + return NULL; + } + return _PyAST_Constant(res, kind, lineno, col_offset, end_lineno, + end_col_offset, p->arena); + } + + if (!f_string_found && len == 1) { + return asdl_seq_GET(strings, 0); + } + + asdl_expr_seq *flattened = + _Py_asdl_expr_seq_new(n_flattened_elements, p->arena); + if (flattened == NULL) { + return NULL; + } + + /* build flattened list */ + Py_ssize_t current_pos = 0; + Py_ssize_t j = 0; + for (i = 0; i < len; i++) { + expr_ty elem = asdl_seq_GET(strings, i); + switch (elem->kind) { + case JoinedStr_kind: + for (j = 0; j < asdl_seq_LEN(elem->v.JoinedStr.values); j++) { + expr_ty subvalue = asdl_seq_GET(elem->v.JoinedStr.values, j); + if (subvalue == NULL) { + return NULL; + } + asdl_seq_SET(flattened, current_pos++, subvalue); + } + break; + default: + asdl_seq_SET(flattened, current_pos++, elem); + break; + } + } + + /* calculate folded element count */ + Py_ssize_t n_elements = 0; + int prev_is_constant = 0; + for (i = 0; i < n_flattened_elements; i++) { + expr_ty elem = asdl_seq_GET(flattened, i); + + /* The concatenation of a FormattedValue and an empty Contant should + lead to the FormattedValue itself. Thus, we will not take any empty + constants into account, just as in `_PyPegen_joined_str` */ + if (f_string_found && elem->kind == Constant_kind && + PyUnicode_CheckExact(elem->v.Constant.value) && + PyUnicode_GET_LENGTH(elem->v.Constant.value) == 0) + continue; + + if (!prev_is_constant || elem->kind != Constant_kind) { + n_elements++; + } + prev_is_constant = elem->kind == Constant_kind; + } + + asdl_expr_seq *values = _Py_asdl_expr_seq_new(n_elements, p->arena); + if (values == NULL) { + return NULL; + } + + /* build folded list */ + _PyUnicodeWriter writer; + current_pos = 0; + for (i = 0; i < n_flattened_elements; i++) { + expr_ty elem = asdl_seq_GET(flattened, i); + + /* if the current elem and the following are constants, + fold them and all consequent constants */ + if (elem->kind == Constant_kind) { + if (i + 1 < n_flattened_elements && + asdl_seq_GET(flattened, i + 1)->kind == Constant_kind) { + expr_ty first_elem = elem; + + /* When a string is getting concatenated, the kind of the string + is determined by the first string in the concatenation + sequence. + + u"abc" "def" -> u"abcdef" + "abc" u"abc" -> "abcabc" */ + PyObject *kind = elem->v.Constant.kind; + + _PyUnicodeWriter_Init(&writer); + expr_ty last_elem = elem; + for (j = i; j < n_flattened_elements; j++) { + expr_ty current_elem = asdl_seq_GET(flattened, j); + if (current_elem->kind == Constant_kind) { + if (_PyUnicodeWriter_WriteStr(&writer, + current_elem->v.Constant.value)) { + _PyUnicodeWriter_Dealloc(&writer); + return NULL; } - n_flattened_elements++; - } else { - n_flattened_elements += asdl_seq_LEN(elem->v.JoinedStr.values); - f_string_found = 1; + last_elem = current_elem; + } else { + break; + } } - } + i = j - 1; - if ((unicode_string_found || f_string_found) && bytes_found) { - RAISE_SYNTAX_ERROR("cannot mix bytes and nonbytes literals"); - return NULL; - } - - if (bytes_found) { - PyObject* res = PyBytes_FromString(""); - - /* Bytes literals never get a kind, but just for consistency - since they are represented as Constant nodes, we'll mirror - the same behavior as unicode strings for determining the - kind. */ - PyObject* kind = asdl_seq_GET(strings, 0)->v.Constant.kind; - for (i = 0; i < len; i++) { - expr_ty elem = asdl_seq_GET(strings, i); - PyBytes_Concat(&res, elem->v.Constant.value); + PyObject *concat_str = _PyUnicodeWriter_Finish(&writer); + if (concat_str == NULL) { + _PyUnicodeWriter_Dealloc(&writer); + return NULL; } - if (!res || _PyArena_AddPyObject(arena, res) < 0) { - Py_XDECREF(res); - return NULL; + if (_PyArena_AddPyObject(p->arena, concat_str) < 0) { + Py_DECREF(concat_str); + return NULL; } - return _PyAST_Constant(res, kind, lineno, col_offset, end_lineno, end_col_offset, p->arena); - } - - if (!f_string_found && len == 1) { - return asdl_seq_GET(strings, 0); - } - - asdl_expr_seq* flattened = _Py_asdl_expr_seq_new(n_flattened_elements, p->arena); - if (flattened == NULL) { - return NULL; - } - - /* build flattened list */ - Py_ssize_t current_pos = 0; - Py_ssize_t j = 0; - for (i = 0; i < len; i++) { - expr_ty elem = asdl_seq_GET(strings, i); - if (elem->kind == Constant_kind) { - asdl_seq_SET(flattened, current_pos++, elem); - } else { - for (j = 0; j < asdl_seq_LEN(elem->v.JoinedStr.values); j++) { - expr_ty subvalue = asdl_seq_GET(elem->v.JoinedStr.values, j); - if (subvalue == NULL) { - return NULL; - } - asdl_seq_SET(flattened, current_pos++, subvalue); - } + elem = _PyAST_Constant(concat_str, kind, first_elem->lineno, + first_elem->col_offset, last_elem->end_lineno, + last_elem->end_col_offset, p->arena); + if (elem == NULL) { + return NULL; } - } + } - /* calculate folded element count */ - Py_ssize_t n_elements = 0; - int prev_is_constant = 0; - for (i = 0; i < n_flattened_elements; i++) { - expr_ty elem = asdl_seq_GET(flattened, i); - - /* The concatenation of a FormattedValue and an empty Contant should - lead to the FormattedValue itself. Thus, we will not take any empty - constants into account, just as in `_PyPegen_joined_str` */ - if (f_string_found && elem->kind == Constant_kind && - PyUnicode_CheckExact(elem->v.Constant.value) && - PyUnicode_GET_LENGTH(elem->v.Constant.value) == 0) - continue; - - if (!prev_is_constant || elem->kind != Constant_kind) { - n_elements++; - } - prev_is_constant = elem->kind == Constant_kind; - } - - asdl_expr_seq* values = _Py_asdl_expr_seq_new(n_elements, p->arena); - if (values == NULL) { - return NULL; + /* Drop all empty contanst strings */ + if (f_string_found && PyUnicode_CheckExact(elem->v.Constant.value) && + PyUnicode_GET_LENGTH(elem->v.Constant.value) == 0) { + continue; + } } - /* build folded list */ - _PyUnicodeWriter writer; - current_pos = 0; - for (i = 0; i < n_flattened_elements; i++) { - expr_ty elem = asdl_seq_GET(flattened, i); - - /* if the current elem and the following are constants, - fold them and all consequent constants */ - if (elem->kind == Constant_kind) { - if (i + 1 < n_flattened_elements && - asdl_seq_GET(flattened, i + 1)->kind == Constant_kind) { - expr_ty first_elem = elem; - - /* When a string is getting concatenated, the kind of the string - is determined by the first string in the concatenation - sequence. - - u"abc" "def" -> u"abcdef" - "abc" u"abc" -> "abcabc" */ - PyObject *kind = elem->v.Constant.kind; - - _PyUnicodeWriter_Init(&writer); - expr_ty last_elem = elem; - for (j = i; j < n_flattened_elements; j++) { - expr_ty current_elem = asdl_seq_GET(flattened, j); - if (current_elem->kind == Constant_kind) { - if (_PyUnicodeWriter_WriteStr( - &writer, current_elem->v.Constant.value)) { - _PyUnicodeWriter_Dealloc(&writer); - return NULL; - } - last_elem = current_elem; - } else { - break; - } - } - i = j - 1; - - PyObject *concat_str = _PyUnicodeWriter_Finish(&writer); - if (concat_str == NULL) { - _PyUnicodeWriter_Dealloc(&writer); - return NULL; - } - if (_PyArena_AddPyObject(p->arena, concat_str) < 0) { - Py_DECREF(concat_str); - return NULL; - } - elem = _PyAST_Constant(concat_str, kind, first_elem->lineno, - first_elem->col_offset, - last_elem->end_lineno, - last_elem->end_col_offset, p->arena); - if (elem == NULL) { - return NULL; - } - } - - /* Drop all empty contanst strings */ - if (f_string_found && - PyUnicode_CheckExact(elem->v.Constant.value) && - PyUnicode_GET_LENGTH(elem->v.Constant.value) == 0) { - continue; - } - } - - asdl_seq_SET(values, current_pos++, elem); - } + asdl_seq_SET(values, current_pos++, elem); + } - if (!f_string_found) { - assert(n_elements == 1); - expr_ty elem = asdl_seq_GET(values, 0); - assert(elem->kind == Constant_kind); - return elem; - } + if (!f_string_found) { + assert(n_elements == 1); + expr_ty elem = asdl_seq_GET(values, 0); + assert(elem->kind == Constant_kind); + return elem; + } - assert(current_pos == n_elements); - return _PyAST_JoinedStr(values, lineno, col_offset, end_lineno, end_col_offset, p->arena); + assert(current_pos == n_elements); + return _PyAST_JoinedStr(values, lineno, col_offset, end_lineno, + end_col_offset, p->arena); } diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py index 2c34f5c1..6f5a772d 100755 --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -813,14 +813,15 @@ def visitModule(self, mod): Py_ssize_t i, numfields = 0; int res = -1; PyObject *key, *value, *fields; - if (_PyObject_LookupAttr((PyObject*)Py_TYPE(self), state->_fields, &fields) < 0) { + + fields = PyObject_GetAttr((PyObject*)Py_TYPE(self), state->_fields); + if (fields == NULL) { goto cleanup; } - if (fields) { - numfields = PySequence_Size(fields); - if (numfields == -1) { - goto cleanup; - } + + numfields = PySequence_Size(fields); + if (numfields == -1) { + goto cleanup; } res = 0; /* if no error occurs, this stays 0 to the end */ diff --git a/Parser/myreadline.c b/Parser/myreadline.c index 7074aba7..2890ff83 100644 --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -386,9 +386,14 @@ PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) } } - _PyOS_ReadlineTState = tstate; Py_BEGIN_ALLOW_THREADS + + // GH-123321: We need to acquire the lock before setting + // _PyOS_ReadlineTState and after the release of the GIL, otherwise + // the variable may be nullified by a different thread or a deadlock + // may occur if the GIL is taken in any sub-function. PyThread_acquire_lock(_PyOS_ReadlineLock, 1); + _PyOS_ReadlineTState = tstate; /* This is needed to handle the unlikely case that the * interpreter is in interactive mode *and* stdin/out are not @@ -412,11 +417,13 @@ PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) else { rv = (*PyOS_ReadlineFunctionPointer)(sys_stdin, sys_stdout, prompt); } - Py_END_ALLOW_THREADS + // gh-123321: Must set the variable and then release the lock before + // taking the GIL. Otherwise a deadlock or segfault may occur. + _PyOS_ReadlineTState = NULL; PyThread_release_lock(_PyOS_ReadlineLock); - _PyOS_ReadlineTState = NULL; + Py_END_ALLOW_THREADS if (rv == NULL) return NULL; diff --git a/Parser/pegen.c b/Parser/pegen.c index 5460fbb2..6ae9bef2 100644 --- a/Parser/pegen.c +++ b/Parser/pegen.c @@ -394,7 +394,7 @@ _PyPegen_is_memoized(Parser *p, int type, void *pres) for (Memo *m = t->memo; m != NULL; m = m->next) { if (m->type == type) { -#if defined(PY_DEBUG) +#if defined(Py_DEBUG) if (0 <= type && type < NSTATISTICS) { long count = m->mark - p->mark; // A memoized negative result counts for one. @@ -581,7 +581,8 @@ _PyPegen_new_identifier(Parser *p, const char *n) } id = id2; } - PyUnicode_InternInPlace(&id); + PyInterpreterState *interp = _PyInterpreterState_GET(); + _PyUnicode_InternImmortal(interp, &id); if (_PyArena_AddPyObject(p->arena, id) < 0) { Py_DECREF(id); diff --git a/Parser/string_parser.c b/Parser/string_parser.c index 65c320c2..164f715e 100644 --- a/Parser/string_parser.c +++ b/Parser/string_parser.c @@ -226,9 +226,14 @@ _PyPegen_parse_string(Parser *p, Token *t) PyErr_BadInternalCall(); return NULL; } + /* Skip the leading quote char. */ s++; len = strlen(s); + // gh-120155: 's' contains at least the trailing quote, + // so the code '--len' below is safe. + assert(len >= 1); + if (len > INT_MAX) { PyErr_SetString(PyExc_OverflowError, "string to parse is too long"); return NULL; diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 04ba0442..9e0dee8c 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -3,53 +3,48 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" -#include "pycore_call.h" // _PyObject_CallNoArgs() +#include "pycore_call.h" // _PyObject_CallNoArgs() -#include #include +#include -#include "tokenizer.h" #include "errcode.h" +#include "tokenizer.h" /* Alternate tab spacing */ #define ALTTABSIZE 1 -#define is_potential_identifier_start(c) (\ - (c >= 'a' && c <= 'z')\ - || (c >= 'A' && c <= 'Z')\ - || c == '_'\ - || (c >= 128)) - -#define is_potential_identifier_char(c) (\ - (c >= 'a' && c <= 'z')\ - || (c >= 'A' && c <= 'Z')\ - || (c >= '0' && c <= '9')\ - || c == '_'\ - || (c >= 128)) +#define is_potential_identifier_start(c) \ + ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= 128)) +#define is_potential_identifier_char(c) \ + ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || \ + (c >= '0' && c <= '9') || c == '_' || (c >= 128)) /* Don't ever change this -- it would break the portability of Python code */ #define TABSIZE 8 -#define MAKE_TOKEN(token_type) token_setup(tok, token, token_type, p_start, p_end) -#define MAKE_TYPE_COMMENT_TOKEN(token_type, col_offset, end_col_offset) (\ - type_comment_token_setup(tok, token, token_type, col_offset, end_col_offset, p_start, p_end)) -#define ADVANCE_LINENO() \ - tok->lineno++; \ - tok->col_offset = 0; +#define MAKE_TOKEN(token_type) \ + token_setup(tok, token, token_type, p_start, p_end) +#define MAKE_TYPE_COMMENT_TOKEN(token_type, col_offset, end_col_offset) \ + (type_comment_token_setup(tok, token, token_type, col_offset, \ + end_col_offset, p_start, p_end)) +#define ADVANCE_LINENO() \ + tok->lineno++; \ + tok->col_offset = 0; #define INSIDE_FSTRING(tok) (tok->tok_mode_stack_index > 0) #define INSIDE_FSTRING_EXPR(tok) (tok->curly_bracket_expr_start_depth >= 0) #ifdef Py_DEBUG -static inline tokenizer_mode* TOK_GET_MODE(struct tok_state* tok) { - assert(tok->tok_mode_stack_index >= 0); - assert(tok->tok_mode_stack_index < MAXFSTRINGLEVEL); - return &(tok->tok_mode_stack[tok->tok_mode_stack_index]); +static inline tokenizer_mode *TOK_GET_MODE(struct tok_state *tok) { + assert(tok->tok_mode_stack_index >= 0); + assert(tok->tok_mode_stack_index < MAXFSTRINGLEVEL); + return &(tok->tok_mode_stack[tok->tok_mode_stack_index]); } -static inline tokenizer_mode* TOK_NEXT_MODE(struct tok_state* tok) { - assert(tok->tok_mode_stack_index >= 0); - assert(tok->tok_mode_stack_index + 1 < MAXFSTRINGLEVEL); - return &(tok->tok_mode_stack[++tok->tok_mode_stack_index]); +static inline tokenizer_mode *TOK_NEXT_MODE(struct tok_state *tok) { + assert(tok->tok_mode_stack_index >= 0); + assert(tok->tok_mode_stack_index + 1 < MAXFSTRINGLEVEL); + return &(tok->tok_mode_stack[++tok->tok_mode_stack_index]); } #else #define TOK_GET_MODE(tok) (&(tok->tok_mode_stack[tok->tok_mode_stack_index])) @@ -64,171 +59,164 @@ static int syntaxerror(struct tok_state *tok, const char *format, ...); /* Spaces in this constant are treated as "zero or more spaces or tabs" when tokenizing. */ -static const char* type_comment_prefix = "# type: "; +static const char *type_comment_prefix = "# type: "; /* Create and initialize a new tok_state structure */ -static struct tok_state * -tok_new(void) -{ - struct tok_state *tok = (struct tok_state *)PyMem_Malloc( - sizeof(struct tok_state)); - if (tok == NULL) - return NULL; - tok->buf = tok->cur = tok->inp = NULL; - tok->fp_interactive = 0; - tok->interactive_src_start = NULL; - tok->interactive_src_end = NULL; - tok->start = NULL; - tok->end = NULL; - tok->done = E_OK; - tok->fp = NULL; - tok->input = NULL; - tok->tabsize = TABSIZE; - tok->indent = 0; - tok->indstack[0] = 0; - tok->atbol = 1; - tok->pendin = 0; - tok->prompt = tok->nextprompt = NULL; - tok->lineno = 0; - tok->starting_col_offset = -1; - tok->col_offset = -1; - tok->level = 0; - tok->altindstack[0] = 0; - tok->decoding_state = STATE_INIT; - tok->decoding_erred = 0; - tok->enc = NULL; - tok->encoding = NULL; - tok->cont_line = 0; - tok->filename = NULL; - tok->decoding_readline = NULL; - tok->decoding_buffer = NULL; - tok->readline = NULL; - tok->type_comments = 0; - tok->async_hacks = 0; - tok->async_def = 0; - tok->async_def_indent = 0; - tok->async_def_nl = 0; - tok->interactive_underflow = IUNDERFLOW_NORMAL; - tok->str = NULL; - tok->report_warnings = 1; - tok->tok_extra_tokens = 0; - tok->comment_newline = 0; - tok->implicit_newline = 0; - tok->tok_mode_stack[0] = (tokenizer_mode){.kind =TOK_REGULAR_MODE, .f_string_quote='\0', .f_string_quote_size = 0, .f_string_debug=0}; - tok->tok_mode_stack_index = 0; +static struct tok_state *tok_new(void) { + struct tok_state *tok = + (struct tok_state *)PyMem_Calloc(1, sizeof(struct tok_state)); + if (tok == NULL) + return NULL; + tok->buf = tok->cur = tok->inp = NULL; + tok->fp_interactive = 0; + tok->interactive_src_start = NULL; + tok->interactive_src_end = NULL; + tok->start = NULL; + tok->end = NULL; + tok->done = E_OK; + tok->fp = NULL; + tok->input = NULL; + tok->tabsize = TABSIZE; + tok->indent = 0; + tok->indstack[0] = 0; + tok->atbol = 1; + tok->pendin = 0; + tok->prompt = tok->nextprompt = NULL; + tok->lineno = 0; + tok->starting_col_offset = -1; + tok->col_offset = -1; + tok->level = 0; + tok->altindstack[0] = 0; + tok->decoding_state = STATE_INIT; + tok->decoding_erred = 0; + tok->enc = NULL; + tok->encoding = NULL; + tok->cont_line = 0; + tok->filename = NULL; + tok->decoding_readline = NULL; + tok->decoding_buffer = NULL; + tok->readline = NULL; + tok->type_comments = 0; + tok->async_hacks = 0; + tok->async_def = 0; + tok->async_def_indent = 0; + tok->async_def_nl = 0; + tok->interactive_underflow = IUNDERFLOW_NORMAL; + tok->str = NULL; + tok->report_warnings = 1; + tok->tok_extra_tokens = 0; + tok->comment_newline = 0; + tok->implicit_newline = 0; + tok->tok_mode_stack[0] = (tokenizer_mode){.kind = TOK_REGULAR_MODE, + .f_string_quote = '\0', + .f_string_quote_size = 0, + .f_string_debug = 0}; + tok->tok_mode_stack_index = 0; #ifdef Py_DEBUG - tok->debug = _Py_GetConfig()->parser_debug; + tok->debug = _Py_GetConfig()->parser_debug; #endif - return tok; + return tok; } -static char * -new_string(const char *s, Py_ssize_t len, struct tok_state *tok) -{ - char* result = (char *)PyMem_Malloc(len + 1); - if (!result) { - tok->done = E_NOMEM; - return NULL; - } - memcpy(result, s, len); - result[len] = '\0'; - return result; +static char *new_string(const char *s, Py_ssize_t len, struct tok_state *tok) { + char *result = (char *)PyMem_Malloc(len + 1); + if (!result) { + tok->done = E_NOMEM; + return NULL; + } + memcpy(result, s, len); + result[len] = '\0'; + return result; } -static char * -error_ret(struct tok_state *tok) /* XXX */ +static char *error_ret(struct tok_state *tok) /* XXX */ { - tok->decoding_erred = 1; - if ((tok->fp != NULL || tok->readline != NULL) && tok->buf != NULL) {/* see _PyTokenizer_Free */ - PyMem_Free(tok->buf); - } - tok->buf = tok->cur = tok->inp = NULL; - tok->start = NULL; - tok->end = NULL; - tok->done = E_DECODE; - return NULL; /* as if it were EOF */ -} - - -static const char * -get_normal_name(const char *s) /* for utf-8 and latin-1 */ + tok->decoding_erred = 1; + if ((tok->fp != NULL || tok->readline != NULL) && + tok->buf != NULL) { /* see _PyTokenizer_Free */ + PyMem_Free(tok->buf); + } + tok->buf = tok->cur = tok->inp = NULL; + tok->start = NULL; + tok->end = NULL; + tok->done = E_DECODE; + return NULL; /* as if it were EOF */ +} + +static const char *get_normal_name(const char *s) /* for utf-8 and latin-1 */ { - char buf[13]; - int i; - for (i = 0; i < 12; i++) { - int c = s[i]; - if (c == '\0') - break; - else if (c == '_') - buf[i] = '-'; - else - buf[i] = tolower(c); - } - buf[i] = '\0'; - if (strcmp(buf, "utf-8") == 0 || - strncmp(buf, "utf-8-", 6) == 0) - return "utf-8"; - else if (strcmp(buf, "latin-1") == 0 || - strcmp(buf, "iso-8859-1") == 0 || - strcmp(buf, "iso-latin-1") == 0 || - strncmp(buf, "latin-1-", 8) == 0 || - strncmp(buf, "iso-8859-1-", 11) == 0 || - strncmp(buf, "iso-latin-1-", 12) == 0) - return "iso-8859-1"; + char buf[13]; + int i; + for (i = 0; i < 12; i++) { + int c = s[i]; + if (c == '\0') + break; + else if (c == '_') + buf[i] = '-'; else - return s; + buf[i] = tolower(c); + } + buf[i] = '\0'; + if (strcmp(buf, "utf-8") == 0 || strncmp(buf, "utf-8-", 6) == 0) + return "utf-8"; + else if (strcmp(buf, "latin-1") == 0 || strcmp(buf, "iso-8859-1") == 0 || + strcmp(buf, "iso-latin-1") == 0 || + strncmp(buf, "latin-1-", 8) == 0 || + strncmp(buf, "iso-8859-1-", 11) == 0 || + strncmp(buf, "iso-latin-1-", 12) == 0) + return "iso-8859-1"; + else + return s; } /* Return the coding spec in S, or NULL if none is found. */ -static int -get_coding_spec(const char *s, char **spec, Py_ssize_t size, struct tok_state *tok) -{ - Py_ssize_t i; - *spec = NULL; - /* Coding spec must be in a comment, and that comment must be - * the only statement on the source code line. */ - for (i = 0; i < size - 6; i++) { - if (s[i] == '#') - break; - if (s[i] != ' ' && s[i] != '\t' && s[i] != '\014') - return 1; - } - for (; i < size - 6; i++) { /* XXX inefficient search */ - const char* t = s + i; - if (memcmp(t, "coding", 6) == 0) { - const char* begin = NULL; - t += 6; - if (t[0] != ':' && t[0] != '=') - continue; - do { - t++; - } while (t[0] == ' ' || t[0] == '\t'); - - begin = t; - while (Py_ISALNUM(t[0]) || - t[0] == '-' || t[0] == '_' || t[0] == '.') - t++; - - if (begin < t) { - char* r = new_string(begin, t - begin, tok); - const char* q; - if (!r) - return 0; - q = get_normal_name(r); - if (r != q) { - PyMem_Free(r); - r = new_string(q, strlen(q), tok); - if (!r) - return 0; - } - *spec = r; - break; - } +static int get_coding_spec(const char *s, char **spec, Py_ssize_t size, + struct tok_state *tok) { + Py_ssize_t i; + *spec = NULL; + /* Coding spec must be in a comment, and that comment must be + * the only statement on the source code line. */ + for (i = 0; i < size - 6; i++) { + if (s[i] == '#') + break; + if (s[i] != ' ' && s[i] != '\t' && s[i] != '\014') + return 1; + } + for (; i < size - 6; i++) { /* XXX inefficient search */ + const char *t = s + i; + if (memcmp(t, "coding", 6) == 0) { + const char *begin = NULL; + t += 6; + if (t[0] != ':' && t[0] != '=') + continue; + do { + t++; + } while (t[0] == ' ' || t[0] == '\t'); + + begin = t; + while (Py_ISALNUM(t[0]) || t[0] == '-' || t[0] == '_' || t[0] == '.') + t++; + + if (begin < t) { + char *r = new_string(begin, t - begin, tok); + const char *q; + if (!r) + return 0; + q = get_normal_name(r); + if (r != q) { + PyMem_Free(r); + r = new_string(q, strlen(q), tok); + if (!r) + return 0; } + *spec = r; + break; + } } - return 1; + } + return 1; } /* Check whether the line contains a coding spec. If it does, @@ -237,299 +225,288 @@ get_coding_spec(const char *s, char **spec, Py_ssize_t size, struct tok_state *t Return 1 on success, 0 on failure. */ static int -check_coding_spec(const char* line, Py_ssize_t size, struct tok_state *tok, - int set_readline(struct tok_state *, const char *)) -{ - char *cs; - if (tok->cont_line) { - /* It's a continuation line, so it can't be a coding spec. */ - tok->decoding_state = STATE_NORMAL; - return 1; - } - if (!get_coding_spec(line, &cs, size, tok)) { - return 0; - } - if (!cs) { - Py_ssize_t i; - for (i = 0; i < size; i++) { - if (line[i] == '#' || line[i] == '\n' || line[i] == '\r') - break; - if (line[i] != ' ' && line[i] != '\t' && line[i] != '\014') { - /* Stop checking coding spec after a line containing - * anything except a comment. */ - tok->decoding_state = STATE_NORMAL; - break; - } - } - return 1; - } +check_coding_spec(const char *line, Py_ssize_t size, struct tok_state *tok, + int set_readline(struct tok_state *, const char *)) { + char *cs; + if (tok->cont_line) { + /* It's a continuation line, so it can't be a coding spec. */ tok->decoding_state = STATE_NORMAL; - if (tok->encoding == NULL) { - assert(tok->decoding_readline == NULL); - if (strcmp(cs, "utf-8") != 0 && !set_readline(tok, cs)) { - error_ret(tok); - PyErr_Format(PyExc_SyntaxError, "encoding problem: %s", cs); - PyMem_Free(cs); - return 0; - } - tok->encoding = cs; - } else { /* then, compare cs with BOM */ - if (strcmp(tok->encoding, cs) != 0) { - error_ret(tok); - PyErr_Format(PyExc_SyntaxError, - "encoding problem: %s with BOM", cs); - PyMem_Free(cs); - return 0; - } - PyMem_Free(cs); + return 1; + } + if (!get_coding_spec(line, &cs, size, tok)) { + return 0; + } + if (!cs) { + Py_ssize_t i; + for (i = 0; i < size; i++) { + if (line[i] == '#' || line[i] == '\n' || line[i] == '\r') + break; + if (line[i] != ' ' && line[i] != '\t' && line[i] != '\014') { + /* Stop checking coding spec after a line containing + * anything except a comment. */ + tok->decoding_state = STATE_NORMAL; + break; + } } return 1; + } + tok->decoding_state = STATE_NORMAL; + if (tok->encoding == NULL) { + assert(tok->decoding_readline == NULL); + if (strcmp(cs, "utf-8") != 0 && !set_readline(tok, cs)) { + error_ret(tok); + PyErr_Format(PyExc_SyntaxError, "encoding problem: %s", cs); + PyMem_Free(cs); + return 0; + } + tok->encoding = cs; + } else { /* then, compare cs with BOM */ + if (strcmp(tok->encoding, cs) != 0) { + error_ret(tok); + PyErr_Format(PyExc_SyntaxError, "encoding problem: %s with BOM", cs); + PyMem_Free(cs); + return 0; + } + PyMem_Free(cs); + } + return 1; } /* See whether the file starts with a BOM. If it does, invoke the set_readline function with the new encoding. Return 1 on success, 0 on failure. */ -static int -check_bom(int get_char(struct tok_state *), - void unget_char(int, struct tok_state *), - int set_readline(struct tok_state *, const char *), - struct tok_state *tok) -{ - int ch1, ch2, ch3; - ch1 = get_char(tok); - tok->decoding_state = STATE_SEEK_CODING; - if (ch1 == EOF) { - return 1; - } else if (ch1 == 0xEF) { - ch2 = get_char(tok); - if (ch2 != 0xBB) { - unget_char(ch2, tok); - unget_char(ch1, tok); - return 1; - } - ch3 = get_char(tok); - if (ch3 != 0xBF) { - unget_char(ch3, tok); - unget_char(ch2, tok); - unget_char(ch1, tok); - return 1; - } - } else { - unget_char(ch1, tok); - return 1; - } - if (tok->encoding != NULL) - PyMem_Free(tok->encoding); - tok->encoding = new_string("utf-8", 5, tok); - if (!tok->encoding) - return 0; - /* No need to set_readline: input is already utf-8 */ +static int check_bom(int get_char(struct tok_state *), + void unget_char(int, struct tok_state *), + int set_readline(struct tok_state *, const char *), + struct tok_state *tok) { + int ch1, ch2, ch3; + ch1 = get_char(tok); + tok->decoding_state = STATE_SEEK_CODING; + if (ch1 == EOF) { + return 1; + } else if (ch1 == 0xEF) { + ch2 = get_char(tok); + if (ch2 != 0xBB) { + unget_char(ch2, tok); + unget_char(ch1, tok); + return 1; + } + ch3 = get_char(tok); + if (ch3 != 0xBF) { + unget_char(ch3, tok); + unget_char(ch2, tok); + unget_char(ch1, tok); + return 1; + } + } else { + unget_char(ch1, tok); return 1; + } + if (tok->encoding != NULL) + PyMem_Free(tok->encoding); + tok->encoding = new_string("utf-8", 5, tok); + if (!tok->encoding) + return 0; + /* No need to set_readline: input is already utf-8 */ + return 1; } -static int -tok_concatenate_interactive_new_line(struct tok_state *tok, const char *line) { - assert(tok->fp_interactive); - - if (!line) { - return 0; - } - - Py_ssize_t current_size = tok->interactive_src_end - tok->interactive_src_start; - Py_ssize_t line_size = strlen(line); - char last_char = line[line_size > 0 ? line_size - 1 : line_size]; - if (last_char != '\n') { - line_size += 1; - } - char* new_str = tok->interactive_src_start; +static int tok_concatenate_interactive_new_line(struct tok_state *tok, + const char *line) { + assert(tok->fp_interactive); - new_str = PyMem_Realloc(new_str, current_size + line_size + 1); - if (!new_str) { - if (tok->interactive_src_start) { - PyMem_Free(tok->interactive_src_start); - } - tok->interactive_src_start = NULL; - tok->interactive_src_end = NULL; - tok->done = E_NOMEM; - return -1; - } - strcpy(new_str + current_size, line); - tok->implicit_newline = 0; - if (last_char != '\n') { - /* Last line does not end in \n, fake one */ - new_str[current_size + line_size - 1] = '\n'; - new_str[current_size + line_size] = '\0'; - tok->implicit_newline = 1; - } - tok->interactive_src_start = new_str; - tok->interactive_src_end = new_str + current_size + line_size; + if (!line) { return 0; + } + + Py_ssize_t current_size = + tok->interactive_src_end - tok->interactive_src_start; + Py_ssize_t line_size = strlen(line); + char last_char = line[line_size > 0 ? line_size - 1 : line_size]; + if (last_char != '\n') { + line_size += 1; + } + char *new_str = tok->interactive_src_start; + + new_str = PyMem_Realloc(new_str, current_size + line_size + 1); + if (!new_str) { + if (tok->interactive_src_start) { + PyMem_Free(tok->interactive_src_start); + } + tok->interactive_src_start = NULL; + tok->interactive_src_end = NULL; + tok->done = E_NOMEM; + return -1; + } + strcpy(new_str + current_size, line); + tok->implicit_newline = 0; + if (last_char != '\n') { + /* Last line does not end in \n, fake one */ + new_str[current_size + line_size - 1] = '\n'; + new_str[current_size + line_size] = '\0'; + tok->implicit_newline = 1; + } + tok->interactive_src_start = new_str; + tok->interactive_src_end = new_str + current_size + line_size; + return 0; } /* Traverse and remember all f-string buffers, in order to be able to restore them after reallocating tok->buf */ -static void -remember_fstring_buffers(struct tok_state *tok) -{ - int index; - tokenizer_mode *mode; +static void remember_fstring_buffers(struct tok_state *tok) { + int index; + tokenizer_mode *mode; - for (index = tok->tok_mode_stack_index; index >= 0; --index) { - mode = &(tok->tok_mode_stack[index]); - mode->f_string_start_offset = mode->f_string_start - tok->buf; - mode->f_string_multi_line_start_offset = mode->f_string_multi_line_start - tok->buf; - } + for (index = tok->tok_mode_stack_index; index >= 0; --index) { + mode = &(tok->tok_mode_stack[index]); + mode->f_string_start_offset = mode->f_string_start - tok->buf; + mode->f_string_multi_line_start_offset = + mode->f_string_multi_line_start - tok->buf; + } } /* Traverse and restore all f-string buffers after reallocating tok->buf */ -static void -restore_fstring_buffers(struct tok_state *tok) -{ - int index; - tokenizer_mode *mode; +static void restore_fstring_buffers(struct tok_state *tok) { + int index; + tokenizer_mode *mode; - for (index = tok->tok_mode_stack_index; index >= 0; --index) { - mode = &(tok->tok_mode_stack[index]); - mode->f_string_start = tok->buf + mode->f_string_start_offset; - mode->f_string_multi_line_start = tok->buf + mode->f_string_multi_line_start_offset; - } + for (index = tok->tok_mode_stack_index; index >= 0; --index) { + mode = &(tok->tok_mode_stack[index]); + mode->f_string_start = tok->buf + mode->f_string_start_offset; + mode->f_string_multi_line_start = + tok->buf + mode->f_string_multi_line_start_offset; + } } -static int -set_fstring_expr(struct tok_state* tok, struct token *token, char c) { - assert(token != NULL); - assert(c == '}' || c == ':' || c == '!'); - tokenizer_mode *tok_mode = TOK_GET_MODE(tok); +static int set_fstring_expr(struct tok_state *tok, struct token *token, + char c) { + assert(token != NULL); + assert(c == '}' || c == ':' || c == '!'); + tokenizer_mode *tok_mode = TOK_GET_MODE(tok); - if (!tok_mode->f_string_debug || token->metadata) { - return 0; - } + if (!tok_mode->f_string_debug || token->metadata) { + return 0; + } - PyObject *res = NULL; + PyObject *res = NULL; - // Check if there is a # character in the expression - int hash_detected = 0; - for (Py_ssize_t i = 0; i < tok_mode->last_expr_size - tok_mode->last_expr_end; i++) { - if (tok_mode->last_expr_buffer[i] == '#') { - hash_detected = 1; - break; - } + // Check if there is a # character in the expression + int hash_detected = 0; + for (Py_ssize_t i = 0; i < tok_mode->last_expr_size - tok_mode->last_expr_end; + i++) { + if (tok_mode->last_expr_buffer[i] == '#') { + hash_detected = 1; + break; } + } - if (hash_detected) { - Py_ssize_t input_length = tok_mode->last_expr_size - tok_mode->last_expr_end; - char *result = (char *)PyObject_Malloc((input_length + 1) * sizeof(char)); - if (!result) { - return -1; - } - - Py_ssize_t i = 0; - Py_ssize_t j = 0; - - for (i = 0, j = 0; i < input_length; i++) { - if (tok_mode->last_expr_buffer[i] == '#') { - // Skip characters until newline or end of string - while (tok_mode->last_expr_buffer[i] != '\0' && i < input_length) { - if (tok_mode->last_expr_buffer[i] == '\n') { - result[j++] = tok_mode->last_expr_buffer[i]; - break; - } - i++; - } - } else { - result[j++] = tok_mode->last_expr_buffer[i]; - } - } - - result[j] = '\0'; // Null-terminate the result string - res = PyUnicode_DecodeUTF8(result, j, NULL); - PyObject_Free(result); - } else { - res = PyUnicode_DecodeUTF8( - tok_mode->last_expr_buffer, - tok_mode->last_expr_size - tok_mode->last_expr_end, - NULL - ); - + if (hash_detected) { + Py_ssize_t input_length = + tok_mode->last_expr_size - tok_mode->last_expr_end; + char *result = (char *)PyObject_Malloc((input_length + 1) * sizeof(char)); + if (!result) { + return -1; } + Py_ssize_t i = 0; + Py_ssize_t j = 0; - if (!res) { - return -1; + for (i = 0, j = 0; i < input_length; i++) { + if (tok_mode->last_expr_buffer[i] == '#') { + // Skip characters until newline or end of string + while (tok_mode->last_expr_buffer[i] != '\0' && i < input_length) { + if (tok_mode->last_expr_buffer[i] == '\n') { + result[j++] = tok_mode->last_expr_buffer[i]; + break; + } + i++; + } + } else { + result[j++] = tok_mode->last_expr_buffer[i]; + } } - token->metadata = res; - return 0; -} -static int -update_fstring_expr(struct tok_state *tok, char cur) -{ - assert(tok->cur != NULL); + result[j] = '\0'; // Null-terminate the result string + res = PyUnicode_DecodeUTF8(result, j, NULL); + PyObject_Free(result); + } else { + res = PyUnicode_DecodeUTF8( + tok_mode->last_expr_buffer, + tok_mode->last_expr_size - tok_mode->last_expr_end, NULL); + } - Py_ssize_t size = strlen(tok->cur); - tokenizer_mode *tok_mode = TOK_GET_MODE(tok); - - switch (cur) { - case 0: - if (!tok_mode->last_expr_buffer || tok_mode->last_expr_end >= 0) { - return 1; - } - char *new_buffer = PyMem_Realloc( - tok_mode->last_expr_buffer, - tok_mode->last_expr_size + size - ); - if (new_buffer == NULL) { - PyMem_Free(tok_mode->last_expr_buffer); - goto error; - } - tok_mode->last_expr_buffer = new_buffer; - strncpy(tok_mode->last_expr_buffer + tok_mode->last_expr_size, tok->cur, size); - tok_mode->last_expr_size += size; - break; - case '{': - if (tok_mode->last_expr_buffer != NULL) { - PyMem_Free(tok_mode->last_expr_buffer); - } - tok_mode->last_expr_buffer = PyMem_Malloc(size); - if (tok_mode->last_expr_buffer == NULL) { - goto error; - } - tok_mode->last_expr_size = size; - tok_mode->last_expr_end = -1; - strncpy(tok_mode->last_expr_buffer, tok->cur, size); - break; - case '}': - case '!': - case ':': - if (tok_mode->last_expr_end == -1) { - tok_mode->last_expr_end = strlen(tok->start); - } - break; - default: - Py_UNREACHABLE(); - } - return 1; + if (!res) { + return -1; + } + token->metadata = res; + return 0; +} + +static int update_fstring_expr(struct tok_state *tok, char cur) { + assert(tok->cur != NULL); + + Py_ssize_t size = strlen(tok->cur); + tokenizer_mode *tok_mode = TOK_GET_MODE(tok); + + switch (cur) { + case 0: + if (!tok_mode->last_expr_buffer || tok_mode->last_expr_end >= 0) { + return 1; + } + char *new_buffer = PyMem_Realloc(tok_mode->last_expr_buffer, + tok_mode->last_expr_size + size); + if (new_buffer == NULL) { + PyMem_Free(tok_mode->last_expr_buffer); + goto error; + } + tok_mode->last_expr_buffer = new_buffer; + strncpy(tok_mode->last_expr_buffer + tok_mode->last_expr_size, tok->cur, + size); + tok_mode->last_expr_size += size; + break; + case '{': + if (tok_mode->last_expr_buffer != NULL) { + PyMem_Free(tok_mode->last_expr_buffer); + } + tok_mode->last_expr_buffer = PyMem_Malloc(size); + if (tok_mode->last_expr_buffer == NULL) { + goto error; + } + tok_mode->last_expr_size = size; + tok_mode->last_expr_end = -1; + strncpy(tok_mode->last_expr_buffer, tok->cur, size); + break; + case '}': + case '!': + case ':': + if (tok_mode->last_expr_end == -1) { + tok_mode->last_expr_end = strlen(tok->start); + } + break; + default: + Py_UNREACHABLE(); + } + return 1; error: - tok->done = E_NOMEM; - return 0; + tok->done = E_NOMEM; + return 0; } -static void -free_fstring_expressions(struct tok_state *tok) -{ - int index; - tokenizer_mode *mode; - - for (index = tok->tok_mode_stack_index; index >= 0; --index) { - mode = &(tok->tok_mode_stack[index]); - if (mode->last_expr_buffer != NULL) { - PyMem_Free(mode->last_expr_buffer); - mode->last_expr_buffer = NULL; - mode->last_expr_size = 0; - mode->last_expr_end = -1; - } +static void free_fstring_expressions(struct tok_state *tok) { + int index; + tokenizer_mode *mode; + + for (index = tok->tok_mode_stack_index; index >= 0; --index) { + mode = &(tok->tok_mode_stack[index]); + if (mode->last_expr_buffer != NULL) { + PyMem_Free(mode->last_expr_buffer); + mode->last_expr_buffer = NULL; + mode->last_expr_size = 0; + mode->last_expr_end = -1; + mode->in_format_spec = 0; } + } } /* Read a line of text from TOK into S, using the stream in TOK. @@ -539,88 +516,85 @@ free_fstring_expressions(struct tok_state *tok) 1) NULL: need to call tok->decoding_readline to get a new line 2) PyUnicodeObject *: decoding_feof has called tok->decoding_readline and stored the result in tok->decoding_buffer - 3) PyByteArrayObject *: previous call to tok_readline_recode did not have enough room - (in the s buffer) to copy entire contents of the line read - by tok->decoding_readline. tok->decoding_buffer has the overflow. - In this case, tok_readline_recode is called in a loop (with an expanded buffer) - until the buffer ends with a '\n' (or until the end of the file is - reached): see tok_nextc and its calls to tok_reserve_buf. + 3) PyByteArrayObject *: previous call to tok_readline_recode did not have + enough room (in the s buffer) to copy entire contents of the line read by + tok->decoding_readline. tok->decoding_buffer has the overflow. In this case, + tok_readline_recode is called in a loop (with an expanded buffer) until the + buffer ends with a '\n' (or until the end of the file is reached): see + tok_nextc and its calls to tok_reserve_buf. */ -static int -tok_reserve_buf(struct tok_state *tok, Py_ssize_t size) -{ - Py_ssize_t cur = tok->cur - tok->buf; - Py_ssize_t oldsize = tok->inp - tok->buf; - Py_ssize_t newsize = oldsize + Py_MAX(size, oldsize >> 1); - if (newsize > tok->end - tok->buf) { - char *newbuf = tok->buf; - Py_ssize_t start = tok->start == NULL ? -1 : tok->start - tok->buf; - Py_ssize_t line_start = tok->start == NULL ? -1 : tok->line_start - tok->buf; - Py_ssize_t multi_line_start = tok->multi_line_start - tok->buf; - remember_fstring_buffers(tok); - newbuf = (char *)PyMem_Realloc(newbuf, newsize); - if (newbuf == NULL) { - tok->done = E_NOMEM; - return 0; - } - tok->buf = newbuf; - tok->cur = tok->buf + cur; - tok->inp = tok->buf + oldsize; - tok->end = tok->buf + newsize; - tok->start = start < 0 ? NULL : tok->buf + start; - tok->line_start = line_start < 0 ? NULL : tok->buf + line_start; - tok->multi_line_start = multi_line_start < 0 ? NULL : tok->buf + multi_line_start; - restore_fstring_buffers(tok); - } - return 1; -} - -static inline int -contains_null_bytes(const char* str, size_t size) { - return memchr(str, 0, size) != NULL; -} - -static int -tok_readline_recode(struct tok_state *tok) { - PyObject *line; - const char *buf; - Py_ssize_t buflen; - line = tok->decoding_buffer; +static int tok_reserve_buf(struct tok_state *tok, Py_ssize_t size) { + Py_ssize_t cur = tok->cur - tok->buf; + Py_ssize_t oldsize = tok->inp - tok->buf; + Py_ssize_t newsize = oldsize + Py_MAX(size, oldsize >> 1); + if (newsize > tok->end - tok->buf) { + char *newbuf = tok->buf; + Py_ssize_t start = tok->start == NULL ? -1 : tok->start - tok->buf; + Py_ssize_t line_start = + tok->start == NULL ? -1 : tok->line_start - tok->buf; + Py_ssize_t multi_line_start = tok->multi_line_start - tok->buf; + remember_fstring_buffers(tok); + newbuf = (char *)PyMem_Realloc(newbuf, newsize); + if (newbuf == NULL) { + tok->done = E_NOMEM; + return 0; + } + tok->buf = newbuf; + tok->cur = tok->buf + cur; + tok->inp = tok->buf + oldsize; + tok->end = tok->buf + newsize; + tok->start = start < 0 ? NULL : tok->buf + start; + tok->line_start = line_start < 0 ? NULL : tok->buf + line_start; + tok->multi_line_start = + multi_line_start < 0 ? NULL : tok->buf + multi_line_start; + restore_fstring_buffers(tok); + } + return 1; +} + +static inline int contains_null_bytes(const char *str, size_t size) { + return memchr(str, 0, size) != NULL; +} + +static int tok_readline_recode(struct tok_state *tok) { + PyObject *line; + const char *buf; + Py_ssize_t buflen; + line = tok->decoding_buffer; + if (line == NULL) { + line = PyObject_CallNoArgs(tok->decoding_readline); if (line == NULL) { - line = PyObject_CallNoArgs(tok->decoding_readline); - if (line == NULL) { - error_ret(tok); - goto error; - } - } - else { - tok->decoding_buffer = NULL; - } - buf = PyUnicode_AsUTF8AndSize(line, &buflen); - if (buf == NULL) { - error_ret(tok); - goto error; - } - // Make room for the null terminator *and* potentially - // an extra newline character that we may need to artificially - // add. - size_t buffer_size = buflen + 2; - if (!tok_reserve_buf(tok, buffer_size)) { - goto error; + error_ret(tok); + goto error; } - memcpy(tok->inp, buf, buflen); - tok->inp += buflen; - *tok->inp = '\0'; - if (tok->fp_interactive && - tok_concatenate_interactive_new_line(tok, buf) == -1) { - goto error; - } - Py_DECREF(line); - return 1; + } else { + tok->decoding_buffer = NULL; + } + buf = PyUnicode_AsUTF8AndSize(line, &buflen); + if (buf == NULL) { + error_ret(tok); + goto error; + } + // Make room for the null terminator *and* potentially + // an extra newline character that we may need to artificially + // add. + size_t buffer_size = buflen + 2; + if (!tok_reserve_buf(tok, buffer_size)) { + goto error; + } + memcpy(tok->inp, buf, buflen); + tok->inp += buflen; + *tok->inp = '\0'; + if (tok->fp_interactive && + tok_concatenate_interactive_new_line(tok, buf) == -1) { + goto error; + } + Py_DECREF(line); + return 1; error: - Py_XDECREF(line); - return 0; + Py_XDECREF(line); + return 0; } /* Set the readline function for TOK to a StreamReader's @@ -633,2383 +607,2293 @@ tok_readline_recode(struct tok_state *tok) { Return 1 on success, 0 on failure. */ -static int -fp_setreadl(struct tok_state *tok, const char* enc) -{ - PyObject *readline, *open, *stream; - int fd; - long pos; - - fd = fileno(tok->fp); - /* Due to buffering the file offset for fd can be different from the file - * position of tok->fp. If tok->fp was opened in text mode on Windows, - * its file position counts CRLF as one char and can't be directly mapped - * to the file offset for fd. Instead we step back one byte and read to - * the end of line.*/ - pos = ftell(tok->fp); - if (pos == -1 || - lseek(fd, (off_t)(pos > 0 ? pos - 1 : pos), SEEK_SET) == (off_t)-1) { - PyErr_SetFromErrnoWithFilename(PyExc_OSError, NULL); - return 0; - } +static int fp_setreadl(struct tok_state *tok, const char *enc) { + PyObject *readline, *open, *stream; + int fd; + long pos; + + fd = fileno(tok->fp); + /* Due to buffering the file offset for fd can be different from the file + * position of tok->fp. If tok->fp was opened in text mode on Windows, + * its file position counts CRLF as one char and can't be directly mapped + * to the file offset for fd. Instead we step back one byte and read to + * the end of line.*/ + pos = ftell(tok->fp); + if (pos == -1 || + lseek(fd, (off_t)(pos > 0 ? pos - 1 : pos), SEEK_SET) == (off_t)-1) { + PyErr_SetFromErrnoWithFilename(PyExc_OSError, NULL); + return 0; + } - open = _PyImport_GetModuleAttrString("io", "open"); - if (open == NULL) { - return 0; - } - stream = PyObject_CallFunction(open, "isisOOO", - fd, "r", -1, enc, Py_None, Py_None, Py_False); - Py_DECREF(open); - if (stream == NULL) { - return 0; - } + open = _PyImport_GetModuleAttrString("io", "open"); + if (open == NULL) { + return 0; + } + stream = PyObject_CallFunction(open, "isisOOO", fd, "r", -1, enc, Py_None, + Py_None, Py_False); + Py_DECREF(open); + if (stream == NULL) { + return 0; + } - readline = PyObject_GetAttr(stream, &_Py_ID(readline)); - Py_DECREF(stream); - if (readline == NULL) { - return 0; - } - Py_XSETREF(tok->decoding_readline, readline); + readline = PyObject_GetAttr(stream, &_Py_ID(readline)); + Py_DECREF(stream); + if (readline == NULL) { + return 0; + } + Py_XSETREF(tok->decoding_readline, readline); - if (pos > 0) { - PyObject *bufobj = _PyObject_CallNoArgs(readline); - if (bufobj == NULL) { - return 0; - } - Py_DECREF(bufobj); + if (pos > 0) { + PyObject *bufobj = _PyObject_CallNoArgs(readline); + if (bufobj == NULL) { + return 0; } + Py_DECREF(bufobj); + } - return 1; + return 1; } /* Fetch the next byte from TOK. */ -static int fp_getc(struct tok_state *tok) { - return getc(tok->fp); -} +static int fp_getc(struct tok_state *tok) { return getc(tok->fp); } /* Unfetch the last byte back into TOK. */ -static void fp_ungetc(int c, struct tok_state *tok) { - ungetc(c, tok->fp); -} +static void fp_ungetc(int c, struct tok_state *tok) { ungetc(c, tok->fp); } /* Check whether the characters at s start a valid UTF-8 sequence. Return the number of characters forming the sequence if yes, 0 if not. The special cases match those in stringlib/codecs.h:utf8_decode. */ -static int -valid_utf8(const unsigned char* s) -{ - int expected = 0; - int length; - if (*s < 0x80) { - /* single-byte code */ - return 1; - } - else if (*s < 0xE0) { - /* \xC2\x80-\xDF\xBF -- 0080-07FF */ - if (*s < 0xC2) { - /* invalid sequence - \x80-\xBF -- continuation byte - \xC0-\xC1 -- fake 0000-007F */ - return 0; - } - expected = 1; - } - else if (*s < 0xF0) { - /* \xE0\xA0\x80-\xEF\xBF\xBF -- 0800-FFFF */ - if (*s == 0xE0 && *(s + 1) < 0xA0) { - /* invalid sequence - \xE0\x80\x80-\xE0\x9F\xBF -- fake 0000-0800 */ - return 0; - } - else if (*s == 0xED && *(s + 1) >= 0xA0) { - /* Decoding UTF-8 sequences in range \xED\xA0\x80-\xED\xBF\xBF - will result in surrogates in range D800-DFFF. Surrogates are - not valid UTF-8 so they are rejected. - See https://www.unicode.org/versions/Unicode5.2.0/ch03.pdf - (table 3-7) and http://www.rfc-editor.org/rfc/rfc3629.txt */ - return 0; - } - expected = 2; - } - else if (*s < 0xF5) { - /* \xF0\x90\x80\x80-\xF4\x8F\xBF\xBF -- 10000-10FFFF */ - if (*(s + 1) < 0x90 ? *s == 0xF0 : *s == 0xF4) { - /* invalid sequence -- one of: - \xF0\x80\x80\x80-\xF0\x8F\xBF\xBF -- fake 0000-FFFF - \xF4\x90\x80\x80- -- 110000- overflow */ - return 0; - } - expected = 3; - } - else { - /* invalid start byte */ - return 0; - } - length = expected + 1; - for (; expected; expected--) - if (s[expected] < 0x80 || s[expected] >= 0xC0) - return 0; - return length; -} - -static int -ensure_utf8(char *line, struct tok_state *tok) -{ - int badchar = 0; - unsigned char *c; - int length; - for (c = (unsigned char *)line; *c; c += length) { - if (!(length = valid_utf8(c))) { - badchar = *c; - break; - } - } - if (badchar) { - PyErr_Format(PyExc_SyntaxError, - "Non-UTF-8 code starting with '\\x%.2x' " - "in file %U on line %i, " - "but no encoding declared; " - "see https://peps.python.org/pep-0263/ for details", - badchar, tok->filename, tok->lineno); - return 0; - } +static int valid_utf8(const unsigned char *s) { + int expected = 0; + int length; + if (*s < 0x80) { + /* single-byte code */ return 1; + } else if (*s < 0xE0) { + /* \xC2\x80-\xDF\xBF -- 0080-07FF */ + if (*s < 0xC2) { + /* invalid sequence + \x80-\xBF -- continuation byte + \xC0-\xC1 -- fake 0000-007F */ + return 0; + } + expected = 1; + } else if (*s < 0xF0) { + /* \xE0\xA0\x80-\xEF\xBF\xBF -- 0800-FFFF */ + if (*s == 0xE0 && *(s + 1) < 0xA0) { + /* invalid sequence + \xE0\x80\x80-\xE0\x9F\xBF -- fake 0000-0800 */ + return 0; + } else if (*s == 0xED && *(s + 1) >= 0xA0) { + /* Decoding UTF-8 sequences in range \xED\xA0\x80-\xED\xBF\xBF + will result in surrogates in range D800-DFFF. Surrogates are + not valid UTF-8 so they are rejected. + See https://www.unicode.org/versions/Unicode5.2.0/ch03.pdf + (table 3-7) and http://www.rfc-editor.org/rfc/rfc3629.txt */ + return 0; + } + expected = 2; + } else if (*s < 0xF5) { + /* \xF0\x90\x80\x80-\xF4\x8F\xBF\xBF -- 10000-10FFFF */ + if (*(s + 1) < 0x90 ? *s == 0xF0 : *s == 0xF4) { + /* invalid sequence -- one of: + \xF0\x80\x80\x80-\xF0\x8F\xBF\xBF -- fake 0000-FFFF + \xF4\x90\x80\x80- -- 110000- overflow */ + return 0; + } + expected = 3; + } else { + /* invalid start byte */ + return 0; + } + length = expected + 1; + for (; expected; expected--) + if (s[expected] < 0x80 || s[expected] >= 0xC0) + return 0; + return length; +} + +static int ensure_utf8(char *line, struct tok_state *tok) { + int badchar = 0; + unsigned char *c; + int length; + for (c = (unsigned char *)line; *c; c += length) { + if (!(length = valid_utf8(c))) { + badchar = *c; + break; + } + } + if (badchar) { + PyErr_Format(PyExc_SyntaxError, + "Non-UTF-8 code starting with '\\x%.2x' " + "in file %U on line %i, " + "but no encoding declared; " + "see https://peps.python.org/pep-0263/ for details", + badchar, tok->filename, tok->lineno); + return 0; + } + return 1; } /* Fetch a byte from TOK, using the string buffer. */ -static int -buf_getc(struct tok_state *tok) { - return Py_CHARMASK(*tok->str++); -} +static int buf_getc(struct tok_state *tok) { return Py_CHARMASK(*tok->str++); } /* Unfetch a byte from TOK, using the string buffer. */ -static void -buf_ungetc(int c, struct tok_state *tok) { - tok->str--; - assert(Py_CHARMASK(*tok->str) == c); /* tok->cur may point to read-only segment */ +static void buf_ungetc(int c, struct tok_state *tok) { + tok->str--; + assert(Py_CHARMASK(*tok->str) == + c); /* tok->cur may point to read-only segment */ } /* Set the readline function for TOK to ENC. For the string-based tokenizer, this means to just record the encoding. */ -static int -buf_setreadl(struct tok_state *tok, const char* enc) { - tok->enc = enc; - return 1; +static int buf_setreadl(struct tok_state *tok, const char *enc) { + tok->enc = enc; + return 1; } /* Return a UTF-8 encoding Python string object from the C byte string STR, which is encoded with ENC. */ -static PyObject * -translate_into_utf8(const char* str, const char* enc) { - PyObject *utf8; - PyObject* buf = PyUnicode_Decode(str, strlen(str), enc, NULL); - if (buf == NULL) - return NULL; - utf8 = PyUnicode_AsUTF8String(buf); - Py_DECREF(buf); - return utf8; -} - - -static char * -translate_newlines(const char *s, int exec_input, int preserve_crlf, - struct tok_state *tok) { - int skip_next_lf = 0; - size_t needed_length = strlen(s) + 2, final_length; - char *buf, *current; - char c = '\0'; - buf = PyMem_Malloc(needed_length); - if (buf == NULL) { - tok->done = E_NOMEM; - return NULL; - } - for (current = buf; *s; s++, current++) { - c = *s; - if (skip_next_lf) { - skip_next_lf = 0; - if (c == '\n') { - c = *++s; - if (!c) - break; - } - } - if (!preserve_crlf && c == '\r') { - skip_next_lf = 1; - c = '\n'; - } - *current = c; - } - /* If this is exec input, add a newline to the end of the string if - there isn't one already. */ - if (exec_input && c != '\n' && c != '\0') { - *current = '\n'; - current++; - } - *current = '\0'; - final_length = current - buf + 1; - if (final_length < needed_length && final_length) { - /* should never fail */ - char* result = PyMem_Realloc(buf, final_length); - if (result == NULL) { - PyMem_Free(buf); - } - buf = result; - } - return buf; +static PyObject *translate_into_utf8(const char *str, const char *enc) { + PyObject *utf8; + PyObject *buf = PyUnicode_Decode(str, strlen(str), enc, NULL); + if (buf == NULL) + return NULL; + utf8 = PyUnicode_AsUTF8String(buf); + Py_DECREF(buf); + return utf8; +} + +static char *translate_newlines(const char *s, int exec_input, + int preserve_crlf, struct tok_state *tok) { + int skip_next_lf = 0; + size_t needed_length = strlen(s) + 2, final_length; + char *buf, *current; + char c = '\0'; + buf = PyMem_Malloc(needed_length); + if (buf == NULL) { + tok->done = E_NOMEM; + return NULL; + } + for (current = buf; *s; s++, current++) { + c = *s; + if (skip_next_lf) { + skip_next_lf = 0; + if (c == '\n') { + c = *++s; + if (!c) + break; + } + } + if (!preserve_crlf && c == '\r') { + skip_next_lf = 1; + c = '\n'; + } + *current = c; + } + /* If this is exec input, add a newline to the end of the string if + there isn't one already. */ + if (exec_input && c != '\n' && c != '\0') { + *current = '\n'; + current++; + } + *current = '\0'; + final_length = current - buf + 1; + if (final_length < needed_length && final_length) { + /* should never fail */ + char *result = PyMem_Realloc(buf, final_length); + if (result == NULL) { + PyMem_Free(buf); + } + buf = result; + } + return buf; } /* Decode a byte string STR for use as the buffer of TOK. Look for encoding declarations inside STR, and record them inside TOK. */ -static char * -decode_str(const char *input, int single, struct tok_state *tok, int preserve_crlf) -{ - PyObject* utf8 = NULL; - char *str; - const char *s; - const char *newl[2] = {NULL, NULL}; - int lineno = 0; - tok->input = str = translate_newlines(input, single, preserve_crlf, tok); - if (str == NULL) - return NULL; - tok->enc = NULL; - tok->str = str; - if (!check_bom(buf_getc, buf_ungetc, buf_setreadl, tok)) - return error_ret(tok); - str = tok->str; /* string after BOM if any */ - assert(str); - if (tok->enc != NULL) { - utf8 = translate_into_utf8(str, tok->enc); - if (utf8 == NULL) - return error_ret(tok); - str = PyBytes_AsString(utf8); - } - for (s = str;; s++) { - if (*s == '\0') break; - else if (*s == '\n') { - assert(lineno < 2); - newl[lineno] = s; - lineno++; - if (lineno == 2) break; - } +static char *decode_str(const char *input, int single, struct tok_state *tok, + int preserve_crlf) { + PyObject *utf8 = NULL; + char *str; + const char *s; + const char *newl[2] = {NULL, NULL}; + int lineno = 0; + tok->input = str = translate_newlines(input, single, preserve_crlf, tok); + if (str == NULL) + return NULL; + tok->enc = NULL; + tok->str = str; + if (!check_bom(buf_getc, buf_ungetc, buf_setreadl, tok)) + return error_ret(tok); + str = tok->str; /* string after BOM if any */ + assert(str); + if (tok->enc != NULL) { + utf8 = translate_into_utf8(str, tok->enc); + if (utf8 == NULL) + return error_ret(tok); + str = PyBytes_AsString(utf8); + } + for (s = str;; s++) { + if (*s == '\0') + break; + else if (*s == '\n') { + assert(lineno < 2); + newl[lineno] = s; + lineno++; + if (lineno == 2) + break; } - tok->enc = NULL; - /* need to check line 1 and 2 separately since check_coding_spec - assumes a single line as input */ - if (newl[0]) { - if (!check_coding_spec(str, newl[0] - str, tok, buf_setreadl)) { - return NULL; - } - if (tok->enc == NULL && tok->decoding_state != STATE_NORMAL && newl[1]) { - if (!check_coding_spec(newl[0]+1, newl[1] - newl[0], - tok, buf_setreadl)) - return NULL; - } + } + tok->enc = NULL; + /* need to check line 1 and 2 separately since check_coding_spec + assumes a single line as input */ + if (newl[0]) { + if (!check_coding_spec(str, newl[0] - str, tok, buf_setreadl)) { + return NULL; } - if (tok->enc != NULL) { - assert(utf8 == NULL); - utf8 = translate_into_utf8(str, tok->enc); - if (utf8 == NULL) - return error_ret(tok); - str = PyBytes_AS_STRING(utf8); + if (tok->enc == NULL && tok->decoding_state != STATE_NORMAL && newl[1]) { + if (!check_coding_spec(newl[0] + 1, newl[1] - newl[0], tok, buf_setreadl)) + return NULL; } - assert(tok->decoding_buffer == NULL); - tok->decoding_buffer = utf8; /* CAUTION */ - return str; + } + if (tok->enc != NULL) { + assert(utf8 == NULL); + utf8 = translate_into_utf8(str, tok->enc); + if (utf8 == NULL) + return error_ret(tok); + str = PyBytes_AS_STRING(utf8); + } + assert(tok->decoding_buffer == NULL); + tok->decoding_buffer = utf8; /* CAUTION */ + return str; } /* Set up tokenizer for string */ -struct tok_state * -_PyTokenizer_FromString(const char *str, int exec_input, int preserve_crlf) -{ - struct tok_state *tok = tok_new(); - char *decoded; +struct tok_state *_PyTokenizer_FromString(const char *str, int exec_input, + int preserve_crlf) { + struct tok_state *tok = tok_new(); + char *decoded; - if (tok == NULL) - return NULL; - decoded = decode_str(str, exec_input, tok, preserve_crlf); - if (decoded == NULL) { - _PyTokenizer_Free(tok); - return NULL; - } + if (tok == NULL) + return NULL; + decoded = decode_str(str, exec_input, tok, preserve_crlf); + if (decoded == NULL) { + _PyTokenizer_Free(tok); + return NULL; + } - tok->buf = tok->cur = tok->inp = decoded; - tok->end = decoded; - return tok; + tok->buf = tok->cur = tok->inp = decoded; + tok->end = decoded; + return tok; } -struct tok_state * -_PyTokenizer_FromReadline(PyObject* readline, const char* enc, - int exec_input, int preserve_crlf) -{ - struct tok_state *tok = tok_new(); - if (tok == NULL) - return NULL; - if ((tok->buf = (char *)PyMem_Malloc(BUFSIZ)) == NULL) { - _PyTokenizer_Free(tok); - return NULL; - } - tok->cur = tok->inp = tok->buf; - tok->end = tok->buf + BUFSIZ; - tok->fp = NULL; - if (enc != NULL) { - tok->encoding = new_string(enc, strlen(enc), tok); - if (!tok->encoding) { - _PyTokenizer_Free(tok); - return NULL; - } +struct tok_state *_PyTokenizer_FromReadline(PyObject *readline, const char *enc, + int exec_input, int preserve_crlf) { + struct tok_state *tok = tok_new(); + if (tok == NULL) + return NULL; + if ((tok->buf = (char *)PyMem_Malloc(BUFSIZ)) == NULL) { + _PyTokenizer_Free(tok); + return NULL; + } + tok->cur = tok->inp = tok->buf; + tok->end = tok->buf + BUFSIZ; + tok->fp = NULL; + if (enc != NULL) { + tok->encoding = new_string(enc, strlen(enc), tok); + if (!tok->encoding) { + _PyTokenizer_Free(tok); + return NULL; } - tok->decoding_state = STATE_NORMAL; - Py_INCREF(readline); - tok->readline = readline; - return tok; + } + tok->decoding_state = STATE_NORMAL; + Py_INCREF(readline); + tok->readline = readline; + return tok; } /* Set up tokenizer for UTF-8 string */ -struct tok_state * -_PyTokenizer_FromUTF8(const char *str, int exec_input, int preserve_crlf) -{ - struct tok_state *tok = tok_new(); - char *translated; - if (tok == NULL) - return NULL; - tok->input = translated = translate_newlines(str, exec_input, preserve_crlf, tok); - if (translated == NULL) { - _PyTokenizer_Free(tok); - return NULL; - } - tok->decoding_state = STATE_NORMAL; - tok->enc = NULL; - tok->str = translated; - tok->encoding = new_string("utf-8", 5, tok); - if (!tok->encoding) { - _PyTokenizer_Free(tok); - return NULL; - } +struct tok_state *_PyTokenizer_FromUTF8(const char *str, int exec_input, + int preserve_crlf) { + struct tok_state *tok = tok_new(); + char *translated; + if (tok == NULL) + return NULL; + tok->input = translated = + translate_newlines(str, exec_input, preserve_crlf, tok); + if (translated == NULL) { + _PyTokenizer_Free(tok); + return NULL; + } + tok->decoding_state = STATE_NORMAL; + tok->enc = NULL; + tok->str = translated; + tok->encoding = new_string("utf-8", 5, tok); + if (!tok->encoding) { + _PyTokenizer_Free(tok); + return NULL; + } - tok->buf = tok->cur = tok->inp = translated; - tok->end = translated; - return tok; + tok->buf = tok->cur = tok->inp = translated; + tok->end = translated; + return tok; } /* Set up tokenizer for file */ -struct tok_state * -_PyTokenizer_FromFile(FILE *fp, const char* enc, - const char *ps1, const char *ps2) -{ - struct tok_state *tok = tok_new(); - if (tok == NULL) - return NULL; - if ((tok->buf = (char *)PyMem_Malloc(BUFSIZ)) == NULL) { - _PyTokenizer_Free(tok); - return NULL; - } - tok->cur = tok->inp = tok->buf; - tok->end = tok->buf + BUFSIZ; - tok->fp = fp; - tok->prompt = ps1; - tok->nextprompt = ps2; - if (enc != NULL) { - /* Must copy encoding declaration since it - gets copied into the parse tree. */ - tok->encoding = new_string(enc, strlen(enc), tok); - if (!tok->encoding) { - _PyTokenizer_Free(tok); - return NULL; - } - tok->decoding_state = STATE_NORMAL; +struct tok_state *_PyTokenizer_FromFile(FILE *fp, const char *enc, + const char *ps1, const char *ps2) { + struct tok_state *tok = tok_new(); + if (tok == NULL) + return NULL; + if ((tok->buf = (char *)PyMem_Malloc(BUFSIZ)) == NULL) { + _PyTokenizer_Free(tok); + return NULL; + } + tok->cur = tok->inp = tok->buf; + tok->end = tok->buf + BUFSIZ; + tok->fp = fp; + tok->prompt = ps1; + tok->nextprompt = ps2; + if (enc != NULL) { + /* Must copy encoding declaration since it + gets copied into the parse tree. */ + tok->encoding = new_string(enc, strlen(enc), tok); + if (!tok->encoding) { + _PyTokenizer_Free(tok); + return NULL; } - return tok; + tok->decoding_state = STATE_NORMAL; + } + return tok; } /* Free a tok_state structure */ -void -_PyTokenizer_Free(struct tok_state *tok) -{ - if (tok->encoding != NULL) { - PyMem_Free(tok->encoding); - } - Py_XDECREF(tok->decoding_readline); - Py_XDECREF(tok->decoding_buffer); - Py_XDECREF(tok->readline); - Py_XDECREF(tok->filename); - if ((tok->readline != NULL || tok->fp != NULL ) && tok->buf != NULL) { - PyMem_Free(tok->buf); +void _PyTokenizer_Free(struct tok_state *tok) { + if (tok->encoding != NULL) { + PyMem_Free(tok->encoding); + } + Py_XDECREF(tok->decoding_readline); + Py_XDECREF(tok->decoding_buffer); + Py_XDECREF(tok->readline); + Py_XDECREF(tok->filename); + if ((tok->readline != NULL || tok->fp != NULL) && tok->buf != NULL) { + PyMem_Free(tok->buf); + } + if (tok->input) { + PyMem_Free(tok->input); + } + if (tok->interactive_src_start != NULL) { + PyMem_Free(tok->interactive_src_start); + } + free_fstring_expressions(tok); + PyMem_Free(tok); +} + +void _PyToken_Free(struct token *token) { Py_XDECREF(token->metadata); } + +void _PyToken_Init(struct token *token) { token->metadata = NULL; } + +static int tok_readline_raw(struct tok_state *tok) { + do { + if (!tok_reserve_buf(tok, BUFSIZ)) { + return 0; + } + int n_chars = (int)(tok->end - tok->inp); + size_t line_size = 0; + char *line = _Py_UniversalNewlineFgetsWithSize(tok->inp, n_chars, tok->fp, + NULL, &line_size); + if (line == NULL) { + return 1; } - if (tok->input) { - PyMem_Free(tok->input); + if (tok->fp_interactive && + tok_concatenate_interactive_new_line(tok, line) == -1) { + return 0; + } + tok->inp += line_size; + if (tok->inp == tok->buf) { + return 0; + } + } while (tok->inp[-1] != '\n'); + return 1; +} + +static int tok_readline_string(struct tok_state *tok) { + PyObject *line = NULL; + PyObject *raw_line = PyObject_CallNoArgs(tok->readline); + if (raw_line == NULL) { + if (PyErr_ExceptionMatches(PyExc_StopIteration)) { + PyErr_Clear(); + return 1; + } + error_ret(tok); + goto error; + } + if (tok->encoding != NULL) { + if (!PyBytes_Check(raw_line)) { + PyErr_Format(PyExc_TypeError, "readline() returned a non-bytes object"); + error_ret(tok); + goto error; + } + line = + PyUnicode_Decode(PyBytes_AS_STRING(raw_line), + PyBytes_GET_SIZE(raw_line), tok->encoding, "replace"); + Py_CLEAR(raw_line); + if (line == NULL) { + error_ret(tok); + goto error; + } + } else { + if (!PyUnicode_Check(raw_line)) { + PyErr_Format(PyExc_TypeError, "readline() returned a non-string object"); + error_ret(tok); + goto error; + } + line = raw_line; + raw_line = NULL; + } + Py_ssize_t buflen; + const char *buf = PyUnicode_AsUTF8AndSize(line, &buflen); + if (buf == NULL) { + error_ret(tok); + goto error; + } + + // Make room for the null terminator *and* potentially + // an extra newline character that we may need to artificially + // add. + size_t buffer_size = buflen + 2; + if (!tok_reserve_buf(tok, buffer_size)) { + goto error; + } + memcpy(tok->inp, buf, buflen); + tok->inp += buflen; + *tok->inp = '\0'; + + tok->line_start = tok->cur; + Py_DECREF(line); + return 1; +error: + Py_XDECREF(raw_line); + Py_XDECREF(line); + return 0; +} + +static int tok_underflow_string(struct tok_state *tok) { + char *end = strchr(tok->inp, '\n'); + if (end != NULL) { + end++; + } else { + end = strchr(tok->inp, '\0'); + if (end == tok->inp) { + tok->done = E_EOF; + return 0; + } + } + if (tok->start == NULL) { + tok->buf = tok->cur; + } + tok->line_start = tok->cur; + ADVANCE_LINENO(); + tok->inp = end; + return 1; +} + +static int tok_underflow_interactive(struct tok_state *tok) { + if (tok->interactive_underflow == IUNDERFLOW_STOP) { + tok->done = E_INTERACT_STOP; + return 1; + } + char *newtok = PyOS_Readline(tok->fp ? tok->fp : stdin, stdout, tok->prompt); + if (newtok != NULL) { + char *translated = translate_newlines(newtok, 0, 0, tok); + PyMem_Free(newtok); + if (translated == NULL) { + return 0; } - if (tok->interactive_src_start != NULL) { - PyMem_Free(tok->interactive_src_start); + newtok = translated; + } + if (tok->encoding && newtok && *newtok) { + /* Recode to UTF-8 */ + Py_ssize_t buflen; + const char *buf; + PyObject *u = translate_into_utf8(newtok, tok->encoding); + PyMem_Free(newtok); + if (u == NULL) { + tok->done = E_DECODE; + return 0; + } + buflen = PyBytes_GET_SIZE(u); + buf = PyBytes_AS_STRING(u); + newtok = PyMem_Malloc(buflen + 1); + if (newtok == NULL) { + Py_DECREF(u); + tok->done = E_NOMEM; + return 0; + } + strcpy(newtok, buf); + Py_DECREF(u); + } + if (tok->fp_interactive && + tok_concatenate_interactive_new_line(tok, newtok) == -1) { + PyMem_Free(newtok); + return 0; + } + if (tok->nextprompt != NULL) { + tok->prompt = tok->nextprompt; + } + if (newtok == NULL) { + tok->done = E_INTR; + } else if (*newtok == '\0') { + PyMem_Free(newtok); + tok->done = E_EOF; + } else if (tok->start != NULL) { + Py_ssize_t cur_multi_line_start = tok->multi_line_start - tok->buf; + remember_fstring_buffers(tok); + size_t size = strlen(newtok); + ADVANCE_LINENO(); + if (!tok_reserve_buf(tok, size + 1)) { + PyMem_Free(tok->buf); + tok->buf = NULL; + PyMem_Free(newtok); + return 0; + } + memcpy(tok->cur, newtok, size + 1); + PyMem_Free(newtok); + tok->inp += size; + tok->multi_line_start = tok->buf + cur_multi_line_start; + restore_fstring_buffers(tok); + } else { + remember_fstring_buffers(tok); + ADVANCE_LINENO(); + PyMem_Free(tok->buf); + tok->buf = newtok; + tok->cur = tok->buf; + tok->line_start = tok->buf; + tok->inp = strchr(tok->buf, '\0'); + tok->end = tok->inp + 1; + restore_fstring_buffers(tok); + } + if (tok->done != E_OK) { + if (tok->prompt != NULL) { + PySys_WriteStderr("\n"); } - free_fstring_expressions(tok); - PyMem_Free(tok); -} + return 0; + } -void -_PyToken_Free(struct token *token) { - Py_XDECREF(token->metadata); -} - -void -_PyToken_Init(struct token *token) { - token->metadata = NULL; -} - -static int -tok_readline_raw(struct tok_state *tok) -{ - do { - if (!tok_reserve_buf(tok, BUFSIZ)) { - return 0; - } - int n_chars = (int)(tok->end - tok->inp); - size_t line_size = 0; - char *line = _Py_UniversalNewlineFgetsWithSize(tok->inp, n_chars, tok->fp, NULL, &line_size); - if (line == NULL) { - return 1; - } - if (tok->fp_interactive && - tok_concatenate_interactive_new_line(tok, line) == -1) { - return 0; - } - tok->inp += line_size; - if (tok->inp == tok->buf) { - return 0; - } - } while (tok->inp[-1] != '\n'); - return 1; + if (tok->tok_mode_stack_index && !update_fstring_expr(tok, 0)) { + return 0; + } + return 1; } -static int -tok_readline_string(struct tok_state* tok) { - PyObject* line = NULL; - PyObject* raw_line = PyObject_CallNoArgs(tok->readline); - if (raw_line == NULL) { - if (PyErr_ExceptionMatches(PyExc_StopIteration)) { - PyErr_Clear(); - return 1; - } - error_ret(tok); - goto error; - } - if(tok->encoding != NULL) { - if (!PyBytes_Check(raw_line)) { - PyErr_Format(PyExc_TypeError, "readline() returned a non-bytes object"); - error_ret(tok); - goto error; - } - line = PyUnicode_Decode(PyBytes_AS_STRING(raw_line), PyBytes_GET_SIZE(raw_line), - tok->encoding, "replace"); - Py_CLEAR(raw_line); - if (line == NULL) { - error_ret(tok); - goto error; - } - } else { - if(!PyUnicode_Check(raw_line)) { - PyErr_Format(PyExc_TypeError, "readline() returned a non-string object"); - error_ret(tok); - goto error; - } - line = raw_line; - raw_line = NULL; - } - Py_ssize_t buflen; - const char* buf = PyUnicode_AsUTF8AndSize(line, &buflen); - if (buf == NULL) { - error_ret(tok); - goto error; - } - - // Make room for the null terminator *and* potentially - // an extra newline character that we may need to artificially - // add. - size_t buffer_size = buflen + 2; - if (!tok_reserve_buf(tok, buffer_size)) { - goto error; - } - memcpy(tok->inp, buf, buflen); - tok->inp += buflen; +static int tok_underflow_file(struct tok_state *tok) { + if (tok->start == NULL && !INSIDE_FSTRING(tok)) { + tok->cur = tok->inp = tok->buf; + } + if (tok->decoding_state == STATE_INIT) { + /* We have not yet determined the encoding. + If an encoding is found, use the file-pointer + reader functions from now on. */ + if (!check_bom(fp_getc, fp_ungetc, fp_setreadl, tok)) { + error_ret(tok); + return 0; + } + assert(tok->decoding_state != STATE_INIT); + } + /* Read until '\n' or EOF */ + if (tok->decoding_readline != NULL) { + /* We already have a codec associated with this input. */ + if (!tok_readline_recode(tok)) { + return 0; + } + } else { + /* We want a 'raw' read. */ + if (!tok_readline_raw(tok)) { + return 0; + } + } + if (tok->inp == tok->cur) { + tok->done = E_EOF; + return 0; + } + tok->implicit_newline = 0; + if (tok->inp[-1] != '\n') { + assert(tok->inp + 1 < tok->end); + /* Last line does not end in \n, fake one */ + *tok->inp++ = '\n'; *tok->inp = '\0'; + tok->implicit_newline = 1; + } - tok->line_start = tok->cur; - Py_DECREF(line); - return 1; -error: - Py_XDECREF(raw_line); - Py_XDECREF(line); + if (tok->tok_mode_stack_index && !update_fstring_expr(tok, 0)) { return 0; + } + + ADVANCE_LINENO(); + if (tok->decoding_state != STATE_NORMAL) { + if (tok->lineno > 2) { + tok->decoding_state = STATE_NORMAL; + } else if (!check_coding_spec(tok->cur, strlen(tok->cur), tok, + fp_setreadl)) { + return 0; + } + } + /* The default encoding is UTF-8, so make sure we don't have any + non-UTF-8 sequences in it. */ + if (!tok->encoding && !ensure_utf8(tok->cur, tok)) { + error_ret(tok); + return 0; + } + assert(tok->done == E_OK); + return tok->done == E_OK; } -static int -tok_underflow_string(struct tok_state *tok) { - char *end = strchr(tok->inp, '\n'); - if (end != NULL) { - end++; - } - else { - end = strchr(tok->inp, '\0'); - if (end == tok->inp) { - tok->done = E_EOF; - return 0; - } - } - if (tok->start == NULL) { - tok->buf = tok->cur; - } - tok->line_start = tok->cur; - ADVANCE_LINENO(); - tok->inp = end; - return 1; -} - -static int -tok_underflow_interactive(struct tok_state *tok) { - if (tok->interactive_underflow == IUNDERFLOW_STOP) { - tok->done = E_INTERACT_STOP; - return 1; - } - char *newtok = PyOS_Readline(tok->fp ? tok->fp : stdin, stdout, tok->prompt); - if (newtok != NULL) { - char *translated = translate_newlines(newtok, 0, 0, tok); - PyMem_Free(newtok); - if (translated == NULL) { - return 0; - } - newtok = translated; - } - if (tok->encoding && newtok && *newtok) { - /* Recode to UTF-8 */ - Py_ssize_t buflen; - const char* buf; - PyObject *u = translate_into_utf8(newtok, tok->encoding); - PyMem_Free(newtok); - if (u == NULL) { - tok->done = E_DECODE; - return 0; - } - buflen = PyBytes_GET_SIZE(u); - buf = PyBytes_AS_STRING(u); - newtok = PyMem_Malloc(buflen+1); - if (newtok == NULL) { - Py_DECREF(u); - tok->done = E_NOMEM; - return 0; - } - strcpy(newtok, buf); - Py_DECREF(u); - } - if (tok->fp_interactive && - tok_concatenate_interactive_new_line(tok, newtok) == -1) { - PyMem_Free(newtok); - return 0; - } - if (tok->nextprompt != NULL) { - tok->prompt = tok->nextprompt; - } - if (newtok == NULL) { - tok->done = E_INTR; - } - else if (*newtok == '\0') { - PyMem_Free(newtok); - tok->done = E_EOF; - } - else if (tok->start != NULL) { - Py_ssize_t cur_multi_line_start = tok->multi_line_start - tok->buf; - remember_fstring_buffers(tok); - size_t size = strlen(newtok); - ADVANCE_LINENO(); - if (!tok_reserve_buf(tok, size + 1)) { - PyMem_Free(tok->buf); - tok->buf = NULL; - PyMem_Free(newtok); - return 0; - } - memcpy(tok->cur, newtok, size + 1); - PyMem_Free(newtok); - tok->inp += size; - tok->multi_line_start = tok->buf + cur_multi_line_start; - restore_fstring_buffers(tok); - } - else { - remember_fstring_buffers(tok); - ADVANCE_LINENO(); - PyMem_Free(tok->buf); - tok->buf = newtok; - tok->cur = tok->buf; - tok->line_start = tok->buf; - tok->inp = strchr(tok->buf, '\0'); - tok->end = tok->inp + 1; - restore_fstring_buffers(tok); - } - if (tok->done != E_OK) { - if (tok->prompt != NULL) { - PySys_WriteStderr("\n"); - } - return 0; - } - - if (tok->tok_mode_stack_index && !update_fstring_expr(tok, 0)) { - return 0; - } - return 1; -} - -static int -tok_underflow_file(struct tok_state *tok) { - if (tok->start == NULL && !INSIDE_FSTRING(tok)) { - tok->cur = tok->inp = tok->buf; - } - if (tok->decoding_state == STATE_INIT) { - /* We have not yet determined the encoding. - If an encoding is found, use the file-pointer - reader functions from now on. */ - if (!check_bom(fp_getc, fp_ungetc, fp_setreadl, tok)) { - error_ret(tok); - return 0; - } - assert(tok->decoding_state != STATE_INIT); - } - /* Read until '\n' or EOF */ - if (tok->decoding_readline != NULL) { - /* We already have a codec associated with this input. */ - if (!tok_readline_recode(tok)) { - return 0; - } - } - else { - /* We want a 'raw' read. */ - if (!tok_readline_raw(tok)) { - return 0; - } - } - if (tok->inp == tok->cur) { - tok->done = E_EOF; - return 0; - } - tok->implicit_newline = 0; - if (tok->inp[-1] != '\n') { - assert(tok->inp + 1 < tok->end); - /* Last line does not end in \n, fake one */ - *tok->inp++ = '\n'; - *tok->inp = '\0'; - tok->implicit_newline = 1; - } - - if (tok->tok_mode_stack_index && !update_fstring_expr(tok, 0)) { - return 0; - } - - ADVANCE_LINENO(); - if (tok->decoding_state != STATE_NORMAL) { - if (tok->lineno > 2) { - tok->decoding_state = STATE_NORMAL; - } - else if (!check_coding_spec(tok->cur, strlen(tok->cur), - tok, fp_setreadl)) - { - return 0; - } - } - /* The default encoding is UTF-8, so make sure we don't have any - non-UTF-8 sequences in it. */ - if (!tok->encoding && !ensure_utf8(tok->cur, tok)) { - error_ret(tok); - return 0; - } - assert(tok->done == E_OK); - return tok->done == E_OK; -} - -static int -tok_underflow_readline(struct tok_state* tok) { - assert(tok->decoding_state == STATE_NORMAL); - assert(tok->fp == NULL && tok->input == NULL && tok->decoding_readline == NULL); - if (tok->start == NULL && !INSIDE_FSTRING(tok)) { - tok->cur = tok->inp = tok->buf; - } - if (!tok_readline_string(tok)) { - return 0; - } - if (tok->inp == tok->cur) { - tok->done = E_EOF; - return 0; - } - tok->implicit_newline = 0; - if (tok->inp[-1] != '\n') { - assert(tok->inp + 1 < tok->end); - /* Last line does not end in \n, fake one */ - *tok->inp++ = '\n'; - *tok->inp = '\0'; - tok->implicit_newline = 1; - } +static int tok_underflow_readline(struct tok_state *tok) { + assert(tok->decoding_state == STATE_NORMAL); + assert(tok->fp == NULL && tok->input == NULL && + tok->decoding_readline == NULL); + if (tok->start == NULL && !INSIDE_FSTRING(tok)) { + tok->cur = tok->inp = tok->buf; + } + if (!tok_readline_string(tok)) { + return 0; + } + if (tok->inp == tok->cur) { + tok->done = E_EOF; + return 0; + } + tok->implicit_newline = 0; + if (tok->inp[-1] != '\n') { + assert(tok->inp + 1 < tok->end); + /* Last line does not end in \n, fake one */ + *tok->inp++ = '\n'; + *tok->inp = '\0'; + tok->implicit_newline = 1; + } - if (tok->tok_mode_stack_index && !update_fstring_expr(tok, 0)) { - return 0; - } + if (tok->tok_mode_stack_index && !update_fstring_expr(tok, 0)) { + return 0; + } - ADVANCE_LINENO(); - /* The default encoding is UTF-8, so make sure we don't have any - non-UTF-8 sequences in it. */ - if (!tok->encoding && !ensure_utf8(tok->cur, tok)) { - error_ret(tok); - return 0; - } - assert(tok->done == E_OK); - return tok->done == E_OK; + ADVANCE_LINENO(); + /* The default encoding is UTF-8, so make sure we don't have any + non-UTF-8 sequences in it. */ + if (!tok->encoding && !ensure_utf8(tok->cur, tok)) { + error_ret(tok); + return 0; + } + assert(tok->done == E_OK); + return tok->done == E_OK; } #if defined(Py_DEBUG) -static void -print_escape(FILE *f, const char *s, Py_ssize_t size) -{ - if (s == NULL) { - fputs("NULL", f); - return; - } - putc('"', f); - while (size-- > 0) { - unsigned char c = *s++; - switch (c) { - case '\n': fputs("\\n", f); break; - case '\r': fputs("\\r", f); break; - case '\t': fputs("\\t", f); break; - case '\f': fputs("\\f", f); break; - case '\'': fputs("\\'", f); break; - case '"': fputs("\\\"", f); break; - default: - if (0x20 <= c && c <= 0x7f) - putc(c, f); - else - fprintf(f, "\\x%02x", c); - } +static void print_escape(FILE *f, const char *s, Py_ssize_t size) { + if (s == NULL) { + fputs("NULL", f); + return; + } + putc('"', f); + while (size-- > 0) { + unsigned char c = *s++; + switch (c) { + case '\n': + fputs("\\n", f); + break; + case '\r': + fputs("\\r", f); + break; + case '\t': + fputs("\\t", f); + break; + case '\f': + fputs("\\f", f); + break; + case '\'': + fputs("\\'", f); + break; + case '"': + fputs("\\\"", f); + break; + default: + if (0x20 <= c && c <= 0x7f) + putc(c, f); + else + fprintf(f, "\\x%02x", c); } - putc('"', f); + } + putc('"', f); } #endif /* Get next char, updating state; error code goes into tok->done */ -static int -tok_nextc(struct tok_state *tok) -{ - int rc; - for (;;) { - if (tok->cur != tok->inp) { - if ((unsigned int) tok->col_offset >= (unsigned int) INT_MAX) { - tok->done = E_COLUMNOVERFLOW; - return EOF; - } - tok->col_offset++; - return Py_CHARMASK(*tok->cur++); /* Fast path */ - } - if (tok->done != E_OK) { - return EOF; - } - if (tok->readline) { - rc = tok_underflow_readline(tok); - } - else if (tok->fp == NULL) { - rc = tok_underflow_string(tok); - } - else if (tok->prompt != NULL) { - rc = tok_underflow_interactive(tok); - } - else { - rc = tok_underflow_file(tok); - } -#if defined(Py_DEBUG) - if (tok->debug) { - fprintf(stderr, "line[%d] = ", tok->lineno); - print_escape(stderr, tok->cur, tok->inp - tok->cur); - fprintf(stderr, " tok->done = %d\n", tok->done); - } -#endif - if (!rc) { - tok->cur = tok->inp; - return EOF; - } - tok->line_start = tok->cur; - - if (contains_null_bytes(tok->line_start, tok->inp - tok->line_start)) { - syntaxerror(tok, "source code cannot contain null bytes"); - tok->cur = tok->inp; - return EOF; - } +static int tok_nextc(struct tok_state *tok) { + int rc; + for (;;) { + if (tok->cur != tok->inp) { + if ((unsigned int)tok->col_offset >= (unsigned int)INT_MAX) { + tok->done = E_COLUMNOVERFLOW; + return EOF; + } + tok->col_offset++; + return Py_CHARMASK(*tok->cur++); /* Fast path */ } - Py_UNREACHABLE(); -} - -/* Back-up one character */ - -static void -tok_backup(struct tok_state *tok, int c) -{ - if (c != EOF) { - if (--tok->cur < tok->buf) { - Py_FatalError("tokenizer beginning of buffer"); - } - if ((int)(unsigned char)*tok->cur != Py_CHARMASK(c)) { - Py_FatalError("tok_backup: wrong character"); - } - tok->col_offset--; + if (tok->done != E_OK) { + return EOF; + } + if (tok->readline) { + rc = tok_underflow_readline(tok); + } else if (tok->fp == NULL) { + rc = tok_underflow_string(tok); + } else if (tok->prompt != NULL) { + rc = tok_underflow_interactive(tok); + } else { + rc = tok_underflow_file(tok); } -} - -static int -_syntaxerror_range(struct tok_state *tok, const char *format, - int col_offset, int end_col_offset, - va_list vargs) -{ - // In release builds, we don't want to overwrite a previous error, but in debug builds we - // want to fail if we are not doing it so we can fix it. - assert(tok->done != E_ERROR); - if (tok->done == E_ERROR) { - return ERRORTOKEN; +#if defined(Py_DEBUG) + if (tok->debug) { + fprintf(stderr, "line[%d] = ", tok->lineno); + print_escape(stderr, tok->cur, tok->inp - tok->cur); + fprintf(stderr, " tok->done = %d\n", tok->done); } - PyObject *errmsg, *errtext, *args; - errmsg = PyUnicode_FromFormatV(format, vargs); - if (!errmsg) { - goto error; +#endif + if (!rc) { + tok->cur = tok->inp; + return EOF; } + tok->line_start = tok->cur; - errtext = PyUnicode_DecodeUTF8(tok->line_start, tok->cur - tok->line_start, - "replace"); - if (!errtext) { - goto error; + if (contains_null_bytes(tok->line_start, tok->inp - tok->line_start)) { + syntaxerror(tok, "source code cannot contain null bytes"); + tok->cur = tok->inp; + return EOF; } + } + Py_UNREACHABLE(); +} - if (col_offset == -1) { - col_offset = (int)PyUnicode_GET_LENGTH(errtext); - } - if (end_col_offset == -1) { - end_col_offset = col_offset; - } +/* Back-up one character */ - Py_ssize_t line_len = strcspn(tok->line_start, "\n"); - if (line_len != tok->cur - tok->line_start) { - Py_DECREF(errtext); - errtext = PyUnicode_DecodeUTF8(tok->line_start, line_len, - "replace"); +static void tok_backup(struct tok_state *tok, int c) { + if (c != EOF) { + if (--tok->cur < tok->buf) { + Py_FatalError("tokenizer beginning of buffer"); } - if (!errtext) { - goto error; + if ((int)(unsigned char)*tok->cur != Py_CHARMASK(c)) { + Py_FatalError("tok_backup: wrong character"); } + tok->col_offset--; + } +} - args = Py_BuildValue("(O(OiiNii))", errmsg, tok->filename, tok->lineno, - col_offset, errtext, tok->lineno, end_col_offset); - if (args) { - PyErr_SetObject(PyExc_SyntaxError, args); - Py_DECREF(args); - } +static int _syntaxerror_range(struct tok_state *tok, const char *format, + int col_offset, int end_col_offset, + va_list vargs) { + // In release builds, we don't want to overwrite a previous error, but in + // debug builds we want to fail if we are not doing it so we can fix it. + assert(tok->done != E_ERROR); + if (tok->done == E_ERROR) { + return ERRORTOKEN; + } + PyObject *errmsg, *errtext, *args; + errmsg = PyUnicode_FromFormatV(format, vargs); + if (!errmsg) { + goto error; + } + + errtext = PyUnicode_DecodeUTF8(tok->line_start, tok->cur - tok->line_start, + "replace"); + if (!errtext) { + goto error; + } + + if (col_offset == -1) { + col_offset = (int)PyUnicode_GET_LENGTH(errtext); + } + if (end_col_offset == -1) { + end_col_offset = col_offset; + } + + Py_ssize_t line_len = strcspn(tok->line_start, "\n"); + if (line_len != tok->cur - tok->line_start) { + Py_DECREF(errtext); + errtext = PyUnicode_DecodeUTF8(tok->line_start, line_len, "replace"); + } + if (!errtext) { + goto error; + } + + args = Py_BuildValue("(O(OiiNii))", errmsg, tok->filename, tok->lineno, + col_offset, errtext, tok->lineno, end_col_offset); + if (args) { + PyErr_SetObject(PyExc_SyntaxError, args); + Py_DECREF(args); + } error: - Py_XDECREF(errmsg); - tok->done = E_ERROR; - return ERRORTOKEN; + Py_XDECREF(errmsg); + tok->done = E_ERROR; + return ERRORTOKEN; } -static int -syntaxerror(struct tok_state *tok, const char *format, ...) -{ - // This errors are cleaned on startup. Todo: Fix it. - va_list vargs; - va_start(vargs, format); - int ret = _syntaxerror_range(tok, format, -1, -1, vargs); - va_end(vargs); - return ret; +static int syntaxerror(struct tok_state *tok, const char *format, ...) { + // This errors are cleaned on startup. Todo: Fix it. + va_list vargs; + va_start(vargs, format); + int ret = _syntaxerror_range(tok, format, -1, -1, vargs); + va_end(vargs); + return ret; } -static int -syntaxerror_known_range(struct tok_state *tok, - int col_offset, int end_col_offset, - const char *format, ...) -{ - va_list vargs; - va_start(vargs, format); - int ret = _syntaxerror_range(tok, format, col_offset, end_col_offset, vargs); - va_end(vargs); - return ret; +static int syntaxerror_known_range(struct tok_state *tok, int col_offset, + int end_col_offset, const char *format, + ...) { + va_list vargs; + va_start(vargs, format); + int ret = _syntaxerror_range(tok, format, col_offset, end_col_offset, vargs); + va_end(vargs); + return ret; } -static int -indenterror(struct tok_state *tok) -{ - tok->done = E_TABSPACE; - tok->cur = tok->inp; - return ERRORTOKEN; +static int indenterror(struct tok_state *tok) { + tok->done = E_TABSPACE; + tok->cur = tok->inp; + return ERRORTOKEN; } -static int -parser_warn(struct tok_state *tok, PyObject *category, const char *format, ...) -{ - if (!tok->report_warnings) { - return 0; - } - - PyObject *errmsg; - va_list vargs; - va_start(vargs, format); - errmsg = PyUnicode_FromFormatV(format, vargs); - va_end(vargs); - if (!errmsg) { - goto error; - } - - if (PyErr_WarnExplicitObject(category, errmsg, tok->filename, - tok->lineno, NULL, NULL) < 0) { - if (PyErr_ExceptionMatches(category)) { - /* Replace the DeprecationWarning exception with a SyntaxError - to get a more accurate error report */ - PyErr_Clear(); - syntaxerror(tok, "%U", errmsg); - } - goto error; - } - Py_DECREF(errmsg); +static int parser_warn(struct tok_state *tok, PyObject *category, + const char *format, ...) { + if (!tok->report_warnings) { return 0; + } + + PyObject *errmsg; + va_list vargs; + va_start(vargs, format); + errmsg = PyUnicode_FromFormatV(format, vargs); + va_end(vargs); + if (!errmsg) { + goto error; + } + + if (PyErr_WarnExplicitObject(category, errmsg, tok->filename, tok->lineno, + NULL, NULL) < 0) { + if (PyErr_ExceptionMatches(category)) { + /* Replace the DeprecationWarning exception with a SyntaxError + to get a more accurate error report */ + PyErr_Clear(); + syntaxerror(tok, "%U", errmsg); + } + goto error; + } + Py_DECREF(errmsg); + return 0; error: - Py_XDECREF(errmsg); - tok->done = E_ERROR; - return -1; + Py_XDECREF(errmsg); + tok->done = E_ERROR; + return -1; } -static int -warn_invalid_escape_sequence(struct tok_state *tok, int first_invalid_escape_char) -{ - if (!tok->report_warnings) { - return 0; - } - - PyObject *msg = PyUnicode_FromFormat( - "invalid escape sequence '\\%c'", - (char) first_invalid_escape_char - ); +static int warn_invalid_escape_sequence(struct tok_state *tok, + int first_invalid_escape_char) { + if (!tok->report_warnings) { + return 0; + } - if (msg == NULL) { - return -1; - } + PyObject *msg = PyUnicode_FromFormat("invalid escape sequence '\\%c'", + (char)first_invalid_escape_char); - if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg, tok->filename, - tok->lineno, NULL, NULL) < 0) { - Py_DECREF(msg); + if (msg == NULL) { + return -1; + } - if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) { - /* Replace the SyntaxWarning exception with a SyntaxError - to get a more accurate error report */ - PyErr_Clear(); - return syntaxerror(tok, "invalid escape sequence '\\%c'", (char) first_invalid_escape_char); - } + if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg, tok->filename, + tok->lineno, NULL, NULL) < 0) { + Py_DECREF(msg); - return -1; + if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) { + /* Replace the SyntaxWarning exception with a SyntaxError + to get a more accurate error report */ + PyErr_Clear(); + return syntaxerror(tok, "invalid escape sequence '\\%c'", + (char)first_invalid_escape_char); } - Py_DECREF(msg); - return 0; + return -1; + } + + Py_DECREF(msg); + return 0; } -static int -lookahead(struct tok_state *tok, const char *test) -{ - const char *s = test; - int res = 0; - while (1) { - int c = tok_nextc(tok); - if (*s == 0) { - res = !is_potential_identifier_char(c); - } - else if (c == *s) { - s++; - continue; - } +static int lookahead(struct tok_state *tok, const char *test) { + const char *s = test; + int res = 0; + while (1) { + int c = tok_nextc(tok); + if (*s == 0) { + res = !is_potential_identifier_char(c); + } else if (c == *s) { + s++; + continue; + } - tok_backup(tok, c); - while (s != test) { - tok_backup(tok, *--s); - } - return res; + tok_backup(tok, c); + while (s != test) { + tok_backup(tok, *--s); } + return res; + } } -static int -verify_end_of_number(struct tok_state *tok, int c, const char *kind) { - if (tok->tok_extra_tokens) { - // When we are parsing extra tokens, we don't want to emit warnings - // about invalid literals, because we want to be a bit more liberal. - return 1; - } - /* Emit a deprecation warning only if the numeric literal is immediately - * followed by one of keywords which can occur after a numeric literal - * in valid code: "and", "else", "for", "if", "in", "is" and "or". - * It allows to gradually deprecate existing valid code without adding - * warning before error in most cases of invalid numeric literal (which - * would be confusing and break existing tests). - * Raise a syntax error with slightly better message than plain - * "invalid syntax" if the numeric literal is immediately followed by - * other keyword or identifier. - */ - int r = 0; - if (c == 'a') { - r = lookahead(tok, "nd"); - } - else if (c == 'e') { - r = lookahead(tok, "lse"); - } - else if (c == 'f') { - r = lookahead(tok, "or"); - } - else if (c == 'i') { - int c2 = tok_nextc(tok); - if (c2 == 'f' || c2 == 'n' || c2 == 's') { - r = 1; - } - tok_backup(tok, c2); - } - else if (c == 'o') { - r = lookahead(tok, "r"); - } - else if (c == 'n') { - r = lookahead(tok, "ot"); - } - if (r) { - tok_backup(tok, c); - if (parser_warn(tok, PyExc_SyntaxWarning, - "invalid %s literal", kind)) - { - return 0; - } - tok_nextc(tok); +static int verify_end_of_number(struct tok_state *tok, int c, + const char *kind) { + if (tok->tok_extra_tokens) { + // When we are parsing extra tokens, we don't want to emit warnings + // about invalid literals, because we want to be a bit more liberal. + return 1; + } + /* Emit a deprecation warning only if the numeric literal is immediately + * followed by one of keywords which can occur after a numeric literal + * in valid code: "and", "else", "for", "if", "in", "is" and "or". + * It allows to gradually deprecate existing valid code without adding + * warning before error in most cases of invalid numeric literal (which + * would be confusing and break existing tests). + * Raise a syntax error with slightly better message than plain + * "invalid syntax" if the numeric literal is immediately followed by + * other keyword or identifier. + */ + int r = 0; + if (c == 'a') { + r = lookahead(tok, "nd"); + } else if (c == 'e') { + r = lookahead(tok, "lse"); + } else if (c == 'f') { + r = lookahead(tok, "or"); + } else if (c == 'i') { + int c2 = tok_nextc(tok); + if (c2 == 'f' || c2 == 'n' || c2 == 's') { + r = 1; + } + tok_backup(tok, c2); + } else if (c == 'o') { + r = lookahead(tok, "r"); + } else if (c == 'n') { + r = lookahead(tok, "ot"); + } + if (r) { + tok_backup(tok, c); + if (parser_warn(tok, PyExc_SyntaxWarning, "invalid %s literal", kind)) { + return 0; } - else /* In future releases, only error will remain. */ + tok_nextc(tok); + } else /* In future releases, only error will remain. */ if (c < 128 && is_potential_identifier_char(c)) { - tok_backup(tok, c); - syntaxerror(tok, "invalid %s literal", kind); - return 0; + tok_backup(tok, c); + syntaxerror(tok, "invalid %s literal", kind); + return 0; } - return 1; + return 1; } /* Verify that the identifier follows PEP 3131. All identifier strings are guaranteed to be "ready" unicode objects. */ -static int -verify_identifier(struct tok_state *tok) -{ - if (tok->tok_extra_tokens) { - return 1; - } - PyObject *s; - if (tok->decoding_erred) - return 0; - s = PyUnicode_DecodeUTF8(tok->start, tok->cur - tok->start, NULL); - if (s == NULL) { - if (PyErr_ExceptionMatches(PyExc_UnicodeDecodeError)) { - tok->done = E_DECODE; - } - else { - tok->done = E_ERROR; - } - return 0; +static int verify_identifier(struct tok_state *tok) { + if (tok->tok_extra_tokens) { + return 1; + } + PyObject *s; + if (tok->decoding_erred) + return 0; + s = PyUnicode_DecodeUTF8(tok->start, tok->cur - tok->start, NULL); + if (s == NULL) { + if (PyErr_ExceptionMatches(PyExc_UnicodeDecodeError)) { + tok->done = E_DECODE; + } else { + tok->done = E_ERROR; } - Py_ssize_t invalid = _PyUnicode_ScanIdentifier(s); - if (invalid < 0) { - Py_DECREF(s); + return 0; + } + Py_ssize_t invalid = _PyUnicode_ScanIdentifier(s); + if (invalid < 0) { + Py_DECREF(s); + tok->done = E_ERROR; + return 0; + } + assert(PyUnicode_GET_LENGTH(s) > 0); + if (invalid < PyUnicode_GET_LENGTH(s)) { + Py_UCS4 ch = PyUnicode_READ_CHAR(s, invalid); + if (invalid + 1 < PyUnicode_GET_LENGTH(s)) { + /* Determine the offset in UTF-8 encoded input */ + Py_SETREF(s, PyUnicode_Substring(s, 0, invalid + 1)); + if (s != NULL) { + Py_SETREF(s, PyUnicode_AsUTF8String(s)); + } + if (s == NULL) { tok->done = E_ERROR; return 0; - } - assert(PyUnicode_GET_LENGTH(s) > 0); - if (invalid < PyUnicode_GET_LENGTH(s)) { - Py_UCS4 ch = PyUnicode_READ_CHAR(s, invalid); - if (invalid + 1 < PyUnicode_GET_LENGTH(s)) { - /* Determine the offset in UTF-8 encoded input */ - Py_SETREF(s, PyUnicode_Substring(s, 0, invalid + 1)); - if (s != NULL) { - Py_SETREF(s, PyUnicode_AsUTF8String(s)); - } - if (s == NULL) { - tok->done = E_ERROR; - return 0; - } - tok->cur = (char *)tok->start + PyBytes_GET_SIZE(s); - } - Py_DECREF(s); - if (Py_UNICODE_ISPRINTABLE(ch)) { - syntaxerror(tok, "invalid character '%c' (U+%04X)", ch, ch); - } - else { - syntaxerror(tok, "invalid non-printable character U+%04X", ch); - } - return 0; + } + tok->cur = (char *)tok->start + PyBytes_GET_SIZE(s); } Py_DECREF(s); - return 1; -} - -static int -tok_decimal_tail(struct tok_state *tok) -{ - int c; - - while (1) { - do { - c = tok_nextc(tok); - } while (isdigit(c)); - if (c != '_') { - break; - } - c = tok_nextc(tok); - if (!isdigit(c)) { - tok_backup(tok, c); - syntaxerror(tok, "invalid decimal literal"); - return 0; - } - } - return c; -} - - -static inline int -tok_continuation_line(struct tok_state *tok) { - int c = tok_nextc(tok); - if (c == '\r') { - c = tok_nextc(tok); - } - if (c != '\n') { - tok->done = E_LINECONT; - return -1; - } - c = tok_nextc(tok); - if (c == EOF) { - tok->done = E_EOF; - tok->cur = tok->inp; - return -1; + if (Py_UNICODE_ISPRINTABLE(ch)) { + syntaxerror(tok, "invalid character '%c' (U+%04X)", ch, ch); } else { - tok_backup(tok, c); + syntaxerror(tok, "invalid non-printable character U+%04X", ch); } - return c; + return 0; + } + Py_DECREF(s); + return 1; } -static int -type_comment_token_setup(struct tok_state *tok, struct token *token, int type, int col_offset, - int end_col_offset, const char *start, const char *end) -{ - token->level = tok->level; - token->lineno = token->end_lineno = tok->lineno; - token->col_offset = col_offset; - token->end_col_offset = end_col_offset; - token->start = start; - token->end = end; - return type; -} +static int tok_decimal_tail(struct tok_state *tok) { + int c; -static int -token_setup(struct tok_state *tok, struct token *token, int type, const char *start, const char *end) -{ - assert((start == NULL && end == NULL) || (start != NULL && end != NULL)); - token->level = tok->level; - if (ISSTRINGLIT(type)) { - token->lineno = tok->first_lineno; - } - else { - token->lineno = tok->lineno; + while (1) { + do { + c = tok_nextc(tok); + } while (isdigit(c)); + if (c != '_') { + break; } - token->end_lineno = tok->lineno; - token->col_offset = token->end_col_offset = -1; - token->start = start; - token->end = end; - - if (start != NULL && end != NULL) { - token->col_offset = tok->starting_col_offset; - token->end_col_offset = tok->col_offset; + c = tok_nextc(tok); + if (!isdigit(c)) { + tok_backup(tok, c); + syntaxerror(tok, "invalid decimal literal"); + return 0; } - return type; + } + return c; } - -static int -tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct token *token) -{ - int c; - int blankline, nonascii; - - const char *p_start = NULL; - const char *p_end = NULL; - nextline: - tok->start = NULL; - tok->starting_col_offset = -1; - blankline = 0; - - - /* Get indentation level */ - if (tok->atbol) { - int col = 0; - int altcol = 0; - tok->atbol = 0; - int cont_line_col = 0; - for (;;) { - c = tok_nextc(tok); - if (c == ' ') { - col++, altcol++; - } - else if (c == '\t') { - col = (col / tok->tabsize + 1) * tok->tabsize; - altcol = (altcol / ALTTABSIZE + 1) * ALTTABSIZE; - } - else if (c == '\014') {/* Control-L (formfeed) */ - col = altcol = 0; /* For Emacs users */ - } - else if (c == '\\') { - // Indentation cannot be split over multiple physical lines - // using backslashes. This means that if we found a backslash - // preceded by whitespace, **the first one we find** determines - // the level of indentation of whatever comes next. - cont_line_col = cont_line_col ? cont_line_col : col; - if ((c = tok_continuation_line(tok)) == -1) { - return MAKE_TOKEN(ERRORTOKEN); - } - } - else { - break; - } - } - tok_backup(tok, c); - if (c == '#' || c == '\n' || c == '\r') { - /* Lines with only whitespace and/or comments - shouldn't affect the indentation and are - not passed to the parser as NEWLINE tokens, - except *totally* empty lines in interactive - mode, which signal the end of a command group. */ - if (col == 0 && c == '\n' && tok->prompt != NULL) { - blankline = 0; /* Let it through */ - } - else if (tok->prompt != NULL && tok->lineno == 1) { - /* In interactive mode, if the first line contains - only spaces and/or a comment, let it through. */ - blankline = 0; - col = altcol = 0; - } - else { - blankline = 1; /* Ignore completely */ - } - /* We can't jump back right here since we still - may need to skip to the end of a comment */ - } - if (!blankline && tok->level == 0) { - col = cont_line_col ? cont_line_col : col; - altcol = cont_line_col ? cont_line_col : altcol; - if (col == tok->indstack[tok->indent]) { - /* No change */ - if (altcol != tok->altindstack[tok->indent]) { - return MAKE_TOKEN(indenterror(tok)); - } - } - else if (col > tok->indstack[tok->indent]) { - /* Indent -- always one */ - if (tok->indent+1 >= MAXINDENT) { - tok->done = E_TOODEEP; - tok->cur = tok->inp; - return MAKE_TOKEN(ERRORTOKEN); - } - if (altcol <= tok->altindstack[tok->indent]) { - return MAKE_TOKEN(indenterror(tok)); - } - tok->pendin++; - tok->indstack[++tok->indent] = col; - tok->altindstack[tok->indent] = altcol; - } - else /* col < tok->indstack[tok->indent] */ { - /* Dedent -- any number, must be consistent */ - while (tok->indent > 0 && - col < tok->indstack[tok->indent]) { - tok->pendin--; - tok->indent--; - } - if (col != tok->indstack[tok->indent]) { - tok->done = E_DEDENT; - tok->cur = tok->inp; - return MAKE_TOKEN(ERRORTOKEN); - } - if (altcol != tok->altindstack[tok->indent]) { - return MAKE_TOKEN(indenterror(tok)); - } - } - } - } - - tok->start = tok->cur; - tok->starting_col_offset = tok->col_offset; - - /* Return pending indents/dedents */ - if (tok->pendin != 0) { - if (tok->pendin < 0) { - if (tok->tok_extra_tokens) { - p_start = tok->cur; - p_end = tok->cur; - } - tok->pendin++; - return MAKE_TOKEN(DEDENT); - } - else { - if (tok->tok_extra_tokens) { - p_start = tok->buf; - p_end = tok->cur; - } - tok->pendin--; - return MAKE_TOKEN(INDENT); +static inline int tok_continuation_line(struct tok_state *tok) { + int c = tok_nextc(tok); + if (c == '\r') { + c = tok_nextc(tok); + } + if (c != '\n') { + tok->done = E_LINECONT; + return -1; + } + c = tok_nextc(tok); + if (c == EOF) { + tok->done = E_EOF; + tok->cur = tok->inp; + return -1; + } else { + tok_backup(tok, c); + } + return c; +} + +static int type_comment_token_setup(struct tok_state *tok, struct token *token, + int type, int col_offset, + int end_col_offset, const char *start, + const char *end) { + token->level = tok->level; + token->lineno = token->end_lineno = tok->lineno; + token->col_offset = col_offset; + token->end_col_offset = end_col_offset; + token->start = start; + token->end = end; + return type; +} + +static int token_setup(struct tok_state *tok, struct token *token, int type, + const char *start, const char *end) { + assert((start == NULL && end == NULL) || (start != NULL && end != NULL)); + token->level = tok->level; + if (ISSTRINGLIT(type)) { + token->lineno = tok->first_lineno; + } else { + token->lineno = tok->lineno; + } + token->end_lineno = tok->lineno; + token->col_offset = token->end_col_offset = -1; + token->start = start; + token->end = end; + + if (start != NULL && end != NULL) { + token->col_offset = tok->starting_col_offset; + token->end_col_offset = tok->col_offset; + } + return type; +} + +static int tok_get_normal_mode(struct tok_state *tok, + tokenizer_mode *current_tok, + struct token *token) { + int c; + int blankline, nonascii; + + const char *p_start = NULL; + const char *p_end = NULL; +nextline: + tok->start = NULL; + tok->starting_col_offset = -1; + blankline = 0; + + /* Get indentation level */ + if (tok->atbol) { + int col = 0; + int altcol = 0; + tok->atbol = 0; + int cont_line_col = 0; + for (;;) { + c = tok_nextc(tok); + if (c == ' ') { + col++, altcol++; + } else if (c == '\t') { + col = (col / tok->tabsize + 1) * tok->tabsize; + altcol = (altcol / ALTTABSIZE + 1) * ALTTABSIZE; + } else if (c == '\014') { /* Control-L (formfeed) */ + col = altcol = 0; /* For Emacs users */ + } else if (c == '\\') { + // Indentation cannot be split over multiple physical lines + // using backslashes. This means that if we found a backslash + // preceded by whitespace, **the first one we find** determines + // the level of indentation of whatever comes next. + cont_line_col = cont_line_col ? cont_line_col : col; + if ((c = tok_continuation_line(tok)) == -1) { + return MAKE_TOKEN(ERRORTOKEN); } + } else { + break; + } } - - /* Peek ahead at the next character */ - c = tok_nextc(tok); tok_backup(tok, c); - /* Check if we are closing an async function */ - if (tok->async_def - && !blankline - /* Due to some implementation artifacts of type comments, - * a TYPE_COMMENT at the start of a function won't set an - * indentation level and it will produce a NEWLINE after it. - * To avoid spuriously ending an async function due to this, - * wait until we have some non-newline char in front of us. */ - && c != '\n' - && tok->level == 0 - /* There was a NEWLINE after ASYNC DEF, - so we're past the signature. */ - && tok->async_def_nl - /* Current indentation level is less than where - the async function was defined */ - && tok->async_def_indent >= tok->indent) - { - tok->async_def = 0; - tok->async_def_indent = 0; - tok->async_def_nl = 0; - } - - again: - tok->start = NULL; - /* Skip spaces */ - do { - c = tok_nextc(tok); - } while (c == ' ' || c == '\t' || c == '\014'); - - /* Set start of current token */ - tok->start = tok->cur == NULL ? NULL : tok->cur - 1; - tok->starting_col_offset = tok->col_offset - 1; - - /* Skip comment, unless it's a type comment */ - if (c == '#') { + if (c == '#' || c == '\n' || c == '\r') { + /* Lines with only whitespace and/or comments + shouldn't affect the indentation and are + not passed to the parser as NEWLINE tokens, + except *totally* empty lines in interactive + mode, which signal the end of a command group. */ + if (col == 0 && c == '\n' && tok->prompt != NULL) { + blankline = 0; /* Let it through */ + } else if (tok->prompt != NULL && tok->lineno == 1) { + /* In interactive mode, if the first line contains + only spaces and/or a comment, let it through. */ + blankline = 0; + col = altcol = 0; + } else { + blankline = 1; /* Ignore completely */ + } + /* We can't jump back right here since we still + may need to skip to the end of a comment */ + } + if (!blankline && tok->level == 0) { + col = cont_line_col ? cont_line_col : col; + altcol = cont_line_col ? cont_line_col : altcol; + if (col == tok->indstack[tok->indent]) { + /* No change */ + if (altcol != tok->altindstack[tok->indent]) { + return MAKE_TOKEN(indenterror(tok)); + } + } else if (col > tok->indstack[tok->indent]) { + /* Indent -- always one */ + if (tok->indent + 1 >= MAXINDENT) { + tok->done = E_TOODEEP; + tok->cur = tok->inp; + return MAKE_TOKEN(ERRORTOKEN); + } + if (altcol <= tok->altindstack[tok->indent]) { + return MAKE_TOKEN(indenterror(tok)); + } + tok->pendin++; + tok->indstack[++tok->indent] = col; + tok->altindstack[tok->indent] = altcol; + } else /* col < tok->indstack[tok->indent] */ { + /* Dedent -- any number, must be consistent */ + while (tok->indent > 0 && col < tok->indstack[tok->indent]) { + tok->pendin--; + tok->indent--; + } + if (col != tok->indstack[tok->indent]) { + tok->done = E_DEDENT; + tok->cur = tok->inp; + return MAKE_TOKEN(ERRORTOKEN); + } + if (altcol != tok->altindstack[tok->indent]) { + return MAKE_TOKEN(indenterror(tok)); + } + } + } + } + + tok->start = tok->cur; + tok->starting_col_offset = tok->col_offset; + + /* Return pending indents/dedents */ + if (tok->pendin != 0) { + if (tok->pendin < 0) { + if (tok->tok_extra_tokens) { + p_start = tok->cur; + p_end = tok->cur; + } + tok->pendin++; + return MAKE_TOKEN(DEDENT); + } else { + if (tok->tok_extra_tokens) { + p_start = tok->buf; + p_end = tok->cur; + } + tok->pendin--; + return MAKE_TOKEN(INDENT); + } + } + + /* Peek ahead at the next character */ + c = tok_nextc(tok); + tok_backup(tok, c); + /* Check if we are closing an async function */ + if (tok->async_def && + !blankline + /* Due to some implementation artifacts of type comments, + * a TYPE_COMMENT at the start of a function won't set an + * indentation level and it will produce a NEWLINE after it. + * To avoid spuriously ending an async function due to this, + * wait until we have some non-newline char in front of us. */ + && c != '\n' && + tok->level == 0 + /* There was a NEWLINE after ASYNC DEF, + so we're past the signature. */ + && tok->async_def_nl + /* Current indentation level is less than where + the async function was defined */ + && tok->async_def_indent >= tok->indent) { + tok->async_def = 0; + tok->async_def_indent = 0; + tok->async_def_nl = 0; + } - const char* p = NULL; - const char *prefix, *type_start; - int current_starting_col_offset; +again: + tok->start = NULL; + /* Skip spaces */ + do { + c = tok_nextc(tok); + } while (c == ' ' || c == '\t' || c == '\014'); - while (c != EOF && c != '\n' && c != '\r') { - c = tok_nextc(tok); - } + /* Set start of current token */ + tok->start = tok->cur == NULL ? NULL : tok->cur - 1; + tok->starting_col_offset = tok->col_offset - 1; - if (tok->tok_extra_tokens) { - p = tok->start; - } + /* Skip comment, unless it's a type comment */ + if (c == '#') { - if (tok->type_comments) { - p = tok->start; - current_starting_col_offset = tok->starting_col_offset; - prefix = type_comment_prefix; - while (*prefix && p < tok->cur) { - if (*prefix == ' ') { - while (*p == ' ' || *p == '\t') { - p++; - current_starting_col_offset++; - } - } else if (*prefix == *p) { - p++; - current_starting_col_offset++; - } else { - break; - } - - prefix++; - } + const char *p = NULL; + const char *prefix, *type_start; + int current_starting_col_offset; - /* This is a type comment if we matched all of type_comment_prefix. */ - if (!*prefix) { - int is_type_ignore = 1; - // +6 in order to skip the word 'ignore' - const char *ignore_end = p + 6; - const int ignore_end_col_offset = current_starting_col_offset + 6; - tok_backup(tok, c); /* don't eat the newline or EOF */ - - type_start = p; - - /* A TYPE_IGNORE is "type: ignore" followed by the end of the token - * or anything ASCII and non-alphanumeric. */ - is_type_ignore = ( - tok->cur >= ignore_end && memcmp(p, "ignore", 6) == 0 - && !(tok->cur > ignore_end - && ((unsigned char)ignore_end[0] >= 128 || Py_ISALNUM(ignore_end[0])))); - - if (is_type_ignore) { - p_start = ignore_end; - p_end = tok->cur; - - /* If this type ignore is the only thing on the line, consume the newline also. */ - if (blankline) { - tok_nextc(tok); - tok->atbol = 1; - } - return MAKE_TYPE_COMMENT_TOKEN(TYPE_IGNORE, ignore_end_col_offset, tok->col_offset); - } else { - p_start = type_start; - p_end = tok->cur; - return MAKE_TYPE_COMMENT_TOKEN(TYPE_COMMENT, current_starting_col_offset, tok->col_offset); - } - } - } - if (tok->tok_extra_tokens) { - tok_backup(tok, c); /* don't eat the newline or EOF */ - p_start = p; - p_end = tok->cur; - tok->comment_newline = blankline; - return MAKE_TOKEN(COMMENT); - } + while (c != EOF && c != '\n' && c != '\r') { + c = tok_nextc(tok); } - if (tok->done == E_INTERACT_STOP) { - return MAKE_TOKEN(ENDMARKER); + if (tok->tok_extra_tokens) { + p = tok->start; + } + + if (tok->type_comments) { + p = tok->start; + current_starting_col_offset = tok->starting_col_offset; + prefix = type_comment_prefix; + while (*prefix && p < tok->cur) { + if (*prefix == ' ') { + while (*p == ' ' || *p == '\t') { + p++; + current_starting_col_offset++; + } + } else if (*prefix == *p) { + p++; + current_starting_col_offset++; + } else { + break; + } + + prefix++; + } + + /* This is a type comment if we matched all of type_comment_prefix. */ + if (!*prefix) { + int is_type_ignore = 1; + // +6 in order to skip the word 'ignore' + const char *ignore_end = p + 6; + const int ignore_end_col_offset = current_starting_col_offset + 6; + tok_backup(tok, c); /* don't eat the newline or EOF */ + + type_start = p; + + /* A TYPE_IGNORE is "type: ignore" followed by the end of the token + * or anything ASCII and non-alphanumeric. */ + is_type_ignore = + (tok->cur >= ignore_end && memcmp(p, "ignore", 6) == 0 && + !(tok->cur > ignore_end && ((unsigned char)ignore_end[0] >= 128 || + Py_ISALNUM(ignore_end[0])))); + + if (is_type_ignore) { + p_start = ignore_end; + p_end = tok->cur; + + /* If this type ignore is the only thing on the line, consume the + * newline also. */ + if (blankline) { + tok_nextc(tok); + tok->atbol = 1; + } + return MAKE_TYPE_COMMENT_TOKEN(TYPE_IGNORE, ignore_end_col_offset, + tok->col_offset); + } else { + p_start = type_start; + p_end = tok->cur; + return MAKE_TYPE_COMMENT_TOKEN( + TYPE_COMMENT, current_starting_col_offset, tok->col_offset); + } + } } - - /* Check for EOF and errors now */ - if (c == EOF) { - if (tok->level) { - return MAKE_TOKEN(ERRORTOKEN); + if (tok->tok_extra_tokens) { + tok_backup(tok, c); /* don't eat the newline or EOF */ + p_start = p; + p_end = tok->cur; + tok->comment_newline = blankline; + return MAKE_TOKEN(COMMENT); + } + } + + if (tok->done == E_INTERACT_STOP) { + return MAKE_TOKEN(ENDMARKER); + } + + /* Check for EOF and errors now */ + if (c == EOF) { + if (tok->level) { + return MAKE_TOKEN(ERRORTOKEN); + } + return MAKE_TOKEN(tok->done == E_EOF ? ENDMARKER : ERRORTOKEN); + } + + /* Identifier (most frequent token!) */ + nonascii = 0; + if (is_potential_identifier_start(c)) { + /* Process the various legal combinations of b"", r"", u"", and f"". */ + int saw_b = 0, saw_r = 0, saw_u = 0, saw_f = 0; + while (1) { + if (!(saw_b || saw_u || saw_f) && (c == 'b' || c == 'B')) + saw_b = 1; + /* Since this is a backwards compatibility support literal we don't + want to support it in arbitrary order like byte literals. */ + else if (!(saw_b || saw_u || saw_r || saw_f) && (c == 'u' || c == 'U')) { + saw_u = 1; + } + /* ur"" and ru"" are not supported */ + else if (!(saw_r || saw_u) && (c == 'r' || c == 'R')) { + saw_r = 1; + } else if (!(saw_f || saw_b || saw_u) && (c == 'f' || c == 'F')) { + saw_f = 1; + } else { + break; + } + c = tok_nextc(tok); + if (c == '"' || c == '\'') { + if (saw_f) { + goto f_string_quote; } - return MAKE_TOKEN(tok->done == E_EOF ? ENDMARKER : ERRORTOKEN); + goto letter_quote; + } + } + while (is_potential_identifier_char(c)) { + if (c >= 128) { + nonascii = 1; + } + c = tok_nextc(tok); + } + tok_backup(tok, c); + if (nonascii && !verify_identifier(tok)) { + return MAKE_TOKEN(ERRORTOKEN); } - /* Identifier (most frequent token!) */ - nonascii = 0; - if (is_potential_identifier_start(c)) { - /* Process the various legal combinations of b"", r"", u"", and f"". */ - int saw_b = 0, saw_r = 0, saw_u = 0, saw_f = 0; - while (1) { - if (!(saw_b || saw_u || saw_f) && (c == 'b' || c == 'B')) - saw_b = 1; - /* Since this is a backwards compatibility support literal we don't - want to support it in arbitrary order like byte literals. */ - else if (!(saw_b || saw_u || saw_r || saw_f) - && (c == 'u'|| c == 'U')) { - saw_u = 1; - } - /* ur"" and ru"" are not supported */ - else if (!(saw_r || saw_u) && (c == 'r' || c == 'R')) { - saw_r = 1; - } - else if (!(saw_f || saw_b || saw_u) && (c == 'f' || c == 'F')) { - saw_f = 1; - } - else { - break; - } - c = tok_nextc(tok); - if (c == '"' || c == '\'') { - if (saw_f) { - goto f_string_quote; - } - goto letter_quote; - } - } - while (is_potential_identifier_char(c)) { - if (c >= 128) { - nonascii = 1; - } - c = tok_nextc(tok); - } - tok_backup(tok, c); - if (nonascii && !verify_identifier(tok)) { - return MAKE_TOKEN(ERRORTOKEN); - } + p_start = tok->start; + p_end = tok->cur; - p_start = tok->start; - p_end = tok->cur; + /* async/await parsing block. */ + if (tok->cur - tok->start == 5 && tok->start[0] == 'a') { + /* May be an 'async' or 'await' token. For Python 3.7 or + later we recognize them unconditionally. For Python + 3.5 or 3.6 we recognize 'async' in front of 'def', and + either one inside of 'async def'. (Technically we + shouldn't recognize these at all for 3.4 or earlier, + but there's no *valid* Python 3.4 code that would be + rejected, and async functions will be rejected in a + later phase.) */ + if (!tok->async_hacks || tok->async_def) { + /* Always recognize the keywords. */ + if (memcmp(tok->start, "async", 5) == 0) { + return MAKE_TOKEN(ASYNC); + } + if (memcmp(tok->start, "await", 5) == 0) { + return MAKE_TOKEN(AWAIT); + } + } else if (memcmp(tok->start, "async", 5) == 0) { + /* The current token is 'async'. + Look ahead one token to see if that is 'def'. */ + + struct tok_state ahead_tok; + struct token ahead_token; + _PyToken_Init(&ahead_token); + int ahead_tok_kind; + + memcpy(&ahead_tok, tok, sizeof(ahead_tok)); + ahead_tok_kind = + tok_get_normal_mode(&ahead_tok, current_tok, &ahead_token); + + if (ahead_tok_kind == NAME && ahead_tok.cur - ahead_tok.start == 3 && + memcmp(ahead_tok.start, "def", 3) == 0) { + /* The next token is going to be 'def', so instead of + returning a plain NAME token, return ASYNC. */ + tok->async_def_indent = tok->indent; + tok->async_def = 1; + _PyToken_Free(&ahead_token); + return MAKE_TOKEN(ASYNC); + } + _PyToken_Free(&ahead_token); + } + } + + return MAKE_TOKEN(NAME); + } + + if (c == '\r') { + c = tok_nextc(tok); + } - /* async/await parsing block. */ - if (tok->cur - tok->start == 5 && tok->start[0] == 'a') { - /* May be an 'async' or 'await' token. For Python 3.7 or - later we recognize them unconditionally. For Python - 3.5 or 3.6 we recognize 'async' in front of 'def', and - either one inside of 'async def'. (Technically we - shouldn't recognize these at all for 3.4 or earlier, - but there's no *valid* Python 3.4 code that would be - rejected, and async functions will be rejected in a - later phase.) */ - if (!tok->async_hacks || tok->async_def) { - /* Always recognize the keywords. */ - if (memcmp(tok->start, "async", 5) == 0) { - return MAKE_TOKEN(ASYNC); - } - if (memcmp(tok->start, "await", 5) == 0) { - return MAKE_TOKEN(AWAIT); - } - } - else if (memcmp(tok->start, "async", 5) == 0) { - /* The current token is 'async'. - Look ahead one token to see if that is 'def'. */ - - struct tok_state ahead_tok; - struct token ahead_token; - _PyToken_Init(&ahead_token); - int ahead_tok_kind; - - memcpy(&ahead_tok, tok, sizeof(ahead_tok)); - ahead_tok_kind = tok_get_normal_mode(&ahead_tok, - current_tok, - &ahead_token); - - if (ahead_tok_kind == NAME - && ahead_tok.cur - ahead_tok.start == 3 - && memcmp(ahead_tok.start, "def", 3) == 0) - { - /* The next token is going to be 'def', so instead of - returning a plain NAME token, return ASYNC. */ - tok->async_def_indent = tok->indent; - tok->async_def = 1; - _PyToken_Free(&ahead_token); - return MAKE_TOKEN(ASYNC); - } - _PyToken_Free(&ahead_token); - } + /* Newline */ + if (c == '\n') { + tok->atbol = 1; + if (blankline || tok->level > 0) { + if (tok->tok_extra_tokens) { + if (tok->comment_newline) { + tok->comment_newline = 0; } - - return MAKE_TOKEN(NAME); + p_start = tok->start; + p_end = tok->cur; + return MAKE_TOKEN(NL); + } + goto nextline; } - - if (c == '\r') { - c = tok_nextc(tok); + if (tok->comment_newline && tok->tok_extra_tokens) { + tok->comment_newline = 0; + p_start = tok->start; + p_end = tok->cur; + return MAKE_TOKEN(NL); + } + p_start = tok->start; + p_end = tok->cur - 1; /* Leave '\n' out of the string */ + tok->cont_line = 0; + if (tok->async_def) { + /* We're somewhere inside an 'async def' function, and + we've encountered a NEWLINE after its signature. */ + tok->async_def_nl = 1; } + return MAKE_TOKEN(NEWLINE); + } - /* Newline */ - if (c == '\n') { - tok->atbol = 1; - if (blankline || tok->level > 0) { - if (tok->tok_extra_tokens) { - if (tok->comment_newline) { - tok->comment_newline = 0; - } - p_start = tok->start; - p_end = tok->cur; - return MAKE_TOKEN(NL); - } - goto nextline; - } - if (tok->comment_newline && tok->tok_extra_tokens) { - tok->comment_newline = 0; - p_start = tok->start; - p_end = tok->cur; - return MAKE_TOKEN(NL); - } + /* Period or number starting with period? */ + if (c == '.') { + c = tok_nextc(tok); + if (isdigit(c)) { + goto fraction; + } else if (c == '.') { + c = tok_nextc(tok); + if (c == '.') { p_start = tok->start; - p_end = tok->cur - 1; /* Leave '\n' out of the string */ - tok->cont_line = 0; - if (tok->async_def) { - /* We're somewhere inside an 'async def' function, and - we've encountered a NEWLINE after its signature. */ - tok->async_def_nl = 1; - } - return MAKE_TOKEN(NEWLINE); + p_end = tok->cur; + return MAKE_TOKEN(ELLIPSIS); + } else { + tok_backup(tok, c); + } + tok_backup(tok, '.'); + } else { + tok_backup(tok, c); } - - /* Period or number starting with period? */ - if (c == '.') { + p_start = tok->start; + p_end = tok->cur; + return MAKE_TOKEN(DOT); + } + + /* Number */ + if (isdigit(c)) { + if (c == '0') { + /* Hex, octal or binary -- maybe. */ + c = tok_nextc(tok); + if (c == 'x' || c == 'X') { + /* Hex */ c = tok_nextc(tok); - if (isdigit(c)) { - goto fraction; - } else if (c == '.') { + do { + if (c == '_') { c = tok_nextc(tok); - if (c == '.') { - p_start = tok->start; - p_end = tok->cur; - return MAKE_TOKEN(ELLIPSIS); - } - else { - tok_backup(tok, c); - } - tok_backup(tok, '.'); - } - else { + } + if (!isxdigit(c)) { tok_backup(tok, c); - } - p_start = tok->start; - p_end = tok->cur; - return MAKE_TOKEN(DOT); - } - - /* Number */ - if (isdigit(c)) { - if (c == '0') { - /* Hex, octal or binary -- maybe. */ + return MAKE_TOKEN(syntaxerror(tok, "invalid hexadecimal literal")); + } + do { c = tok_nextc(tok); - if (c == 'x' || c == 'X') { - /* Hex */ - c = tok_nextc(tok); - do { - if (c == '_') { - c = tok_nextc(tok); - } - if (!isxdigit(c)) { - tok_backup(tok, c); - return MAKE_TOKEN(syntaxerror(tok, "invalid hexadecimal literal")); - } - do { - c = tok_nextc(tok); - } while (isxdigit(c)); - } while (c == '_'); - if (!verify_end_of_number(tok, c, "hexadecimal")) { - return MAKE_TOKEN(ERRORTOKEN); - } - } - else if (c == 'o' || c == 'O') { - /* Octal */ - c = tok_nextc(tok); - do { - if (c == '_') { - c = tok_nextc(tok); - } - if (c < '0' || c >= '8') { - if (isdigit(c)) { - return MAKE_TOKEN(syntaxerror(tok, - "invalid digit '%c' in octal literal", c)); - } - else { - tok_backup(tok, c); - return MAKE_TOKEN(syntaxerror(tok, "invalid octal literal")); - } - } - do { - c = tok_nextc(tok); - } while ('0' <= c && c < '8'); - } while (c == '_'); - if (isdigit(c)) { - return MAKE_TOKEN(syntaxerror(tok, - "invalid digit '%c' in octal literal", c)); - } - if (!verify_end_of_number(tok, c, "octal")) { - return MAKE_TOKEN(ERRORTOKEN); - } - } - else if (c == 'b' || c == 'B') { - /* Binary */ - c = tok_nextc(tok); - do { - if (c == '_') { - c = tok_nextc(tok); - } - if (c != '0' && c != '1') { - if (isdigit(c)) { - return MAKE_TOKEN(syntaxerror(tok, "invalid digit '%c' in binary literal", c)); - } - else { - tok_backup(tok, c); - return MAKE_TOKEN(syntaxerror(tok, "invalid binary literal")); - } - } - do { - c = tok_nextc(tok); - } while (c == '0' || c == '1'); - } while (c == '_'); - if (isdigit(c)) { - return MAKE_TOKEN(syntaxerror(tok, "invalid digit '%c' in binary literal", c)); - } - if (!verify_end_of_number(tok, c, "binary")) { - return MAKE_TOKEN(ERRORTOKEN); - } - } - else { - int nonzero = 0; - /* maybe old-style octal; c is first char of it */ - /* in any case, allow '0' as a literal */ - while (1) { - if (c == '_') { - c = tok_nextc(tok); - if (!isdigit(c)) { - tok_backup(tok, c); - return MAKE_TOKEN(syntaxerror(tok, "invalid decimal literal")); - } - } - if (c != '0') { - break; - } - c = tok_nextc(tok); - } - char* zeros_end = tok->cur; - if (isdigit(c)) { - nonzero = 1; - c = tok_decimal_tail(tok); - if (c == 0) { - return MAKE_TOKEN(ERRORTOKEN); - } - } - if (c == '.') { - c = tok_nextc(tok); - goto fraction; - } - else if (c == 'e' || c == 'E') { - goto exponent; - } - else if (c == 'j' || c == 'J') { - goto imaginary; - } - else if (nonzero && !tok->tok_extra_tokens) { - /* Old-style octal: now disallowed. */ - tok_backup(tok, c); - return MAKE_TOKEN(syntaxerror_known_range( - tok, (int)(tok->start + 1 - tok->line_start), - (int)(zeros_end - tok->line_start), - "leading zeros in decimal integer " - "literals are not permitted; " - "use an 0o prefix for octal integers")); - } - if (!verify_end_of_number(tok, c, "decimal")) { - return MAKE_TOKEN(ERRORTOKEN); - } - } - } - else { - /* Decimal */ - c = tok_decimal_tail(tok); - if (c == 0) { - return MAKE_TOKEN(ERRORTOKEN); - } - { - /* Accept floating point numbers. */ - if (c == '.') { - c = tok_nextc(tok); - fraction: - /* Fraction */ - if (isdigit(c)) { - c = tok_decimal_tail(tok); - if (c == 0) { - return MAKE_TOKEN(ERRORTOKEN); - } - } - } - if (c == 'e' || c == 'E') { - int e; - exponent: - e = c; - /* Exponent part */ - c = tok_nextc(tok); - if (c == '+' || c == '-') { - c = tok_nextc(tok); - if (!isdigit(c)) { - tok_backup(tok, c); - return MAKE_TOKEN(syntaxerror(tok, "invalid decimal literal")); - } - } else if (!isdigit(c)) { - tok_backup(tok, c); - if (!verify_end_of_number(tok, e, "decimal")) { - return MAKE_TOKEN(ERRORTOKEN); - } - tok_backup(tok, e); - p_start = tok->start; - p_end = tok->cur; - return MAKE_TOKEN(NUMBER); - } - c = tok_decimal_tail(tok); - if (c == 0) { - return MAKE_TOKEN(ERRORTOKEN); - } - } - if (c == 'j' || c == 'J') { - /* Imaginary part */ - imaginary: - c = tok_nextc(tok); - if (!verify_end_of_number(tok, c, "imaginary")) { - return MAKE_TOKEN(ERRORTOKEN); - } - } - else if (!verify_end_of_number(tok, c, "decimal")) { - return MAKE_TOKEN(ERRORTOKEN); - } - } + } while (isxdigit(c)); + } while (c == '_'); + if (!verify_end_of_number(tok, c, "hexadecimal")) { + return MAKE_TOKEN(ERRORTOKEN); } - tok_backup(tok, c); - p_start = tok->start; - p_end = tok->cur; - return MAKE_TOKEN(NUMBER); - } - - f_string_quote: - if (((tolower(*tok->start) == 'f' || tolower(*tok->start) == 'r') && (c == '\'' || c == '"'))) { - int quote = c; - int quote_size = 1; /* 1 or 3 */ - - /* Nodes of type STRING, especially multi line strings - must be handled differently in order to get both - the starting line number and the column offset right. - (cf. issue 16806) */ - tok->first_lineno = tok->lineno; - tok->multi_line_start = tok->line_start; - - /* Find the quote size and start of string */ - int after_quote = tok_nextc(tok); - if (after_quote == quote) { - int after_after_quote = tok_nextc(tok); - if (after_after_quote == quote) { - quote_size = 3; - } - else { - // TODO: Check this - tok_backup(tok, after_after_quote); - tok_backup(tok, after_quote); + } else if (c == 'o' || c == 'O') { + /* Octal */ + c = tok_nextc(tok); + do { + if (c == '_') { + c = tok_nextc(tok); + } + if (c < '0' || c >= '8') { + if (isdigit(c)) { + return MAKE_TOKEN( + syntaxerror(tok, "invalid digit '%c' in octal literal", c)); + } else { + tok_backup(tok, c); + return MAKE_TOKEN(syntaxerror(tok, "invalid octal literal")); } + } + do { + c = tok_nextc(tok); + } while ('0' <= c && c < '8'); + } while (c == '_'); + if (isdigit(c)) { + return MAKE_TOKEN( + syntaxerror(tok, "invalid digit '%c' in octal literal", c)); } - if (after_quote != quote) { - tok_backup(tok, after_quote); - } - - - p_start = tok->start; - p_end = tok->cur; - if (tok->tok_mode_stack_index + 1 >= MAXFSTRINGLEVEL) { - return MAKE_TOKEN(syntaxerror(tok, "too many nested f-strings")); - } - tokenizer_mode *the_current_tok = TOK_NEXT_MODE(tok); - the_current_tok->kind = TOK_FSTRING_MODE; - the_current_tok->f_string_quote = quote; - the_current_tok->f_string_quote_size = quote_size; - the_current_tok->f_string_start = tok->start; - the_current_tok->f_string_multi_line_start = tok->line_start; - the_current_tok->f_string_line_start = tok->lineno; - the_current_tok->f_string_start_offset = -1; - the_current_tok->f_string_multi_line_start_offset = -1; - the_current_tok->last_expr_buffer = NULL; - the_current_tok->last_expr_size = 0; - the_current_tok->last_expr_end = -1; - the_current_tok->f_string_debug = 0; - - switch (*tok->start) { - case 'F': - case 'f': - the_current_tok->f_string_raw = tolower(*(tok->start + 1)) == 'r'; - break; - case 'R': - case 'r': - the_current_tok->f_string_raw = 1; - break; - default: - Py_UNREACHABLE(); + if (!verify_end_of_number(tok, c, "octal")) { + return MAKE_TOKEN(ERRORTOKEN); } - - the_current_tok->curly_bracket_depth = 0; - the_current_tok->curly_bracket_expr_start_depth = -1; - return MAKE_TOKEN(FSTRING_START); - } - - letter_quote: - /* String */ - if (c == '\'' || c == '"') { - int quote = c; - int quote_size = 1; /* 1 or 3 */ - int end_quote_size = 0; - - /* Nodes of type STRING, especially multi line strings - must be handled differently in order to get both - the starting line number and the column offset right. - (cf. issue 16806) */ - tok->first_lineno = tok->lineno; - tok->multi_line_start = tok->line_start; - - /* Find the quote size and start of string */ + } else if (c == 'b' || c == 'B') { + /* Binary */ c = tok_nextc(tok); - if (c == quote) { + do { + if (c == '_') { c = tok_nextc(tok); - if (c == quote) { - quote_size = 3; - } - else { - end_quote_size = 1; /* empty string found */ + } + if (c != '0' && c != '1') { + if (isdigit(c)) { + return MAKE_TOKEN( + syntaxerror(tok, "invalid digit '%c' in binary literal", c)); + } else { + tok_backup(tok, c); + return MAKE_TOKEN(syntaxerror(tok, "invalid binary literal")); } + } + do { + c = tok_nextc(tok); + } while (c == '0' || c == '1'); + } while (c == '_'); + if (isdigit(c)) { + return MAKE_TOKEN( + syntaxerror(tok, "invalid digit '%c' in binary literal", c)); } - if (c != quote) { - tok_backup(tok, c); + if (!verify_end_of_number(tok, c, "binary")) { + return MAKE_TOKEN(ERRORTOKEN); } - - /* Get rest of string */ - while (end_quote_size != quote_size) { + } else { + int nonzero = 0; + /* maybe old-style octal; c is first char of it */ + /* in any case, allow '0' as a literal */ + while (1) { + if (c == '_') { c = tok_nextc(tok); - if (tok->done == E_ERROR) { - return MAKE_TOKEN(ERRORTOKEN); - } - if (tok->done == E_DECODE) { - break; - } - if (c == EOF || (quote_size == 1 && c == '\n')) { - assert(tok->multi_line_start != NULL); - // shift the tok_state's location into - // the start of string, and report the error - // from the initial quote character - tok->cur = (char *)tok->start; - tok->cur++; - tok->line_start = tok->multi_line_start; - int start = tok->lineno; - tok->lineno = tok->first_lineno; - - if (INSIDE_FSTRING(tok)) { - /* When we are in an f-string, before raising the - * unterminated string literal error, check whether - * does the initial quote matches with f-strings quotes - * and if it is, then this must be a missing '}' token - * so raise the proper error */ - tokenizer_mode *the_current_tok = TOK_GET_MODE(tok); - if (the_current_tok->f_string_quote == quote && - the_current_tok->f_string_quote_size == quote_size) { - return MAKE_TOKEN(syntaxerror(tok, "f-string: expecting '}'", start)); - } - } - - if (quote_size == 3) { - syntaxerror(tok, "unterminated triple-quoted string literal" - " (detected at line %d)", start); - if (c != '\n') { - tok->done = E_EOFS; - } - return MAKE_TOKEN(ERRORTOKEN); - } - else { - syntaxerror(tok, "unterminated string literal (detected at" - " line %d)", start); - if (c != '\n') { - tok->done = E_EOLS; - } - return MAKE_TOKEN(ERRORTOKEN); - } + if (!isdigit(c)) { + tok_backup(tok, c); + return MAKE_TOKEN(syntaxerror(tok, "invalid decimal literal")); } - if (c == quote) { - end_quote_size += 1; - } - else { - end_quote_size = 0; - if (c == '\\') { - c = tok_nextc(tok); /* skip escaped char */ - if (c == '\r') { - c = tok_nextc(tok); - } - } - } - } - - p_start = tok->start; - p_end = tok->cur; - return MAKE_TOKEN(STRING); - } - - /* Line continuation */ - if (c == '\\') { - if ((c = tok_continuation_line(tok)) == -1) { - return MAKE_TOKEN(ERRORTOKEN); - } - tok->cont_line = 1; - goto again; /* Read next line */ - } - - /* Punctuation character */ - int is_punctuation = (c == ':' || c == '}' || c == '!' || c == '{'); - if (is_punctuation && INSIDE_FSTRING(tok) && INSIDE_FSTRING_EXPR(current_tok)) { - /* This code block gets executed before the curly_bracket_depth is incremented - * by the `{` case, so for ensuring that we are on the 0th level, we need - * to adjust it manually */ - int cursor = current_tok->curly_bracket_depth - (c != '{'); - if (cursor == 0 && !update_fstring_expr(tok, c)) { - return MAKE_TOKEN(ENDMARKER); + } + if (c != '0') { + break; + } + c = tok_nextc(tok); } - if (cursor == 0 && c != '{' && set_fstring_expr(tok, token, c)) { + char *zeros_end = tok->cur; + if (isdigit(c)) { + nonzero = 1; + c = tok_decimal_tail(tok); + if (c == 0) { return MAKE_TOKEN(ERRORTOKEN); + } + } + if (c == '.') { + c = tok_nextc(tok); + goto fraction; + } else if (c == 'e' || c == 'E') { + goto exponent; + } else if (c == 'j' || c == 'J') { + goto imaginary; + } else if (nonzero && !tok->tok_extra_tokens) { + /* Old-style octal: now disallowed. */ + tok_backup(tok, c); + return MAKE_TOKEN(syntaxerror_known_range( + tok, (int)(tok->start + 1 - tok->line_start), + (int)(zeros_end - tok->line_start), + "leading zeros in decimal integer " + "literals are not permitted; " + "use an 0o prefix for octal integers")); + } + if (!verify_end_of_number(tok, c, "decimal")) { + return MAKE_TOKEN(ERRORTOKEN); + } + } + } else { + /* Decimal */ + c = tok_decimal_tail(tok); + if (c == 0) { + return MAKE_TOKEN(ERRORTOKEN); + } + { + /* Accept floating point numbers. */ + if (c == '.') { + c = tok_nextc(tok); + fraction: + /* Fraction */ + if (isdigit(c)) { + c = tok_decimal_tail(tok); + if (c == 0) { + return MAKE_TOKEN(ERRORTOKEN); + } + } } - - if (c == ':' && cursor == current_tok->curly_bracket_expr_start_depth) { - current_tok->kind = TOK_FSTRING_MODE; - p_start = tok->start; - p_end = tok->cur; - return MAKE_TOKEN(_PyToken_OneChar(c)); - } - } - - /* Check for two-character token */ - { - int c2 = tok_nextc(tok); - int current_token = _PyToken_TwoChars(c, c2); - if (current_token != OP) { - int c3 = tok_nextc(tok); - int current_token3 = _PyToken_ThreeChars(c, c2, c3); - if (current_token3 != OP) { - current_token = current_token3; + if (c == 'e' || c == 'E') { + int e; + exponent: + e = c; + /* Exponent part */ + c = tok_nextc(tok); + if (c == '+' || c == '-') { + c = tok_nextc(tok); + if (!isdigit(c)) { + tok_backup(tok, c); + return MAKE_TOKEN(syntaxerror(tok, "invalid decimal literal")); } - else { - tok_backup(tok, c3); + } else if (!isdigit(c)) { + tok_backup(tok, c); + if (!verify_end_of_number(tok, e, "decimal")) { + return MAKE_TOKEN(ERRORTOKEN); } + tok_backup(tok, e); p_start = tok->start; p_end = tok->cur; - return MAKE_TOKEN(current_token); - } - tok_backup(tok, c2); - } - - /* Keep track of parentheses nesting level */ - switch (c) { - case '(': - case '[': - case '{': - if (tok->level >= MAXLEVEL) { - return MAKE_TOKEN(syntaxerror(tok, "too many nested parentheses")); - } - tok->parenstack[tok->level] = c; - tok->parenlinenostack[tok->level] = tok->lineno; - tok->parencolstack[tok->level] = (int)(tok->start - tok->line_start); - tok->level++; - if (INSIDE_FSTRING(tok)) { - current_tok->curly_bracket_depth++; - } - break; - case ')': - case ']': - case '}': - if (INSIDE_FSTRING(tok) && !current_tok->curly_bracket_depth && c == '}') { - return MAKE_TOKEN(syntaxerror(tok, "f-string: single '}' is not allowed")); - } - if (!tok->tok_extra_tokens && !tok->level) { - return MAKE_TOKEN(syntaxerror(tok, "unmatched '%c'", c)); - } - if (tok->level > 0) { - tok->level--; - int opening = tok->parenstack[tok->level]; - if (!tok->tok_extra_tokens && !((opening == '(' && c == ')') || - (opening == '[' && c == ']') || - (opening == '{' && c == '}'))) { - /* If the opening bracket belongs to an f-string's expression - part (e.g. f"{)}") and the closing bracket is an arbitrary - nested expression, then instead of matching a different - syntactical construct with it; we'll throw an unmatched - parentheses error. */ - if (INSIDE_FSTRING(tok) && opening == '{') { - assert(current_tok->curly_bracket_depth >= 0); - int previous_bracket = current_tok->curly_bracket_depth - 1; - if (previous_bracket == current_tok->curly_bracket_expr_start_depth) { - return MAKE_TOKEN(syntaxerror(tok, "f-string: unmatched '%c'", c)); - } - } - if (tok->parenlinenostack[tok->level] != tok->lineno) { - return MAKE_TOKEN(syntaxerror(tok, - "closing parenthesis '%c' does not match " - "opening parenthesis '%c' on line %d", - c, opening, tok->parenlinenostack[tok->level])); - } - else { - return MAKE_TOKEN(syntaxerror(tok, - "closing parenthesis '%c' does not match " - "opening parenthesis '%c'", - c, opening)); - } - } + return MAKE_TOKEN(NUMBER); + } + c = tok_decimal_tail(tok); + if (c == 0) { + return MAKE_TOKEN(ERRORTOKEN); + } } - - if (INSIDE_FSTRING(tok)) { - current_tok->curly_bracket_depth--; - if (c == '}' && current_tok->curly_bracket_depth == current_tok->curly_bracket_expr_start_depth) { - current_tok->curly_bracket_expr_start_depth--; - current_tok->kind = TOK_FSTRING_MODE; - current_tok->f_string_debug = 0; - } + if (c == 'j' || c == 'J') { + /* Imaginary part */ + imaginary: + c = tok_nextc(tok); + if (!verify_end_of_number(tok, c, "imaginary")) { + return MAKE_TOKEN(ERRORTOKEN); + } + } else if (!verify_end_of_number(tok, c, "decimal")) { + return MAKE_TOKEN(ERRORTOKEN); } - break; - default: - break; - } - - if (!Py_UNICODE_ISPRINTABLE(c)) { - return MAKE_TOKEN(syntaxerror(tok, "invalid non-printable character U+%04X", c)); + } } - - if( c == '=' && INSIDE_FSTRING_EXPR(current_tok)) { - current_tok->f_string_debug = 1; - } - - /* Punctuation character */ + tok_backup(tok, c); p_start = tok->start; p_end = tok->cur; - return MAKE_TOKEN(_PyToken_OneChar(c)); -} - -static int -tok_get_fstring_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct token *token) -{ - const char *p_start = NULL; - const char *p_end = NULL; - int end_quote_size = 0; - int unicode_escape = 0; - - tok->start = tok->cur; + return MAKE_TOKEN(NUMBER); + } + +f_string_quote: + if (((tolower(*tok->start) == 'f' || tolower(*tok->start) == 'r') && + (c == '\'' || c == '"'))) { + int quote = c; + int quote_size = 1; /* 1 or 3 */ + + /* Nodes of type STRING, especially multi line strings + must be handled differently in order to get both + the starting line number and the column offset right. + (cf. issue 16806) */ tok->first_lineno = tok->lineno; - tok->starting_col_offset = tok->col_offset; - - // If we start with a bracket, we defer to the normal mode as there is nothing for us to tokenize - // before it. - int start_char = tok_nextc(tok); - if (start_char == '{') { - int peek1 = tok_nextc(tok); - tok_backup(tok, peek1); - tok_backup(tok, start_char); - if (peek1 != '{') { - current_tok->curly_bracket_expr_start_depth++; - if (current_tok->curly_bracket_expr_start_depth >= MAX_EXPR_NESTING) { - return MAKE_TOKEN(syntaxerror(tok, "f-string: expressions nested too deeply")); - } - TOK_GET_MODE(tok)->kind = TOK_REGULAR_MODE; - return tok_get_normal_mode(tok, current_tok, token); - } - } - else { - tok_backup(tok, start_char); - } + tok->multi_line_start = tok->line_start; - // Check if we are at the end of the string - for (int i = 0; i < current_tok->f_string_quote_size; i++) { - int quote = tok_nextc(tok); - if (quote != current_tok->f_string_quote) { - tok_backup(tok, quote); - goto f_string_middle; - } + /* Find the quote size and start of string */ + int after_quote = tok_nextc(tok); + if (after_quote == quote) { + int after_after_quote = tok_nextc(tok); + if (after_after_quote == quote) { + quote_size = 3; + } else { + // TODO: Check this + tok_backup(tok, after_after_quote); + tok_backup(tok, after_quote); + } } - - if (current_tok->last_expr_buffer != NULL) { - PyMem_Free(current_tok->last_expr_buffer); - current_tok->last_expr_buffer = NULL; - current_tok->last_expr_size = 0; - current_tok->last_expr_end = -1; + if (after_quote != quote) { + tok_backup(tok, after_quote); } p_start = tok->start; p_end = tok->cur; - tok->tok_mode_stack_index--; - return MAKE_TOKEN(FSTRING_END); + if (tok->tok_mode_stack_index + 1 >= MAXFSTRINGLEVEL) { + return MAKE_TOKEN(syntaxerror(tok, "too many nested f-strings")); + } + tokenizer_mode *the_current_tok = TOK_NEXT_MODE(tok); + the_current_tok->kind = TOK_FSTRING_MODE; + the_current_tok->f_string_quote = quote; + the_current_tok->f_string_quote_size = quote_size; + the_current_tok->f_string_start = tok->start; + the_current_tok->f_string_multi_line_start = tok->line_start; + the_current_tok->f_string_line_start = tok->lineno; + the_current_tok->f_string_start_offset = -1; + the_current_tok->f_string_multi_line_start_offset = -1; + the_current_tok->last_expr_buffer = NULL; + the_current_tok->last_expr_size = 0; + the_current_tok->last_expr_end = -1; + the_current_tok->f_string_debug = 0; + + switch (*tok->start) { + case 'F': + case 'f': + the_current_tok->f_string_raw = tolower(*(tok->start + 1)) == 'r'; + break; + case 'R': + case 'r': + the_current_tok->f_string_raw = 1; + break; + default: + Py_UNREACHABLE(); + } -f_string_middle: + the_current_tok->curly_bracket_depth = 0; + the_current_tok->curly_bracket_expr_start_depth = -1; + return MAKE_TOKEN(FSTRING_START); + } - // TODO: This is a bit of a hack, but it works for now. We need to find a better way to handle - // this. - tok->multi_line_start = tok->line_start; - while (end_quote_size != current_tok->f_string_quote_size) { - int c = tok_nextc(tok); - if (tok->done == E_ERROR) { - return MAKE_TOKEN(ERRORTOKEN); - } - int in_format_spec = ( - current_tok->last_expr_end != -1 - && - INSIDE_FSTRING_EXPR(current_tok) - ); - - if (c == EOF || (current_tok->f_string_quote_size == 1 && c == '\n')) { - if (tok->decoding_erred) { - return MAKE_TOKEN(ERRORTOKEN); - } +letter_quote: + /* String */ + if (c == '\'' || c == '"') { + int quote = c; + int quote_size = 1; /* 1 or 3 */ + int end_quote_size = 0; - // If we are in a format spec and we found a newline, - // it means that the format spec ends here and we should - // return to the regular mode. - if (in_format_spec && c == '\n') { - tok_backup(tok, c); - TOK_GET_MODE(tok)->kind = TOK_REGULAR_MODE; - p_start = tok->start; - p_end = tok->cur; - return MAKE_TOKEN(FSTRING_MIDDLE); - } + /* Nodes of type STRING, especially multi line strings + must be handled differently in order to get both + the starting line number and the column offset right. + (cf. issue 16806) */ + tok->first_lineno = tok->lineno; + tok->multi_line_start = tok->line_start; - assert(tok->multi_line_start != NULL); - // shift the tok_state's location into - // the start of string, and report the error - // from the initial quote character - tok->cur = (char *)current_tok->f_string_start; - tok->cur++; - tok->line_start = current_tok->f_string_multi_line_start; - int start = tok->lineno; - - tokenizer_mode *the_current_tok = TOK_GET_MODE(tok); - tok->lineno = the_current_tok->f_string_line_start; - - if (current_tok->f_string_quote_size == 3) { - syntaxerror(tok, - "unterminated triple-quoted f-string literal" - " (detected at line %d)", start); - if (c != '\n') { - tok->done = E_EOFS; - } - return MAKE_TOKEN(ERRORTOKEN); - } - else { - return MAKE_TOKEN(syntaxerror(tok, - "unterminated f-string literal (detected at" - " line %d)", start)); - } - } + /* Find the quote size and start of string */ + c = tok_nextc(tok); + if (c == quote) { + c = tok_nextc(tok); + if (c == quote) { + quote_size = 3; + } else { + end_quote_size = 1; /* empty string found */ + } + } + if (c != quote) { + tok_backup(tok, c); + } + + /* Get rest of string */ + while (end_quote_size != quote_size) { + c = tok_nextc(tok); + if (tok->done == E_ERROR) { + return MAKE_TOKEN(ERRORTOKEN); + } + if (tok->done == E_DECODE) { + break; + } + if (c == EOF || (quote_size == 1 && c == '\n')) { + assert(tok->multi_line_start != NULL); + // shift the tok_state's location into + // the start of string, and report the error + // from the initial quote character + tok->cur = (char *)tok->start; + tok->cur++; + tok->line_start = tok->multi_line_start; + int start = tok->lineno; + tok->lineno = tok->first_lineno; - if (c == current_tok->f_string_quote) { - end_quote_size += 1; - continue; + if (INSIDE_FSTRING(tok)) { + /* When we are in an f-string, before raising the + * unterminated string literal error, check whether + * does the initial quote matches with f-strings quotes + * and if it is, then this must be a missing '}' token + * so raise the proper error */ + tokenizer_mode *the_current_tok = TOK_GET_MODE(tok); + if (the_current_tok->f_string_quote == quote && + the_current_tok->f_string_quote_size == quote_size) { + return MAKE_TOKEN( + syntaxerror(tok, "f-string: expecting '}'", start)); + } + } + + if (quote_size == 3) { + syntaxerror(tok, + "unterminated triple-quoted string literal" + " (detected at line %d)", + start); + if (c != '\n') { + tok->done = E_EOFS; + } + return MAKE_TOKEN(ERRORTOKEN); } else { - end_quote_size = 0; - } - - if (c == '{') { - int peek = tok_nextc(tok); - if (peek != '{' || in_format_spec) { - tok_backup(tok, peek); - tok_backup(tok, c); - current_tok->curly_bracket_expr_start_depth++; - if (current_tok->curly_bracket_expr_start_depth >= MAX_EXPR_NESTING) { - return MAKE_TOKEN(syntaxerror(tok, "f-string: expressions nested too deeply")); - } - TOK_GET_MODE(tok)->kind = TOK_REGULAR_MODE; - p_start = tok->start; - p_end = tok->cur; - } else { - p_start = tok->start; - p_end = tok->cur - 1; - } - return MAKE_TOKEN(FSTRING_MIDDLE); - } else if (c == '}') { - if (unicode_escape) { - p_start = tok->start; - p_end = tok->cur; - return MAKE_TOKEN(FSTRING_MIDDLE); - } - int peek = tok_nextc(tok); - - // The tokenizer can only be in the format spec if we have already completed the expression - // scanning (indicated by the end of the expression being set) and we are not at the top level - // of the bracket stack (-1 is the top level). Since format specifiers can't legally use double - // brackets, we can bypass it here. - if (peek == '}' && !in_format_spec) { - p_start = tok->start; - p_end = tok->cur - 1; - } else { - tok_backup(tok, peek); - tok_backup(tok, c); - TOK_GET_MODE(tok)->kind = TOK_REGULAR_MODE; - p_start = tok->start; - p_end = tok->cur; - } - return MAKE_TOKEN(FSTRING_MIDDLE); - } else if (c == '\\') { - int peek = tok_nextc(tok); - if (peek == '\r') { - peek = tok_nextc(tok); - } - // Special case when the backslash is right before a curly - // brace. We have to restore and return the control back - // to the loop for the next iteration. - if (peek == '{' || peek == '}') { - if (!current_tok->f_string_raw) { - if (warn_invalid_escape_sequence(tok, peek)) { - return MAKE_TOKEN(ERRORTOKEN); - } - } - tok_backup(tok, peek); - continue; - } - - if (!current_tok->f_string_raw) { - if (peek == 'N') { - /* Handle named unicode escapes (\N{BULLET}) */ - peek = tok_nextc(tok); - if (peek == '{') { - unicode_escape = 1; - } else { - tok_backup(tok, peek); - } - } - } /* else { - skip the escaped character - }*/ + syntaxerror(tok, + "unterminated string literal (detected at" + " line %d)", + start); + if (c != '\n') { + tok->done = E_EOLS; + } + return MAKE_TOKEN(ERRORTOKEN); + } + } + if (c == quote) { + end_quote_size += 1; + } else { + end_quote_size = 0; + if (c == '\\') { + c = tok_nextc(tok); /* skip escaped char */ + if (c == '\r') { + c = tok_nextc(tok); + } } + } } - // Backup the f-string quotes to emit a final FSTRING_MIDDLE and - // add the quotes to the FSTRING_END in the next tokenizer iteration. - for (int i = 0; i < current_tok->f_string_quote_size; i++) { - tok_backup(tok, current_tok->f_string_quote); - } p_start = tok->start; p_end = tok->cur; - return MAKE_TOKEN(FSTRING_MIDDLE); -} + return MAKE_TOKEN(STRING); + } + + /* Line continuation */ + if (c == '\\') { + if ((c = tok_continuation_line(tok)) == -1) { + return MAKE_TOKEN(ERRORTOKEN); + } + tok->cont_line = 1; + goto again; /* Read next line */ + } + + /* Punctuation character */ + int is_punctuation = (c == ':' || c == '}' || c == '!' || c == '{'); + if (is_punctuation && INSIDE_FSTRING(tok) && + INSIDE_FSTRING_EXPR(current_tok)) { + /* This code block gets executed before the curly_bracket_depth is + * incremented by the `{` case, so for ensuring that we are on the 0th + * level, we need to adjust it manually */ + int cursor = current_tok->curly_bracket_depth - (c != '{'); + int in_format_spec = current_tok->in_format_spec; + int cursor_in_format_with_debug = + cursor == 1 && (current_tok->f_string_debug || in_format_spec); + int cursor_valid = cursor == 0 || cursor_in_format_with_debug; + if (cursor_valid && !update_fstring_expr(tok, c)) { + return MAKE_TOKEN(ENDMARKER); + } + if (cursor_valid && c != '{' && set_fstring_expr(tok, token, c)) { + return MAKE_TOKEN(ERRORTOKEN); + } + + if (c == ':' && cursor == current_tok->curly_bracket_expr_start_depth) { + current_tok->kind = TOK_FSTRING_MODE; + current_tok->in_format_spec = 1; + p_start = tok->start; + p_end = tok->cur; + return MAKE_TOKEN(_PyToken_OneChar(c)); + } + } + + /* Check for two-character token */ + { + int c2 = tok_nextc(tok); + int current_token = _PyToken_TwoChars(c, c2); + if (current_token != OP) { + int c3 = tok_nextc(tok); + int current_token3 = _PyToken_ThreeChars(c, c2, c3); + if (current_token3 != OP) { + current_token = current_token3; + } else { + tok_backup(tok, c3); + } + p_start = tok->start; + p_end = tok->cur; + return MAKE_TOKEN(current_token); + } + tok_backup(tok, c2); + } + + /* Keep track of parentheses nesting level */ + switch (c) { + case '(': + case '[': + case '{': + if (tok->level >= MAXLEVEL) { + return MAKE_TOKEN(syntaxerror(tok, "too many nested parentheses")); + } + tok->parenstack[tok->level] = c; + tok->parenlinenostack[tok->level] = tok->lineno; + tok->parencolstack[tok->level] = (int)(tok->start - tok->line_start); + tok->level++; + if (INSIDE_FSTRING(tok)) { + current_tok->curly_bracket_depth++; + } + break; + case ')': + case ']': + case '}': + if (INSIDE_FSTRING(tok) && !current_tok->curly_bracket_depth && c == '}') { + return MAKE_TOKEN( + syntaxerror(tok, "f-string: single '}' is not allowed")); + } + if (!tok->tok_extra_tokens && !tok->level) { + return MAKE_TOKEN(syntaxerror(tok, "unmatched '%c'", c)); + } + if (tok->level > 0) { + tok->level--; + int opening = tok->parenstack[tok->level]; + if (!tok->tok_extra_tokens && + !((opening == '(' && c == ')') || (opening == '[' && c == ']') || + (opening == '{' && c == '}'))) { + /* If the opening bracket belongs to an f-string's expression + part (e.g. f"{)}") and the closing bracket is an arbitrary + nested expression, then instead of matching a different + syntactical construct with it; we'll throw an unmatched + parentheses error. */ + if (INSIDE_FSTRING(tok) && opening == '{') { + assert(current_tok->curly_bracket_depth >= 0); + int previous_bracket = current_tok->curly_bracket_depth - 1; + if (previous_bracket == current_tok->curly_bracket_expr_start_depth) { + return MAKE_TOKEN(syntaxerror(tok, "f-string: unmatched '%c'", c)); + } + } + if (tok->parenlinenostack[tok->level] != tok->lineno) { + return MAKE_TOKEN( + syntaxerror(tok, + "closing parenthesis '%c' does not match " + "opening parenthesis '%c' on line %d", + c, opening, tok->parenlinenostack[tok->level])); + } else { + return MAKE_TOKEN( + syntaxerror(tok, + "closing parenthesis '%c' does not match " + "opening parenthesis '%c'", + c, opening)); + } + } + } + + if (INSIDE_FSTRING(tok)) { + current_tok->curly_bracket_depth--; + if (current_tok->curly_bracket_depth < 0) { + return MAKE_TOKEN(syntaxerror(tok, "f-string: unmatched '%c'", c)); + } + if (c == '}' && current_tok->curly_bracket_depth == + current_tok->curly_bracket_expr_start_depth) { + current_tok->curly_bracket_expr_start_depth--; + current_tok->kind = TOK_FSTRING_MODE; + current_tok->in_format_spec = 0; + current_tok->f_string_debug = 0; + } + } + break; + default: + break; + } + + if (!Py_UNICODE_ISPRINTABLE(c)) { + return MAKE_TOKEN( + syntaxerror(tok, "invalid non-printable character U+%04X", c)); + } + + if (c == '=' && INSIDE_FSTRING_EXPR(current_tok)) { + current_tok->f_string_debug = 1; + } + + /* Punctuation character */ + p_start = tok->start; + p_end = tok->cur; + return MAKE_TOKEN(_PyToken_OneChar(c)); +} + +static int tok_get_fstring_mode(struct tok_state *tok, + tokenizer_mode *current_tok, + struct token *token) { + const char *p_start = NULL; + const char *p_end = NULL; + int end_quote_size = 0; + int unicode_escape = 0; + + tok->start = tok->cur; + tok->first_lineno = tok->lineno; + tok->starting_col_offset = tok->col_offset; + + // If we start with a bracket, we defer to the normal mode as there is nothing + // for us to tokenize before it. + int start_char = tok_nextc(tok); + if (start_char == '{') { + int peek1 = tok_nextc(tok); + tok_backup(tok, peek1); + tok_backup(tok, start_char); + if (peek1 != '{') { + current_tok->curly_bracket_expr_start_depth++; + if (current_tok->curly_bracket_expr_start_depth >= MAX_EXPR_NESTING) { + return MAKE_TOKEN( + syntaxerror(tok, "f-string: expressions nested too deeply")); + } + TOK_GET_MODE(tok)->kind = TOK_REGULAR_MODE; + return tok_get_normal_mode(tok, current_tok, token); + } + } else { + tok_backup(tok, start_char); + } + + // Check if we are at the end of the string + for (int i = 0; i < current_tok->f_string_quote_size; i++) { + int quote = tok_nextc(tok); + if (quote != current_tok->f_string_quote) { + tok_backup(tok, quote); + goto f_string_middle; + } + } + + if (current_tok->last_expr_buffer != NULL) { + PyMem_Free(current_tok->last_expr_buffer); + current_tok->last_expr_buffer = NULL; + current_tok->last_expr_size = 0; + current_tok->last_expr_end = -1; + } + + p_start = tok->start; + p_end = tok->cur; + tok->tok_mode_stack_index--; + return MAKE_TOKEN(FSTRING_END); +f_string_middle: -static int -tok_get(struct tok_state *tok, struct token *token) -{ - tokenizer_mode *current_tok = TOK_GET_MODE(tok); - if (current_tok->kind == TOK_REGULAR_MODE) { - return tok_get_normal_mode(tok, current_tok, token); - } else { - return tok_get_fstring_mode(tok, current_tok, token); + // TODO: This is a bit of a hack, but it works for now. We need to find a + // better way to handle this. + tok->multi_line_start = tok->line_start; + while (end_quote_size != current_tok->f_string_quote_size) { + int c = tok_nextc(tok); + if (tok->done == E_ERROR || tok->done == E_DECODE) { + return MAKE_TOKEN(ERRORTOKEN); } -} + int in_format_spec = + (current_tok->in_format_spec && INSIDE_FSTRING_EXPR(current_tok)); -int -_PyTokenizer_Get(struct tok_state *tok, struct token *token) -{ - int result = tok_get(tok, token); - if (tok->decoding_erred) { - result = ERRORTOKEN; - tok->done = E_DECODE; + if (c == EOF || (current_tok->f_string_quote_size == 1 && c == '\n')) { + if (tok->decoding_erred) { + return MAKE_TOKEN(ERRORTOKEN); + } + + // If we are in a format spec and we found a newline, + // it means that the format spec ends here and we should + // return to the regular mode. + if (in_format_spec && c == '\n') { + tok_backup(tok, c); + TOK_GET_MODE(tok)->kind = TOK_REGULAR_MODE; + current_tok->in_format_spec = 0; + p_start = tok->start; + p_end = tok->cur; + return MAKE_TOKEN(FSTRING_MIDDLE); + } + + assert(tok->multi_line_start != NULL); + // shift the tok_state's location into + // the start of string, and report the error + // from the initial quote character + tok->cur = (char *)current_tok->f_string_start; + tok->cur++; + tok->line_start = current_tok->f_string_multi_line_start; + int start = tok->lineno; + + tokenizer_mode *the_current_tok = TOK_GET_MODE(tok); + tok->lineno = the_current_tok->f_string_line_start; + + if (current_tok->f_string_quote_size == 3) { + syntaxerror(tok, + "unterminated triple-quoted f-string literal" + " (detected at line %d)", + start); + if (c != '\n') { + tok->done = E_EOFS; + } + return MAKE_TOKEN(ERRORTOKEN); + } else { + return MAKE_TOKEN( + syntaxerror(tok, + "unterminated f-string literal (detected at" + " line %d)", + start)); + } + } + + if (c == current_tok->f_string_quote) { + end_quote_size += 1; + continue; + } else { + end_quote_size = 0; } - return result; + + if (c == '{') { + if (!update_fstring_expr(tok, c)) { + return MAKE_TOKEN(ENDMARKER); + } + int peek = tok_nextc(tok); + if (peek != '{' || in_format_spec) { + tok_backup(tok, peek); + tok_backup(tok, c); + current_tok->curly_bracket_expr_start_depth++; + if (current_tok->curly_bracket_expr_start_depth >= MAX_EXPR_NESTING) { + return MAKE_TOKEN( + syntaxerror(tok, "f-string: expressions nested too deeply")); + } + TOK_GET_MODE(tok)->kind = TOK_REGULAR_MODE; + current_tok->in_format_spec = 0; + p_start = tok->start; + p_end = tok->cur; + } else { + p_start = tok->start; + p_end = tok->cur - 1; + } + return MAKE_TOKEN(FSTRING_MIDDLE); + } else if (c == '}') { + if (unicode_escape) { + p_start = tok->start; + p_end = tok->cur; + return MAKE_TOKEN(FSTRING_MIDDLE); + } + int peek = tok_nextc(tok); + + // The tokenizer can only be in the format spec if we have already + // completed the expression scanning (indicated by the end of the + // expression being set) and we are not at the top level of the bracket + // stack (-1 is the top level). Since format specifiers can't legally use + // double brackets, we can bypass it here. + int cursor = current_tok->curly_bracket_depth; + if (peek == '}' && !in_format_spec && cursor == 0) { + p_start = tok->start; + p_end = tok->cur - 1; + } else { + tok_backup(tok, peek); + tok_backup(tok, c); + TOK_GET_MODE(tok)->kind = TOK_REGULAR_MODE; + p_start = tok->start; + p_end = tok->cur; + } + return MAKE_TOKEN(FSTRING_MIDDLE); + } else if (c == '\\') { + int peek = tok_nextc(tok); + if (peek == '\r') { + peek = tok_nextc(tok); + } + // Special case when the backslash is right before a curly + // brace. We have to restore and return the control back + // to the loop for the next iteration. + if (peek == '{' || peek == '}') { + if (!current_tok->f_string_raw) { + if (warn_invalid_escape_sequence(tok, peek)) { + return MAKE_TOKEN(ERRORTOKEN); + } + } + tok_backup(tok, peek); + continue; + } + + if (!current_tok->f_string_raw) { + if (peek == 'N') { + /* Handle named unicode escapes (\N{BULLET}) */ + peek = tok_nextc(tok); + if (peek == '{') { + unicode_escape = 1; + } else { + tok_backup(tok, peek); + } + } + } /* else { + skip the escaped character + }*/ + } + } + + // Backup the f-string quotes to emit a final FSTRING_MIDDLE and + // add the quotes to the FSTRING_END in the next tokenizer iteration. + for (int i = 0; i < current_tok->f_string_quote_size; i++) { + tok_backup(tok, current_tok->f_string_quote); + } + p_start = tok->start; + p_end = tok->cur; + return MAKE_TOKEN(FSTRING_MIDDLE); +} + +static int tok_get(struct tok_state *tok, struct token *token) { + tokenizer_mode *current_tok = TOK_GET_MODE(tok); + if (current_tok->kind == TOK_REGULAR_MODE) { + return tok_get_normal_mode(tok, current_tok, token); + } else { + return tok_get_fstring_mode(tok, current_tok, token); + } +} + +int _PyTokenizer_Get(struct tok_state *tok, struct token *token) { + int result = tok_get(tok, token); + if (tok->decoding_erred) { + result = ERRORTOKEN; + tok->done = E_DECODE; + } + return result; } -#if defined(__wasi__) || (defined(__EMSCRIPTEN__) && (__EMSCRIPTEN_major__ >= 3)) +#if defined(__wasi__) || \ + (defined(__EMSCRIPTEN__) && (__EMSCRIPTEN_major__ >= 3)) // fdopen() with borrowed fd. WASI does not provide dup() and Emscripten's // dup() emulation with open() is slow. typedef union { - void *cookie; - int fd; + void *cookie; + int fd; } borrowed; -static ssize_t -borrow_read(void *cookie, char *buf, size_t size) -{ - borrowed b = {.cookie = cookie}; - return read(b.fd, (void *)buf, size); +static ssize_t borrow_read(void *cookie, char *buf, size_t size) { + borrowed b = {.cookie = cookie}; + return read(b.fd, (void *)buf, size); } -static FILE * -fdopen_borrow(int fd) { - // supports only reading. seek fails. close and write are no-ops. - cookie_io_functions_t io_cb = {borrow_read, NULL, NULL, NULL}; - borrowed b = {.fd = fd}; - return fopencookie(b.cookie, "r", io_cb); +static FILE *fdopen_borrow(int fd) { + // supports only reading. seek fails. close and write are no-ops. + cookie_io_functions_t io_cb = {borrow_read, NULL, NULL, NULL}; + borrowed b = {.fd = fd}; + return fopencookie(b.cookie, "r", io_cb); } #else -static FILE * -fdopen_borrow(int fd) { - fd = _Py_dup(fd); - if (fd < 0) { - return NULL; - } - return fdopen(fd, "r"); +static FILE *fdopen_borrow(int fd) { + fd = _Py_dup(fd); + if (fd < 0) { + return NULL; + } + return fdopen(fd, "r"); } #endif @@ -3023,59 +2907,54 @@ fdopen_borrow(int fd) { The char* returned is malloc'ed via PyMem_Malloc() and thus must be freed by the caller. */ -char * -_PyTokenizer_FindEncodingFilename(int fd, PyObject *filename) -{ - struct tok_state *tok; - FILE *fp; - char *encoding = NULL; - - fp = fdopen_borrow(fd); - if (fp == NULL) { - return NULL; - } - tok = _PyTokenizer_FromFile(fp, NULL, NULL, NULL); - if (tok == NULL) { - fclose(fp); - return NULL; - } - if (filename != NULL) { - tok->filename = Py_NewRef(filename); - } - else { - tok->filename = PyUnicode_FromString(""); - if (tok->filename == NULL) { - fclose(fp); - _PyTokenizer_Free(tok); - return encoding; - } - } - struct token token; - // We don't want to report warnings here because it could cause infinite recursion - // if fetching the encoding shows a warning. - tok->report_warnings = 0; - while (tok->lineno < 2 && tok->done == E_OK) { - _PyToken_Init(&token); - _PyTokenizer_Get(tok, &token); - _PyToken_Free(&token); - } +char *_PyTokenizer_FindEncodingFilename(int fd, PyObject *filename) { + struct tok_state *tok; + FILE *fp; + char *encoding = NULL; + + fp = fdopen_borrow(fd); + if (fp == NULL) { + return NULL; + } + tok = _PyTokenizer_FromFile(fp, NULL, NULL, NULL); + if (tok == NULL) { fclose(fp); - if (tok->encoding) { - encoding = (char *)PyMem_Malloc(strlen(tok->encoding) + 1); - if (encoding) { - strcpy(encoding, tok->encoding); - } - } - _PyTokenizer_Free(tok); - return encoding; + return NULL; + } + if (filename != NULL) { + tok->filename = Py_NewRef(filename); + } else { + tok->filename = PyUnicode_FromString(""); + if (tok->filename == NULL) { + fclose(fp); + _PyTokenizer_Free(tok); + return encoding; + } + } + struct token token; + // We don't want to report warnings here because it could cause infinite + // recursion if fetching the encoding shows a warning. + tok->report_warnings = 0; + while (tok->lineno < 2 && tok->done == E_OK) { + _PyToken_Init(&token); + _PyTokenizer_Get(tok, &token); + _PyToken_Free(&token); + } + fclose(fp); + if (tok->encoding) { + encoding = (char *)PyMem_Malloc(strlen(tok->encoding) + 1); + if (encoding) { + strcpy(encoding, tok->encoding); + } + } + _PyTokenizer_Free(tok); + return encoding; } #ifdef Py_DEBUG -void -tok_dump(int type, char *start, char *end) -{ - fprintf(stderr, "%s", _PyParser_TokenNames[type]); - if (type == NAME || type == NUMBER || type == STRING || type == OP) - fprintf(stderr, "(%.*s)", (int)(end - start), start); +void tok_dump(int type, char *start, char *end) { + fprintf(stderr, "%s", _PyParser_TokenNames[type]); + if (type == NAME || type == NUMBER || type == STRING || type == OP) + fprintf(stderr, "(%.*s)", (int)(end - start), start); } -#endif // Py_DEBUG +#endif // Py_DEBUG diff --git a/Parser/tokenizer.h b/Parser/tokenizer.h index 1e1daa36..4eeeb1f2 100644 --- a/Parser/tokenizer.h +++ b/Parser/tokenizer.h @@ -14,133 +14,136 @@ extern "C" { #define MAXLEVEL 200 /* Max parentheses level */ #define MAXFSTRINGLEVEL 150 /* Max f-string nesting level */ -enum decoding_state { - STATE_INIT, - STATE_SEEK_CODING, - STATE_NORMAL -}; +enum decoding_state { STATE_INIT, STATE_SEEK_CODING, STATE_NORMAL }; enum interactive_underflow_t { - /* Normal mode of operation: return a new token when asked in interactive mode */ - IUNDERFLOW_NORMAL, - /* Forcefully return ENDMARKER when asked for a new token in interactive mode. This - * can be used to prevent the tokenizer to prompt the user for new tokens */ - IUNDERFLOW_STOP, + /* Normal mode of operation: return a new token when asked in interactive mode + */ + IUNDERFLOW_NORMAL, + /* Forcefully return ENDMARKER when asked for a new token in interactive mode. + * This can be used to prevent the tokenizer to prompt the user for new tokens + */ + IUNDERFLOW_STOP, }; struct token { - int level; - int lineno, col_offset, end_lineno, end_col_offset; - const char *start, *end; - PyObject *metadata; + int level; + int lineno, col_offset, end_lineno, end_col_offset; + const char *start, *end; + PyObject *metadata; }; enum tokenizer_mode_kind_t { - TOK_REGULAR_MODE, - TOK_FSTRING_MODE, + TOK_REGULAR_MODE, + TOK_FSTRING_MODE, }; #define MAX_EXPR_NESTING 3 typedef struct _tokenizer_mode { - enum tokenizer_mode_kind_t kind; - - int curly_bracket_depth; - int curly_bracket_expr_start_depth; - - char f_string_quote; - int f_string_quote_size; - int f_string_raw; - const char* f_string_start; - const char* f_string_multi_line_start; - int f_string_line_start; - - Py_ssize_t f_string_start_offset; - Py_ssize_t f_string_multi_line_start_offset; - - Py_ssize_t last_expr_size; - Py_ssize_t last_expr_end; - char* last_expr_buffer; - int f_string_debug; + enum tokenizer_mode_kind_t kind; + + int curly_bracket_depth; + int curly_bracket_expr_start_depth; + + char f_string_quote; + int f_string_quote_size; + int f_string_raw; + const char *f_string_start; + const char *f_string_multi_line_start; + int f_string_line_start; + + Py_ssize_t f_string_start_offset; + Py_ssize_t f_string_multi_line_start_offset; + + Py_ssize_t last_expr_size; + Py_ssize_t last_expr_end; + char *last_expr_buffer; + int f_string_debug; + int in_format_spec; } tokenizer_mode; /* Tokenizer state */ struct tok_state { - /* Input state; buf <= cur <= inp <= end */ - /* NB an entire line is held in the buffer */ - char *buf; /* Input buffer, or NULL; malloc'ed if fp != NULL or readline != NULL */ - char *cur; /* Next character in buffer */ - char *inp; /* End of data in buffer */ - int fp_interactive; /* If the file descriptor is interactive */ - char *interactive_src_start; /* The start of the source parsed so far in interactive mode */ - char *interactive_src_end; /* The end of the source parsed so far in interactive mode */ - const char *end; /* End of input buffer if buf != NULL */ - const char *start; /* Start of current token if not NULL */ - int done; /* E_OK normally, E_EOF at EOF, otherwise error code */ - /* NB If done != E_OK, cur must be == inp!!! */ - FILE *fp; /* Rest of input; NULL if tokenizing a string */ - int tabsize; /* Tab spacing */ - int indent; /* Current indentation index */ - int indstack[MAXINDENT]; /* Stack of indents */ - int atbol; /* Nonzero if at begin of new line */ - int pendin; /* Pending indents (if > 0) or dedents (if < 0) */ - const char *prompt, *nextprompt; /* For interactive prompting */ - int lineno; /* Current line number */ - int first_lineno; /* First line of a single line or multi line string - expression (cf. issue 16806) */ - int starting_col_offset; /* The column offset at the beginning of a token */ - int col_offset; /* Current col offset */ - int level; /* () [] {} Parentheses nesting level */ - /* Used to allow free continuations inside them */ - char parenstack[MAXLEVEL]; - int parenlinenostack[MAXLEVEL]; - int parencolstack[MAXLEVEL]; - PyObject *filename; - /* Stuff for checking on different tab sizes */ - int altindstack[MAXINDENT]; /* Stack of alternate indents */ - /* Stuff for PEP 0263 */ - enum decoding_state decoding_state; - int decoding_erred; /* whether erred in decoding */ - char *encoding; /* Source encoding. */ - int cont_line; /* whether we are in a continuation line. */ - const char* line_start; /* pointer to start of current line */ - const char* multi_line_start; /* pointer to start of first line of - a single line or multi line string - expression (cf. issue 16806) */ - PyObject *decoding_readline; /* open(...).readline */ - PyObject *decoding_buffer; - PyObject *readline; /* readline() function */ - const char* enc; /* Encoding for the current str. */ - char* str; /* Source string being tokenized (if tokenizing from a string)*/ - char* input; /* Tokenizer's newline translated copy of the string. */ - - int type_comments; /* Whether to look for type comments */ - - /* async/await related fields (still needed depending on feature_version) */ - int async_hacks; /* =1 if async/await aren't always keywords */ - int async_def; /* =1 if tokens are inside an 'async def' body. */ - int async_def_indent; /* Indentation level of the outermost 'async def'. */ - int async_def_nl; /* =1 if the outermost 'async def' had at least one - NEWLINE token after it. */ - /* How to proceed when asked for a new token in interactive mode */ - enum interactive_underflow_t interactive_underflow; - int report_warnings; - // TODO: Factor this into its own thing - tokenizer_mode tok_mode_stack[MAXFSTRINGLEVEL]; - int tok_mode_stack_index; - int tok_extra_tokens; - int comment_newline; - int implicit_newline; + /* Input state; buf <= cur <= inp <= end */ + /* NB an entire line is held in the buffer */ + char *buf; /* Input buffer, or NULL; malloc'ed if fp != NULL or readline != + NULL */ + char *cur; /* Next character in buffer */ + char *inp; /* End of data in buffer */ + int fp_interactive; /* If the file descriptor is interactive */ + char *interactive_src_start; /* The start of the source parsed so far in + interactive mode */ + char *interactive_src_end; /* The end of the source parsed so far in + interactive mode */ + const char *end; /* End of input buffer if buf != NULL */ + const char *start; /* Start of current token if not NULL */ + int done; /* E_OK normally, E_EOF at EOF, otherwise error code */ + /* NB If done != E_OK, cur must be == inp!!! */ + FILE *fp; /* Rest of input; NULL if tokenizing a string */ + int tabsize; /* Tab spacing */ + int indent; /* Current indentation index */ + int indstack[MAXINDENT]; /* Stack of indents */ + int atbol; /* Nonzero if at begin of new line */ + int pendin; /* Pending indents (if > 0) or dedents (if < 0) */ + const char *prompt, *nextprompt; /* For interactive prompting */ + int lineno; /* Current line number */ + int first_lineno; /* First line of a single line or multi line string + expression (cf. issue 16806) */ + int starting_col_offset; /* The column offset at the beginning of a token */ + int col_offset; /* Current col offset */ + int level; /* () [] {} Parentheses nesting level */ + /* Used to allow free continuations inside them */ + char parenstack[MAXLEVEL]; + int parenlinenostack[MAXLEVEL]; + int parencolstack[MAXLEVEL]; + PyObject *filename; + /* Stuff for checking on different tab sizes */ + int altindstack[MAXINDENT]; /* Stack of alternate indents */ + /* Stuff for PEP 0263 */ + enum decoding_state decoding_state; + int decoding_erred; /* whether erred in decoding */ + char *encoding; /* Source encoding. */ + int cont_line; /* whether we are in a continuation line. */ + const char *line_start; /* pointer to start of current line */ + const char *multi_line_start; /* pointer to start of first line of + a single line or multi line string + expression (cf. issue 16806) */ + PyObject *decoding_readline; /* open(...).readline */ + PyObject *decoding_buffer; + PyObject *readline; /* readline() function */ + const char *enc; /* Encoding for the current str. */ + char *str; /* Source string being tokenized (if tokenizing from a string)*/ + char *input; /* Tokenizer's newline translated copy of the string. */ + + int type_comments; /* Whether to look for type comments */ + + /* async/await related fields (still needed depending on feature_version) */ + int async_hacks; /* =1 if async/await aren't always keywords */ + int async_def; /* =1 if tokens are inside an 'async def' body. */ + int async_def_indent; /* Indentation level of the outermost 'async def'. */ + int async_def_nl; /* =1 if the outermost 'async def' had at least one + NEWLINE token after it. */ + /* How to proceed when asked for a new token in interactive mode */ + enum interactive_underflow_t interactive_underflow; + int report_warnings; + // TODO: Factor this into its own thing + tokenizer_mode tok_mode_stack[MAXFSTRINGLEVEL]; + int tok_mode_stack_index; + int tok_extra_tokens; + int comment_newline; + int implicit_newline; #ifdef Py_DEBUG - int debug; + int debug; #endif }; extern struct tok_state *_PyTokenizer_FromString(const char *, int, int); extern struct tok_state *_PyTokenizer_FromUTF8(const char *, int, int); -extern struct tok_state *_PyTokenizer_FromReadline(PyObject*, const char*, int, int); -extern struct tok_state *_PyTokenizer_FromFile(FILE *, const char*, - const char *, const char *); +extern struct tok_state *_PyTokenizer_FromReadline(PyObject *, const char *, + int, int); +extern struct tok_state *_PyTokenizer_FromFile(FILE *, const char *, + const char *, const char *); extern void _PyTokenizer_Free(struct tok_state *); extern void _PyToken_Free(struct token *); extern void _PyToken_Init(struct token *); diff --git a/Programs/_freeze_module.c b/Programs/_freeze_module.c index e55f1d56..c669d96c 100644 --- a/Programs/_freeze_module.c +++ b/Programs/_freeze_module.c @@ -123,6 +123,9 @@ static PyObject * compile_and_marshal(const char *name, const char *text) { char *filename = (char *) malloc(strlen(name) + 10); + if (filename == NULL) { + return PyErr_NoMemory(); + } sprintf(filename, "", name); PyObject *code = Py_CompileStringExFlags(text, filename, Py_file_input, NULL, 0); @@ -146,6 +149,9 @@ get_varname(const char *name, const char *prefix) { size_t n = strlen(prefix); char *varname = (char *) malloc(strlen(name) + n + 1); + if (varname == NULL) { + return NULL; + } (void)strcpy(varname, prefix); for (size_t i = 0; name[i] != '\0'; i++) { if (name[i] == '.') { @@ -191,6 +197,11 @@ write_frozen(const char *outpath, const char *inpath, const char *name, fprintf(outfile, "%s\n", header); char *arrayname = get_varname(name, "_Py_M__"); + if (arrayname == NULL) { + fprintf(stderr, "memory error: could not allocate varname\n"); + fclose(outfile); + return -1; + } write_code(outfile, marshalled, arrayname); free(arrayname); diff --git a/Programs/_testembed.c b/Programs/_testembed.c index f78ba41f..1386153a 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -163,15 +163,23 @@ PyInit_embedded_ext(void) static int test_repeated_init_exec(void) { if (main_argc < 3) { - fprintf(stderr, "usage: %s test_repeated_init_exec CODE\n", PROGRAM); + fprintf(stderr, + "usage: %s test_repeated_init_exec CODE ...\n", PROGRAM); exit(1); } const char *code = main_argv[2]; + int loops = main_argc > 3 + ? main_argc - 2 + : INIT_LOOPS; - for (int i=1; i <= INIT_LOOPS; i++) { - fprintf(stderr, "--- Loop #%d ---\n", i); + for (int i=0; i < loops; i++) { + fprintf(stderr, "--- Loop #%d ---\n", i+1); fflush(stderr); + if (main_argc > 3) { + code = main_argv[i+2]; + } + _testembed_Py_InitializeFromConfig(); int err = PyRun_SimpleString(code); Py_Finalize(); diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index cd9d1032..17a87d9a 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -26,13 +26,12 @@ unsigned char M_test_frozenmain[] = { 103,101,116,95,99,111,110,102,105,103,115,114,3,0,0,0, 218,3,107,101,121,169,0,243,0,0,0,0,250,18,116,101, 115,116,95,102,114,111,122,101,110,109,97,105,110,46,112,121, - 250,8,60,109,111,100,117,108,101,62,114,18,0,0,0,1, - 0,0,0,115,102,0,0,0,240,3,1,1,1,243,8,0, + 218,8,60,109,111,100,117,108,101,62,114,18,0,0,0,1, + 0,0,0,115,97,0,0,0,240,3,1,1,1,243,8,0, 1,11,219,0,24,225,0,5,208,6,26,212,0,27,217,0, 5,128,106,144,35,151,40,145,40,212,0,27,216,9,38,208, 9,26,215,9,38,209,9,38,211,9,40,168,24,209,9,50, - 128,6,240,2,6,12,2,242,0,7,1,42,128,67,241,14, - 0,5,10,136,71,144,67,144,53,152,2,152,54,160,35,153, - 59,152,45,208,10,40,213,4,41,241,15,7,1,42,114,16, - 0,0,0, + 128,6,243,2,6,12,2,128,67,241,14,0,5,10,136,71, + 144,67,144,53,152,2,152,54,160,35,153,59,152,45,208,10, + 40,213,4,41,241,15,6,12,2,114,16,0,0,0, }; diff --git a/Python/Python-ast.c b/Python/Python-ast.c index ecaff204..3d5aeff8 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -863,14 +863,15 @@ ast_type_init(PyObject *self, PyObject *args, PyObject *kw) Py_ssize_t i, numfields = 0; int res = -1; PyObject *key, *value, *fields; - if (_PyObject_LookupAttr((PyObject*)Py_TYPE(self), state->_fields, &fields) < 0) { + + fields = PyObject_GetAttr((PyObject*)Py_TYPE(self), state->_fields); + if (fields == NULL) { goto cleanup; } - if (fields) { - numfields = PySequence_Size(fields); - if (numfields == -1) { - goto cleanup; - } + + numfields = PySequence_Size(fields); + if (numfields == -1) { + goto cleanup; } res = 0; /* if no error occurs, this stays 0 to the end */ diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c index 664e7d8a..baad836d 100644 --- a/Python/Python-tokenize.c +++ b/Python/Python-tokenize.c @@ -35,6 +35,7 @@ typedef struct /* Needed to cache line for performance */ PyObject *last_line; Py_ssize_t last_lineno; + Py_ssize_t last_end_lineno; Py_ssize_t byte_col_offset_diff; } tokenizeriterobject; @@ -76,6 +77,7 @@ tokenizeriter_new_impl(PyTypeObject *type, PyObject *readline, self->last_line = NULL; self->byte_col_offset_diff = 0; self->last_lineno = 0; + self->last_end_lineno = 0; return (PyObject *)self; } @@ -212,6 +214,7 @@ tokenizeriter_next(tokenizeriterobject *it) const char *line_start = ISSTRINGLIT(type) ? it->tok->multi_line_start : it->tok->line_start; PyObject* line = NULL; + int line_changed = 1; if (it->tok->tok_extra_tokens && is_trailing_token) { line = PyUnicode_FromString(""); } else { @@ -230,6 +233,7 @@ tokenizeriter_next(tokenizeriterobject *it) } else { // Line hasn't changed so we reuse the cached one. line = it->last_line; + line_changed = 0; } } if (line == NULL) { @@ -240,13 +244,20 @@ tokenizeriter_next(tokenizeriterobject *it) Py_ssize_t lineno = ISSTRINGLIT(type) ? it->tok->first_lineno : it->tok->lineno; Py_ssize_t end_lineno = it->tok->lineno; it->last_lineno = lineno; + it->last_end_lineno = end_lineno; Py_ssize_t col_offset = -1; Py_ssize_t end_col_offset = -1; Py_ssize_t byte_offset = -1; if (token.start != NULL && token.start >= line_start) { byte_offset = token.start - line_start; - col_offset = byte_offset - it->byte_col_offset_diff; + if (line_changed) { + col_offset = _PyPegen_byte_offset_to_character_offset_line(line, 0, byte_offset); + it->byte_col_offset_diff = byte_offset - col_offset; + } + else { + col_offset = byte_offset - it->byte_col_offset_diff; + } } if (token.end != NULL && token.end >= it->tok->line_start) { Py_ssize_t end_byte_offset = token.end - it->tok->line_start; diff --git a/Python/ast_opt.c b/Python/ast_opt.c index e881b7fe..e8a53786 100644 --- a/Python/ast_opt.c +++ b/Python/ast_opt.c @@ -275,10 +275,9 @@ parse_literal(PyObject *fmt, Py_ssize_t *ppos, PyArena *arena) PyObject *str = PyUnicode_Substring(fmt, start, pos); /* str = str.replace('%%', '%') */ if (str && has_percents) { - _Py_DECLARE_STR(percent, "%"); _Py_DECLARE_STR(dbl_percent, "%%"); Py_SETREF(str, PyUnicode_Replace(str, &_Py_STR(dbl_percent), - &_Py_STR(percent), -1)); + _Py_LATIN1_CHR('%'), -1)); } if (!str) { return NULL; diff --git a/Python/ast_unparse.c b/Python/ast_unparse.c index 8aff0451..10e9d9b7 100644 --- a/Python/ast_unparse.c +++ b/Python/ast_unparse.c @@ -10,9 +10,7 @@ * See ast.unparse for a full unparser (written in Python) */ -_Py_DECLARE_STR(open_br, "{"); _Py_DECLARE_STR(dbl_open_br, "{{"); -_Py_DECLARE_STR(close_br, "}"); _Py_DECLARE_STR(dbl_close_br, "}}"); /* We would statically initialize this if doing so were simple enough. */ @@ -580,11 +578,13 @@ escape_braces(PyObject *orig) { PyObject *temp; PyObject *result; - temp = PyUnicode_Replace(orig, &_Py_STR(open_br), &_Py_STR(dbl_open_br), -1); + temp = PyUnicode_Replace(orig, _Py_LATIN1_CHR('{'), + &_Py_STR(dbl_open_br), -1); if (!temp) { return NULL; } - result = PyUnicode_Replace(temp, &_Py_STR(close_br), &_Py_STR(dbl_close_br), -1); + result = PyUnicode_Replace(temp, _Py_LATIN1_CHR('}'), + &_Py_STR(dbl_close_br), -1); Py_DECREF(temp); return result; } @@ -678,7 +678,7 @@ append_formattedvalue(_PyUnicodeWriter *writer, expr_ty e) if (!temp_fv_str) { return -1; } - if (PyUnicode_Find(temp_fv_str, &_Py_STR(open_br), 0, 1, 1) == 0) { + if (PyUnicode_Find(temp_fv_str, _Py_LATIN1_CHR('{'), 0, 1, 1) == 0) { /* Expression starts with a brace, split it with a space from the outer one. */ outer_brace = "{ "; diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 84fbc33a..1a65ddd0 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -2559,8 +2559,8 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) b = PyLong_AsLongAndOverflow(item, &overflow); } if (overflow == 0 && - (i_result >= 0 ? (b <= LONG_MAX - i_result) - : (b >= LONG_MIN - i_result))) + (i_result >= 0 ? (b <= PY_SSIZE_T_MAX - i_result) + : (b >= PY_SSIZE_T_MIN - i_result))) { i_result += b; Py_DECREF(item); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index e17b2294..b307edd5 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1999,14 +1999,15 @@ dummy_func( new_version = _PyDict_NotifyEvent(tstate->interp, PyDict_EVENT_MODIFIED, dict, name, value); ep->me_value = value; } - Py_DECREF(old_value); - STAT_INC(STORE_ATTR, hit); /* Ensure dict is GC tracked if it needs to be */ if (!_PyObject_GC_IS_TRACKED(dict) && _PyObject_GC_MAY_BE_TRACKED(value)) { _PyObject_GC_TRACK(dict); } - /* PEP 509 */ - dict->ma_version_tag = new_version; + dict->ma_version_tag = new_version; // PEP 509 + // old_value should be DECREFed after GC track checking is done, if not, it could raise a segmentation fault, + // when dict only holds the strong reference to value in ep->me_value. + Py_DECREF(old_value); + STAT_INC(STORE_ATTR, hit); Py_DECREF(owner); } diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h index 7a7c188b..e46c01e1 100644 --- a/Python/clinic/sysmodule.c.h +++ b/Python/clinic/sysmodule.c.h @@ -913,24 +913,64 @@ sys_getallocatedblocks(PyObject *module, PyObject *Py_UNUSED(ignored)) } PyDoc_STRVAR(sys_getunicodeinternedsize__doc__, -"getunicodeinternedsize($module, /)\n" +"getunicodeinternedsize($module, /, *, _only_immortal=False)\n" "--\n" "\n" "Return the number of elements of the unicode interned dictionary"); #define SYS_GETUNICODEINTERNEDSIZE_METHODDEF \ - {"getunicodeinternedsize", (PyCFunction)sys_getunicodeinternedsize, METH_NOARGS, sys_getunicodeinternedsize__doc__}, + {"getunicodeinternedsize", _PyCFunction_CAST(sys_getunicodeinternedsize), METH_FASTCALL|METH_KEYWORDS, sys_getunicodeinternedsize__doc__}, static Py_ssize_t -sys_getunicodeinternedsize_impl(PyObject *module); +sys_getunicodeinternedsize_impl(PyObject *module, int _only_immortal); static PyObject * -sys_getunicodeinternedsize(PyObject *module, PyObject *Py_UNUSED(ignored)) +sys_getunicodeinternedsize(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(_only_immortal), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"_only_immortal", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "getunicodeinternedsize", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + int _only_immortal = 0; Py_ssize_t _return_value; - _return_value = sys_getunicodeinternedsize_impl(module); + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_kwonly; + } + _only_immortal = PyObject_IsTrue(args[0]); + if (_only_immortal < 0) { + goto exit; + } +skip_optional_kwonly: + _return_value = sys_getunicodeinternedsize_impl(module, _only_immortal); if ((_return_value == -1) && PyErr_Occurred()) { goto exit; } @@ -1415,4 +1455,4 @@ sys__getframemodulename(PyObject *module, PyObject *const *args, Py_ssize_t narg #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ -/*[clinic end generated code: output=6d598acc26237fbe input=a9049054013a1b77]*/ +/*[clinic end generated code: output=2a1fbdf7de450c63 input=a9049054013a1b77]*/ diff --git a/Python/codecs.c b/Python/codecs.c index 1983f56b..b041339e 100644 --- a/Python/codecs.c +++ b/Python/codecs.c @@ -144,7 +144,9 @@ PyObject *_PyCodec_Lookup(const char *encoding) if (v == NULL) { return NULL; } - PyUnicode_InternInPlace(&v); + + /* Intern the string. We'll make it immortal later if lookup succeeds. */ + _PyUnicode_InternMortal(interp, &v); /* First, try to lookup the name in the registry dictionary */ PyObject *result = PyDict_GetItemWithError(interp->codec_search_cache, v); @@ -197,6 +199,8 @@ PyObject *_PyCodec_Lookup(const char *encoding) goto onError; } + _PyUnicode_InternImmortal(interp, &v); + /* Cache and return the result */ if (PyDict_SetItem(interp->codec_search_cache, v, result) < 0) { Py_DECREF(result); diff --git a/Python/compile.c b/Python/compile.c index 40335f6d..56fdbfae 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -135,6 +135,7 @@ enum fblocktype { WHILE_LOOP, FOR_LOOP, TRY_EXCEPT, FINALLY_TRY, FINALLY_END, struct fblockinfo { enum fblocktype fb_type; jump_target_label fb_block; + location fb_loc; /* (optional) type-specific exit or cleanup block */ jump_target_label fb_exit; /* (optional) additional information required for unwinding */ @@ -772,8 +773,7 @@ compiler_set_qualname(struct compiler *c) } if (base != NULL) { - _Py_DECLARE_STR(dot, "."); - name = PyUnicode_Concat(base, &_Py_STR(dot)); + name = PyUnicode_Concat(base, _Py_LATIN1_CHR('.')); Py_DECREF(base); if (name == NULL) { return ERROR; @@ -1467,6 +1467,7 @@ compiler_push_fblock(struct compiler *c, location loc, f = &c->u->u_fblock[c->u->u_nfblocks++]; f->fb_type = t; f->fb_block = block_label; + f->fb_loc = loc; f->fb_exit = exit; f->fb_datum = datum; return SUCCESS; @@ -1594,7 +1595,7 @@ compiler_unwind_fblock(struct compiler *c, location *ploc, case WITH: case ASYNC_WITH: - *ploc = LOC((stmt_ty)info->fb_datum); + *ploc = info->fb_loc; ADDOP(c, *ploc, POP_BLOCK); if (preserve_tos) { ADDOP_I(c, *ploc, SWAP, 2); @@ -1834,7 +1835,7 @@ compiler_make_closure(struct compiler *c, location loc, c->u->u_metadata.u_name, co->co_name, freevars); - Py_DECREF(freevars); + Py_XDECREF(freevars); return ERROR; } ADDOP_I(c, loc, LOAD_CLOSURE, arg); @@ -2966,7 +2967,7 @@ compiler_lambda(struct compiler *c, expr_ty e) co = optimize_and_assemble(c, 0); } else { - location loc = LOCATION(e->lineno, e->lineno, 0, 0); + location loc = LOC(e->v.Lambda.body); ADDOP_IN_SCOPE(c, loc, RETURN_VALUE); co = optimize_and_assemble(c, 1); } @@ -3024,11 +3025,18 @@ compiler_for(struct compiler *c, stmt_ty s) RETURN_IF_ERROR(compiler_push_fblock(c, loc, FOR_LOOP, start, end, NULL)); VISIT(c, expr, s->v.For.iter); + + loc = LOC(s->v.For.iter); ADDOP(c, loc, GET_ITER); USE_LABEL(c, start); ADDOP_JUMP(c, loc, FOR_ITER, cleanup); + /* Add NOP to ensure correct line tracing of multiline for statements. + * It will be removed later if redundant. + */ + ADDOP(c, LOC(s->v.For.target), NOP); + USE_LABEL(c, body); VISIT(c, expr, s->v.For.target); VISIT_SEQ(c, stmt, s->v.For.body); @@ -3062,7 +3070,7 @@ compiler_async_for(struct compiler *c, stmt_ty s) NEW_JUMP_TARGET_LABEL(c, end); VISIT(c, expr, s->v.AsyncFor.iter); - ADDOP(c, loc, GET_AITER); + ADDOP(c, LOC(s->v.AsyncFor.iter), GET_AITER); USE_LABEL(c, start); RETURN_IF_ERROR(compiler_push_fblock(c, loc, FOR_LOOP, start, end, NULL)); @@ -5183,9 +5191,12 @@ compiler_call_helper(struct compiler *c, location loc, } -/* List and set comprehensions and generator expressions work by creating a - nested function to perform the actual iteration. This means that the - iteration variables don't leak into the current scope. +/* List and set comprehensions work by being inlined at the location where + they are defined. The isolation of iteration variables is provided by + pushing/popping clashing locals on the stack. Generator expressions work + by creating a nested function to perform the actual iteration. + This means that the iteration variables don't leak into the current scope. + See https://peps.python.org/pep-0709/ for additional information. The defined function is called immediately following its definition, with the result of that call being the result of the expression. The LC/SC version returns the populated container, while the GE version is @@ -5265,14 +5276,15 @@ compiler_sync_comprehension_generator(struct compiler *c, location loc, } if (IS_LABEL(start)) { VISIT(c, expr, gen->iter); - ADDOP(c, loc, GET_ITER); + ADDOP(c, LOC(gen->iter), GET_ITER); } } } + if (IS_LABEL(start)) { depth++; USE_LABEL(c, start); - ADDOP_JUMP(c, loc, FOR_ITER, anchor); + ADDOP_JUMP(c, LOC(gen->iter), FOR_ITER, anchor); } VISIT(c, expr, gen->target); @@ -5359,7 +5371,7 @@ compiler_async_comprehension_generator(struct compiler *c, location loc, else { /* Sub-iter - calculate on the fly */ VISIT(c, expr, gen->iter); - ADDOP(c, loc, GET_AITER); + ADDOP(c, LOC(gen->iter), GET_AITER); } } @@ -5644,15 +5656,14 @@ pop_inlined_comprehension_state(struct compiler *c, location loc, } static inline int -compiler_comprehension_iter(struct compiler *c, location loc, - comprehension_ty comp) +compiler_comprehension_iter(struct compiler *c, comprehension_ty comp) { VISIT(c, expr, comp->iter); if (comp->is_async) { - ADDOP(c, loc, GET_AITER); + ADDOP(c, LOC(comp->iter), GET_AITER); } else { - ADDOP(c, loc, GET_ITER); + ADDOP(c, LOC(comp->iter), GET_ITER); } return SUCCESS; } @@ -5678,7 +5689,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, outermost = (comprehension_ty) asdl_seq_GET(generators, 0); if (is_inlined) { - if (compiler_comprehension_iter(c, loc, outermost)) { + if (compiler_comprehension_iter(c, outermost)) { goto error; } if (push_inlined_comprehension_state(c, loc, entry, &inline_state)) { @@ -5764,7 +5775,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, } Py_CLEAR(co); - if (compiler_comprehension_iter(c, loc, outermost)) { + if (compiler_comprehension_iter(c, outermost)) { goto error; } @@ -5906,7 +5917,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos) /* Evaluate EXPR */ VISIT(c, expr, item->context_expr); - + loc = LOC(item->context_expr); ADDOP(c, loc, BEFORE_ASYNC_WITH); ADDOP_I(c, loc, GET_AWAITABLE, 1); ADDOP_LOAD_CONST(c, loc, Py_None); @@ -6004,7 +6015,7 @@ compiler_with(struct compiler *c, stmt_ty s, int pos) /* Evaluate EXPR */ VISIT(c, expr, item->context_expr); /* Will push bound __exit__ */ - location loc = LOC(s); + location loc = LOC(item->context_expr); ADDOP(c, loc, BEFORE_WITH); ADDOP_JUMP(c, loc, SETUP_WITH, final); @@ -6037,7 +6048,6 @@ compiler_with(struct compiler *c, stmt_ty s, int pos) /* For successful outcome: * call __exit__(None, None, None) */ - loc = LOC(s); RETURN_IF_ERROR(compiler_call_exit_with_nones(c, loc)); ADDOP(c, loc, POP_TOP); ADDOP_JUMP(c, loc, JUMP, exit); @@ -6110,7 +6120,7 @@ compiler_visit_expr1(struct compiler *c, expr_ty e) break; case YieldFrom_kind: if (!_PyST_IsFunctionLike(c->u->u_ste)) { - return compiler_error(c, loc, "'yield' outside function"); + return compiler_error(c, loc, "'yield from' outside function"); } if (c->u->u_scope_type == COMPILER_SCOPE_ASYNC_FUNCTION) { return compiler_error(c, loc, "'yield from' inside async function"); @@ -7682,7 +7692,7 @@ optimize_and_assemble_code_unit(struct compiler_unit *u, PyObject *const_cache, PyCodeObject *co = NULL; PyObject *consts = consts_dict_keys_inorder(u->u_metadata.u_consts); if (consts == NULL) { - goto error; + return NULL; } cfg_builder g; if (instr_sequence_to_cfg(&u->u_instr_sequence, &g) < 0) { diff --git a/Python/context.c b/Python/context.c index 1ffae987..7bccfad1 100644 --- a/Python/context.c +++ b/Python/context.c @@ -669,6 +669,7 @@ context_run(PyContext *self, PyObject *const *args, ts, args[0], args + 1, nargs - 1, kwnames); if (_PyContext_Exit(ts, (PyObject *)self)) { + Py_XDECREF(call_result); return NULL; } diff --git a/Python/errors.c b/Python/errors.c index 6c46d1f2..cbfc2faf 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -1871,44 +1871,44 @@ PyErr_SyntaxLocationEx(const char *filename, int lineno, int col_offset) functionality in tb_displayline() in traceback.c. */ static PyObject * -err_programtext(PyThreadState *tstate, FILE *fp, int lineno, const char* encoding) +err_programtext(FILE *fp, int lineno, const char* encoding) { - int i; char linebuf[1000]; - if (fp == NULL) { - return NULL; + size_t line_size = 0; + + for (int i = 0; i < lineno; ) { + line_size = 0; + if (_Py_UniversalNewlineFgetsWithSize(linebuf, sizeof(linebuf), + fp, NULL, &line_size) == NULL) + { + /* Error or EOF. */ + return NULL; + } + /* fgets read *something*; if it didn't fill the + whole buffer, it must have found a newline + or hit the end of the file; if the last character is \n, + it obviously found a newline; else we haven't + yet seen a newline, so must continue */ + if (i + 1 < lineno + && line_size == sizeof(linebuf) - 1 + && linebuf[sizeof(linebuf) - 2] != '\n') + { + continue; + } + i++; } - for (i = 0; i < lineno; i++) { - char *pLastChar = &linebuf[sizeof(linebuf) - 2]; - do { - *pLastChar = '\0'; - if (Py_UniversalNewlineFgets(linebuf, sizeof linebuf, - fp, NULL) == NULL) { - goto after_loop; - } - /* fgets read *something*; if it didn't get as - far as pLastChar, it must have found a newline - or hit the end of the file; if pLastChar is \n, - it obviously found a newline; else we haven't - yet seen a newline, so must continue */ - } while (*pLastChar != '\0' && *pLastChar != '\n'); + const char *line = linebuf; + /* Skip BOM. */ + if (lineno == 1 && line_size >= 3 && memcmp(line, "\xef\xbb\xbf", 3) == 0) { + line += 3; + line_size -= 3; } - -after_loop: - fclose(fp); - if (i == lineno) { - PyObject *res; - if (encoding != NULL) { - res = PyUnicode_Decode(linebuf, strlen(linebuf), encoding, "replace"); - } else { - res = PyUnicode_FromString(linebuf); - } - if (res == NULL) - _PyErr_Clear(tstate); - return res; + PyObject *res = PyUnicode_Decode(line, line_size, encoding, "replace"); + if (res == NULL) { + PyErr_Clear(); } - return NULL; + return res; } PyObject * @@ -1928,20 +1928,41 @@ PyErr_ProgramText(const char *filename, int lineno) return res; } +/* Function from Parser/tokenizer/file_tokenizer.c */ +extern char* _PyTokenizer_FindEncodingFilename(int, PyObject *); + PyObject * _PyErr_ProgramDecodedTextObject(PyObject *filename, int lineno, const char* encoding) { + char *found_encoding = NULL; if (filename == NULL || lineno <= 0) { return NULL; } - PyThreadState *tstate = _PyThreadState_GET(); FILE *fp = _Py_fopen_obj(filename, "r" PY_STDIOTEXTMODE); if (fp == NULL) { - _PyErr_Clear(tstate); + PyErr_Clear(); return NULL; } - return err_programtext(tstate, fp, lineno, encoding); + if (encoding == NULL) { + int fd = fileno(fp); + found_encoding = _PyTokenizer_FindEncodingFilename(fd, filename); + encoding = found_encoding; + if (encoding == NULL) { + PyErr_Clear(); + encoding = "utf-8"; + } + /* Reset position */ + if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { + fclose(fp); + PyMem_Free(found_encoding); + return NULL; + } + } + PyObject *res = err_programtext(fp, lineno, encoding); + fclose(fp); + PyMem_Free(found_encoding); + return res; } PyObject * diff --git a/Python/frame.c b/Python/frame.c index a49215fa..b84fd9b6 100644 --- a/Python/frame.c +++ b/Python/frame.c @@ -115,18 +115,6 @@ take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame) } } -void -_PyFrame_ClearLocals(_PyInterpreterFrame *frame) -{ - assert(frame->stacktop >= 0); - int stacktop = frame->stacktop; - frame->stacktop = 0; - for (int i = 0; i < stacktop; i++) { - Py_XDECREF(frame->localsplus[i]); - } - Py_CLEAR(frame->f_locals); -} - void _PyFrame_ClearExceptCode(_PyInterpreterFrame *frame) { @@ -147,8 +135,12 @@ _PyFrame_ClearExceptCode(_PyInterpreterFrame *frame) } Py_DECREF(f); } - _PyFrame_ClearLocals(frame); + assert(frame->stacktop >= 0); + for (int i = 0; i < frame->stacktop; i++) { + Py_XDECREF(frame->localsplus[i]); + } Py_XDECREF(frame->frame_obj); + Py_XDECREF(frame->f_locals); Py_DECREF(frame->f_funcobj); } diff --git a/Python/future.c b/Python/future.c index d56f7330..998a7f74 100644 --- a/Python/future.c +++ b/Python/future.c @@ -39,12 +39,20 @@ future_check_features(PyFutureFeatures *ff, stmt_ty s, PyObject *filename) } else if (strcmp(feature, "braces") == 0) { PyErr_SetString(PyExc_SyntaxError, "not a chance"); - PyErr_SyntaxLocationObject(filename, s->lineno, s->col_offset + 1); + PyErr_RangedSyntaxLocationObject(filename, + name->lineno, + name->col_offset + 1, + name->end_lineno, + name->end_col_offset + 1); return 0; } else { PyErr_Format(PyExc_SyntaxError, UNDEFINED_FUTURE_FEATURE, feature); - PyErr_SyntaxLocationObject(filename, s->lineno, s->col_offset + 1); + PyErr_RangedSyntaxLocationObject(filename, + name->lineno, + name->col_offset + 1, + name->end_lineno, + name->end_col_offset + 1); return 0; } } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index a23cbd52..bbaf589e 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2762,16 +2762,17 @@ new_version = _PyDict_NotifyEvent(tstate->interp, PyDict_EVENT_MODIFIED, dict, name, value); ep->me_value = value; } - Py_DECREF(old_value); - STAT_INC(STORE_ATTR, hit); /* Ensure dict is GC tracked if it needs to be */ if (!_PyObject_GC_IS_TRACKED(dict) && _PyObject_GC_MAY_BE_TRACKED(value)) { _PyObject_GC_TRACK(dict); } - /* PEP 509 */ - dict->ma_version_tag = new_version; + dict->ma_version_tag = new_version; // PEP 509 + // old_value should be DECREFed after GC track checking is done, if not, it could raise a segmentation fault, + // when dict only holds the strong reference to value in ep->me_value. + Py_DECREF(old_value); + STAT_INC(STORE_ATTR, hit); Py_DECREF(owner); - #line 2775 "Python/generated_cases.c.h" + #line 2776 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2782,7 +2783,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 2014 "Python/bytecodes.c" + #line 2015 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2792,7 +2793,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2796 "Python/generated_cases.c.h" + #line 2797 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2804,7 +2805,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2033 "Python/bytecodes.c" + #line 2034 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2817,12 +2818,12 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - #line 2821 "Python/generated_cases.c.h" + #line 2822 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2046 "Python/bytecodes.c" + #line 2047 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2826 "Python/generated_cases.c.h" + #line 2827 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2833,7 +2834,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2050 "Python/bytecodes.c" + #line 2051 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2844,7 +2845,7 @@ _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 2848 "Python/generated_cases.c.h" + #line 2849 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2855,7 +2856,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2064 "Python/bytecodes.c" + #line 2065 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -2870,7 +2871,7 @@ _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 2874 "Python/generated_cases.c.h" + #line 2875 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2881,7 +2882,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2082 "Python/bytecodes.c" + #line 2083 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2893,7 +2894,7 @@ assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; - #line 2897 "Python/generated_cases.c.h" + #line 2898 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2904,14 +2905,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2096 "Python/bytecodes.c" + #line 2097 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2910 "Python/generated_cases.c.h" + #line 2911 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2098 "Python/bytecodes.c" + #line 2099 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 2915 "Python/generated_cases.c.h" + #line 2916 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2921,15 +2922,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2102 "Python/bytecodes.c" + #line 2103 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2927 "Python/generated_cases.c.h" + #line 2928 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2104 "Python/bytecodes.c" + #line 2105 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; - #line 2933 "Python/generated_cases.c.h" + #line 2934 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2940,12 +2941,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2109 "Python/bytecodes.c" + #line 2110 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2946 "Python/generated_cases.c.h" + #line 2947 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2111 "Python/bytecodes.c" + #line 2112 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2953,10 +2954,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2957 "Python/generated_cases.c.h" + #line 2958 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2119 "Python/bytecodes.c" + #line 2120 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2965,7 +2966,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 2969 "Python/generated_cases.c.h" + #line 2970 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -2975,21 +2976,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2130 "Python/bytecodes.c" + #line 2131 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 2982 "Python/generated_cases.c.h" + #line 2983 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2133 "Python/bytecodes.c" + #line 2134 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 2989 "Python/generated_cases.c.h" + #line 2990 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2138 "Python/bytecodes.c" + #line 2139 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 2993 "Python/generated_cases.c.h" + #line 2994 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -2998,15 +2999,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2142 "Python/bytecodes.c" + #line 2143 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 3005 "Python/generated_cases.c.h" + #line 3006 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2145 "Python/bytecodes.c" + #line 2146 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 3010 "Python/generated_cases.c.h" + #line 3011 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -3015,29 +3016,29 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2149 "Python/bytecodes.c" + #line 2150 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 3023 "Python/generated_cases.c.h" + #line 3024 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 2155 "Python/bytecodes.c" + #line 2156 "Python/bytecodes.c" JUMPBY(oparg); - #line 3032 "Python/generated_cases.c.h" + #line 3033 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - #line 2159 "Python/bytecodes.c" + #line 2160 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); - #line 3041 "Python/generated_cases.c.h" + #line 3042 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -3045,15 +3046,15 @@ TARGET(POP_JUMP_IF_FALSE) { PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = stack_pointer[-1]; - #line 2165 "Python/bytecodes.c" + #line 2166 "Python/bytecodes.c" if (Py_IsFalse(cond)) { JUMPBY(oparg); } else if (!Py_IsTrue(cond)) { int err = PyObject_IsTrue(cond); - #line 3055 "Python/generated_cases.c.h" + #line 3056 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2171 "Python/bytecodes.c" + #line 2172 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -3061,22 +3062,22 @@ if (err < 0) goto pop_1_error; } } - #line 3065 "Python/generated_cases.c.h" + #line 3066 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2181 "Python/bytecodes.c" + #line 2182 "Python/bytecodes.c" if (Py_IsTrue(cond)) { JUMPBY(oparg); } else if (!Py_IsFalse(cond)) { int err = PyObject_IsTrue(cond); - #line 3078 "Python/generated_cases.c.h" + #line 3079 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2187 "Python/bytecodes.c" + #line 2188 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -3084,63 +3085,63 @@ if (err < 0) goto pop_1_error; } } - #line 3088 "Python/generated_cases.c.h" + #line 3089 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2197 "Python/bytecodes.c" + #line 2198 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 3097 "Python/generated_cases.c.h" + #line 3098 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2199 "Python/bytecodes.c" + #line 2200 "Python/bytecodes.c" JUMPBY(oparg); } - #line 3102 "Python/generated_cases.c.h" + #line 3103 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2204 "Python/bytecodes.c" + #line 2205 "Python/bytecodes.c" if (Py_IsNone(value)) { JUMPBY(oparg); } else { - #line 3114 "Python/generated_cases.c.h" + #line 3115 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2209 "Python/bytecodes.c" + #line 2210 "Python/bytecodes.c" } - #line 3118 "Python/generated_cases.c.h" + #line 3119 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2213 "Python/bytecodes.c" + #line 2214 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); - #line 3131 "Python/generated_cases.c.h" + #line 3132 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2222 "Python/bytecodes.c" + #line 2223 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 3144 "Python/generated_cases.c.h" + #line 3145 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3151,16 +3152,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2230 "Python/bytecodes.c" + #line 2231 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 3160 "Python/generated_cases.c.h" + #line 3161 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2235 "Python/bytecodes.c" + #line 2236 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3168,7 +3169,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 3172 "Python/generated_cases.c.h" + #line 3173 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3177,10 +3178,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2245 "Python/bytecodes.c" + #line 2246 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 3184 "Python/generated_cases.c.h" + #line 3185 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3190,10 +3191,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2251 "Python/bytecodes.c" + #line 2252 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 3197 "Python/generated_cases.c.h" + #line 3198 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3204,11 +3205,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2257 "Python/bytecodes.c" + #line 2258 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 3212 "Python/generated_cases.c.h" + #line 3213 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3217,14 +3218,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2263 "Python/bytecodes.c" + #line 2264 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3224 "Python/generated_cases.c.h" + #line 3225 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2266 "Python/bytecodes.c" + #line 2267 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3228 "Python/generated_cases.c.h" + #line 3229 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3232,7 +3233,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2270 "Python/bytecodes.c" + #line 2271 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3255,11 +3256,11 @@ if (iter == NULL) { goto error; } - #line 3259 "Python/generated_cases.c.h" + #line 3260 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2293 "Python/bytecodes.c" + #line 2294 "Python/bytecodes.c" } - #line 3263 "Python/generated_cases.c.h" + #line 3264 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -3270,7 +3271,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2312 "Python/bytecodes.c" + #line 2313 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3301,7 +3302,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3305 "Python/generated_cases.c.h" + #line 3306 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3309,7 +3310,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2345 "Python/bytecodes.c" + #line 2346 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3335,14 +3336,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3339 "Python/generated_cases.c.h" + #line 3340 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2373 "Python/bytecodes.c" + #line 2374 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3362,7 +3363,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3366 "Python/generated_cases.c.h" + #line 3367 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3372,7 +3373,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2395 "Python/bytecodes.c" + #line 2396 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3392,7 +3393,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3396 "Python/generated_cases.c.h" + #line 3397 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3402,7 +3403,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2417 "Python/bytecodes.c" + #line 2418 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3420,7 +3421,7 @@ if (next == NULL) { goto error; } - #line 3424 "Python/generated_cases.c.h" + #line 3425 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3429,7 +3430,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2437 "Python/bytecodes.c" + #line 2438 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3445,14 +3446,14 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3449 "Python/generated_cases.c.h" + #line 3450 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2455 "Python/bytecodes.c" + #line 2456 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3475,16 +3476,16 @@ Py_DECREF(enter); goto error; } - #line 3479 "Python/generated_cases.c.h" + #line 3480 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2478 "Python/bytecodes.c" + #line 2479 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3488 "Python/generated_cases.c.h" + #line 3489 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3496,7 +3497,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2488 "Python/bytecodes.c" + #line 2489 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3522,16 +3523,16 @@ Py_DECREF(enter); goto error; } - #line 3526 "Python/generated_cases.c.h" + #line 3527 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2514 "Python/bytecodes.c" + #line 2515 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3535 "Python/generated_cases.c.h" + #line 3536 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3543,7 +3544,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2523 "Python/bytecodes.c" + #line 2524 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3569,7 +3570,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3573 "Python/generated_cases.c.h" + #line 3574 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3578,7 +3579,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2551 "Python/bytecodes.c" + #line 2552 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3588,7 +3589,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3592 "Python/generated_cases.c.h" + #line 3593 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3602,7 +3603,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2563 "Python/bytecodes.c" + #line 2564 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3619,7 +3620,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3623 "Python/generated_cases.c.h" + #line 3624 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3633,7 +3634,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2582 "Python/bytecodes.c" + #line 2583 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -3643,7 +3644,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3647 "Python/generated_cases.c.h" + #line 3648 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3657,7 +3658,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2594 "Python/bytecodes.c" + #line 2595 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -3671,7 +3672,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3675 "Python/generated_cases.c.h" + #line 3676 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3680,16 +3681,16 @@ } TARGET(KW_NAMES) { - #line 2610 "Python/bytecodes.c" + #line 2611 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); kwnames = GETITEM(frame->f_code->co_consts, oparg); - #line 3688 "Python/generated_cases.c.h" + #line 3689 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2616 "Python/bytecodes.c" + #line 2617 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3702,7 +3703,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3706 "Python/generated_cases.c.h" + #line 3707 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3712,7 +3713,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2661 "Python/bytecodes.c" + #line 2662 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3794,7 +3795,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3798 "Python/generated_cases.c.h" + #line 3799 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3806,7 +3807,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2749 "Python/bytecodes.c" + #line 2750 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3816,7 +3817,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3820 "Python/generated_cases.c.h" + #line 3821 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3825,7 +3826,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2761 "Python/bytecodes.c" + #line 2762 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3851,7 +3852,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3855 "Python/generated_cases.c.h" + #line 3856 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3859,7 +3860,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2789 "Python/bytecodes.c" + #line 2790 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3895,7 +3896,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3899 "Python/generated_cases.c.h" + #line 3900 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3903,7 +3904,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2827 "Python/bytecodes.c" + #line 2828 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3913,7 +3914,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3917 "Python/generated_cases.c.h" + #line 3918 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3926,7 +3927,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2839 "Python/bytecodes.c" + #line 2840 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3937,7 +3938,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3941 "Python/generated_cases.c.h" + #line 3942 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3951,7 +3952,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2853 "Python/bytecodes.c" + #line 2854 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3962,7 +3963,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3966 "Python/generated_cases.c.h" + #line 3967 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3976,7 +3977,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2867 "Python/bytecodes.c" + #line 2868 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3998,7 +3999,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4002 "Python/generated_cases.c.h" + #line 4003 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4012,7 +4013,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2892 "Python/bytecodes.c" + #line 2893 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4040,7 +4041,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4044 "Python/generated_cases.c.h" + #line 4045 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4054,7 +4055,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2923 "Python/bytecodes.c" + #line 2924 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4086,7 +4087,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4090 "Python/generated_cases.c.h" + #line 4091 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4100,7 +4101,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2958 "Python/bytecodes.c" + #line 2959 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4132,7 +4133,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4136 "Python/generated_cases.c.h" + #line 4137 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4146,7 +4147,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2993 "Python/bytecodes.c" + #line 2994 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4171,7 +4172,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4175 "Python/generated_cases.c.h" + #line 4176 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4184,7 +4185,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3020 "Python/bytecodes.c" + #line 3021 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4211,7 +4212,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4215 "Python/generated_cases.c.h" + #line 4216 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4223,7 +4224,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3050 "Python/bytecodes.c" + #line 3051 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); PyInterpreterState *interp = _PyInterpreterState_GET(); @@ -4241,14 +4242,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4245 "Python/generated_cases.c.h" + #line 4246 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3070 "Python/bytecodes.c" + #line 3071 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4279,7 +4280,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4283 "Python/generated_cases.c.h" + #line 4284 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4292,7 +4293,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3104 "Python/bytecodes.c" + #line 3105 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4321,7 +4322,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4325 "Python/generated_cases.c.h" + #line 4326 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4334,7 +4335,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3136 "Python/bytecodes.c" + #line 3137 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4363,7 +4364,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4367 "Python/generated_cases.c.h" + #line 4368 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4376,7 +4377,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3168 "Python/bytecodes.c" + #line 3169 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4404,7 +4405,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4408 "Python/generated_cases.c.h" + #line 4409 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4414,9 +4415,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3199 "Python/bytecodes.c" + #line 3200 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4420 "Python/generated_cases.c.h" + #line 4421 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4425,7 +4426,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3203 "Python/bytecodes.c" + #line 3204 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4487,14 +4488,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4491 "Python/generated_cases.c.h" + #line 4492 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3265 "Python/bytecodes.c" + #line 3266 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4498 "Python/generated_cases.c.h" + #line 4499 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4509,7 +4510,7 @@ PyObject *kwdefaults = (oparg & 0x02) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0))] : NULL; PyObject *defaults = (oparg & 0x01) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x01) ? 1 : 0))] : NULL; PyObject *func; - #line 3275 "Python/bytecodes.c" + #line 3276 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4538,14 +4539,14 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4542 "Python/generated_cases.c.h" + #line 4543 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0)); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3306 "Python/bytecodes.c" + #line 3307 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4566,7 +4567,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4570 "Python/generated_cases.c.h" + #line 4571 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4574,15 +4575,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3329 "Python/bytecodes.c" + #line 3330 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4580 "Python/generated_cases.c.h" + #line 4581 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3331 "Python/bytecodes.c" + #line 3332 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4586 "Python/generated_cases.c.h" + #line 4587 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4593,7 +4594,7 @@ PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; PyObject *result; - #line 3335 "Python/bytecodes.c" + #line 3336 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4628,7 +4629,7 @@ Py_DECREF(value); Py_XDECREF(fmt_spec); if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } - #line 4632 "Python/generated_cases.c.h" + #line 4633 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4637,10 +4638,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3372 "Python/bytecodes.c" + #line 3373 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4644 "Python/generated_cases.c.h" + #line 4645 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4652,7 +4653,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3377 "Python/bytecodes.c" + #line 3378 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4667,12 +4668,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4671 "Python/generated_cases.c.h" + #line 4672 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3392 "Python/bytecodes.c" + #line 3393 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4676 "Python/generated_cases.c.h" + #line 4677 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4682,16 +4683,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3397 "Python/bytecodes.c" + #line 3398 "Python/bytecodes.c" assert(oparg >= 2); - #line 4688 "Python/generated_cases.c.h" + #line 4689 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3401 "Python/bytecodes.c" + #line 3402 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4703,26 +4704,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4707 "Python/generated_cases.c.h" + #line 4708 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3415 "Python/bytecodes.c" + #line 3416 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4713 "Python/generated_cases.c.h" + #line 4714 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3419 "Python/bytecodes.c" + #line 3420 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr-oparg, PY_MONITORING_EVENT_JUMP); - #line 4720 "Python/generated_cases.c.h" + #line 4721 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3424 "Python/bytecodes.c" + #line 3425 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4731,12 +4732,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4735 "Python/generated_cases.c.h" + #line 4736 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3435 "Python/bytecodes.c" + #line 3436 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4745,12 +4746,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4749 "Python/generated_cases.c.h" + #line 4750 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3446 "Python/bytecodes.c" + #line 3447 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4762,12 +4763,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4766 "Python/generated_cases.c.h" + #line 4767 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3460 "Python/bytecodes.c" + #line 3461 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4779,30 +4780,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4783 "Python/generated_cases.c.h" + #line 4784 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3474 "Python/bytecodes.c" + #line 3475 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4794 "Python/generated_cases.c.h" + #line 4795 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3482 "Python/bytecodes.c" + #line 3483 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4801 "Python/generated_cases.c.h" + #line 4802 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3487 "Python/bytecodes.c" + #line 3488 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4808 "Python/generated_cases.c.h" + #line 4809 "Python/generated_cases.c.h" } diff --git a/Python/getargs.c b/Python/getargs.c index 02bddf06..0bba8b1d 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -1964,7 +1964,8 @@ new_kwtuple(const char * const *keywords, int total, int pos) Py_DECREF(kwtuple); return NULL; } - PyUnicode_InternInPlace(&str); + PyInterpreterState *interp = _PyInterpreterState_GET(); + _PyUnicode_InternImmortal(interp, &str); PyTuple_SET_ITEM(kwtuple, i, str); } return kwtuple; @@ -2071,6 +2072,18 @@ parser_clear(struct _PyArg_Parser *parser) if (parser->initialized == 1) { Py_CLEAR(parser->kwtuple); } + + if (parser->format) { + parser->fname = NULL; + } + else { + assert(parser->fname != NULL); + } + parser->custom_msg = NULL; + parser->pos = 0; + parser->min = 0; + parser->max = 0; + parser->initialized = 0; } static PyObject* @@ -2628,7 +2641,7 @@ _PyArg_UnpackKeywordsWithVararg(PyObject *const *args, Py_ssize_t nargs, * * Otherwise, we leave a place at `buf[vararg]` for vararg tuple * so the index is `i + 1`. */ - if (nargs < vararg) { + if (i < vararg) { buf[i] = current_arg; } else { diff --git a/Python/import.c b/Python/import.c index db709099..66391c04 100644 --- a/Python/import.c +++ b/Python/import.c @@ -917,12 +917,14 @@ extensions_lock_release(void) static void * hashtable_key_from_2_strings(PyObject *str1, PyObject *str2, const char sep) { - Py_ssize_t str1_len, str2_len; - const char *str1_data = PyUnicode_AsUTF8AndSize(str1, &str1_len); - const char *str2_data = PyUnicode_AsUTF8AndSize(str2, &str2_len); + const char *str1_data = _PyUnicode_AsUTF8NoNUL(str1); + const char *str2_data = _PyUnicode_AsUTF8NoNUL(str2); if (str1_data == NULL || str2_data == NULL) { return NULL; } + Py_ssize_t str1_len = strlen(str1_data); + Py_ssize_t str2_len = strlen(str2_data); + /* Make sure sep and the NULL byte won't cause an overflow. */ assert(SIZE_MAX - str1_len - str2_len > 2); size_t size = str1_len + 1 + str2_len + 1; @@ -3539,7 +3541,7 @@ _imp_find_frozen_impl(PyObject *module, PyObject *name, int withdata) if (info.origname != NULL && info.origname[0] != '\0') { origname = PyUnicode_FromString(info.origname); if (origname == NULL) { - Py_DECREF(data); + Py_XDECREF(data); return NULL; } } diff --git a/Python/legacy_tracing.c b/Python/legacy_tracing.c index 43fa5910..4a6565be 100644 --- a/Python/legacy_tracing.c +++ b/Python/legacy_tracing.c @@ -103,6 +103,19 @@ sys_profile_call_or_return( Py_DECREF(meth); return res; } + else if (Py_TYPE(callable) == &PyMethod_Type) { + // CALL instruction will grab the function from the method, + // so if the function is a C function, the return event will + // be emitted. However, CALL event happens before CALL + // instruction, so we need to handle this case here. + PyObject* func = PyMethod_GET_FUNCTION(callable); + if (func == NULL) { + return NULL; + } + if (PyCFunction_Check(func)) { + return call_profile_func(self, func); + } + } Py_RETURN_NONE; } diff --git a/Python/marshal.c b/Python/marshal.c index 90953cbb..3fc3f890 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -14,6 +14,7 @@ #include "pycore_long.h" // _PyLong_DigitCount #include "pycore_hashtable.h" // _Py_hashtable_t #include "marshal.h" // Py_MARSHAL_VERSION +#include "pycore_pystate.h" // _PyInterpreterState_GET() /*[clinic input] module marshal @@ -1158,8 +1159,12 @@ r_object(RFILE *p) v = PyUnicode_FromKindAndData(PyUnicode_1BYTE_KIND, ptr, n); if (v == NULL) break; - if (is_interned) - PyUnicode_InternInPlace(&v); + if (is_interned) { + // marshal is meant to serialize .pyc files with code + // objects, and code-related strings are currently immortal. + PyInterpreterState *interp = _PyInterpreterState_GET(); + _PyUnicode_InternImmortal(interp, &v); + } retval = v; R_REF(retval); break; @@ -1191,8 +1196,12 @@ r_object(RFILE *p) } if (v == NULL) break; - if (is_interned) - PyUnicode_InternInPlace(&v); + if (is_interned) { + // marshal is meant to serialize .pyc files with code + // objects, and code-related strings are currently immortal. + PyInterpreterState *interp = _PyInterpreterState_GET(); + _PyUnicode_InternImmortal(interp, &v); + } retval = v; R_REF(retval); break; @@ -1851,7 +1860,7 @@ machine architecture issues.\n\ Not all Python object types are supported; in general, only objects\n\ whose value is independent from a particular invocation of Python can be\n\ written and read by this module. The following types are supported:\n\ -None, integers, floating point numbers, strings, bytes, bytearrays,\n\ +None, integers, floating-point numbers, strings, bytes, bytearrays,\n\ tuples, lists, sets, dictionaries, and code objects, where it\n\ should be understood that tuples, lists and dictionaries are only\n\ supported as long as the values contained therein are themselves\n\ @@ -1862,7 +1871,7 @@ Variables:\n\ \n\ version -- indicates the format that the module uses. Version 0 is the\n\ historical format, version 1 shares interned strings and version 2\n\ - uses a binary format for floating point numbers.\n\ + uses a binary format for floating-point numbers.\n\ Version 3 shares common object references (New in version 3.4).\n\ \n\ Functions:\n\ diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 2c36527a..e9c1a0d7 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -650,6 +650,10 @@ pycore_create_interpreter(_PyRuntimeState *runtime, return status; } + // This could be done in init_interpreter() (in pystate.c) if it + // didn't depend on interp->feature_flags being set already. + _PyObject_InitState(interp); + PyThreadState *tstate = _PyThreadState_New(interp); if (tstate == NULL) { return _PyStatus_ERR("can't make first thread"); @@ -839,6 +843,13 @@ pycore_interp_init(PyThreadState *tstate) return _PyStatus_ERR("failed to initialize deep-frozen modules"); } + // Per-interpreter interned string dict is created after deep-frozen + // modules have interned the global strings. + status = _PyUnicode_InitInternDict(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + status = pycore_init_types(interp); if (_PyStatus_EXCEPTION(status)) { goto done; @@ -2096,6 +2107,10 @@ new_interpreter(PyThreadState **tstate_p, const PyInterpreterConfig *config) goto error; } + // This could be done in init_interpreter() (in pystate.c) if it + // didn't depend on interp->feature_flags being set already. + _PyObject_InitState(interp); + status = init_interp_create_gil(tstate, config->gil); if (_PyStatus_EXCEPTION(status)) { goto error; diff --git a/Python/pystate.c b/Python/pystate.c index d0651fbd..6aed9ac3 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -686,7 +686,9 @@ init_interpreter(PyInterpreterState *interp, _obmalloc_pools_INIT(interp->obmalloc.pools); memcpy(&interp->obmalloc.pools.used, temp, sizeof(temp)); } - _PyObject_InitState(interp); + + // We would call _PyObject_InitState() at this point + // if interp->feature_flags were alredy set. _PyEval_InitState(interp, pending_lock); _PyGC_InitState(&interp->gc); @@ -1593,7 +1595,9 @@ tstate_delete_common(PyThreadState *tstate) if (tstate->_status.bound_gilstate) { unbind_gilstate_tstate(tstate); } - unbind_tstate(tstate); + if (tstate->_status.bound) { + unbind_tstate(tstate); + } // XXX Move to PyThreadState_Clear()? clear_datastack(tstate); diff --git a/Python/stdlib_module_names.h b/Python/stdlib_module_names.h index ed4a0ac2..1b1a1bde 100644 --- a/Python/stdlib_module_names.h +++ b/Python/stdlib_module_names.h @@ -89,6 +89,7 @@ static const char* _Py_stdlib_module_names[] = { "_weakref", "_weakrefset", "_winapi", +"_wmi", "_zoneinfo", "abc", "aifc", diff --git a/Python/symtable.c b/Python/symtable.c index ba428421..f99ca4fd 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -675,22 +675,19 @@ inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp, if (existing == NULL && PyErr_Occurred()) { return 0; } + // __class__ is never allowed to be free through a class scope (see + // drop_class_free) + if (scope == FREE && ste->ste_type == ClassBlock && + _PyUnicode_EqualToASCIIString(k, "__class__")) { + scope = GLOBAL_IMPLICIT; + if (PySet_Discard(comp_free, k) < 0) { + return 0; + } + remove_dunder_class = 1; + } if (!existing) { // name does not exist in scope, copy from comprehension assert(scope != FREE || PySet_Contains(comp_free, k) == 1); - if (scope == FREE && ste->ste_type == ClassBlock && - _PyUnicode_EqualToASCIIString(k, "__class__")) { - // if __class__ is unbound in the enclosing class scope and free - // in the comprehension scope, it needs special handling; just - // letting it be marked as free in class scope will break due to - // drop_class_free - scope = GLOBAL_IMPLICIT; - only_flags &= ~DEF_FREE; - if (PySet_Discard(comp_free, k) < 0) { - return 0; - } - remove_dunder_class = 1; - } PyObject *v_flags = PyLong_FromLong(only_flags); if (v_flags == NULL) { return 0; diff --git a/Python/sysmodule.c b/Python/sysmodule.c index a99a97fe..d41fe822 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -722,7 +722,7 @@ sys_displayhook(PyObject *module, PyObject *o) if (o == Py_None) { Py_RETURN_NONE; } - if (PyObject_SetAttr(builtins, &_Py_ID(_), Py_None) != 0) + if (PyObject_SetAttr(builtins, _Py_LATIN1_CHR('_'), Py_None) != 0) return NULL; outf = _PySys_GetAttr(tstate, &_Py_ID(stdout)); if (outf == NULL || outf == Py_None) { @@ -744,10 +744,9 @@ sys_displayhook(PyObject *module, PyObject *o) return NULL; } } - _Py_DECLARE_STR(newline, "\n"); - if (PyFile_WriteObject(&_Py_STR(newline), outf, Py_PRINT_RAW) != 0) + if (PyFile_WriteObject(_Py_LATIN1_CHR('\n'), outf, Py_PRINT_RAW) != 0) return NULL; - if (PyObject_SetAttr(builtins, &_Py_ID(_), o) != 0) + if (PyObject_SetAttr(builtins, _Py_LATIN1_CHR('_'), o) != 0) return NULL; Py_RETURN_NONE; } @@ -927,8 +926,9 @@ sys_intern_impl(PyObject *module, PyObject *s) /*[clinic end generated code: output=be680c24f5c9e5d6 input=849483c006924e2f]*/ { if (PyUnicode_CheckExact(s)) { + PyInterpreterState *interp = _PyInterpreterState_GET(); Py_INCREF(s); - PyUnicode_InternInPlace(&s); + _PyUnicode_InternMortal(interp, &s); return s; } else { @@ -1918,14 +1918,22 @@ sys_getallocatedblocks_impl(PyObject *module) /*[clinic input] sys.getunicodeinternedsize -> Py_ssize_t + * + _only_immortal: bool = False + Return the number of elements of the unicode interned dictionary [clinic start generated code]*/ static Py_ssize_t -sys_getunicodeinternedsize_impl(PyObject *module) -/*[clinic end generated code: output=ad0e4c9738ed4129 input=726298eaa063347a]*/ +sys_getunicodeinternedsize_impl(PyObject *module, int _only_immortal) +/*[clinic end generated code: output=29a6377a94a14f70 input=0330b3408dd5bcc6]*/ { - return _PyUnicode_InternedSize(); + if (_only_immortal) { + return _PyUnicode_InternedSize_Immortal(); + } + else { + return _PyUnicode_InternedSize(); + } } /*[clinic input] diff --git a/Python/traceback.c b/Python/traceback.c index fdaf19d3..fba3594e 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -1242,6 +1242,8 @@ _Py_DumpASCII(int fd, PyObject *text) static void dump_frame(int fd, _PyInterpreterFrame *frame) { + assert(frame->owner != FRAME_OWNED_BY_CSTACK); + PyCodeObject *code = frame->f_code; PUTS(fd, " File "); if (code->co_filename != NULL @@ -1315,24 +1317,27 @@ dump_traceback(int fd, PyThreadState *tstate, int write_header) unsigned int depth = 0; while (1) { + if (frame->owner == FRAME_OWNED_BY_CSTACK) { + /* Trampoline frame */ + frame = frame->previous; + if (frame == NULL) { + break; + } + + /* Can't have more than one shim frame in a row */ + assert(frame->owner != FRAME_OWNED_BY_CSTACK); + } + if (MAX_FRAME_DEPTH <= depth) { PUTS(fd, " ...\n"); break; } + dump_frame(fd, frame); frame = frame->previous; if (frame == NULL) { break; } - if (frame->owner == FRAME_OWNED_BY_CSTACK) { - /* Trampoline frame */ - frame = frame->previous; - } - if (frame == NULL) { - break; - } - /* Can't have more than one shim frame in a row */ - assert(frame->owner != FRAME_OWNED_BY_CSTACK); depth++; } } diff --git a/Python/tracemalloc.c b/Python/tracemalloc.c index bc765623..e13064bd 100644 --- a/Python/tracemalloc.c +++ b/Python/tracemalloc.c @@ -836,7 +836,7 @@ _PyTraceMalloc_Init(void) tracemalloc_tracebacks = hashtable_new(hashtable_hash_traceback, hashtable_compare_traceback, - NULL, raw_free); + raw_free, NULL); tracemalloc_traces = tracemalloc_create_traces_table(); tracemalloc_domains = tracemalloc_create_domains_table(); diff --git a/README.rst b/README.rst index 840ac75b..c6dc40b1 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -This is Python version 3.12.4 +This is Python version 3.12.8 ============================= .. image:: https://github.com/python/cpython/workflows/Tests/badge.svg @@ -64,7 +64,7 @@ the executable is called ``python.exe``; elsewhere it's just ``python``. Building a complete Python installation requires the use of various additional third-party libraries, depending on your build platform and configure options. Not all standard library modules are buildable or -useable on all platforms. Refer to the +usable on all platforms. Refer to the `Install dependencies `_ section of the `Developer Guide`_ for current detailed information on dependencies for various Linux distributions and macOS. diff --git a/Tools/build/check_extension_modules.py b/Tools/build/check_extension_modules.py index 59239c62..aa1ade71 100644 --- a/Tools/build/check_extension_modules.py +++ b/Tools/build/check_extension_modules.py @@ -54,6 +54,7 @@ "_overlapped", "_testconsole", "_winapi", + "_wmi", "msvcrt", "nt", "winreg", diff --git a/Tools/build/generate_global_objects.py b/Tools/build/generate_global_objects.py index ded19ee4..4cafeea9 100644 --- a/Tools/build/generate_global_objects.py +++ b/Tools/build/generate_global_objects.py @@ -362,9 +362,14 @@ def generate_static_strings_initializer(identifiers, strings): # This use of _Py_ID() is ignored by iter_global_strings() # since iter_files() ignores .h files. printer.write(f'string = &_Py_ID({i});') + printer.write(f'_PyUnicode_InternStatic(interp, &string);') printer.write(f'assert(_PyUnicode_CheckConsistency(string, 1));') - printer.write(f'_PyUnicode_InternInPlace(interp, &string);') - # XXX What about "strings"? + printer.write(f'assert(PyUnicode_GET_LENGTH(string) != 1);') + for value, name in sorted(strings.items()): + printer.write(f'string = &_Py_STR({name});') + printer.write(f'_PyUnicode_InternStatic(interp, &string);') + printer.write(f'assert(_PyUnicode_CheckConsistency(string, 1));') + printer.write(f'assert(PyUnicode_GET_LENGTH(string) != 1);') printer.write(END) printer.write(after) @@ -406,15 +411,31 @@ def generate_global_object_finalizers(generated_immortal_objects): def get_identifiers_and_strings() -> 'tuple[set[str], dict[str, str]]': identifiers = set(IDENTIFIERS) strings = {} + # Note that we store strings as they appear in C source, so the checks here + # can be defeated, e.g.: + # - "a" and "\0x61" won't be reported as duplicate. + # - "\n" appears as 2 characters. + # Probably not worth adding a C string parser. for name, string, *_ in iter_global_strings(): if string is None: if name not in IGNORED: identifiers.add(name) else: + if len(string) == 1 and ord(string) < 256: + # Give a nice message for common mistakes. + # To cover tricky cases (like "\n") we also generate C asserts. + raise ValueError( + 'do not use &_Py_ID or &_Py_STR for one-character latin-1 ' + + f'strings, use _Py_LATIN1_CHR instead: {string!r}') if string not in strings: strings[string] = name elif name != strings[string]: raise ValueError(f'string mismatch for {name!r} ({string!r} != {strings[name]!r}') + overlap = identifiers & set(strings.keys()) + if overlap: + raise ValueError( + 'do not use both _Py_ID and _Py_DECLARE_STR for the same string: ' + + repr(overlap)) return identifiers, strings diff --git a/Tools/build/generate_re_casefix.py b/Tools/build/generate_re_casefix.py index b57ac074..6cebfbd0 100755 --- a/Tools/build/generate_re_casefix.py +++ b/Tools/build/generate_re_casefix.py @@ -23,9 +23,9 @@ def update_file(file, content): # Maps the code of lowercased character to codes of different lowercased # characters which have the same uppercase. -_EXTRA_CASES = { +_EXTRA_CASES = {{ %s -} +}} """ def uname(i): diff --git a/Tools/build/generate_sbom.py b/Tools/build/generate_sbom.py index c08568f2..3299e447 100644 --- a/Tools/build/generate_sbom.py +++ b/Tools/build/generate_sbom.py @@ -59,6 +59,8 @@ class PackageFiles(typing.NamedTuple): include=["Modules/expat/**"], exclude=[ "Modules/expat/expat_config.h", + "Modules/expat/pyexpatns.h", + "Modules/_hacl/refresh.sh", ] ), "macholib": PackageFiles( @@ -96,6 +98,19 @@ def error_if(value: bool, error_message: str) -> None: sys.exit(1) +def is_root_directory_git_index() -> bool: + """Checks if the root directory is a git index""" + try: + subprocess.check_call( + ["git", "-C", str(CPYTHON_ROOT_DIR), "rev-parse"], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + except subprocess.CalledProcessError: + return False + return True + + def filter_gitignored_paths(paths: list[str]) -> list[str]: """ Filter out paths excluded by the gitignore file. @@ -108,6 +123,10 @@ def filter_gitignored_paths(paths: list[str]) -> list[str]: '.gitignore:9:*.a Tools/lib.a' """ + # No paths means no filtering to be done. + if not paths: + return [] + # Filter out files in gitignore. # Non-matching files show up as '::' git_check_ignore_proc = subprocess.run( @@ -204,6 +223,32 @@ def check_sbom_packages(sbom_data: dict[str, typing.Any]) -> None: "HACL* SBOM version doesn't match value in 'Modules/_hacl/refresh.sh'" ) + # libexpat specifies its expected rev in a refresh script. + if package["name"] == "libexpat": + libexpat_refresh_sh = (CPYTHON_ROOT_DIR / "Modules/expat/refresh.sh").read_text() + libexpat_expected_version_match = re.search( + r"expected_libexpat_version=\"([0-9]+\.[0-9]+\.[0-9]+)\"", + libexpat_refresh_sh + ) + libexpat_expected_sha256_match = re.search( + r"expected_libexpat_sha256=\"[a-f0-9]{40}\"", + libexpat_refresh_sh + ) + libexpat_expected_version = libexpat_expected_version_match and libexpat_expected_version_match.group(1) + libexpat_expected_sha256 = libexpat_expected_sha256_match and libexpat_expected_sha256_match.group(1) + + error_if( + libexpat_expected_version != version, + "libexpat SBOM version doesn't match value in 'Modules/expat/refresh.sh'" + ) + error_if( + package["checksums"] != [{ + "algorithm": "SHA256", + "checksumValue": libexpat_expected_sha256 + }], + "libexpat SBOM checksum doesn't match value in 'Modules/expat/refresh.sh'" + ) + # License must be on the approved list for SPDX. license_concluded = package["licenseConcluded"] error_if( @@ -337,6 +382,11 @@ def create_externals_sbom() -> None: def main() -> None: + # Don't regenerate the SBOM if we're not a git repository. + if not is_root_directory_git_index(): + print("Skipping SBOM generation due to not being a git repository") + return + create_source_sbom() create_externals_sbom() diff --git a/Tools/build/generate_token.py b/Tools/build/generate_token.py index 3bd307c1..6d27bc41 100755 --- a/Tools/build/generate_token.py +++ b/Tools/build/generate_token.py @@ -226,7 +226,8 @@ def make_rst(infile, outfile='Doc/library/token-list.inc'): # {AUTO_GENERATED_BY_SCRIPT} ''' token_py_template += ''' -__all__ = ['tok_name', 'ISTERMINAL', 'ISNONTERMINAL', 'ISEOF'] +__all__ = ['tok_name', 'ISTERMINAL', 'ISNONTERMINAL', 'ISEOF', + 'EXACT_TOKEN_TYPES'] %s N_TOKENS = %d diff --git a/Tools/build/regen-configure.sh b/Tools/build/regen-configure.sh index e34a36c1..c3df2917 100755 --- a/Tools/build/regen-configure.sh +++ b/Tools/build/regen-configure.sh @@ -5,12 +5,10 @@ set -e -x # The check_generated_files job of .github/workflows/build.yml must kept in # sync with this script. Use the same container image than the job so the job # doesn't need to run autoreconf in a container. -IMAGE="ubuntu:22.04" -DEPENDENCIES="autotools-dev autoconf autoconf-archive pkg-config" +IMAGE="ghcr.io/python/autoconf:2024.10.16.11360930377" AUTORECONF="autoreconf -ivf -Werror" WORK_DIR="/src" -SHELL_CMD="apt-get update && apt-get -yq install $DEPENDENCIES && cd $WORK_DIR && $AUTORECONF" abs_srcdir=$(cd $(dirname $0)/../..; pwd) @@ -28,4 +26,4 @@ if command -v selinuxenabled >/dev/null && selinuxenabled; then PATH_OPT=":Z" fi -"$RUNTIME" run --rm -v "$abs_srcdir:$WORK_DIR$PATH_OPT" "$IMAGE" /usr/bin/bash -c "$SHELL_CMD" +"$RUNTIME" run --rm -v "$abs_srcdir:$WORK_DIR$PATH_OPT" "$IMAGE" diff --git a/Tools/build/stable_abi.py b/Tools/build/stable_abi.py index c6363fda..ef162277 100644 --- a/Tools/build/stable_abi.py +++ b/Tools/build/stable_abi.py @@ -226,9 +226,9 @@ def sort_key(item): key=sort_key): write(f'EXPORT_DATA({item.name})') -REST_ROLES = { - 'function': 'function', - 'data': 'var', +ITEM_KIND_TO_DOC_ROLE = { + 'function': 'func', + 'data': 'data', 'struct': 'type', 'macro': 'macro', # 'const': 'const', # all undocumented @@ -237,22 +237,28 @@ def sort_key(item): @generator("doc_list", 'Doc/data/stable_abi.dat') def gen_doc_annotations(manifest, args, outfile): - """Generate/check the stable ABI list for documentation annotations""" + """Generate/check the stable ABI list for documentation annotations + + See ``StableABIEntry`` in ``Doc/tools/extensions/c_annotations.py`` + for a description of each field. + """ writer = csv.DictWriter( outfile, ['role', 'name', 'added', 'ifdef_note', 'struct_abi_kind'], lineterminator='\n') writer.writeheader() - for item in manifest.select(REST_ROLES.keys(), include_abi_only=False): + kinds = set(ITEM_KIND_TO_DOC_ROLE) + for item in manifest.select(kinds, include_abi_only=False): if item.ifdef: ifdef_note = manifest.contents[item.ifdef].doc else: ifdef_note = None row = { - 'role': REST_ROLES[item.kind], + 'role': ITEM_KIND_TO_DOC_ROLE[item.kind], 'name': item.name, 'added': item.added, - 'ifdef_note': ifdef_note} + 'ifdef_note': ifdef_note, + } rows = [row] if item.kind == 'struct': row['struct_abi_kind'] = item.struct_abi_kind @@ -260,7 +266,8 @@ def gen_doc_annotations(manifest, args, outfile): rows.append({ 'role': 'member', 'name': f'{item.name}.{member_name}', - 'added': item.added}) + 'added': item.added, + }) writer.writerows(rows) @generator("ctypes_test", 'Lib/test/test_stable_abi_ctypes.py') diff --git a/Tools/c-analyzer/c_parser/preprocessor/gcc.py b/Tools/c-analyzer/c_parser/preprocessor/gcc.py index 14761570..1108bdef 100644 --- a/Tools/c-analyzer/c_parser/preprocessor/gcc.py +++ b/Tools/c-analyzer/c_parser/preprocessor/gcc.py @@ -125,7 +125,7 @@ def _iter_top_include_lines(lines, topfile, cwd, raw): partial = 0 # depth files = [topfile] - # We start at 1 in case there are source lines (including blank onces) + # We start at 1 in case there are source lines (including blank ones) # before the first marker line. Also, we already verified in # _parse_marker_line() that the preprocessor reported lno as 1. lno = 1 diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index b47393e6..ac60ee4e 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -422,7 +422,6 @@ Modules/_ctypes/_ctypes.c CreateSwappedType suffix - Modules/_ctypes/_ctypes.c - _unpickle - Modules/_ctypes/_ctypes.c PyCArrayType_from_ctype cache - Modules/_cursesmodule.c - ModDict - -Modules/_datetimemodule.c datetime_strptime module - Modules/_datetimemodule.c - PyDateTime_TimeZone_UTC - Modules/_datetimemodule.c - PyDateTime_Epoch - Modules/_datetimemodule.c - us_per_ms - diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index efd519ff..b55bfab3 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -86,6 +86,17 @@ def __repr__(self) -> str: Outputter = Callable[[], str] TemplateDict = dict[str, str] + +def c_id(name: str) -> str: + if len(name) == 1 and ord(name) < 256: + if name.isalnum(): + return f"_Py_LATIN1_CHR('{name}')" + else: + return f'_Py_LATIN1_CHR({ord(name)})' + else: + return f'&_Py_ID({name})' + + class _TextAccumulator(NamedTuple): text: list[str] append: Appender @@ -1504,7 +1515,7 @@ def render_function(self, clinic, f): template_dict['keywords_c'] = ' '.join('"' + k + '",' for k in data.keywords) keywords = [k for k in data.keywords if k] - template_dict['keywords_py'] = ' '.join('&_Py_ID(' + k + '),' + template_dict['keywords_py'] = ' '.join(c_id(k) + ',' for k in keywords) template_dict['format_units'] = ''.join(data.format_units) template_dict['parse_arguments'] = ', '.join(data.parse_arguments) diff --git a/Tools/i18n/pygettext.py b/Tools/i18n/pygettext.py index 3a0b27ba..0d16e8f7 100755 --- a/Tools/i18n/pygettext.py +++ b/Tools/i18n/pygettext.py @@ -341,6 +341,9 @@ def __waiting(self, ttype, tstring, lineno): if ttype == tokenize.NAME and tstring in ('class', 'def'): self.__state = self.__suiteseen return + if ttype == tokenize.NAME and tstring in ('class', 'def'): + self.__state = self.__ignorenext + return if ttype == tokenize.NAME and tstring in opts.keywords: self.__state = self.__keywordseen return @@ -448,6 +451,9 @@ def __openseen(self, ttype, tstring, lineno): }, file=sys.stderr) self.__state = self.__waiting + def __ignorenext(self, ttype, tstring, lineno): + self.__state = self.__waiting + def __addentry(self, msg, lineno=None, isdocstring=0): if lineno is None: lineno = self.__lineno diff --git a/Tools/msi/buildrelease.bat b/Tools/msi/buildrelease.bat index b140839f..28f8bf02 100644 --- a/Tools/msi/buildrelease.bat +++ b/Tools/msi/buildrelease.bat @@ -127,7 +127,7 @@ if "%1" EQU "x86" ( set OUTDIR_PLAT=amd64 set OBJDIR_PLAT=x64 ) else if "%1" EQU "ARM64" ( - set BUILD=%Py_OutDir%amd64\ + set BUILD=%Py_OutDir%arm64\ set PGO=%~2 set BUILD_PLAT=ARM64 set OUTDIR_PLAT=arm64 diff --git a/Tools/msi/pip/pip.wxs b/Tools/msi/pip/pip.wxs index 1d8083ca..627c4710 100644 --- a/Tools/msi/pip/pip.wxs +++ b/Tools/msi/pip/pip.wxs @@ -25,8 +25,8 @@ - - + + (&DefaultFeature=3) AND NOT (!DefaultFeature=3) diff --git a/Tools/peg_generator/peg_extension/peg_extension.c b/Tools/peg_generator/peg_extension/peg_extension.c index 7df134b5..d8545c9d 100644 --- a/Tools/peg_generator/peg_extension/peg_extension.c +++ b/Tools/peg_generator/peg_extension/peg_extension.c @@ -108,7 +108,7 @@ parse_string(PyObject *self, PyObject *args, PyObject *kwds) static PyObject * clear_memo_stats(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) { -#if defined(PY_DEBUG) +#if defined(Py_DEBUG) _PyPegen_clear_memo_statistics(); #endif Py_RETURN_NONE; @@ -117,7 +117,7 @@ clear_memo_stats(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) static PyObject * get_memo_stats(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) { -#if defined(PY_DEBUG) +#if defined(Py_DEBUG) return _PyPegen_get_memo_statistics(); #else Py_RETURN_NONE; @@ -128,7 +128,7 @@ get_memo_stats(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) static PyObject * dump_memo_stats(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) { -#if defined(PY_DEBUG) +#if defined(Py_DEBUG) PyObject *list = _PyPegen_get_memo_statistics(); if (list == NULL) { return NULL; diff --git a/Tools/requirements-hypothesis.txt b/Tools/requirements-hypothesis.txt index 9db2b74c..66898885 100644 --- a/Tools/requirements-hypothesis.txt +++ b/Tools/requirements-hypothesis.txt @@ -1,4 +1,4 @@ # Requirements file for hypothesis that # we use to run our property-based tests in CI. -hypothesis==6.84.0 +hypothesis==6.111.2 diff --git a/Tools/ssl/multissltests.py b/Tools/ssl/multissltests.py index efc4b243..2cab972a 100755 --- a/Tools/ssl/multissltests.py +++ b/Tools/ssl/multissltests.py @@ -43,13 +43,14 @@ log = logging.getLogger("multissl") OPENSSL_OLD_VERSIONS = [ + "1.1.1w", ] OPENSSL_RECENT_VERSIONS = [ - "1.1.1w", - "3.0.13", - "3.1.5", - "3.2.1", + "3.0.15", + "3.1.7", + "3.2.3", + "3.3.2", ] LIBRESSL_OLD_VERSIONS = [ @@ -394,6 +395,7 @@ def run_python_tests(self, tests, network=True): class BuildOpenSSL(AbstractBuilder): library = "OpenSSL" url_templates = ( + "https://github.com/openssl/openssl/releases/download/openssl-{v}/openssl-{v}.tar.gz", "https://www.openssl.org/source/openssl-{v}.tar.gz", "https://www.openssl.org/source/old/{s}/openssl-{v}.tar.gz" ) @@ -436,6 +438,7 @@ def short_version(self): parsed = parsed[:2] return ".".join(str(i) for i in parsed) + class BuildLibreSSL(AbstractBuilder): library = "LibreSSL" url_templates = ( diff --git a/Tools/unicode/makeunicodedata.py b/Tools/unicode/makeunicodedata.py index 034642db..8732db22 100644 --- a/Tools/unicode/makeunicodedata.py +++ b/Tools/unicode/makeunicodedata.py @@ -35,7 +35,7 @@ from textwrap import dedent from typing import Iterator, List, Optional, Set, Tuple -SCRIPT = sys.argv[0] +SCRIPT = os.path.normpath(sys.argv[0]) VERSION = "3.3" # The Unicode Database diff --git a/aclocal.m4 b/aclocal.m4 index 09ae5d1a..97514d83 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -41,32 +41,81 @@ m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun # If neither value is found, the user is instructed to specify the # ordering. # +# Early versions of this macro (i.e., before serial 12) would not work +# when interprocedural optimization (via link-time optimization) was +# enabled. This would happen when, say, the GCC/clang "-flto" flag, or the +# ICC "-ipo" flag was used, for example. The problem was that under +# these conditions, the compiler did not allocate for and write the special +# float value in the data segment of the object file, since doing so might +# not prove optimal once more context was available. Thus, the special value +# (in platform-dependent binary form) could not be found in the object file, +# and the macro would fail. +# +# The solution to the above problem was to: +# +# 1) Compile and link a whole test program rather than just compile an +# object file. This ensures that we reach the point where even an +# interprocedural optimizing compiler writes values to the data segment. +# +# 2) Add code that requires the compiler to write the special value to +# the data segment, as opposed to "optimizing away" the variable's +# allocation. This could be done via compiler keywords or options, but +# it's tricky to make this work for all versions of all compilers with +# all optimization settings. The chosen solution was to make the exit +# code of the test program depend on the storing of the special value +# in memory (in the data segment). Because the exit code can be +# verified, any compiler that aspires to be correct will produce a +# program binary that contains the value, which the macro can then find. +# +# How does the exit code depend on the special value residing in memory? +# Memory, unlike variables and registers, can be addressed indirectly at run +# time. The exit code of this test program is a result of indirectly reading +# and writing to the memory region where the special value is supposed to +# reside. The actual memory addresses used and the values to be written are +# derived from the the program input ("argv") and are therefore not known at +# compile or link time. The compiler has no choice but to defer the +# computation to run time, and to prepare by allocating and populating the +# data segment with the special value. For further details, refer to the +# source code of the test program. +# +# Note that the test program is never meant to be run. It only exists to host +# a double float value in a given platform's binary format. Thus, error +# handling is not included. +# # LICENSE # -# Copyright (c) 2008 Daniel Amelang +# Copyright (c) 2008, 2023 Daniel Amelang # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 11 +#serial 12 AC_DEFUN([AX_C_FLOAT_WORDS_BIGENDIAN], [AC_CACHE_CHECK(whether float word ordering is bigendian, ax_cv_c_float_words_bigendian, [ ax_cv_c_float_words_bigendian=unknown -AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ +AC_LINK_IFELSE([AC_LANG_SOURCE([[ + +#include + +static double m[] = {9.090423496703681e+223, 0.0}; -double d = 90904234967036810337470478905505011476211692735615632014797120844053488865816695273723469097858056257517020191247487429516932130503560650002327564517570778480236724525140520121371739201496540132640109977779420565776568942592.0; +int main (int argc, char *argv[]) +{ + m[atoi (argv[1])] += atof (argv[2]); + return m[atoi (argv[3])] > 0.0; +} ]])], [ -if grep noonsees conftest.$ac_objext >/dev/null ; then +if grep noonsees conftest$EXEEXT >/dev/null ; then ax_cv_c_float_words_bigendian=yes fi -if grep seesnoon conftest.$ac_objext >/dev/null ; then +if grep seesnoon conftest$EXEEXT >/dev/null ; then if test "$ax_cv_c_float_words_bigendian" = unknown; then ax_cv_c_float_words_bigendian=no else diff --git a/configure b/configure index 6dc8a66e..241cf8f3 100755 --- a/configure +++ b/configure @@ -7252,6 +7252,9 @@ fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $EXEEXT" >&5 printf "%s\n" "$EXEEXT" >&6; } +# Make sure we keep EXEEXT and ac_exeext sync'ed. +ac_exeext=$EXEEXT + # Test whether we're running on a non-case-sensitive system, in which # case we give a warning if no ext is given @@ -9509,7 +9512,7 @@ then : else $as_nop py_cflags=$CFLAGS - as_fn_append CFLAGS "-Wextra -Werror" + as_fn_append CFLAGS " -Wextra -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -9627,7 +9630,7 @@ then : else $as_nop py_cflags=$CFLAGS - as_fn_append CFLAGS "-Wunused-result -Werror" + as_fn_append CFLAGS " -Wunused-result -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -9672,7 +9675,7 @@ then : else $as_nop py_cflags=$CFLAGS - as_fn_append CFLAGS "-Wunused-parameter -Werror" + as_fn_append CFLAGS " -Wunused-parameter -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -9713,7 +9716,7 @@ then : else $as_nop py_cflags=$CFLAGS - as_fn_append CFLAGS "-Wint-conversion -Werror" + as_fn_append CFLAGS " -Wint-conversion -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -9754,7 +9757,7 @@ then : else $as_nop py_cflags=$CFLAGS - as_fn_append CFLAGS "-Wmissing-field-initializers -Werror" + as_fn_append CFLAGS " -Wmissing-field-initializers -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -9795,7 +9798,7 @@ then : else $as_nop py_cflags=$CFLAGS - as_fn_append CFLAGS "-Wsign-compare -Werror" + as_fn_append CFLAGS " -Wsign-compare -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -9836,7 +9839,7 @@ then : else $as_nop py_cflags=$CFLAGS - as_fn_append CFLAGS "-Wunreachable-code -Werror" + as_fn_append CFLAGS " -Wunreachable-code -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -9888,7 +9891,7 @@ then : else $as_nop py_cflags=$CFLAGS - as_fn_append CFLAGS "-Wstrict-prototypes -Werror" + as_fn_append CFLAGS " -Wstrict-prototypes -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -12789,7 +12792,7 @@ then BLDSHARED="$LDSHARED" fi ;; - Emscripten|WASI) + Emscripten*|WASI*) LDSHARED='$(CC) -shared' LDCXXSHARED='$(CXX) -shared';; Linux*|GNU*|QNX*|VxWorks*|Haiku*) @@ -22041,16 +22044,18 @@ else $as_nop #include #endif #include + volatile void *func; int main (void) { #ifdef HAVE_CRYPT_R - void *x = crypt_r; + func = crypt_r; #else - void *x = crypt; + func = crypt; #endif + return (func != NULL); ; return 0; @@ -23520,18 +23525,26 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -double d = 90904234967036810337470478905505011476211692735615632014797120844053488865816695273723469097858056257517020191247487429516932130503560650002327564517570778480236724525140520121371739201496540132640109977779420565776568942592.0; +#include + +static double m[] = {9.090423496703681e+223, 0.0}; + +int main (int argc, char *argv[]) +{ + m[atoi (argv[1])] += atof (argv[2]); + return m[atoi (argv[3])] > 0.0; +} _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : -if grep noonsees conftest.$ac_objext >/dev/null ; then +if grep noonsees conftest$EXEEXT >/dev/null ; then ax_cv_c_float_words_bigendian=yes fi -if grep seesnoon conftest.$ac_objext >/dev/null ; then +if grep seesnoon conftest$EXEEXT >/dev/null ; then if test "$ax_cv_c_float_words_bigendian" = unknown; then ax_cv_c_float_words_bigendian=no else @@ -23541,7 +23554,8 @@ fi fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_c_float_words_bigendian" >&5 printf "%s\n" "$ax_cv_c_float_words_bigendian" >&6; } @@ -23549,41 +23563,34 @@ printf "%s\n" "$ax_cv_c_float_words_bigendian" >&6; } case $ax_cv_c_float_words_bigendian in yes) -printf "%s\n" "#define FLOAT_WORDS_BIGENDIAN 1" >>confdefs.h +printf "%s\n" "#define DOUBLE_IS_BIG_ENDIAN_IEEE754 1" >>confdefs.h ;; no) - ;; - *) - as_fn_error $? " - -Unknown float word ordering. You need to manually preset -ax_cv_c_float_words_bigendian=no (or yes) according to your system. - - " "$LINENO" 5 ;; -esac +printf "%s\n" "#define DOUBLE_IS_LITTLE_ENDIAN_IEEE754 1" >>confdefs.h + ;; + *) + case $host_cpu in #( + *arm*) : + # Some ARM platforms use a mixed-endian representation for + # doubles. While Python doesn't currently have full support + # for these platforms (see e.g., issue 1762561), we can at + # least make sure that float <-> string conversions work. + # FLOAT_WORDS_BIGENDIAN doesn't actually detect this case, + # but if it's not big or little, then it must be this? -if test "$ax_cv_c_float_words_bigendian" = "yes" -then - -printf "%s\n" "#define DOUBLE_IS_BIG_ENDIAN_IEEE754 1" >>confdefs.h - -elif test "$ax_cv_c_float_words_bigendian" = "no" -then +printf "%s\n" "#define DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754 1" >>confdefs.h + ;; #( + wasm*) : printf "%s\n" "#define DOUBLE_IS_LITTLE_ENDIAN_IEEE754 1" >>confdefs.h + ;; #( + *) : + ;; +esac ;; +esac -else - # Some ARM platforms use a mixed-endian representation for doubles. - # While Python doesn't currently have full support for these platforms - # (see e.g., issue 1762561), we can at least make sure that float <-> string - # conversions work. - # FLOAT_WORDS_BIGENDIAN doesnt actually detect this case, but if it's not big - # or little, then it must be this? - -printf "%s\n" "#define DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754 1" >>confdefs.h -fi # The short float repr introduced in Python 3.1 requires the # correctly-rounded string <-> double conversion functions from @@ -28646,9 +28653,15 @@ case $ac_sys_system in #( py_cv_module__ctypes_test=n/a + py_cv_module__testexternalinspection=n/a + py_cv_module__testimportmultiple=n/a + py_cv_module__testmultiphase=n/a + py_cv_module__testsinglephase=n/a py_cv_module_fcntl=n/a py_cv_module_mmap=n/a py_cv_module_termios=n/a + py_cv_module_xxlimited=n/a + py_cv_module_xxlimited_35=n/a py_cv_module_=n/a diff --git a/configure.ac b/configure.ac index 8a32cb58..9270b5f7 100644 --- a/configure.ac +++ b/configure.ac @@ -1308,6 +1308,9 @@ AC_ARG_WITH([suffix], ]) AC_MSG_RESULT([$EXEEXT]) +# Make sure we keep EXEEXT and ac_exeext sync'ed. +AS_VAR_SET([ac_exeext], [$EXEEXT]) + # Test whether we're running on a non-case-sensitive system, in which # case we give a warning if no ext is given AC_SUBST([BUILDEXEEXT]) @@ -1599,7 +1602,7 @@ then AS_VAR_IF([host_cpu], [wasm64], [AS_VAR_APPEND([HOSTRUNNER], [" --experimental-wasm-memory64"])]) ], dnl TODO: support other WASI runtimes - dnl wasmtime starts the proces with "/" as CWD. For OOT builds add the + dnl wasmtime starts the process with "/" as CWD. For OOT builds add the dnl directory containing _sysconfigdata to PYTHONPATH. [WASI/*], [HOSTRUNNER='wasmtime run --wasm max-wasm-stack=8388608 --wasi preview2 --env PYTHONPATH=/$(shell realpath --relative-to $(abs_srcdir) $(abs_builddir))/$(shell cat pybuilddir.txt):/Lib --dir $(srcdir)::/'], [HOSTRUNNER=''] @@ -2371,7 +2374,7 @@ AC_DEFUN([PY_CHECK_CC_WARNING], [ AS_VAR_PUSHDEF([py_var], [ac_cv_$1_]m4_normalize($2)[_warning]) AC_CACHE_CHECK([m4_ifblank([$3], [if we can $1 $CC $2 warning], [$3])], [py_var], [ AS_VAR_COPY([py_cflags], [CFLAGS]) - AS_VAR_APPEND([CFLAGS], ["-W$2 -Werror"]) + AS_VAR_APPEND([CFLAGS], [" -W$2 -Werror"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], [AS_VAR_SET([py_var], [yes])], [AS_VAR_SET([py_var], [no])]) @@ -3356,7 +3359,7 @@ then BLDSHARED="$LDSHARED" fi ;; - Emscripten|WASI) + Emscripten*|WASI*) LDSHARED='$(CC) -shared' LDCXXSHARED='$(CXX) -shared';; Linux*|GNU*|QNX*|VxWorks*|Haiku*) @@ -3402,7 +3405,7 @@ then LDCXXSHARED='$(CXX) -Wl,-G,-Bexport';; WASI*) AS_VAR_IF([enable_wasm_dynamic_linking], [yes], [ - dnl not iplemented yet + dnl not implemented yet ]);; CYGWIN*) LDSHARED="gcc -shared -Wl,--enable-auto-image-base" @@ -3572,7 +3575,7 @@ esac AC_MSG_RESULT([$SHLIBS]) dnl perf trampoline is Linux specific and requires an arch-specific -dnl trampoline in asssembly. +dnl trampoline in assembly. AC_MSG_CHECKING([perf trampoline]) AS_CASE([$PLATFORM_TRIPLET], [x86_64-linux-gnu], [perf_trampoline=yes], @@ -5237,12 +5240,14 @@ WITH_SAVE_ENV([ #include #endif #include + volatile void *func; ], [ #ifdef HAVE_CRYPT_R - void *x = crypt_r; + func = crypt_r; #else - void *x = crypt; + func = crypt; #endif + return (func != NULL); ]) ], [ac_cv_crypt_crypt=yes], [ac_cv_crypt_crypt=no]) ]) @@ -5674,28 +5679,26 @@ AS_VAR_IF([ac_cv_gcc_asm_for_x64], [yes], [ # * Check for various properties of floating point * # ************************************************** -AX_C_FLOAT_WORDS_BIGENDIAN -if test "$ax_cv_c_float_words_bigendian" = "yes" -then - AC_DEFINE([DOUBLE_IS_BIG_ENDIAN_IEEE754], [1], - [Define if C doubles are 64-bit IEEE 754 binary format, stored - with the most significant byte first]) -elif test "$ax_cv_c_float_words_bigendian" = "no" -then - AC_DEFINE([DOUBLE_IS_LITTLE_ENDIAN_IEEE754], [1], - [Define if C doubles are 64-bit IEEE 754 binary format, stored - with the least significant byte first]) -else - # Some ARM platforms use a mixed-endian representation for doubles. - # While Python doesn't currently have full support for these platforms - # (see e.g., issue 1762561), we can at least make sure that float <-> string - # conversions work. - # FLOAT_WORDS_BIGENDIAN doesnt actually detect this case, but if it's not big - # or little, then it must be this? - AC_DEFINE([DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754], [1], - [Define if C doubles are 64-bit IEEE 754 binary format, stored - in ARM mixed-endian order (byte order 45670123)]) -fi +AX_C_FLOAT_WORDS_BIGENDIAN( + [AC_DEFINE([DOUBLE_IS_BIG_ENDIAN_IEEE754], [1], + [Define if C doubles are 64-bit IEEE 754 binary format, + stored with the most significant byte first])], + [AC_DEFINE([DOUBLE_IS_LITTLE_ENDIAN_IEEE754], [1], + [Define if C doubles are 64-bit IEEE 754 binary format, + stored with the least significant byte first])], + [AS_CASE([$host_cpu], + [*arm*], [# Some ARM platforms use a mixed-endian representation for + # doubles. While Python doesn't currently have full support + # for these platforms (see e.g., issue 1762561), we can at + # least make sure that float <-> string conversions work. + # FLOAT_WORDS_BIGENDIAN doesn't actually detect this case, + # but if it's not big or little, then it must be this? + AC_DEFINE([DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754], [1], + [Define if C doubles are 64-bit IEEE 754 binary format, + stored in ARM mixed-endian order (byte order 45670123)])], + [wasm*], [AC_DEFINE([DOUBLE_IS_LITTLE_ENDIAN_IEEE754], [1], + [Define if C doubles are 64-bit IEEE 754 binary format, + stored with the least significant byte first])])]) # The short float repr introduced in Python 3.1 requires the # correctly-rounded string <-> double conversion functions from @@ -7300,11 +7303,19 @@ AS_CASE([$ac_sys_system], [Emscripten/node*], [], [WASI/*], [ dnl WASI SDK 15.0 does not support file locking, mmap, and more. + dnl Test modules that must be compiled as shared libraries are not supported + dnl (see Modules/Setup.stdlib.in). PY_STDLIB_MOD_SET_NA( [_ctypes_test], + [_testexternalinspection], + [_testimportmultiple], + [_testmultiphase], + [_testsinglephase], [fcntl], [mmap], [termios], + [xxlimited], + [xxlimited_35], ) ] ) diff --git a/debian/PVER-dbg.postinst.in b/debian/PVER-dbg.postinst.in index 8f0208e8..2f015f9a 100644 --- a/debian/PVER-dbg.postinst.in +++ b/debian/PVER-dbg.postinst.in @@ -3,7 +3,7 @@ set -e if [ "$1" = configure ]; then - files=$(dpkg -L lib@PVER@-dbg@HOST_QUAL@ | sed -n '/^\/usr\/lib\/@PVER@\/.*\.py$/p') + files=$(LC_ALL=C.UTF8 dpkg -L @PVER@-dbg | sed -n '/^\/usr\/lib\/@PVER@\/.*\.py$/p') if [ -n "$files" ]; then /usr/bin/@PVER@ -E -S /usr/lib/@PVER@/py_compile.py $files if grep -sq '^byte-compile[^#]*optimize' /etc/python/debian_config; then diff --git a/debian/PVER-dbg.prerm.in b/debian/PVER-dbg.prerm.in index 3d92951d..fa1c5bb2 100644 --- a/debian/PVER-dbg.prerm.in +++ b/debian/PVER-dbg.prerm.in @@ -6,7 +6,7 @@ remove_bytecode() { pkg=$1 max=$(LANG=C LC_ALL=C xargs --show-limits < /dev/null 2>&1 | awk '/Maximum length/ {print int($NF / 4)}') - dpkg -L $pkg \ + LC_ALL=C.UTF8 dpkg -L $pkg \ | awk -F/ 'BEGIN {OFS="/"} /\.py$/ {$NF=sprintf("__pycache__/%s.*.py[co]", substr($NF,1,length($NF)-3)); print}' \ | xargs --max-chars=$max echo \ | while read files; do rm -f $files; done @@ -17,10 +17,10 @@ remove_bytecode() case "$1" in remove) - remove_bytecode lib@PVER@-dbg@HOST_QUAL@ + remove_bytecode @PVER@-dbg ;; upgrade) - remove_bytecode lib@PVER@-dbg@HOST_QUAL@ + remove_bytecode @PVER@-dbg ;; deconfigure) ;; diff --git a/debian/PVER-tk.postinst.in b/debian/PVER-tk.postinst.in new file mode 100644 index 00000000..da1df3c7 --- /dev/null +++ b/debian/PVER-tk.postinst.in @@ -0,0 +1,22 @@ +#! /bin/sh + +set -e + +case "$1" in + configure) + files=$(LC_ALL=C.UTF8 dpkg -L @PVER@-tk | sed -n '/^\/usr\/lib\/@PVER@\/.*\.py$/p') + if [ -n "$files" ]; then + if command -v @PVER@ >/dev/null; then + /usr/bin/@PVER@ -E -S /usr/lib/@PVER@/py_compile.py $files + if grep -sq '^byte-compile[^#]*optimize' /etc/python/debian_config; then + /usr/bin/@PVER@ -E -S -O /usr/lib/@PVER@/py_compile.py $files + fi + fi + else + echo >&2 "@PVER@: can't get files for byte-compilation" + fi +esac + +#DEBHELPER# + +exit 0 diff --git a/debian/PVER-tk.prerm.in b/debian/PVER-tk.prerm.in new file mode 100644 index 00000000..c0c9d324 --- /dev/null +++ b/debian/PVER-tk.prerm.in @@ -0,0 +1,35 @@ +#! /bin/sh + +set -e + +remove_bytecode() +{ + pkg=$1 + max=$(LANG=C LC_ALL=C xargs --show-limits < /dev/null 2>&1 | awk '/Maximum length/ {print int($NF / 4)}') + LC_ALL=C.UTF8 dpkg -L $pkg \ + | awk -F/ 'BEGIN {OFS="/"} /\.py$/ {$NF=sprintf("__pycache__/%s.*.py[co]", substr($NF,1,length($NF)-3)); print}' \ + | xargs --max-chars="$max" echo \ + | while read files; do rm -f $files; done + + find /usr/lib/@PVER@/tkinter \ + -name __pycache__ -type d -empty -print \ + | xargs -r rm -rf +} + +case "$1" in + remove) + remove_bytecode @PVER@-tk + ;; + upgrade) + ;; + deconfigure) + ;; + failed-upgrade) + ;; + *) + echo "prerm called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +#DEBHELPER# diff --git a/debian/PVER-venv.postinst.in b/debian/PVER-venv.postinst.in index a8304858..654a75e2 100644 --- a/debian/PVER-venv.postinst.in +++ b/debian/PVER-venv.postinst.in @@ -4,7 +4,7 @@ set -e case "$1" in configure) - files=$(dpkg -L @PVER@-venv | sed -n '/^\/usr\/lib\/@PVER@\/.*\.py$/p') + files=$(LC_ALL=C.UTF8 dpkg -L @PVER@-venv | sed -n '/^\/usr\/lib\/@PVER@\/.*\.py$/p') if [ -n "$files" ]; then /usr/bin/@PVER@ -E -S /usr/lib/@PVER@/py_compile.py $files if grep -sq '^byte-compile[^#]*optimize' /etc/python/debian_config; then diff --git a/debian/PVER-venv.prerm.in b/debian/PVER-venv.prerm.in index 9d864f0f..ad7706f2 100644 --- a/debian/PVER-venv.prerm.in +++ b/debian/PVER-venv.prerm.in @@ -6,7 +6,7 @@ remove_bytecode() { pkg=$1 max=$(LANG=C LC_ALL=C xargs --show-limits < /dev/null 2>&1 | awk '/Maximum length/ {print int($NF / 4)}') - dpkg -L $pkg \ + LC_ALL=C.UTF8 dpkg -L $pkg \ | awk -F/ 'BEGIN {OFS="/"} /\.py$/ {$NF=sprintf("__pycache__/%s.*.py[co]", substr($NF,1,length($NF)-3)); print}' \ | xargs --max-chars="$max" echo \ | while read files; do rm -f $files; done diff --git a/debian/PVER.postinst.in b/debian/PVER.postinst.in index 073bfb84..b158aecd 100644 --- a/debian/PVER.postinst.in +++ b/debian/PVER.postinst.in @@ -4,7 +4,7 @@ set -e case "$1" in configure) - files=$(dpkg -L lib@PVER@-stdlib@HOST_QUAL@ | sed -n '/^\/usr\/lib\/@PVER@\/.*\.py$/p') + files=$(LC_ALL=C.UTF8 dpkg -L lib@PVER@-stdlib@HOST_QUAL@ | sed -n '/^\/usr\/lib\/@PVER@\/.*\.py$/p') if [ -n "$files" ]; then /usr/bin/@PVER@ -E -S /usr/lib/@PVER@/py_compile.py $files if grep -sq '^byte-compile[^#]*optimize' /etc/python/debian_config; then diff --git a/debian/PVER.prerm.in b/debian/PVER.prerm.in index 0e7e5c59..a3cf30aa 100644 --- a/debian/PVER.prerm.in +++ b/debian/PVER.prerm.in @@ -6,7 +6,7 @@ remove_bytecode() { pkg=$1 max=$(LANG=C LC_ALL=C xargs --show-limits < /dev/null 2>&1 | awk '/Maximum length/ {print int($NF / 4)}') - dpkg -L $pkg \ + LC_ALL=C.UTF8 dpkg -L $pkg \ | awk -F/ 'BEGIN {OFS="/"} /\.py$/ {$NF=sprintf("__pycache__/%s.*.py[co]", substr($NF,1,length($NF)-3)); print}' \ | xargs --max-chars="$max" echo \ | while read files; do rm -f $files; done diff --git a/debian/changelog b/debian/changelog index ecda2f89..e8c1f3fe 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,9 +1,182 @@ -python3.12 (3.12.4-0deepin1) unstable; urgency=medium +python3.12 (3.12.8-3deepin1) UNRELEASED; urgency=medium + + * Revert t64 changes. + + -- Tianyu Chen Wed, 18 Dec 2024 18:05:18 +0800 + +python3.12 (3.12.8-3) unstable; urgency=medium + + * Update to the 3.12 branch 2024-12-13. + - Make sure extern "C" is closed when using Py_LIMITED_API (#127904). + Closes: #1089823. + + -- Matthias Klose Fri, 13 Dec 2024 14:19:48 +0100 + +python3.12 (3.12.8-2) unstable; urgency=medium + + * Update to the 3.12 branch 2024-12-12. + - Fix issue #127655, CVE-2024-12254. + * Add support for OpenSSL 3.4, issue #127330. + + -- Matthias Klose Thu, 12 Dec 2024 11:32:36 +0100 + +python3.12 (3.12.8-1) unstable; urgency=medium + + * Python 3.12.8 release. + * Refresh patches. + + -- Stefano Rivera Wed, 04 Dec 2024 08:15:27 -0400 + +python3.12 (3.12.7-3) unstable; urgency=medium + + * Strip the trailing + from PY_VERSION, again. (Closes: #1087011) + + -- Stefano Rivera Fri, 08 Nov 2024 09:55:36 -0800 + +python3.12 (3.12.7-2) unstable; urgency=medium + + * Update symbols file. + * Apply git updates to 2024-11-03. + * Adjust lib-argparse.diff to avoid failing test_argparse's translation + test. + + -- Stefano Rivera Mon, 04 Nov 2024 20:56:37 -0800 + +python3.12 (3.12.7-1) unstable; urgency=medium + + * Python 3.12.7 release. + * Refresh patches. + * Build-Depend on python3-{pip,setuptools,wheel}-whl for tests. + * Verify upstream PGP signature. + * Patch: Strip absolute --libdir paths from configure args in test_freeze. + + -- Stefano Rivera Thu, 03 Oct 2024 09:15:22 -0600 + +python3.12 (3.12.6-1) unstable; urgency=medium + + * Python 3.12.6 release. + - Fixes: CVE-2015-2104, CVE-2023-27043 (Closes: #1059299), CVE-2024-4030, + CVE-2024-4032, CVE-2024-6232, CVE-2024-6923, CVE-2024-7592, and + CVE-2024-8088. + * Refresh patches. + * Remove debian/locale-gen, we use locales-all. (Closes: #1076778) + * Re-enable build-time tests. (Closes: #1076779) + - Build-Depend on xvfb and xauth again. + + -- Stefano Rivera Sat, 07 Sep 2024 16:20:15 +0200 + +python3.12 (3.12.5-4) unstable; urgency=medium + + * python3.x-tk: Make byte-compilation depend on the availability of + the interpreter. + + -- Matthias Klose Thu, 22 Aug 2024 15:11:09 +0200 + +python3.12 (3.12.5-3) unstable; urgency=medium + + * Add python3.x-tk maintainer scripts. + * Call dpkg with LC_ALL=C.UTF8 set. + + -- Matthias Klose Thu, 22 Aug 2024 09:49:39 +0200 + +python3.12 (3.12.5-2) experimental; urgency=medium + + * Build python3.12-gdbm and python3.12-tk packages again; Having these + extensions hidden in the libpython-stdlib packages raises some chrootkit + warnings. These packages should not be used as dependencies, and do not + depend on the Python interpreter. For dependencies, the existing + python3-gdbm and python3-tk packages should be used. + + -- Matthias Klose Wed, 21 Aug 2024 09:45:53 +0200 + +python3.12 (3.12.5-1) unstable; urgency=medium + + * Python 3.12.5 release. + * libpython-stdlib: Include the _gdbm and _tkinter extensions, prefixed + with a dot, and no dependencies on the gbm and tcl/tk libraries. + * Refresh patches. + * Bump standards version. + + -- Matthias Klose Wed, 07 Aug 2024 15:49:14 +0200 + +python3.12 (3.12.4-3) unstable; urgency=medium + + [ Matthias Klose ] + * Set ELF_PACKAGE_METADATA, if unset. + * Fix multiarch path for hurd-amd64. Closes: #1076321. + * Don't configure -with-dtrace on the Hurd. Closes: #1065456. + * Update from the 3.12 branch 2024-07-15. + + [ Benjamin Drung ] + * debian/rules: Use pkg-info.mk. + * debian/rules: Use architecture.mk. + * Rely on SOURCE_DATE_EPOCH for reproducibility. + + [ Graham Inggs ] + * Drop test dependencies on python3-distutils. + * Skip test_exceptions and test_repl which never run to + completion on the Ubuntu autopkgtest infrastructure. + + -- Matthias Klose Mon, 15 Jul 2024 14:17:32 +0200 + +python3.12 (3.12.4-1) unstable; urgency=medium * Python 3.12.4 release. * Refresh patches. + * Patch: Ignore test/wheeldata completely in test_makefile. + + -- Stefano Rivera Wed, 12 Jun 2024 20:06:53 +0100 + +python3.12 (3.12.3-1) unstable; urgency=medium + + * Python 3.12.3 release. + + -- Matthias Klose Wed, 10 Apr 2024 07:33:47 +0200 + +python3.12 (3.12.2-5) unstable; urgency=medium + + * Update to the 3.12 branch 2024-02-02. + - Make C API compatible with ISO C90 (GH-116950). Closes: #1064028. + - Upstream patch for GH-115874. + - Still identify as "3.12.2", because "3.12.2+" is mis-treated by some + third-party packages. + * Use CFLAGS_NODIST, LDFLAGS_NODIST for passing build flags. + * d/rules: Move configure/build targets for each build together. + * Drop ffi configure options, obsolete. + * Re-enable PGO/LTO builds. + + -- Matthias Klose Tue, 02 Apr 2024 16:53:02 +0200 + +python3.12 (3.12.2-4) unstable; urgency=medium + + [ Stefano Rivera ] + * Build-Depend on libnsl-dev for NIS support. Closes: #1065128. + + [ Matthias Klose ] + * Fix override files for renamed t64 packages. + * Fix package names in PVER-dbg maintainer scripts. Addresses: #1065164. + * Really build without LTO when requested. + * Disable LTO builds and testsuite for now (mesa t64 transition ...). + + -- Matthias Klose Sun, 03 Mar 2024 10:11:00 +0100 + +python3.12 (3.12.2-3) unstable; urgency=medium + + * Actually apply the teedataobject_clear patch. Closes: #1063345. + + -- Stefano Rivera Thu, 29 Feb 2024 11:43:19 -0400 + +python3.12 (3.12.2-2) unstable; urgency=medium + + [ Colin Watson ] + * Don't rely on module state in teedataobject_clear (from Brandt Bucher in + https://github.com/python/cpython/issues/115874). Closes: #1063345. + + [ Steve Langasek ] + * Rename libraries for 64-bit time_t transition, declare X-Time64-Compat + to get proper Provides (Steve Langasek). Closes: #1064336. - -- Tianyu Chen Tue, 09 Jul 2024 11:31:23 +0200 + -- Matthias Klose Thu, 29 Feb 2024 02:56:09 +0100 python3.12 (3.12.2-1) unstable; urgency=medium diff --git a/debian/control b/debian/control index 84901df4..ac403ab2 100644 --- a/debian/control +++ b/debian/control @@ -9,18 +9,25 @@ Build-Depends: debhelper (>= 11), dpkg-dev (>= 1.17.11), libreadline-dev | libeditreadline-dev, libncurses-dev, zlib1g-dev, libbz2-dev, liblzma-dev, libgdbm-dev, libdb-dev, - tk-dev, blt-dev (>= 2.4z), libssl-dev, + tk-dev, blt-dev (>= 2.4z), + libssl-dev, libexpat1-dev, libbluetooth-dev [linux-any] , locales-all, + libnsl-dev, libsqlite3-dev, libffi-dev (>= 3.0.5) [!or1k], libgpm2 [linux-any], media-types | mime-support, netbase, bzip2, time, python3:any, python3.12:any , - net-tools, xvfb , xauth , tzdata , + net-tools, + python3-pip-whl , + python3-setuptools-whl , + python3-wheel-whl , + xvfb , xauth , + tzdata , systemtap-sdt-dev [!hurd-amd64 !hurd-i386], valgrind-if-available, Build-Depends-Indep: python3-sphinx, python3-docs-theme, texinfo -Standards-Version: 4.6.2 +Standards-Version: 4.7.0 Vcs-Browser: https://salsa.debian.org/cpython-team/python3 Vcs-Git: https://salsa.debian.org/cpython-team/python3.git XS-Testsuite: autopkgtest @@ -240,8 +247,10 @@ Architecture: any Multi-Arch: same Pre-Depends: ${misc:Pre-Depends} Depends: libpython3.12-stdlib (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} -Breaks: python3-gdbm-dbg (<< 3.9.9-1~) -Replaces: python3-gdbm-dbg (<< 3.9.9-1~) +Breaks: libpython3.12-dbg (<< ${source:Version}), + python3-gdbm-dbg (<< 3.12.5-2~), python3-tk-dbg (<< 3.12.5-2~) +Replaces: libpython3.12-dbg, + python3-gdbm-dbg (<< 3.12.5-2~), python3-tk-dbg (<< 3.12.5-2~) Description: Debug Build of the Python Interpreter (version 3.12) The package holds two things: . @@ -276,3 +285,25 @@ Description: Python Interpreter with complete class library (version 3.12) . According to the Debian Python policy, this package must not be used in build dependencies, dependencies and recommendations. + +Package: python3.12-tk +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Enhances: python3.12 +Suggests: tix +Breaks: python3-tk (<< 3.12.5-2~) +Replaces: python3-tk (<< 3.12.5-2~) +XB-Python-Version: 3.12 +Description: Tkinter - Writing Tk applications with Python (v3.12) + A module for writing portable GUI applications with Python (v3.12) using Tk. + Also known as Tkinter. + +Package: python3.12-gdbm +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Enhances: python3.12 +Breaks: python3-gdbm (<< 3.12.5-2~) +Replaces: python3-gdbm (<< 3.12.5-2~) +Description: GNU dbm database support for Python (v3.12) + GNU dbm database module for Python. Install this if you want to + create or read GNU dbm database files with Python. diff --git a/debian/control.in b/debian/control.in index 8b7d1df2..a6186fae 100644 --- a/debian/control.in +++ b/debian/control.in @@ -9,18 +9,25 @@ Build-Depends: debhelper (>= 11), @bd_dpkgdev@ libreadline-dev | libeditreadline-dev, libncurses-dev, @bd_gcc@ zlib1g-dev, libbz2-dev, liblzma-dev, libgdbm-dev, @bd_dbm@, - tk-dev, blt-dev (>= 2.4z), libssl-dev, + tk-dev, blt-dev (>= 2.4z), + libssl-dev, libexpat1-dev, libbluetooth-dev [linux-any] , locales-all, + libnsl-dev, libsqlite3-dev, libffi-dev (>= 3.0.5) [!or1k], libgpm2 [linux-any], media-types | mime-support, netbase, bzip2, time, python3@bd_qual@, @PVER@@bd_qual@ , - net-tools, xvfb , xauth , tzdata , + net-tools, + python3-pip-whl , + python3-setuptools-whl , + python3-wheel-whl , + xvfb , xauth , + tzdata , systemtap-sdt-dev [!hurd-amd64 !hurd-i386], valgrind-if-available, Build-Depends-Indep: python3-sphinx, python3-docs-theme, texinfo -Standards-Version: 4.6.2 +Standards-Version: 4.7.0 Vcs-Browser: https://salsa.debian.org/cpython-team/python3 Vcs-Git: https://salsa.debian.org/cpython-team/python3.git XS-Testsuite: autopkgtest @@ -240,8 +247,10 @@ Architecture: any Multi-Arch: same Pre-Depends: ${misc:Pre-Depends} Depends: lib@PVER@-stdlib (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} -Breaks: python3-gdbm-dbg (<< 3.9.9-1~) -Replaces: python3-gdbm-dbg (<< 3.9.9-1~) +Breaks: lib@PVER@-dbg (<< ${source:Version}), + python3-gdbm-dbg (<< 3.12.5-2~), python3-tk-dbg (<< 3.12.5-2~) +Replaces: lib@PVER@-dbg, + python3-gdbm-dbg (<< 3.12.5-2~), python3-tk-dbg (<< 3.12.5-2~) Description: Debug Build of the Python Interpreter (version @VER@) The package holds two things: . diff --git a/debian/control.stdlib b/debian/control.stdlib index fa1d4446..c1c5c4d5 100644 --- a/debian/control.stdlib +++ b/debian/control.stdlib @@ -1,7 +1,11 @@ + Package: @PVER@-tk Architecture: any -Depends: @PVER@ (= ${Source-Version}), ${shlibs:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends} +Enhances: @PVER@ Suggests: tix +Breaks: python3-tk (<< 3.12.5-2~) +Replaces: python3-tk (<< 3.12.5-2~) XB-Python-Version: @VER@ Description: Tkinter - Writing Tk applications with Python (v@VER@) A module for writing portable GUI applications with Python (v@VER@) using Tk. @@ -9,8 +13,10 @@ Description: Tkinter - Writing Tk applications with Python (v@VER@) Package: @PVER@-gdbm Architecture: any -Depends: @PVER@ (= ${Source-Version}), ${shlibs:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends} +Enhances: @PVER@ +Breaks: python3-gdbm (<< 3.12.5-2~) +Replaces: python3-gdbm (<< 3.12.5-2~) Description: GNU dbm database support for Python (v@VER@) GNU dbm database module for Python. Install this if you want to create or read GNU dbm database files with Python. - diff --git a/debian/idle-PVER.prerm.in b/debian/idle-PVER.prerm.in index 6fc9ca63..de035f8b 100644 --- a/debian/idle-PVER.prerm.in +++ b/debian/idle-PVER.prerm.in @@ -6,7 +6,7 @@ remove_bytecode() { pkg=$1 max=$(LANG=C LC_ALL=C xargs --show-limits < /dev/null 2>&1 | awk '/Maximum length/ {print int($NF / 4)}') - dpkg -L $pkg \ + LC_ALL=C.UTF8 dpkg -L $pkg \ | awk -F/ 'BEGIN {OFS="/"} /\.py$/ {$NF=sprintf("__pycache__/%s.*.py[co]", substr($NF,1,length($NF)-3)); print}' \ | xargs --max-chars=$max echo \ | while read files; do rm -f $files; done diff --git a/debian/libPVER-dbg.overrides.in b/debian/libPVER-dbg.overrides.in index 2496cd5f..edd9f468 100644 --- a/debian/libPVER-dbg.overrides.in +++ b/debian/libPVER-dbg.overrides.in @@ -1,4 +1,3 @@ -lib@PVER@-dbg binary: package-name-doesnt-match-sonames lib@PVER@-dbg binary: non-dev-pkg-with-shlib-symlink # no, it's not unusual diff --git a/debian/libPVER-minimal.postrm.in b/debian/libPVER-minimal.postrm.in index e267ac41..e44228d2 100644 --- a/debian/libPVER-minimal.postrm.in +++ b/debian/libPVER-minimal.postrm.in @@ -3,7 +3,7 @@ set -e if [ "$1" = "purge" ]; then - pc=$(dpkg-query -f '${db:Status-Abbrev} ${binary:Package}\n' -W lib@PVER@-minimal \ + pc=$(LC_ALL=C.UTF8 dpkg-query -f '${db:Status-Abbrev} ${binary:Package}\n' -W lib@PVER@-minimal \ | grep -v '^.n' | wc -l) if [ "$pc" -lt 1 ]; then find /usr/lib/@PVER@ -depth -type d -name __pycache__ \ diff --git a/debian/libPVER-minimal.prerm.in b/debian/libPVER-minimal.prerm.in index 16aa0840..65e75b92 100644 --- a/debian/libPVER-minimal.prerm.in +++ b/debian/libPVER-minimal.prerm.in @@ -6,7 +6,7 @@ remove_bytecode() { pkg=$1 max=$(LANG=C LC_ALL=C xargs --show-limits < /dev/null 2>&1 | awk '/Maximum length/ {print int($NF / 4)}') - dpkg -L $pkg \ + LC_ALL=C.UTF8 dpkg -L $pkg \ | awk -F/ 'BEGIN {OFS="/"} /\.py$/ {$NF=sprintf("__pycache__/%s.*.py[co]", substr($NF,1,length($NF)-3)); print}' \ | xargs --max-chars="$max" echo \ | while read files; do rm -f $files; done @@ -18,7 +18,7 @@ remove_bytecode() case "$1" in remove) - pc=$(dpkg-query -f '${db:Status-Abbrev} ${binary:Package}\n' -W lib@PVER@-minimal \ + pc=$(LC_ALL=C.UTF8 dpkg-query -f '${db:Status-Abbrev} ${binary:Package}\n' -W lib@PVER@-minimal \ | grep -v '^.n' | wc -l) if [ "$pc" -le 1 ]; then remove_bytecode lib@PVER@-minimal@HOST_QUAL@ diff --git a/debian/libPVER-stdlib.prerm.in b/debian/libPVER-stdlib.prerm.in index 4a5611b6..897eabfa 100644 --- a/debian/libPVER-stdlib.prerm.in +++ b/debian/libPVER-stdlib.prerm.in @@ -6,7 +6,7 @@ remove_bytecode() { pkg=$1 max=$(LANG=C LC_ALL=C xargs --show-limits < /dev/null 2>&1 | awk '/Maximum length/ {print int($NF / 4)}') - dpkg -L $pkg \ + LC_ALL=C.UTF8 dpkg -L $pkg \ | awk -F/ 'BEGIN {OFS="/"} /\.py$/ {$NF=sprintf("__pycache__/%s.*.py[co]", substr($NF,1,length($NF)-3)); print}' \ | xargs --max-chars="$max" echo \ | while read files; do rm -f $files; done @@ -20,7 +20,7 @@ remove_bytecode() case "$1" in remove) - pc=$(dpkg-query -f '${db:Status-Abbrev} ${binary:Package}\n' -W lib@PVER@-stdlib \ + pc=$(LC_ALL=C.UTF8 dpkg-query -f '${db:Status-Abbrev} ${binary:Package}\n' -W lib@PVER@-stdlib \ | grep -v '^.n' | wc -l) if [ "$pc" -le 1 ]; then remove_bytecode lib@PVER@-stdlib@HOST_QUAL@ diff --git a/debian/libPVER-testsuite.postinst.in b/debian/libPVER-testsuite.postinst.in index 45b81e97..d11ca230 100644 --- a/debian/libPVER-testsuite.postinst.in +++ b/debian/libPVER-testsuite.postinst.in @@ -4,7 +4,7 @@ set -e case "$1" in configure) - files=$(dpkg -L lib@PVER@-testsuite | sed -n '/^\/usr\/lib\/@PVER@\/.*\.py$/p' | grep -Ev '/test_lib2to3/data|/tokenizedata/bad_|/badsyntax_') + files=$(LC_ALL=C.UTF8 dpkg -L lib@PVER@-testsuite | sed -n '/^\/usr\/lib\/@PVER@\/.*\.py$/p' | grep -Ev '/test_lib2to3/data|/tokenizedata/bad_|/badsyntax_') if [ -n "$files" ]; then /usr/bin/@PVER@ -E -S -W ignore /usr/lib/@PVER@/py_compile.py $files if grep -sq '^byte-compile[^#]*optimize' /etc/python/debian_config; then diff --git a/debian/libPVER-testsuite.prerm.in b/debian/libPVER-testsuite.prerm.in index f003f91a..eddeb91c 100644 --- a/debian/libPVER-testsuite.prerm.in +++ b/debian/libPVER-testsuite.prerm.in @@ -6,7 +6,7 @@ remove_bytecode() { pkg=$1 max=$(LANG=C LC_ALL=C xargs --show-limits < /dev/null 2>&1 | awk '/Maximum length/ {print int($NF / 4)}') - dpkg -L $pkg \ + LC_ALL=C.UTF8 dpkg -L $pkg \ | awk -F/ 'BEGIN {OFS="/"} /\.py$/ {$NF=sprintf("__pycache__/%s.*.py[co]", substr($NF,1,length($NF)-3)); print}' \ | xargs --max-chars="$max" echo \ | while read files; do rm -f $files; done diff --git a/debian/libPVER.overrides.in b/debian/libPVER.overrides.in index 062dd469..aeb562aa 100644 --- a/debian/libPVER.overrides.in +++ b/debian/libPVER.overrides.in @@ -1,4 +1,2 @@ -lib@PVER@ binary: package-name-doesnt-match-sonames - # pyexpat.c contains expat error messages that lintian mis-attributes to embedding lib@PVER@ binary: embedded-library diff --git a/debian/libpython.symbols.in b/debian/libpython.symbols.in index 2169c972..a70c6194 100644 --- a/debian/libpython.symbols.in +++ b/debian/libpython.symbols.in @@ -1567,6 +1567,9 @@ _PyUnicode_FromASCII@Base @SVER@ _PyUnicode_FromId@Base @SVER@ _PyUnicode_InsertThousandsGrouping@Base @SVER@ + _PyUnicode_InternImmortal@Base @SVER@ + _PyUnicode_InternInPlace@Base @SVER@ + _PyUnicode_InternMortal@Base @SVER@ _PyUnicode_IsAlpha@Base @SVER@ _PyUnicode_IsCaseIgnorable@Base @SVER@ _PyUnicode_IsCased@Base @SVER@ diff --git a/debian/multiarch.h.in b/debian/multiarch.h.in index e00632c6..bb37cec9 100644 --- a/debian/multiarch.h.in +++ b/debian/multiarch.h.in @@ -115,7 +115,13 @@ # error unknown multiarch location for @header@ # endif #elif defined(__gnu_hurd__) -# include +# if defined(__LP64__) +# include +# elif defined(__i386__) +# include +# else +# error unknown multiarch location for @header@ +# endif #else # error unknown multiarch location for @header@ #endif diff --git a/debian/patches/argparse-no-shutil.diff b/debian/patches/argparse-no-shutil.diff index b105553f..a3b08cf2 100644 --- a/debian/patches/argparse-no-shutil.diff +++ b/debian/patches/argparse-no-shutil.diff @@ -6,7 +6,7 @@ Forwarded: not-needed --- a/Lib/argparse.py +++ b/Lib/argparse.py -@@ -178,9 +178,12 @@ +@@ -180,9 +180,12 @@ # default setting for width if width is None: diff --git a/debian/patches/deb-locations.diff b/debian/patches/deb-locations.diff index b5a39f26..4c19fb20 100644 --- a/debian/patches/deb-locations.diff +++ b/debian/patches/deb-locations.diff @@ -3,7 +3,7 @@ Forwarded: not-needed --- a/Lib/pydoc.py +++ b/Lib/pydoc.py -@@ -31,6 +31,10 @@ +@@ -31,6 +31,10 @@ to a file named ".html". Module docs for core modules are assumed to be in @@ -16,7 +16,7 @@ Forwarded: not-needed This can be overridden by setting the PYTHONDOCS environment variable --- a/Misc/python.man +++ b/Misc/python.man -@@ -425,7 +425,7 @@ +@@ -426,7 +426,7 @@ exception). Error messages are written These are subject to difference depending on local installation conventions; ${prefix} and ${exec_prefix} are installation-dependent and should be interpreted as for GNU software; they may be the same. diff --git a/debian/patches/destshared-location.diff b/debian/patches/destshared-location.diff index 6b918741..d03d1e5d 100644 --- a/debian/patches/destshared-location.diff +++ b/debian/patches/destshared-location.diff @@ -6,10 +6,10 @@ Forwarded: no --- a/Makefile.pre.in +++ b/Makefile.pre.in -@@ -168,7 +168,7 @@ EXT_SUFFIX= @EXT_SUFFIX@ +@@ -168,7 +168,7 @@ LDSHARED= @LDSHARED@ $(PY_LDFLAGS) BLDSHARED= @BLDSHARED@ $(PY_CORE_LDFLAGS) - LDCXXSHARED= @LDCXXSHARED@ + LDCXXSHARED= @LDCXXSHARED@ $(PY_LDFLAGS) -DESTSHARED= $(BINLIBDEST)/lib-dynload +DESTSHARED= $(LIBDEST)/lib-dynload diff --git a/debian/patches/disable-sem-check.diff b/debian/patches/disable-sem-check.diff index 4fa84e50..d5adc1d5 100644 --- a/debian/patches/disable-sem-check.diff +++ b/debian/patches/disable-sem-check.diff @@ -6,7 +6,7 @@ Forwarded: not-needed --- a/configure.ac +++ b/configure.ac -@@ -5790,10 +5790,15 @@ AC_CACHE_CHECK([whether POSIX semaphores +@@ -5819,10 +5819,15 @@ [ac_cv_posix_semaphores_enabled=yes]) ) AS_VAR_IF([ac_cv_posix_semaphores_enabled], [no], [ diff --git a/debian/patches/distutils-install-layout.diff b/debian/patches/distutils-install-layout.diff index 77463538..d101da0f 100644 --- a/debian/patches/distutils-install-layout.diff +++ b/debian/patches/distutils-install-layout.diff @@ -34,7 +34,7 @@ Forwarded: not-needed If a file named "pyvenv.cfg" exists one directory above sys.executable, sys.prefix and sys.exec_prefix are set to that directory and it is also checked for site-packages (sys.base_prefix and -@@ -377,6 +383,8 @@ def getsitepackages(prefixes=None): +@@ -377,6 +383,8 @@ if prefixes is None: prefixes = PREFIXES @@ -43,7 +43,7 @@ Forwarded: not-needed for prefix in prefixes: if not prefix or prefix in seen: continue -@@ -387,10 +395,21 @@ def getsitepackages(prefixes=None): +@@ -387,10 +395,21 @@ if sys.platlibdir != "lib": libdirs.append("lib") @@ -68,7 +68,7 @@ Forwarded: not-needed sitepackages.append(prefix) --- a/Lib/test/test_site.py +++ b/Lib/test/test_site.py -@@ -325,16 +325,16 @@ class HelperFunctionsTests(unittest.Test +@@ -325,16 +325,16 @@ if os.sep == '/': # OS X, Linux, FreeBSD, etc if sys.platlibdir != "lib": @@ -92,7 +92,7 @@ Forwarded: not-needed # other platforms --- a/Lib/pydoc.py +++ b/Lib/pydoc.py -@@ -532,6 +532,7 @@ class Doc: +@@ -532,6 +532,7 @@ 'marshal', 'posix', 'signal', 'sys', '_thread', 'zipimport') or (file.startswith(basedir) and diff --git a/debian/patches/ensurepip-disabled.diff b/debian/patches/ensurepip-disabled.diff index 1f11ce99..b2cea69e 100644 --- a/debian/patches/ensurepip-disabled.diff +++ b/debian/patches/ensurepip-disabled.diff @@ -6,7 +6,7 @@ Forwarded: not-needed --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py -@@ -7,6 +7,34 @@ import sysconfig +@@ -7,6 +7,34 @@ import tempfile from importlib import resources @@ -41,7 +41,7 @@ Forwarded: not-needed __all__ = ["version", "bootstrap"] _PACKAGE_NAMES = ('pip',) -@@ -144,6 +172,11 @@ def _bootstrap(*, root=None, upgrade=Fal +@@ -144,6 +172,11 @@ Note that calling this function will alter both sys.path and os.environ. """ @@ -55,7 +55,7 @@ Forwarded: not-needed --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py -@@ -356,8 +356,26 @@ class EnvBuilder: +@@ -384,8 +384,26 @@ def _setup_pip(self, context): """Installs or upgrades pip in a virtual environment""" diff --git a/debian/patches/git-updates.diff b/debian/patches/git-updates.diff index cbede850..6311b0eb 100644 --- a/debian/patches/git-updates.diff +++ b/debian/patches/git-updates.diff @@ -1,6 +1,1370 @@ -Description: Updates from the 3.12 branch (until 2023-12-02). +Description: Updates from the 3.12 branch (until 2024-12-13). We pick the latest updates from the maintainance branch, and carry them in a patch, rather than creating and uploading uploading a new .orig tarball. -# git diff --no-renames 0fb18b02c8ad56299d6a2910be0bab8ad601ef24 acc62db8af4e472a4922c10b91c60c36c49a5f79 | filterdiff -x ?/.hgignore -x ?/.hgeol -x ?/.hgtags -x ?/.hgtouch -x ?/.gitignore -x ?/.gitattributes -x '?/.github/*' -x '?/.git*' -x ?/.codecov.yml -x ?/.travis.yml -x ?/configure --remove-timestamps +# git diff --no-renames 2dc476bcb9142cd25d7e1d52392b73a3dcdf1756 6544f994637c7d4fc86d8a360e519a4e560606db | filterdiff -x ?/.hgignore -x ?/.hgeol -x ?/.hgtags -x ?/.hgtouch -x ?/.gitignore -x ?/.gitattributes -x '?/.github/*' -x '?/.git*' -x ?/.codecov.yml -x ?/.travis.yml -x ?/configure --remove-timestamps +diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst +index 2109b12bac9..cefd384fd35 100644 +--- a/Doc/c-api/object.rst ++++ b/Doc/c-api/object.rst +@@ -410,6 +410,12 @@ Object Protocol + iterated. + + ++.. c:function:: PyObject* PyObject_SelfIter(PyObject *obj) ++ ++ This is equivalent to the Python ``__iter__(self): return self`` method. ++ It is intended for :term:`iterator` types, to be used in the :c:member:`PyTypeObject.tp_iter` slot. ++ ++ + .. c:function:: PyObject* PyObject_GetAIter(PyObject *o) + + This is the equivalent to the Python expression ``aiter(o)``. Takes an +diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat +index 28532620ba6..88d283aa51e 100644 +--- a/Doc/data/refcounts.dat ++++ b/Doc/data/refcounts.dat +@@ -1818,6 +1818,9 @@ PyObject_RichCompareBool:PyObject*:o1:0: + PyObject_RichCompareBool:PyObject*:o2:0: + PyObject_RichCompareBool:int:opid:: + ++PyObject_SelfIter:PyObject*::+1: ++PyObject_SelfIter:PyObject*:obj:0: ++ + PyObject_SetAttr:int::: + PyObject_SetAttr:PyObject*:o:0: + PyObject_SetAttr:PyObject*:attr_name:0: +diff --git a/Doc/howto/enum.rst b/Doc/howto/enum.rst +index 9b6bb613749..3743e68192f 100644 +--- a/Doc/howto/enum.rst ++++ b/Doc/howto/enum.rst +@@ -1,3 +1,5 @@ ++.. _enum-howto: ++ + ========== + Enum HOWTO + ========== +diff --git a/Doc/howto/functional.rst b/Doc/howto/functional.rst +index b0f9d22d74f..1f0608fb0fc 100644 +--- a/Doc/howto/functional.rst ++++ b/Doc/howto/functional.rst +@@ -1,3 +1,5 @@ ++.. _functional-howto: ++ + ******************************** + Functional Programming HOWTO + ******************************** +diff --git a/Doc/howto/gdb_helpers.rst b/Doc/howto/gdb_helpers.rst +index 53bbf7ddaa2..98ce813ca4a 100644 +--- a/Doc/howto/gdb_helpers.rst ++++ b/Doc/howto/gdb_helpers.rst +@@ -180,7 +180,7 @@ regular machine-level integer:: + (gdb) p some_python_integer + $4 = 42 + +-The internal structure can be revealed with a cast to :c:expr:`PyLongObject *`: ++The internal structure can be revealed with a cast to :c:expr:`PyLongObject *`:: + + (gdb) p *(PyLongObject*)some_python_integer + $5 = {ob_base = {ob_base = {ob_refcnt = 8, ob_type = 0x3dad39f5e0}, ob_size = 1}, +diff --git a/Doc/howto/index.rst b/Doc/howto/index.rst +index 9c8458f2bb6..98364aaf027 100644 +--- a/Doc/howto/index.rst ++++ b/Doc/howto/index.rst +@@ -2,16 +2,14 @@ + Python HOWTOs + *************** + +-Python HOWTOs are documents that cover a single, specific topic, +-and attempt to cover it fairly completely. Modelled on the Linux +-Documentation Project's HOWTO collection, this collection is an ++Python HOWTOs are documents that cover a specific topic in-depth. ++Modeled on the Linux Documentation Project's HOWTO collection, this collection is an + effort to foster documentation that's more detailed than the + Python Library Reference. + +-Currently, the HOWTOs are: +- + .. toctree:: + :maxdepth: 1 ++ :hidden: + + cporting.rst + curses.rst +@@ -33,3 +31,32 @@ Currently, the HOWTOs are: + annotations.rst + isolating-extensions.rst + mro.rst ++ ++General: ++ ++* :ref:`annotations-howto` ++* :ref:`argparse-tutorial` ++* :ref:`descriptorhowto` ++* :ref:`enum-howto` ++* :ref:`functional-howto` ++* :ref:`ipaddress-howto` ++* :ref:`logging-howto` ++* :ref:`logging-cookbook` ++* :ref:`regex-howto` ++* :ref:`sortinghowto` ++* :ref:`unicode-howto` ++* :ref:`urllib-howto` ++ ++Advanced development: ++ ++* :ref:`curses-howto` ++* :ref:`isolating-extensions-howto` ++* :ref:`python_2.3_mro` ++* :ref:`socket-howto` ++* :ref:`cporting-howto` ++ ++Debugging and profiling: ++ ++* :ref:`gdb` ++* :ref:`instrumentation` ++* :ref:`perf_profiling` +diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst +index 5a392f94da4..597de77a828 100644 +--- a/Doc/howto/logging.rst ++++ b/Doc/howto/logging.rst +@@ -1,3 +1,5 @@ ++.. _logging-howto: ++ + ============= + Logging HOWTO + ============= +diff --git a/Doc/library/http.cookies.rst b/Doc/library/http.cookies.rst +index 4ce2e3c4f4c..ad37a0fca47 100644 +--- a/Doc/library/http.cookies.rst ++++ b/Doc/library/http.cookies.rst +@@ -98,7 +98,7 @@ Cookie Objects + .. method:: BaseCookie.output(attrs=None, header='Set-Cookie:', sep='\r\n') + + Return a string representation suitable to be sent as HTTP headers. *attrs* and +- *header* are sent to each :class:`Morsel`'s :meth:`output` method. *sep* is used ++ *header* are sent to each :class:`Morsel`'s :meth:`~Morsel.output` method. *sep* is used + to join the headers together, and is by default the combination ``'\r\n'`` + (CRLF). + +diff --git a/Doc/library/traceback.rst b/Doc/library/traceback.rst +index 9d57c354523..0a2b9c5cfb1 100644 +--- a/Doc/library/traceback.rst ++++ b/Doc/library/traceback.rst +@@ -157,6 +157,13 @@ Module-Level Functions + arguments have the same meaning as for :func:`print_stack`. + + ++.. function:: print_list(extracted_list, file=None) ++ ++ Print the list of tuples as returned by :func:`extract_tb` or ++ :func:`extract_stack` as a formatted stack trace to the given file. ++ If *file* is ``None``, the output is written to :data:`sys.stderr`. ++ ++ + .. function:: format_list(extracted_list) + + Given a list of tuples or :class:`FrameSummary` objects as returned by +@@ -256,7 +263,7 @@ Module-Level Functions + :class:`!TracebackException` objects are created from actual exceptions to + capture data for later printing. They offer a more lightweight method of + storing this information by avoiding holding references to +-:ref:`traceback` and :ref:`frame` objects ++:ref:`traceback` and :ref:`frame` objects. + In addition, they expose more options to configure the output compared to + the module-level functions described above. + +diff --git a/Doc/library/xmlrpc.client.rst b/Doc/library/xmlrpc.client.rst +index c57f433e6ef..971e6560584 100644 +--- a/Doc/library/xmlrpc.client.rst ++++ b/Doc/library/xmlrpc.client.rst +@@ -64,11 +64,11 @@ between conformable Python objects and XML on the wire. + The obsolete *use_datetime* flag is similar to *use_builtin_types* but it + applies only to date/time values. + +-.. versionchanged:: 3.3 +- The *use_builtin_types* flag was added. ++ .. versionchanged:: 3.3 ++ The *use_builtin_types* flag was added. + +-.. versionchanged:: 3.8 +- The *headers* parameter was added. ++ .. versionchanged:: 3.8 ++ The *headers* parameter was added. + + Both the HTTP and HTTPS transports support the URL syntax extension for HTTP + Basic Authentication: ``http://user:pass@host:port/path``. The ``user:pass`` +diff --git a/Doc/library/xmlrpc.rst b/Doc/library/xmlrpc.rst +index 5f0a2cf68d0..a93d08f78cf 100644 +--- a/Doc/library/xmlrpc.rst ++++ b/Doc/library/xmlrpc.rst +@@ -1,6 +1,9 @@ + :mod:`!xmlrpc` --- XMLRPC server and client modules + =================================================== + ++.. module:: xmlrpc ++ :synopsis: Server and client modules implementing XML-RPC. ++ + XML-RPC is a Remote Procedure Call method that uses XML passed via HTTP as a + transport. With it, a client can call methods with parameters on a remote + server (the server is named by a URI) and get back structured data. +diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore +index c665ddd1bb9..e69e6100945 100644 +--- a/Doc/tools/.nitignore ++++ b/Doc/tools/.nitignore +@@ -94,7 +94,6 @@ Doc/whatsnew/2.4.rst + Doc/whatsnew/2.5.rst + Doc/whatsnew/2.6.rst + Doc/whatsnew/2.7.rst +-Doc/whatsnew/3.0.rst + Doc/whatsnew/3.3.rst + Doc/whatsnew/3.4.rst + Doc/whatsnew/3.5.rst +diff --git a/Doc/tutorial/datastructures.rst b/Doc/tutorial/datastructures.rst +index 263b0c2e281..cbe780e075b 100644 +--- a/Doc/tutorial/datastructures.rst ++++ b/Doc/tutorial/datastructures.rst +@@ -142,8 +142,8 @@ Using Lists as Stacks + + The list methods make it very easy to use a list as a stack, where the last + element added is the first element retrieved ("last-in, first-out"). To add an +-item to the top of the stack, use :meth:`!~list.append`. To retrieve an item from the +-top of the stack, use :meth:`!~list.pop` without an explicit index. For example:: ++item to the top of the stack, use :meth:`!append`. To retrieve an item from the ++top of the stack, use :meth:`!pop` without an explicit index. For example:: + + >>> stack = [3, 4, 5] + >>> stack.append(6) +@@ -340,7 +340,7 @@ The :keyword:`!del` statement + ============================= + + There is a way to remove an item from a list given its index instead of its +-value: the :keyword:`del` statement. This differs from the :meth:`!~list.pop` method ++value: the :keyword:`del` statement. This differs from the :meth:`!pop` method + which returns a value. The :keyword:`!del` statement can also be used to remove + slices from a list or clear the entire list (which we did earlier by assignment + of an empty list to the slice). For example:: +@@ -500,8 +500,8 @@ any immutable type; strings and numbers can always be keys. Tuples can be used + as keys if they contain only strings, numbers, or tuples; if a tuple contains + any mutable object either directly or indirectly, it cannot be used as a key. + You can't use lists as keys, since lists can be modified in place using index +-assignments, slice assignments, or methods like :meth:`!~list.append` and +-:meth:`!~list.extend`. ++assignments, slice assignments, or methods like :meth:`!append` and ++:meth:`!extend`. + + It is best to think of a dictionary as a set of *key: value* pairs, + with the requirement that the keys are unique (within one dictionary). A pair of +diff --git a/Doc/whatsnew/3.0.rst b/Doc/whatsnew/3.0.rst +index 766db5ecc67..7cd2ffd39c9 100644 +--- a/Doc/whatsnew/3.0.rst ++++ b/Doc/whatsnew/3.0.rst +@@ -150,8 +150,8 @@ Some well-known APIs no longer return lists: + sorted(d)`` instead (this works in Python 2.5 too and is just + as efficient). + +-* Also, the :meth:`dict.iterkeys`, :meth:`dict.iteritems` and +- :meth:`dict.itervalues` methods are no longer supported. ++* Also, the :meth:`!dict.iterkeys`, :meth:`!dict.iteritems` and ++ :meth:`!dict.itervalues` methods are no longer supported. + + * :func:`map` and :func:`filter` return iterators. If you really need + a list and the input sequences are all of equal length, a quick +@@ -170,7 +170,7 @@ Some well-known APIs no longer return lists: + :func:`itertools.zip_longest`, e.g. ``map(func, *sequences)`` becomes + ``list(map(func, itertools.zip_longest(*sequences)))``. + +-* :func:`range` now behaves like :func:`xrange` used to behave, except ++* :func:`range` now behaves like :func:`!xrange` used to behave, except + it works with values of arbitrary size. The latter no longer + exists. + +@@ -192,33 +192,33 @@ Python 3.0 has simplified the rules for ordering comparisons: + operators: objects of different incomparable types always compare + unequal to each other. + +-* :meth:`builtin.sorted` and :meth:`list.sort` no longer accept the ++* :meth:`sorted` and :meth:`list.sort` no longer accept the + *cmp* argument providing a comparison function. Use the *key* + argument instead. N.B. the *key* and *reverse* arguments are now + "keyword-only". + +-* The :func:`cmp` function should be treated as gone, and the :meth:`__cmp__` +- special method is no longer supported. Use :meth:`__lt__` for sorting, +- :meth:`__eq__` with :meth:`__hash__`, and other rich comparisons as needed. +- (If you really need the :func:`cmp` functionality, you could use the ++* The :func:`!cmp` function should be treated as gone, and the :meth:`!__cmp__` ++ special method is no longer supported. Use :meth:`~object.__lt__` for sorting, ++ :meth:`~object.__eq__` with :meth:`~object.__hash__`, and other rich comparisons as needed. ++ (If you really need the :func:`!cmp` functionality, you could use the + expression ``(a > b) - (a < b)`` as the equivalent for ``cmp(a, b)``.) + + Integers + -------- + +-* :pep:`237`: Essentially, :class:`long` renamed to :class:`int`. ++* :pep:`237`: Essentially, :class:`!long` renamed to :class:`int`. + That is, there is only one built-in integral type, named +- :class:`int`; but it behaves mostly like the old :class:`long` type. ++ :class:`int`; but it behaves mostly like the old :class:`!long` type. + + * :pep:`238`: An expression like ``1/2`` returns a float. Use + ``1//2`` to get the truncating behavior. (The latter syntax has + existed for years, at least since Python 2.2.) + +-* The :data:`sys.maxint` constant was removed, since there is no ++* The :data:`!sys.maxint` constant was removed, since there is no + longer a limit to the value of integers. However, :data:`sys.maxsize` + can be used as an integer larger than any practical list or string + index. It conforms to the implementation's "natural" integer size +- and is typically the same as :data:`sys.maxint` in previous releases ++ and is typically the same as :data:`!sys.maxint` in previous releases + on the same platform (assuming the same build options). + + * The :func:`repr` of a long integer doesn't include the trailing ``L`` +@@ -251,7 +251,7 @@ changed. + that uses Unicode, encodings or binary data most likely has to + change. The change is for the better, as in the 2.x world there + were numerous bugs having to do with mixing encoded and unencoded +- text. To be prepared in Python 2.x, start using :class:`unicode` ++ text. To be prepared in Python 2.x, start using :class:`!unicode` + for all unencoded text, and :class:`str` for binary or encoded data + only. Then the ``2to3`` tool will do most of the work for you. + +@@ -269,7 +269,7 @@ changed. + separate *mutable* type to hold buffered binary data, + :class:`bytearray`. Nearly all APIs that accept :class:`bytes` also + accept :class:`bytearray`. The mutable API is based on +- :class:`collections.MutableSequence`. ++ :class:`collections.MutableSequence `. + + * All backslashes in raw string literals are interpreted literally. + This means that ``'\U'`` and ``'\u'`` escapes in raw strings are not +@@ -278,11 +278,11 @@ changed. + single "euro" character. (Of course, this change only affects raw + string literals; the euro character is ``'\u20ac'`` in Python 3.0.) + +-* The built-in :class:`basestring` abstract type was removed. Use ++* The built-in :class:`!basestring` abstract type was removed. Use + :class:`str` instead. The :class:`str` and :class:`bytes` types + don't have functionality enough in common to warrant a shared base + class. The ``2to3`` tool (see below) replaces every occurrence of +- :class:`basestring` with :class:`str`. ++ :class:`!basestring` with :class:`str`. + + * Files opened as text files (still the default mode for :func:`open`) + always use an encoding to map between strings (in memory) and bytes +@@ -357,7 +357,7 @@ New Syntax + provides a standardized way of annotating a function's parameters + and return value. There are no semantics attached to such + annotations except that they can be introspected at runtime using +- the :attr:`~object.__annotations__` attribute. The intent is to ++ the :attr:`!__annotations__` attribute. The intent is to + encourage experimentation through metaclasses, decorators or frameworks. + + * :pep:`3102`: Keyword-only arguments. Named parameters occurring +@@ -428,7 +428,7 @@ Changed Syntax + class C(metaclass=M): + ... + +- The module-global :data:`__metaclass__` variable is no longer ++ The module-global :data:`!__metaclass__` variable is no longer + supported. (It was a crutch to make it easier to default to + new-style classes without deriving every class from + :class:`object`.) +@@ -522,19 +522,19 @@ consulted for longer descriptions. + *encoding*, *errors*, *newline* and *closefd*. Also note that an + invalid *mode* argument now raises :exc:`ValueError`, not + :exc:`IOError`. The binary file object underlying a text file +- object can be accessed as :attr:`f.buffer` (but beware that the ++ object can be accessed as :attr:`!f.buffer` (but beware that the + text object maintains a buffer of itself in order to speed up + the encoding and decoding operations). + +-* :ref:`pep-3118`. The old builtin :func:`buffer` is now really gone; ++* :ref:`pep-3118`. The old builtin :func:`!buffer` is now really gone; + the new builtin :func:`memoryview` provides (mostly) similar + functionality. + + * :ref:`pep-3119`. The :mod:`abc` module and the ABCs defined in the + :mod:`collections` module plays a somewhat more prominent role in + the language now, and built-in collection types like :class:`dict` +- and :class:`list` conform to the :class:`collections.MutableMapping` +- and :class:`collections.MutableSequence` ABCs, respectively. ++ and :class:`list` conform to the :class:`collections.MutableMapping ` ++ and :class:`collections.MutableSequence ` ABCs, respectively. + + * :ref:`pep-3127`. As mentioned above, the new octal literal + notation is the only one supported, and binary literals have been +@@ -612,7 +612,7 @@ review: + :mod:`!CGIHTTPServer`, :mod:`!SimpleHTTPServer`, :mod:`!Cookie`, + :mod:`!cookielib`). + +- * :mod:`tkinter` (all :mod:`Tkinter`-related modules except ++ * :mod:`tkinter` (all ``Tkinter``-related modules except + :mod:`turtle`). The target audience of :mod:`turtle` doesn't + really care about :mod:`tkinter`. Also note that as of Python + 2.6, the functionality of :mod:`turtle` has been greatly enhanced. +@@ -628,47 +628,47 @@ Some other changes to standard library modules, not covered by + + * Killed :mod:`!sets`. Use the built-in :func:`set` class. + +-* Cleanup of the :mod:`sys` module: removed :func:`sys.exitfunc`, +- :func:`sys.exc_clear`, :data:`sys.exc_type`, :data:`sys.exc_value`, +- :data:`sys.exc_traceback`. (Note that :data:`sys.last_type` ++* Cleanup of the :mod:`sys` module: removed :func:`!sys.exitfunc`, ++ :func:`!sys.exc_clear`, :data:`!sys.exc_type`, :data:`!sys.exc_value`, ++ :data:`!sys.exc_traceback`. (Note that :data:`sys.last_type` + etc. remain.) + +-* Cleanup of the :class:`array.array` type: the :meth:`read` and +- :meth:`write` methods are gone; use :meth:`fromfile` and +- :meth:`tofile` instead. Also, the ``'c'`` typecode for array is ++* Cleanup of the :class:`array.array` type: the :meth:`!read` and ++ :meth:`!write` methods are gone; use :meth:`~array.array.fromfile` and ++ :meth:`~array.array.tofile` instead. Also, the ``'c'`` typecode for array is + gone -- use either ``'b'`` for bytes or ``'u'`` for Unicode + characters. + + * Cleanup of the :mod:`operator` module: removed +- :func:`sequenceIncludes` and :func:`isCallable`. ++ :func:`!sequenceIncludes` and :func:`!isCallable`. + + * Cleanup of the :mod:`!thread` module: :func:`!acquire_lock` and + :func:`!release_lock` are gone; use :meth:`~threading.Lock.acquire` and + :meth:`~threading.Lock.release` instead. + +-* Cleanup of the :mod:`random` module: removed the :func:`jumpahead` API. ++* Cleanup of the :mod:`random` module: removed the :func:`!jumpahead` API. + + * The :mod:`!new` module is gone. + +-* The functions :func:`os.tmpnam`, :func:`os.tempnam` and +- :func:`os.tmpfile` have been removed in favor of the :mod:`tempfile` ++* The functions :func:`!os.tmpnam`, :func:`!os.tempnam` and ++ :func:`!os.tmpfile` have been removed in favor of the :mod:`tempfile` + module. + + * The :mod:`tokenize` module has been changed to work with bytes. The + main entry point is now :func:`tokenize.tokenize`, instead of + generate_tokens. + +-* :data:`string.letters` and its friends (:data:`string.lowercase` and +- :data:`string.uppercase`) are gone. Use ++* :data:`!string.letters` and its friends (:data:`!string.lowercase` and ++ :data:`!string.uppercase`) are gone. Use + :data:`string.ascii_letters` etc. instead. (The reason for the +- removal is that :data:`string.letters` and friends had ++ removal is that :data:`!string.letters` and friends had + locale-specific behavior, which is a bad idea for such + attractively named global "constants".) + +-* Renamed module :mod:`__builtin__` to :mod:`builtins` (removing the +- underscores, adding an 's'). The :data:`__builtins__` variable ++* Renamed module :mod:`!__builtin__` to :mod:`builtins` (removing the ++ underscores, adding an 's'). The :data:`!__builtins__` variable + found in most global namespaces is unchanged. To modify a builtin, +- you should use :mod:`builtins`, not :data:`__builtins__`! ++ you should use :mod:`builtins`, not :data:`!__builtins__`! + + + :pep:`3101`: A New Approach To String Formatting +@@ -702,9 +702,9 @@ new powerful features added: + idiom for handling all exceptions except for this latter category is + to use :keyword:`except` :exc:`Exception`. + +-* :exc:`StandardError` was removed. ++* :exc:`!StandardError` was removed. + +-* Exceptions no longer behave as sequences. Use the :attr:`args` ++* Exceptions no longer behave as sequences. Use the :attr:`~BaseException.args` + attribute instead. + + * :pep:`3109`: Raising exceptions. You must now use :samp:`raise +@@ -765,20 +765,20 @@ Operators And Special Methods + When referencing a method as a class attribute, you now get a plain + function object. + +-* :meth:`__getslice__`, :meth:`__setslice__` and :meth:`__delslice__` ++* :meth:`!__getslice__`, :meth:`!__setslice__` and :meth:`!__delslice__` + were killed. The syntax ``a[i:j]`` now translates to +- ``a.__getitem__(slice(i, j))`` (or :meth:`__setitem__` or +- :meth:`__delitem__`, when used as an assignment or deletion target, ++ ``a.__getitem__(slice(i, j))`` (or :meth:`~object.__setitem__` or ++ :meth:`~object.__delitem__`, when used as an assignment or deletion target, + respectively). + + * :pep:`3114`: the standard :meth:`next` method has been renamed to + :meth:`~iterator.__next__`. + +-* The :meth:`__oct__` and :meth:`__hex__` special methods are removed +- -- :func:`oct` and :func:`hex` use :meth:`__index__` now to convert ++* The :meth:`!__oct__` and :meth:`!__hex__` special methods are removed ++ -- :func:`oct` and :func:`hex` use :meth:`~object.__index__` now to convert + the argument to an integer. + +-* Removed support for :attr:`__members__` and :attr:`__methods__`. ++* Removed support for :attr:`!__members__` and :attr:`!__methods__`. + + * The function attributes named :attr:`!func_X` have been renamed to + use the :attr:`!__X__` form, freeing up these names in the function +@@ -802,7 +802,7 @@ Builtins + instance will automatically be chosen. With arguments, the behavior + of :func:`super` is unchanged. + +-* :pep:`3111`: :func:`raw_input` was renamed to :func:`input`. That ++* :pep:`3111`: :func:`!raw_input` was renamed to :func:`input`. That + is, the new :func:`input` function reads a line from + :data:`sys.stdin` and returns it with the trailing newline stripped. + It raises :exc:`EOFError` if the input is terminated prematurely. +@@ -820,31 +820,31 @@ Builtins + argument and a value of the same type as ``x`` when called with two + arguments. + +-* Moved :func:`intern` to :func:`sys.intern`. ++* Moved :func:`!intern` to :func:`sys.intern`. + +-* Removed: :func:`apply`. Instead of ``apply(f, args)`` use ++* Removed: :func:`!apply`. Instead of ``apply(f, args)`` use + ``f(*args)``. + + * Removed :func:`callable`. Instead of ``callable(f)`` you can use +- ``isinstance(f, collections.Callable)``. The :func:`operator.isCallable` ++ ``isinstance(f, collections.Callable)``. The :func:`!operator.isCallable` + function is also gone. + +-* Removed :func:`coerce`. This function no longer serves a purpose ++* Removed :func:`!coerce`. This function no longer serves a purpose + now that classic classes are gone. + +-* Removed :func:`execfile`. Instead of ``execfile(fn)`` use ++* Removed :func:`!execfile`. Instead of ``execfile(fn)`` use + ``exec(open(fn).read())``. + +-* Removed the :class:`file` type. Use :func:`open`. There are now several ++* Removed the :class:`!file` type. Use :func:`open`. There are now several + different kinds of streams that open can return in the :mod:`io` module. + +-* Removed :func:`reduce`. Use :func:`functools.reduce` if you really ++* Removed :func:`!reduce`. Use :func:`functools.reduce` if you really + need it; however, 99 percent of the time an explicit :keyword:`for` + loop is more readable. + +-* Removed :func:`reload`. Use :func:`!imp.reload`. ++* Removed :func:`!reload`. Use :func:`!imp.reload`. + +-* Removed. :meth:`dict.has_key` -- use the :keyword:`in` operator ++* Removed. :meth:`!dict.has_key` -- use the :keyword:`in` operator + instead. + + .. ====================================================================== +diff --git a/Include/cpython/pytime.h b/Include/cpython/pytime.h +index 16d88d191e9..46cc97bd7cf 100644 +--- a/Include/cpython/pytime.h ++++ b/Include/cpython/pytime.h +@@ -53,7 +53,7 @@ functions and constants + extern "C" { + #endif + +-#ifdef __clang__ ++#if defined(__clang__) || defined(_MSC_VER) + struct timeval; + #endif + +diff --git a/Include/patchlevel.h b/Include/patchlevel.h +index 6c597837da0..2fa45090034 100644 +--- a/Include/patchlevel.h ++++ b/Include/patchlevel.h +@@ -23,7 +23,7 @@ + #define PY_RELEASE_SERIAL 0 + + /* Version as a string */ +-#define PY_VERSION "3.12.8" ++#define PY_VERSION "3.12.8+" + /*--end constants--*/ + + /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. +diff --git a/Include/pymacro.h b/Include/pymacro.h +index d5700dc3893..94e6248d283 100644 +--- a/Include/pymacro.h ++++ b/Include/pymacro.h +@@ -118,6 +118,15 @@ + */ + #if defined(__GNUC__) || defined(__clang__) + # define Py_UNUSED(name) _unused_ ## name __attribute__((unused)) ++#elif defined(_MSC_VER) ++ // Disable warning C4100: unreferenced formal parameter, ++ // declare the parameter, ++ // restore old compiler warnings. ++# define Py_UNUSED(name) \ ++ __pragma(warning(push)) \ ++ __pragma(warning(suppress: 4100)) \ ++ _unused_ ## name \ ++ __pragma(warning(pop)) + #else + # define Py_UNUSED(name) _unused_ ## name + #endif +diff --git a/Include/tracemalloc.h b/Include/tracemalloc.h +index 580027a8e36..4db34b9509e 100644 +--- a/Include/tracemalloc.h ++++ b/Include/tracemalloc.h +@@ -1,7 +1,10 @@ + #ifndef Py_TRACEMALLOC_H + #define Py_TRACEMALLOC_H +- + #ifndef Py_LIMITED_API ++#ifdef __cplusplus ++extern "C" { ++#endif ++ + /* Track an allocated memory block in the tracemalloc module. + Return 0 on success, return -1 on error (failed to allocate memory to store + the trace). +@@ -67,6 +70,8 @@ PyAPI_FUNC(PyObject *) _PyTraceMalloc_GetTracedMemory(void); + /* Set the peak size of traced memory blocks to the current size */ + PyAPI_FUNC(void) _PyTraceMalloc_ResetPeak(void); + ++#ifdef __cplusplus ++} + #endif +- ++#endif /* !Py_LIMITED_API */ + #endif /* !Py_TRACEMALLOC_H */ +diff --git a/Lib/_pydecimal.py b/Lib/_pydecimal.py +index 75df3db2624..ff80180a79e 100644 +--- a/Lib/_pydecimal.py ++++ b/Lib/_pydecimal.py +@@ -97,7 +97,7 @@ class DecimalException(ArithmeticError): + + Used exceptions derive from this. + If an exception derives from another exception besides this (such as +- Underflow (Inexact, Rounded, Subnormal) that indicates that it is only ++ Underflow (Inexact, Rounded, Subnormal)) that indicates that it is only + called if the others are present. This isn't actually used for + anything, though. + +@@ -145,7 +145,7 @@ class InvalidOperation(DecimalException): + x ** (+-)INF + An operand is invalid + +- The result of the operation after these is a quiet positive NaN, ++ The result of the operation after this is a quiet positive NaN, + except when the cause is a signaling NaN, in which case the result is + also a quiet NaN, but with the original sign, and an optional + diagnostic information. +diff --git a/Lib/_strptime.py b/Lib/_strptime.py +index dfd2bc5d8b4..5d9df2b12f8 100644 +--- a/Lib/_strptime.py ++++ b/Lib/_strptime.py +@@ -300,8 +300,6 @@ def __init__(self, locale_time=None): + 'V': r"(?P5[0-3]|0[1-9]|[1-4]\d|\d)", + # W is set below by using 'U' + 'y': r"(?P\d\d)", +- #XXX: Does 'Y' need to worry about having less or more than +- # 4 digits? + 'Y': r"(?P\d\d\d\d)", + 'z': r"(?P[+-]\d\d:?[0-5]\d(:?[0-5]\d(\.\d{1,6})?)?|(?-i:Z))", + 'A': self.__seqToRE(self.locale_time.f_weekday, 'A'), +diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py +index 790711f8340..dd79ad18df3 100644 +--- a/Lib/asyncio/selector_events.py ++++ b/Lib/asyncio/selector_events.py +@@ -1183,6 +1183,7 @@ def writelines(self, list_of_data): + # If the entire buffer couldn't be written, register a write handler + if self._buffer: + self._loop._add_writer(self._sock_fd, self._write_ready) ++ self._maybe_pause_protocol() + + def can_write_eof(self): + return True +diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py +index 6b9ed24ad8e..57791c6ab08 100644 +--- a/Lib/http/cookies.py ++++ b/Lib/http/cookies.py +@@ -424,9 +424,11 @@ def OutputString(self, attrs=None): + ( # Optional group: there may not be a value. + \s*=\s* # Equal Sign + (?P # Start of group 'val' +- "(?:[^\\"]|\\.)*" # Any doublequoted string ++ "(?:[^\\"]|\\.)*" # Any double-quoted string + | # or +- \w{3},\s[\w\d\s-]{9,11}\s[\d:]{8}\sGMT # Special case for "expires" attr ++ # Special case for "expires" attr ++ (\w{3,6}day|\w{3}),\s # Day of the week or abbreviated day ++ [\w\d\s-]{9,11}\s[\d:]{8}\sGMT # Date and time in specific format + | # or + [""" + _LegalValueChars + r"""]* # Any word or empty string + ) # End of group 'val' +diff --git a/Lib/linecache.py b/Lib/linecache.py +index 248cba93874..b6453fe2f31 100644 +--- a/Lib/linecache.py ++++ b/Lib/linecache.py +@@ -54,14 +54,17 @@ def checkcache(filename=None): + (This is not checked upon each call!)""" + + if filename is None: +- filenames = list(cache.keys()) +- elif filename in cache: +- filenames = [filename] ++ # get keys atomically ++ filenames = cache.copy().keys() + else: +- return ++ filenames = [filename] + + for filename in filenames: +- entry = cache[filename] ++ try: ++ entry = cache[filename] ++ except KeyError: ++ continue ++ + if len(entry) == 1: + # lazy cache entry, leave it lazy. + continue +diff --git a/Lib/platform.py b/Lib/platform.py +index c5b60480369..b86e6834911 100755 +--- a/Lib/platform.py ++++ b/Lib/platform.py +@@ -348,7 +348,8 @@ def _wmi_query(table, *keys): + ] + + _WIN32_SERVER_RELEASES = [ +- ((10, 1, 0), "post2022Server"), ++ ((10, 1, 0), "post2025Server"), ++ ((10, 0, 26100), "2025Server"), + ((10, 0, 20348), "2022Server"), + ((10, 0, 17763), "2019Server"), + ((6, 4, 0), "2016Server"), +diff --git a/Lib/poplib.py b/Lib/poplib.py +index 9a5ef03c983..81b01385987 100644 +--- a/Lib/poplib.py ++++ b/Lib/poplib.py +@@ -309,7 +309,7 @@ def close(self): + # optional commands: + + def rpop(self, user): +- """Not sure what this does.""" ++ """Send RPOP command to access the mailbox with an alternate user.""" + return self._shortcmd('RPOP %s' % user) + + +diff --git a/Lib/test/test__locale.py b/Lib/test/test__locale.py +index 89c20325055..606dd297452 100644 +--- a/Lib/test/test__locale.py ++++ b/Lib/test/test__locale.py +@@ -102,6 +102,11 @@ def accept(loc): + # ps_AF doesn't work on Windows: see bpo-38324 (msg361830) + del known_numerics['ps_AF'] + ++if sys.platform == 'sunos5': ++ # On Solaris, Japanese ERAs start with the year 1927, ++ # and thus there's less of them. ++ known_era['ja_JP'] = (5, '+:1:2019/05/01:2019/12/31:令和:%EC元年') ++ + class _LocaleTests(unittest.TestCase): + + def setUp(self): +diff --git a/Lib/test/test_asyncio/test_selector_events.py b/Lib/test/test_asyncio/test_selector_events.py +index 47693ea4d3c..736c19796ef 100644 +--- a/Lib/test/test_asyncio/test_selector_events.py ++++ b/Lib/test/test_asyncio/test_selector_events.py +@@ -805,6 +805,18 @@ def test_writelines_send_partial(self): + self.assertTrue(self.sock.send.called) + self.assertTrue(self.loop.writers) + ++ def test_writelines_pauses_protocol(self): ++ data = memoryview(b'data') ++ self.sock.send.return_value = 2 ++ self.sock.send.fileno.return_value = 7 ++ ++ transport = self.socket_transport() ++ transport._high_water = 1 ++ transport.writelines([data]) ++ self.assertTrue(self.protocol.pause_writing.called) ++ self.assertTrue(self.sock.send.called) ++ self.assertTrue(self.loop.writers) ++ + @unittest.skipUnless(selector_events._HAS_SENDMSG, 'no sendmsg') + def test_write_sendmsg_full(self): + data = memoryview(b'data') +diff --git a/Lib/test/test_cppext/__init__.py b/Lib/test/test_cppext/__init__.py +index f02a823bd22..efd79448c66 100644 +--- a/Lib/test/test_cppext/__init__.py ++++ b/Lib/test/test_cppext/__init__.py +@@ -1,45 +1,52 @@ + # gh-91321: Build a basic C++ test extension to check that the Python C API is + # compatible with C++ and does not emit C++ compiler warnings. + import os.path ++import shlex + import shutil +-import sys +-import unittest + import subprocess +-import sysconfig ++import unittest + from test import support +-from test.support import os_helper + + + SOURCE = os.path.join(os.path.dirname(__file__), 'extension.cpp') + SETUP = os.path.join(os.path.dirname(__file__), 'setup.py') + + ++# With MSVC on a debug build, the linker fails with: cannot open file ++# 'python311.lib', it should look 'python311_d.lib'. ++@unittest.skipIf(support.MS_WINDOWS and support.Py_DEBUG, ++ 'test fails on Windows debug build') ++# Building and running an extension in clang sanitizing mode is not ++# straightforward ++@support.skip_if_sanitizer('test does not work with analyzing builds', ++ address=True, memory=True, ub=True, thread=True) ++# the test uses venv+pip: skip if it's not available ++@support.requires_venv_with_pip() + @support.requires_subprocess() ++@support.requires_resource('cpu') + class TestCPPExt(unittest.TestCase): +- @support.requires_resource('cpu') +- def test_build_cpp11(self): +- self.check_build(False, '_testcpp11ext') ++ def test_build(self): ++ self.check_build('_testcppext') + +- @support.requires_resource('cpu') + def test_build_cpp03(self): +- self.check_build(True, '_testcpp03ext') ++ self.check_build('_testcpp03ext', std='c++03') ++ ++ @unittest.skipIf(support.MS_WINDOWS, "MSVC doesn't support /std:c++11") ++ def test_build_cpp11(self): ++ self.check_build('_testcpp11ext', std='c++11') ++ ++ # Only test C++14 on MSVC. ++ # On s390x RHEL7, GCC 4.8.5 doesn't support C++14. ++ @unittest.skipIf(not support.MS_WINDOWS, "need Windows") ++ def test_build_cpp14(self): ++ self.check_build('_testcpp14ext', std='c++14') + +- # With MSVC, the linker fails with: cannot open file 'python311.lib' +- # https://github.com/python/cpython/pull/32175#issuecomment-1111175897 +- @unittest.skipIf(support.MS_WINDOWS, 'test fails on Windows') +- # Building and running an extension in clang sanitizing mode is not +- # straightforward +- @unittest.skipIf( +- '-fsanitize' in (sysconfig.get_config_var('PY_CFLAGS') or ''), +- 'test does not work with analyzing builds') +- # the test uses venv+pip: skip if it's not available +- @support.requires_venv_with_pip() +- def check_build(self, std_cpp03, extension_name): ++ def check_build(self, extension_name, std=None): + venv_dir = 'env' + with support.setup_venv_with_pip_setuptools_wheel(venv_dir) as python_exe: +- self._check_build(std_cpp03, extension_name, python_exe) ++ self._check_build(extension_name, python_exe, std=std) + +- def _check_build(self, std_cpp03, extension_name, python_exe): ++ def _check_build(self, extension_name, python_exe, std): + pkg_dir = 'pkg' + os.mkdir(pkg_dir) + shutil.copy(SETUP, os.path.join(pkg_dir, os.path.basename(SETUP))) +@@ -47,10 +54,11 @@ def _check_build(self, std_cpp03, extension_name, python_exe): + + def run_cmd(operation, cmd): + env = os.environ.copy() +- env['CPYTHON_TEST_CPP_STD'] = 'c++03' if std_cpp03 else 'c++11' ++ if std: ++ env['CPYTHON_TEST_CPP_STD'] = std + env['CPYTHON_TEST_EXT_NAME'] = extension_name + if support.verbose: +- print('Run:', ' '.join(cmd)) ++ print('Run:', ' '.join(map(shlex.quote, cmd))) + subprocess.run(cmd, check=True, env=env) + else: + proc = subprocess.run(cmd, +@@ -59,6 +67,7 @@ def run_cmd(operation, cmd): + stderr=subprocess.STDOUT, + text=True) + if proc.returncode: ++ print('Run:', ' '.join(map(shlex.quote, cmd))) + print(proc.stdout, end='') + self.fail( + f"{operation} failed with exit code {proc.returncode}") +@@ -67,6 +76,8 @@ def run_cmd(operation, cmd): + cmd = [python_exe, '-X', 'dev', + '-m', 'pip', 'install', '--no-build-isolation', + os.path.abspath(pkg_dir)] ++ if support.verbose: ++ cmd.append('-v') + run_cmd('Install', cmd) + + # Do a reference run. Until we test that running python +diff --git a/Lib/test/test_cppext/extension.cpp b/Lib/test/test_cppext/extension.cpp +index 90669b10cb2..ab485b629b7 100644 +--- a/Lib/test/test_cppext/extension.cpp ++++ b/Lib/test/test_cppext/extension.cpp +@@ -8,10 +8,8 @@ + + #include "Python.h" + +-#if __cplusplus >= 201103 +-# define NAME _testcpp11ext +-#else +-# define NAME _testcpp03ext ++#ifndef MODULE_NAME ++# error "MODULE_NAME macro must be defined" + #endif + + #define _STR(NAME) #NAME +@@ -160,7 +158,7 @@ PyType_Slot VirtualPyObject_Slots[] = { + }; + + PyType_Spec VirtualPyObject_Spec = { +- /* .name */ STR(NAME) ".VirtualPyObject", ++ /* .name */ STR(MODULE_NAME) ".VirtualPyObject", + /* .basicsize */ sizeof(VirtualPyObject), + /* .itemsize */ 0, + /* .flags */ Py_TPFLAGS_DEFAULT, +@@ -227,6 +225,10 @@ _testcppext_exec(PyObject *module) + if (!result) return -1; + Py_DECREF(result); + ++ // test Py_BUILD_ASSERT() and Py_BUILD_ASSERT_EXPR() ++ Py_BUILD_ASSERT(sizeof(int) == sizeof(unsigned int)); ++ assert(Py_BUILD_ASSERT_EXPR(sizeof(int) == sizeof(unsigned int)) == 0); ++ + return 0; + } + +@@ -240,7 +242,7 @@ PyDoc_STRVAR(_testcppext_doc, "C++ test extension."); + + static struct PyModuleDef _testcppext_module = { + PyModuleDef_HEAD_INIT, // m_base +- STR(NAME), // m_name ++ STR(MODULE_NAME), // m_name + _testcppext_doc, // m_doc + 0, // m_size + _testcppext_methods, // m_methods +@@ -254,7 +256,7 @@ static struct PyModuleDef _testcppext_module = { + #define FUNC_NAME(NAME) _FUNC_NAME(NAME) + + PyMODINIT_FUNC +-FUNC_NAME(NAME)(void) ++FUNC_NAME(MODULE_NAME)(void) + { + return PyModuleDef_Init(&_testcppext_module); + } +diff --git a/Lib/test/test_cppext/setup.py b/Lib/test/test_cppext/setup.py +index c7ba1efb4dd..d97b238b8d1 100644 +--- a/Lib/test/test_cppext/setup.py ++++ b/Lib/test/test_cppext/setup.py +@@ -1,8 +1,8 @@ + # gh-91321: Build a basic C++ test extension to check that the Python C API is + # compatible with C++ and does not emit C++ compiler warnings. + import os ++import platform + import shlex +-import sys + import sysconfig + from test import support + +@@ -10,6 +10,7 @@ + + + SOURCE = 'extension.cpp' ++ + if not support.MS_WINDOWS: + # C++ compiler flags for GCC and clang + CPPFLAGS = [ +@@ -19,34 +20,77 @@ + '-Werror', + ] + else: +- # Don't pass any compiler flag to MSVC +- CPPFLAGS = [] ++ # MSVC compiler flags ++ CPPFLAGS = [ ++ # Display warnings level 1 to 4 ++ '/W4', ++ # Treat all compiler warnings as compiler errors ++ '/WX', ++ ] + + + def main(): + cppflags = list(CPPFLAGS) +- std = os.environ["CPYTHON_TEST_CPP_STD"] +- name = os.environ["CPYTHON_TEST_EXT_NAME"] ++ std = os.environ.get("CPYTHON_TEST_CPP_STD", "") ++ module_name = os.environ["CPYTHON_TEST_EXT_NAME"] + +- cppflags = [*CPPFLAGS, f'-std={std}'] ++ cppflags = list(CPPFLAGS) ++ cppflags.append(f'-DMODULE_NAME={module_name}') ++ ++ # Add -std=STD or /std:STD (MSVC) compiler flag ++ if std: ++ if support.MS_WINDOWS: ++ cppflags.append(f'/std:{std}') ++ else: ++ cppflags.append(f'-std={std}') + + # gh-105776: When "gcc -std=11" is used as the C++ compiler, -std=c11 + # option emits a C++ compiler warning. Remove "-std11" option from the + # CC command. + cmd = (sysconfig.get_config_var('CC') or '') + if cmd is not None: ++ if support.MS_WINDOWS: ++ std_prefix = '/std' ++ else: ++ std_prefix = '-std' + cmd = shlex.split(cmd) +- cmd = [arg for arg in cmd if not arg.startswith('-std=')] ++ cmd = [arg for arg in cmd if not arg.startswith(std_prefix)] + cmd = shlex.join(cmd) + # CC env var overrides sysconfig CC variable in setuptools + os.environ['CC'] = cmd + +- cpp_ext = Extension( +- name, ++ # On Windows, add PCbuild\amd64\ to include and library directories ++ include_dirs = [] ++ library_dirs = [] ++ if support.MS_WINDOWS: ++ srcdir = sysconfig.get_config_var('srcdir') ++ machine = platform.uname().machine ++ pcbuild = os.path.join(srcdir, 'PCbuild', machine) ++ if os.path.exists(pcbuild): ++ # pyconfig.h is generated in PCbuild\amd64\ ++ include_dirs.append(pcbuild) ++ # python313.lib is generated in PCbuild\amd64\ ++ library_dirs.append(pcbuild) ++ print(f"Add PCbuild directory: {pcbuild}") ++ ++ # Display information to help debugging ++ for env_name in ('CC', 'CFLAGS', 'CPPFLAGS'): ++ if env_name in os.environ: ++ print(f"{env_name} env var: {os.environ[env_name]!r}") ++ else: ++ print(f"{env_name} env var: ") ++ print(f"extra_compile_args: {cppflags!r}") ++ ++ ext = Extension( ++ module_name, + sources=[SOURCE], + language='c++', +- extra_compile_args=cppflags) +- setup(name='internal' + name, version='0.0', ext_modules=[cpp_ext]) ++ extra_compile_args=cppflags, ++ include_dirs=include_dirs, ++ library_dirs=library_dirs) ++ setup(name=f'internal_{module_name}', ++ version='0.0', ++ ext_modules=[ext]) + + + if __name__ == "__main__": +diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py +index 72c86eecae2..f4f2011a51a 100644 +--- a/Lib/test/test_exceptions.py ++++ b/Lib/test/test_exceptions.py +@@ -2195,6 +2195,22 @@ def test_range_of_offsets(self): + self.assertIn(expected, err.getvalue()) + the_exception = exc + ++ def test_subclass(self): ++ class MySyntaxError(SyntaxError): ++ pass ++ ++ try: ++ raise MySyntaxError("bad bad", ("bad.py", 1, 2, "abcdefg", 1, 7)) ++ except SyntaxError as exc: ++ with support.captured_stderr() as err: ++ sys.__excepthook__(*sys.exc_info()) ++ self.assertIn(""" ++ File "bad.py", line 1 ++ abcdefg ++ ^^^^^ ++""", err.getvalue()) ++ ++ + def test_encodings(self): + self.addCleanup(unlink, TESTFN) + source = ( +diff --git a/Lib/test/test_http_cookies.py b/Lib/test/test_http_cookies.py +index 8879902a6e2..7b3dc0fdaed 100644 +--- a/Lib/test/test_http_cookies.py ++++ b/Lib/test/test_http_cookies.py +@@ -59,6 +59,52 @@ def test_basic(self): + for k, v in sorted(case['dict'].items()): + self.assertEqual(C[k].value, v) + ++ def test_obsolete_rfc850_date_format(self): ++ # Test cases with different days and dates in obsolete RFC 850 format ++ test_cases = [ ++ # from RFC 850, change EST to GMT ++ # https://datatracker.ietf.org/doc/html/rfc850#section-2 ++ { ++ 'data': 'key=value; expires=Saturday, 01-Jan-83 00:00:00 GMT', ++ 'output': 'Saturday, 01-Jan-83 00:00:00 GMT' ++ }, ++ { ++ 'data': 'key=value; expires=Friday, 19-Nov-82 16:59:30 GMT', ++ 'output': 'Friday, 19-Nov-82 16:59:30 GMT' ++ }, ++ # from RFC 9110 ++ # https://www.rfc-editor.org/rfc/rfc9110.html#section-5.6.7-6 ++ { ++ 'data': 'key=value; expires=Sunday, 06-Nov-94 08:49:37 GMT', ++ 'output': 'Sunday, 06-Nov-94 08:49:37 GMT' ++ }, ++ # other test cases ++ { ++ 'data': 'key=value; expires=Wednesday, 09-Nov-94 08:49:37 GMT', ++ 'output': 'Wednesday, 09-Nov-94 08:49:37 GMT' ++ }, ++ { ++ 'data': 'key=value; expires=Friday, 11-Nov-94 08:49:37 GMT', ++ 'output': 'Friday, 11-Nov-94 08:49:37 GMT' ++ }, ++ { ++ 'data': 'key=value; expires=Monday, 14-Nov-94 08:49:37 GMT', ++ 'output': 'Monday, 14-Nov-94 08:49:37 GMT' ++ }, ++ ] ++ ++ for case in test_cases: ++ with self.subTest(data=case['data']): ++ C = cookies.SimpleCookie() ++ C.load(case['data']) ++ ++ # Extract the cookie name from the data string ++ cookie_name = case['data'].split('=')[0] ++ ++ # Check if the cookie is loaded correctly ++ self.assertIn(cookie_name, C) ++ self.assertEqual(C[cookie_name].get('expires'), case['output']) ++ + def test_unquote(self): + cases = [ + (r'a="b=\""', 'b="'), +diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py +index d299c34cec0..41b973da2c7 100644 +--- a/Lib/test/test_long.py ++++ b/Lib/test/test_long.py +@@ -1639,6 +1639,8 @@ class MyInt(int): + MyInt.__basicsize__ + MyInt.__itemsize__ * ndigits + ) + ++ # GH-117195 -- This shouldn't crash ++ object.__sizeof__(1) + + if __name__ == "__main__": + unittest.main() +diff --git a/Lib/test/test_readline.py b/Lib/test/test_readline.py +index fab124ae4ad..e8a92f2b912 100644 +--- a/Lib/test/test_readline.py ++++ b/Lib/test/test_readline.py +@@ -114,6 +114,14 @@ def test_write_read_append(self): + # write_history_file can create the target + readline.write_history_file(hfilename) + ++ # Negative values should be disallowed ++ with self.assertRaises(ValueError): ++ readline.append_history_file(-42, hfilename) ++ ++ # See gh-122431, using the minimum signed integer value caused a segfault ++ with self.assertRaises(ValueError): ++ readline.append_history_file(-2147483648, hfilename) ++ + def test_nonascii_history(self): + readline.clear_history() + try: +diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py +index 9a559f44152..c7ded0f67fc 100644 +--- a/Lib/urllib/request.py ++++ b/Lib/urllib/request.py +@@ -903,9 +903,9 @@ def find_user_password(self, realm, authuri): + + class HTTPPasswordMgrWithPriorAuth(HTTPPasswordMgrWithDefaultRealm): + +- def __init__(self, *args, **kwargs): ++ def __init__(self): + self.authenticated = {} +- super().__init__(*args, **kwargs) ++ super().__init__() + + def add_password(self, realm, uri, user, passwd, is_authenticated=False): + self.update_authenticated(uri, is_authenticated) +diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c +index d5298519b58..82078a56988 100644 +--- a/Modules/posixmodule.c ++++ b/Modules/posixmodule.c +@@ -61,6 +61,9 @@ + + #include // ctermid() + #include // system() ++#ifdef HAVE_SYS_PIDFD_H ++# include // PIDFD_NONBLOCK ++#endif + + /* + * A number of APIs are available on macOS from a certain macOS version. +diff --git a/Modules/readline.c b/Modules/readline.c +index 0b6f96fdbfd..db2e7e35a49 100644 +--- a/Modules/readline.c ++++ b/Modules/readline.c +@@ -336,6 +336,12 @@ readline_append_history_file_impl(PyObject *module, int nelements, + PyObject *filename_obj) + /*[clinic end generated code: output=5df06fc9da56e4e4 input=784b774db3a4b7c5]*/ + { ++ if (nelements < 0) ++ { ++ PyErr_SetString(PyExc_ValueError, "nelements must be positive"); ++ return NULL; ++ } ++ + PyObject *filename_bytes; + const char *filename; + int err; +diff --git a/Objects/dictobject.c b/Objects/dictobject.c +index 4e965314945..7337e290e89 100644 +--- a/Objects/dictobject.c ++++ b/Objects/dictobject.c +@@ -458,11 +458,14 @@ estimate_log2_keysize(Py_ssize_t n) + + /* This immutable, empty PyDictKeysObject is used for PyDict_Clear() + * (which cannot fail and thus can do no allocation). ++ * ++ * See https://github.com/python/cpython/pull/127568#discussion_r1868070614 ++ * for the rationale of using dk_log2_index_bytes=3 instead of 0. + */ + static PyDictKeysObject empty_keys_struct = { + _Py_IMMORTAL_REFCNT, /* dk_refcnt */ + 0, /* dk_log2_size */ +- 0, /* dk_log2_index_bytes */ ++ 3, /* dk_log2_index_bytes */ + DICT_KEYS_UNICODE, /* dk_kind */ + 1, /* dk_version */ + 0, /* dk_usable (immutable) */ +diff --git a/Objects/typeobject.c b/Objects/typeobject.c +index 5bca4b4e788..06857e36857 100644 +--- a/Objects/typeobject.c ++++ b/Objects/typeobject.c +@@ -6462,8 +6462,11 @@ object___sizeof___impl(PyObject *self) + + res = 0; + isize = Py_TYPE(self)->tp_itemsize; +- if (isize > 0) +- res = Py_SIZE(self) * isize; ++ if (isize > 0) { ++ /* This assumes that ob_size is valid if tp_itemsize is not 0, ++ which isn't true for PyLongObject. */ ++ res = _PyVarObject_CAST(self)->ob_size * isize; ++ } + res += Py_TYPE(self)->tp_basicsize; + + return PyLong_FromSsize_t(res); +diff --git a/Python/pythonrun.c b/Python/pythonrun.c +index 5f3d249df45..cf84573a8e6 100644 +--- a/Python/pythonrun.c ++++ b/Python/pythonrun.c +@@ -538,43 +538,37 @@ parse_syntax_error(PyObject *err, PyObject **message, PyObject **filename, + *offset = hold; + } + +- if (Py_TYPE(err) == (PyTypeObject*)PyExc_SyntaxError) { +- v = PyObject_GetAttr(err, &_Py_ID(end_lineno)); +- if (!v) { +- PyErr_Clear(); +- *end_lineno = *lineno; +- } +- else if (v == Py_None) { +- *end_lineno = *lineno; +- Py_DECREF(v); +- } else { +- hold = PyLong_AsSsize_t(v); +- Py_DECREF(v); +- if (hold < 0 && PyErr_Occurred()) +- goto finally; +- *end_lineno = hold; +- } +- +- v = PyObject_GetAttr(err, &_Py_ID(end_offset)); +- if (!v) { +- PyErr_Clear(); +- *end_offset = -1; +- } +- else if (v == Py_None) { +- *end_offset = -1; +- Py_DECREF(v); +- } else { +- hold = PyLong_AsSsize_t(v); +- Py_DECREF(v); +- if (hold < 0 && PyErr_Occurred()) +- goto finally; +- *end_offset = hold; +- } +- } else { +- // SyntaxError subclasses ++ v = PyObject_GetAttr(err, &_Py_ID(end_lineno)); ++ if (!v) { ++ PyErr_Clear(); + *end_lineno = *lineno; ++ } ++ else if (v == Py_None) { ++ *end_lineno = *lineno; ++ Py_DECREF(v); ++ } else { ++ hold = PyLong_AsSsize_t(v); ++ Py_DECREF(v); ++ if (hold < 0 && PyErr_Occurred()) ++ goto finally; ++ *end_lineno = hold; ++ } ++ ++ v = PyObject_GetAttr(err, &_Py_ID(end_offset)); ++ if (!v) { ++ PyErr_Clear(); + *end_offset = -1; + } ++ else if (v == Py_None) { ++ *end_offset = -1; ++ Py_DECREF(v); ++ } else { ++ hold = PyLong_AsSsize_t(v); ++ Py_DECREF(v); ++ if (hold < 0 && PyErr_Occurred()) ++ goto finally; ++ *end_offset = hold; ++ } + + v = PyObject_GetAttr(err, &_Py_ID(text)); + if (!v) +diff --git a/configure.ac b/configure.ac +index 9270b5f7172..de9d7f56ffb 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -2874,7 +2874,7 @@ AC_CHECK_HEADERS([ \ + linux/tipc.h linux/wait.h netdb.h net/ethernet.h netinet/in.h netpacket/packet.h poll.h process.h pthread.h pty.h \ + sched.h setjmp.h shadow.h signal.h spawn.h stropts.h sys/audioio.h sys/bsdtty.h sys/devpoll.h \ + sys/endian.h sys/epoll.h sys/event.h sys/eventfd.h sys/file.h sys/ioctl.h sys/kern_control.h \ +- sys/loadavg.h sys/lock.h sys/memfd.h sys/mkdev.h sys/mman.h sys/modem.h sys/param.h sys/poll.h \ ++ sys/loadavg.h sys/lock.h sys/memfd.h sys/mkdev.h sys/mman.h sys/modem.h sys/param.h sys/pidfd.h sys/poll.h \ + sys/random.h sys/resource.h sys/select.h sys/sendfile.h sys/socket.h sys/soundcard.h sys/stat.h \ + sys/statvfs.h sys/sys_domain.h sys/syscall.h sys/sysmacros.h sys/termio.h sys/time.h sys/times.h \ + sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h sys/xattr.h sysexits.h syslog.h \ +diff --git a/pyconfig.h.in b/pyconfig.h.in +index 7d3537e5dd8..167c6a11411 100644 +--- a/pyconfig.h.in ++++ b/pyconfig.h.in +@@ -1332,6 +1332,9 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_SYS_PARAM_H + ++/* Define to 1 if you have the header file. */ ++#undef HAVE_SYS_PIDFD_H ++ + /* Define to 1 if you have the header file. */ + #undef HAVE_SYS_POLL_H + diff --git a/debian/patches/ignore-wheeldata.diff b/debian/patches/ignore-wheeldata.diff new file mode 100644 index 00000000..303e83a4 --- /dev/null +++ b/debian/patches/ignore-wheeldata.diff @@ -0,0 +1,39 @@ +Description: Don't assume wheeldata is deleted if `WHEEL_PKG_DIR` is set + Remove wheeldata from both sides of the `assertEqual`, so that we're + *actually* ignoring it from the test set. + . + This test is only making assertions about the source tree, no code is being + executed that would do anything different based on the value of + `WHEEL_PKG_DIR`. +Author: Stefano Rivera +Bug-upstream: https://github.com/python/cpython/issues/120418 +Forwarded: https://github.com/python/cpython/pull/120419 + +--- a/Lib/test/test_tools/test_makefile.py ++++ b/Lib/test/test_tools/test_makefile.py +@@ -40,7 +40,7 @@ + idle_test = 'idlelib/idle_test' + self.assertIn(idle_test, test_dirs) + +- used = [idle_test] ++ used = set([idle_test]) + for dirpath, dirs, files in os.walk(support.TEST_HOME_DIR): + dirname = os.path.basename(dirpath) + # Skip temporary dirs: +@@ -67,13 +67,14 @@ + "of test directories to install" + ) + ) +- used.append(relpath) ++ used.add(relpath) + + # Don't check the wheel dir when Python is built --with-wheel-pkg-dir + if sysconfig.get_config_var('WHEEL_PKG_DIR'): + test_dirs.remove('test/wheeldata') ++ used.discard('test/wheeldata') + + # Check that there are no extra entries: + unique_test_dirs = set(test_dirs) +- self.assertSetEqual(unique_test_dirs, set(used)) ++ self.assertSetEqual(unique_test_dirs, used) + self.assertEqual(len(test_dirs), len(unique_test_dirs)) diff --git a/debian/patches/issue127330.diff b/debian/patches/issue127330.diff new file mode 100644 index 00000000..3ea33048 --- /dev/null +++ b/debian/patches/issue127330.diff @@ -0,0 +1,18006 @@ +--- a/Modules/_ssl.c ++++ b/Modules/_ssl.c +@@ -116,8 +116,9 @@ static void _PySSLFixErrno(void) { + #endif + + /* Include generated data (error codes) */ ++/* See make_ssl_data.h for notes on adding a new version. */ + #if (OPENSSL_VERSION_NUMBER >= 0x30100000L) +-#include "_ssl_data_31.h" ++#include "_ssl_data_34.h" + #elif (OPENSSL_VERSION_NUMBER >= 0x30000000L) + #include "_ssl_data_300.h" + #elif (OPENSSL_VERSION_NUMBER >= 0x10101000L) && !defined(LIBRESSL_VERSION_NUMBER) +--- a/Modules/_ssl_data_111.h ++++ b/Modules/_ssl_data_111.h +@@ -1,4 +1,6 @@ +-/* File generated by Tools/ssl/make_ssl_data.py *//* Generated on 2023-06-01T02:58:04.081473 */ ++/* File generated by Tools/ssl/make_ssl_data.py */ ++/* Generated on 2024-11-27T12:48:46.194048+00:00 */ ++/* Generated from Git commit OpenSSL_1_1_1w-0-ge04bd3433f */ + static struct py_ssl_library_code library_codes[] = { + #ifdef ERR_LIB_ASN1 + {"ASN1", ERR_LIB_ASN1}, +--- a/Modules/_ssl_data_300.h ++++ b/Modules/_ssl_data_300.h +@@ -1,4 +1,7 @@ +-/* File generated by Tools/ssl/make_ssl_data.py *//* Generated on 2023-06-01T03:03:52.163218 */ ++/* File generated by Tools/ssl/make_ssl_data.py */ ++/* Generated on 2023-06-01T03:03:52.163218 */ ++/* Manually edited to add definitions from 1.1.1 (GH-105174) */ ++ + static struct py_ssl_library_code library_codes[] = { + #ifdef ERR_LIB_ASN1 + {"ASN1", ERR_LIB_ASN1}, +--- a/Modules/_ssl_data_31.h ++++ /dev/null +@@ -1,8605 +0,0 @@ +-/* File generated by Tools/ssl/make_ssl_data.py *//* Generated on 2023-06-01T03:04:00.275280 */ +-static struct py_ssl_library_code library_codes[] = { +-#ifdef ERR_LIB_ASN1 +- {"ASN1", ERR_LIB_ASN1}, +-#endif +-#ifdef ERR_LIB_ASYNC +- {"ASYNC", ERR_LIB_ASYNC}, +-#endif +-#ifdef ERR_LIB_BIO +- {"BIO", ERR_LIB_BIO}, +-#endif +-#ifdef ERR_LIB_BN +- {"BN", ERR_LIB_BN}, +-#endif +-#ifdef ERR_LIB_BUF +- {"BUF", ERR_LIB_BUF}, +-#endif +-#ifdef ERR_LIB_CMP +- {"CMP", ERR_LIB_CMP}, +-#endif +-#ifdef ERR_LIB_CMS +- {"CMS", ERR_LIB_CMS}, +-#endif +-#ifdef ERR_LIB_COMP +- {"COMP", ERR_LIB_COMP}, +-#endif +-#ifdef ERR_LIB_CONF +- {"CONF", ERR_LIB_CONF}, +-#endif +-#ifdef ERR_LIB_CRMF +- {"CRMF", ERR_LIB_CRMF}, +-#endif +-#ifdef ERR_LIB_CRYPTO +- {"CRYPTO", ERR_LIB_CRYPTO}, +-#endif +-#ifdef ERR_LIB_CT +- {"CT", ERR_LIB_CT}, +-#endif +-#ifdef ERR_LIB_DH +- {"DH", ERR_LIB_DH}, +-#endif +-#ifdef ERR_LIB_DSA +- {"DSA", ERR_LIB_DSA}, +-#endif +-#ifdef ERR_LIB_DSO +- {"DSO", ERR_LIB_DSO}, +-#endif +-#ifdef ERR_LIB_EC +- {"EC", ERR_LIB_EC}, +-#endif +-#ifdef ERR_LIB_ECDH +- {"ECDH", ERR_LIB_ECDH}, +-#endif +-#ifdef ERR_LIB_ECDSA +- {"ECDSA", ERR_LIB_ECDSA}, +-#endif +-#ifdef ERR_LIB_ENGINE +- {"ENGINE", ERR_LIB_ENGINE}, +-#endif +-#ifdef ERR_LIB_ESS +- {"ESS", ERR_LIB_ESS}, +-#endif +-#ifdef ERR_LIB_EVP +- {"EVP", ERR_LIB_EVP}, +-#endif +-#ifdef ERR_LIB_FIPS +- {"FIPS", ERR_LIB_FIPS}, +-#endif +-#ifdef ERR_LIB_HMAC +- {"HMAC", ERR_LIB_HMAC}, +-#endif +-#ifdef ERR_LIB_HTTP +- {"HTTP", ERR_LIB_HTTP}, +-#endif +-#ifdef ERR_LIB_JPAKE +- {"JPAKE", ERR_LIB_JPAKE}, +-#endif +-#ifdef ERR_LIB_KDF +- {"KDF", ERR_LIB_KDF}, +-#endif +-#ifdef ERR_LIB_MASK +- {"MASK", ERR_LIB_MASK}, +-#endif +-#ifdef ERR_LIB_METH +- {"METH", ERR_LIB_METH}, +-#endif +-#ifdef ERR_LIB_NONE +- {"NONE", ERR_LIB_NONE}, +-#endif +-#ifdef ERR_LIB_OBJ +- {"OBJ", ERR_LIB_OBJ}, +-#endif +-#ifdef ERR_LIB_OCSP +- {"OCSP", ERR_LIB_OCSP}, +-#endif +-#ifdef ERR_LIB_OFFSET +- {"OFFSET", ERR_LIB_OFFSET}, +-#endif +-#ifdef ERR_LIB_OSSL_DECODER +- {"OSSL_DECODER", ERR_LIB_OSSL_DECODER}, +-#endif +-#ifdef ERR_LIB_OSSL_ENCODER +- {"OSSL_ENCODER", ERR_LIB_OSSL_ENCODER}, +-#endif +-#ifdef ERR_LIB_OSSL_STORE +- {"OSSL_STORE", ERR_LIB_OSSL_STORE}, +-#endif +-#ifdef ERR_LIB_PEM +- {"PEM", ERR_LIB_PEM}, +-#endif +-#ifdef ERR_LIB_PKCS12 +- {"PKCS12", ERR_LIB_PKCS12}, +-#endif +-#ifdef ERR_LIB_PKCS7 +- {"PKCS7", ERR_LIB_PKCS7}, +-#endif +-#ifdef ERR_LIB_PROP +- {"PROP", ERR_LIB_PROP}, +-#endif +-#ifdef ERR_LIB_PROV +- {"PROV", ERR_LIB_PROV}, +-#endif +-#ifdef ERR_LIB_PROXY +- {"PROXY", ERR_LIB_PROXY}, +-#endif +-#ifdef ERR_LIB_RAND +- {"RAND", ERR_LIB_RAND}, +-#endif +-#ifdef ERR_LIB_RSA +- {"RSA", ERR_LIB_RSA}, +-#endif +-#ifdef ERR_LIB_RSAREF +- {"RSAREF", ERR_LIB_RSAREF}, +-#endif +-#ifdef ERR_LIB_SM2 +- {"SM2", ERR_LIB_SM2}, +-#endif +-#ifdef ERR_LIB_SSL +- {"SSL", ERR_LIB_SSL}, +-#endif +-#ifdef ERR_LIB_SSL2 +- {"SSL2", ERR_LIB_SSL2}, +-#endif +-#ifdef ERR_LIB_SSL23 +- {"SSL23", ERR_LIB_SSL23}, +-#endif +-#ifdef ERR_LIB_SSL3 +- {"SSL3", ERR_LIB_SSL3}, +-#endif +-#ifdef ERR_LIB_SYS +- {"SYS", ERR_LIB_SYS}, +-#endif +-#ifdef ERR_LIB_TS +- {"TS", ERR_LIB_TS}, +-#endif +-#ifdef ERR_LIB_UI +- {"UI", ERR_LIB_UI}, +-#endif +-#ifdef ERR_LIB_USER +- {"USER", ERR_LIB_USER}, +-#endif +-#ifdef ERR_LIB_X509 +- {"X509", ERR_LIB_X509}, +-#endif +-#ifdef ERR_LIB_X509V3 +- {"X509V3", ERR_LIB_X509V3}, +-#endif +- { NULL } +-}; +- +- +-static struct py_ssl_error_code error_codes[] = { +- #ifdef ASN1_R_ADDING_OBJECT +- {"ADDING_OBJECT", ERR_LIB_ASN1, ASN1_R_ADDING_OBJECT}, +- #else +- {"ADDING_OBJECT", 13, 171}, +- #endif +- #ifdef ASN1_R_ASN1_PARSE_ERROR +- {"ASN1_PARSE_ERROR", ERR_LIB_ASN1, ASN1_R_ASN1_PARSE_ERROR}, +- #else +- {"ASN1_PARSE_ERROR", 13, 203}, +- #endif +- #ifdef ASN1_R_ASN1_SIG_PARSE_ERROR +- {"ASN1_SIG_PARSE_ERROR", ERR_LIB_ASN1, ASN1_R_ASN1_SIG_PARSE_ERROR}, +- #else +- {"ASN1_SIG_PARSE_ERROR", 13, 204}, +- #endif +- #ifdef ASN1_R_AUX_ERROR +- {"AUX_ERROR", ERR_LIB_ASN1, ASN1_R_AUX_ERROR}, +- #else +- {"AUX_ERROR", 13, 100}, +- #endif +- #ifdef ASN1_R_BAD_OBJECT_HEADER +- {"BAD_OBJECT_HEADER", ERR_LIB_ASN1, ASN1_R_BAD_OBJECT_HEADER}, +- #else +- {"BAD_OBJECT_HEADER", 13, 102}, +- #endif +- #ifdef ASN1_R_BAD_TEMPLATE +- {"BAD_TEMPLATE", ERR_LIB_ASN1, ASN1_R_BAD_TEMPLATE}, +- #else +- {"BAD_TEMPLATE", 13, 230}, +- #endif +- #ifdef ASN1_R_BMPSTRING_IS_WRONG_LENGTH +- {"BMPSTRING_IS_WRONG_LENGTH", ERR_LIB_ASN1, ASN1_R_BMPSTRING_IS_WRONG_LENGTH}, +- #else +- {"BMPSTRING_IS_WRONG_LENGTH", 13, 214}, +- #endif +- #ifdef ASN1_R_BN_LIB +- {"BN_LIB", ERR_LIB_ASN1, ASN1_R_BN_LIB}, +- #else +- {"BN_LIB", 13, 105}, +- #endif +- #ifdef ASN1_R_BOOLEAN_IS_WRONG_LENGTH +- {"BOOLEAN_IS_WRONG_LENGTH", ERR_LIB_ASN1, ASN1_R_BOOLEAN_IS_WRONG_LENGTH}, +- #else +- {"BOOLEAN_IS_WRONG_LENGTH", 13, 106}, +- #endif +- #ifdef ASN1_R_BUFFER_TOO_SMALL +- {"BUFFER_TOO_SMALL", ERR_LIB_ASN1, ASN1_R_BUFFER_TOO_SMALL}, +- #else +- {"BUFFER_TOO_SMALL", 13, 107}, +- #endif +- #ifdef ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER +- {"CIPHER_HAS_NO_OBJECT_IDENTIFIER", ERR_LIB_ASN1, ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER}, +- #else +- {"CIPHER_HAS_NO_OBJECT_IDENTIFIER", 13, 108}, +- #endif +- #ifdef ASN1_R_CONTEXT_NOT_INITIALISED +- {"CONTEXT_NOT_INITIALISED", ERR_LIB_ASN1, ASN1_R_CONTEXT_NOT_INITIALISED}, +- #else +- {"CONTEXT_NOT_INITIALISED", 13, 217}, +- #endif +- #ifdef ASN1_R_DATA_IS_WRONG +- {"DATA_IS_WRONG", ERR_LIB_ASN1, ASN1_R_DATA_IS_WRONG}, +- #else +- {"DATA_IS_WRONG", 13, 109}, +- #endif +- #ifdef ASN1_R_DECODE_ERROR +- {"DECODE_ERROR", ERR_LIB_ASN1, ASN1_R_DECODE_ERROR}, +- #else +- {"DECODE_ERROR", 13, 110}, +- #endif +- #ifdef ASN1_R_DEPTH_EXCEEDED +- {"DEPTH_EXCEEDED", ERR_LIB_ASN1, ASN1_R_DEPTH_EXCEEDED}, +- #else +- {"DEPTH_EXCEEDED", 13, 174}, +- #endif +- #ifdef ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED +- {"DIGEST_AND_KEY_TYPE_NOT_SUPPORTED", ERR_LIB_ASN1, ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED}, +- #else +- {"DIGEST_AND_KEY_TYPE_NOT_SUPPORTED", 13, 198}, +- #endif +- #ifdef ASN1_R_ENCODE_ERROR +- {"ENCODE_ERROR", ERR_LIB_ASN1, ASN1_R_ENCODE_ERROR}, +- #else +- {"ENCODE_ERROR", 13, 112}, +- #endif +- #ifdef ASN1_R_ERROR_GETTING_TIME +- {"ERROR_GETTING_TIME", ERR_LIB_ASN1, ASN1_R_ERROR_GETTING_TIME}, +- #else +- {"ERROR_GETTING_TIME", 13, 173}, +- #endif +- #ifdef ASN1_R_ERROR_LOADING_SECTION +- {"ERROR_LOADING_SECTION", ERR_LIB_ASN1, ASN1_R_ERROR_LOADING_SECTION}, +- #else +- {"ERROR_LOADING_SECTION", 13, 172}, +- #endif +- #ifdef ASN1_R_ERROR_SETTING_CIPHER_PARAMS +- {"ERROR_SETTING_CIPHER_PARAMS", ERR_LIB_ASN1, ASN1_R_ERROR_SETTING_CIPHER_PARAMS}, +- #else +- {"ERROR_SETTING_CIPHER_PARAMS", 13, 114}, +- #endif +- #ifdef ASN1_R_EXPECTING_AN_INTEGER +- {"EXPECTING_AN_INTEGER", ERR_LIB_ASN1, ASN1_R_EXPECTING_AN_INTEGER}, +- #else +- {"EXPECTING_AN_INTEGER", 13, 115}, +- #endif +- #ifdef ASN1_R_EXPECTING_AN_OBJECT +- {"EXPECTING_AN_OBJECT", ERR_LIB_ASN1, ASN1_R_EXPECTING_AN_OBJECT}, +- #else +- {"EXPECTING_AN_OBJECT", 13, 116}, +- #endif +- #ifdef ASN1_R_EXPLICIT_LENGTH_MISMATCH +- {"EXPLICIT_LENGTH_MISMATCH", ERR_LIB_ASN1, ASN1_R_EXPLICIT_LENGTH_MISMATCH}, +- #else +- {"EXPLICIT_LENGTH_MISMATCH", 13, 119}, +- #endif +- #ifdef ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED +- {"EXPLICIT_TAG_NOT_CONSTRUCTED", ERR_LIB_ASN1, ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED}, +- #else +- {"EXPLICIT_TAG_NOT_CONSTRUCTED", 13, 120}, +- #endif +- #ifdef ASN1_R_FIELD_MISSING +- {"FIELD_MISSING", ERR_LIB_ASN1, ASN1_R_FIELD_MISSING}, +- #else +- {"FIELD_MISSING", 13, 121}, +- #endif +- #ifdef ASN1_R_FIRST_NUM_TOO_LARGE +- {"FIRST_NUM_TOO_LARGE", ERR_LIB_ASN1, ASN1_R_FIRST_NUM_TOO_LARGE}, +- #else +- {"FIRST_NUM_TOO_LARGE", 13, 122}, +- #endif +- #ifdef ASN1_R_HEADER_TOO_LONG +- {"HEADER_TOO_LONG", ERR_LIB_ASN1, ASN1_R_HEADER_TOO_LONG}, +- #else +- {"HEADER_TOO_LONG", 13, 123}, +- #endif +- #ifdef ASN1_R_ILLEGAL_BITSTRING_FORMAT +- {"ILLEGAL_BITSTRING_FORMAT", ERR_LIB_ASN1, ASN1_R_ILLEGAL_BITSTRING_FORMAT}, +- #else +- {"ILLEGAL_BITSTRING_FORMAT", 13, 175}, +- #endif +- #ifdef ASN1_R_ILLEGAL_BOOLEAN +- {"ILLEGAL_BOOLEAN", ERR_LIB_ASN1, ASN1_R_ILLEGAL_BOOLEAN}, +- #else +- {"ILLEGAL_BOOLEAN", 13, 176}, +- #endif +- #ifdef ASN1_R_ILLEGAL_CHARACTERS +- {"ILLEGAL_CHARACTERS", ERR_LIB_ASN1, ASN1_R_ILLEGAL_CHARACTERS}, +- #else +- {"ILLEGAL_CHARACTERS", 13, 124}, +- #endif +- #ifdef ASN1_R_ILLEGAL_FORMAT +- {"ILLEGAL_FORMAT", ERR_LIB_ASN1, ASN1_R_ILLEGAL_FORMAT}, +- #else +- {"ILLEGAL_FORMAT", 13, 177}, +- #endif +- #ifdef ASN1_R_ILLEGAL_HEX +- {"ILLEGAL_HEX", ERR_LIB_ASN1, ASN1_R_ILLEGAL_HEX}, +- #else +- {"ILLEGAL_HEX", 13, 178}, +- #endif +- #ifdef ASN1_R_ILLEGAL_IMPLICIT_TAG +- {"ILLEGAL_IMPLICIT_TAG", ERR_LIB_ASN1, ASN1_R_ILLEGAL_IMPLICIT_TAG}, +- #else +- {"ILLEGAL_IMPLICIT_TAG", 13, 179}, +- #endif +- #ifdef ASN1_R_ILLEGAL_INTEGER +- {"ILLEGAL_INTEGER", ERR_LIB_ASN1, ASN1_R_ILLEGAL_INTEGER}, +- #else +- {"ILLEGAL_INTEGER", 13, 180}, +- #endif +- #ifdef ASN1_R_ILLEGAL_NEGATIVE_VALUE +- {"ILLEGAL_NEGATIVE_VALUE", ERR_LIB_ASN1, ASN1_R_ILLEGAL_NEGATIVE_VALUE}, +- #else +- {"ILLEGAL_NEGATIVE_VALUE", 13, 226}, +- #endif +- #ifdef ASN1_R_ILLEGAL_NESTED_TAGGING +- {"ILLEGAL_NESTED_TAGGING", ERR_LIB_ASN1, ASN1_R_ILLEGAL_NESTED_TAGGING}, +- #else +- {"ILLEGAL_NESTED_TAGGING", 13, 181}, +- #endif +- #ifdef ASN1_R_ILLEGAL_NULL +- {"ILLEGAL_NULL", ERR_LIB_ASN1, ASN1_R_ILLEGAL_NULL}, +- #else +- {"ILLEGAL_NULL", 13, 125}, +- #endif +- #ifdef ASN1_R_ILLEGAL_NULL_VALUE +- {"ILLEGAL_NULL_VALUE", ERR_LIB_ASN1, ASN1_R_ILLEGAL_NULL_VALUE}, +- #else +- {"ILLEGAL_NULL_VALUE", 13, 182}, +- #endif +- #ifdef ASN1_R_ILLEGAL_OBJECT +- {"ILLEGAL_OBJECT", ERR_LIB_ASN1, ASN1_R_ILLEGAL_OBJECT}, +- #else +- {"ILLEGAL_OBJECT", 13, 183}, +- #endif +- #ifdef ASN1_R_ILLEGAL_OPTIONAL_ANY +- {"ILLEGAL_OPTIONAL_ANY", ERR_LIB_ASN1, ASN1_R_ILLEGAL_OPTIONAL_ANY}, +- #else +- {"ILLEGAL_OPTIONAL_ANY", 13, 126}, +- #endif +- #ifdef ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE +- {"ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE", ERR_LIB_ASN1, ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE}, +- #else +- {"ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE", 13, 170}, +- #endif +- #ifdef ASN1_R_ILLEGAL_PADDING +- {"ILLEGAL_PADDING", ERR_LIB_ASN1, ASN1_R_ILLEGAL_PADDING}, +- #else +- {"ILLEGAL_PADDING", 13, 221}, +- #endif +- #ifdef ASN1_R_ILLEGAL_TAGGED_ANY +- {"ILLEGAL_TAGGED_ANY", ERR_LIB_ASN1, ASN1_R_ILLEGAL_TAGGED_ANY}, +- #else +- {"ILLEGAL_TAGGED_ANY", 13, 127}, +- #endif +- #ifdef ASN1_R_ILLEGAL_TIME_VALUE +- {"ILLEGAL_TIME_VALUE", ERR_LIB_ASN1, ASN1_R_ILLEGAL_TIME_VALUE}, +- #else +- {"ILLEGAL_TIME_VALUE", 13, 184}, +- #endif +- #ifdef ASN1_R_ILLEGAL_ZERO_CONTENT +- {"ILLEGAL_ZERO_CONTENT", ERR_LIB_ASN1, ASN1_R_ILLEGAL_ZERO_CONTENT}, +- #else +- {"ILLEGAL_ZERO_CONTENT", 13, 222}, +- #endif +- #ifdef ASN1_R_INTEGER_NOT_ASCII_FORMAT +- {"INTEGER_NOT_ASCII_FORMAT", ERR_LIB_ASN1, ASN1_R_INTEGER_NOT_ASCII_FORMAT}, +- #else +- {"INTEGER_NOT_ASCII_FORMAT", 13, 185}, +- #endif +- #ifdef ASN1_R_INTEGER_TOO_LARGE_FOR_LONG +- {"INTEGER_TOO_LARGE_FOR_LONG", ERR_LIB_ASN1, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG}, +- #else +- {"INTEGER_TOO_LARGE_FOR_LONG", 13, 128}, +- #endif +- #ifdef ASN1_R_INVALID_BIT_STRING_BITS_LEFT +- {"INVALID_BIT_STRING_BITS_LEFT", ERR_LIB_ASN1, ASN1_R_INVALID_BIT_STRING_BITS_LEFT}, +- #else +- {"INVALID_BIT_STRING_BITS_LEFT", 13, 220}, +- #endif +- #ifdef ASN1_R_INVALID_BMPSTRING_LENGTH +- {"INVALID_BMPSTRING_LENGTH", ERR_LIB_ASN1, ASN1_R_INVALID_BMPSTRING_LENGTH}, +- #else +- {"INVALID_BMPSTRING_LENGTH", 13, 129}, +- #endif +- #ifdef ASN1_R_INVALID_DIGIT +- {"INVALID_DIGIT", ERR_LIB_ASN1, ASN1_R_INVALID_DIGIT}, +- #else +- {"INVALID_DIGIT", 13, 130}, +- #endif +- #ifdef ASN1_R_INVALID_MIME_TYPE +- {"INVALID_MIME_TYPE", ERR_LIB_ASN1, ASN1_R_INVALID_MIME_TYPE}, +- #else +- {"INVALID_MIME_TYPE", 13, 205}, +- #endif +- #ifdef ASN1_R_INVALID_MODIFIER +- {"INVALID_MODIFIER", ERR_LIB_ASN1, ASN1_R_INVALID_MODIFIER}, +- #else +- {"INVALID_MODIFIER", 13, 186}, +- #endif +- #ifdef ASN1_R_INVALID_NUMBER +- {"INVALID_NUMBER", ERR_LIB_ASN1, ASN1_R_INVALID_NUMBER}, +- #else +- {"INVALID_NUMBER", 13, 187}, +- #endif +- #ifdef ASN1_R_INVALID_OBJECT_ENCODING +- {"INVALID_OBJECT_ENCODING", ERR_LIB_ASN1, ASN1_R_INVALID_OBJECT_ENCODING}, +- #else +- {"INVALID_OBJECT_ENCODING", 13, 216}, +- #endif +- #ifdef ASN1_R_INVALID_SCRYPT_PARAMETERS +- {"INVALID_SCRYPT_PARAMETERS", ERR_LIB_ASN1, ASN1_R_INVALID_SCRYPT_PARAMETERS}, +- #else +- {"INVALID_SCRYPT_PARAMETERS", 13, 227}, +- #endif +- #ifdef ASN1_R_INVALID_SEPARATOR +- {"INVALID_SEPARATOR", ERR_LIB_ASN1, ASN1_R_INVALID_SEPARATOR}, +- #else +- {"INVALID_SEPARATOR", 13, 131}, +- #endif +- #ifdef ASN1_R_INVALID_STRING_TABLE_VALUE +- {"INVALID_STRING_TABLE_VALUE", ERR_LIB_ASN1, ASN1_R_INVALID_STRING_TABLE_VALUE}, +- #else +- {"INVALID_STRING_TABLE_VALUE", 13, 218}, +- #endif +- #ifdef ASN1_R_INVALID_UNIVERSALSTRING_LENGTH +- {"INVALID_UNIVERSALSTRING_LENGTH", ERR_LIB_ASN1, ASN1_R_INVALID_UNIVERSALSTRING_LENGTH}, +- #else +- {"INVALID_UNIVERSALSTRING_LENGTH", 13, 133}, +- #endif +- #ifdef ASN1_R_INVALID_UTF8STRING +- {"INVALID_UTF8STRING", ERR_LIB_ASN1, ASN1_R_INVALID_UTF8STRING}, +- #else +- {"INVALID_UTF8STRING", 13, 134}, +- #endif +- #ifdef ASN1_R_INVALID_VALUE +- {"INVALID_VALUE", ERR_LIB_ASN1, ASN1_R_INVALID_VALUE}, +- #else +- {"INVALID_VALUE", 13, 219}, +- #endif +- #ifdef ASN1_R_LENGTH_TOO_LONG +- {"LENGTH_TOO_LONG", ERR_LIB_ASN1, ASN1_R_LENGTH_TOO_LONG}, +- #else +- {"LENGTH_TOO_LONG", 13, 231}, +- #endif +- #ifdef ASN1_R_LIST_ERROR +- {"LIST_ERROR", ERR_LIB_ASN1, ASN1_R_LIST_ERROR}, +- #else +- {"LIST_ERROR", 13, 188}, +- #endif +- #ifdef ASN1_R_MIME_NO_CONTENT_TYPE +- {"MIME_NO_CONTENT_TYPE", ERR_LIB_ASN1, ASN1_R_MIME_NO_CONTENT_TYPE}, +- #else +- {"MIME_NO_CONTENT_TYPE", 13, 206}, +- #endif +- #ifdef ASN1_R_MIME_PARSE_ERROR +- {"MIME_PARSE_ERROR", ERR_LIB_ASN1, ASN1_R_MIME_PARSE_ERROR}, +- #else +- {"MIME_PARSE_ERROR", 13, 207}, +- #endif +- #ifdef ASN1_R_MIME_SIG_PARSE_ERROR +- {"MIME_SIG_PARSE_ERROR", ERR_LIB_ASN1, ASN1_R_MIME_SIG_PARSE_ERROR}, +- #else +- {"MIME_SIG_PARSE_ERROR", 13, 208}, +- #endif +- #ifdef ASN1_R_MISSING_EOC +- {"MISSING_EOC", ERR_LIB_ASN1, ASN1_R_MISSING_EOC}, +- #else +- {"MISSING_EOC", 13, 137}, +- #endif +- #ifdef ASN1_R_MISSING_SECOND_NUMBER +- {"MISSING_SECOND_NUMBER", ERR_LIB_ASN1, ASN1_R_MISSING_SECOND_NUMBER}, +- #else +- {"MISSING_SECOND_NUMBER", 13, 138}, +- #endif +- #ifdef ASN1_R_MISSING_VALUE +- {"MISSING_VALUE", ERR_LIB_ASN1, ASN1_R_MISSING_VALUE}, +- #else +- {"MISSING_VALUE", 13, 189}, +- #endif +- #ifdef ASN1_R_MSTRING_NOT_UNIVERSAL +- {"MSTRING_NOT_UNIVERSAL", ERR_LIB_ASN1, ASN1_R_MSTRING_NOT_UNIVERSAL}, +- #else +- {"MSTRING_NOT_UNIVERSAL", 13, 139}, +- #endif +- #ifdef ASN1_R_MSTRING_WRONG_TAG +- {"MSTRING_WRONG_TAG", ERR_LIB_ASN1, ASN1_R_MSTRING_WRONG_TAG}, +- #else +- {"MSTRING_WRONG_TAG", 13, 140}, +- #endif +- #ifdef ASN1_R_NESTED_ASN1_STRING +- {"NESTED_ASN1_STRING", ERR_LIB_ASN1, ASN1_R_NESTED_ASN1_STRING}, +- #else +- {"NESTED_ASN1_STRING", 13, 197}, +- #endif +- #ifdef ASN1_R_NESTED_TOO_DEEP +- {"NESTED_TOO_DEEP", ERR_LIB_ASN1, ASN1_R_NESTED_TOO_DEEP}, +- #else +- {"NESTED_TOO_DEEP", 13, 201}, +- #endif +- #ifdef ASN1_R_NON_HEX_CHARACTERS +- {"NON_HEX_CHARACTERS", ERR_LIB_ASN1, ASN1_R_NON_HEX_CHARACTERS}, +- #else +- {"NON_HEX_CHARACTERS", 13, 141}, +- #endif +- #ifdef ASN1_R_NOT_ASCII_FORMAT +- {"NOT_ASCII_FORMAT", ERR_LIB_ASN1, ASN1_R_NOT_ASCII_FORMAT}, +- #else +- {"NOT_ASCII_FORMAT", 13, 190}, +- #endif +- #ifdef ASN1_R_NOT_ENOUGH_DATA +- {"NOT_ENOUGH_DATA", ERR_LIB_ASN1, ASN1_R_NOT_ENOUGH_DATA}, +- #else +- {"NOT_ENOUGH_DATA", 13, 142}, +- #endif +- #ifdef ASN1_R_NO_CONTENT_TYPE +- {"NO_CONTENT_TYPE", ERR_LIB_ASN1, ASN1_R_NO_CONTENT_TYPE}, +- #else +- {"NO_CONTENT_TYPE", 13, 209}, +- #endif +- #ifdef ASN1_R_NO_MATCHING_CHOICE_TYPE +- {"NO_MATCHING_CHOICE_TYPE", ERR_LIB_ASN1, ASN1_R_NO_MATCHING_CHOICE_TYPE}, +- #else +- {"NO_MATCHING_CHOICE_TYPE", 13, 143}, +- #endif +- #ifdef ASN1_R_NO_MULTIPART_BODY_FAILURE +- {"NO_MULTIPART_BODY_FAILURE", ERR_LIB_ASN1, ASN1_R_NO_MULTIPART_BODY_FAILURE}, +- #else +- {"NO_MULTIPART_BODY_FAILURE", 13, 210}, +- #endif +- #ifdef ASN1_R_NO_MULTIPART_BOUNDARY +- {"NO_MULTIPART_BOUNDARY", ERR_LIB_ASN1, ASN1_R_NO_MULTIPART_BOUNDARY}, +- #else +- {"NO_MULTIPART_BOUNDARY", 13, 211}, +- #endif +- #ifdef ASN1_R_NO_SIG_CONTENT_TYPE +- {"NO_SIG_CONTENT_TYPE", ERR_LIB_ASN1, ASN1_R_NO_SIG_CONTENT_TYPE}, +- #else +- {"NO_SIG_CONTENT_TYPE", 13, 212}, +- #endif +- #ifdef ASN1_R_NULL_IS_WRONG_LENGTH +- {"NULL_IS_WRONG_LENGTH", ERR_LIB_ASN1, ASN1_R_NULL_IS_WRONG_LENGTH}, +- #else +- {"NULL_IS_WRONG_LENGTH", 13, 144}, +- #endif +- #ifdef ASN1_R_OBJECT_NOT_ASCII_FORMAT +- {"OBJECT_NOT_ASCII_FORMAT", ERR_LIB_ASN1, ASN1_R_OBJECT_NOT_ASCII_FORMAT}, +- #else +- {"OBJECT_NOT_ASCII_FORMAT", 13, 191}, +- #endif +- #ifdef ASN1_R_ODD_NUMBER_OF_CHARS +- {"ODD_NUMBER_OF_CHARS", ERR_LIB_ASN1, ASN1_R_ODD_NUMBER_OF_CHARS}, +- #else +- {"ODD_NUMBER_OF_CHARS", 13, 145}, +- #endif +- #ifdef ASN1_R_SECOND_NUMBER_TOO_LARGE +- {"SECOND_NUMBER_TOO_LARGE", ERR_LIB_ASN1, ASN1_R_SECOND_NUMBER_TOO_LARGE}, +- #else +- {"SECOND_NUMBER_TOO_LARGE", 13, 147}, +- #endif +- #ifdef ASN1_R_SEQUENCE_LENGTH_MISMATCH +- {"SEQUENCE_LENGTH_MISMATCH", ERR_LIB_ASN1, ASN1_R_SEQUENCE_LENGTH_MISMATCH}, +- #else +- {"SEQUENCE_LENGTH_MISMATCH", 13, 148}, +- #endif +- #ifdef ASN1_R_SEQUENCE_NOT_CONSTRUCTED +- {"SEQUENCE_NOT_CONSTRUCTED", ERR_LIB_ASN1, ASN1_R_SEQUENCE_NOT_CONSTRUCTED}, +- #else +- {"SEQUENCE_NOT_CONSTRUCTED", 13, 149}, +- #endif +- #ifdef ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG +- {"SEQUENCE_OR_SET_NEEDS_CONFIG", ERR_LIB_ASN1, ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG}, +- #else +- {"SEQUENCE_OR_SET_NEEDS_CONFIG", 13, 192}, +- #endif +- #ifdef ASN1_R_SHORT_LINE +- {"SHORT_LINE", ERR_LIB_ASN1, ASN1_R_SHORT_LINE}, +- #else +- {"SHORT_LINE", 13, 150}, +- #endif +- #ifdef ASN1_R_SIG_INVALID_MIME_TYPE +- {"SIG_INVALID_MIME_TYPE", ERR_LIB_ASN1, ASN1_R_SIG_INVALID_MIME_TYPE}, +- #else +- {"SIG_INVALID_MIME_TYPE", 13, 213}, +- #endif +- #ifdef ASN1_R_STREAMING_NOT_SUPPORTED +- {"STREAMING_NOT_SUPPORTED", ERR_LIB_ASN1, ASN1_R_STREAMING_NOT_SUPPORTED}, +- #else +- {"STREAMING_NOT_SUPPORTED", 13, 202}, +- #endif +- #ifdef ASN1_R_STRING_TOO_LONG +- {"STRING_TOO_LONG", ERR_LIB_ASN1, ASN1_R_STRING_TOO_LONG}, +- #else +- {"STRING_TOO_LONG", 13, 151}, +- #endif +- #ifdef ASN1_R_STRING_TOO_SHORT +- {"STRING_TOO_SHORT", ERR_LIB_ASN1, ASN1_R_STRING_TOO_SHORT}, +- #else +- {"STRING_TOO_SHORT", 13, 152}, +- #endif +- #ifdef ASN1_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD +- {"THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD", ERR_LIB_ASN1, ASN1_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD}, +- #else +- {"THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD", 13, 154}, +- #endif +- #ifdef ASN1_R_TIME_NOT_ASCII_FORMAT +- {"TIME_NOT_ASCII_FORMAT", ERR_LIB_ASN1, ASN1_R_TIME_NOT_ASCII_FORMAT}, +- #else +- {"TIME_NOT_ASCII_FORMAT", 13, 193}, +- #endif +- #ifdef ASN1_R_TOO_LARGE +- {"TOO_LARGE", ERR_LIB_ASN1, ASN1_R_TOO_LARGE}, +- #else +- {"TOO_LARGE", 13, 223}, +- #endif +- #ifdef ASN1_R_TOO_LONG +- {"TOO_LONG", ERR_LIB_ASN1, ASN1_R_TOO_LONG}, +- #else +- {"TOO_LONG", 13, 155}, +- #endif +- #ifdef ASN1_R_TOO_SMALL +- {"TOO_SMALL", ERR_LIB_ASN1, ASN1_R_TOO_SMALL}, +- #else +- {"TOO_SMALL", 13, 224}, +- #endif +- #ifdef ASN1_R_TYPE_NOT_CONSTRUCTED +- {"TYPE_NOT_CONSTRUCTED", ERR_LIB_ASN1, ASN1_R_TYPE_NOT_CONSTRUCTED}, +- #else +- {"TYPE_NOT_CONSTRUCTED", 13, 156}, +- #endif +- #ifdef ASN1_R_TYPE_NOT_PRIMITIVE +- {"TYPE_NOT_PRIMITIVE", ERR_LIB_ASN1, ASN1_R_TYPE_NOT_PRIMITIVE}, +- #else +- {"TYPE_NOT_PRIMITIVE", 13, 195}, +- #endif +- #ifdef ASN1_R_UNEXPECTED_EOC +- {"UNEXPECTED_EOC", ERR_LIB_ASN1, ASN1_R_UNEXPECTED_EOC}, +- #else +- {"UNEXPECTED_EOC", 13, 159}, +- #endif +- #ifdef ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH +- {"UNIVERSALSTRING_IS_WRONG_LENGTH", ERR_LIB_ASN1, ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH}, +- #else +- {"UNIVERSALSTRING_IS_WRONG_LENGTH", 13, 215}, +- #endif +- #ifdef ASN1_R_UNKNOWN_DIGEST +- {"UNKNOWN_DIGEST", ERR_LIB_ASN1, ASN1_R_UNKNOWN_DIGEST}, +- #else +- {"UNKNOWN_DIGEST", 13, 229}, +- #endif +- #ifdef ASN1_R_UNKNOWN_FORMAT +- {"UNKNOWN_FORMAT", ERR_LIB_ASN1, ASN1_R_UNKNOWN_FORMAT}, +- #else +- {"UNKNOWN_FORMAT", 13, 160}, +- #endif +- #ifdef ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM +- {"UNKNOWN_MESSAGE_DIGEST_ALGORITHM", ERR_LIB_ASN1, ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM}, +- #else +- {"UNKNOWN_MESSAGE_DIGEST_ALGORITHM", 13, 161}, +- #endif +- #ifdef ASN1_R_UNKNOWN_OBJECT_TYPE +- {"UNKNOWN_OBJECT_TYPE", ERR_LIB_ASN1, ASN1_R_UNKNOWN_OBJECT_TYPE}, +- #else +- {"UNKNOWN_OBJECT_TYPE", 13, 162}, +- #endif +- #ifdef ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE +- {"UNKNOWN_PUBLIC_KEY_TYPE", ERR_LIB_ASN1, ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE}, +- #else +- {"UNKNOWN_PUBLIC_KEY_TYPE", 13, 163}, +- #endif +- #ifdef ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM +- {"UNKNOWN_SIGNATURE_ALGORITHM", ERR_LIB_ASN1, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM}, +- #else +- {"UNKNOWN_SIGNATURE_ALGORITHM", 13, 199}, +- #endif +- #ifdef ASN1_R_UNKNOWN_TAG +- {"UNKNOWN_TAG", ERR_LIB_ASN1, ASN1_R_UNKNOWN_TAG}, +- #else +- {"UNKNOWN_TAG", 13, 194}, +- #endif +- #ifdef ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE +- {"UNSUPPORTED_ANY_DEFINED_BY_TYPE", ERR_LIB_ASN1, ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE}, +- #else +- {"UNSUPPORTED_ANY_DEFINED_BY_TYPE", 13, 164}, +- #endif +- #ifdef ASN1_R_UNSUPPORTED_CIPHER +- {"UNSUPPORTED_CIPHER", ERR_LIB_ASN1, ASN1_R_UNSUPPORTED_CIPHER}, +- #else +- {"UNSUPPORTED_CIPHER", 13, 228}, +- #endif +- #ifdef ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE +- {"UNSUPPORTED_PUBLIC_KEY_TYPE", ERR_LIB_ASN1, ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE}, +- #else +- {"UNSUPPORTED_PUBLIC_KEY_TYPE", 13, 167}, +- #endif +- #ifdef ASN1_R_UNSUPPORTED_TYPE +- {"UNSUPPORTED_TYPE", ERR_LIB_ASN1, ASN1_R_UNSUPPORTED_TYPE}, +- #else +- {"UNSUPPORTED_TYPE", 13, 196}, +- #endif +- #ifdef ASN1_R_WRONG_INTEGER_TYPE +- {"WRONG_INTEGER_TYPE", ERR_LIB_ASN1, ASN1_R_WRONG_INTEGER_TYPE}, +- #else +- {"WRONG_INTEGER_TYPE", 13, 225}, +- #endif +- #ifdef ASN1_R_WRONG_PUBLIC_KEY_TYPE +- {"WRONG_PUBLIC_KEY_TYPE", ERR_LIB_ASN1, ASN1_R_WRONG_PUBLIC_KEY_TYPE}, +- #else +- {"WRONG_PUBLIC_KEY_TYPE", 13, 200}, +- #endif +- #ifdef ASN1_R_WRONG_TAG +- {"WRONG_TAG", ERR_LIB_ASN1, ASN1_R_WRONG_TAG}, +- #else +- {"WRONG_TAG", 13, 168}, +- #endif +- #ifdef ASYNC_R_FAILED_TO_SET_POOL +- {"FAILED_TO_SET_POOL", ERR_LIB_ASYNC, ASYNC_R_FAILED_TO_SET_POOL}, +- #else +- {"FAILED_TO_SET_POOL", 51, 101}, +- #endif +- #ifdef ASYNC_R_FAILED_TO_SWAP_CONTEXT +- {"FAILED_TO_SWAP_CONTEXT", ERR_LIB_ASYNC, ASYNC_R_FAILED_TO_SWAP_CONTEXT}, +- #else +- {"FAILED_TO_SWAP_CONTEXT", 51, 102}, +- #endif +- #ifdef ASYNC_R_INIT_FAILED +- {"INIT_FAILED", ERR_LIB_ASYNC, ASYNC_R_INIT_FAILED}, +- #else +- {"INIT_FAILED", 51, 105}, +- #endif +- #ifdef ASYNC_R_INVALID_POOL_SIZE +- {"INVALID_POOL_SIZE", ERR_LIB_ASYNC, ASYNC_R_INVALID_POOL_SIZE}, +- #else +- {"INVALID_POOL_SIZE", 51, 103}, +- #endif +- #ifdef BIO_R_ACCEPT_ERROR +- {"ACCEPT_ERROR", ERR_LIB_BIO, BIO_R_ACCEPT_ERROR}, +- #else +- {"ACCEPT_ERROR", 32, 100}, +- #endif +- #ifdef BIO_R_ADDRINFO_ADDR_IS_NOT_AF_INET +- {"ADDRINFO_ADDR_IS_NOT_AF_INET", ERR_LIB_BIO, BIO_R_ADDRINFO_ADDR_IS_NOT_AF_INET}, +- #else +- {"ADDRINFO_ADDR_IS_NOT_AF_INET", 32, 141}, +- #endif +- #ifdef BIO_R_AMBIGUOUS_HOST_OR_SERVICE +- {"AMBIGUOUS_HOST_OR_SERVICE", ERR_LIB_BIO, BIO_R_AMBIGUOUS_HOST_OR_SERVICE}, +- #else +- {"AMBIGUOUS_HOST_OR_SERVICE", 32, 129}, +- #endif +- #ifdef BIO_R_BAD_FOPEN_MODE +- {"BAD_FOPEN_MODE", ERR_LIB_BIO, BIO_R_BAD_FOPEN_MODE}, +- #else +- {"BAD_FOPEN_MODE", 32, 101}, +- #endif +- #ifdef BIO_R_BROKEN_PIPE +- {"BROKEN_PIPE", ERR_LIB_BIO, BIO_R_BROKEN_PIPE}, +- #else +- {"BROKEN_PIPE", 32, 124}, +- #endif +- #ifdef BIO_R_CONNECT_ERROR +- {"CONNECT_ERROR", ERR_LIB_BIO, BIO_R_CONNECT_ERROR}, +- #else +- {"CONNECT_ERROR", 32, 103}, +- #endif +- #ifdef BIO_R_CONNECT_TIMEOUT +- {"CONNECT_TIMEOUT", ERR_LIB_BIO, BIO_R_CONNECT_TIMEOUT}, +- #else +- {"CONNECT_TIMEOUT", 32, 147}, +- #endif +- #ifdef BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET +- {"GETHOSTBYNAME_ADDR_IS_NOT_AF_INET", ERR_LIB_BIO, BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET}, +- #else +- {"GETHOSTBYNAME_ADDR_IS_NOT_AF_INET", 32, 107}, +- #endif +- #ifdef BIO_R_GETSOCKNAME_ERROR +- {"GETSOCKNAME_ERROR", ERR_LIB_BIO, BIO_R_GETSOCKNAME_ERROR}, +- #else +- {"GETSOCKNAME_ERROR", 32, 132}, +- #endif +- #ifdef BIO_R_GETSOCKNAME_TRUNCATED_ADDRESS +- {"GETSOCKNAME_TRUNCATED_ADDRESS", ERR_LIB_BIO, BIO_R_GETSOCKNAME_TRUNCATED_ADDRESS}, +- #else +- {"GETSOCKNAME_TRUNCATED_ADDRESS", 32, 133}, +- #endif +- #ifdef BIO_R_GETTING_SOCKTYPE +- {"GETTING_SOCKTYPE", ERR_LIB_BIO, BIO_R_GETTING_SOCKTYPE}, +- #else +- {"GETTING_SOCKTYPE", 32, 134}, +- #endif +- #ifdef BIO_R_INVALID_ARGUMENT +- {"INVALID_ARGUMENT", ERR_LIB_BIO, BIO_R_INVALID_ARGUMENT}, +- #else +- {"INVALID_ARGUMENT", 32, 125}, +- #endif +- #ifdef BIO_R_INVALID_SOCKET +- {"INVALID_SOCKET", ERR_LIB_BIO, BIO_R_INVALID_SOCKET}, +- #else +- {"INVALID_SOCKET", 32, 135}, +- #endif +- #ifdef BIO_R_IN_USE +- {"IN_USE", ERR_LIB_BIO, BIO_R_IN_USE}, +- #else +- {"IN_USE", 32, 123}, +- #endif +- #ifdef BIO_R_LENGTH_TOO_LONG +- {"LENGTH_TOO_LONG", ERR_LIB_BIO, BIO_R_LENGTH_TOO_LONG}, +- #else +- {"LENGTH_TOO_LONG", 32, 102}, +- #endif +- #ifdef BIO_R_LISTEN_V6_ONLY +- {"LISTEN_V6_ONLY", ERR_LIB_BIO, BIO_R_LISTEN_V6_ONLY}, +- #else +- {"LISTEN_V6_ONLY", 32, 136}, +- #endif +- #ifdef BIO_R_LOOKUP_RETURNED_NOTHING +- {"LOOKUP_RETURNED_NOTHING", ERR_LIB_BIO, BIO_R_LOOKUP_RETURNED_NOTHING}, +- #else +- {"LOOKUP_RETURNED_NOTHING", 32, 142}, +- #endif +- #ifdef BIO_R_MALFORMED_HOST_OR_SERVICE +- {"MALFORMED_HOST_OR_SERVICE", ERR_LIB_BIO, BIO_R_MALFORMED_HOST_OR_SERVICE}, +- #else +- {"MALFORMED_HOST_OR_SERVICE", 32, 130}, +- #endif +- #ifdef BIO_R_NBIO_CONNECT_ERROR +- {"NBIO_CONNECT_ERROR", ERR_LIB_BIO, BIO_R_NBIO_CONNECT_ERROR}, +- #else +- {"NBIO_CONNECT_ERROR", 32, 110}, +- #endif +- #ifdef BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED +- {"NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED", ERR_LIB_BIO, BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED}, +- #else +- {"NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED", 32, 143}, +- #endif +- #ifdef BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED +- {"NO_HOSTNAME_OR_SERVICE_SPECIFIED", ERR_LIB_BIO, BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED}, +- #else +- {"NO_HOSTNAME_OR_SERVICE_SPECIFIED", 32, 144}, +- #endif +- #ifdef BIO_R_NO_PORT_DEFINED +- {"NO_PORT_DEFINED", ERR_LIB_BIO, BIO_R_NO_PORT_DEFINED}, +- #else +- {"NO_PORT_DEFINED", 32, 113}, +- #endif +- #ifdef BIO_R_NO_SUCH_FILE +- {"NO_SUCH_FILE", ERR_LIB_BIO, BIO_R_NO_SUCH_FILE}, +- #else +- {"NO_SUCH_FILE", 32, 128}, +- #endif +- #ifdef BIO_R_TRANSFER_ERROR +- {"TRANSFER_ERROR", ERR_LIB_BIO, BIO_R_TRANSFER_ERROR}, +- #else +- {"TRANSFER_ERROR", 32, 104}, +- #endif +- #ifdef BIO_R_TRANSFER_TIMEOUT +- {"TRANSFER_TIMEOUT", ERR_LIB_BIO, BIO_R_TRANSFER_TIMEOUT}, +- #else +- {"TRANSFER_TIMEOUT", 32, 105}, +- #endif +- #ifdef BIO_R_UNABLE_TO_BIND_SOCKET +- {"UNABLE_TO_BIND_SOCKET", ERR_LIB_BIO, BIO_R_UNABLE_TO_BIND_SOCKET}, +- #else +- {"UNABLE_TO_BIND_SOCKET", 32, 117}, +- #endif +- #ifdef BIO_R_UNABLE_TO_CREATE_SOCKET +- {"UNABLE_TO_CREATE_SOCKET", ERR_LIB_BIO, BIO_R_UNABLE_TO_CREATE_SOCKET}, +- #else +- {"UNABLE_TO_CREATE_SOCKET", 32, 118}, +- #endif +- #ifdef BIO_R_UNABLE_TO_KEEPALIVE +- {"UNABLE_TO_KEEPALIVE", ERR_LIB_BIO, BIO_R_UNABLE_TO_KEEPALIVE}, +- #else +- {"UNABLE_TO_KEEPALIVE", 32, 137}, +- #endif +- #ifdef BIO_R_UNABLE_TO_LISTEN_SOCKET +- {"UNABLE_TO_LISTEN_SOCKET", ERR_LIB_BIO, BIO_R_UNABLE_TO_LISTEN_SOCKET}, +- #else +- {"UNABLE_TO_LISTEN_SOCKET", 32, 119}, +- #endif +- #ifdef BIO_R_UNABLE_TO_NODELAY +- {"UNABLE_TO_NODELAY", ERR_LIB_BIO, BIO_R_UNABLE_TO_NODELAY}, +- #else +- {"UNABLE_TO_NODELAY", 32, 138}, +- #endif +- #ifdef BIO_R_UNABLE_TO_REUSEADDR +- {"UNABLE_TO_REUSEADDR", ERR_LIB_BIO, BIO_R_UNABLE_TO_REUSEADDR}, +- #else +- {"UNABLE_TO_REUSEADDR", 32, 139}, +- #endif +- #ifdef BIO_R_UNAVAILABLE_IP_FAMILY +- {"UNAVAILABLE_IP_FAMILY", ERR_LIB_BIO, BIO_R_UNAVAILABLE_IP_FAMILY}, +- #else +- {"UNAVAILABLE_IP_FAMILY", 32, 145}, +- #endif +- #ifdef BIO_R_UNINITIALIZED +- {"UNINITIALIZED", ERR_LIB_BIO, BIO_R_UNINITIALIZED}, +- #else +- {"UNINITIALIZED", 32, 120}, +- #endif +- #ifdef BIO_R_UNKNOWN_INFO_TYPE +- {"UNKNOWN_INFO_TYPE", ERR_LIB_BIO, BIO_R_UNKNOWN_INFO_TYPE}, +- #else +- {"UNKNOWN_INFO_TYPE", 32, 140}, +- #endif +- #ifdef BIO_R_UNSUPPORTED_IP_FAMILY +- {"UNSUPPORTED_IP_FAMILY", ERR_LIB_BIO, BIO_R_UNSUPPORTED_IP_FAMILY}, +- #else +- {"UNSUPPORTED_IP_FAMILY", 32, 146}, +- #endif +- #ifdef BIO_R_UNSUPPORTED_METHOD +- {"UNSUPPORTED_METHOD", ERR_LIB_BIO, BIO_R_UNSUPPORTED_METHOD}, +- #else +- {"UNSUPPORTED_METHOD", 32, 121}, +- #endif +- #ifdef BIO_R_UNSUPPORTED_PROTOCOL_FAMILY +- {"UNSUPPORTED_PROTOCOL_FAMILY", ERR_LIB_BIO, BIO_R_UNSUPPORTED_PROTOCOL_FAMILY}, +- #else +- {"UNSUPPORTED_PROTOCOL_FAMILY", 32, 131}, +- #endif +- #ifdef BIO_R_WRITE_TO_READ_ONLY_BIO +- {"WRITE_TO_READ_ONLY_BIO", ERR_LIB_BIO, BIO_R_WRITE_TO_READ_ONLY_BIO}, +- #else +- {"WRITE_TO_READ_ONLY_BIO", 32, 126}, +- #endif +- #ifdef BIO_R_WSASTARTUP +- {"WSASTARTUP", ERR_LIB_BIO, BIO_R_WSASTARTUP}, +- #else +- {"WSASTARTUP", 32, 122}, +- #endif +- #ifdef BN_R_ARG2_LT_ARG3 +- {"ARG2_LT_ARG3", ERR_LIB_BN, BN_R_ARG2_LT_ARG3}, +- #else +- {"ARG2_LT_ARG3", 3, 100}, +- #endif +- #ifdef BN_R_BAD_RECIPROCAL +- {"BAD_RECIPROCAL", ERR_LIB_BN, BN_R_BAD_RECIPROCAL}, +- #else +- {"BAD_RECIPROCAL", 3, 101}, +- #endif +- #ifdef BN_R_BIGNUM_TOO_LONG +- {"BIGNUM_TOO_LONG", ERR_LIB_BN, BN_R_BIGNUM_TOO_LONG}, +- #else +- {"BIGNUM_TOO_LONG", 3, 114}, +- #endif +- #ifdef BN_R_BITS_TOO_SMALL +- {"BITS_TOO_SMALL", ERR_LIB_BN, BN_R_BITS_TOO_SMALL}, +- #else +- {"BITS_TOO_SMALL", 3, 118}, +- #endif +- #ifdef BN_R_CALLED_WITH_EVEN_MODULUS +- {"CALLED_WITH_EVEN_MODULUS", ERR_LIB_BN, BN_R_CALLED_WITH_EVEN_MODULUS}, +- #else +- {"CALLED_WITH_EVEN_MODULUS", 3, 102}, +- #endif +- #ifdef BN_R_DIV_BY_ZERO +- {"DIV_BY_ZERO", ERR_LIB_BN, BN_R_DIV_BY_ZERO}, +- #else +- {"DIV_BY_ZERO", 3, 103}, +- #endif +- #ifdef BN_R_ENCODING_ERROR +- {"ENCODING_ERROR", ERR_LIB_BN, BN_R_ENCODING_ERROR}, +- #else +- {"ENCODING_ERROR", 3, 104}, +- #endif +- #ifdef BN_R_EXPAND_ON_STATIC_BIGNUM_DATA +- {"EXPAND_ON_STATIC_BIGNUM_DATA", ERR_LIB_BN, BN_R_EXPAND_ON_STATIC_BIGNUM_DATA}, +- #else +- {"EXPAND_ON_STATIC_BIGNUM_DATA", 3, 105}, +- #endif +- #ifdef BN_R_INPUT_NOT_REDUCED +- {"INPUT_NOT_REDUCED", ERR_LIB_BN, BN_R_INPUT_NOT_REDUCED}, +- #else +- {"INPUT_NOT_REDUCED", 3, 110}, +- #endif +- #ifdef BN_R_INVALID_LENGTH +- {"INVALID_LENGTH", ERR_LIB_BN, BN_R_INVALID_LENGTH}, +- #else +- {"INVALID_LENGTH", 3, 106}, +- #endif +- #ifdef BN_R_INVALID_RANGE +- {"INVALID_RANGE", ERR_LIB_BN, BN_R_INVALID_RANGE}, +- #else +- {"INVALID_RANGE", 3, 115}, +- #endif +- #ifdef BN_R_INVALID_SHIFT +- {"INVALID_SHIFT", ERR_LIB_BN, BN_R_INVALID_SHIFT}, +- #else +- {"INVALID_SHIFT", 3, 119}, +- #endif +- #ifdef BN_R_NOT_A_SQUARE +- {"NOT_A_SQUARE", ERR_LIB_BN, BN_R_NOT_A_SQUARE}, +- #else +- {"NOT_A_SQUARE", 3, 111}, +- #endif +- #ifdef BN_R_NOT_INITIALIZED +- {"NOT_INITIALIZED", ERR_LIB_BN, BN_R_NOT_INITIALIZED}, +- #else +- {"NOT_INITIALIZED", 3, 107}, +- #endif +- #ifdef BN_R_NO_INVERSE +- {"NO_INVERSE", ERR_LIB_BN, BN_R_NO_INVERSE}, +- #else +- {"NO_INVERSE", 3, 108}, +- #endif +- #ifdef BN_R_NO_PRIME_CANDIDATE +- {"NO_PRIME_CANDIDATE", ERR_LIB_BN, BN_R_NO_PRIME_CANDIDATE}, +- #else +- {"NO_PRIME_CANDIDATE", 3, 121}, +- #endif +- #ifdef BN_R_NO_SOLUTION +- {"NO_SOLUTION", ERR_LIB_BN, BN_R_NO_SOLUTION}, +- #else +- {"NO_SOLUTION", 3, 116}, +- #endif +- #ifdef BN_R_NO_SUITABLE_DIGEST +- {"NO_SUITABLE_DIGEST", ERR_LIB_BN, BN_R_NO_SUITABLE_DIGEST}, +- #else +- {"NO_SUITABLE_DIGEST", 3, 120}, +- #endif +- #ifdef BN_R_PRIVATE_KEY_TOO_LARGE +- {"PRIVATE_KEY_TOO_LARGE", ERR_LIB_BN, BN_R_PRIVATE_KEY_TOO_LARGE}, +- #else +- {"PRIVATE_KEY_TOO_LARGE", 3, 117}, +- #endif +- #ifdef BN_R_P_IS_NOT_PRIME +- {"P_IS_NOT_PRIME", ERR_LIB_BN, BN_R_P_IS_NOT_PRIME}, +- #else +- {"P_IS_NOT_PRIME", 3, 112}, +- #endif +- #ifdef BN_R_TOO_MANY_ITERATIONS +- {"TOO_MANY_ITERATIONS", ERR_LIB_BN, BN_R_TOO_MANY_ITERATIONS}, +- #else +- {"TOO_MANY_ITERATIONS", 3, 113}, +- #endif +- #ifdef BN_R_TOO_MANY_TEMPORARY_VARIABLES +- {"TOO_MANY_TEMPORARY_VARIABLES", ERR_LIB_BN, BN_R_TOO_MANY_TEMPORARY_VARIABLES}, +- #else +- {"TOO_MANY_TEMPORARY_VARIABLES", 3, 109}, +- #endif +- #ifdef CMP_R_ALGORITHM_NOT_SUPPORTED +- {"ALGORITHM_NOT_SUPPORTED", ERR_LIB_CMP, CMP_R_ALGORITHM_NOT_SUPPORTED}, +- #else +- {"ALGORITHM_NOT_SUPPORTED", 58, 139}, +- #endif +- #ifdef CMP_R_BAD_CHECKAFTER_IN_POLLREP +- {"BAD_CHECKAFTER_IN_POLLREP", ERR_LIB_CMP, CMP_R_BAD_CHECKAFTER_IN_POLLREP}, +- #else +- {"BAD_CHECKAFTER_IN_POLLREP", 58, 167}, +- #endif +- #ifdef CMP_R_BAD_REQUEST_ID +- {"BAD_REQUEST_ID", ERR_LIB_CMP, CMP_R_BAD_REQUEST_ID}, +- #else +- {"BAD_REQUEST_ID", 58, 108}, +- #endif +- #ifdef CMP_R_CERTHASH_UNMATCHED +- {"CERTHASH_UNMATCHED", ERR_LIB_CMP, CMP_R_CERTHASH_UNMATCHED}, +- #else +- {"CERTHASH_UNMATCHED", 58, 156}, +- #endif +- #ifdef CMP_R_CERTID_NOT_FOUND +- {"CERTID_NOT_FOUND", ERR_LIB_CMP, CMP_R_CERTID_NOT_FOUND}, +- #else +- {"CERTID_NOT_FOUND", 58, 109}, +- #endif +- #ifdef CMP_R_CERTIFICATE_NOT_ACCEPTED +- {"CERTIFICATE_NOT_ACCEPTED", ERR_LIB_CMP, CMP_R_CERTIFICATE_NOT_ACCEPTED}, +- #else +- {"CERTIFICATE_NOT_ACCEPTED", 58, 169}, +- #endif +- #ifdef CMP_R_CERTIFICATE_NOT_FOUND +- {"CERTIFICATE_NOT_FOUND", ERR_LIB_CMP, CMP_R_CERTIFICATE_NOT_FOUND}, +- #else +- {"CERTIFICATE_NOT_FOUND", 58, 112}, +- #endif +- #ifdef CMP_R_CERTREQMSG_NOT_FOUND +- {"CERTREQMSG_NOT_FOUND", ERR_LIB_CMP, CMP_R_CERTREQMSG_NOT_FOUND}, +- #else +- {"CERTREQMSG_NOT_FOUND", 58, 157}, +- #endif +- #ifdef CMP_R_CERTRESPONSE_NOT_FOUND +- {"CERTRESPONSE_NOT_FOUND", ERR_LIB_CMP, CMP_R_CERTRESPONSE_NOT_FOUND}, +- #else +- {"CERTRESPONSE_NOT_FOUND", 58, 113}, +- #endif +- #ifdef CMP_R_CERT_AND_KEY_DO_NOT_MATCH +- {"CERT_AND_KEY_DO_NOT_MATCH", ERR_LIB_CMP, CMP_R_CERT_AND_KEY_DO_NOT_MATCH}, +- #else +- {"CERT_AND_KEY_DO_NOT_MATCH", 58, 114}, +- #endif +- #ifdef CMP_R_CHECKAFTER_OUT_OF_RANGE +- {"CHECKAFTER_OUT_OF_RANGE", ERR_LIB_CMP, CMP_R_CHECKAFTER_OUT_OF_RANGE}, +- #else +- {"CHECKAFTER_OUT_OF_RANGE", 58, 181}, +- #endif +- #ifdef CMP_R_ENCOUNTERED_KEYUPDATEWARNING +- {"ENCOUNTERED_KEYUPDATEWARNING", ERR_LIB_CMP, CMP_R_ENCOUNTERED_KEYUPDATEWARNING}, +- #else +- {"ENCOUNTERED_KEYUPDATEWARNING", 58, 176}, +- #endif +- #ifdef CMP_R_ENCOUNTERED_WAITING +- {"ENCOUNTERED_WAITING", ERR_LIB_CMP, CMP_R_ENCOUNTERED_WAITING}, +- #else +- {"ENCOUNTERED_WAITING", 58, 162}, +- #endif +- #ifdef CMP_R_ERROR_CALCULATING_PROTECTION +- {"ERROR_CALCULATING_PROTECTION", ERR_LIB_CMP, CMP_R_ERROR_CALCULATING_PROTECTION}, +- #else +- {"ERROR_CALCULATING_PROTECTION", 58, 115}, +- #endif +- #ifdef CMP_R_ERROR_CREATING_CERTCONF +- {"ERROR_CREATING_CERTCONF", ERR_LIB_CMP, CMP_R_ERROR_CREATING_CERTCONF}, +- #else +- {"ERROR_CREATING_CERTCONF", 58, 116}, +- #endif +- #ifdef CMP_R_ERROR_CREATING_CERTREP +- {"ERROR_CREATING_CERTREP", ERR_LIB_CMP, CMP_R_ERROR_CREATING_CERTREP}, +- #else +- {"ERROR_CREATING_CERTREP", 58, 117}, +- #endif +- #ifdef CMP_R_ERROR_CREATING_CERTREQ +- {"ERROR_CREATING_CERTREQ", ERR_LIB_CMP, CMP_R_ERROR_CREATING_CERTREQ}, +- #else +- {"ERROR_CREATING_CERTREQ", 58, 163}, +- #endif +- #ifdef CMP_R_ERROR_CREATING_ERROR +- {"ERROR_CREATING_ERROR", ERR_LIB_CMP, CMP_R_ERROR_CREATING_ERROR}, +- #else +- {"ERROR_CREATING_ERROR", 58, 118}, +- #endif +- #ifdef CMP_R_ERROR_CREATING_GENM +- {"ERROR_CREATING_GENM", ERR_LIB_CMP, CMP_R_ERROR_CREATING_GENM}, +- #else +- {"ERROR_CREATING_GENM", 58, 119}, +- #endif +- #ifdef CMP_R_ERROR_CREATING_GENP +- {"ERROR_CREATING_GENP", ERR_LIB_CMP, CMP_R_ERROR_CREATING_GENP}, +- #else +- {"ERROR_CREATING_GENP", 58, 120}, +- #endif +- #ifdef CMP_R_ERROR_CREATING_PKICONF +- {"ERROR_CREATING_PKICONF", ERR_LIB_CMP, CMP_R_ERROR_CREATING_PKICONF}, +- #else +- {"ERROR_CREATING_PKICONF", 58, 122}, +- #endif +- #ifdef CMP_R_ERROR_CREATING_POLLREP +- {"ERROR_CREATING_POLLREP", ERR_LIB_CMP, CMP_R_ERROR_CREATING_POLLREP}, +- #else +- {"ERROR_CREATING_POLLREP", 58, 123}, +- #endif +- #ifdef CMP_R_ERROR_CREATING_POLLREQ +- {"ERROR_CREATING_POLLREQ", ERR_LIB_CMP, CMP_R_ERROR_CREATING_POLLREQ}, +- #else +- {"ERROR_CREATING_POLLREQ", 58, 124}, +- #endif +- #ifdef CMP_R_ERROR_CREATING_RP +- {"ERROR_CREATING_RP", ERR_LIB_CMP, CMP_R_ERROR_CREATING_RP}, +- #else +- {"ERROR_CREATING_RP", 58, 125}, +- #endif +- #ifdef CMP_R_ERROR_CREATING_RR +- {"ERROR_CREATING_RR", ERR_LIB_CMP, CMP_R_ERROR_CREATING_RR}, +- #else +- {"ERROR_CREATING_RR", 58, 126}, +- #endif +- #ifdef CMP_R_ERROR_PARSING_PKISTATUS +- {"ERROR_PARSING_PKISTATUS", ERR_LIB_CMP, CMP_R_ERROR_PARSING_PKISTATUS}, +- #else +- {"ERROR_PARSING_PKISTATUS", 58, 107}, +- #endif +- #ifdef CMP_R_ERROR_PROCESSING_MESSAGE +- {"ERROR_PROCESSING_MESSAGE", ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE}, +- #else +- {"ERROR_PROCESSING_MESSAGE", 58, 158}, +- #endif +- #ifdef CMP_R_ERROR_PROTECTING_MESSAGE +- {"ERROR_PROTECTING_MESSAGE", ERR_LIB_CMP, CMP_R_ERROR_PROTECTING_MESSAGE}, +- #else +- {"ERROR_PROTECTING_MESSAGE", 58, 127}, +- #endif +- #ifdef CMP_R_ERROR_SETTING_CERTHASH +- {"ERROR_SETTING_CERTHASH", ERR_LIB_CMP, CMP_R_ERROR_SETTING_CERTHASH}, +- #else +- {"ERROR_SETTING_CERTHASH", 58, 128}, +- #endif +- #ifdef CMP_R_ERROR_UNEXPECTED_CERTCONF +- {"ERROR_UNEXPECTED_CERTCONF", ERR_LIB_CMP, CMP_R_ERROR_UNEXPECTED_CERTCONF}, +- #else +- {"ERROR_UNEXPECTED_CERTCONF", 58, 160}, +- #endif +- #ifdef CMP_R_ERROR_VALIDATING_PROTECTION +- {"ERROR_VALIDATING_PROTECTION", ERR_LIB_CMP, CMP_R_ERROR_VALIDATING_PROTECTION}, +- #else +- {"ERROR_VALIDATING_PROTECTION", 58, 140}, +- #endif +- #ifdef CMP_R_ERROR_VALIDATING_SIGNATURE +- {"ERROR_VALIDATING_SIGNATURE", ERR_LIB_CMP, CMP_R_ERROR_VALIDATING_SIGNATURE}, +- #else +- {"ERROR_VALIDATING_SIGNATURE", 58, 171}, +- #endif +- #ifdef CMP_R_FAILED_BUILDING_OWN_CHAIN +- {"FAILED_BUILDING_OWN_CHAIN", ERR_LIB_CMP, CMP_R_FAILED_BUILDING_OWN_CHAIN}, +- #else +- {"FAILED_BUILDING_OWN_CHAIN", 58, 164}, +- #endif +- #ifdef CMP_R_FAILED_EXTRACTING_PUBKEY +- {"FAILED_EXTRACTING_PUBKEY", ERR_LIB_CMP, CMP_R_FAILED_EXTRACTING_PUBKEY}, +- #else +- {"FAILED_EXTRACTING_PUBKEY", 58, 141}, +- #endif +- #ifdef CMP_R_FAILURE_OBTAINING_RANDOM +- {"FAILURE_OBTAINING_RANDOM", ERR_LIB_CMP, CMP_R_FAILURE_OBTAINING_RANDOM}, +- #else +- {"FAILURE_OBTAINING_RANDOM", 58, 110}, +- #endif +- #ifdef CMP_R_FAIL_INFO_OUT_OF_RANGE +- {"FAIL_INFO_OUT_OF_RANGE", ERR_LIB_CMP, CMP_R_FAIL_INFO_OUT_OF_RANGE}, +- #else +- {"FAIL_INFO_OUT_OF_RANGE", 58, 129}, +- #endif +- #ifdef CMP_R_INVALID_ARGS +- {"INVALID_ARGS", ERR_LIB_CMP, CMP_R_INVALID_ARGS}, +- #else +- {"INVALID_ARGS", 58, 100}, +- #endif +- #ifdef CMP_R_INVALID_OPTION +- {"INVALID_OPTION", ERR_LIB_CMP, CMP_R_INVALID_OPTION}, +- #else +- {"INVALID_OPTION", 58, 174}, +- #endif +- #ifdef CMP_R_MISSING_CERTID +- {"MISSING_CERTID", ERR_LIB_CMP, CMP_R_MISSING_CERTID}, +- #else +- {"MISSING_CERTID", 58, 165}, +- #endif +- #ifdef CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION +- {"MISSING_KEY_INPUT_FOR_CREATING_PROTECTION", ERR_LIB_CMP, CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION}, +- #else +- {"MISSING_KEY_INPUT_FOR_CREATING_PROTECTION", 58, 130}, +- #endif +- #ifdef CMP_R_MISSING_KEY_USAGE_DIGITALSIGNATURE +- {"MISSING_KEY_USAGE_DIGITALSIGNATURE", ERR_LIB_CMP, CMP_R_MISSING_KEY_USAGE_DIGITALSIGNATURE}, +- #else +- {"MISSING_KEY_USAGE_DIGITALSIGNATURE", 58, 142}, +- #endif +- #ifdef CMP_R_MISSING_P10CSR +- {"MISSING_P10CSR", ERR_LIB_CMP, CMP_R_MISSING_P10CSR}, +- #else +- {"MISSING_P10CSR", 58, 121}, +- #endif +- #ifdef CMP_R_MISSING_PBM_SECRET +- {"MISSING_PBM_SECRET", ERR_LIB_CMP, CMP_R_MISSING_PBM_SECRET}, +- #else +- {"MISSING_PBM_SECRET", 58, 166}, +- #endif +- #ifdef CMP_R_MISSING_PRIVATE_KEY +- {"MISSING_PRIVATE_KEY", ERR_LIB_CMP, CMP_R_MISSING_PRIVATE_KEY}, +- #else +- {"MISSING_PRIVATE_KEY", 58, 131}, +- #endif +- #ifdef CMP_R_MISSING_PRIVATE_KEY_FOR_POPO +- {"MISSING_PRIVATE_KEY_FOR_POPO", ERR_LIB_CMP, CMP_R_MISSING_PRIVATE_KEY_FOR_POPO}, +- #else +- {"MISSING_PRIVATE_KEY_FOR_POPO", 58, 190}, +- #endif +- #ifdef CMP_R_MISSING_PROTECTION +- {"MISSING_PROTECTION", ERR_LIB_CMP, CMP_R_MISSING_PROTECTION}, +- #else +- {"MISSING_PROTECTION", 58, 143}, +- #endif +- #ifdef CMP_R_MISSING_PUBLIC_KEY +- {"MISSING_PUBLIC_KEY", ERR_LIB_CMP, CMP_R_MISSING_PUBLIC_KEY}, +- #else +- {"MISSING_PUBLIC_KEY", 58, 183}, +- #endif +- #ifdef CMP_R_MISSING_REFERENCE_CERT +- {"MISSING_REFERENCE_CERT", ERR_LIB_CMP, CMP_R_MISSING_REFERENCE_CERT}, +- #else +- {"MISSING_REFERENCE_CERT", 58, 168}, +- #endif +- #ifdef CMP_R_MISSING_SECRET +- {"MISSING_SECRET", ERR_LIB_CMP, CMP_R_MISSING_SECRET}, +- #else +- {"MISSING_SECRET", 58, 178}, +- #endif +- #ifdef CMP_R_MISSING_SENDER_IDENTIFICATION +- {"MISSING_SENDER_IDENTIFICATION", ERR_LIB_CMP, CMP_R_MISSING_SENDER_IDENTIFICATION}, +- #else +- {"MISSING_SENDER_IDENTIFICATION", 58, 111}, +- #endif +- #ifdef CMP_R_MISSING_TRUST_ANCHOR +- {"MISSING_TRUST_ANCHOR", ERR_LIB_CMP, CMP_R_MISSING_TRUST_ANCHOR}, +- #else +- {"MISSING_TRUST_ANCHOR", 58, 179}, +- #endif +- #ifdef CMP_R_MISSING_TRUST_STORE +- {"MISSING_TRUST_STORE", ERR_LIB_CMP, CMP_R_MISSING_TRUST_STORE}, +- #else +- {"MISSING_TRUST_STORE", 58, 144}, +- #endif +- #ifdef CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED +- {"MULTIPLE_REQUESTS_NOT_SUPPORTED", ERR_LIB_CMP, CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED}, +- #else +- {"MULTIPLE_REQUESTS_NOT_SUPPORTED", 58, 161}, +- #endif +- #ifdef CMP_R_MULTIPLE_RESPONSES_NOT_SUPPORTED +- {"MULTIPLE_RESPONSES_NOT_SUPPORTED", ERR_LIB_CMP, CMP_R_MULTIPLE_RESPONSES_NOT_SUPPORTED}, +- #else +- {"MULTIPLE_RESPONSES_NOT_SUPPORTED", 58, 170}, +- #endif +- #ifdef CMP_R_MULTIPLE_SAN_SOURCES +- {"MULTIPLE_SAN_SOURCES", ERR_LIB_CMP, CMP_R_MULTIPLE_SAN_SOURCES}, +- #else +- {"MULTIPLE_SAN_SOURCES", 58, 102}, +- #endif +- #ifdef CMP_R_NO_STDIO +- {"NO_STDIO", ERR_LIB_CMP, CMP_R_NO_STDIO}, +- #else +- {"NO_STDIO", 58, 194}, +- #endif +- #ifdef CMP_R_NO_SUITABLE_SENDER_CERT +- {"NO_SUITABLE_SENDER_CERT", ERR_LIB_CMP, CMP_R_NO_SUITABLE_SENDER_CERT}, +- #else +- {"NO_SUITABLE_SENDER_CERT", 58, 145}, +- #endif +- #ifdef CMP_R_NULL_ARGUMENT +- {"NULL_ARGUMENT", ERR_LIB_CMP, CMP_R_NULL_ARGUMENT}, +- #else +- {"NULL_ARGUMENT", 58, 103}, +- #endif +- #ifdef CMP_R_PKIBODY_ERROR +- {"PKIBODY_ERROR", ERR_LIB_CMP, CMP_R_PKIBODY_ERROR}, +- #else +- {"PKIBODY_ERROR", 58, 146}, +- #endif +- #ifdef CMP_R_PKISTATUSINFO_NOT_FOUND +- {"PKISTATUSINFO_NOT_FOUND", ERR_LIB_CMP, CMP_R_PKISTATUSINFO_NOT_FOUND}, +- #else +- {"PKISTATUSINFO_NOT_FOUND", 58, 132}, +- #endif +- #ifdef CMP_R_POLLING_FAILED +- {"POLLING_FAILED", ERR_LIB_CMP, CMP_R_POLLING_FAILED}, +- #else +- {"POLLING_FAILED", 58, 172}, +- #endif +- #ifdef CMP_R_POTENTIALLY_INVALID_CERTIFICATE +- {"POTENTIALLY_INVALID_CERTIFICATE", ERR_LIB_CMP, CMP_R_POTENTIALLY_INVALID_CERTIFICATE}, +- #else +- {"POTENTIALLY_INVALID_CERTIFICATE", 58, 147}, +- #endif +- #ifdef CMP_R_RECEIVED_ERROR +- {"RECEIVED_ERROR", ERR_LIB_CMP, CMP_R_RECEIVED_ERROR}, +- #else +- {"RECEIVED_ERROR", 58, 180}, +- #endif +- #ifdef CMP_R_RECIPNONCE_UNMATCHED +- {"RECIPNONCE_UNMATCHED", ERR_LIB_CMP, CMP_R_RECIPNONCE_UNMATCHED}, +- #else +- {"RECIPNONCE_UNMATCHED", 58, 148}, +- #endif +- #ifdef CMP_R_REQUEST_NOT_ACCEPTED +- {"REQUEST_NOT_ACCEPTED", ERR_LIB_CMP, CMP_R_REQUEST_NOT_ACCEPTED}, +- #else +- {"REQUEST_NOT_ACCEPTED", 58, 149}, +- #endif +- #ifdef CMP_R_REQUEST_REJECTED_BY_SERVER +- {"REQUEST_REJECTED_BY_SERVER", ERR_LIB_CMP, CMP_R_REQUEST_REJECTED_BY_SERVER}, +- #else +- {"REQUEST_REJECTED_BY_SERVER", 58, 182}, +- #endif +- #ifdef CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED +- {"SENDER_GENERALNAME_TYPE_NOT_SUPPORTED", ERR_LIB_CMP, CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED}, +- #else +- {"SENDER_GENERALNAME_TYPE_NOT_SUPPORTED", 58, 150}, +- #endif +- #ifdef CMP_R_SRVCERT_DOES_NOT_VALIDATE_MSG +- {"SRVCERT_DOES_NOT_VALIDATE_MSG", ERR_LIB_CMP, CMP_R_SRVCERT_DOES_NOT_VALIDATE_MSG}, +- #else +- {"SRVCERT_DOES_NOT_VALIDATE_MSG", 58, 151}, +- #endif +- #ifdef CMP_R_TOTAL_TIMEOUT +- {"TOTAL_TIMEOUT", ERR_LIB_CMP, CMP_R_TOTAL_TIMEOUT}, +- #else +- {"TOTAL_TIMEOUT", 58, 184}, +- #endif +- #ifdef CMP_R_TRANSACTIONID_UNMATCHED +- {"TRANSACTIONID_UNMATCHED", ERR_LIB_CMP, CMP_R_TRANSACTIONID_UNMATCHED}, +- #else +- {"TRANSACTIONID_UNMATCHED", 58, 152}, +- #endif +- #ifdef CMP_R_TRANSFER_ERROR +- {"TRANSFER_ERROR", ERR_LIB_CMP, CMP_R_TRANSFER_ERROR}, +- #else +- {"TRANSFER_ERROR", 58, 159}, +- #endif +- #ifdef CMP_R_UNEXPECTED_PKIBODY +- {"UNEXPECTED_PKIBODY", ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY}, +- #else +- {"UNEXPECTED_PKIBODY", 58, 133}, +- #endif +- #ifdef CMP_R_UNEXPECTED_PKISTATUS +- {"UNEXPECTED_PKISTATUS", ERR_LIB_CMP, CMP_R_UNEXPECTED_PKISTATUS}, +- #else +- {"UNEXPECTED_PKISTATUS", 58, 185}, +- #endif +- #ifdef CMP_R_UNEXPECTED_PVNO +- {"UNEXPECTED_PVNO", ERR_LIB_CMP, CMP_R_UNEXPECTED_PVNO}, +- #else +- {"UNEXPECTED_PVNO", 58, 153}, +- #endif +- #ifdef CMP_R_UNKNOWN_ALGORITHM_ID +- {"UNKNOWN_ALGORITHM_ID", ERR_LIB_CMP, CMP_R_UNKNOWN_ALGORITHM_ID}, +- #else +- {"UNKNOWN_ALGORITHM_ID", 58, 134}, +- #endif +- #ifdef CMP_R_UNKNOWN_CERT_TYPE +- {"UNKNOWN_CERT_TYPE", ERR_LIB_CMP, CMP_R_UNKNOWN_CERT_TYPE}, +- #else +- {"UNKNOWN_CERT_TYPE", 58, 135}, +- #endif +- #ifdef CMP_R_UNKNOWN_PKISTATUS +- {"UNKNOWN_PKISTATUS", ERR_LIB_CMP, CMP_R_UNKNOWN_PKISTATUS}, +- #else +- {"UNKNOWN_PKISTATUS", 58, 186}, +- #endif +- #ifdef CMP_R_UNSUPPORTED_ALGORITHM +- {"UNSUPPORTED_ALGORITHM", ERR_LIB_CMP, CMP_R_UNSUPPORTED_ALGORITHM}, +- #else +- {"UNSUPPORTED_ALGORITHM", 58, 136}, +- #endif +- #ifdef CMP_R_UNSUPPORTED_KEY_TYPE +- {"UNSUPPORTED_KEY_TYPE", ERR_LIB_CMP, CMP_R_UNSUPPORTED_KEY_TYPE}, +- #else +- {"UNSUPPORTED_KEY_TYPE", 58, 137}, +- #endif +- #ifdef CMP_R_UNSUPPORTED_PROTECTION_ALG_DHBASEDMAC +- {"UNSUPPORTED_PROTECTION_ALG_DHBASEDMAC", ERR_LIB_CMP, CMP_R_UNSUPPORTED_PROTECTION_ALG_DHBASEDMAC}, +- #else +- {"UNSUPPORTED_PROTECTION_ALG_DHBASEDMAC", 58, 154}, +- #endif +- #ifdef CMP_R_VALUE_TOO_LARGE +- {"VALUE_TOO_LARGE", ERR_LIB_CMP, CMP_R_VALUE_TOO_LARGE}, +- #else +- {"VALUE_TOO_LARGE", 58, 175}, +- #endif +- #ifdef CMP_R_VALUE_TOO_SMALL +- {"VALUE_TOO_SMALL", ERR_LIB_CMP, CMP_R_VALUE_TOO_SMALL}, +- #else +- {"VALUE_TOO_SMALL", 58, 177}, +- #endif +- #ifdef CMP_R_WRONG_ALGORITHM_OID +- {"WRONG_ALGORITHM_OID", ERR_LIB_CMP, CMP_R_WRONG_ALGORITHM_OID}, +- #else +- {"WRONG_ALGORITHM_OID", 58, 138}, +- #endif +- #ifdef CMP_R_WRONG_CERTID +- {"WRONG_CERTID", ERR_LIB_CMP, CMP_R_WRONG_CERTID}, +- #else +- {"WRONG_CERTID", 58, 189}, +- #endif +- #ifdef CMP_R_WRONG_CERTID_IN_RP +- {"WRONG_CERTID_IN_RP", ERR_LIB_CMP, CMP_R_WRONG_CERTID_IN_RP}, +- #else +- {"WRONG_CERTID_IN_RP", 58, 187}, +- #endif +- #ifdef CMP_R_WRONG_PBM_VALUE +- {"WRONG_PBM_VALUE", ERR_LIB_CMP, CMP_R_WRONG_PBM_VALUE}, +- #else +- {"WRONG_PBM_VALUE", 58, 155}, +- #endif +- #ifdef CMP_R_WRONG_RP_COMPONENT_COUNT +- {"WRONG_RP_COMPONENT_COUNT", ERR_LIB_CMP, CMP_R_WRONG_RP_COMPONENT_COUNT}, +- #else +- {"WRONG_RP_COMPONENT_COUNT", 58, 188}, +- #endif +- #ifdef CMP_R_WRONG_SERIAL_IN_RP +- {"WRONG_SERIAL_IN_RP", ERR_LIB_CMP, CMP_R_WRONG_SERIAL_IN_RP}, +- #else +- {"WRONG_SERIAL_IN_RP", 58, 173}, +- #endif +- #ifdef CMS_R_ADD_SIGNER_ERROR +- {"ADD_SIGNER_ERROR", ERR_LIB_CMS, CMS_R_ADD_SIGNER_ERROR}, +- #else +- {"ADD_SIGNER_ERROR", 46, 99}, +- #endif +- #ifdef CMS_R_ATTRIBUTE_ERROR +- {"ATTRIBUTE_ERROR", ERR_LIB_CMS, CMS_R_ATTRIBUTE_ERROR}, +- #else +- {"ATTRIBUTE_ERROR", 46, 161}, +- #endif +- #ifdef CMS_R_CERTIFICATE_ALREADY_PRESENT +- {"CERTIFICATE_ALREADY_PRESENT", ERR_LIB_CMS, CMS_R_CERTIFICATE_ALREADY_PRESENT}, +- #else +- {"CERTIFICATE_ALREADY_PRESENT", 46, 175}, +- #endif +- #ifdef CMS_R_CERTIFICATE_HAS_NO_KEYID +- {"CERTIFICATE_HAS_NO_KEYID", ERR_LIB_CMS, CMS_R_CERTIFICATE_HAS_NO_KEYID}, +- #else +- {"CERTIFICATE_HAS_NO_KEYID", 46, 160}, +- #endif +- #ifdef CMS_R_CERTIFICATE_VERIFY_ERROR +- {"CERTIFICATE_VERIFY_ERROR", ERR_LIB_CMS, CMS_R_CERTIFICATE_VERIFY_ERROR}, +- #else +- {"CERTIFICATE_VERIFY_ERROR", 46, 100}, +- #endif +- #ifdef CMS_R_CIPHER_AEAD_SET_TAG_ERROR +- {"CIPHER_AEAD_SET_TAG_ERROR", ERR_LIB_CMS, CMS_R_CIPHER_AEAD_SET_TAG_ERROR}, +- #else +- {"CIPHER_AEAD_SET_TAG_ERROR", 46, 184}, +- #endif +- #ifdef CMS_R_CIPHER_GET_TAG +- {"CIPHER_GET_TAG", ERR_LIB_CMS, CMS_R_CIPHER_GET_TAG}, +- #else +- {"CIPHER_GET_TAG", 46, 185}, +- #endif +- #ifdef CMS_R_CIPHER_INITIALISATION_ERROR +- {"CIPHER_INITIALISATION_ERROR", ERR_LIB_CMS, CMS_R_CIPHER_INITIALISATION_ERROR}, +- #else +- {"CIPHER_INITIALISATION_ERROR", 46, 101}, +- #endif +- #ifdef CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR +- {"CIPHER_PARAMETER_INITIALISATION_ERROR", ERR_LIB_CMS, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR}, +- #else +- {"CIPHER_PARAMETER_INITIALISATION_ERROR", 46, 102}, +- #endif +- #ifdef CMS_R_CMS_DATAFINAL_ERROR +- {"CMS_DATAFINAL_ERROR", ERR_LIB_CMS, CMS_R_CMS_DATAFINAL_ERROR}, +- #else +- {"CMS_DATAFINAL_ERROR", 46, 103}, +- #endif +- #ifdef CMS_R_CMS_LIB +- {"CMS_LIB", ERR_LIB_CMS, CMS_R_CMS_LIB}, +- #else +- {"CMS_LIB", 46, 104}, +- #endif +- #ifdef CMS_R_CONTENTIDENTIFIER_MISMATCH +- {"CONTENTIDENTIFIER_MISMATCH", ERR_LIB_CMS, CMS_R_CONTENTIDENTIFIER_MISMATCH}, +- #else +- {"CONTENTIDENTIFIER_MISMATCH", 46, 170}, +- #endif +- #ifdef CMS_R_CONTENT_NOT_FOUND +- {"CONTENT_NOT_FOUND", ERR_LIB_CMS, CMS_R_CONTENT_NOT_FOUND}, +- #else +- {"CONTENT_NOT_FOUND", 46, 105}, +- #endif +- #ifdef CMS_R_CONTENT_TYPE_MISMATCH +- {"CONTENT_TYPE_MISMATCH", ERR_LIB_CMS, CMS_R_CONTENT_TYPE_MISMATCH}, +- #else +- {"CONTENT_TYPE_MISMATCH", 46, 171}, +- #endif +- #ifdef CMS_R_CONTENT_TYPE_NOT_COMPRESSED_DATA +- {"CONTENT_TYPE_NOT_COMPRESSED_DATA", ERR_LIB_CMS, CMS_R_CONTENT_TYPE_NOT_COMPRESSED_DATA}, +- #else +- {"CONTENT_TYPE_NOT_COMPRESSED_DATA", 46, 106}, +- #endif +- #ifdef CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA +- {"CONTENT_TYPE_NOT_ENVELOPED_DATA", ERR_LIB_CMS, CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA}, +- #else +- {"CONTENT_TYPE_NOT_ENVELOPED_DATA", 46, 107}, +- #endif +- #ifdef CMS_R_CONTENT_TYPE_NOT_SIGNED_DATA +- {"CONTENT_TYPE_NOT_SIGNED_DATA", ERR_LIB_CMS, CMS_R_CONTENT_TYPE_NOT_SIGNED_DATA}, +- #else +- {"CONTENT_TYPE_NOT_SIGNED_DATA", 46, 108}, +- #endif +- #ifdef CMS_R_CONTENT_VERIFY_ERROR +- {"CONTENT_VERIFY_ERROR", ERR_LIB_CMS, CMS_R_CONTENT_VERIFY_ERROR}, +- #else +- {"CONTENT_VERIFY_ERROR", 46, 109}, +- #endif +- #ifdef CMS_R_CTRL_ERROR +- {"CTRL_ERROR", ERR_LIB_CMS, CMS_R_CTRL_ERROR}, +- #else +- {"CTRL_ERROR", 46, 110}, +- #endif +- #ifdef CMS_R_CTRL_FAILURE +- {"CTRL_FAILURE", ERR_LIB_CMS, CMS_R_CTRL_FAILURE}, +- #else +- {"CTRL_FAILURE", 46, 111}, +- #endif +- #ifdef CMS_R_DECODE_ERROR +- {"DECODE_ERROR", ERR_LIB_CMS, CMS_R_DECODE_ERROR}, +- #else +- {"DECODE_ERROR", 46, 187}, +- #endif +- #ifdef CMS_R_DECRYPT_ERROR +- {"DECRYPT_ERROR", ERR_LIB_CMS, CMS_R_DECRYPT_ERROR}, +- #else +- {"DECRYPT_ERROR", 46, 112}, +- #endif +- #ifdef CMS_R_ERROR_GETTING_PUBLIC_KEY +- {"ERROR_GETTING_PUBLIC_KEY", ERR_LIB_CMS, CMS_R_ERROR_GETTING_PUBLIC_KEY}, +- #else +- {"ERROR_GETTING_PUBLIC_KEY", 46, 113}, +- #endif +- #ifdef CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE +- {"ERROR_READING_MESSAGEDIGEST_ATTRIBUTE", ERR_LIB_CMS, CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE}, +- #else +- {"ERROR_READING_MESSAGEDIGEST_ATTRIBUTE", 46, 114}, +- #endif +- #ifdef CMS_R_ERROR_SETTING_KEY +- {"ERROR_SETTING_KEY", ERR_LIB_CMS, CMS_R_ERROR_SETTING_KEY}, +- #else +- {"ERROR_SETTING_KEY", 46, 115}, +- #endif +- #ifdef CMS_R_ERROR_SETTING_RECIPIENTINFO +- {"ERROR_SETTING_RECIPIENTINFO", ERR_LIB_CMS, CMS_R_ERROR_SETTING_RECIPIENTINFO}, +- #else +- {"ERROR_SETTING_RECIPIENTINFO", 46, 116}, +- #endif +- #ifdef CMS_R_ESS_SIGNING_CERTID_MISMATCH_ERROR +- {"ESS_SIGNING_CERTID_MISMATCH_ERROR", ERR_LIB_CMS, CMS_R_ESS_SIGNING_CERTID_MISMATCH_ERROR}, +- #else +- {"ESS_SIGNING_CERTID_MISMATCH_ERROR", 46, 183}, +- #endif +- #ifdef CMS_R_INVALID_ENCRYPTED_KEY_LENGTH +- {"INVALID_ENCRYPTED_KEY_LENGTH", ERR_LIB_CMS, CMS_R_INVALID_ENCRYPTED_KEY_LENGTH}, +- #else +- {"INVALID_ENCRYPTED_KEY_LENGTH", 46, 117}, +- #endif +- #ifdef CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER +- {"INVALID_KEY_ENCRYPTION_PARAMETER", ERR_LIB_CMS, CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER}, +- #else +- {"INVALID_KEY_ENCRYPTION_PARAMETER", 46, 176}, +- #endif +- #ifdef CMS_R_INVALID_KEY_LENGTH +- {"INVALID_KEY_LENGTH", ERR_LIB_CMS, CMS_R_INVALID_KEY_LENGTH}, +- #else +- {"INVALID_KEY_LENGTH", 46, 118}, +- #endif +- #ifdef CMS_R_INVALID_LABEL +- {"INVALID_LABEL", ERR_LIB_CMS, CMS_R_INVALID_LABEL}, +- #else +- {"INVALID_LABEL", 46, 190}, +- #endif +- #ifdef CMS_R_INVALID_OAEP_PARAMETERS +- {"INVALID_OAEP_PARAMETERS", ERR_LIB_CMS, CMS_R_INVALID_OAEP_PARAMETERS}, +- #else +- {"INVALID_OAEP_PARAMETERS", 46, 191}, +- #endif +- #ifdef CMS_R_KDF_PARAMETER_ERROR +- {"KDF_PARAMETER_ERROR", ERR_LIB_CMS, CMS_R_KDF_PARAMETER_ERROR}, +- #else +- {"KDF_PARAMETER_ERROR", 46, 186}, +- #endif +- #ifdef CMS_R_MD_BIO_INIT_ERROR +- {"MD_BIO_INIT_ERROR", ERR_LIB_CMS, CMS_R_MD_BIO_INIT_ERROR}, +- #else +- {"MD_BIO_INIT_ERROR", 46, 119}, +- #endif +- #ifdef CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH +- {"MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH", ERR_LIB_CMS, CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH}, +- #else +- {"MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH", 46, 120}, +- #endif +- #ifdef CMS_R_MESSAGEDIGEST_WRONG_LENGTH +- {"MESSAGEDIGEST_WRONG_LENGTH", ERR_LIB_CMS, CMS_R_MESSAGEDIGEST_WRONG_LENGTH}, +- #else +- {"MESSAGEDIGEST_WRONG_LENGTH", 46, 121}, +- #endif +- #ifdef CMS_R_MSGSIGDIGEST_ERROR +- {"MSGSIGDIGEST_ERROR", ERR_LIB_CMS, CMS_R_MSGSIGDIGEST_ERROR}, +- #else +- {"MSGSIGDIGEST_ERROR", 46, 172}, +- #endif +- #ifdef CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE +- {"MSGSIGDIGEST_VERIFICATION_FAILURE", ERR_LIB_CMS, CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE}, +- #else +- {"MSGSIGDIGEST_VERIFICATION_FAILURE", 46, 162}, +- #endif +- #ifdef CMS_R_MSGSIGDIGEST_WRONG_LENGTH +- {"MSGSIGDIGEST_WRONG_LENGTH", ERR_LIB_CMS, CMS_R_MSGSIGDIGEST_WRONG_LENGTH}, +- #else +- {"MSGSIGDIGEST_WRONG_LENGTH", 46, 163}, +- #endif +- #ifdef CMS_R_NEED_ONE_SIGNER +- {"NEED_ONE_SIGNER", ERR_LIB_CMS, CMS_R_NEED_ONE_SIGNER}, +- #else +- {"NEED_ONE_SIGNER", 46, 164}, +- #endif +- #ifdef CMS_R_NOT_A_SIGNED_RECEIPT +- {"NOT_A_SIGNED_RECEIPT", ERR_LIB_CMS, CMS_R_NOT_A_SIGNED_RECEIPT}, +- #else +- {"NOT_A_SIGNED_RECEIPT", 46, 165}, +- #endif +- #ifdef CMS_R_NOT_ENCRYPTED_DATA +- {"NOT_ENCRYPTED_DATA", ERR_LIB_CMS, CMS_R_NOT_ENCRYPTED_DATA}, +- #else +- {"NOT_ENCRYPTED_DATA", 46, 122}, +- #endif +- #ifdef CMS_R_NOT_KEK +- {"NOT_KEK", ERR_LIB_CMS, CMS_R_NOT_KEK}, +- #else +- {"NOT_KEK", 46, 123}, +- #endif +- #ifdef CMS_R_NOT_KEY_AGREEMENT +- {"NOT_KEY_AGREEMENT", ERR_LIB_CMS, CMS_R_NOT_KEY_AGREEMENT}, +- #else +- {"NOT_KEY_AGREEMENT", 46, 181}, +- #endif +- #ifdef CMS_R_NOT_KEY_TRANSPORT +- {"NOT_KEY_TRANSPORT", ERR_LIB_CMS, CMS_R_NOT_KEY_TRANSPORT}, +- #else +- {"NOT_KEY_TRANSPORT", 46, 124}, +- #endif +- #ifdef CMS_R_NOT_PWRI +- {"NOT_PWRI", ERR_LIB_CMS, CMS_R_NOT_PWRI}, +- #else +- {"NOT_PWRI", 46, 177}, +- #endif +- #ifdef CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE +- {"NOT_SUPPORTED_FOR_THIS_KEY_TYPE", ERR_LIB_CMS, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE}, +- #else +- {"NOT_SUPPORTED_FOR_THIS_KEY_TYPE", 46, 125}, +- #endif +- #ifdef CMS_R_NO_CIPHER +- {"NO_CIPHER", ERR_LIB_CMS, CMS_R_NO_CIPHER}, +- #else +- {"NO_CIPHER", 46, 126}, +- #endif +- #ifdef CMS_R_NO_CONTENT +- {"NO_CONTENT", ERR_LIB_CMS, CMS_R_NO_CONTENT}, +- #else +- {"NO_CONTENT", 46, 127}, +- #endif +- #ifdef CMS_R_NO_CONTENT_TYPE +- {"NO_CONTENT_TYPE", ERR_LIB_CMS, CMS_R_NO_CONTENT_TYPE}, +- #else +- {"NO_CONTENT_TYPE", 46, 173}, +- #endif +- #ifdef CMS_R_NO_DEFAULT_DIGEST +- {"NO_DEFAULT_DIGEST", ERR_LIB_CMS, CMS_R_NO_DEFAULT_DIGEST}, +- #else +- {"NO_DEFAULT_DIGEST", 46, 128}, +- #endif +- #ifdef CMS_R_NO_DIGEST_SET +- {"NO_DIGEST_SET", ERR_LIB_CMS, CMS_R_NO_DIGEST_SET}, +- #else +- {"NO_DIGEST_SET", 46, 129}, +- #endif +- #ifdef CMS_R_NO_KEY +- {"NO_KEY", ERR_LIB_CMS, CMS_R_NO_KEY}, +- #else +- {"NO_KEY", 46, 130}, +- #endif +- #ifdef CMS_R_NO_KEY_OR_CERT +- {"NO_KEY_OR_CERT", ERR_LIB_CMS, CMS_R_NO_KEY_OR_CERT}, +- #else +- {"NO_KEY_OR_CERT", 46, 174}, +- #endif +- #ifdef CMS_R_NO_MATCHING_DIGEST +- {"NO_MATCHING_DIGEST", ERR_LIB_CMS, CMS_R_NO_MATCHING_DIGEST}, +- #else +- {"NO_MATCHING_DIGEST", 46, 131}, +- #endif +- #ifdef CMS_R_NO_MATCHING_RECIPIENT +- {"NO_MATCHING_RECIPIENT", ERR_LIB_CMS, CMS_R_NO_MATCHING_RECIPIENT}, +- #else +- {"NO_MATCHING_RECIPIENT", 46, 132}, +- #endif +- #ifdef CMS_R_NO_MATCHING_SIGNATURE +- {"NO_MATCHING_SIGNATURE", ERR_LIB_CMS, CMS_R_NO_MATCHING_SIGNATURE}, +- #else +- {"NO_MATCHING_SIGNATURE", 46, 166}, +- #endif +- #ifdef CMS_R_NO_MSGSIGDIGEST +- {"NO_MSGSIGDIGEST", ERR_LIB_CMS, CMS_R_NO_MSGSIGDIGEST}, +- #else +- {"NO_MSGSIGDIGEST", 46, 167}, +- #endif +- #ifdef CMS_R_NO_PASSWORD +- {"NO_PASSWORD", ERR_LIB_CMS, CMS_R_NO_PASSWORD}, +- #else +- {"NO_PASSWORD", 46, 178}, +- #endif +- #ifdef CMS_R_NO_PRIVATE_KEY +- {"NO_PRIVATE_KEY", ERR_LIB_CMS, CMS_R_NO_PRIVATE_KEY}, +- #else +- {"NO_PRIVATE_KEY", 46, 133}, +- #endif +- #ifdef CMS_R_NO_PUBLIC_KEY +- {"NO_PUBLIC_KEY", ERR_LIB_CMS, CMS_R_NO_PUBLIC_KEY}, +- #else +- {"NO_PUBLIC_KEY", 46, 134}, +- #endif +- #ifdef CMS_R_NO_RECEIPT_REQUEST +- {"NO_RECEIPT_REQUEST", ERR_LIB_CMS, CMS_R_NO_RECEIPT_REQUEST}, +- #else +- {"NO_RECEIPT_REQUEST", 46, 168}, +- #endif +- #ifdef CMS_R_NO_SIGNERS +- {"NO_SIGNERS", ERR_LIB_CMS, CMS_R_NO_SIGNERS}, +- #else +- {"NO_SIGNERS", 46, 135}, +- #endif +- #ifdef CMS_R_PEER_KEY_ERROR +- {"PEER_KEY_ERROR", ERR_LIB_CMS, CMS_R_PEER_KEY_ERROR}, +- #else +- {"PEER_KEY_ERROR", 46, 188}, +- #endif +- #ifdef CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE +- {"PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE", ERR_LIB_CMS, CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE}, +- #else +- {"PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE", 46, 136}, +- #endif +- #ifdef CMS_R_RECEIPT_DECODE_ERROR +- {"RECEIPT_DECODE_ERROR", ERR_LIB_CMS, CMS_R_RECEIPT_DECODE_ERROR}, +- #else +- {"RECEIPT_DECODE_ERROR", 46, 169}, +- #endif +- #ifdef CMS_R_RECIPIENT_ERROR +- {"RECIPIENT_ERROR", ERR_LIB_CMS, CMS_R_RECIPIENT_ERROR}, +- #else +- {"RECIPIENT_ERROR", 46, 137}, +- #endif +- #ifdef CMS_R_SHARED_INFO_ERROR +- {"SHARED_INFO_ERROR", ERR_LIB_CMS, CMS_R_SHARED_INFO_ERROR}, +- #else +- {"SHARED_INFO_ERROR", 46, 189}, +- #endif +- #ifdef CMS_R_SIGNER_CERTIFICATE_NOT_FOUND +- {"SIGNER_CERTIFICATE_NOT_FOUND", ERR_LIB_CMS, CMS_R_SIGNER_CERTIFICATE_NOT_FOUND}, +- #else +- {"SIGNER_CERTIFICATE_NOT_FOUND", 46, 138}, +- #endif +- #ifdef CMS_R_SIGNFINAL_ERROR +- {"SIGNFINAL_ERROR", ERR_LIB_CMS, CMS_R_SIGNFINAL_ERROR}, +- #else +- {"SIGNFINAL_ERROR", 46, 139}, +- #endif +- #ifdef CMS_R_SMIME_TEXT_ERROR +- {"SMIME_TEXT_ERROR", ERR_LIB_CMS, CMS_R_SMIME_TEXT_ERROR}, +- #else +- {"SMIME_TEXT_ERROR", 46, 140}, +- #endif +- #ifdef CMS_R_STORE_INIT_ERROR +- {"STORE_INIT_ERROR", ERR_LIB_CMS, CMS_R_STORE_INIT_ERROR}, +- #else +- {"STORE_INIT_ERROR", 46, 141}, +- #endif +- #ifdef CMS_R_TYPE_NOT_COMPRESSED_DATA +- {"TYPE_NOT_COMPRESSED_DATA", ERR_LIB_CMS, CMS_R_TYPE_NOT_COMPRESSED_DATA}, +- #else +- {"TYPE_NOT_COMPRESSED_DATA", 46, 142}, +- #endif +- #ifdef CMS_R_TYPE_NOT_DATA +- {"TYPE_NOT_DATA", ERR_LIB_CMS, CMS_R_TYPE_NOT_DATA}, +- #else +- {"TYPE_NOT_DATA", 46, 143}, +- #endif +- #ifdef CMS_R_TYPE_NOT_DIGESTED_DATA +- {"TYPE_NOT_DIGESTED_DATA", ERR_LIB_CMS, CMS_R_TYPE_NOT_DIGESTED_DATA}, +- #else +- {"TYPE_NOT_DIGESTED_DATA", 46, 144}, +- #endif +- #ifdef CMS_R_TYPE_NOT_ENCRYPTED_DATA +- {"TYPE_NOT_ENCRYPTED_DATA", ERR_LIB_CMS, CMS_R_TYPE_NOT_ENCRYPTED_DATA}, +- #else +- {"TYPE_NOT_ENCRYPTED_DATA", 46, 145}, +- #endif +- #ifdef CMS_R_TYPE_NOT_ENVELOPED_DATA +- {"TYPE_NOT_ENVELOPED_DATA", ERR_LIB_CMS, CMS_R_TYPE_NOT_ENVELOPED_DATA}, +- #else +- {"TYPE_NOT_ENVELOPED_DATA", 46, 146}, +- #endif +- #ifdef CMS_R_UNABLE_TO_FINALIZE_CONTEXT +- {"UNABLE_TO_FINALIZE_CONTEXT", ERR_LIB_CMS, CMS_R_UNABLE_TO_FINALIZE_CONTEXT}, +- #else +- {"UNABLE_TO_FINALIZE_CONTEXT", 46, 147}, +- #endif +- #ifdef CMS_R_UNKNOWN_CIPHER +- {"UNKNOWN_CIPHER", ERR_LIB_CMS, CMS_R_UNKNOWN_CIPHER}, +- #else +- {"UNKNOWN_CIPHER", 46, 148}, +- #endif +- #ifdef CMS_R_UNKNOWN_DIGEST_ALGORITHM +- {"UNKNOWN_DIGEST_ALGORITHM", ERR_LIB_CMS, CMS_R_UNKNOWN_DIGEST_ALGORITHM}, +- #else +- {"UNKNOWN_DIGEST_ALGORITHM", 46, 149}, +- #endif +- #ifdef CMS_R_UNKNOWN_ID +- {"UNKNOWN_ID", ERR_LIB_CMS, CMS_R_UNKNOWN_ID}, +- #else +- {"UNKNOWN_ID", 46, 150}, +- #endif +- #ifdef CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM +- {"UNSUPPORTED_COMPRESSION_ALGORITHM", ERR_LIB_CMS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM}, +- #else +- {"UNSUPPORTED_COMPRESSION_ALGORITHM", 46, 151}, +- #endif +- #ifdef CMS_R_UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM +- {"UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM", ERR_LIB_CMS, CMS_R_UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM}, +- #else +- {"UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM", 46, 194}, +- #endif +- #ifdef CMS_R_UNSUPPORTED_CONTENT_TYPE +- {"UNSUPPORTED_CONTENT_TYPE", ERR_LIB_CMS, CMS_R_UNSUPPORTED_CONTENT_TYPE}, +- #else +- {"UNSUPPORTED_CONTENT_TYPE", 46, 152}, +- #endif +- #ifdef CMS_R_UNSUPPORTED_ENCRYPTION_TYPE +- {"UNSUPPORTED_ENCRYPTION_TYPE", ERR_LIB_CMS, CMS_R_UNSUPPORTED_ENCRYPTION_TYPE}, +- #else +- {"UNSUPPORTED_ENCRYPTION_TYPE", 46, 192}, +- #endif +- #ifdef CMS_R_UNSUPPORTED_KEK_ALGORITHM +- {"UNSUPPORTED_KEK_ALGORITHM", ERR_LIB_CMS, CMS_R_UNSUPPORTED_KEK_ALGORITHM}, +- #else +- {"UNSUPPORTED_KEK_ALGORITHM", 46, 153}, +- #endif +- #ifdef CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM +- {"UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM", ERR_LIB_CMS, CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM}, +- #else +- {"UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM", 46, 179}, +- #endif +- #ifdef CMS_R_UNSUPPORTED_LABEL_SOURCE +- {"UNSUPPORTED_LABEL_SOURCE", ERR_LIB_CMS, CMS_R_UNSUPPORTED_LABEL_SOURCE}, +- #else +- {"UNSUPPORTED_LABEL_SOURCE", 46, 193}, +- #endif +- #ifdef CMS_R_UNSUPPORTED_RECIPIENTINFO_TYPE +- {"UNSUPPORTED_RECIPIENTINFO_TYPE", ERR_LIB_CMS, CMS_R_UNSUPPORTED_RECIPIENTINFO_TYPE}, +- #else +- {"UNSUPPORTED_RECIPIENTINFO_TYPE", 46, 155}, +- #endif +- #ifdef CMS_R_UNSUPPORTED_RECIPIENT_TYPE +- {"UNSUPPORTED_RECIPIENT_TYPE", ERR_LIB_CMS, CMS_R_UNSUPPORTED_RECIPIENT_TYPE}, +- #else +- {"UNSUPPORTED_RECIPIENT_TYPE", 46, 154}, +- #endif +- #ifdef CMS_R_UNSUPPORTED_TYPE +- {"UNSUPPORTED_TYPE", ERR_LIB_CMS, CMS_R_UNSUPPORTED_TYPE}, +- #else +- {"UNSUPPORTED_TYPE", 46, 156}, +- #endif +- #ifdef CMS_R_UNWRAP_ERROR +- {"UNWRAP_ERROR", ERR_LIB_CMS, CMS_R_UNWRAP_ERROR}, +- #else +- {"UNWRAP_ERROR", 46, 157}, +- #endif +- #ifdef CMS_R_UNWRAP_FAILURE +- {"UNWRAP_FAILURE", ERR_LIB_CMS, CMS_R_UNWRAP_FAILURE}, +- #else +- {"UNWRAP_FAILURE", 46, 180}, +- #endif +- #ifdef CMS_R_VERIFICATION_FAILURE +- {"VERIFICATION_FAILURE", ERR_LIB_CMS, CMS_R_VERIFICATION_FAILURE}, +- #else +- {"VERIFICATION_FAILURE", 46, 158}, +- #endif +- #ifdef CMS_R_WRAP_ERROR +- {"WRAP_ERROR", ERR_LIB_CMS, CMS_R_WRAP_ERROR}, +- #else +- {"WRAP_ERROR", 46, 159}, +- #endif +- #ifdef COMP_R_ZLIB_DEFLATE_ERROR +- {"ZLIB_DEFLATE_ERROR", ERR_LIB_COMP, COMP_R_ZLIB_DEFLATE_ERROR}, +- #else +- {"ZLIB_DEFLATE_ERROR", 41, 99}, +- #endif +- #ifdef COMP_R_ZLIB_INFLATE_ERROR +- {"ZLIB_INFLATE_ERROR", ERR_LIB_COMP, COMP_R_ZLIB_INFLATE_ERROR}, +- #else +- {"ZLIB_INFLATE_ERROR", 41, 100}, +- #endif +- #ifdef COMP_R_ZLIB_NOT_SUPPORTED +- {"ZLIB_NOT_SUPPORTED", ERR_LIB_COMP, COMP_R_ZLIB_NOT_SUPPORTED}, +- #else +- {"ZLIB_NOT_SUPPORTED", 41, 101}, +- #endif +- #ifdef CONF_R_ERROR_LOADING_DSO +- {"ERROR_LOADING_DSO", ERR_LIB_CONF, CONF_R_ERROR_LOADING_DSO}, +- #else +- {"ERROR_LOADING_DSO", 14, 110}, +- #endif +- #ifdef CONF_R_INVALID_PRAGMA +- {"INVALID_PRAGMA", ERR_LIB_CONF, CONF_R_INVALID_PRAGMA}, +- #else +- {"INVALID_PRAGMA", 14, 122}, +- #endif +- #ifdef CONF_R_LIST_CANNOT_BE_NULL +- {"LIST_CANNOT_BE_NULL", ERR_LIB_CONF, CONF_R_LIST_CANNOT_BE_NULL}, +- #else +- {"LIST_CANNOT_BE_NULL", 14, 115}, +- #endif +- #ifdef CONF_R_MANDATORY_BRACES_IN_VARIABLE_EXPANSION +- {"MANDATORY_BRACES_IN_VARIABLE_EXPANSION", ERR_LIB_CONF, CONF_R_MANDATORY_BRACES_IN_VARIABLE_EXPANSION}, +- #else +- {"MANDATORY_BRACES_IN_VARIABLE_EXPANSION", 14, 123}, +- #endif +- #ifdef CONF_R_MISSING_CLOSE_SQUARE_BRACKET +- {"MISSING_CLOSE_SQUARE_BRACKET", ERR_LIB_CONF, CONF_R_MISSING_CLOSE_SQUARE_BRACKET}, +- #else +- {"MISSING_CLOSE_SQUARE_BRACKET", 14, 100}, +- #endif +- #ifdef CONF_R_MISSING_EQUAL_SIGN +- {"MISSING_EQUAL_SIGN", ERR_LIB_CONF, CONF_R_MISSING_EQUAL_SIGN}, +- #else +- {"MISSING_EQUAL_SIGN", 14, 101}, +- #endif +- #ifdef CONF_R_MISSING_INIT_FUNCTION +- {"MISSING_INIT_FUNCTION", ERR_LIB_CONF, CONF_R_MISSING_INIT_FUNCTION}, +- #else +- {"MISSING_INIT_FUNCTION", 14, 112}, +- #endif +- #ifdef CONF_R_MODULE_INITIALIZATION_ERROR +- {"MODULE_INITIALIZATION_ERROR", ERR_LIB_CONF, CONF_R_MODULE_INITIALIZATION_ERROR}, +- #else +- {"MODULE_INITIALIZATION_ERROR", 14, 109}, +- #endif +- #ifdef CONF_R_NO_CLOSE_BRACE +- {"NO_CLOSE_BRACE", ERR_LIB_CONF, CONF_R_NO_CLOSE_BRACE}, +- #else +- {"NO_CLOSE_BRACE", 14, 102}, +- #endif +- #ifdef CONF_R_NO_CONF +- {"NO_CONF", ERR_LIB_CONF, CONF_R_NO_CONF}, +- #else +- {"NO_CONF", 14, 105}, +- #endif +- #ifdef CONF_R_NO_CONF_OR_ENVIRONMENT_VARIABLE +- {"NO_CONF_OR_ENVIRONMENT_VARIABLE", ERR_LIB_CONF, CONF_R_NO_CONF_OR_ENVIRONMENT_VARIABLE}, +- #else +- {"NO_CONF_OR_ENVIRONMENT_VARIABLE", 14, 106}, +- #endif +- #ifdef CONF_R_NO_SECTION +- {"NO_SECTION", ERR_LIB_CONF, CONF_R_NO_SECTION}, +- #else +- {"NO_SECTION", 14, 107}, +- #endif +- #ifdef CONF_R_NO_SUCH_FILE +- {"NO_SUCH_FILE", ERR_LIB_CONF, CONF_R_NO_SUCH_FILE}, +- #else +- {"NO_SUCH_FILE", 14, 114}, +- #endif +- #ifdef CONF_R_NO_VALUE +- {"NO_VALUE", ERR_LIB_CONF, CONF_R_NO_VALUE}, +- #else +- {"NO_VALUE", 14, 108}, +- #endif +- #ifdef CONF_R_NUMBER_TOO_LARGE +- {"NUMBER_TOO_LARGE", ERR_LIB_CONF, CONF_R_NUMBER_TOO_LARGE}, +- #else +- {"NUMBER_TOO_LARGE", 14, 121}, +- #endif +- #ifdef CONF_R_OPENSSL_CONF_REFERENCES_MISSING_SECTION +- {"OPENSSL_CONF_REFERENCES_MISSING_SECTION", ERR_LIB_CONF, CONF_R_OPENSSL_CONF_REFERENCES_MISSING_SECTION}, +- #else +- {"OPENSSL_CONF_REFERENCES_MISSING_SECTION", 14, 124}, +- #endif +- #ifdef CONF_R_RECURSIVE_DIRECTORY_INCLUDE +- {"RECURSIVE_DIRECTORY_INCLUDE", ERR_LIB_CONF, CONF_R_RECURSIVE_DIRECTORY_INCLUDE}, +- #else +- {"RECURSIVE_DIRECTORY_INCLUDE", 14, 111}, +- #endif +- #ifdef CONF_R_RELATIVE_PATH +- {"RELATIVE_PATH", ERR_LIB_CONF, CONF_R_RELATIVE_PATH}, +- #else +- {"RELATIVE_PATH", 14, 125}, +- #endif +- #ifdef CONF_R_SSL_COMMAND_SECTION_EMPTY +- {"SSL_COMMAND_SECTION_EMPTY", ERR_LIB_CONF, CONF_R_SSL_COMMAND_SECTION_EMPTY}, +- #else +- {"SSL_COMMAND_SECTION_EMPTY", 14, 117}, +- #endif +- #ifdef CONF_R_SSL_COMMAND_SECTION_NOT_FOUND +- {"SSL_COMMAND_SECTION_NOT_FOUND", ERR_LIB_CONF, CONF_R_SSL_COMMAND_SECTION_NOT_FOUND}, +- #else +- {"SSL_COMMAND_SECTION_NOT_FOUND", 14, 118}, +- #endif +- #ifdef CONF_R_SSL_SECTION_EMPTY +- {"SSL_SECTION_EMPTY", ERR_LIB_CONF, CONF_R_SSL_SECTION_EMPTY}, +- #else +- {"SSL_SECTION_EMPTY", 14, 119}, +- #endif +- #ifdef CONF_R_SSL_SECTION_NOT_FOUND +- {"SSL_SECTION_NOT_FOUND", ERR_LIB_CONF, CONF_R_SSL_SECTION_NOT_FOUND}, +- #else +- {"SSL_SECTION_NOT_FOUND", 14, 120}, +- #endif +- #ifdef CONF_R_UNABLE_TO_CREATE_NEW_SECTION +- {"UNABLE_TO_CREATE_NEW_SECTION", ERR_LIB_CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION}, +- #else +- {"UNABLE_TO_CREATE_NEW_SECTION", 14, 103}, +- #endif +- #ifdef CONF_R_UNKNOWN_MODULE_NAME +- {"UNKNOWN_MODULE_NAME", ERR_LIB_CONF, CONF_R_UNKNOWN_MODULE_NAME}, +- #else +- {"UNKNOWN_MODULE_NAME", 14, 113}, +- #endif +- #ifdef CONF_R_VARIABLE_EXPANSION_TOO_LONG +- {"VARIABLE_EXPANSION_TOO_LONG", ERR_LIB_CONF, CONF_R_VARIABLE_EXPANSION_TOO_LONG}, +- #else +- {"VARIABLE_EXPANSION_TOO_LONG", 14, 116}, +- #endif +- #ifdef CONF_R_VARIABLE_HAS_NO_VALUE +- {"VARIABLE_HAS_NO_VALUE", ERR_LIB_CONF, CONF_R_VARIABLE_HAS_NO_VALUE}, +- #else +- {"VARIABLE_HAS_NO_VALUE", 14, 104}, +- #endif +- #ifdef CRMF_R_BAD_PBM_ITERATIONCOUNT +- {"BAD_PBM_ITERATIONCOUNT", ERR_LIB_CRMF, CRMF_R_BAD_PBM_ITERATIONCOUNT}, +- #else +- {"BAD_PBM_ITERATIONCOUNT", 56, 100}, +- #endif +- #ifdef CRMF_R_CRMFERROR +- {"CRMFERROR", ERR_LIB_CRMF, CRMF_R_CRMFERROR}, +- #else +- {"CRMFERROR", 56, 102}, +- #endif +- #ifdef CRMF_R_ERROR +- {"ERROR", ERR_LIB_CRMF, CRMF_R_ERROR}, +- #else +- {"ERROR", 56, 103}, +- #endif +- #ifdef CRMF_R_ERROR_DECODING_CERTIFICATE +- {"ERROR_DECODING_CERTIFICATE", ERR_LIB_CRMF, CRMF_R_ERROR_DECODING_CERTIFICATE}, +- #else +- {"ERROR_DECODING_CERTIFICATE", 56, 104}, +- #endif +- #ifdef CRMF_R_ERROR_DECRYPTING_CERTIFICATE +- {"ERROR_DECRYPTING_CERTIFICATE", ERR_LIB_CRMF, CRMF_R_ERROR_DECRYPTING_CERTIFICATE}, +- #else +- {"ERROR_DECRYPTING_CERTIFICATE", 56, 105}, +- #endif +- #ifdef CRMF_R_ERROR_DECRYPTING_SYMMETRIC_KEY +- {"ERROR_DECRYPTING_SYMMETRIC_KEY", ERR_LIB_CRMF, CRMF_R_ERROR_DECRYPTING_SYMMETRIC_KEY}, +- #else +- {"ERROR_DECRYPTING_SYMMETRIC_KEY", 56, 106}, +- #endif +- #ifdef CRMF_R_FAILURE_OBTAINING_RANDOM +- {"FAILURE_OBTAINING_RANDOM", ERR_LIB_CRMF, CRMF_R_FAILURE_OBTAINING_RANDOM}, +- #else +- {"FAILURE_OBTAINING_RANDOM", 56, 107}, +- #endif +- #ifdef CRMF_R_ITERATIONCOUNT_BELOW_100 +- {"ITERATIONCOUNT_BELOW_100", ERR_LIB_CRMF, CRMF_R_ITERATIONCOUNT_BELOW_100}, +- #else +- {"ITERATIONCOUNT_BELOW_100", 56, 108}, +- #endif +- #ifdef CRMF_R_MALFORMED_IV +- {"MALFORMED_IV", ERR_LIB_CRMF, CRMF_R_MALFORMED_IV}, +- #else +- {"MALFORMED_IV", 56, 101}, +- #endif +- #ifdef CRMF_R_NULL_ARGUMENT +- {"NULL_ARGUMENT", ERR_LIB_CRMF, CRMF_R_NULL_ARGUMENT}, +- #else +- {"NULL_ARGUMENT", 56, 109}, +- #endif +- #ifdef CRMF_R_POPOSKINPUT_NOT_SUPPORTED +- {"POPOSKINPUT_NOT_SUPPORTED", ERR_LIB_CRMF, CRMF_R_POPOSKINPUT_NOT_SUPPORTED}, +- #else +- {"POPOSKINPUT_NOT_SUPPORTED", 56, 113}, +- #endif +- #ifdef CRMF_R_POPO_INCONSISTENT_PUBLIC_KEY +- {"POPO_INCONSISTENT_PUBLIC_KEY", ERR_LIB_CRMF, CRMF_R_POPO_INCONSISTENT_PUBLIC_KEY}, +- #else +- {"POPO_INCONSISTENT_PUBLIC_KEY", 56, 117}, +- #endif +- #ifdef CRMF_R_POPO_MISSING +- {"POPO_MISSING", ERR_LIB_CRMF, CRMF_R_POPO_MISSING}, +- #else +- {"POPO_MISSING", 56, 121}, +- #endif +- #ifdef CRMF_R_POPO_MISSING_PUBLIC_KEY +- {"POPO_MISSING_PUBLIC_KEY", ERR_LIB_CRMF, CRMF_R_POPO_MISSING_PUBLIC_KEY}, +- #else +- {"POPO_MISSING_PUBLIC_KEY", 56, 118}, +- #endif +- #ifdef CRMF_R_POPO_MISSING_SUBJECT +- {"POPO_MISSING_SUBJECT", ERR_LIB_CRMF, CRMF_R_POPO_MISSING_SUBJECT}, +- #else +- {"POPO_MISSING_SUBJECT", 56, 119}, +- #endif +- #ifdef CRMF_R_POPO_RAVERIFIED_NOT_ACCEPTED +- {"POPO_RAVERIFIED_NOT_ACCEPTED", ERR_LIB_CRMF, CRMF_R_POPO_RAVERIFIED_NOT_ACCEPTED}, +- #else +- {"POPO_RAVERIFIED_NOT_ACCEPTED", 56, 120}, +- #endif +- #ifdef CRMF_R_SETTING_MAC_ALGOR_FAILURE +- {"SETTING_MAC_ALGOR_FAILURE", ERR_LIB_CRMF, CRMF_R_SETTING_MAC_ALGOR_FAILURE}, +- #else +- {"SETTING_MAC_ALGOR_FAILURE", 56, 110}, +- #endif +- #ifdef CRMF_R_SETTING_OWF_ALGOR_FAILURE +- {"SETTING_OWF_ALGOR_FAILURE", ERR_LIB_CRMF, CRMF_R_SETTING_OWF_ALGOR_FAILURE}, +- #else +- {"SETTING_OWF_ALGOR_FAILURE", 56, 111}, +- #endif +- #ifdef CRMF_R_UNSUPPORTED_ALGORITHM +- {"UNSUPPORTED_ALGORITHM", ERR_LIB_CRMF, CRMF_R_UNSUPPORTED_ALGORITHM}, +- #else +- {"UNSUPPORTED_ALGORITHM", 56, 112}, +- #endif +- #ifdef CRMF_R_UNSUPPORTED_CIPHER +- {"UNSUPPORTED_CIPHER", ERR_LIB_CRMF, CRMF_R_UNSUPPORTED_CIPHER}, +- #else +- {"UNSUPPORTED_CIPHER", 56, 114}, +- #endif +- #ifdef CRMF_R_UNSUPPORTED_METHOD_FOR_CREATING_POPO +- {"UNSUPPORTED_METHOD_FOR_CREATING_POPO", ERR_LIB_CRMF, CRMF_R_UNSUPPORTED_METHOD_FOR_CREATING_POPO}, +- #else +- {"UNSUPPORTED_METHOD_FOR_CREATING_POPO", 56, 115}, +- #endif +- #ifdef CRMF_R_UNSUPPORTED_POPO_METHOD +- {"UNSUPPORTED_POPO_METHOD", ERR_LIB_CRMF, CRMF_R_UNSUPPORTED_POPO_METHOD}, +- #else +- {"UNSUPPORTED_POPO_METHOD", 56, 116}, +- #endif +- #ifdef CRYPTO_R_BAD_ALGORITHM_NAME +- {"BAD_ALGORITHM_NAME", ERR_LIB_CRYPTO, CRYPTO_R_BAD_ALGORITHM_NAME}, +- #else +- {"BAD_ALGORITHM_NAME", 15, 117}, +- #endif +- #ifdef CRYPTO_R_CONFLICTING_NAMES +- {"CONFLICTING_NAMES", ERR_LIB_CRYPTO, CRYPTO_R_CONFLICTING_NAMES}, +- #else +- {"CONFLICTING_NAMES", 15, 118}, +- #endif +- #ifdef CRYPTO_R_HEX_STRING_TOO_SHORT +- {"HEX_STRING_TOO_SHORT", ERR_LIB_CRYPTO, CRYPTO_R_HEX_STRING_TOO_SHORT}, +- #else +- {"HEX_STRING_TOO_SHORT", 15, 121}, +- #endif +- #ifdef CRYPTO_R_ILLEGAL_HEX_DIGIT +- {"ILLEGAL_HEX_DIGIT", ERR_LIB_CRYPTO, CRYPTO_R_ILLEGAL_HEX_DIGIT}, +- #else +- {"ILLEGAL_HEX_DIGIT", 15, 102}, +- #endif +- #ifdef CRYPTO_R_INSUFFICIENT_DATA_SPACE +- {"INSUFFICIENT_DATA_SPACE", ERR_LIB_CRYPTO, CRYPTO_R_INSUFFICIENT_DATA_SPACE}, +- #else +- {"INSUFFICIENT_DATA_SPACE", 15, 106}, +- #endif +- #ifdef CRYPTO_R_INSUFFICIENT_PARAM_SIZE +- {"INSUFFICIENT_PARAM_SIZE", ERR_LIB_CRYPTO, CRYPTO_R_INSUFFICIENT_PARAM_SIZE}, +- #else +- {"INSUFFICIENT_PARAM_SIZE", 15, 107}, +- #endif +- #ifdef CRYPTO_R_INSUFFICIENT_SECURE_DATA_SPACE +- {"INSUFFICIENT_SECURE_DATA_SPACE", ERR_LIB_CRYPTO, CRYPTO_R_INSUFFICIENT_SECURE_DATA_SPACE}, +- #else +- {"INSUFFICIENT_SECURE_DATA_SPACE", 15, 108}, +- #endif +- #ifdef CRYPTO_R_INTEGER_OVERFLOW +- {"INTEGER_OVERFLOW", ERR_LIB_CRYPTO, CRYPTO_R_INTEGER_OVERFLOW}, +- #else +- {"INTEGER_OVERFLOW", 15, 127}, +- #endif +- #ifdef CRYPTO_R_INVALID_NEGATIVE_VALUE +- {"INVALID_NEGATIVE_VALUE", ERR_LIB_CRYPTO, CRYPTO_R_INVALID_NEGATIVE_VALUE}, +- #else +- {"INVALID_NEGATIVE_VALUE", 15, 122}, +- #endif +- #ifdef CRYPTO_R_INVALID_NULL_ARGUMENT +- {"INVALID_NULL_ARGUMENT", ERR_LIB_CRYPTO, CRYPTO_R_INVALID_NULL_ARGUMENT}, +- #else +- {"INVALID_NULL_ARGUMENT", 15, 109}, +- #endif +- #ifdef CRYPTO_R_INVALID_OSSL_PARAM_TYPE +- {"INVALID_OSSL_PARAM_TYPE", ERR_LIB_CRYPTO, CRYPTO_R_INVALID_OSSL_PARAM_TYPE}, +- #else +- {"INVALID_OSSL_PARAM_TYPE", 15, 110}, +- #endif +- #ifdef CRYPTO_R_NO_PARAMS_TO_MERGE +- {"NO_PARAMS_TO_MERGE", ERR_LIB_CRYPTO, CRYPTO_R_NO_PARAMS_TO_MERGE}, +- #else +- {"NO_PARAMS_TO_MERGE", 15, 131}, +- #endif +- #ifdef CRYPTO_R_NO_SPACE_FOR_TERMINATING_NULL +- {"NO_SPACE_FOR_TERMINATING_NULL", ERR_LIB_CRYPTO, CRYPTO_R_NO_SPACE_FOR_TERMINATING_NULL}, +- #else +- {"NO_SPACE_FOR_TERMINATING_NULL", 15, 128}, +- #endif +- #ifdef CRYPTO_R_ODD_NUMBER_OF_DIGITS +- {"ODD_NUMBER_OF_DIGITS", ERR_LIB_CRYPTO, CRYPTO_R_ODD_NUMBER_OF_DIGITS}, +- #else +- {"ODD_NUMBER_OF_DIGITS", 15, 103}, +- #endif +- #ifdef CRYPTO_R_PARAM_CANNOT_BE_REPRESENTED_EXACTLY +- {"PARAM_CANNOT_BE_REPRESENTED_EXACTLY", ERR_LIB_CRYPTO, CRYPTO_R_PARAM_CANNOT_BE_REPRESENTED_EXACTLY}, +- #else +- {"PARAM_CANNOT_BE_REPRESENTED_EXACTLY", 15, 123}, +- #endif +- #ifdef CRYPTO_R_PARAM_NOT_INTEGER_TYPE +- {"PARAM_NOT_INTEGER_TYPE", ERR_LIB_CRYPTO, CRYPTO_R_PARAM_NOT_INTEGER_TYPE}, +- #else +- {"PARAM_NOT_INTEGER_TYPE", 15, 124}, +- #endif +- #ifdef CRYPTO_R_PARAM_OF_INCOMPATIBLE_TYPE +- {"PARAM_OF_INCOMPATIBLE_TYPE", ERR_LIB_CRYPTO, CRYPTO_R_PARAM_OF_INCOMPATIBLE_TYPE}, +- #else +- {"PARAM_OF_INCOMPATIBLE_TYPE", 15, 129}, +- #endif +- #ifdef CRYPTO_R_PARAM_UNSIGNED_INTEGER_NEGATIVE_VALUE_UNSUPPORTED +- {"PARAM_UNSIGNED_INTEGER_NEGATIVE_VALUE_UNSUPPORTED", ERR_LIB_CRYPTO, CRYPTO_R_PARAM_UNSIGNED_INTEGER_NEGATIVE_VALUE_UNSUPPORTED}, +- #else +- {"PARAM_UNSIGNED_INTEGER_NEGATIVE_VALUE_UNSUPPORTED", 15, 125}, +- #endif +- #ifdef CRYPTO_R_PARAM_UNSUPPORTED_FLOATING_POINT_FORMAT +- {"PARAM_UNSUPPORTED_FLOATING_POINT_FORMAT", ERR_LIB_CRYPTO, CRYPTO_R_PARAM_UNSUPPORTED_FLOATING_POINT_FORMAT}, +- #else +- {"PARAM_UNSUPPORTED_FLOATING_POINT_FORMAT", 15, 130}, +- #endif +- #ifdef CRYPTO_R_PARAM_VALUE_TOO_LARGE_FOR_DESTINATION +- {"PARAM_VALUE_TOO_LARGE_FOR_DESTINATION", ERR_LIB_CRYPTO, CRYPTO_R_PARAM_VALUE_TOO_LARGE_FOR_DESTINATION}, +- #else +- {"PARAM_VALUE_TOO_LARGE_FOR_DESTINATION", 15, 126}, +- #endif +- #ifdef CRYPTO_R_PROVIDER_ALREADY_EXISTS +- {"PROVIDER_ALREADY_EXISTS", ERR_LIB_CRYPTO, CRYPTO_R_PROVIDER_ALREADY_EXISTS}, +- #else +- {"PROVIDER_ALREADY_EXISTS", 15, 104}, +- #endif +- #ifdef CRYPTO_R_PROVIDER_SECTION_ERROR +- {"PROVIDER_SECTION_ERROR", ERR_LIB_CRYPTO, CRYPTO_R_PROVIDER_SECTION_ERROR}, +- #else +- {"PROVIDER_SECTION_ERROR", 15, 105}, +- #endif +- #ifdef CRYPTO_R_RANDOM_SECTION_ERROR +- {"RANDOM_SECTION_ERROR", ERR_LIB_CRYPTO, CRYPTO_R_RANDOM_SECTION_ERROR}, +- #else +- {"RANDOM_SECTION_ERROR", 15, 119}, +- #endif +- #ifdef CRYPTO_R_SECURE_MALLOC_FAILURE +- {"SECURE_MALLOC_FAILURE", ERR_LIB_CRYPTO, CRYPTO_R_SECURE_MALLOC_FAILURE}, +- #else +- {"SECURE_MALLOC_FAILURE", 15, 111}, +- #endif +- #ifdef CRYPTO_R_STRING_TOO_LONG +- {"STRING_TOO_LONG", ERR_LIB_CRYPTO, CRYPTO_R_STRING_TOO_LONG}, +- #else +- {"STRING_TOO_LONG", 15, 112}, +- #endif +- #ifdef CRYPTO_R_TOO_MANY_BYTES +- {"TOO_MANY_BYTES", ERR_LIB_CRYPTO, CRYPTO_R_TOO_MANY_BYTES}, +- #else +- {"TOO_MANY_BYTES", 15, 113}, +- #endif +- #ifdef CRYPTO_R_TOO_MANY_RECORDS +- {"TOO_MANY_RECORDS", ERR_LIB_CRYPTO, CRYPTO_R_TOO_MANY_RECORDS}, +- #else +- {"TOO_MANY_RECORDS", 15, 114}, +- #endif +- #ifdef CRYPTO_R_TOO_SMALL_BUFFER +- {"TOO_SMALL_BUFFER", ERR_LIB_CRYPTO, CRYPTO_R_TOO_SMALL_BUFFER}, +- #else +- {"TOO_SMALL_BUFFER", 15, 116}, +- #endif +- #ifdef CRYPTO_R_UNKNOWN_NAME_IN_RANDOM_SECTION +- {"UNKNOWN_NAME_IN_RANDOM_SECTION", ERR_LIB_CRYPTO, CRYPTO_R_UNKNOWN_NAME_IN_RANDOM_SECTION}, +- #else +- {"UNKNOWN_NAME_IN_RANDOM_SECTION", 15, 120}, +- #endif +- #ifdef CRYPTO_R_ZERO_LENGTH_NUMBER +- {"ZERO_LENGTH_NUMBER", ERR_LIB_CRYPTO, CRYPTO_R_ZERO_LENGTH_NUMBER}, +- #else +- {"ZERO_LENGTH_NUMBER", 15, 115}, +- #endif +- #ifdef CT_R_BASE64_DECODE_ERROR +- {"BASE64_DECODE_ERROR", ERR_LIB_CT, CT_R_BASE64_DECODE_ERROR}, +- #else +- {"BASE64_DECODE_ERROR", 50, 108}, +- #endif +- #ifdef CT_R_INVALID_LOG_ID_LENGTH +- {"INVALID_LOG_ID_LENGTH", ERR_LIB_CT, CT_R_INVALID_LOG_ID_LENGTH}, +- #else +- {"INVALID_LOG_ID_LENGTH", 50, 100}, +- #endif +- #ifdef CT_R_LOG_CONF_INVALID +- {"LOG_CONF_INVALID", ERR_LIB_CT, CT_R_LOG_CONF_INVALID}, +- #else +- {"LOG_CONF_INVALID", 50, 109}, +- #endif +- #ifdef CT_R_LOG_CONF_INVALID_KEY +- {"LOG_CONF_INVALID_KEY", ERR_LIB_CT, CT_R_LOG_CONF_INVALID_KEY}, +- #else +- {"LOG_CONF_INVALID_KEY", 50, 110}, +- #endif +- #ifdef CT_R_LOG_CONF_MISSING_DESCRIPTION +- {"LOG_CONF_MISSING_DESCRIPTION", ERR_LIB_CT, CT_R_LOG_CONF_MISSING_DESCRIPTION}, +- #else +- {"LOG_CONF_MISSING_DESCRIPTION", 50, 111}, +- #endif +- #ifdef CT_R_LOG_CONF_MISSING_KEY +- {"LOG_CONF_MISSING_KEY", ERR_LIB_CT, CT_R_LOG_CONF_MISSING_KEY}, +- #else +- {"LOG_CONF_MISSING_KEY", 50, 112}, +- #endif +- #ifdef CT_R_LOG_KEY_INVALID +- {"LOG_KEY_INVALID", ERR_LIB_CT, CT_R_LOG_KEY_INVALID}, +- #else +- {"LOG_KEY_INVALID", 50, 113}, +- #endif +- #ifdef CT_R_SCT_FUTURE_TIMESTAMP +- {"SCT_FUTURE_TIMESTAMP", ERR_LIB_CT, CT_R_SCT_FUTURE_TIMESTAMP}, +- #else +- {"SCT_FUTURE_TIMESTAMP", 50, 116}, +- #endif +- #ifdef CT_R_SCT_INVALID +- {"SCT_INVALID", ERR_LIB_CT, CT_R_SCT_INVALID}, +- #else +- {"SCT_INVALID", 50, 104}, +- #endif +- #ifdef CT_R_SCT_INVALID_SIGNATURE +- {"SCT_INVALID_SIGNATURE", ERR_LIB_CT, CT_R_SCT_INVALID_SIGNATURE}, +- #else +- {"SCT_INVALID_SIGNATURE", 50, 107}, +- #endif +- #ifdef CT_R_SCT_LIST_INVALID +- {"SCT_LIST_INVALID", ERR_LIB_CT, CT_R_SCT_LIST_INVALID}, +- #else +- {"SCT_LIST_INVALID", 50, 105}, +- #endif +- #ifdef CT_R_SCT_LOG_ID_MISMATCH +- {"SCT_LOG_ID_MISMATCH", ERR_LIB_CT, CT_R_SCT_LOG_ID_MISMATCH}, +- #else +- {"SCT_LOG_ID_MISMATCH", 50, 114}, +- #endif +- #ifdef CT_R_SCT_NOT_SET +- {"SCT_NOT_SET", ERR_LIB_CT, CT_R_SCT_NOT_SET}, +- #else +- {"SCT_NOT_SET", 50, 106}, +- #endif +- #ifdef CT_R_SCT_UNSUPPORTED_VERSION +- {"SCT_UNSUPPORTED_VERSION", ERR_LIB_CT, CT_R_SCT_UNSUPPORTED_VERSION}, +- #else +- {"SCT_UNSUPPORTED_VERSION", 50, 115}, +- #endif +- #ifdef CT_R_UNRECOGNIZED_SIGNATURE_NID +- {"UNRECOGNIZED_SIGNATURE_NID", ERR_LIB_CT, CT_R_UNRECOGNIZED_SIGNATURE_NID}, +- #else +- {"UNRECOGNIZED_SIGNATURE_NID", 50, 101}, +- #endif +- #ifdef CT_R_UNSUPPORTED_ENTRY_TYPE +- {"UNSUPPORTED_ENTRY_TYPE", ERR_LIB_CT, CT_R_UNSUPPORTED_ENTRY_TYPE}, +- #else +- {"UNSUPPORTED_ENTRY_TYPE", 50, 102}, +- #endif +- #ifdef CT_R_UNSUPPORTED_VERSION +- {"UNSUPPORTED_VERSION", ERR_LIB_CT, CT_R_UNSUPPORTED_VERSION}, +- #else +- {"UNSUPPORTED_VERSION", 50, 103}, +- #endif +- #ifdef DH_R_BAD_FFC_PARAMETERS +- {"BAD_FFC_PARAMETERS", ERR_LIB_DH, DH_R_BAD_FFC_PARAMETERS}, +- #else +- {"BAD_FFC_PARAMETERS", 5, 127}, +- #endif +- #ifdef DH_R_BAD_GENERATOR +- {"BAD_GENERATOR", ERR_LIB_DH, DH_R_BAD_GENERATOR}, +- #else +- {"BAD_GENERATOR", 5, 101}, +- #endif +- #ifdef DH_R_BN_DECODE_ERROR +- {"BN_DECODE_ERROR", ERR_LIB_DH, DH_R_BN_DECODE_ERROR}, +- #else +- {"BN_DECODE_ERROR", 5, 109}, +- #endif +- #ifdef DH_R_BN_ERROR +- {"BN_ERROR", ERR_LIB_DH, DH_R_BN_ERROR}, +- #else +- {"BN_ERROR", 5, 106}, +- #endif +- #ifdef DH_R_CHECK_INVALID_J_VALUE +- {"CHECK_INVALID_J_VALUE", ERR_LIB_DH, DH_R_CHECK_INVALID_J_VALUE}, +- #else +- {"CHECK_INVALID_J_VALUE", 5, 115}, +- #endif +- #ifdef DH_R_CHECK_INVALID_Q_VALUE +- {"CHECK_INVALID_Q_VALUE", ERR_LIB_DH, DH_R_CHECK_INVALID_Q_VALUE}, +- #else +- {"CHECK_INVALID_Q_VALUE", 5, 116}, +- #endif +- #ifdef DH_R_CHECK_PUBKEY_INVALID +- {"CHECK_PUBKEY_INVALID", ERR_LIB_DH, DH_R_CHECK_PUBKEY_INVALID}, +- #else +- {"CHECK_PUBKEY_INVALID", 5, 122}, +- #endif +- #ifdef DH_R_CHECK_PUBKEY_TOO_LARGE +- {"CHECK_PUBKEY_TOO_LARGE", ERR_LIB_DH, DH_R_CHECK_PUBKEY_TOO_LARGE}, +- #else +- {"CHECK_PUBKEY_TOO_LARGE", 5, 123}, +- #endif +- #ifdef DH_R_CHECK_PUBKEY_TOO_SMALL +- {"CHECK_PUBKEY_TOO_SMALL", ERR_LIB_DH, DH_R_CHECK_PUBKEY_TOO_SMALL}, +- #else +- {"CHECK_PUBKEY_TOO_SMALL", 5, 124}, +- #endif +- #ifdef DH_R_CHECK_P_NOT_PRIME +- {"CHECK_P_NOT_PRIME", ERR_LIB_DH, DH_R_CHECK_P_NOT_PRIME}, +- #else +- {"CHECK_P_NOT_PRIME", 5, 117}, +- #endif +- #ifdef DH_R_CHECK_P_NOT_SAFE_PRIME +- {"CHECK_P_NOT_SAFE_PRIME", ERR_LIB_DH, DH_R_CHECK_P_NOT_SAFE_PRIME}, +- #else +- {"CHECK_P_NOT_SAFE_PRIME", 5, 118}, +- #endif +- #ifdef DH_R_CHECK_Q_NOT_PRIME +- {"CHECK_Q_NOT_PRIME", ERR_LIB_DH, DH_R_CHECK_Q_NOT_PRIME}, +- #else +- {"CHECK_Q_NOT_PRIME", 5, 119}, +- #endif +- #ifdef DH_R_DECODE_ERROR +- {"DECODE_ERROR", ERR_LIB_DH, DH_R_DECODE_ERROR}, +- #else +- {"DECODE_ERROR", 5, 104}, +- #endif +- #ifdef DH_R_INVALID_PARAMETER_NAME +- {"INVALID_PARAMETER_NAME", ERR_LIB_DH, DH_R_INVALID_PARAMETER_NAME}, +- #else +- {"INVALID_PARAMETER_NAME", 5, 110}, +- #endif +- #ifdef DH_R_INVALID_PARAMETER_NID +- {"INVALID_PARAMETER_NID", ERR_LIB_DH, DH_R_INVALID_PARAMETER_NID}, +- #else +- {"INVALID_PARAMETER_NID", 5, 114}, +- #endif +- #ifdef DH_R_INVALID_PUBKEY +- {"INVALID_PUBKEY", ERR_LIB_DH, DH_R_INVALID_PUBKEY}, +- #else +- {"INVALID_PUBKEY", 5, 102}, +- #endif +- #ifdef DH_R_INVALID_SECRET +- {"INVALID_SECRET", ERR_LIB_DH, DH_R_INVALID_SECRET}, +- #else +- {"INVALID_SECRET", 5, 128}, +- #endif +- #ifdef DH_R_KDF_PARAMETER_ERROR +- {"KDF_PARAMETER_ERROR", ERR_LIB_DH, DH_R_KDF_PARAMETER_ERROR}, +- #else +- {"KDF_PARAMETER_ERROR", 5, 112}, +- #endif +- #ifdef DH_R_KEYS_NOT_SET +- {"KEYS_NOT_SET", ERR_LIB_DH, DH_R_KEYS_NOT_SET}, +- #else +- {"KEYS_NOT_SET", 5, 108}, +- #endif +- #ifdef DH_R_MISSING_PUBKEY +- {"MISSING_PUBKEY", ERR_LIB_DH, DH_R_MISSING_PUBKEY}, +- #else +- {"MISSING_PUBKEY", 5, 125}, +- #endif +- #ifdef DH_R_MODULUS_TOO_LARGE +- {"MODULUS_TOO_LARGE", ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE}, +- #else +- {"MODULUS_TOO_LARGE", 5, 103}, +- #endif +- #ifdef DH_R_MODULUS_TOO_SMALL +- {"MODULUS_TOO_SMALL", ERR_LIB_DH, DH_R_MODULUS_TOO_SMALL}, +- #else +- {"MODULUS_TOO_SMALL", 5, 126}, +- #endif +- #ifdef DH_R_NOT_SUITABLE_GENERATOR +- {"NOT_SUITABLE_GENERATOR", ERR_LIB_DH, DH_R_NOT_SUITABLE_GENERATOR}, +- #else +- {"NOT_SUITABLE_GENERATOR", 5, 120}, +- #endif +- #ifdef DH_R_NO_PARAMETERS_SET +- {"NO_PARAMETERS_SET", ERR_LIB_DH, DH_R_NO_PARAMETERS_SET}, +- #else +- {"NO_PARAMETERS_SET", 5, 107}, +- #endif +- #ifdef DH_R_NO_PRIVATE_VALUE +- {"NO_PRIVATE_VALUE", ERR_LIB_DH, DH_R_NO_PRIVATE_VALUE}, +- #else +- {"NO_PRIVATE_VALUE", 5, 100}, +- #endif +- #ifdef DH_R_PARAMETER_ENCODING_ERROR +- {"PARAMETER_ENCODING_ERROR", ERR_LIB_DH, DH_R_PARAMETER_ENCODING_ERROR}, +- #else +- {"PARAMETER_ENCODING_ERROR", 5, 105}, +- #endif +- #ifdef DH_R_PEER_KEY_ERROR +- {"PEER_KEY_ERROR", ERR_LIB_DH, DH_R_PEER_KEY_ERROR}, +- #else +- {"PEER_KEY_ERROR", 5, 111}, +- #endif +- #ifdef DH_R_SHARED_INFO_ERROR +- {"SHARED_INFO_ERROR", ERR_LIB_DH, DH_R_SHARED_INFO_ERROR}, +- #else +- {"SHARED_INFO_ERROR", 5, 113}, +- #endif +- #ifdef DH_R_UNABLE_TO_CHECK_GENERATOR +- {"UNABLE_TO_CHECK_GENERATOR", ERR_LIB_DH, DH_R_UNABLE_TO_CHECK_GENERATOR}, +- #else +- {"UNABLE_TO_CHECK_GENERATOR", 5, 121}, +- #endif +- #ifdef DSA_R_BAD_FFC_PARAMETERS +- {"BAD_FFC_PARAMETERS", ERR_LIB_DSA, DSA_R_BAD_FFC_PARAMETERS}, +- #else +- {"BAD_FFC_PARAMETERS", 10, 114}, +- #endif +- #ifdef DSA_R_BAD_Q_VALUE +- {"BAD_Q_VALUE", ERR_LIB_DSA, DSA_R_BAD_Q_VALUE}, +- #else +- {"BAD_Q_VALUE", 10, 102}, +- #endif +- #ifdef DSA_R_BN_DECODE_ERROR +- {"BN_DECODE_ERROR", ERR_LIB_DSA, DSA_R_BN_DECODE_ERROR}, +- #else +- {"BN_DECODE_ERROR", 10, 108}, +- #endif +- #ifdef DSA_R_BN_ERROR +- {"BN_ERROR", ERR_LIB_DSA, DSA_R_BN_ERROR}, +- #else +- {"BN_ERROR", 10, 109}, +- #endif +- #ifdef DSA_R_DECODE_ERROR +- {"DECODE_ERROR", ERR_LIB_DSA, DSA_R_DECODE_ERROR}, +- #else +- {"DECODE_ERROR", 10, 104}, +- #endif +- #ifdef DSA_R_INVALID_DIGEST_TYPE +- {"INVALID_DIGEST_TYPE", ERR_LIB_DSA, DSA_R_INVALID_DIGEST_TYPE}, +- #else +- {"INVALID_DIGEST_TYPE", 10, 106}, +- #endif +- #ifdef DSA_R_INVALID_PARAMETERS +- {"INVALID_PARAMETERS", ERR_LIB_DSA, DSA_R_INVALID_PARAMETERS}, +- #else +- {"INVALID_PARAMETERS", 10, 112}, +- #endif +- #ifdef DSA_R_MISSING_PARAMETERS +- {"MISSING_PARAMETERS", ERR_LIB_DSA, DSA_R_MISSING_PARAMETERS}, +- #else +- {"MISSING_PARAMETERS", 10, 101}, +- #endif +- #ifdef DSA_R_MISSING_PRIVATE_KEY +- {"MISSING_PRIVATE_KEY", ERR_LIB_DSA, DSA_R_MISSING_PRIVATE_KEY}, +- #else +- {"MISSING_PRIVATE_KEY", 10, 111}, +- #endif +- #ifdef DSA_R_MODULUS_TOO_LARGE +- {"MODULUS_TOO_LARGE", ERR_LIB_DSA, DSA_R_MODULUS_TOO_LARGE}, +- #else +- {"MODULUS_TOO_LARGE", 10, 103}, +- #endif +- #ifdef DSA_R_NO_PARAMETERS_SET +- {"NO_PARAMETERS_SET", ERR_LIB_DSA, DSA_R_NO_PARAMETERS_SET}, +- #else +- {"NO_PARAMETERS_SET", 10, 107}, +- #endif +- #ifdef DSA_R_PARAMETER_ENCODING_ERROR +- {"PARAMETER_ENCODING_ERROR", ERR_LIB_DSA, DSA_R_PARAMETER_ENCODING_ERROR}, +- #else +- {"PARAMETER_ENCODING_ERROR", 10, 105}, +- #endif +- #ifdef DSA_R_P_NOT_PRIME +- {"P_NOT_PRIME", ERR_LIB_DSA, DSA_R_P_NOT_PRIME}, +- #else +- {"P_NOT_PRIME", 10, 115}, +- #endif +- #ifdef DSA_R_Q_NOT_PRIME +- {"Q_NOT_PRIME", ERR_LIB_DSA, DSA_R_Q_NOT_PRIME}, +- #else +- {"Q_NOT_PRIME", 10, 113}, +- #endif +- #ifdef DSA_R_SEED_LEN_SMALL +- {"SEED_LEN_SMALL", ERR_LIB_DSA, DSA_R_SEED_LEN_SMALL}, +- #else +- {"SEED_LEN_SMALL", 10, 110}, +- #endif +- #ifdef DSA_R_TOO_MANY_RETRIES +- {"TOO_MANY_RETRIES", ERR_LIB_DSA, DSA_R_TOO_MANY_RETRIES}, +- #else +- {"TOO_MANY_RETRIES", 10, 116}, +- #endif +- #ifdef DSO_R_CTRL_FAILED +- {"CTRL_FAILED", ERR_LIB_DSO, DSO_R_CTRL_FAILED}, +- #else +- {"CTRL_FAILED", 37, 100}, +- #endif +- #ifdef DSO_R_DSO_ALREADY_LOADED +- {"DSO_ALREADY_LOADED", ERR_LIB_DSO, DSO_R_DSO_ALREADY_LOADED}, +- #else +- {"DSO_ALREADY_LOADED", 37, 110}, +- #endif +- #ifdef DSO_R_EMPTY_FILE_STRUCTURE +- {"EMPTY_FILE_STRUCTURE", ERR_LIB_DSO, DSO_R_EMPTY_FILE_STRUCTURE}, +- #else +- {"EMPTY_FILE_STRUCTURE", 37, 113}, +- #endif +- #ifdef DSO_R_FAILURE +- {"FAILURE", ERR_LIB_DSO, DSO_R_FAILURE}, +- #else +- {"FAILURE", 37, 114}, +- #endif +- #ifdef DSO_R_FILENAME_TOO_BIG +- {"FILENAME_TOO_BIG", ERR_LIB_DSO, DSO_R_FILENAME_TOO_BIG}, +- #else +- {"FILENAME_TOO_BIG", 37, 101}, +- #endif +- #ifdef DSO_R_FINISH_FAILED +- {"FINISH_FAILED", ERR_LIB_DSO, DSO_R_FINISH_FAILED}, +- #else +- {"FINISH_FAILED", 37, 102}, +- #endif +- #ifdef DSO_R_INCORRECT_FILE_SYNTAX +- {"INCORRECT_FILE_SYNTAX", ERR_LIB_DSO, DSO_R_INCORRECT_FILE_SYNTAX}, +- #else +- {"INCORRECT_FILE_SYNTAX", 37, 115}, +- #endif +- #ifdef DSO_R_LOAD_FAILED +- {"LOAD_FAILED", ERR_LIB_DSO, DSO_R_LOAD_FAILED}, +- #else +- {"LOAD_FAILED", 37, 103}, +- #endif +- #ifdef DSO_R_NAME_TRANSLATION_FAILED +- {"NAME_TRANSLATION_FAILED", ERR_LIB_DSO, DSO_R_NAME_TRANSLATION_FAILED}, +- #else +- {"NAME_TRANSLATION_FAILED", 37, 109}, +- #endif +- #ifdef DSO_R_NO_FILENAME +- {"NO_FILENAME", ERR_LIB_DSO, DSO_R_NO_FILENAME}, +- #else +- {"NO_FILENAME", 37, 111}, +- #endif +- #ifdef DSO_R_NULL_HANDLE +- {"NULL_HANDLE", ERR_LIB_DSO, DSO_R_NULL_HANDLE}, +- #else +- {"NULL_HANDLE", 37, 104}, +- #endif +- #ifdef DSO_R_SET_FILENAME_FAILED +- {"SET_FILENAME_FAILED", ERR_LIB_DSO, DSO_R_SET_FILENAME_FAILED}, +- #else +- {"SET_FILENAME_FAILED", 37, 112}, +- #endif +- #ifdef DSO_R_STACK_ERROR +- {"STACK_ERROR", ERR_LIB_DSO, DSO_R_STACK_ERROR}, +- #else +- {"STACK_ERROR", 37, 105}, +- #endif +- #ifdef DSO_R_SYM_FAILURE +- {"SYM_FAILURE", ERR_LIB_DSO, DSO_R_SYM_FAILURE}, +- #else +- {"SYM_FAILURE", 37, 106}, +- #endif +- #ifdef DSO_R_UNLOAD_FAILED +- {"UNLOAD_FAILED", ERR_LIB_DSO, DSO_R_UNLOAD_FAILED}, +- #else +- {"UNLOAD_FAILED", 37, 107}, +- #endif +- #ifdef DSO_R_UNSUPPORTED +- {"UNSUPPORTED", ERR_LIB_DSO, DSO_R_UNSUPPORTED}, +- #else +- {"UNSUPPORTED", 37, 108}, +- #endif +- #ifdef EC_R_ASN1_ERROR +- {"ASN1_ERROR", ERR_LIB_EC, EC_R_ASN1_ERROR}, +- #else +- {"ASN1_ERROR", 16, 115}, +- #endif +- #ifdef EC_R_BAD_SIGNATURE +- {"BAD_SIGNATURE", ERR_LIB_EC, EC_R_BAD_SIGNATURE}, +- #else +- {"BAD_SIGNATURE", 16, 156}, +- #endif +- #ifdef EC_R_BIGNUM_OUT_OF_RANGE +- {"BIGNUM_OUT_OF_RANGE", ERR_LIB_EC, EC_R_BIGNUM_OUT_OF_RANGE}, +- #else +- {"BIGNUM_OUT_OF_RANGE", 16, 144}, +- #endif +- #ifdef EC_R_BUFFER_TOO_SMALL +- {"BUFFER_TOO_SMALL", ERR_LIB_EC, EC_R_BUFFER_TOO_SMALL}, +- #else +- {"BUFFER_TOO_SMALL", 16, 100}, +- #endif +- #ifdef EC_R_CANNOT_INVERT +- {"CANNOT_INVERT", ERR_LIB_EC, EC_R_CANNOT_INVERT}, +- #else +- {"CANNOT_INVERT", 16, 165}, +- #endif +- #ifdef EC_R_COORDINATES_OUT_OF_RANGE +- {"COORDINATES_OUT_OF_RANGE", ERR_LIB_EC, EC_R_COORDINATES_OUT_OF_RANGE}, +- #else +- {"COORDINATES_OUT_OF_RANGE", 16, 146}, +- #endif +- #ifdef EC_R_CURVE_DOES_NOT_SUPPORT_ECDH +- {"CURVE_DOES_NOT_SUPPORT_ECDH", ERR_LIB_EC, EC_R_CURVE_DOES_NOT_SUPPORT_ECDH}, +- #else +- {"CURVE_DOES_NOT_SUPPORT_ECDH", 16, 160}, +- #endif +- #ifdef EC_R_CURVE_DOES_NOT_SUPPORT_ECDSA +- {"CURVE_DOES_NOT_SUPPORT_ECDSA", ERR_LIB_EC, EC_R_CURVE_DOES_NOT_SUPPORT_ECDSA}, +- #else +- {"CURVE_DOES_NOT_SUPPORT_ECDSA", 16, 170}, +- #endif +- #ifdef EC_R_CURVE_DOES_NOT_SUPPORT_SIGNING +- {"CURVE_DOES_NOT_SUPPORT_SIGNING", ERR_LIB_EC, EC_R_CURVE_DOES_NOT_SUPPORT_SIGNING}, +- #else +- {"CURVE_DOES_NOT_SUPPORT_SIGNING", 16, 159}, +- #endif +- #ifdef EC_R_DECODE_ERROR +- {"DECODE_ERROR", ERR_LIB_EC, EC_R_DECODE_ERROR}, +- #else +- {"DECODE_ERROR", 16, 142}, +- #endif +- #ifdef EC_R_DISCRIMINANT_IS_ZERO +- {"DISCRIMINANT_IS_ZERO", ERR_LIB_EC, EC_R_DISCRIMINANT_IS_ZERO}, +- #else +- {"DISCRIMINANT_IS_ZERO", 16, 118}, +- #endif +- #ifdef EC_R_EC_GROUP_NEW_BY_NAME_FAILURE +- {"EC_GROUP_NEW_BY_NAME_FAILURE", ERR_LIB_EC, EC_R_EC_GROUP_NEW_BY_NAME_FAILURE}, +- #else +- {"EC_GROUP_NEW_BY_NAME_FAILURE", 16, 119}, +- #endif +- #ifdef EC_R_EXPLICIT_PARAMS_NOT_SUPPORTED +- {"EXPLICIT_PARAMS_NOT_SUPPORTED", ERR_LIB_EC, EC_R_EXPLICIT_PARAMS_NOT_SUPPORTED}, +- #else +- {"EXPLICIT_PARAMS_NOT_SUPPORTED", 16, 127}, +- #endif +- #ifdef EC_R_FAILED_MAKING_PUBLIC_KEY +- {"FAILED_MAKING_PUBLIC_KEY", ERR_LIB_EC, EC_R_FAILED_MAKING_PUBLIC_KEY}, +- #else +- {"FAILED_MAKING_PUBLIC_KEY", 16, 166}, +- #endif +- #ifdef EC_R_FIELD_TOO_LARGE +- {"FIELD_TOO_LARGE", ERR_LIB_EC, EC_R_FIELD_TOO_LARGE}, +- #else +- {"FIELD_TOO_LARGE", 16, 143}, +- #endif +- #ifdef EC_R_GF2M_NOT_SUPPORTED +- {"GF2M_NOT_SUPPORTED", ERR_LIB_EC, EC_R_GF2M_NOT_SUPPORTED}, +- #else +- {"GF2M_NOT_SUPPORTED", 16, 147}, +- #endif +- #ifdef EC_R_GROUP2PKPARAMETERS_FAILURE +- {"GROUP2PKPARAMETERS_FAILURE", ERR_LIB_EC, EC_R_GROUP2PKPARAMETERS_FAILURE}, +- #else +- {"GROUP2PKPARAMETERS_FAILURE", 16, 120}, +- #endif +- #ifdef EC_R_I2D_ECPKPARAMETERS_FAILURE +- {"I2D_ECPKPARAMETERS_FAILURE", ERR_LIB_EC, EC_R_I2D_ECPKPARAMETERS_FAILURE}, +- #else +- {"I2D_ECPKPARAMETERS_FAILURE", 16, 121}, +- #endif +- #ifdef EC_R_INCOMPATIBLE_OBJECTS +- {"INCOMPATIBLE_OBJECTS", ERR_LIB_EC, EC_R_INCOMPATIBLE_OBJECTS}, +- #else +- {"INCOMPATIBLE_OBJECTS", 16, 101}, +- #endif +- #ifdef EC_R_INVALID_A +- {"INVALID_A", ERR_LIB_EC, EC_R_INVALID_A}, +- #else +- {"INVALID_A", 16, 168}, +- #endif +- #ifdef EC_R_INVALID_ARGUMENT +- {"INVALID_ARGUMENT", ERR_LIB_EC, EC_R_INVALID_ARGUMENT}, +- #else +- {"INVALID_ARGUMENT", 16, 112}, +- #endif +- #ifdef EC_R_INVALID_B +- {"INVALID_B", ERR_LIB_EC, EC_R_INVALID_B}, +- #else +- {"INVALID_B", 16, 169}, +- #endif +- #ifdef EC_R_INVALID_COFACTOR +- {"INVALID_COFACTOR", ERR_LIB_EC, EC_R_INVALID_COFACTOR}, +- #else +- {"INVALID_COFACTOR", 16, 171}, +- #endif +- #ifdef EC_R_INVALID_COMPRESSED_POINT +- {"INVALID_COMPRESSED_POINT", ERR_LIB_EC, EC_R_INVALID_COMPRESSED_POINT}, +- #else +- {"INVALID_COMPRESSED_POINT", 16, 110}, +- #endif +- #ifdef EC_R_INVALID_COMPRESSION_BIT +- {"INVALID_COMPRESSION_BIT", ERR_LIB_EC, EC_R_INVALID_COMPRESSION_BIT}, +- #else +- {"INVALID_COMPRESSION_BIT", 16, 109}, +- #endif +- #ifdef EC_R_INVALID_CURVE +- {"INVALID_CURVE", ERR_LIB_EC, EC_R_INVALID_CURVE}, +- #else +- {"INVALID_CURVE", 16, 141}, +- #endif +- #ifdef EC_R_INVALID_DIGEST +- {"INVALID_DIGEST", ERR_LIB_EC, EC_R_INVALID_DIGEST}, +- #else +- {"INVALID_DIGEST", 16, 151}, +- #endif +- #ifdef EC_R_INVALID_DIGEST_TYPE +- {"INVALID_DIGEST_TYPE", ERR_LIB_EC, EC_R_INVALID_DIGEST_TYPE}, +- #else +- {"INVALID_DIGEST_TYPE", 16, 138}, +- #endif +- #ifdef EC_R_INVALID_ENCODING +- {"INVALID_ENCODING", ERR_LIB_EC, EC_R_INVALID_ENCODING}, +- #else +- {"INVALID_ENCODING", 16, 102}, +- #endif +- #ifdef EC_R_INVALID_FIELD +- {"INVALID_FIELD", ERR_LIB_EC, EC_R_INVALID_FIELD}, +- #else +- {"INVALID_FIELD", 16, 103}, +- #endif +- #ifdef EC_R_INVALID_FORM +- {"INVALID_FORM", ERR_LIB_EC, EC_R_INVALID_FORM}, +- #else +- {"INVALID_FORM", 16, 104}, +- #endif +- #ifdef EC_R_INVALID_GENERATOR +- {"INVALID_GENERATOR", ERR_LIB_EC, EC_R_INVALID_GENERATOR}, +- #else +- {"INVALID_GENERATOR", 16, 173}, +- #endif +- #ifdef EC_R_INVALID_GROUP_ORDER +- {"INVALID_GROUP_ORDER", ERR_LIB_EC, EC_R_INVALID_GROUP_ORDER}, +- #else +- {"INVALID_GROUP_ORDER", 16, 122}, +- #endif +- #ifdef EC_R_INVALID_KEY +- {"INVALID_KEY", ERR_LIB_EC, EC_R_INVALID_KEY}, +- #else +- {"INVALID_KEY", 16, 116}, +- #endif +- #ifdef EC_R_INVALID_LENGTH +- {"INVALID_LENGTH", ERR_LIB_EC, EC_R_INVALID_LENGTH}, +- #else +- {"INVALID_LENGTH", 16, 117}, +- #endif +- #ifdef EC_R_INVALID_NAMED_GROUP_CONVERSION +- {"INVALID_NAMED_GROUP_CONVERSION", ERR_LIB_EC, EC_R_INVALID_NAMED_GROUP_CONVERSION}, +- #else +- {"INVALID_NAMED_GROUP_CONVERSION", 16, 174}, +- #endif +- #ifdef EC_R_INVALID_OUTPUT_LENGTH +- {"INVALID_OUTPUT_LENGTH", ERR_LIB_EC, EC_R_INVALID_OUTPUT_LENGTH}, +- #else +- {"INVALID_OUTPUT_LENGTH", 16, 161}, +- #endif +- #ifdef EC_R_INVALID_P +- {"INVALID_P", ERR_LIB_EC, EC_R_INVALID_P}, +- #else +- {"INVALID_P", 16, 172}, +- #endif +- #ifdef EC_R_INVALID_PEER_KEY +- {"INVALID_PEER_KEY", ERR_LIB_EC, EC_R_INVALID_PEER_KEY}, +- #else +- {"INVALID_PEER_KEY", 16, 133}, +- #endif +- #ifdef EC_R_INVALID_PENTANOMIAL_BASIS +- {"INVALID_PENTANOMIAL_BASIS", ERR_LIB_EC, EC_R_INVALID_PENTANOMIAL_BASIS}, +- #else +- {"INVALID_PENTANOMIAL_BASIS", 16, 132}, +- #endif +- #ifdef EC_R_INVALID_PRIVATE_KEY +- {"INVALID_PRIVATE_KEY", ERR_LIB_EC, EC_R_INVALID_PRIVATE_KEY}, +- #else +- {"INVALID_PRIVATE_KEY", 16, 123}, +- #endif +- #ifdef EC_R_INVALID_SEED +- {"INVALID_SEED", ERR_LIB_EC, EC_R_INVALID_SEED}, +- #else +- {"INVALID_SEED", 16, 175}, +- #endif +- #ifdef EC_R_INVALID_TRINOMIAL_BASIS +- {"INVALID_TRINOMIAL_BASIS", ERR_LIB_EC, EC_R_INVALID_TRINOMIAL_BASIS}, +- #else +- {"INVALID_TRINOMIAL_BASIS", 16, 137}, +- #endif +- #ifdef EC_R_KDF_PARAMETER_ERROR +- {"KDF_PARAMETER_ERROR", ERR_LIB_EC, EC_R_KDF_PARAMETER_ERROR}, +- #else +- {"KDF_PARAMETER_ERROR", 16, 148}, +- #endif +- #ifdef EC_R_KEYS_NOT_SET +- {"KEYS_NOT_SET", ERR_LIB_EC, EC_R_KEYS_NOT_SET}, +- #else +- {"KEYS_NOT_SET", 16, 140}, +- #endif +- #ifdef EC_R_LADDER_POST_FAILURE +- {"LADDER_POST_FAILURE", ERR_LIB_EC, EC_R_LADDER_POST_FAILURE}, +- #else +- {"LADDER_POST_FAILURE", 16, 136}, +- #endif +- #ifdef EC_R_LADDER_PRE_FAILURE +- {"LADDER_PRE_FAILURE", ERR_LIB_EC, EC_R_LADDER_PRE_FAILURE}, +- #else +- {"LADDER_PRE_FAILURE", 16, 153}, +- #endif +- #ifdef EC_R_LADDER_STEP_FAILURE +- {"LADDER_STEP_FAILURE", ERR_LIB_EC, EC_R_LADDER_STEP_FAILURE}, +- #else +- {"LADDER_STEP_FAILURE", 16, 162}, +- #endif +- #ifdef EC_R_MISSING_OID +- {"MISSING_OID", ERR_LIB_EC, EC_R_MISSING_OID}, +- #else +- {"MISSING_OID", 16, 167}, +- #endif +- #ifdef EC_R_MISSING_PARAMETERS +- {"MISSING_PARAMETERS", ERR_LIB_EC, EC_R_MISSING_PARAMETERS}, +- #else +- {"MISSING_PARAMETERS", 16, 124}, +- #endif +- #ifdef EC_R_MISSING_PRIVATE_KEY +- {"MISSING_PRIVATE_KEY", ERR_LIB_EC, EC_R_MISSING_PRIVATE_KEY}, +- #else +- {"MISSING_PRIVATE_KEY", 16, 125}, +- #endif +- #ifdef EC_R_NEED_NEW_SETUP_VALUES +- {"NEED_NEW_SETUP_VALUES", ERR_LIB_EC, EC_R_NEED_NEW_SETUP_VALUES}, +- #else +- {"NEED_NEW_SETUP_VALUES", 16, 157}, +- #endif +- #ifdef EC_R_NOT_A_NIST_PRIME +- {"NOT_A_NIST_PRIME", ERR_LIB_EC, EC_R_NOT_A_NIST_PRIME}, +- #else +- {"NOT_A_NIST_PRIME", 16, 135}, +- #endif +- #ifdef EC_R_NOT_IMPLEMENTED +- {"NOT_IMPLEMENTED", ERR_LIB_EC, EC_R_NOT_IMPLEMENTED}, +- #else +- {"NOT_IMPLEMENTED", 16, 126}, +- #endif +- #ifdef EC_R_NOT_INITIALIZED +- {"NOT_INITIALIZED", ERR_LIB_EC, EC_R_NOT_INITIALIZED}, +- #else +- {"NOT_INITIALIZED", 16, 111}, +- #endif +- #ifdef EC_R_NO_PARAMETERS_SET +- {"NO_PARAMETERS_SET", ERR_LIB_EC, EC_R_NO_PARAMETERS_SET}, +- #else +- {"NO_PARAMETERS_SET", 16, 139}, +- #endif +- #ifdef EC_R_NO_PRIVATE_VALUE +- {"NO_PRIVATE_VALUE", ERR_LIB_EC, EC_R_NO_PRIVATE_VALUE}, +- #else +- {"NO_PRIVATE_VALUE", 16, 154}, +- #endif +- #ifdef EC_R_OPERATION_NOT_SUPPORTED +- {"OPERATION_NOT_SUPPORTED", ERR_LIB_EC, EC_R_OPERATION_NOT_SUPPORTED}, +- #else +- {"OPERATION_NOT_SUPPORTED", 16, 152}, +- #endif +- #ifdef EC_R_PASSED_NULL_PARAMETER +- {"PASSED_NULL_PARAMETER", ERR_LIB_EC, EC_R_PASSED_NULL_PARAMETER}, +- #else +- {"PASSED_NULL_PARAMETER", 16, 134}, +- #endif +- #ifdef EC_R_PEER_KEY_ERROR +- {"PEER_KEY_ERROR", ERR_LIB_EC, EC_R_PEER_KEY_ERROR}, +- #else +- {"PEER_KEY_ERROR", 16, 149}, +- #endif +- #ifdef EC_R_POINT_ARITHMETIC_FAILURE +- {"POINT_ARITHMETIC_FAILURE", ERR_LIB_EC, EC_R_POINT_ARITHMETIC_FAILURE}, +- #else +- {"POINT_ARITHMETIC_FAILURE", 16, 155}, +- #endif +- #ifdef EC_R_POINT_AT_INFINITY +- {"POINT_AT_INFINITY", ERR_LIB_EC, EC_R_POINT_AT_INFINITY}, +- #else +- {"POINT_AT_INFINITY", 16, 106}, +- #endif +- #ifdef EC_R_POINT_COORDINATES_BLIND_FAILURE +- {"POINT_COORDINATES_BLIND_FAILURE", ERR_LIB_EC, EC_R_POINT_COORDINATES_BLIND_FAILURE}, +- #else +- {"POINT_COORDINATES_BLIND_FAILURE", 16, 163}, +- #endif +- #ifdef EC_R_POINT_IS_NOT_ON_CURVE +- {"POINT_IS_NOT_ON_CURVE", ERR_LIB_EC, EC_R_POINT_IS_NOT_ON_CURVE}, +- #else +- {"POINT_IS_NOT_ON_CURVE", 16, 107}, +- #endif +- #ifdef EC_R_RANDOM_NUMBER_GENERATION_FAILED +- {"RANDOM_NUMBER_GENERATION_FAILED", ERR_LIB_EC, EC_R_RANDOM_NUMBER_GENERATION_FAILED}, +- #else +- {"RANDOM_NUMBER_GENERATION_FAILED", 16, 158}, +- #endif +- #ifdef EC_R_SHARED_INFO_ERROR +- {"SHARED_INFO_ERROR", ERR_LIB_EC, EC_R_SHARED_INFO_ERROR}, +- #else +- {"SHARED_INFO_ERROR", 16, 150}, +- #endif +- #ifdef EC_R_SLOT_FULL +- {"SLOT_FULL", ERR_LIB_EC, EC_R_SLOT_FULL}, +- #else +- {"SLOT_FULL", 16, 108}, +- #endif +- #ifdef EC_R_TOO_MANY_RETRIES +- {"TOO_MANY_RETRIES", ERR_LIB_EC, EC_R_TOO_MANY_RETRIES}, +- #else +- {"TOO_MANY_RETRIES", 16, 176}, +- #endif +- #ifdef EC_R_UNDEFINED_GENERATOR +- {"UNDEFINED_GENERATOR", ERR_LIB_EC, EC_R_UNDEFINED_GENERATOR}, +- #else +- {"UNDEFINED_GENERATOR", 16, 113}, +- #endif +- #ifdef EC_R_UNDEFINED_ORDER +- {"UNDEFINED_ORDER", ERR_LIB_EC, EC_R_UNDEFINED_ORDER}, +- #else +- {"UNDEFINED_ORDER", 16, 128}, +- #endif +- #ifdef EC_R_UNKNOWN_COFACTOR +- {"UNKNOWN_COFACTOR", ERR_LIB_EC, EC_R_UNKNOWN_COFACTOR}, +- #else +- {"UNKNOWN_COFACTOR", 16, 164}, +- #endif +- #ifdef EC_R_UNKNOWN_GROUP +- {"UNKNOWN_GROUP", ERR_LIB_EC, EC_R_UNKNOWN_GROUP}, +- #else +- {"UNKNOWN_GROUP", 16, 129}, +- #endif +- #ifdef EC_R_UNKNOWN_ORDER +- {"UNKNOWN_ORDER", ERR_LIB_EC, EC_R_UNKNOWN_ORDER}, +- #else +- {"UNKNOWN_ORDER", 16, 114}, +- #endif +- #ifdef EC_R_UNSUPPORTED_FIELD +- {"UNSUPPORTED_FIELD", ERR_LIB_EC, EC_R_UNSUPPORTED_FIELD}, +- #else +- {"UNSUPPORTED_FIELD", 16, 131}, +- #endif +- #ifdef EC_R_WRONG_CURVE_PARAMETERS +- {"WRONG_CURVE_PARAMETERS", ERR_LIB_EC, EC_R_WRONG_CURVE_PARAMETERS}, +- #else +- {"WRONG_CURVE_PARAMETERS", 16, 145}, +- #endif +- #ifdef EC_R_WRONG_ORDER +- {"WRONG_ORDER", ERR_LIB_EC, EC_R_WRONG_ORDER}, +- #else +- {"WRONG_ORDER", 16, 130}, +- #endif +- #ifdef ENGINE_R_ALREADY_LOADED +- {"ALREADY_LOADED", ERR_LIB_ENGINE, ENGINE_R_ALREADY_LOADED}, +- #else +- {"ALREADY_LOADED", 38, 100}, +- #endif +- #ifdef ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER +- {"ARGUMENT_IS_NOT_A_NUMBER", ERR_LIB_ENGINE, ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER}, +- #else +- {"ARGUMENT_IS_NOT_A_NUMBER", 38, 133}, +- #endif +- #ifdef ENGINE_R_CMD_NOT_EXECUTABLE +- {"CMD_NOT_EXECUTABLE", ERR_LIB_ENGINE, ENGINE_R_CMD_NOT_EXECUTABLE}, +- #else +- {"CMD_NOT_EXECUTABLE", 38, 134}, +- #endif +- #ifdef ENGINE_R_COMMAND_TAKES_INPUT +- {"COMMAND_TAKES_INPUT", ERR_LIB_ENGINE, ENGINE_R_COMMAND_TAKES_INPUT}, +- #else +- {"COMMAND_TAKES_INPUT", 38, 135}, +- #endif +- #ifdef ENGINE_R_COMMAND_TAKES_NO_INPUT +- {"COMMAND_TAKES_NO_INPUT", ERR_LIB_ENGINE, ENGINE_R_COMMAND_TAKES_NO_INPUT}, +- #else +- {"COMMAND_TAKES_NO_INPUT", 38, 136}, +- #endif +- #ifdef ENGINE_R_CONFLICTING_ENGINE_ID +- {"CONFLICTING_ENGINE_ID", ERR_LIB_ENGINE, ENGINE_R_CONFLICTING_ENGINE_ID}, +- #else +- {"CONFLICTING_ENGINE_ID", 38, 103}, +- #endif +- #ifdef ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED +- {"CTRL_COMMAND_NOT_IMPLEMENTED", ERR_LIB_ENGINE, ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED}, +- #else +- {"CTRL_COMMAND_NOT_IMPLEMENTED", 38, 119}, +- #endif +- #ifdef ENGINE_R_DSO_FAILURE +- {"DSO_FAILURE", ERR_LIB_ENGINE, ENGINE_R_DSO_FAILURE}, +- #else +- {"DSO_FAILURE", 38, 104}, +- #endif +- #ifdef ENGINE_R_DSO_NOT_FOUND +- {"DSO_NOT_FOUND", ERR_LIB_ENGINE, ENGINE_R_DSO_NOT_FOUND}, +- #else +- {"DSO_NOT_FOUND", 38, 132}, +- #endif +- #ifdef ENGINE_R_ENGINES_SECTION_ERROR +- {"ENGINES_SECTION_ERROR", ERR_LIB_ENGINE, ENGINE_R_ENGINES_SECTION_ERROR}, +- #else +- {"ENGINES_SECTION_ERROR", 38, 148}, +- #endif +- #ifdef ENGINE_R_ENGINE_CONFIGURATION_ERROR +- {"ENGINE_CONFIGURATION_ERROR", ERR_LIB_ENGINE, ENGINE_R_ENGINE_CONFIGURATION_ERROR}, +- #else +- {"ENGINE_CONFIGURATION_ERROR", 38, 102}, +- #endif +- #ifdef ENGINE_R_ENGINE_IS_NOT_IN_LIST +- {"ENGINE_IS_NOT_IN_LIST", ERR_LIB_ENGINE, ENGINE_R_ENGINE_IS_NOT_IN_LIST}, +- #else +- {"ENGINE_IS_NOT_IN_LIST", 38, 105}, +- #endif +- #ifdef ENGINE_R_ENGINE_SECTION_ERROR +- {"ENGINE_SECTION_ERROR", ERR_LIB_ENGINE, ENGINE_R_ENGINE_SECTION_ERROR}, +- #else +- {"ENGINE_SECTION_ERROR", 38, 149}, +- #endif +- #ifdef ENGINE_R_FAILED_LOADING_PRIVATE_KEY +- {"FAILED_LOADING_PRIVATE_KEY", ERR_LIB_ENGINE, ENGINE_R_FAILED_LOADING_PRIVATE_KEY}, +- #else +- {"FAILED_LOADING_PRIVATE_KEY", 38, 128}, +- #endif +- #ifdef ENGINE_R_FAILED_LOADING_PUBLIC_KEY +- {"FAILED_LOADING_PUBLIC_KEY", ERR_LIB_ENGINE, ENGINE_R_FAILED_LOADING_PUBLIC_KEY}, +- #else +- {"FAILED_LOADING_PUBLIC_KEY", 38, 129}, +- #endif +- #ifdef ENGINE_R_FINISH_FAILED +- {"FINISH_FAILED", ERR_LIB_ENGINE, ENGINE_R_FINISH_FAILED}, +- #else +- {"FINISH_FAILED", 38, 106}, +- #endif +- #ifdef ENGINE_R_ID_OR_NAME_MISSING +- {"ID_OR_NAME_MISSING", ERR_LIB_ENGINE, ENGINE_R_ID_OR_NAME_MISSING}, +- #else +- {"ID_OR_NAME_MISSING", 38, 108}, +- #endif +- #ifdef ENGINE_R_INIT_FAILED +- {"INIT_FAILED", ERR_LIB_ENGINE, ENGINE_R_INIT_FAILED}, +- #else +- {"INIT_FAILED", 38, 109}, +- #endif +- #ifdef ENGINE_R_INTERNAL_LIST_ERROR +- {"INTERNAL_LIST_ERROR", ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR}, +- #else +- {"INTERNAL_LIST_ERROR", 38, 110}, +- #endif +- #ifdef ENGINE_R_INVALID_ARGUMENT +- {"INVALID_ARGUMENT", ERR_LIB_ENGINE, ENGINE_R_INVALID_ARGUMENT}, +- #else +- {"INVALID_ARGUMENT", 38, 143}, +- #endif +- #ifdef ENGINE_R_INVALID_CMD_NAME +- {"INVALID_CMD_NAME", ERR_LIB_ENGINE, ENGINE_R_INVALID_CMD_NAME}, +- #else +- {"INVALID_CMD_NAME", 38, 137}, +- #endif +- #ifdef ENGINE_R_INVALID_CMD_NUMBER +- {"INVALID_CMD_NUMBER", ERR_LIB_ENGINE, ENGINE_R_INVALID_CMD_NUMBER}, +- #else +- {"INVALID_CMD_NUMBER", 38, 138}, +- #endif +- #ifdef ENGINE_R_INVALID_INIT_VALUE +- {"INVALID_INIT_VALUE", ERR_LIB_ENGINE, ENGINE_R_INVALID_INIT_VALUE}, +- #else +- {"INVALID_INIT_VALUE", 38, 151}, +- #endif +- #ifdef ENGINE_R_INVALID_STRING +- {"INVALID_STRING", ERR_LIB_ENGINE, ENGINE_R_INVALID_STRING}, +- #else +- {"INVALID_STRING", 38, 150}, +- #endif +- #ifdef ENGINE_R_NOT_INITIALISED +- {"NOT_INITIALISED", ERR_LIB_ENGINE, ENGINE_R_NOT_INITIALISED}, +- #else +- {"NOT_INITIALISED", 38, 117}, +- #endif +- #ifdef ENGINE_R_NOT_LOADED +- {"NOT_LOADED", ERR_LIB_ENGINE, ENGINE_R_NOT_LOADED}, +- #else +- {"NOT_LOADED", 38, 112}, +- #endif +- #ifdef ENGINE_R_NO_CONTROL_FUNCTION +- {"NO_CONTROL_FUNCTION", ERR_LIB_ENGINE, ENGINE_R_NO_CONTROL_FUNCTION}, +- #else +- {"NO_CONTROL_FUNCTION", 38, 120}, +- #endif +- #ifdef ENGINE_R_NO_INDEX +- {"NO_INDEX", ERR_LIB_ENGINE, ENGINE_R_NO_INDEX}, +- #else +- {"NO_INDEX", 38, 144}, +- #endif +- #ifdef ENGINE_R_NO_LOAD_FUNCTION +- {"NO_LOAD_FUNCTION", ERR_LIB_ENGINE, ENGINE_R_NO_LOAD_FUNCTION}, +- #else +- {"NO_LOAD_FUNCTION", 38, 125}, +- #endif +- #ifdef ENGINE_R_NO_REFERENCE +- {"NO_REFERENCE", ERR_LIB_ENGINE, ENGINE_R_NO_REFERENCE}, +- #else +- {"NO_REFERENCE", 38, 130}, +- #endif +- #ifdef ENGINE_R_NO_SUCH_ENGINE +- {"NO_SUCH_ENGINE", ERR_LIB_ENGINE, ENGINE_R_NO_SUCH_ENGINE}, +- #else +- {"NO_SUCH_ENGINE", 38, 116}, +- #endif +- #ifdef ENGINE_R_UNIMPLEMENTED_CIPHER +- {"UNIMPLEMENTED_CIPHER", ERR_LIB_ENGINE, ENGINE_R_UNIMPLEMENTED_CIPHER}, +- #else +- {"UNIMPLEMENTED_CIPHER", 38, 146}, +- #endif +- #ifdef ENGINE_R_UNIMPLEMENTED_DIGEST +- {"UNIMPLEMENTED_DIGEST", ERR_LIB_ENGINE, ENGINE_R_UNIMPLEMENTED_DIGEST}, +- #else +- {"UNIMPLEMENTED_DIGEST", 38, 147}, +- #endif +- #ifdef ENGINE_R_UNIMPLEMENTED_PUBLIC_KEY_METHOD +- {"UNIMPLEMENTED_PUBLIC_KEY_METHOD", ERR_LIB_ENGINE, ENGINE_R_UNIMPLEMENTED_PUBLIC_KEY_METHOD}, +- #else +- {"UNIMPLEMENTED_PUBLIC_KEY_METHOD", 38, 101}, +- #endif +- #ifdef ENGINE_R_VERSION_INCOMPATIBILITY +- {"VERSION_INCOMPATIBILITY", ERR_LIB_ENGINE, ENGINE_R_VERSION_INCOMPATIBILITY}, +- #else +- {"VERSION_INCOMPATIBILITY", 38, 145}, +- #endif +- #ifdef ESS_R_EMPTY_ESS_CERT_ID_LIST +- {"EMPTY_ESS_CERT_ID_LIST", ERR_LIB_ESS, ESS_R_EMPTY_ESS_CERT_ID_LIST}, +- #else +- {"EMPTY_ESS_CERT_ID_LIST", 54, 107}, +- #endif +- #ifdef ESS_R_ESS_CERT_DIGEST_ERROR +- {"ESS_CERT_DIGEST_ERROR", ERR_LIB_ESS, ESS_R_ESS_CERT_DIGEST_ERROR}, +- #else +- {"ESS_CERT_DIGEST_ERROR", 54, 103}, +- #endif +- #ifdef ESS_R_ESS_CERT_ID_NOT_FOUND +- {"ESS_CERT_ID_NOT_FOUND", ERR_LIB_ESS, ESS_R_ESS_CERT_ID_NOT_FOUND}, +- #else +- {"ESS_CERT_ID_NOT_FOUND", 54, 104}, +- #endif +- #ifdef ESS_R_ESS_CERT_ID_WRONG_ORDER +- {"ESS_CERT_ID_WRONG_ORDER", ERR_LIB_ESS, ESS_R_ESS_CERT_ID_WRONG_ORDER}, +- #else +- {"ESS_CERT_ID_WRONG_ORDER", 54, 105}, +- #endif +- #ifdef ESS_R_ESS_DIGEST_ALG_UNKNOWN +- {"ESS_DIGEST_ALG_UNKNOWN", ERR_LIB_ESS, ESS_R_ESS_DIGEST_ALG_UNKNOWN}, +- #else +- {"ESS_DIGEST_ALG_UNKNOWN", 54, 106}, +- #endif +- #ifdef ESS_R_ESS_SIGNING_CERTIFICATE_ERROR +- {"ESS_SIGNING_CERTIFICATE_ERROR", ERR_LIB_ESS, ESS_R_ESS_SIGNING_CERTIFICATE_ERROR}, +- #else +- {"ESS_SIGNING_CERTIFICATE_ERROR", 54, 102}, +- #endif +- #ifdef ESS_R_ESS_SIGNING_CERT_ADD_ERROR +- {"ESS_SIGNING_CERT_ADD_ERROR", ERR_LIB_ESS, ESS_R_ESS_SIGNING_CERT_ADD_ERROR}, +- #else +- {"ESS_SIGNING_CERT_ADD_ERROR", 54, 100}, +- #endif +- #ifdef ESS_R_ESS_SIGNING_CERT_V2_ADD_ERROR +- {"ESS_SIGNING_CERT_V2_ADD_ERROR", ERR_LIB_ESS, ESS_R_ESS_SIGNING_CERT_V2_ADD_ERROR}, +- #else +- {"ESS_SIGNING_CERT_V2_ADD_ERROR", 54, 101}, +- #endif +- #ifdef ESS_R_MISSING_SIGNING_CERTIFICATE_ATTRIBUTE +- {"MISSING_SIGNING_CERTIFICATE_ATTRIBUTE", ERR_LIB_ESS, ESS_R_MISSING_SIGNING_CERTIFICATE_ATTRIBUTE}, +- #else +- {"MISSING_SIGNING_CERTIFICATE_ATTRIBUTE", 54, 108}, +- #endif +- #ifdef EVP_R_AES_KEY_SETUP_FAILED +- {"AES_KEY_SETUP_FAILED", ERR_LIB_EVP, EVP_R_AES_KEY_SETUP_FAILED}, +- #else +- {"AES_KEY_SETUP_FAILED", 6, 143}, +- #endif +- #ifdef EVP_R_ARIA_KEY_SETUP_FAILED +- {"ARIA_KEY_SETUP_FAILED", ERR_LIB_EVP, EVP_R_ARIA_KEY_SETUP_FAILED}, +- #else +- {"ARIA_KEY_SETUP_FAILED", 6, 176}, +- #endif +- #ifdef EVP_R_BAD_ALGORITHM_NAME +- {"BAD_ALGORITHM_NAME", ERR_LIB_EVP, EVP_R_BAD_ALGORITHM_NAME}, +- #else +- {"BAD_ALGORITHM_NAME", 6, 200}, +- #endif +- #ifdef EVP_R_BAD_DECRYPT +- {"BAD_DECRYPT", ERR_LIB_EVP, EVP_R_BAD_DECRYPT}, +- #else +- {"BAD_DECRYPT", 6, 100}, +- #endif +- #ifdef EVP_R_BAD_KEY_LENGTH +- {"BAD_KEY_LENGTH", ERR_LIB_EVP, EVP_R_BAD_KEY_LENGTH}, +- #else +- {"BAD_KEY_LENGTH", 6, 195}, +- #endif +- #ifdef EVP_R_BUFFER_TOO_SMALL +- {"BUFFER_TOO_SMALL", ERR_LIB_EVP, EVP_R_BUFFER_TOO_SMALL}, +- #else +- {"BUFFER_TOO_SMALL", 6, 155}, +- #endif +- #ifdef EVP_R_CACHE_CONSTANTS_FAILED +- {"CACHE_CONSTANTS_FAILED", ERR_LIB_EVP, EVP_R_CACHE_CONSTANTS_FAILED}, +- #else +- {"CACHE_CONSTANTS_FAILED", 6, 225}, +- #endif +- #ifdef EVP_R_CAMELLIA_KEY_SETUP_FAILED +- {"CAMELLIA_KEY_SETUP_FAILED", ERR_LIB_EVP, EVP_R_CAMELLIA_KEY_SETUP_FAILED}, +- #else +- {"CAMELLIA_KEY_SETUP_FAILED", 6, 157}, +- #endif +- #ifdef EVP_R_CANNOT_GET_PARAMETERS +- {"CANNOT_GET_PARAMETERS", ERR_LIB_EVP, EVP_R_CANNOT_GET_PARAMETERS}, +- #else +- {"CANNOT_GET_PARAMETERS", 6, 197}, +- #endif +- #ifdef EVP_R_CANNOT_SET_PARAMETERS +- {"CANNOT_SET_PARAMETERS", ERR_LIB_EVP, EVP_R_CANNOT_SET_PARAMETERS}, +- #else +- {"CANNOT_SET_PARAMETERS", 6, 198}, +- #endif +- #ifdef EVP_R_CIPHER_NOT_GCM_MODE +- {"CIPHER_NOT_GCM_MODE", ERR_LIB_EVP, EVP_R_CIPHER_NOT_GCM_MODE}, +- #else +- {"CIPHER_NOT_GCM_MODE", 6, 184}, +- #endif +- #ifdef EVP_R_CIPHER_PARAMETER_ERROR +- {"CIPHER_PARAMETER_ERROR", ERR_LIB_EVP, EVP_R_CIPHER_PARAMETER_ERROR}, +- #else +- {"CIPHER_PARAMETER_ERROR", 6, 122}, +- #endif +- #ifdef EVP_R_COMMAND_NOT_SUPPORTED +- {"COMMAND_NOT_SUPPORTED", ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED}, +- #else +- {"COMMAND_NOT_SUPPORTED", 6, 147}, +- #endif +- #ifdef EVP_R_CONFLICTING_ALGORITHM_NAME +- {"CONFLICTING_ALGORITHM_NAME", ERR_LIB_EVP, EVP_R_CONFLICTING_ALGORITHM_NAME}, +- #else +- {"CONFLICTING_ALGORITHM_NAME", 6, 201}, +- #endif +- #ifdef EVP_R_COPY_ERROR +- {"COPY_ERROR", ERR_LIB_EVP, EVP_R_COPY_ERROR}, +- #else +- {"COPY_ERROR", 6, 173}, +- #endif +- #ifdef EVP_R_CTRL_NOT_IMPLEMENTED +- {"CTRL_NOT_IMPLEMENTED", ERR_LIB_EVP, EVP_R_CTRL_NOT_IMPLEMENTED}, +- #else +- {"CTRL_NOT_IMPLEMENTED", 6, 132}, +- #endif +- #ifdef EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED +- {"CTRL_OPERATION_NOT_IMPLEMENTED", ERR_LIB_EVP, EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED}, +- #else +- {"CTRL_OPERATION_NOT_IMPLEMENTED", 6, 133}, +- #endif +- #ifdef EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH +- {"DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH", ERR_LIB_EVP, EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH}, +- #else +- {"DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH", 6, 138}, +- #endif +- #ifdef EVP_R_DECODE_ERROR +- {"DECODE_ERROR", ERR_LIB_EVP, EVP_R_DECODE_ERROR}, +- #else +- {"DECODE_ERROR", 6, 114}, +- #endif +- #ifdef EVP_R_DEFAULT_QUERY_PARSE_ERROR +- {"DEFAULT_QUERY_PARSE_ERROR", ERR_LIB_EVP, EVP_R_DEFAULT_QUERY_PARSE_ERROR}, +- #else +- {"DEFAULT_QUERY_PARSE_ERROR", 6, 210}, +- #endif +- #ifdef EVP_R_DIFFERENT_KEY_TYPES +- {"DIFFERENT_KEY_TYPES", ERR_LIB_EVP, EVP_R_DIFFERENT_KEY_TYPES}, +- #else +- {"DIFFERENT_KEY_TYPES", 6, 101}, +- #endif +- #ifdef EVP_R_DIFFERENT_PARAMETERS +- {"DIFFERENT_PARAMETERS", ERR_LIB_EVP, EVP_R_DIFFERENT_PARAMETERS}, +- #else +- {"DIFFERENT_PARAMETERS", 6, 153}, +- #endif +- #ifdef EVP_R_ERROR_LOADING_SECTION +- {"ERROR_LOADING_SECTION", ERR_LIB_EVP, EVP_R_ERROR_LOADING_SECTION}, +- #else +- {"ERROR_LOADING_SECTION", 6, 165}, +- #endif +- #ifdef EVP_R_EXPECTING_AN_HMAC_KEY +- {"EXPECTING_AN_HMAC_KEY", ERR_LIB_EVP, EVP_R_EXPECTING_AN_HMAC_KEY}, +- #else +- {"EXPECTING_AN_HMAC_KEY", 6, 174}, +- #endif +- #ifdef EVP_R_EXPECTING_AN_RSA_KEY +- {"EXPECTING_AN_RSA_KEY", ERR_LIB_EVP, EVP_R_EXPECTING_AN_RSA_KEY}, +- #else +- {"EXPECTING_AN_RSA_KEY", 6, 127}, +- #endif +- #ifdef EVP_R_EXPECTING_A_DH_KEY +- {"EXPECTING_A_DH_KEY", ERR_LIB_EVP, EVP_R_EXPECTING_A_DH_KEY}, +- #else +- {"EXPECTING_A_DH_KEY", 6, 128}, +- #endif +- #ifdef EVP_R_EXPECTING_A_DSA_KEY +- {"EXPECTING_A_DSA_KEY", ERR_LIB_EVP, EVP_R_EXPECTING_A_DSA_KEY}, +- #else +- {"EXPECTING_A_DSA_KEY", 6, 129}, +- #endif +- #ifdef EVP_R_EXPECTING_A_ECX_KEY +- {"EXPECTING_A_ECX_KEY", ERR_LIB_EVP, EVP_R_EXPECTING_A_ECX_KEY}, +- #else +- {"EXPECTING_A_ECX_KEY", 6, 219}, +- #endif +- #ifdef EVP_R_EXPECTING_A_EC_KEY +- {"EXPECTING_A_EC_KEY", ERR_LIB_EVP, EVP_R_EXPECTING_A_EC_KEY}, +- #else +- {"EXPECTING_A_EC_KEY", 6, 142}, +- #endif +- #ifdef EVP_R_EXPECTING_A_POLY1305_KEY +- {"EXPECTING_A_POLY1305_KEY", ERR_LIB_EVP, EVP_R_EXPECTING_A_POLY1305_KEY}, +- #else +- {"EXPECTING_A_POLY1305_KEY", 6, 164}, +- #endif +- #ifdef EVP_R_EXPECTING_A_SIPHASH_KEY +- {"EXPECTING_A_SIPHASH_KEY", ERR_LIB_EVP, EVP_R_EXPECTING_A_SIPHASH_KEY}, +- #else +- {"EXPECTING_A_SIPHASH_KEY", 6, 175}, +- #endif +- #ifdef EVP_R_FINAL_ERROR +- {"FINAL_ERROR", ERR_LIB_EVP, EVP_R_FINAL_ERROR}, +- #else +- {"FINAL_ERROR", 6, 188}, +- #endif +- #ifdef EVP_R_GENERATE_ERROR +- {"GENERATE_ERROR", ERR_LIB_EVP, EVP_R_GENERATE_ERROR}, +- #else +- {"GENERATE_ERROR", 6, 214}, +- #endif +- #ifdef EVP_R_GET_RAW_KEY_FAILED +- {"GET_RAW_KEY_FAILED", ERR_LIB_EVP, EVP_R_GET_RAW_KEY_FAILED}, +- #else +- {"GET_RAW_KEY_FAILED", 6, 182}, +- #endif +- #ifdef EVP_R_ILLEGAL_SCRYPT_PARAMETERS +- {"ILLEGAL_SCRYPT_PARAMETERS", ERR_LIB_EVP, EVP_R_ILLEGAL_SCRYPT_PARAMETERS}, +- #else +- {"ILLEGAL_SCRYPT_PARAMETERS", 6, 171}, +- #endif +- #ifdef EVP_R_INACCESSIBLE_DOMAIN_PARAMETERS +- {"INACCESSIBLE_DOMAIN_PARAMETERS", ERR_LIB_EVP, EVP_R_INACCESSIBLE_DOMAIN_PARAMETERS}, +- #else +- {"INACCESSIBLE_DOMAIN_PARAMETERS", 6, 204}, +- #endif +- #ifdef EVP_R_INACCESSIBLE_KEY +- {"INACCESSIBLE_KEY", ERR_LIB_EVP, EVP_R_INACCESSIBLE_KEY}, +- #else +- {"INACCESSIBLE_KEY", 6, 203}, +- #endif +- #ifdef EVP_R_INITIALIZATION_ERROR +- {"INITIALIZATION_ERROR", ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR}, +- #else +- {"INITIALIZATION_ERROR", 6, 134}, +- #endif +- #ifdef EVP_R_INPUT_NOT_INITIALIZED +- {"INPUT_NOT_INITIALIZED", ERR_LIB_EVP, EVP_R_INPUT_NOT_INITIALIZED}, +- #else +- {"INPUT_NOT_INITIALIZED", 6, 111}, +- #endif +- #ifdef EVP_R_INVALID_CUSTOM_LENGTH +- {"INVALID_CUSTOM_LENGTH", ERR_LIB_EVP, EVP_R_INVALID_CUSTOM_LENGTH}, +- #else +- {"INVALID_CUSTOM_LENGTH", 6, 185}, +- #endif +- #ifdef EVP_R_INVALID_DIGEST +- {"INVALID_DIGEST", ERR_LIB_EVP, EVP_R_INVALID_DIGEST}, +- #else +- {"INVALID_DIGEST", 6, 152}, +- #endif +- #ifdef EVP_R_INVALID_IV_LENGTH +- {"INVALID_IV_LENGTH", ERR_LIB_EVP, EVP_R_INVALID_IV_LENGTH}, +- #else +- {"INVALID_IV_LENGTH", 6, 194}, +- #endif +- #ifdef EVP_R_INVALID_KEY +- {"INVALID_KEY", ERR_LIB_EVP, EVP_R_INVALID_KEY}, +- #else +- {"INVALID_KEY", 6, 163}, +- #endif +- #ifdef EVP_R_INVALID_KEY_LENGTH +- {"INVALID_KEY_LENGTH", ERR_LIB_EVP, EVP_R_INVALID_KEY_LENGTH}, +- #else +- {"INVALID_KEY_LENGTH", 6, 130}, +- #endif +- #ifdef EVP_R_INVALID_LENGTH +- {"INVALID_LENGTH", ERR_LIB_EVP, EVP_R_INVALID_LENGTH}, +- #else +- {"INVALID_LENGTH", 6, 221}, +- #endif +- #ifdef EVP_R_INVALID_NULL_ALGORITHM +- {"INVALID_NULL_ALGORITHM", ERR_LIB_EVP, EVP_R_INVALID_NULL_ALGORITHM}, +- #else +- {"INVALID_NULL_ALGORITHM", 6, 218}, +- #endif +- #ifdef EVP_R_INVALID_OPERATION +- {"INVALID_OPERATION", ERR_LIB_EVP, EVP_R_INVALID_OPERATION}, +- #else +- {"INVALID_OPERATION", 6, 148}, +- #endif +- #ifdef EVP_R_INVALID_PROVIDER_FUNCTIONS +- {"INVALID_PROVIDER_FUNCTIONS", ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS}, +- #else +- {"INVALID_PROVIDER_FUNCTIONS", 6, 193}, +- #endif +- #ifdef EVP_R_INVALID_SALT_LENGTH +- {"INVALID_SALT_LENGTH", ERR_LIB_EVP, EVP_R_INVALID_SALT_LENGTH}, +- #else +- {"INVALID_SALT_LENGTH", 6, 186}, +- #endif +- #ifdef EVP_R_INVALID_SECRET_LENGTH +- {"INVALID_SECRET_LENGTH", ERR_LIB_EVP, EVP_R_INVALID_SECRET_LENGTH}, +- #else +- {"INVALID_SECRET_LENGTH", 6, 223}, +- #endif +- #ifdef EVP_R_INVALID_SEED_LENGTH +- {"INVALID_SEED_LENGTH", ERR_LIB_EVP, EVP_R_INVALID_SEED_LENGTH}, +- #else +- {"INVALID_SEED_LENGTH", 6, 220}, +- #endif +- #ifdef EVP_R_INVALID_VALUE +- {"INVALID_VALUE", ERR_LIB_EVP, EVP_R_INVALID_VALUE}, +- #else +- {"INVALID_VALUE", 6, 222}, +- #endif +- #ifdef EVP_R_KEYMGMT_EXPORT_FAILURE +- {"KEYMGMT_EXPORT_FAILURE", ERR_LIB_EVP, EVP_R_KEYMGMT_EXPORT_FAILURE}, +- #else +- {"KEYMGMT_EXPORT_FAILURE", 6, 205}, +- #endif +- #ifdef EVP_R_KEY_SETUP_FAILED +- {"KEY_SETUP_FAILED", ERR_LIB_EVP, EVP_R_KEY_SETUP_FAILED}, +- #else +- {"KEY_SETUP_FAILED", 6, 180}, +- #endif +- #ifdef EVP_R_LOCKING_NOT_SUPPORTED +- {"LOCKING_NOT_SUPPORTED", ERR_LIB_EVP, EVP_R_LOCKING_NOT_SUPPORTED}, +- #else +- {"LOCKING_NOT_SUPPORTED", 6, 213}, +- #endif +- #ifdef EVP_R_MEMORY_LIMIT_EXCEEDED +- {"MEMORY_LIMIT_EXCEEDED", ERR_LIB_EVP, EVP_R_MEMORY_LIMIT_EXCEEDED}, +- #else +- {"MEMORY_LIMIT_EXCEEDED", 6, 172}, +- #endif +- #ifdef EVP_R_MESSAGE_DIGEST_IS_NULL +- {"MESSAGE_DIGEST_IS_NULL", ERR_LIB_EVP, EVP_R_MESSAGE_DIGEST_IS_NULL}, +- #else +- {"MESSAGE_DIGEST_IS_NULL", 6, 159}, +- #endif +- #ifdef EVP_R_METHOD_NOT_SUPPORTED +- {"METHOD_NOT_SUPPORTED", ERR_LIB_EVP, EVP_R_METHOD_NOT_SUPPORTED}, +- #else +- {"METHOD_NOT_SUPPORTED", 6, 144}, +- #endif +- #ifdef EVP_R_MISSING_PARAMETERS +- {"MISSING_PARAMETERS", ERR_LIB_EVP, EVP_R_MISSING_PARAMETERS}, +- #else +- {"MISSING_PARAMETERS", 6, 103}, +- #endif +- #ifdef EVP_R_NOT_ABLE_TO_COPY_CTX +- {"NOT_ABLE_TO_COPY_CTX", ERR_LIB_EVP, EVP_R_NOT_ABLE_TO_COPY_CTX}, +- #else +- {"NOT_ABLE_TO_COPY_CTX", 6, 190}, +- #endif +- #ifdef EVP_R_NOT_XOF_OR_INVALID_LENGTH +- {"NOT_XOF_OR_INVALID_LENGTH", ERR_LIB_EVP, EVP_R_NOT_XOF_OR_INVALID_LENGTH}, +- #else +- {"NOT_XOF_OR_INVALID_LENGTH", 6, 178}, +- #endif +- #ifdef EVP_R_NO_CIPHER_SET +- {"NO_CIPHER_SET", ERR_LIB_EVP, EVP_R_NO_CIPHER_SET}, +- #else +- {"NO_CIPHER_SET", 6, 131}, +- #endif +- #ifdef EVP_R_NO_DEFAULT_DIGEST +- {"NO_DEFAULT_DIGEST", ERR_LIB_EVP, EVP_R_NO_DEFAULT_DIGEST}, +- #else +- {"NO_DEFAULT_DIGEST", 6, 158}, +- #endif +- #ifdef EVP_R_NO_DIGEST_SET +- {"NO_DIGEST_SET", ERR_LIB_EVP, EVP_R_NO_DIGEST_SET}, +- #else +- {"NO_DIGEST_SET", 6, 139}, +- #endif +- #ifdef EVP_R_NO_IMPORT_FUNCTION +- {"NO_IMPORT_FUNCTION", ERR_LIB_EVP, EVP_R_NO_IMPORT_FUNCTION}, +- #else +- {"NO_IMPORT_FUNCTION", 6, 206}, +- #endif +- #ifdef EVP_R_NO_KEYMGMT_AVAILABLE +- {"NO_KEYMGMT_AVAILABLE", ERR_LIB_EVP, EVP_R_NO_KEYMGMT_AVAILABLE}, +- #else +- {"NO_KEYMGMT_AVAILABLE", 6, 199}, +- #endif +- #ifdef EVP_R_NO_KEYMGMT_PRESENT +- {"NO_KEYMGMT_PRESENT", ERR_LIB_EVP, EVP_R_NO_KEYMGMT_PRESENT}, +- #else +- {"NO_KEYMGMT_PRESENT", 6, 196}, +- #endif +- #ifdef EVP_R_NO_KEY_SET +- {"NO_KEY_SET", ERR_LIB_EVP, EVP_R_NO_KEY_SET}, +- #else +- {"NO_KEY_SET", 6, 154}, +- #endif +- #ifdef EVP_R_NO_OPERATION_SET +- {"NO_OPERATION_SET", ERR_LIB_EVP, EVP_R_NO_OPERATION_SET}, +- #else +- {"NO_OPERATION_SET", 6, 149}, +- #endif +- #ifdef EVP_R_NULL_MAC_PKEY_CTX +- {"NULL_MAC_PKEY_CTX", ERR_LIB_EVP, EVP_R_NULL_MAC_PKEY_CTX}, +- #else +- {"NULL_MAC_PKEY_CTX", 6, 208}, +- #endif +- #ifdef EVP_R_ONLY_ONESHOT_SUPPORTED +- {"ONLY_ONESHOT_SUPPORTED", ERR_LIB_EVP, EVP_R_ONLY_ONESHOT_SUPPORTED}, +- #else +- {"ONLY_ONESHOT_SUPPORTED", 6, 177}, +- #endif +- #ifdef EVP_R_OPERATION_NOT_INITIALIZED +- {"OPERATION_NOT_INITIALIZED", ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED}, +- #else +- {"OPERATION_NOT_INITIALIZED", 6, 151}, +- #endif +- #ifdef EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE +- {"OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE", ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE}, +- #else +- {"OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE", 6, 150}, +- #endif +- #ifdef EVP_R_OUTPUT_WOULD_OVERFLOW +- {"OUTPUT_WOULD_OVERFLOW", ERR_LIB_EVP, EVP_R_OUTPUT_WOULD_OVERFLOW}, +- #else +- {"OUTPUT_WOULD_OVERFLOW", 6, 202}, +- #endif +- #ifdef EVP_R_PARAMETER_TOO_LARGE +- {"PARAMETER_TOO_LARGE", ERR_LIB_EVP, EVP_R_PARAMETER_TOO_LARGE}, +- #else +- {"PARAMETER_TOO_LARGE", 6, 187}, +- #endif +- #ifdef EVP_R_PARTIALLY_OVERLAPPING +- {"PARTIALLY_OVERLAPPING", ERR_LIB_EVP, EVP_R_PARTIALLY_OVERLAPPING}, +- #else +- {"PARTIALLY_OVERLAPPING", 6, 162}, +- #endif +- #ifdef EVP_R_PBKDF2_ERROR +- {"PBKDF2_ERROR", ERR_LIB_EVP, EVP_R_PBKDF2_ERROR}, +- #else +- {"PBKDF2_ERROR", 6, 181}, +- #endif +- #ifdef EVP_R_PKEY_APPLICATION_ASN1_METHOD_ALREADY_REGISTERED +- {"PKEY_APPLICATION_ASN1_METHOD_ALREADY_REGISTERED", ERR_LIB_EVP, EVP_R_PKEY_APPLICATION_ASN1_METHOD_ALREADY_REGISTERED}, +- #else +- {"PKEY_APPLICATION_ASN1_METHOD_ALREADY_REGISTERED", 6, 179}, +- #endif +- #ifdef EVP_R_PRIVATE_KEY_DECODE_ERROR +- {"PRIVATE_KEY_DECODE_ERROR", ERR_LIB_EVP, EVP_R_PRIVATE_KEY_DECODE_ERROR}, +- #else +- {"PRIVATE_KEY_DECODE_ERROR", 6, 145}, +- #endif +- #ifdef EVP_R_PRIVATE_KEY_ENCODE_ERROR +- {"PRIVATE_KEY_ENCODE_ERROR", ERR_LIB_EVP, EVP_R_PRIVATE_KEY_ENCODE_ERROR}, +- #else +- {"PRIVATE_KEY_ENCODE_ERROR", 6, 146}, +- #endif +- #ifdef EVP_R_PUBLIC_KEY_NOT_RSA +- {"PUBLIC_KEY_NOT_RSA", ERR_LIB_EVP, EVP_R_PUBLIC_KEY_NOT_RSA}, +- #else +- {"PUBLIC_KEY_NOT_RSA", 6, 106}, +- #endif +- #ifdef EVP_R_SETTING_XOF_FAILED +- {"SETTING_XOF_FAILED", ERR_LIB_EVP, EVP_R_SETTING_XOF_FAILED}, +- #else +- {"SETTING_XOF_FAILED", 6, 227}, +- #endif +- #ifdef EVP_R_SET_DEFAULT_PROPERTY_FAILURE +- {"SET_DEFAULT_PROPERTY_FAILURE", ERR_LIB_EVP, EVP_R_SET_DEFAULT_PROPERTY_FAILURE}, +- #else +- {"SET_DEFAULT_PROPERTY_FAILURE", 6, 209}, +- #endif +- #ifdef EVP_R_TOO_MANY_RECORDS +- {"TOO_MANY_RECORDS", ERR_LIB_EVP, EVP_R_TOO_MANY_RECORDS}, +- #else +- {"TOO_MANY_RECORDS", 6, 183}, +- #endif +- #ifdef EVP_R_UNABLE_TO_ENABLE_LOCKING +- {"UNABLE_TO_ENABLE_LOCKING", ERR_LIB_EVP, EVP_R_UNABLE_TO_ENABLE_LOCKING}, +- #else +- {"UNABLE_TO_ENABLE_LOCKING", 6, 212}, +- #endif +- #ifdef EVP_R_UNABLE_TO_GET_MAXIMUM_REQUEST_SIZE +- {"UNABLE_TO_GET_MAXIMUM_REQUEST_SIZE", ERR_LIB_EVP, EVP_R_UNABLE_TO_GET_MAXIMUM_REQUEST_SIZE}, +- #else +- {"UNABLE_TO_GET_MAXIMUM_REQUEST_SIZE", 6, 215}, +- #endif +- #ifdef EVP_R_UNABLE_TO_GET_RANDOM_STRENGTH +- {"UNABLE_TO_GET_RANDOM_STRENGTH", ERR_LIB_EVP, EVP_R_UNABLE_TO_GET_RANDOM_STRENGTH}, +- #else +- {"UNABLE_TO_GET_RANDOM_STRENGTH", 6, 216}, +- #endif +- #ifdef EVP_R_UNABLE_TO_LOCK_CONTEXT +- {"UNABLE_TO_LOCK_CONTEXT", ERR_LIB_EVP, EVP_R_UNABLE_TO_LOCK_CONTEXT}, +- #else +- {"UNABLE_TO_LOCK_CONTEXT", 6, 211}, +- #endif +- #ifdef EVP_R_UNABLE_TO_SET_CALLBACKS +- {"UNABLE_TO_SET_CALLBACKS", ERR_LIB_EVP, EVP_R_UNABLE_TO_SET_CALLBACKS}, +- #else +- {"UNABLE_TO_SET_CALLBACKS", 6, 217}, +- #endif +- #ifdef EVP_R_UNKNOWN_CIPHER +- {"UNKNOWN_CIPHER", ERR_LIB_EVP, EVP_R_UNKNOWN_CIPHER}, +- #else +- {"UNKNOWN_CIPHER", 6, 160}, +- #endif +- #ifdef EVP_R_UNKNOWN_DIGEST +- {"UNKNOWN_DIGEST", ERR_LIB_EVP, EVP_R_UNKNOWN_DIGEST}, +- #else +- {"UNKNOWN_DIGEST", 6, 161}, +- #endif +- #ifdef EVP_R_UNKNOWN_KEY_TYPE +- {"UNKNOWN_KEY_TYPE", ERR_LIB_EVP, EVP_R_UNKNOWN_KEY_TYPE}, +- #else +- {"UNKNOWN_KEY_TYPE", 6, 207}, +- #endif +- #ifdef EVP_R_UNKNOWN_OPTION +- {"UNKNOWN_OPTION", ERR_LIB_EVP, EVP_R_UNKNOWN_OPTION}, +- #else +- {"UNKNOWN_OPTION", 6, 169}, +- #endif +- #ifdef EVP_R_UNKNOWN_PBE_ALGORITHM +- {"UNKNOWN_PBE_ALGORITHM", ERR_LIB_EVP, EVP_R_UNKNOWN_PBE_ALGORITHM}, +- #else +- {"UNKNOWN_PBE_ALGORITHM", 6, 121}, +- #endif +- #ifdef EVP_R_UNSUPPORTED_ALGORITHM +- {"UNSUPPORTED_ALGORITHM", ERR_LIB_EVP, EVP_R_UNSUPPORTED_ALGORITHM}, +- #else +- {"UNSUPPORTED_ALGORITHM", 6, 156}, +- #endif +- #ifdef EVP_R_UNSUPPORTED_CIPHER +- {"UNSUPPORTED_CIPHER", ERR_LIB_EVP, EVP_R_UNSUPPORTED_CIPHER}, +- #else +- {"UNSUPPORTED_CIPHER", 6, 107}, +- #endif +- #ifdef EVP_R_UNSUPPORTED_KEYLENGTH +- {"UNSUPPORTED_KEYLENGTH", ERR_LIB_EVP, EVP_R_UNSUPPORTED_KEYLENGTH}, +- #else +- {"UNSUPPORTED_KEYLENGTH", 6, 123}, +- #endif +- #ifdef EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION +- {"UNSUPPORTED_KEY_DERIVATION_FUNCTION", ERR_LIB_EVP, EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION}, +- #else +- {"UNSUPPORTED_KEY_DERIVATION_FUNCTION", 6, 124}, +- #endif +- #ifdef EVP_R_UNSUPPORTED_KEY_SIZE +- {"UNSUPPORTED_KEY_SIZE", ERR_LIB_EVP, EVP_R_UNSUPPORTED_KEY_SIZE}, +- #else +- {"UNSUPPORTED_KEY_SIZE", 6, 108}, +- #endif +- #ifdef EVP_R_UNSUPPORTED_KEY_TYPE +- {"UNSUPPORTED_KEY_TYPE", ERR_LIB_EVP, EVP_R_UNSUPPORTED_KEY_TYPE}, +- #else +- {"UNSUPPORTED_KEY_TYPE", 6, 224}, +- #endif +- #ifdef EVP_R_UNSUPPORTED_NUMBER_OF_ROUNDS +- {"UNSUPPORTED_NUMBER_OF_ROUNDS", ERR_LIB_EVP, EVP_R_UNSUPPORTED_NUMBER_OF_ROUNDS}, +- #else +- {"UNSUPPORTED_NUMBER_OF_ROUNDS", 6, 135}, +- #endif +- #ifdef EVP_R_UNSUPPORTED_PRF +- {"UNSUPPORTED_PRF", ERR_LIB_EVP, EVP_R_UNSUPPORTED_PRF}, +- #else +- {"UNSUPPORTED_PRF", 6, 125}, +- #endif +- #ifdef EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM +- {"UNSUPPORTED_PRIVATE_KEY_ALGORITHM", ERR_LIB_EVP, EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM}, +- #else +- {"UNSUPPORTED_PRIVATE_KEY_ALGORITHM", 6, 118}, +- #endif +- #ifdef EVP_R_UNSUPPORTED_SALT_TYPE +- {"UNSUPPORTED_SALT_TYPE", ERR_LIB_EVP, EVP_R_UNSUPPORTED_SALT_TYPE}, +- #else +- {"UNSUPPORTED_SALT_TYPE", 6, 126}, +- #endif +- #ifdef EVP_R_UPDATE_ERROR +- {"UPDATE_ERROR", ERR_LIB_EVP, EVP_R_UPDATE_ERROR}, +- #else +- {"UPDATE_ERROR", 6, 189}, +- #endif +- #ifdef EVP_R_WRAP_MODE_NOT_ALLOWED +- {"WRAP_MODE_NOT_ALLOWED", ERR_LIB_EVP, EVP_R_WRAP_MODE_NOT_ALLOWED}, +- #else +- {"WRAP_MODE_NOT_ALLOWED", 6, 170}, +- #endif +- #ifdef EVP_R_WRONG_FINAL_BLOCK_LENGTH +- {"WRONG_FINAL_BLOCK_LENGTH", ERR_LIB_EVP, EVP_R_WRONG_FINAL_BLOCK_LENGTH}, +- #else +- {"WRONG_FINAL_BLOCK_LENGTH", 6, 109}, +- #endif +- #ifdef EVP_R_XTS_DATA_UNIT_IS_TOO_LARGE +- {"XTS_DATA_UNIT_IS_TOO_LARGE", ERR_LIB_EVP, EVP_R_XTS_DATA_UNIT_IS_TOO_LARGE}, +- #else +- {"XTS_DATA_UNIT_IS_TOO_LARGE", 6, 191}, +- #endif +- #ifdef EVP_R_XTS_DUPLICATED_KEYS +- {"XTS_DUPLICATED_KEYS", ERR_LIB_EVP, EVP_R_XTS_DUPLICATED_KEYS}, +- #else +- {"XTS_DUPLICATED_KEYS", 6, 192}, +- #endif +- #ifdef HTTP_R_ASN1_LEN_EXCEEDS_MAX_RESP_LEN +- {"ASN1_LEN_EXCEEDS_MAX_RESP_LEN", ERR_LIB_HTTP, HTTP_R_ASN1_LEN_EXCEEDS_MAX_RESP_LEN}, +- #else +- {"ASN1_LEN_EXCEEDS_MAX_RESP_LEN", 61, 108}, +- #endif +- #ifdef HTTP_R_CONNECT_FAILURE +- {"CONNECT_FAILURE", ERR_LIB_HTTP, HTTP_R_CONNECT_FAILURE}, +- #else +- {"CONNECT_FAILURE", 61, 100}, +- #endif +- #ifdef HTTP_R_ERROR_PARSING_ASN1_LENGTH +- {"ERROR_PARSING_ASN1_LENGTH", ERR_LIB_HTTP, HTTP_R_ERROR_PARSING_ASN1_LENGTH}, +- #else +- {"ERROR_PARSING_ASN1_LENGTH", 61, 109}, +- #endif +- #ifdef HTTP_R_ERROR_PARSING_CONTENT_LENGTH +- {"ERROR_PARSING_CONTENT_LENGTH", ERR_LIB_HTTP, HTTP_R_ERROR_PARSING_CONTENT_LENGTH}, +- #else +- {"ERROR_PARSING_CONTENT_LENGTH", 61, 119}, +- #endif +- #ifdef HTTP_R_ERROR_PARSING_URL +- {"ERROR_PARSING_URL", ERR_LIB_HTTP, HTTP_R_ERROR_PARSING_URL}, +- #else +- {"ERROR_PARSING_URL", 61, 101}, +- #endif +- #ifdef HTTP_R_ERROR_RECEIVING +- {"ERROR_RECEIVING", ERR_LIB_HTTP, HTTP_R_ERROR_RECEIVING}, +- #else +- {"ERROR_RECEIVING", 61, 103}, +- #endif +- #ifdef HTTP_R_ERROR_SENDING +- {"ERROR_SENDING", ERR_LIB_HTTP, HTTP_R_ERROR_SENDING}, +- #else +- {"ERROR_SENDING", 61, 102}, +- #endif +- #ifdef HTTP_R_FAILED_READING_DATA +- {"FAILED_READING_DATA", ERR_LIB_HTTP, HTTP_R_FAILED_READING_DATA}, +- #else +- {"FAILED_READING_DATA", 61, 128}, +- #endif +- #ifdef HTTP_R_HEADER_PARSE_ERROR +- {"HEADER_PARSE_ERROR", ERR_LIB_HTTP, HTTP_R_HEADER_PARSE_ERROR}, +- #else +- {"HEADER_PARSE_ERROR", 61, 126}, +- #endif +- #ifdef HTTP_R_INCONSISTENT_CONTENT_LENGTH +- {"INCONSISTENT_CONTENT_LENGTH", ERR_LIB_HTTP, HTTP_R_INCONSISTENT_CONTENT_LENGTH}, +- #else +- {"INCONSISTENT_CONTENT_LENGTH", 61, 120}, +- #endif +- #ifdef HTTP_R_INVALID_PORT_NUMBER +- {"INVALID_PORT_NUMBER", ERR_LIB_HTTP, HTTP_R_INVALID_PORT_NUMBER}, +- #else +- {"INVALID_PORT_NUMBER", 61, 123}, +- #endif +- #ifdef HTTP_R_INVALID_URL_PATH +- {"INVALID_URL_PATH", ERR_LIB_HTTP, HTTP_R_INVALID_URL_PATH}, +- #else +- {"INVALID_URL_PATH", 61, 125}, +- #endif +- #ifdef HTTP_R_INVALID_URL_SCHEME +- {"INVALID_URL_SCHEME", ERR_LIB_HTTP, HTTP_R_INVALID_URL_SCHEME}, +- #else +- {"INVALID_URL_SCHEME", 61, 124}, +- #endif +- #ifdef HTTP_R_MAX_RESP_LEN_EXCEEDED +- {"MAX_RESP_LEN_EXCEEDED", ERR_LIB_HTTP, HTTP_R_MAX_RESP_LEN_EXCEEDED}, +- #else +- {"MAX_RESP_LEN_EXCEEDED", 61, 117}, +- #endif +- #ifdef HTTP_R_MISSING_ASN1_ENCODING +- {"MISSING_ASN1_ENCODING", ERR_LIB_HTTP, HTTP_R_MISSING_ASN1_ENCODING}, +- #else +- {"MISSING_ASN1_ENCODING", 61, 110}, +- #endif +- #ifdef HTTP_R_MISSING_CONTENT_TYPE +- {"MISSING_CONTENT_TYPE", ERR_LIB_HTTP, HTTP_R_MISSING_CONTENT_TYPE}, +- #else +- {"MISSING_CONTENT_TYPE", 61, 121}, +- #endif +- #ifdef HTTP_R_MISSING_REDIRECT_LOCATION +- {"MISSING_REDIRECT_LOCATION", ERR_LIB_HTTP, HTTP_R_MISSING_REDIRECT_LOCATION}, +- #else +- {"MISSING_REDIRECT_LOCATION", 61, 111}, +- #endif +- #ifdef HTTP_R_RECEIVED_ERROR +- {"RECEIVED_ERROR", ERR_LIB_HTTP, HTTP_R_RECEIVED_ERROR}, +- #else +- {"RECEIVED_ERROR", 61, 105}, +- #endif +- #ifdef HTTP_R_RECEIVED_WRONG_HTTP_VERSION +- {"RECEIVED_WRONG_HTTP_VERSION", ERR_LIB_HTTP, HTTP_R_RECEIVED_WRONG_HTTP_VERSION}, +- #else +- {"RECEIVED_WRONG_HTTP_VERSION", 61, 106}, +- #endif +- #ifdef HTTP_R_REDIRECTION_FROM_HTTPS_TO_HTTP +- {"REDIRECTION_FROM_HTTPS_TO_HTTP", ERR_LIB_HTTP, HTTP_R_REDIRECTION_FROM_HTTPS_TO_HTTP}, +- #else +- {"REDIRECTION_FROM_HTTPS_TO_HTTP", 61, 112}, +- #endif +- #ifdef HTTP_R_REDIRECTION_NOT_ENABLED +- {"REDIRECTION_NOT_ENABLED", ERR_LIB_HTTP, HTTP_R_REDIRECTION_NOT_ENABLED}, +- #else +- {"REDIRECTION_NOT_ENABLED", 61, 116}, +- #endif +- #ifdef HTTP_R_RESPONSE_LINE_TOO_LONG +- {"RESPONSE_LINE_TOO_LONG", ERR_LIB_HTTP, HTTP_R_RESPONSE_LINE_TOO_LONG}, +- #else +- {"RESPONSE_LINE_TOO_LONG", 61, 113}, +- #endif +- #ifdef HTTP_R_RESPONSE_PARSE_ERROR +- {"RESPONSE_PARSE_ERROR", ERR_LIB_HTTP, HTTP_R_RESPONSE_PARSE_ERROR}, +- #else +- {"RESPONSE_PARSE_ERROR", 61, 104}, +- #endif +- #ifdef HTTP_R_RETRY_TIMEOUT +- {"RETRY_TIMEOUT", ERR_LIB_HTTP, HTTP_R_RETRY_TIMEOUT}, +- #else +- {"RETRY_TIMEOUT", 61, 129}, +- #endif +- #ifdef HTTP_R_SERVER_CANCELED_CONNECTION +- {"SERVER_CANCELED_CONNECTION", ERR_LIB_HTTP, HTTP_R_SERVER_CANCELED_CONNECTION}, +- #else +- {"SERVER_CANCELED_CONNECTION", 61, 127}, +- #endif +- #ifdef HTTP_R_SOCK_NOT_SUPPORTED +- {"SOCK_NOT_SUPPORTED", ERR_LIB_HTTP, HTTP_R_SOCK_NOT_SUPPORTED}, +- #else +- {"SOCK_NOT_SUPPORTED", 61, 122}, +- #endif +- #ifdef HTTP_R_STATUS_CODE_UNSUPPORTED +- {"STATUS_CODE_UNSUPPORTED", ERR_LIB_HTTP, HTTP_R_STATUS_CODE_UNSUPPORTED}, +- #else +- {"STATUS_CODE_UNSUPPORTED", 61, 114}, +- #endif +- #ifdef HTTP_R_TLS_NOT_ENABLED +- {"TLS_NOT_ENABLED", ERR_LIB_HTTP, HTTP_R_TLS_NOT_ENABLED}, +- #else +- {"TLS_NOT_ENABLED", 61, 107}, +- #endif +- #ifdef HTTP_R_TOO_MANY_REDIRECTIONS +- {"TOO_MANY_REDIRECTIONS", ERR_LIB_HTTP, HTTP_R_TOO_MANY_REDIRECTIONS}, +- #else +- {"TOO_MANY_REDIRECTIONS", 61, 115}, +- #endif +- #ifdef HTTP_R_UNEXPECTED_CONTENT_TYPE +- {"UNEXPECTED_CONTENT_TYPE", ERR_LIB_HTTP, HTTP_R_UNEXPECTED_CONTENT_TYPE}, +- #else +- {"UNEXPECTED_CONTENT_TYPE", 61, 118}, +- #endif +- #ifdef OBJ_R_OID_EXISTS +- {"OID_EXISTS", ERR_LIB_OBJ, OBJ_R_OID_EXISTS}, +- #else +- {"OID_EXISTS", 8, 102}, +- #endif +- #ifdef OBJ_R_UNKNOWN_NID +- {"UNKNOWN_NID", ERR_LIB_OBJ, OBJ_R_UNKNOWN_NID}, +- #else +- {"UNKNOWN_NID", 8, 101}, +- #endif +- #ifdef OBJ_R_UNKNOWN_OBJECT_NAME +- {"UNKNOWN_OBJECT_NAME", ERR_LIB_OBJ, OBJ_R_UNKNOWN_OBJECT_NAME}, +- #else +- {"UNKNOWN_OBJECT_NAME", 8, 103}, +- #endif +- #ifdef OCSP_R_CERTIFICATE_VERIFY_ERROR +- {"CERTIFICATE_VERIFY_ERROR", ERR_LIB_OCSP, OCSP_R_CERTIFICATE_VERIFY_ERROR}, +- #else +- {"CERTIFICATE_VERIFY_ERROR", 39, 101}, +- #endif +- #ifdef OCSP_R_DIGEST_ERR +- {"DIGEST_ERR", ERR_LIB_OCSP, OCSP_R_DIGEST_ERR}, +- #else +- {"DIGEST_ERR", 39, 102}, +- #endif +- #ifdef OCSP_R_DIGEST_NAME_ERR +- {"DIGEST_NAME_ERR", ERR_LIB_OCSP, OCSP_R_DIGEST_NAME_ERR}, +- #else +- {"DIGEST_NAME_ERR", 39, 106}, +- #endif +- #ifdef OCSP_R_DIGEST_SIZE_ERR +- {"DIGEST_SIZE_ERR", ERR_LIB_OCSP, OCSP_R_DIGEST_SIZE_ERR}, +- #else +- {"DIGEST_SIZE_ERR", 39, 107}, +- #endif +- #ifdef OCSP_R_ERROR_IN_NEXTUPDATE_FIELD +- {"ERROR_IN_NEXTUPDATE_FIELD", ERR_LIB_OCSP, OCSP_R_ERROR_IN_NEXTUPDATE_FIELD}, +- #else +- {"ERROR_IN_NEXTUPDATE_FIELD", 39, 122}, +- #endif +- #ifdef OCSP_R_ERROR_IN_THISUPDATE_FIELD +- {"ERROR_IN_THISUPDATE_FIELD", ERR_LIB_OCSP, OCSP_R_ERROR_IN_THISUPDATE_FIELD}, +- #else +- {"ERROR_IN_THISUPDATE_FIELD", 39, 123}, +- #endif +- #ifdef OCSP_R_MISSING_OCSPSIGNING_USAGE +- {"MISSING_OCSPSIGNING_USAGE", ERR_LIB_OCSP, OCSP_R_MISSING_OCSPSIGNING_USAGE}, +- #else +- {"MISSING_OCSPSIGNING_USAGE", 39, 103}, +- #endif +- #ifdef OCSP_R_NEXTUPDATE_BEFORE_THISUPDATE +- {"NEXTUPDATE_BEFORE_THISUPDATE", ERR_LIB_OCSP, OCSP_R_NEXTUPDATE_BEFORE_THISUPDATE}, +- #else +- {"NEXTUPDATE_BEFORE_THISUPDATE", 39, 124}, +- #endif +- #ifdef OCSP_R_NOT_BASIC_RESPONSE +- {"NOT_BASIC_RESPONSE", ERR_LIB_OCSP, OCSP_R_NOT_BASIC_RESPONSE}, +- #else +- {"NOT_BASIC_RESPONSE", 39, 104}, +- #endif +- #ifdef OCSP_R_NO_CERTIFICATES_IN_CHAIN +- {"NO_CERTIFICATES_IN_CHAIN", ERR_LIB_OCSP, OCSP_R_NO_CERTIFICATES_IN_CHAIN}, +- #else +- {"NO_CERTIFICATES_IN_CHAIN", 39, 105}, +- #endif +- #ifdef OCSP_R_NO_RESPONSE_DATA +- {"NO_RESPONSE_DATA", ERR_LIB_OCSP, OCSP_R_NO_RESPONSE_DATA}, +- #else +- {"NO_RESPONSE_DATA", 39, 108}, +- #endif +- #ifdef OCSP_R_NO_REVOKED_TIME +- {"NO_REVOKED_TIME", ERR_LIB_OCSP, OCSP_R_NO_REVOKED_TIME}, +- #else +- {"NO_REVOKED_TIME", 39, 109}, +- #endif +- #ifdef OCSP_R_NO_SIGNER_KEY +- {"NO_SIGNER_KEY", ERR_LIB_OCSP, OCSP_R_NO_SIGNER_KEY}, +- #else +- {"NO_SIGNER_KEY", 39, 130}, +- #endif +- #ifdef OCSP_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE +- {"PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE", ERR_LIB_OCSP, OCSP_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE}, +- #else +- {"PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE", 39, 110}, +- #endif +- #ifdef OCSP_R_REQUEST_NOT_SIGNED +- {"REQUEST_NOT_SIGNED", ERR_LIB_OCSP, OCSP_R_REQUEST_NOT_SIGNED}, +- #else +- {"REQUEST_NOT_SIGNED", 39, 128}, +- #endif +- #ifdef OCSP_R_RESPONSE_CONTAINS_NO_REVOCATION_DATA +- {"RESPONSE_CONTAINS_NO_REVOCATION_DATA", ERR_LIB_OCSP, OCSP_R_RESPONSE_CONTAINS_NO_REVOCATION_DATA}, +- #else +- {"RESPONSE_CONTAINS_NO_REVOCATION_DATA", 39, 111}, +- #endif +- #ifdef OCSP_R_ROOT_CA_NOT_TRUSTED +- {"ROOT_CA_NOT_TRUSTED", ERR_LIB_OCSP, OCSP_R_ROOT_CA_NOT_TRUSTED}, +- #else +- {"ROOT_CA_NOT_TRUSTED", 39, 112}, +- #endif +- #ifdef OCSP_R_SIGNATURE_FAILURE +- {"SIGNATURE_FAILURE", ERR_LIB_OCSP, OCSP_R_SIGNATURE_FAILURE}, +- #else +- {"SIGNATURE_FAILURE", 39, 117}, +- #endif +- #ifdef OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND +- {"SIGNER_CERTIFICATE_NOT_FOUND", ERR_LIB_OCSP, OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND}, +- #else +- {"SIGNER_CERTIFICATE_NOT_FOUND", 39, 118}, +- #endif +- #ifdef OCSP_R_STATUS_EXPIRED +- {"STATUS_EXPIRED", ERR_LIB_OCSP, OCSP_R_STATUS_EXPIRED}, +- #else +- {"STATUS_EXPIRED", 39, 125}, +- #endif +- #ifdef OCSP_R_STATUS_NOT_YET_VALID +- {"STATUS_NOT_YET_VALID", ERR_LIB_OCSP, OCSP_R_STATUS_NOT_YET_VALID}, +- #else +- {"STATUS_NOT_YET_VALID", 39, 126}, +- #endif +- #ifdef OCSP_R_STATUS_TOO_OLD +- {"STATUS_TOO_OLD", ERR_LIB_OCSP, OCSP_R_STATUS_TOO_OLD}, +- #else +- {"STATUS_TOO_OLD", 39, 127}, +- #endif +- #ifdef OCSP_R_UNKNOWN_MESSAGE_DIGEST +- {"UNKNOWN_MESSAGE_DIGEST", ERR_LIB_OCSP, OCSP_R_UNKNOWN_MESSAGE_DIGEST}, +- #else +- {"UNKNOWN_MESSAGE_DIGEST", 39, 119}, +- #endif +- #ifdef OCSP_R_UNKNOWN_NID +- {"UNKNOWN_NID", ERR_LIB_OCSP, OCSP_R_UNKNOWN_NID}, +- #else +- {"UNKNOWN_NID", 39, 120}, +- #endif +- #ifdef OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE +- {"UNSUPPORTED_REQUESTORNAME_TYPE", ERR_LIB_OCSP, OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE}, +- #else +- {"UNSUPPORTED_REQUESTORNAME_TYPE", 39, 129}, +- #endif +- #ifdef OSSL_DECODER_R_COULD_NOT_DECODE_OBJECT +- {"COULD_NOT_DECODE_OBJECT", ERR_LIB_OSSL_DECODER, OSSL_DECODER_R_COULD_NOT_DECODE_OBJECT}, +- #else +- {"COULD_NOT_DECODE_OBJECT", 60, 101}, +- #endif +- #ifdef OSSL_DECODER_R_DECODER_NOT_FOUND +- {"DECODER_NOT_FOUND", ERR_LIB_OSSL_DECODER, OSSL_DECODER_R_DECODER_NOT_FOUND}, +- #else +- {"DECODER_NOT_FOUND", 60, 102}, +- #endif +- #ifdef OSSL_DECODER_R_MISSING_GET_PARAMS +- {"MISSING_GET_PARAMS", ERR_LIB_OSSL_DECODER, OSSL_DECODER_R_MISSING_GET_PARAMS}, +- #else +- {"MISSING_GET_PARAMS", 60, 100}, +- #endif +- #ifdef OSSL_ENCODER_R_ENCODER_NOT_FOUND +- {"ENCODER_NOT_FOUND", ERR_LIB_OSSL_ENCODER, OSSL_ENCODER_R_ENCODER_NOT_FOUND}, +- #else +- {"ENCODER_NOT_FOUND", 59, 101}, +- #endif +- #ifdef OSSL_ENCODER_R_INCORRECT_PROPERTY_QUERY +- {"INCORRECT_PROPERTY_QUERY", ERR_LIB_OSSL_ENCODER, OSSL_ENCODER_R_INCORRECT_PROPERTY_QUERY}, +- #else +- {"INCORRECT_PROPERTY_QUERY", 59, 100}, +- #endif +- #ifdef OSSL_ENCODER_R_MISSING_GET_PARAMS +- {"MISSING_GET_PARAMS", ERR_LIB_OSSL_ENCODER, OSSL_ENCODER_R_MISSING_GET_PARAMS}, +- #else +- {"MISSING_GET_PARAMS", 59, 102}, +- #endif +- #ifdef OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE +- {"AMBIGUOUS_CONTENT_TYPE", ERR_LIB_OSSL_STORE, OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE}, +- #else +- {"AMBIGUOUS_CONTENT_TYPE", 44, 107}, +- #endif +- #ifdef OSSL_STORE_R_BAD_PASSWORD_READ +- {"BAD_PASSWORD_READ", ERR_LIB_OSSL_STORE, OSSL_STORE_R_BAD_PASSWORD_READ}, +- #else +- {"BAD_PASSWORD_READ", 44, 115}, +- #endif +- #ifdef OSSL_STORE_R_ERROR_VERIFYING_PKCS12_MAC +- {"ERROR_VERIFYING_PKCS12_MAC", ERR_LIB_OSSL_STORE, OSSL_STORE_R_ERROR_VERIFYING_PKCS12_MAC}, +- #else +- {"ERROR_VERIFYING_PKCS12_MAC", 44, 113}, +- #endif +- #ifdef OSSL_STORE_R_FINGERPRINT_SIZE_DOES_NOT_MATCH_DIGEST +- {"FINGERPRINT_SIZE_DOES_NOT_MATCH_DIGEST", ERR_LIB_OSSL_STORE, OSSL_STORE_R_FINGERPRINT_SIZE_DOES_NOT_MATCH_DIGEST}, +- #else +- {"FINGERPRINT_SIZE_DOES_NOT_MATCH_DIGEST", 44, 121}, +- #endif +- #ifdef OSSL_STORE_R_INVALID_SCHEME +- {"INVALID_SCHEME", ERR_LIB_OSSL_STORE, OSSL_STORE_R_INVALID_SCHEME}, +- #else +- {"INVALID_SCHEME", 44, 106}, +- #endif +- #ifdef OSSL_STORE_R_IS_NOT_A +- {"IS_NOT_A", ERR_LIB_OSSL_STORE, OSSL_STORE_R_IS_NOT_A}, +- #else +- {"IS_NOT_A", 44, 112}, +- #endif +- #ifdef OSSL_STORE_R_LOADER_INCOMPLETE +- {"LOADER_INCOMPLETE", ERR_LIB_OSSL_STORE, OSSL_STORE_R_LOADER_INCOMPLETE}, +- #else +- {"LOADER_INCOMPLETE", 44, 116}, +- #endif +- #ifdef OSSL_STORE_R_LOADING_STARTED +- {"LOADING_STARTED", ERR_LIB_OSSL_STORE, OSSL_STORE_R_LOADING_STARTED}, +- #else +- {"LOADING_STARTED", 44, 117}, +- #endif +- #ifdef OSSL_STORE_R_NOT_A_CERTIFICATE +- {"NOT_A_CERTIFICATE", ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_CERTIFICATE}, +- #else +- {"NOT_A_CERTIFICATE", 44, 100}, +- #endif +- #ifdef OSSL_STORE_R_NOT_A_CRL +- {"NOT_A_CRL", ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_CRL}, +- #else +- {"NOT_A_CRL", 44, 101}, +- #endif +- #ifdef OSSL_STORE_R_NOT_A_NAME +- {"NOT_A_NAME", ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_NAME}, +- #else +- {"NOT_A_NAME", 44, 103}, +- #endif +- #ifdef OSSL_STORE_R_NOT_A_PRIVATE_KEY +- {"NOT_A_PRIVATE_KEY", ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_PRIVATE_KEY}, +- #else +- {"NOT_A_PRIVATE_KEY", 44, 102}, +- #endif +- #ifdef OSSL_STORE_R_NOT_A_PUBLIC_KEY +- {"NOT_A_PUBLIC_KEY", ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_PUBLIC_KEY}, +- #else +- {"NOT_A_PUBLIC_KEY", 44, 122}, +- #endif +- #ifdef OSSL_STORE_R_NOT_PARAMETERS +- {"NOT_PARAMETERS", ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_PARAMETERS}, +- #else +- {"NOT_PARAMETERS", 44, 104}, +- #endif +- #ifdef OSSL_STORE_R_NO_LOADERS_FOUND +- {"NO_LOADERS_FOUND", ERR_LIB_OSSL_STORE, OSSL_STORE_R_NO_LOADERS_FOUND}, +- #else +- {"NO_LOADERS_FOUND", 44, 123}, +- #endif +- #ifdef OSSL_STORE_R_PASSPHRASE_CALLBACK_ERROR +- {"PASSPHRASE_CALLBACK_ERROR", ERR_LIB_OSSL_STORE, OSSL_STORE_R_PASSPHRASE_CALLBACK_ERROR}, +- #else +- {"PASSPHRASE_CALLBACK_ERROR", 44, 114}, +- #endif +- #ifdef OSSL_STORE_R_PATH_MUST_BE_ABSOLUTE +- {"PATH_MUST_BE_ABSOLUTE", ERR_LIB_OSSL_STORE, OSSL_STORE_R_PATH_MUST_BE_ABSOLUTE}, +- #else +- {"PATH_MUST_BE_ABSOLUTE", 44, 108}, +- #endif +- #ifdef OSSL_STORE_R_SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES +- {"SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES", ERR_LIB_OSSL_STORE, OSSL_STORE_R_SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES}, +- #else +- {"SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES", 44, 119}, +- #endif +- #ifdef OSSL_STORE_R_UI_PROCESS_INTERRUPTED_OR_CANCELLED +- {"UI_PROCESS_INTERRUPTED_OR_CANCELLED", ERR_LIB_OSSL_STORE, OSSL_STORE_R_UI_PROCESS_INTERRUPTED_OR_CANCELLED}, +- #else +- {"UI_PROCESS_INTERRUPTED_OR_CANCELLED", 44, 109}, +- #endif +- #ifdef OSSL_STORE_R_UNREGISTERED_SCHEME +- {"UNREGISTERED_SCHEME", ERR_LIB_OSSL_STORE, OSSL_STORE_R_UNREGISTERED_SCHEME}, +- #else +- {"UNREGISTERED_SCHEME", 44, 105}, +- #endif +- #ifdef OSSL_STORE_R_UNSUPPORTED_CONTENT_TYPE +- {"UNSUPPORTED_CONTENT_TYPE", ERR_LIB_OSSL_STORE, OSSL_STORE_R_UNSUPPORTED_CONTENT_TYPE}, +- #else +- {"UNSUPPORTED_CONTENT_TYPE", 44, 110}, +- #endif +- #ifdef OSSL_STORE_R_UNSUPPORTED_OPERATION +- {"UNSUPPORTED_OPERATION", ERR_LIB_OSSL_STORE, OSSL_STORE_R_UNSUPPORTED_OPERATION}, +- #else +- {"UNSUPPORTED_OPERATION", 44, 118}, +- #endif +- #ifdef OSSL_STORE_R_UNSUPPORTED_SEARCH_TYPE +- {"UNSUPPORTED_SEARCH_TYPE", ERR_LIB_OSSL_STORE, OSSL_STORE_R_UNSUPPORTED_SEARCH_TYPE}, +- #else +- {"UNSUPPORTED_SEARCH_TYPE", 44, 120}, +- #endif +- #ifdef OSSL_STORE_R_URI_AUTHORITY_UNSUPPORTED +- {"URI_AUTHORITY_UNSUPPORTED", ERR_LIB_OSSL_STORE, OSSL_STORE_R_URI_AUTHORITY_UNSUPPORTED}, +- #else +- {"URI_AUTHORITY_UNSUPPORTED", 44, 111}, +- #endif +- #ifdef PEM_R_BAD_BASE64_DECODE +- {"BAD_BASE64_DECODE", ERR_LIB_PEM, PEM_R_BAD_BASE64_DECODE}, +- #else +- {"BAD_BASE64_DECODE", 9, 100}, +- #endif +- #ifdef PEM_R_BAD_DECRYPT +- {"BAD_DECRYPT", ERR_LIB_PEM, PEM_R_BAD_DECRYPT}, +- #else +- {"BAD_DECRYPT", 9, 101}, +- #endif +- #ifdef PEM_R_BAD_END_LINE +- {"BAD_END_LINE", ERR_LIB_PEM, PEM_R_BAD_END_LINE}, +- #else +- {"BAD_END_LINE", 9, 102}, +- #endif +- #ifdef PEM_R_BAD_IV_CHARS +- {"BAD_IV_CHARS", ERR_LIB_PEM, PEM_R_BAD_IV_CHARS}, +- #else +- {"BAD_IV_CHARS", 9, 103}, +- #endif +- #ifdef PEM_R_BAD_MAGIC_NUMBER +- {"BAD_MAGIC_NUMBER", ERR_LIB_PEM, PEM_R_BAD_MAGIC_NUMBER}, +- #else +- {"BAD_MAGIC_NUMBER", 9, 116}, +- #endif +- #ifdef PEM_R_BAD_PASSWORD_READ +- {"BAD_PASSWORD_READ", ERR_LIB_PEM, PEM_R_BAD_PASSWORD_READ}, +- #else +- {"BAD_PASSWORD_READ", 9, 104}, +- #endif +- #ifdef PEM_R_BAD_VERSION_NUMBER +- {"BAD_VERSION_NUMBER", ERR_LIB_PEM, PEM_R_BAD_VERSION_NUMBER}, +- #else +- {"BAD_VERSION_NUMBER", 9, 117}, +- #endif +- #ifdef PEM_R_BIO_WRITE_FAILURE +- {"BIO_WRITE_FAILURE", ERR_LIB_PEM, PEM_R_BIO_WRITE_FAILURE}, +- #else +- {"BIO_WRITE_FAILURE", 9, 118}, +- #endif +- #ifdef PEM_R_CIPHER_IS_NULL +- {"CIPHER_IS_NULL", ERR_LIB_PEM, PEM_R_CIPHER_IS_NULL}, +- #else +- {"CIPHER_IS_NULL", 9, 127}, +- #endif +- #ifdef PEM_R_ERROR_CONVERTING_PRIVATE_KEY +- {"ERROR_CONVERTING_PRIVATE_KEY", ERR_LIB_PEM, PEM_R_ERROR_CONVERTING_PRIVATE_KEY}, +- #else +- {"ERROR_CONVERTING_PRIVATE_KEY", 9, 115}, +- #endif +- #ifdef PEM_R_EXPECTING_DSS_KEY_BLOB +- {"EXPECTING_DSS_KEY_BLOB", ERR_LIB_PEM, PEM_R_EXPECTING_DSS_KEY_BLOB}, +- #else +- {"EXPECTING_DSS_KEY_BLOB", 9, 131}, +- #endif +- #ifdef PEM_R_EXPECTING_PRIVATE_KEY_BLOB +- {"EXPECTING_PRIVATE_KEY_BLOB", ERR_LIB_PEM, PEM_R_EXPECTING_PRIVATE_KEY_BLOB}, +- #else +- {"EXPECTING_PRIVATE_KEY_BLOB", 9, 119}, +- #endif +- #ifdef PEM_R_EXPECTING_PUBLIC_KEY_BLOB +- {"EXPECTING_PUBLIC_KEY_BLOB", ERR_LIB_PEM, PEM_R_EXPECTING_PUBLIC_KEY_BLOB}, +- #else +- {"EXPECTING_PUBLIC_KEY_BLOB", 9, 120}, +- #endif +- #ifdef PEM_R_EXPECTING_RSA_KEY_BLOB +- {"EXPECTING_RSA_KEY_BLOB", ERR_LIB_PEM, PEM_R_EXPECTING_RSA_KEY_BLOB}, +- #else +- {"EXPECTING_RSA_KEY_BLOB", 9, 132}, +- #endif +- #ifdef PEM_R_HEADER_TOO_LONG +- {"HEADER_TOO_LONG", ERR_LIB_PEM, PEM_R_HEADER_TOO_LONG}, +- #else +- {"HEADER_TOO_LONG", 9, 128}, +- #endif +- #ifdef PEM_R_INCONSISTENT_HEADER +- {"INCONSISTENT_HEADER", ERR_LIB_PEM, PEM_R_INCONSISTENT_HEADER}, +- #else +- {"INCONSISTENT_HEADER", 9, 121}, +- #endif +- #ifdef PEM_R_KEYBLOB_HEADER_PARSE_ERROR +- {"KEYBLOB_HEADER_PARSE_ERROR", ERR_LIB_PEM, PEM_R_KEYBLOB_HEADER_PARSE_ERROR}, +- #else +- {"KEYBLOB_HEADER_PARSE_ERROR", 9, 122}, +- #endif +- #ifdef PEM_R_KEYBLOB_TOO_SHORT +- {"KEYBLOB_TOO_SHORT", ERR_LIB_PEM, PEM_R_KEYBLOB_TOO_SHORT}, +- #else +- {"KEYBLOB_TOO_SHORT", 9, 123}, +- #endif +- #ifdef PEM_R_MISSING_DEK_IV +- {"MISSING_DEK_IV", ERR_LIB_PEM, PEM_R_MISSING_DEK_IV}, +- #else +- {"MISSING_DEK_IV", 9, 129}, +- #endif +- #ifdef PEM_R_NOT_DEK_INFO +- {"NOT_DEK_INFO", ERR_LIB_PEM, PEM_R_NOT_DEK_INFO}, +- #else +- {"NOT_DEK_INFO", 9, 105}, +- #endif +- #ifdef PEM_R_NOT_ENCRYPTED +- {"NOT_ENCRYPTED", ERR_LIB_PEM, PEM_R_NOT_ENCRYPTED}, +- #else +- {"NOT_ENCRYPTED", 9, 106}, +- #endif +- #ifdef PEM_R_NOT_PROC_TYPE +- {"NOT_PROC_TYPE", ERR_LIB_PEM, PEM_R_NOT_PROC_TYPE}, +- #else +- {"NOT_PROC_TYPE", 9, 107}, +- #endif +- #ifdef PEM_R_NO_START_LINE +- {"NO_START_LINE", ERR_LIB_PEM, PEM_R_NO_START_LINE}, +- #else +- {"NO_START_LINE", 9, 108}, +- #endif +- #ifdef PEM_R_PROBLEMS_GETTING_PASSWORD +- {"PROBLEMS_GETTING_PASSWORD", ERR_LIB_PEM, PEM_R_PROBLEMS_GETTING_PASSWORD}, +- #else +- {"PROBLEMS_GETTING_PASSWORD", 9, 109}, +- #endif +- #ifdef PEM_R_PVK_DATA_TOO_SHORT +- {"PVK_DATA_TOO_SHORT", ERR_LIB_PEM, PEM_R_PVK_DATA_TOO_SHORT}, +- #else +- {"PVK_DATA_TOO_SHORT", 9, 124}, +- #endif +- #ifdef PEM_R_PVK_TOO_SHORT +- {"PVK_TOO_SHORT", ERR_LIB_PEM, PEM_R_PVK_TOO_SHORT}, +- #else +- {"PVK_TOO_SHORT", 9, 125}, +- #endif +- #ifdef PEM_R_READ_KEY +- {"READ_KEY", ERR_LIB_PEM, PEM_R_READ_KEY}, +- #else +- {"READ_KEY", 9, 111}, +- #endif +- #ifdef PEM_R_SHORT_HEADER +- {"SHORT_HEADER", ERR_LIB_PEM, PEM_R_SHORT_HEADER}, +- #else +- {"SHORT_HEADER", 9, 112}, +- #endif +- #ifdef PEM_R_UNEXPECTED_DEK_IV +- {"UNEXPECTED_DEK_IV", ERR_LIB_PEM, PEM_R_UNEXPECTED_DEK_IV}, +- #else +- {"UNEXPECTED_DEK_IV", 9, 130}, +- #endif +- #ifdef PEM_R_UNSUPPORTED_CIPHER +- {"UNSUPPORTED_CIPHER", ERR_LIB_PEM, PEM_R_UNSUPPORTED_CIPHER}, +- #else +- {"UNSUPPORTED_CIPHER", 9, 113}, +- #endif +- #ifdef PEM_R_UNSUPPORTED_ENCRYPTION +- {"UNSUPPORTED_ENCRYPTION", ERR_LIB_PEM, PEM_R_UNSUPPORTED_ENCRYPTION}, +- #else +- {"UNSUPPORTED_ENCRYPTION", 9, 114}, +- #endif +- #ifdef PEM_R_UNSUPPORTED_KEY_COMPONENTS +- {"UNSUPPORTED_KEY_COMPONENTS", ERR_LIB_PEM, PEM_R_UNSUPPORTED_KEY_COMPONENTS}, +- #else +- {"UNSUPPORTED_KEY_COMPONENTS", 9, 126}, +- #endif +- #ifdef PEM_R_UNSUPPORTED_PUBLIC_KEY_TYPE +- {"UNSUPPORTED_PUBLIC_KEY_TYPE", ERR_LIB_PEM, PEM_R_UNSUPPORTED_PUBLIC_KEY_TYPE}, +- #else +- {"UNSUPPORTED_PUBLIC_KEY_TYPE", 9, 110}, +- #endif +- #ifdef PKCS12_R_CANT_PACK_STRUCTURE +- {"CANT_PACK_STRUCTURE", ERR_LIB_PKCS12, PKCS12_R_CANT_PACK_STRUCTURE}, +- #else +- {"CANT_PACK_STRUCTURE", 35, 100}, +- #endif +- #ifdef PKCS12_R_CONTENT_TYPE_NOT_DATA +- {"CONTENT_TYPE_NOT_DATA", ERR_LIB_PKCS12, PKCS12_R_CONTENT_TYPE_NOT_DATA}, +- #else +- {"CONTENT_TYPE_NOT_DATA", 35, 121}, +- #endif +- #ifdef PKCS12_R_DECODE_ERROR +- {"DECODE_ERROR", ERR_LIB_PKCS12, PKCS12_R_DECODE_ERROR}, +- #else +- {"DECODE_ERROR", 35, 101}, +- #endif +- #ifdef PKCS12_R_ENCODE_ERROR +- {"ENCODE_ERROR", ERR_LIB_PKCS12, PKCS12_R_ENCODE_ERROR}, +- #else +- {"ENCODE_ERROR", 35, 102}, +- #endif +- #ifdef PKCS12_R_ENCRYPT_ERROR +- {"ENCRYPT_ERROR", ERR_LIB_PKCS12, PKCS12_R_ENCRYPT_ERROR}, +- #else +- {"ENCRYPT_ERROR", 35, 103}, +- #endif +- #ifdef PKCS12_R_ERROR_SETTING_ENCRYPTED_DATA_TYPE +- {"ERROR_SETTING_ENCRYPTED_DATA_TYPE", ERR_LIB_PKCS12, PKCS12_R_ERROR_SETTING_ENCRYPTED_DATA_TYPE}, +- #else +- {"ERROR_SETTING_ENCRYPTED_DATA_TYPE", 35, 120}, +- #endif +- #ifdef PKCS12_R_INVALID_NULL_ARGUMENT +- {"INVALID_NULL_ARGUMENT", ERR_LIB_PKCS12, PKCS12_R_INVALID_NULL_ARGUMENT}, +- #else +- {"INVALID_NULL_ARGUMENT", 35, 104}, +- #endif +- #ifdef PKCS12_R_INVALID_NULL_PKCS12_POINTER +- {"INVALID_NULL_PKCS12_POINTER", ERR_LIB_PKCS12, PKCS12_R_INVALID_NULL_PKCS12_POINTER}, +- #else +- {"INVALID_NULL_PKCS12_POINTER", 35, 105}, +- #endif +- #ifdef PKCS12_R_INVALID_TYPE +- {"INVALID_TYPE", ERR_LIB_PKCS12, PKCS12_R_INVALID_TYPE}, +- #else +- {"INVALID_TYPE", 35, 112}, +- #endif +- #ifdef PKCS12_R_IV_GEN_ERROR +- {"IV_GEN_ERROR", ERR_LIB_PKCS12, PKCS12_R_IV_GEN_ERROR}, +- #else +- {"IV_GEN_ERROR", 35, 106}, +- #endif +- #ifdef PKCS12_R_KEY_GEN_ERROR +- {"KEY_GEN_ERROR", ERR_LIB_PKCS12, PKCS12_R_KEY_GEN_ERROR}, +- #else +- {"KEY_GEN_ERROR", 35, 107}, +- #endif +- #ifdef PKCS12_R_MAC_ABSENT +- {"MAC_ABSENT", ERR_LIB_PKCS12, PKCS12_R_MAC_ABSENT}, +- #else +- {"MAC_ABSENT", 35, 108}, +- #endif +- #ifdef PKCS12_R_MAC_GENERATION_ERROR +- {"MAC_GENERATION_ERROR", ERR_LIB_PKCS12, PKCS12_R_MAC_GENERATION_ERROR}, +- #else +- {"MAC_GENERATION_ERROR", 35, 109}, +- #endif +- #ifdef PKCS12_R_MAC_SETUP_ERROR +- {"MAC_SETUP_ERROR", ERR_LIB_PKCS12, PKCS12_R_MAC_SETUP_ERROR}, +- #else +- {"MAC_SETUP_ERROR", 35, 110}, +- #endif +- #ifdef PKCS12_R_MAC_STRING_SET_ERROR +- {"MAC_STRING_SET_ERROR", ERR_LIB_PKCS12, PKCS12_R_MAC_STRING_SET_ERROR}, +- #else +- {"MAC_STRING_SET_ERROR", 35, 111}, +- #endif +- #ifdef PKCS12_R_MAC_VERIFY_FAILURE +- {"MAC_VERIFY_FAILURE", ERR_LIB_PKCS12, PKCS12_R_MAC_VERIFY_FAILURE}, +- #else +- {"MAC_VERIFY_FAILURE", 35, 113}, +- #endif +- #ifdef PKCS12_R_PARSE_ERROR +- {"PARSE_ERROR", ERR_LIB_PKCS12, PKCS12_R_PARSE_ERROR}, +- #else +- {"PARSE_ERROR", 35, 114}, +- #endif +- #ifdef PKCS12_R_PKCS12_CIPHERFINAL_ERROR +- {"PKCS12_CIPHERFINAL_ERROR", ERR_LIB_PKCS12, PKCS12_R_PKCS12_CIPHERFINAL_ERROR}, +- #else +- {"PKCS12_CIPHERFINAL_ERROR", 35, 116}, +- #endif +- #ifdef PKCS12_R_UNKNOWN_DIGEST_ALGORITHM +- {"UNKNOWN_DIGEST_ALGORITHM", ERR_LIB_PKCS12, PKCS12_R_UNKNOWN_DIGEST_ALGORITHM}, +- #else +- {"UNKNOWN_DIGEST_ALGORITHM", 35, 118}, +- #endif +- #ifdef PKCS12_R_UNSUPPORTED_PKCS12_MODE +- {"UNSUPPORTED_PKCS12_MODE", ERR_LIB_PKCS12, PKCS12_R_UNSUPPORTED_PKCS12_MODE}, +- #else +- {"UNSUPPORTED_PKCS12_MODE", 35, 119}, +- #endif +- #ifdef PKCS7_R_CERTIFICATE_VERIFY_ERROR +- {"CERTIFICATE_VERIFY_ERROR", ERR_LIB_PKCS7, PKCS7_R_CERTIFICATE_VERIFY_ERROR}, +- #else +- {"CERTIFICATE_VERIFY_ERROR", 33, 117}, +- #endif +- #ifdef PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER +- {"CIPHER_HAS_NO_OBJECT_IDENTIFIER", ERR_LIB_PKCS7, PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER}, +- #else +- {"CIPHER_HAS_NO_OBJECT_IDENTIFIER", 33, 144}, +- #endif +- #ifdef PKCS7_R_CIPHER_NOT_INITIALIZED +- {"CIPHER_NOT_INITIALIZED", ERR_LIB_PKCS7, PKCS7_R_CIPHER_NOT_INITIALIZED}, +- #else +- {"CIPHER_NOT_INITIALIZED", 33, 116}, +- #endif +- #ifdef PKCS7_R_CONTENT_AND_DATA_PRESENT +- {"CONTENT_AND_DATA_PRESENT", ERR_LIB_PKCS7, PKCS7_R_CONTENT_AND_DATA_PRESENT}, +- #else +- {"CONTENT_AND_DATA_PRESENT", 33, 118}, +- #endif +- #ifdef PKCS7_R_CTRL_ERROR +- {"CTRL_ERROR", ERR_LIB_PKCS7, PKCS7_R_CTRL_ERROR}, +- #else +- {"CTRL_ERROR", 33, 152}, +- #endif +- #ifdef PKCS7_R_DECRYPT_ERROR +- {"DECRYPT_ERROR", ERR_LIB_PKCS7, PKCS7_R_DECRYPT_ERROR}, +- #else +- {"DECRYPT_ERROR", 33, 119}, +- #endif +- #ifdef PKCS7_R_DIGEST_FAILURE +- {"DIGEST_FAILURE", ERR_LIB_PKCS7, PKCS7_R_DIGEST_FAILURE}, +- #else +- {"DIGEST_FAILURE", 33, 101}, +- #endif +- #ifdef PKCS7_R_ENCRYPTION_CTRL_FAILURE +- {"ENCRYPTION_CTRL_FAILURE", ERR_LIB_PKCS7, PKCS7_R_ENCRYPTION_CTRL_FAILURE}, +- #else +- {"ENCRYPTION_CTRL_FAILURE", 33, 149}, +- #endif +- #ifdef PKCS7_R_ENCRYPTION_NOT_SUPPORTED_FOR_THIS_KEY_TYPE +- {"ENCRYPTION_NOT_SUPPORTED_FOR_THIS_KEY_TYPE", ERR_LIB_PKCS7, PKCS7_R_ENCRYPTION_NOT_SUPPORTED_FOR_THIS_KEY_TYPE}, +- #else +- {"ENCRYPTION_NOT_SUPPORTED_FOR_THIS_KEY_TYPE", 33, 150}, +- #endif +- #ifdef PKCS7_R_ERROR_ADDING_RECIPIENT +- {"ERROR_ADDING_RECIPIENT", ERR_LIB_PKCS7, PKCS7_R_ERROR_ADDING_RECIPIENT}, +- #else +- {"ERROR_ADDING_RECIPIENT", 33, 120}, +- #endif +- #ifdef PKCS7_R_ERROR_SETTING_CIPHER +- {"ERROR_SETTING_CIPHER", ERR_LIB_PKCS7, PKCS7_R_ERROR_SETTING_CIPHER}, +- #else +- {"ERROR_SETTING_CIPHER", 33, 121}, +- #endif +- #ifdef PKCS7_R_INVALID_NULL_POINTER +- {"INVALID_NULL_POINTER", ERR_LIB_PKCS7, PKCS7_R_INVALID_NULL_POINTER}, +- #else +- {"INVALID_NULL_POINTER", 33, 143}, +- #endif +- #ifdef PKCS7_R_INVALID_SIGNED_DATA_TYPE +- {"INVALID_SIGNED_DATA_TYPE", ERR_LIB_PKCS7, PKCS7_R_INVALID_SIGNED_DATA_TYPE}, +- #else +- {"INVALID_SIGNED_DATA_TYPE", 33, 155}, +- #endif +- #ifdef PKCS7_R_NO_CONTENT +- {"NO_CONTENT", ERR_LIB_PKCS7, PKCS7_R_NO_CONTENT}, +- #else +- {"NO_CONTENT", 33, 122}, +- #endif +- #ifdef PKCS7_R_NO_DEFAULT_DIGEST +- {"NO_DEFAULT_DIGEST", ERR_LIB_PKCS7, PKCS7_R_NO_DEFAULT_DIGEST}, +- #else +- {"NO_DEFAULT_DIGEST", 33, 151}, +- #endif +- #ifdef PKCS7_R_NO_MATCHING_DIGEST_TYPE_FOUND +- {"NO_MATCHING_DIGEST_TYPE_FOUND", ERR_LIB_PKCS7, PKCS7_R_NO_MATCHING_DIGEST_TYPE_FOUND}, +- #else +- {"NO_MATCHING_DIGEST_TYPE_FOUND", 33, 154}, +- #endif +- #ifdef PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE +- {"NO_RECIPIENT_MATCHES_CERTIFICATE", ERR_LIB_PKCS7, PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE}, +- #else +- {"NO_RECIPIENT_MATCHES_CERTIFICATE", 33, 115}, +- #endif +- #ifdef PKCS7_R_NO_SIGNATURES_ON_DATA +- {"NO_SIGNATURES_ON_DATA", ERR_LIB_PKCS7, PKCS7_R_NO_SIGNATURES_ON_DATA}, +- #else +- {"NO_SIGNATURES_ON_DATA", 33, 123}, +- #endif +- #ifdef PKCS7_R_NO_SIGNERS +- {"NO_SIGNERS", ERR_LIB_PKCS7, PKCS7_R_NO_SIGNERS}, +- #else +- {"NO_SIGNERS", 33, 142}, +- #endif +- #ifdef PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE +- {"OPERATION_NOT_SUPPORTED_ON_THIS_TYPE", ERR_LIB_PKCS7, PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE}, +- #else +- {"OPERATION_NOT_SUPPORTED_ON_THIS_TYPE", 33, 104}, +- #endif +- #ifdef PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR +- {"PKCS7_ADD_SIGNATURE_ERROR", ERR_LIB_PKCS7, PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR}, +- #else +- {"PKCS7_ADD_SIGNATURE_ERROR", 33, 124}, +- #endif +- #ifdef PKCS7_R_PKCS7_ADD_SIGNER_ERROR +- {"PKCS7_ADD_SIGNER_ERROR", ERR_LIB_PKCS7, PKCS7_R_PKCS7_ADD_SIGNER_ERROR}, +- #else +- {"PKCS7_ADD_SIGNER_ERROR", 33, 153}, +- #endif +- #ifdef PKCS7_R_PKCS7_DATASIGN +- {"PKCS7_DATASIGN", ERR_LIB_PKCS7, PKCS7_R_PKCS7_DATASIGN}, +- #else +- {"PKCS7_DATASIGN", 33, 145}, +- #endif +- #ifdef PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE +- {"PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE", ERR_LIB_PKCS7, PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE}, +- #else +- {"PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE", 33, 127}, +- #endif +- #ifdef PKCS7_R_SIGNATURE_FAILURE +- {"SIGNATURE_FAILURE", ERR_LIB_PKCS7, PKCS7_R_SIGNATURE_FAILURE}, +- #else +- {"SIGNATURE_FAILURE", 33, 105}, +- #endif +- #ifdef PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND +- {"SIGNER_CERTIFICATE_NOT_FOUND", ERR_LIB_PKCS7, PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND}, +- #else +- {"SIGNER_CERTIFICATE_NOT_FOUND", 33, 128}, +- #endif +- #ifdef PKCS7_R_SIGNING_CTRL_FAILURE +- {"SIGNING_CTRL_FAILURE", ERR_LIB_PKCS7, PKCS7_R_SIGNING_CTRL_FAILURE}, +- #else +- {"SIGNING_CTRL_FAILURE", 33, 147}, +- #endif +- #ifdef PKCS7_R_SIGNING_NOT_SUPPORTED_FOR_THIS_KEY_TYPE +- {"SIGNING_NOT_SUPPORTED_FOR_THIS_KEY_TYPE", ERR_LIB_PKCS7, PKCS7_R_SIGNING_NOT_SUPPORTED_FOR_THIS_KEY_TYPE}, +- #else +- {"SIGNING_NOT_SUPPORTED_FOR_THIS_KEY_TYPE", 33, 148}, +- #endif +- #ifdef PKCS7_R_SMIME_TEXT_ERROR +- {"SMIME_TEXT_ERROR", ERR_LIB_PKCS7, PKCS7_R_SMIME_TEXT_ERROR}, +- #else +- {"SMIME_TEXT_ERROR", 33, 129}, +- #endif +- #ifdef PKCS7_R_UNABLE_TO_FIND_CERTIFICATE +- {"UNABLE_TO_FIND_CERTIFICATE", ERR_LIB_PKCS7, PKCS7_R_UNABLE_TO_FIND_CERTIFICATE}, +- #else +- {"UNABLE_TO_FIND_CERTIFICATE", 33, 106}, +- #endif +- #ifdef PKCS7_R_UNABLE_TO_FIND_MEM_BIO +- {"UNABLE_TO_FIND_MEM_BIO", ERR_LIB_PKCS7, PKCS7_R_UNABLE_TO_FIND_MEM_BIO}, +- #else +- {"UNABLE_TO_FIND_MEM_BIO", 33, 107}, +- #endif +- #ifdef PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST +- {"UNABLE_TO_FIND_MESSAGE_DIGEST", ERR_LIB_PKCS7, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST}, +- #else +- {"UNABLE_TO_FIND_MESSAGE_DIGEST", 33, 108}, +- #endif +- #ifdef PKCS7_R_UNKNOWN_DIGEST_TYPE +- {"UNKNOWN_DIGEST_TYPE", ERR_LIB_PKCS7, PKCS7_R_UNKNOWN_DIGEST_TYPE}, +- #else +- {"UNKNOWN_DIGEST_TYPE", 33, 109}, +- #endif +- #ifdef PKCS7_R_UNKNOWN_OPERATION +- {"UNKNOWN_OPERATION", ERR_LIB_PKCS7, PKCS7_R_UNKNOWN_OPERATION}, +- #else +- {"UNKNOWN_OPERATION", 33, 110}, +- #endif +- #ifdef PKCS7_R_UNSUPPORTED_CIPHER_TYPE +- {"UNSUPPORTED_CIPHER_TYPE", ERR_LIB_PKCS7, PKCS7_R_UNSUPPORTED_CIPHER_TYPE}, +- #else +- {"UNSUPPORTED_CIPHER_TYPE", 33, 111}, +- #endif +- #ifdef PKCS7_R_UNSUPPORTED_CONTENT_TYPE +- {"UNSUPPORTED_CONTENT_TYPE", ERR_LIB_PKCS7, PKCS7_R_UNSUPPORTED_CONTENT_TYPE}, +- #else +- {"UNSUPPORTED_CONTENT_TYPE", 33, 112}, +- #endif +- #ifdef PKCS7_R_WRONG_CONTENT_TYPE +- {"WRONG_CONTENT_TYPE", ERR_LIB_PKCS7, PKCS7_R_WRONG_CONTENT_TYPE}, +- #else +- {"WRONG_CONTENT_TYPE", 33, 113}, +- #endif +- #ifdef PKCS7_R_WRONG_PKCS7_TYPE +- {"WRONG_PKCS7_TYPE", ERR_LIB_PKCS7, PKCS7_R_WRONG_PKCS7_TYPE}, +- #else +- {"WRONG_PKCS7_TYPE", 33, 114}, +- #endif +- #ifdef PROP_R_NAME_TOO_LONG +- {"NAME_TOO_LONG", ERR_LIB_PROP, PROP_R_NAME_TOO_LONG}, +- #else +- {"NAME_TOO_LONG", 55, 100}, +- #endif +- #ifdef PROP_R_NOT_AN_ASCII_CHARACTER +- {"NOT_AN_ASCII_CHARACTER", ERR_LIB_PROP, PROP_R_NOT_AN_ASCII_CHARACTER}, +- #else +- {"NOT_AN_ASCII_CHARACTER", 55, 101}, +- #endif +- #ifdef PROP_R_NOT_AN_HEXADECIMAL_DIGIT +- {"NOT_AN_HEXADECIMAL_DIGIT", ERR_LIB_PROP, PROP_R_NOT_AN_HEXADECIMAL_DIGIT}, +- #else +- {"NOT_AN_HEXADECIMAL_DIGIT", 55, 102}, +- #endif +- #ifdef PROP_R_NOT_AN_IDENTIFIER +- {"NOT_AN_IDENTIFIER", ERR_LIB_PROP, PROP_R_NOT_AN_IDENTIFIER}, +- #else +- {"NOT_AN_IDENTIFIER", 55, 103}, +- #endif +- #ifdef PROP_R_NOT_AN_OCTAL_DIGIT +- {"NOT_AN_OCTAL_DIGIT", ERR_LIB_PROP, PROP_R_NOT_AN_OCTAL_DIGIT}, +- #else +- {"NOT_AN_OCTAL_DIGIT", 55, 104}, +- #endif +- #ifdef PROP_R_NOT_A_DECIMAL_DIGIT +- {"NOT_A_DECIMAL_DIGIT", ERR_LIB_PROP, PROP_R_NOT_A_DECIMAL_DIGIT}, +- #else +- {"NOT_A_DECIMAL_DIGIT", 55, 105}, +- #endif +- #ifdef PROP_R_NO_MATCHING_STRING_DELIMITER +- {"NO_MATCHING_STRING_DELIMITER", ERR_LIB_PROP, PROP_R_NO_MATCHING_STRING_DELIMITER}, +- #else +- {"NO_MATCHING_STRING_DELIMITER", 55, 106}, +- #endif +- #ifdef PROP_R_NO_VALUE +- {"NO_VALUE", ERR_LIB_PROP, PROP_R_NO_VALUE}, +- #else +- {"NO_VALUE", 55, 107}, +- #endif +- #ifdef PROP_R_PARSE_FAILED +- {"PARSE_FAILED", ERR_LIB_PROP, PROP_R_PARSE_FAILED}, +- #else +- {"PARSE_FAILED", 55, 108}, +- #endif +- #ifdef PROP_R_STRING_TOO_LONG +- {"STRING_TOO_LONG", ERR_LIB_PROP, PROP_R_STRING_TOO_LONG}, +- #else +- {"STRING_TOO_LONG", 55, 109}, +- #endif +- #ifdef PROP_R_TRAILING_CHARACTERS +- {"TRAILING_CHARACTERS", ERR_LIB_PROP, PROP_R_TRAILING_CHARACTERS}, +- #else +- {"TRAILING_CHARACTERS", 55, 110}, +- #endif +- #ifdef PROV_R_ADDITIONAL_INPUT_TOO_LONG +- {"ADDITIONAL_INPUT_TOO_LONG", ERR_LIB_PROV, PROV_R_ADDITIONAL_INPUT_TOO_LONG}, +- #else +- {"ADDITIONAL_INPUT_TOO_LONG", 57, 184}, +- #endif +- #ifdef PROV_R_ALGORITHM_MISMATCH +- {"ALGORITHM_MISMATCH", ERR_LIB_PROV, PROV_R_ALGORITHM_MISMATCH}, +- #else +- {"ALGORITHM_MISMATCH", 57, 173}, +- #endif +- #ifdef PROV_R_ALREADY_INSTANTIATED +- {"ALREADY_INSTANTIATED", ERR_LIB_PROV, PROV_R_ALREADY_INSTANTIATED}, +- #else +- {"ALREADY_INSTANTIATED", 57, 185}, +- #endif +- #ifdef PROV_R_BAD_DECRYPT +- {"BAD_DECRYPT", ERR_LIB_PROV, PROV_R_BAD_DECRYPT}, +- #else +- {"BAD_DECRYPT", 57, 100}, +- #endif +- #ifdef PROV_R_BAD_ENCODING +- {"BAD_ENCODING", ERR_LIB_PROV, PROV_R_BAD_ENCODING}, +- #else +- {"BAD_ENCODING", 57, 141}, +- #endif +- #ifdef PROV_R_BAD_LENGTH +- {"BAD_LENGTH", ERR_LIB_PROV, PROV_R_BAD_LENGTH}, +- #else +- {"BAD_LENGTH", 57, 142}, +- #endif +- #ifdef PROV_R_BAD_TLS_CLIENT_VERSION +- {"BAD_TLS_CLIENT_VERSION", ERR_LIB_PROV, PROV_R_BAD_TLS_CLIENT_VERSION}, +- #else +- {"BAD_TLS_CLIENT_VERSION", 57, 161}, +- #endif +- #ifdef PROV_R_BN_ERROR +- {"BN_ERROR", ERR_LIB_PROV, PROV_R_BN_ERROR}, +- #else +- {"BN_ERROR", 57, 160}, +- #endif +- #ifdef PROV_R_CIPHER_OPERATION_FAILED +- {"CIPHER_OPERATION_FAILED", ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED}, +- #else +- {"CIPHER_OPERATION_FAILED", 57, 102}, +- #endif +- #ifdef PROV_R_DERIVATION_FUNCTION_INIT_FAILED +- {"DERIVATION_FUNCTION_INIT_FAILED", ERR_LIB_PROV, PROV_R_DERIVATION_FUNCTION_INIT_FAILED}, +- #else +- {"DERIVATION_FUNCTION_INIT_FAILED", 57, 205}, +- #endif +- #ifdef PROV_R_DIGEST_NOT_ALLOWED +- {"DIGEST_NOT_ALLOWED", ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED}, +- #else +- {"DIGEST_NOT_ALLOWED", 57, 174}, +- #endif +- #ifdef PROV_R_EMS_NOT_ENABLED +- {"EMS_NOT_ENABLED", ERR_LIB_PROV, PROV_R_EMS_NOT_ENABLED}, +- #else +- {"EMS_NOT_ENABLED", 57, 233}, +- #endif +- #ifdef PROV_R_ENTROPY_SOURCE_STRENGTH_TOO_WEAK +- {"ENTROPY_SOURCE_STRENGTH_TOO_WEAK", ERR_LIB_PROV, PROV_R_ENTROPY_SOURCE_STRENGTH_TOO_WEAK}, +- #else +- {"ENTROPY_SOURCE_STRENGTH_TOO_WEAK", 57, 186}, +- #endif +- #ifdef PROV_R_ERROR_INSTANTIATING_DRBG +- {"ERROR_INSTANTIATING_DRBG", ERR_LIB_PROV, PROV_R_ERROR_INSTANTIATING_DRBG}, +- #else +- {"ERROR_INSTANTIATING_DRBG", 57, 188}, +- #endif +- #ifdef PROV_R_ERROR_RETRIEVING_ENTROPY +- {"ERROR_RETRIEVING_ENTROPY", ERR_LIB_PROV, PROV_R_ERROR_RETRIEVING_ENTROPY}, +- #else +- {"ERROR_RETRIEVING_ENTROPY", 57, 189}, +- #endif +- #ifdef PROV_R_ERROR_RETRIEVING_NONCE +- {"ERROR_RETRIEVING_NONCE", ERR_LIB_PROV, PROV_R_ERROR_RETRIEVING_NONCE}, +- #else +- {"ERROR_RETRIEVING_NONCE", 57, 190}, +- #endif +- #ifdef PROV_R_FAILED_DURING_DERIVATION +- {"FAILED_DURING_DERIVATION", ERR_LIB_PROV, PROV_R_FAILED_DURING_DERIVATION}, +- #else +- {"FAILED_DURING_DERIVATION", 57, 164}, +- #endif +- #ifdef PROV_R_FAILED_TO_CREATE_LOCK +- {"FAILED_TO_CREATE_LOCK", ERR_LIB_PROV, PROV_R_FAILED_TO_CREATE_LOCK}, +- #else +- {"FAILED_TO_CREATE_LOCK", 57, 180}, +- #endif +- #ifdef PROV_R_FAILED_TO_DECRYPT +- {"FAILED_TO_DECRYPT", ERR_LIB_PROV, PROV_R_FAILED_TO_DECRYPT}, +- #else +- {"FAILED_TO_DECRYPT", 57, 162}, +- #endif +- #ifdef PROV_R_FAILED_TO_GENERATE_KEY +- {"FAILED_TO_GENERATE_KEY", ERR_LIB_PROV, PROV_R_FAILED_TO_GENERATE_KEY}, +- #else +- {"FAILED_TO_GENERATE_KEY", 57, 121}, +- #endif +- #ifdef PROV_R_FAILED_TO_GET_PARAMETER +- {"FAILED_TO_GET_PARAMETER", ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER}, +- #else +- {"FAILED_TO_GET_PARAMETER", 57, 103}, +- #endif +- #ifdef PROV_R_FAILED_TO_SET_PARAMETER +- {"FAILED_TO_SET_PARAMETER", ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER}, +- #else +- {"FAILED_TO_SET_PARAMETER", 57, 104}, +- #endif +- #ifdef PROV_R_FAILED_TO_SIGN +- {"FAILED_TO_SIGN", ERR_LIB_PROV, PROV_R_FAILED_TO_SIGN}, +- #else +- {"FAILED_TO_SIGN", 57, 175}, +- #endif +- #ifdef PROV_R_FIPS_MODULE_CONDITIONAL_ERROR +- {"FIPS_MODULE_CONDITIONAL_ERROR", ERR_LIB_PROV, PROV_R_FIPS_MODULE_CONDITIONAL_ERROR}, +- #else +- {"FIPS_MODULE_CONDITIONAL_ERROR", 57, 227}, +- #endif +- #ifdef PROV_R_FIPS_MODULE_ENTERING_ERROR_STATE +- {"FIPS_MODULE_ENTERING_ERROR_STATE", ERR_LIB_PROV, PROV_R_FIPS_MODULE_ENTERING_ERROR_STATE}, +- #else +- {"FIPS_MODULE_ENTERING_ERROR_STATE", 57, 224}, +- #endif +- #ifdef PROV_R_FIPS_MODULE_IN_ERROR_STATE +- {"FIPS_MODULE_IN_ERROR_STATE", ERR_LIB_PROV, PROV_R_FIPS_MODULE_IN_ERROR_STATE}, +- #else +- {"FIPS_MODULE_IN_ERROR_STATE", 57, 225}, +- #endif +- #ifdef PROV_R_GENERATE_ERROR +- {"GENERATE_ERROR", ERR_LIB_PROV, PROV_R_GENERATE_ERROR}, +- #else +- {"GENERATE_ERROR", 57, 191}, +- #endif +- #ifdef PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE +- {"ILLEGAL_OR_UNSUPPORTED_PADDING_MODE", ERR_LIB_PROV, PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE}, +- #else +- {"ILLEGAL_OR_UNSUPPORTED_PADDING_MODE", 57, 165}, +- #endif +- #ifdef PROV_R_INDICATOR_INTEGRITY_FAILURE +- {"INDICATOR_INTEGRITY_FAILURE", ERR_LIB_PROV, PROV_R_INDICATOR_INTEGRITY_FAILURE}, +- #else +- {"INDICATOR_INTEGRITY_FAILURE", 57, 210}, +- #endif +- #ifdef PROV_R_INSUFFICIENT_DRBG_STRENGTH +- {"INSUFFICIENT_DRBG_STRENGTH", ERR_LIB_PROV, PROV_R_INSUFFICIENT_DRBG_STRENGTH}, +- #else +- {"INSUFFICIENT_DRBG_STRENGTH", 57, 181}, +- #endif +- #ifdef PROV_R_INVALID_AAD +- {"INVALID_AAD", ERR_LIB_PROV, PROV_R_INVALID_AAD}, +- #else +- {"INVALID_AAD", 57, 108}, +- #endif +- #ifdef PROV_R_INVALID_CONFIG_DATA +- {"INVALID_CONFIG_DATA", ERR_LIB_PROV, PROV_R_INVALID_CONFIG_DATA}, +- #else +- {"INVALID_CONFIG_DATA", 57, 211}, +- #endif +- #ifdef PROV_R_INVALID_CONSTANT_LENGTH +- {"INVALID_CONSTANT_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_CONSTANT_LENGTH}, +- #else +- {"INVALID_CONSTANT_LENGTH", 57, 157}, +- #endif +- #ifdef PROV_R_INVALID_CURVE +- {"INVALID_CURVE", ERR_LIB_PROV, PROV_R_INVALID_CURVE}, +- #else +- {"INVALID_CURVE", 57, 176}, +- #endif +- #ifdef PROV_R_INVALID_CUSTOM_LENGTH +- {"INVALID_CUSTOM_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_CUSTOM_LENGTH}, +- #else +- {"INVALID_CUSTOM_LENGTH", 57, 111}, +- #endif +- #ifdef PROV_R_INVALID_DATA +- {"INVALID_DATA", ERR_LIB_PROV, PROV_R_INVALID_DATA}, +- #else +- {"INVALID_DATA", 57, 115}, +- #endif +- #ifdef PROV_R_INVALID_DIGEST +- {"INVALID_DIGEST", ERR_LIB_PROV, PROV_R_INVALID_DIGEST}, +- #else +- {"INVALID_DIGEST", 57, 122}, +- #endif +- #ifdef PROV_R_INVALID_DIGEST_LENGTH +- {"INVALID_DIGEST_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_DIGEST_LENGTH}, +- #else +- {"INVALID_DIGEST_LENGTH", 57, 166}, +- #endif +- #ifdef PROV_R_INVALID_DIGEST_SIZE +- {"INVALID_DIGEST_SIZE", ERR_LIB_PROV, PROV_R_INVALID_DIGEST_SIZE}, +- #else +- {"INVALID_DIGEST_SIZE", 57, 218}, +- #endif +- #ifdef PROV_R_INVALID_INPUT_LENGTH +- {"INVALID_INPUT_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_INPUT_LENGTH}, +- #else +- {"INVALID_INPUT_LENGTH", 57, 230}, +- #endif +- #ifdef PROV_R_INVALID_ITERATION_COUNT +- {"INVALID_ITERATION_COUNT", ERR_LIB_PROV, PROV_R_INVALID_ITERATION_COUNT}, +- #else +- {"INVALID_ITERATION_COUNT", 57, 123}, +- #endif +- #ifdef PROV_R_INVALID_IV_LENGTH +- {"INVALID_IV_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH}, +- #else +- {"INVALID_IV_LENGTH", 57, 109}, +- #endif +- #ifdef PROV_R_INVALID_KEY +- {"INVALID_KEY", ERR_LIB_PROV, PROV_R_INVALID_KEY}, +- #else +- {"INVALID_KEY", 57, 158}, +- #endif +- #ifdef PROV_R_INVALID_KEY_LENGTH +- {"INVALID_KEY_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH}, +- #else +- {"INVALID_KEY_LENGTH", 57, 105}, +- #endif +- #ifdef PROV_R_INVALID_MAC +- {"INVALID_MAC", ERR_LIB_PROV, PROV_R_INVALID_MAC}, +- #else +- {"INVALID_MAC", 57, 151}, +- #endif +- #ifdef PROV_R_INVALID_MGF1_MD +- {"INVALID_MGF1_MD", ERR_LIB_PROV, PROV_R_INVALID_MGF1_MD}, +- #else +- {"INVALID_MGF1_MD", 57, 167}, +- #endif +- #ifdef PROV_R_INVALID_MODE +- {"INVALID_MODE", ERR_LIB_PROV, PROV_R_INVALID_MODE}, +- #else +- {"INVALID_MODE", 57, 125}, +- #endif +- #ifdef PROV_R_INVALID_OUTPUT_LENGTH +- {"INVALID_OUTPUT_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_OUTPUT_LENGTH}, +- #else +- {"INVALID_OUTPUT_LENGTH", 57, 217}, +- #endif +- #ifdef PROV_R_INVALID_PADDING_MODE +- {"INVALID_PADDING_MODE", ERR_LIB_PROV, PROV_R_INVALID_PADDING_MODE}, +- #else +- {"INVALID_PADDING_MODE", 57, 168}, +- #endif +- #ifdef PROV_R_INVALID_PUBINFO +- {"INVALID_PUBINFO", ERR_LIB_PROV, PROV_R_INVALID_PUBINFO}, +- #else +- {"INVALID_PUBINFO", 57, 198}, +- #endif +- #ifdef PROV_R_INVALID_SALT_LENGTH +- {"INVALID_SALT_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_SALT_LENGTH}, +- #else +- {"INVALID_SALT_LENGTH", 57, 112}, +- #endif +- #ifdef PROV_R_INVALID_SEED_LENGTH +- {"INVALID_SEED_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_SEED_LENGTH}, +- #else +- {"INVALID_SEED_LENGTH", 57, 154}, +- #endif +- #ifdef PROV_R_INVALID_SIGNATURE_SIZE +- {"INVALID_SIGNATURE_SIZE", ERR_LIB_PROV, PROV_R_INVALID_SIGNATURE_SIZE}, +- #else +- {"INVALID_SIGNATURE_SIZE", 57, 179}, +- #endif +- #ifdef PROV_R_INVALID_STATE +- {"INVALID_STATE", ERR_LIB_PROV, PROV_R_INVALID_STATE}, +- #else +- {"INVALID_STATE", 57, 212}, +- #endif +- #ifdef PROV_R_INVALID_TAG +- {"INVALID_TAG", ERR_LIB_PROV, PROV_R_INVALID_TAG}, +- #else +- {"INVALID_TAG", 57, 110}, +- #endif +- #ifdef PROV_R_INVALID_TAG_LENGTH +- {"INVALID_TAG_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_TAG_LENGTH}, +- #else +- {"INVALID_TAG_LENGTH", 57, 118}, +- #endif +- #ifdef PROV_R_INVALID_UKM_LENGTH +- {"INVALID_UKM_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_UKM_LENGTH}, +- #else +- {"INVALID_UKM_LENGTH", 57, 200}, +- #endif +- #ifdef PROV_R_INVALID_X931_DIGEST +- {"INVALID_X931_DIGEST", ERR_LIB_PROV, PROV_R_INVALID_X931_DIGEST}, +- #else +- {"INVALID_X931_DIGEST", 57, 170}, +- #endif +- #ifdef PROV_R_IN_ERROR_STATE +- {"IN_ERROR_STATE", ERR_LIB_PROV, PROV_R_IN_ERROR_STATE}, +- #else +- {"IN_ERROR_STATE", 57, 192}, +- #endif +- #ifdef PROV_R_KEY_SETUP_FAILED +- {"KEY_SETUP_FAILED", ERR_LIB_PROV, PROV_R_KEY_SETUP_FAILED}, +- #else +- {"KEY_SETUP_FAILED", 57, 101}, +- #endif +- #ifdef PROV_R_KEY_SIZE_TOO_SMALL +- {"KEY_SIZE_TOO_SMALL", ERR_LIB_PROV, PROV_R_KEY_SIZE_TOO_SMALL}, +- #else +- {"KEY_SIZE_TOO_SMALL", 57, 171}, +- #endif +- #ifdef PROV_R_LENGTH_TOO_LARGE +- {"LENGTH_TOO_LARGE", ERR_LIB_PROV, PROV_R_LENGTH_TOO_LARGE}, +- #else +- {"LENGTH_TOO_LARGE", 57, 202}, +- #endif +- #ifdef PROV_R_MISMATCHING_DOMAIN_PARAMETERS +- {"MISMATCHING_DOMAIN_PARAMETERS", ERR_LIB_PROV, PROV_R_MISMATCHING_DOMAIN_PARAMETERS}, +- #else +- {"MISMATCHING_DOMAIN_PARAMETERS", 57, 203}, +- #endif +- #ifdef PROV_R_MISSING_CEK_ALG +- {"MISSING_CEK_ALG", ERR_LIB_PROV, PROV_R_MISSING_CEK_ALG}, +- #else +- {"MISSING_CEK_ALG", 57, 144}, +- #endif +- #ifdef PROV_R_MISSING_CIPHER +- {"MISSING_CIPHER", ERR_LIB_PROV, PROV_R_MISSING_CIPHER}, +- #else +- {"MISSING_CIPHER", 57, 155}, +- #endif +- #ifdef PROV_R_MISSING_CONFIG_DATA +- {"MISSING_CONFIG_DATA", ERR_LIB_PROV, PROV_R_MISSING_CONFIG_DATA}, +- #else +- {"MISSING_CONFIG_DATA", 57, 213}, +- #endif +- #ifdef PROV_R_MISSING_CONSTANT +- {"MISSING_CONSTANT", ERR_LIB_PROV, PROV_R_MISSING_CONSTANT}, +- #else +- {"MISSING_CONSTANT", 57, 156}, +- #endif +- #ifdef PROV_R_MISSING_KEY +- {"MISSING_KEY", ERR_LIB_PROV, PROV_R_MISSING_KEY}, +- #else +- {"MISSING_KEY", 57, 128}, +- #endif +- #ifdef PROV_R_MISSING_MAC +- {"MISSING_MAC", ERR_LIB_PROV, PROV_R_MISSING_MAC}, +- #else +- {"MISSING_MAC", 57, 150}, +- #endif +- #ifdef PROV_R_MISSING_MESSAGE_DIGEST +- {"MISSING_MESSAGE_DIGEST", ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST}, +- #else +- {"MISSING_MESSAGE_DIGEST", 57, 129}, +- #endif +- #ifdef PROV_R_MISSING_OID +- {"MISSING_OID", ERR_LIB_PROV, PROV_R_MISSING_OID}, +- #else +- {"MISSING_OID", 57, 209}, +- #endif +- #ifdef PROV_R_MISSING_PASS +- {"MISSING_PASS", ERR_LIB_PROV, PROV_R_MISSING_PASS}, +- #else +- {"MISSING_PASS", 57, 130}, +- #endif +- #ifdef PROV_R_MISSING_SALT +- {"MISSING_SALT", ERR_LIB_PROV, PROV_R_MISSING_SALT}, +- #else +- {"MISSING_SALT", 57, 131}, +- #endif +- #ifdef PROV_R_MISSING_SECRET +- {"MISSING_SECRET", ERR_LIB_PROV, PROV_R_MISSING_SECRET}, +- #else +- {"MISSING_SECRET", 57, 132}, +- #endif +- #ifdef PROV_R_MISSING_SEED +- {"MISSING_SEED", ERR_LIB_PROV, PROV_R_MISSING_SEED}, +- #else +- {"MISSING_SEED", 57, 140}, +- #endif +- #ifdef PROV_R_MISSING_SESSION_ID +- {"MISSING_SESSION_ID", ERR_LIB_PROV, PROV_R_MISSING_SESSION_ID}, +- #else +- {"MISSING_SESSION_ID", 57, 133}, +- #endif +- #ifdef PROV_R_MISSING_TYPE +- {"MISSING_TYPE", ERR_LIB_PROV, PROV_R_MISSING_TYPE}, +- #else +- {"MISSING_TYPE", 57, 134}, +- #endif +- #ifdef PROV_R_MISSING_XCGHASH +- {"MISSING_XCGHASH", ERR_LIB_PROV, PROV_R_MISSING_XCGHASH}, +- #else +- {"MISSING_XCGHASH", 57, 135}, +- #endif +- #ifdef PROV_R_MODULE_INTEGRITY_FAILURE +- {"MODULE_INTEGRITY_FAILURE", ERR_LIB_PROV, PROV_R_MODULE_INTEGRITY_FAILURE}, +- #else +- {"MODULE_INTEGRITY_FAILURE", 57, 214}, +- #endif +- #ifdef PROV_R_NOT_A_PRIVATE_KEY +- {"NOT_A_PRIVATE_KEY", ERR_LIB_PROV, PROV_R_NOT_A_PRIVATE_KEY}, +- #else +- {"NOT_A_PRIVATE_KEY", 57, 221}, +- #endif +- #ifdef PROV_R_NOT_A_PUBLIC_KEY +- {"NOT_A_PUBLIC_KEY", ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY}, +- #else +- {"NOT_A_PUBLIC_KEY", 57, 220}, +- #endif +- #ifdef PROV_R_NOT_INSTANTIATED +- {"NOT_INSTANTIATED", ERR_LIB_PROV, PROV_R_NOT_INSTANTIATED}, +- #else +- {"NOT_INSTANTIATED", 57, 193}, +- #endif +- #ifdef PROV_R_NOT_PARAMETERS +- {"NOT_PARAMETERS", ERR_LIB_PROV, PROV_R_NOT_PARAMETERS}, +- #else +- {"NOT_PARAMETERS", 57, 226}, +- #endif +- #ifdef PROV_R_NOT_SUPPORTED +- {"NOT_SUPPORTED", ERR_LIB_PROV, PROV_R_NOT_SUPPORTED}, +- #else +- {"NOT_SUPPORTED", 57, 136}, +- #endif +- #ifdef PROV_R_NOT_XOF_OR_INVALID_LENGTH +- {"NOT_XOF_OR_INVALID_LENGTH", ERR_LIB_PROV, PROV_R_NOT_XOF_OR_INVALID_LENGTH}, +- #else +- {"NOT_XOF_OR_INVALID_LENGTH", 57, 113}, +- #endif +- #ifdef PROV_R_NO_KEY_SET +- {"NO_KEY_SET", ERR_LIB_PROV, PROV_R_NO_KEY_SET}, +- #else +- {"NO_KEY_SET", 57, 114}, +- #endif +- #ifdef PROV_R_NO_PARAMETERS_SET +- {"NO_PARAMETERS_SET", ERR_LIB_PROV, PROV_R_NO_PARAMETERS_SET}, +- #else +- {"NO_PARAMETERS_SET", 57, 177}, +- #endif +- #ifdef PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE +- {"OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE", ERR_LIB_PROV, PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE}, +- #else +- {"OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE", 57, 178}, +- #endif +- #ifdef PROV_R_OUTPUT_BUFFER_TOO_SMALL +- {"OUTPUT_BUFFER_TOO_SMALL", ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL}, +- #else +- {"OUTPUT_BUFFER_TOO_SMALL", 57, 106}, +- #endif +- #ifdef PROV_R_PARENT_CANNOT_GENERATE_RANDOM_NUMBERS +- {"PARENT_CANNOT_GENERATE_RANDOM_NUMBERS", ERR_LIB_PROV, PROV_R_PARENT_CANNOT_GENERATE_RANDOM_NUMBERS}, +- #else +- {"PARENT_CANNOT_GENERATE_RANDOM_NUMBERS", 57, 228}, +- #endif +- #ifdef PROV_R_PARENT_CANNOT_SUPPLY_ENTROPY_SEED +- {"PARENT_CANNOT_SUPPLY_ENTROPY_SEED", ERR_LIB_PROV, PROV_R_PARENT_CANNOT_SUPPLY_ENTROPY_SEED}, +- #else +- {"PARENT_CANNOT_SUPPLY_ENTROPY_SEED", 57, 187}, +- #endif +- #ifdef PROV_R_PARENT_LOCKING_NOT_ENABLED +- {"PARENT_LOCKING_NOT_ENABLED", ERR_LIB_PROV, PROV_R_PARENT_LOCKING_NOT_ENABLED}, +- #else +- {"PARENT_LOCKING_NOT_ENABLED", 57, 182}, +- #endif +- #ifdef PROV_R_PARENT_STRENGTH_TOO_WEAK +- {"PARENT_STRENGTH_TOO_WEAK", ERR_LIB_PROV, PROV_R_PARENT_STRENGTH_TOO_WEAK}, +- #else +- {"PARENT_STRENGTH_TOO_WEAK", 57, 194}, +- #endif +- #ifdef PROV_R_PATH_MUST_BE_ABSOLUTE +- {"PATH_MUST_BE_ABSOLUTE", ERR_LIB_PROV, PROV_R_PATH_MUST_BE_ABSOLUTE}, +- #else +- {"PATH_MUST_BE_ABSOLUTE", 57, 219}, +- #endif +- #ifdef PROV_R_PERSONALISATION_STRING_TOO_LONG +- {"PERSONALISATION_STRING_TOO_LONG", ERR_LIB_PROV, PROV_R_PERSONALISATION_STRING_TOO_LONG}, +- #else +- {"PERSONALISATION_STRING_TOO_LONG", 57, 195}, +- #endif +- #ifdef PROV_R_PSS_SALTLEN_TOO_SMALL +- {"PSS_SALTLEN_TOO_SMALL", ERR_LIB_PROV, PROV_R_PSS_SALTLEN_TOO_SMALL}, +- #else +- {"PSS_SALTLEN_TOO_SMALL", 57, 172}, +- #endif +- #ifdef PROV_R_REQUEST_TOO_LARGE_FOR_DRBG +- {"REQUEST_TOO_LARGE_FOR_DRBG", ERR_LIB_PROV, PROV_R_REQUEST_TOO_LARGE_FOR_DRBG}, +- #else +- {"REQUEST_TOO_LARGE_FOR_DRBG", 57, 196}, +- #endif +- #ifdef PROV_R_REQUIRE_CTR_MODE_CIPHER +- {"REQUIRE_CTR_MODE_CIPHER", ERR_LIB_PROV, PROV_R_REQUIRE_CTR_MODE_CIPHER}, +- #else +- {"REQUIRE_CTR_MODE_CIPHER", 57, 206}, +- #endif +- #ifdef PROV_R_RESEED_ERROR +- {"RESEED_ERROR", ERR_LIB_PROV, PROV_R_RESEED_ERROR}, +- #else +- {"RESEED_ERROR", 57, 197}, +- #endif +- #ifdef PROV_R_SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES +- {"SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES", ERR_LIB_PROV, PROV_R_SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES}, +- #else +- {"SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES", 57, 222}, +- #endif +- #ifdef PROV_R_SEED_SOURCES_MUST_NOT_HAVE_A_PARENT +- {"SEED_SOURCES_MUST_NOT_HAVE_A_PARENT", ERR_LIB_PROV, PROV_R_SEED_SOURCES_MUST_NOT_HAVE_A_PARENT}, +- #else +- {"SEED_SOURCES_MUST_NOT_HAVE_A_PARENT", 57, 229}, +- #endif +- #ifdef PROV_R_SELF_TEST_KAT_FAILURE +- {"SELF_TEST_KAT_FAILURE", ERR_LIB_PROV, PROV_R_SELF_TEST_KAT_FAILURE}, +- #else +- {"SELF_TEST_KAT_FAILURE", 57, 215}, +- #endif +- #ifdef PROV_R_SELF_TEST_POST_FAILURE +- {"SELF_TEST_POST_FAILURE", ERR_LIB_PROV, PROV_R_SELF_TEST_POST_FAILURE}, +- #else +- {"SELF_TEST_POST_FAILURE", 57, 216}, +- #endif +- #ifdef PROV_R_TAG_NOT_NEEDED +- {"TAG_NOT_NEEDED", ERR_LIB_PROV, PROV_R_TAG_NOT_NEEDED}, +- #else +- {"TAG_NOT_NEEDED", 57, 120}, +- #endif +- #ifdef PROV_R_TAG_NOT_SET +- {"TAG_NOT_SET", ERR_LIB_PROV, PROV_R_TAG_NOT_SET}, +- #else +- {"TAG_NOT_SET", 57, 119}, +- #endif +- #ifdef PROV_R_TOO_MANY_RECORDS +- {"TOO_MANY_RECORDS", ERR_LIB_PROV, PROV_R_TOO_MANY_RECORDS}, +- #else +- {"TOO_MANY_RECORDS", 57, 126}, +- #endif +- #ifdef PROV_R_UNABLE_TO_FIND_CIPHERS +- {"UNABLE_TO_FIND_CIPHERS", ERR_LIB_PROV, PROV_R_UNABLE_TO_FIND_CIPHERS}, +- #else +- {"UNABLE_TO_FIND_CIPHERS", 57, 207}, +- #endif +- #ifdef PROV_R_UNABLE_TO_GET_PARENT_STRENGTH +- {"UNABLE_TO_GET_PARENT_STRENGTH", ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_PARENT_STRENGTH}, +- #else +- {"UNABLE_TO_GET_PARENT_STRENGTH", 57, 199}, +- #endif +- #ifdef PROV_R_UNABLE_TO_GET_PASSPHRASE +- {"UNABLE_TO_GET_PASSPHRASE", ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_PASSPHRASE}, +- #else +- {"UNABLE_TO_GET_PASSPHRASE", 57, 159}, +- #endif +- #ifdef PROV_R_UNABLE_TO_INITIALISE_CIPHERS +- {"UNABLE_TO_INITIALISE_CIPHERS", ERR_LIB_PROV, PROV_R_UNABLE_TO_INITIALISE_CIPHERS}, +- #else +- {"UNABLE_TO_INITIALISE_CIPHERS", 57, 208}, +- #endif +- #ifdef PROV_R_UNABLE_TO_LOAD_SHA256 +- {"UNABLE_TO_LOAD_SHA256", ERR_LIB_PROV, PROV_R_UNABLE_TO_LOAD_SHA256}, +- #else +- {"UNABLE_TO_LOAD_SHA256", 57, 147}, +- #endif +- #ifdef PROV_R_UNABLE_TO_LOCK_PARENT +- {"UNABLE_TO_LOCK_PARENT", ERR_LIB_PROV, PROV_R_UNABLE_TO_LOCK_PARENT}, +- #else +- {"UNABLE_TO_LOCK_PARENT", 57, 201}, +- #endif +- #ifdef PROV_R_UNABLE_TO_RESEED +- {"UNABLE_TO_RESEED", ERR_LIB_PROV, PROV_R_UNABLE_TO_RESEED}, +- #else +- {"UNABLE_TO_RESEED", 57, 204}, +- #endif +- #ifdef PROV_R_UNSUPPORTED_CEK_ALG +- {"UNSUPPORTED_CEK_ALG", ERR_LIB_PROV, PROV_R_UNSUPPORTED_CEK_ALG}, +- #else +- {"UNSUPPORTED_CEK_ALG", 57, 145}, +- #endif +- #ifdef PROV_R_UNSUPPORTED_KEY_SIZE +- {"UNSUPPORTED_KEY_SIZE", ERR_LIB_PROV, PROV_R_UNSUPPORTED_KEY_SIZE}, +- #else +- {"UNSUPPORTED_KEY_SIZE", 57, 153}, +- #endif +- #ifdef PROV_R_UNSUPPORTED_MAC_TYPE +- {"UNSUPPORTED_MAC_TYPE", ERR_LIB_PROV, PROV_R_UNSUPPORTED_MAC_TYPE}, +- #else +- {"UNSUPPORTED_MAC_TYPE", 57, 137}, +- #endif +- #ifdef PROV_R_UNSUPPORTED_NUMBER_OF_ROUNDS +- {"UNSUPPORTED_NUMBER_OF_ROUNDS", ERR_LIB_PROV, PROV_R_UNSUPPORTED_NUMBER_OF_ROUNDS}, +- #else +- {"UNSUPPORTED_NUMBER_OF_ROUNDS", 57, 152}, +- #endif +- #ifdef PROV_R_URI_AUTHORITY_UNSUPPORTED +- {"URI_AUTHORITY_UNSUPPORTED", ERR_LIB_PROV, PROV_R_URI_AUTHORITY_UNSUPPORTED}, +- #else +- {"URI_AUTHORITY_UNSUPPORTED", 57, 223}, +- #endif +- #ifdef PROV_R_VALUE_ERROR +- {"VALUE_ERROR", ERR_LIB_PROV, PROV_R_VALUE_ERROR}, +- #else +- {"VALUE_ERROR", 57, 138}, +- #endif +- #ifdef PROV_R_WRONG_FINAL_BLOCK_LENGTH +- {"WRONG_FINAL_BLOCK_LENGTH", ERR_LIB_PROV, PROV_R_WRONG_FINAL_BLOCK_LENGTH}, +- #else +- {"WRONG_FINAL_BLOCK_LENGTH", 57, 107}, +- #endif +- #ifdef PROV_R_WRONG_OUTPUT_BUFFER_SIZE +- {"WRONG_OUTPUT_BUFFER_SIZE", ERR_LIB_PROV, PROV_R_WRONG_OUTPUT_BUFFER_SIZE}, +- #else +- {"WRONG_OUTPUT_BUFFER_SIZE", 57, 139}, +- #endif +- #ifdef PROV_R_XOF_DIGESTS_NOT_ALLOWED +- {"XOF_DIGESTS_NOT_ALLOWED", ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED}, +- #else +- {"XOF_DIGESTS_NOT_ALLOWED", 57, 183}, +- #endif +- #ifdef PROV_R_XTS_DATA_UNIT_IS_TOO_LARGE +- {"XTS_DATA_UNIT_IS_TOO_LARGE", ERR_LIB_PROV, PROV_R_XTS_DATA_UNIT_IS_TOO_LARGE}, +- #else +- {"XTS_DATA_UNIT_IS_TOO_LARGE", 57, 148}, +- #endif +- #ifdef PROV_R_XTS_DUPLICATED_KEYS +- {"XTS_DUPLICATED_KEYS", ERR_LIB_PROV, PROV_R_XTS_DUPLICATED_KEYS}, +- #else +- {"XTS_DUPLICATED_KEYS", 57, 149}, +- #endif +- #ifdef RAND_R_ADDITIONAL_INPUT_TOO_LONG +- {"ADDITIONAL_INPUT_TOO_LONG", ERR_LIB_RAND, RAND_R_ADDITIONAL_INPUT_TOO_LONG}, +- #else +- {"ADDITIONAL_INPUT_TOO_LONG", 36, 102}, +- #endif +- #ifdef RAND_R_ALREADY_INSTANTIATED +- {"ALREADY_INSTANTIATED", ERR_LIB_RAND, RAND_R_ALREADY_INSTANTIATED}, +- #else +- {"ALREADY_INSTANTIATED", 36, 103}, +- #endif +- #ifdef RAND_R_ARGUMENT_OUT_OF_RANGE +- {"ARGUMENT_OUT_OF_RANGE", ERR_LIB_RAND, RAND_R_ARGUMENT_OUT_OF_RANGE}, +- #else +- {"ARGUMENT_OUT_OF_RANGE", 36, 105}, +- #endif +- #ifdef RAND_R_CANNOT_OPEN_FILE +- {"CANNOT_OPEN_FILE", ERR_LIB_RAND, RAND_R_CANNOT_OPEN_FILE}, +- #else +- {"CANNOT_OPEN_FILE", 36, 121}, +- #endif +- #ifdef RAND_R_DRBG_ALREADY_INITIALIZED +- {"DRBG_ALREADY_INITIALIZED", ERR_LIB_RAND, RAND_R_DRBG_ALREADY_INITIALIZED}, +- #else +- {"DRBG_ALREADY_INITIALIZED", 36, 129}, +- #endif +- #ifdef RAND_R_DRBG_NOT_INITIALISED +- {"DRBG_NOT_INITIALISED", ERR_LIB_RAND, RAND_R_DRBG_NOT_INITIALISED}, +- #else +- {"DRBG_NOT_INITIALISED", 36, 104}, +- #endif +- #ifdef RAND_R_ENTROPY_INPUT_TOO_LONG +- {"ENTROPY_INPUT_TOO_LONG", ERR_LIB_RAND, RAND_R_ENTROPY_INPUT_TOO_LONG}, +- #else +- {"ENTROPY_INPUT_TOO_LONG", 36, 106}, +- #endif +- #ifdef RAND_R_ENTROPY_OUT_OF_RANGE +- {"ENTROPY_OUT_OF_RANGE", ERR_LIB_RAND, RAND_R_ENTROPY_OUT_OF_RANGE}, +- #else +- {"ENTROPY_OUT_OF_RANGE", 36, 124}, +- #endif +- #ifdef RAND_R_ERROR_ENTROPY_POOL_WAS_IGNORED +- {"ERROR_ENTROPY_POOL_WAS_IGNORED", ERR_LIB_RAND, RAND_R_ERROR_ENTROPY_POOL_WAS_IGNORED}, +- #else +- {"ERROR_ENTROPY_POOL_WAS_IGNORED", 36, 127}, +- #endif +- #ifdef RAND_R_ERROR_INITIALISING_DRBG +- {"ERROR_INITIALISING_DRBG", ERR_LIB_RAND, RAND_R_ERROR_INITIALISING_DRBG}, +- #else +- {"ERROR_INITIALISING_DRBG", 36, 107}, +- #endif +- #ifdef RAND_R_ERROR_INSTANTIATING_DRBG +- {"ERROR_INSTANTIATING_DRBG", ERR_LIB_RAND, RAND_R_ERROR_INSTANTIATING_DRBG}, +- #else +- {"ERROR_INSTANTIATING_DRBG", 36, 108}, +- #endif +- #ifdef RAND_R_ERROR_RETRIEVING_ADDITIONAL_INPUT +- {"ERROR_RETRIEVING_ADDITIONAL_INPUT", ERR_LIB_RAND, RAND_R_ERROR_RETRIEVING_ADDITIONAL_INPUT}, +- #else +- {"ERROR_RETRIEVING_ADDITIONAL_INPUT", 36, 109}, +- #endif +- #ifdef RAND_R_ERROR_RETRIEVING_ENTROPY +- {"ERROR_RETRIEVING_ENTROPY", ERR_LIB_RAND, RAND_R_ERROR_RETRIEVING_ENTROPY}, +- #else +- {"ERROR_RETRIEVING_ENTROPY", 36, 110}, +- #endif +- #ifdef RAND_R_ERROR_RETRIEVING_NONCE +- {"ERROR_RETRIEVING_NONCE", ERR_LIB_RAND, RAND_R_ERROR_RETRIEVING_NONCE}, +- #else +- {"ERROR_RETRIEVING_NONCE", 36, 111}, +- #endif +- #ifdef RAND_R_FAILED_TO_CREATE_LOCK +- {"FAILED_TO_CREATE_LOCK", ERR_LIB_RAND, RAND_R_FAILED_TO_CREATE_LOCK}, +- #else +- {"FAILED_TO_CREATE_LOCK", 36, 126}, +- #endif +- #ifdef RAND_R_FUNC_NOT_IMPLEMENTED +- {"FUNC_NOT_IMPLEMENTED", ERR_LIB_RAND, RAND_R_FUNC_NOT_IMPLEMENTED}, +- #else +- {"FUNC_NOT_IMPLEMENTED", 36, 101}, +- #endif +- #ifdef RAND_R_FWRITE_ERROR +- {"FWRITE_ERROR", ERR_LIB_RAND, RAND_R_FWRITE_ERROR}, +- #else +- {"FWRITE_ERROR", 36, 123}, +- #endif +- #ifdef RAND_R_GENERATE_ERROR +- {"GENERATE_ERROR", ERR_LIB_RAND, RAND_R_GENERATE_ERROR}, +- #else +- {"GENERATE_ERROR", 36, 112}, +- #endif +- #ifdef RAND_R_INSUFFICIENT_DRBG_STRENGTH +- {"INSUFFICIENT_DRBG_STRENGTH", ERR_LIB_RAND, RAND_R_INSUFFICIENT_DRBG_STRENGTH}, +- #else +- {"INSUFFICIENT_DRBG_STRENGTH", 36, 139}, +- #endif +- #ifdef RAND_R_INTERNAL_ERROR +- {"INTERNAL_ERROR", ERR_LIB_RAND, RAND_R_INTERNAL_ERROR}, +- #else +- {"INTERNAL_ERROR", 36, 113}, +- #endif +- #ifdef RAND_R_IN_ERROR_STATE +- {"IN_ERROR_STATE", ERR_LIB_RAND, RAND_R_IN_ERROR_STATE}, +- #else +- {"IN_ERROR_STATE", 36, 114}, +- #endif +- #ifdef RAND_R_NOT_A_REGULAR_FILE +- {"NOT_A_REGULAR_FILE", ERR_LIB_RAND, RAND_R_NOT_A_REGULAR_FILE}, +- #else +- {"NOT_A_REGULAR_FILE", 36, 122}, +- #endif +- #ifdef RAND_R_NOT_INSTANTIATED +- {"NOT_INSTANTIATED", ERR_LIB_RAND, RAND_R_NOT_INSTANTIATED}, +- #else +- {"NOT_INSTANTIATED", 36, 115}, +- #endif +- #ifdef RAND_R_NO_DRBG_IMPLEMENTATION_SELECTED +- {"NO_DRBG_IMPLEMENTATION_SELECTED", ERR_LIB_RAND, RAND_R_NO_DRBG_IMPLEMENTATION_SELECTED}, +- #else +- {"NO_DRBG_IMPLEMENTATION_SELECTED", 36, 128}, +- #endif +- #ifdef RAND_R_PARENT_LOCKING_NOT_ENABLED +- {"PARENT_LOCKING_NOT_ENABLED", ERR_LIB_RAND, RAND_R_PARENT_LOCKING_NOT_ENABLED}, +- #else +- {"PARENT_LOCKING_NOT_ENABLED", 36, 130}, +- #endif +- #ifdef RAND_R_PARENT_STRENGTH_TOO_WEAK +- {"PARENT_STRENGTH_TOO_WEAK", ERR_LIB_RAND, RAND_R_PARENT_STRENGTH_TOO_WEAK}, +- #else +- {"PARENT_STRENGTH_TOO_WEAK", 36, 131}, +- #endif +- #ifdef RAND_R_PERSONALISATION_STRING_TOO_LONG +- {"PERSONALISATION_STRING_TOO_LONG", ERR_LIB_RAND, RAND_R_PERSONALISATION_STRING_TOO_LONG}, +- #else +- {"PERSONALISATION_STRING_TOO_LONG", 36, 116}, +- #endif +- #ifdef RAND_R_PREDICTION_RESISTANCE_NOT_SUPPORTED +- {"PREDICTION_RESISTANCE_NOT_SUPPORTED", ERR_LIB_RAND, RAND_R_PREDICTION_RESISTANCE_NOT_SUPPORTED}, +- #else +- {"PREDICTION_RESISTANCE_NOT_SUPPORTED", 36, 133}, +- #endif +- #ifdef RAND_R_PRNG_NOT_SEEDED +- {"PRNG_NOT_SEEDED", ERR_LIB_RAND, RAND_R_PRNG_NOT_SEEDED}, +- #else +- {"PRNG_NOT_SEEDED", 36, 100}, +- #endif +- #ifdef RAND_R_RANDOM_POOL_OVERFLOW +- {"RANDOM_POOL_OVERFLOW", ERR_LIB_RAND, RAND_R_RANDOM_POOL_OVERFLOW}, +- #else +- {"RANDOM_POOL_OVERFLOW", 36, 125}, +- #endif +- #ifdef RAND_R_RANDOM_POOL_UNDERFLOW +- {"RANDOM_POOL_UNDERFLOW", ERR_LIB_RAND, RAND_R_RANDOM_POOL_UNDERFLOW}, +- #else +- {"RANDOM_POOL_UNDERFLOW", 36, 134}, +- #endif +- #ifdef RAND_R_REQUEST_TOO_LARGE_FOR_DRBG +- {"REQUEST_TOO_LARGE_FOR_DRBG", ERR_LIB_RAND, RAND_R_REQUEST_TOO_LARGE_FOR_DRBG}, +- #else +- {"REQUEST_TOO_LARGE_FOR_DRBG", 36, 117}, +- #endif +- #ifdef RAND_R_RESEED_ERROR +- {"RESEED_ERROR", ERR_LIB_RAND, RAND_R_RESEED_ERROR}, +- #else +- {"RESEED_ERROR", 36, 118}, +- #endif +- #ifdef RAND_R_SELFTEST_FAILURE +- {"SELFTEST_FAILURE", ERR_LIB_RAND, RAND_R_SELFTEST_FAILURE}, +- #else +- {"SELFTEST_FAILURE", 36, 119}, +- #endif +- #ifdef RAND_R_TOO_LITTLE_NONCE_REQUESTED +- {"TOO_LITTLE_NONCE_REQUESTED", ERR_LIB_RAND, RAND_R_TOO_LITTLE_NONCE_REQUESTED}, +- #else +- {"TOO_LITTLE_NONCE_REQUESTED", 36, 135}, +- #endif +- #ifdef RAND_R_TOO_MUCH_NONCE_REQUESTED +- {"TOO_MUCH_NONCE_REQUESTED", ERR_LIB_RAND, RAND_R_TOO_MUCH_NONCE_REQUESTED}, +- #else +- {"TOO_MUCH_NONCE_REQUESTED", 36, 136}, +- #endif +- #ifdef RAND_R_UNABLE_TO_CREATE_DRBG +- {"UNABLE_TO_CREATE_DRBG", ERR_LIB_RAND, RAND_R_UNABLE_TO_CREATE_DRBG}, +- #else +- {"UNABLE_TO_CREATE_DRBG", 36, 143}, +- #endif +- #ifdef RAND_R_UNABLE_TO_FETCH_DRBG +- {"UNABLE_TO_FETCH_DRBG", ERR_LIB_RAND, RAND_R_UNABLE_TO_FETCH_DRBG}, +- #else +- {"UNABLE_TO_FETCH_DRBG", 36, 144}, +- #endif +- #ifdef RAND_R_UNABLE_TO_GET_PARENT_RESEED_PROP_COUNTER +- {"UNABLE_TO_GET_PARENT_RESEED_PROP_COUNTER", ERR_LIB_RAND, RAND_R_UNABLE_TO_GET_PARENT_RESEED_PROP_COUNTER}, +- #else +- {"UNABLE_TO_GET_PARENT_RESEED_PROP_COUNTER", 36, 141}, +- #endif +- #ifdef RAND_R_UNABLE_TO_GET_PARENT_STRENGTH +- {"UNABLE_TO_GET_PARENT_STRENGTH", ERR_LIB_RAND, RAND_R_UNABLE_TO_GET_PARENT_STRENGTH}, +- #else +- {"UNABLE_TO_GET_PARENT_STRENGTH", 36, 138}, +- #endif +- #ifdef RAND_R_UNABLE_TO_LOCK_PARENT +- {"UNABLE_TO_LOCK_PARENT", ERR_LIB_RAND, RAND_R_UNABLE_TO_LOCK_PARENT}, +- #else +- {"UNABLE_TO_LOCK_PARENT", 36, 140}, +- #endif +- #ifdef RAND_R_UNSUPPORTED_DRBG_FLAGS +- {"UNSUPPORTED_DRBG_FLAGS", ERR_LIB_RAND, RAND_R_UNSUPPORTED_DRBG_FLAGS}, +- #else +- {"UNSUPPORTED_DRBG_FLAGS", 36, 132}, +- #endif +- #ifdef RAND_R_UNSUPPORTED_DRBG_TYPE +- {"UNSUPPORTED_DRBG_TYPE", ERR_LIB_RAND, RAND_R_UNSUPPORTED_DRBG_TYPE}, +- #else +- {"UNSUPPORTED_DRBG_TYPE", 36, 120}, +- #endif +- #ifdef RSA_R_ALGORITHM_MISMATCH +- {"ALGORITHM_MISMATCH", ERR_LIB_RSA, RSA_R_ALGORITHM_MISMATCH}, +- #else +- {"ALGORITHM_MISMATCH", 4, 100}, +- #endif +- #ifdef RSA_R_BAD_E_VALUE +- {"BAD_E_VALUE", ERR_LIB_RSA, RSA_R_BAD_E_VALUE}, +- #else +- {"BAD_E_VALUE", 4, 101}, +- #endif +- #ifdef RSA_R_BAD_FIXED_HEADER_DECRYPT +- {"BAD_FIXED_HEADER_DECRYPT", ERR_LIB_RSA, RSA_R_BAD_FIXED_HEADER_DECRYPT}, +- #else +- {"BAD_FIXED_HEADER_DECRYPT", 4, 102}, +- #endif +- #ifdef RSA_R_BAD_PAD_BYTE_COUNT +- {"BAD_PAD_BYTE_COUNT", ERR_LIB_RSA, RSA_R_BAD_PAD_BYTE_COUNT}, +- #else +- {"BAD_PAD_BYTE_COUNT", 4, 103}, +- #endif +- #ifdef RSA_R_BAD_SIGNATURE +- {"BAD_SIGNATURE", ERR_LIB_RSA, RSA_R_BAD_SIGNATURE}, +- #else +- {"BAD_SIGNATURE", 4, 104}, +- #endif +- #ifdef RSA_R_BLOCK_TYPE_IS_NOT_01 +- {"BLOCK_TYPE_IS_NOT_01", ERR_LIB_RSA, RSA_R_BLOCK_TYPE_IS_NOT_01}, +- #else +- {"BLOCK_TYPE_IS_NOT_01", 4, 106}, +- #endif +- #ifdef RSA_R_BLOCK_TYPE_IS_NOT_02 +- {"BLOCK_TYPE_IS_NOT_02", ERR_LIB_RSA, RSA_R_BLOCK_TYPE_IS_NOT_02}, +- #else +- {"BLOCK_TYPE_IS_NOT_02", 4, 107}, +- #endif +- #ifdef RSA_R_DATA_GREATER_THAN_MOD_LEN +- {"DATA_GREATER_THAN_MOD_LEN", ERR_LIB_RSA, RSA_R_DATA_GREATER_THAN_MOD_LEN}, +- #else +- {"DATA_GREATER_THAN_MOD_LEN", 4, 108}, +- #endif +- #ifdef RSA_R_DATA_TOO_LARGE +- {"DATA_TOO_LARGE", ERR_LIB_RSA, RSA_R_DATA_TOO_LARGE}, +- #else +- {"DATA_TOO_LARGE", 4, 109}, +- #endif +- #ifdef RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE +- {"DATA_TOO_LARGE_FOR_KEY_SIZE", ERR_LIB_RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE}, +- #else +- {"DATA_TOO_LARGE_FOR_KEY_SIZE", 4, 110}, +- #endif +- #ifdef RSA_R_DATA_TOO_LARGE_FOR_MODULUS +- {"DATA_TOO_LARGE_FOR_MODULUS", ERR_LIB_RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS}, +- #else +- {"DATA_TOO_LARGE_FOR_MODULUS", 4, 132}, +- #endif +- #ifdef RSA_R_DATA_TOO_SMALL +- {"DATA_TOO_SMALL", ERR_LIB_RSA, RSA_R_DATA_TOO_SMALL}, +- #else +- {"DATA_TOO_SMALL", 4, 111}, +- #endif +- #ifdef RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE +- {"DATA_TOO_SMALL_FOR_KEY_SIZE", ERR_LIB_RSA, RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE}, +- #else +- {"DATA_TOO_SMALL_FOR_KEY_SIZE", 4, 122}, +- #endif +- #ifdef RSA_R_DIGEST_DOES_NOT_MATCH +- {"DIGEST_DOES_NOT_MATCH", ERR_LIB_RSA, RSA_R_DIGEST_DOES_NOT_MATCH}, +- #else +- {"DIGEST_DOES_NOT_MATCH", 4, 158}, +- #endif +- #ifdef RSA_R_DIGEST_NOT_ALLOWED +- {"DIGEST_NOT_ALLOWED", ERR_LIB_RSA, RSA_R_DIGEST_NOT_ALLOWED}, +- #else +- {"DIGEST_NOT_ALLOWED", 4, 145}, +- #endif +- #ifdef RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY +- {"DIGEST_TOO_BIG_FOR_RSA_KEY", ERR_LIB_RSA, RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY}, +- #else +- {"DIGEST_TOO_BIG_FOR_RSA_KEY", 4, 112}, +- #endif +- #ifdef RSA_R_DMP1_NOT_CONGRUENT_TO_D +- {"DMP1_NOT_CONGRUENT_TO_D", ERR_LIB_RSA, RSA_R_DMP1_NOT_CONGRUENT_TO_D}, +- #else +- {"DMP1_NOT_CONGRUENT_TO_D", 4, 124}, +- #endif +- #ifdef RSA_R_DMQ1_NOT_CONGRUENT_TO_D +- {"DMQ1_NOT_CONGRUENT_TO_D", ERR_LIB_RSA, RSA_R_DMQ1_NOT_CONGRUENT_TO_D}, +- #else +- {"DMQ1_NOT_CONGRUENT_TO_D", 4, 125}, +- #endif +- #ifdef RSA_R_D_E_NOT_CONGRUENT_TO_1 +- {"D_E_NOT_CONGRUENT_TO_1", ERR_LIB_RSA, RSA_R_D_E_NOT_CONGRUENT_TO_1}, +- #else +- {"D_E_NOT_CONGRUENT_TO_1", 4, 123}, +- #endif +- #ifdef RSA_R_FIRST_OCTET_INVALID +- {"FIRST_OCTET_INVALID", ERR_LIB_RSA, RSA_R_FIRST_OCTET_INVALID}, +- #else +- {"FIRST_OCTET_INVALID", 4, 133}, +- #endif +- #ifdef RSA_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE +- {"ILLEGAL_OR_UNSUPPORTED_PADDING_MODE", ERR_LIB_RSA, RSA_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE}, +- #else +- {"ILLEGAL_OR_UNSUPPORTED_PADDING_MODE", 4, 144}, +- #endif +- #ifdef RSA_R_INVALID_DIGEST +- {"INVALID_DIGEST", ERR_LIB_RSA, RSA_R_INVALID_DIGEST}, +- #else +- {"INVALID_DIGEST", 4, 157}, +- #endif +- #ifdef RSA_R_INVALID_DIGEST_LENGTH +- {"INVALID_DIGEST_LENGTH", ERR_LIB_RSA, RSA_R_INVALID_DIGEST_LENGTH}, +- #else +- {"INVALID_DIGEST_LENGTH", 4, 143}, +- #endif +- #ifdef RSA_R_INVALID_HEADER +- {"INVALID_HEADER", ERR_LIB_RSA, RSA_R_INVALID_HEADER}, +- #else +- {"INVALID_HEADER", 4, 137}, +- #endif +- #ifdef RSA_R_INVALID_KEYPAIR +- {"INVALID_KEYPAIR", ERR_LIB_RSA, RSA_R_INVALID_KEYPAIR}, +- #else +- {"INVALID_KEYPAIR", 4, 171}, +- #endif +- #ifdef RSA_R_INVALID_KEY_LENGTH +- {"INVALID_KEY_LENGTH", ERR_LIB_RSA, RSA_R_INVALID_KEY_LENGTH}, +- #else +- {"INVALID_KEY_LENGTH", 4, 173}, +- #endif +- #ifdef RSA_R_INVALID_LABEL +- {"INVALID_LABEL", ERR_LIB_RSA, RSA_R_INVALID_LABEL}, +- #else +- {"INVALID_LABEL", 4, 160}, +- #endif +- #ifdef RSA_R_INVALID_LENGTH +- {"INVALID_LENGTH", ERR_LIB_RSA, RSA_R_INVALID_LENGTH}, +- #else +- {"INVALID_LENGTH", 4, 181}, +- #endif +- #ifdef RSA_R_INVALID_MESSAGE_LENGTH +- {"INVALID_MESSAGE_LENGTH", ERR_LIB_RSA, RSA_R_INVALID_MESSAGE_LENGTH}, +- #else +- {"INVALID_MESSAGE_LENGTH", 4, 131}, +- #endif +- #ifdef RSA_R_INVALID_MGF1_MD +- {"INVALID_MGF1_MD", ERR_LIB_RSA, RSA_R_INVALID_MGF1_MD}, +- #else +- {"INVALID_MGF1_MD", 4, 156}, +- #endif +- #ifdef RSA_R_INVALID_MODULUS +- {"INVALID_MODULUS", ERR_LIB_RSA, RSA_R_INVALID_MODULUS}, +- #else +- {"INVALID_MODULUS", 4, 174}, +- #endif +- #ifdef RSA_R_INVALID_MULTI_PRIME_KEY +- {"INVALID_MULTI_PRIME_KEY", ERR_LIB_RSA, RSA_R_INVALID_MULTI_PRIME_KEY}, +- #else +- {"INVALID_MULTI_PRIME_KEY", 4, 167}, +- #endif +- #ifdef RSA_R_INVALID_OAEP_PARAMETERS +- {"INVALID_OAEP_PARAMETERS", ERR_LIB_RSA, RSA_R_INVALID_OAEP_PARAMETERS}, +- #else +- {"INVALID_OAEP_PARAMETERS", 4, 161}, +- #endif +- #ifdef RSA_R_INVALID_PADDING +- {"INVALID_PADDING", ERR_LIB_RSA, RSA_R_INVALID_PADDING}, +- #else +- {"INVALID_PADDING", 4, 138}, +- #endif +- #ifdef RSA_R_INVALID_PADDING_MODE +- {"INVALID_PADDING_MODE", ERR_LIB_RSA, RSA_R_INVALID_PADDING_MODE}, +- #else +- {"INVALID_PADDING_MODE", 4, 141}, +- #endif +- #ifdef RSA_R_INVALID_PSS_PARAMETERS +- {"INVALID_PSS_PARAMETERS", ERR_LIB_RSA, RSA_R_INVALID_PSS_PARAMETERS}, +- #else +- {"INVALID_PSS_PARAMETERS", 4, 149}, +- #endif +- #ifdef RSA_R_INVALID_PSS_SALTLEN +- {"INVALID_PSS_SALTLEN", ERR_LIB_RSA, RSA_R_INVALID_PSS_SALTLEN}, +- #else +- {"INVALID_PSS_SALTLEN", 4, 146}, +- #endif +- #ifdef RSA_R_INVALID_REQUEST +- {"INVALID_REQUEST", ERR_LIB_RSA, RSA_R_INVALID_REQUEST}, +- #else +- {"INVALID_REQUEST", 4, 175}, +- #endif +- #ifdef RSA_R_INVALID_SALT_LENGTH +- {"INVALID_SALT_LENGTH", ERR_LIB_RSA, RSA_R_INVALID_SALT_LENGTH}, +- #else +- {"INVALID_SALT_LENGTH", 4, 150}, +- #endif +- #ifdef RSA_R_INVALID_STRENGTH +- {"INVALID_STRENGTH", ERR_LIB_RSA, RSA_R_INVALID_STRENGTH}, +- #else +- {"INVALID_STRENGTH", 4, 176}, +- #endif +- #ifdef RSA_R_INVALID_TRAILER +- {"INVALID_TRAILER", ERR_LIB_RSA, RSA_R_INVALID_TRAILER}, +- #else +- {"INVALID_TRAILER", 4, 139}, +- #endif +- #ifdef RSA_R_INVALID_X931_DIGEST +- {"INVALID_X931_DIGEST", ERR_LIB_RSA, RSA_R_INVALID_X931_DIGEST}, +- #else +- {"INVALID_X931_DIGEST", 4, 142}, +- #endif +- #ifdef RSA_R_IQMP_NOT_INVERSE_OF_Q +- {"IQMP_NOT_INVERSE_OF_Q", ERR_LIB_RSA, RSA_R_IQMP_NOT_INVERSE_OF_Q}, +- #else +- {"IQMP_NOT_INVERSE_OF_Q", 4, 126}, +- #endif +- #ifdef RSA_R_KEY_PRIME_NUM_INVALID +- {"KEY_PRIME_NUM_INVALID", ERR_LIB_RSA, RSA_R_KEY_PRIME_NUM_INVALID}, +- #else +- {"KEY_PRIME_NUM_INVALID", 4, 165}, +- #endif +- #ifdef RSA_R_KEY_SIZE_TOO_SMALL +- {"KEY_SIZE_TOO_SMALL", ERR_LIB_RSA, RSA_R_KEY_SIZE_TOO_SMALL}, +- #else +- {"KEY_SIZE_TOO_SMALL", 4, 120}, +- #endif +- #ifdef RSA_R_LAST_OCTET_INVALID +- {"LAST_OCTET_INVALID", ERR_LIB_RSA, RSA_R_LAST_OCTET_INVALID}, +- #else +- {"LAST_OCTET_INVALID", 4, 134}, +- #endif +- #ifdef RSA_R_MGF1_DIGEST_NOT_ALLOWED +- {"MGF1_DIGEST_NOT_ALLOWED", ERR_LIB_RSA, RSA_R_MGF1_DIGEST_NOT_ALLOWED}, +- #else +- {"MGF1_DIGEST_NOT_ALLOWED", 4, 152}, +- #endif +- #ifdef RSA_R_MISSING_PRIVATE_KEY +- {"MISSING_PRIVATE_KEY", ERR_LIB_RSA, RSA_R_MISSING_PRIVATE_KEY}, +- #else +- {"MISSING_PRIVATE_KEY", 4, 179}, +- #endif +- #ifdef RSA_R_MODULUS_TOO_LARGE +- {"MODULUS_TOO_LARGE", ERR_LIB_RSA, RSA_R_MODULUS_TOO_LARGE}, +- #else +- {"MODULUS_TOO_LARGE", 4, 105}, +- #endif +- #ifdef RSA_R_MP_COEFFICIENT_NOT_INVERSE_OF_R +- {"MP_COEFFICIENT_NOT_INVERSE_OF_R", ERR_LIB_RSA, RSA_R_MP_COEFFICIENT_NOT_INVERSE_OF_R}, +- #else +- {"MP_COEFFICIENT_NOT_INVERSE_OF_R", 4, 168}, +- #endif +- #ifdef RSA_R_MP_EXPONENT_NOT_CONGRUENT_TO_D +- {"MP_EXPONENT_NOT_CONGRUENT_TO_D", ERR_LIB_RSA, RSA_R_MP_EXPONENT_NOT_CONGRUENT_TO_D}, +- #else +- {"MP_EXPONENT_NOT_CONGRUENT_TO_D", 4, 169}, +- #endif +- #ifdef RSA_R_MP_R_NOT_PRIME +- {"MP_R_NOT_PRIME", ERR_LIB_RSA, RSA_R_MP_R_NOT_PRIME}, +- #else +- {"MP_R_NOT_PRIME", 4, 170}, +- #endif +- #ifdef RSA_R_NO_PUBLIC_EXPONENT +- {"NO_PUBLIC_EXPONENT", ERR_LIB_RSA, RSA_R_NO_PUBLIC_EXPONENT}, +- #else +- {"NO_PUBLIC_EXPONENT", 4, 140}, +- #endif +- #ifdef RSA_R_NULL_BEFORE_BLOCK_MISSING +- {"NULL_BEFORE_BLOCK_MISSING", ERR_LIB_RSA, RSA_R_NULL_BEFORE_BLOCK_MISSING}, +- #else +- {"NULL_BEFORE_BLOCK_MISSING", 4, 113}, +- #endif +- #ifdef RSA_R_N_DOES_NOT_EQUAL_PRODUCT_OF_PRIMES +- {"N_DOES_NOT_EQUAL_PRODUCT_OF_PRIMES", ERR_LIB_RSA, RSA_R_N_DOES_NOT_EQUAL_PRODUCT_OF_PRIMES}, +- #else +- {"N_DOES_NOT_EQUAL_PRODUCT_OF_PRIMES", 4, 172}, +- #endif +- #ifdef RSA_R_N_DOES_NOT_EQUAL_P_Q +- {"N_DOES_NOT_EQUAL_P_Q", ERR_LIB_RSA, RSA_R_N_DOES_NOT_EQUAL_P_Q}, +- #else +- {"N_DOES_NOT_EQUAL_P_Q", 4, 127}, +- #endif +- #ifdef RSA_R_OAEP_DECODING_ERROR +- {"OAEP_DECODING_ERROR", ERR_LIB_RSA, RSA_R_OAEP_DECODING_ERROR}, +- #else +- {"OAEP_DECODING_ERROR", 4, 121}, +- #endif +- #ifdef RSA_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE +- {"OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE", ERR_LIB_RSA, RSA_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE}, +- #else +- {"OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE", 4, 148}, +- #endif +- #ifdef RSA_R_PADDING_CHECK_FAILED +- {"PADDING_CHECK_FAILED", ERR_LIB_RSA, RSA_R_PADDING_CHECK_FAILED}, +- #else +- {"PADDING_CHECK_FAILED", 4, 114}, +- #endif +- #ifdef RSA_R_PAIRWISE_TEST_FAILURE +- {"PAIRWISE_TEST_FAILURE", ERR_LIB_RSA, RSA_R_PAIRWISE_TEST_FAILURE}, +- #else +- {"PAIRWISE_TEST_FAILURE", 4, 177}, +- #endif +- #ifdef RSA_R_PKCS_DECODING_ERROR +- {"PKCS_DECODING_ERROR", ERR_LIB_RSA, RSA_R_PKCS_DECODING_ERROR}, +- #else +- {"PKCS_DECODING_ERROR", 4, 159}, +- #endif +- #ifdef RSA_R_PSS_SALTLEN_TOO_SMALL +- {"PSS_SALTLEN_TOO_SMALL", ERR_LIB_RSA, RSA_R_PSS_SALTLEN_TOO_SMALL}, +- #else +- {"PSS_SALTLEN_TOO_SMALL", 4, 164}, +- #endif +- #ifdef RSA_R_PUB_EXPONENT_OUT_OF_RANGE +- {"PUB_EXPONENT_OUT_OF_RANGE", ERR_LIB_RSA, RSA_R_PUB_EXPONENT_OUT_OF_RANGE}, +- #else +- {"PUB_EXPONENT_OUT_OF_RANGE", 4, 178}, +- #endif +- #ifdef RSA_R_P_NOT_PRIME +- {"P_NOT_PRIME", ERR_LIB_RSA, RSA_R_P_NOT_PRIME}, +- #else +- {"P_NOT_PRIME", 4, 128}, +- #endif +- #ifdef RSA_R_Q_NOT_PRIME +- {"Q_NOT_PRIME", ERR_LIB_RSA, RSA_R_Q_NOT_PRIME}, +- #else +- {"Q_NOT_PRIME", 4, 129}, +- #endif +- #ifdef RSA_R_RANDOMNESS_SOURCE_STRENGTH_INSUFFICIENT +- {"RANDOMNESS_SOURCE_STRENGTH_INSUFFICIENT", ERR_LIB_RSA, RSA_R_RANDOMNESS_SOURCE_STRENGTH_INSUFFICIENT}, +- #else +- {"RANDOMNESS_SOURCE_STRENGTH_INSUFFICIENT", 4, 180}, +- #endif +- #ifdef RSA_R_RSA_OPERATIONS_NOT_SUPPORTED +- {"RSA_OPERATIONS_NOT_SUPPORTED", ERR_LIB_RSA, RSA_R_RSA_OPERATIONS_NOT_SUPPORTED}, +- #else +- {"RSA_OPERATIONS_NOT_SUPPORTED", 4, 130}, +- #endif +- #ifdef RSA_R_SLEN_CHECK_FAILED +- {"SLEN_CHECK_FAILED", ERR_LIB_RSA, RSA_R_SLEN_CHECK_FAILED}, +- #else +- {"SLEN_CHECK_FAILED", 4, 136}, +- #endif +- #ifdef RSA_R_SLEN_RECOVERY_FAILED +- {"SLEN_RECOVERY_FAILED", ERR_LIB_RSA, RSA_R_SLEN_RECOVERY_FAILED}, +- #else +- {"SLEN_RECOVERY_FAILED", 4, 135}, +- #endif +- #ifdef RSA_R_SSLV3_ROLLBACK_ATTACK +- {"SSLV3_ROLLBACK_ATTACK", ERR_LIB_RSA, RSA_R_SSLV3_ROLLBACK_ATTACK}, +- #else +- {"SSLV3_ROLLBACK_ATTACK", 4, 115}, +- #endif +- #ifdef RSA_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD +- {"THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD", ERR_LIB_RSA, RSA_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD}, +- #else +- {"THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD", 4, 116}, +- #endif +- #ifdef RSA_R_UNKNOWN_ALGORITHM_TYPE +- {"UNKNOWN_ALGORITHM_TYPE", ERR_LIB_RSA, RSA_R_UNKNOWN_ALGORITHM_TYPE}, +- #else +- {"UNKNOWN_ALGORITHM_TYPE", 4, 117}, +- #endif +- #ifdef RSA_R_UNKNOWN_DIGEST +- {"UNKNOWN_DIGEST", ERR_LIB_RSA, RSA_R_UNKNOWN_DIGEST}, +- #else +- {"UNKNOWN_DIGEST", 4, 166}, +- #endif +- #ifdef RSA_R_UNKNOWN_MASK_DIGEST +- {"UNKNOWN_MASK_DIGEST", ERR_LIB_RSA, RSA_R_UNKNOWN_MASK_DIGEST}, +- #else +- {"UNKNOWN_MASK_DIGEST", 4, 151}, +- #endif +- #ifdef RSA_R_UNKNOWN_PADDING_TYPE +- {"UNKNOWN_PADDING_TYPE", ERR_LIB_RSA, RSA_R_UNKNOWN_PADDING_TYPE}, +- #else +- {"UNKNOWN_PADDING_TYPE", 4, 118}, +- #endif +- #ifdef RSA_R_UNSUPPORTED_ENCRYPTION_TYPE +- {"UNSUPPORTED_ENCRYPTION_TYPE", ERR_LIB_RSA, RSA_R_UNSUPPORTED_ENCRYPTION_TYPE}, +- #else +- {"UNSUPPORTED_ENCRYPTION_TYPE", 4, 162}, +- #endif +- #ifdef RSA_R_UNSUPPORTED_LABEL_SOURCE +- {"UNSUPPORTED_LABEL_SOURCE", ERR_LIB_RSA, RSA_R_UNSUPPORTED_LABEL_SOURCE}, +- #else +- {"UNSUPPORTED_LABEL_SOURCE", 4, 163}, +- #endif +- #ifdef RSA_R_UNSUPPORTED_MASK_ALGORITHM +- {"UNSUPPORTED_MASK_ALGORITHM", ERR_LIB_RSA, RSA_R_UNSUPPORTED_MASK_ALGORITHM}, +- #else +- {"UNSUPPORTED_MASK_ALGORITHM", 4, 153}, +- #endif +- #ifdef RSA_R_UNSUPPORTED_MASK_PARAMETER +- {"UNSUPPORTED_MASK_PARAMETER", ERR_LIB_RSA, RSA_R_UNSUPPORTED_MASK_PARAMETER}, +- #else +- {"UNSUPPORTED_MASK_PARAMETER", 4, 154}, +- #endif +- #ifdef RSA_R_UNSUPPORTED_SIGNATURE_TYPE +- {"UNSUPPORTED_SIGNATURE_TYPE", ERR_LIB_RSA, RSA_R_UNSUPPORTED_SIGNATURE_TYPE}, +- #else +- {"UNSUPPORTED_SIGNATURE_TYPE", 4, 155}, +- #endif +- #ifdef RSA_R_VALUE_MISSING +- {"VALUE_MISSING", ERR_LIB_RSA, RSA_R_VALUE_MISSING}, +- #else +- {"VALUE_MISSING", 4, 147}, +- #endif +- #ifdef RSA_R_WRONG_SIGNATURE_LENGTH +- {"WRONG_SIGNATURE_LENGTH", ERR_LIB_RSA, RSA_R_WRONG_SIGNATURE_LENGTH}, +- #else +- {"WRONG_SIGNATURE_LENGTH", 4, 119}, +- #endif +- #ifdef SM2_R_ASN1_ERROR +- {"ASN1_ERROR", ERR_LIB_SM2, SM2_R_ASN1_ERROR}, +- #else +- {"ASN1_ERROR", 53, 100}, +- #endif +- #ifdef SM2_R_BAD_SIGNATURE +- {"BAD_SIGNATURE", ERR_LIB_SM2, SM2_R_BAD_SIGNATURE}, +- #else +- {"BAD_SIGNATURE", 53, 101}, +- #endif +- #ifdef SM2_R_BUFFER_TOO_SMALL +- {"BUFFER_TOO_SMALL", ERR_LIB_SM2, SM2_R_BUFFER_TOO_SMALL}, +- #else +- {"BUFFER_TOO_SMALL", 53, 107}, +- #endif +- #ifdef SM2_R_DIST_ID_TOO_LARGE +- {"DIST_ID_TOO_LARGE", ERR_LIB_SM2, SM2_R_DIST_ID_TOO_LARGE}, +- #else +- {"DIST_ID_TOO_LARGE", 53, 110}, +- #endif +- #ifdef SM2_R_ID_NOT_SET +- {"ID_NOT_SET", ERR_LIB_SM2, SM2_R_ID_NOT_SET}, +- #else +- {"ID_NOT_SET", 53, 112}, +- #endif +- #ifdef SM2_R_ID_TOO_LARGE +- {"ID_TOO_LARGE", ERR_LIB_SM2, SM2_R_ID_TOO_LARGE}, +- #else +- {"ID_TOO_LARGE", 53, 111}, +- #endif +- #ifdef SM2_R_INVALID_CURVE +- {"INVALID_CURVE", ERR_LIB_SM2, SM2_R_INVALID_CURVE}, +- #else +- {"INVALID_CURVE", 53, 108}, +- #endif +- #ifdef SM2_R_INVALID_DIGEST +- {"INVALID_DIGEST", ERR_LIB_SM2, SM2_R_INVALID_DIGEST}, +- #else +- {"INVALID_DIGEST", 53, 102}, +- #endif +- #ifdef SM2_R_INVALID_DIGEST_TYPE +- {"INVALID_DIGEST_TYPE", ERR_LIB_SM2, SM2_R_INVALID_DIGEST_TYPE}, +- #else +- {"INVALID_DIGEST_TYPE", 53, 103}, +- #endif +- #ifdef SM2_R_INVALID_ENCODING +- {"INVALID_ENCODING", ERR_LIB_SM2, SM2_R_INVALID_ENCODING}, +- #else +- {"INVALID_ENCODING", 53, 104}, +- #endif +- #ifdef SM2_R_INVALID_FIELD +- {"INVALID_FIELD", ERR_LIB_SM2, SM2_R_INVALID_FIELD}, +- #else +- {"INVALID_FIELD", 53, 105}, +- #endif +- #ifdef SM2_R_INVALID_PRIVATE_KEY +- {"INVALID_PRIVATE_KEY", ERR_LIB_SM2, SM2_R_INVALID_PRIVATE_KEY}, +- #else +- {"INVALID_PRIVATE_KEY", 53, 113}, +- #endif +- #ifdef SM2_R_NO_PARAMETERS_SET +- {"NO_PARAMETERS_SET", ERR_LIB_SM2, SM2_R_NO_PARAMETERS_SET}, +- #else +- {"NO_PARAMETERS_SET", 53, 109}, +- #endif +- #ifdef SM2_R_USER_ID_TOO_LARGE +- {"USER_ID_TOO_LARGE", ERR_LIB_SM2, SM2_R_USER_ID_TOO_LARGE}, +- #else +- {"USER_ID_TOO_LARGE", 53, 106}, +- #endif +- #ifdef SSL_R_APPLICATION_DATA_AFTER_CLOSE_NOTIFY +- {"APPLICATION_DATA_AFTER_CLOSE_NOTIFY", ERR_LIB_SSL, SSL_R_APPLICATION_DATA_AFTER_CLOSE_NOTIFY}, +- #else +- {"APPLICATION_DATA_AFTER_CLOSE_NOTIFY", 20, 291}, +- #endif +- #ifdef SSL_R_APP_DATA_IN_HANDSHAKE +- {"APP_DATA_IN_HANDSHAKE", ERR_LIB_SSL, SSL_R_APP_DATA_IN_HANDSHAKE}, +- #else +- {"APP_DATA_IN_HANDSHAKE", 20, 100}, +- #endif +- #ifdef SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT +- {"ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT", ERR_LIB_SSL, SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT}, +- #else +- {"ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT", 20, 272}, +- #endif +- #ifdef SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE +- {"AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE", ERR_LIB_SSL, SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE}, +- #else +- {"AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE", 20, 158}, +- #endif +- #ifdef SSL_R_BAD_CHANGE_CIPHER_SPEC +- {"BAD_CHANGE_CIPHER_SPEC", ERR_LIB_SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC}, +- #else +- {"BAD_CHANGE_CIPHER_SPEC", 20, 103}, +- #endif +- #ifdef SSL_R_BAD_CIPHER +- {"BAD_CIPHER", ERR_LIB_SSL, SSL_R_BAD_CIPHER}, +- #else +- {"BAD_CIPHER", 20, 186}, +- #endif +- #ifdef SSL_R_BAD_DATA +- {"BAD_DATA", ERR_LIB_SSL, SSL_R_BAD_DATA}, +- #else +- {"BAD_DATA", 20, 390}, +- #endif +- #ifdef SSL_R_BAD_DATA_RETURNED_BY_CALLBACK +- {"BAD_DATA_RETURNED_BY_CALLBACK", ERR_LIB_SSL, SSL_R_BAD_DATA_RETURNED_BY_CALLBACK}, +- #else +- {"BAD_DATA_RETURNED_BY_CALLBACK", 20, 106}, +- #endif +- #ifdef SSL_R_BAD_DECOMPRESSION +- {"BAD_DECOMPRESSION", ERR_LIB_SSL, SSL_R_BAD_DECOMPRESSION}, +- #else +- {"BAD_DECOMPRESSION", 20, 107}, +- #endif +- #ifdef SSL_R_BAD_DH_VALUE +- {"BAD_DH_VALUE", ERR_LIB_SSL, SSL_R_BAD_DH_VALUE}, +- #else +- {"BAD_DH_VALUE", 20, 102}, +- #endif +- #ifdef SSL_R_BAD_DIGEST_LENGTH +- {"BAD_DIGEST_LENGTH", ERR_LIB_SSL, SSL_R_BAD_DIGEST_LENGTH}, +- #else +- {"BAD_DIGEST_LENGTH", 20, 111}, +- #endif +- #ifdef SSL_R_BAD_EARLY_DATA +- {"BAD_EARLY_DATA", ERR_LIB_SSL, SSL_R_BAD_EARLY_DATA}, +- #else +- {"BAD_EARLY_DATA", 20, 233}, +- #endif +- #ifdef SSL_R_BAD_ECC_CERT +- {"BAD_ECC_CERT", ERR_LIB_SSL, SSL_R_BAD_ECC_CERT}, +- #else +- {"BAD_ECC_CERT", 20, 304}, +- #endif +- #ifdef SSL_R_BAD_ECPOINT +- {"BAD_ECPOINT", ERR_LIB_SSL, SSL_R_BAD_ECPOINT}, +- #else +- {"BAD_ECPOINT", 20, 306}, +- #endif +- #ifdef SSL_R_BAD_EXTENSION +- {"BAD_EXTENSION", ERR_LIB_SSL, SSL_R_BAD_EXTENSION}, +- #else +- {"BAD_EXTENSION", 20, 110}, +- #endif +- #ifdef SSL_R_BAD_HANDSHAKE_LENGTH +- {"BAD_HANDSHAKE_LENGTH", ERR_LIB_SSL, SSL_R_BAD_HANDSHAKE_LENGTH}, +- #else +- {"BAD_HANDSHAKE_LENGTH", 20, 332}, +- #endif +- #ifdef SSL_R_BAD_HANDSHAKE_STATE +- {"BAD_HANDSHAKE_STATE", ERR_LIB_SSL, SSL_R_BAD_HANDSHAKE_STATE}, +- #else +- {"BAD_HANDSHAKE_STATE", 20, 236}, +- #endif +- #ifdef SSL_R_BAD_HELLO_REQUEST +- {"BAD_HELLO_REQUEST", ERR_LIB_SSL, SSL_R_BAD_HELLO_REQUEST}, +- #else +- {"BAD_HELLO_REQUEST", 20, 105}, +- #endif +- #ifdef SSL_R_BAD_HRR_VERSION +- {"BAD_HRR_VERSION", ERR_LIB_SSL, SSL_R_BAD_HRR_VERSION}, +- #else +- {"BAD_HRR_VERSION", 20, 263}, +- #endif +- #ifdef SSL_R_BAD_KEY_SHARE +- {"BAD_KEY_SHARE", ERR_LIB_SSL, SSL_R_BAD_KEY_SHARE}, +- #else +- {"BAD_KEY_SHARE", 20, 108}, +- #endif +- #ifdef SSL_R_BAD_KEY_UPDATE +- {"BAD_KEY_UPDATE", ERR_LIB_SSL, SSL_R_BAD_KEY_UPDATE}, +- #else +- {"BAD_KEY_UPDATE", 20, 122}, +- #endif +- #ifdef SSL_R_BAD_LEGACY_VERSION +- {"BAD_LEGACY_VERSION", ERR_LIB_SSL, SSL_R_BAD_LEGACY_VERSION}, +- #else +- {"BAD_LEGACY_VERSION", 20, 292}, +- #endif +- #ifdef SSL_R_BAD_LENGTH +- {"BAD_LENGTH", ERR_LIB_SSL, SSL_R_BAD_LENGTH}, +- #else +- {"BAD_LENGTH", 20, 271}, +- #endif +- #ifdef SSL_R_BAD_PACKET +- {"BAD_PACKET", ERR_LIB_SSL, SSL_R_BAD_PACKET}, +- #else +- {"BAD_PACKET", 20, 240}, +- #endif +- #ifdef SSL_R_BAD_PACKET_LENGTH +- {"BAD_PACKET_LENGTH", ERR_LIB_SSL, SSL_R_BAD_PACKET_LENGTH}, +- #else +- {"BAD_PACKET_LENGTH", 20, 115}, +- #endif +- #ifdef SSL_R_BAD_PROTOCOL_VERSION_NUMBER +- {"BAD_PROTOCOL_VERSION_NUMBER", ERR_LIB_SSL, SSL_R_BAD_PROTOCOL_VERSION_NUMBER}, +- #else +- {"BAD_PROTOCOL_VERSION_NUMBER", 20, 116}, +- #endif +- #ifdef SSL_R_BAD_PSK +- {"BAD_PSK", ERR_LIB_SSL, SSL_R_BAD_PSK}, +- #else +- {"BAD_PSK", 20, 219}, +- #endif +- #ifdef SSL_R_BAD_PSK_IDENTITY +- {"BAD_PSK_IDENTITY", ERR_LIB_SSL, SSL_R_BAD_PSK_IDENTITY}, +- #else +- {"BAD_PSK_IDENTITY", 20, 114}, +- #endif +- #ifdef SSL_R_BAD_RECORD_TYPE +- {"BAD_RECORD_TYPE", ERR_LIB_SSL, SSL_R_BAD_RECORD_TYPE}, +- #else +- {"BAD_RECORD_TYPE", 20, 443}, +- #endif +- #ifdef SSL_R_BAD_RSA_ENCRYPT +- {"BAD_RSA_ENCRYPT", ERR_LIB_SSL, SSL_R_BAD_RSA_ENCRYPT}, +- #else +- {"BAD_RSA_ENCRYPT", 20, 119}, +- #endif +- #ifdef SSL_R_BAD_SIGNATURE +- {"BAD_SIGNATURE", ERR_LIB_SSL, SSL_R_BAD_SIGNATURE}, +- #else +- {"BAD_SIGNATURE", 20, 123}, +- #endif +- #ifdef SSL_R_BAD_SRP_A_LENGTH +- {"BAD_SRP_A_LENGTH", ERR_LIB_SSL, SSL_R_BAD_SRP_A_LENGTH}, +- #else +- {"BAD_SRP_A_LENGTH", 20, 347}, +- #endif +- #ifdef SSL_R_BAD_SRP_PARAMETERS +- {"BAD_SRP_PARAMETERS", ERR_LIB_SSL, SSL_R_BAD_SRP_PARAMETERS}, +- #else +- {"BAD_SRP_PARAMETERS", 20, 371}, +- #endif +- #ifdef SSL_R_BAD_SRTP_MKI_VALUE +- {"BAD_SRTP_MKI_VALUE", ERR_LIB_SSL, SSL_R_BAD_SRTP_MKI_VALUE}, +- #else +- {"BAD_SRTP_MKI_VALUE", 20, 352}, +- #endif +- #ifdef SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST +- {"BAD_SRTP_PROTECTION_PROFILE_LIST", ERR_LIB_SSL, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST}, +- #else +- {"BAD_SRTP_PROTECTION_PROFILE_LIST", 20, 353}, +- #endif +- #ifdef SSL_R_BAD_SSL_FILETYPE +- {"BAD_SSL_FILETYPE", ERR_LIB_SSL, SSL_R_BAD_SSL_FILETYPE}, +- #else +- {"BAD_SSL_FILETYPE", 20, 124}, +- #endif +- #ifdef SSL_R_BAD_VALUE +- {"BAD_VALUE", ERR_LIB_SSL, SSL_R_BAD_VALUE}, +- #else +- {"BAD_VALUE", 20, 384}, +- #endif +- #ifdef SSL_R_BAD_WRITE_RETRY +- {"BAD_WRITE_RETRY", ERR_LIB_SSL, SSL_R_BAD_WRITE_RETRY}, +- #else +- {"BAD_WRITE_RETRY", 20, 127}, +- #endif +- #ifdef SSL_R_BINDER_DOES_NOT_VERIFY +- {"BINDER_DOES_NOT_VERIFY", ERR_LIB_SSL, SSL_R_BINDER_DOES_NOT_VERIFY}, +- #else +- {"BINDER_DOES_NOT_VERIFY", 20, 253}, +- #endif +- #ifdef SSL_R_BIO_NOT_SET +- {"BIO_NOT_SET", ERR_LIB_SSL, SSL_R_BIO_NOT_SET}, +- #else +- {"BIO_NOT_SET", 20, 128}, +- #endif +- #ifdef SSL_R_BLOCK_CIPHER_PAD_IS_WRONG +- {"BLOCK_CIPHER_PAD_IS_WRONG", ERR_LIB_SSL, SSL_R_BLOCK_CIPHER_PAD_IS_WRONG}, +- #else +- {"BLOCK_CIPHER_PAD_IS_WRONG", 20, 129}, +- #endif +- #ifdef SSL_R_BN_LIB +- {"BN_LIB", ERR_LIB_SSL, SSL_R_BN_LIB}, +- #else +- {"BN_LIB", 20, 130}, +- #endif +- #ifdef SSL_R_CALLBACK_FAILED +- {"CALLBACK_FAILED", ERR_LIB_SSL, SSL_R_CALLBACK_FAILED}, +- #else +- {"CALLBACK_FAILED", 20, 234}, +- #endif +- #ifdef SSL_R_CANNOT_CHANGE_CIPHER +- {"CANNOT_CHANGE_CIPHER", ERR_LIB_SSL, SSL_R_CANNOT_CHANGE_CIPHER}, +- #else +- {"CANNOT_CHANGE_CIPHER", 20, 109}, +- #endif +- #ifdef SSL_R_CANNOT_GET_GROUP_NAME +- {"CANNOT_GET_GROUP_NAME", ERR_LIB_SSL, SSL_R_CANNOT_GET_GROUP_NAME}, +- #else +- {"CANNOT_GET_GROUP_NAME", 20, 299}, +- #endif +- #ifdef SSL_R_CA_DN_LENGTH_MISMATCH +- {"CA_DN_LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_CA_DN_LENGTH_MISMATCH}, +- #else +- {"CA_DN_LENGTH_MISMATCH", 20, 131}, +- #endif +- #ifdef SSL_R_CA_KEY_TOO_SMALL +- {"CA_KEY_TOO_SMALL", ERR_LIB_SSL, SSL_R_CA_KEY_TOO_SMALL}, +- #else +- {"CA_KEY_TOO_SMALL", 20, 397}, +- #endif +- #ifdef SSL_R_CA_MD_TOO_WEAK +- {"CA_MD_TOO_WEAK", ERR_LIB_SSL, SSL_R_CA_MD_TOO_WEAK}, +- #else +- {"CA_MD_TOO_WEAK", 20, 398}, +- #endif +- #ifdef SSL_R_CCS_RECEIVED_EARLY +- {"CCS_RECEIVED_EARLY", ERR_LIB_SSL, SSL_R_CCS_RECEIVED_EARLY}, +- #else +- {"CCS_RECEIVED_EARLY", 20, 133}, +- #endif +- #ifdef SSL_R_CERTIFICATE_VERIFY_FAILED +- {"CERTIFICATE_VERIFY_FAILED", ERR_LIB_SSL, SSL_R_CERTIFICATE_VERIFY_FAILED}, +- #else +- {"CERTIFICATE_VERIFY_FAILED", 20, 134}, +- #endif +- #ifdef SSL_R_CERT_CB_ERROR +- {"CERT_CB_ERROR", ERR_LIB_SSL, SSL_R_CERT_CB_ERROR}, +- #else +- {"CERT_CB_ERROR", 20, 377}, +- #endif +- #ifdef SSL_R_CERT_LENGTH_MISMATCH +- {"CERT_LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_CERT_LENGTH_MISMATCH}, +- #else +- {"CERT_LENGTH_MISMATCH", 20, 135}, +- #endif +- #ifdef SSL_R_CIPHERSUITE_DIGEST_HAS_CHANGED +- {"CIPHERSUITE_DIGEST_HAS_CHANGED", ERR_LIB_SSL, SSL_R_CIPHERSUITE_DIGEST_HAS_CHANGED}, +- #else +- {"CIPHERSUITE_DIGEST_HAS_CHANGED", 20, 218}, +- #endif +- #ifdef SSL_R_CIPHER_CODE_WRONG_LENGTH +- {"CIPHER_CODE_WRONG_LENGTH", ERR_LIB_SSL, SSL_R_CIPHER_CODE_WRONG_LENGTH}, +- #else +- {"CIPHER_CODE_WRONG_LENGTH", 20, 137}, +- #endif +- #ifdef SSL_R_CLIENTHELLO_TLSEXT +- {"CLIENTHELLO_TLSEXT", ERR_LIB_SSL, SSL_R_CLIENTHELLO_TLSEXT}, +- #else +- {"CLIENTHELLO_TLSEXT", 20, 226}, +- #endif +- #ifdef SSL_R_COMPRESSED_LENGTH_TOO_LONG +- {"COMPRESSED_LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_COMPRESSED_LENGTH_TOO_LONG}, +- #else +- {"COMPRESSED_LENGTH_TOO_LONG", 20, 140}, +- #endif +- #ifdef SSL_R_COMPRESSION_DISABLED +- {"COMPRESSION_DISABLED", ERR_LIB_SSL, SSL_R_COMPRESSION_DISABLED}, +- #else +- {"COMPRESSION_DISABLED", 20, 343}, +- #endif +- #ifdef SSL_R_COMPRESSION_FAILURE +- {"COMPRESSION_FAILURE", ERR_LIB_SSL, SSL_R_COMPRESSION_FAILURE}, +- #else +- {"COMPRESSION_FAILURE", 20, 141}, +- #endif +- #ifdef SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE +- {"COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE", ERR_LIB_SSL, SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE}, +- #else +- {"COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE", 20, 307}, +- #endif +- #ifdef SSL_R_COMPRESSION_LIBRARY_ERROR +- {"COMPRESSION_LIBRARY_ERROR", ERR_LIB_SSL, SSL_R_COMPRESSION_LIBRARY_ERROR}, +- #else +- {"COMPRESSION_LIBRARY_ERROR", 20, 142}, +- #endif +- #ifdef SSL_R_CONNECTION_TYPE_NOT_SET +- {"CONNECTION_TYPE_NOT_SET", ERR_LIB_SSL, SSL_R_CONNECTION_TYPE_NOT_SET}, +- #else +- {"CONNECTION_TYPE_NOT_SET", 20, 144}, +- #endif +- #ifdef SSL_R_CONTEXT_NOT_DANE_ENABLED +- {"CONTEXT_NOT_DANE_ENABLED", ERR_LIB_SSL, SSL_R_CONTEXT_NOT_DANE_ENABLED}, +- #else +- {"CONTEXT_NOT_DANE_ENABLED", 20, 167}, +- #endif +- #ifdef SSL_R_COOKIE_GEN_CALLBACK_FAILURE +- {"COOKIE_GEN_CALLBACK_FAILURE", ERR_LIB_SSL, SSL_R_COOKIE_GEN_CALLBACK_FAILURE}, +- #else +- {"COOKIE_GEN_CALLBACK_FAILURE", 20, 400}, +- #endif +- #ifdef SSL_R_COOKIE_MISMATCH +- {"COOKIE_MISMATCH", ERR_LIB_SSL, SSL_R_COOKIE_MISMATCH}, +- #else +- {"COOKIE_MISMATCH", 20, 308}, +- #endif +- #ifdef SSL_R_COPY_PARAMETERS_FAILED +- {"COPY_PARAMETERS_FAILED", ERR_LIB_SSL, SSL_R_COPY_PARAMETERS_FAILED}, +- #else +- {"COPY_PARAMETERS_FAILED", 20, 296}, +- #endif +- #ifdef SSL_R_CUSTOM_EXT_HANDLER_ALREADY_INSTALLED +- {"CUSTOM_EXT_HANDLER_ALREADY_INSTALLED", ERR_LIB_SSL, SSL_R_CUSTOM_EXT_HANDLER_ALREADY_INSTALLED}, +- #else +- {"CUSTOM_EXT_HANDLER_ALREADY_INSTALLED", 20, 206}, +- #endif +- #ifdef SSL_R_DANE_ALREADY_ENABLED +- {"DANE_ALREADY_ENABLED", ERR_LIB_SSL, SSL_R_DANE_ALREADY_ENABLED}, +- #else +- {"DANE_ALREADY_ENABLED", 20, 172}, +- #endif +- #ifdef SSL_R_DANE_CANNOT_OVERRIDE_MTYPE_FULL +- {"DANE_CANNOT_OVERRIDE_MTYPE_FULL", ERR_LIB_SSL, SSL_R_DANE_CANNOT_OVERRIDE_MTYPE_FULL}, +- #else +- {"DANE_CANNOT_OVERRIDE_MTYPE_FULL", 20, 173}, +- #endif +- #ifdef SSL_R_DANE_NOT_ENABLED +- {"DANE_NOT_ENABLED", ERR_LIB_SSL, SSL_R_DANE_NOT_ENABLED}, +- #else +- {"DANE_NOT_ENABLED", 20, 175}, +- #endif +- #ifdef SSL_R_DANE_TLSA_BAD_CERTIFICATE +- {"DANE_TLSA_BAD_CERTIFICATE", ERR_LIB_SSL, SSL_R_DANE_TLSA_BAD_CERTIFICATE}, +- #else +- {"DANE_TLSA_BAD_CERTIFICATE", 20, 180}, +- #endif +- #ifdef SSL_R_DANE_TLSA_BAD_CERTIFICATE_USAGE +- {"DANE_TLSA_BAD_CERTIFICATE_USAGE", ERR_LIB_SSL, SSL_R_DANE_TLSA_BAD_CERTIFICATE_USAGE}, +- #else +- {"DANE_TLSA_BAD_CERTIFICATE_USAGE", 20, 184}, +- #endif +- #ifdef SSL_R_DANE_TLSA_BAD_DATA_LENGTH +- {"DANE_TLSA_BAD_DATA_LENGTH", ERR_LIB_SSL, SSL_R_DANE_TLSA_BAD_DATA_LENGTH}, +- #else +- {"DANE_TLSA_BAD_DATA_LENGTH", 20, 189}, +- #endif +- #ifdef SSL_R_DANE_TLSA_BAD_DIGEST_LENGTH +- {"DANE_TLSA_BAD_DIGEST_LENGTH", ERR_LIB_SSL, SSL_R_DANE_TLSA_BAD_DIGEST_LENGTH}, +- #else +- {"DANE_TLSA_BAD_DIGEST_LENGTH", 20, 192}, +- #endif +- #ifdef SSL_R_DANE_TLSA_BAD_MATCHING_TYPE +- {"DANE_TLSA_BAD_MATCHING_TYPE", ERR_LIB_SSL, SSL_R_DANE_TLSA_BAD_MATCHING_TYPE}, +- #else +- {"DANE_TLSA_BAD_MATCHING_TYPE", 20, 200}, +- #endif +- #ifdef SSL_R_DANE_TLSA_BAD_PUBLIC_KEY +- {"DANE_TLSA_BAD_PUBLIC_KEY", ERR_LIB_SSL, SSL_R_DANE_TLSA_BAD_PUBLIC_KEY}, +- #else +- {"DANE_TLSA_BAD_PUBLIC_KEY", 20, 201}, +- #endif +- #ifdef SSL_R_DANE_TLSA_BAD_SELECTOR +- {"DANE_TLSA_BAD_SELECTOR", ERR_LIB_SSL, SSL_R_DANE_TLSA_BAD_SELECTOR}, +- #else +- {"DANE_TLSA_BAD_SELECTOR", 20, 202}, +- #endif +- #ifdef SSL_R_DANE_TLSA_NULL_DATA +- {"DANE_TLSA_NULL_DATA", ERR_LIB_SSL, SSL_R_DANE_TLSA_NULL_DATA}, +- #else +- {"DANE_TLSA_NULL_DATA", 20, 203}, +- #endif +- #ifdef SSL_R_DATA_BETWEEN_CCS_AND_FINISHED +- {"DATA_BETWEEN_CCS_AND_FINISHED", ERR_LIB_SSL, SSL_R_DATA_BETWEEN_CCS_AND_FINISHED}, +- #else +- {"DATA_BETWEEN_CCS_AND_FINISHED", 20, 145}, +- #endif +- #ifdef SSL_R_DATA_LENGTH_TOO_LONG +- {"DATA_LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_DATA_LENGTH_TOO_LONG}, +- #else +- {"DATA_LENGTH_TOO_LONG", 20, 146}, +- #endif +- #ifdef SSL_R_DECRYPTION_FAILED +- {"DECRYPTION_FAILED", ERR_LIB_SSL, SSL_R_DECRYPTION_FAILED}, +- #else +- {"DECRYPTION_FAILED", 20, 147}, +- #endif +- #ifdef SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC +- {"DECRYPTION_FAILED_OR_BAD_RECORD_MAC", ERR_LIB_SSL, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC}, +- #else +- {"DECRYPTION_FAILED_OR_BAD_RECORD_MAC", 20, 281}, +- #endif +- #ifdef SSL_R_DH_KEY_TOO_SMALL +- {"DH_KEY_TOO_SMALL", ERR_LIB_SSL, SSL_R_DH_KEY_TOO_SMALL}, +- #else +- {"DH_KEY_TOO_SMALL", 20, 394}, +- #endif +- #ifdef SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG +- {"DH_PUBLIC_VALUE_LENGTH_IS_WRONG", ERR_LIB_SSL, SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG}, +- #else +- {"DH_PUBLIC_VALUE_LENGTH_IS_WRONG", 20, 148}, +- #endif +- #ifdef SSL_R_DIGEST_CHECK_FAILED +- {"DIGEST_CHECK_FAILED", ERR_LIB_SSL, SSL_R_DIGEST_CHECK_FAILED}, +- #else +- {"DIGEST_CHECK_FAILED", 20, 149}, +- #endif +- #ifdef SSL_R_DTLS_MESSAGE_TOO_BIG +- {"DTLS_MESSAGE_TOO_BIG", ERR_LIB_SSL, SSL_R_DTLS_MESSAGE_TOO_BIG}, +- #else +- {"DTLS_MESSAGE_TOO_BIG", 20, 334}, +- #endif +- #ifdef SSL_R_DUPLICATE_COMPRESSION_ID +- {"DUPLICATE_COMPRESSION_ID", ERR_LIB_SSL, SSL_R_DUPLICATE_COMPRESSION_ID}, +- #else +- {"DUPLICATE_COMPRESSION_ID", 20, 309}, +- #endif +- #ifdef SSL_R_ECC_CERT_NOT_FOR_SIGNING +- {"ECC_CERT_NOT_FOR_SIGNING", ERR_LIB_SSL, SSL_R_ECC_CERT_NOT_FOR_SIGNING}, +- #else +- {"ECC_CERT_NOT_FOR_SIGNING", 20, 318}, +- #endif +- #ifdef SSL_R_ECDH_REQUIRED_FOR_SUITEB_MODE +- {"ECDH_REQUIRED_FOR_SUITEB_MODE", ERR_LIB_SSL, SSL_R_ECDH_REQUIRED_FOR_SUITEB_MODE}, +- #else +- {"ECDH_REQUIRED_FOR_SUITEB_MODE", 20, 374}, +- #endif +- #ifdef SSL_R_EE_KEY_TOO_SMALL +- {"EE_KEY_TOO_SMALL", ERR_LIB_SSL, SSL_R_EE_KEY_TOO_SMALL}, +- #else +- {"EE_KEY_TOO_SMALL", 20, 399}, +- #endif +- #ifdef SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST +- {"EMPTY_SRTP_PROTECTION_PROFILE_LIST", ERR_LIB_SSL, SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST}, +- #else +- {"EMPTY_SRTP_PROTECTION_PROFILE_LIST", 20, 354}, +- #endif +- #ifdef SSL_R_ENCRYPTED_LENGTH_TOO_LONG +- {"ENCRYPTED_LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_ENCRYPTED_LENGTH_TOO_LONG}, +- #else +- {"ENCRYPTED_LENGTH_TOO_LONG", 20, 150}, +- #endif +- #ifdef SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST +- {"ERROR_IN_RECEIVED_CIPHER_LIST", ERR_LIB_SSL, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST}, +- #else +- {"ERROR_IN_RECEIVED_CIPHER_LIST", 20, 151}, +- #endif +- #ifdef SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN +- {"ERROR_SETTING_TLSA_BASE_DOMAIN", ERR_LIB_SSL, SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN}, +- #else +- {"ERROR_SETTING_TLSA_BASE_DOMAIN", 20, 204}, +- #endif +- #ifdef SSL_R_EXCEEDS_MAX_FRAGMENT_SIZE +- {"EXCEEDS_MAX_FRAGMENT_SIZE", ERR_LIB_SSL, SSL_R_EXCEEDS_MAX_FRAGMENT_SIZE}, +- #else +- {"EXCEEDS_MAX_FRAGMENT_SIZE", 20, 194}, +- #endif +- #ifdef SSL_R_EXCESSIVE_MESSAGE_SIZE +- {"EXCESSIVE_MESSAGE_SIZE", ERR_LIB_SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE}, +- #else +- {"EXCESSIVE_MESSAGE_SIZE", 20, 152}, +- #endif +- #ifdef SSL_R_EXTENSION_NOT_RECEIVED +- {"EXTENSION_NOT_RECEIVED", ERR_LIB_SSL, SSL_R_EXTENSION_NOT_RECEIVED}, +- #else +- {"EXTENSION_NOT_RECEIVED", 20, 279}, +- #endif +- #ifdef SSL_R_EXTRA_DATA_IN_MESSAGE +- {"EXTRA_DATA_IN_MESSAGE", ERR_LIB_SSL, SSL_R_EXTRA_DATA_IN_MESSAGE}, +- #else +- {"EXTRA_DATA_IN_MESSAGE", 20, 153}, +- #endif +- #ifdef SSL_R_EXT_LENGTH_MISMATCH +- {"EXT_LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_EXT_LENGTH_MISMATCH}, +- #else +- {"EXT_LENGTH_MISMATCH", 20, 163}, +- #endif +- #ifdef SSL_R_FAILED_TO_INIT_ASYNC +- {"FAILED_TO_INIT_ASYNC", ERR_LIB_SSL, SSL_R_FAILED_TO_INIT_ASYNC}, +- #else +- {"FAILED_TO_INIT_ASYNC", 20, 405}, +- #endif +- #ifdef SSL_R_FRAGMENTED_CLIENT_HELLO +- {"FRAGMENTED_CLIENT_HELLO", ERR_LIB_SSL, SSL_R_FRAGMENTED_CLIENT_HELLO}, +- #else +- {"FRAGMENTED_CLIENT_HELLO", 20, 401}, +- #endif +- #ifdef SSL_R_GOT_A_FIN_BEFORE_A_CCS +- {"GOT_A_FIN_BEFORE_A_CCS", ERR_LIB_SSL, SSL_R_GOT_A_FIN_BEFORE_A_CCS}, +- #else +- {"GOT_A_FIN_BEFORE_A_CCS", 20, 154}, +- #endif +- #ifdef SSL_R_HTTPS_PROXY_REQUEST +- {"HTTPS_PROXY_REQUEST", ERR_LIB_SSL, SSL_R_HTTPS_PROXY_REQUEST}, +- #else +- {"HTTPS_PROXY_REQUEST", 20, 155}, +- #endif +- #ifdef SSL_R_HTTP_REQUEST +- {"HTTP_REQUEST", ERR_LIB_SSL, SSL_R_HTTP_REQUEST}, +- #else +- {"HTTP_REQUEST", 20, 156}, +- #endif +- #ifdef SSL_R_ILLEGAL_POINT_COMPRESSION +- {"ILLEGAL_POINT_COMPRESSION", ERR_LIB_SSL, SSL_R_ILLEGAL_POINT_COMPRESSION}, +- #else +- {"ILLEGAL_POINT_COMPRESSION", 20, 162}, +- #endif +- #ifdef SSL_R_ILLEGAL_SUITEB_DIGEST +- {"ILLEGAL_SUITEB_DIGEST", ERR_LIB_SSL, SSL_R_ILLEGAL_SUITEB_DIGEST}, +- #else +- {"ILLEGAL_SUITEB_DIGEST", 20, 380}, +- #endif +- #ifdef SSL_R_INAPPROPRIATE_FALLBACK +- {"INAPPROPRIATE_FALLBACK", ERR_LIB_SSL, SSL_R_INAPPROPRIATE_FALLBACK}, +- #else +- {"INAPPROPRIATE_FALLBACK", 20, 373}, +- #endif +- #ifdef SSL_R_INCONSISTENT_COMPRESSION +- {"INCONSISTENT_COMPRESSION", ERR_LIB_SSL, SSL_R_INCONSISTENT_COMPRESSION}, +- #else +- {"INCONSISTENT_COMPRESSION", 20, 340}, +- #endif +- #ifdef SSL_R_INCONSISTENT_EARLY_DATA_ALPN +- {"INCONSISTENT_EARLY_DATA_ALPN", ERR_LIB_SSL, SSL_R_INCONSISTENT_EARLY_DATA_ALPN}, +- #else +- {"INCONSISTENT_EARLY_DATA_ALPN", 20, 222}, +- #endif +- #ifdef SSL_R_INCONSISTENT_EARLY_DATA_SNI +- {"INCONSISTENT_EARLY_DATA_SNI", ERR_LIB_SSL, SSL_R_INCONSISTENT_EARLY_DATA_SNI}, +- #else +- {"INCONSISTENT_EARLY_DATA_SNI", 20, 231}, +- #endif +- #ifdef SSL_R_INCONSISTENT_EXTMS +- {"INCONSISTENT_EXTMS", ERR_LIB_SSL, SSL_R_INCONSISTENT_EXTMS}, +- #else +- {"INCONSISTENT_EXTMS", 20, 104}, +- #endif +- #ifdef SSL_R_INSUFFICIENT_SECURITY +- {"INSUFFICIENT_SECURITY", ERR_LIB_SSL, SSL_R_INSUFFICIENT_SECURITY}, +- #else +- {"INSUFFICIENT_SECURITY", 20, 241}, +- #endif +- #ifdef SSL_R_INVALID_ALERT +- {"INVALID_ALERT", ERR_LIB_SSL, SSL_R_INVALID_ALERT}, +- #else +- {"INVALID_ALERT", 20, 205}, +- #endif +- #ifdef SSL_R_INVALID_CCS_MESSAGE +- {"INVALID_CCS_MESSAGE", ERR_LIB_SSL, SSL_R_INVALID_CCS_MESSAGE}, +- #else +- {"INVALID_CCS_MESSAGE", 20, 260}, +- #endif +- #ifdef SSL_R_INVALID_CERTIFICATE_OR_ALG +- {"INVALID_CERTIFICATE_OR_ALG", ERR_LIB_SSL, SSL_R_INVALID_CERTIFICATE_OR_ALG}, +- #else +- {"INVALID_CERTIFICATE_OR_ALG", 20, 238}, +- #endif +- #ifdef SSL_R_INVALID_COMMAND +- {"INVALID_COMMAND", ERR_LIB_SSL, SSL_R_INVALID_COMMAND}, +- #else +- {"INVALID_COMMAND", 20, 280}, +- #endif +- #ifdef SSL_R_INVALID_COMPRESSION_ALGORITHM +- {"INVALID_COMPRESSION_ALGORITHM", ERR_LIB_SSL, SSL_R_INVALID_COMPRESSION_ALGORITHM}, +- #else +- {"INVALID_COMPRESSION_ALGORITHM", 20, 341}, +- #endif +- #ifdef SSL_R_INVALID_CONFIG +- {"INVALID_CONFIG", ERR_LIB_SSL, SSL_R_INVALID_CONFIG}, +- #else +- {"INVALID_CONFIG", 20, 283}, +- #endif +- #ifdef SSL_R_INVALID_CONFIGURATION_NAME +- {"INVALID_CONFIGURATION_NAME", ERR_LIB_SSL, SSL_R_INVALID_CONFIGURATION_NAME}, +- #else +- {"INVALID_CONFIGURATION_NAME", 20, 113}, +- #endif +- #ifdef SSL_R_INVALID_CONTEXT +- {"INVALID_CONTEXT", ERR_LIB_SSL, SSL_R_INVALID_CONTEXT}, +- #else +- {"INVALID_CONTEXT", 20, 282}, +- #endif +- #ifdef SSL_R_INVALID_CT_VALIDATION_TYPE +- {"INVALID_CT_VALIDATION_TYPE", ERR_LIB_SSL, SSL_R_INVALID_CT_VALIDATION_TYPE}, +- #else +- {"INVALID_CT_VALIDATION_TYPE", 20, 212}, +- #endif +- #ifdef SSL_R_INVALID_KEY_UPDATE_TYPE +- {"INVALID_KEY_UPDATE_TYPE", ERR_LIB_SSL, SSL_R_INVALID_KEY_UPDATE_TYPE}, +- #else +- {"INVALID_KEY_UPDATE_TYPE", 20, 120}, +- #endif +- #ifdef SSL_R_INVALID_MAX_EARLY_DATA +- {"INVALID_MAX_EARLY_DATA", ERR_LIB_SSL, SSL_R_INVALID_MAX_EARLY_DATA}, +- #else +- {"INVALID_MAX_EARLY_DATA", 20, 174}, +- #endif +- #ifdef SSL_R_INVALID_NULL_CMD_NAME +- {"INVALID_NULL_CMD_NAME", ERR_LIB_SSL, SSL_R_INVALID_NULL_CMD_NAME}, +- #else +- {"INVALID_NULL_CMD_NAME", 20, 385}, +- #endif +- #ifdef SSL_R_INVALID_SEQUENCE_NUMBER +- {"INVALID_SEQUENCE_NUMBER", ERR_LIB_SSL, SSL_R_INVALID_SEQUENCE_NUMBER}, +- #else +- {"INVALID_SEQUENCE_NUMBER", 20, 402}, +- #endif +- #ifdef SSL_R_INVALID_SERVERINFO_DATA +- {"INVALID_SERVERINFO_DATA", ERR_LIB_SSL, SSL_R_INVALID_SERVERINFO_DATA}, +- #else +- {"INVALID_SERVERINFO_DATA", 20, 388}, +- #endif +- #ifdef SSL_R_INVALID_SESSION_ID +- {"INVALID_SESSION_ID", ERR_LIB_SSL, SSL_R_INVALID_SESSION_ID}, +- #else +- {"INVALID_SESSION_ID", 20, 999}, +- #endif +- #ifdef SSL_R_INVALID_SRP_USERNAME +- {"INVALID_SRP_USERNAME", ERR_LIB_SSL, SSL_R_INVALID_SRP_USERNAME}, +- #else +- {"INVALID_SRP_USERNAME", 20, 357}, +- #endif +- #ifdef SSL_R_INVALID_STATUS_RESPONSE +- {"INVALID_STATUS_RESPONSE", ERR_LIB_SSL, SSL_R_INVALID_STATUS_RESPONSE}, +- #else +- {"INVALID_STATUS_RESPONSE", 20, 328}, +- #endif +- #ifdef SSL_R_INVALID_TICKET_KEYS_LENGTH +- {"INVALID_TICKET_KEYS_LENGTH", ERR_LIB_SSL, SSL_R_INVALID_TICKET_KEYS_LENGTH}, +- #else +- {"INVALID_TICKET_KEYS_LENGTH", 20, 325}, +- #endif +- #ifdef SSL_R_LEGACY_SIGALG_DISALLOWED_OR_UNSUPPORTED +- {"LEGACY_SIGALG_DISALLOWED_OR_UNSUPPORTED", ERR_LIB_SSL, SSL_R_LEGACY_SIGALG_DISALLOWED_OR_UNSUPPORTED}, +- #else +- {"LEGACY_SIGALG_DISALLOWED_OR_UNSUPPORTED", 20, 333}, +- #endif +- #ifdef SSL_R_LENGTH_MISMATCH +- {"LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_LENGTH_MISMATCH}, +- #else +- {"LENGTH_MISMATCH", 20, 159}, +- #endif +- #ifdef SSL_R_LENGTH_TOO_LONG +- {"LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_LENGTH_TOO_LONG}, +- #else +- {"LENGTH_TOO_LONG", 20, 404}, +- #endif +- #ifdef SSL_R_LENGTH_TOO_SHORT +- {"LENGTH_TOO_SHORT", ERR_LIB_SSL, SSL_R_LENGTH_TOO_SHORT}, +- #else +- {"LENGTH_TOO_SHORT", 20, 160}, +- #endif +- #ifdef SSL_R_LIBRARY_BUG +- {"LIBRARY_BUG", ERR_LIB_SSL, SSL_R_LIBRARY_BUG}, +- #else +- {"LIBRARY_BUG", 20, 274}, +- #endif +- #ifdef SSL_R_LIBRARY_HAS_NO_CIPHERS +- {"LIBRARY_HAS_NO_CIPHERS", ERR_LIB_SSL, SSL_R_LIBRARY_HAS_NO_CIPHERS}, +- #else +- {"LIBRARY_HAS_NO_CIPHERS", 20, 161}, +- #endif +- #ifdef SSL_R_MISSING_DSA_SIGNING_CERT +- {"MISSING_DSA_SIGNING_CERT", ERR_LIB_SSL, SSL_R_MISSING_DSA_SIGNING_CERT}, +- #else +- {"MISSING_DSA_SIGNING_CERT", 20, 165}, +- #endif +- #ifdef SSL_R_MISSING_ECDSA_SIGNING_CERT +- {"MISSING_ECDSA_SIGNING_CERT", ERR_LIB_SSL, SSL_R_MISSING_ECDSA_SIGNING_CERT}, +- #else +- {"MISSING_ECDSA_SIGNING_CERT", 20, 381}, +- #endif +- #ifdef SSL_R_MISSING_FATAL +- {"MISSING_FATAL", ERR_LIB_SSL, SSL_R_MISSING_FATAL}, +- #else +- {"MISSING_FATAL", 20, 256}, +- #endif +- #ifdef SSL_R_MISSING_PARAMETERS +- {"MISSING_PARAMETERS", ERR_LIB_SSL, SSL_R_MISSING_PARAMETERS}, +- #else +- {"MISSING_PARAMETERS", 20, 290}, +- #endif +- #ifdef SSL_R_MISSING_PSK_KEX_MODES_EXTENSION +- {"MISSING_PSK_KEX_MODES_EXTENSION", ERR_LIB_SSL, SSL_R_MISSING_PSK_KEX_MODES_EXTENSION}, +- #else +- {"MISSING_PSK_KEX_MODES_EXTENSION", 20, 310}, +- #endif +- #ifdef SSL_R_MISSING_RSA_CERTIFICATE +- {"MISSING_RSA_CERTIFICATE", ERR_LIB_SSL, SSL_R_MISSING_RSA_CERTIFICATE}, +- #else +- {"MISSING_RSA_CERTIFICATE", 20, 168}, +- #endif +- #ifdef SSL_R_MISSING_RSA_ENCRYPTING_CERT +- {"MISSING_RSA_ENCRYPTING_CERT", ERR_LIB_SSL, SSL_R_MISSING_RSA_ENCRYPTING_CERT}, +- #else +- {"MISSING_RSA_ENCRYPTING_CERT", 20, 169}, +- #endif +- #ifdef SSL_R_MISSING_RSA_SIGNING_CERT +- {"MISSING_RSA_SIGNING_CERT", ERR_LIB_SSL, SSL_R_MISSING_RSA_SIGNING_CERT}, +- #else +- {"MISSING_RSA_SIGNING_CERT", 20, 170}, +- #endif +- #ifdef SSL_R_MISSING_SIGALGS_EXTENSION +- {"MISSING_SIGALGS_EXTENSION", ERR_LIB_SSL, SSL_R_MISSING_SIGALGS_EXTENSION}, +- #else +- {"MISSING_SIGALGS_EXTENSION", 20, 112}, +- #endif +- #ifdef SSL_R_MISSING_SIGNING_CERT +- {"MISSING_SIGNING_CERT", ERR_LIB_SSL, SSL_R_MISSING_SIGNING_CERT}, +- #else +- {"MISSING_SIGNING_CERT", 20, 221}, +- #endif +- #ifdef SSL_R_MISSING_SRP_PARAM +- {"MISSING_SRP_PARAM", ERR_LIB_SSL, SSL_R_MISSING_SRP_PARAM}, +- #else +- {"MISSING_SRP_PARAM", 20, 358}, +- #endif +- #ifdef SSL_R_MISSING_SUPPORTED_GROUPS_EXTENSION +- {"MISSING_SUPPORTED_GROUPS_EXTENSION", ERR_LIB_SSL, SSL_R_MISSING_SUPPORTED_GROUPS_EXTENSION}, +- #else +- {"MISSING_SUPPORTED_GROUPS_EXTENSION", 20, 209}, +- #endif +- #ifdef SSL_R_MISSING_TMP_DH_KEY +- {"MISSING_TMP_DH_KEY", ERR_LIB_SSL, SSL_R_MISSING_TMP_DH_KEY}, +- #else +- {"MISSING_TMP_DH_KEY", 20, 171}, +- #endif +- #ifdef SSL_R_MISSING_TMP_ECDH_KEY +- {"MISSING_TMP_ECDH_KEY", ERR_LIB_SSL, SSL_R_MISSING_TMP_ECDH_KEY}, +- #else +- {"MISSING_TMP_ECDH_KEY", 20, 311}, +- #endif +- #ifdef SSL_R_MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA +- {"MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA", ERR_LIB_SSL, SSL_R_MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA}, +- #else +- {"MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA", 20, 293}, +- #endif +- #ifdef SSL_R_NOT_ON_RECORD_BOUNDARY +- {"NOT_ON_RECORD_BOUNDARY", ERR_LIB_SSL, SSL_R_NOT_ON_RECORD_BOUNDARY}, +- #else +- {"NOT_ON_RECORD_BOUNDARY", 20, 182}, +- #endif +- #ifdef SSL_R_NOT_REPLACING_CERTIFICATE +- {"NOT_REPLACING_CERTIFICATE", ERR_LIB_SSL, SSL_R_NOT_REPLACING_CERTIFICATE}, +- #else +- {"NOT_REPLACING_CERTIFICATE", 20, 289}, +- #endif +- #ifdef SSL_R_NOT_SERVER +- {"NOT_SERVER", ERR_LIB_SSL, SSL_R_NOT_SERVER}, +- #else +- {"NOT_SERVER", 20, 284}, +- #endif +- #ifdef SSL_R_NO_APPLICATION_PROTOCOL +- {"NO_APPLICATION_PROTOCOL", ERR_LIB_SSL, SSL_R_NO_APPLICATION_PROTOCOL}, +- #else +- {"NO_APPLICATION_PROTOCOL", 20, 235}, +- #endif +- #ifdef SSL_R_NO_CERTIFICATES_RETURNED +- {"NO_CERTIFICATES_RETURNED", ERR_LIB_SSL, SSL_R_NO_CERTIFICATES_RETURNED}, +- #else +- {"NO_CERTIFICATES_RETURNED", 20, 176}, +- #endif +- #ifdef SSL_R_NO_CERTIFICATE_ASSIGNED +- {"NO_CERTIFICATE_ASSIGNED", ERR_LIB_SSL, SSL_R_NO_CERTIFICATE_ASSIGNED}, +- #else +- {"NO_CERTIFICATE_ASSIGNED", 20, 177}, +- #endif +- #ifdef SSL_R_NO_CERTIFICATE_SET +- {"NO_CERTIFICATE_SET", ERR_LIB_SSL, SSL_R_NO_CERTIFICATE_SET}, +- #else +- {"NO_CERTIFICATE_SET", 20, 179}, +- #endif +- #ifdef SSL_R_NO_CHANGE_FOLLOWING_HRR +- {"NO_CHANGE_FOLLOWING_HRR", ERR_LIB_SSL, SSL_R_NO_CHANGE_FOLLOWING_HRR}, +- #else +- {"NO_CHANGE_FOLLOWING_HRR", 20, 214}, +- #endif +- #ifdef SSL_R_NO_CIPHERS_AVAILABLE +- {"NO_CIPHERS_AVAILABLE", ERR_LIB_SSL, SSL_R_NO_CIPHERS_AVAILABLE}, +- #else +- {"NO_CIPHERS_AVAILABLE", 20, 181}, +- #endif +- #ifdef SSL_R_NO_CIPHERS_SPECIFIED +- {"NO_CIPHERS_SPECIFIED", ERR_LIB_SSL, SSL_R_NO_CIPHERS_SPECIFIED}, +- #else +- {"NO_CIPHERS_SPECIFIED", 20, 183}, +- #endif +- #ifdef SSL_R_NO_CIPHER_MATCH +- {"NO_CIPHER_MATCH", ERR_LIB_SSL, SSL_R_NO_CIPHER_MATCH}, +- #else +- {"NO_CIPHER_MATCH", 20, 185}, +- #endif +- #ifdef SSL_R_NO_CLIENT_CERT_METHOD +- {"NO_CLIENT_CERT_METHOD", ERR_LIB_SSL, SSL_R_NO_CLIENT_CERT_METHOD}, +- #else +- {"NO_CLIENT_CERT_METHOD", 20, 331}, +- #endif +- #ifdef SSL_R_NO_COMPRESSION_SPECIFIED +- {"NO_COMPRESSION_SPECIFIED", ERR_LIB_SSL, SSL_R_NO_COMPRESSION_SPECIFIED}, +- #else +- {"NO_COMPRESSION_SPECIFIED", 20, 187}, +- #endif +- #ifdef SSL_R_NO_COOKIE_CALLBACK_SET +- {"NO_COOKIE_CALLBACK_SET", ERR_LIB_SSL, SSL_R_NO_COOKIE_CALLBACK_SET}, +- #else +- {"NO_COOKIE_CALLBACK_SET", 20, 287}, +- #endif +- #ifdef SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER +- {"NO_GOST_CERTIFICATE_SENT_BY_PEER", ERR_LIB_SSL, SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER}, +- #else +- {"NO_GOST_CERTIFICATE_SENT_BY_PEER", 20, 330}, +- #endif +- #ifdef SSL_R_NO_METHOD_SPECIFIED +- {"NO_METHOD_SPECIFIED", ERR_LIB_SSL, SSL_R_NO_METHOD_SPECIFIED}, +- #else +- {"NO_METHOD_SPECIFIED", 20, 188}, +- #endif +- #ifdef SSL_R_NO_PEM_EXTENSIONS +- {"NO_PEM_EXTENSIONS", ERR_LIB_SSL, SSL_R_NO_PEM_EXTENSIONS}, +- #else +- {"NO_PEM_EXTENSIONS", 20, 389}, +- #endif +- #ifdef SSL_R_NO_PRIVATE_KEY_ASSIGNED +- {"NO_PRIVATE_KEY_ASSIGNED", ERR_LIB_SSL, SSL_R_NO_PRIVATE_KEY_ASSIGNED}, +- #else +- {"NO_PRIVATE_KEY_ASSIGNED", 20, 190}, +- #endif +- #ifdef SSL_R_NO_PROTOCOLS_AVAILABLE +- {"NO_PROTOCOLS_AVAILABLE", ERR_LIB_SSL, SSL_R_NO_PROTOCOLS_AVAILABLE}, +- #else +- {"NO_PROTOCOLS_AVAILABLE", 20, 191}, +- #endif +- #ifdef SSL_R_NO_RENEGOTIATION +- {"NO_RENEGOTIATION", ERR_LIB_SSL, SSL_R_NO_RENEGOTIATION}, +- #else +- {"NO_RENEGOTIATION", 20, 339}, +- #endif +- #ifdef SSL_R_NO_REQUIRED_DIGEST +- {"NO_REQUIRED_DIGEST", ERR_LIB_SSL, SSL_R_NO_REQUIRED_DIGEST}, +- #else +- {"NO_REQUIRED_DIGEST", 20, 324}, +- #endif +- #ifdef SSL_R_NO_SHARED_CIPHER +- {"NO_SHARED_CIPHER", ERR_LIB_SSL, SSL_R_NO_SHARED_CIPHER}, +- #else +- {"NO_SHARED_CIPHER", 20, 193}, +- #endif +- #ifdef SSL_R_NO_SHARED_GROUPS +- {"NO_SHARED_GROUPS", ERR_LIB_SSL, SSL_R_NO_SHARED_GROUPS}, +- #else +- {"NO_SHARED_GROUPS", 20, 410}, +- #endif +- #ifdef SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS +- {"NO_SHARED_SIGNATURE_ALGORITHMS", ERR_LIB_SSL, SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS}, +- #else +- {"NO_SHARED_SIGNATURE_ALGORITHMS", 20, 376}, +- #endif +- #ifdef SSL_R_NO_SRTP_PROFILES +- {"NO_SRTP_PROFILES", ERR_LIB_SSL, SSL_R_NO_SRTP_PROFILES}, +- #else +- {"NO_SRTP_PROFILES", 20, 359}, +- #endif +- #ifdef SSL_R_NO_SUITABLE_DIGEST_ALGORITHM +- {"NO_SUITABLE_DIGEST_ALGORITHM", ERR_LIB_SSL, SSL_R_NO_SUITABLE_DIGEST_ALGORITHM}, +- #else +- {"NO_SUITABLE_DIGEST_ALGORITHM", 20, 297}, +- #endif +- #ifdef SSL_R_NO_SUITABLE_GROUPS +- {"NO_SUITABLE_GROUPS", ERR_LIB_SSL, SSL_R_NO_SUITABLE_GROUPS}, +- #else +- {"NO_SUITABLE_GROUPS", 20, 295}, +- #endif +- #ifdef SSL_R_NO_SUITABLE_KEY_SHARE +- {"NO_SUITABLE_KEY_SHARE", ERR_LIB_SSL, SSL_R_NO_SUITABLE_KEY_SHARE}, +- #else +- {"NO_SUITABLE_KEY_SHARE", 20, 101}, +- #endif +- #ifdef SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM +- {"NO_SUITABLE_SIGNATURE_ALGORITHM", ERR_LIB_SSL, SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM}, +- #else +- {"NO_SUITABLE_SIGNATURE_ALGORITHM", 20, 118}, +- #endif +- #ifdef SSL_R_NO_VALID_SCTS +- {"NO_VALID_SCTS", ERR_LIB_SSL, SSL_R_NO_VALID_SCTS}, +- #else +- {"NO_VALID_SCTS", 20, 216}, +- #endif +- #ifdef SSL_R_NO_VERIFY_COOKIE_CALLBACK +- {"NO_VERIFY_COOKIE_CALLBACK", ERR_LIB_SSL, SSL_R_NO_VERIFY_COOKIE_CALLBACK}, +- #else +- {"NO_VERIFY_COOKIE_CALLBACK", 20, 403}, +- #endif +- #ifdef SSL_R_NULL_SSL_CTX +- {"NULL_SSL_CTX", ERR_LIB_SSL, SSL_R_NULL_SSL_CTX}, +- #else +- {"NULL_SSL_CTX", 20, 195}, +- #endif +- #ifdef SSL_R_NULL_SSL_METHOD_PASSED +- {"NULL_SSL_METHOD_PASSED", ERR_LIB_SSL, SSL_R_NULL_SSL_METHOD_PASSED}, +- #else +- {"NULL_SSL_METHOD_PASSED", 20, 196}, +- #endif +- #ifdef SSL_R_OCSP_CALLBACK_FAILURE +- {"OCSP_CALLBACK_FAILURE", ERR_LIB_SSL, SSL_R_OCSP_CALLBACK_FAILURE}, +- #else +- {"OCSP_CALLBACK_FAILURE", 20, 305}, +- #endif +- #ifdef SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED +- {"OLD_SESSION_CIPHER_NOT_RETURNED", ERR_LIB_SSL, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED}, +- #else +- {"OLD_SESSION_CIPHER_NOT_RETURNED", 20, 197}, +- #endif +- #ifdef SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED +- {"OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED", ERR_LIB_SSL, SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED}, +- #else +- {"OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED", 20, 344}, +- #endif +- #ifdef SSL_R_OVERFLOW_ERROR +- {"OVERFLOW_ERROR", ERR_LIB_SSL, SSL_R_OVERFLOW_ERROR}, +- #else +- {"OVERFLOW_ERROR", 20, 237}, +- #endif +- #ifdef SSL_R_PACKET_LENGTH_TOO_LONG +- {"PACKET_LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_PACKET_LENGTH_TOO_LONG}, +- #else +- {"PACKET_LENGTH_TOO_LONG", 20, 198}, +- #endif +- #ifdef SSL_R_PARSE_TLSEXT +- {"PARSE_TLSEXT", ERR_LIB_SSL, SSL_R_PARSE_TLSEXT}, +- #else +- {"PARSE_TLSEXT", 20, 227}, +- #endif +- #ifdef SSL_R_PATH_TOO_LONG +- {"PATH_TOO_LONG", ERR_LIB_SSL, SSL_R_PATH_TOO_LONG}, +- #else +- {"PATH_TOO_LONG", 20, 270}, +- #endif +- #ifdef SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE +- {"PEER_DID_NOT_RETURN_A_CERTIFICATE", ERR_LIB_SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE}, +- #else +- {"PEER_DID_NOT_RETURN_A_CERTIFICATE", 20, 199}, +- #endif +- #ifdef SSL_R_PEM_NAME_BAD_PREFIX +- {"PEM_NAME_BAD_PREFIX", ERR_LIB_SSL, SSL_R_PEM_NAME_BAD_PREFIX}, +- #else +- {"PEM_NAME_BAD_PREFIX", 20, 391}, +- #endif +- #ifdef SSL_R_PEM_NAME_TOO_SHORT +- {"PEM_NAME_TOO_SHORT", ERR_LIB_SSL, SSL_R_PEM_NAME_TOO_SHORT}, +- #else +- {"PEM_NAME_TOO_SHORT", 20, 392}, +- #endif +- #ifdef SSL_R_PIPELINE_FAILURE +- {"PIPELINE_FAILURE", ERR_LIB_SSL, SSL_R_PIPELINE_FAILURE}, +- #else +- {"PIPELINE_FAILURE", 20, 406}, +- #endif +- #ifdef SSL_R_POST_HANDSHAKE_AUTH_ENCODING_ERR +- {"POST_HANDSHAKE_AUTH_ENCODING_ERR", ERR_LIB_SSL, SSL_R_POST_HANDSHAKE_AUTH_ENCODING_ERR}, +- #else +- {"POST_HANDSHAKE_AUTH_ENCODING_ERR", 20, 278}, +- #endif +- #ifdef SSL_R_PRIVATE_KEY_MISMATCH +- {"PRIVATE_KEY_MISMATCH", ERR_LIB_SSL, SSL_R_PRIVATE_KEY_MISMATCH}, +- #else +- {"PRIVATE_KEY_MISMATCH", 20, 288}, +- #endif +- #ifdef SSL_R_PROTOCOL_IS_SHUTDOWN +- {"PROTOCOL_IS_SHUTDOWN", ERR_LIB_SSL, SSL_R_PROTOCOL_IS_SHUTDOWN}, +- #else +- {"PROTOCOL_IS_SHUTDOWN", 20, 207}, +- #endif +- #ifdef SSL_R_PSK_IDENTITY_NOT_FOUND +- {"PSK_IDENTITY_NOT_FOUND", ERR_LIB_SSL, SSL_R_PSK_IDENTITY_NOT_FOUND}, +- #else +- {"PSK_IDENTITY_NOT_FOUND", 20, 223}, +- #endif +- #ifdef SSL_R_PSK_NO_CLIENT_CB +- {"PSK_NO_CLIENT_CB", ERR_LIB_SSL, SSL_R_PSK_NO_CLIENT_CB}, +- #else +- {"PSK_NO_CLIENT_CB", 20, 224}, +- #endif +- #ifdef SSL_R_PSK_NO_SERVER_CB +- {"PSK_NO_SERVER_CB", ERR_LIB_SSL, SSL_R_PSK_NO_SERVER_CB}, +- #else +- {"PSK_NO_SERVER_CB", 20, 225}, +- #endif +- #ifdef SSL_R_READ_BIO_NOT_SET +- {"READ_BIO_NOT_SET", ERR_LIB_SSL, SSL_R_READ_BIO_NOT_SET}, +- #else +- {"READ_BIO_NOT_SET", 20, 211}, +- #endif +- #ifdef SSL_R_READ_TIMEOUT_EXPIRED +- {"READ_TIMEOUT_EXPIRED", ERR_LIB_SSL, SSL_R_READ_TIMEOUT_EXPIRED}, +- #else +- {"READ_TIMEOUT_EXPIRED", 20, 312}, +- #endif +- #ifdef SSL_R_RECORD_LENGTH_MISMATCH +- {"RECORD_LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_RECORD_LENGTH_MISMATCH}, +- #else +- {"RECORD_LENGTH_MISMATCH", 20, 213}, +- #endif +- #ifdef SSL_R_RECORD_TOO_SMALL +- {"RECORD_TOO_SMALL", ERR_LIB_SSL, SSL_R_RECORD_TOO_SMALL}, +- #else +- {"RECORD_TOO_SMALL", 20, 298}, +- #endif +- #ifdef SSL_R_RENEGOTIATE_EXT_TOO_LONG +- {"RENEGOTIATE_EXT_TOO_LONG", ERR_LIB_SSL, SSL_R_RENEGOTIATE_EXT_TOO_LONG}, +- #else +- {"RENEGOTIATE_EXT_TOO_LONG", 20, 335}, +- #endif +- #ifdef SSL_R_RENEGOTIATION_ENCODING_ERR +- {"RENEGOTIATION_ENCODING_ERR", ERR_LIB_SSL, SSL_R_RENEGOTIATION_ENCODING_ERR}, +- #else +- {"RENEGOTIATION_ENCODING_ERR", 20, 336}, +- #endif +- #ifdef SSL_R_RENEGOTIATION_MISMATCH +- {"RENEGOTIATION_MISMATCH", ERR_LIB_SSL, SSL_R_RENEGOTIATION_MISMATCH}, +- #else +- {"RENEGOTIATION_MISMATCH", 20, 337}, +- #endif +- #ifdef SSL_R_REQUEST_PENDING +- {"REQUEST_PENDING", ERR_LIB_SSL, SSL_R_REQUEST_PENDING}, +- #else +- {"REQUEST_PENDING", 20, 285}, +- #endif +- #ifdef SSL_R_REQUEST_SENT +- {"REQUEST_SENT", ERR_LIB_SSL, SSL_R_REQUEST_SENT}, +- #else +- {"REQUEST_SENT", 20, 286}, +- #endif +- #ifdef SSL_R_REQUIRED_CIPHER_MISSING +- {"REQUIRED_CIPHER_MISSING", ERR_LIB_SSL, SSL_R_REQUIRED_CIPHER_MISSING}, +- #else +- {"REQUIRED_CIPHER_MISSING", 20, 215}, +- #endif +- #ifdef SSL_R_REQUIRED_COMPRESSION_ALGORITHM_MISSING +- {"REQUIRED_COMPRESSION_ALGORITHM_MISSING", ERR_LIB_SSL, SSL_R_REQUIRED_COMPRESSION_ALGORITHM_MISSING}, +- #else +- {"REQUIRED_COMPRESSION_ALGORITHM_MISSING", 20, 342}, +- #endif +- #ifdef SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING +- {"SCSV_RECEIVED_WHEN_RENEGOTIATING", ERR_LIB_SSL, SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING}, +- #else +- {"SCSV_RECEIVED_WHEN_RENEGOTIATING", 20, 345}, +- #endif +- #ifdef SSL_R_SCT_VERIFICATION_FAILED +- {"SCT_VERIFICATION_FAILED", ERR_LIB_SSL, SSL_R_SCT_VERIFICATION_FAILED}, +- #else +- {"SCT_VERIFICATION_FAILED", 20, 208}, +- #endif +- #ifdef SSL_R_SERVERHELLO_TLSEXT +- {"SERVERHELLO_TLSEXT", ERR_LIB_SSL, SSL_R_SERVERHELLO_TLSEXT}, +- #else +- {"SERVERHELLO_TLSEXT", 20, 275}, +- #endif +- #ifdef SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED +- {"SESSION_ID_CONTEXT_UNINITIALIZED", ERR_LIB_SSL, SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED}, +- #else +- {"SESSION_ID_CONTEXT_UNINITIALIZED", 20, 277}, +- #endif +- #ifdef SSL_R_SHUTDOWN_WHILE_IN_INIT +- {"SHUTDOWN_WHILE_IN_INIT", ERR_LIB_SSL, SSL_R_SHUTDOWN_WHILE_IN_INIT}, +- #else +- {"SHUTDOWN_WHILE_IN_INIT", 20, 407}, +- #endif +- #ifdef SSL_R_SIGNATURE_ALGORITHMS_ERROR +- {"SIGNATURE_ALGORITHMS_ERROR", ERR_LIB_SSL, SSL_R_SIGNATURE_ALGORITHMS_ERROR}, +- #else +- {"SIGNATURE_ALGORITHMS_ERROR", 20, 360}, +- #endif +- #ifdef SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE +- {"SIGNATURE_FOR_NON_SIGNING_CERTIFICATE", ERR_LIB_SSL, SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE}, +- #else +- {"SIGNATURE_FOR_NON_SIGNING_CERTIFICATE", 20, 220}, +- #endif +- #ifdef SSL_R_SRP_A_CALC +- {"SRP_A_CALC", ERR_LIB_SSL, SSL_R_SRP_A_CALC}, +- #else +- {"SRP_A_CALC", 20, 361}, +- #endif +- #ifdef SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES +- {"SRTP_COULD_NOT_ALLOCATE_PROFILES", ERR_LIB_SSL, SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES}, +- #else +- {"SRTP_COULD_NOT_ALLOCATE_PROFILES", 20, 362}, +- #endif +- #ifdef SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG +- {"SRTP_PROTECTION_PROFILE_LIST_TOO_LONG", ERR_LIB_SSL, SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG}, +- #else +- {"SRTP_PROTECTION_PROFILE_LIST_TOO_LONG", 20, 363}, +- #endif +- #ifdef SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE +- {"SRTP_UNKNOWN_PROTECTION_PROFILE", ERR_LIB_SSL, SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE}, +- #else +- {"SRTP_UNKNOWN_PROTECTION_PROFILE", 20, 364}, +- #endif +- #ifdef SSL_R_SSL3_EXT_INVALID_MAX_FRAGMENT_LENGTH +- {"SSL3_EXT_INVALID_MAX_FRAGMENT_LENGTH", ERR_LIB_SSL, SSL_R_SSL3_EXT_INVALID_MAX_FRAGMENT_LENGTH}, +- #else +- {"SSL3_EXT_INVALID_MAX_FRAGMENT_LENGTH", 20, 232}, +- #endif +- #ifdef SSL_R_SSL3_EXT_INVALID_SERVERNAME +- {"SSL3_EXT_INVALID_SERVERNAME", ERR_LIB_SSL, SSL_R_SSL3_EXT_INVALID_SERVERNAME}, +- #else +- {"SSL3_EXT_INVALID_SERVERNAME", 20, 319}, +- #endif +- #ifdef SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE +- {"SSL3_EXT_INVALID_SERVERNAME_TYPE", ERR_LIB_SSL, SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE}, +- #else +- {"SSL3_EXT_INVALID_SERVERNAME_TYPE", 20, 320}, +- #endif +- #ifdef SSL_R_SSL3_SESSION_ID_TOO_LONG +- {"SSL3_SESSION_ID_TOO_LONG", ERR_LIB_SSL, SSL_R_SSL3_SESSION_ID_TOO_LONG}, +- #else +- {"SSL3_SESSION_ID_TOO_LONG", 20, 300}, +- #endif +- #ifdef SSL_R_SSLV3_ALERT_BAD_CERTIFICATE +- {"SSLV3_ALERT_BAD_CERTIFICATE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_BAD_CERTIFICATE}, +- #else +- {"SSLV3_ALERT_BAD_CERTIFICATE", 20, 1042}, +- #endif +- #ifdef SSL_R_SSLV3_ALERT_BAD_RECORD_MAC +- {"SSLV3_ALERT_BAD_RECORD_MAC", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_BAD_RECORD_MAC}, +- #else +- {"SSLV3_ALERT_BAD_RECORD_MAC", 20, 1020}, +- #endif +- #ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED +- {"SSLV3_ALERT_CERTIFICATE_EXPIRED", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED}, +- #else +- {"SSLV3_ALERT_CERTIFICATE_EXPIRED", 20, 1045}, +- #endif +- #ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED +- {"SSLV3_ALERT_CERTIFICATE_REVOKED", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED}, +- #else +- {"SSLV3_ALERT_CERTIFICATE_REVOKED", 20, 1044}, +- #endif +- #ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN +- {"SSLV3_ALERT_CERTIFICATE_UNKNOWN", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN}, +- #else +- {"SSLV3_ALERT_CERTIFICATE_UNKNOWN", 20, 1046}, +- #endif +- #ifdef SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE +- {"SSLV3_ALERT_DECOMPRESSION_FAILURE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE}, +- #else +- {"SSLV3_ALERT_DECOMPRESSION_FAILURE", 20, 1030}, +- #endif +- #ifdef SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE +- {"SSLV3_ALERT_HANDSHAKE_FAILURE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE}, +- #else +- {"SSLV3_ALERT_HANDSHAKE_FAILURE", 20, 1040}, +- #endif +- #ifdef SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER +- {"SSLV3_ALERT_ILLEGAL_PARAMETER", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER}, +- #else +- {"SSLV3_ALERT_ILLEGAL_PARAMETER", 20, 1047}, +- #endif +- #ifdef SSL_R_SSLV3_ALERT_NO_CERTIFICATE +- {"SSLV3_ALERT_NO_CERTIFICATE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_NO_CERTIFICATE}, +- #else +- {"SSLV3_ALERT_NO_CERTIFICATE", 20, 1041}, +- #endif +- #ifdef SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE +- {"SSLV3_ALERT_UNEXPECTED_MESSAGE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE}, +- #else +- {"SSLV3_ALERT_UNEXPECTED_MESSAGE", 20, 1010}, +- #endif +- #ifdef SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE +- {"SSLV3_ALERT_UNSUPPORTED_CERTIFICATE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE}, +- #else +- {"SSLV3_ALERT_UNSUPPORTED_CERTIFICATE", 20, 1043}, +- #endif +- #ifdef SSL_R_SSL_COMMAND_SECTION_EMPTY +- {"SSL_COMMAND_SECTION_EMPTY", ERR_LIB_SSL, SSL_R_SSL_COMMAND_SECTION_EMPTY}, +- #else +- {"SSL_COMMAND_SECTION_EMPTY", 20, 117}, +- #endif +- #ifdef SSL_R_SSL_COMMAND_SECTION_NOT_FOUND +- {"SSL_COMMAND_SECTION_NOT_FOUND", ERR_LIB_SSL, SSL_R_SSL_COMMAND_SECTION_NOT_FOUND}, +- #else +- {"SSL_COMMAND_SECTION_NOT_FOUND", 20, 125}, +- #endif +- #ifdef SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION +- {"SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION", ERR_LIB_SSL, SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION}, +- #else +- {"SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION", 20, 228}, +- #endif +- #ifdef SSL_R_SSL_HANDSHAKE_FAILURE +- {"SSL_HANDSHAKE_FAILURE", ERR_LIB_SSL, SSL_R_SSL_HANDSHAKE_FAILURE}, +- #else +- {"SSL_HANDSHAKE_FAILURE", 20, 229}, +- #endif +- #ifdef SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS +- {"SSL_LIBRARY_HAS_NO_CIPHERS", ERR_LIB_SSL, SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS}, +- #else +- {"SSL_LIBRARY_HAS_NO_CIPHERS", 20, 230}, +- #endif +- #ifdef SSL_R_SSL_NEGATIVE_LENGTH +- {"SSL_NEGATIVE_LENGTH", ERR_LIB_SSL, SSL_R_SSL_NEGATIVE_LENGTH}, +- #else +- {"SSL_NEGATIVE_LENGTH", 20, 372}, +- #endif +- #ifdef SSL_R_SSL_SECTION_EMPTY +- {"SSL_SECTION_EMPTY", ERR_LIB_SSL, SSL_R_SSL_SECTION_EMPTY}, +- #else +- {"SSL_SECTION_EMPTY", 20, 126}, +- #endif +- #ifdef SSL_R_SSL_SECTION_NOT_FOUND +- {"SSL_SECTION_NOT_FOUND", ERR_LIB_SSL, SSL_R_SSL_SECTION_NOT_FOUND}, +- #else +- {"SSL_SECTION_NOT_FOUND", 20, 136}, +- #endif +- #ifdef SSL_R_SSL_SESSION_ID_CALLBACK_FAILED +- {"SSL_SESSION_ID_CALLBACK_FAILED", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_CALLBACK_FAILED}, +- #else +- {"SSL_SESSION_ID_CALLBACK_FAILED", 20, 301}, +- #endif +- #ifdef SSL_R_SSL_SESSION_ID_CONFLICT +- {"SSL_SESSION_ID_CONFLICT", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_CONFLICT}, +- #else +- {"SSL_SESSION_ID_CONFLICT", 20, 302}, +- #endif +- #ifdef SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG +- {"SSL_SESSION_ID_CONTEXT_TOO_LONG", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG}, +- #else +- {"SSL_SESSION_ID_CONTEXT_TOO_LONG", 20, 273}, +- #endif +- #ifdef SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH +- {"SSL_SESSION_ID_HAS_BAD_LENGTH", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH}, +- #else +- {"SSL_SESSION_ID_HAS_BAD_LENGTH", 20, 303}, +- #endif +- #ifdef SSL_R_SSL_SESSION_ID_TOO_LONG +- {"SSL_SESSION_ID_TOO_LONG", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_TOO_LONG}, +- #else +- {"SSL_SESSION_ID_TOO_LONG", 20, 408}, +- #endif +- #ifdef SSL_R_SSL_SESSION_VERSION_MISMATCH +- {"SSL_SESSION_VERSION_MISMATCH", ERR_LIB_SSL, SSL_R_SSL_SESSION_VERSION_MISMATCH}, +- #else +- {"SSL_SESSION_VERSION_MISMATCH", 20, 210}, +- #endif +- #ifdef SSL_R_STILL_IN_INIT +- {"STILL_IN_INIT", ERR_LIB_SSL, SSL_R_STILL_IN_INIT}, +- #else +- {"STILL_IN_INIT", 20, 121}, +- #endif +- #ifdef SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED +- {"TLSV13_ALERT_CERTIFICATE_REQUIRED", ERR_LIB_SSL, SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED}, +- #else +- {"TLSV13_ALERT_CERTIFICATE_REQUIRED", 20, 1116}, +- #endif +- #ifdef SSL_R_TLSV13_ALERT_MISSING_EXTENSION +- {"TLSV13_ALERT_MISSING_EXTENSION", ERR_LIB_SSL, SSL_R_TLSV13_ALERT_MISSING_EXTENSION}, +- #else +- {"TLSV13_ALERT_MISSING_EXTENSION", 20, 1109}, +- #endif +- #ifdef SSL_R_TLSV1_ALERT_ACCESS_DENIED +- {"TLSV1_ALERT_ACCESS_DENIED", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_ACCESS_DENIED}, +- #else +- {"TLSV1_ALERT_ACCESS_DENIED", 20, 1049}, +- #endif +- #ifdef SSL_R_TLSV1_ALERT_DECODE_ERROR +- {"TLSV1_ALERT_DECODE_ERROR", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_DECODE_ERROR}, +- #else +- {"TLSV1_ALERT_DECODE_ERROR", 20, 1050}, +- #endif +- #ifdef SSL_R_TLSV1_ALERT_DECRYPTION_FAILED +- {"TLSV1_ALERT_DECRYPTION_FAILED", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_DECRYPTION_FAILED}, +- #else +- {"TLSV1_ALERT_DECRYPTION_FAILED", 20, 1021}, +- #endif +- #ifdef SSL_R_TLSV1_ALERT_DECRYPT_ERROR +- {"TLSV1_ALERT_DECRYPT_ERROR", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_DECRYPT_ERROR}, +- #else +- {"TLSV1_ALERT_DECRYPT_ERROR", 20, 1051}, +- #endif +- #ifdef SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION +- {"TLSV1_ALERT_EXPORT_RESTRICTION", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION}, +- #else +- {"TLSV1_ALERT_EXPORT_RESTRICTION", 20, 1060}, +- #endif +- #ifdef SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK +- {"TLSV1_ALERT_INAPPROPRIATE_FALLBACK", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK}, +- #else +- {"TLSV1_ALERT_INAPPROPRIATE_FALLBACK", 20, 1086}, +- #endif +- #ifdef SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY +- {"TLSV1_ALERT_INSUFFICIENT_SECURITY", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY}, +- #else +- {"TLSV1_ALERT_INSUFFICIENT_SECURITY", 20, 1071}, +- #endif +- #ifdef SSL_R_TLSV1_ALERT_INTERNAL_ERROR +- {"TLSV1_ALERT_INTERNAL_ERROR", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_INTERNAL_ERROR}, +- #else +- {"TLSV1_ALERT_INTERNAL_ERROR", 20, 1080}, +- #endif +- #ifdef SSL_R_TLSV1_ALERT_NO_RENEGOTIATION +- {"TLSV1_ALERT_NO_RENEGOTIATION", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_NO_RENEGOTIATION}, +- #else +- {"TLSV1_ALERT_NO_RENEGOTIATION", 20, 1100}, +- #endif +- #ifdef SSL_R_TLSV1_ALERT_PROTOCOL_VERSION +- {"TLSV1_ALERT_PROTOCOL_VERSION", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_PROTOCOL_VERSION}, +- #else +- {"TLSV1_ALERT_PROTOCOL_VERSION", 20, 1070}, +- #endif +- #ifdef SSL_R_TLSV1_ALERT_RECORD_OVERFLOW +- {"TLSV1_ALERT_RECORD_OVERFLOW", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_RECORD_OVERFLOW}, +- #else +- {"TLSV1_ALERT_RECORD_OVERFLOW", 20, 1022}, +- #endif +- #ifdef SSL_R_TLSV1_ALERT_UNKNOWN_CA +- {"TLSV1_ALERT_UNKNOWN_CA", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_UNKNOWN_CA}, +- #else +- {"TLSV1_ALERT_UNKNOWN_CA", 20, 1048}, +- #endif +- #ifdef SSL_R_TLSV1_ALERT_USER_CANCELLED +- {"TLSV1_ALERT_USER_CANCELLED", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_USER_CANCELLED}, +- #else +- {"TLSV1_ALERT_USER_CANCELLED", 20, 1090}, +- #endif +- #ifdef SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE +- {"TLSV1_BAD_CERTIFICATE_HASH_VALUE", ERR_LIB_SSL, SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE}, +- #else +- {"TLSV1_BAD_CERTIFICATE_HASH_VALUE", 20, 1114}, +- #endif +- #ifdef SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE +- {"TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE", ERR_LIB_SSL, SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE}, +- #else +- {"TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE", 20, 1113}, +- #endif +- #ifdef SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE +- {"TLSV1_CERTIFICATE_UNOBTAINABLE", ERR_LIB_SSL, SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE}, +- #else +- {"TLSV1_CERTIFICATE_UNOBTAINABLE", 20, 1111}, +- #endif +- #ifdef SSL_R_TLSV1_UNRECOGNIZED_NAME +- {"TLSV1_UNRECOGNIZED_NAME", ERR_LIB_SSL, SSL_R_TLSV1_UNRECOGNIZED_NAME}, +- #else +- {"TLSV1_UNRECOGNIZED_NAME", 20, 1112}, +- #endif +- #ifdef SSL_R_TLSV1_UNSUPPORTED_EXTENSION +- {"TLSV1_UNSUPPORTED_EXTENSION", ERR_LIB_SSL, SSL_R_TLSV1_UNSUPPORTED_EXTENSION}, +- #else +- {"TLSV1_UNSUPPORTED_EXTENSION", 20, 1110}, +- #endif +- #ifdef SSL_R_TLS_ILLEGAL_EXPORTER_LABEL +- {"TLS_ILLEGAL_EXPORTER_LABEL", ERR_LIB_SSL, SSL_R_TLS_ILLEGAL_EXPORTER_LABEL}, +- #else +- {"TLS_ILLEGAL_EXPORTER_LABEL", 20, 367}, +- #endif +- #ifdef SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST +- {"TLS_INVALID_ECPOINTFORMAT_LIST", ERR_LIB_SSL, SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST}, +- #else +- {"TLS_INVALID_ECPOINTFORMAT_LIST", 20, 157}, +- #endif +- #ifdef SSL_R_TOO_MANY_KEY_UPDATES +- {"TOO_MANY_KEY_UPDATES", ERR_LIB_SSL, SSL_R_TOO_MANY_KEY_UPDATES}, +- #else +- {"TOO_MANY_KEY_UPDATES", 20, 132}, +- #endif +- #ifdef SSL_R_TOO_MANY_WARN_ALERTS +- {"TOO_MANY_WARN_ALERTS", ERR_LIB_SSL, SSL_R_TOO_MANY_WARN_ALERTS}, +- #else +- {"TOO_MANY_WARN_ALERTS", 20, 409}, +- #endif +- #ifdef SSL_R_TOO_MUCH_EARLY_DATA +- {"TOO_MUCH_EARLY_DATA", ERR_LIB_SSL, SSL_R_TOO_MUCH_EARLY_DATA}, +- #else +- {"TOO_MUCH_EARLY_DATA", 20, 164}, +- #endif +- #ifdef SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS +- {"UNABLE_TO_FIND_ECDH_PARAMETERS", ERR_LIB_SSL, SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS}, +- #else +- {"UNABLE_TO_FIND_ECDH_PARAMETERS", 20, 314}, +- #endif +- #ifdef SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS +- {"UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS", ERR_LIB_SSL, SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS}, +- #else +- {"UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS", 20, 239}, +- #endif +- #ifdef SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES +- {"UNABLE_TO_LOAD_SSL3_MD5_ROUTINES", ERR_LIB_SSL, SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES}, +- #else +- {"UNABLE_TO_LOAD_SSL3_MD5_ROUTINES", 20, 242}, +- #endif +- #ifdef SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES +- {"UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES", ERR_LIB_SSL, SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES}, +- #else +- {"UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES", 20, 243}, +- #endif +- #ifdef SSL_R_UNEXPECTED_CCS_MESSAGE +- {"UNEXPECTED_CCS_MESSAGE", ERR_LIB_SSL, SSL_R_UNEXPECTED_CCS_MESSAGE}, +- #else +- {"UNEXPECTED_CCS_MESSAGE", 20, 262}, +- #endif +- #ifdef SSL_R_UNEXPECTED_END_OF_EARLY_DATA +- {"UNEXPECTED_END_OF_EARLY_DATA", ERR_LIB_SSL, SSL_R_UNEXPECTED_END_OF_EARLY_DATA}, +- #else +- {"UNEXPECTED_END_OF_EARLY_DATA", 20, 178}, +- #endif +- #ifdef SSL_R_UNEXPECTED_EOF_WHILE_READING +- {"UNEXPECTED_EOF_WHILE_READING", ERR_LIB_SSL, SSL_R_UNEXPECTED_EOF_WHILE_READING}, +- #else +- {"UNEXPECTED_EOF_WHILE_READING", 20, 294}, +- #endif +- #ifdef SSL_R_UNEXPECTED_MESSAGE +- {"UNEXPECTED_MESSAGE", ERR_LIB_SSL, SSL_R_UNEXPECTED_MESSAGE}, +- #else +- {"UNEXPECTED_MESSAGE", 20, 244}, +- #endif +- #ifdef SSL_R_UNEXPECTED_RECORD +- {"UNEXPECTED_RECORD", ERR_LIB_SSL, SSL_R_UNEXPECTED_RECORD}, +- #else +- {"UNEXPECTED_RECORD", 20, 245}, +- #endif +- #ifdef SSL_R_UNINITIALIZED +- {"UNINITIALIZED", ERR_LIB_SSL, SSL_R_UNINITIALIZED}, +- #else +- {"UNINITIALIZED", 20, 276}, +- #endif +- #ifdef SSL_R_UNKNOWN_ALERT_TYPE +- {"UNKNOWN_ALERT_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_ALERT_TYPE}, +- #else +- {"UNKNOWN_ALERT_TYPE", 20, 246}, +- #endif +- #ifdef SSL_R_UNKNOWN_CERTIFICATE_TYPE +- {"UNKNOWN_CERTIFICATE_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE}, +- #else +- {"UNKNOWN_CERTIFICATE_TYPE", 20, 247}, +- #endif +- #ifdef SSL_R_UNKNOWN_CIPHER_RETURNED +- {"UNKNOWN_CIPHER_RETURNED", ERR_LIB_SSL, SSL_R_UNKNOWN_CIPHER_RETURNED}, +- #else +- {"UNKNOWN_CIPHER_RETURNED", 20, 248}, +- #endif +- #ifdef SSL_R_UNKNOWN_CIPHER_TYPE +- {"UNKNOWN_CIPHER_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_CIPHER_TYPE}, +- #else +- {"UNKNOWN_CIPHER_TYPE", 20, 249}, +- #endif +- #ifdef SSL_R_UNKNOWN_CMD_NAME +- {"UNKNOWN_CMD_NAME", ERR_LIB_SSL, SSL_R_UNKNOWN_CMD_NAME}, +- #else +- {"UNKNOWN_CMD_NAME", 20, 386}, +- #endif +- #ifdef SSL_R_UNKNOWN_COMMAND +- {"UNKNOWN_COMMAND", ERR_LIB_SSL, SSL_R_UNKNOWN_COMMAND}, +- #else +- {"UNKNOWN_COMMAND", 20, 139}, +- #endif +- #ifdef SSL_R_UNKNOWN_DIGEST +- {"UNKNOWN_DIGEST", ERR_LIB_SSL, SSL_R_UNKNOWN_DIGEST}, +- #else +- {"UNKNOWN_DIGEST", 20, 368}, +- #endif +- #ifdef SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE +- {"UNKNOWN_KEY_EXCHANGE_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE}, +- #else +- {"UNKNOWN_KEY_EXCHANGE_TYPE", 20, 250}, +- #endif +- #ifdef SSL_R_UNKNOWN_PKEY_TYPE +- {"UNKNOWN_PKEY_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_PKEY_TYPE}, +- #else +- {"UNKNOWN_PKEY_TYPE", 20, 251}, +- #endif +- #ifdef SSL_R_UNKNOWN_PROTOCOL +- {"UNKNOWN_PROTOCOL", ERR_LIB_SSL, SSL_R_UNKNOWN_PROTOCOL}, +- #else +- {"UNKNOWN_PROTOCOL", 20, 252}, +- #endif +- #ifdef SSL_R_UNKNOWN_SSL_VERSION +- {"UNKNOWN_SSL_VERSION", ERR_LIB_SSL, SSL_R_UNKNOWN_SSL_VERSION}, +- #else +- {"UNKNOWN_SSL_VERSION", 20, 254}, +- #endif +- #ifdef SSL_R_UNKNOWN_STATE +- {"UNKNOWN_STATE", ERR_LIB_SSL, SSL_R_UNKNOWN_STATE}, +- #else +- {"UNKNOWN_STATE", 20, 255}, +- #endif +- #ifdef SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED +- {"UNSAFE_LEGACY_RENEGOTIATION_DISABLED", ERR_LIB_SSL, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED}, +- #else +- {"UNSAFE_LEGACY_RENEGOTIATION_DISABLED", 20, 338}, +- #endif +- #ifdef SSL_R_UNSOLICITED_EXTENSION +- {"UNSOLICITED_EXTENSION", ERR_LIB_SSL, SSL_R_UNSOLICITED_EXTENSION}, +- #else +- {"UNSOLICITED_EXTENSION", 20, 217}, +- #endif +- #ifdef SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM +- {"UNSUPPORTED_COMPRESSION_ALGORITHM", ERR_LIB_SSL, SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM}, +- #else +- {"UNSUPPORTED_COMPRESSION_ALGORITHM", 20, 257}, +- #endif +- #ifdef SSL_R_UNSUPPORTED_ELLIPTIC_CURVE +- {"UNSUPPORTED_ELLIPTIC_CURVE", ERR_LIB_SSL, SSL_R_UNSUPPORTED_ELLIPTIC_CURVE}, +- #else +- {"UNSUPPORTED_ELLIPTIC_CURVE", 20, 315}, +- #endif +- #ifdef SSL_R_UNSUPPORTED_PROTOCOL +- {"UNSUPPORTED_PROTOCOL", ERR_LIB_SSL, SSL_R_UNSUPPORTED_PROTOCOL}, +- #else +- {"UNSUPPORTED_PROTOCOL", 20, 258}, +- #endif +- #ifdef SSL_R_UNSUPPORTED_SSL_VERSION +- {"UNSUPPORTED_SSL_VERSION", ERR_LIB_SSL, SSL_R_UNSUPPORTED_SSL_VERSION}, +- #else +- {"UNSUPPORTED_SSL_VERSION", 20, 259}, +- #endif +- #ifdef SSL_R_UNSUPPORTED_STATUS_TYPE +- {"UNSUPPORTED_STATUS_TYPE", ERR_LIB_SSL, SSL_R_UNSUPPORTED_STATUS_TYPE}, +- #else +- {"UNSUPPORTED_STATUS_TYPE", 20, 329}, +- #endif +- #ifdef SSL_R_USE_SRTP_NOT_NEGOTIATED +- {"USE_SRTP_NOT_NEGOTIATED", ERR_LIB_SSL, SSL_R_USE_SRTP_NOT_NEGOTIATED}, +- #else +- {"USE_SRTP_NOT_NEGOTIATED", 20, 369}, +- #endif +- #ifdef SSL_R_VERSION_TOO_HIGH +- {"VERSION_TOO_HIGH", ERR_LIB_SSL, SSL_R_VERSION_TOO_HIGH}, +- #else +- {"VERSION_TOO_HIGH", 20, 166}, +- #endif +- #ifdef SSL_R_VERSION_TOO_LOW +- {"VERSION_TOO_LOW", ERR_LIB_SSL, SSL_R_VERSION_TOO_LOW}, +- #else +- {"VERSION_TOO_LOW", 20, 396}, +- #endif +- #ifdef SSL_R_WRONG_CERTIFICATE_TYPE +- {"WRONG_CERTIFICATE_TYPE", ERR_LIB_SSL, SSL_R_WRONG_CERTIFICATE_TYPE}, +- #else +- {"WRONG_CERTIFICATE_TYPE", 20, 383}, +- #endif +- #ifdef SSL_R_WRONG_CIPHER_RETURNED +- {"WRONG_CIPHER_RETURNED", ERR_LIB_SSL, SSL_R_WRONG_CIPHER_RETURNED}, +- #else +- {"WRONG_CIPHER_RETURNED", 20, 261}, +- #endif +- #ifdef SSL_R_WRONG_CURVE +- {"WRONG_CURVE", ERR_LIB_SSL, SSL_R_WRONG_CURVE}, +- #else +- {"WRONG_CURVE", 20, 378}, +- #endif +- #ifdef SSL_R_WRONG_SIGNATURE_LENGTH +- {"WRONG_SIGNATURE_LENGTH", ERR_LIB_SSL, SSL_R_WRONG_SIGNATURE_LENGTH}, +- #else +- {"WRONG_SIGNATURE_LENGTH", 20, 264}, +- #endif +- #ifdef SSL_R_WRONG_SIGNATURE_SIZE +- {"WRONG_SIGNATURE_SIZE", ERR_LIB_SSL, SSL_R_WRONG_SIGNATURE_SIZE}, +- #else +- {"WRONG_SIGNATURE_SIZE", 20, 265}, +- #endif +- #ifdef SSL_R_WRONG_SIGNATURE_TYPE +- {"WRONG_SIGNATURE_TYPE", ERR_LIB_SSL, SSL_R_WRONG_SIGNATURE_TYPE}, +- #else +- {"WRONG_SIGNATURE_TYPE", 20, 370}, +- #endif +- #ifdef SSL_R_WRONG_SSL_VERSION +- {"WRONG_SSL_VERSION", ERR_LIB_SSL, SSL_R_WRONG_SSL_VERSION}, +- #else +- {"WRONG_SSL_VERSION", 20, 266}, +- #endif +- #ifdef SSL_R_WRONG_VERSION_NUMBER +- {"WRONG_VERSION_NUMBER", ERR_LIB_SSL, SSL_R_WRONG_VERSION_NUMBER}, +- #else +- {"WRONG_VERSION_NUMBER", 20, 267}, +- #endif +- #ifdef SSL_R_X509_LIB +- {"X509_LIB", ERR_LIB_SSL, SSL_R_X509_LIB}, +- #else +- {"X509_LIB", 20, 268}, +- #endif +- #ifdef SSL_R_X509_VERIFICATION_SETUP_PROBLEMS +- {"X509_VERIFICATION_SETUP_PROBLEMS", ERR_LIB_SSL, SSL_R_X509_VERIFICATION_SETUP_PROBLEMS}, +- #else +- {"X509_VERIFICATION_SETUP_PROBLEMS", 20, 269}, +- #endif +- #ifdef TS_R_BAD_PKCS7_TYPE +- {"BAD_PKCS7_TYPE", ERR_LIB_TS, TS_R_BAD_PKCS7_TYPE}, +- #else +- {"BAD_PKCS7_TYPE", 47, 132}, +- #endif +- #ifdef TS_R_BAD_TYPE +- {"BAD_TYPE", ERR_LIB_TS, TS_R_BAD_TYPE}, +- #else +- {"BAD_TYPE", 47, 133}, +- #endif +- #ifdef TS_R_CANNOT_LOAD_CERT +- {"CANNOT_LOAD_CERT", ERR_LIB_TS, TS_R_CANNOT_LOAD_CERT}, +- #else +- {"CANNOT_LOAD_CERT", 47, 137}, +- #endif +- #ifdef TS_R_CANNOT_LOAD_KEY +- {"CANNOT_LOAD_KEY", ERR_LIB_TS, TS_R_CANNOT_LOAD_KEY}, +- #else +- {"CANNOT_LOAD_KEY", 47, 138}, +- #endif +- #ifdef TS_R_CERTIFICATE_VERIFY_ERROR +- {"CERTIFICATE_VERIFY_ERROR", ERR_LIB_TS, TS_R_CERTIFICATE_VERIFY_ERROR}, +- #else +- {"CERTIFICATE_VERIFY_ERROR", 47, 100}, +- #endif +- #ifdef TS_R_COULD_NOT_SET_ENGINE +- {"COULD_NOT_SET_ENGINE", ERR_LIB_TS, TS_R_COULD_NOT_SET_ENGINE}, +- #else +- {"COULD_NOT_SET_ENGINE", 47, 127}, +- #endif +- #ifdef TS_R_COULD_NOT_SET_TIME +- {"COULD_NOT_SET_TIME", ERR_LIB_TS, TS_R_COULD_NOT_SET_TIME}, +- #else +- {"COULD_NOT_SET_TIME", 47, 115}, +- #endif +- #ifdef TS_R_DETACHED_CONTENT +- {"DETACHED_CONTENT", ERR_LIB_TS, TS_R_DETACHED_CONTENT}, +- #else +- {"DETACHED_CONTENT", 47, 134}, +- #endif +- #ifdef TS_R_ESS_ADD_SIGNING_CERT_ERROR +- {"ESS_ADD_SIGNING_CERT_ERROR", ERR_LIB_TS, TS_R_ESS_ADD_SIGNING_CERT_ERROR}, +- #else +- {"ESS_ADD_SIGNING_CERT_ERROR", 47, 116}, +- #endif +- #ifdef TS_R_ESS_ADD_SIGNING_CERT_V2_ERROR +- {"ESS_ADD_SIGNING_CERT_V2_ERROR", ERR_LIB_TS, TS_R_ESS_ADD_SIGNING_CERT_V2_ERROR}, +- #else +- {"ESS_ADD_SIGNING_CERT_V2_ERROR", 47, 139}, +- #endif +- #ifdef TS_R_ESS_SIGNING_CERTIFICATE_ERROR +- {"ESS_SIGNING_CERTIFICATE_ERROR", ERR_LIB_TS, TS_R_ESS_SIGNING_CERTIFICATE_ERROR}, +- #else +- {"ESS_SIGNING_CERTIFICATE_ERROR", 47, 101}, +- #endif +- #ifdef TS_R_INVALID_NULL_POINTER +- {"INVALID_NULL_POINTER", ERR_LIB_TS, TS_R_INVALID_NULL_POINTER}, +- #else +- {"INVALID_NULL_POINTER", 47, 102}, +- #endif +- #ifdef TS_R_INVALID_SIGNER_CERTIFICATE_PURPOSE +- {"INVALID_SIGNER_CERTIFICATE_PURPOSE", ERR_LIB_TS, TS_R_INVALID_SIGNER_CERTIFICATE_PURPOSE}, +- #else +- {"INVALID_SIGNER_CERTIFICATE_PURPOSE", 47, 117}, +- #endif +- #ifdef TS_R_MESSAGE_IMPRINT_MISMATCH +- {"MESSAGE_IMPRINT_MISMATCH", ERR_LIB_TS, TS_R_MESSAGE_IMPRINT_MISMATCH}, +- #else +- {"MESSAGE_IMPRINT_MISMATCH", 47, 103}, +- #endif +- #ifdef TS_R_NONCE_MISMATCH +- {"NONCE_MISMATCH", ERR_LIB_TS, TS_R_NONCE_MISMATCH}, +- #else +- {"NONCE_MISMATCH", 47, 104}, +- #endif +- #ifdef TS_R_NONCE_NOT_RETURNED +- {"NONCE_NOT_RETURNED", ERR_LIB_TS, TS_R_NONCE_NOT_RETURNED}, +- #else +- {"NONCE_NOT_RETURNED", 47, 105}, +- #endif +- #ifdef TS_R_NO_CONTENT +- {"NO_CONTENT", ERR_LIB_TS, TS_R_NO_CONTENT}, +- #else +- {"NO_CONTENT", 47, 106}, +- #endif +- #ifdef TS_R_NO_TIME_STAMP_TOKEN +- {"NO_TIME_STAMP_TOKEN", ERR_LIB_TS, TS_R_NO_TIME_STAMP_TOKEN}, +- #else +- {"NO_TIME_STAMP_TOKEN", 47, 107}, +- #endif +- #ifdef TS_R_PKCS7_ADD_SIGNATURE_ERROR +- {"PKCS7_ADD_SIGNATURE_ERROR", ERR_LIB_TS, TS_R_PKCS7_ADD_SIGNATURE_ERROR}, +- #else +- {"PKCS7_ADD_SIGNATURE_ERROR", 47, 118}, +- #endif +- #ifdef TS_R_PKCS7_ADD_SIGNED_ATTR_ERROR +- {"PKCS7_ADD_SIGNED_ATTR_ERROR", ERR_LIB_TS, TS_R_PKCS7_ADD_SIGNED_ATTR_ERROR}, +- #else +- {"PKCS7_ADD_SIGNED_ATTR_ERROR", 47, 119}, +- #endif +- #ifdef TS_R_PKCS7_TO_TS_TST_INFO_FAILED +- {"PKCS7_TO_TS_TST_INFO_FAILED", ERR_LIB_TS, TS_R_PKCS7_TO_TS_TST_INFO_FAILED}, +- #else +- {"PKCS7_TO_TS_TST_INFO_FAILED", 47, 129}, +- #endif +- #ifdef TS_R_POLICY_MISMATCH +- {"POLICY_MISMATCH", ERR_LIB_TS, TS_R_POLICY_MISMATCH}, +- #else +- {"POLICY_MISMATCH", 47, 108}, +- #endif +- #ifdef TS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE +- {"PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE", ERR_LIB_TS, TS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE}, +- #else +- {"PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE", 47, 120}, +- #endif +- #ifdef TS_R_RESPONSE_SETUP_ERROR +- {"RESPONSE_SETUP_ERROR", ERR_LIB_TS, TS_R_RESPONSE_SETUP_ERROR}, +- #else +- {"RESPONSE_SETUP_ERROR", 47, 121}, +- #endif +- #ifdef TS_R_SIGNATURE_FAILURE +- {"SIGNATURE_FAILURE", ERR_LIB_TS, TS_R_SIGNATURE_FAILURE}, +- #else +- {"SIGNATURE_FAILURE", 47, 109}, +- #endif +- #ifdef TS_R_THERE_MUST_BE_ONE_SIGNER +- {"THERE_MUST_BE_ONE_SIGNER", ERR_LIB_TS, TS_R_THERE_MUST_BE_ONE_SIGNER}, +- #else +- {"THERE_MUST_BE_ONE_SIGNER", 47, 110}, +- #endif +- #ifdef TS_R_TIME_SYSCALL_ERROR +- {"TIME_SYSCALL_ERROR", ERR_LIB_TS, TS_R_TIME_SYSCALL_ERROR}, +- #else +- {"TIME_SYSCALL_ERROR", 47, 122}, +- #endif +- #ifdef TS_R_TOKEN_NOT_PRESENT +- {"TOKEN_NOT_PRESENT", ERR_LIB_TS, TS_R_TOKEN_NOT_PRESENT}, +- #else +- {"TOKEN_NOT_PRESENT", 47, 130}, +- #endif +- #ifdef TS_R_TOKEN_PRESENT +- {"TOKEN_PRESENT", ERR_LIB_TS, TS_R_TOKEN_PRESENT}, +- #else +- {"TOKEN_PRESENT", 47, 131}, +- #endif +- #ifdef TS_R_TSA_NAME_MISMATCH +- {"TSA_NAME_MISMATCH", ERR_LIB_TS, TS_R_TSA_NAME_MISMATCH}, +- #else +- {"TSA_NAME_MISMATCH", 47, 111}, +- #endif +- #ifdef TS_R_TSA_UNTRUSTED +- {"TSA_UNTRUSTED", ERR_LIB_TS, TS_R_TSA_UNTRUSTED}, +- #else +- {"TSA_UNTRUSTED", 47, 112}, +- #endif +- #ifdef TS_R_TST_INFO_SETUP_ERROR +- {"TST_INFO_SETUP_ERROR", ERR_LIB_TS, TS_R_TST_INFO_SETUP_ERROR}, +- #else +- {"TST_INFO_SETUP_ERROR", 47, 123}, +- #endif +- #ifdef TS_R_TS_DATASIGN +- {"TS_DATASIGN", ERR_LIB_TS, TS_R_TS_DATASIGN}, +- #else +- {"TS_DATASIGN", 47, 124}, +- #endif +- #ifdef TS_R_UNACCEPTABLE_POLICY +- {"UNACCEPTABLE_POLICY", ERR_LIB_TS, TS_R_UNACCEPTABLE_POLICY}, +- #else +- {"UNACCEPTABLE_POLICY", 47, 125}, +- #endif +- #ifdef TS_R_UNSUPPORTED_MD_ALGORITHM +- {"UNSUPPORTED_MD_ALGORITHM", ERR_LIB_TS, TS_R_UNSUPPORTED_MD_ALGORITHM}, +- #else +- {"UNSUPPORTED_MD_ALGORITHM", 47, 126}, +- #endif +- #ifdef TS_R_UNSUPPORTED_VERSION +- {"UNSUPPORTED_VERSION", ERR_LIB_TS, TS_R_UNSUPPORTED_VERSION}, +- #else +- {"UNSUPPORTED_VERSION", 47, 113}, +- #endif +- #ifdef TS_R_VAR_BAD_VALUE +- {"VAR_BAD_VALUE", ERR_LIB_TS, TS_R_VAR_BAD_VALUE}, +- #else +- {"VAR_BAD_VALUE", 47, 135}, +- #endif +- #ifdef TS_R_VAR_LOOKUP_FAILURE +- {"VAR_LOOKUP_FAILURE", ERR_LIB_TS, TS_R_VAR_LOOKUP_FAILURE}, +- #else +- {"VAR_LOOKUP_FAILURE", 47, 136}, +- #endif +- #ifdef TS_R_WRONG_CONTENT_TYPE +- {"WRONG_CONTENT_TYPE", ERR_LIB_TS, TS_R_WRONG_CONTENT_TYPE}, +- #else +- {"WRONG_CONTENT_TYPE", 47, 114}, +- #endif +- #ifdef UI_R_COMMON_OK_AND_CANCEL_CHARACTERS +- {"COMMON_OK_AND_CANCEL_CHARACTERS", ERR_LIB_UI, UI_R_COMMON_OK_AND_CANCEL_CHARACTERS}, +- #else +- {"COMMON_OK_AND_CANCEL_CHARACTERS", 40, 104}, +- #endif +- #ifdef UI_R_INDEX_TOO_LARGE +- {"INDEX_TOO_LARGE", ERR_LIB_UI, UI_R_INDEX_TOO_LARGE}, +- #else +- {"INDEX_TOO_LARGE", 40, 102}, +- #endif +- #ifdef UI_R_INDEX_TOO_SMALL +- {"INDEX_TOO_SMALL", ERR_LIB_UI, UI_R_INDEX_TOO_SMALL}, +- #else +- {"INDEX_TOO_SMALL", 40, 103}, +- #endif +- #ifdef UI_R_NO_RESULT_BUFFER +- {"NO_RESULT_BUFFER", ERR_LIB_UI, UI_R_NO_RESULT_BUFFER}, +- #else +- {"NO_RESULT_BUFFER", 40, 105}, +- #endif +- #ifdef UI_R_PROCESSING_ERROR +- {"PROCESSING_ERROR", ERR_LIB_UI, UI_R_PROCESSING_ERROR}, +- #else +- {"PROCESSING_ERROR", 40, 107}, +- #endif +- #ifdef UI_R_RESULT_TOO_LARGE +- {"RESULT_TOO_LARGE", ERR_LIB_UI, UI_R_RESULT_TOO_LARGE}, +- #else +- {"RESULT_TOO_LARGE", 40, 100}, +- #endif +- #ifdef UI_R_RESULT_TOO_SMALL +- {"RESULT_TOO_SMALL", ERR_LIB_UI, UI_R_RESULT_TOO_SMALL}, +- #else +- {"RESULT_TOO_SMALL", 40, 101}, +- #endif +- #ifdef UI_R_SYSASSIGN_ERROR +- {"SYSASSIGN_ERROR", ERR_LIB_UI, UI_R_SYSASSIGN_ERROR}, +- #else +- {"SYSASSIGN_ERROR", 40, 109}, +- #endif +- #ifdef UI_R_SYSDASSGN_ERROR +- {"SYSDASSGN_ERROR", ERR_LIB_UI, UI_R_SYSDASSGN_ERROR}, +- #else +- {"SYSDASSGN_ERROR", 40, 110}, +- #endif +- #ifdef UI_R_SYSQIOW_ERROR +- {"SYSQIOW_ERROR", ERR_LIB_UI, UI_R_SYSQIOW_ERROR}, +- #else +- {"SYSQIOW_ERROR", 40, 111}, +- #endif +- #ifdef UI_R_UNKNOWN_CONTROL_COMMAND +- {"UNKNOWN_CONTROL_COMMAND", ERR_LIB_UI, UI_R_UNKNOWN_CONTROL_COMMAND}, +- #else +- {"UNKNOWN_CONTROL_COMMAND", 40, 106}, +- #endif +- #ifdef UI_R_UNKNOWN_TTYGET_ERRNO_VALUE +- {"UNKNOWN_TTYGET_ERRNO_VALUE", ERR_LIB_UI, UI_R_UNKNOWN_TTYGET_ERRNO_VALUE}, +- #else +- {"UNKNOWN_TTYGET_ERRNO_VALUE", 40, 108}, +- #endif +- #ifdef UI_R_USER_DATA_DUPLICATION_UNSUPPORTED +- {"USER_DATA_DUPLICATION_UNSUPPORTED", ERR_LIB_UI, UI_R_USER_DATA_DUPLICATION_UNSUPPORTED}, +- #else +- {"USER_DATA_DUPLICATION_UNSUPPORTED", 40, 112}, +- #endif +- #ifdef X509V3_R_BAD_IP_ADDRESS +- {"BAD_IP_ADDRESS", ERR_LIB_X509V3, X509V3_R_BAD_IP_ADDRESS}, +- #else +- {"BAD_IP_ADDRESS", 34, 118}, +- #endif +- #ifdef X509V3_R_BAD_OBJECT +- {"BAD_OBJECT", ERR_LIB_X509V3, X509V3_R_BAD_OBJECT}, +- #else +- {"BAD_OBJECT", 34, 119}, +- #endif +- #ifdef X509V3_R_BN_DEC2BN_ERROR +- {"BN_DEC2BN_ERROR", ERR_LIB_X509V3, X509V3_R_BN_DEC2BN_ERROR}, +- #else +- {"BN_DEC2BN_ERROR", 34, 100}, +- #endif +- #ifdef X509V3_R_BN_TO_ASN1_INTEGER_ERROR +- {"BN_TO_ASN1_INTEGER_ERROR", ERR_LIB_X509V3, X509V3_R_BN_TO_ASN1_INTEGER_ERROR}, +- #else +- {"BN_TO_ASN1_INTEGER_ERROR", 34, 101}, +- #endif +- #ifdef X509V3_R_DIRNAME_ERROR +- {"DIRNAME_ERROR", ERR_LIB_X509V3, X509V3_R_DIRNAME_ERROR}, +- #else +- {"DIRNAME_ERROR", 34, 149}, +- #endif +- #ifdef X509V3_R_DISTPOINT_ALREADY_SET +- {"DISTPOINT_ALREADY_SET", ERR_LIB_X509V3, X509V3_R_DISTPOINT_ALREADY_SET}, +- #else +- {"DISTPOINT_ALREADY_SET", 34, 160}, +- #endif +- #ifdef X509V3_R_DUPLICATE_ZONE_ID +- {"DUPLICATE_ZONE_ID", ERR_LIB_X509V3, X509V3_R_DUPLICATE_ZONE_ID}, +- #else +- {"DUPLICATE_ZONE_ID", 34, 133}, +- #endif +- #ifdef X509V3_R_EMPTY_KEY_USAGE +- {"EMPTY_KEY_USAGE", ERR_LIB_X509V3, X509V3_R_EMPTY_KEY_USAGE}, +- #else +- {"EMPTY_KEY_USAGE", 34, 169}, +- #endif +- #ifdef X509V3_R_ERROR_CONVERTING_ZONE +- {"ERROR_CONVERTING_ZONE", ERR_LIB_X509V3, X509V3_R_ERROR_CONVERTING_ZONE}, +- #else +- {"ERROR_CONVERTING_ZONE", 34, 131}, +- #endif +- #ifdef X509V3_R_ERROR_CREATING_EXTENSION +- {"ERROR_CREATING_EXTENSION", ERR_LIB_X509V3, X509V3_R_ERROR_CREATING_EXTENSION}, +- #else +- {"ERROR_CREATING_EXTENSION", 34, 144}, +- #endif +- #ifdef X509V3_R_ERROR_IN_EXTENSION +- {"ERROR_IN_EXTENSION", ERR_LIB_X509V3, X509V3_R_ERROR_IN_EXTENSION}, +- #else +- {"ERROR_IN_EXTENSION", 34, 128}, +- #endif +- #ifdef X509V3_R_EXPECTED_A_SECTION_NAME +- {"EXPECTED_A_SECTION_NAME", ERR_LIB_X509V3, X509V3_R_EXPECTED_A_SECTION_NAME}, +- #else +- {"EXPECTED_A_SECTION_NAME", 34, 137}, +- #endif +- #ifdef X509V3_R_EXTENSION_EXISTS +- {"EXTENSION_EXISTS", ERR_LIB_X509V3, X509V3_R_EXTENSION_EXISTS}, +- #else +- {"EXTENSION_EXISTS", 34, 145}, +- #endif +- #ifdef X509V3_R_EXTENSION_NAME_ERROR +- {"EXTENSION_NAME_ERROR", ERR_LIB_X509V3, X509V3_R_EXTENSION_NAME_ERROR}, +- #else +- {"EXTENSION_NAME_ERROR", 34, 115}, +- #endif +- #ifdef X509V3_R_EXTENSION_NOT_FOUND +- {"EXTENSION_NOT_FOUND", ERR_LIB_X509V3, X509V3_R_EXTENSION_NOT_FOUND}, +- #else +- {"EXTENSION_NOT_FOUND", 34, 102}, +- #endif +- #ifdef X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED +- {"EXTENSION_SETTING_NOT_SUPPORTED", ERR_LIB_X509V3, X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED}, +- #else +- {"EXTENSION_SETTING_NOT_SUPPORTED", 34, 103}, +- #endif +- #ifdef X509V3_R_EXTENSION_VALUE_ERROR +- {"EXTENSION_VALUE_ERROR", ERR_LIB_X509V3, X509V3_R_EXTENSION_VALUE_ERROR}, +- #else +- {"EXTENSION_VALUE_ERROR", 34, 116}, +- #endif +- #ifdef X509V3_R_ILLEGAL_EMPTY_EXTENSION +- {"ILLEGAL_EMPTY_EXTENSION", ERR_LIB_X509V3, X509V3_R_ILLEGAL_EMPTY_EXTENSION}, +- #else +- {"ILLEGAL_EMPTY_EXTENSION", 34, 151}, +- #endif +- #ifdef X509V3_R_INCORRECT_POLICY_SYNTAX_TAG +- {"INCORRECT_POLICY_SYNTAX_TAG", ERR_LIB_X509V3, X509V3_R_INCORRECT_POLICY_SYNTAX_TAG}, +- #else +- {"INCORRECT_POLICY_SYNTAX_TAG", 34, 152}, +- #endif +- #ifdef X509V3_R_INVALID_ASNUMBER +- {"INVALID_ASNUMBER", ERR_LIB_X509V3, X509V3_R_INVALID_ASNUMBER}, +- #else +- {"INVALID_ASNUMBER", 34, 162}, +- #endif +- #ifdef X509V3_R_INVALID_ASRANGE +- {"INVALID_ASRANGE", ERR_LIB_X509V3, X509V3_R_INVALID_ASRANGE}, +- #else +- {"INVALID_ASRANGE", 34, 163}, +- #endif +- #ifdef X509V3_R_INVALID_BOOLEAN_STRING +- {"INVALID_BOOLEAN_STRING", ERR_LIB_X509V3, X509V3_R_INVALID_BOOLEAN_STRING}, +- #else +- {"INVALID_BOOLEAN_STRING", 34, 104}, +- #endif +- #ifdef X509V3_R_INVALID_CERTIFICATE +- {"INVALID_CERTIFICATE", ERR_LIB_X509V3, X509V3_R_INVALID_CERTIFICATE}, +- #else +- {"INVALID_CERTIFICATE", 34, 158}, +- #endif +- #ifdef X509V3_R_INVALID_EMPTY_NAME +- {"INVALID_EMPTY_NAME", ERR_LIB_X509V3, X509V3_R_INVALID_EMPTY_NAME}, +- #else +- {"INVALID_EMPTY_NAME", 34, 108}, +- #endif +- #ifdef X509V3_R_INVALID_EXTENSION_STRING +- {"INVALID_EXTENSION_STRING", ERR_LIB_X509V3, X509V3_R_INVALID_EXTENSION_STRING}, +- #else +- {"INVALID_EXTENSION_STRING", 34, 105}, +- #endif +- #ifdef X509V3_R_INVALID_INHERITANCE +- {"INVALID_INHERITANCE", ERR_LIB_X509V3, X509V3_R_INVALID_INHERITANCE}, +- #else +- {"INVALID_INHERITANCE", 34, 165}, +- #endif +- #ifdef X509V3_R_INVALID_IPADDRESS +- {"INVALID_IPADDRESS", ERR_LIB_X509V3, X509V3_R_INVALID_IPADDRESS}, +- #else +- {"INVALID_IPADDRESS", 34, 166}, +- #endif +- #ifdef X509V3_R_INVALID_MULTIPLE_RDNS +- {"INVALID_MULTIPLE_RDNS", ERR_LIB_X509V3, X509V3_R_INVALID_MULTIPLE_RDNS}, +- #else +- {"INVALID_MULTIPLE_RDNS", 34, 161}, +- #endif +- #ifdef X509V3_R_INVALID_NAME +- {"INVALID_NAME", ERR_LIB_X509V3, X509V3_R_INVALID_NAME}, +- #else +- {"INVALID_NAME", 34, 106}, +- #endif +- #ifdef X509V3_R_INVALID_NULL_ARGUMENT +- {"INVALID_NULL_ARGUMENT", ERR_LIB_X509V3, X509V3_R_INVALID_NULL_ARGUMENT}, +- #else +- {"INVALID_NULL_ARGUMENT", 34, 107}, +- #endif +- #ifdef X509V3_R_INVALID_NULL_VALUE +- {"INVALID_NULL_VALUE", ERR_LIB_X509V3, X509V3_R_INVALID_NULL_VALUE}, +- #else +- {"INVALID_NULL_VALUE", 34, 109}, +- #endif +- #ifdef X509V3_R_INVALID_NUMBER +- {"INVALID_NUMBER", ERR_LIB_X509V3, X509V3_R_INVALID_NUMBER}, +- #else +- {"INVALID_NUMBER", 34, 140}, +- #endif +- #ifdef X509V3_R_INVALID_NUMBERS +- {"INVALID_NUMBERS", ERR_LIB_X509V3, X509V3_R_INVALID_NUMBERS}, +- #else +- {"INVALID_NUMBERS", 34, 141}, +- #endif +- #ifdef X509V3_R_INVALID_OBJECT_IDENTIFIER +- {"INVALID_OBJECT_IDENTIFIER", ERR_LIB_X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER}, +- #else +- {"INVALID_OBJECT_IDENTIFIER", 34, 110}, +- #endif +- #ifdef X509V3_R_INVALID_OPTION +- {"INVALID_OPTION", ERR_LIB_X509V3, X509V3_R_INVALID_OPTION}, +- #else +- {"INVALID_OPTION", 34, 138}, +- #endif +- #ifdef X509V3_R_INVALID_POLICY_IDENTIFIER +- {"INVALID_POLICY_IDENTIFIER", ERR_LIB_X509V3, X509V3_R_INVALID_POLICY_IDENTIFIER}, +- #else +- {"INVALID_POLICY_IDENTIFIER", 34, 134}, +- #endif +- #ifdef X509V3_R_INVALID_PROXY_POLICY_SETTING +- {"INVALID_PROXY_POLICY_SETTING", ERR_LIB_X509V3, X509V3_R_INVALID_PROXY_POLICY_SETTING}, +- #else +- {"INVALID_PROXY_POLICY_SETTING", 34, 153}, +- #endif +- #ifdef X509V3_R_INVALID_PURPOSE +- {"INVALID_PURPOSE", ERR_LIB_X509V3, X509V3_R_INVALID_PURPOSE}, +- #else +- {"INVALID_PURPOSE", 34, 146}, +- #endif +- #ifdef X509V3_R_INVALID_SAFI +- {"INVALID_SAFI", ERR_LIB_X509V3, X509V3_R_INVALID_SAFI}, +- #else +- {"INVALID_SAFI", 34, 164}, +- #endif +- #ifdef X509V3_R_INVALID_SECTION +- {"INVALID_SECTION", ERR_LIB_X509V3, X509V3_R_INVALID_SECTION}, +- #else +- {"INVALID_SECTION", 34, 135}, +- #endif +- #ifdef X509V3_R_INVALID_SYNTAX +- {"INVALID_SYNTAX", ERR_LIB_X509V3, X509V3_R_INVALID_SYNTAX}, +- #else +- {"INVALID_SYNTAX", 34, 143}, +- #endif +- #ifdef X509V3_R_ISSUER_DECODE_ERROR +- {"ISSUER_DECODE_ERROR", ERR_LIB_X509V3, X509V3_R_ISSUER_DECODE_ERROR}, +- #else +- {"ISSUER_DECODE_ERROR", 34, 126}, +- #endif +- #ifdef X509V3_R_MISSING_VALUE +- {"MISSING_VALUE", ERR_LIB_X509V3, X509V3_R_MISSING_VALUE}, +- #else +- {"MISSING_VALUE", 34, 124}, +- #endif +- #ifdef X509V3_R_NEED_ORGANIZATION_AND_NUMBERS +- {"NEED_ORGANIZATION_AND_NUMBERS", ERR_LIB_X509V3, X509V3_R_NEED_ORGANIZATION_AND_NUMBERS}, +- #else +- {"NEED_ORGANIZATION_AND_NUMBERS", 34, 142}, +- #endif +- #ifdef X509V3_R_NEGATIVE_PATHLEN +- {"NEGATIVE_PATHLEN", ERR_LIB_X509V3, X509V3_R_NEGATIVE_PATHLEN}, +- #else +- {"NEGATIVE_PATHLEN", 34, 168}, +- #endif +- #ifdef X509V3_R_NO_CONFIG_DATABASE +- {"NO_CONFIG_DATABASE", ERR_LIB_X509V3, X509V3_R_NO_CONFIG_DATABASE}, +- #else +- {"NO_CONFIG_DATABASE", 34, 136}, +- #endif +- #ifdef X509V3_R_NO_ISSUER_CERTIFICATE +- {"NO_ISSUER_CERTIFICATE", ERR_LIB_X509V3, X509V3_R_NO_ISSUER_CERTIFICATE}, +- #else +- {"NO_ISSUER_CERTIFICATE", 34, 121}, +- #endif +- #ifdef X509V3_R_NO_ISSUER_DETAILS +- {"NO_ISSUER_DETAILS", ERR_LIB_X509V3, X509V3_R_NO_ISSUER_DETAILS}, +- #else +- {"NO_ISSUER_DETAILS", 34, 127}, +- #endif +- #ifdef X509V3_R_NO_POLICY_IDENTIFIER +- {"NO_POLICY_IDENTIFIER", ERR_LIB_X509V3, X509V3_R_NO_POLICY_IDENTIFIER}, +- #else +- {"NO_POLICY_IDENTIFIER", 34, 139}, +- #endif +- #ifdef X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED +- {"NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED", ERR_LIB_X509V3, X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED}, +- #else +- {"NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED", 34, 154}, +- #endif +- #ifdef X509V3_R_NO_PUBLIC_KEY +- {"NO_PUBLIC_KEY", ERR_LIB_X509V3, X509V3_R_NO_PUBLIC_KEY}, +- #else +- {"NO_PUBLIC_KEY", 34, 114}, +- #endif +- #ifdef X509V3_R_NO_SUBJECT_DETAILS +- {"NO_SUBJECT_DETAILS", ERR_LIB_X509V3, X509V3_R_NO_SUBJECT_DETAILS}, +- #else +- {"NO_SUBJECT_DETAILS", 34, 125}, +- #endif +- #ifdef X509V3_R_OPERATION_NOT_DEFINED +- {"OPERATION_NOT_DEFINED", ERR_LIB_X509V3, X509V3_R_OPERATION_NOT_DEFINED}, +- #else +- {"OPERATION_NOT_DEFINED", 34, 148}, +- #endif +- #ifdef X509V3_R_OTHERNAME_ERROR +- {"OTHERNAME_ERROR", ERR_LIB_X509V3, X509V3_R_OTHERNAME_ERROR}, +- #else +- {"OTHERNAME_ERROR", 34, 147}, +- #endif +- #ifdef X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED +- {"POLICY_LANGUAGE_ALREADY_DEFINED", ERR_LIB_X509V3, X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED}, +- #else +- {"POLICY_LANGUAGE_ALREADY_DEFINED", 34, 155}, +- #endif +- #ifdef X509V3_R_POLICY_PATH_LENGTH +- {"POLICY_PATH_LENGTH", ERR_LIB_X509V3, X509V3_R_POLICY_PATH_LENGTH}, +- #else +- {"POLICY_PATH_LENGTH", 34, 156}, +- #endif +- #ifdef X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED +- {"POLICY_PATH_LENGTH_ALREADY_DEFINED", ERR_LIB_X509V3, X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED}, +- #else +- {"POLICY_PATH_LENGTH_ALREADY_DEFINED", 34, 157}, +- #endif +- #ifdef X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY +- {"POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY", ERR_LIB_X509V3, X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY}, +- #else +- {"POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY", 34, 159}, +- #endif +- #ifdef X509V3_R_SECTION_NOT_FOUND +- {"SECTION_NOT_FOUND", ERR_LIB_X509V3, X509V3_R_SECTION_NOT_FOUND}, +- #else +- {"SECTION_NOT_FOUND", 34, 150}, +- #endif +- #ifdef X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS +- {"UNABLE_TO_GET_ISSUER_DETAILS", ERR_LIB_X509V3, X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS}, +- #else +- {"UNABLE_TO_GET_ISSUER_DETAILS", 34, 122}, +- #endif +- #ifdef X509V3_R_UNABLE_TO_GET_ISSUER_KEYID +- {"UNABLE_TO_GET_ISSUER_KEYID", ERR_LIB_X509V3, X509V3_R_UNABLE_TO_GET_ISSUER_KEYID}, +- #else +- {"UNABLE_TO_GET_ISSUER_KEYID", 34, 123}, +- #endif +- #ifdef X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT +- {"UNKNOWN_BIT_STRING_ARGUMENT", ERR_LIB_X509V3, X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT}, +- #else +- {"UNKNOWN_BIT_STRING_ARGUMENT", 34, 111}, +- #endif +- #ifdef X509V3_R_UNKNOWN_EXTENSION +- {"UNKNOWN_EXTENSION", ERR_LIB_X509V3, X509V3_R_UNKNOWN_EXTENSION}, +- #else +- {"UNKNOWN_EXTENSION", 34, 129}, +- #endif +- #ifdef X509V3_R_UNKNOWN_EXTENSION_NAME +- {"UNKNOWN_EXTENSION_NAME", ERR_LIB_X509V3, X509V3_R_UNKNOWN_EXTENSION_NAME}, +- #else +- {"UNKNOWN_EXTENSION_NAME", 34, 130}, +- #endif +- #ifdef X509V3_R_UNKNOWN_OPTION +- {"UNKNOWN_OPTION", ERR_LIB_X509V3, X509V3_R_UNKNOWN_OPTION}, +- #else +- {"UNKNOWN_OPTION", 34, 120}, +- #endif +- #ifdef X509V3_R_UNSUPPORTED_OPTION +- {"UNSUPPORTED_OPTION", ERR_LIB_X509V3, X509V3_R_UNSUPPORTED_OPTION}, +- #else +- {"UNSUPPORTED_OPTION", 34, 117}, +- #endif +- #ifdef X509V3_R_UNSUPPORTED_TYPE +- {"UNSUPPORTED_TYPE", ERR_LIB_X509V3, X509V3_R_UNSUPPORTED_TYPE}, +- #else +- {"UNSUPPORTED_TYPE", 34, 167}, +- #endif +- #ifdef X509V3_R_USER_TOO_LONG +- {"USER_TOO_LONG", ERR_LIB_X509V3, X509V3_R_USER_TOO_LONG}, +- #else +- {"USER_TOO_LONG", 34, 132}, +- #endif +- #ifdef X509_R_AKID_MISMATCH +- {"AKID_MISMATCH", ERR_LIB_X509, X509_R_AKID_MISMATCH}, +- #else +- {"AKID_MISMATCH", 11, 110}, +- #endif +- #ifdef X509_R_BAD_SELECTOR +- {"BAD_SELECTOR", ERR_LIB_X509, X509_R_BAD_SELECTOR}, +- #else +- {"BAD_SELECTOR", 11, 133}, +- #endif +- #ifdef X509_R_BAD_X509_FILETYPE +- {"BAD_X509_FILETYPE", ERR_LIB_X509, X509_R_BAD_X509_FILETYPE}, +- #else +- {"BAD_X509_FILETYPE", 11, 100}, +- #endif +- #ifdef X509_R_BASE64_DECODE_ERROR +- {"BASE64_DECODE_ERROR", ERR_LIB_X509, X509_R_BASE64_DECODE_ERROR}, +- #else +- {"BASE64_DECODE_ERROR", 11, 118}, +- #endif +- #ifdef X509_R_CANT_CHECK_DH_KEY +- {"CANT_CHECK_DH_KEY", ERR_LIB_X509, X509_R_CANT_CHECK_DH_KEY}, +- #else +- {"CANT_CHECK_DH_KEY", 11, 114}, +- #endif +- #ifdef X509_R_CERTIFICATE_VERIFICATION_FAILED +- {"CERTIFICATE_VERIFICATION_FAILED", ERR_LIB_X509, X509_R_CERTIFICATE_VERIFICATION_FAILED}, +- #else +- {"CERTIFICATE_VERIFICATION_FAILED", 11, 139}, +- #endif +- #ifdef X509_R_CERT_ALREADY_IN_HASH_TABLE +- {"CERT_ALREADY_IN_HASH_TABLE", ERR_LIB_X509, X509_R_CERT_ALREADY_IN_HASH_TABLE}, +- #else +- {"CERT_ALREADY_IN_HASH_TABLE", 11, 101}, +- #endif +- #ifdef X509_R_CRL_ALREADY_DELTA +- {"CRL_ALREADY_DELTA", ERR_LIB_X509, X509_R_CRL_ALREADY_DELTA}, +- #else +- {"CRL_ALREADY_DELTA", 11, 127}, +- #endif +- #ifdef X509_R_CRL_VERIFY_FAILURE +- {"CRL_VERIFY_FAILURE", ERR_LIB_X509, X509_R_CRL_VERIFY_FAILURE}, +- #else +- {"CRL_VERIFY_FAILURE", 11, 131}, +- #endif +- #ifdef X509_R_ERROR_GETTING_MD_BY_NID +- {"ERROR_GETTING_MD_BY_NID", ERR_LIB_X509, X509_R_ERROR_GETTING_MD_BY_NID}, +- #else +- {"ERROR_GETTING_MD_BY_NID", 11, 141}, +- #endif +- #ifdef X509_R_ERROR_USING_SIGINF_SET +- {"ERROR_USING_SIGINF_SET", ERR_LIB_X509, X509_R_ERROR_USING_SIGINF_SET}, +- #else +- {"ERROR_USING_SIGINF_SET", 11, 142}, +- #endif +- #ifdef X509_R_IDP_MISMATCH +- {"IDP_MISMATCH", ERR_LIB_X509, X509_R_IDP_MISMATCH}, +- #else +- {"IDP_MISMATCH", 11, 128}, +- #endif +- #ifdef X509_R_INVALID_ATTRIBUTES +- {"INVALID_ATTRIBUTES", ERR_LIB_X509, X509_R_INVALID_ATTRIBUTES}, +- #else +- {"INVALID_ATTRIBUTES", 11, 138}, +- #endif +- #ifdef X509_R_INVALID_DIRECTORY +- {"INVALID_DIRECTORY", ERR_LIB_X509, X509_R_INVALID_DIRECTORY}, +- #else +- {"INVALID_DIRECTORY", 11, 113}, +- #endif +- #ifdef X509_R_INVALID_DISTPOINT +- {"INVALID_DISTPOINT", ERR_LIB_X509, X509_R_INVALID_DISTPOINT}, +- #else +- {"INVALID_DISTPOINT", 11, 143}, +- #endif +- #ifdef X509_R_INVALID_FIELD_NAME +- {"INVALID_FIELD_NAME", ERR_LIB_X509, X509_R_INVALID_FIELD_NAME}, +- #else +- {"INVALID_FIELD_NAME", 11, 119}, +- #endif +- #ifdef X509_R_INVALID_TRUST +- {"INVALID_TRUST", ERR_LIB_X509, X509_R_INVALID_TRUST}, +- #else +- {"INVALID_TRUST", 11, 123}, +- #endif +- #ifdef X509_R_ISSUER_MISMATCH +- {"ISSUER_MISMATCH", ERR_LIB_X509, X509_R_ISSUER_MISMATCH}, +- #else +- {"ISSUER_MISMATCH", 11, 129}, +- #endif +- #ifdef X509_R_KEY_TYPE_MISMATCH +- {"KEY_TYPE_MISMATCH", ERR_LIB_X509, X509_R_KEY_TYPE_MISMATCH}, +- #else +- {"KEY_TYPE_MISMATCH", 11, 115}, +- #endif +- #ifdef X509_R_KEY_VALUES_MISMATCH +- {"KEY_VALUES_MISMATCH", ERR_LIB_X509, X509_R_KEY_VALUES_MISMATCH}, +- #else +- {"KEY_VALUES_MISMATCH", 11, 116}, +- #endif +- #ifdef X509_R_LOADING_CERT_DIR +- {"LOADING_CERT_DIR", ERR_LIB_X509, X509_R_LOADING_CERT_DIR}, +- #else +- {"LOADING_CERT_DIR", 11, 103}, +- #endif +- #ifdef X509_R_LOADING_DEFAULTS +- {"LOADING_DEFAULTS", ERR_LIB_X509, X509_R_LOADING_DEFAULTS}, +- #else +- {"LOADING_DEFAULTS", 11, 104}, +- #endif +- #ifdef X509_R_METHOD_NOT_SUPPORTED +- {"METHOD_NOT_SUPPORTED", ERR_LIB_X509, X509_R_METHOD_NOT_SUPPORTED}, +- #else +- {"METHOD_NOT_SUPPORTED", 11, 124}, +- #endif +- #ifdef X509_R_NAME_TOO_LONG +- {"NAME_TOO_LONG", ERR_LIB_X509, X509_R_NAME_TOO_LONG}, +- #else +- {"NAME_TOO_LONG", 11, 134}, +- #endif +- #ifdef X509_R_NEWER_CRL_NOT_NEWER +- {"NEWER_CRL_NOT_NEWER", ERR_LIB_X509, X509_R_NEWER_CRL_NOT_NEWER}, +- #else +- {"NEWER_CRL_NOT_NEWER", 11, 132}, +- #endif +- #ifdef X509_R_NO_CERTIFICATE_FOUND +- {"NO_CERTIFICATE_FOUND", ERR_LIB_X509, X509_R_NO_CERTIFICATE_FOUND}, +- #else +- {"NO_CERTIFICATE_FOUND", 11, 135}, +- #endif +- #ifdef X509_R_NO_CERTIFICATE_OR_CRL_FOUND +- {"NO_CERTIFICATE_OR_CRL_FOUND", ERR_LIB_X509, X509_R_NO_CERTIFICATE_OR_CRL_FOUND}, +- #else +- {"NO_CERTIFICATE_OR_CRL_FOUND", 11, 136}, +- #endif +- #ifdef X509_R_NO_CERT_SET_FOR_US_TO_VERIFY +- {"NO_CERT_SET_FOR_US_TO_VERIFY", ERR_LIB_X509, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY}, +- #else +- {"NO_CERT_SET_FOR_US_TO_VERIFY", 11, 105}, +- #endif +- #ifdef X509_R_NO_CRL_FOUND +- {"NO_CRL_FOUND", ERR_LIB_X509, X509_R_NO_CRL_FOUND}, +- #else +- {"NO_CRL_FOUND", 11, 137}, +- #endif +- #ifdef X509_R_NO_CRL_NUMBER +- {"NO_CRL_NUMBER", ERR_LIB_X509, X509_R_NO_CRL_NUMBER}, +- #else +- {"NO_CRL_NUMBER", 11, 130}, +- #endif +- #ifdef X509_R_PUBLIC_KEY_DECODE_ERROR +- {"PUBLIC_KEY_DECODE_ERROR", ERR_LIB_X509, X509_R_PUBLIC_KEY_DECODE_ERROR}, +- #else +- {"PUBLIC_KEY_DECODE_ERROR", 11, 125}, +- #endif +- #ifdef X509_R_PUBLIC_KEY_ENCODE_ERROR +- {"PUBLIC_KEY_ENCODE_ERROR", ERR_LIB_X509, X509_R_PUBLIC_KEY_ENCODE_ERROR}, +- #else +- {"PUBLIC_KEY_ENCODE_ERROR", 11, 126}, +- #endif +- #ifdef X509_R_SHOULD_RETRY +- {"SHOULD_RETRY", ERR_LIB_X509, X509_R_SHOULD_RETRY}, +- #else +- {"SHOULD_RETRY", 11, 106}, +- #endif +- #ifdef X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN +- {"UNABLE_TO_FIND_PARAMETERS_IN_CHAIN", ERR_LIB_X509, X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN}, +- #else +- {"UNABLE_TO_FIND_PARAMETERS_IN_CHAIN", 11, 107}, +- #endif +- #ifdef X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY +- {"UNABLE_TO_GET_CERTS_PUBLIC_KEY", ERR_LIB_X509, X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY}, +- #else +- {"UNABLE_TO_GET_CERTS_PUBLIC_KEY", 11, 108}, +- #endif +- #ifdef X509_R_UNKNOWN_KEY_TYPE +- {"UNKNOWN_KEY_TYPE", ERR_LIB_X509, X509_R_UNKNOWN_KEY_TYPE}, +- #else +- {"UNKNOWN_KEY_TYPE", 11, 117}, +- #endif +- #ifdef X509_R_UNKNOWN_NID +- {"UNKNOWN_NID", ERR_LIB_X509, X509_R_UNKNOWN_NID}, +- #else +- {"UNKNOWN_NID", 11, 109}, +- #endif +- #ifdef X509_R_UNKNOWN_PURPOSE_ID +- {"UNKNOWN_PURPOSE_ID", ERR_LIB_X509, X509_R_UNKNOWN_PURPOSE_ID}, +- #else +- {"UNKNOWN_PURPOSE_ID", 11, 121}, +- #endif +- #ifdef X509_R_UNKNOWN_SIGID_ALGS +- {"UNKNOWN_SIGID_ALGS", ERR_LIB_X509, X509_R_UNKNOWN_SIGID_ALGS}, +- #else +- {"UNKNOWN_SIGID_ALGS", 11, 144}, +- #endif +- #ifdef X509_R_UNKNOWN_TRUST_ID +- {"UNKNOWN_TRUST_ID", ERR_LIB_X509, X509_R_UNKNOWN_TRUST_ID}, +- #else +- {"UNKNOWN_TRUST_ID", 11, 120}, +- #endif +- #ifdef X509_R_UNSUPPORTED_ALGORITHM +- {"UNSUPPORTED_ALGORITHM", ERR_LIB_X509, X509_R_UNSUPPORTED_ALGORITHM}, +- #else +- {"UNSUPPORTED_ALGORITHM", 11, 111}, +- #endif +- #ifdef X509_R_WRONG_LOOKUP_TYPE +- {"WRONG_LOOKUP_TYPE", ERR_LIB_X509, X509_R_WRONG_LOOKUP_TYPE}, +- #else +- {"WRONG_LOOKUP_TYPE", 11, 112}, +- #endif +- #ifdef X509_R_WRONG_TYPE +- {"WRONG_TYPE", ERR_LIB_X509, X509_R_WRONG_TYPE}, +- #else +- {"WRONG_TYPE", 11, 122}, +- #endif +- { NULL } +-}; +- +--- /dev/null ++++ b/Modules/_ssl_data_34.h +@@ -0,0 +1,9277 @@ ++/* File generated by Tools/ssl/make_ssl_data.py */ ++/* Generated on 2024-11-27T12:35:52.276767+00:00 */ ++/* Generated from Git commit openssl-3.4.0-0-g98acb6b028 */ ++static struct py_ssl_library_code library_codes[] = { ++#ifdef ERR_LIB_ASN1 ++ {"ASN1", ERR_LIB_ASN1}, ++#endif ++#ifdef ERR_LIB_ASYNC ++ {"ASYNC", ERR_LIB_ASYNC}, ++#endif ++#ifdef ERR_LIB_BIO ++ {"BIO", ERR_LIB_BIO}, ++#endif ++#ifdef ERR_LIB_BN ++ {"BN", ERR_LIB_BN}, ++#endif ++#ifdef ERR_LIB_BUF ++ {"BUF", ERR_LIB_BUF}, ++#endif ++#ifdef ERR_LIB_CMP ++ {"CMP", ERR_LIB_CMP}, ++#endif ++#ifdef ERR_LIB_CMS ++ {"CMS", ERR_LIB_CMS}, ++#endif ++#ifdef ERR_LIB_COMP ++ {"COMP", ERR_LIB_COMP}, ++#endif ++#ifdef ERR_LIB_CONF ++ {"CONF", ERR_LIB_CONF}, ++#endif ++#ifdef ERR_LIB_CRMF ++ {"CRMF", ERR_LIB_CRMF}, ++#endif ++#ifdef ERR_LIB_CRYPTO ++ {"CRYPTO", ERR_LIB_CRYPTO}, ++#endif ++#ifdef ERR_LIB_CT ++ {"CT", ERR_LIB_CT}, ++#endif ++#ifdef ERR_LIB_DH ++ {"DH", ERR_LIB_DH}, ++#endif ++#ifdef ERR_LIB_DSA ++ {"DSA", ERR_LIB_DSA}, ++#endif ++#ifdef ERR_LIB_DSO ++ {"DSO", ERR_LIB_DSO}, ++#endif ++#ifdef ERR_LIB_EC ++ {"EC", ERR_LIB_EC}, ++#endif ++#ifdef ERR_LIB_ECDH ++ {"ECDH", ERR_LIB_ECDH}, ++#endif ++#ifdef ERR_LIB_ECDSA ++ {"ECDSA", ERR_LIB_ECDSA}, ++#endif ++#ifdef ERR_LIB_ENGINE ++ {"ENGINE", ERR_LIB_ENGINE}, ++#endif ++#ifdef ERR_LIB_ESS ++ {"ESS", ERR_LIB_ESS}, ++#endif ++#ifdef ERR_LIB_EVP ++ {"EVP", ERR_LIB_EVP}, ++#endif ++#ifdef ERR_LIB_FIPS ++ {"FIPS", ERR_LIB_FIPS}, ++#endif ++#ifdef ERR_LIB_HMAC ++ {"HMAC", ERR_LIB_HMAC}, ++#endif ++#ifdef ERR_LIB_HTTP ++ {"HTTP", ERR_LIB_HTTP}, ++#endif ++#ifdef ERR_LIB_JPAKE ++ {"JPAKE", ERR_LIB_JPAKE}, ++#endif ++#ifdef ERR_LIB_KDF ++ {"KDF", ERR_LIB_KDF}, ++#endif ++#ifdef ERR_LIB_MASK ++ {"MASK", ERR_LIB_MASK}, ++#endif ++#ifdef ERR_LIB_METH ++ {"METH", ERR_LIB_METH}, ++#endif ++#ifdef ERR_LIB_NONE ++ {"NONE", ERR_LIB_NONE}, ++#endif ++#ifdef ERR_LIB_OBJ ++ {"OBJ", ERR_LIB_OBJ}, ++#endif ++#ifdef ERR_LIB_OCSP ++ {"OCSP", ERR_LIB_OCSP}, ++#endif ++#ifdef ERR_LIB_OFFSET ++ {"OFFSET", ERR_LIB_OFFSET}, ++#endif ++#ifdef ERR_LIB_OSSL_DECODER ++ {"OSSL_DECODER", ERR_LIB_OSSL_DECODER}, ++#endif ++#ifdef ERR_LIB_OSSL_ENCODER ++ {"OSSL_ENCODER", ERR_LIB_OSSL_ENCODER}, ++#endif ++#ifdef ERR_LIB_OSSL_STORE ++ {"OSSL_STORE", ERR_LIB_OSSL_STORE}, ++#endif ++#ifdef ERR_LIB_PEM ++ {"PEM", ERR_LIB_PEM}, ++#endif ++#ifdef ERR_LIB_PKCS12 ++ {"PKCS12", ERR_LIB_PKCS12}, ++#endif ++#ifdef ERR_LIB_PKCS7 ++ {"PKCS7", ERR_LIB_PKCS7}, ++#endif ++#ifdef ERR_LIB_PROP ++ {"PROP", ERR_LIB_PROP}, ++#endif ++#ifdef ERR_LIB_PROV ++ {"PROV", ERR_LIB_PROV}, ++#endif ++#ifdef ERR_LIB_PROXY ++ {"PROXY", ERR_LIB_PROXY}, ++#endif ++#ifdef ERR_LIB_RAND ++ {"RAND", ERR_LIB_RAND}, ++#endif ++#ifdef ERR_LIB_RSA ++ {"RSA", ERR_LIB_RSA}, ++#endif ++#ifdef ERR_LIB_RSAREF ++ {"RSAREF", ERR_LIB_RSAREF}, ++#endif ++#ifdef ERR_LIB_SM2 ++ {"SM2", ERR_LIB_SM2}, ++#endif ++#ifdef ERR_LIB_SSL ++ {"SSL", ERR_LIB_SSL}, ++#endif ++#ifdef ERR_LIB_SSL2 ++ {"SSL2", ERR_LIB_SSL2}, ++#endif ++#ifdef ERR_LIB_SSL23 ++ {"SSL23", ERR_LIB_SSL23}, ++#endif ++#ifdef ERR_LIB_SSL3 ++ {"SSL3", ERR_LIB_SSL3}, ++#endif ++#ifdef ERR_LIB_SYS ++ {"SYS", ERR_LIB_SYS}, ++#endif ++#ifdef ERR_LIB_TS ++ {"TS", ERR_LIB_TS}, ++#endif ++#ifdef ERR_LIB_UI ++ {"UI", ERR_LIB_UI}, ++#endif ++#ifdef ERR_LIB_USER ++ {"USER", ERR_LIB_USER}, ++#endif ++#ifdef ERR_LIB_X509 ++ {"X509", ERR_LIB_X509}, ++#endif ++#ifdef ERR_LIB_X509V3 ++ {"X509V3", ERR_LIB_X509V3}, ++#endif ++ { NULL } ++}; ++ ++ ++static struct py_ssl_error_code error_codes[] = { ++ #ifdef ASN1_R_ADDING_OBJECT ++ {"ADDING_OBJECT", ERR_LIB_ASN1, ASN1_R_ADDING_OBJECT}, ++ #else ++ {"ADDING_OBJECT", 13, 171}, ++ #endif ++ #ifdef ASN1_R_ASN1_PARSE_ERROR ++ {"ASN1_PARSE_ERROR", ERR_LIB_ASN1, ASN1_R_ASN1_PARSE_ERROR}, ++ #else ++ {"ASN1_PARSE_ERROR", 13, 203}, ++ #endif ++ #ifdef ASN1_R_ASN1_SIG_PARSE_ERROR ++ {"ASN1_SIG_PARSE_ERROR", ERR_LIB_ASN1, ASN1_R_ASN1_SIG_PARSE_ERROR}, ++ #else ++ {"ASN1_SIG_PARSE_ERROR", 13, 204}, ++ #endif ++ #ifdef ASN1_R_AUX_ERROR ++ {"AUX_ERROR", ERR_LIB_ASN1, ASN1_R_AUX_ERROR}, ++ #else ++ {"AUX_ERROR", 13, 100}, ++ #endif ++ #ifdef ASN1_R_BAD_OBJECT_HEADER ++ {"BAD_OBJECT_HEADER", ERR_LIB_ASN1, ASN1_R_BAD_OBJECT_HEADER}, ++ #else ++ {"BAD_OBJECT_HEADER", 13, 102}, ++ #endif ++ #ifdef ASN1_R_BAD_TEMPLATE ++ {"BAD_TEMPLATE", ERR_LIB_ASN1, ASN1_R_BAD_TEMPLATE}, ++ #else ++ {"BAD_TEMPLATE", 13, 230}, ++ #endif ++ #ifdef ASN1_R_BMPSTRING_IS_WRONG_LENGTH ++ {"BMPSTRING_IS_WRONG_LENGTH", ERR_LIB_ASN1, ASN1_R_BMPSTRING_IS_WRONG_LENGTH}, ++ #else ++ {"BMPSTRING_IS_WRONG_LENGTH", 13, 214}, ++ #endif ++ #ifdef ASN1_R_BN_LIB ++ {"BN_LIB", ERR_LIB_ASN1, ASN1_R_BN_LIB}, ++ #else ++ {"BN_LIB", 13, 105}, ++ #endif ++ #ifdef ASN1_R_BOOLEAN_IS_WRONG_LENGTH ++ {"BOOLEAN_IS_WRONG_LENGTH", ERR_LIB_ASN1, ASN1_R_BOOLEAN_IS_WRONG_LENGTH}, ++ #else ++ {"BOOLEAN_IS_WRONG_LENGTH", 13, 106}, ++ #endif ++ #ifdef ASN1_R_BUFFER_TOO_SMALL ++ {"BUFFER_TOO_SMALL", ERR_LIB_ASN1, ASN1_R_BUFFER_TOO_SMALL}, ++ #else ++ {"BUFFER_TOO_SMALL", 13, 107}, ++ #endif ++ #ifdef ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER ++ {"CIPHER_HAS_NO_OBJECT_IDENTIFIER", ERR_LIB_ASN1, ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER}, ++ #else ++ {"CIPHER_HAS_NO_OBJECT_IDENTIFIER", 13, 108}, ++ #endif ++ #ifdef ASN1_R_CONTEXT_NOT_INITIALISED ++ {"CONTEXT_NOT_INITIALISED", ERR_LIB_ASN1, ASN1_R_CONTEXT_NOT_INITIALISED}, ++ #else ++ {"CONTEXT_NOT_INITIALISED", 13, 217}, ++ #endif ++ #ifdef ASN1_R_DATA_IS_WRONG ++ {"DATA_IS_WRONG", ERR_LIB_ASN1, ASN1_R_DATA_IS_WRONG}, ++ #else ++ {"DATA_IS_WRONG", 13, 109}, ++ #endif ++ #ifdef ASN1_R_DECODE_ERROR ++ {"DECODE_ERROR", ERR_LIB_ASN1, ASN1_R_DECODE_ERROR}, ++ #else ++ {"DECODE_ERROR", 13, 110}, ++ #endif ++ #ifdef ASN1_R_DEPTH_EXCEEDED ++ {"DEPTH_EXCEEDED", ERR_LIB_ASN1, ASN1_R_DEPTH_EXCEEDED}, ++ #else ++ {"DEPTH_EXCEEDED", 13, 174}, ++ #endif ++ #ifdef ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED ++ {"DIGEST_AND_KEY_TYPE_NOT_SUPPORTED", ERR_LIB_ASN1, ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED}, ++ #else ++ {"DIGEST_AND_KEY_TYPE_NOT_SUPPORTED", 13, 198}, ++ #endif ++ #ifdef ASN1_R_ENCODE_ERROR ++ {"ENCODE_ERROR", ERR_LIB_ASN1, ASN1_R_ENCODE_ERROR}, ++ #else ++ {"ENCODE_ERROR", 13, 112}, ++ #endif ++ #ifdef ASN1_R_ERROR_GETTING_TIME ++ {"ERROR_GETTING_TIME", ERR_LIB_ASN1, ASN1_R_ERROR_GETTING_TIME}, ++ #else ++ {"ERROR_GETTING_TIME", 13, 173}, ++ #endif ++ #ifdef ASN1_R_ERROR_LOADING_SECTION ++ {"ERROR_LOADING_SECTION", ERR_LIB_ASN1, ASN1_R_ERROR_LOADING_SECTION}, ++ #else ++ {"ERROR_LOADING_SECTION", 13, 172}, ++ #endif ++ #ifdef ASN1_R_ERROR_SETTING_CIPHER_PARAMS ++ {"ERROR_SETTING_CIPHER_PARAMS", ERR_LIB_ASN1, ASN1_R_ERROR_SETTING_CIPHER_PARAMS}, ++ #else ++ {"ERROR_SETTING_CIPHER_PARAMS", 13, 114}, ++ #endif ++ #ifdef ASN1_R_EXPECTING_AN_INTEGER ++ {"EXPECTING_AN_INTEGER", ERR_LIB_ASN1, ASN1_R_EXPECTING_AN_INTEGER}, ++ #else ++ {"EXPECTING_AN_INTEGER", 13, 115}, ++ #endif ++ #ifdef ASN1_R_EXPECTING_AN_OBJECT ++ {"EXPECTING_AN_OBJECT", ERR_LIB_ASN1, ASN1_R_EXPECTING_AN_OBJECT}, ++ #else ++ {"EXPECTING_AN_OBJECT", 13, 116}, ++ #endif ++ #ifdef ASN1_R_EXPLICIT_LENGTH_MISMATCH ++ {"EXPLICIT_LENGTH_MISMATCH", ERR_LIB_ASN1, ASN1_R_EXPLICIT_LENGTH_MISMATCH}, ++ #else ++ {"EXPLICIT_LENGTH_MISMATCH", 13, 119}, ++ #endif ++ #ifdef ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED ++ {"EXPLICIT_TAG_NOT_CONSTRUCTED", ERR_LIB_ASN1, ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED}, ++ #else ++ {"EXPLICIT_TAG_NOT_CONSTRUCTED", 13, 120}, ++ #endif ++ #ifdef ASN1_R_FIELD_MISSING ++ {"FIELD_MISSING", ERR_LIB_ASN1, ASN1_R_FIELD_MISSING}, ++ #else ++ {"FIELD_MISSING", 13, 121}, ++ #endif ++ #ifdef ASN1_R_FIRST_NUM_TOO_LARGE ++ {"FIRST_NUM_TOO_LARGE", ERR_LIB_ASN1, ASN1_R_FIRST_NUM_TOO_LARGE}, ++ #else ++ {"FIRST_NUM_TOO_LARGE", 13, 122}, ++ #endif ++ #ifdef ASN1_R_GENERALIZEDTIME_IS_TOO_SHORT ++ {"GENERALIZEDTIME_IS_TOO_SHORT", ERR_LIB_ASN1, ASN1_R_GENERALIZEDTIME_IS_TOO_SHORT}, ++ #else ++ {"GENERALIZEDTIME_IS_TOO_SHORT", 13, 232}, ++ #endif ++ #ifdef ASN1_R_HEADER_TOO_LONG ++ {"HEADER_TOO_LONG", ERR_LIB_ASN1, ASN1_R_HEADER_TOO_LONG}, ++ #else ++ {"HEADER_TOO_LONG", 13, 123}, ++ #endif ++ #ifdef ASN1_R_ILLEGAL_BITSTRING_FORMAT ++ {"ILLEGAL_BITSTRING_FORMAT", ERR_LIB_ASN1, ASN1_R_ILLEGAL_BITSTRING_FORMAT}, ++ #else ++ {"ILLEGAL_BITSTRING_FORMAT", 13, 175}, ++ #endif ++ #ifdef ASN1_R_ILLEGAL_BOOLEAN ++ {"ILLEGAL_BOOLEAN", ERR_LIB_ASN1, ASN1_R_ILLEGAL_BOOLEAN}, ++ #else ++ {"ILLEGAL_BOOLEAN", 13, 176}, ++ #endif ++ #ifdef ASN1_R_ILLEGAL_CHARACTERS ++ {"ILLEGAL_CHARACTERS", ERR_LIB_ASN1, ASN1_R_ILLEGAL_CHARACTERS}, ++ #else ++ {"ILLEGAL_CHARACTERS", 13, 124}, ++ #endif ++ #ifdef ASN1_R_ILLEGAL_FORMAT ++ {"ILLEGAL_FORMAT", ERR_LIB_ASN1, ASN1_R_ILLEGAL_FORMAT}, ++ #else ++ {"ILLEGAL_FORMAT", 13, 177}, ++ #endif ++ #ifdef ASN1_R_ILLEGAL_HEX ++ {"ILLEGAL_HEX", ERR_LIB_ASN1, ASN1_R_ILLEGAL_HEX}, ++ #else ++ {"ILLEGAL_HEX", 13, 178}, ++ #endif ++ #ifdef ASN1_R_ILLEGAL_IMPLICIT_TAG ++ {"ILLEGAL_IMPLICIT_TAG", ERR_LIB_ASN1, ASN1_R_ILLEGAL_IMPLICIT_TAG}, ++ #else ++ {"ILLEGAL_IMPLICIT_TAG", 13, 179}, ++ #endif ++ #ifdef ASN1_R_ILLEGAL_INTEGER ++ {"ILLEGAL_INTEGER", ERR_LIB_ASN1, ASN1_R_ILLEGAL_INTEGER}, ++ #else ++ {"ILLEGAL_INTEGER", 13, 180}, ++ #endif ++ #ifdef ASN1_R_ILLEGAL_NEGATIVE_VALUE ++ {"ILLEGAL_NEGATIVE_VALUE", ERR_LIB_ASN1, ASN1_R_ILLEGAL_NEGATIVE_VALUE}, ++ #else ++ {"ILLEGAL_NEGATIVE_VALUE", 13, 226}, ++ #endif ++ #ifdef ASN1_R_ILLEGAL_NESTED_TAGGING ++ {"ILLEGAL_NESTED_TAGGING", ERR_LIB_ASN1, ASN1_R_ILLEGAL_NESTED_TAGGING}, ++ #else ++ {"ILLEGAL_NESTED_TAGGING", 13, 181}, ++ #endif ++ #ifdef ASN1_R_ILLEGAL_NULL ++ {"ILLEGAL_NULL", ERR_LIB_ASN1, ASN1_R_ILLEGAL_NULL}, ++ #else ++ {"ILLEGAL_NULL", 13, 125}, ++ #endif ++ #ifdef ASN1_R_ILLEGAL_NULL_VALUE ++ {"ILLEGAL_NULL_VALUE", ERR_LIB_ASN1, ASN1_R_ILLEGAL_NULL_VALUE}, ++ #else ++ {"ILLEGAL_NULL_VALUE", 13, 182}, ++ #endif ++ #ifdef ASN1_R_ILLEGAL_OBJECT ++ {"ILLEGAL_OBJECT", ERR_LIB_ASN1, ASN1_R_ILLEGAL_OBJECT}, ++ #else ++ {"ILLEGAL_OBJECT", 13, 183}, ++ #endif ++ #ifdef ASN1_R_ILLEGAL_OPTIONAL_ANY ++ {"ILLEGAL_OPTIONAL_ANY", ERR_LIB_ASN1, ASN1_R_ILLEGAL_OPTIONAL_ANY}, ++ #else ++ {"ILLEGAL_OPTIONAL_ANY", 13, 126}, ++ #endif ++ #ifdef ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE ++ {"ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE", ERR_LIB_ASN1, ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE}, ++ #else ++ {"ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE", 13, 170}, ++ #endif ++ #ifdef ASN1_R_ILLEGAL_PADDING ++ {"ILLEGAL_PADDING", ERR_LIB_ASN1, ASN1_R_ILLEGAL_PADDING}, ++ #else ++ {"ILLEGAL_PADDING", 13, 221}, ++ #endif ++ #ifdef ASN1_R_ILLEGAL_TAGGED_ANY ++ {"ILLEGAL_TAGGED_ANY", ERR_LIB_ASN1, ASN1_R_ILLEGAL_TAGGED_ANY}, ++ #else ++ {"ILLEGAL_TAGGED_ANY", 13, 127}, ++ #endif ++ #ifdef ASN1_R_ILLEGAL_TIME_VALUE ++ {"ILLEGAL_TIME_VALUE", ERR_LIB_ASN1, ASN1_R_ILLEGAL_TIME_VALUE}, ++ #else ++ {"ILLEGAL_TIME_VALUE", 13, 184}, ++ #endif ++ #ifdef ASN1_R_ILLEGAL_ZERO_CONTENT ++ {"ILLEGAL_ZERO_CONTENT", ERR_LIB_ASN1, ASN1_R_ILLEGAL_ZERO_CONTENT}, ++ #else ++ {"ILLEGAL_ZERO_CONTENT", 13, 222}, ++ #endif ++ #ifdef ASN1_R_INTEGER_NOT_ASCII_FORMAT ++ {"INTEGER_NOT_ASCII_FORMAT", ERR_LIB_ASN1, ASN1_R_INTEGER_NOT_ASCII_FORMAT}, ++ #else ++ {"INTEGER_NOT_ASCII_FORMAT", 13, 185}, ++ #endif ++ #ifdef ASN1_R_INTEGER_TOO_LARGE_FOR_LONG ++ {"INTEGER_TOO_LARGE_FOR_LONG", ERR_LIB_ASN1, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG}, ++ #else ++ {"INTEGER_TOO_LARGE_FOR_LONG", 13, 128}, ++ #endif ++ #ifdef ASN1_R_INVALID_BIT_STRING_BITS_LEFT ++ {"INVALID_BIT_STRING_BITS_LEFT", ERR_LIB_ASN1, ASN1_R_INVALID_BIT_STRING_BITS_LEFT}, ++ #else ++ {"INVALID_BIT_STRING_BITS_LEFT", 13, 220}, ++ #endif ++ #ifdef ASN1_R_INVALID_BMPSTRING_LENGTH ++ {"INVALID_BMPSTRING_LENGTH", ERR_LIB_ASN1, ASN1_R_INVALID_BMPSTRING_LENGTH}, ++ #else ++ {"INVALID_BMPSTRING_LENGTH", 13, 129}, ++ #endif ++ #ifdef ASN1_R_INVALID_DIGIT ++ {"INVALID_DIGIT", ERR_LIB_ASN1, ASN1_R_INVALID_DIGIT}, ++ #else ++ {"INVALID_DIGIT", 13, 130}, ++ #endif ++ #ifdef ASN1_R_INVALID_MIME_TYPE ++ {"INVALID_MIME_TYPE", ERR_LIB_ASN1, ASN1_R_INVALID_MIME_TYPE}, ++ #else ++ {"INVALID_MIME_TYPE", 13, 205}, ++ #endif ++ #ifdef ASN1_R_INVALID_MODIFIER ++ {"INVALID_MODIFIER", ERR_LIB_ASN1, ASN1_R_INVALID_MODIFIER}, ++ #else ++ {"INVALID_MODIFIER", 13, 186}, ++ #endif ++ #ifdef ASN1_R_INVALID_NUMBER ++ {"INVALID_NUMBER", ERR_LIB_ASN1, ASN1_R_INVALID_NUMBER}, ++ #else ++ {"INVALID_NUMBER", 13, 187}, ++ #endif ++ #ifdef ASN1_R_INVALID_OBJECT_ENCODING ++ {"INVALID_OBJECT_ENCODING", ERR_LIB_ASN1, ASN1_R_INVALID_OBJECT_ENCODING}, ++ #else ++ {"INVALID_OBJECT_ENCODING", 13, 216}, ++ #endif ++ #ifdef ASN1_R_INVALID_SCRYPT_PARAMETERS ++ {"INVALID_SCRYPT_PARAMETERS", ERR_LIB_ASN1, ASN1_R_INVALID_SCRYPT_PARAMETERS}, ++ #else ++ {"INVALID_SCRYPT_PARAMETERS", 13, 227}, ++ #endif ++ #ifdef ASN1_R_INVALID_SEPARATOR ++ {"INVALID_SEPARATOR", ERR_LIB_ASN1, ASN1_R_INVALID_SEPARATOR}, ++ #else ++ {"INVALID_SEPARATOR", 13, 131}, ++ #endif ++ #ifdef ASN1_R_INVALID_STRING_TABLE_VALUE ++ {"INVALID_STRING_TABLE_VALUE", ERR_LIB_ASN1, ASN1_R_INVALID_STRING_TABLE_VALUE}, ++ #else ++ {"INVALID_STRING_TABLE_VALUE", 13, 218}, ++ #endif ++ #ifdef ASN1_R_INVALID_UNIVERSALSTRING_LENGTH ++ {"INVALID_UNIVERSALSTRING_LENGTH", ERR_LIB_ASN1, ASN1_R_INVALID_UNIVERSALSTRING_LENGTH}, ++ #else ++ {"INVALID_UNIVERSALSTRING_LENGTH", 13, 133}, ++ #endif ++ #ifdef ASN1_R_INVALID_UTF8STRING ++ {"INVALID_UTF8STRING", ERR_LIB_ASN1, ASN1_R_INVALID_UTF8STRING}, ++ #else ++ {"INVALID_UTF8STRING", 13, 134}, ++ #endif ++ #ifdef ASN1_R_INVALID_VALUE ++ {"INVALID_VALUE", ERR_LIB_ASN1, ASN1_R_INVALID_VALUE}, ++ #else ++ {"INVALID_VALUE", 13, 219}, ++ #endif ++ #ifdef ASN1_R_LENGTH_TOO_LONG ++ {"LENGTH_TOO_LONG", ERR_LIB_ASN1, ASN1_R_LENGTH_TOO_LONG}, ++ #else ++ {"LENGTH_TOO_LONG", 13, 231}, ++ #endif ++ #ifdef ASN1_R_LIST_ERROR ++ {"LIST_ERROR", ERR_LIB_ASN1, ASN1_R_LIST_ERROR}, ++ #else ++ {"LIST_ERROR", 13, 188}, ++ #endif ++ #ifdef ASN1_R_MIME_NO_CONTENT_TYPE ++ {"MIME_NO_CONTENT_TYPE", ERR_LIB_ASN1, ASN1_R_MIME_NO_CONTENT_TYPE}, ++ #else ++ {"MIME_NO_CONTENT_TYPE", 13, 206}, ++ #endif ++ #ifdef ASN1_R_MIME_PARSE_ERROR ++ {"MIME_PARSE_ERROR", ERR_LIB_ASN1, ASN1_R_MIME_PARSE_ERROR}, ++ #else ++ {"MIME_PARSE_ERROR", 13, 207}, ++ #endif ++ #ifdef ASN1_R_MIME_SIG_PARSE_ERROR ++ {"MIME_SIG_PARSE_ERROR", ERR_LIB_ASN1, ASN1_R_MIME_SIG_PARSE_ERROR}, ++ #else ++ {"MIME_SIG_PARSE_ERROR", 13, 208}, ++ #endif ++ #ifdef ASN1_R_MISSING_EOC ++ {"MISSING_EOC", ERR_LIB_ASN1, ASN1_R_MISSING_EOC}, ++ #else ++ {"MISSING_EOC", 13, 137}, ++ #endif ++ #ifdef ASN1_R_MISSING_SECOND_NUMBER ++ {"MISSING_SECOND_NUMBER", ERR_LIB_ASN1, ASN1_R_MISSING_SECOND_NUMBER}, ++ #else ++ {"MISSING_SECOND_NUMBER", 13, 138}, ++ #endif ++ #ifdef ASN1_R_MISSING_VALUE ++ {"MISSING_VALUE", ERR_LIB_ASN1, ASN1_R_MISSING_VALUE}, ++ #else ++ {"MISSING_VALUE", 13, 189}, ++ #endif ++ #ifdef ASN1_R_MSTRING_NOT_UNIVERSAL ++ {"MSTRING_NOT_UNIVERSAL", ERR_LIB_ASN1, ASN1_R_MSTRING_NOT_UNIVERSAL}, ++ #else ++ {"MSTRING_NOT_UNIVERSAL", 13, 139}, ++ #endif ++ #ifdef ASN1_R_MSTRING_WRONG_TAG ++ {"MSTRING_WRONG_TAG", ERR_LIB_ASN1, ASN1_R_MSTRING_WRONG_TAG}, ++ #else ++ {"MSTRING_WRONG_TAG", 13, 140}, ++ #endif ++ #ifdef ASN1_R_NESTED_ASN1_STRING ++ {"NESTED_ASN1_STRING", ERR_LIB_ASN1, ASN1_R_NESTED_ASN1_STRING}, ++ #else ++ {"NESTED_ASN1_STRING", 13, 197}, ++ #endif ++ #ifdef ASN1_R_NESTED_TOO_DEEP ++ {"NESTED_TOO_DEEP", ERR_LIB_ASN1, ASN1_R_NESTED_TOO_DEEP}, ++ #else ++ {"NESTED_TOO_DEEP", 13, 201}, ++ #endif ++ #ifdef ASN1_R_NON_HEX_CHARACTERS ++ {"NON_HEX_CHARACTERS", ERR_LIB_ASN1, ASN1_R_NON_HEX_CHARACTERS}, ++ #else ++ {"NON_HEX_CHARACTERS", 13, 141}, ++ #endif ++ #ifdef ASN1_R_NOT_ASCII_FORMAT ++ {"NOT_ASCII_FORMAT", ERR_LIB_ASN1, ASN1_R_NOT_ASCII_FORMAT}, ++ #else ++ {"NOT_ASCII_FORMAT", 13, 190}, ++ #endif ++ #ifdef ASN1_R_NOT_ENOUGH_DATA ++ {"NOT_ENOUGH_DATA", ERR_LIB_ASN1, ASN1_R_NOT_ENOUGH_DATA}, ++ #else ++ {"NOT_ENOUGH_DATA", 13, 142}, ++ #endif ++ #ifdef ASN1_R_NO_CONTENT_TYPE ++ {"NO_CONTENT_TYPE", ERR_LIB_ASN1, ASN1_R_NO_CONTENT_TYPE}, ++ #else ++ {"NO_CONTENT_TYPE", 13, 209}, ++ #endif ++ #ifdef ASN1_R_NO_MATCHING_CHOICE_TYPE ++ {"NO_MATCHING_CHOICE_TYPE", ERR_LIB_ASN1, ASN1_R_NO_MATCHING_CHOICE_TYPE}, ++ #else ++ {"NO_MATCHING_CHOICE_TYPE", 13, 143}, ++ #endif ++ #ifdef ASN1_R_NO_MULTIPART_BODY_FAILURE ++ {"NO_MULTIPART_BODY_FAILURE", ERR_LIB_ASN1, ASN1_R_NO_MULTIPART_BODY_FAILURE}, ++ #else ++ {"NO_MULTIPART_BODY_FAILURE", 13, 210}, ++ #endif ++ #ifdef ASN1_R_NO_MULTIPART_BOUNDARY ++ {"NO_MULTIPART_BOUNDARY", ERR_LIB_ASN1, ASN1_R_NO_MULTIPART_BOUNDARY}, ++ #else ++ {"NO_MULTIPART_BOUNDARY", 13, 211}, ++ #endif ++ #ifdef ASN1_R_NO_SIG_CONTENT_TYPE ++ {"NO_SIG_CONTENT_TYPE", ERR_LIB_ASN1, ASN1_R_NO_SIG_CONTENT_TYPE}, ++ #else ++ {"NO_SIG_CONTENT_TYPE", 13, 212}, ++ #endif ++ #ifdef ASN1_R_NULL_IS_WRONG_LENGTH ++ {"NULL_IS_WRONG_LENGTH", ERR_LIB_ASN1, ASN1_R_NULL_IS_WRONG_LENGTH}, ++ #else ++ {"NULL_IS_WRONG_LENGTH", 13, 144}, ++ #endif ++ #ifdef ASN1_R_OBJECT_NOT_ASCII_FORMAT ++ {"OBJECT_NOT_ASCII_FORMAT", ERR_LIB_ASN1, ASN1_R_OBJECT_NOT_ASCII_FORMAT}, ++ #else ++ {"OBJECT_NOT_ASCII_FORMAT", 13, 191}, ++ #endif ++ #ifdef ASN1_R_ODD_NUMBER_OF_CHARS ++ {"ODD_NUMBER_OF_CHARS", ERR_LIB_ASN1, ASN1_R_ODD_NUMBER_OF_CHARS}, ++ #else ++ {"ODD_NUMBER_OF_CHARS", 13, 145}, ++ #endif ++ #ifdef ASN1_R_SECOND_NUMBER_TOO_LARGE ++ {"SECOND_NUMBER_TOO_LARGE", ERR_LIB_ASN1, ASN1_R_SECOND_NUMBER_TOO_LARGE}, ++ #else ++ {"SECOND_NUMBER_TOO_LARGE", 13, 147}, ++ #endif ++ #ifdef ASN1_R_SEQUENCE_LENGTH_MISMATCH ++ {"SEQUENCE_LENGTH_MISMATCH", ERR_LIB_ASN1, ASN1_R_SEQUENCE_LENGTH_MISMATCH}, ++ #else ++ {"SEQUENCE_LENGTH_MISMATCH", 13, 148}, ++ #endif ++ #ifdef ASN1_R_SEQUENCE_NOT_CONSTRUCTED ++ {"SEQUENCE_NOT_CONSTRUCTED", ERR_LIB_ASN1, ASN1_R_SEQUENCE_NOT_CONSTRUCTED}, ++ #else ++ {"SEQUENCE_NOT_CONSTRUCTED", 13, 149}, ++ #endif ++ #ifdef ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG ++ {"SEQUENCE_OR_SET_NEEDS_CONFIG", ERR_LIB_ASN1, ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG}, ++ #else ++ {"SEQUENCE_OR_SET_NEEDS_CONFIG", 13, 192}, ++ #endif ++ #ifdef ASN1_R_SHORT_LINE ++ {"SHORT_LINE", ERR_LIB_ASN1, ASN1_R_SHORT_LINE}, ++ #else ++ {"SHORT_LINE", 13, 150}, ++ #endif ++ #ifdef ASN1_R_SIG_INVALID_MIME_TYPE ++ {"SIG_INVALID_MIME_TYPE", ERR_LIB_ASN1, ASN1_R_SIG_INVALID_MIME_TYPE}, ++ #else ++ {"SIG_INVALID_MIME_TYPE", 13, 213}, ++ #endif ++ #ifdef ASN1_R_STREAMING_NOT_SUPPORTED ++ {"STREAMING_NOT_SUPPORTED", ERR_LIB_ASN1, ASN1_R_STREAMING_NOT_SUPPORTED}, ++ #else ++ {"STREAMING_NOT_SUPPORTED", 13, 202}, ++ #endif ++ #ifdef ASN1_R_STRING_TOO_LONG ++ {"STRING_TOO_LONG", ERR_LIB_ASN1, ASN1_R_STRING_TOO_LONG}, ++ #else ++ {"STRING_TOO_LONG", 13, 151}, ++ #endif ++ #ifdef ASN1_R_STRING_TOO_SHORT ++ {"STRING_TOO_SHORT", ERR_LIB_ASN1, ASN1_R_STRING_TOO_SHORT}, ++ #else ++ {"STRING_TOO_SHORT", 13, 152}, ++ #endif ++ #ifdef ASN1_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD ++ {"THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD", ERR_LIB_ASN1, ASN1_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD}, ++ #else ++ {"THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD", 13, 154}, ++ #endif ++ #ifdef ASN1_R_TIME_NOT_ASCII_FORMAT ++ {"TIME_NOT_ASCII_FORMAT", ERR_LIB_ASN1, ASN1_R_TIME_NOT_ASCII_FORMAT}, ++ #else ++ {"TIME_NOT_ASCII_FORMAT", 13, 193}, ++ #endif ++ #ifdef ASN1_R_TOO_LARGE ++ {"TOO_LARGE", ERR_LIB_ASN1, ASN1_R_TOO_LARGE}, ++ #else ++ {"TOO_LARGE", 13, 223}, ++ #endif ++ #ifdef ASN1_R_TOO_LONG ++ {"TOO_LONG", ERR_LIB_ASN1, ASN1_R_TOO_LONG}, ++ #else ++ {"TOO_LONG", 13, 155}, ++ #endif ++ #ifdef ASN1_R_TOO_SMALL ++ {"TOO_SMALL", ERR_LIB_ASN1, ASN1_R_TOO_SMALL}, ++ #else ++ {"TOO_SMALL", 13, 224}, ++ #endif ++ #ifdef ASN1_R_TYPE_NOT_CONSTRUCTED ++ {"TYPE_NOT_CONSTRUCTED", ERR_LIB_ASN1, ASN1_R_TYPE_NOT_CONSTRUCTED}, ++ #else ++ {"TYPE_NOT_CONSTRUCTED", 13, 156}, ++ #endif ++ #ifdef ASN1_R_TYPE_NOT_PRIMITIVE ++ {"TYPE_NOT_PRIMITIVE", ERR_LIB_ASN1, ASN1_R_TYPE_NOT_PRIMITIVE}, ++ #else ++ {"TYPE_NOT_PRIMITIVE", 13, 195}, ++ #endif ++ #ifdef ASN1_R_UNEXPECTED_EOC ++ {"UNEXPECTED_EOC", ERR_LIB_ASN1, ASN1_R_UNEXPECTED_EOC}, ++ #else ++ {"UNEXPECTED_EOC", 13, 159}, ++ #endif ++ #ifdef ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH ++ {"UNIVERSALSTRING_IS_WRONG_LENGTH", ERR_LIB_ASN1, ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH}, ++ #else ++ {"UNIVERSALSTRING_IS_WRONG_LENGTH", 13, 215}, ++ #endif ++ #ifdef ASN1_R_UNKNOWN_DIGEST ++ {"UNKNOWN_DIGEST", ERR_LIB_ASN1, ASN1_R_UNKNOWN_DIGEST}, ++ #else ++ {"UNKNOWN_DIGEST", 13, 229}, ++ #endif ++ #ifdef ASN1_R_UNKNOWN_FORMAT ++ {"UNKNOWN_FORMAT", ERR_LIB_ASN1, ASN1_R_UNKNOWN_FORMAT}, ++ #else ++ {"UNKNOWN_FORMAT", 13, 160}, ++ #endif ++ #ifdef ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM ++ {"UNKNOWN_MESSAGE_DIGEST_ALGORITHM", ERR_LIB_ASN1, ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM}, ++ #else ++ {"UNKNOWN_MESSAGE_DIGEST_ALGORITHM", 13, 161}, ++ #endif ++ #ifdef ASN1_R_UNKNOWN_OBJECT_TYPE ++ {"UNKNOWN_OBJECT_TYPE", ERR_LIB_ASN1, ASN1_R_UNKNOWN_OBJECT_TYPE}, ++ #else ++ {"UNKNOWN_OBJECT_TYPE", 13, 162}, ++ #endif ++ #ifdef ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE ++ {"UNKNOWN_PUBLIC_KEY_TYPE", ERR_LIB_ASN1, ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE}, ++ #else ++ {"UNKNOWN_PUBLIC_KEY_TYPE", 13, 163}, ++ #endif ++ #ifdef ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM ++ {"UNKNOWN_SIGNATURE_ALGORITHM", ERR_LIB_ASN1, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM}, ++ #else ++ {"UNKNOWN_SIGNATURE_ALGORITHM", 13, 199}, ++ #endif ++ #ifdef ASN1_R_UNKNOWN_TAG ++ {"UNKNOWN_TAG", ERR_LIB_ASN1, ASN1_R_UNKNOWN_TAG}, ++ #else ++ {"UNKNOWN_TAG", 13, 194}, ++ #endif ++ #ifdef ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE ++ {"UNSUPPORTED_ANY_DEFINED_BY_TYPE", ERR_LIB_ASN1, ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE}, ++ #else ++ {"UNSUPPORTED_ANY_DEFINED_BY_TYPE", 13, 164}, ++ #endif ++ #ifdef ASN1_R_UNSUPPORTED_CIPHER ++ {"UNSUPPORTED_CIPHER", ERR_LIB_ASN1, ASN1_R_UNSUPPORTED_CIPHER}, ++ #else ++ {"UNSUPPORTED_CIPHER", 13, 228}, ++ #endif ++ #ifdef ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE ++ {"UNSUPPORTED_PUBLIC_KEY_TYPE", ERR_LIB_ASN1, ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE}, ++ #else ++ {"UNSUPPORTED_PUBLIC_KEY_TYPE", 13, 167}, ++ #endif ++ #ifdef ASN1_R_UNSUPPORTED_TYPE ++ {"UNSUPPORTED_TYPE", ERR_LIB_ASN1, ASN1_R_UNSUPPORTED_TYPE}, ++ #else ++ {"UNSUPPORTED_TYPE", 13, 196}, ++ #endif ++ #ifdef ASN1_R_UTCTIME_IS_TOO_SHORT ++ {"UTCTIME_IS_TOO_SHORT", ERR_LIB_ASN1, ASN1_R_UTCTIME_IS_TOO_SHORT}, ++ #else ++ {"UTCTIME_IS_TOO_SHORT", 13, 233}, ++ #endif ++ #ifdef ASN1_R_WRONG_INTEGER_TYPE ++ {"WRONG_INTEGER_TYPE", ERR_LIB_ASN1, ASN1_R_WRONG_INTEGER_TYPE}, ++ #else ++ {"WRONG_INTEGER_TYPE", 13, 225}, ++ #endif ++ #ifdef ASN1_R_WRONG_PUBLIC_KEY_TYPE ++ {"WRONG_PUBLIC_KEY_TYPE", ERR_LIB_ASN1, ASN1_R_WRONG_PUBLIC_KEY_TYPE}, ++ #else ++ {"WRONG_PUBLIC_KEY_TYPE", 13, 200}, ++ #endif ++ #ifdef ASN1_R_WRONG_TAG ++ {"WRONG_TAG", ERR_LIB_ASN1, ASN1_R_WRONG_TAG}, ++ #else ++ {"WRONG_TAG", 13, 168}, ++ #endif ++ #ifdef ASYNC_R_FAILED_TO_SET_POOL ++ {"FAILED_TO_SET_POOL", ERR_LIB_ASYNC, ASYNC_R_FAILED_TO_SET_POOL}, ++ #else ++ {"FAILED_TO_SET_POOL", 51, 101}, ++ #endif ++ #ifdef ASYNC_R_FAILED_TO_SWAP_CONTEXT ++ {"FAILED_TO_SWAP_CONTEXT", ERR_LIB_ASYNC, ASYNC_R_FAILED_TO_SWAP_CONTEXT}, ++ #else ++ {"FAILED_TO_SWAP_CONTEXT", 51, 102}, ++ #endif ++ #ifdef ASYNC_R_INIT_FAILED ++ {"INIT_FAILED", ERR_LIB_ASYNC, ASYNC_R_INIT_FAILED}, ++ #else ++ {"INIT_FAILED", 51, 105}, ++ #endif ++ #ifdef ASYNC_R_INVALID_POOL_SIZE ++ {"INVALID_POOL_SIZE", ERR_LIB_ASYNC, ASYNC_R_INVALID_POOL_SIZE}, ++ #else ++ {"INVALID_POOL_SIZE", 51, 103}, ++ #endif ++ #ifdef BIO_R_ACCEPT_ERROR ++ {"ACCEPT_ERROR", ERR_LIB_BIO, BIO_R_ACCEPT_ERROR}, ++ #else ++ {"ACCEPT_ERROR", 32, 100}, ++ #endif ++ #ifdef BIO_R_ADDRINFO_ADDR_IS_NOT_AF_INET ++ {"ADDRINFO_ADDR_IS_NOT_AF_INET", ERR_LIB_BIO, BIO_R_ADDRINFO_ADDR_IS_NOT_AF_INET}, ++ #else ++ {"ADDRINFO_ADDR_IS_NOT_AF_INET", 32, 141}, ++ #endif ++ #ifdef BIO_R_AMBIGUOUS_HOST_OR_SERVICE ++ {"AMBIGUOUS_HOST_OR_SERVICE", ERR_LIB_BIO, BIO_R_AMBIGUOUS_HOST_OR_SERVICE}, ++ #else ++ {"AMBIGUOUS_HOST_OR_SERVICE", 32, 129}, ++ #endif ++ #ifdef BIO_R_BAD_FOPEN_MODE ++ {"BAD_FOPEN_MODE", ERR_LIB_BIO, BIO_R_BAD_FOPEN_MODE}, ++ #else ++ {"BAD_FOPEN_MODE", 32, 101}, ++ #endif ++ #ifdef BIO_R_BROKEN_PIPE ++ {"BROKEN_PIPE", ERR_LIB_BIO, BIO_R_BROKEN_PIPE}, ++ #else ++ {"BROKEN_PIPE", 32, 124}, ++ #endif ++ #ifdef BIO_R_CONNECT_ERROR ++ {"CONNECT_ERROR", ERR_LIB_BIO, BIO_R_CONNECT_ERROR}, ++ #else ++ {"CONNECT_ERROR", 32, 103}, ++ #endif ++ #ifdef BIO_R_CONNECT_TIMEOUT ++ {"CONNECT_TIMEOUT", ERR_LIB_BIO, BIO_R_CONNECT_TIMEOUT}, ++ #else ++ {"CONNECT_TIMEOUT", 32, 147}, ++ #endif ++ #ifdef BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET ++ {"GETHOSTBYNAME_ADDR_IS_NOT_AF_INET", ERR_LIB_BIO, BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET}, ++ #else ++ {"GETHOSTBYNAME_ADDR_IS_NOT_AF_INET", 32, 107}, ++ #endif ++ #ifdef BIO_R_GETSOCKNAME_ERROR ++ {"GETSOCKNAME_ERROR", ERR_LIB_BIO, BIO_R_GETSOCKNAME_ERROR}, ++ #else ++ {"GETSOCKNAME_ERROR", 32, 132}, ++ #endif ++ #ifdef BIO_R_GETSOCKNAME_TRUNCATED_ADDRESS ++ {"GETSOCKNAME_TRUNCATED_ADDRESS", ERR_LIB_BIO, BIO_R_GETSOCKNAME_TRUNCATED_ADDRESS}, ++ #else ++ {"GETSOCKNAME_TRUNCATED_ADDRESS", 32, 133}, ++ #endif ++ #ifdef BIO_R_GETTING_SOCKTYPE ++ {"GETTING_SOCKTYPE", ERR_LIB_BIO, BIO_R_GETTING_SOCKTYPE}, ++ #else ++ {"GETTING_SOCKTYPE", 32, 134}, ++ #endif ++ #ifdef BIO_R_INVALID_ARGUMENT ++ {"INVALID_ARGUMENT", ERR_LIB_BIO, BIO_R_INVALID_ARGUMENT}, ++ #else ++ {"INVALID_ARGUMENT", 32, 125}, ++ #endif ++ #ifdef BIO_R_INVALID_SOCKET ++ {"INVALID_SOCKET", ERR_LIB_BIO, BIO_R_INVALID_SOCKET}, ++ #else ++ {"INVALID_SOCKET", 32, 135}, ++ #endif ++ #ifdef BIO_R_IN_USE ++ {"IN_USE", ERR_LIB_BIO, BIO_R_IN_USE}, ++ #else ++ {"IN_USE", 32, 123}, ++ #endif ++ #ifdef BIO_R_LENGTH_TOO_LONG ++ {"LENGTH_TOO_LONG", ERR_LIB_BIO, BIO_R_LENGTH_TOO_LONG}, ++ #else ++ {"LENGTH_TOO_LONG", 32, 102}, ++ #endif ++ #ifdef BIO_R_LISTEN_V6_ONLY ++ {"LISTEN_V6_ONLY", ERR_LIB_BIO, BIO_R_LISTEN_V6_ONLY}, ++ #else ++ {"LISTEN_V6_ONLY", 32, 136}, ++ #endif ++ #ifdef BIO_R_LOCAL_ADDR_NOT_AVAILABLE ++ {"LOCAL_ADDR_NOT_AVAILABLE", ERR_LIB_BIO, BIO_R_LOCAL_ADDR_NOT_AVAILABLE}, ++ #else ++ {"LOCAL_ADDR_NOT_AVAILABLE", 32, 111}, ++ #endif ++ #ifdef BIO_R_LOOKUP_RETURNED_NOTHING ++ {"LOOKUP_RETURNED_NOTHING", ERR_LIB_BIO, BIO_R_LOOKUP_RETURNED_NOTHING}, ++ #else ++ {"LOOKUP_RETURNED_NOTHING", 32, 142}, ++ #endif ++ #ifdef BIO_R_MALFORMED_HOST_OR_SERVICE ++ {"MALFORMED_HOST_OR_SERVICE", ERR_LIB_BIO, BIO_R_MALFORMED_HOST_OR_SERVICE}, ++ #else ++ {"MALFORMED_HOST_OR_SERVICE", 32, 130}, ++ #endif ++ #ifdef BIO_R_NBIO_CONNECT_ERROR ++ {"NBIO_CONNECT_ERROR", ERR_LIB_BIO, BIO_R_NBIO_CONNECT_ERROR}, ++ #else ++ {"NBIO_CONNECT_ERROR", 32, 110}, ++ #endif ++ #ifdef BIO_R_NON_FATAL ++ {"NON_FATAL", ERR_LIB_BIO, BIO_R_NON_FATAL}, ++ #else ++ {"NON_FATAL", 32, 112}, ++ #endif ++ #ifdef BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED ++ {"NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED", ERR_LIB_BIO, BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED}, ++ #else ++ {"NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED", 32, 143}, ++ #endif ++ #ifdef BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED ++ {"NO_HOSTNAME_OR_SERVICE_SPECIFIED", ERR_LIB_BIO, BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED}, ++ #else ++ {"NO_HOSTNAME_OR_SERVICE_SPECIFIED", 32, 144}, ++ #endif ++ #ifdef BIO_R_NO_PORT_DEFINED ++ {"NO_PORT_DEFINED", ERR_LIB_BIO, BIO_R_NO_PORT_DEFINED}, ++ #else ++ {"NO_PORT_DEFINED", 32, 113}, ++ #endif ++ #ifdef BIO_R_NO_SUCH_FILE ++ {"NO_SUCH_FILE", ERR_LIB_BIO, BIO_R_NO_SUCH_FILE}, ++ #else ++ {"NO_SUCH_FILE", 32, 128}, ++ #endif ++ #ifdef BIO_R_PEER_ADDR_NOT_AVAILABLE ++ {"PEER_ADDR_NOT_AVAILABLE", ERR_LIB_BIO, BIO_R_PEER_ADDR_NOT_AVAILABLE}, ++ #else ++ {"PEER_ADDR_NOT_AVAILABLE", 32, 114}, ++ #endif ++ #ifdef BIO_R_PORT_MISMATCH ++ {"PORT_MISMATCH", ERR_LIB_BIO, BIO_R_PORT_MISMATCH}, ++ #else ++ {"PORT_MISMATCH", 32, 150}, ++ #endif ++ #ifdef BIO_R_TFO_DISABLED ++ {"TFO_DISABLED", ERR_LIB_BIO, BIO_R_TFO_DISABLED}, ++ #else ++ {"TFO_DISABLED", 32, 106}, ++ #endif ++ #ifdef BIO_R_TFO_NO_KERNEL_SUPPORT ++ {"TFO_NO_KERNEL_SUPPORT", ERR_LIB_BIO, BIO_R_TFO_NO_KERNEL_SUPPORT}, ++ #else ++ {"TFO_NO_KERNEL_SUPPORT", 32, 108}, ++ #endif ++ #ifdef BIO_R_TRANSFER_ERROR ++ {"TRANSFER_ERROR", ERR_LIB_BIO, BIO_R_TRANSFER_ERROR}, ++ #else ++ {"TRANSFER_ERROR", 32, 104}, ++ #endif ++ #ifdef BIO_R_TRANSFER_TIMEOUT ++ {"TRANSFER_TIMEOUT", ERR_LIB_BIO, BIO_R_TRANSFER_TIMEOUT}, ++ #else ++ {"TRANSFER_TIMEOUT", 32, 105}, ++ #endif ++ #ifdef BIO_R_UNABLE_TO_BIND_SOCKET ++ {"UNABLE_TO_BIND_SOCKET", ERR_LIB_BIO, BIO_R_UNABLE_TO_BIND_SOCKET}, ++ #else ++ {"UNABLE_TO_BIND_SOCKET", 32, 117}, ++ #endif ++ #ifdef BIO_R_UNABLE_TO_CREATE_SOCKET ++ {"UNABLE_TO_CREATE_SOCKET", ERR_LIB_BIO, BIO_R_UNABLE_TO_CREATE_SOCKET}, ++ #else ++ {"UNABLE_TO_CREATE_SOCKET", 32, 118}, ++ #endif ++ #ifdef BIO_R_UNABLE_TO_KEEPALIVE ++ {"UNABLE_TO_KEEPALIVE", ERR_LIB_BIO, BIO_R_UNABLE_TO_KEEPALIVE}, ++ #else ++ {"UNABLE_TO_KEEPALIVE", 32, 137}, ++ #endif ++ #ifdef BIO_R_UNABLE_TO_LISTEN_SOCKET ++ {"UNABLE_TO_LISTEN_SOCKET", ERR_LIB_BIO, BIO_R_UNABLE_TO_LISTEN_SOCKET}, ++ #else ++ {"UNABLE_TO_LISTEN_SOCKET", 32, 119}, ++ #endif ++ #ifdef BIO_R_UNABLE_TO_NODELAY ++ {"UNABLE_TO_NODELAY", ERR_LIB_BIO, BIO_R_UNABLE_TO_NODELAY}, ++ #else ++ {"UNABLE_TO_NODELAY", 32, 138}, ++ #endif ++ #ifdef BIO_R_UNABLE_TO_REUSEADDR ++ {"UNABLE_TO_REUSEADDR", ERR_LIB_BIO, BIO_R_UNABLE_TO_REUSEADDR}, ++ #else ++ {"UNABLE_TO_REUSEADDR", 32, 139}, ++ #endif ++ #ifdef BIO_R_UNABLE_TO_TFO ++ {"UNABLE_TO_TFO", ERR_LIB_BIO, BIO_R_UNABLE_TO_TFO}, ++ #else ++ {"UNABLE_TO_TFO", 32, 109}, ++ #endif ++ #ifdef BIO_R_UNAVAILABLE_IP_FAMILY ++ {"UNAVAILABLE_IP_FAMILY", ERR_LIB_BIO, BIO_R_UNAVAILABLE_IP_FAMILY}, ++ #else ++ {"UNAVAILABLE_IP_FAMILY", 32, 145}, ++ #endif ++ #ifdef BIO_R_UNINITIALIZED ++ {"UNINITIALIZED", ERR_LIB_BIO, BIO_R_UNINITIALIZED}, ++ #else ++ {"UNINITIALIZED", 32, 120}, ++ #endif ++ #ifdef BIO_R_UNKNOWN_INFO_TYPE ++ {"UNKNOWN_INFO_TYPE", ERR_LIB_BIO, BIO_R_UNKNOWN_INFO_TYPE}, ++ #else ++ {"UNKNOWN_INFO_TYPE", 32, 140}, ++ #endif ++ #ifdef BIO_R_UNSUPPORTED_IP_FAMILY ++ {"UNSUPPORTED_IP_FAMILY", ERR_LIB_BIO, BIO_R_UNSUPPORTED_IP_FAMILY}, ++ #else ++ {"UNSUPPORTED_IP_FAMILY", 32, 146}, ++ #endif ++ #ifdef BIO_R_UNSUPPORTED_METHOD ++ {"UNSUPPORTED_METHOD", ERR_LIB_BIO, BIO_R_UNSUPPORTED_METHOD}, ++ #else ++ {"UNSUPPORTED_METHOD", 32, 121}, ++ #endif ++ #ifdef BIO_R_UNSUPPORTED_PROTOCOL_FAMILY ++ {"UNSUPPORTED_PROTOCOL_FAMILY", ERR_LIB_BIO, BIO_R_UNSUPPORTED_PROTOCOL_FAMILY}, ++ #else ++ {"UNSUPPORTED_PROTOCOL_FAMILY", 32, 131}, ++ #endif ++ #ifdef BIO_R_WRITE_TO_READ_ONLY_BIO ++ {"WRITE_TO_READ_ONLY_BIO", ERR_LIB_BIO, BIO_R_WRITE_TO_READ_ONLY_BIO}, ++ #else ++ {"WRITE_TO_READ_ONLY_BIO", 32, 126}, ++ #endif ++ #ifdef BIO_R_WSASTARTUP ++ {"WSASTARTUP", ERR_LIB_BIO, BIO_R_WSASTARTUP}, ++ #else ++ {"WSASTARTUP", 32, 122}, ++ #endif ++ #ifdef BN_R_ARG2_LT_ARG3 ++ {"ARG2_LT_ARG3", ERR_LIB_BN, BN_R_ARG2_LT_ARG3}, ++ #else ++ {"ARG2_LT_ARG3", 3, 100}, ++ #endif ++ #ifdef BN_R_BAD_RECIPROCAL ++ {"BAD_RECIPROCAL", ERR_LIB_BN, BN_R_BAD_RECIPROCAL}, ++ #else ++ {"BAD_RECIPROCAL", 3, 101}, ++ #endif ++ #ifdef BN_R_BIGNUM_TOO_LONG ++ {"BIGNUM_TOO_LONG", ERR_LIB_BN, BN_R_BIGNUM_TOO_LONG}, ++ #else ++ {"BIGNUM_TOO_LONG", 3, 114}, ++ #endif ++ #ifdef BN_R_BITS_TOO_SMALL ++ {"BITS_TOO_SMALL", ERR_LIB_BN, BN_R_BITS_TOO_SMALL}, ++ #else ++ {"BITS_TOO_SMALL", 3, 118}, ++ #endif ++ #ifdef BN_R_CALLED_WITH_EVEN_MODULUS ++ {"CALLED_WITH_EVEN_MODULUS", ERR_LIB_BN, BN_R_CALLED_WITH_EVEN_MODULUS}, ++ #else ++ {"CALLED_WITH_EVEN_MODULUS", 3, 102}, ++ #endif ++ #ifdef BN_R_DIV_BY_ZERO ++ {"DIV_BY_ZERO", ERR_LIB_BN, BN_R_DIV_BY_ZERO}, ++ #else ++ {"DIV_BY_ZERO", 3, 103}, ++ #endif ++ #ifdef BN_R_ENCODING_ERROR ++ {"ENCODING_ERROR", ERR_LIB_BN, BN_R_ENCODING_ERROR}, ++ #else ++ {"ENCODING_ERROR", 3, 104}, ++ #endif ++ #ifdef BN_R_EXPAND_ON_STATIC_BIGNUM_DATA ++ {"EXPAND_ON_STATIC_BIGNUM_DATA", ERR_LIB_BN, BN_R_EXPAND_ON_STATIC_BIGNUM_DATA}, ++ #else ++ {"EXPAND_ON_STATIC_BIGNUM_DATA", 3, 105}, ++ #endif ++ #ifdef BN_R_INPUT_NOT_REDUCED ++ {"INPUT_NOT_REDUCED", ERR_LIB_BN, BN_R_INPUT_NOT_REDUCED}, ++ #else ++ {"INPUT_NOT_REDUCED", 3, 110}, ++ #endif ++ #ifdef BN_R_INVALID_LENGTH ++ {"INVALID_LENGTH", ERR_LIB_BN, BN_R_INVALID_LENGTH}, ++ #else ++ {"INVALID_LENGTH", 3, 106}, ++ #endif ++ #ifdef BN_R_INVALID_RANGE ++ {"INVALID_RANGE", ERR_LIB_BN, BN_R_INVALID_RANGE}, ++ #else ++ {"INVALID_RANGE", 3, 115}, ++ #endif ++ #ifdef BN_R_INVALID_SHIFT ++ {"INVALID_SHIFT", ERR_LIB_BN, BN_R_INVALID_SHIFT}, ++ #else ++ {"INVALID_SHIFT", 3, 119}, ++ #endif ++ #ifdef BN_R_NOT_A_SQUARE ++ {"NOT_A_SQUARE", ERR_LIB_BN, BN_R_NOT_A_SQUARE}, ++ #else ++ {"NOT_A_SQUARE", 3, 111}, ++ #endif ++ #ifdef BN_R_NOT_INITIALIZED ++ {"NOT_INITIALIZED", ERR_LIB_BN, BN_R_NOT_INITIALIZED}, ++ #else ++ {"NOT_INITIALIZED", 3, 107}, ++ #endif ++ #ifdef BN_R_NO_INVERSE ++ {"NO_INVERSE", ERR_LIB_BN, BN_R_NO_INVERSE}, ++ #else ++ {"NO_INVERSE", 3, 108}, ++ #endif ++ #ifdef BN_R_NO_PRIME_CANDIDATE ++ {"NO_PRIME_CANDIDATE", ERR_LIB_BN, BN_R_NO_PRIME_CANDIDATE}, ++ #else ++ {"NO_PRIME_CANDIDATE", 3, 121}, ++ #endif ++ #ifdef BN_R_NO_SOLUTION ++ {"NO_SOLUTION", ERR_LIB_BN, BN_R_NO_SOLUTION}, ++ #else ++ {"NO_SOLUTION", 3, 116}, ++ #endif ++ #ifdef BN_R_NO_SUITABLE_DIGEST ++ {"NO_SUITABLE_DIGEST", ERR_LIB_BN, BN_R_NO_SUITABLE_DIGEST}, ++ #else ++ {"NO_SUITABLE_DIGEST", 3, 120}, ++ #endif ++ #ifdef BN_R_PRIVATE_KEY_TOO_LARGE ++ {"PRIVATE_KEY_TOO_LARGE", ERR_LIB_BN, BN_R_PRIVATE_KEY_TOO_LARGE}, ++ #else ++ {"PRIVATE_KEY_TOO_LARGE", 3, 117}, ++ #endif ++ #ifdef BN_R_P_IS_NOT_PRIME ++ {"P_IS_NOT_PRIME", ERR_LIB_BN, BN_R_P_IS_NOT_PRIME}, ++ #else ++ {"P_IS_NOT_PRIME", 3, 112}, ++ #endif ++ #ifdef BN_R_TOO_MANY_ITERATIONS ++ {"TOO_MANY_ITERATIONS", ERR_LIB_BN, BN_R_TOO_MANY_ITERATIONS}, ++ #else ++ {"TOO_MANY_ITERATIONS", 3, 113}, ++ #endif ++ #ifdef BN_R_TOO_MANY_TEMPORARY_VARIABLES ++ {"TOO_MANY_TEMPORARY_VARIABLES", ERR_LIB_BN, BN_R_TOO_MANY_TEMPORARY_VARIABLES}, ++ #else ++ {"TOO_MANY_TEMPORARY_VARIABLES", 3, 109}, ++ #endif ++ #ifdef CMP_R_ALGORITHM_NOT_SUPPORTED ++ {"ALGORITHM_NOT_SUPPORTED", ERR_LIB_CMP, CMP_R_ALGORITHM_NOT_SUPPORTED}, ++ #else ++ {"ALGORITHM_NOT_SUPPORTED", 58, 139}, ++ #endif ++ #ifdef CMP_R_BAD_CHECKAFTER_IN_POLLREP ++ {"BAD_CHECKAFTER_IN_POLLREP", ERR_LIB_CMP, CMP_R_BAD_CHECKAFTER_IN_POLLREP}, ++ #else ++ {"BAD_CHECKAFTER_IN_POLLREP", 58, 167}, ++ #endif ++ #ifdef CMP_R_BAD_REQUEST_ID ++ {"BAD_REQUEST_ID", ERR_LIB_CMP, CMP_R_BAD_REQUEST_ID}, ++ #else ++ {"BAD_REQUEST_ID", 58, 108}, ++ #endif ++ #ifdef CMP_R_CERTHASH_UNMATCHED ++ {"CERTHASH_UNMATCHED", ERR_LIB_CMP, CMP_R_CERTHASH_UNMATCHED}, ++ #else ++ {"CERTHASH_UNMATCHED", 58, 156}, ++ #endif ++ #ifdef CMP_R_CERTID_NOT_FOUND ++ {"CERTID_NOT_FOUND", ERR_LIB_CMP, CMP_R_CERTID_NOT_FOUND}, ++ #else ++ {"CERTID_NOT_FOUND", 58, 109}, ++ #endif ++ #ifdef CMP_R_CERTIFICATE_NOT_ACCEPTED ++ {"CERTIFICATE_NOT_ACCEPTED", ERR_LIB_CMP, CMP_R_CERTIFICATE_NOT_ACCEPTED}, ++ #else ++ {"CERTIFICATE_NOT_ACCEPTED", 58, 169}, ++ #endif ++ #ifdef CMP_R_CERTIFICATE_NOT_FOUND ++ {"CERTIFICATE_NOT_FOUND", ERR_LIB_CMP, CMP_R_CERTIFICATE_NOT_FOUND}, ++ #else ++ {"CERTIFICATE_NOT_FOUND", 58, 112}, ++ #endif ++ #ifdef CMP_R_CERTREQMSG_NOT_FOUND ++ {"CERTREQMSG_NOT_FOUND", ERR_LIB_CMP, CMP_R_CERTREQMSG_NOT_FOUND}, ++ #else ++ {"CERTREQMSG_NOT_FOUND", 58, 157}, ++ #endif ++ #ifdef CMP_R_CERTRESPONSE_NOT_FOUND ++ {"CERTRESPONSE_NOT_FOUND", ERR_LIB_CMP, CMP_R_CERTRESPONSE_NOT_FOUND}, ++ #else ++ {"CERTRESPONSE_NOT_FOUND", 58, 113}, ++ #endif ++ #ifdef CMP_R_CERT_AND_KEY_DO_NOT_MATCH ++ {"CERT_AND_KEY_DO_NOT_MATCH", ERR_LIB_CMP, CMP_R_CERT_AND_KEY_DO_NOT_MATCH}, ++ #else ++ {"CERT_AND_KEY_DO_NOT_MATCH", 58, 114}, ++ #endif ++ #ifdef CMP_R_CHECKAFTER_OUT_OF_RANGE ++ {"CHECKAFTER_OUT_OF_RANGE", ERR_LIB_CMP, CMP_R_CHECKAFTER_OUT_OF_RANGE}, ++ #else ++ {"CHECKAFTER_OUT_OF_RANGE", 58, 181}, ++ #endif ++ #ifdef CMP_R_ENCOUNTERED_KEYUPDATEWARNING ++ {"ENCOUNTERED_KEYUPDATEWARNING", ERR_LIB_CMP, CMP_R_ENCOUNTERED_KEYUPDATEWARNING}, ++ #else ++ {"ENCOUNTERED_KEYUPDATEWARNING", 58, 176}, ++ #endif ++ #ifdef CMP_R_ENCOUNTERED_WAITING ++ {"ENCOUNTERED_WAITING", ERR_LIB_CMP, CMP_R_ENCOUNTERED_WAITING}, ++ #else ++ {"ENCOUNTERED_WAITING", 58, 162}, ++ #endif ++ #ifdef CMP_R_ERROR_CALCULATING_PROTECTION ++ {"ERROR_CALCULATING_PROTECTION", ERR_LIB_CMP, CMP_R_ERROR_CALCULATING_PROTECTION}, ++ #else ++ {"ERROR_CALCULATING_PROTECTION", 58, 115}, ++ #endif ++ #ifdef CMP_R_ERROR_CREATING_CERTCONF ++ {"ERROR_CREATING_CERTCONF", ERR_LIB_CMP, CMP_R_ERROR_CREATING_CERTCONF}, ++ #else ++ {"ERROR_CREATING_CERTCONF", 58, 116}, ++ #endif ++ #ifdef CMP_R_ERROR_CREATING_CERTREP ++ {"ERROR_CREATING_CERTREP", ERR_LIB_CMP, CMP_R_ERROR_CREATING_CERTREP}, ++ #else ++ {"ERROR_CREATING_CERTREP", 58, 117}, ++ #endif ++ #ifdef CMP_R_ERROR_CREATING_CERTREQ ++ {"ERROR_CREATING_CERTREQ", ERR_LIB_CMP, CMP_R_ERROR_CREATING_CERTREQ}, ++ #else ++ {"ERROR_CREATING_CERTREQ", 58, 163}, ++ #endif ++ #ifdef CMP_R_ERROR_CREATING_ERROR ++ {"ERROR_CREATING_ERROR", ERR_LIB_CMP, CMP_R_ERROR_CREATING_ERROR}, ++ #else ++ {"ERROR_CREATING_ERROR", 58, 118}, ++ #endif ++ #ifdef CMP_R_ERROR_CREATING_GENM ++ {"ERROR_CREATING_GENM", ERR_LIB_CMP, CMP_R_ERROR_CREATING_GENM}, ++ #else ++ {"ERROR_CREATING_GENM", 58, 119}, ++ #endif ++ #ifdef CMP_R_ERROR_CREATING_GENP ++ {"ERROR_CREATING_GENP", ERR_LIB_CMP, CMP_R_ERROR_CREATING_GENP}, ++ #else ++ {"ERROR_CREATING_GENP", 58, 120}, ++ #endif ++ #ifdef CMP_R_ERROR_CREATING_PKICONF ++ {"ERROR_CREATING_PKICONF", ERR_LIB_CMP, CMP_R_ERROR_CREATING_PKICONF}, ++ #else ++ {"ERROR_CREATING_PKICONF", 58, 122}, ++ #endif ++ #ifdef CMP_R_ERROR_CREATING_POLLREP ++ {"ERROR_CREATING_POLLREP", ERR_LIB_CMP, CMP_R_ERROR_CREATING_POLLREP}, ++ #else ++ {"ERROR_CREATING_POLLREP", 58, 123}, ++ #endif ++ #ifdef CMP_R_ERROR_CREATING_POLLREQ ++ {"ERROR_CREATING_POLLREQ", ERR_LIB_CMP, CMP_R_ERROR_CREATING_POLLREQ}, ++ #else ++ {"ERROR_CREATING_POLLREQ", 58, 124}, ++ #endif ++ #ifdef CMP_R_ERROR_CREATING_RP ++ {"ERROR_CREATING_RP", ERR_LIB_CMP, CMP_R_ERROR_CREATING_RP}, ++ #else ++ {"ERROR_CREATING_RP", 58, 125}, ++ #endif ++ #ifdef CMP_R_ERROR_CREATING_RR ++ {"ERROR_CREATING_RR", ERR_LIB_CMP, CMP_R_ERROR_CREATING_RR}, ++ #else ++ {"ERROR_CREATING_RR", 58, 126}, ++ #endif ++ #ifdef CMP_R_ERROR_PARSING_PKISTATUS ++ {"ERROR_PARSING_PKISTATUS", ERR_LIB_CMP, CMP_R_ERROR_PARSING_PKISTATUS}, ++ #else ++ {"ERROR_PARSING_PKISTATUS", 58, 107}, ++ #endif ++ #ifdef CMP_R_ERROR_PROCESSING_MESSAGE ++ {"ERROR_PROCESSING_MESSAGE", ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE}, ++ #else ++ {"ERROR_PROCESSING_MESSAGE", 58, 158}, ++ #endif ++ #ifdef CMP_R_ERROR_PROTECTING_MESSAGE ++ {"ERROR_PROTECTING_MESSAGE", ERR_LIB_CMP, CMP_R_ERROR_PROTECTING_MESSAGE}, ++ #else ++ {"ERROR_PROTECTING_MESSAGE", 58, 127}, ++ #endif ++ #ifdef CMP_R_ERROR_SETTING_CERTHASH ++ {"ERROR_SETTING_CERTHASH", ERR_LIB_CMP, CMP_R_ERROR_SETTING_CERTHASH}, ++ #else ++ {"ERROR_SETTING_CERTHASH", 58, 128}, ++ #endif ++ #ifdef CMP_R_ERROR_UNEXPECTED_CERTCONF ++ {"ERROR_UNEXPECTED_CERTCONF", ERR_LIB_CMP, CMP_R_ERROR_UNEXPECTED_CERTCONF}, ++ #else ++ {"ERROR_UNEXPECTED_CERTCONF", 58, 160}, ++ #endif ++ #ifdef CMP_R_ERROR_VALIDATING_PROTECTION ++ {"ERROR_VALIDATING_PROTECTION", ERR_LIB_CMP, CMP_R_ERROR_VALIDATING_PROTECTION}, ++ #else ++ {"ERROR_VALIDATING_PROTECTION", 58, 140}, ++ #endif ++ #ifdef CMP_R_ERROR_VALIDATING_SIGNATURE ++ {"ERROR_VALIDATING_SIGNATURE", ERR_LIB_CMP, CMP_R_ERROR_VALIDATING_SIGNATURE}, ++ #else ++ {"ERROR_VALIDATING_SIGNATURE", 58, 171}, ++ #endif ++ #ifdef CMP_R_EXPECTED_POLLREQ ++ {"EXPECTED_POLLREQ", ERR_LIB_CMP, CMP_R_EXPECTED_POLLREQ}, ++ #else ++ {"EXPECTED_POLLREQ", 58, 104}, ++ #endif ++ #ifdef CMP_R_FAILED_BUILDING_OWN_CHAIN ++ {"FAILED_BUILDING_OWN_CHAIN", ERR_LIB_CMP, CMP_R_FAILED_BUILDING_OWN_CHAIN}, ++ #else ++ {"FAILED_BUILDING_OWN_CHAIN", 58, 164}, ++ #endif ++ #ifdef CMP_R_FAILED_EXTRACTING_PUBKEY ++ {"FAILED_EXTRACTING_PUBKEY", ERR_LIB_CMP, CMP_R_FAILED_EXTRACTING_PUBKEY}, ++ #else ++ {"FAILED_EXTRACTING_PUBKEY", 58, 141}, ++ #endif ++ #ifdef CMP_R_FAILURE_OBTAINING_RANDOM ++ {"FAILURE_OBTAINING_RANDOM", ERR_LIB_CMP, CMP_R_FAILURE_OBTAINING_RANDOM}, ++ #else ++ {"FAILURE_OBTAINING_RANDOM", 58, 110}, ++ #endif ++ #ifdef CMP_R_FAIL_INFO_OUT_OF_RANGE ++ {"FAIL_INFO_OUT_OF_RANGE", ERR_LIB_CMP, CMP_R_FAIL_INFO_OUT_OF_RANGE}, ++ #else ++ {"FAIL_INFO_OUT_OF_RANGE", 58, 129}, ++ #endif ++ #ifdef CMP_R_GENERATE_CERTREQTEMPLATE ++ {"GENERATE_CERTREQTEMPLATE", ERR_LIB_CMP, CMP_R_GENERATE_CERTREQTEMPLATE}, ++ #else ++ {"GENERATE_CERTREQTEMPLATE", 58, 197}, ++ #endif ++ #ifdef CMP_R_GENERATE_CRLSTATUS ++ {"GENERATE_CRLSTATUS", ERR_LIB_CMP, CMP_R_GENERATE_CRLSTATUS}, ++ #else ++ {"GENERATE_CRLSTATUS", 58, 198}, ++ #endif ++ #ifdef CMP_R_GETTING_GENP ++ {"GETTING_GENP", ERR_LIB_CMP, CMP_R_GETTING_GENP}, ++ #else ++ {"GETTING_GENP", 58, 192}, ++ #endif ++ #ifdef CMP_R_GET_ITAV ++ {"GET_ITAV", ERR_LIB_CMP, CMP_R_GET_ITAV}, ++ #else ++ {"GET_ITAV", 58, 199}, ++ #endif ++ #ifdef CMP_R_INVALID_ARGS ++ {"INVALID_ARGS", ERR_LIB_CMP, CMP_R_INVALID_ARGS}, ++ #else ++ {"INVALID_ARGS", 58, 100}, ++ #endif ++ #ifdef CMP_R_INVALID_GENP ++ {"INVALID_GENP", ERR_LIB_CMP, CMP_R_INVALID_GENP}, ++ #else ++ {"INVALID_GENP", 58, 193}, ++ #endif ++ #ifdef CMP_R_INVALID_KEYSPEC ++ {"INVALID_KEYSPEC", ERR_LIB_CMP, CMP_R_INVALID_KEYSPEC}, ++ #else ++ {"INVALID_KEYSPEC", 58, 202}, ++ #endif ++ #ifdef CMP_R_INVALID_OPTION ++ {"INVALID_OPTION", ERR_LIB_CMP, CMP_R_INVALID_OPTION}, ++ #else ++ {"INVALID_OPTION", 58, 174}, ++ #endif ++ #ifdef CMP_R_INVALID_ROOTCAKEYUPDATE ++ {"INVALID_ROOTCAKEYUPDATE", ERR_LIB_CMP, CMP_R_INVALID_ROOTCAKEYUPDATE}, ++ #else ++ {"INVALID_ROOTCAKEYUPDATE", 58, 195}, ++ #endif ++ #ifdef CMP_R_MISSING_CERTID ++ {"MISSING_CERTID", ERR_LIB_CMP, CMP_R_MISSING_CERTID}, ++ #else ++ {"MISSING_CERTID", 58, 165}, ++ #endif ++ #ifdef CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION ++ {"MISSING_KEY_INPUT_FOR_CREATING_PROTECTION", ERR_LIB_CMP, CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION}, ++ #else ++ {"MISSING_KEY_INPUT_FOR_CREATING_PROTECTION", 58, 130}, ++ #endif ++ #ifdef CMP_R_MISSING_KEY_USAGE_DIGITALSIGNATURE ++ {"MISSING_KEY_USAGE_DIGITALSIGNATURE", ERR_LIB_CMP, CMP_R_MISSING_KEY_USAGE_DIGITALSIGNATURE}, ++ #else ++ {"MISSING_KEY_USAGE_DIGITALSIGNATURE", 58, 142}, ++ #endif ++ #ifdef CMP_R_MISSING_P10CSR ++ {"MISSING_P10CSR", ERR_LIB_CMP, CMP_R_MISSING_P10CSR}, ++ #else ++ {"MISSING_P10CSR", 58, 121}, ++ #endif ++ #ifdef CMP_R_MISSING_PBM_SECRET ++ {"MISSING_PBM_SECRET", ERR_LIB_CMP, CMP_R_MISSING_PBM_SECRET}, ++ #else ++ {"MISSING_PBM_SECRET", 58, 166}, ++ #endif ++ #ifdef CMP_R_MISSING_PRIVATE_KEY ++ {"MISSING_PRIVATE_KEY", ERR_LIB_CMP, CMP_R_MISSING_PRIVATE_KEY}, ++ #else ++ {"MISSING_PRIVATE_KEY", 58, 131}, ++ #endif ++ #ifdef CMP_R_MISSING_PRIVATE_KEY_FOR_POPO ++ {"MISSING_PRIVATE_KEY_FOR_POPO", ERR_LIB_CMP, CMP_R_MISSING_PRIVATE_KEY_FOR_POPO}, ++ #else ++ {"MISSING_PRIVATE_KEY_FOR_POPO", 58, 190}, ++ #endif ++ #ifdef CMP_R_MISSING_PROTECTION ++ {"MISSING_PROTECTION", ERR_LIB_CMP, CMP_R_MISSING_PROTECTION}, ++ #else ++ {"MISSING_PROTECTION", 58, 143}, ++ #endif ++ #ifdef CMP_R_MISSING_PUBLIC_KEY ++ {"MISSING_PUBLIC_KEY", ERR_LIB_CMP, CMP_R_MISSING_PUBLIC_KEY}, ++ #else ++ {"MISSING_PUBLIC_KEY", 58, 183}, ++ #endif ++ #ifdef CMP_R_MISSING_REFERENCE_CERT ++ {"MISSING_REFERENCE_CERT", ERR_LIB_CMP, CMP_R_MISSING_REFERENCE_CERT}, ++ #else ++ {"MISSING_REFERENCE_CERT", 58, 168}, ++ #endif ++ #ifdef CMP_R_MISSING_SECRET ++ {"MISSING_SECRET", ERR_LIB_CMP, CMP_R_MISSING_SECRET}, ++ #else ++ {"MISSING_SECRET", 58, 178}, ++ #endif ++ #ifdef CMP_R_MISSING_SENDER_IDENTIFICATION ++ {"MISSING_SENDER_IDENTIFICATION", ERR_LIB_CMP, CMP_R_MISSING_SENDER_IDENTIFICATION}, ++ #else ++ {"MISSING_SENDER_IDENTIFICATION", 58, 111}, ++ #endif ++ #ifdef CMP_R_MISSING_TRUST_ANCHOR ++ {"MISSING_TRUST_ANCHOR", ERR_LIB_CMP, CMP_R_MISSING_TRUST_ANCHOR}, ++ #else ++ {"MISSING_TRUST_ANCHOR", 58, 179}, ++ #endif ++ #ifdef CMP_R_MISSING_TRUST_STORE ++ {"MISSING_TRUST_STORE", ERR_LIB_CMP, CMP_R_MISSING_TRUST_STORE}, ++ #else ++ {"MISSING_TRUST_STORE", 58, 144}, ++ #endif ++ #ifdef CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED ++ {"MULTIPLE_REQUESTS_NOT_SUPPORTED", ERR_LIB_CMP, CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED}, ++ #else ++ {"MULTIPLE_REQUESTS_NOT_SUPPORTED", 58, 161}, ++ #endif ++ #ifdef CMP_R_MULTIPLE_RESPONSES_NOT_SUPPORTED ++ {"MULTIPLE_RESPONSES_NOT_SUPPORTED", ERR_LIB_CMP, CMP_R_MULTIPLE_RESPONSES_NOT_SUPPORTED}, ++ #else ++ {"MULTIPLE_RESPONSES_NOT_SUPPORTED", 58, 170}, ++ #endif ++ #ifdef CMP_R_MULTIPLE_SAN_SOURCES ++ {"MULTIPLE_SAN_SOURCES", ERR_LIB_CMP, CMP_R_MULTIPLE_SAN_SOURCES}, ++ #else ++ {"MULTIPLE_SAN_SOURCES", 58, 102}, ++ #endif ++ #ifdef CMP_R_NO_STDIO ++ {"NO_STDIO", ERR_LIB_CMP, CMP_R_NO_STDIO}, ++ #else ++ {"NO_STDIO", 58, 194}, ++ #endif ++ #ifdef CMP_R_NO_SUITABLE_SENDER_CERT ++ {"NO_SUITABLE_SENDER_CERT", ERR_LIB_CMP, CMP_R_NO_SUITABLE_SENDER_CERT}, ++ #else ++ {"NO_SUITABLE_SENDER_CERT", 58, 145}, ++ #endif ++ #ifdef CMP_R_NULL_ARGUMENT ++ {"NULL_ARGUMENT", ERR_LIB_CMP, CMP_R_NULL_ARGUMENT}, ++ #else ++ {"NULL_ARGUMENT", 58, 103}, ++ #endif ++ #ifdef CMP_R_PKIBODY_ERROR ++ {"PKIBODY_ERROR", ERR_LIB_CMP, CMP_R_PKIBODY_ERROR}, ++ #else ++ {"PKIBODY_ERROR", 58, 146}, ++ #endif ++ #ifdef CMP_R_PKISTATUSINFO_NOT_FOUND ++ {"PKISTATUSINFO_NOT_FOUND", ERR_LIB_CMP, CMP_R_PKISTATUSINFO_NOT_FOUND}, ++ #else ++ {"PKISTATUSINFO_NOT_FOUND", 58, 132}, ++ #endif ++ #ifdef CMP_R_POLLING_FAILED ++ {"POLLING_FAILED", ERR_LIB_CMP, CMP_R_POLLING_FAILED}, ++ #else ++ {"POLLING_FAILED", 58, 172}, ++ #endif ++ #ifdef CMP_R_POTENTIALLY_INVALID_CERTIFICATE ++ {"POTENTIALLY_INVALID_CERTIFICATE", ERR_LIB_CMP, CMP_R_POTENTIALLY_INVALID_CERTIFICATE}, ++ #else ++ {"POTENTIALLY_INVALID_CERTIFICATE", 58, 147}, ++ #endif ++ #ifdef CMP_R_RECEIVED_ERROR ++ {"RECEIVED_ERROR", ERR_LIB_CMP, CMP_R_RECEIVED_ERROR}, ++ #else ++ {"RECEIVED_ERROR", 58, 180}, ++ #endif ++ #ifdef CMP_R_RECIPNONCE_UNMATCHED ++ {"RECIPNONCE_UNMATCHED", ERR_LIB_CMP, CMP_R_RECIPNONCE_UNMATCHED}, ++ #else ++ {"RECIPNONCE_UNMATCHED", 58, 148}, ++ #endif ++ #ifdef CMP_R_REQUEST_NOT_ACCEPTED ++ {"REQUEST_NOT_ACCEPTED", ERR_LIB_CMP, CMP_R_REQUEST_NOT_ACCEPTED}, ++ #else ++ {"REQUEST_NOT_ACCEPTED", 58, 149}, ++ #endif ++ #ifdef CMP_R_REQUEST_REJECTED_BY_SERVER ++ {"REQUEST_REJECTED_BY_SERVER", ERR_LIB_CMP, CMP_R_REQUEST_REJECTED_BY_SERVER}, ++ #else ++ {"REQUEST_REJECTED_BY_SERVER", 58, 182}, ++ #endif ++ #ifdef CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED ++ {"SENDER_GENERALNAME_TYPE_NOT_SUPPORTED", ERR_LIB_CMP, CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED}, ++ #else ++ {"SENDER_GENERALNAME_TYPE_NOT_SUPPORTED", 58, 150}, ++ #endif ++ #ifdef CMP_R_SRVCERT_DOES_NOT_VALIDATE_MSG ++ {"SRVCERT_DOES_NOT_VALIDATE_MSG", ERR_LIB_CMP, CMP_R_SRVCERT_DOES_NOT_VALIDATE_MSG}, ++ #else ++ {"SRVCERT_DOES_NOT_VALIDATE_MSG", 58, 151}, ++ #endif ++ #ifdef CMP_R_TOTAL_TIMEOUT ++ {"TOTAL_TIMEOUT", ERR_LIB_CMP, CMP_R_TOTAL_TIMEOUT}, ++ #else ++ {"TOTAL_TIMEOUT", 58, 184}, ++ #endif ++ #ifdef CMP_R_TRANSACTIONID_UNMATCHED ++ {"TRANSACTIONID_UNMATCHED", ERR_LIB_CMP, CMP_R_TRANSACTIONID_UNMATCHED}, ++ #else ++ {"TRANSACTIONID_UNMATCHED", 58, 152}, ++ #endif ++ #ifdef CMP_R_TRANSFER_ERROR ++ {"TRANSFER_ERROR", ERR_LIB_CMP, CMP_R_TRANSFER_ERROR}, ++ #else ++ {"TRANSFER_ERROR", 58, 159}, ++ #endif ++ #ifdef CMP_R_UNCLEAN_CTX ++ {"UNCLEAN_CTX", ERR_LIB_CMP, CMP_R_UNCLEAN_CTX}, ++ #else ++ {"UNCLEAN_CTX", 58, 191}, ++ #endif ++ #ifdef CMP_R_UNEXPECTED_CERTPROFILE ++ {"UNEXPECTED_CERTPROFILE", ERR_LIB_CMP, CMP_R_UNEXPECTED_CERTPROFILE}, ++ #else ++ {"UNEXPECTED_CERTPROFILE", 58, 196}, ++ #endif ++ #ifdef CMP_R_UNEXPECTED_CRLSTATUSLIST ++ {"UNEXPECTED_CRLSTATUSLIST", ERR_LIB_CMP, CMP_R_UNEXPECTED_CRLSTATUSLIST}, ++ #else ++ {"UNEXPECTED_CRLSTATUSLIST", 58, 201}, ++ #endif ++ #ifdef CMP_R_UNEXPECTED_PKIBODY ++ {"UNEXPECTED_PKIBODY", ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY}, ++ #else ++ {"UNEXPECTED_PKIBODY", 58, 133}, ++ #endif ++ #ifdef CMP_R_UNEXPECTED_PKISTATUS ++ {"UNEXPECTED_PKISTATUS", ERR_LIB_CMP, CMP_R_UNEXPECTED_PKISTATUS}, ++ #else ++ {"UNEXPECTED_PKISTATUS", 58, 185}, ++ #endif ++ #ifdef CMP_R_UNEXPECTED_POLLREQ ++ {"UNEXPECTED_POLLREQ", ERR_LIB_CMP, CMP_R_UNEXPECTED_POLLREQ}, ++ #else ++ {"UNEXPECTED_POLLREQ", 58, 105}, ++ #endif ++ #ifdef CMP_R_UNEXPECTED_PVNO ++ {"UNEXPECTED_PVNO", ERR_LIB_CMP, CMP_R_UNEXPECTED_PVNO}, ++ #else ++ {"UNEXPECTED_PVNO", 58, 153}, ++ #endif ++ #ifdef CMP_R_UNEXPECTED_SENDER ++ {"UNEXPECTED_SENDER", ERR_LIB_CMP, CMP_R_UNEXPECTED_SENDER}, ++ #else ++ {"UNEXPECTED_SENDER", 58, 106}, ++ #endif ++ #ifdef CMP_R_UNKNOWN_ALGORITHM_ID ++ {"UNKNOWN_ALGORITHM_ID", ERR_LIB_CMP, CMP_R_UNKNOWN_ALGORITHM_ID}, ++ #else ++ {"UNKNOWN_ALGORITHM_ID", 58, 134}, ++ #endif ++ #ifdef CMP_R_UNKNOWN_CERT_TYPE ++ {"UNKNOWN_CERT_TYPE", ERR_LIB_CMP, CMP_R_UNKNOWN_CERT_TYPE}, ++ #else ++ {"UNKNOWN_CERT_TYPE", 58, 135}, ++ #endif ++ #ifdef CMP_R_UNKNOWN_CRL_ISSUER ++ {"UNKNOWN_CRL_ISSUER", ERR_LIB_CMP, CMP_R_UNKNOWN_CRL_ISSUER}, ++ #else ++ {"UNKNOWN_CRL_ISSUER", 58, 200}, ++ #endif ++ #ifdef CMP_R_UNKNOWN_PKISTATUS ++ {"UNKNOWN_PKISTATUS", ERR_LIB_CMP, CMP_R_UNKNOWN_PKISTATUS}, ++ #else ++ {"UNKNOWN_PKISTATUS", 58, 186}, ++ #endif ++ #ifdef CMP_R_UNSUPPORTED_ALGORITHM ++ {"UNSUPPORTED_ALGORITHM", ERR_LIB_CMP, CMP_R_UNSUPPORTED_ALGORITHM}, ++ #else ++ {"UNSUPPORTED_ALGORITHM", 58, 136}, ++ #endif ++ #ifdef CMP_R_UNSUPPORTED_KEY_TYPE ++ {"UNSUPPORTED_KEY_TYPE", ERR_LIB_CMP, CMP_R_UNSUPPORTED_KEY_TYPE}, ++ #else ++ {"UNSUPPORTED_KEY_TYPE", 58, 137}, ++ #endif ++ #ifdef CMP_R_UNSUPPORTED_PKIBODY ++ {"UNSUPPORTED_PKIBODY", ERR_LIB_CMP, CMP_R_UNSUPPORTED_PKIBODY}, ++ #else ++ {"UNSUPPORTED_PKIBODY", 58, 101}, ++ #endif ++ #ifdef CMP_R_UNSUPPORTED_PROTECTION_ALG_DHBASEDMAC ++ {"UNSUPPORTED_PROTECTION_ALG_DHBASEDMAC", ERR_LIB_CMP, CMP_R_UNSUPPORTED_PROTECTION_ALG_DHBASEDMAC}, ++ #else ++ {"UNSUPPORTED_PROTECTION_ALG_DHBASEDMAC", 58, 154}, ++ #endif ++ #ifdef CMP_R_VALUE_TOO_LARGE ++ {"VALUE_TOO_LARGE", ERR_LIB_CMP, CMP_R_VALUE_TOO_LARGE}, ++ #else ++ {"VALUE_TOO_LARGE", 58, 175}, ++ #endif ++ #ifdef CMP_R_VALUE_TOO_SMALL ++ {"VALUE_TOO_SMALL", ERR_LIB_CMP, CMP_R_VALUE_TOO_SMALL}, ++ #else ++ {"VALUE_TOO_SMALL", 58, 177}, ++ #endif ++ #ifdef CMP_R_WRONG_ALGORITHM_OID ++ {"WRONG_ALGORITHM_OID", ERR_LIB_CMP, CMP_R_WRONG_ALGORITHM_OID}, ++ #else ++ {"WRONG_ALGORITHM_OID", 58, 138}, ++ #endif ++ #ifdef CMP_R_WRONG_CERTID ++ {"WRONG_CERTID", ERR_LIB_CMP, CMP_R_WRONG_CERTID}, ++ #else ++ {"WRONG_CERTID", 58, 189}, ++ #endif ++ #ifdef CMP_R_WRONG_CERTID_IN_RP ++ {"WRONG_CERTID_IN_RP", ERR_LIB_CMP, CMP_R_WRONG_CERTID_IN_RP}, ++ #else ++ {"WRONG_CERTID_IN_RP", 58, 187}, ++ #endif ++ #ifdef CMP_R_WRONG_PBM_VALUE ++ {"WRONG_PBM_VALUE", ERR_LIB_CMP, CMP_R_WRONG_PBM_VALUE}, ++ #else ++ {"WRONG_PBM_VALUE", 58, 155}, ++ #endif ++ #ifdef CMP_R_WRONG_RP_COMPONENT_COUNT ++ {"WRONG_RP_COMPONENT_COUNT", ERR_LIB_CMP, CMP_R_WRONG_RP_COMPONENT_COUNT}, ++ #else ++ {"WRONG_RP_COMPONENT_COUNT", 58, 188}, ++ #endif ++ #ifdef CMP_R_WRONG_SERIAL_IN_RP ++ {"WRONG_SERIAL_IN_RP", ERR_LIB_CMP, CMP_R_WRONG_SERIAL_IN_RP}, ++ #else ++ {"WRONG_SERIAL_IN_RP", 58, 173}, ++ #endif ++ #ifdef CMS_R_ADD_SIGNER_ERROR ++ {"ADD_SIGNER_ERROR", ERR_LIB_CMS, CMS_R_ADD_SIGNER_ERROR}, ++ #else ++ {"ADD_SIGNER_ERROR", 46, 99}, ++ #endif ++ #ifdef CMS_R_ATTRIBUTE_ERROR ++ {"ATTRIBUTE_ERROR", ERR_LIB_CMS, CMS_R_ATTRIBUTE_ERROR}, ++ #else ++ {"ATTRIBUTE_ERROR", 46, 161}, ++ #endif ++ #ifdef CMS_R_CERTIFICATE_ALREADY_PRESENT ++ {"CERTIFICATE_ALREADY_PRESENT", ERR_LIB_CMS, CMS_R_CERTIFICATE_ALREADY_PRESENT}, ++ #else ++ {"CERTIFICATE_ALREADY_PRESENT", 46, 175}, ++ #endif ++ #ifdef CMS_R_CERTIFICATE_HAS_NO_KEYID ++ {"CERTIFICATE_HAS_NO_KEYID", ERR_LIB_CMS, CMS_R_CERTIFICATE_HAS_NO_KEYID}, ++ #else ++ {"CERTIFICATE_HAS_NO_KEYID", 46, 160}, ++ #endif ++ #ifdef CMS_R_CERTIFICATE_VERIFY_ERROR ++ {"CERTIFICATE_VERIFY_ERROR", ERR_LIB_CMS, CMS_R_CERTIFICATE_VERIFY_ERROR}, ++ #else ++ {"CERTIFICATE_VERIFY_ERROR", 46, 100}, ++ #endif ++ #ifdef CMS_R_CIPHER_AEAD_SET_TAG_ERROR ++ {"CIPHER_AEAD_SET_TAG_ERROR", ERR_LIB_CMS, CMS_R_CIPHER_AEAD_SET_TAG_ERROR}, ++ #else ++ {"CIPHER_AEAD_SET_TAG_ERROR", 46, 184}, ++ #endif ++ #ifdef CMS_R_CIPHER_GET_TAG ++ {"CIPHER_GET_TAG", ERR_LIB_CMS, CMS_R_CIPHER_GET_TAG}, ++ #else ++ {"CIPHER_GET_TAG", 46, 185}, ++ #endif ++ #ifdef CMS_R_CIPHER_INITIALISATION_ERROR ++ {"CIPHER_INITIALISATION_ERROR", ERR_LIB_CMS, CMS_R_CIPHER_INITIALISATION_ERROR}, ++ #else ++ {"CIPHER_INITIALISATION_ERROR", 46, 101}, ++ #endif ++ #ifdef CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR ++ {"CIPHER_PARAMETER_INITIALISATION_ERROR", ERR_LIB_CMS, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR}, ++ #else ++ {"CIPHER_PARAMETER_INITIALISATION_ERROR", 46, 102}, ++ #endif ++ #ifdef CMS_R_CMS_DATAFINAL_ERROR ++ {"CMS_DATAFINAL_ERROR", ERR_LIB_CMS, CMS_R_CMS_DATAFINAL_ERROR}, ++ #else ++ {"CMS_DATAFINAL_ERROR", 46, 103}, ++ #endif ++ #ifdef CMS_R_CMS_LIB ++ {"CMS_LIB", ERR_LIB_CMS, CMS_R_CMS_LIB}, ++ #else ++ {"CMS_LIB", 46, 104}, ++ #endif ++ #ifdef CMS_R_CONTENTIDENTIFIER_MISMATCH ++ {"CONTENTIDENTIFIER_MISMATCH", ERR_LIB_CMS, CMS_R_CONTENTIDENTIFIER_MISMATCH}, ++ #else ++ {"CONTENTIDENTIFIER_MISMATCH", 46, 170}, ++ #endif ++ #ifdef CMS_R_CONTENT_NOT_FOUND ++ {"CONTENT_NOT_FOUND", ERR_LIB_CMS, CMS_R_CONTENT_NOT_FOUND}, ++ #else ++ {"CONTENT_NOT_FOUND", 46, 105}, ++ #endif ++ #ifdef CMS_R_CONTENT_TYPE_MISMATCH ++ {"CONTENT_TYPE_MISMATCH", ERR_LIB_CMS, CMS_R_CONTENT_TYPE_MISMATCH}, ++ #else ++ {"CONTENT_TYPE_MISMATCH", 46, 171}, ++ #endif ++ #ifdef CMS_R_CONTENT_TYPE_NOT_COMPRESSED_DATA ++ {"CONTENT_TYPE_NOT_COMPRESSED_DATA", ERR_LIB_CMS, CMS_R_CONTENT_TYPE_NOT_COMPRESSED_DATA}, ++ #else ++ {"CONTENT_TYPE_NOT_COMPRESSED_DATA", 46, 106}, ++ #endif ++ #ifdef CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA ++ {"CONTENT_TYPE_NOT_ENVELOPED_DATA", ERR_LIB_CMS, CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA}, ++ #else ++ {"CONTENT_TYPE_NOT_ENVELOPED_DATA", 46, 107}, ++ #endif ++ #ifdef CMS_R_CONTENT_TYPE_NOT_SIGNED_DATA ++ {"CONTENT_TYPE_NOT_SIGNED_DATA", ERR_LIB_CMS, CMS_R_CONTENT_TYPE_NOT_SIGNED_DATA}, ++ #else ++ {"CONTENT_TYPE_NOT_SIGNED_DATA", 46, 108}, ++ #endif ++ #ifdef CMS_R_CONTENT_VERIFY_ERROR ++ {"CONTENT_VERIFY_ERROR", ERR_LIB_CMS, CMS_R_CONTENT_VERIFY_ERROR}, ++ #else ++ {"CONTENT_VERIFY_ERROR", 46, 109}, ++ #endif ++ #ifdef CMS_R_CTRL_ERROR ++ {"CTRL_ERROR", ERR_LIB_CMS, CMS_R_CTRL_ERROR}, ++ #else ++ {"CTRL_ERROR", 46, 110}, ++ #endif ++ #ifdef CMS_R_CTRL_FAILURE ++ {"CTRL_FAILURE", ERR_LIB_CMS, CMS_R_CTRL_FAILURE}, ++ #else ++ {"CTRL_FAILURE", 46, 111}, ++ #endif ++ #ifdef CMS_R_DECODE_ERROR ++ {"DECODE_ERROR", ERR_LIB_CMS, CMS_R_DECODE_ERROR}, ++ #else ++ {"DECODE_ERROR", 46, 187}, ++ #endif ++ #ifdef CMS_R_DECRYPT_ERROR ++ {"DECRYPT_ERROR", ERR_LIB_CMS, CMS_R_DECRYPT_ERROR}, ++ #else ++ {"DECRYPT_ERROR", 46, 112}, ++ #endif ++ #ifdef CMS_R_ERROR_GETTING_PUBLIC_KEY ++ {"ERROR_GETTING_PUBLIC_KEY", ERR_LIB_CMS, CMS_R_ERROR_GETTING_PUBLIC_KEY}, ++ #else ++ {"ERROR_GETTING_PUBLIC_KEY", 46, 113}, ++ #endif ++ #ifdef CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE ++ {"ERROR_READING_MESSAGEDIGEST_ATTRIBUTE", ERR_LIB_CMS, CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE}, ++ #else ++ {"ERROR_READING_MESSAGEDIGEST_ATTRIBUTE", 46, 114}, ++ #endif ++ #ifdef CMS_R_ERROR_SETTING_KEY ++ {"ERROR_SETTING_KEY", ERR_LIB_CMS, CMS_R_ERROR_SETTING_KEY}, ++ #else ++ {"ERROR_SETTING_KEY", 46, 115}, ++ #endif ++ #ifdef CMS_R_ERROR_SETTING_RECIPIENTINFO ++ {"ERROR_SETTING_RECIPIENTINFO", ERR_LIB_CMS, CMS_R_ERROR_SETTING_RECIPIENTINFO}, ++ #else ++ {"ERROR_SETTING_RECIPIENTINFO", 46, 116}, ++ #endif ++ #ifdef CMS_R_ESS_SIGNING_CERTID_MISMATCH_ERROR ++ {"ESS_SIGNING_CERTID_MISMATCH_ERROR", ERR_LIB_CMS, CMS_R_ESS_SIGNING_CERTID_MISMATCH_ERROR}, ++ #else ++ {"ESS_SIGNING_CERTID_MISMATCH_ERROR", 46, 183}, ++ #endif ++ #ifdef CMS_R_INVALID_ENCRYPTED_KEY_LENGTH ++ {"INVALID_ENCRYPTED_KEY_LENGTH", ERR_LIB_CMS, CMS_R_INVALID_ENCRYPTED_KEY_LENGTH}, ++ #else ++ {"INVALID_ENCRYPTED_KEY_LENGTH", 46, 117}, ++ #endif ++ #ifdef CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER ++ {"INVALID_KEY_ENCRYPTION_PARAMETER", ERR_LIB_CMS, CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER}, ++ #else ++ {"INVALID_KEY_ENCRYPTION_PARAMETER", 46, 176}, ++ #endif ++ #ifdef CMS_R_INVALID_KEY_LENGTH ++ {"INVALID_KEY_LENGTH", ERR_LIB_CMS, CMS_R_INVALID_KEY_LENGTH}, ++ #else ++ {"INVALID_KEY_LENGTH", 46, 118}, ++ #endif ++ #ifdef CMS_R_INVALID_LABEL ++ {"INVALID_LABEL", ERR_LIB_CMS, CMS_R_INVALID_LABEL}, ++ #else ++ {"INVALID_LABEL", 46, 190}, ++ #endif ++ #ifdef CMS_R_INVALID_OAEP_PARAMETERS ++ {"INVALID_OAEP_PARAMETERS", ERR_LIB_CMS, CMS_R_INVALID_OAEP_PARAMETERS}, ++ #else ++ {"INVALID_OAEP_PARAMETERS", 46, 191}, ++ #endif ++ #ifdef CMS_R_KDF_PARAMETER_ERROR ++ {"KDF_PARAMETER_ERROR", ERR_LIB_CMS, CMS_R_KDF_PARAMETER_ERROR}, ++ #else ++ {"KDF_PARAMETER_ERROR", 46, 186}, ++ #endif ++ #ifdef CMS_R_MD_BIO_INIT_ERROR ++ {"MD_BIO_INIT_ERROR", ERR_LIB_CMS, CMS_R_MD_BIO_INIT_ERROR}, ++ #else ++ {"MD_BIO_INIT_ERROR", 46, 119}, ++ #endif ++ #ifdef CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH ++ {"MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH", ERR_LIB_CMS, CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH}, ++ #else ++ {"MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH", 46, 120}, ++ #endif ++ #ifdef CMS_R_MESSAGEDIGEST_WRONG_LENGTH ++ {"MESSAGEDIGEST_WRONG_LENGTH", ERR_LIB_CMS, CMS_R_MESSAGEDIGEST_WRONG_LENGTH}, ++ #else ++ {"MESSAGEDIGEST_WRONG_LENGTH", 46, 121}, ++ #endif ++ #ifdef CMS_R_MSGSIGDIGEST_ERROR ++ {"MSGSIGDIGEST_ERROR", ERR_LIB_CMS, CMS_R_MSGSIGDIGEST_ERROR}, ++ #else ++ {"MSGSIGDIGEST_ERROR", 46, 172}, ++ #endif ++ #ifdef CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE ++ {"MSGSIGDIGEST_VERIFICATION_FAILURE", ERR_LIB_CMS, CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE}, ++ #else ++ {"MSGSIGDIGEST_VERIFICATION_FAILURE", 46, 162}, ++ #endif ++ #ifdef CMS_R_MSGSIGDIGEST_WRONG_LENGTH ++ {"MSGSIGDIGEST_WRONG_LENGTH", ERR_LIB_CMS, CMS_R_MSGSIGDIGEST_WRONG_LENGTH}, ++ #else ++ {"MSGSIGDIGEST_WRONG_LENGTH", 46, 163}, ++ #endif ++ #ifdef CMS_R_NEED_ONE_SIGNER ++ {"NEED_ONE_SIGNER", ERR_LIB_CMS, CMS_R_NEED_ONE_SIGNER}, ++ #else ++ {"NEED_ONE_SIGNER", 46, 164}, ++ #endif ++ #ifdef CMS_R_NOT_A_SIGNED_RECEIPT ++ {"NOT_A_SIGNED_RECEIPT", ERR_LIB_CMS, CMS_R_NOT_A_SIGNED_RECEIPT}, ++ #else ++ {"NOT_A_SIGNED_RECEIPT", 46, 165}, ++ #endif ++ #ifdef CMS_R_NOT_ENCRYPTED_DATA ++ {"NOT_ENCRYPTED_DATA", ERR_LIB_CMS, CMS_R_NOT_ENCRYPTED_DATA}, ++ #else ++ {"NOT_ENCRYPTED_DATA", 46, 122}, ++ #endif ++ #ifdef CMS_R_NOT_KEK ++ {"NOT_KEK", ERR_LIB_CMS, CMS_R_NOT_KEK}, ++ #else ++ {"NOT_KEK", 46, 123}, ++ #endif ++ #ifdef CMS_R_NOT_KEY_AGREEMENT ++ {"NOT_KEY_AGREEMENT", ERR_LIB_CMS, CMS_R_NOT_KEY_AGREEMENT}, ++ #else ++ {"NOT_KEY_AGREEMENT", 46, 181}, ++ #endif ++ #ifdef CMS_R_NOT_KEY_TRANSPORT ++ {"NOT_KEY_TRANSPORT", ERR_LIB_CMS, CMS_R_NOT_KEY_TRANSPORT}, ++ #else ++ {"NOT_KEY_TRANSPORT", 46, 124}, ++ #endif ++ #ifdef CMS_R_NOT_PWRI ++ {"NOT_PWRI", ERR_LIB_CMS, CMS_R_NOT_PWRI}, ++ #else ++ {"NOT_PWRI", 46, 177}, ++ #endif ++ #ifdef CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE ++ {"NOT_SUPPORTED_FOR_THIS_KEY_TYPE", ERR_LIB_CMS, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE}, ++ #else ++ {"NOT_SUPPORTED_FOR_THIS_KEY_TYPE", 46, 125}, ++ #endif ++ #ifdef CMS_R_NO_CIPHER ++ {"NO_CIPHER", ERR_LIB_CMS, CMS_R_NO_CIPHER}, ++ #else ++ {"NO_CIPHER", 46, 126}, ++ #endif ++ #ifdef CMS_R_NO_CONTENT ++ {"NO_CONTENT", ERR_LIB_CMS, CMS_R_NO_CONTENT}, ++ #else ++ {"NO_CONTENT", 46, 127}, ++ #endif ++ #ifdef CMS_R_NO_CONTENT_TYPE ++ {"NO_CONTENT_TYPE", ERR_LIB_CMS, CMS_R_NO_CONTENT_TYPE}, ++ #else ++ {"NO_CONTENT_TYPE", 46, 173}, ++ #endif ++ #ifdef CMS_R_NO_DEFAULT_DIGEST ++ {"NO_DEFAULT_DIGEST", ERR_LIB_CMS, CMS_R_NO_DEFAULT_DIGEST}, ++ #else ++ {"NO_DEFAULT_DIGEST", 46, 128}, ++ #endif ++ #ifdef CMS_R_NO_DIGEST_SET ++ {"NO_DIGEST_SET", ERR_LIB_CMS, CMS_R_NO_DIGEST_SET}, ++ #else ++ {"NO_DIGEST_SET", 46, 129}, ++ #endif ++ #ifdef CMS_R_NO_KEY ++ {"NO_KEY", ERR_LIB_CMS, CMS_R_NO_KEY}, ++ #else ++ {"NO_KEY", 46, 130}, ++ #endif ++ #ifdef CMS_R_NO_KEY_OR_CERT ++ {"NO_KEY_OR_CERT", ERR_LIB_CMS, CMS_R_NO_KEY_OR_CERT}, ++ #else ++ {"NO_KEY_OR_CERT", 46, 174}, ++ #endif ++ #ifdef CMS_R_NO_MATCHING_DIGEST ++ {"NO_MATCHING_DIGEST", ERR_LIB_CMS, CMS_R_NO_MATCHING_DIGEST}, ++ #else ++ {"NO_MATCHING_DIGEST", 46, 131}, ++ #endif ++ #ifdef CMS_R_NO_MATCHING_RECIPIENT ++ {"NO_MATCHING_RECIPIENT", ERR_LIB_CMS, CMS_R_NO_MATCHING_RECIPIENT}, ++ #else ++ {"NO_MATCHING_RECIPIENT", 46, 132}, ++ #endif ++ #ifdef CMS_R_NO_MATCHING_SIGNATURE ++ {"NO_MATCHING_SIGNATURE", ERR_LIB_CMS, CMS_R_NO_MATCHING_SIGNATURE}, ++ #else ++ {"NO_MATCHING_SIGNATURE", 46, 166}, ++ #endif ++ #ifdef CMS_R_NO_MSGSIGDIGEST ++ {"NO_MSGSIGDIGEST", ERR_LIB_CMS, CMS_R_NO_MSGSIGDIGEST}, ++ #else ++ {"NO_MSGSIGDIGEST", 46, 167}, ++ #endif ++ #ifdef CMS_R_NO_PASSWORD ++ {"NO_PASSWORD", ERR_LIB_CMS, CMS_R_NO_PASSWORD}, ++ #else ++ {"NO_PASSWORD", 46, 178}, ++ #endif ++ #ifdef CMS_R_NO_PRIVATE_KEY ++ {"NO_PRIVATE_KEY", ERR_LIB_CMS, CMS_R_NO_PRIVATE_KEY}, ++ #else ++ {"NO_PRIVATE_KEY", 46, 133}, ++ #endif ++ #ifdef CMS_R_NO_PUBLIC_KEY ++ {"NO_PUBLIC_KEY", ERR_LIB_CMS, CMS_R_NO_PUBLIC_KEY}, ++ #else ++ {"NO_PUBLIC_KEY", 46, 134}, ++ #endif ++ #ifdef CMS_R_NO_RECEIPT_REQUEST ++ {"NO_RECEIPT_REQUEST", ERR_LIB_CMS, CMS_R_NO_RECEIPT_REQUEST}, ++ #else ++ {"NO_RECEIPT_REQUEST", 46, 168}, ++ #endif ++ #ifdef CMS_R_NO_SIGNERS ++ {"NO_SIGNERS", ERR_LIB_CMS, CMS_R_NO_SIGNERS}, ++ #else ++ {"NO_SIGNERS", 46, 135}, ++ #endif ++ #ifdef CMS_R_OPERATION_UNSUPPORTED ++ {"OPERATION_UNSUPPORTED", ERR_LIB_CMS, CMS_R_OPERATION_UNSUPPORTED}, ++ #else ++ {"OPERATION_UNSUPPORTED", 46, 182}, ++ #endif ++ #ifdef CMS_R_PEER_KEY_ERROR ++ {"PEER_KEY_ERROR", ERR_LIB_CMS, CMS_R_PEER_KEY_ERROR}, ++ #else ++ {"PEER_KEY_ERROR", 46, 188}, ++ #endif ++ #ifdef CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE ++ {"PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE", ERR_LIB_CMS, CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE}, ++ #else ++ {"PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE", 46, 136}, ++ #endif ++ #ifdef CMS_R_RECEIPT_DECODE_ERROR ++ {"RECEIPT_DECODE_ERROR", ERR_LIB_CMS, CMS_R_RECEIPT_DECODE_ERROR}, ++ #else ++ {"RECEIPT_DECODE_ERROR", 46, 169}, ++ #endif ++ #ifdef CMS_R_RECIPIENT_ERROR ++ {"RECIPIENT_ERROR", ERR_LIB_CMS, CMS_R_RECIPIENT_ERROR}, ++ #else ++ {"RECIPIENT_ERROR", 46, 137}, ++ #endif ++ #ifdef CMS_R_SHARED_INFO_ERROR ++ {"SHARED_INFO_ERROR", ERR_LIB_CMS, CMS_R_SHARED_INFO_ERROR}, ++ #else ++ {"SHARED_INFO_ERROR", 46, 189}, ++ #endif ++ #ifdef CMS_R_SIGNER_CERTIFICATE_NOT_FOUND ++ {"SIGNER_CERTIFICATE_NOT_FOUND", ERR_LIB_CMS, CMS_R_SIGNER_CERTIFICATE_NOT_FOUND}, ++ #else ++ {"SIGNER_CERTIFICATE_NOT_FOUND", 46, 138}, ++ #endif ++ #ifdef CMS_R_SIGNFINAL_ERROR ++ {"SIGNFINAL_ERROR", ERR_LIB_CMS, CMS_R_SIGNFINAL_ERROR}, ++ #else ++ {"SIGNFINAL_ERROR", 46, 139}, ++ #endif ++ #ifdef CMS_R_SMIME_TEXT_ERROR ++ {"SMIME_TEXT_ERROR", ERR_LIB_CMS, CMS_R_SMIME_TEXT_ERROR}, ++ #else ++ {"SMIME_TEXT_ERROR", 46, 140}, ++ #endif ++ #ifdef CMS_R_STORE_INIT_ERROR ++ {"STORE_INIT_ERROR", ERR_LIB_CMS, CMS_R_STORE_INIT_ERROR}, ++ #else ++ {"STORE_INIT_ERROR", 46, 141}, ++ #endif ++ #ifdef CMS_R_TYPE_NOT_COMPRESSED_DATA ++ {"TYPE_NOT_COMPRESSED_DATA", ERR_LIB_CMS, CMS_R_TYPE_NOT_COMPRESSED_DATA}, ++ #else ++ {"TYPE_NOT_COMPRESSED_DATA", 46, 142}, ++ #endif ++ #ifdef CMS_R_TYPE_NOT_DATA ++ {"TYPE_NOT_DATA", ERR_LIB_CMS, CMS_R_TYPE_NOT_DATA}, ++ #else ++ {"TYPE_NOT_DATA", 46, 143}, ++ #endif ++ #ifdef CMS_R_TYPE_NOT_DIGESTED_DATA ++ {"TYPE_NOT_DIGESTED_DATA", ERR_LIB_CMS, CMS_R_TYPE_NOT_DIGESTED_DATA}, ++ #else ++ {"TYPE_NOT_DIGESTED_DATA", 46, 144}, ++ #endif ++ #ifdef CMS_R_TYPE_NOT_ENCRYPTED_DATA ++ {"TYPE_NOT_ENCRYPTED_DATA", ERR_LIB_CMS, CMS_R_TYPE_NOT_ENCRYPTED_DATA}, ++ #else ++ {"TYPE_NOT_ENCRYPTED_DATA", 46, 145}, ++ #endif ++ #ifdef CMS_R_TYPE_NOT_ENVELOPED_DATA ++ {"TYPE_NOT_ENVELOPED_DATA", ERR_LIB_CMS, CMS_R_TYPE_NOT_ENVELOPED_DATA}, ++ #else ++ {"TYPE_NOT_ENVELOPED_DATA", 46, 146}, ++ #endif ++ #ifdef CMS_R_UNABLE_TO_FINALIZE_CONTEXT ++ {"UNABLE_TO_FINALIZE_CONTEXT", ERR_LIB_CMS, CMS_R_UNABLE_TO_FINALIZE_CONTEXT}, ++ #else ++ {"UNABLE_TO_FINALIZE_CONTEXT", 46, 147}, ++ #endif ++ #ifdef CMS_R_UNKNOWN_CIPHER ++ {"UNKNOWN_CIPHER", ERR_LIB_CMS, CMS_R_UNKNOWN_CIPHER}, ++ #else ++ {"UNKNOWN_CIPHER", 46, 148}, ++ #endif ++ #ifdef CMS_R_UNKNOWN_DIGEST_ALGORITHM ++ {"UNKNOWN_DIGEST_ALGORITHM", ERR_LIB_CMS, CMS_R_UNKNOWN_DIGEST_ALGORITHM}, ++ #else ++ {"UNKNOWN_DIGEST_ALGORITHM", 46, 149}, ++ #endif ++ #ifdef CMS_R_UNKNOWN_ID ++ {"UNKNOWN_ID", ERR_LIB_CMS, CMS_R_UNKNOWN_ID}, ++ #else ++ {"UNKNOWN_ID", 46, 150}, ++ #endif ++ #ifdef CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM ++ {"UNSUPPORTED_COMPRESSION_ALGORITHM", ERR_LIB_CMS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM}, ++ #else ++ {"UNSUPPORTED_COMPRESSION_ALGORITHM", 46, 151}, ++ #endif ++ #ifdef CMS_R_UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM ++ {"UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM", ERR_LIB_CMS, CMS_R_UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM}, ++ #else ++ {"UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM", 46, 194}, ++ #endif ++ #ifdef CMS_R_UNSUPPORTED_CONTENT_TYPE ++ {"UNSUPPORTED_CONTENT_TYPE", ERR_LIB_CMS, CMS_R_UNSUPPORTED_CONTENT_TYPE}, ++ #else ++ {"UNSUPPORTED_CONTENT_TYPE", 46, 152}, ++ #endif ++ #ifdef CMS_R_UNSUPPORTED_ENCRYPTION_TYPE ++ {"UNSUPPORTED_ENCRYPTION_TYPE", ERR_LIB_CMS, CMS_R_UNSUPPORTED_ENCRYPTION_TYPE}, ++ #else ++ {"UNSUPPORTED_ENCRYPTION_TYPE", 46, 192}, ++ #endif ++ #ifdef CMS_R_UNSUPPORTED_KEK_ALGORITHM ++ {"UNSUPPORTED_KEK_ALGORITHM", ERR_LIB_CMS, CMS_R_UNSUPPORTED_KEK_ALGORITHM}, ++ #else ++ {"UNSUPPORTED_KEK_ALGORITHM", 46, 153}, ++ #endif ++ #ifdef CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM ++ {"UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM", ERR_LIB_CMS, CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM}, ++ #else ++ {"UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM", 46, 179}, ++ #endif ++ #ifdef CMS_R_UNSUPPORTED_LABEL_SOURCE ++ {"UNSUPPORTED_LABEL_SOURCE", ERR_LIB_CMS, CMS_R_UNSUPPORTED_LABEL_SOURCE}, ++ #else ++ {"UNSUPPORTED_LABEL_SOURCE", 46, 193}, ++ #endif ++ #ifdef CMS_R_UNSUPPORTED_RECIPIENTINFO_TYPE ++ {"UNSUPPORTED_RECIPIENTINFO_TYPE", ERR_LIB_CMS, CMS_R_UNSUPPORTED_RECIPIENTINFO_TYPE}, ++ #else ++ {"UNSUPPORTED_RECIPIENTINFO_TYPE", 46, 155}, ++ #endif ++ #ifdef CMS_R_UNSUPPORTED_RECIPIENT_TYPE ++ {"UNSUPPORTED_RECIPIENT_TYPE", ERR_LIB_CMS, CMS_R_UNSUPPORTED_RECIPIENT_TYPE}, ++ #else ++ {"UNSUPPORTED_RECIPIENT_TYPE", 46, 154}, ++ #endif ++ #ifdef CMS_R_UNSUPPORTED_SIGNATURE_ALGORITHM ++ {"UNSUPPORTED_SIGNATURE_ALGORITHM", ERR_LIB_CMS, CMS_R_UNSUPPORTED_SIGNATURE_ALGORITHM}, ++ #else ++ {"UNSUPPORTED_SIGNATURE_ALGORITHM", 46, 195}, ++ #endif ++ #ifdef CMS_R_UNSUPPORTED_TYPE ++ {"UNSUPPORTED_TYPE", ERR_LIB_CMS, CMS_R_UNSUPPORTED_TYPE}, ++ #else ++ {"UNSUPPORTED_TYPE", 46, 156}, ++ #endif ++ #ifdef CMS_R_UNWRAP_ERROR ++ {"UNWRAP_ERROR", ERR_LIB_CMS, CMS_R_UNWRAP_ERROR}, ++ #else ++ {"UNWRAP_ERROR", 46, 157}, ++ #endif ++ #ifdef CMS_R_UNWRAP_FAILURE ++ {"UNWRAP_FAILURE", ERR_LIB_CMS, CMS_R_UNWRAP_FAILURE}, ++ #else ++ {"UNWRAP_FAILURE", 46, 180}, ++ #endif ++ #ifdef CMS_R_VERIFICATION_FAILURE ++ {"VERIFICATION_FAILURE", ERR_LIB_CMS, CMS_R_VERIFICATION_FAILURE}, ++ #else ++ {"VERIFICATION_FAILURE", 46, 158}, ++ #endif ++ #ifdef CMS_R_WRAP_ERROR ++ {"WRAP_ERROR", ERR_LIB_CMS, CMS_R_WRAP_ERROR}, ++ #else ++ {"WRAP_ERROR", 46, 159}, ++ #endif ++ #ifdef COMP_R_BROTLI_DECODE_ERROR ++ {"BROTLI_DECODE_ERROR", ERR_LIB_COMP, COMP_R_BROTLI_DECODE_ERROR}, ++ #else ++ {"BROTLI_DECODE_ERROR", 41, 102}, ++ #endif ++ #ifdef COMP_R_BROTLI_DEFLATE_ERROR ++ {"BROTLI_DEFLATE_ERROR", ERR_LIB_COMP, COMP_R_BROTLI_DEFLATE_ERROR}, ++ #else ++ {"BROTLI_DEFLATE_ERROR", 41, 103}, ++ #endif ++ #ifdef COMP_R_BROTLI_ENCODE_ERROR ++ {"BROTLI_ENCODE_ERROR", ERR_LIB_COMP, COMP_R_BROTLI_ENCODE_ERROR}, ++ #else ++ {"BROTLI_ENCODE_ERROR", 41, 106}, ++ #endif ++ #ifdef COMP_R_BROTLI_INFLATE_ERROR ++ {"BROTLI_INFLATE_ERROR", ERR_LIB_COMP, COMP_R_BROTLI_INFLATE_ERROR}, ++ #else ++ {"BROTLI_INFLATE_ERROR", 41, 104}, ++ #endif ++ #ifdef COMP_R_BROTLI_NOT_SUPPORTED ++ {"BROTLI_NOT_SUPPORTED", ERR_LIB_COMP, COMP_R_BROTLI_NOT_SUPPORTED}, ++ #else ++ {"BROTLI_NOT_SUPPORTED", 41, 105}, ++ #endif ++ #ifdef COMP_R_ZLIB_DEFLATE_ERROR ++ {"ZLIB_DEFLATE_ERROR", ERR_LIB_COMP, COMP_R_ZLIB_DEFLATE_ERROR}, ++ #else ++ {"ZLIB_DEFLATE_ERROR", 41, 99}, ++ #endif ++ #ifdef COMP_R_ZLIB_INFLATE_ERROR ++ {"ZLIB_INFLATE_ERROR", ERR_LIB_COMP, COMP_R_ZLIB_INFLATE_ERROR}, ++ #else ++ {"ZLIB_INFLATE_ERROR", 41, 100}, ++ #endif ++ #ifdef COMP_R_ZLIB_NOT_SUPPORTED ++ {"ZLIB_NOT_SUPPORTED", ERR_LIB_COMP, COMP_R_ZLIB_NOT_SUPPORTED}, ++ #else ++ {"ZLIB_NOT_SUPPORTED", 41, 101}, ++ #endif ++ #ifdef COMP_R_ZSTD_COMPRESS_ERROR ++ {"ZSTD_COMPRESS_ERROR", ERR_LIB_COMP, COMP_R_ZSTD_COMPRESS_ERROR}, ++ #else ++ {"ZSTD_COMPRESS_ERROR", 41, 107}, ++ #endif ++ #ifdef COMP_R_ZSTD_DECODE_ERROR ++ {"ZSTD_DECODE_ERROR", ERR_LIB_COMP, COMP_R_ZSTD_DECODE_ERROR}, ++ #else ++ {"ZSTD_DECODE_ERROR", 41, 108}, ++ #endif ++ #ifdef COMP_R_ZSTD_DECOMPRESS_ERROR ++ {"ZSTD_DECOMPRESS_ERROR", ERR_LIB_COMP, COMP_R_ZSTD_DECOMPRESS_ERROR}, ++ #else ++ {"ZSTD_DECOMPRESS_ERROR", 41, 109}, ++ #endif ++ #ifdef COMP_R_ZSTD_NOT_SUPPORTED ++ {"ZSTD_NOT_SUPPORTED", ERR_LIB_COMP, COMP_R_ZSTD_NOT_SUPPORTED}, ++ #else ++ {"ZSTD_NOT_SUPPORTED", 41, 110}, ++ #endif ++ #ifdef CONF_R_ERROR_LOADING_DSO ++ {"ERROR_LOADING_DSO", ERR_LIB_CONF, CONF_R_ERROR_LOADING_DSO}, ++ #else ++ {"ERROR_LOADING_DSO", 14, 110}, ++ #endif ++ #ifdef CONF_R_INVALID_PRAGMA ++ {"INVALID_PRAGMA", ERR_LIB_CONF, CONF_R_INVALID_PRAGMA}, ++ #else ++ {"INVALID_PRAGMA", 14, 122}, ++ #endif ++ #ifdef CONF_R_LIST_CANNOT_BE_NULL ++ {"LIST_CANNOT_BE_NULL", ERR_LIB_CONF, CONF_R_LIST_CANNOT_BE_NULL}, ++ #else ++ {"LIST_CANNOT_BE_NULL", 14, 115}, ++ #endif ++ #ifdef CONF_R_MANDATORY_BRACES_IN_VARIABLE_EXPANSION ++ {"MANDATORY_BRACES_IN_VARIABLE_EXPANSION", ERR_LIB_CONF, CONF_R_MANDATORY_BRACES_IN_VARIABLE_EXPANSION}, ++ #else ++ {"MANDATORY_BRACES_IN_VARIABLE_EXPANSION", 14, 123}, ++ #endif ++ #ifdef CONF_R_MISSING_CLOSE_SQUARE_BRACKET ++ {"MISSING_CLOSE_SQUARE_BRACKET", ERR_LIB_CONF, CONF_R_MISSING_CLOSE_SQUARE_BRACKET}, ++ #else ++ {"MISSING_CLOSE_SQUARE_BRACKET", 14, 100}, ++ #endif ++ #ifdef CONF_R_MISSING_EQUAL_SIGN ++ {"MISSING_EQUAL_SIGN", ERR_LIB_CONF, CONF_R_MISSING_EQUAL_SIGN}, ++ #else ++ {"MISSING_EQUAL_SIGN", 14, 101}, ++ #endif ++ #ifdef CONF_R_MISSING_INIT_FUNCTION ++ {"MISSING_INIT_FUNCTION", ERR_LIB_CONF, CONF_R_MISSING_INIT_FUNCTION}, ++ #else ++ {"MISSING_INIT_FUNCTION", 14, 112}, ++ #endif ++ #ifdef CONF_R_MODULE_INITIALIZATION_ERROR ++ {"MODULE_INITIALIZATION_ERROR", ERR_LIB_CONF, CONF_R_MODULE_INITIALIZATION_ERROR}, ++ #else ++ {"MODULE_INITIALIZATION_ERROR", 14, 109}, ++ #endif ++ #ifdef CONF_R_NO_CLOSE_BRACE ++ {"NO_CLOSE_BRACE", ERR_LIB_CONF, CONF_R_NO_CLOSE_BRACE}, ++ #else ++ {"NO_CLOSE_BRACE", 14, 102}, ++ #endif ++ #ifdef CONF_R_NO_CONF ++ {"NO_CONF", ERR_LIB_CONF, CONF_R_NO_CONF}, ++ #else ++ {"NO_CONF", 14, 105}, ++ #endif ++ #ifdef CONF_R_NO_CONF_OR_ENVIRONMENT_VARIABLE ++ {"NO_CONF_OR_ENVIRONMENT_VARIABLE", ERR_LIB_CONF, CONF_R_NO_CONF_OR_ENVIRONMENT_VARIABLE}, ++ #else ++ {"NO_CONF_OR_ENVIRONMENT_VARIABLE", 14, 106}, ++ #endif ++ #ifdef CONF_R_NO_SECTION ++ {"NO_SECTION", ERR_LIB_CONF, CONF_R_NO_SECTION}, ++ #else ++ {"NO_SECTION", 14, 107}, ++ #endif ++ #ifdef CONF_R_NO_SUCH_FILE ++ {"NO_SUCH_FILE", ERR_LIB_CONF, CONF_R_NO_SUCH_FILE}, ++ #else ++ {"NO_SUCH_FILE", 14, 114}, ++ #endif ++ #ifdef CONF_R_NO_VALUE ++ {"NO_VALUE", ERR_LIB_CONF, CONF_R_NO_VALUE}, ++ #else ++ {"NO_VALUE", 14, 108}, ++ #endif ++ #ifdef CONF_R_NUMBER_TOO_LARGE ++ {"NUMBER_TOO_LARGE", ERR_LIB_CONF, CONF_R_NUMBER_TOO_LARGE}, ++ #else ++ {"NUMBER_TOO_LARGE", 14, 121}, ++ #endif ++ #ifdef CONF_R_OPENSSL_CONF_REFERENCES_MISSING_SECTION ++ {"OPENSSL_CONF_REFERENCES_MISSING_SECTION", ERR_LIB_CONF, CONF_R_OPENSSL_CONF_REFERENCES_MISSING_SECTION}, ++ #else ++ {"OPENSSL_CONF_REFERENCES_MISSING_SECTION", 14, 124}, ++ #endif ++ #ifdef CONF_R_RECURSIVE_DIRECTORY_INCLUDE ++ {"RECURSIVE_DIRECTORY_INCLUDE", ERR_LIB_CONF, CONF_R_RECURSIVE_DIRECTORY_INCLUDE}, ++ #else ++ {"RECURSIVE_DIRECTORY_INCLUDE", 14, 111}, ++ #endif ++ #ifdef CONF_R_RECURSIVE_SECTION_REFERENCE ++ {"RECURSIVE_SECTION_REFERENCE", ERR_LIB_CONF, CONF_R_RECURSIVE_SECTION_REFERENCE}, ++ #else ++ {"RECURSIVE_SECTION_REFERENCE", 14, 126}, ++ #endif ++ #ifdef CONF_R_RELATIVE_PATH ++ {"RELATIVE_PATH", ERR_LIB_CONF, CONF_R_RELATIVE_PATH}, ++ #else ++ {"RELATIVE_PATH", 14, 125}, ++ #endif ++ #ifdef CONF_R_SSL_COMMAND_SECTION_EMPTY ++ {"SSL_COMMAND_SECTION_EMPTY", ERR_LIB_CONF, CONF_R_SSL_COMMAND_SECTION_EMPTY}, ++ #else ++ {"SSL_COMMAND_SECTION_EMPTY", 14, 117}, ++ #endif ++ #ifdef CONF_R_SSL_COMMAND_SECTION_NOT_FOUND ++ {"SSL_COMMAND_SECTION_NOT_FOUND", ERR_LIB_CONF, CONF_R_SSL_COMMAND_SECTION_NOT_FOUND}, ++ #else ++ {"SSL_COMMAND_SECTION_NOT_FOUND", 14, 118}, ++ #endif ++ #ifdef CONF_R_SSL_SECTION_EMPTY ++ {"SSL_SECTION_EMPTY", ERR_LIB_CONF, CONF_R_SSL_SECTION_EMPTY}, ++ #else ++ {"SSL_SECTION_EMPTY", 14, 119}, ++ #endif ++ #ifdef CONF_R_SSL_SECTION_NOT_FOUND ++ {"SSL_SECTION_NOT_FOUND", ERR_LIB_CONF, CONF_R_SSL_SECTION_NOT_FOUND}, ++ #else ++ {"SSL_SECTION_NOT_FOUND", 14, 120}, ++ #endif ++ #ifdef CONF_R_UNABLE_TO_CREATE_NEW_SECTION ++ {"UNABLE_TO_CREATE_NEW_SECTION", ERR_LIB_CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION}, ++ #else ++ {"UNABLE_TO_CREATE_NEW_SECTION", 14, 103}, ++ #endif ++ #ifdef CONF_R_UNKNOWN_MODULE_NAME ++ {"UNKNOWN_MODULE_NAME", ERR_LIB_CONF, CONF_R_UNKNOWN_MODULE_NAME}, ++ #else ++ {"UNKNOWN_MODULE_NAME", 14, 113}, ++ #endif ++ #ifdef CONF_R_VARIABLE_EXPANSION_TOO_LONG ++ {"VARIABLE_EXPANSION_TOO_LONG", ERR_LIB_CONF, CONF_R_VARIABLE_EXPANSION_TOO_LONG}, ++ #else ++ {"VARIABLE_EXPANSION_TOO_LONG", 14, 116}, ++ #endif ++ #ifdef CONF_R_VARIABLE_HAS_NO_VALUE ++ {"VARIABLE_HAS_NO_VALUE", ERR_LIB_CONF, CONF_R_VARIABLE_HAS_NO_VALUE}, ++ #else ++ {"VARIABLE_HAS_NO_VALUE", 14, 104}, ++ #endif ++ #ifdef CRMF_R_BAD_PBM_ITERATIONCOUNT ++ {"BAD_PBM_ITERATIONCOUNT", ERR_LIB_CRMF, CRMF_R_BAD_PBM_ITERATIONCOUNT}, ++ #else ++ {"BAD_PBM_ITERATIONCOUNT", 56, 100}, ++ #endif ++ #ifdef CRMF_R_CRMFERROR ++ {"CRMFERROR", ERR_LIB_CRMF, CRMF_R_CRMFERROR}, ++ #else ++ {"CRMFERROR", 56, 102}, ++ #endif ++ #ifdef CRMF_R_ERROR ++ {"ERROR", ERR_LIB_CRMF, CRMF_R_ERROR}, ++ #else ++ {"ERROR", 56, 103}, ++ #endif ++ #ifdef CRMF_R_ERROR_DECODING_CERTIFICATE ++ {"ERROR_DECODING_CERTIFICATE", ERR_LIB_CRMF, CRMF_R_ERROR_DECODING_CERTIFICATE}, ++ #else ++ {"ERROR_DECODING_CERTIFICATE", 56, 104}, ++ #endif ++ #ifdef CRMF_R_ERROR_DECRYPTING_CERTIFICATE ++ {"ERROR_DECRYPTING_CERTIFICATE", ERR_LIB_CRMF, CRMF_R_ERROR_DECRYPTING_CERTIFICATE}, ++ #else ++ {"ERROR_DECRYPTING_CERTIFICATE", 56, 105}, ++ #endif ++ #ifdef CRMF_R_ERROR_DECRYPTING_SYMMETRIC_KEY ++ {"ERROR_DECRYPTING_SYMMETRIC_KEY", ERR_LIB_CRMF, CRMF_R_ERROR_DECRYPTING_SYMMETRIC_KEY}, ++ #else ++ {"ERROR_DECRYPTING_SYMMETRIC_KEY", 56, 106}, ++ #endif ++ #ifdef CRMF_R_FAILURE_OBTAINING_RANDOM ++ {"FAILURE_OBTAINING_RANDOM", ERR_LIB_CRMF, CRMF_R_FAILURE_OBTAINING_RANDOM}, ++ #else ++ {"FAILURE_OBTAINING_RANDOM", 56, 107}, ++ #endif ++ #ifdef CRMF_R_ITERATIONCOUNT_BELOW_100 ++ {"ITERATIONCOUNT_BELOW_100", ERR_LIB_CRMF, CRMF_R_ITERATIONCOUNT_BELOW_100}, ++ #else ++ {"ITERATIONCOUNT_BELOW_100", 56, 108}, ++ #endif ++ #ifdef CRMF_R_MALFORMED_IV ++ {"MALFORMED_IV", ERR_LIB_CRMF, CRMF_R_MALFORMED_IV}, ++ #else ++ {"MALFORMED_IV", 56, 101}, ++ #endif ++ #ifdef CRMF_R_NULL_ARGUMENT ++ {"NULL_ARGUMENT", ERR_LIB_CRMF, CRMF_R_NULL_ARGUMENT}, ++ #else ++ {"NULL_ARGUMENT", 56, 109}, ++ #endif ++ #ifdef CRMF_R_POPOSKINPUT_NOT_SUPPORTED ++ {"POPOSKINPUT_NOT_SUPPORTED", ERR_LIB_CRMF, CRMF_R_POPOSKINPUT_NOT_SUPPORTED}, ++ #else ++ {"POPOSKINPUT_NOT_SUPPORTED", 56, 113}, ++ #endif ++ #ifdef CRMF_R_POPO_INCONSISTENT_PUBLIC_KEY ++ {"POPO_INCONSISTENT_PUBLIC_KEY", ERR_LIB_CRMF, CRMF_R_POPO_INCONSISTENT_PUBLIC_KEY}, ++ #else ++ {"POPO_INCONSISTENT_PUBLIC_KEY", 56, 117}, ++ #endif ++ #ifdef CRMF_R_POPO_MISSING ++ {"POPO_MISSING", ERR_LIB_CRMF, CRMF_R_POPO_MISSING}, ++ #else ++ {"POPO_MISSING", 56, 121}, ++ #endif ++ #ifdef CRMF_R_POPO_MISSING_PUBLIC_KEY ++ {"POPO_MISSING_PUBLIC_KEY", ERR_LIB_CRMF, CRMF_R_POPO_MISSING_PUBLIC_KEY}, ++ #else ++ {"POPO_MISSING_PUBLIC_KEY", 56, 118}, ++ #endif ++ #ifdef CRMF_R_POPO_MISSING_SUBJECT ++ {"POPO_MISSING_SUBJECT", ERR_LIB_CRMF, CRMF_R_POPO_MISSING_SUBJECT}, ++ #else ++ {"POPO_MISSING_SUBJECT", 56, 119}, ++ #endif ++ #ifdef CRMF_R_POPO_RAVERIFIED_NOT_ACCEPTED ++ {"POPO_RAVERIFIED_NOT_ACCEPTED", ERR_LIB_CRMF, CRMF_R_POPO_RAVERIFIED_NOT_ACCEPTED}, ++ #else ++ {"POPO_RAVERIFIED_NOT_ACCEPTED", 56, 120}, ++ #endif ++ #ifdef CRMF_R_SETTING_MAC_ALGOR_FAILURE ++ {"SETTING_MAC_ALGOR_FAILURE", ERR_LIB_CRMF, CRMF_R_SETTING_MAC_ALGOR_FAILURE}, ++ #else ++ {"SETTING_MAC_ALGOR_FAILURE", 56, 110}, ++ #endif ++ #ifdef CRMF_R_SETTING_OWF_ALGOR_FAILURE ++ {"SETTING_OWF_ALGOR_FAILURE", ERR_LIB_CRMF, CRMF_R_SETTING_OWF_ALGOR_FAILURE}, ++ #else ++ {"SETTING_OWF_ALGOR_FAILURE", 56, 111}, ++ #endif ++ #ifdef CRMF_R_UNSUPPORTED_ALGORITHM ++ {"UNSUPPORTED_ALGORITHM", ERR_LIB_CRMF, CRMF_R_UNSUPPORTED_ALGORITHM}, ++ #else ++ {"UNSUPPORTED_ALGORITHM", 56, 112}, ++ #endif ++ #ifdef CRMF_R_UNSUPPORTED_CIPHER ++ {"UNSUPPORTED_CIPHER", ERR_LIB_CRMF, CRMF_R_UNSUPPORTED_CIPHER}, ++ #else ++ {"UNSUPPORTED_CIPHER", 56, 114}, ++ #endif ++ #ifdef CRMF_R_UNSUPPORTED_METHOD_FOR_CREATING_POPO ++ {"UNSUPPORTED_METHOD_FOR_CREATING_POPO", ERR_LIB_CRMF, CRMF_R_UNSUPPORTED_METHOD_FOR_CREATING_POPO}, ++ #else ++ {"UNSUPPORTED_METHOD_FOR_CREATING_POPO", 56, 115}, ++ #endif ++ #ifdef CRMF_R_UNSUPPORTED_POPO_METHOD ++ {"UNSUPPORTED_POPO_METHOD", ERR_LIB_CRMF, CRMF_R_UNSUPPORTED_POPO_METHOD}, ++ #else ++ {"UNSUPPORTED_POPO_METHOD", 56, 116}, ++ #endif ++ #ifdef CRYPTO_R_BAD_ALGORITHM_NAME ++ {"BAD_ALGORITHM_NAME", ERR_LIB_CRYPTO, CRYPTO_R_BAD_ALGORITHM_NAME}, ++ #else ++ {"BAD_ALGORITHM_NAME", 15, 117}, ++ #endif ++ #ifdef CRYPTO_R_CONFLICTING_NAMES ++ {"CONFLICTING_NAMES", ERR_LIB_CRYPTO, CRYPTO_R_CONFLICTING_NAMES}, ++ #else ++ {"CONFLICTING_NAMES", 15, 118}, ++ #endif ++ #ifdef CRYPTO_R_HEX_STRING_TOO_SHORT ++ {"HEX_STRING_TOO_SHORT", ERR_LIB_CRYPTO, CRYPTO_R_HEX_STRING_TOO_SHORT}, ++ #else ++ {"HEX_STRING_TOO_SHORT", 15, 121}, ++ #endif ++ #ifdef CRYPTO_R_ILLEGAL_HEX_DIGIT ++ {"ILLEGAL_HEX_DIGIT", ERR_LIB_CRYPTO, CRYPTO_R_ILLEGAL_HEX_DIGIT}, ++ #else ++ {"ILLEGAL_HEX_DIGIT", 15, 102}, ++ #endif ++ #ifdef CRYPTO_R_INSUFFICIENT_DATA_SPACE ++ {"INSUFFICIENT_DATA_SPACE", ERR_LIB_CRYPTO, CRYPTO_R_INSUFFICIENT_DATA_SPACE}, ++ #else ++ {"INSUFFICIENT_DATA_SPACE", 15, 106}, ++ #endif ++ #ifdef CRYPTO_R_INSUFFICIENT_PARAM_SIZE ++ {"INSUFFICIENT_PARAM_SIZE", ERR_LIB_CRYPTO, CRYPTO_R_INSUFFICIENT_PARAM_SIZE}, ++ #else ++ {"INSUFFICIENT_PARAM_SIZE", 15, 107}, ++ #endif ++ #ifdef CRYPTO_R_INSUFFICIENT_SECURE_DATA_SPACE ++ {"INSUFFICIENT_SECURE_DATA_SPACE", ERR_LIB_CRYPTO, CRYPTO_R_INSUFFICIENT_SECURE_DATA_SPACE}, ++ #else ++ {"INSUFFICIENT_SECURE_DATA_SPACE", 15, 108}, ++ #endif ++ #ifdef CRYPTO_R_INTEGER_OVERFLOW ++ {"INTEGER_OVERFLOW", ERR_LIB_CRYPTO, CRYPTO_R_INTEGER_OVERFLOW}, ++ #else ++ {"INTEGER_OVERFLOW", 15, 127}, ++ #endif ++ #ifdef CRYPTO_R_INVALID_NEGATIVE_VALUE ++ {"INVALID_NEGATIVE_VALUE", ERR_LIB_CRYPTO, CRYPTO_R_INVALID_NEGATIVE_VALUE}, ++ #else ++ {"INVALID_NEGATIVE_VALUE", 15, 122}, ++ #endif ++ #ifdef CRYPTO_R_INVALID_NULL_ARGUMENT ++ {"INVALID_NULL_ARGUMENT", ERR_LIB_CRYPTO, CRYPTO_R_INVALID_NULL_ARGUMENT}, ++ #else ++ {"INVALID_NULL_ARGUMENT", 15, 109}, ++ #endif ++ #ifdef CRYPTO_R_INVALID_OSSL_PARAM_TYPE ++ {"INVALID_OSSL_PARAM_TYPE", ERR_LIB_CRYPTO, CRYPTO_R_INVALID_OSSL_PARAM_TYPE}, ++ #else ++ {"INVALID_OSSL_PARAM_TYPE", 15, 110}, ++ #endif ++ #ifdef CRYPTO_R_NO_PARAMS_TO_MERGE ++ {"NO_PARAMS_TO_MERGE", ERR_LIB_CRYPTO, CRYPTO_R_NO_PARAMS_TO_MERGE}, ++ #else ++ {"NO_PARAMS_TO_MERGE", 15, 131}, ++ #endif ++ #ifdef CRYPTO_R_NO_SPACE_FOR_TERMINATING_NULL ++ {"NO_SPACE_FOR_TERMINATING_NULL", ERR_LIB_CRYPTO, CRYPTO_R_NO_SPACE_FOR_TERMINATING_NULL}, ++ #else ++ {"NO_SPACE_FOR_TERMINATING_NULL", 15, 128}, ++ #endif ++ #ifdef CRYPTO_R_ODD_NUMBER_OF_DIGITS ++ {"ODD_NUMBER_OF_DIGITS", ERR_LIB_CRYPTO, CRYPTO_R_ODD_NUMBER_OF_DIGITS}, ++ #else ++ {"ODD_NUMBER_OF_DIGITS", 15, 103}, ++ #endif ++ #ifdef CRYPTO_R_PARAM_CANNOT_BE_REPRESENTED_EXACTLY ++ {"PARAM_CANNOT_BE_REPRESENTED_EXACTLY", ERR_LIB_CRYPTO, CRYPTO_R_PARAM_CANNOT_BE_REPRESENTED_EXACTLY}, ++ #else ++ {"PARAM_CANNOT_BE_REPRESENTED_EXACTLY", 15, 123}, ++ #endif ++ #ifdef CRYPTO_R_PARAM_NOT_INTEGER_TYPE ++ {"PARAM_NOT_INTEGER_TYPE", ERR_LIB_CRYPTO, CRYPTO_R_PARAM_NOT_INTEGER_TYPE}, ++ #else ++ {"PARAM_NOT_INTEGER_TYPE", 15, 124}, ++ #endif ++ #ifdef CRYPTO_R_PARAM_OF_INCOMPATIBLE_TYPE ++ {"PARAM_OF_INCOMPATIBLE_TYPE", ERR_LIB_CRYPTO, CRYPTO_R_PARAM_OF_INCOMPATIBLE_TYPE}, ++ #else ++ {"PARAM_OF_INCOMPATIBLE_TYPE", 15, 129}, ++ #endif ++ #ifdef CRYPTO_R_PARAM_UNSIGNED_INTEGER_NEGATIVE_VALUE_UNSUPPORTED ++ {"PARAM_UNSIGNED_INTEGER_NEGATIVE_VALUE_UNSUPPORTED", ERR_LIB_CRYPTO, CRYPTO_R_PARAM_UNSIGNED_INTEGER_NEGATIVE_VALUE_UNSUPPORTED}, ++ #else ++ {"PARAM_UNSIGNED_INTEGER_NEGATIVE_VALUE_UNSUPPORTED", 15, 125}, ++ #endif ++ #ifdef CRYPTO_R_PARAM_UNSUPPORTED_FLOATING_POINT_FORMAT ++ {"PARAM_UNSUPPORTED_FLOATING_POINT_FORMAT", ERR_LIB_CRYPTO, CRYPTO_R_PARAM_UNSUPPORTED_FLOATING_POINT_FORMAT}, ++ #else ++ {"PARAM_UNSUPPORTED_FLOATING_POINT_FORMAT", 15, 130}, ++ #endif ++ #ifdef CRYPTO_R_PARAM_VALUE_TOO_LARGE_FOR_DESTINATION ++ {"PARAM_VALUE_TOO_LARGE_FOR_DESTINATION", ERR_LIB_CRYPTO, CRYPTO_R_PARAM_VALUE_TOO_LARGE_FOR_DESTINATION}, ++ #else ++ {"PARAM_VALUE_TOO_LARGE_FOR_DESTINATION", 15, 126}, ++ #endif ++ #ifdef CRYPTO_R_PROVIDER_ALREADY_EXISTS ++ {"PROVIDER_ALREADY_EXISTS", ERR_LIB_CRYPTO, CRYPTO_R_PROVIDER_ALREADY_EXISTS}, ++ #else ++ {"PROVIDER_ALREADY_EXISTS", 15, 104}, ++ #endif ++ #ifdef CRYPTO_R_PROVIDER_SECTION_ERROR ++ {"PROVIDER_SECTION_ERROR", ERR_LIB_CRYPTO, CRYPTO_R_PROVIDER_SECTION_ERROR}, ++ #else ++ {"PROVIDER_SECTION_ERROR", 15, 105}, ++ #endif ++ #ifdef CRYPTO_R_RANDOM_SECTION_ERROR ++ {"RANDOM_SECTION_ERROR", ERR_LIB_CRYPTO, CRYPTO_R_RANDOM_SECTION_ERROR}, ++ #else ++ {"RANDOM_SECTION_ERROR", 15, 119}, ++ #endif ++ #ifdef CRYPTO_R_SECURE_MALLOC_FAILURE ++ {"SECURE_MALLOC_FAILURE", ERR_LIB_CRYPTO, CRYPTO_R_SECURE_MALLOC_FAILURE}, ++ #else ++ {"SECURE_MALLOC_FAILURE", 15, 111}, ++ #endif ++ #ifdef CRYPTO_R_STRING_TOO_LONG ++ {"STRING_TOO_LONG", ERR_LIB_CRYPTO, CRYPTO_R_STRING_TOO_LONG}, ++ #else ++ {"STRING_TOO_LONG", 15, 112}, ++ #endif ++ #ifdef CRYPTO_R_TOO_MANY_BYTES ++ {"TOO_MANY_BYTES", ERR_LIB_CRYPTO, CRYPTO_R_TOO_MANY_BYTES}, ++ #else ++ {"TOO_MANY_BYTES", 15, 113}, ++ #endif ++ #ifdef CRYPTO_R_TOO_MANY_NAMES ++ {"TOO_MANY_NAMES", ERR_LIB_CRYPTO, CRYPTO_R_TOO_MANY_NAMES}, ++ #else ++ {"TOO_MANY_NAMES", 15, 132}, ++ #endif ++ #ifdef CRYPTO_R_TOO_MANY_RECORDS ++ {"TOO_MANY_RECORDS", ERR_LIB_CRYPTO, CRYPTO_R_TOO_MANY_RECORDS}, ++ #else ++ {"TOO_MANY_RECORDS", 15, 114}, ++ #endif ++ #ifdef CRYPTO_R_TOO_SMALL_BUFFER ++ {"TOO_SMALL_BUFFER", ERR_LIB_CRYPTO, CRYPTO_R_TOO_SMALL_BUFFER}, ++ #else ++ {"TOO_SMALL_BUFFER", 15, 116}, ++ #endif ++ #ifdef CRYPTO_R_UNKNOWN_NAME_IN_RANDOM_SECTION ++ {"UNKNOWN_NAME_IN_RANDOM_SECTION", ERR_LIB_CRYPTO, CRYPTO_R_UNKNOWN_NAME_IN_RANDOM_SECTION}, ++ #else ++ {"UNKNOWN_NAME_IN_RANDOM_SECTION", 15, 120}, ++ #endif ++ #ifdef CRYPTO_R_ZERO_LENGTH_NUMBER ++ {"ZERO_LENGTH_NUMBER", ERR_LIB_CRYPTO, CRYPTO_R_ZERO_LENGTH_NUMBER}, ++ #else ++ {"ZERO_LENGTH_NUMBER", 15, 115}, ++ #endif ++ #ifdef CT_R_BASE64_DECODE_ERROR ++ {"BASE64_DECODE_ERROR", ERR_LIB_CT, CT_R_BASE64_DECODE_ERROR}, ++ #else ++ {"BASE64_DECODE_ERROR", 50, 108}, ++ #endif ++ #ifdef CT_R_INVALID_LOG_ID_LENGTH ++ {"INVALID_LOG_ID_LENGTH", ERR_LIB_CT, CT_R_INVALID_LOG_ID_LENGTH}, ++ #else ++ {"INVALID_LOG_ID_LENGTH", 50, 100}, ++ #endif ++ #ifdef CT_R_LOG_CONF_INVALID ++ {"LOG_CONF_INVALID", ERR_LIB_CT, CT_R_LOG_CONF_INVALID}, ++ #else ++ {"LOG_CONF_INVALID", 50, 109}, ++ #endif ++ #ifdef CT_R_LOG_CONF_INVALID_KEY ++ {"LOG_CONF_INVALID_KEY", ERR_LIB_CT, CT_R_LOG_CONF_INVALID_KEY}, ++ #else ++ {"LOG_CONF_INVALID_KEY", 50, 110}, ++ #endif ++ #ifdef CT_R_LOG_CONF_MISSING_DESCRIPTION ++ {"LOG_CONF_MISSING_DESCRIPTION", ERR_LIB_CT, CT_R_LOG_CONF_MISSING_DESCRIPTION}, ++ #else ++ {"LOG_CONF_MISSING_DESCRIPTION", 50, 111}, ++ #endif ++ #ifdef CT_R_LOG_CONF_MISSING_KEY ++ {"LOG_CONF_MISSING_KEY", ERR_LIB_CT, CT_R_LOG_CONF_MISSING_KEY}, ++ #else ++ {"LOG_CONF_MISSING_KEY", 50, 112}, ++ #endif ++ #ifdef CT_R_LOG_KEY_INVALID ++ {"LOG_KEY_INVALID", ERR_LIB_CT, CT_R_LOG_KEY_INVALID}, ++ #else ++ {"LOG_KEY_INVALID", 50, 113}, ++ #endif ++ #ifdef CT_R_SCT_FUTURE_TIMESTAMP ++ {"SCT_FUTURE_TIMESTAMP", ERR_LIB_CT, CT_R_SCT_FUTURE_TIMESTAMP}, ++ #else ++ {"SCT_FUTURE_TIMESTAMP", 50, 116}, ++ #endif ++ #ifdef CT_R_SCT_INVALID ++ {"SCT_INVALID", ERR_LIB_CT, CT_R_SCT_INVALID}, ++ #else ++ {"SCT_INVALID", 50, 104}, ++ #endif ++ #ifdef CT_R_SCT_INVALID_SIGNATURE ++ {"SCT_INVALID_SIGNATURE", ERR_LIB_CT, CT_R_SCT_INVALID_SIGNATURE}, ++ #else ++ {"SCT_INVALID_SIGNATURE", 50, 107}, ++ #endif ++ #ifdef CT_R_SCT_LIST_INVALID ++ {"SCT_LIST_INVALID", ERR_LIB_CT, CT_R_SCT_LIST_INVALID}, ++ #else ++ {"SCT_LIST_INVALID", 50, 105}, ++ #endif ++ #ifdef CT_R_SCT_LOG_ID_MISMATCH ++ {"SCT_LOG_ID_MISMATCH", ERR_LIB_CT, CT_R_SCT_LOG_ID_MISMATCH}, ++ #else ++ {"SCT_LOG_ID_MISMATCH", 50, 114}, ++ #endif ++ #ifdef CT_R_SCT_NOT_SET ++ {"SCT_NOT_SET", ERR_LIB_CT, CT_R_SCT_NOT_SET}, ++ #else ++ {"SCT_NOT_SET", 50, 106}, ++ #endif ++ #ifdef CT_R_SCT_UNSUPPORTED_VERSION ++ {"SCT_UNSUPPORTED_VERSION", ERR_LIB_CT, CT_R_SCT_UNSUPPORTED_VERSION}, ++ #else ++ {"SCT_UNSUPPORTED_VERSION", 50, 115}, ++ #endif ++ #ifdef CT_R_UNRECOGNIZED_SIGNATURE_NID ++ {"UNRECOGNIZED_SIGNATURE_NID", ERR_LIB_CT, CT_R_UNRECOGNIZED_SIGNATURE_NID}, ++ #else ++ {"UNRECOGNIZED_SIGNATURE_NID", 50, 101}, ++ #endif ++ #ifdef CT_R_UNSUPPORTED_ENTRY_TYPE ++ {"UNSUPPORTED_ENTRY_TYPE", ERR_LIB_CT, CT_R_UNSUPPORTED_ENTRY_TYPE}, ++ #else ++ {"UNSUPPORTED_ENTRY_TYPE", 50, 102}, ++ #endif ++ #ifdef CT_R_UNSUPPORTED_VERSION ++ {"UNSUPPORTED_VERSION", ERR_LIB_CT, CT_R_UNSUPPORTED_VERSION}, ++ #else ++ {"UNSUPPORTED_VERSION", 50, 103}, ++ #endif ++ #ifdef DH_R_BAD_FFC_PARAMETERS ++ {"BAD_FFC_PARAMETERS", ERR_LIB_DH, DH_R_BAD_FFC_PARAMETERS}, ++ #else ++ {"BAD_FFC_PARAMETERS", 5, 127}, ++ #endif ++ #ifdef DH_R_BAD_GENERATOR ++ {"BAD_GENERATOR", ERR_LIB_DH, DH_R_BAD_GENERATOR}, ++ #else ++ {"BAD_GENERATOR", 5, 101}, ++ #endif ++ #ifdef DH_R_BN_DECODE_ERROR ++ {"BN_DECODE_ERROR", ERR_LIB_DH, DH_R_BN_DECODE_ERROR}, ++ #else ++ {"BN_DECODE_ERROR", 5, 109}, ++ #endif ++ #ifdef DH_R_BN_ERROR ++ {"BN_ERROR", ERR_LIB_DH, DH_R_BN_ERROR}, ++ #else ++ {"BN_ERROR", 5, 106}, ++ #endif ++ #ifdef DH_R_CHECK_INVALID_J_VALUE ++ {"CHECK_INVALID_J_VALUE", ERR_LIB_DH, DH_R_CHECK_INVALID_J_VALUE}, ++ #else ++ {"CHECK_INVALID_J_VALUE", 5, 115}, ++ #endif ++ #ifdef DH_R_CHECK_INVALID_Q_VALUE ++ {"CHECK_INVALID_Q_VALUE", ERR_LIB_DH, DH_R_CHECK_INVALID_Q_VALUE}, ++ #else ++ {"CHECK_INVALID_Q_VALUE", 5, 116}, ++ #endif ++ #ifdef DH_R_CHECK_PUBKEY_INVALID ++ {"CHECK_PUBKEY_INVALID", ERR_LIB_DH, DH_R_CHECK_PUBKEY_INVALID}, ++ #else ++ {"CHECK_PUBKEY_INVALID", 5, 122}, ++ #endif ++ #ifdef DH_R_CHECK_PUBKEY_TOO_LARGE ++ {"CHECK_PUBKEY_TOO_LARGE", ERR_LIB_DH, DH_R_CHECK_PUBKEY_TOO_LARGE}, ++ #else ++ {"CHECK_PUBKEY_TOO_LARGE", 5, 123}, ++ #endif ++ #ifdef DH_R_CHECK_PUBKEY_TOO_SMALL ++ {"CHECK_PUBKEY_TOO_SMALL", ERR_LIB_DH, DH_R_CHECK_PUBKEY_TOO_SMALL}, ++ #else ++ {"CHECK_PUBKEY_TOO_SMALL", 5, 124}, ++ #endif ++ #ifdef DH_R_CHECK_P_NOT_PRIME ++ {"CHECK_P_NOT_PRIME", ERR_LIB_DH, DH_R_CHECK_P_NOT_PRIME}, ++ #else ++ {"CHECK_P_NOT_PRIME", 5, 117}, ++ #endif ++ #ifdef DH_R_CHECK_P_NOT_SAFE_PRIME ++ {"CHECK_P_NOT_SAFE_PRIME", ERR_LIB_DH, DH_R_CHECK_P_NOT_SAFE_PRIME}, ++ #else ++ {"CHECK_P_NOT_SAFE_PRIME", 5, 118}, ++ #endif ++ #ifdef DH_R_CHECK_Q_NOT_PRIME ++ {"CHECK_Q_NOT_PRIME", ERR_LIB_DH, DH_R_CHECK_Q_NOT_PRIME}, ++ #else ++ {"CHECK_Q_NOT_PRIME", 5, 119}, ++ #endif ++ #ifdef DH_R_DECODE_ERROR ++ {"DECODE_ERROR", ERR_LIB_DH, DH_R_DECODE_ERROR}, ++ #else ++ {"DECODE_ERROR", 5, 104}, ++ #endif ++ #ifdef DH_R_INVALID_PARAMETER_NAME ++ {"INVALID_PARAMETER_NAME", ERR_LIB_DH, DH_R_INVALID_PARAMETER_NAME}, ++ #else ++ {"INVALID_PARAMETER_NAME", 5, 110}, ++ #endif ++ #ifdef DH_R_INVALID_PARAMETER_NID ++ {"INVALID_PARAMETER_NID", ERR_LIB_DH, DH_R_INVALID_PARAMETER_NID}, ++ #else ++ {"INVALID_PARAMETER_NID", 5, 114}, ++ #endif ++ #ifdef DH_R_INVALID_PUBKEY ++ {"INVALID_PUBKEY", ERR_LIB_DH, DH_R_INVALID_PUBKEY}, ++ #else ++ {"INVALID_PUBKEY", 5, 102}, ++ #endif ++ #ifdef DH_R_INVALID_SECRET ++ {"INVALID_SECRET", ERR_LIB_DH, DH_R_INVALID_SECRET}, ++ #else ++ {"INVALID_SECRET", 5, 128}, ++ #endif ++ #ifdef DH_R_INVALID_SIZE ++ {"INVALID_SIZE", ERR_LIB_DH, DH_R_INVALID_SIZE}, ++ #else ++ {"INVALID_SIZE", 5, 129}, ++ #endif ++ #ifdef DH_R_KDF_PARAMETER_ERROR ++ {"KDF_PARAMETER_ERROR", ERR_LIB_DH, DH_R_KDF_PARAMETER_ERROR}, ++ #else ++ {"KDF_PARAMETER_ERROR", 5, 112}, ++ #endif ++ #ifdef DH_R_KEYS_NOT_SET ++ {"KEYS_NOT_SET", ERR_LIB_DH, DH_R_KEYS_NOT_SET}, ++ #else ++ {"KEYS_NOT_SET", 5, 108}, ++ #endif ++ #ifdef DH_R_MISSING_PUBKEY ++ {"MISSING_PUBKEY", ERR_LIB_DH, DH_R_MISSING_PUBKEY}, ++ #else ++ {"MISSING_PUBKEY", 5, 125}, ++ #endif ++ #ifdef DH_R_MODULUS_TOO_LARGE ++ {"MODULUS_TOO_LARGE", ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE}, ++ #else ++ {"MODULUS_TOO_LARGE", 5, 103}, ++ #endif ++ #ifdef DH_R_MODULUS_TOO_SMALL ++ {"MODULUS_TOO_SMALL", ERR_LIB_DH, DH_R_MODULUS_TOO_SMALL}, ++ #else ++ {"MODULUS_TOO_SMALL", 5, 126}, ++ #endif ++ #ifdef DH_R_NOT_SUITABLE_GENERATOR ++ {"NOT_SUITABLE_GENERATOR", ERR_LIB_DH, DH_R_NOT_SUITABLE_GENERATOR}, ++ #else ++ {"NOT_SUITABLE_GENERATOR", 5, 120}, ++ #endif ++ #ifdef DH_R_NO_PARAMETERS_SET ++ {"NO_PARAMETERS_SET", ERR_LIB_DH, DH_R_NO_PARAMETERS_SET}, ++ #else ++ {"NO_PARAMETERS_SET", 5, 107}, ++ #endif ++ #ifdef DH_R_NO_PRIVATE_VALUE ++ {"NO_PRIVATE_VALUE", ERR_LIB_DH, DH_R_NO_PRIVATE_VALUE}, ++ #else ++ {"NO_PRIVATE_VALUE", 5, 100}, ++ #endif ++ #ifdef DH_R_PARAMETER_ENCODING_ERROR ++ {"PARAMETER_ENCODING_ERROR", ERR_LIB_DH, DH_R_PARAMETER_ENCODING_ERROR}, ++ #else ++ {"PARAMETER_ENCODING_ERROR", 5, 105}, ++ #endif ++ #ifdef DH_R_PEER_KEY_ERROR ++ {"PEER_KEY_ERROR", ERR_LIB_DH, DH_R_PEER_KEY_ERROR}, ++ #else ++ {"PEER_KEY_ERROR", 5, 111}, ++ #endif ++ #ifdef DH_R_Q_TOO_LARGE ++ {"Q_TOO_LARGE", ERR_LIB_DH, DH_R_Q_TOO_LARGE}, ++ #else ++ {"Q_TOO_LARGE", 5, 130}, ++ #endif ++ #ifdef DH_R_SHARED_INFO_ERROR ++ {"SHARED_INFO_ERROR", ERR_LIB_DH, DH_R_SHARED_INFO_ERROR}, ++ #else ++ {"SHARED_INFO_ERROR", 5, 113}, ++ #endif ++ #ifdef DH_R_UNABLE_TO_CHECK_GENERATOR ++ {"UNABLE_TO_CHECK_GENERATOR", ERR_LIB_DH, DH_R_UNABLE_TO_CHECK_GENERATOR}, ++ #else ++ {"UNABLE_TO_CHECK_GENERATOR", 5, 121}, ++ #endif ++ #ifdef DSA_R_BAD_FFC_PARAMETERS ++ {"BAD_FFC_PARAMETERS", ERR_LIB_DSA, DSA_R_BAD_FFC_PARAMETERS}, ++ #else ++ {"BAD_FFC_PARAMETERS", 10, 114}, ++ #endif ++ #ifdef DSA_R_BAD_Q_VALUE ++ {"BAD_Q_VALUE", ERR_LIB_DSA, DSA_R_BAD_Q_VALUE}, ++ #else ++ {"BAD_Q_VALUE", 10, 102}, ++ #endif ++ #ifdef DSA_R_BN_DECODE_ERROR ++ {"BN_DECODE_ERROR", ERR_LIB_DSA, DSA_R_BN_DECODE_ERROR}, ++ #else ++ {"BN_DECODE_ERROR", 10, 108}, ++ #endif ++ #ifdef DSA_R_BN_ERROR ++ {"BN_ERROR", ERR_LIB_DSA, DSA_R_BN_ERROR}, ++ #else ++ {"BN_ERROR", 10, 109}, ++ #endif ++ #ifdef DSA_R_DECODE_ERROR ++ {"DECODE_ERROR", ERR_LIB_DSA, DSA_R_DECODE_ERROR}, ++ #else ++ {"DECODE_ERROR", 10, 104}, ++ #endif ++ #ifdef DSA_R_INVALID_DIGEST_TYPE ++ {"INVALID_DIGEST_TYPE", ERR_LIB_DSA, DSA_R_INVALID_DIGEST_TYPE}, ++ #else ++ {"INVALID_DIGEST_TYPE", 10, 106}, ++ #endif ++ #ifdef DSA_R_INVALID_PARAMETERS ++ {"INVALID_PARAMETERS", ERR_LIB_DSA, DSA_R_INVALID_PARAMETERS}, ++ #else ++ {"INVALID_PARAMETERS", 10, 112}, ++ #endif ++ #ifdef DSA_R_MISSING_PARAMETERS ++ {"MISSING_PARAMETERS", ERR_LIB_DSA, DSA_R_MISSING_PARAMETERS}, ++ #else ++ {"MISSING_PARAMETERS", 10, 101}, ++ #endif ++ #ifdef DSA_R_MISSING_PRIVATE_KEY ++ {"MISSING_PRIVATE_KEY", ERR_LIB_DSA, DSA_R_MISSING_PRIVATE_KEY}, ++ #else ++ {"MISSING_PRIVATE_KEY", 10, 111}, ++ #endif ++ #ifdef DSA_R_MODULUS_TOO_LARGE ++ {"MODULUS_TOO_LARGE", ERR_LIB_DSA, DSA_R_MODULUS_TOO_LARGE}, ++ #else ++ {"MODULUS_TOO_LARGE", 10, 103}, ++ #endif ++ #ifdef DSA_R_NO_PARAMETERS_SET ++ {"NO_PARAMETERS_SET", ERR_LIB_DSA, DSA_R_NO_PARAMETERS_SET}, ++ #else ++ {"NO_PARAMETERS_SET", 10, 107}, ++ #endif ++ #ifdef DSA_R_PARAMETER_ENCODING_ERROR ++ {"PARAMETER_ENCODING_ERROR", ERR_LIB_DSA, DSA_R_PARAMETER_ENCODING_ERROR}, ++ #else ++ {"PARAMETER_ENCODING_ERROR", 10, 105}, ++ #endif ++ #ifdef DSA_R_P_NOT_PRIME ++ {"P_NOT_PRIME", ERR_LIB_DSA, DSA_R_P_NOT_PRIME}, ++ #else ++ {"P_NOT_PRIME", 10, 115}, ++ #endif ++ #ifdef DSA_R_Q_NOT_PRIME ++ {"Q_NOT_PRIME", ERR_LIB_DSA, DSA_R_Q_NOT_PRIME}, ++ #else ++ {"Q_NOT_PRIME", 10, 113}, ++ #endif ++ #ifdef DSA_R_SEED_LEN_SMALL ++ {"SEED_LEN_SMALL", ERR_LIB_DSA, DSA_R_SEED_LEN_SMALL}, ++ #else ++ {"SEED_LEN_SMALL", 10, 110}, ++ #endif ++ #ifdef DSA_R_TOO_MANY_RETRIES ++ {"TOO_MANY_RETRIES", ERR_LIB_DSA, DSA_R_TOO_MANY_RETRIES}, ++ #else ++ {"TOO_MANY_RETRIES", 10, 116}, ++ #endif ++ #ifdef DSO_R_CTRL_FAILED ++ {"CTRL_FAILED", ERR_LIB_DSO, DSO_R_CTRL_FAILED}, ++ #else ++ {"CTRL_FAILED", 37, 100}, ++ #endif ++ #ifdef DSO_R_DSO_ALREADY_LOADED ++ {"DSO_ALREADY_LOADED", ERR_LIB_DSO, DSO_R_DSO_ALREADY_LOADED}, ++ #else ++ {"DSO_ALREADY_LOADED", 37, 110}, ++ #endif ++ #ifdef DSO_R_EMPTY_FILE_STRUCTURE ++ {"EMPTY_FILE_STRUCTURE", ERR_LIB_DSO, DSO_R_EMPTY_FILE_STRUCTURE}, ++ #else ++ {"EMPTY_FILE_STRUCTURE", 37, 113}, ++ #endif ++ #ifdef DSO_R_FAILURE ++ {"FAILURE", ERR_LIB_DSO, DSO_R_FAILURE}, ++ #else ++ {"FAILURE", 37, 114}, ++ #endif ++ #ifdef DSO_R_FILENAME_TOO_BIG ++ {"FILENAME_TOO_BIG", ERR_LIB_DSO, DSO_R_FILENAME_TOO_BIG}, ++ #else ++ {"FILENAME_TOO_BIG", 37, 101}, ++ #endif ++ #ifdef DSO_R_FINISH_FAILED ++ {"FINISH_FAILED", ERR_LIB_DSO, DSO_R_FINISH_FAILED}, ++ #else ++ {"FINISH_FAILED", 37, 102}, ++ #endif ++ #ifdef DSO_R_INCORRECT_FILE_SYNTAX ++ {"INCORRECT_FILE_SYNTAX", ERR_LIB_DSO, DSO_R_INCORRECT_FILE_SYNTAX}, ++ #else ++ {"INCORRECT_FILE_SYNTAX", 37, 115}, ++ #endif ++ #ifdef DSO_R_LOAD_FAILED ++ {"LOAD_FAILED", ERR_LIB_DSO, DSO_R_LOAD_FAILED}, ++ #else ++ {"LOAD_FAILED", 37, 103}, ++ #endif ++ #ifdef DSO_R_NAME_TRANSLATION_FAILED ++ {"NAME_TRANSLATION_FAILED", ERR_LIB_DSO, DSO_R_NAME_TRANSLATION_FAILED}, ++ #else ++ {"NAME_TRANSLATION_FAILED", 37, 109}, ++ #endif ++ #ifdef DSO_R_NO_FILENAME ++ {"NO_FILENAME", ERR_LIB_DSO, DSO_R_NO_FILENAME}, ++ #else ++ {"NO_FILENAME", 37, 111}, ++ #endif ++ #ifdef DSO_R_NULL_HANDLE ++ {"NULL_HANDLE", ERR_LIB_DSO, DSO_R_NULL_HANDLE}, ++ #else ++ {"NULL_HANDLE", 37, 104}, ++ #endif ++ #ifdef DSO_R_SET_FILENAME_FAILED ++ {"SET_FILENAME_FAILED", ERR_LIB_DSO, DSO_R_SET_FILENAME_FAILED}, ++ #else ++ {"SET_FILENAME_FAILED", 37, 112}, ++ #endif ++ #ifdef DSO_R_STACK_ERROR ++ {"STACK_ERROR", ERR_LIB_DSO, DSO_R_STACK_ERROR}, ++ #else ++ {"STACK_ERROR", 37, 105}, ++ #endif ++ #ifdef DSO_R_SYM_FAILURE ++ {"SYM_FAILURE", ERR_LIB_DSO, DSO_R_SYM_FAILURE}, ++ #else ++ {"SYM_FAILURE", 37, 106}, ++ #endif ++ #ifdef DSO_R_UNLOAD_FAILED ++ {"UNLOAD_FAILED", ERR_LIB_DSO, DSO_R_UNLOAD_FAILED}, ++ #else ++ {"UNLOAD_FAILED", 37, 107}, ++ #endif ++ #ifdef DSO_R_UNSUPPORTED ++ {"UNSUPPORTED", ERR_LIB_DSO, DSO_R_UNSUPPORTED}, ++ #else ++ {"UNSUPPORTED", 37, 108}, ++ #endif ++ #ifdef EC_R_ASN1_ERROR ++ {"ASN1_ERROR", ERR_LIB_EC, EC_R_ASN1_ERROR}, ++ #else ++ {"ASN1_ERROR", 16, 115}, ++ #endif ++ #ifdef EC_R_BAD_SIGNATURE ++ {"BAD_SIGNATURE", ERR_LIB_EC, EC_R_BAD_SIGNATURE}, ++ #else ++ {"BAD_SIGNATURE", 16, 156}, ++ #endif ++ #ifdef EC_R_BIGNUM_OUT_OF_RANGE ++ {"BIGNUM_OUT_OF_RANGE", ERR_LIB_EC, EC_R_BIGNUM_OUT_OF_RANGE}, ++ #else ++ {"BIGNUM_OUT_OF_RANGE", 16, 144}, ++ #endif ++ #ifdef EC_R_BUFFER_TOO_SMALL ++ {"BUFFER_TOO_SMALL", ERR_LIB_EC, EC_R_BUFFER_TOO_SMALL}, ++ #else ++ {"BUFFER_TOO_SMALL", 16, 100}, ++ #endif ++ #ifdef EC_R_CANNOT_INVERT ++ {"CANNOT_INVERT", ERR_LIB_EC, EC_R_CANNOT_INVERT}, ++ #else ++ {"CANNOT_INVERT", 16, 165}, ++ #endif ++ #ifdef EC_R_COORDINATES_OUT_OF_RANGE ++ {"COORDINATES_OUT_OF_RANGE", ERR_LIB_EC, EC_R_COORDINATES_OUT_OF_RANGE}, ++ #else ++ {"COORDINATES_OUT_OF_RANGE", 16, 146}, ++ #endif ++ #ifdef EC_R_CURVE_DOES_NOT_SUPPORT_ECDH ++ {"CURVE_DOES_NOT_SUPPORT_ECDH", ERR_LIB_EC, EC_R_CURVE_DOES_NOT_SUPPORT_ECDH}, ++ #else ++ {"CURVE_DOES_NOT_SUPPORT_ECDH", 16, 160}, ++ #endif ++ #ifdef EC_R_CURVE_DOES_NOT_SUPPORT_ECDSA ++ {"CURVE_DOES_NOT_SUPPORT_ECDSA", ERR_LIB_EC, EC_R_CURVE_DOES_NOT_SUPPORT_ECDSA}, ++ #else ++ {"CURVE_DOES_NOT_SUPPORT_ECDSA", 16, 170}, ++ #endif ++ #ifdef EC_R_CURVE_DOES_NOT_SUPPORT_SIGNING ++ {"CURVE_DOES_NOT_SUPPORT_SIGNING", ERR_LIB_EC, EC_R_CURVE_DOES_NOT_SUPPORT_SIGNING}, ++ #else ++ {"CURVE_DOES_NOT_SUPPORT_SIGNING", 16, 159}, ++ #endif ++ #ifdef EC_R_DECODE_ERROR ++ {"DECODE_ERROR", ERR_LIB_EC, EC_R_DECODE_ERROR}, ++ #else ++ {"DECODE_ERROR", 16, 142}, ++ #endif ++ #ifdef EC_R_DISCRIMINANT_IS_ZERO ++ {"DISCRIMINANT_IS_ZERO", ERR_LIB_EC, EC_R_DISCRIMINANT_IS_ZERO}, ++ #else ++ {"DISCRIMINANT_IS_ZERO", 16, 118}, ++ #endif ++ #ifdef EC_R_EC_GROUP_NEW_BY_NAME_FAILURE ++ {"EC_GROUP_NEW_BY_NAME_FAILURE", ERR_LIB_EC, EC_R_EC_GROUP_NEW_BY_NAME_FAILURE}, ++ #else ++ {"EC_GROUP_NEW_BY_NAME_FAILURE", 16, 119}, ++ #endif ++ #ifdef EC_R_EXPLICIT_PARAMS_NOT_SUPPORTED ++ {"EXPLICIT_PARAMS_NOT_SUPPORTED", ERR_LIB_EC, EC_R_EXPLICIT_PARAMS_NOT_SUPPORTED}, ++ #else ++ {"EXPLICIT_PARAMS_NOT_SUPPORTED", 16, 127}, ++ #endif ++ #ifdef EC_R_FAILED_MAKING_PUBLIC_KEY ++ {"FAILED_MAKING_PUBLIC_KEY", ERR_LIB_EC, EC_R_FAILED_MAKING_PUBLIC_KEY}, ++ #else ++ {"FAILED_MAKING_PUBLIC_KEY", 16, 166}, ++ #endif ++ #ifdef EC_R_FIELD_TOO_LARGE ++ {"FIELD_TOO_LARGE", ERR_LIB_EC, EC_R_FIELD_TOO_LARGE}, ++ #else ++ {"FIELD_TOO_LARGE", 16, 143}, ++ #endif ++ #ifdef EC_R_GF2M_NOT_SUPPORTED ++ {"GF2M_NOT_SUPPORTED", ERR_LIB_EC, EC_R_GF2M_NOT_SUPPORTED}, ++ #else ++ {"GF2M_NOT_SUPPORTED", 16, 147}, ++ #endif ++ #ifdef EC_R_GROUP2PKPARAMETERS_FAILURE ++ {"GROUP2PKPARAMETERS_FAILURE", ERR_LIB_EC, EC_R_GROUP2PKPARAMETERS_FAILURE}, ++ #else ++ {"GROUP2PKPARAMETERS_FAILURE", 16, 120}, ++ #endif ++ #ifdef EC_R_I2D_ECPKPARAMETERS_FAILURE ++ {"I2D_ECPKPARAMETERS_FAILURE", ERR_LIB_EC, EC_R_I2D_ECPKPARAMETERS_FAILURE}, ++ #else ++ {"I2D_ECPKPARAMETERS_FAILURE", 16, 121}, ++ #endif ++ #ifdef EC_R_INCOMPATIBLE_OBJECTS ++ {"INCOMPATIBLE_OBJECTS", ERR_LIB_EC, EC_R_INCOMPATIBLE_OBJECTS}, ++ #else ++ {"INCOMPATIBLE_OBJECTS", 16, 101}, ++ #endif ++ #ifdef EC_R_INVALID_A ++ {"INVALID_A", ERR_LIB_EC, EC_R_INVALID_A}, ++ #else ++ {"INVALID_A", 16, 168}, ++ #endif ++ #ifdef EC_R_INVALID_ARGUMENT ++ {"INVALID_ARGUMENT", ERR_LIB_EC, EC_R_INVALID_ARGUMENT}, ++ #else ++ {"INVALID_ARGUMENT", 16, 112}, ++ #endif ++ #ifdef EC_R_INVALID_B ++ {"INVALID_B", ERR_LIB_EC, EC_R_INVALID_B}, ++ #else ++ {"INVALID_B", 16, 169}, ++ #endif ++ #ifdef EC_R_INVALID_COFACTOR ++ {"INVALID_COFACTOR", ERR_LIB_EC, EC_R_INVALID_COFACTOR}, ++ #else ++ {"INVALID_COFACTOR", 16, 171}, ++ #endif ++ #ifdef EC_R_INVALID_COMPRESSED_POINT ++ {"INVALID_COMPRESSED_POINT", ERR_LIB_EC, EC_R_INVALID_COMPRESSED_POINT}, ++ #else ++ {"INVALID_COMPRESSED_POINT", 16, 110}, ++ #endif ++ #ifdef EC_R_INVALID_COMPRESSION_BIT ++ {"INVALID_COMPRESSION_BIT", ERR_LIB_EC, EC_R_INVALID_COMPRESSION_BIT}, ++ #else ++ {"INVALID_COMPRESSION_BIT", 16, 109}, ++ #endif ++ #ifdef EC_R_INVALID_CURVE ++ {"INVALID_CURVE", ERR_LIB_EC, EC_R_INVALID_CURVE}, ++ #else ++ {"INVALID_CURVE", 16, 141}, ++ #endif ++ #ifdef EC_R_INVALID_DIGEST ++ {"INVALID_DIGEST", ERR_LIB_EC, EC_R_INVALID_DIGEST}, ++ #else ++ {"INVALID_DIGEST", 16, 151}, ++ #endif ++ #ifdef EC_R_INVALID_DIGEST_TYPE ++ {"INVALID_DIGEST_TYPE", ERR_LIB_EC, EC_R_INVALID_DIGEST_TYPE}, ++ #else ++ {"INVALID_DIGEST_TYPE", 16, 138}, ++ #endif ++ #ifdef EC_R_INVALID_ENCODING ++ {"INVALID_ENCODING", ERR_LIB_EC, EC_R_INVALID_ENCODING}, ++ #else ++ {"INVALID_ENCODING", 16, 102}, ++ #endif ++ #ifdef EC_R_INVALID_FIELD ++ {"INVALID_FIELD", ERR_LIB_EC, EC_R_INVALID_FIELD}, ++ #else ++ {"INVALID_FIELD", 16, 103}, ++ #endif ++ #ifdef EC_R_INVALID_FORM ++ {"INVALID_FORM", ERR_LIB_EC, EC_R_INVALID_FORM}, ++ #else ++ {"INVALID_FORM", 16, 104}, ++ #endif ++ #ifdef EC_R_INVALID_GENERATOR ++ {"INVALID_GENERATOR", ERR_LIB_EC, EC_R_INVALID_GENERATOR}, ++ #else ++ {"INVALID_GENERATOR", 16, 173}, ++ #endif ++ #ifdef EC_R_INVALID_GROUP_ORDER ++ {"INVALID_GROUP_ORDER", ERR_LIB_EC, EC_R_INVALID_GROUP_ORDER}, ++ #else ++ {"INVALID_GROUP_ORDER", 16, 122}, ++ #endif ++ #ifdef EC_R_INVALID_KEY ++ {"INVALID_KEY", ERR_LIB_EC, EC_R_INVALID_KEY}, ++ #else ++ {"INVALID_KEY", 16, 116}, ++ #endif ++ #ifdef EC_R_INVALID_LENGTH ++ {"INVALID_LENGTH", ERR_LIB_EC, EC_R_INVALID_LENGTH}, ++ #else ++ {"INVALID_LENGTH", 16, 117}, ++ #endif ++ #ifdef EC_R_INVALID_NAMED_GROUP_CONVERSION ++ {"INVALID_NAMED_GROUP_CONVERSION", ERR_LIB_EC, EC_R_INVALID_NAMED_GROUP_CONVERSION}, ++ #else ++ {"INVALID_NAMED_GROUP_CONVERSION", 16, 174}, ++ #endif ++ #ifdef EC_R_INVALID_OUTPUT_LENGTH ++ {"INVALID_OUTPUT_LENGTH", ERR_LIB_EC, EC_R_INVALID_OUTPUT_LENGTH}, ++ #else ++ {"INVALID_OUTPUT_LENGTH", 16, 161}, ++ #endif ++ #ifdef EC_R_INVALID_P ++ {"INVALID_P", ERR_LIB_EC, EC_R_INVALID_P}, ++ #else ++ {"INVALID_P", 16, 172}, ++ #endif ++ #ifdef EC_R_INVALID_PEER_KEY ++ {"INVALID_PEER_KEY", ERR_LIB_EC, EC_R_INVALID_PEER_KEY}, ++ #else ++ {"INVALID_PEER_KEY", 16, 133}, ++ #endif ++ #ifdef EC_R_INVALID_PENTANOMIAL_BASIS ++ {"INVALID_PENTANOMIAL_BASIS", ERR_LIB_EC, EC_R_INVALID_PENTANOMIAL_BASIS}, ++ #else ++ {"INVALID_PENTANOMIAL_BASIS", 16, 132}, ++ #endif ++ #ifdef EC_R_INVALID_PRIVATE_KEY ++ {"INVALID_PRIVATE_KEY", ERR_LIB_EC, EC_R_INVALID_PRIVATE_KEY}, ++ #else ++ {"INVALID_PRIVATE_KEY", 16, 123}, ++ #endif ++ #ifdef EC_R_INVALID_SEED ++ {"INVALID_SEED", ERR_LIB_EC, EC_R_INVALID_SEED}, ++ #else ++ {"INVALID_SEED", 16, 175}, ++ #endif ++ #ifdef EC_R_INVALID_TRINOMIAL_BASIS ++ {"INVALID_TRINOMIAL_BASIS", ERR_LIB_EC, EC_R_INVALID_TRINOMIAL_BASIS}, ++ #else ++ {"INVALID_TRINOMIAL_BASIS", 16, 137}, ++ #endif ++ #ifdef EC_R_KDF_PARAMETER_ERROR ++ {"KDF_PARAMETER_ERROR", ERR_LIB_EC, EC_R_KDF_PARAMETER_ERROR}, ++ #else ++ {"KDF_PARAMETER_ERROR", 16, 148}, ++ #endif ++ #ifdef EC_R_KEYS_NOT_SET ++ {"KEYS_NOT_SET", ERR_LIB_EC, EC_R_KEYS_NOT_SET}, ++ #else ++ {"KEYS_NOT_SET", 16, 140}, ++ #endif ++ #ifdef EC_R_LADDER_POST_FAILURE ++ {"LADDER_POST_FAILURE", ERR_LIB_EC, EC_R_LADDER_POST_FAILURE}, ++ #else ++ {"LADDER_POST_FAILURE", 16, 136}, ++ #endif ++ #ifdef EC_R_LADDER_PRE_FAILURE ++ {"LADDER_PRE_FAILURE", ERR_LIB_EC, EC_R_LADDER_PRE_FAILURE}, ++ #else ++ {"LADDER_PRE_FAILURE", 16, 153}, ++ #endif ++ #ifdef EC_R_LADDER_STEP_FAILURE ++ {"LADDER_STEP_FAILURE", ERR_LIB_EC, EC_R_LADDER_STEP_FAILURE}, ++ #else ++ {"LADDER_STEP_FAILURE", 16, 162}, ++ #endif ++ #ifdef EC_R_MISSING_OID ++ {"MISSING_OID", ERR_LIB_EC, EC_R_MISSING_OID}, ++ #else ++ {"MISSING_OID", 16, 167}, ++ #endif ++ #ifdef EC_R_MISSING_PARAMETERS ++ {"MISSING_PARAMETERS", ERR_LIB_EC, EC_R_MISSING_PARAMETERS}, ++ #else ++ {"MISSING_PARAMETERS", 16, 124}, ++ #endif ++ #ifdef EC_R_MISSING_PRIVATE_KEY ++ {"MISSING_PRIVATE_KEY", ERR_LIB_EC, EC_R_MISSING_PRIVATE_KEY}, ++ #else ++ {"MISSING_PRIVATE_KEY", 16, 125}, ++ #endif ++ #ifdef EC_R_NEED_NEW_SETUP_VALUES ++ {"NEED_NEW_SETUP_VALUES", ERR_LIB_EC, EC_R_NEED_NEW_SETUP_VALUES}, ++ #else ++ {"NEED_NEW_SETUP_VALUES", 16, 157}, ++ #endif ++ #ifdef EC_R_NOT_A_NIST_PRIME ++ {"NOT_A_NIST_PRIME", ERR_LIB_EC, EC_R_NOT_A_NIST_PRIME}, ++ #else ++ {"NOT_A_NIST_PRIME", 16, 135}, ++ #endif ++ #ifdef EC_R_NOT_IMPLEMENTED ++ {"NOT_IMPLEMENTED", ERR_LIB_EC, EC_R_NOT_IMPLEMENTED}, ++ #else ++ {"NOT_IMPLEMENTED", 16, 126}, ++ #endif ++ #ifdef EC_R_NOT_INITIALIZED ++ {"NOT_INITIALIZED", ERR_LIB_EC, EC_R_NOT_INITIALIZED}, ++ #else ++ {"NOT_INITIALIZED", 16, 111}, ++ #endif ++ #ifdef EC_R_NO_PARAMETERS_SET ++ {"NO_PARAMETERS_SET", ERR_LIB_EC, EC_R_NO_PARAMETERS_SET}, ++ #else ++ {"NO_PARAMETERS_SET", 16, 139}, ++ #endif ++ #ifdef EC_R_NO_PRIVATE_VALUE ++ {"NO_PRIVATE_VALUE", ERR_LIB_EC, EC_R_NO_PRIVATE_VALUE}, ++ #else ++ {"NO_PRIVATE_VALUE", 16, 154}, ++ #endif ++ #ifdef EC_R_OPERATION_NOT_SUPPORTED ++ {"OPERATION_NOT_SUPPORTED", ERR_LIB_EC, EC_R_OPERATION_NOT_SUPPORTED}, ++ #else ++ {"OPERATION_NOT_SUPPORTED", 16, 152}, ++ #endif ++ #ifdef EC_R_PASSED_NULL_PARAMETER ++ {"PASSED_NULL_PARAMETER", ERR_LIB_EC, EC_R_PASSED_NULL_PARAMETER}, ++ #else ++ {"PASSED_NULL_PARAMETER", 16, 134}, ++ #endif ++ #ifdef EC_R_PEER_KEY_ERROR ++ {"PEER_KEY_ERROR", ERR_LIB_EC, EC_R_PEER_KEY_ERROR}, ++ #else ++ {"PEER_KEY_ERROR", 16, 149}, ++ #endif ++ #ifdef EC_R_POINT_ARITHMETIC_FAILURE ++ {"POINT_ARITHMETIC_FAILURE", ERR_LIB_EC, EC_R_POINT_ARITHMETIC_FAILURE}, ++ #else ++ {"POINT_ARITHMETIC_FAILURE", 16, 155}, ++ #endif ++ #ifdef EC_R_POINT_AT_INFINITY ++ {"POINT_AT_INFINITY", ERR_LIB_EC, EC_R_POINT_AT_INFINITY}, ++ #else ++ {"POINT_AT_INFINITY", 16, 106}, ++ #endif ++ #ifdef EC_R_POINT_COORDINATES_BLIND_FAILURE ++ {"POINT_COORDINATES_BLIND_FAILURE", ERR_LIB_EC, EC_R_POINT_COORDINATES_BLIND_FAILURE}, ++ #else ++ {"POINT_COORDINATES_BLIND_FAILURE", 16, 163}, ++ #endif ++ #ifdef EC_R_POINT_IS_NOT_ON_CURVE ++ {"POINT_IS_NOT_ON_CURVE", ERR_LIB_EC, EC_R_POINT_IS_NOT_ON_CURVE}, ++ #else ++ {"POINT_IS_NOT_ON_CURVE", 16, 107}, ++ #endif ++ #ifdef EC_R_RANDOM_NUMBER_GENERATION_FAILED ++ {"RANDOM_NUMBER_GENERATION_FAILED", ERR_LIB_EC, EC_R_RANDOM_NUMBER_GENERATION_FAILED}, ++ #else ++ {"RANDOM_NUMBER_GENERATION_FAILED", 16, 158}, ++ #endif ++ #ifdef EC_R_SHARED_INFO_ERROR ++ {"SHARED_INFO_ERROR", ERR_LIB_EC, EC_R_SHARED_INFO_ERROR}, ++ #else ++ {"SHARED_INFO_ERROR", 16, 150}, ++ #endif ++ #ifdef EC_R_SLOT_FULL ++ {"SLOT_FULL", ERR_LIB_EC, EC_R_SLOT_FULL}, ++ #else ++ {"SLOT_FULL", 16, 108}, ++ #endif ++ #ifdef EC_R_TOO_MANY_RETRIES ++ {"TOO_MANY_RETRIES", ERR_LIB_EC, EC_R_TOO_MANY_RETRIES}, ++ #else ++ {"TOO_MANY_RETRIES", 16, 176}, ++ #endif ++ #ifdef EC_R_UNDEFINED_GENERATOR ++ {"UNDEFINED_GENERATOR", ERR_LIB_EC, EC_R_UNDEFINED_GENERATOR}, ++ #else ++ {"UNDEFINED_GENERATOR", 16, 113}, ++ #endif ++ #ifdef EC_R_UNDEFINED_ORDER ++ {"UNDEFINED_ORDER", ERR_LIB_EC, EC_R_UNDEFINED_ORDER}, ++ #else ++ {"UNDEFINED_ORDER", 16, 128}, ++ #endif ++ #ifdef EC_R_UNKNOWN_COFACTOR ++ {"UNKNOWN_COFACTOR", ERR_LIB_EC, EC_R_UNKNOWN_COFACTOR}, ++ #else ++ {"UNKNOWN_COFACTOR", 16, 164}, ++ #endif ++ #ifdef EC_R_UNKNOWN_GROUP ++ {"UNKNOWN_GROUP", ERR_LIB_EC, EC_R_UNKNOWN_GROUP}, ++ #else ++ {"UNKNOWN_GROUP", 16, 129}, ++ #endif ++ #ifdef EC_R_UNKNOWN_ORDER ++ {"UNKNOWN_ORDER", ERR_LIB_EC, EC_R_UNKNOWN_ORDER}, ++ #else ++ {"UNKNOWN_ORDER", 16, 114}, ++ #endif ++ #ifdef EC_R_UNSUPPORTED_FIELD ++ {"UNSUPPORTED_FIELD", ERR_LIB_EC, EC_R_UNSUPPORTED_FIELD}, ++ #else ++ {"UNSUPPORTED_FIELD", 16, 131}, ++ #endif ++ #ifdef EC_R_WRONG_CURVE_PARAMETERS ++ {"WRONG_CURVE_PARAMETERS", ERR_LIB_EC, EC_R_WRONG_CURVE_PARAMETERS}, ++ #else ++ {"WRONG_CURVE_PARAMETERS", 16, 145}, ++ #endif ++ #ifdef EC_R_WRONG_ORDER ++ {"WRONG_ORDER", ERR_LIB_EC, EC_R_WRONG_ORDER}, ++ #else ++ {"WRONG_ORDER", 16, 130}, ++ #endif ++ #ifdef ENGINE_R_ALREADY_LOADED ++ {"ALREADY_LOADED", ERR_LIB_ENGINE, ENGINE_R_ALREADY_LOADED}, ++ #else ++ {"ALREADY_LOADED", 38, 100}, ++ #endif ++ #ifdef ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER ++ {"ARGUMENT_IS_NOT_A_NUMBER", ERR_LIB_ENGINE, ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER}, ++ #else ++ {"ARGUMENT_IS_NOT_A_NUMBER", 38, 133}, ++ #endif ++ #ifdef ENGINE_R_CMD_NOT_EXECUTABLE ++ {"CMD_NOT_EXECUTABLE", ERR_LIB_ENGINE, ENGINE_R_CMD_NOT_EXECUTABLE}, ++ #else ++ {"CMD_NOT_EXECUTABLE", 38, 134}, ++ #endif ++ #ifdef ENGINE_R_COMMAND_TAKES_INPUT ++ {"COMMAND_TAKES_INPUT", ERR_LIB_ENGINE, ENGINE_R_COMMAND_TAKES_INPUT}, ++ #else ++ {"COMMAND_TAKES_INPUT", 38, 135}, ++ #endif ++ #ifdef ENGINE_R_COMMAND_TAKES_NO_INPUT ++ {"COMMAND_TAKES_NO_INPUT", ERR_LIB_ENGINE, ENGINE_R_COMMAND_TAKES_NO_INPUT}, ++ #else ++ {"COMMAND_TAKES_NO_INPUT", 38, 136}, ++ #endif ++ #ifdef ENGINE_R_CONFLICTING_ENGINE_ID ++ {"CONFLICTING_ENGINE_ID", ERR_LIB_ENGINE, ENGINE_R_CONFLICTING_ENGINE_ID}, ++ #else ++ {"CONFLICTING_ENGINE_ID", 38, 103}, ++ #endif ++ #ifdef ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED ++ {"CTRL_COMMAND_NOT_IMPLEMENTED", ERR_LIB_ENGINE, ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED}, ++ #else ++ {"CTRL_COMMAND_NOT_IMPLEMENTED", 38, 119}, ++ #endif ++ #ifdef ENGINE_R_DSO_FAILURE ++ {"DSO_FAILURE", ERR_LIB_ENGINE, ENGINE_R_DSO_FAILURE}, ++ #else ++ {"DSO_FAILURE", 38, 104}, ++ #endif ++ #ifdef ENGINE_R_DSO_NOT_FOUND ++ {"DSO_NOT_FOUND", ERR_LIB_ENGINE, ENGINE_R_DSO_NOT_FOUND}, ++ #else ++ {"DSO_NOT_FOUND", 38, 132}, ++ #endif ++ #ifdef ENGINE_R_ENGINES_SECTION_ERROR ++ {"ENGINES_SECTION_ERROR", ERR_LIB_ENGINE, ENGINE_R_ENGINES_SECTION_ERROR}, ++ #else ++ {"ENGINES_SECTION_ERROR", 38, 148}, ++ #endif ++ #ifdef ENGINE_R_ENGINE_CONFIGURATION_ERROR ++ {"ENGINE_CONFIGURATION_ERROR", ERR_LIB_ENGINE, ENGINE_R_ENGINE_CONFIGURATION_ERROR}, ++ #else ++ {"ENGINE_CONFIGURATION_ERROR", 38, 102}, ++ #endif ++ #ifdef ENGINE_R_ENGINE_IS_NOT_IN_LIST ++ {"ENGINE_IS_NOT_IN_LIST", ERR_LIB_ENGINE, ENGINE_R_ENGINE_IS_NOT_IN_LIST}, ++ #else ++ {"ENGINE_IS_NOT_IN_LIST", 38, 105}, ++ #endif ++ #ifdef ENGINE_R_ENGINE_SECTION_ERROR ++ {"ENGINE_SECTION_ERROR", ERR_LIB_ENGINE, ENGINE_R_ENGINE_SECTION_ERROR}, ++ #else ++ {"ENGINE_SECTION_ERROR", 38, 149}, ++ #endif ++ #ifdef ENGINE_R_FAILED_LOADING_PRIVATE_KEY ++ {"FAILED_LOADING_PRIVATE_KEY", ERR_LIB_ENGINE, ENGINE_R_FAILED_LOADING_PRIVATE_KEY}, ++ #else ++ {"FAILED_LOADING_PRIVATE_KEY", 38, 128}, ++ #endif ++ #ifdef ENGINE_R_FAILED_LOADING_PUBLIC_KEY ++ {"FAILED_LOADING_PUBLIC_KEY", ERR_LIB_ENGINE, ENGINE_R_FAILED_LOADING_PUBLIC_KEY}, ++ #else ++ {"FAILED_LOADING_PUBLIC_KEY", 38, 129}, ++ #endif ++ #ifdef ENGINE_R_FINISH_FAILED ++ {"FINISH_FAILED", ERR_LIB_ENGINE, ENGINE_R_FINISH_FAILED}, ++ #else ++ {"FINISH_FAILED", 38, 106}, ++ #endif ++ #ifdef ENGINE_R_ID_OR_NAME_MISSING ++ {"ID_OR_NAME_MISSING", ERR_LIB_ENGINE, ENGINE_R_ID_OR_NAME_MISSING}, ++ #else ++ {"ID_OR_NAME_MISSING", 38, 108}, ++ #endif ++ #ifdef ENGINE_R_INIT_FAILED ++ {"INIT_FAILED", ERR_LIB_ENGINE, ENGINE_R_INIT_FAILED}, ++ #else ++ {"INIT_FAILED", 38, 109}, ++ #endif ++ #ifdef ENGINE_R_INTERNAL_LIST_ERROR ++ {"INTERNAL_LIST_ERROR", ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR}, ++ #else ++ {"INTERNAL_LIST_ERROR", 38, 110}, ++ #endif ++ #ifdef ENGINE_R_INVALID_ARGUMENT ++ {"INVALID_ARGUMENT", ERR_LIB_ENGINE, ENGINE_R_INVALID_ARGUMENT}, ++ #else ++ {"INVALID_ARGUMENT", 38, 143}, ++ #endif ++ #ifdef ENGINE_R_INVALID_CMD_NAME ++ {"INVALID_CMD_NAME", ERR_LIB_ENGINE, ENGINE_R_INVALID_CMD_NAME}, ++ #else ++ {"INVALID_CMD_NAME", 38, 137}, ++ #endif ++ #ifdef ENGINE_R_INVALID_CMD_NUMBER ++ {"INVALID_CMD_NUMBER", ERR_LIB_ENGINE, ENGINE_R_INVALID_CMD_NUMBER}, ++ #else ++ {"INVALID_CMD_NUMBER", 38, 138}, ++ #endif ++ #ifdef ENGINE_R_INVALID_INIT_VALUE ++ {"INVALID_INIT_VALUE", ERR_LIB_ENGINE, ENGINE_R_INVALID_INIT_VALUE}, ++ #else ++ {"INVALID_INIT_VALUE", 38, 151}, ++ #endif ++ #ifdef ENGINE_R_INVALID_STRING ++ {"INVALID_STRING", ERR_LIB_ENGINE, ENGINE_R_INVALID_STRING}, ++ #else ++ {"INVALID_STRING", 38, 150}, ++ #endif ++ #ifdef ENGINE_R_NOT_INITIALISED ++ {"NOT_INITIALISED", ERR_LIB_ENGINE, ENGINE_R_NOT_INITIALISED}, ++ #else ++ {"NOT_INITIALISED", 38, 117}, ++ #endif ++ #ifdef ENGINE_R_NOT_LOADED ++ {"NOT_LOADED", ERR_LIB_ENGINE, ENGINE_R_NOT_LOADED}, ++ #else ++ {"NOT_LOADED", 38, 112}, ++ #endif ++ #ifdef ENGINE_R_NO_CONTROL_FUNCTION ++ {"NO_CONTROL_FUNCTION", ERR_LIB_ENGINE, ENGINE_R_NO_CONTROL_FUNCTION}, ++ #else ++ {"NO_CONTROL_FUNCTION", 38, 120}, ++ #endif ++ #ifdef ENGINE_R_NO_INDEX ++ {"NO_INDEX", ERR_LIB_ENGINE, ENGINE_R_NO_INDEX}, ++ #else ++ {"NO_INDEX", 38, 144}, ++ #endif ++ #ifdef ENGINE_R_NO_LOAD_FUNCTION ++ {"NO_LOAD_FUNCTION", ERR_LIB_ENGINE, ENGINE_R_NO_LOAD_FUNCTION}, ++ #else ++ {"NO_LOAD_FUNCTION", 38, 125}, ++ #endif ++ #ifdef ENGINE_R_NO_REFERENCE ++ {"NO_REFERENCE", ERR_LIB_ENGINE, ENGINE_R_NO_REFERENCE}, ++ #else ++ {"NO_REFERENCE", 38, 130}, ++ #endif ++ #ifdef ENGINE_R_NO_SUCH_ENGINE ++ {"NO_SUCH_ENGINE", ERR_LIB_ENGINE, ENGINE_R_NO_SUCH_ENGINE}, ++ #else ++ {"NO_SUCH_ENGINE", 38, 116}, ++ #endif ++ #ifdef ENGINE_R_UNIMPLEMENTED_CIPHER ++ {"UNIMPLEMENTED_CIPHER", ERR_LIB_ENGINE, ENGINE_R_UNIMPLEMENTED_CIPHER}, ++ #else ++ {"UNIMPLEMENTED_CIPHER", 38, 146}, ++ #endif ++ #ifdef ENGINE_R_UNIMPLEMENTED_DIGEST ++ {"UNIMPLEMENTED_DIGEST", ERR_LIB_ENGINE, ENGINE_R_UNIMPLEMENTED_DIGEST}, ++ #else ++ {"UNIMPLEMENTED_DIGEST", 38, 147}, ++ #endif ++ #ifdef ENGINE_R_UNIMPLEMENTED_PUBLIC_KEY_METHOD ++ {"UNIMPLEMENTED_PUBLIC_KEY_METHOD", ERR_LIB_ENGINE, ENGINE_R_UNIMPLEMENTED_PUBLIC_KEY_METHOD}, ++ #else ++ {"UNIMPLEMENTED_PUBLIC_KEY_METHOD", 38, 101}, ++ #endif ++ #ifdef ENGINE_R_VERSION_INCOMPATIBILITY ++ {"VERSION_INCOMPATIBILITY", ERR_LIB_ENGINE, ENGINE_R_VERSION_INCOMPATIBILITY}, ++ #else ++ {"VERSION_INCOMPATIBILITY", 38, 145}, ++ #endif ++ #ifdef ESS_R_EMPTY_ESS_CERT_ID_LIST ++ {"EMPTY_ESS_CERT_ID_LIST", ERR_LIB_ESS, ESS_R_EMPTY_ESS_CERT_ID_LIST}, ++ #else ++ {"EMPTY_ESS_CERT_ID_LIST", 54, 107}, ++ #endif ++ #ifdef ESS_R_ESS_CERT_DIGEST_ERROR ++ {"ESS_CERT_DIGEST_ERROR", ERR_LIB_ESS, ESS_R_ESS_CERT_DIGEST_ERROR}, ++ #else ++ {"ESS_CERT_DIGEST_ERROR", 54, 103}, ++ #endif ++ #ifdef ESS_R_ESS_CERT_ID_NOT_FOUND ++ {"ESS_CERT_ID_NOT_FOUND", ERR_LIB_ESS, ESS_R_ESS_CERT_ID_NOT_FOUND}, ++ #else ++ {"ESS_CERT_ID_NOT_FOUND", 54, 104}, ++ #endif ++ #ifdef ESS_R_ESS_CERT_ID_WRONG_ORDER ++ {"ESS_CERT_ID_WRONG_ORDER", ERR_LIB_ESS, ESS_R_ESS_CERT_ID_WRONG_ORDER}, ++ #else ++ {"ESS_CERT_ID_WRONG_ORDER", 54, 105}, ++ #endif ++ #ifdef ESS_R_ESS_DIGEST_ALG_UNKNOWN ++ {"ESS_DIGEST_ALG_UNKNOWN", ERR_LIB_ESS, ESS_R_ESS_DIGEST_ALG_UNKNOWN}, ++ #else ++ {"ESS_DIGEST_ALG_UNKNOWN", 54, 106}, ++ #endif ++ #ifdef ESS_R_ESS_SIGNING_CERTIFICATE_ERROR ++ {"ESS_SIGNING_CERTIFICATE_ERROR", ERR_LIB_ESS, ESS_R_ESS_SIGNING_CERTIFICATE_ERROR}, ++ #else ++ {"ESS_SIGNING_CERTIFICATE_ERROR", 54, 102}, ++ #endif ++ #ifdef ESS_R_ESS_SIGNING_CERT_ADD_ERROR ++ {"ESS_SIGNING_CERT_ADD_ERROR", ERR_LIB_ESS, ESS_R_ESS_SIGNING_CERT_ADD_ERROR}, ++ #else ++ {"ESS_SIGNING_CERT_ADD_ERROR", 54, 100}, ++ #endif ++ #ifdef ESS_R_ESS_SIGNING_CERT_V2_ADD_ERROR ++ {"ESS_SIGNING_CERT_V2_ADD_ERROR", ERR_LIB_ESS, ESS_R_ESS_SIGNING_CERT_V2_ADD_ERROR}, ++ #else ++ {"ESS_SIGNING_CERT_V2_ADD_ERROR", 54, 101}, ++ #endif ++ #ifdef ESS_R_MISSING_SIGNING_CERTIFICATE_ATTRIBUTE ++ {"MISSING_SIGNING_CERTIFICATE_ATTRIBUTE", ERR_LIB_ESS, ESS_R_MISSING_SIGNING_CERTIFICATE_ATTRIBUTE}, ++ #else ++ {"MISSING_SIGNING_CERTIFICATE_ATTRIBUTE", 54, 108}, ++ #endif ++ #ifdef EVP_R_AES_KEY_SETUP_FAILED ++ {"AES_KEY_SETUP_FAILED", ERR_LIB_EVP, EVP_R_AES_KEY_SETUP_FAILED}, ++ #else ++ {"AES_KEY_SETUP_FAILED", 6, 143}, ++ #endif ++ #ifdef EVP_R_ARIA_KEY_SETUP_FAILED ++ {"ARIA_KEY_SETUP_FAILED", ERR_LIB_EVP, EVP_R_ARIA_KEY_SETUP_FAILED}, ++ #else ++ {"ARIA_KEY_SETUP_FAILED", 6, 176}, ++ #endif ++ #ifdef EVP_R_BAD_ALGORITHM_NAME ++ {"BAD_ALGORITHM_NAME", ERR_LIB_EVP, EVP_R_BAD_ALGORITHM_NAME}, ++ #else ++ {"BAD_ALGORITHM_NAME", 6, 200}, ++ #endif ++ #ifdef EVP_R_BAD_DECRYPT ++ {"BAD_DECRYPT", ERR_LIB_EVP, EVP_R_BAD_DECRYPT}, ++ #else ++ {"BAD_DECRYPT", 6, 100}, ++ #endif ++ #ifdef EVP_R_BAD_KEY_LENGTH ++ {"BAD_KEY_LENGTH", ERR_LIB_EVP, EVP_R_BAD_KEY_LENGTH}, ++ #else ++ {"BAD_KEY_LENGTH", 6, 195}, ++ #endif ++ #ifdef EVP_R_BUFFER_TOO_SMALL ++ {"BUFFER_TOO_SMALL", ERR_LIB_EVP, EVP_R_BUFFER_TOO_SMALL}, ++ #else ++ {"BUFFER_TOO_SMALL", 6, 155}, ++ #endif ++ #ifdef EVP_R_CACHE_CONSTANTS_FAILED ++ {"CACHE_CONSTANTS_FAILED", ERR_LIB_EVP, EVP_R_CACHE_CONSTANTS_FAILED}, ++ #else ++ {"CACHE_CONSTANTS_FAILED", 6, 225}, ++ #endif ++ #ifdef EVP_R_CAMELLIA_KEY_SETUP_FAILED ++ {"CAMELLIA_KEY_SETUP_FAILED", ERR_LIB_EVP, EVP_R_CAMELLIA_KEY_SETUP_FAILED}, ++ #else ++ {"CAMELLIA_KEY_SETUP_FAILED", 6, 157}, ++ #endif ++ #ifdef EVP_R_CANNOT_GET_PARAMETERS ++ {"CANNOT_GET_PARAMETERS", ERR_LIB_EVP, EVP_R_CANNOT_GET_PARAMETERS}, ++ #else ++ {"CANNOT_GET_PARAMETERS", 6, 197}, ++ #endif ++ #ifdef EVP_R_CANNOT_SET_PARAMETERS ++ {"CANNOT_SET_PARAMETERS", ERR_LIB_EVP, EVP_R_CANNOT_SET_PARAMETERS}, ++ #else ++ {"CANNOT_SET_PARAMETERS", 6, 198}, ++ #endif ++ #ifdef EVP_R_CIPHER_NOT_GCM_MODE ++ {"CIPHER_NOT_GCM_MODE", ERR_LIB_EVP, EVP_R_CIPHER_NOT_GCM_MODE}, ++ #else ++ {"CIPHER_NOT_GCM_MODE", 6, 184}, ++ #endif ++ #ifdef EVP_R_CIPHER_PARAMETER_ERROR ++ {"CIPHER_PARAMETER_ERROR", ERR_LIB_EVP, EVP_R_CIPHER_PARAMETER_ERROR}, ++ #else ++ {"CIPHER_PARAMETER_ERROR", 6, 122}, ++ #endif ++ #ifdef EVP_R_COMMAND_NOT_SUPPORTED ++ {"COMMAND_NOT_SUPPORTED", ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED}, ++ #else ++ {"COMMAND_NOT_SUPPORTED", 6, 147}, ++ #endif ++ #ifdef EVP_R_CONFLICTING_ALGORITHM_NAME ++ {"CONFLICTING_ALGORITHM_NAME", ERR_LIB_EVP, EVP_R_CONFLICTING_ALGORITHM_NAME}, ++ #else ++ {"CONFLICTING_ALGORITHM_NAME", 6, 201}, ++ #endif ++ #ifdef EVP_R_COPY_ERROR ++ {"COPY_ERROR", ERR_LIB_EVP, EVP_R_COPY_ERROR}, ++ #else ++ {"COPY_ERROR", 6, 173}, ++ #endif ++ #ifdef EVP_R_CTRL_NOT_IMPLEMENTED ++ {"CTRL_NOT_IMPLEMENTED", ERR_LIB_EVP, EVP_R_CTRL_NOT_IMPLEMENTED}, ++ #else ++ {"CTRL_NOT_IMPLEMENTED", 6, 132}, ++ #endif ++ #ifdef EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED ++ {"CTRL_OPERATION_NOT_IMPLEMENTED", ERR_LIB_EVP, EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED}, ++ #else ++ {"CTRL_OPERATION_NOT_IMPLEMENTED", 6, 133}, ++ #endif ++ #ifdef EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH ++ {"DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH", ERR_LIB_EVP, EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH}, ++ #else ++ {"DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH", 6, 138}, ++ #endif ++ #ifdef EVP_R_DECODE_ERROR ++ {"DECODE_ERROR", ERR_LIB_EVP, EVP_R_DECODE_ERROR}, ++ #else ++ {"DECODE_ERROR", 6, 114}, ++ #endif ++ #ifdef EVP_R_DEFAULT_QUERY_PARSE_ERROR ++ {"DEFAULT_QUERY_PARSE_ERROR", ERR_LIB_EVP, EVP_R_DEFAULT_QUERY_PARSE_ERROR}, ++ #else ++ {"DEFAULT_QUERY_PARSE_ERROR", 6, 210}, ++ #endif ++ #ifdef EVP_R_DIFFERENT_KEY_TYPES ++ {"DIFFERENT_KEY_TYPES", ERR_LIB_EVP, EVP_R_DIFFERENT_KEY_TYPES}, ++ #else ++ {"DIFFERENT_KEY_TYPES", 6, 101}, ++ #endif ++ #ifdef EVP_R_DIFFERENT_PARAMETERS ++ {"DIFFERENT_PARAMETERS", ERR_LIB_EVP, EVP_R_DIFFERENT_PARAMETERS}, ++ #else ++ {"DIFFERENT_PARAMETERS", 6, 153}, ++ #endif ++ #ifdef EVP_R_ERROR_LOADING_SECTION ++ {"ERROR_LOADING_SECTION", ERR_LIB_EVP, EVP_R_ERROR_LOADING_SECTION}, ++ #else ++ {"ERROR_LOADING_SECTION", 6, 165}, ++ #endif ++ #ifdef EVP_R_EXPECTING_AN_HMAC_KEY ++ {"EXPECTING_AN_HMAC_KEY", ERR_LIB_EVP, EVP_R_EXPECTING_AN_HMAC_KEY}, ++ #else ++ {"EXPECTING_AN_HMAC_KEY", 6, 174}, ++ #endif ++ #ifdef EVP_R_EXPECTING_AN_RSA_KEY ++ {"EXPECTING_AN_RSA_KEY", ERR_LIB_EVP, EVP_R_EXPECTING_AN_RSA_KEY}, ++ #else ++ {"EXPECTING_AN_RSA_KEY", 6, 127}, ++ #endif ++ #ifdef EVP_R_EXPECTING_A_DH_KEY ++ {"EXPECTING_A_DH_KEY", ERR_LIB_EVP, EVP_R_EXPECTING_A_DH_KEY}, ++ #else ++ {"EXPECTING_A_DH_KEY", 6, 128}, ++ #endif ++ #ifdef EVP_R_EXPECTING_A_DSA_KEY ++ {"EXPECTING_A_DSA_KEY", ERR_LIB_EVP, EVP_R_EXPECTING_A_DSA_KEY}, ++ #else ++ {"EXPECTING_A_DSA_KEY", 6, 129}, ++ #endif ++ #ifdef EVP_R_EXPECTING_A_ECX_KEY ++ {"EXPECTING_A_ECX_KEY", ERR_LIB_EVP, EVP_R_EXPECTING_A_ECX_KEY}, ++ #else ++ {"EXPECTING_A_ECX_KEY", 6, 219}, ++ #endif ++ #ifdef EVP_R_EXPECTING_A_EC_KEY ++ {"EXPECTING_A_EC_KEY", ERR_LIB_EVP, EVP_R_EXPECTING_A_EC_KEY}, ++ #else ++ {"EXPECTING_A_EC_KEY", 6, 142}, ++ #endif ++ #ifdef EVP_R_EXPECTING_A_POLY1305_KEY ++ {"EXPECTING_A_POLY1305_KEY", ERR_LIB_EVP, EVP_R_EXPECTING_A_POLY1305_KEY}, ++ #else ++ {"EXPECTING_A_POLY1305_KEY", 6, 164}, ++ #endif ++ #ifdef EVP_R_EXPECTING_A_SIPHASH_KEY ++ {"EXPECTING_A_SIPHASH_KEY", ERR_LIB_EVP, EVP_R_EXPECTING_A_SIPHASH_KEY}, ++ #else ++ {"EXPECTING_A_SIPHASH_KEY", 6, 175}, ++ #endif ++ #ifdef EVP_R_FINAL_ERROR ++ {"FINAL_ERROR", ERR_LIB_EVP, EVP_R_FINAL_ERROR}, ++ #else ++ {"FINAL_ERROR", 6, 188}, ++ #endif ++ #ifdef EVP_R_GENERATE_ERROR ++ {"GENERATE_ERROR", ERR_LIB_EVP, EVP_R_GENERATE_ERROR}, ++ #else ++ {"GENERATE_ERROR", 6, 214}, ++ #endif ++ #ifdef EVP_R_GETTING_ALGORITHMIDENTIFIER_NOT_SUPPORTED ++ {"GETTING_ALGORITHMIDENTIFIER_NOT_SUPPORTED", ERR_LIB_EVP, EVP_R_GETTING_ALGORITHMIDENTIFIER_NOT_SUPPORTED}, ++ #else ++ {"GETTING_ALGORITHMIDENTIFIER_NOT_SUPPORTED", 6, 229}, ++ #endif ++ #ifdef EVP_R_GET_RAW_KEY_FAILED ++ {"GET_RAW_KEY_FAILED", ERR_LIB_EVP, EVP_R_GET_RAW_KEY_FAILED}, ++ #else ++ {"GET_RAW_KEY_FAILED", 6, 182}, ++ #endif ++ #ifdef EVP_R_ILLEGAL_SCRYPT_PARAMETERS ++ {"ILLEGAL_SCRYPT_PARAMETERS", ERR_LIB_EVP, EVP_R_ILLEGAL_SCRYPT_PARAMETERS}, ++ #else ++ {"ILLEGAL_SCRYPT_PARAMETERS", 6, 171}, ++ #endif ++ #ifdef EVP_R_INACCESSIBLE_DOMAIN_PARAMETERS ++ {"INACCESSIBLE_DOMAIN_PARAMETERS", ERR_LIB_EVP, EVP_R_INACCESSIBLE_DOMAIN_PARAMETERS}, ++ #else ++ {"INACCESSIBLE_DOMAIN_PARAMETERS", 6, 204}, ++ #endif ++ #ifdef EVP_R_INACCESSIBLE_KEY ++ {"INACCESSIBLE_KEY", ERR_LIB_EVP, EVP_R_INACCESSIBLE_KEY}, ++ #else ++ {"INACCESSIBLE_KEY", 6, 203}, ++ #endif ++ #ifdef EVP_R_INITIALIZATION_ERROR ++ {"INITIALIZATION_ERROR", ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR}, ++ #else ++ {"INITIALIZATION_ERROR", 6, 134}, ++ #endif ++ #ifdef EVP_R_INPUT_NOT_INITIALIZED ++ {"INPUT_NOT_INITIALIZED", ERR_LIB_EVP, EVP_R_INPUT_NOT_INITIALIZED}, ++ #else ++ {"INPUT_NOT_INITIALIZED", 6, 111}, ++ #endif ++ #ifdef EVP_R_INVALID_CUSTOM_LENGTH ++ {"INVALID_CUSTOM_LENGTH", ERR_LIB_EVP, EVP_R_INVALID_CUSTOM_LENGTH}, ++ #else ++ {"INVALID_CUSTOM_LENGTH", 6, 185}, ++ #endif ++ #ifdef EVP_R_INVALID_DIGEST ++ {"INVALID_DIGEST", ERR_LIB_EVP, EVP_R_INVALID_DIGEST}, ++ #else ++ {"INVALID_DIGEST", 6, 152}, ++ #endif ++ #ifdef EVP_R_INVALID_IV_LENGTH ++ {"INVALID_IV_LENGTH", ERR_LIB_EVP, EVP_R_INVALID_IV_LENGTH}, ++ #else ++ {"INVALID_IV_LENGTH", 6, 194}, ++ #endif ++ #ifdef EVP_R_INVALID_KEY ++ {"INVALID_KEY", ERR_LIB_EVP, EVP_R_INVALID_KEY}, ++ #else ++ {"INVALID_KEY", 6, 163}, ++ #endif ++ #ifdef EVP_R_INVALID_KEY_LENGTH ++ {"INVALID_KEY_LENGTH", ERR_LIB_EVP, EVP_R_INVALID_KEY_LENGTH}, ++ #else ++ {"INVALID_KEY_LENGTH", 6, 130}, ++ #endif ++ #ifdef EVP_R_INVALID_LENGTH ++ {"INVALID_LENGTH", ERR_LIB_EVP, EVP_R_INVALID_LENGTH}, ++ #else ++ {"INVALID_LENGTH", 6, 221}, ++ #endif ++ #ifdef EVP_R_INVALID_NULL_ALGORITHM ++ {"INVALID_NULL_ALGORITHM", ERR_LIB_EVP, EVP_R_INVALID_NULL_ALGORITHM}, ++ #else ++ {"INVALID_NULL_ALGORITHM", 6, 218}, ++ #endif ++ #ifdef EVP_R_INVALID_OPERATION ++ {"INVALID_OPERATION", ERR_LIB_EVP, EVP_R_INVALID_OPERATION}, ++ #else ++ {"INVALID_OPERATION", 6, 148}, ++ #endif ++ #ifdef EVP_R_INVALID_PROVIDER_FUNCTIONS ++ {"INVALID_PROVIDER_FUNCTIONS", ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS}, ++ #else ++ {"INVALID_PROVIDER_FUNCTIONS", 6, 193}, ++ #endif ++ #ifdef EVP_R_INVALID_SALT_LENGTH ++ {"INVALID_SALT_LENGTH", ERR_LIB_EVP, EVP_R_INVALID_SALT_LENGTH}, ++ #else ++ {"INVALID_SALT_LENGTH", 6, 186}, ++ #endif ++ #ifdef EVP_R_INVALID_SECRET_LENGTH ++ {"INVALID_SECRET_LENGTH", ERR_LIB_EVP, EVP_R_INVALID_SECRET_LENGTH}, ++ #else ++ {"INVALID_SECRET_LENGTH", 6, 223}, ++ #endif ++ #ifdef EVP_R_INVALID_SEED_LENGTH ++ {"INVALID_SEED_LENGTH", ERR_LIB_EVP, EVP_R_INVALID_SEED_LENGTH}, ++ #else ++ {"INVALID_SEED_LENGTH", 6, 220}, ++ #endif ++ #ifdef EVP_R_INVALID_VALUE ++ {"INVALID_VALUE", ERR_LIB_EVP, EVP_R_INVALID_VALUE}, ++ #else ++ {"INVALID_VALUE", 6, 222}, ++ #endif ++ #ifdef EVP_R_KEYMGMT_EXPORT_FAILURE ++ {"KEYMGMT_EXPORT_FAILURE", ERR_LIB_EVP, EVP_R_KEYMGMT_EXPORT_FAILURE}, ++ #else ++ {"KEYMGMT_EXPORT_FAILURE", 6, 205}, ++ #endif ++ #ifdef EVP_R_KEY_SETUP_FAILED ++ {"KEY_SETUP_FAILED", ERR_LIB_EVP, EVP_R_KEY_SETUP_FAILED}, ++ #else ++ {"KEY_SETUP_FAILED", 6, 180}, ++ #endif ++ #ifdef EVP_R_LOCKING_NOT_SUPPORTED ++ {"LOCKING_NOT_SUPPORTED", ERR_LIB_EVP, EVP_R_LOCKING_NOT_SUPPORTED}, ++ #else ++ {"LOCKING_NOT_SUPPORTED", 6, 213}, ++ #endif ++ #ifdef EVP_R_MEMORY_LIMIT_EXCEEDED ++ {"MEMORY_LIMIT_EXCEEDED", ERR_LIB_EVP, EVP_R_MEMORY_LIMIT_EXCEEDED}, ++ #else ++ {"MEMORY_LIMIT_EXCEEDED", 6, 172}, ++ #endif ++ #ifdef EVP_R_MESSAGE_DIGEST_IS_NULL ++ {"MESSAGE_DIGEST_IS_NULL", ERR_LIB_EVP, EVP_R_MESSAGE_DIGEST_IS_NULL}, ++ #else ++ {"MESSAGE_DIGEST_IS_NULL", 6, 159}, ++ #endif ++ #ifdef EVP_R_METHOD_NOT_SUPPORTED ++ {"METHOD_NOT_SUPPORTED", ERR_LIB_EVP, EVP_R_METHOD_NOT_SUPPORTED}, ++ #else ++ {"METHOD_NOT_SUPPORTED", 6, 144}, ++ #endif ++ #ifdef EVP_R_MISSING_PARAMETERS ++ {"MISSING_PARAMETERS", ERR_LIB_EVP, EVP_R_MISSING_PARAMETERS}, ++ #else ++ {"MISSING_PARAMETERS", 6, 103}, ++ #endif ++ #ifdef EVP_R_NOT_ABLE_TO_COPY_CTX ++ {"NOT_ABLE_TO_COPY_CTX", ERR_LIB_EVP, EVP_R_NOT_ABLE_TO_COPY_CTX}, ++ #else ++ {"NOT_ABLE_TO_COPY_CTX", 6, 190}, ++ #endif ++ #ifdef EVP_R_NOT_XOF_OR_INVALID_LENGTH ++ {"NOT_XOF_OR_INVALID_LENGTH", ERR_LIB_EVP, EVP_R_NOT_XOF_OR_INVALID_LENGTH}, ++ #else ++ {"NOT_XOF_OR_INVALID_LENGTH", 6, 178}, ++ #endif ++ #ifdef EVP_R_NO_CIPHER_SET ++ {"NO_CIPHER_SET", ERR_LIB_EVP, EVP_R_NO_CIPHER_SET}, ++ #else ++ {"NO_CIPHER_SET", 6, 131}, ++ #endif ++ #ifdef EVP_R_NO_DEFAULT_DIGEST ++ {"NO_DEFAULT_DIGEST", ERR_LIB_EVP, EVP_R_NO_DEFAULT_DIGEST}, ++ #else ++ {"NO_DEFAULT_DIGEST", 6, 158}, ++ #endif ++ #ifdef EVP_R_NO_DIGEST_SET ++ {"NO_DIGEST_SET", ERR_LIB_EVP, EVP_R_NO_DIGEST_SET}, ++ #else ++ {"NO_DIGEST_SET", 6, 139}, ++ #endif ++ #ifdef EVP_R_NO_IMPORT_FUNCTION ++ {"NO_IMPORT_FUNCTION", ERR_LIB_EVP, EVP_R_NO_IMPORT_FUNCTION}, ++ #else ++ {"NO_IMPORT_FUNCTION", 6, 206}, ++ #endif ++ #ifdef EVP_R_NO_KEYMGMT_AVAILABLE ++ {"NO_KEYMGMT_AVAILABLE", ERR_LIB_EVP, EVP_R_NO_KEYMGMT_AVAILABLE}, ++ #else ++ {"NO_KEYMGMT_AVAILABLE", 6, 199}, ++ #endif ++ #ifdef EVP_R_NO_KEYMGMT_PRESENT ++ {"NO_KEYMGMT_PRESENT", ERR_LIB_EVP, EVP_R_NO_KEYMGMT_PRESENT}, ++ #else ++ {"NO_KEYMGMT_PRESENT", 6, 196}, ++ #endif ++ #ifdef EVP_R_NO_KEY_SET ++ {"NO_KEY_SET", ERR_LIB_EVP, EVP_R_NO_KEY_SET}, ++ #else ++ {"NO_KEY_SET", 6, 154}, ++ #endif ++ #ifdef EVP_R_NO_OPERATION_SET ++ {"NO_OPERATION_SET", ERR_LIB_EVP, EVP_R_NO_OPERATION_SET}, ++ #else ++ {"NO_OPERATION_SET", 6, 149}, ++ #endif ++ #ifdef EVP_R_NULL_MAC_PKEY_CTX ++ {"NULL_MAC_PKEY_CTX", ERR_LIB_EVP, EVP_R_NULL_MAC_PKEY_CTX}, ++ #else ++ {"NULL_MAC_PKEY_CTX", 6, 208}, ++ #endif ++ #ifdef EVP_R_ONLY_ONESHOT_SUPPORTED ++ {"ONLY_ONESHOT_SUPPORTED", ERR_LIB_EVP, EVP_R_ONLY_ONESHOT_SUPPORTED}, ++ #else ++ {"ONLY_ONESHOT_SUPPORTED", 6, 177}, ++ #endif ++ #ifdef EVP_R_OPERATION_NOT_INITIALIZED ++ {"OPERATION_NOT_INITIALIZED", ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED}, ++ #else ++ {"OPERATION_NOT_INITIALIZED", 6, 151}, ++ #endif ++ #ifdef EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE ++ {"OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE", ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE}, ++ #else ++ {"OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE", 6, 150}, ++ #endif ++ #ifdef EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_SIGNATURE_TYPE ++ {"OPERATION_NOT_SUPPORTED_FOR_THIS_SIGNATURE_TYPE", ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_SIGNATURE_TYPE}, ++ #else ++ {"OPERATION_NOT_SUPPORTED_FOR_THIS_SIGNATURE_TYPE", 6, 226}, ++ #endif ++ #ifdef EVP_R_OUTPUT_WOULD_OVERFLOW ++ {"OUTPUT_WOULD_OVERFLOW", ERR_LIB_EVP, EVP_R_OUTPUT_WOULD_OVERFLOW}, ++ #else ++ {"OUTPUT_WOULD_OVERFLOW", 6, 202}, ++ #endif ++ #ifdef EVP_R_PARAMETER_TOO_LARGE ++ {"PARAMETER_TOO_LARGE", ERR_LIB_EVP, EVP_R_PARAMETER_TOO_LARGE}, ++ #else ++ {"PARAMETER_TOO_LARGE", 6, 187}, ++ #endif ++ #ifdef EVP_R_PARTIALLY_OVERLAPPING ++ {"PARTIALLY_OVERLAPPING", ERR_LIB_EVP, EVP_R_PARTIALLY_OVERLAPPING}, ++ #else ++ {"PARTIALLY_OVERLAPPING", 6, 162}, ++ #endif ++ #ifdef EVP_R_PBKDF2_ERROR ++ {"PBKDF2_ERROR", ERR_LIB_EVP, EVP_R_PBKDF2_ERROR}, ++ #else ++ {"PBKDF2_ERROR", 6, 181}, ++ #endif ++ #ifdef EVP_R_PKEY_APPLICATION_ASN1_METHOD_ALREADY_REGISTERED ++ {"PKEY_APPLICATION_ASN1_METHOD_ALREADY_REGISTERED", ERR_LIB_EVP, EVP_R_PKEY_APPLICATION_ASN1_METHOD_ALREADY_REGISTERED}, ++ #else ++ {"PKEY_APPLICATION_ASN1_METHOD_ALREADY_REGISTERED", 6, 179}, ++ #endif ++ #ifdef EVP_R_PRIVATE_KEY_DECODE_ERROR ++ {"PRIVATE_KEY_DECODE_ERROR", ERR_LIB_EVP, EVP_R_PRIVATE_KEY_DECODE_ERROR}, ++ #else ++ {"PRIVATE_KEY_DECODE_ERROR", 6, 145}, ++ #endif ++ #ifdef EVP_R_PRIVATE_KEY_ENCODE_ERROR ++ {"PRIVATE_KEY_ENCODE_ERROR", ERR_LIB_EVP, EVP_R_PRIVATE_KEY_ENCODE_ERROR}, ++ #else ++ {"PRIVATE_KEY_ENCODE_ERROR", 6, 146}, ++ #endif ++ #ifdef EVP_R_PUBLIC_KEY_NOT_RSA ++ {"PUBLIC_KEY_NOT_RSA", ERR_LIB_EVP, EVP_R_PUBLIC_KEY_NOT_RSA}, ++ #else ++ {"PUBLIC_KEY_NOT_RSA", 6, 106}, ++ #endif ++ #ifdef EVP_R_SETTING_XOF_FAILED ++ {"SETTING_XOF_FAILED", ERR_LIB_EVP, EVP_R_SETTING_XOF_FAILED}, ++ #else ++ {"SETTING_XOF_FAILED", 6, 227}, ++ #endif ++ #ifdef EVP_R_SET_DEFAULT_PROPERTY_FAILURE ++ {"SET_DEFAULT_PROPERTY_FAILURE", ERR_LIB_EVP, EVP_R_SET_DEFAULT_PROPERTY_FAILURE}, ++ #else ++ {"SET_DEFAULT_PROPERTY_FAILURE", 6, 209}, ++ #endif ++ #ifdef EVP_R_SIGNATURE_TYPE_AND_KEY_TYPE_INCOMPATIBLE ++ {"SIGNATURE_TYPE_AND_KEY_TYPE_INCOMPATIBLE", ERR_LIB_EVP, EVP_R_SIGNATURE_TYPE_AND_KEY_TYPE_INCOMPATIBLE}, ++ #else ++ {"SIGNATURE_TYPE_AND_KEY_TYPE_INCOMPATIBLE", 6, 228}, ++ #endif ++ #ifdef EVP_R_TOO_MANY_RECORDS ++ {"TOO_MANY_RECORDS", ERR_LIB_EVP, EVP_R_TOO_MANY_RECORDS}, ++ #else ++ {"TOO_MANY_RECORDS", 6, 183}, ++ #endif ++ #ifdef EVP_R_UNABLE_TO_ENABLE_LOCKING ++ {"UNABLE_TO_ENABLE_LOCKING", ERR_LIB_EVP, EVP_R_UNABLE_TO_ENABLE_LOCKING}, ++ #else ++ {"UNABLE_TO_ENABLE_LOCKING", 6, 212}, ++ #endif ++ #ifdef EVP_R_UNABLE_TO_GET_MAXIMUM_REQUEST_SIZE ++ {"UNABLE_TO_GET_MAXIMUM_REQUEST_SIZE", ERR_LIB_EVP, EVP_R_UNABLE_TO_GET_MAXIMUM_REQUEST_SIZE}, ++ #else ++ {"UNABLE_TO_GET_MAXIMUM_REQUEST_SIZE", 6, 215}, ++ #endif ++ #ifdef EVP_R_UNABLE_TO_GET_RANDOM_STRENGTH ++ {"UNABLE_TO_GET_RANDOM_STRENGTH", ERR_LIB_EVP, EVP_R_UNABLE_TO_GET_RANDOM_STRENGTH}, ++ #else ++ {"UNABLE_TO_GET_RANDOM_STRENGTH", 6, 216}, ++ #endif ++ #ifdef EVP_R_UNABLE_TO_LOCK_CONTEXT ++ {"UNABLE_TO_LOCK_CONTEXT", ERR_LIB_EVP, EVP_R_UNABLE_TO_LOCK_CONTEXT}, ++ #else ++ {"UNABLE_TO_LOCK_CONTEXT", 6, 211}, ++ #endif ++ #ifdef EVP_R_UNABLE_TO_SET_CALLBACKS ++ {"UNABLE_TO_SET_CALLBACKS", ERR_LIB_EVP, EVP_R_UNABLE_TO_SET_CALLBACKS}, ++ #else ++ {"UNABLE_TO_SET_CALLBACKS", 6, 217}, ++ #endif ++ #ifdef EVP_R_UNKNOWN_BITS ++ {"UNKNOWN_BITS", ERR_LIB_EVP, EVP_R_UNKNOWN_BITS}, ++ #else ++ {"UNKNOWN_BITS", 6, 166}, ++ #endif ++ #ifdef EVP_R_UNKNOWN_CIPHER ++ {"UNKNOWN_CIPHER", ERR_LIB_EVP, EVP_R_UNKNOWN_CIPHER}, ++ #else ++ {"UNKNOWN_CIPHER", 6, 160}, ++ #endif ++ #ifdef EVP_R_UNKNOWN_DIGEST ++ {"UNKNOWN_DIGEST", ERR_LIB_EVP, EVP_R_UNKNOWN_DIGEST}, ++ #else ++ {"UNKNOWN_DIGEST", 6, 161}, ++ #endif ++ #ifdef EVP_R_UNKNOWN_KEY_TYPE ++ {"UNKNOWN_KEY_TYPE", ERR_LIB_EVP, EVP_R_UNKNOWN_KEY_TYPE}, ++ #else ++ {"UNKNOWN_KEY_TYPE", 6, 207}, ++ #endif ++ #ifdef EVP_R_UNKNOWN_MAX_SIZE ++ {"UNKNOWN_MAX_SIZE", ERR_LIB_EVP, EVP_R_UNKNOWN_MAX_SIZE}, ++ #else ++ {"UNKNOWN_MAX_SIZE", 6, 167}, ++ #endif ++ #ifdef EVP_R_UNKNOWN_OPTION ++ {"UNKNOWN_OPTION", ERR_LIB_EVP, EVP_R_UNKNOWN_OPTION}, ++ #else ++ {"UNKNOWN_OPTION", 6, 169}, ++ #endif ++ #ifdef EVP_R_UNKNOWN_PBE_ALGORITHM ++ {"UNKNOWN_PBE_ALGORITHM", ERR_LIB_EVP, EVP_R_UNKNOWN_PBE_ALGORITHM}, ++ #else ++ {"UNKNOWN_PBE_ALGORITHM", 6, 121}, ++ #endif ++ #ifdef EVP_R_UNKNOWN_SECURITY_BITS ++ {"UNKNOWN_SECURITY_BITS", ERR_LIB_EVP, EVP_R_UNKNOWN_SECURITY_BITS}, ++ #else ++ {"UNKNOWN_SECURITY_BITS", 6, 168}, ++ #endif ++ #ifdef EVP_R_UNSUPPORTED_ALGORITHM ++ {"UNSUPPORTED_ALGORITHM", ERR_LIB_EVP, EVP_R_UNSUPPORTED_ALGORITHM}, ++ #else ++ {"UNSUPPORTED_ALGORITHM", 6, 156}, ++ #endif ++ #ifdef EVP_R_UNSUPPORTED_CIPHER ++ {"UNSUPPORTED_CIPHER", ERR_LIB_EVP, EVP_R_UNSUPPORTED_CIPHER}, ++ #else ++ {"UNSUPPORTED_CIPHER", 6, 107}, ++ #endif ++ #ifdef EVP_R_UNSUPPORTED_KEYLENGTH ++ {"UNSUPPORTED_KEYLENGTH", ERR_LIB_EVP, EVP_R_UNSUPPORTED_KEYLENGTH}, ++ #else ++ {"UNSUPPORTED_KEYLENGTH", 6, 123}, ++ #endif ++ #ifdef EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION ++ {"UNSUPPORTED_KEY_DERIVATION_FUNCTION", ERR_LIB_EVP, EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION}, ++ #else ++ {"UNSUPPORTED_KEY_DERIVATION_FUNCTION", 6, 124}, ++ #endif ++ #ifdef EVP_R_UNSUPPORTED_KEY_SIZE ++ {"UNSUPPORTED_KEY_SIZE", ERR_LIB_EVP, EVP_R_UNSUPPORTED_KEY_SIZE}, ++ #else ++ {"UNSUPPORTED_KEY_SIZE", 6, 108}, ++ #endif ++ #ifdef EVP_R_UNSUPPORTED_KEY_TYPE ++ {"UNSUPPORTED_KEY_TYPE", ERR_LIB_EVP, EVP_R_UNSUPPORTED_KEY_TYPE}, ++ #else ++ {"UNSUPPORTED_KEY_TYPE", 6, 224}, ++ #endif ++ #ifdef EVP_R_UNSUPPORTED_NUMBER_OF_ROUNDS ++ {"UNSUPPORTED_NUMBER_OF_ROUNDS", ERR_LIB_EVP, EVP_R_UNSUPPORTED_NUMBER_OF_ROUNDS}, ++ #else ++ {"UNSUPPORTED_NUMBER_OF_ROUNDS", 6, 135}, ++ #endif ++ #ifdef EVP_R_UNSUPPORTED_PRF ++ {"UNSUPPORTED_PRF", ERR_LIB_EVP, EVP_R_UNSUPPORTED_PRF}, ++ #else ++ {"UNSUPPORTED_PRF", 6, 125}, ++ #endif ++ #ifdef EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM ++ {"UNSUPPORTED_PRIVATE_KEY_ALGORITHM", ERR_LIB_EVP, EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM}, ++ #else ++ {"UNSUPPORTED_PRIVATE_KEY_ALGORITHM", 6, 118}, ++ #endif ++ #ifdef EVP_R_UNSUPPORTED_SALT_TYPE ++ {"UNSUPPORTED_SALT_TYPE", ERR_LIB_EVP, EVP_R_UNSUPPORTED_SALT_TYPE}, ++ #else ++ {"UNSUPPORTED_SALT_TYPE", 6, 126}, ++ #endif ++ #ifdef EVP_R_UPDATE_ERROR ++ {"UPDATE_ERROR", ERR_LIB_EVP, EVP_R_UPDATE_ERROR}, ++ #else ++ {"UPDATE_ERROR", 6, 189}, ++ #endif ++ #ifdef EVP_R_WRAP_MODE_NOT_ALLOWED ++ {"WRAP_MODE_NOT_ALLOWED", ERR_LIB_EVP, EVP_R_WRAP_MODE_NOT_ALLOWED}, ++ #else ++ {"WRAP_MODE_NOT_ALLOWED", 6, 170}, ++ #endif ++ #ifdef EVP_R_WRONG_FINAL_BLOCK_LENGTH ++ {"WRONG_FINAL_BLOCK_LENGTH", ERR_LIB_EVP, EVP_R_WRONG_FINAL_BLOCK_LENGTH}, ++ #else ++ {"WRONG_FINAL_BLOCK_LENGTH", 6, 109}, ++ #endif ++ #ifdef EVP_R_XTS_DATA_UNIT_IS_TOO_LARGE ++ {"XTS_DATA_UNIT_IS_TOO_LARGE", ERR_LIB_EVP, EVP_R_XTS_DATA_UNIT_IS_TOO_LARGE}, ++ #else ++ {"XTS_DATA_UNIT_IS_TOO_LARGE", 6, 191}, ++ #endif ++ #ifdef EVP_R_XTS_DUPLICATED_KEYS ++ {"XTS_DUPLICATED_KEYS", ERR_LIB_EVP, EVP_R_XTS_DUPLICATED_KEYS}, ++ #else ++ {"XTS_DUPLICATED_KEYS", 6, 192}, ++ #endif ++ #ifdef HTTP_R_ASN1_LEN_EXCEEDS_MAX_RESP_LEN ++ {"ASN1_LEN_EXCEEDS_MAX_RESP_LEN", ERR_LIB_HTTP, HTTP_R_ASN1_LEN_EXCEEDS_MAX_RESP_LEN}, ++ #else ++ {"ASN1_LEN_EXCEEDS_MAX_RESP_LEN", 61, 108}, ++ #endif ++ #ifdef HTTP_R_CONNECT_FAILURE ++ {"CONNECT_FAILURE", ERR_LIB_HTTP, HTTP_R_CONNECT_FAILURE}, ++ #else ++ {"CONNECT_FAILURE", 61, 100}, ++ #endif ++ #ifdef HTTP_R_ERROR_PARSING_ASN1_LENGTH ++ {"ERROR_PARSING_ASN1_LENGTH", ERR_LIB_HTTP, HTTP_R_ERROR_PARSING_ASN1_LENGTH}, ++ #else ++ {"ERROR_PARSING_ASN1_LENGTH", 61, 109}, ++ #endif ++ #ifdef HTTP_R_ERROR_PARSING_CONTENT_LENGTH ++ {"ERROR_PARSING_CONTENT_LENGTH", ERR_LIB_HTTP, HTTP_R_ERROR_PARSING_CONTENT_LENGTH}, ++ #else ++ {"ERROR_PARSING_CONTENT_LENGTH", 61, 119}, ++ #endif ++ #ifdef HTTP_R_ERROR_PARSING_URL ++ {"ERROR_PARSING_URL", ERR_LIB_HTTP, HTTP_R_ERROR_PARSING_URL}, ++ #else ++ {"ERROR_PARSING_URL", 61, 101}, ++ #endif ++ #ifdef HTTP_R_ERROR_RECEIVING ++ {"ERROR_RECEIVING", ERR_LIB_HTTP, HTTP_R_ERROR_RECEIVING}, ++ #else ++ {"ERROR_RECEIVING", 61, 103}, ++ #endif ++ #ifdef HTTP_R_ERROR_SENDING ++ {"ERROR_SENDING", ERR_LIB_HTTP, HTTP_R_ERROR_SENDING}, ++ #else ++ {"ERROR_SENDING", 61, 102}, ++ #endif ++ #ifdef HTTP_R_FAILED_READING_DATA ++ {"FAILED_READING_DATA", ERR_LIB_HTTP, HTTP_R_FAILED_READING_DATA}, ++ #else ++ {"FAILED_READING_DATA", 61, 128}, ++ #endif ++ #ifdef HTTP_R_HEADER_PARSE_ERROR ++ {"HEADER_PARSE_ERROR", ERR_LIB_HTTP, HTTP_R_HEADER_PARSE_ERROR}, ++ #else ++ {"HEADER_PARSE_ERROR", 61, 126}, ++ #endif ++ #ifdef HTTP_R_INCONSISTENT_CONTENT_LENGTH ++ {"INCONSISTENT_CONTENT_LENGTH", ERR_LIB_HTTP, HTTP_R_INCONSISTENT_CONTENT_LENGTH}, ++ #else ++ {"INCONSISTENT_CONTENT_LENGTH", 61, 120}, ++ #endif ++ #ifdef HTTP_R_INVALID_PORT_NUMBER ++ {"INVALID_PORT_NUMBER", ERR_LIB_HTTP, HTTP_R_INVALID_PORT_NUMBER}, ++ #else ++ {"INVALID_PORT_NUMBER", 61, 123}, ++ #endif ++ #ifdef HTTP_R_INVALID_URL_PATH ++ {"INVALID_URL_PATH", ERR_LIB_HTTP, HTTP_R_INVALID_URL_PATH}, ++ #else ++ {"INVALID_URL_PATH", 61, 125}, ++ #endif ++ #ifdef HTTP_R_INVALID_URL_SCHEME ++ {"INVALID_URL_SCHEME", ERR_LIB_HTTP, HTTP_R_INVALID_URL_SCHEME}, ++ #else ++ {"INVALID_URL_SCHEME", 61, 124}, ++ #endif ++ #ifdef HTTP_R_MAX_RESP_LEN_EXCEEDED ++ {"MAX_RESP_LEN_EXCEEDED", ERR_LIB_HTTP, HTTP_R_MAX_RESP_LEN_EXCEEDED}, ++ #else ++ {"MAX_RESP_LEN_EXCEEDED", 61, 117}, ++ #endif ++ #ifdef HTTP_R_MISSING_ASN1_ENCODING ++ {"MISSING_ASN1_ENCODING", ERR_LIB_HTTP, HTTP_R_MISSING_ASN1_ENCODING}, ++ #else ++ {"MISSING_ASN1_ENCODING", 61, 110}, ++ #endif ++ #ifdef HTTP_R_MISSING_CONTENT_TYPE ++ {"MISSING_CONTENT_TYPE", ERR_LIB_HTTP, HTTP_R_MISSING_CONTENT_TYPE}, ++ #else ++ {"MISSING_CONTENT_TYPE", 61, 121}, ++ #endif ++ #ifdef HTTP_R_MISSING_REDIRECT_LOCATION ++ {"MISSING_REDIRECT_LOCATION", ERR_LIB_HTTP, HTTP_R_MISSING_REDIRECT_LOCATION}, ++ #else ++ {"MISSING_REDIRECT_LOCATION", 61, 111}, ++ #endif ++ #ifdef HTTP_R_RECEIVED_ERROR ++ {"RECEIVED_ERROR", ERR_LIB_HTTP, HTTP_R_RECEIVED_ERROR}, ++ #else ++ {"RECEIVED_ERROR", 61, 105}, ++ #endif ++ #ifdef HTTP_R_RECEIVED_WRONG_HTTP_VERSION ++ {"RECEIVED_WRONG_HTTP_VERSION", ERR_LIB_HTTP, HTTP_R_RECEIVED_WRONG_HTTP_VERSION}, ++ #else ++ {"RECEIVED_WRONG_HTTP_VERSION", 61, 106}, ++ #endif ++ #ifdef HTTP_R_REDIRECTION_FROM_HTTPS_TO_HTTP ++ {"REDIRECTION_FROM_HTTPS_TO_HTTP", ERR_LIB_HTTP, HTTP_R_REDIRECTION_FROM_HTTPS_TO_HTTP}, ++ #else ++ {"REDIRECTION_FROM_HTTPS_TO_HTTP", 61, 112}, ++ #endif ++ #ifdef HTTP_R_REDIRECTION_NOT_ENABLED ++ {"REDIRECTION_NOT_ENABLED", ERR_LIB_HTTP, HTTP_R_REDIRECTION_NOT_ENABLED}, ++ #else ++ {"REDIRECTION_NOT_ENABLED", 61, 116}, ++ #endif ++ #ifdef HTTP_R_RESPONSE_LINE_TOO_LONG ++ {"RESPONSE_LINE_TOO_LONG", ERR_LIB_HTTP, HTTP_R_RESPONSE_LINE_TOO_LONG}, ++ #else ++ {"RESPONSE_LINE_TOO_LONG", 61, 113}, ++ #endif ++ #ifdef HTTP_R_RESPONSE_PARSE_ERROR ++ {"RESPONSE_PARSE_ERROR", ERR_LIB_HTTP, HTTP_R_RESPONSE_PARSE_ERROR}, ++ #else ++ {"RESPONSE_PARSE_ERROR", 61, 104}, ++ #endif ++ #ifdef HTTP_R_RESPONSE_TOO_MANY_HDRLINES ++ {"RESPONSE_TOO_MANY_HDRLINES", ERR_LIB_HTTP, HTTP_R_RESPONSE_TOO_MANY_HDRLINES}, ++ #else ++ {"RESPONSE_TOO_MANY_HDRLINES", 61, 130}, ++ #endif ++ #ifdef HTTP_R_RETRY_TIMEOUT ++ {"RETRY_TIMEOUT", ERR_LIB_HTTP, HTTP_R_RETRY_TIMEOUT}, ++ #else ++ {"RETRY_TIMEOUT", 61, 129}, ++ #endif ++ #ifdef HTTP_R_SERVER_CANCELED_CONNECTION ++ {"SERVER_CANCELED_CONNECTION", ERR_LIB_HTTP, HTTP_R_SERVER_CANCELED_CONNECTION}, ++ #else ++ {"SERVER_CANCELED_CONNECTION", 61, 127}, ++ #endif ++ #ifdef HTTP_R_SOCK_NOT_SUPPORTED ++ {"SOCK_NOT_SUPPORTED", ERR_LIB_HTTP, HTTP_R_SOCK_NOT_SUPPORTED}, ++ #else ++ {"SOCK_NOT_SUPPORTED", 61, 122}, ++ #endif ++ #ifdef HTTP_R_STATUS_CODE_UNSUPPORTED ++ {"STATUS_CODE_UNSUPPORTED", ERR_LIB_HTTP, HTTP_R_STATUS_CODE_UNSUPPORTED}, ++ #else ++ {"STATUS_CODE_UNSUPPORTED", 61, 114}, ++ #endif ++ #ifdef HTTP_R_TLS_NOT_ENABLED ++ {"TLS_NOT_ENABLED", ERR_LIB_HTTP, HTTP_R_TLS_NOT_ENABLED}, ++ #else ++ {"TLS_NOT_ENABLED", 61, 107}, ++ #endif ++ #ifdef HTTP_R_TOO_MANY_REDIRECTIONS ++ {"TOO_MANY_REDIRECTIONS", ERR_LIB_HTTP, HTTP_R_TOO_MANY_REDIRECTIONS}, ++ #else ++ {"TOO_MANY_REDIRECTIONS", 61, 115}, ++ #endif ++ #ifdef HTTP_R_UNEXPECTED_CONTENT_TYPE ++ {"UNEXPECTED_CONTENT_TYPE", ERR_LIB_HTTP, HTTP_R_UNEXPECTED_CONTENT_TYPE}, ++ #else ++ {"UNEXPECTED_CONTENT_TYPE", 61, 118}, ++ #endif ++ #ifdef OBJ_R_OID_EXISTS ++ {"OID_EXISTS", ERR_LIB_OBJ, OBJ_R_OID_EXISTS}, ++ #else ++ {"OID_EXISTS", 8, 102}, ++ #endif ++ #ifdef OBJ_R_UNKNOWN_NID ++ {"UNKNOWN_NID", ERR_LIB_OBJ, OBJ_R_UNKNOWN_NID}, ++ #else ++ {"UNKNOWN_NID", 8, 101}, ++ #endif ++ #ifdef OBJ_R_UNKNOWN_OBJECT_NAME ++ {"UNKNOWN_OBJECT_NAME", ERR_LIB_OBJ, OBJ_R_UNKNOWN_OBJECT_NAME}, ++ #else ++ {"UNKNOWN_OBJECT_NAME", 8, 103}, ++ #endif ++ #ifdef OCSP_R_CERTIFICATE_VERIFY_ERROR ++ {"CERTIFICATE_VERIFY_ERROR", ERR_LIB_OCSP, OCSP_R_CERTIFICATE_VERIFY_ERROR}, ++ #else ++ {"CERTIFICATE_VERIFY_ERROR", 39, 101}, ++ #endif ++ #ifdef OCSP_R_DIGEST_ERR ++ {"DIGEST_ERR", ERR_LIB_OCSP, OCSP_R_DIGEST_ERR}, ++ #else ++ {"DIGEST_ERR", 39, 102}, ++ #endif ++ #ifdef OCSP_R_DIGEST_NAME_ERR ++ {"DIGEST_NAME_ERR", ERR_LIB_OCSP, OCSP_R_DIGEST_NAME_ERR}, ++ #else ++ {"DIGEST_NAME_ERR", 39, 106}, ++ #endif ++ #ifdef OCSP_R_DIGEST_SIZE_ERR ++ {"DIGEST_SIZE_ERR", ERR_LIB_OCSP, OCSP_R_DIGEST_SIZE_ERR}, ++ #else ++ {"DIGEST_SIZE_ERR", 39, 107}, ++ #endif ++ #ifdef OCSP_R_ERROR_IN_NEXTUPDATE_FIELD ++ {"ERROR_IN_NEXTUPDATE_FIELD", ERR_LIB_OCSP, OCSP_R_ERROR_IN_NEXTUPDATE_FIELD}, ++ #else ++ {"ERROR_IN_NEXTUPDATE_FIELD", 39, 122}, ++ #endif ++ #ifdef OCSP_R_ERROR_IN_THISUPDATE_FIELD ++ {"ERROR_IN_THISUPDATE_FIELD", ERR_LIB_OCSP, OCSP_R_ERROR_IN_THISUPDATE_FIELD}, ++ #else ++ {"ERROR_IN_THISUPDATE_FIELD", 39, 123}, ++ #endif ++ #ifdef OCSP_R_MISSING_OCSPSIGNING_USAGE ++ {"MISSING_OCSPSIGNING_USAGE", ERR_LIB_OCSP, OCSP_R_MISSING_OCSPSIGNING_USAGE}, ++ #else ++ {"MISSING_OCSPSIGNING_USAGE", 39, 103}, ++ #endif ++ #ifdef OCSP_R_NEXTUPDATE_BEFORE_THISUPDATE ++ {"NEXTUPDATE_BEFORE_THISUPDATE", ERR_LIB_OCSP, OCSP_R_NEXTUPDATE_BEFORE_THISUPDATE}, ++ #else ++ {"NEXTUPDATE_BEFORE_THISUPDATE", 39, 124}, ++ #endif ++ #ifdef OCSP_R_NOT_BASIC_RESPONSE ++ {"NOT_BASIC_RESPONSE", ERR_LIB_OCSP, OCSP_R_NOT_BASIC_RESPONSE}, ++ #else ++ {"NOT_BASIC_RESPONSE", 39, 104}, ++ #endif ++ #ifdef OCSP_R_NO_CERTIFICATES_IN_CHAIN ++ {"NO_CERTIFICATES_IN_CHAIN", ERR_LIB_OCSP, OCSP_R_NO_CERTIFICATES_IN_CHAIN}, ++ #else ++ {"NO_CERTIFICATES_IN_CHAIN", 39, 105}, ++ #endif ++ #ifdef OCSP_R_NO_RESPONSE_DATA ++ {"NO_RESPONSE_DATA", ERR_LIB_OCSP, OCSP_R_NO_RESPONSE_DATA}, ++ #else ++ {"NO_RESPONSE_DATA", 39, 108}, ++ #endif ++ #ifdef OCSP_R_NO_REVOKED_TIME ++ {"NO_REVOKED_TIME", ERR_LIB_OCSP, OCSP_R_NO_REVOKED_TIME}, ++ #else ++ {"NO_REVOKED_TIME", 39, 109}, ++ #endif ++ #ifdef OCSP_R_NO_SIGNER_KEY ++ {"NO_SIGNER_KEY", ERR_LIB_OCSP, OCSP_R_NO_SIGNER_KEY}, ++ #else ++ {"NO_SIGNER_KEY", 39, 130}, ++ #endif ++ #ifdef OCSP_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE ++ {"PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE", ERR_LIB_OCSP, OCSP_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE}, ++ #else ++ {"PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE", 39, 110}, ++ #endif ++ #ifdef OCSP_R_REQUEST_NOT_SIGNED ++ {"REQUEST_NOT_SIGNED", ERR_LIB_OCSP, OCSP_R_REQUEST_NOT_SIGNED}, ++ #else ++ {"REQUEST_NOT_SIGNED", 39, 128}, ++ #endif ++ #ifdef OCSP_R_RESPONSE_CONTAINS_NO_REVOCATION_DATA ++ {"RESPONSE_CONTAINS_NO_REVOCATION_DATA", ERR_LIB_OCSP, OCSP_R_RESPONSE_CONTAINS_NO_REVOCATION_DATA}, ++ #else ++ {"RESPONSE_CONTAINS_NO_REVOCATION_DATA", 39, 111}, ++ #endif ++ #ifdef OCSP_R_ROOT_CA_NOT_TRUSTED ++ {"ROOT_CA_NOT_TRUSTED", ERR_LIB_OCSP, OCSP_R_ROOT_CA_NOT_TRUSTED}, ++ #else ++ {"ROOT_CA_NOT_TRUSTED", 39, 112}, ++ #endif ++ #ifdef OCSP_R_SIGNATURE_FAILURE ++ {"SIGNATURE_FAILURE", ERR_LIB_OCSP, OCSP_R_SIGNATURE_FAILURE}, ++ #else ++ {"SIGNATURE_FAILURE", 39, 117}, ++ #endif ++ #ifdef OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND ++ {"SIGNER_CERTIFICATE_NOT_FOUND", ERR_LIB_OCSP, OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND}, ++ #else ++ {"SIGNER_CERTIFICATE_NOT_FOUND", 39, 118}, ++ #endif ++ #ifdef OCSP_R_STATUS_EXPIRED ++ {"STATUS_EXPIRED", ERR_LIB_OCSP, OCSP_R_STATUS_EXPIRED}, ++ #else ++ {"STATUS_EXPIRED", 39, 125}, ++ #endif ++ #ifdef OCSP_R_STATUS_NOT_YET_VALID ++ {"STATUS_NOT_YET_VALID", ERR_LIB_OCSP, OCSP_R_STATUS_NOT_YET_VALID}, ++ #else ++ {"STATUS_NOT_YET_VALID", 39, 126}, ++ #endif ++ #ifdef OCSP_R_STATUS_TOO_OLD ++ {"STATUS_TOO_OLD", ERR_LIB_OCSP, OCSP_R_STATUS_TOO_OLD}, ++ #else ++ {"STATUS_TOO_OLD", 39, 127}, ++ #endif ++ #ifdef OCSP_R_UNKNOWN_MESSAGE_DIGEST ++ {"UNKNOWN_MESSAGE_DIGEST", ERR_LIB_OCSP, OCSP_R_UNKNOWN_MESSAGE_DIGEST}, ++ #else ++ {"UNKNOWN_MESSAGE_DIGEST", 39, 119}, ++ #endif ++ #ifdef OCSP_R_UNKNOWN_NID ++ {"UNKNOWN_NID", ERR_LIB_OCSP, OCSP_R_UNKNOWN_NID}, ++ #else ++ {"UNKNOWN_NID", 39, 120}, ++ #endif ++ #ifdef OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE ++ {"UNSUPPORTED_REQUESTORNAME_TYPE", ERR_LIB_OCSP, OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE}, ++ #else ++ {"UNSUPPORTED_REQUESTORNAME_TYPE", 39, 129}, ++ #endif ++ #ifdef OSSL_DECODER_R_COULD_NOT_DECODE_OBJECT ++ {"COULD_NOT_DECODE_OBJECT", ERR_LIB_OSSL_DECODER, OSSL_DECODER_R_COULD_NOT_DECODE_OBJECT}, ++ #else ++ {"COULD_NOT_DECODE_OBJECT", 60, 101}, ++ #endif ++ #ifdef OSSL_DECODER_R_DECODER_NOT_FOUND ++ {"DECODER_NOT_FOUND", ERR_LIB_OSSL_DECODER, OSSL_DECODER_R_DECODER_NOT_FOUND}, ++ #else ++ {"DECODER_NOT_FOUND", 60, 102}, ++ #endif ++ #ifdef OSSL_DECODER_R_MISSING_GET_PARAMS ++ {"MISSING_GET_PARAMS", ERR_LIB_OSSL_DECODER, OSSL_DECODER_R_MISSING_GET_PARAMS}, ++ #else ++ {"MISSING_GET_PARAMS", 60, 100}, ++ #endif ++ #ifdef OSSL_ENCODER_R_ENCODER_NOT_FOUND ++ {"ENCODER_NOT_FOUND", ERR_LIB_OSSL_ENCODER, OSSL_ENCODER_R_ENCODER_NOT_FOUND}, ++ #else ++ {"ENCODER_NOT_FOUND", 59, 101}, ++ #endif ++ #ifdef OSSL_ENCODER_R_INCORRECT_PROPERTY_QUERY ++ {"INCORRECT_PROPERTY_QUERY", ERR_LIB_OSSL_ENCODER, OSSL_ENCODER_R_INCORRECT_PROPERTY_QUERY}, ++ #else ++ {"INCORRECT_PROPERTY_QUERY", 59, 100}, ++ #endif ++ #ifdef OSSL_ENCODER_R_MISSING_GET_PARAMS ++ {"MISSING_GET_PARAMS", ERR_LIB_OSSL_ENCODER, OSSL_ENCODER_R_MISSING_GET_PARAMS}, ++ #else ++ {"MISSING_GET_PARAMS", 59, 102}, ++ #endif ++ #ifdef OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE ++ {"AMBIGUOUS_CONTENT_TYPE", ERR_LIB_OSSL_STORE, OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE}, ++ #else ++ {"AMBIGUOUS_CONTENT_TYPE", 44, 107}, ++ #endif ++ #ifdef OSSL_STORE_R_BAD_PASSWORD_READ ++ {"BAD_PASSWORD_READ", ERR_LIB_OSSL_STORE, OSSL_STORE_R_BAD_PASSWORD_READ}, ++ #else ++ {"BAD_PASSWORD_READ", 44, 115}, ++ #endif ++ #ifdef OSSL_STORE_R_ERROR_VERIFYING_PKCS12_MAC ++ {"ERROR_VERIFYING_PKCS12_MAC", ERR_LIB_OSSL_STORE, OSSL_STORE_R_ERROR_VERIFYING_PKCS12_MAC}, ++ #else ++ {"ERROR_VERIFYING_PKCS12_MAC", 44, 113}, ++ #endif ++ #ifdef OSSL_STORE_R_FINGERPRINT_SIZE_DOES_NOT_MATCH_DIGEST ++ {"FINGERPRINT_SIZE_DOES_NOT_MATCH_DIGEST", ERR_LIB_OSSL_STORE, OSSL_STORE_R_FINGERPRINT_SIZE_DOES_NOT_MATCH_DIGEST}, ++ #else ++ {"FINGERPRINT_SIZE_DOES_NOT_MATCH_DIGEST", 44, 121}, ++ #endif ++ #ifdef OSSL_STORE_R_INVALID_SCHEME ++ {"INVALID_SCHEME", ERR_LIB_OSSL_STORE, OSSL_STORE_R_INVALID_SCHEME}, ++ #else ++ {"INVALID_SCHEME", 44, 106}, ++ #endif ++ #ifdef OSSL_STORE_R_IS_NOT_A ++ {"IS_NOT_A", ERR_LIB_OSSL_STORE, OSSL_STORE_R_IS_NOT_A}, ++ #else ++ {"IS_NOT_A", 44, 112}, ++ #endif ++ #ifdef OSSL_STORE_R_LOADER_INCOMPLETE ++ {"LOADER_INCOMPLETE", ERR_LIB_OSSL_STORE, OSSL_STORE_R_LOADER_INCOMPLETE}, ++ #else ++ {"LOADER_INCOMPLETE", 44, 116}, ++ #endif ++ #ifdef OSSL_STORE_R_LOADING_STARTED ++ {"LOADING_STARTED", ERR_LIB_OSSL_STORE, OSSL_STORE_R_LOADING_STARTED}, ++ #else ++ {"LOADING_STARTED", 44, 117}, ++ #endif ++ #ifdef OSSL_STORE_R_NOT_A_CERTIFICATE ++ {"NOT_A_CERTIFICATE", ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_CERTIFICATE}, ++ #else ++ {"NOT_A_CERTIFICATE", 44, 100}, ++ #endif ++ #ifdef OSSL_STORE_R_NOT_A_CRL ++ {"NOT_A_CRL", ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_CRL}, ++ #else ++ {"NOT_A_CRL", 44, 101}, ++ #endif ++ #ifdef OSSL_STORE_R_NOT_A_NAME ++ {"NOT_A_NAME", ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_NAME}, ++ #else ++ {"NOT_A_NAME", 44, 103}, ++ #endif ++ #ifdef OSSL_STORE_R_NOT_A_PRIVATE_KEY ++ {"NOT_A_PRIVATE_KEY", ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_PRIVATE_KEY}, ++ #else ++ {"NOT_A_PRIVATE_KEY", 44, 102}, ++ #endif ++ #ifdef OSSL_STORE_R_NOT_A_PUBLIC_KEY ++ {"NOT_A_PUBLIC_KEY", ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_PUBLIC_KEY}, ++ #else ++ {"NOT_A_PUBLIC_KEY", 44, 122}, ++ #endif ++ #ifdef OSSL_STORE_R_NOT_PARAMETERS ++ {"NOT_PARAMETERS", ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_PARAMETERS}, ++ #else ++ {"NOT_PARAMETERS", 44, 104}, ++ #endif ++ #ifdef OSSL_STORE_R_NO_LOADERS_FOUND ++ {"NO_LOADERS_FOUND", ERR_LIB_OSSL_STORE, OSSL_STORE_R_NO_LOADERS_FOUND}, ++ #else ++ {"NO_LOADERS_FOUND", 44, 123}, ++ #endif ++ #ifdef OSSL_STORE_R_PASSPHRASE_CALLBACK_ERROR ++ {"PASSPHRASE_CALLBACK_ERROR", ERR_LIB_OSSL_STORE, OSSL_STORE_R_PASSPHRASE_CALLBACK_ERROR}, ++ #else ++ {"PASSPHRASE_CALLBACK_ERROR", 44, 114}, ++ #endif ++ #ifdef OSSL_STORE_R_PATH_MUST_BE_ABSOLUTE ++ {"PATH_MUST_BE_ABSOLUTE", ERR_LIB_OSSL_STORE, OSSL_STORE_R_PATH_MUST_BE_ABSOLUTE}, ++ #else ++ {"PATH_MUST_BE_ABSOLUTE", 44, 108}, ++ #endif ++ #ifdef OSSL_STORE_R_SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES ++ {"SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES", ERR_LIB_OSSL_STORE, OSSL_STORE_R_SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES}, ++ #else ++ {"SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES", 44, 119}, ++ #endif ++ #ifdef OSSL_STORE_R_UI_PROCESS_INTERRUPTED_OR_CANCELLED ++ {"UI_PROCESS_INTERRUPTED_OR_CANCELLED", ERR_LIB_OSSL_STORE, OSSL_STORE_R_UI_PROCESS_INTERRUPTED_OR_CANCELLED}, ++ #else ++ {"UI_PROCESS_INTERRUPTED_OR_CANCELLED", 44, 109}, ++ #endif ++ #ifdef OSSL_STORE_R_UNREGISTERED_SCHEME ++ {"UNREGISTERED_SCHEME", ERR_LIB_OSSL_STORE, OSSL_STORE_R_UNREGISTERED_SCHEME}, ++ #else ++ {"UNREGISTERED_SCHEME", 44, 105}, ++ #endif ++ #ifdef OSSL_STORE_R_UNSUPPORTED_CONTENT_TYPE ++ {"UNSUPPORTED_CONTENT_TYPE", ERR_LIB_OSSL_STORE, OSSL_STORE_R_UNSUPPORTED_CONTENT_TYPE}, ++ #else ++ {"UNSUPPORTED_CONTENT_TYPE", 44, 110}, ++ #endif ++ #ifdef OSSL_STORE_R_UNSUPPORTED_OPERATION ++ {"UNSUPPORTED_OPERATION", ERR_LIB_OSSL_STORE, OSSL_STORE_R_UNSUPPORTED_OPERATION}, ++ #else ++ {"UNSUPPORTED_OPERATION", 44, 118}, ++ #endif ++ #ifdef OSSL_STORE_R_UNSUPPORTED_SEARCH_TYPE ++ {"UNSUPPORTED_SEARCH_TYPE", ERR_LIB_OSSL_STORE, OSSL_STORE_R_UNSUPPORTED_SEARCH_TYPE}, ++ #else ++ {"UNSUPPORTED_SEARCH_TYPE", 44, 120}, ++ #endif ++ #ifdef OSSL_STORE_R_URI_AUTHORITY_UNSUPPORTED ++ {"URI_AUTHORITY_UNSUPPORTED", ERR_LIB_OSSL_STORE, OSSL_STORE_R_URI_AUTHORITY_UNSUPPORTED}, ++ #else ++ {"URI_AUTHORITY_UNSUPPORTED", 44, 111}, ++ #endif ++ #ifdef PEM_R_BAD_BASE64_DECODE ++ {"BAD_BASE64_DECODE", ERR_LIB_PEM, PEM_R_BAD_BASE64_DECODE}, ++ #else ++ {"BAD_BASE64_DECODE", 9, 100}, ++ #endif ++ #ifdef PEM_R_BAD_DECRYPT ++ {"BAD_DECRYPT", ERR_LIB_PEM, PEM_R_BAD_DECRYPT}, ++ #else ++ {"BAD_DECRYPT", 9, 101}, ++ #endif ++ #ifdef PEM_R_BAD_END_LINE ++ {"BAD_END_LINE", ERR_LIB_PEM, PEM_R_BAD_END_LINE}, ++ #else ++ {"BAD_END_LINE", 9, 102}, ++ #endif ++ #ifdef PEM_R_BAD_IV_CHARS ++ {"BAD_IV_CHARS", ERR_LIB_PEM, PEM_R_BAD_IV_CHARS}, ++ #else ++ {"BAD_IV_CHARS", 9, 103}, ++ #endif ++ #ifdef PEM_R_BAD_MAGIC_NUMBER ++ {"BAD_MAGIC_NUMBER", ERR_LIB_PEM, PEM_R_BAD_MAGIC_NUMBER}, ++ #else ++ {"BAD_MAGIC_NUMBER", 9, 116}, ++ #endif ++ #ifdef PEM_R_BAD_PASSWORD_READ ++ {"BAD_PASSWORD_READ", ERR_LIB_PEM, PEM_R_BAD_PASSWORD_READ}, ++ #else ++ {"BAD_PASSWORD_READ", 9, 104}, ++ #endif ++ #ifdef PEM_R_BAD_VERSION_NUMBER ++ {"BAD_VERSION_NUMBER", ERR_LIB_PEM, PEM_R_BAD_VERSION_NUMBER}, ++ #else ++ {"BAD_VERSION_NUMBER", 9, 117}, ++ #endif ++ #ifdef PEM_R_BIO_WRITE_FAILURE ++ {"BIO_WRITE_FAILURE", ERR_LIB_PEM, PEM_R_BIO_WRITE_FAILURE}, ++ #else ++ {"BIO_WRITE_FAILURE", 9, 118}, ++ #endif ++ #ifdef PEM_R_CIPHER_IS_NULL ++ {"CIPHER_IS_NULL", ERR_LIB_PEM, PEM_R_CIPHER_IS_NULL}, ++ #else ++ {"CIPHER_IS_NULL", 9, 127}, ++ #endif ++ #ifdef PEM_R_ERROR_CONVERTING_PRIVATE_KEY ++ {"ERROR_CONVERTING_PRIVATE_KEY", ERR_LIB_PEM, PEM_R_ERROR_CONVERTING_PRIVATE_KEY}, ++ #else ++ {"ERROR_CONVERTING_PRIVATE_KEY", 9, 115}, ++ #endif ++ #ifdef PEM_R_EXPECTING_DSS_KEY_BLOB ++ {"EXPECTING_DSS_KEY_BLOB", ERR_LIB_PEM, PEM_R_EXPECTING_DSS_KEY_BLOB}, ++ #else ++ {"EXPECTING_DSS_KEY_BLOB", 9, 131}, ++ #endif ++ #ifdef PEM_R_EXPECTING_PRIVATE_KEY_BLOB ++ {"EXPECTING_PRIVATE_KEY_BLOB", ERR_LIB_PEM, PEM_R_EXPECTING_PRIVATE_KEY_BLOB}, ++ #else ++ {"EXPECTING_PRIVATE_KEY_BLOB", 9, 119}, ++ #endif ++ #ifdef PEM_R_EXPECTING_PUBLIC_KEY_BLOB ++ {"EXPECTING_PUBLIC_KEY_BLOB", ERR_LIB_PEM, PEM_R_EXPECTING_PUBLIC_KEY_BLOB}, ++ #else ++ {"EXPECTING_PUBLIC_KEY_BLOB", 9, 120}, ++ #endif ++ #ifdef PEM_R_EXPECTING_RSA_KEY_BLOB ++ {"EXPECTING_RSA_KEY_BLOB", ERR_LIB_PEM, PEM_R_EXPECTING_RSA_KEY_BLOB}, ++ #else ++ {"EXPECTING_RSA_KEY_BLOB", 9, 132}, ++ #endif ++ #ifdef PEM_R_HEADER_TOO_LONG ++ {"HEADER_TOO_LONG", ERR_LIB_PEM, PEM_R_HEADER_TOO_LONG}, ++ #else ++ {"HEADER_TOO_LONG", 9, 128}, ++ #endif ++ #ifdef PEM_R_INCONSISTENT_HEADER ++ {"INCONSISTENT_HEADER", ERR_LIB_PEM, PEM_R_INCONSISTENT_HEADER}, ++ #else ++ {"INCONSISTENT_HEADER", 9, 121}, ++ #endif ++ #ifdef PEM_R_KEYBLOB_HEADER_PARSE_ERROR ++ {"KEYBLOB_HEADER_PARSE_ERROR", ERR_LIB_PEM, PEM_R_KEYBLOB_HEADER_PARSE_ERROR}, ++ #else ++ {"KEYBLOB_HEADER_PARSE_ERROR", 9, 122}, ++ #endif ++ #ifdef PEM_R_KEYBLOB_TOO_SHORT ++ {"KEYBLOB_TOO_SHORT", ERR_LIB_PEM, PEM_R_KEYBLOB_TOO_SHORT}, ++ #else ++ {"KEYBLOB_TOO_SHORT", 9, 123}, ++ #endif ++ #ifdef PEM_R_MISSING_DEK_IV ++ {"MISSING_DEK_IV", ERR_LIB_PEM, PEM_R_MISSING_DEK_IV}, ++ #else ++ {"MISSING_DEK_IV", 9, 129}, ++ #endif ++ #ifdef PEM_R_NOT_DEK_INFO ++ {"NOT_DEK_INFO", ERR_LIB_PEM, PEM_R_NOT_DEK_INFO}, ++ #else ++ {"NOT_DEK_INFO", 9, 105}, ++ #endif ++ #ifdef PEM_R_NOT_ENCRYPTED ++ {"NOT_ENCRYPTED", ERR_LIB_PEM, PEM_R_NOT_ENCRYPTED}, ++ #else ++ {"NOT_ENCRYPTED", 9, 106}, ++ #endif ++ #ifdef PEM_R_NOT_PROC_TYPE ++ {"NOT_PROC_TYPE", ERR_LIB_PEM, PEM_R_NOT_PROC_TYPE}, ++ #else ++ {"NOT_PROC_TYPE", 9, 107}, ++ #endif ++ #ifdef PEM_R_NO_START_LINE ++ {"NO_START_LINE", ERR_LIB_PEM, PEM_R_NO_START_LINE}, ++ #else ++ {"NO_START_LINE", 9, 108}, ++ #endif ++ #ifdef PEM_R_PROBLEMS_GETTING_PASSWORD ++ {"PROBLEMS_GETTING_PASSWORD", ERR_LIB_PEM, PEM_R_PROBLEMS_GETTING_PASSWORD}, ++ #else ++ {"PROBLEMS_GETTING_PASSWORD", 9, 109}, ++ #endif ++ #ifdef PEM_R_PVK_DATA_TOO_SHORT ++ {"PVK_DATA_TOO_SHORT", ERR_LIB_PEM, PEM_R_PVK_DATA_TOO_SHORT}, ++ #else ++ {"PVK_DATA_TOO_SHORT", 9, 124}, ++ #endif ++ #ifdef PEM_R_PVK_TOO_SHORT ++ {"PVK_TOO_SHORT", ERR_LIB_PEM, PEM_R_PVK_TOO_SHORT}, ++ #else ++ {"PVK_TOO_SHORT", 9, 125}, ++ #endif ++ #ifdef PEM_R_READ_KEY ++ {"READ_KEY", ERR_LIB_PEM, PEM_R_READ_KEY}, ++ #else ++ {"READ_KEY", 9, 111}, ++ #endif ++ #ifdef PEM_R_SHORT_HEADER ++ {"SHORT_HEADER", ERR_LIB_PEM, PEM_R_SHORT_HEADER}, ++ #else ++ {"SHORT_HEADER", 9, 112}, ++ #endif ++ #ifdef PEM_R_UNEXPECTED_DEK_IV ++ {"UNEXPECTED_DEK_IV", ERR_LIB_PEM, PEM_R_UNEXPECTED_DEK_IV}, ++ #else ++ {"UNEXPECTED_DEK_IV", 9, 130}, ++ #endif ++ #ifdef PEM_R_UNSUPPORTED_CIPHER ++ {"UNSUPPORTED_CIPHER", ERR_LIB_PEM, PEM_R_UNSUPPORTED_CIPHER}, ++ #else ++ {"UNSUPPORTED_CIPHER", 9, 113}, ++ #endif ++ #ifdef PEM_R_UNSUPPORTED_ENCRYPTION ++ {"UNSUPPORTED_ENCRYPTION", ERR_LIB_PEM, PEM_R_UNSUPPORTED_ENCRYPTION}, ++ #else ++ {"UNSUPPORTED_ENCRYPTION", 9, 114}, ++ #endif ++ #ifdef PEM_R_UNSUPPORTED_KEY_COMPONENTS ++ {"UNSUPPORTED_KEY_COMPONENTS", ERR_LIB_PEM, PEM_R_UNSUPPORTED_KEY_COMPONENTS}, ++ #else ++ {"UNSUPPORTED_KEY_COMPONENTS", 9, 126}, ++ #endif ++ #ifdef PEM_R_UNSUPPORTED_PUBLIC_KEY_TYPE ++ {"UNSUPPORTED_PUBLIC_KEY_TYPE", ERR_LIB_PEM, PEM_R_UNSUPPORTED_PUBLIC_KEY_TYPE}, ++ #else ++ {"UNSUPPORTED_PUBLIC_KEY_TYPE", 9, 110}, ++ #endif ++ #ifdef PKCS12_R_CALLBACK_FAILED ++ {"CALLBACK_FAILED", ERR_LIB_PKCS12, PKCS12_R_CALLBACK_FAILED}, ++ #else ++ {"CALLBACK_FAILED", 35, 115}, ++ #endif ++ #ifdef PKCS12_R_CANT_PACK_STRUCTURE ++ {"CANT_PACK_STRUCTURE", ERR_LIB_PKCS12, PKCS12_R_CANT_PACK_STRUCTURE}, ++ #else ++ {"CANT_PACK_STRUCTURE", 35, 100}, ++ #endif ++ #ifdef PKCS12_R_CONTENT_TYPE_NOT_DATA ++ {"CONTENT_TYPE_NOT_DATA", ERR_LIB_PKCS12, PKCS12_R_CONTENT_TYPE_NOT_DATA}, ++ #else ++ {"CONTENT_TYPE_NOT_DATA", 35, 121}, ++ #endif ++ #ifdef PKCS12_R_DECODE_ERROR ++ {"DECODE_ERROR", ERR_LIB_PKCS12, PKCS12_R_DECODE_ERROR}, ++ #else ++ {"DECODE_ERROR", 35, 101}, ++ #endif ++ #ifdef PKCS12_R_ENCODE_ERROR ++ {"ENCODE_ERROR", ERR_LIB_PKCS12, PKCS12_R_ENCODE_ERROR}, ++ #else ++ {"ENCODE_ERROR", 35, 102}, ++ #endif ++ #ifdef PKCS12_R_ENCRYPT_ERROR ++ {"ENCRYPT_ERROR", ERR_LIB_PKCS12, PKCS12_R_ENCRYPT_ERROR}, ++ #else ++ {"ENCRYPT_ERROR", 35, 103}, ++ #endif ++ #ifdef PKCS12_R_ERROR_SETTING_ENCRYPTED_DATA_TYPE ++ {"ERROR_SETTING_ENCRYPTED_DATA_TYPE", ERR_LIB_PKCS12, PKCS12_R_ERROR_SETTING_ENCRYPTED_DATA_TYPE}, ++ #else ++ {"ERROR_SETTING_ENCRYPTED_DATA_TYPE", 35, 120}, ++ #endif ++ #ifdef PKCS12_R_INVALID_NULL_ARGUMENT ++ {"INVALID_NULL_ARGUMENT", ERR_LIB_PKCS12, PKCS12_R_INVALID_NULL_ARGUMENT}, ++ #else ++ {"INVALID_NULL_ARGUMENT", 35, 104}, ++ #endif ++ #ifdef PKCS12_R_INVALID_NULL_PKCS12_POINTER ++ {"INVALID_NULL_PKCS12_POINTER", ERR_LIB_PKCS12, PKCS12_R_INVALID_NULL_PKCS12_POINTER}, ++ #else ++ {"INVALID_NULL_PKCS12_POINTER", 35, 105}, ++ #endif ++ #ifdef PKCS12_R_INVALID_TYPE ++ {"INVALID_TYPE", ERR_LIB_PKCS12, PKCS12_R_INVALID_TYPE}, ++ #else ++ {"INVALID_TYPE", 35, 112}, ++ #endif ++ #ifdef PKCS12_R_IV_GEN_ERROR ++ {"IV_GEN_ERROR", ERR_LIB_PKCS12, PKCS12_R_IV_GEN_ERROR}, ++ #else ++ {"IV_GEN_ERROR", 35, 106}, ++ #endif ++ #ifdef PKCS12_R_KEY_GEN_ERROR ++ {"KEY_GEN_ERROR", ERR_LIB_PKCS12, PKCS12_R_KEY_GEN_ERROR}, ++ #else ++ {"KEY_GEN_ERROR", 35, 107}, ++ #endif ++ #ifdef PKCS12_R_MAC_ABSENT ++ {"MAC_ABSENT", ERR_LIB_PKCS12, PKCS12_R_MAC_ABSENT}, ++ #else ++ {"MAC_ABSENT", 35, 108}, ++ #endif ++ #ifdef PKCS12_R_MAC_GENERATION_ERROR ++ {"MAC_GENERATION_ERROR", ERR_LIB_PKCS12, PKCS12_R_MAC_GENERATION_ERROR}, ++ #else ++ {"MAC_GENERATION_ERROR", 35, 109}, ++ #endif ++ #ifdef PKCS12_R_MAC_SETUP_ERROR ++ {"MAC_SETUP_ERROR", ERR_LIB_PKCS12, PKCS12_R_MAC_SETUP_ERROR}, ++ #else ++ {"MAC_SETUP_ERROR", 35, 110}, ++ #endif ++ #ifdef PKCS12_R_MAC_STRING_SET_ERROR ++ {"MAC_STRING_SET_ERROR", ERR_LIB_PKCS12, PKCS12_R_MAC_STRING_SET_ERROR}, ++ #else ++ {"MAC_STRING_SET_ERROR", 35, 111}, ++ #endif ++ #ifdef PKCS12_R_MAC_VERIFY_FAILURE ++ {"MAC_VERIFY_FAILURE", ERR_LIB_PKCS12, PKCS12_R_MAC_VERIFY_FAILURE}, ++ #else ++ {"MAC_VERIFY_FAILURE", 35, 113}, ++ #endif ++ #ifdef PKCS12_R_PARSE_ERROR ++ {"PARSE_ERROR", ERR_LIB_PKCS12, PKCS12_R_PARSE_ERROR}, ++ #else ++ {"PARSE_ERROR", 35, 114}, ++ #endif ++ #ifdef PKCS12_R_PKCS12_CIPHERFINAL_ERROR ++ {"PKCS12_CIPHERFINAL_ERROR", ERR_LIB_PKCS12, PKCS12_R_PKCS12_CIPHERFINAL_ERROR}, ++ #else ++ {"PKCS12_CIPHERFINAL_ERROR", 35, 116}, ++ #endif ++ #ifdef PKCS12_R_UNKNOWN_DIGEST_ALGORITHM ++ {"UNKNOWN_DIGEST_ALGORITHM", ERR_LIB_PKCS12, PKCS12_R_UNKNOWN_DIGEST_ALGORITHM}, ++ #else ++ {"UNKNOWN_DIGEST_ALGORITHM", 35, 118}, ++ #endif ++ #ifdef PKCS12_R_UNSUPPORTED_PKCS12_MODE ++ {"UNSUPPORTED_PKCS12_MODE", ERR_LIB_PKCS12, PKCS12_R_UNSUPPORTED_PKCS12_MODE}, ++ #else ++ {"UNSUPPORTED_PKCS12_MODE", 35, 119}, ++ #endif ++ #ifdef PKCS7_R_CERTIFICATE_VERIFY_ERROR ++ {"CERTIFICATE_VERIFY_ERROR", ERR_LIB_PKCS7, PKCS7_R_CERTIFICATE_VERIFY_ERROR}, ++ #else ++ {"CERTIFICATE_VERIFY_ERROR", 33, 117}, ++ #endif ++ #ifdef PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER ++ {"CIPHER_HAS_NO_OBJECT_IDENTIFIER", ERR_LIB_PKCS7, PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER}, ++ #else ++ {"CIPHER_HAS_NO_OBJECT_IDENTIFIER", 33, 144}, ++ #endif ++ #ifdef PKCS7_R_CIPHER_NOT_INITIALIZED ++ {"CIPHER_NOT_INITIALIZED", ERR_LIB_PKCS7, PKCS7_R_CIPHER_NOT_INITIALIZED}, ++ #else ++ {"CIPHER_NOT_INITIALIZED", 33, 116}, ++ #endif ++ #ifdef PKCS7_R_CONTENT_AND_DATA_PRESENT ++ {"CONTENT_AND_DATA_PRESENT", ERR_LIB_PKCS7, PKCS7_R_CONTENT_AND_DATA_PRESENT}, ++ #else ++ {"CONTENT_AND_DATA_PRESENT", 33, 118}, ++ #endif ++ #ifdef PKCS7_R_CTRL_ERROR ++ {"CTRL_ERROR", ERR_LIB_PKCS7, PKCS7_R_CTRL_ERROR}, ++ #else ++ {"CTRL_ERROR", 33, 152}, ++ #endif ++ #ifdef PKCS7_R_DECRYPT_ERROR ++ {"DECRYPT_ERROR", ERR_LIB_PKCS7, PKCS7_R_DECRYPT_ERROR}, ++ #else ++ {"DECRYPT_ERROR", 33, 119}, ++ #endif ++ #ifdef PKCS7_R_DIGEST_FAILURE ++ {"DIGEST_FAILURE", ERR_LIB_PKCS7, PKCS7_R_DIGEST_FAILURE}, ++ #else ++ {"DIGEST_FAILURE", 33, 101}, ++ #endif ++ #ifdef PKCS7_R_ENCRYPTION_CTRL_FAILURE ++ {"ENCRYPTION_CTRL_FAILURE", ERR_LIB_PKCS7, PKCS7_R_ENCRYPTION_CTRL_FAILURE}, ++ #else ++ {"ENCRYPTION_CTRL_FAILURE", 33, 149}, ++ #endif ++ #ifdef PKCS7_R_ENCRYPTION_NOT_SUPPORTED_FOR_THIS_KEY_TYPE ++ {"ENCRYPTION_NOT_SUPPORTED_FOR_THIS_KEY_TYPE", ERR_LIB_PKCS7, PKCS7_R_ENCRYPTION_NOT_SUPPORTED_FOR_THIS_KEY_TYPE}, ++ #else ++ {"ENCRYPTION_NOT_SUPPORTED_FOR_THIS_KEY_TYPE", 33, 150}, ++ #endif ++ #ifdef PKCS7_R_ERROR_ADDING_RECIPIENT ++ {"ERROR_ADDING_RECIPIENT", ERR_LIB_PKCS7, PKCS7_R_ERROR_ADDING_RECIPIENT}, ++ #else ++ {"ERROR_ADDING_RECIPIENT", 33, 120}, ++ #endif ++ #ifdef PKCS7_R_ERROR_SETTING_CIPHER ++ {"ERROR_SETTING_CIPHER", ERR_LIB_PKCS7, PKCS7_R_ERROR_SETTING_CIPHER}, ++ #else ++ {"ERROR_SETTING_CIPHER", 33, 121}, ++ #endif ++ #ifdef PKCS7_R_INVALID_NULL_POINTER ++ {"INVALID_NULL_POINTER", ERR_LIB_PKCS7, PKCS7_R_INVALID_NULL_POINTER}, ++ #else ++ {"INVALID_NULL_POINTER", 33, 143}, ++ #endif ++ #ifdef PKCS7_R_INVALID_SIGNED_DATA_TYPE ++ {"INVALID_SIGNED_DATA_TYPE", ERR_LIB_PKCS7, PKCS7_R_INVALID_SIGNED_DATA_TYPE}, ++ #else ++ {"INVALID_SIGNED_DATA_TYPE", 33, 155}, ++ #endif ++ #ifdef PKCS7_R_NO_CONTENT ++ {"NO_CONTENT", ERR_LIB_PKCS7, PKCS7_R_NO_CONTENT}, ++ #else ++ {"NO_CONTENT", 33, 122}, ++ #endif ++ #ifdef PKCS7_R_NO_DEFAULT_DIGEST ++ {"NO_DEFAULT_DIGEST", ERR_LIB_PKCS7, PKCS7_R_NO_DEFAULT_DIGEST}, ++ #else ++ {"NO_DEFAULT_DIGEST", 33, 151}, ++ #endif ++ #ifdef PKCS7_R_NO_MATCHING_DIGEST_TYPE_FOUND ++ {"NO_MATCHING_DIGEST_TYPE_FOUND", ERR_LIB_PKCS7, PKCS7_R_NO_MATCHING_DIGEST_TYPE_FOUND}, ++ #else ++ {"NO_MATCHING_DIGEST_TYPE_FOUND", 33, 154}, ++ #endif ++ #ifdef PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE ++ {"NO_RECIPIENT_MATCHES_CERTIFICATE", ERR_LIB_PKCS7, PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE}, ++ #else ++ {"NO_RECIPIENT_MATCHES_CERTIFICATE", 33, 115}, ++ #endif ++ #ifdef PKCS7_R_NO_SIGNATURES_ON_DATA ++ {"NO_SIGNATURES_ON_DATA", ERR_LIB_PKCS7, PKCS7_R_NO_SIGNATURES_ON_DATA}, ++ #else ++ {"NO_SIGNATURES_ON_DATA", 33, 123}, ++ #endif ++ #ifdef PKCS7_R_NO_SIGNERS ++ {"NO_SIGNERS", ERR_LIB_PKCS7, PKCS7_R_NO_SIGNERS}, ++ #else ++ {"NO_SIGNERS", 33, 142}, ++ #endif ++ #ifdef PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE ++ {"OPERATION_NOT_SUPPORTED_ON_THIS_TYPE", ERR_LIB_PKCS7, PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE}, ++ #else ++ {"OPERATION_NOT_SUPPORTED_ON_THIS_TYPE", 33, 104}, ++ #endif ++ #ifdef PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR ++ {"PKCS7_ADD_SIGNATURE_ERROR", ERR_LIB_PKCS7, PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR}, ++ #else ++ {"PKCS7_ADD_SIGNATURE_ERROR", 33, 124}, ++ #endif ++ #ifdef PKCS7_R_PKCS7_ADD_SIGNER_ERROR ++ {"PKCS7_ADD_SIGNER_ERROR", ERR_LIB_PKCS7, PKCS7_R_PKCS7_ADD_SIGNER_ERROR}, ++ #else ++ {"PKCS7_ADD_SIGNER_ERROR", 33, 153}, ++ #endif ++ #ifdef PKCS7_R_PKCS7_DATASIGN ++ {"PKCS7_DATASIGN", ERR_LIB_PKCS7, PKCS7_R_PKCS7_DATASIGN}, ++ #else ++ {"PKCS7_DATASIGN", 33, 145}, ++ #endif ++ #ifdef PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE ++ {"PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE", ERR_LIB_PKCS7, PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE}, ++ #else ++ {"PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE", 33, 127}, ++ #endif ++ #ifdef PKCS7_R_SIGNATURE_FAILURE ++ {"SIGNATURE_FAILURE", ERR_LIB_PKCS7, PKCS7_R_SIGNATURE_FAILURE}, ++ #else ++ {"SIGNATURE_FAILURE", 33, 105}, ++ #endif ++ #ifdef PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND ++ {"SIGNER_CERTIFICATE_NOT_FOUND", ERR_LIB_PKCS7, PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND}, ++ #else ++ {"SIGNER_CERTIFICATE_NOT_FOUND", 33, 128}, ++ #endif ++ #ifdef PKCS7_R_SIGNING_CTRL_FAILURE ++ {"SIGNING_CTRL_FAILURE", ERR_LIB_PKCS7, PKCS7_R_SIGNING_CTRL_FAILURE}, ++ #else ++ {"SIGNING_CTRL_FAILURE", 33, 147}, ++ #endif ++ #ifdef PKCS7_R_SIGNING_NOT_SUPPORTED_FOR_THIS_KEY_TYPE ++ {"SIGNING_NOT_SUPPORTED_FOR_THIS_KEY_TYPE", ERR_LIB_PKCS7, PKCS7_R_SIGNING_NOT_SUPPORTED_FOR_THIS_KEY_TYPE}, ++ #else ++ {"SIGNING_NOT_SUPPORTED_FOR_THIS_KEY_TYPE", 33, 148}, ++ #endif ++ #ifdef PKCS7_R_SMIME_TEXT_ERROR ++ {"SMIME_TEXT_ERROR", ERR_LIB_PKCS7, PKCS7_R_SMIME_TEXT_ERROR}, ++ #else ++ {"SMIME_TEXT_ERROR", 33, 129}, ++ #endif ++ #ifdef PKCS7_R_UNABLE_TO_FIND_CERTIFICATE ++ {"UNABLE_TO_FIND_CERTIFICATE", ERR_LIB_PKCS7, PKCS7_R_UNABLE_TO_FIND_CERTIFICATE}, ++ #else ++ {"UNABLE_TO_FIND_CERTIFICATE", 33, 106}, ++ #endif ++ #ifdef PKCS7_R_UNABLE_TO_FIND_MEM_BIO ++ {"UNABLE_TO_FIND_MEM_BIO", ERR_LIB_PKCS7, PKCS7_R_UNABLE_TO_FIND_MEM_BIO}, ++ #else ++ {"UNABLE_TO_FIND_MEM_BIO", 33, 107}, ++ #endif ++ #ifdef PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST ++ {"UNABLE_TO_FIND_MESSAGE_DIGEST", ERR_LIB_PKCS7, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST}, ++ #else ++ {"UNABLE_TO_FIND_MESSAGE_DIGEST", 33, 108}, ++ #endif ++ #ifdef PKCS7_R_UNKNOWN_DIGEST_TYPE ++ {"UNKNOWN_DIGEST_TYPE", ERR_LIB_PKCS7, PKCS7_R_UNKNOWN_DIGEST_TYPE}, ++ #else ++ {"UNKNOWN_DIGEST_TYPE", 33, 109}, ++ #endif ++ #ifdef PKCS7_R_UNKNOWN_OPERATION ++ {"UNKNOWN_OPERATION", ERR_LIB_PKCS7, PKCS7_R_UNKNOWN_OPERATION}, ++ #else ++ {"UNKNOWN_OPERATION", 33, 110}, ++ #endif ++ #ifdef PKCS7_R_UNSUPPORTED_CIPHER_TYPE ++ {"UNSUPPORTED_CIPHER_TYPE", ERR_LIB_PKCS7, PKCS7_R_UNSUPPORTED_CIPHER_TYPE}, ++ #else ++ {"UNSUPPORTED_CIPHER_TYPE", 33, 111}, ++ #endif ++ #ifdef PKCS7_R_UNSUPPORTED_CONTENT_TYPE ++ {"UNSUPPORTED_CONTENT_TYPE", ERR_LIB_PKCS7, PKCS7_R_UNSUPPORTED_CONTENT_TYPE}, ++ #else ++ {"UNSUPPORTED_CONTENT_TYPE", 33, 112}, ++ #endif ++ #ifdef PKCS7_R_WRONG_CONTENT_TYPE ++ {"WRONG_CONTENT_TYPE", ERR_LIB_PKCS7, PKCS7_R_WRONG_CONTENT_TYPE}, ++ #else ++ {"WRONG_CONTENT_TYPE", 33, 113}, ++ #endif ++ #ifdef PKCS7_R_WRONG_PKCS7_TYPE ++ {"WRONG_PKCS7_TYPE", ERR_LIB_PKCS7, PKCS7_R_WRONG_PKCS7_TYPE}, ++ #else ++ {"WRONG_PKCS7_TYPE", 33, 114}, ++ #endif ++ #ifdef PROP_R_NAME_TOO_LONG ++ {"NAME_TOO_LONG", ERR_LIB_PROP, PROP_R_NAME_TOO_LONG}, ++ #else ++ {"NAME_TOO_LONG", 55, 100}, ++ #endif ++ #ifdef PROP_R_NOT_AN_ASCII_CHARACTER ++ {"NOT_AN_ASCII_CHARACTER", ERR_LIB_PROP, PROP_R_NOT_AN_ASCII_CHARACTER}, ++ #else ++ {"NOT_AN_ASCII_CHARACTER", 55, 101}, ++ #endif ++ #ifdef PROP_R_NOT_AN_HEXADECIMAL_DIGIT ++ {"NOT_AN_HEXADECIMAL_DIGIT", ERR_LIB_PROP, PROP_R_NOT_AN_HEXADECIMAL_DIGIT}, ++ #else ++ {"NOT_AN_HEXADECIMAL_DIGIT", 55, 102}, ++ #endif ++ #ifdef PROP_R_NOT_AN_IDENTIFIER ++ {"NOT_AN_IDENTIFIER", ERR_LIB_PROP, PROP_R_NOT_AN_IDENTIFIER}, ++ #else ++ {"NOT_AN_IDENTIFIER", 55, 103}, ++ #endif ++ #ifdef PROP_R_NOT_AN_OCTAL_DIGIT ++ {"NOT_AN_OCTAL_DIGIT", ERR_LIB_PROP, PROP_R_NOT_AN_OCTAL_DIGIT}, ++ #else ++ {"NOT_AN_OCTAL_DIGIT", 55, 104}, ++ #endif ++ #ifdef PROP_R_NOT_A_DECIMAL_DIGIT ++ {"NOT_A_DECIMAL_DIGIT", ERR_LIB_PROP, PROP_R_NOT_A_DECIMAL_DIGIT}, ++ #else ++ {"NOT_A_DECIMAL_DIGIT", 55, 105}, ++ #endif ++ #ifdef PROP_R_NO_MATCHING_STRING_DELIMITER ++ {"NO_MATCHING_STRING_DELIMITER", ERR_LIB_PROP, PROP_R_NO_MATCHING_STRING_DELIMITER}, ++ #else ++ {"NO_MATCHING_STRING_DELIMITER", 55, 106}, ++ #endif ++ #ifdef PROP_R_NO_VALUE ++ {"NO_VALUE", ERR_LIB_PROP, PROP_R_NO_VALUE}, ++ #else ++ {"NO_VALUE", 55, 107}, ++ #endif ++ #ifdef PROP_R_PARSE_FAILED ++ {"PARSE_FAILED", ERR_LIB_PROP, PROP_R_PARSE_FAILED}, ++ #else ++ {"PARSE_FAILED", 55, 108}, ++ #endif ++ #ifdef PROP_R_STRING_TOO_LONG ++ {"STRING_TOO_LONG", ERR_LIB_PROP, PROP_R_STRING_TOO_LONG}, ++ #else ++ {"STRING_TOO_LONG", 55, 109}, ++ #endif ++ #ifdef PROP_R_TRAILING_CHARACTERS ++ {"TRAILING_CHARACTERS", ERR_LIB_PROP, PROP_R_TRAILING_CHARACTERS}, ++ #else ++ {"TRAILING_CHARACTERS", 55, 110}, ++ #endif ++ #ifdef PROV_R_ADDITIONAL_INPUT_TOO_LONG ++ {"ADDITIONAL_INPUT_TOO_LONG", ERR_LIB_PROV, PROV_R_ADDITIONAL_INPUT_TOO_LONG}, ++ #else ++ {"ADDITIONAL_INPUT_TOO_LONG", 57, 184}, ++ #endif ++ #ifdef PROV_R_ALGORITHM_MISMATCH ++ {"ALGORITHM_MISMATCH", ERR_LIB_PROV, PROV_R_ALGORITHM_MISMATCH}, ++ #else ++ {"ALGORITHM_MISMATCH", 57, 173}, ++ #endif ++ #ifdef PROV_R_ALREADY_INSTANTIATED ++ {"ALREADY_INSTANTIATED", ERR_LIB_PROV, PROV_R_ALREADY_INSTANTIATED}, ++ #else ++ {"ALREADY_INSTANTIATED", 57, 185}, ++ #endif ++ #ifdef PROV_R_BAD_DECRYPT ++ {"BAD_DECRYPT", ERR_LIB_PROV, PROV_R_BAD_DECRYPT}, ++ #else ++ {"BAD_DECRYPT", 57, 100}, ++ #endif ++ #ifdef PROV_R_BAD_ENCODING ++ {"BAD_ENCODING", ERR_LIB_PROV, PROV_R_BAD_ENCODING}, ++ #else ++ {"BAD_ENCODING", 57, 141}, ++ #endif ++ #ifdef PROV_R_BAD_LENGTH ++ {"BAD_LENGTH", ERR_LIB_PROV, PROV_R_BAD_LENGTH}, ++ #else ++ {"BAD_LENGTH", 57, 142}, ++ #endif ++ #ifdef PROV_R_BAD_TLS_CLIENT_VERSION ++ {"BAD_TLS_CLIENT_VERSION", ERR_LIB_PROV, PROV_R_BAD_TLS_CLIENT_VERSION}, ++ #else ++ {"BAD_TLS_CLIENT_VERSION", 57, 161}, ++ #endif ++ #ifdef PROV_R_BN_ERROR ++ {"BN_ERROR", ERR_LIB_PROV, PROV_R_BN_ERROR}, ++ #else ++ {"BN_ERROR", 57, 160}, ++ #endif ++ #ifdef PROV_R_CIPHER_OPERATION_FAILED ++ {"CIPHER_OPERATION_FAILED", ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED}, ++ #else ++ {"CIPHER_OPERATION_FAILED", 57, 102}, ++ #endif ++ #ifdef PROV_R_COFACTOR_REQUIRED ++ {"COFACTOR_REQUIRED", ERR_LIB_PROV, PROV_R_COFACTOR_REQUIRED}, ++ #else ++ {"COFACTOR_REQUIRED", 57, 236}, ++ #endif ++ #ifdef PROV_R_DERIVATION_FUNCTION_INIT_FAILED ++ {"DERIVATION_FUNCTION_INIT_FAILED", ERR_LIB_PROV, PROV_R_DERIVATION_FUNCTION_INIT_FAILED}, ++ #else ++ {"DERIVATION_FUNCTION_INIT_FAILED", 57, 205}, ++ #endif ++ #ifdef PROV_R_DIGEST_NOT_ALLOWED ++ {"DIGEST_NOT_ALLOWED", ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED}, ++ #else ++ {"DIGEST_NOT_ALLOWED", 57, 174}, ++ #endif ++ #ifdef PROV_R_EMS_NOT_ENABLED ++ {"EMS_NOT_ENABLED", ERR_LIB_PROV, PROV_R_EMS_NOT_ENABLED}, ++ #else ++ {"EMS_NOT_ENABLED", 57, 233}, ++ #endif ++ #ifdef PROV_R_ENTROPY_SOURCE_FAILED_CONTINUOUS_TESTS ++ {"ENTROPY_SOURCE_FAILED_CONTINUOUS_TESTS", ERR_LIB_PROV, PROV_R_ENTROPY_SOURCE_FAILED_CONTINUOUS_TESTS}, ++ #else ++ {"ENTROPY_SOURCE_FAILED_CONTINUOUS_TESTS", 57, 244}, ++ #endif ++ #ifdef PROV_R_ENTROPY_SOURCE_STRENGTH_TOO_WEAK ++ {"ENTROPY_SOURCE_STRENGTH_TOO_WEAK", ERR_LIB_PROV, PROV_R_ENTROPY_SOURCE_STRENGTH_TOO_WEAK}, ++ #else ++ {"ENTROPY_SOURCE_STRENGTH_TOO_WEAK", 57, 186}, ++ #endif ++ #ifdef PROV_R_ERROR_INSTANTIATING_DRBG ++ {"ERROR_INSTANTIATING_DRBG", ERR_LIB_PROV, PROV_R_ERROR_INSTANTIATING_DRBG}, ++ #else ++ {"ERROR_INSTANTIATING_DRBG", 57, 188}, ++ #endif ++ #ifdef PROV_R_ERROR_RETRIEVING_ENTROPY ++ {"ERROR_RETRIEVING_ENTROPY", ERR_LIB_PROV, PROV_R_ERROR_RETRIEVING_ENTROPY}, ++ #else ++ {"ERROR_RETRIEVING_ENTROPY", 57, 189}, ++ #endif ++ #ifdef PROV_R_ERROR_RETRIEVING_NONCE ++ {"ERROR_RETRIEVING_NONCE", ERR_LIB_PROV, PROV_R_ERROR_RETRIEVING_NONCE}, ++ #else ++ {"ERROR_RETRIEVING_NONCE", 57, 190}, ++ #endif ++ #ifdef PROV_R_FAILED_DURING_DERIVATION ++ {"FAILED_DURING_DERIVATION", ERR_LIB_PROV, PROV_R_FAILED_DURING_DERIVATION}, ++ #else ++ {"FAILED_DURING_DERIVATION", 57, 164}, ++ #endif ++ #ifdef PROV_R_FAILED_TO_CREATE_LOCK ++ {"FAILED_TO_CREATE_LOCK", ERR_LIB_PROV, PROV_R_FAILED_TO_CREATE_LOCK}, ++ #else ++ {"FAILED_TO_CREATE_LOCK", 57, 180}, ++ #endif ++ #ifdef PROV_R_FAILED_TO_DECRYPT ++ {"FAILED_TO_DECRYPT", ERR_LIB_PROV, PROV_R_FAILED_TO_DECRYPT}, ++ #else ++ {"FAILED_TO_DECRYPT", 57, 162}, ++ #endif ++ #ifdef PROV_R_FAILED_TO_GENERATE_KEY ++ {"FAILED_TO_GENERATE_KEY", ERR_LIB_PROV, PROV_R_FAILED_TO_GENERATE_KEY}, ++ #else ++ {"FAILED_TO_GENERATE_KEY", 57, 121}, ++ #endif ++ #ifdef PROV_R_FAILED_TO_GET_PARAMETER ++ {"FAILED_TO_GET_PARAMETER", ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER}, ++ #else ++ {"FAILED_TO_GET_PARAMETER", 57, 103}, ++ #endif ++ #ifdef PROV_R_FAILED_TO_SET_PARAMETER ++ {"FAILED_TO_SET_PARAMETER", ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER}, ++ #else ++ {"FAILED_TO_SET_PARAMETER", 57, 104}, ++ #endif ++ #ifdef PROV_R_FAILED_TO_SIGN ++ {"FAILED_TO_SIGN", ERR_LIB_PROV, PROV_R_FAILED_TO_SIGN}, ++ #else ++ {"FAILED_TO_SIGN", 57, 175}, ++ #endif ++ #ifdef PROV_R_FINAL_CALL_OUT_OF_ORDER ++ {"FINAL_CALL_OUT_OF_ORDER", ERR_LIB_PROV, PROV_R_FINAL_CALL_OUT_OF_ORDER}, ++ #else ++ {"FINAL_CALL_OUT_OF_ORDER", 57, 237}, ++ #endif ++ #ifdef PROV_R_FIPS_MODULE_CONDITIONAL_ERROR ++ {"FIPS_MODULE_CONDITIONAL_ERROR", ERR_LIB_PROV, PROV_R_FIPS_MODULE_CONDITIONAL_ERROR}, ++ #else ++ {"FIPS_MODULE_CONDITIONAL_ERROR", 57, 227}, ++ #endif ++ #ifdef PROV_R_FIPS_MODULE_ENTERING_ERROR_STATE ++ {"FIPS_MODULE_ENTERING_ERROR_STATE", ERR_LIB_PROV, PROV_R_FIPS_MODULE_ENTERING_ERROR_STATE}, ++ #else ++ {"FIPS_MODULE_ENTERING_ERROR_STATE", 57, 224}, ++ #endif ++ #ifdef PROV_R_FIPS_MODULE_IN_ERROR_STATE ++ {"FIPS_MODULE_IN_ERROR_STATE", ERR_LIB_PROV, PROV_R_FIPS_MODULE_IN_ERROR_STATE}, ++ #else ++ {"FIPS_MODULE_IN_ERROR_STATE", 57, 225}, ++ #endif ++ #ifdef PROV_R_GENERATE_ERROR ++ {"GENERATE_ERROR", ERR_LIB_PROV, PROV_R_GENERATE_ERROR}, ++ #else ++ {"GENERATE_ERROR", 57, 191}, ++ #endif ++ #ifdef PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE ++ {"ILLEGAL_OR_UNSUPPORTED_PADDING_MODE", ERR_LIB_PROV, PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE}, ++ #else ++ {"ILLEGAL_OR_UNSUPPORTED_PADDING_MODE", 57, 165}, ++ #endif ++ #ifdef PROV_R_INDICATOR_INTEGRITY_FAILURE ++ {"INDICATOR_INTEGRITY_FAILURE", ERR_LIB_PROV, PROV_R_INDICATOR_INTEGRITY_FAILURE}, ++ #else ++ {"INDICATOR_INTEGRITY_FAILURE", 57, 210}, ++ #endif ++ #ifdef PROV_R_INIT_CALL_OUT_OF_ORDER ++ {"INIT_CALL_OUT_OF_ORDER", ERR_LIB_PROV, PROV_R_INIT_CALL_OUT_OF_ORDER}, ++ #else ++ {"INIT_CALL_OUT_OF_ORDER", 57, 238}, ++ #endif ++ #ifdef PROV_R_INSUFFICIENT_DRBG_STRENGTH ++ {"INSUFFICIENT_DRBG_STRENGTH", ERR_LIB_PROV, PROV_R_INSUFFICIENT_DRBG_STRENGTH}, ++ #else ++ {"INSUFFICIENT_DRBG_STRENGTH", 57, 181}, ++ #endif ++ #ifdef PROV_R_INVALID_AAD ++ {"INVALID_AAD", ERR_LIB_PROV, PROV_R_INVALID_AAD}, ++ #else ++ {"INVALID_AAD", 57, 108}, ++ #endif ++ #ifdef PROV_R_INVALID_AEAD ++ {"INVALID_AEAD", ERR_LIB_PROV, PROV_R_INVALID_AEAD}, ++ #else ++ {"INVALID_AEAD", 57, 231}, ++ #endif ++ #ifdef PROV_R_INVALID_CONFIG_DATA ++ {"INVALID_CONFIG_DATA", ERR_LIB_PROV, PROV_R_INVALID_CONFIG_DATA}, ++ #else ++ {"INVALID_CONFIG_DATA", 57, 211}, ++ #endif ++ #ifdef PROV_R_INVALID_CONSTANT_LENGTH ++ {"INVALID_CONSTANT_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_CONSTANT_LENGTH}, ++ #else ++ {"INVALID_CONSTANT_LENGTH", 57, 157}, ++ #endif ++ #ifdef PROV_R_INVALID_CURVE ++ {"INVALID_CURVE", ERR_LIB_PROV, PROV_R_INVALID_CURVE}, ++ #else ++ {"INVALID_CURVE", 57, 176}, ++ #endif ++ #ifdef PROV_R_INVALID_CUSTOM_LENGTH ++ {"INVALID_CUSTOM_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_CUSTOM_LENGTH}, ++ #else ++ {"INVALID_CUSTOM_LENGTH", 57, 111}, ++ #endif ++ #ifdef PROV_R_INVALID_DATA ++ {"INVALID_DATA", ERR_LIB_PROV, PROV_R_INVALID_DATA}, ++ #else ++ {"INVALID_DATA", 57, 115}, ++ #endif ++ #ifdef PROV_R_INVALID_DIGEST ++ {"INVALID_DIGEST", ERR_LIB_PROV, PROV_R_INVALID_DIGEST}, ++ #else ++ {"INVALID_DIGEST", 57, 122}, ++ #endif ++ #ifdef PROV_R_INVALID_DIGEST_LENGTH ++ {"INVALID_DIGEST_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_DIGEST_LENGTH}, ++ #else ++ {"INVALID_DIGEST_LENGTH", 57, 166}, ++ #endif ++ #ifdef PROV_R_INVALID_DIGEST_SIZE ++ {"INVALID_DIGEST_SIZE", ERR_LIB_PROV, PROV_R_INVALID_DIGEST_SIZE}, ++ #else ++ {"INVALID_DIGEST_SIZE", 57, 218}, ++ #endif ++ #ifdef PROV_R_INVALID_EDDSA_INSTANCE_FOR_ATTEMPTED_OPERATION ++ {"INVALID_EDDSA_INSTANCE_FOR_ATTEMPTED_OPERATION", ERR_LIB_PROV, PROV_R_INVALID_EDDSA_INSTANCE_FOR_ATTEMPTED_OPERATION}, ++ #else ++ {"INVALID_EDDSA_INSTANCE_FOR_ATTEMPTED_OPERATION", 57, 243}, ++ #endif ++ #ifdef PROV_R_INVALID_INPUT_LENGTH ++ {"INVALID_INPUT_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_INPUT_LENGTH}, ++ #else ++ {"INVALID_INPUT_LENGTH", 57, 230}, ++ #endif ++ #ifdef PROV_R_INVALID_ITERATION_COUNT ++ {"INVALID_ITERATION_COUNT", ERR_LIB_PROV, PROV_R_INVALID_ITERATION_COUNT}, ++ #else ++ {"INVALID_ITERATION_COUNT", 57, 123}, ++ #endif ++ #ifdef PROV_R_INVALID_IV_LENGTH ++ {"INVALID_IV_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH}, ++ #else ++ {"INVALID_IV_LENGTH", 57, 109}, ++ #endif ++ #ifdef PROV_R_INVALID_KDF ++ {"INVALID_KDF", ERR_LIB_PROV, PROV_R_INVALID_KDF}, ++ #else ++ {"INVALID_KDF", 57, 232}, ++ #endif ++ #ifdef PROV_R_INVALID_KEY ++ {"INVALID_KEY", ERR_LIB_PROV, PROV_R_INVALID_KEY}, ++ #else ++ {"INVALID_KEY", 57, 158}, ++ #endif ++ #ifdef PROV_R_INVALID_KEY_LENGTH ++ {"INVALID_KEY_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH}, ++ #else ++ {"INVALID_KEY_LENGTH", 57, 105}, ++ #endif ++ #ifdef PROV_R_INVALID_MAC ++ {"INVALID_MAC", ERR_LIB_PROV, PROV_R_INVALID_MAC}, ++ #else ++ {"INVALID_MAC", 57, 151}, ++ #endif ++ #ifdef PROV_R_INVALID_MEMORY_SIZE ++ {"INVALID_MEMORY_SIZE", ERR_LIB_PROV, PROV_R_INVALID_MEMORY_SIZE}, ++ #else ++ {"INVALID_MEMORY_SIZE", 57, 235}, ++ #endif ++ #ifdef PROV_R_INVALID_MGF1_MD ++ {"INVALID_MGF1_MD", ERR_LIB_PROV, PROV_R_INVALID_MGF1_MD}, ++ #else ++ {"INVALID_MGF1_MD", 57, 167}, ++ #endif ++ #ifdef PROV_R_INVALID_MODE ++ {"INVALID_MODE", ERR_LIB_PROV, PROV_R_INVALID_MODE}, ++ #else ++ {"INVALID_MODE", 57, 125}, ++ #endif ++ #ifdef PROV_R_INVALID_OUTPUT_LENGTH ++ {"INVALID_OUTPUT_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_OUTPUT_LENGTH}, ++ #else ++ {"INVALID_OUTPUT_LENGTH", 57, 217}, ++ #endif ++ #ifdef PROV_R_INVALID_PADDING_MODE ++ {"INVALID_PADDING_MODE", ERR_LIB_PROV, PROV_R_INVALID_PADDING_MODE}, ++ #else ++ {"INVALID_PADDING_MODE", 57, 168}, ++ #endif ++ #ifdef PROV_R_INVALID_PREHASHED_DIGEST_LENGTH ++ {"INVALID_PREHASHED_DIGEST_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_PREHASHED_DIGEST_LENGTH}, ++ #else ++ {"INVALID_PREHASHED_DIGEST_LENGTH", 57, 241}, ++ #endif ++ #ifdef PROV_R_INVALID_PUBINFO ++ {"INVALID_PUBINFO", ERR_LIB_PROV, PROV_R_INVALID_PUBINFO}, ++ #else ++ {"INVALID_PUBINFO", 57, 198}, ++ #endif ++ #ifdef PROV_R_INVALID_SALT_LENGTH ++ {"INVALID_SALT_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_SALT_LENGTH}, ++ #else ++ {"INVALID_SALT_LENGTH", 57, 112}, ++ #endif ++ #ifdef PROV_R_INVALID_SEED_LENGTH ++ {"INVALID_SEED_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_SEED_LENGTH}, ++ #else ++ {"INVALID_SEED_LENGTH", 57, 154}, ++ #endif ++ #ifdef PROV_R_INVALID_SIGNATURE_SIZE ++ {"INVALID_SIGNATURE_SIZE", ERR_LIB_PROV, PROV_R_INVALID_SIGNATURE_SIZE}, ++ #else ++ {"INVALID_SIGNATURE_SIZE", 57, 179}, ++ #endif ++ #ifdef PROV_R_INVALID_STATE ++ {"INVALID_STATE", ERR_LIB_PROV, PROV_R_INVALID_STATE}, ++ #else ++ {"INVALID_STATE", 57, 212}, ++ #endif ++ #ifdef PROV_R_INVALID_TAG ++ {"INVALID_TAG", ERR_LIB_PROV, PROV_R_INVALID_TAG}, ++ #else ++ {"INVALID_TAG", 57, 110}, ++ #endif ++ #ifdef PROV_R_INVALID_TAG_LENGTH ++ {"INVALID_TAG_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_TAG_LENGTH}, ++ #else ++ {"INVALID_TAG_LENGTH", 57, 118}, ++ #endif ++ #ifdef PROV_R_INVALID_THREAD_POOL_SIZE ++ {"INVALID_THREAD_POOL_SIZE", ERR_LIB_PROV, PROV_R_INVALID_THREAD_POOL_SIZE}, ++ #else ++ {"INVALID_THREAD_POOL_SIZE", 57, 234}, ++ #endif ++ #ifdef PROV_R_INVALID_UKM_LENGTH ++ {"INVALID_UKM_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_UKM_LENGTH}, ++ #else ++ {"INVALID_UKM_LENGTH", 57, 200}, ++ #endif ++ #ifdef PROV_R_INVALID_X931_DIGEST ++ {"INVALID_X931_DIGEST", ERR_LIB_PROV, PROV_R_INVALID_X931_DIGEST}, ++ #else ++ {"INVALID_X931_DIGEST", 57, 170}, ++ #endif ++ #ifdef PROV_R_IN_ERROR_STATE ++ {"IN_ERROR_STATE", ERR_LIB_PROV, PROV_R_IN_ERROR_STATE}, ++ #else ++ {"IN_ERROR_STATE", 57, 192}, ++ #endif ++ #ifdef PROV_R_KEY_SETUP_FAILED ++ {"KEY_SETUP_FAILED", ERR_LIB_PROV, PROV_R_KEY_SETUP_FAILED}, ++ #else ++ {"KEY_SETUP_FAILED", 57, 101}, ++ #endif ++ #ifdef PROV_R_KEY_SIZE_TOO_SMALL ++ {"KEY_SIZE_TOO_SMALL", ERR_LIB_PROV, PROV_R_KEY_SIZE_TOO_SMALL}, ++ #else ++ {"KEY_SIZE_TOO_SMALL", 57, 171}, ++ #endif ++ #ifdef PROV_R_LENGTH_TOO_LARGE ++ {"LENGTH_TOO_LARGE", ERR_LIB_PROV, PROV_R_LENGTH_TOO_LARGE}, ++ #else ++ {"LENGTH_TOO_LARGE", 57, 202}, ++ #endif ++ #ifdef PROV_R_MISMATCHING_DOMAIN_PARAMETERS ++ {"MISMATCHING_DOMAIN_PARAMETERS", ERR_LIB_PROV, PROV_R_MISMATCHING_DOMAIN_PARAMETERS}, ++ #else ++ {"MISMATCHING_DOMAIN_PARAMETERS", 57, 203}, ++ #endif ++ #ifdef PROV_R_MISSING_CEK_ALG ++ {"MISSING_CEK_ALG", ERR_LIB_PROV, PROV_R_MISSING_CEK_ALG}, ++ #else ++ {"MISSING_CEK_ALG", 57, 144}, ++ #endif ++ #ifdef PROV_R_MISSING_CIPHER ++ {"MISSING_CIPHER", ERR_LIB_PROV, PROV_R_MISSING_CIPHER}, ++ #else ++ {"MISSING_CIPHER", 57, 155}, ++ #endif ++ #ifdef PROV_R_MISSING_CONFIG_DATA ++ {"MISSING_CONFIG_DATA", ERR_LIB_PROV, PROV_R_MISSING_CONFIG_DATA}, ++ #else ++ {"MISSING_CONFIG_DATA", 57, 213}, ++ #endif ++ #ifdef PROV_R_MISSING_CONSTANT ++ {"MISSING_CONSTANT", ERR_LIB_PROV, PROV_R_MISSING_CONSTANT}, ++ #else ++ {"MISSING_CONSTANT", 57, 156}, ++ #endif ++ #ifdef PROV_R_MISSING_KEY ++ {"MISSING_KEY", ERR_LIB_PROV, PROV_R_MISSING_KEY}, ++ #else ++ {"MISSING_KEY", 57, 128}, ++ #endif ++ #ifdef PROV_R_MISSING_MAC ++ {"MISSING_MAC", ERR_LIB_PROV, PROV_R_MISSING_MAC}, ++ #else ++ {"MISSING_MAC", 57, 150}, ++ #endif ++ #ifdef PROV_R_MISSING_MESSAGE_DIGEST ++ {"MISSING_MESSAGE_DIGEST", ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST}, ++ #else ++ {"MISSING_MESSAGE_DIGEST", 57, 129}, ++ #endif ++ #ifdef PROV_R_MISSING_OID ++ {"MISSING_OID", ERR_LIB_PROV, PROV_R_MISSING_OID}, ++ #else ++ {"MISSING_OID", 57, 209}, ++ #endif ++ #ifdef PROV_R_MISSING_PASS ++ {"MISSING_PASS", ERR_LIB_PROV, PROV_R_MISSING_PASS}, ++ #else ++ {"MISSING_PASS", 57, 130}, ++ #endif ++ #ifdef PROV_R_MISSING_SALT ++ {"MISSING_SALT", ERR_LIB_PROV, PROV_R_MISSING_SALT}, ++ #else ++ {"MISSING_SALT", 57, 131}, ++ #endif ++ #ifdef PROV_R_MISSING_SECRET ++ {"MISSING_SECRET", ERR_LIB_PROV, PROV_R_MISSING_SECRET}, ++ #else ++ {"MISSING_SECRET", 57, 132}, ++ #endif ++ #ifdef PROV_R_MISSING_SEED ++ {"MISSING_SEED", ERR_LIB_PROV, PROV_R_MISSING_SEED}, ++ #else ++ {"MISSING_SEED", 57, 140}, ++ #endif ++ #ifdef PROV_R_MISSING_SESSION_ID ++ {"MISSING_SESSION_ID", ERR_LIB_PROV, PROV_R_MISSING_SESSION_ID}, ++ #else ++ {"MISSING_SESSION_ID", 57, 133}, ++ #endif ++ #ifdef PROV_R_MISSING_TYPE ++ {"MISSING_TYPE", ERR_LIB_PROV, PROV_R_MISSING_TYPE}, ++ #else ++ {"MISSING_TYPE", 57, 134}, ++ #endif ++ #ifdef PROV_R_MISSING_XCGHASH ++ {"MISSING_XCGHASH", ERR_LIB_PROV, PROV_R_MISSING_XCGHASH}, ++ #else ++ {"MISSING_XCGHASH", 57, 135}, ++ #endif ++ #ifdef PROV_R_MODULE_INTEGRITY_FAILURE ++ {"MODULE_INTEGRITY_FAILURE", ERR_LIB_PROV, PROV_R_MODULE_INTEGRITY_FAILURE}, ++ #else ++ {"MODULE_INTEGRITY_FAILURE", 57, 214}, ++ #endif ++ #ifdef PROV_R_NOT_A_PRIVATE_KEY ++ {"NOT_A_PRIVATE_KEY", ERR_LIB_PROV, PROV_R_NOT_A_PRIVATE_KEY}, ++ #else ++ {"NOT_A_PRIVATE_KEY", 57, 221}, ++ #endif ++ #ifdef PROV_R_NOT_A_PUBLIC_KEY ++ {"NOT_A_PUBLIC_KEY", ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY}, ++ #else ++ {"NOT_A_PUBLIC_KEY", 57, 220}, ++ #endif ++ #ifdef PROV_R_NOT_INSTANTIATED ++ {"NOT_INSTANTIATED", ERR_LIB_PROV, PROV_R_NOT_INSTANTIATED}, ++ #else ++ {"NOT_INSTANTIATED", 57, 193}, ++ #endif ++ #ifdef PROV_R_NOT_PARAMETERS ++ {"NOT_PARAMETERS", ERR_LIB_PROV, PROV_R_NOT_PARAMETERS}, ++ #else ++ {"NOT_PARAMETERS", 57, 226}, ++ #endif ++ #ifdef PROV_R_NOT_SUPPORTED ++ {"NOT_SUPPORTED", ERR_LIB_PROV, PROV_R_NOT_SUPPORTED}, ++ #else ++ {"NOT_SUPPORTED", 57, 136}, ++ #endif ++ #ifdef PROV_R_NOT_XOF_OR_INVALID_LENGTH ++ {"NOT_XOF_OR_INVALID_LENGTH", ERR_LIB_PROV, PROV_R_NOT_XOF_OR_INVALID_LENGTH}, ++ #else ++ {"NOT_XOF_OR_INVALID_LENGTH", 57, 113}, ++ #endif ++ #ifdef PROV_R_NO_INSTANCE_ALLOWED ++ {"NO_INSTANCE_ALLOWED", ERR_LIB_PROV, PROV_R_NO_INSTANCE_ALLOWED}, ++ #else ++ {"NO_INSTANCE_ALLOWED", 57, 242}, ++ #endif ++ #ifdef PROV_R_NO_KEY_SET ++ {"NO_KEY_SET", ERR_LIB_PROV, PROV_R_NO_KEY_SET}, ++ #else ++ {"NO_KEY_SET", 57, 114}, ++ #endif ++ #ifdef PROV_R_NO_PARAMETERS_SET ++ {"NO_PARAMETERS_SET", ERR_LIB_PROV, PROV_R_NO_PARAMETERS_SET}, ++ #else ++ {"NO_PARAMETERS_SET", 57, 177}, ++ #endif ++ #ifdef PROV_R_ONESHOT_CALL_OUT_OF_ORDER ++ {"ONESHOT_CALL_OUT_OF_ORDER", ERR_LIB_PROV, PROV_R_ONESHOT_CALL_OUT_OF_ORDER}, ++ #else ++ {"ONESHOT_CALL_OUT_OF_ORDER", 57, 239}, ++ #endif ++ #ifdef PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE ++ {"OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE", ERR_LIB_PROV, PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE}, ++ #else ++ {"OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE", 57, 178}, ++ #endif ++ #ifdef PROV_R_OUTPUT_BUFFER_TOO_SMALL ++ {"OUTPUT_BUFFER_TOO_SMALL", ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL}, ++ #else ++ {"OUTPUT_BUFFER_TOO_SMALL", 57, 106}, ++ #endif ++ #ifdef PROV_R_PARENT_CANNOT_GENERATE_RANDOM_NUMBERS ++ {"PARENT_CANNOT_GENERATE_RANDOM_NUMBERS", ERR_LIB_PROV, PROV_R_PARENT_CANNOT_GENERATE_RANDOM_NUMBERS}, ++ #else ++ {"PARENT_CANNOT_GENERATE_RANDOM_NUMBERS", 57, 228}, ++ #endif ++ #ifdef PROV_R_PARENT_CANNOT_SUPPLY_ENTROPY_SEED ++ {"PARENT_CANNOT_SUPPLY_ENTROPY_SEED", ERR_LIB_PROV, PROV_R_PARENT_CANNOT_SUPPLY_ENTROPY_SEED}, ++ #else ++ {"PARENT_CANNOT_SUPPLY_ENTROPY_SEED", 57, 187}, ++ #endif ++ #ifdef PROV_R_PARENT_LOCKING_NOT_ENABLED ++ {"PARENT_LOCKING_NOT_ENABLED", ERR_LIB_PROV, PROV_R_PARENT_LOCKING_NOT_ENABLED}, ++ #else ++ {"PARENT_LOCKING_NOT_ENABLED", 57, 182}, ++ #endif ++ #ifdef PROV_R_PARENT_STRENGTH_TOO_WEAK ++ {"PARENT_STRENGTH_TOO_WEAK", ERR_LIB_PROV, PROV_R_PARENT_STRENGTH_TOO_WEAK}, ++ #else ++ {"PARENT_STRENGTH_TOO_WEAK", 57, 194}, ++ #endif ++ #ifdef PROV_R_PATH_MUST_BE_ABSOLUTE ++ {"PATH_MUST_BE_ABSOLUTE", ERR_LIB_PROV, PROV_R_PATH_MUST_BE_ABSOLUTE}, ++ #else ++ {"PATH_MUST_BE_ABSOLUTE", 57, 219}, ++ #endif ++ #ifdef PROV_R_PERSONALISATION_STRING_TOO_LONG ++ {"PERSONALISATION_STRING_TOO_LONG", ERR_LIB_PROV, PROV_R_PERSONALISATION_STRING_TOO_LONG}, ++ #else ++ {"PERSONALISATION_STRING_TOO_LONG", 57, 195}, ++ #endif ++ #ifdef PROV_R_PSS_SALTLEN_TOO_SMALL ++ {"PSS_SALTLEN_TOO_SMALL", ERR_LIB_PROV, PROV_R_PSS_SALTLEN_TOO_SMALL}, ++ #else ++ {"PSS_SALTLEN_TOO_SMALL", 57, 172}, ++ #endif ++ #ifdef PROV_R_REQUEST_TOO_LARGE_FOR_DRBG ++ {"REQUEST_TOO_LARGE_FOR_DRBG", ERR_LIB_PROV, PROV_R_REQUEST_TOO_LARGE_FOR_DRBG}, ++ #else ++ {"REQUEST_TOO_LARGE_FOR_DRBG", 57, 196}, ++ #endif ++ #ifdef PROV_R_REQUIRE_CTR_MODE_CIPHER ++ {"REQUIRE_CTR_MODE_CIPHER", ERR_LIB_PROV, PROV_R_REQUIRE_CTR_MODE_CIPHER}, ++ #else ++ {"REQUIRE_CTR_MODE_CIPHER", 57, 206}, ++ #endif ++ #ifdef PROV_R_RESEED_ERROR ++ {"RESEED_ERROR", ERR_LIB_PROV, PROV_R_RESEED_ERROR}, ++ #else ++ {"RESEED_ERROR", 57, 197}, ++ #endif ++ #ifdef PROV_R_SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES ++ {"SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES", ERR_LIB_PROV, PROV_R_SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES}, ++ #else ++ {"SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES", 57, 222}, ++ #endif ++ #ifdef PROV_R_SEED_SOURCES_MUST_NOT_HAVE_A_PARENT ++ {"SEED_SOURCES_MUST_NOT_HAVE_A_PARENT", ERR_LIB_PROV, PROV_R_SEED_SOURCES_MUST_NOT_HAVE_A_PARENT}, ++ #else ++ {"SEED_SOURCES_MUST_NOT_HAVE_A_PARENT", 57, 229}, ++ #endif ++ #ifdef PROV_R_SELF_TEST_KAT_FAILURE ++ {"SELF_TEST_KAT_FAILURE", ERR_LIB_PROV, PROV_R_SELF_TEST_KAT_FAILURE}, ++ #else ++ {"SELF_TEST_KAT_FAILURE", 57, 215}, ++ #endif ++ #ifdef PROV_R_SELF_TEST_POST_FAILURE ++ {"SELF_TEST_POST_FAILURE", ERR_LIB_PROV, PROV_R_SELF_TEST_POST_FAILURE}, ++ #else ++ {"SELF_TEST_POST_FAILURE", 57, 216}, ++ #endif ++ #ifdef PROV_R_TAG_NOT_NEEDED ++ {"TAG_NOT_NEEDED", ERR_LIB_PROV, PROV_R_TAG_NOT_NEEDED}, ++ #else ++ {"TAG_NOT_NEEDED", 57, 120}, ++ #endif ++ #ifdef PROV_R_TAG_NOT_SET ++ {"TAG_NOT_SET", ERR_LIB_PROV, PROV_R_TAG_NOT_SET}, ++ #else ++ {"TAG_NOT_SET", 57, 119}, ++ #endif ++ #ifdef PROV_R_TOO_MANY_RECORDS ++ {"TOO_MANY_RECORDS", ERR_LIB_PROV, PROV_R_TOO_MANY_RECORDS}, ++ #else ++ {"TOO_MANY_RECORDS", 57, 126}, ++ #endif ++ #ifdef PROV_R_UNABLE_TO_FIND_CIPHERS ++ {"UNABLE_TO_FIND_CIPHERS", ERR_LIB_PROV, PROV_R_UNABLE_TO_FIND_CIPHERS}, ++ #else ++ {"UNABLE_TO_FIND_CIPHERS", 57, 207}, ++ #endif ++ #ifdef PROV_R_UNABLE_TO_GET_PARENT_STRENGTH ++ {"UNABLE_TO_GET_PARENT_STRENGTH", ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_PARENT_STRENGTH}, ++ #else ++ {"UNABLE_TO_GET_PARENT_STRENGTH", 57, 199}, ++ #endif ++ #ifdef PROV_R_UNABLE_TO_GET_PASSPHRASE ++ {"UNABLE_TO_GET_PASSPHRASE", ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_PASSPHRASE}, ++ #else ++ {"UNABLE_TO_GET_PASSPHRASE", 57, 159}, ++ #endif ++ #ifdef PROV_R_UNABLE_TO_INITIALISE_CIPHERS ++ {"UNABLE_TO_INITIALISE_CIPHERS", ERR_LIB_PROV, PROV_R_UNABLE_TO_INITIALISE_CIPHERS}, ++ #else ++ {"UNABLE_TO_INITIALISE_CIPHERS", 57, 208}, ++ #endif ++ #ifdef PROV_R_UNABLE_TO_LOAD_SHA256 ++ {"UNABLE_TO_LOAD_SHA256", ERR_LIB_PROV, PROV_R_UNABLE_TO_LOAD_SHA256}, ++ #else ++ {"UNABLE_TO_LOAD_SHA256", 57, 147}, ++ #endif ++ #ifdef PROV_R_UNABLE_TO_LOCK_PARENT ++ {"UNABLE_TO_LOCK_PARENT", ERR_LIB_PROV, PROV_R_UNABLE_TO_LOCK_PARENT}, ++ #else ++ {"UNABLE_TO_LOCK_PARENT", 57, 201}, ++ #endif ++ #ifdef PROV_R_UNABLE_TO_RESEED ++ {"UNABLE_TO_RESEED", ERR_LIB_PROV, PROV_R_UNABLE_TO_RESEED}, ++ #else ++ {"UNABLE_TO_RESEED", 57, 204}, ++ #endif ++ #ifdef PROV_R_UNSUPPORTED_CEK_ALG ++ {"UNSUPPORTED_CEK_ALG", ERR_LIB_PROV, PROV_R_UNSUPPORTED_CEK_ALG}, ++ #else ++ {"UNSUPPORTED_CEK_ALG", 57, 145}, ++ #endif ++ #ifdef PROV_R_UNSUPPORTED_KEY_SIZE ++ {"UNSUPPORTED_KEY_SIZE", ERR_LIB_PROV, PROV_R_UNSUPPORTED_KEY_SIZE}, ++ #else ++ {"UNSUPPORTED_KEY_SIZE", 57, 153}, ++ #endif ++ #ifdef PROV_R_UNSUPPORTED_MAC_TYPE ++ {"UNSUPPORTED_MAC_TYPE", ERR_LIB_PROV, PROV_R_UNSUPPORTED_MAC_TYPE}, ++ #else ++ {"UNSUPPORTED_MAC_TYPE", 57, 137}, ++ #endif ++ #ifdef PROV_R_UNSUPPORTED_NUMBER_OF_ROUNDS ++ {"UNSUPPORTED_NUMBER_OF_ROUNDS", ERR_LIB_PROV, PROV_R_UNSUPPORTED_NUMBER_OF_ROUNDS}, ++ #else ++ {"UNSUPPORTED_NUMBER_OF_ROUNDS", 57, 152}, ++ #endif ++ #ifdef PROV_R_UPDATE_CALL_OUT_OF_ORDER ++ {"UPDATE_CALL_OUT_OF_ORDER", ERR_LIB_PROV, PROV_R_UPDATE_CALL_OUT_OF_ORDER}, ++ #else ++ {"UPDATE_CALL_OUT_OF_ORDER", 57, 240}, ++ #endif ++ #ifdef PROV_R_URI_AUTHORITY_UNSUPPORTED ++ {"URI_AUTHORITY_UNSUPPORTED", ERR_LIB_PROV, PROV_R_URI_AUTHORITY_UNSUPPORTED}, ++ #else ++ {"URI_AUTHORITY_UNSUPPORTED", 57, 223}, ++ #endif ++ #ifdef PROV_R_VALUE_ERROR ++ {"VALUE_ERROR", ERR_LIB_PROV, PROV_R_VALUE_ERROR}, ++ #else ++ {"VALUE_ERROR", 57, 138}, ++ #endif ++ #ifdef PROV_R_WRONG_FINAL_BLOCK_LENGTH ++ {"WRONG_FINAL_BLOCK_LENGTH", ERR_LIB_PROV, PROV_R_WRONG_FINAL_BLOCK_LENGTH}, ++ #else ++ {"WRONG_FINAL_BLOCK_LENGTH", 57, 107}, ++ #endif ++ #ifdef PROV_R_WRONG_OUTPUT_BUFFER_SIZE ++ {"WRONG_OUTPUT_BUFFER_SIZE", ERR_LIB_PROV, PROV_R_WRONG_OUTPUT_BUFFER_SIZE}, ++ #else ++ {"WRONG_OUTPUT_BUFFER_SIZE", 57, 139}, ++ #endif ++ #ifdef PROV_R_XOF_DIGESTS_NOT_ALLOWED ++ {"XOF_DIGESTS_NOT_ALLOWED", ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED}, ++ #else ++ {"XOF_DIGESTS_NOT_ALLOWED", 57, 183}, ++ #endif ++ #ifdef PROV_R_XTS_DATA_UNIT_IS_TOO_LARGE ++ {"XTS_DATA_UNIT_IS_TOO_LARGE", ERR_LIB_PROV, PROV_R_XTS_DATA_UNIT_IS_TOO_LARGE}, ++ #else ++ {"XTS_DATA_UNIT_IS_TOO_LARGE", 57, 148}, ++ #endif ++ #ifdef PROV_R_XTS_DUPLICATED_KEYS ++ {"XTS_DUPLICATED_KEYS", ERR_LIB_PROV, PROV_R_XTS_DUPLICATED_KEYS}, ++ #else ++ {"XTS_DUPLICATED_KEYS", 57, 149}, ++ #endif ++ #ifdef RAND_R_ADDITIONAL_INPUT_TOO_LONG ++ {"ADDITIONAL_INPUT_TOO_LONG", ERR_LIB_RAND, RAND_R_ADDITIONAL_INPUT_TOO_LONG}, ++ #else ++ {"ADDITIONAL_INPUT_TOO_LONG", 36, 102}, ++ #endif ++ #ifdef RAND_R_ALREADY_INSTANTIATED ++ {"ALREADY_INSTANTIATED", ERR_LIB_RAND, RAND_R_ALREADY_INSTANTIATED}, ++ #else ++ {"ALREADY_INSTANTIATED", 36, 103}, ++ #endif ++ #ifdef RAND_R_ARGUMENT_OUT_OF_RANGE ++ {"ARGUMENT_OUT_OF_RANGE", ERR_LIB_RAND, RAND_R_ARGUMENT_OUT_OF_RANGE}, ++ #else ++ {"ARGUMENT_OUT_OF_RANGE", 36, 105}, ++ #endif ++ #ifdef RAND_R_CANNOT_OPEN_FILE ++ {"CANNOT_OPEN_FILE", ERR_LIB_RAND, RAND_R_CANNOT_OPEN_FILE}, ++ #else ++ {"CANNOT_OPEN_FILE", 36, 121}, ++ #endif ++ #ifdef RAND_R_DRBG_ALREADY_INITIALIZED ++ {"DRBG_ALREADY_INITIALIZED", ERR_LIB_RAND, RAND_R_DRBG_ALREADY_INITIALIZED}, ++ #else ++ {"DRBG_ALREADY_INITIALIZED", 36, 129}, ++ #endif ++ #ifdef RAND_R_DRBG_NOT_INITIALISED ++ {"DRBG_NOT_INITIALISED", ERR_LIB_RAND, RAND_R_DRBG_NOT_INITIALISED}, ++ #else ++ {"DRBG_NOT_INITIALISED", 36, 104}, ++ #endif ++ #ifdef RAND_R_ENTROPY_INPUT_TOO_LONG ++ {"ENTROPY_INPUT_TOO_LONG", ERR_LIB_RAND, RAND_R_ENTROPY_INPUT_TOO_LONG}, ++ #else ++ {"ENTROPY_INPUT_TOO_LONG", 36, 106}, ++ #endif ++ #ifdef RAND_R_ENTROPY_OUT_OF_RANGE ++ {"ENTROPY_OUT_OF_RANGE", ERR_LIB_RAND, RAND_R_ENTROPY_OUT_OF_RANGE}, ++ #else ++ {"ENTROPY_OUT_OF_RANGE", 36, 124}, ++ #endif ++ #ifdef RAND_R_ERROR_ENTROPY_POOL_WAS_IGNORED ++ {"ERROR_ENTROPY_POOL_WAS_IGNORED", ERR_LIB_RAND, RAND_R_ERROR_ENTROPY_POOL_WAS_IGNORED}, ++ #else ++ {"ERROR_ENTROPY_POOL_WAS_IGNORED", 36, 127}, ++ #endif ++ #ifdef RAND_R_ERROR_INITIALISING_DRBG ++ {"ERROR_INITIALISING_DRBG", ERR_LIB_RAND, RAND_R_ERROR_INITIALISING_DRBG}, ++ #else ++ {"ERROR_INITIALISING_DRBG", 36, 107}, ++ #endif ++ #ifdef RAND_R_ERROR_INSTANTIATING_DRBG ++ {"ERROR_INSTANTIATING_DRBG", ERR_LIB_RAND, RAND_R_ERROR_INSTANTIATING_DRBG}, ++ #else ++ {"ERROR_INSTANTIATING_DRBG", 36, 108}, ++ #endif ++ #ifdef RAND_R_ERROR_RETRIEVING_ADDITIONAL_INPUT ++ {"ERROR_RETRIEVING_ADDITIONAL_INPUT", ERR_LIB_RAND, RAND_R_ERROR_RETRIEVING_ADDITIONAL_INPUT}, ++ #else ++ {"ERROR_RETRIEVING_ADDITIONAL_INPUT", 36, 109}, ++ #endif ++ #ifdef RAND_R_ERROR_RETRIEVING_ENTROPY ++ {"ERROR_RETRIEVING_ENTROPY", ERR_LIB_RAND, RAND_R_ERROR_RETRIEVING_ENTROPY}, ++ #else ++ {"ERROR_RETRIEVING_ENTROPY", 36, 110}, ++ #endif ++ #ifdef RAND_R_ERROR_RETRIEVING_NONCE ++ {"ERROR_RETRIEVING_NONCE", ERR_LIB_RAND, RAND_R_ERROR_RETRIEVING_NONCE}, ++ #else ++ {"ERROR_RETRIEVING_NONCE", 36, 111}, ++ #endif ++ #ifdef RAND_R_FAILED_TO_CREATE_LOCK ++ {"FAILED_TO_CREATE_LOCK", ERR_LIB_RAND, RAND_R_FAILED_TO_CREATE_LOCK}, ++ #else ++ {"FAILED_TO_CREATE_LOCK", 36, 126}, ++ #endif ++ #ifdef RAND_R_FUNC_NOT_IMPLEMENTED ++ {"FUNC_NOT_IMPLEMENTED", ERR_LIB_RAND, RAND_R_FUNC_NOT_IMPLEMENTED}, ++ #else ++ {"FUNC_NOT_IMPLEMENTED", 36, 101}, ++ #endif ++ #ifdef RAND_R_FWRITE_ERROR ++ {"FWRITE_ERROR", ERR_LIB_RAND, RAND_R_FWRITE_ERROR}, ++ #else ++ {"FWRITE_ERROR", 36, 123}, ++ #endif ++ #ifdef RAND_R_GENERATE_ERROR ++ {"GENERATE_ERROR", ERR_LIB_RAND, RAND_R_GENERATE_ERROR}, ++ #else ++ {"GENERATE_ERROR", 36, 112}, ++ #endif ++ #ifdef RAND_R_INSUFFICIENT_DRBG_STRENGTH ++ {"INSUFFICIENT_DRBG_STRENGTH", ERR_LIB_RAND, RAND_R_INSUFFICIENT_DRBG_STRENGTH}, ++ #else ++ {"INSUFFICIENT_DRBG_STRENGTH", 36, 139}, ++ #endif ++ #ifdef RAND_R_INTERNAL_ERROR ++ {"INTERNAL_ERROR", ERR_LIB_RAND, RAND_R_INTERNAL_ERROR}, ++ #else ++ {"INTERNAL_ERROR", 36, 113}, ++ #endif ++ #ifdef RAND_R_INVALID_PROPERTY_QUERY ++ {"INVALID_PROPERTY_QUERY", ERR_LIB_RAND, RAND_R_INVALID_PROPERTY_QUERY}, ++ #else ++ {"INVALID_PROPERTY_QUERY", 36, 137}, ++ #endif ++ #ifdef RAND_R_IN_ERROR_STATE ++ {"IN_ERROR_STATE", ERR_LIB_RAND, RAND_R_IN_ERROR_STATE}, ++ #else ++ {"IN_ERROR_STATE", 36, 114}, ++ #endif ++ #ifdef RAND_R_NOT_A_REGULAR_FILE ++ {"NOT_A_REGULAR_FILE", ERR_LIB_RAND, RAND_R_NOT_A_REGULAR_FILE}, ++ #else ++ {"NOT_A_REGULAR_FILE", 36, 122}, ++ #endif ++ #ifdef RAND_R_NOT_INSTANTIATED ++ {"NOT_INSTANTIATED", ERR_LIB_RAND, RAND_R_NOT_INSTANTIATED}, ++ #else ++ {"NOT_INSTANTIATED", 36, 115}, ++ #endif ++ #ifdef RAND_R_NO_DRBG_IMPLEMENTATION_SELECTED ++ {"NO_DRBG_IMPLEMENTATION_SELECTED", ERR_LIB_RAND, RAND_R_NO_DRBG_IMPLEMENTATION_SELECTED}, ++ #else ++ {"NO_DRBG_IMPLEMENTATION_SELECTED", 36, 128}, ++ #endif ++ #ifdef RAND_R_PARENT_LOCKING_NOT_ENABLED ++ {"PARENT_LOCKING_NOT_ENABLED", ERR_LIB_RAND, RAND_R_PARENT_LOCKING_NOT_ENABLED}, ++ #else ++ {"PARENT_LOCKING_NOT_ENABLED", 36, 130}, ++ #endif ++ #ifdef RAND_R_PARENT_STRENGTH_TOO_WEAK ++ {"PARENT_STRENGTH_TOO_WEAK", ERR_LIB_RAND, RAND_R_PARENT_STRENGTH_TOO_WEAK}, ++ #else ++ {"PARENT_STRENGTH_TOO_WEAK", 36, 131}, ++ #endif ++ #ifdef RAND_R_PERSONALISATION_STRING_TOO_LONG ++ {"PERSONALISATION_STRING_TOO_LONG", ERR_LIB_RAND, RAND_R_PERSONALISATION_STRING_TOO_LONG}, ++ #else ++ {"PERSONALISATION_STRING_TOO_LONG", 36, 116}, ++ #endif ++ #ifdef RAND_R_PREDICTION_RESISTANCE_NOT_SUPPORTED ++ {"PREDICTION_RESISTANCE_NOT_SUPPORTED", ERR_LIB_RAND, RAND_R_PREDICTION_RESISTANCE_NOT_SUPPORTED}, ++ #else ++ {"PREDICTION_RESISTANCE_NOT_SUPPORTED", 36, 133}, ++ #endif ++ #ifdef RAND_R_PRNG_NOT_SEEDED ++ {"PRNG_NOT_SEEDED", ERR_LIB_RAND, RAND_R_PRNG_NOT_SEEDED}, ++ #else ++ {"PRNG_NOT_SEEDED", 36, 100}, ++ #endif ++ #ifdef RAND_R_RANDOM_POOL_OVERFLOW ++ {"RANDOM_POOL_OVERFLOW", ERR_LIB_RAND, RAND_R_RANDOM_POOL_OVERFLOW}, ++ #else ++ {"RANDOM_POOL_OVERFLOW", 36, 125}, ++ #endif ++ #ifdef RAND_R_RANDOM_POOL_UNDERFLOW ++ {"RANDOM_POOL_UNDERFLOW", ERR_LIB_RAND, RAND_R_RANDOM_POOL_UNDERFLOW}, ++ #else ++ {"RANDOM_POOL_UNDERFLOW", 36, 134}, ++ #endif ++ #ifdef RAND_R_REQUEST_TOO_LARGE_FOR_DRBG ++ {"REQUEST_TOO_LARGE_FOR_DRBG", ERR_LIB_RAND, RAND_R_REQUEST_TOO_LARGE_FOR_DRBG}, ++ #else ++ {"REQUEST_TOO_LARGE_FOR_DRBG", 36, 117}, ++ #endif ++ #ifdef RAND_R_RESEED_ERROR ++ {"RESEED_ERROR", ERR_LIB_RAND, RAND_R_RESEED_ERROR}, ++ #else ++ {"RESEED_ERROR", 36, 118}, ++ #endif ++ #ifdef RAND_R_SELFTEST_FAILURE ++ {"SELFTEST_FAILURE", ERR_LIB_RAND, RAND_R_SELFTEST_FAILURE}, ++ #else ++ {"SELFTEST_FAILURE", 36, 119}, ++ #endif ++ #ifdef RAND_R_TOO_LITTLE_NONCE_REQUESTED ++ {"TOO_LITTLE_NONCE_REQUESTED", ERR_LIB_RAND, RAND_R_TOO_LITTLE_NONCE_REQUESTED}, ++ #else ++ {"TOO_LITTLE_NONCE_REQUESTED", 36, 135}, ++ #endif ++ #ifdef RAND_R_TOO_MUCH_NONCE_REQUESTED ++ {"TOO_MUCH_NONCE_REQUESTED", ERR_LIB_RAND, RAND_R_TOO_MUCH_NONCE_REQUESTED}, ++ #else ++ {"TOO_MUCH_NONCE_REQUESTED", 36, 136}, ++ #endif ++ #ifdef RAND_R_UNABLE_TO_CREATE_DRBG ++ {"UNABLE_TO_CREATE_DRBG", ERR_LIB_RAND, RAND_R_UNABLE_TO_CREATE_DRBG}, ++ #else ++ {"UNABLE_TO_CREATE_DRBG", 36, 143}, ++ #endif ++ #ifdef RAND_R_UNABLE_TO_FETCH_DRBG ++ {"UNABLE_TO_FETCH_DRBG", ERR_LIB_RAND, RAND_R_UNABLE_TO_FETCH_DRBG}, ++ #else ++ {"UNABLE_TO_FETCH_DRBG", 36, 144}, ++ #endif ++ #ifdef RAND_R_UNABLE_TO_GET_PARENT_RESEED_PROP_COUNTER ++ {"UNABLE_TO_GET_PARENT_RESEED_PROP_COUNTER", ERR_LIB_RAND, RAND_R_UNABLE_TO_GET_PARENT_RESEED_PROP_COUNTER}, ++ #else ++ {"UNABLE_TO_GET_PARENT_RESEED_PROP_COUNTER", 36, 141}, ++ #endif ++ #ifdef RAND_R_UNABLE_TO_GET_PARENT_STRENGTH ++ {"UNABLE_TO_GET_PARENT_STRENGTH", ERR_LIB_RAND, RAND_R_UNABLE_TO_GET_PARENT_STRENGTH}, ++ #else ++ {"UNABLE_TO_GET_PARENT_STRENGTH", 36, 138}, ++ #endif ++ #ifdef RAND_R_UNABLE_TO_LOCK_PARENT ++ {"UNABLE_TO_LOCK_PARENT", ERR_LIB_RAND, RAND_R_UNABLE_TO_LOCK_PARENT}, ++ #else ++ {"UNABLE_TO_LOCK_PARENT", 36, 140}, ++ #endif ++ #ifdef RAND_R_UNSUPPORTED_DRBG_FLAGS ++ {"UNSUPPORTED_DRBG_FLAGS", ERR_LIB_RAND, RAND_R_UNSUPPORTED_DRBG_FLAGS}, ++ #else ++ {"UNSUPPORTED_DRBG_FLAGS", 36, 132}, ++ #endif ++ #ifdef RAND_R_UNSUPPORTED_DRBG_TYPE ++ {"UNSUPPORTED_DRBG_TYPE", ERR_LIB_RAND, RAND_R_UNSUPPORTED_DRBG_TYPE}, ++ #else ++ {"UNSUPPORTED_DRBG_TYPE", 36, 120}, ++ #endif ++ #ifdef RSA_R_ALGORITHM_MISMATCH ++ {"ALGORITHM_MISMATCH", ERR_LIB_RSA, RSA_R_ALGORITHM_MISMATCH}, ++ #else ++ {"ALGORITHM_MISMATCH", 4, 100}, ++ #endif ++ #ifdef RSA_R_BAD_E_VALUE ++ {"BAD_E_VALUE", ERR_LIB_RSA, RSA_R_BAD_E_VALUE}, ++ #else ++ {"BAD_E_VALUE", 4, 101}, ++ #endif ++ #ifdef RSA_R_BAD_FIXED_HEADER_DECRYPT ++ {"BAD_FIXED_HEADER_DECRYPT", ERR_LIB_RSA, RSA_R_BAD_FIXED_HEADER_DECRYPT}, ++ #else ++ {"BAD_FIXED_HEADER_DECRYPT", 4, 102}, ++ #endif ++ #ifdef RSA_R_BAD_PAD_BYTE_COUNT ++ {"BAD_PAD_BYTE_COUNT", ERR_LIB_RSA, RSA_R_BAD_PAD_BYTE_COUNT}, ++ #else ++ {"BAD_PAD_BYTE_COUNT", 4, 103}, ++ #endif ++ #ifdef RSA_R_BAD_SIGNATURE ++ {"BAD_SIGNATURE", ERR_LIB_RSA, RSA_R_BAD_SIGNATURE}, ++ #else ++ {"BAD_SIGNATURE", 4, 104}, ++ #endif ++ #ifdef RSA_R_BLOCK_TYPE_IS_NOT_01 ++ {"BLOCK_TYPE_IS_NOT_01", ERR_LIB_RSA, RSA_R_BLOCK_TYPE_IS_NOT_01}, ++ #else ++ {"BLOCK_TYPE_IS_NOT_01", 4, 106}, ++ #endif ++ #ifdef RSA_R_BLOCK_TYPE_IS_NOT_02 ++ {"BLOCK_TYPE_IS_NOT_02", ERR_LIB_RSA, RSA_R_BLOCK_TYPE_IS_NOT_02}, ++ #else ++ {"BLOCK_TYPE_IS_NOT_02", 4, 107}, ++ #endif ++ #ifdef RSA_R_DATA_GREATER_THAN_MOD_LEN ++ {"DATA_GREATER_THAN_MOD_LEN", ERR_LIB_RSA, RSA_R_DATA_GREATER_THAN_MOD_LEN}, ++ #else ++ {"DATA_GREATER_THAN_MOD_LEN", 4, 108}, ++ #endif ++ #ifdef RSA_R_DATA_TOO_LARGE ++ {"DATA_TOO_LARGE", ERR_LIB_RSA, RSA_R_DATA_TOO_LARGE}, ++ #else ++ {"DATA_TOO_LARGE", 4, 109}, ++ #endif ++ #ifdef RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE ++ {"DATA_TOO_LARGE_FOR_KEY_SIZE", ERR_LIB_RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE}, ++ #else ++ {"DATA_TOO_LARGE_FOR_KEY_SIZE", 4, 110}, ++ #endif ++ #ifdef RSA_R_DATA_TOO_LARGE_FOR_MODULUS ++ {"DATA_TOO_LARGE_FOR_MODULUS", ERR_LIB_RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS}, ++ #else ++ {"DATA_TOO_LARGE_FOR_MODULUS", 4, 132}, ++ #endif ++ #ifdef RSA_R_DATA_TOO_SMALL ++ {"DATA_TOO_SMALL", ERR_LIB_RSA, RSA_R_DATA_TOO_SMALL}, ++ #else ++ {"DATA_TOO_SMALL", 4, 111}, ++ #endif ++ #ifdef RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE ++ {"DATA_TOO_SMALL_FOR_KEY_SIZE", ERR_LIB_RSA, RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE}, ++ #else ++ {"DATA_TOO_SMALL_FOR_KEY_SIZE", 4, 122}, ++ #endif ++ #ifdef RSA_R_DIGEST_DOES_NOT_MATCH ++ {"DIGEST_DOES_NOT_MATCH", ERR_LIB_RSA, RSA_R_DIGEST_DOES_NOT_MATCH}, ++ #else ++ {"DIGEST_DOES_NOT_MATCH", 4, 158}, ++ #endif ++ #ifdef RSA_R_DIGEST_NOT_ALLOWED ++ {"DIGEST_NOT_ALLOWED", ERR_LIB_RSA, RSA_R_DIGEST_NOT_ALLOWED}, ++ #else ++ {"DIGEST_NOT_ALLOWED", 4, 145}, ++ #endif ++ #ifdef RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY ++ {"DIGEST_TOO_BIG_FOR_RSA_KEY", ERR_LIB_RSA, RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY}, ++ #else ++ {"DIGEST_TOO_BIG_FOR_RSA_KEY", 4, 112}, ++ #endif ++ #ifdef RSA_R_DMP1_NOT_CONGRUENT_TO_D ++ {"DMP1_NOT_CONGRUENT_TO_D", ERR_LIB_RSA, RSA_R_DMP1_NOT_CONGRUENT_TO_D}, ++ #else ++ {"DMP1_NOT_CONGRUENT_TO_D", 4, 124}, ++ #endif ++ #ifdef RSA_R_DMQ1_NOT_CONGRUENT_TO_D ++ {"DMQ1_NOT_CONGRUENT_TO_D", ERR_LIB_RSA, RSA_R_DMQ1_NOT_CONGRUENT_TO_D}, ++ #else ++ {"DMQ1_NOT_CONGRUENT_TO_D", 4, 125}, ++ #endif ++ #ifdef RSA_R_D_E_NOT_CONGRUENT_TO_1 ++ {"D_E_NOT_CONGRUENT_TO_1", ERR_LIB_RSA, RSA_R_D_E_NOT_CONGRUENT_TO_1}, ++ #else ++ {"D_E_NOT_CONGRUENT_TO_1", 4, 123}, ++ #endif ++ #ifdef RSA_R_FIRST_OCTET_INVALID ++ {"FIRST_OCTET_INVALID", ERR_LIB_RSA, RSA_R_FIRST_OCTET_INVALID}, ++ #else ++ {"FIRST_OCTET_INVALID", 4, 133}, ++ #endif ++ #ifdef RSA_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE ++ {"ILLEGAL_OR_UNSUPPORTED_PADDING_MODE", ERR_LIB_RSA, RSA_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE}, ++ #else ++ {"ILLEGAL_OR_UNSUPPORTED_PADDING_MODE", 4, 144}, ++ #endif ++ #ifdef RSA_R_INVALID_DIGEST ++ {"INVALID_DIGEST", ERR_LIB_RSA, RSA_R_INVALID_DIGEST}, ++ #else ++ {"INVALID_DIGEST", 4, 157}, ++ #endif ++ #ifdef RSA_R_INVALID_DIGEST_LENGTH ++ {"INVALID_DIGEST_LENGTH", ERR_LIB_RSA, RSA_R_INVALID_DIGEST_LENGTH}, ++ #else ++ {"INVALID_DIGEST_LENGTH", 4, 143}, ++ #endif ++ #ifdef RSA_R_INVALID_HEADER ++ {"INVALID_HEADER", ERR_LIB_RSA, RSA_R_INVALID_HEADER}, ++ #else ++ {"INVALID_HEADER", 4, 137}, ++ #endif ++ #ifdef RSA_R_INVALID_KEYPAIR ++ {"INVALID_KEYPAIR", ERR_LIB_RSA, RSA_R_INVALID_KEYPAIR}, ++ #else ++ {"INVALID_KEYPAIR", 4, 171}, ++ #endif ++ #ifdef RSA_R_INVALID_KEY_LENGTH ++ {"INVALID_KEY_LENGTH", ERR_LIB_RSA, RSA_R_INVALID_KEY_LENGTH}, ++ #else ++ {"INVALID_KEY_LENGTH", 4, 173}, ++ #endif ++ #ifdef RSA_R_INVALID_LABEL ++ {"INVALID_LABEL", ERR_LIB_RSA, RSA_R_INVALID_LABEL}, ++ #else ++ {"INVALID_LABEL", 4, 160}, ++ #endif ++ #ifdef RSA_R_INVALID_LENGTH ++ {"INVALID_LENGTH", ERR_LIB_RSA, RSA_R_INVALID_LENGTH}, ++ #else ++ {"INVALID_LENGTH", 4, 181}, ++ #endif ++ #ifdef RSA_R_INVALID_MESSAGE_LENGTH ++ {"INVALID_MESSAGE_LENGTH", ERR_LIB_RSA, RSA_R_INVALID_MESSAGE_LENGTH}, ++ #else ++ {"INVALID_MESSAGE_LENGTH", 4, 131}, ++ #endif ++ #ifdef RSA_R_INVALID_MGF1_MD ++ {"INVALID_MGF1_MD", ERR_LIB_RSA, RSA_R_INVALID_MGF1_MD}, ++ #else ++ {"INVALID_MGF1_MD", 4, 156}, ++ #endif ++ #ifdef RSA_R_INVALID_MODULUS ++ {"INVALID_MODULUS", ERR_LIB_RSA, RSA_R_INVALID_MODULUS}, ++ #else ++ {"INVALID_MODULUS", 4, 174}, ++ #endif ++ #ifdef RSA_R_INVALID_MULTI_PRIME_KEY ++ {"INVALID_MULTI_PRIME_KEY", ERR_LIB_RSA, RSA_R_INVALID_MULTI_PRIME_KEY}, ++ #else ++ {"INVALID_MULTI_PRIME_KEY", 4, 167}, ++ #endif ++ #ifdef RSA_R_INVALID_OAEP_PARAMETERS ++ {"INVALID_OAEP_PARAMETERS", ERR_LIB_RSA, RSA_R_INVALID_OAEP_PARAMETERS}, ++ #else ++ {"INVALID_OAEP_PARAMETERS", 4, 161}, ++ #endif ++ #ifdef RSA_R_INVALID_PADDING ++ {"INVALID_PADDING", ERR_LIB_RSA, RSA_R_INVALID_PADDING}, ++ #else ++ {"INVALID_PADDING", 4, 138}, ++ #endif ++ #ifdef RSA_R_INVALID_PADDING_MODE ++ {"INVALID_PADDING_MODE", ERR_LIB_RSA, RSA_R_INVALID_PADDING_MODE}, ++ #else ++ {"INVALID_PADDING_MODE", 4, 141}, ++ #endif ++ #ifdef RSA_R_INVALID_PSS_PARAMETERS ++ {"INVALID_PSS_PARAMETERS", ERR_LIB_RSA, RSA_R_INVALID_PSS_PARAMETERS}, ++ #else ++ {"INVALID_PSS_PARAMETERS", 4, 149}, ++ #endif ++ #ifdef RSA_R_INVALID_PSS_SALTLEN ++ {"INVALID_PSS_SALTLEN", ERR_LIB_RSA, RSA_R_INVALID_PSS_SALTLEN}, ++ #else ++ {"INVALID_PSS_SALTLEN", 4, 146}, ++ #endif ++ #ifdef RSA_R_INVALID_REQUEST ++ {"INVALID_REQUEST", ERR_LIB_RSA, RSA_R_INVALID_REQUEST}, ++ #else ++ {"INVALID_REQUEST", 4, 175}, ++ #endif ++ #ifdef RSA_R_INVALID_SALT_LENGTH ++ {"INVALID_SALT_LENGTH", ERR_LIB_RSA, RSA_R_INVALID_SALT_LENGTH}, ++ #else ++ {"INVALID_SALT_LENGTH", 4, 150}, ++ #endif ++ #ifdef RSA_R_INVALID_STRENGTH ++ {"INVALID_STRENGTH", ERR_LIB_RSA, RSA_R_INVALID_STRENGTH}, ++ #else ++ {"INVALID_STRENGTH", 4, 176}, ++ #endif ++ #ifdef RSA_R_INVALID_TRAILER ++ {"INVALID_TRAILER", ERR_LIB_RSA, RSA_R_INVALID_TRAILER}, ++ #else ++ {"INVALID_TRAILER", 4, 139}, ++ #endif ++ #ifdef RSA_R_INVALID_X931_DIGEST ++ {"INVALID_X931_DIGEST", ERR_LIB_RSA, RSA_R_INVALID_X931_DIGEST}, ++ #else ++ {"INVALID_X931_DIGEST", 4, 142}, ++ #endif ++ #ifdef RSA_R_IQMP_NOT_INVERSE_OF_Q ++ {"IQMP_NOT_INVERSE_OF_Q", ERR_LIB_RSA, RSA_R_IQMP_NOT_INVERSE_OF_Q}, ++ #else ++ {"IQMP_NOT_INVERSE_OF_Q", 4, 126}, ++ #endif ++ #ifdef RSA_R_KEY_PRIME_NUM_INVALID ++ {"KEY_PRIME_NUM_INVALID", ERR_LIB_RSA, RSA_R_KEY_PRIME_NUM_INVALID}, ++ #else ++ {"KEY_PRIME_NUM_INVALID", 4, 165}, ++ #endif ++ #ifdef RSA_R_KEY_SIZE_TOO_SMALL ++ {"KEY_SIZE_TOO_SMALL", ERR_LIB_RSA, RSA_R_KEY_SIZE_TOO_SMALL}, ++ #else ++ {"KEY_SIZE_TOO_SMALL", 4, 120}, ++ #endif ++ #ifdef RSA_R_LAST_OCTET_INVALID ++ {"LAST_OCTET_INVALID", ERR_LIB_RSA, RSA_R_LAST_OCTET_INVALID}, ++ #else ++ {"LAST_OCTET_INVALID", 4, 134}, ++ #endif ++ #ifdef RSA_R_MGF1_DIGEST_NOT_ALLOWED ++ {"MGF1_DIGEST_NOT_ALLOWED", ERR_LIB_RSA, RSA_R_MGF1_DIGEST_NOT_ALLOWED}, ++ #else ++ {"MGF1_DIGEST_NOT_ALLOWED", 4, 152}, ++ #endif ++ #ifdef RSA_R_MISSING_PRIVATE_KEY ++ {"MISSING_PRIVATE_KEY", ERR_LIB_RSA, RSA_R_MISSING_PRIVATE_KEY}, ++ #else ++ {"MISSING_PRIVATE_KEY", 4, 179}, ++ #endif ++ #ifdef RSA_R_MODULUS_TOO_LARGE ++ {"MODULUS_TOO_LARGE", ERR_LIB_RSA, RSA_R_MODULUS_TOO_LARGE}, ++ #else ++ {"MODULUS_TOO_LARGE", 4, 105}, ++ #endif ++ #ifdef RSA_R_MP_COEFFICIENT_NOT_INVERSE_OF_R ++ {"MP_COEFFICIENT_NOT_INVERSE_OF_R", ERR_LIB_RSA, RSA_R_MP_COEFFICIENT_NOT_INVERSE_OF_R}, ++ #else ++ {"MP_COEFFICIENT_NOT_INVERSE_OF_R", 4, 168}, ++ #endif ++ #ifdef RSA_R_MP_EXPONENT_NOT_CONGRUENT_TO_D ++ {"MP_EXPONENT_NOT_CONGRUENT_TO_D", ERR_LIB_RSA, RSA_R_MP_EXPONENT_NOT_CONGRUENT_TO_D}, ++ #else ++ {"MP_EXPONENT_NOT_CONGRUENT_TO_D", 4, 169}, ++ #endif ++ #ifdef RSA_R_MP_R_NOT_PRIME ++ {"MP_R_NOT_PRIME", ERR_LIB_RSA, RSA_R_MP_R_NOT_PRIME}, ++ #else ++ {"MP_R_NOT_PRIME", 4, 170}, ++ #endif ++ #ifdef RSA_R_NO_PUBLIC_EXPONENT ++ {"NO_PUBLIC_EXPONENT", ERR_LIB_RSA, RSA_R_NO_PUBLIC_EXPONENT}, ++ #else ++ {"NO_PUBLIC_EXPONENT", 4, 140}, ++ #endif ++ #ifdef RSA_R_NULL_BEFORE_BLOCK_MISSING ++ {"NULL_BEFORE_BLOCK_MISSING", ERR_LIB_RSA, RSA_R_NULL_BEFORE_BLOCK_MISSING}, ++ #else ++ {"NULL_BEFORE_BLOCK_MISSING", 4, 113}, ++ #endif ++ #ifdef RSA_R_N_DOES_NOT_EQUAL_PRODUCT_OF_PRIMES ++ {"N_DOES_NOT_EQUAL_PRODUCT_OF_PRIMES", ERR_LIB_RSA, RSA_R_N_DOES_NOT_EQUAL_PRODUCT_OF_PRIMES}, ++ #else ++ {"N_DOES_NOT_EQUAL_PRODUCT_OF_PRIMES", 4, 172}, ++ #endif ++ #ifdef RSA_R_N_DOES_NOT_EQUAL_P_Q ++ {"N_DOES_NOT_EQUAL_P_Q", ERR_LIB_RSA, RSA_R_N_DOES_NOT_EQUAL_P_Q}, ++ #else ++ {"N_DOES_NOT_EQUAL_P_Q", 4, 127}, ++ #endif ++ #ifdef RSA_R_OAEP_DECODING_ERROR ++ {"OAEP_DECODING_ERROR", ERR_LIB_RSA, RSA_R_OAEP_DECODING_ERROR}, ++ #else ++ {"OAEP_DECODING_ERROR", 4, 121}, ++ #endif ++ #ifdef RSA_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE ++ {"OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE", ERR_LIB_RSA, RSA_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE}, ++ #else ++ {"OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE", 4, 148}, ++ #endif ++ #ifdef RSA_R_PADDING_CHECK_FAILED ++ {"PADDING_CHECK_FAILED", ERR_LIB_RSA, RSA_R_PADDING_CHECK_FAILED}, ++ #else ++ {"PADDING_CHECK_FAILED", 4, 114}, ++ #endif ++ #ifdef RSA_R_PAIRWISE_TEST_FAILURE ++ {"PAIRWISE_TEST_FAILURE", ERR_LIB_RSA, RSA_R_PAIRWISE_TEST_FAILURE}, ++ #else ++ {"PAIRWISE_TEST_FAILURE", 4, 177}, ++ #endif ++ #ifdef RSA_R_PKCS_DECODING_ERROR ++ {"PKCS_DECODING_ERROR", ERR_LIB_RSA, RSA_R_PKCS_DECODING_ERROR}, ++ #else ++ {"PKCS_DECODING_ERROR", 4, 159}, ++ #endif ++ #ifdef RSA_R_PSS_SALTLEN_TOO_SMALL ++ {"PSS_SALTLEN_TOO_SMALL", ERR_LIB_RSA, RSA_R_PSS_SALTLEN_TOO_SMALL}, ++ #else ++ {"PSS_SALTLEN_TOO_SMALL", 4, 164}, ++ #endif ++ #ifdef RSA_R_PUB_EXPONENT_OUT_OF_RANGE ++ {"PUB_EXPONENT_OUT_OF_RANGE", ERR_LIB_RSA, RSA_R_PUB_EXPONENT_OUT_OF_RANGE}, ++ #else ++ {"PUB_EXPONENT_OUT_OF_RANGE", 4, 178}, ++ #endif ++ #ifdef RSA_R_P_NOT_PRIME ++ {"P_NOT_PRIME", ERR_LIB_RSA, RSA_R_P_NOT_PRIME}, ++ #else ++ {"P_NOT_PRIME", 4, 128}, ++ #endif ++ #ifdef RSA_R_Q_NOT_PRIME ++ {"Q_NOT_PRIME", ERR_LIB_RSA, RSA_R_Q_NOT_PRIME}, ++ #else ++ {"Q_NOT_PRIME", 4, 129}, ++ #endif ++ #ifdef RSA_R_RANDOMNESS_SOURCE_STRENGTH_INSUFFICIENT ++ {"RANDOMNESS_SOURCE_STRENGTH_INSUFFICIENT", ERR_LIB_RSA, RSA_R_RANDOMNESS_SOURCE_STRENGTH_INSUFFICIENT}, ++ #else ++ {"RANDOMNESS_SOURCE_STRENGTH_INSUFFICIENT", 4, 180}, ++ #endif ++ #ifdef RSA_R_RSA_OPERATIONS_NOT_SUPPORTED ++ {"RSA_OPERATIONS_NOT_SUPPORTED", ERR_LIB_RSA, RSA_R_RSA_OPERATIONS_NOT_SUPPORTED}, ++ #else ++ {"RSA_OPERATIONS_NOT_SUPPORTED", 4, 130}, ++ #endif ++ #ifdef RSA_R_SLEN_CHECK_FAILED ++ {"SLEN_CHECK_FAILED", ERR_LIB_RSA, RSA_R_SLEN_CHECK_FAILED}, ++ #else ++ {"SLEN_CHECK_FAILED", 4, 136}, ++ #endif ++ #ifdef RSA_R_SLEN_RECOVERY_FAILED ++ {"SLEN_RECOVERY_FAILED", ERR_LIB_RSA, RSA_R_SLEN_RECOVERY_FAILED}, ++ #else ++ {"SLEN_RECOVERY_FAILED", 4, 135}, ++ #endif ++ #ifdef RSA_R_SSLV3_ROLLBACK_ATTACK ++ {"SSLV3_ROLLBACK_ATTACK", ERR_LIB_RSA, RSA_R_SSLV3_ROLLBACK_ATTACK}, ++ #else ++ {"SSLV3_ROLLBACK_ATTACK", 4, 115}, ++ #endif ++ #ifdef RSA_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD ++ {"THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD", ERR_LIB_RSA, RSA_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD}, ++ #else ++ {"THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD", 4, 116}, ++ #endif ++ #ifdef RSA_R_UNKNOWN_ALGORITHM_TYPE ++ {"UNKNOWN_ALGORITHM_TYPE", ERR_LIB_RSA, RSA_R_UNKNOWN_ALGORITHM_TYPE}, ++ #else ++ {"UNKNOWN_ALGORITHM_TYPE", 4, 117}, ++ #endif ++ #ifdef RSA_R_UNKNOWN_DIGEST ++ {"UNKNOWN_DIGEST", ERR_LIB_RSA, RSA_R_UNKNOWN_DIGEST}, ++ #else ++ {"UNKNOWN_DIGEST", 4, 166}, ++ #endif ++ #ifdef RSA_R_UNKNOWN_MASK_DIGEST ++ {"UNKNOWN_MASK_DIGEST", ERR_LIB_RSA, RSA_R_UNKNOWN_MASK_DIGEST}, ++ #else ++ {"UNKNOWN_MASK_DIGEST", 4, 151}, ++ #endif ++ #ifdef RSA_R_UNKNOWN_PADDING_TYPE ++ {"UNKNOWN_PADDING_TYPE", ERR_LIB_RSA, RSA_R_UNKNOWN_PADDING_TYPE}, ++ #else ++ {"UNKNOWN_PADDING_TYPE", 4, 118}, ++ #endif ++ #ifdef RSA_R_UNSUPPORTED_ENCRYPTION_TYPE ++ {"UNSUPPORTED_ENCRYPTION_TYPE", ERR_LIB_RSA, RSA_R_UNSUPPORTED_ENCRYPTION_TYPE}, ++ #else ++ {"UNSUPPORTED_ENCRYPTION_TYPE", 4, 162}, ++ #endif ++ #ifdef RSA_R_UNSUPPORTED_LABEL_SOURCE ++ {"UNSUPPORTED_LABEL_SOURCE", ERR_LIB_RSA, RSA_R_UNSUPPORTED_LABEL_SOURCE}, ++ #else ++ {"UNSUPPORTED_LABEL_SOURCE", 4, 163}, ++ #endif ++ #ifdef RSA_R_UNSUPPORTED_MASK_ALGORITHM ++ {"UNSUPPORTED_MASK_ALGORITHM", ERR_LIB_RSA, RSA_R_UNSUPPORTED_MASK_ALGORITHM}, ++ #else ++ {"UNSUPPORTED_MASK_ALGORITHM", 4, 153}, ++ #endif ++ #ifdef RSA_R_UNSUPPORTED_MASK_PARAMETER ++ {"UNSUPPORTED_MASK_PARAMETER", ERR_LIB_RSA, RSA_R_UNSUPPORTED_MASK_PARAMETER}, ++ #else ++ {"UNSUPPORTED_MASK_PARAMETER", 4, 154}, ++ #endif ++ #ifdef RSA_R_UNSUPPORTED_SIGNATURE_TYPE ++ {"UNSUPPORTED_SIGNATURE_TYPE", ERR_LIB_RSA, RSA_R_UNSUPPORTED_SIGNATURE_TYPE}, ++ #else ++ {"UNSUPPORTED_SIGNATURE_TYPE", 4, 155}, ++ #endif ++ #ifdef RSA_R_VALUE_MISSING ++ {"VALUE_MISSING", ERR_LIB_RSA, RSA_R_VALUE_MISSING}, ++ #else ++ {"VALUE_MISSING", 4, 147}, ++ #endif ++ #ifdef RSA_R_WRONG_SIGNATURE_LENGTH ++ {"WRONG_SIGNATURE_LENGTH", ERR_LIB_RSA, RSA_R_WRONG_SIGNATURE_LENGTH}, ++ #else ++ {"WRONG_SIGNATURE_LENGTH", 4, 119}, ++ #endif ++ #ifdef SM2_R_ASN1_ERROR ++ {"ASN1_ERROR", ERR_LIB_SM2, SM2_R_ASN1_ERROR}, ++ #else ++ {"ASN1_ERROR", 53, 100}, ++ #endif ++ #ifdef SM2_R_BAD_SIGNATURE ++ {"BAD_SIGNATURE", ERR_LIB_SM2, SM2_R_BAD_SIGNATURE}, ++ #else ++ {"BAD_SIGNATURE", 53, 101}, ++ #endif ++ #ifdef SM2_R_BUFFER_TOO_SMALL ++ {"BUFFER_TOO_SMALL", ERR_LIB_SM2, SM2_R_BUFFER_TOO_SMALL}, ++ #else ++ {"BUFFER_TOO_SMALL", 53, 107}, ++ #endif ++ #ifdef SM2_R_DIST_ID_TOO_LARGE ++ {"DIST_ID_TOO_LARGE", ERR_LIB_SM2, SM2_R_DIST_ID_TOO_LARGE}, ++ #else ++ {"DIST_ID_TOO_LARGE", 53, 110}, ++ #endif ++ #ifdef SM2_R_ID_NOT_SET ++ {"ID_NOT_SET", ERR_LIB_SM2, SM2_R_ID_NOT_SET}, ++ #else ++ {"ID_NOT_SET", 53, 112}, ++ #endif ++ #ifdef SM2_R_ID_TOO_LARGE ++ {"ID_TOO_LARGE", ERR_LIB_SM2, SM2_R_ID_TOO_LARGE}, ++ #else ++ {"ID_TOO_LARGE", 53, 111}, ++ #endif ++ #ifdef SM2_R_INVALID_CURVE ++ {"INVALID_CURVE", ERR_LIB_SM2, SM2_R_INVALID_CURVE}, ++ #else ++ {"INVALID_CURVE", 53, 108}, ++ #endif ++ #ifdef SM2_R_INVALID_DIGEST ++ {"INVALID_DIGEST", ERR_LIB_SM2, SM2_R_INVALID_DIGEST}, ++ #else ++ {"INVALID_DIGEST", 53, 102}, ++ #endif ++ #ifdef SM2_R_INVALID_DIGEST_TYPE ++ {"INVALID_DIGEST_TYPE", ERR_LIB_SM2, SM2_R_INVALID_DIGEST_TYPE}, ++ #else ++ {"INVALID_DIGEST_TYPE", 53, 103}, ++ #endif ++ #ifdef SM2_R_INVALID_ENCODING ++ {"INVALID_ENCODING", ERR_LIB_SM2, SM2_R_INVALID_ENCODING}, ++ #else ++ {"INVALID_ENCODING", 53, 104}, ++ #endif ++ #ifdef SM2_R_INVALID_FIELD ++ {"INVALID_FIELD", ERR_LIB_SM2, SM2_R_INVALID_FIELD}, ++ #else ++ {"INVALID_FIELD", 53, 105}, ++ #endif ++ #ifdef SM2_R_INVALID_PRIVATE_KEY ++ {"INVALID_PRIVATE_KEY", ERR_LIB_SM2, SM2_R_INVALID_PRIVATE_KEY}, ++ #else ++ {"INVALID_PRIVATE_KEY", 53, 113}, ++ #endif ++ #ifdef SM2_R_NO_PARAMETERS_SET ++ {"NO_PARAMETERS_SET", ERR_LIB_SM2, SM2_R_NO_PARAMETERS_SET}, ++ #else ++ {"NO_PARAMETERS_SET", 53, 109}, ++ #endif ++ #ifdef SM2_R_USER_ID_TOO_LARGE ++ {"USER_ID_TOO_LARGE", ERR_LIB_SM2, SM2_R_USER_ID_TOO_LARGE}, ++ #else ++ {"USER_ID_TOO_LARGE", 53, 106}, ++ #endif ++ #ifdef SSL_R_APPLICATION_DATA_AFTER_CLOSE_NOTIFY ++ {"APPLICATION_DATA_AFTER_CLOSE_NOTIFY", ERR_LIB_SSL, SSL_R_APPLICATION_DATA_AFTER_CLOSE_NOTIFY}, ++ #else ++ {"APPLICATION_DATA_AFTER_CLOSE_NOTIFY", 20, 291}, ++ #endif ++ #ifdef SSL_R_APP_DATA_IN_HANDSHAKE ++ {"APP_DATA_IN_HANDSHAKE", ERR_LIB_SSL, SSL_R_APP_DATA_IN_HANDSHAKE}, ++ #else ++ {"APP_DATA_IN_HANDSHAKE", 20, 100}, ++ #endif ++ #ifdef SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT ++ {"ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT", ERR_LIB_SSL, SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT}, ++ #else ++ {"ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT", 20, 272}, ++ #endif ++ #ifdef SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE ++ {"AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE", ERR_LIB_SSL, SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE}, ++ #else ++ {"AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE", 20, 158}, ++ #endif ++ #ifdef SSL_R_BAD_CERTIFICATE ++ {"BAD_CERTIFICATE", ERR_LIB_SSL, SSL_R_BAD_CERTIFICATE}, ++ #else ++ {"BAD_CERTIFICATE", 20, 348}, ++ #endif ++ #ifdef SSL_R_BAD_CHANGE_CIPHER_SPEC ++ {"BAD_CHANGE_CIPHER_SPEC", ERR_LIB_SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC}, ++ #else ++ {"BAD_CHANGE_CIPHER_SPEC", 20, 103}, ++ #endif ++ #ifdef SSL_R_BAD_CIPHER ++ {"BAD_CIPHER", ERR_LIB_SSL, SSL_R_BAD_CIPHER}, ++ #else ++ {"BAD_CIPHER", 20, 186}, ++ #endif ++ #ifdef SSL_R_BAD_COMPRESSION_ALGORITHM ++ {"BAD_COMPRESSION_ALGORITHM", ERR_LIB_SSL, SSL_R_BAD_COMPRESSION_ALGORITHM}, ++ #else ++ {"BAD_COMPRESSION_ALGORITHM", 20, 326}, ++ #endif ++ #ifdef SSL_R_BAD_DATA ++ {"BAD_DATA", ERR_LIB_SSL, SSL_R_BAD_DATA}, ++ #else ++ {"BAD_DATA", 20, 390}, ++ #endif ++ #ifdef SSL_R_BAD_DATA_RETURNED_BY_CALLBACK ++ {"BAD_DATA_RETURNED_BY_CALLBACK", ERR_LIB_SSL, SSL_R_BAD_DATA_RETURNED_BY_CALLBACK}, ++ #else ++ {"BAD_DATA_RETURNED_BY_CALLBACK", 20, 106}, ++ #endif ++ #ifdef SSL_R_BAD_DECOMPRESSION ++ {"BAD_DECOMPRESSION", ERR_LIB_SSL, SSL_R_BAD_DECOMPRESSION}, ++ #else ++ {"BAD_DECOMPRESSION", 20, 107}, ++ #endif ++ #ifdef SSL_R_BAD_DH_VALUE ++ {"BAD_DH_VALUE", ERR_LIB_SSL, SSL_R_BAD_DH_VALUE}, ++ #else ++ {"BAD_DH_VALUE", 20, 102}, ++ #endif ++ #ifdef SSL_R_BAD_DIGEST_LENGTH ++ {"BAD_DIGEST_LENGTH", ERR_LIB_SSL, SSL_R_BAD_DIGEST_LENGTH}, ++ #else ++ {"BAD_DIGEST_LENGTH", 20, 111}, ++ #endif ++ #ifdef SSL_R_BAD_EARLY_DATA ++ {"BAD_EARLY_DATA", ERR_LIB_SSL, SSL_R_BAD_EARLY_DATA}, ++ #else ++ {"BAD_EARLY_DATA", 20, 233}, ++ #endif ++ #ifdef SSL_R_BAD_ECC_CERT ++ {"BAD_ECC_CERT", ERR_LIB_SSL, SSL_R_BAD_ECC_CERT}, ++ #else ++ {"BAD_ECC_CERT", 20, 304}, ++ #endif ++ #ifdef SSL_R_BAD_ECPOINT ++ {"BAD_ECPOINT", ERR_LIB_SSL, SSL_R_BAD_ECPOINT}, ++ #else ++ {"BAD_ECPOINT", 20, 306}, ++ #endif ++ #ifdef SSL_R_BAD_EXTENSION ++ {"BAD_EXTENSION", ERR_LIB_SSL, SSL_R_BAD_EXTENSION}, ++ #else ++ {"BAD_EXTENSION", 20, 110}, ++ #endif ++ #ifdef SSL_R_BAD_HANDSHAKE_LENGTH ++ {"BAD_HANDSHAKE_LENGTH", ERR_LIB_SSL, SSL_R_BAD_HANDSHAKE_LENGTH}, ++ #else ++ {"BAD_HANDSHAKE_LENGTH", 20, 332}, ++ #endif ++ #ifdef SSL_R_BAD_HANDSHAKE_STATE ++ {"BAD_HANDSHAKE_STATE", ERR_LIB_SSL, SSL_R_BAD_HANDSHAKE_STATE}, ++ #else ++ {"BAD_HANDSHAKE_STATE", 20, 236}, ++ #endif ++ #ifdef SSL_R_BAD_HELLO_REQUEST ++ {"BAD_HELLO_REQUEST", ERR_LIB_SSL, SSL_R_BAD_HELLO_REQUEST}, ++ #else ++ {"BAD_HELLO_REQUEST", 20, 105}, ++ #endif ++ #ifdef SSL_R_BAD_HRR_VERSION ++ {"BAD_HRR_VERSION", ERR_LIB_SSL, SSL_R_BAD_HRR_VERSION}, ++ #else ++ {"BAD_HRR_VERSION", 20, 263}, ++ #endif ++ #ifdef SSL_R_BAD_KEY_SHARE ++ {"BAD_KEY_SHARE", ERR_LIB_SSL, SSL_R_BAD_KEY_SHARE}, ++ #else ++ {"BAD_KEY_SHARE", 20, 108}, ++ #endif ++ #ifdef SSL_R_BAD_KEY_UPDATE ++ {"BAD_KEY_UPDATE", ERR_LIB_SSL, SSL_R_BAD_KEY_UPDATE}, ++ #else ++ {"BAD_KEY_UPDATE", 20, 122}, ++ #endif ++ #ifdef SSL_R_BAD_LEGACY_VERSION ++ {"BAD_LEGACY_VERSION", ERR_LIB_SSL, SSL_R_BAD_LEGACY_VERSION}, ++ #else ++ {"BAD_LEGACY_VERSION", 20, 292}, ++ #endif ++ #ifdef SSL_R_BAD_LENGTH ++ {"BAD_LENGTH", ERR_LIB_SSL, SSL_R_BAD_LENGTH}, ++ #else ++ {"BAD_LENGTH", 20, 271}, ++ #endif ++ #ifdef SSL_R_BAD_PACKET ++ {"BAD_PACKET", ERR_LIB_SSL, SSL_R_BAD_PACKET}, ++ #else ++ {"BAD_PACKET", 20, 240}, ++ #endif ++ #ifdef SSL_R_BAD_PACKET_LENGTH ++ {"BAD_PACKET_LENGTH", ERR_LIB_SSL, SSL_R_BAD_PACKET_LENGTH}, ++ #else ++ {"BAD_PACKET_LENGTH", 20, 115}, ++ #endif ++ #ifdef SSL_R_BAD_PROTOCOL_VERSION_NUMBER ++ {"BAD_PROTOCOL_VERSION_NUMBER", ERR_LIB_SSL, SSL_R_BAD_PROTOCOL_VERSION_NUMBER}, ++ #else ++ {"BAD_PROTOCOL_VERSION_NUMBER", 20, 116}, ++ #endif ++ #ifdef SSL_R_BAD_PSK ++ {"BAD_PSK", ERR_LIB_SSL, SSL_R_BAD_PSK}, ++ #else ++ {"BAD_PSK", 20, 219}, ++ #endif ++ #ifdef SSL_R_BAD_PSK_IDENTITY ++ {"BAD_PSK_IDENTITY", ERR_LIB_SSL, SSL_R_BAD_PSK_IDENTITY}, ++ #else ++ {"BAD_PSK_IDENTITY", 20, 114}, ++ #endif ++ #ifdef SSL_R_BAD_RECORD_TYPE ++ {"BAD_RECORD_TYPE", ERR_LIB_SSL, SSL_R_BAD_RECORD_TYPE}, ++ #else ++ {"BAD_RECORD_TYPE", 20, 443}, ++ #endif ++ #ifdef SSL_R_BAD_RSA_ENCRYPT ++ {"BAD_RSA_ENCRYPT", ERR_LIB_SSL, SSL_R_BAD_RSA_ENCRYPT}, ++ #else ++ {"BAD_RSA_ENCRYPT", 20, 119}, ++ #endif ++ #ifdef SSL_R_BAD_SIGNATURE ++ {"BAD_SIGNATURE", ERR_LIB_SSL, SSL_R_BAD_SIGNATURE}, ++ #else ++ {"BAD_SIGNATURE", 20, 123}, ++ #endif ++ #ifdef SSL_R_BAD_SRP_A_LENGTH ++ {"BAD_SRP_A_LENGTH", ERR_LIB_SSL, SSL_R_BAD_SRP_A_LENGTH}, ++ #else ++ {"BAD_SRP_A_LENGTH", 20, 347}, ++ #endif ++ #ifdef SSL_R_BAD_SRP_PARAMETERS ++ {"BAD_SRP_PARAMETERS", ERR_LIB_SSL, SSL_R_BAD_SRP_PARAMETERS}, ++ #else ++ {"BAD_SRP_PARAMETERS", 20, 371}, ++ #endif ++ #ifdef SSL_R_BAD_SRTP_MKI_VALUE ++ {"BAD_SRTP_MKI_VALUE", ERR_LIB_SSL, SSL_R_BAD_SRTP_MKI_VALUE}, ++ #else ++ {"BAD_SRTP_MKI_VALUE", 20, 352}, ++ #endif ++ #ifdef SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST ++ {"BAD_SRTP_PROTECTION_PROFILE_LIST", ERR_LIB_SSL, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST}, ++ #else ++ {"BAD_SRTP_PROTECTION_PROFILE_LIST", 20, 353}, ++ #endif ++ #ifdef SSL_R_BAD_SSL_FILETYPE ++ {"BAD_SSL_FILETYPE", ERR_LIB_SSL, SSL_R_BAD_SSL_FILETYPE}, ++ #else ++ {"BAD_SSL_FILETYPE", 20, 124}, ++ #endif ++ #ifdef SSL_R_BAD_VALUE ++ {"BAD_VALUE", ERR_LIB_SSL, SSL_R_BAD_VALUE}, ++ #else ++ {"BAD_VALUE", 20, 384}, ++ #endif ++ #ifdef SSL_R_BAD_WRITE_RETRY ++ {"BAD_WRITE_RETRY", ERR_LIB_SSL, SSL_R_BAD_WRITE_RETRY}, ++ #else ++ {"BAD_WRITE_RETRY", 20, 127}, ++ #endif ++ #ifdef SSL_R_BINDER_DOES_NOT_VERIFY ++ {"BINDER_DOES_NOT_VERIFY", ERR_LIB_SSL, SSL_R_BINDER_DOES_NOT_VERIFY}, ++ #else ++ {"BINDER_DOES_NOT_VERIFY", 20, 253}, ++ #endif ++ #ifdef SSL_R_BIO_NOT_SET ++ {"BIO_NOT_SET", ERR_LIB_SSL, SSL_R_BIO_NOT_SET}, ++ #else ++ {"BIO_NOT_SET", 20, 128}, ++ #endif ++ #ifdef SSL_R_BLOCK_CIPHER_PAD_IS_WRONG ++ {"BLOCK_CIPHER_PAD_IS_WRONG", ERR_LIB_SSL, SSL_R_BLOCK_CIPHER_PAD_IS_WRONG}, ++ #else ++ {"BLOCK_CIPHER_PAD_IS_WRONG", 20, 129}, ++ #endif ++ #ifdef SSL_R_BN_LIB ++ {"BN_LIB", ERR_LIB_SSL, SSL_R_BN_LIB}, ++ #else ++ {"BN_LIB", 20, 130}, ++ #endif ++ #ifdef SSL_R_CALLBACK_FAILED ++ {"CALLBACK_FAILED", ERR_LIB_SSL, SSL_R_CALLBACK_FAILED}, ++ #else ++ {"CALLBACK_FAILED", 20, 234}, ++ #endif ++ #ifdef SSL_R_CANNOT_CHANGE_CIPHER ++ {"CANNOT_CHANGE_CIPHER", ERR_LIB_SSL, SSL_R_CANNOT_CHANGE_CIPHER}, ++ #else ++ {"CANNOT_CHANGE_CIPHER", 20, 109}, ++ #endif ++ #ifdef SSL_R_CANNOT_GET_GROUP_NAME ++ {"CANNOT_GET_GROUP_NAME", ERR_LIB_SSL, SSL_R_CANNOT_GET_GROUP_NAME}, ++ #else ++ {"CANNOT_GET_GROUP_NAME", 20, 299}, ++ #endif ++ #ifdef SSL_R_CA_DN_LENGTH_MISMATCH ++ {"CA_DN_LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_CA_DN_LENGTH_MISMATCH}, ++ #else ++ {"CA_DN_LENGTH_MISMATCH", 20, 131}, ++ #endif ++ #ifdef SSL_R_CA_KEY_TOO_SMALL ++ {"CA_KEY_TOO_SMALL", ERR_LIB_SSL, SSL_R_CA_KEY_TOO_SMALL}, ++ #else ++ {"CA_KEY_TOO_SMALL", 20, 397}, ++ #endif ++ #ifdef SSL_R_CA_MD_TOO_WEAK ++ {"CA_MD_TOO_WEAK", ERR_LIB_SSL, SSL_R_CA_MD_TOO_WEAK}, ++ #else ++ {"CA_MD_TOO_WEAK", 20, 398}, ++ #endif ++ #ifdef SSL_R_CCS_RECEIVED_EARLY ++ {"CCS_RECEIVED_EARLY", ERR_LIB_SSL, SSL_R_CCS_RECEIVED_EARLY}, ++ #else ++ {"CCS_RECEIVED_EARLY", 20, 133}, ++ #endif ++ #ifdef SSL_R_CERTIFICATE_VERIFY_FAILED ++ {"CERTIFICATE_VERIFY_FAILED", ERR_LIB_SSL, SSL_R_CERTIFICATE_VERIFY_FAILED}, ++ #else ++ {"CERTIFICATE_VERIFY_FAILED", 20, 134}, ++ #endif ++ #ifdef SSL_R_CERT_CB_ERROR ++ {"CERT_CB_ERROR", ERR_LIB_SSL, SSL_R_CERT_CB_ERROR}, ++ #else ++ {"CERT_CB_ERROR", 20, 377}, ++ #endif ++ #ifdef SSL_R_CERT_LENGTH_MISMATCH ++ {"CERT_LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_CERT_LENGTH_MISMATCH}, ++ #else ++ {"CERT_LENGTH_MISMATCH", 20, 135}, ++ #endif ++ #ifdef SSL_R_CIPHERSUITE_DIGEST_HAS_CHANGED ++ {"CIPHERSUITE_DIGEST_HAS_CHANGED", ERR_LIB_SSL, SSL_R_CIPHERSUITE_DIGEST_HAS_CHANGED}, ++ #else ++ {"CIPHERSUITE_DIGEST_HAS_CHANGED", 20, 218}, ++ #endif ++ #ifdef SSL_R_CIPHER_CODE_WRONG_LENGTH ++ {"CIPHER_CODE_WRONG_LENGTH", ERR_LIB_SSL, SSL_R_CIPHER_CODE_WRONG_LENGTH}, ++ #else ++ {"CIPHER_CODE_WRONG_LENGTH", 20, 137}, ++ #endif ++ #ifdef SSL_R_CLIENTHELLO_TLSEXT ++ {"CLIENTHELLO_TLSEXT", ERR_LIB_SSL, SSL_R_CLIENTHELLO_TLSEXT}, ++ #else ++ {"CLIENTHELLO_TLSEXT", 20, 226}, ++ #endif ++ #ifdef SSL_R_COMPRESSED_LENGTH_TOO_LONG ++ {"COMPRESSED_LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_COMPRESSED_LENGTH_TOO_LONG}, ++ #else ++ {"COMPRESSED_LENGTH_TOO_LONG", 20, 140}, ++ #endif ++ #ifdef SSL_R_COMPRESSION_DISABLED ++ {"COMPRESSION_DISABLED", ERR_LIB_SSL, SSL_R_COMPRESSION_DISABLED}, ++ #else ++ {"COMPRESSION_DISABLED", 20, 343}, ++ #endif ++ #ifdef SSL_R_COMPRESSION_FAILURE ++ {"COMPRESSION_FAILURE", ERR_LIB_SSL, SSL_R_COMPRESSION_FAILURE}, ++ #else ++ {"COMPRESSION_FAILURE", 20, 141}, ++ #endif ++ #ifdef SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE ++ {"COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE", ERR_LIB_SSL, SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE}, ++ #else ++ {"COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE", 20, 307}, ++ #endif ++ #ifdef SSL_R_COMPRESSION_LIBRARY_ERROR ++ {"COMPRESSION_LIBRARY_ERROR", ERR_LIB_SSL, SSL_R_COMPRESSION_LIBRARY_ERROR}, ++ #else ++ {"COMPRESSION_LIBRARY_ERROR", 20, 142}, ++ #endif ++ #ifdef SSL_R_CONNECTION_TYPE_NOT_SET ++ {"CONNECTION_TYPE_NOT_SET", ERR_LIB_SSL, SSL_R_CONNECTION_TYPE_NOT_SET}, ++ #else ++ {"CONNECTION_TYPE_NOT_SET", 20, 144}, ++ #endif ++ #ifdef SSL_R_CONN_USE_ONLY ++ {"CONN_USE_ONLY", ERR_LIB_SSL, SSL_R_CONN_USE_ONLY}, ++ #else ++ {"CONN_USE_ONLY", 20, 356}, ++ #endif ++ #ifdef SSL_R_CONTEXT_NOT_DANE_ENABLED ++ {"CONTEXT_NOT_DANE_ENABLED", ERR_LIB_SSL, SSL_R_CONTEXT_NOT_DANE_ENABLED}, ++ #else ++ {"CONTEXT_NOT_DANE_ENABLED", 20, 167}, ++ #endif ++ #ifdef SSL_R_COOKIE_GEN_CALLBACK_FAILURE ++ {"COOKIE_GEN_CALLBACK_FAILURE", ERR_LIB_SSL, SSL_R_COOKIE_GEN_CALLBACK_FAILURE}, ++ #else ++ {"COOKIE_GEN_CALLBACK_FAILURE", 20, 400}, ++ #endif ++ #ifdef SSL_R_COOKIE_MISMATCH ++ {"COOKIE_MISMATCH", ERR_LIB_SSL, SSL_R_COOKIE_MISMATCH}, ++ #else ++ {"COOKIE_MISMATCH", 20, 308}, ++ #endif ++ #ifdef SSL_R_COPY_PARAMETERS_FAILED ++ {"COPY_PARAMETERS_FAILED", ERR_LIB_SSL, SSL_R_COPY_PARAMETERS_FAILED}, ++ #else ++ {"COPY_PARAMETERS_FAILED", 20, 296}, ++ #endif ++ #ifdef SSL_R_CUSTOM_EXT_HANDLER_ALREADY_INSTALLED ++ {"CUSTOM_EXT_HANDLER_ALREADY_INSTALLED", ERR_LIB_SSL, SSL_R_CUSTOM_EXT_HANDLER_ALREADY_INSTALLED}, ++ #else ++ {"CUSTOM_EXT_HANDLER_ALREADY_INSTALLED", 20, 206}, ++ #endif ++ #ifdef SSL_R_DANE_ALREADY_ENABLED ++ {"DANE_ALREADY_ENABLED", ERR_LIB_SSL, SSL_R_DANE_ALREADY_ENABLED}, ++ #else ++ {"DANE_ALREADY_ENABLED", 20, 172}, ++ #endif ++ #ifdef SSL_R_DANE_CANNOT_OVERRIDE_MTYPE_FULL ++ {"DANE_CANNOT_OVERRIDE_MTYPE_FULL", ERR_LIB_SSL, SSL_R_DANE_CANNOT_OVERRIDE_MTYPE_FULL}, ++ #else ++ {"DANE_CANNOT_OVERRIDE_MTYPE_FULL", 20, 173}, ++ #endif ++ #ifdef SSL_R_DANE_NOT_ENABLED ++ {"DANE_NOT_ENABLED", ERR_LIB_SSL, SSL_R_DANE_NOT_ENABLED}, ++ #else ++ {"DANE_NOT_ENABLED", 20, 175}, ++ #endif ++ #ifdef SSL_R_DANE_TLSA_BAD_CERTIFICATE ++ {"DANE_TLSA_BAD_CERTIFICATE", ERR_LIB_SSL, SSL_R_DANE_TLSA_BAD_CERTIFICATE}, ++ #else ++ {"DANE_TLSA_BAD_CERTIFICATE", 20, 180}, ++ #endif ++ #ifdef SSL_R_DANE_TLSA_BAD_CERTIFICATE_USAGE ++ {"DANE_TLSA_BAD_CERTIFICATE_USAGE", ERR_LIB_SSL, SSL_R_DANE_TLSA_BAD_CERTIFICATE_USAGE}, ++ #else ++ {"DANE_TLSA_BAD_CERTIFICATE_USAGE", 20, 184}, ++ #endif ++ #ifdef SSL_R_DANE_TLSA_BAD_DATA_LENGTH ++ {"DANE_TLSA_BAD_DATA_LENGTH", ERR_LIB_SSL, SSL_R_DANE_TLSA_BAD_DATA_LENGTH}, ++ #else ++ {"DANE_TLSA_BAD_DATA_LENGTH", 20, 189}, ++ #endif ++ #ifdef SSL_R_DANE_TLSA_BAD_DIGEST_LENGTH ++ {"DANE_TLSA_BAD_DIGEST_LENGTH", ERR_LIB_SSL, SSL_R_DANE_TLSA_BAD_DIGEST_LENGTH}, ++ #else ++ {"DANE_TLSA_BAD_DIGEST_LENGTH", 20, 192}, ++ #endif ++ #ifdef SSL_R_DANE_TLSA_BAD_MATCHING_TYPE ++ {"DANE_TLSA_BAD_MATCHING_TYPE", ERR_LIB_SSL, SSL_R_DANE_TLSA_BAD_MATCHING_TYPE}, ++ #else ++ {"DANE_TLSA_BAD_MATCHING_TYPE", 20, 200}, ++ #endif ++ #ifdef SSL_R_DANE_TLSA_BAD_PUBLIC_KEY ++ {"DANE_TLSA_BAD_PUBLIC_KEY", ERR_LIB_SSL, SSL_R_DANE_TLSA_BAD_PUBLIC_KEY}, ++ #else ++ {"DANE_TLSA_BAD_PUBLIC_KEY", 20, 201}, ++ #endif ++ #ifdef SSL_R_DANE_TLSA_BAD_SELECTOR ++ {"DANE_TLSA_BAD_SELECTOR", ERR_LIB_SSL, SSL_R_DANE_TLSA_BAD_SELECTOR}, ++ #else ++ {"DANE_TLSA_BAD_SELECTOR", 20, 202}, ++ #endif ++ #ifdef SSL_R_DANE_TLSA_NULL_DATA ++ {"DANE_TLSA_NULL_DATA", ERR_LIB_SSL, SSL_R_DANE_TLSA_NULL_DATA}, ++ #else ++ {"DANE_TLSA_NULL_DATA", 20, 203}, ++ #endif ++ #ifdef SSL_R_DATA_BETWEEN_CCS_AND_FINISHED ++ {"DATA_BETWEEN_CCS_AND_FINISHED", ERR_LIB_SSL, SSL_R_DATA_BETWEEN_CCS_AND_FINISHED}, ++ #else ++ {"DATA_BETWEEN_CCS_AND_FINISHED", 20, 145}, ++ #endif ++ #ifdef SSL_R_DATA_LENGTH_TOO_LONG ++ {"DATA_LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_DATA_LENGTH_TOO_LONG}, ++ #else ++ {"DATA_LENGTH_TOO_LONG", 20, 146}, ++ #endif ++ #ifdef SSL_R_DECRYPTION_FAILED ++ {"DECRYPTION_FAILED", ERR_LIB_SSL, SSL_R_DECRYPTION_FAILED}, ++ #else ++ {"DECRYPTION_FAILED", 20, 147}, ++ #endif ++ #ifdef SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC ++ {"DECRYPTION_FAILED_OR_BAD_RECORD_MAC", ERR_LIB_SSL, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC}, ++ #else ++ {"DECRYPTION_FAILED_OR_BAD_RECORD_MAC", 20, 281}, ++ #endif ++ #ifdef SSL_R_DH_KEY_TOO_SMALL ++ {"DH_KEY_TOO_SMALL", ERR_LIB_SSL, SSL_R_DH_KEY_TOO_SMALL}, ++ #else ++ {"DH_KEY_TOO_SMALL", 20, 394}, ++ #endif ++ #ifdef SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG ++ {"DH_PUBLIC_VALUE_LENGTH_IS_WRONG", ERR_LIB_SSL, SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG}, ++ #else ++ {"DH_PUBLIC_VALUE_LENGTH_IS_WRONG", 20, 148}, ++ #endif ++ #ifdef SSL_R_DIGEST_CHECK_FAILED ++ {"DIGEST_CHECK_FAILED", ERR_LIB_SSL, SSL_R_DIGEST_CHECK_FAILED}, ++ #else ++ {"DIGEST_CHECK_FAILED", 20, 149}, ++ #endif ++ #ifdef SSL_R_DTLS_MESSAGE_TOO_BIG ++ {"DTLS_MESSAGE_TOO_BIG", ERR_LIB_SSL, SSL_R_DTLS_MESSAGE_TOO_BIG}, ++ #else ++ {"DTLS_MESSAGE_TOO_BIG", 20, 334}, ++ #endif ++ #ifdef SSL_R_DUPLICATE_COMPRESSION_ID ++ {"DUPLICATE_COMPRESSION_ID", ERR_LIB_SSL, SSL_R_DUPLICATE_COMPRESSION_ID}, ++ #else ++ {"DUPLICATE_COMPRESSION_ID", 20, 309}, ++ #endif ++ #ifdef SSL_R_ECC_CERT_NOT_FOR_SIGNING ++ {"ECC_CERT_NOT_FOR_SIGNING", ERR_LIB_SSL, SSL_R_ECC_CERT_NOT_FOR_SIGNING}, ++ #else ++ {"ECC_CERT_NOT_FOR_SIGNING", 20, 318}, ++ #endif ++ #ifdef SSL_R_ECDH_REQUIRED_FOR_SUITEB_MODE ++ {"ECDH_REQUIRED_FOR_SUITEB_MODE", ERR_LIB_SSL, SSL_R_ECDH_REQUIRED_FOR_SUITEB_MODE}, ++ #else ++ {"ECDH_REQUIRED_FOR_SUITEB_MODE", 20, 374}, ++ #endif ++ #ifdef SSL_R_EE_KEY_TOO_SMALL ++ {"EE_KEY_TOO_SMALL", ERR_LIB_SSL, SSL_R_EE_KEY_TOO_SMALL}, ++ #else ++ {"EE_KEY_TOO_SMALL", 20, 399}, ++ #endif ++ #ifdef SSL_R_EMPTY_RAW_PUBLIC_KEY ++ {"EMPTY_RAW_PUBLIC_KEY", ERR_LIB_SSL, SSL_R_EMPTY_RAW_PUBLIC_KEY}, ++ #else ++ {"EMPTY_RAW_PUBLIC_KEY", 20, 349}, ++ #endif ++ #ifdef SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST ++ {"EMPTY_SRTP_PROTECTION_PROFILE_LIST", ERR_LIB_SSL, SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST}, ++ #else ++ {"EMPTY_SRTP_PROTECTION_PROFILE_LIST", 20, 354}, ++ #endif ++ #ifdef SSL_R_ENCRYPTED_LENGTH_TOO_LONG ++ {"ENCRYPTED_LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_ENCRYPTED_LENGTH_TOO_LONG}, ++ #else ++ {"ENCRYPTED_LENGTH_TOO_LONG", 20, 150}, ++ #endif ++ #ifdef SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST ++ {"ERROR_IN_RECEIVED_CIPHER_LIST", ERR_LIB_SSL, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST}, ++ #else ++ {"ERROR_IN_RECEIVED_CIPHER_LIST", 20, 151}, ++ #endif ++ #ifdef SSL_R_ERROR_IN_SYSTEM_DEFAULT_CONFIG ++ {"ERROR_IN_SYSTEM_DEFAULT_CONFIG", ERR_LIB_SSL, SSL_R_ERROR_IN_SYSTEM_DEFAULT_CONFIG}, ++ #else ++ {"ERROR_IN_SYSTEM_DEFAULT_CONFIG", 20, 419}, ++ #endif ++ #ifdef SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN ++ {"ERROR_SETTING_TLSA_BASE_DOMAIN", ERR_LIB_SSL, SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN}, ++ #else ++ {"ERROR_SETTING_TLSA_BASE_DOMAIN", 20, 204}, ++ #endif ++ #ifdef SSL_R_EXCEEDS_MAX_FRAGMENT_SIZE ++ {"EXCEEDS_MAX_FRAGMENT_SIZE", ERR_LIB_SSL, SSL_R_EXCEEDS_MAX_FRAGMENT_SIZE}, ++ #else ++ {"EXCEEDS_MAX_FRAGMENT_SIZE", 20, 194}, ++ #endif ++ #ifdef SSL_R_EXCESSIVE_MESSAGE_SIZE ++ {"EXCESSIVE_MESSAGE_SIZE", ERR_LIB_SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE}, ++ #else ++ {"EXCESSIVE_MESSAGE_SIZE", 20, 152}, ++ #endif ++ #ifdef SSL_R_EXTENSION_NOT_RECEIVED ++ {"EXTENSION_NOT_RECEIVED", ERR_LIB_SSL, SSL_R_EXTENSION_NOT_RECEIVED}, ++ #else ++ {"EXTENSION_NOT_RECEIVED", 20, 279}, ++ #endif ++ #ifdef SSL_R_EXTRA_DATA_IN_MESSAGE ++ {"EXTRA_DATA_IN_MESSAGE", ERR_LIB_SSL, SSL_R_EXTRA_DATA_IN_MESSAGE}, ++ #else ++ {"EXTRA_DATA_IN_MESSAGE", 20, 153}, ++ #endif ++ #ifdef SSL_R_EXT_LENGTH_MISMATCH ++ {"EXT_LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_EXT_LENGTH_MISMATCH}, ++ #else ++ {"EXT_LENGTH_MISMATCH", 20, 163}, ++ #endif ++ #ifdef SSL_R_FAILED_TO_GET_PARAMETER ++ {"FAILED_TO_GET_PARAMETER", ERR_LIB_SSL, SSL_R_FAILED_TO_GET_PARAMETER}, ++ #else ++ {"FAILED_TO_GET_PARAMETER", 20, 316}, ++ #endif ++ #ifdef SSL_R_FAILED_TO_INIT_ASYNC ++ {"FAILED_TO_INIT_ASYNC", ERR_LIB_SSL, SSL_R_FAILED_TO_INIT_ASYNC}, ++ #else ++ {"FAILED_TO_INIT_ASYNC", 20, 405}, ++ #endif ++ #ifdef SSL_R_FEATURE_NEGOTIATION_NOT_COMPLETE ++ {"FEATURE_NEGOTIATION_NOT_COMPLETE", ERR_LIB_SSL, SSL_R_FEATURE_NEGOTIATION_NOT_COMPLETE}, ++ #else ++ {"FEATURE_NEGOTIATION_NOT_COMPLETE", 20, 417}, ++ #endif ++ #ifdef SSL_R_FEATURE_NOT_RENEGOTIABLE ++ {"FEATURE_NOT_RENEGOTIABLE", ERR_LIB_SSL, SSL_R_FEATURE_NOT_RENEGOTIABLE}, ++ #else ++ {"FEATURE_NOT_RENEGOTIABLE", 20, 413}, ++ #endif ++ #ifdef SSL_R_FRAGMENTED_CLIENT_HELLO ++ {"FRAGMENTED_CLIENT_HELLO", ERR_LIB_SSL, SSL_R_FRAGMENTED_CLIENT_HELLO}, ++ #else ++ {"FRAGMENTED_CLIENT_HELLO", 20, 401}, ++ #endif ++ #ifdef SSL_R_GOT_A_FIN_BEFORE_A_CCS ++ {"GOT_A_FIN_BEFORE_A_CCS", ERR_LIB_SSL, SSL_R_GOT_A_FIN_BEFORE_A_CCS}, ++ #else ++ {"GOT_A_FIN_BEFORE_A_CCS", 20, 154}, ++ #endif ++ #ifdef SSL_R_HTTPS_PROXY_REQUEST ++ {"HTTPS_PROXY_REQUEST", ERR_LIB_SSL, SSL_R_HTTPS_PROXY_REQUEST}, ++ #else ++ {"HTTPS_PROXY_REQUEST", 20, 155}, ++ #endif ++ #ifdef SSL_R_HTTP_REQUEST ++ {"HTTP_REQUEST", ERR_LIB_SSL, SSL_R_HTTP_REQUEST}, ++ #else ++ {"HTTP_REQUEST", 20, 156}, ++ #endif ++ #ifdef SSL_R_ILLEGAL_POINT_COMPRESSION ++ {"ILLEGAL_POINT_COMPRESSION", ERR_LIB_SSL, SSL_R_ILLEGAL_POINT_COMPRESSION}, ++ #else ++ {"ILLEGAL_POINT_COMPRESSION", 20, 162}, ++ #endif ++ #ifdef SSL_R_ILLEGAL_SUITEB_DIGEST ++ {"ILLEGAL_SUITEB_DIGEST", ERR_LIB_SSL, SSL_R_ILLEGAL_SUITEB_DIGEST}, ++ #else ++ {"ILLEGAL_SUITEB_DIGEST", 20, 380}, ++ #endif ++ #ifdef SSL_R_INAPPROPRIATE_FALLBACK ++ {"INAPPROPRIATE_FALLBACK", ERR_LIB_SSL, SSL_R_INAPPROPRIATE_FALLBACK}, ++ #else ++ {"INAPPROPRIATE_FALLBACK", 20, 373}, ++ #endif ++ #ifdef SSL_R_INCONSISTENT_COMPRESSION ++ {"INCONSISTENT_COMPRESSION", ERR_LIB_SSL, SSL_R_INCONSISTENT_COMPRESSION}, ++ #else ++ {"INCONSISTENT_COMPRESSION", 20, 340}, ++ #endif ++ #ifdef SSL_R_INCONSISTENT_EARLY_DATA_ALPN ++ {"INCONSISTENT_EARLY_DATA_ALPN", ERR_LIB_SSL, SSL_R_INCONSISTENT_EARLY_DATA_ALPN}, ++ #else ++ {"INCONSISTENT_EARLY_DATA_ALPN", 20, 222}, ++ #endif ++ #ifdef SSL_R_INCONSISTENT_EARLY_DATA_SNI ++ {"INCONSISTENT_EARLY_DATA_SNI", ERR_LIB_SSL, SSL_R_INCONSISTENT_EARLY_DATA_SNI}, ++ #else ++ {"INCONSISTENT_EARLY_DATA_SNI", 20, 231}, ++ #endif ++ #ifdef SSL_R_INCONSISTENT_EXTMS ++ {"INCONSISTENT_EXTMS", ERR_LIB_SSL, SSL_R_INCONSISTENT_EXTMS}, ++ #else ++ {"INCONSISTENT_EXTMS", 20, 104}, ++ #endif ++ #ifdef SSL_R_INSUFFICIENT_SECURITY ++ {"INSUFFICIENT_SECURITY", ERR_LIB_SSL, SSL_R_INSUFFICIENT_SECURITY}, ++ #else ++ {"INSUFFICIENT_SECURITY", 20, 241}, ++ #endif ++ #ifdef SSL_R_INVALID_ALERT ++ {"INVALID_ALERT", ERR_LIB_SSL, SSL_R_INVALID_ALERT}, ++ #else ++ {"INVALID_ALERT", 20, 205}, ++ #endif ++ #ifdef SSL_R_INVALID_CCS_MESSAGE ++ {"INVALID_CCS_MESSAGE", ERR_LIB_SSL, SSL_R_INVALID_CCS_MESSAGE}, ++ #else ++ {"INVALID_CCS_MESSAGE", 20, 260}, ++ #endif ++ #ifdef SSL_R_INVALID_CERTIFICATE_OR_ALG ++ {"INVALID_CERTIFICATE_OR_ALG", ERR_LIB_SSL, SSL_R_INVALID_CERTIFICATE_OR_ALG}, ++ #else ++ {"INVALID_CERTIFICATE_OR_ALG", 20, 238}, ++ #endif ++ #ifdef SSL_R_INVALID_COMMAND ++ {"INVALID_COMMAND", ERR_LIB_SSL, SSL_R_INVALID_COMMAND}, ++ #else ++ {"INVALID_COMMAND", 20, 280}, ++ #endif ++ #ifdef SSL_R_INVALID_COMPRESSION_ALGORITHM ++ {"INVALID_COMPRESSION_ALGORITHM", ERR_LIB_SSL, SSL_R_INVALID_COMPRESSION_ALGORITHM}, ++ #else ++ {"INVALID_COMPRESSION_ALGORITHM", 20, 341}, ++ #endif ++ #ifdef SSL_R_INVALID_CONFIG ++ {"INVALID_CONFIG", ERR_LIB_SSL, SSL_R_INVALID_CONFIG}, ++ #else ++ {"INVALID_CONFIG", 20, 283}, ++ #endif ++ #ifdef SSL_R_INVALID_CONFIGURATION_NAME ++ {"INVALID_CONFIGURATION_NAME", ERR_LIB_SSL, SSL_R_INVALID_CONFIGURATION_NAME}, ++ #else ++ {"INVALID_CONFIGURATION_NAME", 20, 113}, ++ #endif ++ #ifdef SSL_R_INVALID_CONTEXT ++ {"INVALID_CONTEXT", ERR_LIB_SSL, SSL_R_INVALID_CONTEXT}, ++ #else ++ {"INVALID_CONTEXT", 20, 282}, ++ #endif ++ #ifdef SSL_R_INVALID_CT_VALIDATION_TYPE ++ {"INVALID_CT_VALIDATION_TYPE", ERR_LIB_SSL, SSL_R_INVALID_CT_VALIDATION_TYPE}, ++ #else ++ {"INVALID_CT_VALIDATION_TYPE", 20, 212}, ++ #endif ++ #ifdef SSL_R_INVALID_KEY_UPDATE_TYPE ++ {"INVALID_KEY_UPDATE_TYPE", ERR_LIB_SSL, SSL_R_INVALID_KEY_UPDATE_TYPE}, ++ #else ++ {"INVALID_KEY_UPDATE_TYPE", 20, 120}, ++ #endif ++ #ifdef SSL_R_INVALID_MAX_EARLY_DATA ++ {"INVALID_MAX_EARLY_DATA", ERR_LIB_SSL, SSL_R_INVALID_MAX_EARLY_DATA}, ++ #else ++ {"INVALID_MAX_EARLY_DATA", 20, 174}, ++ #endif ++ #ifdef SSL_R_INVALID_NULL_CMD_NAME ++ {"INVALID_NULL_CMD_NAME", ERR_LIB_SSL, SSL_R_INVALID_NULL_CMD_NAME}, ++ #else ++ {"INVALID_NULL_CMD_NAME", 20, 385}, ++ #endif ++ #ifdef SSL_R_INVALID_RAW_PUBLIC_KEY ++ {"INVALID_RAW_PUBLIC_KEY", ERR_LIB_SSL, SSL_R_INVALID_RAW_PUBLIC_KEY}, ++ #else ++ {"INVALID_RAW_PUBLIC_KEY", 20, 350}, ++ #endif ++ #ifdef SSL_R_INVALID_RECORD ++ {"INVALID_RECORD", ERR_LIB_SSL, SSL_R_INVALID_RECORD}, ++ #else ++ {"INVALID_RECORD", 20, 317}, ++ #endif ++ #ifdef SSL_R_INVALID_SEQUENCE_NUMBER ++ {"INVALID_SEQUENCE_NUMBER", ERR_LIB_SSL, SSL_R_INVALID_SEQUENCE_NUMBER}, ++ #else ++ {"INVALID_SEQUENCE_NUMBER", 20, 402}, ++ #endif ++ #ifdef SSL_R_INVALID_SERVERINFO_DATA ++ {"INVALID_SERVERINFO_DATA", ERR_LIB_SSL, SSL_R_INVALID_SERVERINFO_DATA}, ++ #else ++ {"INVALID_SERVERINFO_DATA", 20, 388}, ++ #endif ++ #ifdef SSL_R_INVALID_SESSION_ID ++ {"INVALID_SESSION_ID", ERR_LIB_SSL, SSL_R_INVALID_SESSION_ID}, ++ #else ++ {"INVALID_SESSION_ID", 20, 999}, ++ #endif ++ #ifdef SSL_R_INVALID_SRP_USERNAME ++ {"INVALID_SRP_USERNAME", ERR_LIB_SSL, SSL_R_INVALID_SRP_USERNAME}, ++ #else ++ {"INVALID_SRP_USERNAME", 20, 357}, ++ #endif ++ #ifdef SSL_R_INVALID_STATUS_RESPONSE ++ {"INVALID_STATUS_RESPONSE", ERR_LIB_SSL, SSL_R_INVALID_STATUS_RESPONSE}, ++ #else ++ {"INVALID_STATUS_RESPONSE", 20, 328}, ++ #endif ++ #ifdef SSL_R_INVALID_TICKET_KEYS_LENGTH ++ {"INVALID_TICKET_KEYS_LENGTH", ERR_LIB_SSL, SSL_R_INVALID_TICKET_KEYS_LENGTH}, ++ #else ++ {"INVALID_TICKET_KEYS_LENGTH", 20, 325}, ++ #endif ++ #ifdef SSL_R_LEGACY_SIGALG_DISALLOWED_OR_UNSUPPORTED ++ {"LEGACY_SIGALG_DISALLOWED_OR_UNSUPPORTED", ERR_LIB_SSL, SSL_R_LEGACY_SIGALG_DISALLOWED_OR_UNSUPPORTED}, ++ #else ++ {"LEGACY_SIGALG_DISALLOWED_OR_UNSUPPORTED", 20, 333}, ++ #endif ++ #ifdef SSL_R_LENGTH_MISMATCH ++ {"LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_LENGTH_MISMATCH}, ++ #else ++ {"LENGTH_MISMATCH", 20, 159}, ++ #endif ++ #ifdef SSL_R_LENGTH_TOO_LONG ++ {"LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_LENGTH_TOO_LONG}, ++ #else ++ {"LENGTH_TOO_LONG", 20, 404}, ++ #endif ++ #ifdef SSL_R_LENGTH_TOO_SHORT ++ {"LENGTH_TOO_SHORT", ERR_LIB_SSL, SSL_R_LENGTH_TOO_SHORT}, ++ #else ++ {"LENGTH_TOO_SHORT", 20, 160}, ++ #endif ++ #ifdef SSL_R_LIBRARY_BUG ++ {"LIBRARY_BUG", ERR_LIB_SSL, SSL_R_LIBRARY_BUG}, ++ #else ++ {"LIBRARY_BUG", 20, 274}, ++ #endif ++ #ifdef SSL_R_LIBRARY_HAS_NO_CIPHERS ++ {"LIBRARY_HAS_NO_CIPHERS", ERR_LIB_SSL, SSL_R_LIBRARY_HAS_NO_CIPHERS}, ++ #else ++ {"LIBRARY_HAS_NO_CIPHERS", 20, 161}, ++ #endif ++ #ifdef SSL_R_MAXIMUM_ENCRYPTED_PKTS_REACHED ++ {"MAXIMUM_ENCRYPTED_PKTS_REACHED", ERR_LIB_SSL, SSL_R_MAXIMUM_ENCRYPTED_PKTS_REACHED}, ++ #else ++ {"MAXIMUM_ENCRYPTED_PKTS_REACHED", 20, 395}, ++ #endif ++ #ifdef SSL_R_MISSING_DSA_SIGNING_CERT ++ {"MISSING_DSA_SIGNING_CERT", ERR_LIB_SSL, SSL_R_MISSING_DSA_SIGNING_CERT}, ++ #else ++ {"MISSING_DSA_SIGNING_CERT", 20, 165}, ++ #endif ++ #ifdef SSL_R_MISSING_ECDSA_SIGNING_CERT ++ {"MISSING_ECDSA_SIGNING_CERT", ERR_LIB_SSL, SSL_R_MISSING_ECDSA_SIGNING_CERT}, ++ #else ++ {"MISSING_ECDSA_SIGNING_CERT", 20, 381}, ++ #endif ++ #ifdef SSL_R_MISSING_FATAL ++ {"MISSING_FATAL", ERR_LIB_SSL, SSL_R_MISSING_FATAL}, ++ #else ++ {"MISSING_FATAL", 20, 256}, ++ #endif ++ #ifdef SSL_R_MISSING_PARAMETERS ++ {"MISSING_PARAMETERS", ERR_LIB_SSL, SSL_R_MISSING_PARAMETERS}, ++ #else ++ {"MISSING_PARAMETERS", 20, 290}, ++ #endif ++ #ifdef SSL_R_MISSING_PSK_KEX_MODES_EXTENSION ++ {"MISSING_PSK_KEX_MODES_EXTENSION", ERR_LIB_SSL, SSL_R_MISSING_PSK_KEX_MODES_EXTENSION}, ++ #else ++ {"MISSING_PSK_KEX_MODES_EXTENSION", 20, 310}, ++ #endif ++ #ifdef SSL_R_MISSING_RSA_CERTIFICATE ++ {"MISSING_RSA_CERTIFICATE", ERR_LIB_SSL, SSL_R_MISSING_RSA_CERTIFICATE}, ++ #else ++ {"MISSING_RSA_CERTIFICATE", 20, 168}, ++ #endif ++ #ifdef SSL_R_MISSING_RSA_ENCRYPTING_CERT ++ {"MISSING_RSA_ENCRYPTING_CERT", ERR_LIB_SSL, SSL_R_MISSING_RSA_ENCRYPTING_CERT}, ++ #else ++ {"MISSING_RSA_ENCRYPTING_CERT", 20, 169}, ++ #endif ++ #ifdef SSL_R_MISSING_RSA_SIGNING_CERT ++ {"MISSING_RSA_SIGNING_CERT", ERR_LIB_SSL, SSL_R_MISSING_RSA_SIGNING_CERT}, ++ #else ++ {"MISSING_RSA_SIGNING_CERT", 20, 170}, ++ #endif ++ #ifdef SSL_R_MISSING_SIGALGS_EXTENSION ++ {"MISSING_SIGALGS_EXTENSION", ERR_LIB_SSL, SSL_R_MISSING_SIGALGS_EXTENSION}, ++ #else ++ {"MISSING_SIGALGS_EXTENSION", 20, 112}, ++ #endif ++ #ifdef SSL_R_MISSING_SIGNING_CERT ++ {"MISSING_SIGNING_CERT", ERR_LIB_SSL, SSL_R_MISSING_SIGNING_CERT}, ++ #else ++ {"MISSING_SIGNING_CERT", 20, 221}, ++ #endif ++ #ifdef SSL_R_MISSING_SRP_PARAM ++ {"MISSING_SRP_PARAM", ERR_LIB_SSL, SSL_R_MISSING_SRP_PARAM}, ++ #else ++ {"MISSING_SRP_PARAM", 20, 358}, ++ #endif ++ #ifdef SSL_R_MISSING_SUPPORTED_GROUPS_EXTENSION ++ {"MISSING_SUPPORTED_GROUPS_EXTENSION", ERR_LIB_SSL, SSL_R_MISSING_SUPPORTED_GROUPS_EXTENSION}, ++ #else ++ {"MISSING_SUPPORTED_GROUPS_EXTENSION", 20, 209}, ++ #endif ++ #ifdef SSL_R_MISSING_SUPPORTED_VERSIONS_EXTENSION ++ {"MISSING_SUPPORTED_VERSIONS_EXTENSION", ERR_LIB_SSL, SSL_R_MISSING_SUPPORTED_VERSIONS_EXTENSION}, ++ #else ++ {"MISSING_SUPPORTED_VERSIONS_EXTENSION", 20, 420}, ++ #endif ++ #ifdef SSL_R_MISSING_TMP_DH_KEY ++ {"MISSING_TMP_DH_KEY", ERR_LIB_SSL, SSL_R_MISSING_TMP_DH_KEY}, ++ #else ++ {"MISSING_TMP_DH_KEY", 20, 171}, ++ #endif ++ #ifdef SSL_R_MISSING_TMP_ECDH_KEY ++ {"MISSING_TMP_ECDH_KEY", ERR_LIB_SSL, SSL_R_MISSING_TMP_ECDH_KEY}, ++ #else ++ {"MISSING_TMP_ECDH_KEY", 20, 311}, ++ #endif ++ #ifdef SSL_R_MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA ++ {"MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA", ERR_LIB_SSL, SSL_R_MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA}, ++ #else ++ {"MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA", 20, 293}, ++ #endif ++ #ifdef SSL_R_NOT_ON_RECORD_BOUNDARY ++ {"NOT_ON_RECORD_BOUNDARY", ERR_LIB_SSL, SSL_R_NOT_ON_RECORD_BOUNDARY}, ++ #else ++ {"NOT_ON_RECORD_BOUNDARY", 20, 182}, ++ #endif ++ #ifdef SSL_R_NOT_REPLACING_CERTIFICATE ++ {"NOT_REPLACING_CERTIFICATE", ERR_LIB_SSL, SSL_R_NOT_REPLACING_CERTIFICATE}, ++ #else ++ {"NOT_REPLACING_CERTIFICATE", 20, 289}, ++ #endif ++ #ifdef SSL_R_NOT_SERVER ++ {"NOT_SERVER", ERR_LIB_SSL, SSL_R_NOT_SERVER}, ++ #else ++ {"NOT_SERVER", 20, 284}, ++ #endif ++ #ifdef SSL_R_NO_APPLICATION_PROTOCOL ++ {"NO_APPLICATION_PROTOCOL", ERR_LIB_SSL, SSL_R_NO_APPLICATION_PROTOCOL}, ++ #else ++ {"NO_APPLICATION_PROTOCOL", 20, 235}, ++ #endif ++ #ifdef SSL_R_NO_CERTIFICATES_RETURNED ++ {"NO_CERTIFICATES_RETURNED", ERR_LIB_SSL, SSL_R_NO_CERTIFICATES_RETURNED}, ++ #else ++ {"NO_CERTIFICATES_RETURNED", 20, 176}, ++ #endif ++ #ifdef SSL_R_NO_CERTIFICATE_ASSIGNED ++ {"NO_CERTIFICATE_ASSIGNED", ERR_LIB_SSL, SSL_R_NO_CERTIFICATE_ASSIGNED}, ++ #else ++ {"NO_CERTIFICATE_ASSIGNED", 20, 177}, ++ #endif ++ #ifdef SSL_R_NO_CERTIFICATE_SET ++ {"NO_CERTIFICATE_SET", ERR_LIB_SSL, SSL_R_NO_CERTIFICATE_SET}, ++ #else ++ {"NO_CERTIFICATE_SET", 20, 179}, ++ #endif ++ #ifdef SSL_R_NO_CHANGE_FOLLOWING_HRR ++ {"NO_CHANGE_FOLLOWING_HRR", ERR_LIB_SSL, SSL_R_NO_CHANGE_FOLLOWING_HRR}, ++ #else ++ {"NO_CHANGE_FOLLOWING_HRR", 20, 214}, ++ #endif ++ #ifdef SSL_R_NO_CIPHERS_AVAILABLE ++ {"NO_CIPHERS_AVAILABLE", ERR_LIB_SSL, SSL_R_NO_CIPHERS_AVAILABLE}, ++ #else ++ {"NO_CIPHERS_AVAILABLE", 20, 181}, ++ #endif ++ #ifdef SSL_R_NO_CIPHERS_SPECIFIED ++ {"NO_CIPHERS_SPECIFIED", ERR_LIB_SSL, SSL_R_NO_CIPHERS_SPECIFIED}, ++ #else ++ {"NO_CIPHERS_SPECIFIED", 20, 183}, ++ #endif ++ #ifdef SSL_R_NO_CIPHER_MATCH ++ {"NO_CIPHER_MATCH", ERR_LIB_SSL, SSL_R_NO_CIPHER_MATCH}, ++ #else ++ {"NO_CIPHER_MATCH", 20, 185}, ++ #endif ++ #ifdef SSL_R_NO_CLIENT_CERT_METHOD ++ {"NO_CLIENT_CERT_METHOD", ERR_LIB_SSL, SSL_R_NO_CLIENT_CERT_METHOD}, ++ #else ++ {"NO_CLIENT_CERT_METHOD", 20, 331}, ++ #endif ++ #ifdef SSL_R_NO_COMPRESSION_SPECIFIED ++ {"NO_COMPRESSION_SPECIFIED", ERR_LIB_SSL, SSL_R_NO_COMPRESSION_SPECIFIED}, ++ #else ++ {"NO_COMPRESSION_SPECIFIED", 20, 187}, ++ #endif ++ #ifdef SSL_R_NO_COOKIE_CALLBACK_SET ++ {"NO_COOKIE_CALLBACK_SET", ERR_LIB_SSL, SSL_R_NO_COOKIE_CALLBACK_SET}, ++ #else ++ {"NO_COOKIE_CALLBACK_SET", 20, 287}, ++ #endif ++ #ifdef SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER ++ {"NO_GOST_CERTIFICATE_SENT_BY_PEER", ERR_LIB_SSL, SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER}, ++ #else ++ {"NO_GOST_CERTIFICATE_SENT_BY_PEER", 20, 330}, ++ #endif ++ #ifdef SSL_R_NO_METHOD_SPECIFIED ++ {"NO_METHOD_SPECIFIED", ERR_LIB_SSL, SSL_R_NO_METHOD_SPECIFIED}, ++ #else ++ {"NO_METHOD_SPECIFIED", 20, 188}, ++ #endif ++ #ifdef SSL_R_NO_PEM_EXTENSIONS ++ {"NO_PEM_EXTENSIONS", ERR_LIB_SSL, SSL_R_NO_PEM_EXTENSIONS}, ++ #else ++ {"NO_PEM_EXTENSIONS", 20, 389}, ++ #endif ++ #ifdef SSL_R_NO_PRIVATE_KEY_ASSIGNED ++ {"NO_PRIVATE_KEY_ASSIGNED", ERR_LIB_SSL, SSL_R_NO_PRIVATE_KEY_ASSIGNED}, ++ #else ++ {"NO_PRIVATE_KEY_ASSIGNED", 20, 190}, ++ #endif ++ #ifdef SSL_R_NO_PROTOCOLS_AVAILABLE ++ {"NO_PROTOCOLS_AVAILABLE", ERR_LIB_SSL, SSL_R_NO_PROTOCOLS_AVAILABLE}, ++ #else ++ {"NO_PROTOCOLS_AVAILABLE", 20, 191}, ++ #endif ++ #ifdef SSL_R_NO_RENEGOTIATION ++ {"NO_RENEGOTIATION", ERR_LIB_SSL, SSL_R_NO_RENEGOTIATION}, ++ #else ++ {"NO_RENEGOTIATION", 20, 339}, ++ #endif ++ #ifdef SSL_R_NO_REQUIRED_DIGEST ++ {"NO_REQUIRED_DIGEST", ERR_LIB_SSL, SSL_R_NO_REQUIRED_DIGEST}, ++ #else ++ {"NO_REQUIRED_DIGEST", 20, 324}, ++ #endif ++ #ifdef SSL_R_NO_SHARED_CIPHER ++ {"NO_SHARED_CIPHER", ERR_LIB_SSL, SSL_R_NO_SHARED_CIPHER}, ++ #else ++ {"NO_SHARED_CIPHER", 20, 193}, ++ #endif ++ #ifdef SSL_R_NO_SHARED_GROUPS ++ {"NO_SHARED_GROUPS", ERR_LIB_SSL, SSL_R_NO_SHARED_GROUPS}, ++ #else ++ {"NO_SHARED_GROUPS", 20, 410}, ++ #endif ++ #ifdef SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS ++ {"NO_SHARED_SIGNATURE_ALGORITHMS", ERR_LIB_SSL, SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS}, ++ #else ++ {"NO_SHARED_SIGNATURE_ALGORITHMS", 20, 376}, ++ #endif ++ #ifdef SSL_R_NO_SRTP_PROFILES ++ {"NO_SRTP_PROFILES", ERR_LIB_SSL, SSL_R_NO_SRTP_PROFILES}, ++ #else ++ {"NO_SRTP_PROFILES", 20, 359}, ++ #endif ++ #ifdef SSL_R_NO_STREAM ++ {"NO_STREAM", ERR_LIB_SSL, SSL_R_NO_STREAM}, ++ #else ++ {"NO_STREAM", 20, 355}, ++ #endif ++ #ifdef SSL_R_NO_SUITABLE_DIGEST_ALGORITHM ++ {"NO_SUITABLE_DIGEST_ALGORITHM", ERR_LIB_SSL, SSL_R_NO_SUITABLE_DIGEST_ALGORITHM}, ++ #else ++ {"NO_SUITABLE_DIGEST_ALGORITHM", 20, 297}, ++ #endif ++ #ifdef SSL_R_NO_SUITABLE_GROUPS ++ {"NO_SUITABLE_GROUPS", ERR_LIB_SSL, SSL_R_NO_SUITABLE_GROUPS}, ++ #else ++ {"NO_SUITABLE_GROUPS", 20, 295}, ++ #endif ++ #ifdef SSL_R_NO_SUITABLE_KEY_SHARE ++ {"NO_SUITABLE_KEY_SHARE", ERR_LIB_SSL, SSL_R_NO_SUITABLE_KEY_SHARE}, ++ #else ++ {"NO_SUITABLE_KEY_SHARE", 20, 101}, ++ #endif ++ #ifdef SSL_R_NO_SUITABLE_RECORD_LAYER ++ {"NO_SUITABLE_RECORD_LAYER", ERR_LIB_SSL, SSL_R_NO_SUITABLE_RECORD_LAYER}, ++ #else ++ {"NO_SUITABLE_RECORD_LAYER", 20, 322}, ++ #endif ++ #ifdef SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM ++ {"NO_SUITABLE_SIGNATURE_ALGORITHM", ERR_LIB_SSL, SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM}, ++ #else ++ {"NO_SUITABLE_SIGNATURE_ALGORITHM", 20, 118}, ++ #endif ++ #ifdef SSL_R_NO_VALID_SCTS ++ {"NO_VALID_SCTS", ERR_LIB_SSL, SSL_R_NO_VALID_SCTS}, ++ #else ++ {"NO_VALID_SCTS", 20, 216}, ++ #endif ++ #ifdef SSL_R_NO_VERIFY_COOKIE_CALLBACK ++ {"NO_VERIFY_COOKIE_CALLBACK", ERR_LIB_SSL, SSL_R_NO_VERIFY_COOKIE_CALLBACK}, ++ #else ++ {"NO_VERIFY_COOKIE_CALLBACK", 20, 403}, ++ #endif ++ #ifdef SSL_R_NULL_SSL_CTX ++ {"NULL_SSL_CTX", ERR_LIB_SSL, SSL_R_NULL_SSL_CTX}, ++ #else ++ {"NULL_SSL_CTX", 20, 195}, ++ #endif ++ #ifdef SSL_R_NULL_SSL_METHOD_PASSED ++ {"NULL_SSL_METHOD_PASSED", ERR_LIB_SSL, SSL_R_NULL_SSL_METHOD_PASSED}, ++ #else ++ {"NULL_SSL_METHOD_PASSED", 20, 196}, ++ #endif ++ #ifdef SSL_R_OCSP_CALLBACK_FAILURE ++ {"OCSP_CALLBACK_FAILURE", ERR_LIB_SSL, SSL_R_OCSP_CALLBACK_FAILURE}, ++ #else ++ {"OCSP_CALLBACK_FAILURE", 20, 305}, ++ #endif ++ #ifdef SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED ++ {"OLD_SESSION_CIPHER_NOT_RETURNED", ERR_LIB_SSL, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED}, ++ #else ++ {"OLD_SESSION_CIPHER_NOT_RETURNED", 20, 197}, ++ #endif ++ #ifdef SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED ++ {"OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED", ERR_LIB_SSL, SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED}, ++ #else ++ {"OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED", 20, 344}, ++ #endif ++ #ifdef SSL_R_OVERFLOW_ERROR ++ {"OVERFLOW_ERROR", ERR_LIB_SSL, SSL_R_OVERFLOW_ERROR}, ++ #else ++ {"OVERFLOW_ERROR", 20, 237}, ++ #endif ++ #ifdef SSL_R_PACKET_LENGTH_TOO_LONG ++ {"PACKET_LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_PACKET_LENGTH_TOO_LONG}, ++ #else ++ {"PACKET_LENGTH_TOO_LONG", 20, 198}, ++ #endif ++ #ifdef SSL_R_PARSE_TLSEXT ++ {"PARSE_TLSEXT", ERR_LIB_SSL, SSL_R_PARSE_TLSEXT}, ++ #else ++ {"PARSE_TLSEXT", 20, 227}, ++ #endif ++ #ifdef SSL_R_PATH_TOO_LONG ++ {"PATH_TOO_LONG", ERR_LIB_SSL, SSL_R_PATH_TOO_LONG}, ++ #else ++ {"PATH_TOO_LONG", 20, 270}, ++ #endif ++ #ifdef SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE ++ {"PEER_DID_NOT_RETURN_A_CERTIFICATE", ERR_LIB_SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE}, ++ #else ++ {"PEER_DID_NOT_RETURN_A_CERTIFICATE", 20, 199}, ++ #endif ++ #ifdef SSL_R_PEM_NAME_BAD_PREFIX ++ {"PEM_NAME_BAD_PREFIX", ERR_LIB_SSL, SSL_R_PEM_NAME_BAD_PREFIX}, ++ #else ++ {"PEM_NAME_BAD_PREFIX", 20, 391}, ++ #endif ++ #ifdef SSL_R_PEM_NAME_TOO_SHORT ++ {"PEM_NAME_TOO_SHORT", ERR_LIB_SSL, SSL_R_PEM_NAME_TOO_SHORT}, ++ #else ++ {"PEM_NAME_TOO_SHORT", 20, 392}, ++ #endif ++ #ifdef SSL_R_PIPELINE_FAILURE ++ {"PIPELINE_FAILURE", ERR_LIB_SSL, SSL_R_PIPELINE_FAILURE}, ++ #else ++ {"PIPELINE_FAILURE", 20, 406}, ++ #endif ++ #ifdef SSL_R_POLL_REQUEST_NOT_SUPPORTED ++ {"POLL_REQUEST_NOT_SUPPORTED", ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED}, ++ #else ++ {"POLL_REQUEST_NOT_SUPPORTED", 20, 418}, ++ #endif ++ #ifdef SSL_R_POST_HANDSHAKE_AUTH_ENCODING_ERR ++ {"POST_HANDSHAKE_AUTH_ENCODING_ERR", ERR_LIB_SSL, SSL_R_POST_HANDSHAKE_AUTH_ENCODING_ERR}, ++ #else ++ {"POST_HANDSHAKE_AUTH_ENCODING_ERR", 20, 278}, ++ #endif ++ #ifdef SSL_R_PRIVATE_KEY_MISMATCH ++ {"PRIVATE_KEY_MISMATCH", ERR_LIB_SSL, SSL_R_PRIVATE_KEY_MISMATCH}, ++ #else ++ {"PRIVATE_KEY_MISMATCH", 20, 288}, ++ #endif ++ #ifdef SSL_R_PROTOCOL_IS_SHUTDOWN ++ {"PROTOCOL_IS_SHUTDOWN", ERR_LIB_SSL, SSL_R_PROTOCOL_IS_SHUTDOWN}, ++ #else ++ {"PROTOCOL_IS_SHUTDOWN", 20, 207}, ++ #endif ++ #ifdef SSL_R_PSK_IDENTITY_NOT_FOUND ++ {"PSK_IDENTITY_NOT_FOUND", ERR_LIB_SSL, SSL_R_PSK_IDENTITY_NOT_FOUND}, ++ #else ++ {"PSK_IDENTITY_NOT_FOUND", 20, 223}, ++ #endif ++ #ifdef SSL_R_PSK_NO_CLIENT_CB ++ {"PSK_NO_CLIENT_CB", ERR_LIB_SSL, SSL_R_PSK_NO_CLIENT_CB}, ++ #else ++ {"PSK_NO_CLIENT_CB", 20, 224}, ++ #endif ++ #ifdef SSL_R_PSK_NO_SERVER_CB ++ {"PSK_NO_SERVER_CB", ERR_LIB_SSL, SSL_R_PSK_NO_SERVER_CB}, ++ #else ++ {"PSK_NO_SERVER_CB", 20, 225}, ++ #endif ++ #ifdef SSL_R_QUIC_HANDSHAKE_LAYER_ERROR ++ {"QUIC_HANDSHAKE_LAYER_ERROR", ERR_LIB_SSL, SSL_R_QUIC_HANDSHAKE_LAYER_ERROR}, ++ #else ++ {"QUIC_HANDSHAKE_LAYER_ERROR", 20, 393}, ++ #endif ++ #ifdef SSL_R_QUIC_NETWORK_ERROR ++ {"QUIC_NETWORK_ERROR", ERR_LIB_SSL, SSL_R_QUIC_NETWORK_ERROR}, ++ #else ++ {"QUIC_NETWORK_ERROR", 20, 387}, ++ #endif ++ #ifdef SSL_R_QUIC_PROTOCOL_ERROR ++ {"QUIC_PROTOCOL_ERROR", ERR_LIB_SSL, SSL_R_QUIC_PROTOCOL_ERROR}, ++ #else ++ {"QUIC_PROTOCOL_ERROR", 20, 382}, ++ #endif ++ #ifdef SSL_R_READ_BIO_NOT_SET ++ {"READ_BIO_NOT_SET", ERR_LIB_SSL, SSL_R_READ_BIO_NOT_SET}, ++ #else ++ {"READ_BIO_NOT_SET", 20, 211}, ++ #endif ++ #ifdef SSL_R_READ_TIMEOUT_EXPIRED ++ {"READ_TIMEOUT_EXPIRED", ERR_LIB_SSL, SSL_R_READ_TIMEOUT_EXPIRED}, ++ #else ++ {"READ_TIMEOUT_EXPIRED", 20, 312}, ++ #endif ++ #ifdef SSL_R_RECORDS_NOT_RELEASED ++ {"RECORDS_NOT_RELEASED", ERR_LIB_SSL, SSL_R_RECORDS_NOT_RELEASED}, ++ #else ++ {"RECORDS_NOT_RELEASED", 20, 321}, ++ #endif ++ #ifdef SSL_R_RECORD_LAYER_FAILURE ++ {"RECORD_LAYER_FAILURE", ERR_LIB_SSL, SSL_R_RECORD_LAYER_FAILURE}, ++ #else ++ {"RECORD_LAYER_FAILURE", 20, 313}, ++ #endif ++ #ifdef SSL_R_RECORD_LENGTH_MISMATCH ++ {"RECORD_LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_RECORD_LENGTH_MISMATCH}, ++ #else ++ {"RECORD_LENGTH_MISMATCH", 20, 213}, ++ #endif ++ #ifdef SSL_R_RECORD_TOO_SMALL ++ {"RECORD_TOO_SMALL", ERR_LIB_SSL, SSL_R_RECORD_TOO_SMALL}, ++ #else ++ {"RECORD_TOO_SMALL", 20, 298}, ++ #endif ++ #ifdef SSL_R_REMOTE_PEER_ADDRESS_NOT_SET ++ {"REMOTE_PEER_ADDRESS_NOT_SET", ERR_LIB_SSL, SSL_R_REMOTE_PEER_ADDRESS_NOT_SET}, ++ #else ++ {"REMOTE_PEER_ADDRESS_NOT_SET", 20, 346}, ++ #endif ++ #ifdef SSL_R_RENEGOTIATE_EXT_TOO_LONG ++ {"RENEGOTIATE_EXT_TOO_LONG", ERR_LIB_SSL, SSL_R_RENEGOTIATE_EXT_TOO_LONG}, ++ #else ++ {"RENEGOTIATE_EXT_TOO_LONG", 20, 335}, ++ #endif ++ #ifdef SSL_R_RENEGOTIATION_ENCODING_ERR ++ {"RENEGOTIATION_ENCODING_ERR", ERR_LIB_SSL, SSL_R_RENEGOTIATION_ENCODING_ERR}, ++ #else ++ {"RENEGOTIATION_ENCODING_ERR", 20, 336}, ++ #endif ++ #ifdef SSL_R_RENEGOTIATION_MISMATCH ++ {"RENEGOTIATION_MISMATCH", ERR_LIB_SSL, SSL_R_RENEGOTIATION_MISMATCH}, ++ #else ++ {"RENEGOTIATION_MISMATCH", 20, 337}, ++ #endif ++ #ifdef SSL_R_REQUEST_PENDING ++ {"REQUEST_PENDING", ERR_LIB_SSL, SSL_R_REQUEST_PENDING}, ++ #else ++ {"REQUEST_PENDING", 20, 285}, ++ #endif ++ #ifdef SSL_R_REQUEST_SENT ++ {"REQUEST_SENT", ERR_LIB_SSL, SSL_R_REQUEST_SENT}, ++ #else ++ {"REQUEST_SENT", 20, 286}, ++ #endif ++ #ifdef SSL_R_REQUIRED_CIPHER_MISSING ++ {"REQUIRED_CIPHER_MISSING", ERR_LIB_SSL, SSL_R_REQUIRED_CIPHER_MISSING}, ++ #else ++ {"REQUIRED_CIPHER_MISSING", 20, 215}, ++ #endif ++ #ifdef SSL_R_REQUIRED_COMPRESSION_ALGORITHM_MISSING ++ {"REQUIRED_COMPRESSION_ALGORITHM_MISSING", ERR_LIB_SSL, SSL_R_REQUIRED_COMPRESSION_ALGORITHM_MISSING}, ++ #else ++ {"REQUIRED_COMPRESSION_ALGORITHM_MISSING", 20, 342}, ++ #endif ++ #ifdef SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING ++ {"SCSV_RECEIVED_WHEN_RENEGOTIATING", ERR_LIB_SSL, SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING}, ++ #else ++ {"SCSV_RECEIVED_WHEN_RENEGOTIATING", 20, 345}, ++ #endif ++ #ifdef SSL_R_SCT_VERIFICATION_FAILED ++ {"SCT_VERIFICATION_FAILED", ERR_LIB_SSL, SSL_R_SCT_VERIFICATION_FAILED}, ++ #else ++ {"SCT_VERIFICATION_FAILED", 20, 208}, ++ #endif ++ #ifdef SSL_R_SEQUENCE_CTR_WRAPPED ++ {"SEQUENCE_CTR_WRAPPED", ERR_LIB_SSL, SSL_R_SEQUENCE_CTR_WRAPPED}, ++ #else ++ {"SEQUENCE_CTR_WRAPPED", 20, 327}, ++ #endif ++ #ifdef SSL_R_SERVERHELLO_TLSEXT ++ {"SERVERHELLO_TLSEXT", ERR_LIB_SSL, SSL_R_SERVERHELLO_TLSEXT}, ++ #else ++ {"SERVERHELLO_TLSEXT", 20, 275}, ++ #endif ++ #ifdef SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED ++ {"SESSION_ID_CONTEXT_UNINITIALIZED", ERR_LIB_SSL, SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED}, ++ #else ++ {"SESSION_ID_CONTEXT_UNINITIALIZED", 20, 277}, ++ #endif ++ #ifdef SSL_R_SHUTDOWN_WHILE_IN_INIT ++ {"SHUTDOWN_WHILE_IN_INIT", ERR_LIB_SSL, SSL_R_SHUTDOWN_WHILE_IN_INIT}, ++ #else ++ {"SHUTDOWN_WHILE_IN_INIT", 20, 407}, ++ #endif ++ #ifdef SSL_R_SIGNATURE_ALGORITHMS_ERROR ++ {"SIGNATURE_ALGORITHMS_ERROR", ERR_LIB_SSL, SSL_R_SIGNATURE_ALGORITHMS_ERROR}, ++ #else ++ {"SIGNATURE_ALGORITHMS_ERROR", 20, 360}, ++ #endif ++ #ifdef SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE ++ {"SIGNATURE_FOR_NON_SIGNING_CERTIFICATE", ERR_LIB_SSL, SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE}, ++ #else ++ {"SIGNATURE_FOR_NON_SIGNING_CERTIFICATE", 20, 220}, ++ #endif ++ #ifdef SSL_R_SRP_A_CALC ++ {"SRP_A_CALC", ERR_LIB_SSL, SSL_R_SRP_A_CALC}, ++ #else ++ {"SRP_A_CALC", 20, 361}, ++ #endif ++ #ifdef SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES ++ {"SRTP_COULD_NOT_ALLOCATE_PROFILES", ERR_LIB_SSL, SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES}, ++ #else ++ {"SRTP_COULD_NOT_ALLOCATE_PROFILES", 20, 362}, ++ #endif ++ #ifdef SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG ++ {"SRTP_PROTECTION_PROFILE_LIST_TOO_LONG", ERR_LIB_SSL, SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG}, ++ #else ++ {"SRTP_PROTECTION_PROFILE_LIST_TOO_LONG", 20, 363}, ++ #endif ++ #ifdef SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE ++ {"SRTP_UNKNOWN_PROTECTION_PROFILE", ERR_LIB_SSL, SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE}, ++ #else ++ {"SRTP_UNKNOWN_PROTECTION_PROFILE", 20, 364}, ++ #endif ++ #ifdef SSL_R_SSL3_EXT_INVALID_MAX_FRAGMENT_LENGTH ++ {"SSL3_EXT_INVALID_MAX_FRAGMENT_LENGTH", ERR_LIB_SSL, SSL_R_SSL3_EXT_INVALID_MAX_FRAGMENT_LENGTH}, ++ #else ++ {"SSL3_EXT_INVALID_MAX_FRAGMENT_LENGTH", 20, 232}, ++ #endif ++ #ifdef SSL_R_SSL3_EXT_INVALID_SERVERNAME ++ {"SSL3_EXT_INVALID_SERVERNAME", ERR_LIB_SSL, SSL_R_SSL3_EXT_INVALID_SERVERNAME}, ++ #else ++ {"SSL3_EXT_INVALID_SERVERNAME", 20, 319}, ++ #endif ++ #ifdef SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE ++ {"SSL3_EXT_INVALID_SERVERNAME_TYPE", ERR_LIB_SSL, SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE}, ++ #else ++ {"SSL3_EXT_INVALID_SERVERNAME_TYPE", 20, 320}, ++ #endif ++ #ifdef SSL_R_SSL3_SESSION_ID_TOO_LONG ++ {"SSL3_SESSION_ID_TOO_LONG", ERR_LIB_SSL, SSL_R_SSL3_SESSION_ID_TOO_LONG}, ++ #else ++ {"SSL3_SESSION_ID_TOO_LONG", 20, 300}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_BAD_CERTIFICATE ++ {"SSLV3_ALERT_BAD_CERTIFICATE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_BAD_CERTIFICATE}, ++ #else ++ {"SSLV3_ALERT_BAD_CERTIFICATE", 20, 1042}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_BAD_CERTIFICATE ++ {"SSLV3_ALERT_BAD_CERTIFICATE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_BAD_CERTIFICATE}, ++ #else ++ {"SSLV3_ALERT_BAD_CERTIFICATE", 20, 1042}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_BAD_RECORD_MAC ++ {"SSLV3_ALERT_BAD_RECORD_MAC", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_BAD_RECORD_MAC}, ++ #else ++ {"SSLV3_ALERT_BAD_RECORD_MAC", 20, 1020}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_BAD_RECORD_MAC ++ {"SSLV3_ALERT_BAD_RECORD_MAC", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_BAD_RECORD_MAC}, ++ #else ++ {"SSLV3_ALERT_BAD_RECORD_MAC", 20, 1020}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED ++ {"SSLV3_ALERT_CERTIFICATE_EXPIRED", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED}, ++ #else ++ {"SSLV3_ALERT_CERTIFICATE_EXPIRED", 20, 1045}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED ++ {"SSLV3_ALERT_CERTIFICATE_EXPIRED", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED}, ++ #else ++ {"SSLV3_ALERT_CERTIFICATE_EXPIRED", 20, 1045}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED ++ {"SSLV3_ALERT_CERTIFICATE_REVOKED", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED}, ++ #else ++ {"SSLV3_ALERT_CERTIFICATE_REVOKED", 20, 1044}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED ++ {"SSLV3_ALERT_CERTIFICATE_REVOKED", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED}, ++ #else ++ {"SSLV3_ALERT_CERTIFICATE_REVOKED", 20, 1044}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN ++ {"SSLV3_ALERT_CERTIFICATE_UNKNOWN", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN}, ++ #else ++ {"SSLV3_ALERT_CERTIFICATE_UNKNOWN", 20, 1046}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN ++ {"SSLV3_ALERT_CERTIFICATE_UNKNOWN", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN}, ++ #else ++ {"SSLV3_ALERT_CERTIFICATE_UNKNOWN", 20, 1046}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE ++ {"SSLV3_ALERT_DECOMPRESSION_FAILURE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE}, ++ #else ++ {"SSLV3_ALERT_DECOMPRESSION_FAILURE", 20, 1030}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE ++ {"SSLV3_ALERT_DECOMPRESSION_FAILURE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE}, ++ #else ++ {"SSLV3_ALERT_DECOMPRESSION_FAILURE", 20, 1030}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE ++ {"SSLV3_ALERT_HANDSHAKE_FAILURE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE}, ++ #else ++ {"SSLV3_ALERT_HANDSHAKE_FAILURE", 20, 1040}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE ++ {"SSLV3_ALERT_HANDSHAKE_FAILURE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE}, ++ #else ++ {"SSLV3_ALERT_HANDSHAKE_FAILURE", 20, 1040}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER ++ {"SSLV3_ALERT_ILLEGAL_PARAMETER", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER}, ++ #else ++ {"SSLV3_ALERT_ILLEGAL_PARAMETER", 20, 1047}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER ++ {"SSLV3_ALERT_ILLEGAL_PARAMETER", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER}, ++ #else ++ {"SSLV3_ALERT_ILLEGAL_PARAMETER", 20, 1047}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_NO_CERTIFICATE ++ {"SSLV3_ALERT_NO_CERTIFICATE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_NO_CERTIFICATE}, ++ #else ++ {"SSLV3_ALERT_NO_CERTIFICATE", 20, 1041}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_NO_CERTIFICATE ++ {"SSLV3_ALERT_NO_CERTIFICATE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_NO_CERTIFICATE}, ++ #else ++ {"SSLV3_ALERT_NO_CERTIFICATE", 20, 1041}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE ++ {"SSLV3_ALERT_UNEXPECTED_MESSAGE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE}, ++ #else ++ {"SSLV3_ALERT_UNEXPECTED_MESSAGE", 20, 1010}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE ++ {"SSLV3_ALERT_UNEXPECTED_MESSAGE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE}, ++ #else ++ {"SSLV3_ALERT_UNEXPECTED_MESSAGE", 20, 1010}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE ++ {"SSLV3_ALERT_UNSUPPORTED_CERTIFICATE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE}, ++ #else ++ {"SSLV3_ALERT_UNSUPPORTED_CERTIFICATE", 20, 1043}, ++ #endif ++ #ifdef SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE ++ {"SSLV3_ALERT_UNSUPPORTED_CERTIFICATE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE}, ++ #else ++ {"SSLV3_ALERT_UNSUPPORTED_CERTIFICATE", 20, 1043}, ++ #endif ++ #ifdef SSL_R_SSL_COMMAND_SECTION_EMPTY ++ {"SSL_COMMAND_SECTION_EMPTY", ERR_LIB_SSL, SSL_R_SSL_COMMAND_SECTION_EMPTY}, ++ #else ++ {"SSL_COMMAND_SECTION_EMPTY", 20, 117}, ++ #endif ++ #ifdef SSL_R_SSL_COMMAND_SECTION_NOT_FOUND ++ {"SSL_COMMAND_SECTION_NOT_FOUND", ERR_LIB_SSL, SSL_R_SSL_COMMAND_SECTION_NOT_FOUND}, ++ #else ++ {"SSL_COMMAND_SECTION_NOT_FOUND", 20, 125}, ++ #endif ++ #ifdef SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION ++ {"SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION", ERR_LIB_SSL, SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION}, ++ #else ++ {"SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION", 20, 228}, ++ #endif ++ #ifdef SSL_R_SSL_HANDSHAKE_FAILURE ++ {"SSL_HANDSHAKE_FAILURE", ERR_LIB_SSL, SSL_R_SSL_HANDSHAKE_FAILURE}, ++ #else ++ {"SSL_HANDSHAKE_FAILURE", 20, 229}, ++ #endif ++ #ifdef SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS ++ {"SSL_LIBRARY_HAS_NO_CIPHERS", ERR_LIB_SSL, SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS}, ++ #else ++ {"SSL_LIBRARY_HAS_NO_CIPHERS", 20, 230}, ++ #endif ++ #ifdef SSL_R_SSL_NEGATIVE_LENGTH ++ {"SSL_NEGATIVE_LENGTH", ERR_LIB_SSL, SSL_R_SSL_NEGATIVE_LENGTH}, ++ #else ++ {"SSL_NEGATIVE_LENGTH", 20, 372}, ++ #endif ++ #ifdef SSL_R_SSL_SECTION_EMPTY ++ {"SSL_SECTION_EMPTY", ERR_LIB_SSL, SSL_R_SSL_SECTION_EMPTY}, ++ #else ++ {"SSL_SECTION_EMPTY", 20, 126}, ++ #endif ++ #ifdef SSL_R_SSL_SECTION_NOT_FOUND ++ {"SSL_SECTION_NOT_FOUND", ERR_LIB_SSL, SSL_R_SSL_SECTION_NOT_FOUND}, ++ #else ++ {"SSL_SECTION_NOT_FOUND", 20, 136}, ++ #endif ++ #ifdef SSL_R_SSL_SESSION_ID_CALLBACK_FAILED ++ {"SSL_SESSION_ID_CALLBACK_FAILED", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_CALLBACK_FAILED}, ++ #else ++ {"SSL_SESSION_ID_CALLBACK_FAILED", 20, 301}, ++ #endif ++ #ifdef SSL_R_SSL_SESSION_ID_CONFLICT ++ {"SSL_SESSION_ID_CONFLICT", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_CONFLICT}, ++ #else ++ {"SSL_SESSION_ID_CONFLICT", 20, 302}, ++ #endif ++ #ifdef SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG ++ {"SSL_SESSION_ID_CONTEXT_TOO_LONG", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG}, ++ #else ++ {"SSL_SESSION_ID_CONTEXT_TOO_LONG", 20, 273}, ++ #endif ++ #ifdef SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH ++ {"SSL_SESSION_ID_HAS_BAD_LENGTH", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH}, ++ #else ++ {"SSL_SESSION_ID_HAS_BAD_LENGTH", 20, 303}, ++ #endif ++ #ifdef SSL_R_SSL_SESSION_ID_TOO_LONG ++ {"SSL_SESSION_ID_TOO_LONG", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_TOO_LONG}, ++ #else ++ {"SSL_SESSION_ID_TOO_LONG", 20, 408}, ++ #endif ++ #ifdef SSL_R_SSL_SESSION_VERSION_MISMATCH ++ {"SSL_SESSION_VERSION_MISMATCH", ERR_LIB_SSL, SSL_R_SSL_SESSION_VERSION_MISMATCH}, ++ #else ++ {"SSL_SESSION_VERSION_MISMATCH", 20, 210}, ++ #endif ++ #ifdef SSL_R_STILL_IN_INIT ++ {"STILL_IN_INIT", ERR_LIB_SSL, SSL_R_STILL_IN_INIT}, ++ #else ++ {"STILL_IN_INIT", 20, 121}, ++ #endif ++ #ifdef SSL_R_STREAM_COUNT_LIMITED ++ {"STREAM_COUNT_LIMITED", ERR_LIB_SSL, SSL_R_STREAM_COUNT_LIMITED}, ++ #else ++ {"STREAM_COUNT_LIMITED", 20, 411}, ++ #endif ++ #ifdef SSL_R_STREAM_FINISHED ++ {"STREAM_FINISHED", ERR_LIB_SSL, SSL_R_STREAM_FINISHED}, ++ #else ++ {"STREAM_FINISHED", 20, 365}, ++ #endif ++ #ifdef SSL_R_STREAM_RECV_ONLY ++ {"STREAM_RECV_ONLY", ERR_LIB_SSL, SSL_R_STREAM_RECV_ONLY}, ++ #else ++ {"STREAM_RECV_ONLY", 20, 366}, ++ #endif ++ #ifdef SSL_R_STREAM_RESET ++ {"STREAM_RESET", ERR_LIB_SSL, SSL_R_STREAM_RESET}, ++ #else ++ {"STREAM_RESET", 20, 375}, ++ #endif ++ #ifdef SSL_R_STREAM_SEND_ONLY ++ {"STREAM_SEND_ONLY", ERR_LIB_SSL, SSL_R_STREAM_SEND_ONLY}, ++ #else ++ {"STREAM_SEND_ONLY", 20, 379}, ++ #endif ++ #ifdef SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED ++ {"TLSV13_ALERT_CERTIFICATE_REQUIRED", ERR_LIB_SSL, SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED}, ++ #else ++ {"TLSV13_ALERT_CERTIFICATE_REQUIRED", 20, 1116}, ++ #endif ++ #ifdef SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED ++ {"TLSV13_ALERT_CERTIFICATE_REQUIRED", ERR_LIB_SSL, SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED}, ++ #else ++ {"TLSV13_ALERT_CERTIFICATE_REQUIRED", 20, 1116}, ++ #endif ++ #ifdef SSL_R_TLSV13_ALERT_MISSING_EXTENSION ++ {"TLSV13_ALERT_MISSING_EXTENSION", ERR_LIB_SSL, SSL_R_TLSV13_ALERT_MISSING_EXTENSION}, ++ #else ++ {"TLSV13_ALERT_MISSING_EXTENSION", 20, 1109}, ++ #endif ++ #ifdef SSL_R_TLSV13_ALERT_MISSING_EXTENSION ++ {"TLSV13_ALERT_MISSING_EXTENSION", ERR_LIB_SSL, SSL_R_TLSV13_ALERT_MISSING_EXTENSION}, ++ #else ++ {"TLSV13_ALERT_MISSING_EXTENSION", 20, 1109}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_ACCESS_DENIED ++ {"TLSV1_ALERT_ACCESS_DENIED", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_ACCESS_DENIED}, ++ #else ++ {"TLSV1_ALERT_ACCESS_DENIED", 20, 1049}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_ACCESS_DENIED ++ {"TLSV1_ALERT_ACCESS_DENIED", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_ACCESS_DENIED}, ++ #else ++ {"TLSV1_ALERT_ACCESS_DENIED", 20, 1049}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_DECODE_ERROR ++ {"TLSV1_ALERT_DECODE_ERROR", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_DECODE_ERROR}, ++ #else ++ {"TLSV1_ALERT_DECODE_ERROR", 20, 1050}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_DECODE_ERROR ++ {"TLSV1_ALERT_DECODE_ERROR", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_DECODE_ERROR}, ++ #else ++ {"TLSV1_ALERT_DECODE_ERROR", 20, 1050}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_DECRYPTION_FAILED ++ {"TLSV1_ALERT_DECRYPTION_FAILED", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_DECRYPTION_FAILED}, ++ #else ++ {"TLSV1_ALERT_DECRYPTION_FAILED", 20, 1021}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_DECRYPTION_FAILED ++ {"TLSV1_ALERT_DECRYPTION_FAILED", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_DECRYPTION_FAILED}, ++ #else ++ {"TLSV1_ALERT_DECRYPTION_FAILED", 20, 1021}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_DECRYPT_ERROR ++ {"TLSV1_ALERT_DECRYPT_ERROR", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_DECRYPT_ERROR}, ++ #else ++ {"TLSV1_ALERT_DECRYPT_ERROR", 20, 1051}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_DECRYPT_ERROR ++ {"TLSV1_ALERT_DECRYPT_ERROR", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_DECRYPT_ERROR}, ++ #else ++ {"TLSV1_ALERT_DECRYPT_ERROR", 20, 1051}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION ++ {"TLSV1_ALERT_EXPORT_RESTRICTION", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION}, ++ #else ++ {"TLSV1_ALERT_EXPORT_RESTRICTION", 20, 1060}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION ++ {"TLSV1_ALERT_EXPORT_RESTRICTION", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION}, ++ #else ++ {"TLSV1_ALERT_EXPORT_RESTRICTION", 20, 1060}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK ++ {"TLSV1_ALERT_INAPPROPRIATE_FALLBACK", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK}, ++ #else ++ {"TLSV1_ALERT_INAPPROPRIATE_FALLBACK", 20, 1086}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK ++ {"TLSV1_ALERT_INAPPROPRIATE_FALLBACK", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK}, ++ #else ++ {"TLSV1_ALERT_INAPPROPRIATE_FALLBACK", 20, 1086}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY ++ {"TLSV1_ALERT_INSUFFICIENT_SECURITY", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY}, ++ #else ++ {"TLSV1_ALERT_INSUFFICIENT_SECURITY", 20, 1071}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY ++ {"TLSV1_ALERT_INSUFFICIENT_SECURITY", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY}, ++ #else ++ {"TLSV1_ALERT_INSUFFICIENT_SECURITY", 20, 1071}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_INTERNAL_ERROR ++ {"TLSV1_ALERT_INTERNAL_ERROR", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_INTERNAL_ERROR}, ++ #else ++ {"TLSV1_ALERT_INTERNAL_ERROR", 20, 1080}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_INTERNAL_ERROR ++ {"TLSV1_ALERT_INTERNAL_ERROR", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_INTERNAL_ERROR}, ++ #else ++ {"TLSV1_ALERT_INTERNAL_ERROR", 20, 1080}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_NO_APPLICATION_PROTOCOL ++ {"TLSV1_ALERT_NO_APPLICATION_PROTOCOL", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_NO_APPLICATION_PROTOCOL}, ++ #else ++ {"TLSV1_ALERT_NO_APPLICATION_PROTOCOL", 20, 1120}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_NO_APPLICATION_PROTOCOL ++ {"TLSV1_ALERT_NO_APPLICATION_PROTOCOL", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_NO_APPLICATION_PROTOCOL}, ++ #else ++ {"TLSV1_ALERT_NO_APPLICATION_PROTOCOL", 20, 1120}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_NO_RENEGOTIATION ++ {"TLSV1_ALERT_NO_RENEGOTIATION", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_NO_RENEGOTIATION}, ++ #else ++ {"TLSV1_ALERT_NO_RENEGOTIATION", 20, 1100}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_NO_RENEGOTIATION ++ {"TLSV1_ALERT_NO_RENEGOTIATION", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_NO_RENEGOTIATION}, ++ #else ++ {"TLSV1_ALERT_NO_RENEGOTIATION", 20, 1100}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_PROTOCOL_VERSION ++ {"TLSV1_ALERT_PROTOCOL_VERSION", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_PROTOCOL_VERSION}, ++ #else ++ {"TLSV1_ALERT_PROTOCOL_VERSION", 20, 1070}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_PROTOCOL_VERSION ++ {"TLSV1_ALERT_PROTOCOL_VERSION", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_PROTOCOL_VERSION}, ++ #else ++ {"TLSV1_ALERT_PROTOCOL_VERSION", 20, 1070}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_RECORD_OVERFLOW ++ {"TLSV1_ALERT_RECORD_OVERFLOW", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_RECORD_OVERFLOW}, ++ #else ++ {"TLSV1_ALERT_RECORD_OVERFLOW", 20, 1022}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_RECORD_OVERFLOW ++ {"TLSV1_ALERT_RECORD_OVERFLOW", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_RECORD_OVERFLOW}, ++ #else ++ {"TLSV1_ALERT_RECORD_OVERFLOW", 20, 1022}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_UNKNOWN_CA ++ {"TLSV1_ALERT_UNKNOWN_CA", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_UNKNOWN_CA}, ++ #else ++ {"TLSV1_ALERT_UNKNOWN_CA", 20, 1048}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_UNKNOWN_CA ++ {"TLSV1_ALERT_UNKNOWN_CA", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_UNKNOWN_CA}, ++ #else ++ {"TLSV1_ALERT_UNKNOWN_CA", 20, 1048}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_UNKNOWN_PSK_IDENTITY ++ {"TLSV1_ALERT_UNKNOWN_PSK_IDENTITY", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_UNKNOWN_PSK_IDENTITY}, ++ #else ++ {"TLSV1_ALERT_UNKNOWN_PSK_IDENTITY", 20, 1115}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_UNKNOWN_PSK_IDENTITY ++ {"TLSV1_ALERT_UNKNOWN_PSK_IDENTITY", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_UNKNOWN_PSK_IDENTITY}, ++ #else ++ {"TLSV1_ALERT_UNKNOWN_PSK_IDENTITY", 20, 1115}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_USER_CANCELLED ++ {"TLSV1_ALERT_USER_CANCELLED", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_USER_CANCELLED}, ++ #else ++ {"TLSV1_ALERT_USER_CANCELLED", 20, 1090}, ++ #endif ++ #ifdef SSL_R_TLSV1_ALERT_USER_CANCELLED ++ {"TLSV1_ALERT_USER_CANCELLED", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_USER_CANCELLED}, ++ #else ++ {"TLSV1_ALERT_USER_CANCELLED", 20, 1090}, ++ #endif ++ #ifdef SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE ++ {"TLSV1_BAD_CERTIFICATE_HASH_VALUE", ERR_LIB_SSL, SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE}, ++ #else ++ {"TLSV1_BAD_CERTIFICATE_HASH_VALUE", 20, 1114}, ++ #endif ++ #ifdef SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE ++ {"TLSV1_BAD_CERTIFICATE_HASH_VALUE", ERR_LIB_SSL, SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE}, ++ #else ++ {"TLSV1_BAD_CERTIFICATE_HASH_VALUE", 20, 1114}, ++ #endif ++ #ifdef SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE ++ {"TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE", ERR_LIB_SSL, SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE}, ++ #else ++ {"TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE", 20, 1113}, ++ #endif ++ #ifdef SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE ++ {"TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE", ERR_LIB_SSL, SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE}, ++ #else ++ {"TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE", 20, 1113}, ++ #endif ++ #ifdef SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE ++ {"TLSV1_CERTIFICATE_UNOBTAINABLE", ERR_LIB_SSL, SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE}, ++ #else ++ {"TLSV1_CERTIFICATE_UNOBTAINABLE", 20, 1111}, ++ #endif ++ #ifdef SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE ++ {"TLSV1_CERTIFICATE_UNOBTAINABLE", ERR_LIB_SSL, SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE}, ++ #else ++ {"TLSV1_CERTIFICATE_UNOBTAINABLE", 20, 1111}, ++ #endif ++ #ifdef SSL_R_TLSV1_UNRECOGNIZED_NAME ++ {"TLSV1_UNRECOGNIZED_NAME", ERR_LIB_SSL, SSL_R_TLSV1_UNRECOGNIZED_NAME}, ++ #else ++ {"TLSV1_UNRECOGNIZED_NAME", 20, 1112}, ++ #endif ++ #ifdef SSL_R_TLSV1_UNRECOGNIZED_NAME ++ {"TLSV1_UNRECOGNIZED_NAME", ERR_LIB_SSL, SSL_R_TLSV1_UNRECOGNIZED_NAME}, ++ #else ++ {"TLSV1_UNRECOGNIZED_NAME", 20, 1112}, ++ #endif ++ #ifdef SSL_R_TLSV1_UNSUPPORTED_EXTENSION ++ {"TLSV1_UNSUPPORTED_EXTENSION", ERR_LIB_SSL, SSL_R_TLSV1_UNSUPPORTED_EXTENSION}, ++ #else ++ {"TLSV1_UNSUPPORTED_EXTENSION", 20, 1110}, ++ #endif ++ #ifdef SSL_R_TLSV1_UNSUPPORTED_EXTENSION ++ {"TLSV1_UNSUPPORTED_EXTENSION", ERR_LIB_SSL, SSL_R_TLSV1_UNSUPPORTED_EXTENSION}, ++ #else ++ {"TLSV1_UNSUPPORTED_EXTENSION", 20, 1110}, ++ #endif ++ #ifdef SSL_R_TLS_ILLEGAL_EXPORTER_LABEL ++ {"TLS_ILLEGAL_EXPORTER_LABEL", ERR_LIB_SSL, SSL_R_TLS_ILLEGAL_EXPORTER_LABEL}, ++ #else ++ {"TLS_ILLEGAL_EXPORTER_LABEL", 20, 367}, ++ #endif ++ #ifdef SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST ++ {"TLS_INVALID_ECPOINTFORMAT_LIST", ERR_LIB_SSL, SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST}, ++ #else ++ {"TLS_INVALID_ECPOINTFORMAT_LIST", 20, 157}, ++ #endif ++ #ifdef SSL_R_TOO_MANY_KEY_UPDATES ++ {"TOO_MANY_KEY_UPDATES", ERR_LIB_SSL, SSL_R_TOO_MANY_KEY_UPDATES}, ++ #else ++ {"TOO_MANY_KEY_UPDATES", 20, 132}, ++ #endif ++ #ifdef SSL_R_TOO_MANY_WARN_ALERTS ++ {"TOO_MANY_WARN_ALERTS", ERR_LIB_SSL, SSL_R_TOO_MANY_WARN_ALERTS}, ++ #else ++ {"TOO_MANY_WARN_ALERTS", 20, 409}, ++ #endif ++ #ifdef SSL_R_TOO_MUCH_EARLY_DATA ++ {"TOO_MUCH_EARLY_DATA", ERR_LIB_SSL, SSL_R_TOO_MUCH_EARLY_DATA}, ++ #else ++ {"TOO_MUCH_EARLY_DATA", 20, 164}, ++ #endif ++ #ifdef SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS ++ {"UNABLE_TO_FIND_ECDH_PARAMETERS", ERR_LIB_SSL, SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS}, ++ #else ++ {"UNABLE_TO_FIND_ECDH_PARAMETERS", 20, 314}, ++ #endif ++ #ifdef SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS ++ {"UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS", ERR_LIB_SSL, SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS}, ++ #else ++ {"UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS", 20, 239}, ++ #endif ++ #ifdef SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES ++ {"UNABLE_TO_LOAD_SSL3_MD5_ROUTINES", ERR_LIB_SSL, SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES}, ++ #else ++ {"UNABLE_TO_LOAD_SSL3_MD5_ROUTINES", 20, 242}, ++ #endif ++ #ifdef SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES ++ {"UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES", ERR_LIB_SSL, SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES}, ++ #else ++ {"UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES", 20, 243}, ++ #endif ++ #ifdef SSL_R_UNEXPECTED_CCS_MESSAGE ++ {"UNEXPECTED_CCS_MESSAGE", ERR_LIB_SSL, SSL_R_UNEXPECTED_CCS_MESSAGE}, ++ #else ++ {"UNEXPECTED_CCS_MESSAGE", 20, 262}, ++ #endif ++ #ifdef SSL_R_UNEXPECTED_END_OF_EARLY_DATA ++ {"UNEXPECTED_END_OF_EARLY_DATA", ERR_LIB_SSL, SSL_R_UNEXPECTED_END_OF_EARLY_DATA}, ++ #else ++ {"UNEXPECTED_END_OF_EARLY_DATA", 20, 178}, ++ #endif ++ #ifdef SSL_R_UNEXPECTED_EOF_WHILE_READING ++ {"UNEXPECTED_EOF_WHILE_READING", ERR_LIB_SSL, SSL_R_UNEXPECTED_EOF_WHILE_READING}, ++ #else ++ {"UNEXPECTED_EOF_WHILE_READING", 20, 294}, ++ #endif ++ #ifdef SSL_R_UNEXPECTED_MESSAGE ++ {"UNEXPECTED_MESSAGE", ERR_LIB_SSL, SSL_R_UNEXPECTED_MESSAGE}, ++ #else ++ {"UNEXPECTED_MESSAGE", 20, 244}, ++ #endif ++ #ifdef SSL_R_UNEXPECTED_RECORD ++ {"UNEXPECTED_RECORD", ERR_LIB_SSL, SSL_R_UNEXPECTED_RECORD}, ++ #else ++ {"UNEXPECTED_RECORD", 20, 245}, ++ #endif ++ #ifdef SSL_R_UNINITIALIZED ++ {"UNINITIALIZED", ERR_LIB_SSL, SSL_R_UNINITIALIZED}, ++ #else ++ {"UNINITIALIZED", 20, 276}, ++ #endif ++ #ifdef SSL_R_UNKNOWN_ALERT_TYPE ++ {"UNKNOWN_ALERT_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_ALERT_TYPE}, ++ #else ++ {"UNKNOWN_ALERT_TYPE", 20, 246}, ++ #endif ++ #ifdef SSL_R_UNKNOWN_CERTIFICATE_TYPE ++ {"UNKNOWN_CERTIFICATE_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE}, ++ #else ++ {"UNKNOWN_CERTIFICATE_TYPE", 20, 247}, ++ #endif ++ #ifdef SSL_R_UNKNOWN_CIPHER_RETURNED ++ {"UNKNOWN_CIPHER_RETURNED", ERR_LIB_SSL, SSL_R_UNKNOWN_CIPHER_RETURNED}, ++ #else ++ {"UNKNOWN_CIPHER_RETURNED", 20, 248}, ++ #endif ++ #ifdef SSL_R_UNKNOWN_CIPHER_TYPE ++ {"UNKNOWN_CIPHER_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_CIPHER_TYPE}, ++ #else ++ {"UNKNOWN_CIPHER_TYPE", 20, 249}, ++ #endif ++ #ifdef SSL_R_UNKNOWN_CMD_NAME ++ {"UNKNOWN_CMD_NAME", ERR_LIB_SSL, SSL_R_UNKNOWN_CMD_NAME}, ++ #else ++ {"UNKNOWN_CMD_NAME", 20, 386}, ++ #endif ++ #ifdef SSL_R_UNKNOWN_COMMAND ++ {"UNKNOWN_COMMAND", ERR_LIB_SSL, SSL_R_UNKNOWN_COMMAND}, ++ #else ++ {"UNKNOWN_COMMAND", 20, 139}, ++ #endif ++ #ifdef SSL_R_UNKNOWN_DIGEST ++ {"UNKNOWN_DIGEST", ERR_LIB_SSL, SSL_R_UNKNOWN_DIGEST}, ++ #else ++ {"UNKNOWN_DIGEST", 20, 368}, ++ #endif ++ #ifdef SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE ++ {"UNKNOWN_KEY_EXCHANGE_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE}, ++ #else ++ {"UNKNOWN_KEY_EXCHANGE_TYPE", 20, 250}, ++ #endif ++ #ifdef SSL_R_UNKNOWN_MANDATORY_PARAMETER ++ {"UNKNOWN_MANDATORY_PARAMETER", ERR_LIB_SSL, SSL_R_UNKNOWN_MANDATORY_PARAMETER}, ++ #else ++ {"UNKNOWN_MANDATORY_PARAMETER", 20, 323}, ++ #endif ++ #ifdef SSL_R_UNKNOWN_PKEY_TYPE ++ {"UNKNOWN_PKEY_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_PKEY_TYPE}, ++ #else ++ {"UNKNOWN_PKEY_TYPE", 20, 251}, ++ #endif ++ #ifdef SSL_R_UNKNOWN_PROTOCOL ++ {"UNKNOWN_PROTOCOL", ERR_LIB_SSL, SSL_R_UNKNOWN_PROTOCOL}, ++ #else ++ {"UNKNOWN_PROTOCOL", 20, 252}, ++ #endif ++ #ifdef SSL_R_UNKNOWN_SSL_VERSION ++ {"UNKNOWN_SSL_VERSION", ERR_LIB_SSL, SSL_R_UNKNOWN_SSL_VERSION}, ++ #else ++ {"UNKNOWN_SSL_VERSION", 20, 254}, ++ #endif ++ #ifdef SSL_R_UNKNOWN_STATE ++ {"UNKNOWN_STATE", ERR_LIB_SSL, SSL_R_UNKNOWN_STATE}, ++ #else ++ {"UNKNOWN_STATE", 20, 255}, ++ #endif ++ #ifdef SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED ++ {"UNSAFE_LEGACY_RENEGOTIATION_DISABLED", ERR_LIB_SSL, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED}, ++ #else ++ {"UNSAFE_LEGACY_RENEGOTIATION_DISABLED", 20, 338}, ++ #endif ++ #ifdef SSL_R_UNSOLICITED_EXTENSION ++ {"UNSOLICITED_EXTENSION", ERR_LIB_SSL, SSL_R_UNSOLICITED_EXTENSION}, ++ #else ++ {"UNSOLICITED_EXTENSION", 20, 217}, ++ #endif ++ #ifdef SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM ++ {"UNSUPPORTED_COMPRESSION_ALGORITHM", ERR_LIB_SSL, SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM}, ++ #else ++ {"UNSUPPORTED_COMPRESSION_ALGORITHM", 20, 257}, ++ #endif ++ #ifdef SSL_R_UNSUPPORTED_CONFIG_VALUE ++ {"UNSUPPORTED_CONFIG_VALUE", ERR_LIB_SSL, SSL_R_UNSUPPORTED_CONFIG_VALUE}, ++ #else ++ {"UNSUPPORTED_CONFIG_VALUE", 20, 414}, ++ #endif ++ #ifdef SSL_R_UNSUPPORTED_CONFIG_VALUE_CLASS ++ {"UNSUPPORTED_CONFIG_VALUE_CLASS", ERR_LIB_SSL, SSL_R_UNSUPPORTED_CONFIG_VALUE_CLASS}, ++ #else ++ {"UNSUPPORTED_CONFIG_VALUE_CLASS", 20, 415}, ++ #endif ++ #ifdef SSL_R_UNSUPPORTED_CONFIG_VALUE_OP ++ {"UNSUPPORTED_CONFIG_VALUE_OP", ERR_LIB_SSL, SSL_R_UNSUPPORTED_CONFIG_VALUE_OP}, ++ #else ++ {"UNSUPPORTED_CONFIG_VALUE_OP", 20, 416}, ++ #endif ++ #ifdef SSL_R_UNSUPPORTED_ELLIPTIC_CURVE ++ {"UNSUPPORTED_ELLIPTIC_CURVE", ERR_LIB_SSL, SSL_R_UNSUPPORTED_ELLIPTIC_CURVE}, ++ #else ++ {"UNSUPPORTED_ELLIPTIC_CURVE", 20, 315}, ++ #endif ++ #ifdef SSL_R_UNSUPPORTED_PROTOCOL ++ {"UNSUPPORTED_PROTOCOL", ERR_LIB_SSL, SSL_R_UNSUPPORTED_PROTOCOL}, ++ #else ++ {"UNSUPPORTED_PROTOCOL", 20, 258}, ++ #endif ++ #ifdef SSL_R_UNSUPPORTED_SSL_VERSION ++ {"UNSUPPORTED_SSL_VERSION", ERR_LIB_SSL, SSL_R_UNSUPPORTED_SSL_VERSION}, ++ #else ++ {"UNSUPPORTED_SSL_VERSION", 20, 259}, ++ #endif ++ #ifdef SSL_R_UNSUPPORTED_STATUS_TYPE ++ {"UNSUPPORTED_STATUS_TYPE", ERR_LIB_SSL, SSL_R_UNSUPPORTED_STATUS_TYPE}, ++ #else ++ {"UNSUPPORTED_STATUS_TYPE", 20, 329}, ++ #endif ++ #ifdef SSL_R_UNSUPPORTED_WRITE_FLAG ++ {"UNSUPPORTED_WRITE_FLAG", ERR_LIB_SSL, SSL_R_UNSUPPORTED_WRITE_FLAG}, ++ #else ++ {"UNSUPPORTED_WRITE_FLAG", 20, 412}, ++ #endif ++ #ifdef SSL_R_USE_SRTP_NOT_NEGOTIATED ++ {"USE_SRTP_NOT_NEGOTIATED", ERR_LIB_SSL, SSL_R_USE_SRTP_NOT_NEGOTIATED}, ++ #else ++ {"USE_SRTP_NOT_NEGOTIATED", 20, 369}, ++ #endif ++ #ifdef SSL_R_VERSION_TOO_HIGH ++ {"VERSION_TOO_HIGH", ERR_LIB_SSL, SSL_R_VERSION_TOO_HIGH}, ++ #else ++ {"VERSION_TOO_HIGH", 20, 166}, ++ #endif ++ #ifdef SSL_R_VERSION_TOO_LOW ++ {"VERSION_TOO_LOW", ERR_LIB_SSL, SSL_R_VERSION_TOO_LOW}, ++ #else ++ {"VERSION_TOO_LOW", 20, 396}, ++ #endif ++ #ifdef SSL_R_WRONG_CERTIFICATE_TYPE ++ {"WRONG_CERTIFICATE_TYPE", ERR_LIB_SSL, SSL_R_WRONG_CERTIFICATE_TYPE}, ++ #else ++ {"WRONG_CERTIFICATE_TYPE", 20, 383}, ++ #endif ++ #ifdef SSL_R_WRONG_CIPHER_RETURNED ++ {"WRONG_CIPHER_RETURNED", ERR_LIB_SSL, SSL_R_WRONG_CIPHER_RETURNED}, ++ #else ++ {"WRONG_CIPHER_RETURNED", 20, 261}, ++ #endif ++ #ifdef SSL_R_WRONG_CURVE ++ {"WRONG_CURVE", ERR_LIB_SSL, SSL_R_WRONG_CURVE}, ++ #else ++ {"WRONG_CURVE", 20, 378}, ++ #endif ++ #ifdef SSL_R_WRONG_RPK_TYPE ++ {"WRONG_RPK_TYPE", ERR_LIB_SSL, SSL_R_WRONG_RPK_TYPE}, ++ #else ++ {"WRONG_RPK_TYPE", 20, 351}, ++ #endif ++ #ifdef SSL_R_WRONG_SIGNATURE_LENGTH ++ {"WRONG_SIGNATURE_LENGTH", ERR_LIB_SSL, SSL_R_WRONG_SIGNATURE_LENGTH}, ++ #else ++ {"WRONG_SIGNATURE_LENGTH", 20, 264}, ++ #endif ++ #ifdef SSL_R_WRONG_SIGNATURE_SIZE ++ {"WRONG_SIGNATURE_SIZE", ERR_LIB_SSL, SSL_R_WRONG_SIGNATURE_SIZE}, ++ #else ++ {"WRONG_SIGNATURE_SIZE", 20, 265}, ++ #endif ++ #ifdef SSL_R_WRONG_SIGNATURE_TYPE ++ {"WRONG_SIGNATURE_TYPE", ERR_LIB_SSL, SSL_R_WRONG_SIGNATURE_TYPE}, ++ #else ++ {"WRONG_SIGNATURE_TYPE", 20, 370}, ++ #endif ++ #ifdef SSL_R_WRONG_SSL_VERSION ++ {"WRONG_SSL_VERSION", ERR_LIB_SSL, SSL_R_WRONG_SSL_VERSION}, ++ #else ++ {"WRONG_SSL_VERSION", 20, 266}, ++ #endif ++ #ifdef SSL_R_WRONG_VERSION_NUMBER ++ {"WRONG_VERSION_NUMBER", ERR_LIB_SSL, SSL_R_WRONG_VERSION_NUMBER}, ++ #else ++ {"WRONG_VERSION_NUMBER", 20, 267}, ++ #endif ++ #ifdef SSL_R_X509_LIB ++ {"X509_LIB", ERR_LIB_SSL, SSL_R_X509_LIB}, ++ #else ++ {"X509_LIB", 20, 268}, ++ #endif ++ #ifdef SSL_R_X509_VERIFICATION_SETUP_PROBLEMS ++ {"X509_VERIFICATION_SETUP_PROBLEMS", ERR_LIB_SSL, SSL_R_X509_VERIFICATION_SETUP_PROBLEMS}, ++ #else ++ {"X509_VERIFICATION_SETUP_PROBLEMS", 20, 269}, ++ #endif ++ #ifdef TS_R_BAD_PKCS7_TYPE ++ {"BAD_PKCS7_TYPE", ERR_LIB_TS, TS_R_BAD_PKCS7_TYPE}, ++ #else ++ {"BAD_PKCS7_TYPE", 47, 132}, ++ #endif ++ #ifdef TS_R_BAD_TYPE ++ {"BAD_TYPE", ERR_LIB_TS, TS_R_BAD_TYPE}, ++ #else ++ {"BAD_TYPE", 47, 133}, ++ #endif ++ #ifdef TS_R_CANNOT_LOAD_CERT ++ {"CANNOT_LOAD_CERT", ERR_LIB_TS, TS_R_CANNOT_LOAD_CERT}, ++ #else ++ {"CANNOT_LOAD_CERT", 47, 137}, ++ #endif ++ #ifdef TS_R_CANNOT_LOAD_KEY ++ {"CANNOT_LOAD_KEY", ERR_LIB_TS, TS_R_CANNOT_LOAD_KEY}, ++ #else ++ {"CANNOT_LOAD_KEY", 47, 138}, ++ #endif ++ #ifdef TS_R_CERTIFICATE_VERIFY_ERROR ++ {"CERTIFICATE_VERIFY_ERROR", ERR_LIB_TS, TS_R_CERTIFICATE_VERIFY_ERROR}, ++ #else ++ {"CERTIFICATE_VERIFY_ERROR", 47, 100}, ++ #endif ++ #ifdef TS_R_COULD_NOT_SET_ENGINE ++ {"COULD_NOT_SET_ENGINE", ERR_LIB_TS, TS_R_COULD_NOT_SET_ENGINE}, ++ #else ++ {"COULD_NOT_SET_ENGINE", 47, 127}, ++ #endif ++ #ifdef TS_R_COULD_NOT_SET_TIME ++ {"COULD_NOT_SET_TIME", ERR_LIB_TS, TS_R_COULD_NOT_SET_TIME}, ++ #else ++ {"COULD_NOT_SET_TIME", 47, 115}, ++ #endif ++ #ifdef TS_R_DETACHED_CONTENT ++ {"DETACHED_CONTENT", ERR_LIB_TS, TS_R_DETACHED_CONTENT}, ++ #else ++ {"DETACHED_CONTENT", 47, 134}, ++ #endif ++ #ifdef TS_R_ESS_ADD_SIGNING_CERT_ERROR ++ {"ESS_ADD_SIGNING_CERT_ERROR", ERR_LIB_TS, TS_R_ESS_ADD_SIGNING_CERT_ERROR}, ++ #else ++ {"ESS_ADD_SIGNING_CERT_ERROR", 47, 116}, ++ #endif ++ #ifdef TS_R_ESS_ADD_SIGNING_CERT_V2_ERROR ++ {"ESS_ADD_SIGNING_CERT_V2_ERROR", ERR_LIB_TS, TS_R_ESS_ADD_SIGNING_CERT_V2_ERROR}, ++ #else ++ {"ESS_ADD_SIGNING_CERT_V2_ERROR", 47, 139}, ++ #endif ++ #ifdef TS_R_ESS_SIGNING_CERTIFICATE_ERROR ++ {"ESS_SIGNING_CERTIFICATE_ERROR", ERR_LIB_TS, TS_R_ESS_SIGNING_CERTIFICATE_ERROR}, ++ #else ++ {"ESS_SIGNING_CERTIFICATE_ERROR", 47, 101}, ++ #endif ++ #ifdef TS_R_INVALID_NULL_POINTER ++ {"INVALID_NULL_POINTER", ERR_LIB_TS, TS_R_INVALID_NULL_POINTER}, ++ #else ++ {"INVALID_NULL_POINTER", 47, 102}, ++ #endif ++ #ifdef TS_R_INVALID_SIGNER_CERTIFICATE_PURPOSE ++ {"INVALID_SIGNER_CERTIFICATE_PURPOSE", ERR_LIB_TS, TS_R_INVALID_SIGNER_CERTIFICATE_PURPOSE}, ++ #else ++ {"INVALID_SIGNER_CERTIFICATE_PURPOSE", 47, 117}, ++ #endif ++ #ifdef TS_R_MESSAGE_IMPRINT_MISMATCH ++ {"MESSAGE_IMPRINT_MISMATCH", ERR_LIB_TS, TS_R_MESSAGE_IMPRINT_MISMATCH}, ++ #else ++ {"MESSAGE_IMPRINT_MISMATCH", 47, 103}, ++ #endif ++ #ifdef TS_R_NONCE_MISMATCH ++ {"NONCE_MISMATCH", ERR_LIB_TS, TS_R_NONCE_MISMATCH}, ++ #else ++ {"NONCE_MISMATCH", 47, 104}, ++ #endif ++ #ifdef TS_R_NONCE_NOT_RETURNED ++ {"NONCE_NOT_RETURNED", ERR_LIB_TS, TS_R_NONCE_NOT_RETURNED}, ++ #else ++ {"NONCE_NOT_RETURNED", 47, 105}, ++ #endif ++ #ifdef TS_R_NO_CONTENT ++ {"NO_CONTENT", ERR_LIB_TS, TS_R_NO_CONTENT}, ++ #else ++ {"NO_CONTENT", 47, 106}, ++ #endif ++ #ifdef TS_R_NO_TIME_STAMP_TOKEN ++ {"NO_TIME_STAMP_TOKEN", ERR_LIB_TS, TS_R_NO_TIME_STAMP_TOKEN}, ++ #else ++ {"NO_TIME_STAMP_TOKEN", 47, 107}, ++ #endif ++ #ifdef TS_R_PKCS7_ADD_SIGNATURE_ERROR ++ {"PKCS7_ADD_SIGNATURE_ERROR", ERR_LIB_TS, TS_R_PKCS7_ADD_SIGNATURE_ERROR}, ++ #else ++ {"PKCS7_ADD_SIGNATURE_ERROR", 47, 118}, ++ #endif ++ #ifdef TS_R_PKCS7_ADD_SIGNED_ATTR_ERROR ++ {"PKCS7_ADD_SIGNED_ATTR_ERROR", ERR_LIB_TS, TS_R_PKCS7_ADD_SIGNED_ATTR_ERROR}, ++ #else ++ {"PKCS7_ADD_SIGNED_ATTR_ERROR", 47, 119}, ++ #endif ++ #ifdef TS_R_PKCS7_TO_TS_TST_INFO_FAILED ++ {"PKCS7_TO_TS_TST_INFO_FAILED", ERR_LIB_TS, TS_R_PKCS7_TO_TS_TST_INFO_FAILED}, ++ #else ++ {"PKCS7_TO_TS_TST_INFO_FAILED", 47, 129}, ++ #endif ++ #ifdef TS_R_POLICY_MISMATCH ++ {"POLICY_MISMATCH", ERR_LIB_TS, TS_R_POLICY_MISMATCH}, ++ #else ++ {"POLICY_MISMATCH", 47, 108}, ++ #endif ++ #ifdef TS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE ++ {"PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE", ERR_LIB_TS, TS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE}, ++ #else ++ {"PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE", 47, 120}, ++ #endif ++ #ifdef TS_R_RESPONSE_SETUP_ERROR ++ {"RESPONSE_SETUP_ERROR", ERR_LIB_TS, TS_R_RESPONSE_SETUP_ERROR}, ++ #else ++ {"RESPONSE_SETUP_ERROR", 47, 121}, ++ #endif ++ #ifdef TS_R_SIGNATURE_FAILURE ++ {"SIGNATURE_FAILURE", ERR_LIB_TS, TS_R_SIGNATURE_FAILURE}, ++ #else ++ {"SIGNATURE_FAILURE", 47, 109}, ++ #endif ++ #ifdef TS_R_THERE_MUST_BE_ONE_SIGNER ++ {"THERE_MUST_BE_ONE_SIGNER", ERR_LIB_TS, TS_R_THERE_MUST_BE_ONE_SIGNER}, ++ #else ++ {"THERE_MUST_BE_ONE_SIGNER", 47, 110}, ++ #endif ++ #ifdef TS_R_TIME_SYSCALL_ERROR ++ {"TIME_SYSCALL_ERROR", ERR_LIB_TS, TS_R_TIME_SYSCALL_ERROR}, ++ #else ++ {"TIME_SYSCALL_ERROR", 47, 122}, ++ #endif ++ #ifdef TS_R_TOKEN_NOT_PRESENT ++ {"TOKEN_NOT_PRESENT", ERR_LIB_TS, TS_R_TOKEN_NOT_PRESENT}, ++ #else ++ {"TOKEN_NOT_PRESENT", 47, 130}, ++ #endif ++ #ifdef TS_R_TOKEN_PRESENT ++ {"TOKEN_PRESENT", ERR_LIB_TS, TS_R_TOKEN_PRESENT}, ++ #else ++ {"TOKEN_PRESENT", 47, 131}, ++ #endif ++ #ifdef TS_R_TSA_NAME_MISMATCH ++ {"TSA_NAME_MISMATCH", ERR_LIB_TS, TS_R_TSA_NAME_MISMATCH}, ++ #else ++ {"TSA_NAME_MISMATCH", 47, 111}, ++ #endif ++ #ifdef TS_R_TSA_UNTRUSTED ++ {"TSA_UNTRUSTED", ERR_LIB_TS, TS_R_TSA_UNTRUSTED}, ++ #else ++ {"TSA_UNTRUSTED", 47, 112}, ++ #endif ++ #ifdef TS_R_TST_INFO_SETUP_ERROR ++ {"TST_INFO_SETUP_ERROR", ERR_LIB_TS, TS_R_TST_INFO_SETUP_ERROR}, ++ #else ++ {"TST_INFO_SETUP_ERROR", 47, 123}, ++ #endif ++ #ifdef TS_R_TS_DATASIGN ++ {"TS_DATASIGN", ERR_LIB_TS, TS_R_TS_DATASIGN}, ++ #else ++ {"TS_DATASIGN", 47, 124}, ++ #endif ++ #ifdef TS_R_UNACCEPTABLE_POLICY ++ {"UNACCEPTABLE_POLICY", ERR_LIB_TS, TS_R_UNACCEPTABLE_POLICY}, ++ #else ++ {"UNACCEPTABLE_POLICY", 47, 125}, ++ #endif ++ #ifdef TS_R_UNSUPPORTED_MD_ALGORITHM ++ {"UNSUPPORTED_MD_ALGORITHM", ERR_LIB_TS, TS_R_UNSUPPORTED_MD_ALGORITHM}, ++ #else ++ {"UNSUPPORTED_MD_ALGORITHM", 47, 126}, ++ #endif ++ #ifdef TS_R_UNSUPPORTED_VERSION ++ {"UNSUPPORTED_VERSION", ERR_LIB_TS, TS_R_UNSUPPORTED_VERSION}, ++ #else ++ {"UNSUPPORTED_VERSION", 47, 113}, ++ #endif ++ #ifdef TS_R_VAR_BAD_VALUE ++ {"VAR_BAD_VALUE", ERR_LIB_TS, TS_R_VAR_BAD_VALUE}, ++ #else ++ {"VAR_BAD_VALUE", 47, 135}, ++ #endif ++ #ifdef TS_R_VAR_LOOKUP_FAILURE ++ {"VAR_LOOKUP_FAILURE", ERR_LIB_TS, TS_R_VAR_LOOKUP_FAILURE}, ++ #else ++ {"VAR_LOOKUP_FAILURE", 47, 136}, ++ #endif ++ #ifdef TS_R_WRONG_CONTENT_TYPE ++ {"WRONG_CONTENT_TYPE", ERR_LIB_TS, TS_R_WRONG_CONTENT_TYPE}, ++ #else ++ {"WRONG_CONTENT_TYPE", 47, 114}, ++ #endif ++ #ifdef UI_R_COMMON_OK_AND_CANCEL_CHARACTERS ++ {"COMMON_OK_AND_CANCEL_CHARACTERS", ERR_LIB_UI, UI_R_COMMON_OK_AND_CANCEL_CHARACTERS}, ++ #else ++ {"COMMON_OK_AND_CANCEL_CHARACTERS", 40, 104}, ++ #endif ++ #ifdef UI_R_INDEX_TOO_LARGE ++ {"INDEX_TOO_LARGE", ERR_LIB_UI, UI_R_INDEX_TOO_LARGE}, ++ #else ++ {"INDEX_TOO_LARGE", 40, 102}, ++ #endif ++ #ifdef UI_R_INDEX_TOO_SMALL ++ {"INDEX_TOO_SMALL", ERR_LIB_UI, UI_R_INDEX_TOO_SMALL}, ++ #else ++ {"INDEX_TOO_SMALL", 40, 103}, ++ #endif ++ #ifdef UI_R_NO_RESULT_BUFFER ++ {"NO_RESULT_BUFFER", ERR_LIB_UI, UI_R_NO_RESULT_BUFFER}, ++ #else ++ {"NO_RESULT_BUFFER", 40, 105}, ++ #endif ++ #ifdef UI_R_PROCESSING_ERROR ++ {"PROCESSING_ERROR", ERR_LIB_UI, UI_R_PROCESSING_ERROR}, ++ #else ++ {"PROCESSING_ERROR", 40, 107}, ++ #endif ++ #ifdef UI_R_RESULT_TOO_LARGE ++ {"RESULT_TOO_LARGE", ERR_LIB_UI, UI_R_RESULT_TOO_LARGE}, ++ #else ++ {"RESULT_TOO_LARGE", 40, 100}, ++ #endif ++ #ifdef UI_R_RESULT_TOO_SMALL ++ {"RESULT_TOO_SMALL", ERR_LIB_UI, UI_R_RESULT_TOO_SMALL}, ++ #else ++ {"RESULT_TOO_SMALL", 40, 101}, ++ #endif ++ #ifdef UI_R_SYSASSIGN_ERROR ++ {"SYSASSIGN_ERROR", ERR_LIB_UI, UI_R_SYSASSIGN_ERROR}, ++ #else ++ {"SYSASSIGN_ERROR", 40, 109}, ++ #endif ++ #ifdef UI_R_SYSDASSGN_ERROR ++ {"SYSDASSGN_ERROR", ERR_LIB_UI, UI_R_SYSDASSGN_ERROR}, ++ #else ++ {"SYSDASSGN_ERROR", 40, 110}, ++ #endif ++ #ifdef UI_R_SYSQIOW_ERROR ++ {"SYSQIOW_ERROR", ERR_LIB_UI, UI_R_SYSQIOW_ERROR}, ++ #else ++ {"SYSQIOW_ERROR", 40, 111}, ++ #endif ++ #ifdef UI_R_UNKNOWN_CONTROL_COMMAND ++ {"UNKNOWN_CONTROL_COMMAND", ERR_LIB_UI, UI_R_UNKNOWN_CONTROL_COMMAND}, ++ #else ++ {"UNKNOWN_CONTROL_COMMAND", 40, 106}, ++ #endif ++ #ifdef UI_R_UNKNOWN_TTYGET_ERRNO_VALUE ++ {"UNKNOWN_TTYGET_ERRNO_VALUE", ERR_LIB_UI, UI_R_UNKNOWN_TTYGET_ERRNO_VALUE}, ++ #else ++ {"UNKNOWN_TTYGET_ERRNO_VALUE", 40, 108}, ++ #endif ++ #ifdef UI_R_USER_DATA_DUPLICATION_UNSUPPORTED ++ {"USER_DATA_DUPLICATION_UNSUPPORTED", ERR_LIB_UI, UI_R_USER_DATA_DUPLICATION_UNSUPPORTED}, ++ #else ++ {"USER_DATA_DUPLICATION_UNSUPPORTED", 40, 112}, ++ #endif ++ #ifdef X509V3_R_BAD_IP_ADDRESS ++ {"BAD_IP_ADDRESS", ERR_LIB_X509V3, X509V3_R_BAD_IP_ADDRESS}, ++ #else ++ {"BAD_IP_ADDRESS", 34, 118}, ++ #endif ++ #ifdef X509V3_R_BAD_OBJECT ++ {"BAD_OBJECT", ERR_LIB_X509V3, X509V3_R_BAD_OBJECT}, ++ #else ++ {"BAD_OBJECT", 34, 119}, ++ #endif ++ #ifdef X509V3_R_BAD_OPTION ++ {"BAD_OPTION", ERR_LIB_X509V3, X509V3_R_BAD_OPTION}, ++ #else ++ {"BAD_OPTION", 34, 170}, ++ #endif ++ #ifdef X509V3_R_BAD_VALUE ++ {"BAD_VALUE", ERR_LIB_X509V3, X509V3_R_BAD_VALUE}, ++ #else ++ {"BAD_VALUE", 34, 171}, ++ #endif ++ #ifdef X509V3_R_BN_DEC2BN_ERROR ++ {"BN_DEC2BN_ERROR", ERR_LIB_X509V3, X509V3_R_BN_DEC2BN_ERROR}, ++ #else ++ {"BN_DEC2BN_ERROR", 34, 100}, ++ #endif ++ #ifdef X509V3_R_BN_TO_ASN1_INTEGER_ERROR ++ {"BN_TO_ASN1_INTEGER_ERROR", ERR_LIB_X509V3, X509V3_R_BN_TO_ASN1_INTEGER_ERROR}, ++ #else ++ {"BN_TO_ASN1_INTEGER_ERROR", 34, 101}, ++ #endif ++ #ifdef X509V3_R_DIRNAME_ERROR ++ {"DIRNAME_ERROR", ERR_LIB_X509V3, X509V3_R_DIRNAME_ERROR}, ++ #else ++ {"DIRNAME_ERROR", 34, 149}, ++ #endif ++ #ifdef X509V3_R_DISTPOINT_ALREADY_SET ++ {"DISTPOINT_ALREADY_SET", ERR_LIB_X509V3, X509V3_R_DISTPOINT_ALREADY_SET}, ++ #else ++ {"DISTPOINT_ALREADY_SET", 34, 160}, ++ #endif ++ #ifdef X509V3_R_DUPLICATE_ZONE_ID ++ {"DUPLICATE_ZONE_ID", ERR_LIB_X509V3, X509V3_R_DUPLICATE_ZONE_ID}, ++ #else ++ {"DUPLICATE_ZONE_ID", 34, 133}, ++ #endif ++ #ifdef X509V3_R_EMPTY_KEY_USAGE ++ {"EMPTY_KEY_USAGE", ERR_LIB_X509V3, X509V3_R_EMPTY_KEY_USAGE}, ++ #else ++ {"EMPTY_KEY_USAGE", 34, 169}, ++ #endif ++ #ifdef X509V3_R_ERROR_CONVERTING_ZONE ++ {"ERROR_CONVERTING_ZONE", ERR_LIB_X509V3, X509V3_R_ERROR_CONVERTING_ZONE}, ++ #else ++ {"ERROR_CONVERTING_ZONE", 34, 131}, ++ #endif ++ #ifdef X509V3_R_ERROR_CREATING_EXTENSION ++ {"ERROR_CREATING_EXTENSION", ERR_LIB_X509V3, X509V3_R_ERROR_CREATING_EXTENSION}, ++ #else ++ {"ERROR_CREATING_EXTENSION", 34, 144}, ++ #endif ++ #ifdef X509V3_R_ERROR_IN_EXTENSION ++ {"ERROR_IN_EXTENSION", ERR_LIB_X509V3, X509V3_R_ERROR_IN_EXTENSION}, ++ #else ++ {"ERROR_IN_EXTENSION", 34, 128}, ++ #endif ++ #ifdef X509V3_R_EXPECTED_A_SECTION_NAME ++ {"EXPECTED_A_SECTION_NAME", ERR_LIB_X509V3, X509V3_R_EXPECTED_A_SECTION_NAME}, ++ #else ++ {"EXPECTED_A_SECTION_NAME", 34, 137}, ++ #endif ++ #ifdef X509V3_R_EXTENSION_EXISTS ++ {"EXTENSION_EXISTS", ERR_LIB_X509V3, X509V3_R_EXTENSION_EXISTS}, ++ #else ++ {"EXTENSION_EXISTS", 34, 145}, ++ #endif ++ #ifdef X509V3_R_EXTENSION_NAME_ERROR ++ {"EXTENSION_NAME_ERROR", ERR_LIB_X509V3, X509V3_R_EXTENSION_NAME_ERROR}, ++ #else ++ {"EXTENSION_NAME_ERROR", 34, 115}, ++ #endif ++ #ifdef X509V3_R_EXTENSION_NOT_FOUND ++ {"EXTENSION_NOT_FOUND", ERR_LIB_X509V3, X509V3_R_EXTENSION_NOT_FOUND}, ++ #else ++ {"EXTENSION_NOT_FOUND", 34, 102}, ++ #endif ++ #ifdef X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED ++ {"EXTENSION_SETTING_NOT_SUPPORTED", ERR_LIB_X509V3, X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED}, ++ #else ++ {"EXTENSION_SETTING_NOT_SUPPORTED", 34, 103}, ++ #endif ++ #ifdef X509V3_R_EXTENSION_VALUE_ERROR ++ {"EXTENSION_VALUE_ERROR", ERR_LIB_X509V3, X509V3_R_EXTENSION_VALUE_ERROR}, ++ #else ++ {"EXTENSION_VALUE_ERROR", 34, 116}, ++ #endif ++ #ifdef X509V3_R_ILLEGAL_EMPTY_EXTENSION ++ {"ILLEGAL_EMPTY_EXTENSION", ERR_LIB_X509V3, X509V3_R_ILLEGAL_EMPTY_EXTENSION}, ++ #else ++ {"ILLEGAL_EMPTY_EXTENSION", 34, 151}, ++ #endif ++ #ifdef X509V3_R_INCORRECT_POLICY_SYNTAX_TAG ++ {"INCORRECT_POLICY_SYNTAX_TAG", ERR_LIB_X509V3, X509V3_R_INCORRECT_POLICY_SYNTAX_TAG}, ++ #else ++ {"INCORRECT_POLICY_SYNTAX_TAG", 34, 152}, ++ #endif ++ #ifdef X509V3_R_INVALID_ASNUMBER ++ {"INVALID_ASNUMBER", ERR_LIB_X509V3, X509V3_R_INVALID_ASNUMBER}, ++ #else ++ {"INVALID_ASNUMBER", 34, 162}, ++ #endif ++ #ifdef X509V3_R_INVALID_ASRANGE ++ {"INVALID_ASRANGE", ERR_LIB_X509V3, X509V3_R_INVALID_ASRANGE}, ++ #else ++ {"INVALID_ASRANGE", 34, 163}, ++ #endif ++ #ifdef X509V3_R_INVALID_BOOLEAN_STRING ++ {"INVALID_BOOLEAN_STRING", ERR_LIB_X509V3, X509V3_R_INVALID_BOOLEAN_STRING}, ++ #else ++ {"INVALID_BOOLEAN_STRING", 34, 104}, ++ #endif ++ #ifdef X509V3_R_INVALID_CERTIFICATE ++ {"INVALID_CERTIFICATE", ERR_LIB_X509V3, X509V3_R_INVALID_CERTIFICATE}, ++ #else ++ {"INVALID_CERTIFICATE", 34, 158}, ++ #endif ++ #ifdef X509V3_R_INVALID_EMPTY_NAME ++ {"INVALID_EMPTY_NAME", ERR_LIB_X509V3, X509V3_R_INVALID_EMPTY_NAME}, ++ #else ++ {"INVALID_EMPTY_NAME", 34, 108}, ++ #endif ++ #ifdef X509V3_R_INVALID_EXTENSION_STRING ++ {"INVALID_EXTENSION_STRING", ERR_LIB_X509V3, X509V3_R_INVALID_EXTENSION_STRING}, ++ #else ++ {"INVALID_EXTENSION_STRING", 34, 105}, ++ #endif ++ #ifdef X509V3_R_INVALID_INHERITANCE ++ {"INVALID_INHERITANCE", ERR_LIB_X509V3, X509V3_R_INVALID_INHERITANCE}, ++ #else ++ {"INVALID_INHERITANCE", 34, 165}, ++ #endif ++ #ifdef X509V3_R_INVALID_IPADDRESS ++ {"INVALID_IPADDRESS", ERR_LIB_X509V3, X509V3_R_INVALID_IPADDRESS}, ++ #else ++ {"INVALID_IPADDRESS", 34, 166}, ++ #endif ++ #ifdef X509V3_R_INVALID_MULTIPLE_RDNS ++ {"INVALID_MULTIPLE_RDNS", ERR_LIB_X509V3, X509V3_R_INVALID_MULTIPLE_RDNS}, ++ #else ++ {"INVALID_MULTIPLE_RDNS", 34, 161}, ++ #endif ++ #ifdef X509V3_R_INVALID_NAME ++ {"INVALID_NAME", ERR_LIB_X509V3, X509V3_R_INVALID_NAME}, ++ #else ++ {"INVALID_NAME", 34, 106}, ++ #endif ++ #ifdef X509V3_R_INVALID_NULL_ARGUMENT ++ {"INVALID_NULL_ARGUMENT", ERR_LIB_X509V3, X509V3_R_INVALID_NULL_ARGUMENT}, ++ #else ++ {"INVALID_NULL_ARGUMENT", 34, 107}, ++ #endif ++ #ifdef X509V3_R_INVALID_NULL_VALUE ++ {"INVALID_NULL_VALUE", ERR_LIB_X509V3, X509V3_R_INVALID_NULL_VALUE}, ++ #else ++ {"INVALID_NULL_VALUE", 34, 109}, ++ #endif ++ #ifdef X509V3_R_INVALID_NUMBER ++ {"INVALID_NUMBER", ERR_LIB_X509V3, X509V3_R_INVALID_NUMBER}, ++ #else ++ {"INVALID_NUMBER", 34, 140}, ++ #endif ++ #ifdef X509V3_R_INVALID_NUMBERS ++ {"INVALID_NUMBERS", ERR_LIB_X509V3, X509V3_R_INVALID_NUMBERS}, ++ #else ++ {"INVALID_NUMBERS", 34, 141}, ++ #endif ++ #ifdef X509V3_R_INVALID_OBJECT_IDENTIFIER ++ {"INVALID_OBJECT_IDENTIFIER", ERR_LIB_X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER}, ++ #else ++ {"INVALID_OBJECT_IDENTIFIER", 34, 110}, ++ #endif ++ #ifdef X509V3_R_INVALID_OPTION ++ {"INVALID_OPTION", ERR_LIB_X509V3, X509V3_R_INVALID_OPTION}, ++ #else ++ {"INVALID_OPTION", 34, 138}, ++ #endif ++ #ifdef X509V3_R_INVALID_POLICY_IDENTIFIER ++ {"INVALID_POLICY_IDENTIFIER", ERR_LIB_X509V3, X509V3_R_INVALID_POLICY_IDENTIFIER}, ++ #else ++ {"INVALID_POLICY_IDENTIFIER", 34, 134}, ++ #endif ++ #ifdef X509V3_R_INVALID_PROXY_POLICY_SETTING ++ {"INVALID_PROXY_POLICY_SETTING", ERR_LIB_X509V3, X509V3_R_INVALID_PROXY_POLICY_SETTING}, ++ #else ++ {"INVALID_PROXY_POLICY_SETTING", 34, 153}, ++ #endif ++ #ifdef X509V3_R_INVALID_PURPOSE ++ {"INVALID_PURPOSE", ERR_LIB_X509V3, X509V3_R_INVALID_PURPOSE}, ++ #else ++ {"INVALID_PURPOSE", 34, 146}, ++ #endif ++ #ifdef X509V3_R_INVALID_SAFI ++ {"INVALID_SAFI", ERR_LIB_X509V3, X509V3_R_INVALID_SAFI}, ++ #else ++ {"INVALID_SAFI", 34, 164}, ++ #endif ++ #ifdef X509V3_R_INVALID_SECTION ++ {"INVALID_SECTION", ERR_LIB_X509V3, X509V3_R_INVALID_SECTION}, ++ #else ++ {"INVALID_SECTION", 34, 135}, ++ #endif ++ #ifdef X509V3_R_INVALID_SYNTAX ++ {"INVALID_SYNTAX", ERR_LIB_X509V3, X509V3_R_INVALID_SYNTAX}, ++ #else ++ {"INVALID_SYNTAX", 34, 143}, ++ #endif ++ #ifdef X509V3_R_ISSUER_DECODE_ERROR ++ {"ISSUER_DECODE_ERROR", ERR_LIB_X509V3, X509V3_R_ISSUER_DECODE_ERROR}, ++ #else ++ {"ISSUER_DECODE_ERROR", 34, 126}, ++ #endif ++ #ifdef X509V3_R_MISSING_VALUE ++ {"MISSING_VALUE", ERR_LIB_X509V3, X509V3_R_MISSING_VALUE}, ++ #else ++ {"MISSING_VALUE", 34, 124}, ++ #endif ++ #ifdef X509V3_R_NEED_ORGANIZATION_AND_NUMBERS ++ {"NEED_ORGANIZATION_AND_NUMBERS", ERR_LIB_X509V3, X509V3_R_NEED_ORGANIZATION_AND_NUMBERS}, ++ #else ++ {"NEED_ORGANIZATION_AND_NUMBERS", 34, 142}, ++ #endif ++ #ifdef X509V3_R_NEGATIVE_PATHLEN ++ {"NEGATIVE_PATHLEN", ERR_LIB_X509V3, X509V3_R_NEGATIVE_PATHLEN}, ++ #else ++ {"NEGATIVE_PATHLEN", 34, 168}, ++ #endif ++ #ifdef X509V3_R_NO_CONFIG_DATABASE ++ {"NO_CONFIG_DATABASE", ERR_LIB_X509V3, X509V3_R_NO_CONFIG_DATABASE}, ++ #else ++ {"NO_CONFIG_DATABASE", 34, 136}, ++ #endif ++ #ifdef X509V3_R_NO_ISSUER_CERTIFICATE ++ {"NO_ISSUER_CERTIFICATE", ERR_LIB_X509V3, X509V3_R_NO_ISSUER_CERTIFICATE}, ++ #else ++ {"NO_ISSUER_CERTIFICATE", 34, 121}, ++ #endif ++ #ifdef X509V3_R_NO_ISSUER_DETAILS ++ {"NO_ISSUER_DETAILS", ERR_LIB_X509V3, X509V3_R_NO_ISSUER_DETAILS}, ++ #else ++ {"NO_ISSUER_DETAILS", 34, 127}, ++ #endif ++ #ifdef X509V3_R_NO_POLICY_IDENTIFIER ++ {"NO_POLICY_IDENTIFIER", ERR_LIB_X509V3, X509V3_R_NO_POLICY_IDENTIFIER}, ++ #else ++ {"NO_POLICY_IDENTIFIER", 34, 139}, ++ #endif ++ #ifdef X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED ++ {"NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED", ERR_LIB_X509V3, X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED}, ++ #else ++ {"NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED", 34, 154}, ++ #endif ++ #ifdef X509V3_R_NO_PUBLIC_KEY ++ {"NO_PUBLIC_KEY", ERR_LIB_X509V3, X509V3_R_NO_PUBLIC_KEY}, ++ #else ++ {"NO_PUBLIC_KEY", 34, 114}, ++ #endif ++ #ifdef X509V3_R_NO_SUBJECT_DETAILS ++ {"NO_SUBJECT_DETAILS", ERR_LIB_X509V3, X509V3_R_NO_SUBJECT_DETAILS}, ++ #else ++ {"NO_SUBJECT_DETAILS", 34, 125}, ++ #endif ++ #ifdef X509V3_R_OPERATION_NOT_DEFINED ++ {"OPERATION_NOT_DEFINED", ERR_LIB_X509V3, X509V3_R_OPERATION_NOT_DEFINED}, ++ #else ++ {"OPERATION_NOT_DEFINED", 34, 148}, ++ #endif ++ #ifdef X509V3_R_OTHERNAME_ERROR ++ {"OTHERNAME_ERROR", ERR_LIB_X509V3, X509V3_R_OTHERNAME_ERROR}, ++ #else ++ {"OTHERNAME_ERROR", 34, 147}, ++ #endif ++ #ifdef X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED ++ {"POLICY_LANGUAGE_ALREADY_DEFINED", ERR_LIB_X509V3, X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED}, ++ #else ++ {"POLICY_LANGUAGE_ALREADY_DEFINED", 34, 155}, ++ #endif ++ #ifdef X509V3_R_POLICY_PATH_LENGTH ++ {"POLICY_PATH_LENGTH", ERR_LIB_X509V3, X509V3_R_POLICY_PATH_LENGTH}, ++ #else ++ {"POLICY_PATH_LENGTH", 34, 156}, ++ #endif ++ #ifdef X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED ++ {"POLICY_PATH_LENGTH_ALREADY_DEFINED", ERR_LIB_X509V3, X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED}, ++ #else ++ {"POLICY_PATH_LENGTH_ALREADY_DEFINED", 34, 157}, ++ #endif ++ #ifdef X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY ++ {"POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY", ERR_LIB_X509V3, X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY}, ++ #else ++ {"POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY", 34, 159}, ++ #endif ++ #ifdef X509V3_R_SECTION_NOT_FOUND ++ {"SECTION_NOT_FOUND", ERR_LIB_X509V3, X509V3_R_SECTION_NOT_FOUND}, ++ #else ++ {"SECTION_NOT_FOUND", 34, 150}, ++ #endif ++ #ifdef X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS ++ {"UNABLE_TO_GET_ISSUER_DETAILS", ERR_LIB_X509V3, X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS}, ++ #else ++ {"UNABLE_TO_GET_ISSUER_DETAILS", 34, 122}, ++ #endif ++ #ifdef X509V3_R_UNABLE_TO_GET_ISSUER_KEYID ++ {"UNABLE_TO_GET_ISSUER_KEYID", ERR_LIB_X509V3, X509V3_R_UNABLE_TO_GET_ISSUER_KEYID}, ++ #else ++ {"UNABLE_TO_GET_ISSUER_KEYID", 34, 123}, ++ #endif ++ #ifdef X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT ++ {"UNKNOWN_BIT_STRING_ARGUMENT", ERR_LIB_X509V3, X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT}, ++ #else ++ {"UNKNOWN_BIT_STRING_ARGUMENT", 34, 111}, ++ #endif ++ #ifdef X509V3_R_UNKNOWN_EXTENSION ++ {"UNKNOWN_EXTENSION", ERR_LIB_X509V3, X509V3_R_UNKNOWN_EXTENSION}, ++ #else ++ {"UNKNOWN_EXTENSION", 34, 129}, ++ #endif ++ #ifdef X509V3_R_UNKNOWN_EXTENSION_NAME ++ {"UNKNOWN_EXTENSION_NAME", ERR_LIB_X509V3, X509V3_R_UNKNOWN_EXTENSION_NAME}, ++ #else ++ {"UNKNOWN_EXTENSION_NAME", 34, 130}, ++ #endif ++ #ifdef X509V3_R_UNKNOWN_OPTION ++ {"UNKNOWN_OPTION", ERR_LIB_X509V3, X509V3_R_UNKNOWN_OPTION}, ++ #else ++ {"UNKNOWN_OPTION", 34, 120}, ++ #endif ++ #ifdef X509V3_R_UNKNOWN_VALUE ++ {"UNKNOWN_VALUE", ERR_LIB_X509V3, X509V3_R_UNKNOWN_VALUE}, ++ #else ++ {"UNKNOWN_VALUE", 34, 172}, ++ #endif ++ #ifdef X509V3_R_UNSUPPORTED_OPTION ++ {"UNSUPPORTED_OPTION", ERR_LIB_X509V3, X509V3_R_UNSUPPORTED_OPTION}, ++ #else ++ {"UNSUPPORTED_OPTION", 34, 117}, ++ #endif ++ #ifdef X509V3_R_UNSUPPORTED_TYPE ++ {"UNSUPPORTED_TYPE", ERR_LIB_X509V3, X509V3_R_UNSUPPORTED_TYPE}, ++ #else ++ {"UNSUPPORTED_TYPE", 34, 167}, ++ #endif ++ #ifdef X509V3_R_USER_TOO_LONG ++ {"USER_TOO_LONG", ERR_LIB_X509V3, X509V3_R_USER_TOO_LONG}, ++ #else ++ {"USER_TOO_LONG", 34, 132}, ++ #endif ++ #ifdef X509_R_AKID_MISMATCH ++ {"AKID_MISMATCH", ERR_LIB_X509, X509_R_AKID_MISMATCH}, ++ #else ++ {"AKID_MISMATCH", 11, 110}, ++ #endif ++ #ifdef X509_R_BAD_SELECTOR ++ {"BAD_SELECTOR", ERR_LIB_X509, X509_R_BAD_SELECTOR}, ++ #else ++ {"BAD_SELECTOR", 11, 133}, ++ #endif ++ #ifdef X509_R_BAD_X509_FILETYPE ++ {"BAD_X509_FILETYPE", ERR_LIB_X509, X509_R_BAD_X509_FILETYPE}, ++ #else ++ {"BAD_X509_FILETYPE", 11, 100}, ++ #endif ++ #ifdef X509_R_BASE64_DECODE_ERROR ++ {"BASE64_DECODE_ERROR", ERR_LIB_X509, X509_R_BASE64_DECODE_ERROR}, ++ #else ++ {"BASE64_DECODE_ERROR", 11, 118}, ++ #endif ++ #ifdef X509_R_CANT_CHECK_DH_KEY ++ {"CANT_CHECK_DH_KEY", ERR_LIB_X509, X509_R_CANT_CHECK_DH_KEY}, ++ #else ++ {"CANT_CHECK_DH_KEY", 11, 114}, ++ #endif ++ #ifdef X509_R_CERTIFICATE_VERIFICATION_FAILED ++ {"CERTIFICATE_VERIFICATION_FAILED", ERR_LIB_X509, X509_R_CERTIFICATE_VERIFICATION_FAILED}, ++ #else ++ {"CERTIFICATE_VERIFICATION_FAILED", 11, 139}, ++ #endif ++ #ifdef X509_R_CERT_ALREADY_IN_HASH_TABLE ++ {"CERT_ALREADY_IN_HASH_TABLE", ERR_LIB_X509, X509_R_CERT_ALREADY_IN_HASH_TABLE}, ++ #else ++ {"CERT_ALREADY_IN_HASH_TABLE", 11, 101}, ++ #endif ++ #ifdef X509_R_CRL_ALREADY_DELTA ++ {"CRL_ALREADY_DELTA", ERR_LIB_X509, X509_R_CRL_ALREADY_DELTA}, ++ #else ++ {"CRL_ALREADY_DELTA", 11, 127}, ++ #endif ++ #ifdef X509_R_CRL_VERIFY_FAILURE ++ {"CRL_VERIFY_FAILURE", ERR_LIB_X509, X509_R_CRL_VERIFY_FAILURE}, ++ #else ++ {"CRL_VERIFY_FAILURE", 11, 131}, ++ #endif ++ #ifdef X509_R_DUPLICATE_ATTRIBUTE ++ {"DUPLICATE_ATTRIBUTE", ERR_LIB_X509, X509_R_DUPLICATE_ATTRIBUTE}, ++ #else ++ {"DUPLICATE_ATTRIBUTE", 11, 140}, ++ #endif ++ #ifdef X509_R_ERROR_GETTING_MD_BY_NID ++ {"ERROR_GETTING_MD_BY_NID", ERR_LIB_X509, X509_R_ERROR_GETTING_MD_BY_NID}, ++ #else ++ {"ERROR_GETTING_MD_BY_NID", 11, 141}, ++ #endif ++ #ifdef X509_R_ERROR_USING_SIGINF_SET ++ {"ERROR_USING_SIGINF_SET", ERR_LIB_X509, X509_R_ERROR_USING_SIGINF_SET}, ++ #else ++ {"ERROR_USING_SIGINF_SET", 11, 142}, ++ #endif ++ #ifdef X509_R_IDP_MISMATCH ++ {"IDP_MISMATCH", ERR_LIB_X509, X509_R_IDP_MISMATCH}, ++ #else ++ {"IDP_MISMATCH", 11, 128}, ++ #endif ++ #ifdef X509_R_INVALID_ATTRIBUTES ++ {"INVALID_ATTRIBUTES", ERR_LIB_X509, X509_R_INVALID_ATTRIBUTES}, ++ #else ++ {"INVALID_ATTRIBUTES", 11, 138}, ++ #endif ++ #ifdef X509_R_INVALID_DIRECTORY ++ {"INVALID_DIRECTORY", ERR_LIB_X509, X509_R_INVALID_DIRECTORY}, ++ #else ++ {"INVALID_DIRECTORY", 11, 113}, ++ #endif ++ #ifdef X509_R_INVALID_DISTPOINT ++ {"INVALID_DISTPOINT", ERR_LIB_X509, X509_R_INVALID_DISTPOINT}, ++ #else ++ {"INVALID_DISTPOINT", 11, 143}, ++ #endif ++ #ifdef X509_R_INVALID_FIELD_NAME ++ {"INVALID_FIELD_NAME", ERR_LIB_X509, X509_R_INVALID_FIELD_NAME}, ++ #else ++ {"INVALID_FIELD_NAME", 11, 119}, ++ #endif ++ #ifdef X509_R_INVALID_TRUST ++ {"INVALID_TRUST", ERR_LIB_X509, X509_R_INVALID_TRUST}, ++ #else ++ {"INVALID_TRUST", 11, 123}, ++ #endif ++ #ifdef X509_R_ISSUER_MISMATCH ++ {"ISSUER_MISMATCH", ERR_LIB_X509, X509_R_ISSUER_MISMATCH}, ++ #else ++ {"ISSUER_MISMATCH", 11, 129}, ++ #endif ++ #ifdef X509_R_KEY_TYPE_MISMATCH ++ {"KEY_TYPE_MISMATCH", ERR_LIB_X509, X509_R_KEY_TYPE_MISMATCH}, ++ #else ++ {"KEY_TYPE_MISMATCH", 11, 115}, ++ #endif ++ #ifdef X509_R_KEY_VALUES_MISMATCH ++ {"KEY_VALUES_MISMATCH", ERR_LIB_X509, X509_R_KEY_VALUES_MISMATCH}, ++ #else ++ {"KEY_VALUES_MISMATCH", 11, 116}, ++ #endif ++ #ifdef X509_R_LOADING_CERT_DIR ++ {"LOADING_CERT_DIR", ERR_LIB_X509, X509_R_LOADING_CERT_DIR}, ++ #else ++ {"LOADING_CERT_DIR", 11, 103}, ++ #endif ++ #ifdef X509_R_LOADING_DEFAULTS ++ {"LOADING_DEFAULTS", ERR_LIB_X509, X509_R_LOADING_DEFAULTS}, ++ #else ++ {"LOADING_DEFAULTS", 11, 104}, ++ #endif ++ #ifdef X509_R_METHOD_NOT_SUPPORTED ++ {"METHOD_NOT_SUPPORTED", ERR_LIB_X509, X509_R_METHOD_NOT_SUPPORTED}, ++ #else ++ {"METHOD_NOT_SUPPORTED", 11, 124}, ++ #endif ++ #ifdef X509_R_NAME_TOO_LONG ++ {"NAME_TOO_LONG", ERR_LIB_X509, X509_R_NAME_TOO_LONG}, ++ #else ++ {"NAME_TOO_LONG", 11, 134}, ++ #endif ++ #ifdef X509_R_NEWER_CRL_NOT_NEWER ++ {"NEWER_CRL_NOT_NEWER", ERR_LIB_X509, X509_R_NEWER_CRL_NOT_NEWER}, ++ #else ++ {"NEWER_CRL_NOT_NEWER", 11, 132}, ++ #endif ++ #ifdef X509_R_NO_CERTIFICATE_FOUND ++ {"NO_CERTIFICATE_FOUND", ERR_LIB_X509, X509_R_NO_CERTIFICATE_FOUND}, ++ #else ++ {"NO_CERTIFICATE_FOUND", 11, 135}, ++ #endif ++ #ifdef X509_R_NO_CERTIFICATE_OR_CRL_FOUND ++ {"NO_CERTIFICATE_OR_CRL_FOUND", ERR_LIB_X509, X509_R_NO_CERTIFICATE_OR_CRL_FOUND}, ++ #else ++ {"NO_CERTIFICATE_OR_CRL_FOUND", 11, 136}, ++ #endif ++ #ifdef X509_R_NO_CERT_SET_FOR_US_TO_VERIFY ++ {"NO_CERT_SET_FOR_US_TO_VERIFY", ERR_LIB_X509, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY}, ++ #else ++ {"NO_CERT_SET_FOR_US_TO_VERIFY", 11, 105}, ++ #endif ++ #ifdef X509_R_NO_CRL_FOUND ++ {"NO_CRL_FOUND", ERR_LIB_X509, X509_R_NO_CRL_FOUND}, ++ #else ++ {"NO_CRL_FOUND", 11, 137}, ++ #endif ++ #ifdef X509_R_NO_CRL_NUMBER ++ {"NO_CRL_NUMBER", ERR_LIB_X509, X509_R_NO_CRL_NUMBER}, ++ #else ++ {"NO_CRL_NUMBER", 11, 130}, ++ #endif ++ #ifdef X509_R_PUBLIC_KEY_DECODE_ERROR ++ {"PUBLIC_KEY_DECODE_ERROR", ERR_LIB_X509, X509_R_PUBLIC_KEY_DECODE_ERROR}, ++ #else ++ {"PUBLIC_KEY_DECODE_ERROR", 11, 125}, ++ #endif ++ #ifdef X509_R_PUBLIC_KEY_ENCODE_ERROR ++ {"PUBLIC_KEY_ENCODE_ERROR", ERR_LIB_X509, X509_R_PUBLIC_KEY_ENCODE_ERROR}, ++ #else ++ {"PUBLIC_KEY_ENCODE_ERROR", 11, 126}, ++ #endif ++ #ifdef X509_R_SHOULD_RETRY ++ {"SHOULD_RETRY", ERR_LIB_X509, X509_R_SHOULD_RETRY}, ++ #else ++ {"SHOULD_RETRY", 11, 106}, ++ #endif ++ #ifdef X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN ++ {"UNABLE_TO_FIND_PARAMETERS_IN_CHAIN", ERR_LIB_X509, X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN}, ++ #else ++ {"UNABLE_TO_FIND_PARAMETERS_IN_CHAIN", 11, 107}, ++ #endif ++ #ifdef X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY ++ {"UNABLE_TO_GET_CERTS_PUBLIC_KEY", ERR_LIB_X509, X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY}, ++ #else ++ {"UNABLE_TO_GET_CERTS_PUBLIC_KEY", 11, 108}, ++ #endif ++ #ifdef X509_R_UNKNOWN_KEY_TYPE ++ {"UNKNOWN_KEY_TYPE", ERR_LIB_X509, X509_R_UNKNOWN_KEY_TYPE}, ++ #else ++ {"UNKNOWN_KEY_TYPE", 11, 117}, ++ #endif ++ #ifdef X509_R_UNKNOWN_NID ++ {"UNKNOWN_NID", ERR_LIB_X509, X509_R_UNKNOWN_NID}, ++ #else ++ {"UNKNOWN_NID", 11, 109}, ++ #endif ++ #ifdef X509_R_UNKNOWN_PURPOSE_ID ++ {"UNKNOWN_PURPOSE_ID", ERR_LIB_X509, X509_R_UNKNOWN_PURPOSE_ID}, ++ #else ++ {"UNKNOWN_PURPOSE_ID", 11, 121}, ++ #endif ++ #ifdef X509_R_UNKNOWN_SIGID_ALGS ++ {"UNKNOWN_SIGID_ALGS", ERR_LIB_X509, X509_R_UNKNOWN_SIGID_ALGS}, ++ #else ++ {"UNKNOWN_SIGID_ALGS", 11, 144}, ++ #endif ++ #ifdef X509_R_UNKNOWN_TRUST_ID ++ {"UNKNOWN_TRUST_ID", ERR_LIB_X509, X509_R_UNKNOWN_TRUST_ID}, ++ #else ++ {"UNKNOWN_TRUST_ID", 11, 120}, ++ #endif ++ #ifdef X509_R_UNSUPPORTED_ALGORITHM ++ {"UNSUPPORTED_ALGORITHM", ERR_LIB_X509, X509_R_UNSUPPORTED_ALGORITHM}, ++ #else ++ {"UNSUPPORTED_ALGORITHM", 11, 111}, ++ #endif ++ #ifdef X509_R_UNSUPPORTED_VERSION ++ {"UNSUPPORTED_VERSION", ERR_LIB_X509, X509_R_UNSUPPORTED_VERSION}, ++ #else ++ {"UNSUPPORTED_VERSION", 11, 145}, ++ #endif ++ #ifdef X509_R_WRONG_LOOKUP_TYPE ++ {"WRONG_LOOKUP_TYPE", ERR_LIB_X509, X509_R_WRONG_LOOKUP_TYPE}, ++ #else ++ {"WRONG_LOOKUP_TYPE", 11, 112}, ++ #endif ++ #ifdef X509_R_WRONG_TYPE ++ {"WRONG_TYPE", ERR_LIB_X509, X509_R_WRONG_TYPE}, ++ #else ++ {"WRONG_TYPE", 11, 122}, ++ #endif ++ { NULL } ++}; ++ +--- a/Tools/c-analyzer/cpython/_parser.py ++++ b/Tools/c-analyzer/cpython/_parser.py +@@ -71,9 +71,7 @@ Python/thread_pthread_stubs.h + + # only huge constants (safe but parsing is slow) + Modules/_ssl_data.h +-Modules/_ssl_data_31.h +-Modules/_ssl_data_300.h +-Modules/_ssl_data_111.h ++Modules/_ssl_data_*.h + Modules/cjkcodecs/mappings_*.h + Modules/unicodedata_db.h + Modules/unicodename_db.h +--- a/Tools/ssl/make_ssl_data.py ++++ b/Tools/ssl/make_ssl_data.py +@@ -5,9 +5,28 @@ This script should be called *manually* + `library` and `reason` mnemonics to a more recent OpenSSL version. + + It takes two arguments: +-- the path to the OpenSSL source tree (e.g. git checkout) ++- the path to the OpenSSL git checkout + - the path to the header file to be generated Modules/_ssl_data_{version}.h + - error codes are version specific ++ ++The OpenSSL git checkout should be at a specific tag, using commands like: ++ git tag --list 'openssl-*' ++ git switch --detach openssl-3.4.0 ++ ++ ++After generating the definitions, compare the result with newest pre-existing file. ++You can use a command like: ++ ++ git diff --no-index Modules/_ssl_data_31.h Modules/_ssl_data_34.h ++ ++- If the new version *only* adds new definitions, remove the pre-existing file ++ and adjust the #include in _ssl.c to point to the new version. ++- If the new version removes or renumbers some definitions, keep both files and ++ add a new #include in _ssl.c. ++ ++A newly supported OpenSSL version should also be added to: ++- Tools/ssl/multissltests.py ++- .github/workflows/build.yml + """ + + import argparse +@@ -16,6 +35,7 @@ import operator + import os + import re + import sys ++import subprocess + + + parser = argparse.ArgumentParser( +@@ -118,9 +138,17 @@ def main(): + # sort by libname, numeric error code + args.reasons = sorted(reasons, key=operator.itemgetter(0, 3)) + ++ git_describe = subprocess.run( ++ ['git', 'describe', '--long', '--dirty'], ++ cwd=args.srcdir, ++ capture_output=True, ++ encoding='utf-8', ++ check=True, ++ ) + lines = [ +- "/* File generated by Tools/ssl/make_ssl_data.py */" +- f"/* Generated on {datetime.datetime.utcnow().isoformat()} */" ++ "/* File generated by Tools/ssl/make_ssl_data.py */", ++ f"/* Generated on {datetime.datetime.now(datetime.UTC).isoformat()} */", ++ f"/* Generated from Git commit {git_describe.stdout.strip()} */", + ] + lines.extend(gen_library_codes(args)) + lines.append("") +--- a/Tools/ssl/multissltests.py ++++ b/Tools/ssl/multissltests.py +@@ -51,6 +51,8 @@ OPENSSL_RECENT_VERSIONS = [ + "3.1.7", + "3.2.3", + "3.3.2", ++ "3.4.0", ++ # See make_ssl_data.py for notes on adding a new version. + ] + + LIBRESSL_OLD_VERSIONS = [ diff --git a/debian/patches/lib-argparse.diff b/debian/patches/lib-argparse.diff index fd05b667..0999084c 100644 --- a/debian/patches/lib-argparse.diff +++ b/debian/patches/lib-argparse.diff @@ -6,7 +6,7 @@ Forwarded: not-needed --- a/Lib/argparse.py +++ b/Lib/argparse.py -@@ -91,7 +91,16 @@ +@@ -91,7 +91,18 @@ import warnings @@ -14,8 +14,10 @@ Forwarded: not-needed +try: + from gettext import gettext as _, ngettext +except ImportError: -+ def _(message): ++ def gettext(message): + return message ++ _ = gettext # avoid the definition above looking like a translated string ++ del gettext + def ngettext(singular,plural,n): + if n == 1: + return singular diff --git a/debian/patches/link-opt.diff b/debian/patches/link-opt.diff index 798e795d..315e9271 100644 --- a/debian/patches/link-opt.diff +++ b/debian/patches/link-opt.diff @@ -5,7 +5,7 @@ Forwarded: no --- a/configure.ac +++ b/configure.ac -@@ -3334,8 +3334,8 @@ then +@@ -3363,8 +3363,8 @@ LDSHARED='$(CC) -shared' LDCXXSHARED='$(CXX) -shared';; Linux*|GNU*|QNX*|VxWorks*|Haiku*) @@ -16,7 +16,7 @@ Forwarded: no FreeBSD*) if [[ "`$CC -dM -E - + {% endif %} - + {% if builder != "htmlhelp" %} @@ -15,10 +15,10 @@ Forwarded: not-needed {% endif %} --- a/Lib/idlelib/help.html +++ b/Lib/idlelib/help.html -@@ -26,7 +26,7 @@ - +@@ -27,7 +27,7 @@ + - + diff --git a/debian/patches/makefile-bootstrap.diff b/debian/patches/makefile-bootstrap.diff new file mode 100644 index 00000000..62bdd58f --- /dev/null +++ b/debian/patches/makefile-bootstrap.diff @@ -0,0 +1,14 @@ +# DP: needs forwarding. bootstrap python fails with a compiler defaulting to -fPIE, +# DP: then setting CFLAGS_NODIST and LDFLAGS_NODIST to -fno-PIE. + +--- a/Makefile.pre.in ++++ b/Makefile.pre.in +@@ -95,7 +95,7 @@ CONFIGURE_LDFLAGS_NODIST=@LDFLAGS_NODIST + # of _bootstrap_python and _freeze_module tools, which don't need LTO. + CONFIGURE_LDFLAGS_NOLTO=@LDFLAGS_NOLTO@ + CONFIGURE_CPPFLAGS= @CPPFLAGS@ +-CONFIGURE_LDFLAGS= @LDFLAGS@ ++CONFIGURE_LDFLAGS= @LDFLAGS_NODIST@ + # Avoid assigning CFLAGS, LDFLAGS, etc. so users can use them on the + # command line to append to these values without stomping the pre-set + # values. diff --git a/debian/patches/multiarch.diff b/debian/patches/multiarch.diff index 2bfc68c1..405d417e 100644 --- a/debian/patches/multiarch.diff +++ b/debian/patches/multiarch.diff @@ -7,7 +7,7 @@ Forwarded: no --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py -@@ -710,6 +710,12 @@ def _init_config_vars(): +@@ -710,6 +710,12 @@ # the init-function. _CONFIG_VARS['userbase'] = _getuserbase() @@ -22,7 +22,7 @@ Forwarded: no if os.name == 'posix': --- a/Makefile.pre.in +++ b/Makefile.pre.in -@@ -1377,6 +1377,7 @@ Modules/signalmodule.o: $(srcdir)/Module +@@ -1379,6 +1379,7 @@ Python/dynload_shlib.o: $(srcdir)/Python/dynload_shlib.c Makefile $(CC) -c $(PY_CORE_CFLAGS) \ diff --git a/debian/patches/patchlevel-noplus.diff b/debian/patches/patchlevel-noplus.diff new file mode 100644 index 00000000..cd3f75e1 --- /dev/null +++ b/debian/patches/patchlevel-noplus.diff @@ -0,0 +1,11 @@ +--- a/Include/patchlevel.h ++++ b/Include/patchlevel.h +@@ -23,7 +23,7 @@ + #define PY_RELEASE_SERIAL 0 + + /* Version as a string */ +-#define PY_VERSION "3.12.8+" ++#define PY_VERSION "3.12.8" + /*--end constants--*/ + + /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/debian/patches/profiled-build.diff b/debian/patches/profiled-build.diff index 3e35a220..d0249d6f 100644 --- a/debian/patches/profiled-build.diff +++ b/debian/patches/profiled-build.diff @@ -5,7 +5,7 @@ Forwarded: no --- a/Makefile.pre.in +++ b/Makefile.pre.in -@@ -659,7 +659,16 @@ profile-run-stamp: +@@ -661,7 +661,16 @@ $(MAKE) profile-gen-stamp # Next, run the profile task to generate the profile information. @ # FIXME: can't run for a cross build diff --git a/debian/patches/pydoc-use-pager.diff b/debian/patches/pydoc-use-pager.diff index 6d204568..9fedc296 100644 --- a/debian/patches/pydoc-use-pager.diff +++ b/debian/patches/pydoc-use-pager.diff @@ -6,7 +6,7 @@ Forwarded: no --- a/Lib/pydoc.py +++ b/Lib/pydoc.py -@@ -1584,6 +1584,8 @@ def getpager(): +@@ -1667,6 +1667,8 @@ return plainpager if sys.platform == 'win32': return lambda text: tempfilepager(plain(text), 'more <') diff --git a/debian/patches/reproducible-buildinfo.diff b/debian/patches/reproducible-buildinfo.diff deleted file mode 100644 index d48edd20..00000000 --- a/debian/patches/reproducible-buildinfo.diff +++ /dev/null @@ -1,17 +0,0 @@ -Description: Build reproduceable date and time into build info - Build information is encoded into getbuildinfo.o at build time. - Use the date and time from the debian changelog, to make this reproduceable. - -Forwarded: no - ---- a/Makefile.pre.in -+++ b/Makefile.pre.in -@@ -1347,6 +1347,8 @@ Modules/getbuildinfo.o: $(PARSER_OBJS) \ - -DGITVERSION="\"`LC_ALL=C $(GITVERSION)`\"" \ - -DGITTAG="\"`LC_ALL=C $(GITTAG)`\"" \ - -DGITBRANCH="\"`LC_ALL=C $(GITBRANCH)`\"" \ -+ $(if $(BUILD_DATE),-DDATE='"$(BUILD_DATE)"') \ -+ $(if $(BUILD_TIME),-DTIME='"$(BUILD_TIME)"') \ - -o $@ $(srcdir)/Modules/getbuildinfo.c - - Modules/getpath.o: $(srcdir)/Modules/getpath.c Python/frozen_modules/getpath.h Makefile $(PYTHON_HEADERS) diff --git a/debian/patches/series b/debian/patches/series index 63c72c27..834ffca8 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,4 +1,5 @@ -#git-updates.diff +git-updates.diff +patchlevel-noplus.diff #FIXME deb-setup.diff deb-locations.diff distutils-install-layout.diff @@ -19,7 +20,6 @@ multiarch.diff test-no-random-order.diff tempfile-minimal.diff ensurepip-disabled.diff -reproducible-buildinfo.diff pydoc-use-pager.diff local-doc-references.diff #build-math-object.diff @@ -31,3 +31,7 @@ fix-py_compile.diff ntpath-import.diff python3.12-updates.diff issue108447.diff +makefile-bootstrap.diff +ignore-wheeldata.diff +test-freeze-strip-libdir.diff +issue127330.diff diff --git a/debian/patches/sphinx3.diff b/debian/patches/sphinx3.diff index 13287bf5..caed72e1 100644 --- a/debian/patches/sphinx3.diff +++ b/debian/patches/sphinx3.diff @@ -6,8 +6,8 @@ Origin: upstream, https://github.com/python/cpython/commit/423e77d6de497931585d1 --- a/Doc/conf.py +++ b/Doc/conf.py -@@ -280,6 +280,10 @@ gettext_additional_targets = [ - 'index', +@@ -309,6 +309,10 @@ + 'literal-block', ] +# Allow to build with Sphinx >= 3.2 @@ -19,7 +19,7 @@ Origin: upstream, https://github.com/python/cpython/commit/423e77d6de497931585d1 --- a/Doc/Makefile +++ b/Doc/Makefile -@@ -13,7 +13,7 @@ PAPER = +@@ -14,7 +14,7 @@ SOURCES = DISTVERSION = $(shell $(PYTHON) tools/extensions/patchlevel.py) REQUIREMENTS = requirements.txt diff --git a/debian/patches/sysconfig-debian-schemes.diff b/debian/patches/sysconfig-debian-schemes.diff index a9ce5565..d42228c3 100644 --- a/debian/patches/sysconfig-debian-schemes.diff +++ b/debian/patches/sysconfig-debian-schemes.diff @@ -1,8 +1,6 @@ -Index: b/Lib/sysconfig.py -=================================================================== --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py -@@ -37,6 +37,30 @@ _INSTALL_SCHEMES = { +@@ -37,6 +37,30 @@ 'scripts': '{base}/bin', 'data': '{base}', }, @@ -33,7 +31,7 @@ Index: b/Lib/sysconfig.py 'posix_home': { 'stdlib': '{installed_base}/lib/python', 'platstdlib': '{base}/lib/python', -@@ -234,7 +258,7 @@ def is_python_build(check_home=None): +@@ -232,7 +256,7 @@ _PYTHON_BUILD = is_python_build() if _PYTHON_BUILD: @@ -42,7 +40,7 @@ Index: b/Lib/sysconfig.py # On POSIX-y platforms, Python will: # - Build from .h files in 'headers' (which is only added to the # scheme when building CPython) -@@ -294,8 +318,20 @@ def _get_preferred_schemes(): +@@ -292,8 +316,20 @@ 'home': 'posix_home', 'user': 'osx_framework_user', } @@ -64,7 +62,7 @@ Index: b/Lib/sysconfig.py 'home': 'posix_home', 'user': 'posix_user', } -@@ -602,7 +638,7 @@ def get_config_h_filename(): +@@ -600,7 +636,7 @@ else: inc_dir = _PROJECT_BASE else: @@ -73,11 +71,9 @@ Index: b/Lib/sysconfig.py return os.path.join(inc_dir, 'pyconfig.h') -Index: b/Lib/test/test_sysconfig.py -=================================================================== --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py -@@ -335,7 +335,7 @@ class TestSysConfig(unittest.TestCase): +@@ -353,7 +353,7 @@ self.assertTrue(os.path.isfile(config_h), config_h) def test_get_scheme_names(self): diff --git a/debian/patches/sysconfigdata-name.diff b/debian/patches/sysconfigdata-name.diff index c64e3e9f..61a796ae 100644 --- a/debian/patches/sysconfigdata-name.diff +++ b/debian/patches/sysconfigdata-name.diff @@ -7,7 +7,7 @@ Forwarded: no --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py -@@ -498,7 +498,7 @@ def _get_sysconfigdata_name(): +@@ -496,7 +496,7 @@ multiarch = getattr(sys.implementation, '_multiarch', '') return os.environ.get( '_PYTHON_SYSCONFIGDATA_NAME', @@ -18,7 +18,7 @@ Forwarded: no --- a/Makefile.pre.in +++ b/Makefile.pre.in -@@ -2328,8 +2328,10 @@ libinstall: all $(srcdir)/Modules/xxmodu +@@ -2341,8 +2341,10 @@ esac; \ done; \ done @@ -33,7 +33,7 @@ Forwarded: no -PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \ --- a/configure.ac +++ b/configure.ac -@@ -164,7 +164,7 @@ AC_ARG_WITH([build-python], +@@ -164,7 +164,7 @@ dnl Build Python interpreter is used for regeneration and freezing. ac_cv_prog_PYTHON_FOR_REGEN=$with_build_python PYTHON_FOR_FREEZE="$with_build_python" diff --git a/debian/patches/test-freeze-strip-libdir.diff b/debian/patches/test-freeze-strip-libdir.diff new file mode 100644 index 00000000..1ffc6ca2 --- /dev/null +++ b/debian/patches/test-freeze-strip-libdir.diff @@ -0,0 +1,25 @@ +From f6966024e86e2530fb6c7fe26b69e5054fc8e310 Mon Sep 17 00:00:00 2001 +From: Stefano Rivera +Date: Wed, 2 Oct 2024 18:24:57 +0200 +Subject: [PATCH] Strip absolute --libdir paths from configure args in + test_freeze + +We are trying to install into a prefix, any absolute path would not +necessarily be writeable. e.g. if Python is configured with +--libdir=/usr/lib/$(MULTIARCH)/ during a Debian build. + +Forwarded: https://github.com/python/cpython/pull/124916 +--- + Tools/freeze/test/freeze.py | 1 + + 1 file changed, 1 insertion(+) + +--- a/Tools/freeze/test/freeze.py ++++ b/Tools/freeze/test/freeze.py +@@ -128,6 +128,7 @@ + # Run configure. + print(f'configuring python in {builddir}...') + config_args = shlex.split(sysconfig.get_config_var('CONFIG_ARGS') or '') ++ config_args = [arg for arg in config_args if not arg.startswith("--libdir=/")] + cmd = [os.path.join(srcdir, 'configure'), *config_args] + ensure_opt(cmd, 'cache-file', os.path.join(outdir, 'python-config.cache')) + prefix = os.path.join(outdir, 'python-installation') diff --git a/debian/rules b/debian/rules index a4e46036..00ae1d1d 100755 --- a/debian/rules +++ b/debian/rules @@ -1,5 +1,8 @@ #!/usr/bin/make -f +include /usr/share/dpkg/architecture.mk +include /usr/share/dpkg/pkg-info.mk + unexport LANG LC_ALL LC_CTYPE LC_COLLATE LC_TIME LC_NUMERIC LC_MESSAGES unexport CFLAGS CXXFLAGS LDFLAGS CPPFLAGS @@ -8,16 +11,6 @@ export SHELL = /bin/bash # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 -vafilt = $(subst $(2)=,,$(filter $(2)=%,$(1))) -DPKG_VARS := $(shell dpkg-architecture) -DEB_BUILD_ARCH ?= $(call vafilt,$(DPKG_VARS),DEB_BUILD_ARCH) -DEB_BUILD_GNU_TYPE ?= $(call vafilt,$(DPKG_VARS),DEB_BUILD_GNU_TYPE) -DEB_HOST_ARCH ?= $(call vafilt,$(DPKG_VARS),DEB_HOST_ARCH) -DEB_HOST_ARCH_ENDIAN ?= $(call vafilt,$(DPKG_VARS),DEB_HOST_ARCH_ENDIAN) -DEB_HOST_ARCH_OS ?= $(call vafilt,$(DPKG_VARS),DEB_HOST_ARCH_OS) -DEB_HOST_GNU_TYPE ?= $(call vafilt,$(DPKG_VARS),DEB_HOST_GNU_TYPE) -DEB_HOST_MULTIARCH ?= $(call vafilt,$(DPKG_VARS),DEB_HOST_MULTIARCH) - ifeq ($(DEB_HOST_ARCH_OS),linux) PLAT = linux else ifeq ($(DEB_HOST_ARCH_OS),kfreebsd) @@ -29,17 +22,8 @@ else PLAT = unknown endif -CHANGELOG_VARS := $(shell dpkg-parsechangelog | \ - sed -n 's/ /_/g;/^[^_]/s/^\([^:]*\):_\(.*\)/\1=\2/p') -PKGSOURCE := $(call vafilt,$(CHANGELOG_VARS),Source) -PKGVERSION := $(call vafilt,$(CHANGELOG_VARS),Version) - -LAST_CHANGE := $(shell dpkg-parsechangelog -S Date) -export BUILD_DATE := $(shell LC_ALL=C date -u +'%b %e %Y' -d '$(LAST_CHANGE)') -export BUILD_TIME := $(shell LC_ALL=C date -u +'%H:%M:%S' -d '$(LAST_CHANGE)') - -SPHINXOPTS := -D today='$(shell LC_ALL=C date -u +'%B %d, %Y' -d '$(LAST_CHANGE)')' -SPHINXOPTS += -D html_last_updated_fmt='$(shell LC_ALL=C date -u +'%B %d, %Y' -d '$(LAST_CHANGE)')' +SPHINXOPTS := -D today='$(shell LC_ALL=C date -u +'%B %d, %Y' -d '@$(SOURCE_DATE_EPOCH)')' +SPHINXOPTS += -D html_last_updated_fmt='$(shell LC_ALL=C date -u +'%B %d, %Y' -d '@$(SOURCE_DATE_EPOCH)')' export SPHINXOPTS on_buildd := $(shell [ -f /CurrentlyBuilding -o "$$LOGNAME" = buildd -o "$$USER" = buildd ] && echo yes) @@ -66,6 +50,7 @@ ifneq ($(DEB_HOST_GNU_TYPE),$(DEB_BUILD_GNU_TYPE)) WITHOUT_CHECK := yes endif +SPACE = $(EMPTY) $(EMPTY) COMMA = , ifneq (,$(filter parallel=%,$(subst $(COMMA), ,$(DEB_BUILD_OPTIONS)))) NJOBS := -j $(subst parallel=,,$(filter parallel=%,$(subst $(COMMA), ,$(DEB_BUILD_OPTIONS)))) @@ -78,6 +63,21 @@ derivative := $(shell \ elif dpkg-vendor --derives-from Debian; then echo Debian; \ else echo Unknown; fi) +# package metadata information +ifeq (,$(ELF_PACKAGE_METADATA)) + ELF_PACKAGE_METADATA := $(subst $(SPACE),,{ \ + "type":"deb", \ + "os":"$(shell awk -F= '/^ID=/ {print $$2}' /etc/os-release)", \ + "name":"$(DEB_SOURCE)", \ + "version":"$(DEB_VERSION)", \ + "architecture":"$(DEB_HOST_ARCH)" \ + $(if $(DEB_BUILD_DEBUG_INFO_URL),$(COMMA)"debugInfoUrl":"$(DEB_BUILD_DEBUG_INFO_URL)") \ + }) + export ELF_PACKAGE_METADATA +endif + +# we inject our own lto flags +DPKG_OPTIMIZE = optimize=-lto dpkg_buildflags = DEB_BUILD_MAINT_OPTIONS="hardening=-pie $(DPKG_OPTIMIZE)" dpkg-buildflags dpkg_pieflags = DEB_BUILD_MAINT_OPTIONS="hardening=-pie $(DPKG_OPTIMIZE)"dpkg-buildflags ifeq (,$(filter $(distrelease),stretch buster bullseye trusty xenial bionic focal impish)) @@ -100,7 +100,7 @@ ifneq (,$(filter valgrind, $(shell dpkg-query --show -f '$${Depends}\n' valgrind endif VER=3.12 -SVER=3.12.1 +SVER=3.12.7 NVER=3.13 PVER=python$(VER) EXT_VER=$(subst .,,$(VER)) @@ -129,7 +129,8 @@ MIN_ENCODINGS := $(foreach i, \ encodings/$(i)) \ codecs.py stringprep.py -with_tk := no +with_tk := yes +with_gdbm := yes with_interp := static #with_interp := shared @@ -248,11 +249,9 @@ sysconfig_substflags = \ -e '/^OPT/s,-O3,-O2,' \ -e 's/-O3/-O2/g' \ -e 's/-fprofile-use *-fprofile-correction//g' \ - -e 's/-fstack-protector /-fstack-protector-strong /g' \ -e "s/-specs=[^ '\"]*//g" \ -e "s/-fdebug-prefix-map=[^ '\"]*//g" \ -e "s/-ffile-prefix-map=[^ '\"]*//g" \ - -e 's/-Wl,-z,relro//g' \ -e 's,^RUNSHARED *=.*,RUNSHARED=,' \ -e '/BLDLIBRARY/s/-L\. //' @@ -280,6 +279,7 @@ p_base := $(PVER) p_npie := $(PVER)-nopie p_min := $(PVER)-minimal p_lib := lib$(PVER) +p_gdbm := $(PVER)-gdbm p_tk := $(PVER)-tk p_dev := $(PVER)-dev p_exam := $(PVER)-examples @@ -300,6 +300,7 @@ d_base := debian/$(p_base) d_min := debian/$(p_min) d_npie := debian/$(p_npie) d_lib := debian/$(p_lib) +d_gdbm := debian/$(p_gdbm) d_tk := debian/$(p_tk) d_dev := debian/$(p_dev) d_exam := debian/$(p_exam) @@ -357,74 +358,11 @@ PROFILE_TASK = ../Lib/test/regrtest.py \ -j 1 -unone,decimal \ -x $(sort $(TEST_EXCLUDES) $(PROFILE_EXCLUDES)) -stamps/stamp-build-static: stamps/stamp-configure-static - dh_testdir - $(MAKE) $(NJOBS) -C $(buildd_static) \ - EXTRA_CFLAGS="$(EXTRA_OPT_CFLAGS)" \ - CONFIGURE_LDFLAGS="$(DPKG_PIE_LDFLAGS) $(LTO_CFLAGS)" \ - PROFILE_TASK='$(PROFILE_TASK)' $(make_build_target) - -ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) - : # check that things are correctly built - ifneq (,$(filter $(DEB_HOST_ARCH_OS), linux)) - cd $(buildd_static) && ./python -c 'from _multiprocessing import SemLock' - endif - cd $(buildd_static) && ./python -c 'import _decimal' - cd $(buildd_static) && ./python -c 'import math, cmath' -endif - - touch stamps/stamp-build-static - -stamps/stamp-build-nopie: stamps/stamp-configure-nopie - dh_testdir - $(MAKE) $(NJOBS) -C $(buildd_nopie) \ - EXTRA_CFLAGS="$(EXTRA_OPT_CFLAGS)" \ - CONFIGURE_LDFLAGS="$(DPKG_LDFLAGS) $(LTO_CFLAGS)" \ - PROFILE_TASK='$(PROFILE_TASK)' $(make_build_target) - -ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) - : # check that things are correctly built - ifneq (,$(filter $(DEB_HOST_ARCH_OS), linux)) - cd $(buildd_nopie) && ./python -c 'from _multiprocessing import SemLock' - endif - cd $(buildd_nopie) && ./python -c 'import _decimal' - cd $(buildd_nopie) && ./python -c 'import math, cmath' -endif - - touch stamps/stamp-build-nopie run-profile-task: $(MAKE) -C $(buildd_static) \ PROFILE_TASK='$(PROFILE_TASK)' run_profile_task -stamps/stamp-build-shared: stamps/stamp-configure-shared - dh_testdir - $(MAKE) $(NJOBS) -C $(buildd_shared) \ - EXTRA_CFLAGS="$(EXTRA_OPT_CFLAGS)" - : # build a static library with PIC objects - $(MAKE) $(NJOBS) -C $(buildd_shared) \ - EXTRA_CFLAGS="$(EXTRA_OPT_CFLAGS)" \ - LIBRARY=libpython$(VER)-pic.a libpython$(VER)-pic.a - touch stamps/stamp-build-shared - -stamps/stamp-build-debug: stamps/stamp-configure-debug - dh_testdir - $(MAKE) $(NJOBS) -C $(buildd_debug) \ - EXTRA_CFLAGS="$(DEBUG_CFLAGS)" - -ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) - cd $(buildd_static) && ./python -c 'import _decimal' - cd $(buildd_debug) && ./python -c 'import math, cmath' -endif - - touch stamps/stamp-build-debug - -stamps/stamp-build-shared-debug: stamps/stamp-configure-shared-debug - dh_testdir - : # build the shared debug library - $(MAKE) $(NJOBS) -C $(buildd_shdebug) \ - EXTRA_CFLAGS="$(DEBUG_CFLAGS)" - touch stamps/stamp-build-shared-debug common_configure_args = \ --prefix=/usr \ @@ -435,20 +373,16 @@ common_configure_args = \ --with-computed-gotos \ --without-ensurepip \ --with-system-expat \ - --with-dtrace \ --with-ssl-default-suites=openssl \ --with-wheel-pkg-dir=/usr/share/python-wheels/ \ - --with-ssl-default-suites=openssl \ MKDIR_P="/bin/mkdir -p" \ # FIXME, only temporaray #common_configure_args += \ # --without-builtin-hashlib-hashes -ifneq (,$(filter $(DEB_HOST_ARCH), or1k)) - common_configure_args += --without-ffi -else - common_configure_args += --with-system-ffi +ifeq (,$(filter $(DEB_HOST_ARCH_OS), hurd)) + common_configure_args += --with-dtrace endif ifneq ($(DEB_HOST_GNU_TYPE),$(DEB_BUILD_GNU_TYPE)) @@ -468,8 +402,9 @@ stamps/stamp-configure-shared: stamps/stamp-patch rm -rf $(buildd_shared) mkdir -p $(buildd_shared) cd $(buildd_shared) && \ - AR="$(AR)" RANLIB="$(RANLIB)" CFLAGS="$(OPT_CFLAGS)" \ - CPPFLAGS="$(DPKG_CPPFLAGS)" LDFLAGS="$(DPKG_LDFLAGS) $(LTO_CFLAGS)" \ + AR="$(AR)" RANLIB="$(RANLIB)" \ + CFLAGS_NODIST="$(DPKG_CPPFLAGS) $(OPT_CFLAGS)" \ + LDFLAGS_NODIST="$(DPKG_LDFLAGS) $(LTO_CFLAGS)" \ $(config_site) \ ../configure \ --enable-shared \ @@ -482,12 +417,37 @@ stamps/stamp-configure-shared: stamps/stamp-patch touch $@ +stamps/stamp-build-static: stamps/stamp-configure-static + dh_testdir + $(MAKE) $(NJOBS) -C $(buildd_static) \ + PROFILE_TASK='$(PROFILE_TASK)' $(make_build_target) + +ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) + : # check that things are correctly built + ifneq (,$(filter $(DEB_HOST_ARCH_OS), linux)) + cd $(buildd_static) && ./python -c 'from _multiprocessing import SemLock' + endif + cd $(buildd_static) && ./python -c 'import _decimal' + cd $(buildd_static) && ./python -c 'import math, cmath' +endif + touch $@ + +stamps/stamp-build-shared: stamps/stamp-configure-shared + dh_testdir + $(MAKE) $(NJOBS) -C $(buildd_shared) + + : # build a static library with PIC objects + $(MAKE) $(NJOBS) -C $(buildd_shared) \ + LIBRARY=libpython$(VER)-pic.a libpython$(VER)-pic.a + touch $@ + stamps/stamp-configure-static: stamps/stamp-patch rm -rf $(buildd_static) mkdir -p $(buildd_static) cd $(buildd_static) && \ - AR="$(AR)" RANLIB="$(RANLIB)" CFLAGS="$(OPT_PIE_CFLAGS)" \ - CPPFLAGS="$(DPKG_PIE_CPPFLAGS)" LDFLAGS="$(DPKG_PIE_LDFLAGS) $(LTO_CFLAGS)" \ + AR="$(AR)" RANLIB="$(RANLIB)" \ + CFLAGS_NODIST="$(DPKG_PIE_CPPFLAGS) $(OPT_PIE_CFLAGS)" \ + LDFLAGS_NODIST="$(DPKG_PIE_LDFLAGS) $(LTO_CFLAGS)" \ $(config_site) \ ../configure \ $(common_configure_args) @@ -499,8 +459,9 @@ stamps/stamp-configure-nopie: stamps/stamp-patch rm -rf $(buildd_nopie) mkdir -p $(buildd_nopie) cd $(buildd_nopie) && \ - AR="$(AR)" RANLIB="$(RANLIB)" CFLAGS="$(OPT_CFLAGS)" \ - CPPFLAGS="$(DPKG_CPPFLAGS)" LDFLAGS="$(DPKG_LDFLAGS) $(LTO_CFLAGS)" \ + AR="$(AR)" RANLIB="$(RANLIB)" \ + CFLAGS_NODIST="$(DPKG_CPPFLAGS) $(OPT_CFLAGS)" \ + LDFLAGS_NODIST="$(DPKG_LDFLAGS) $(LTO_CFLAGS)" \ $(config_site) \ ../configure \ $(common_configure_args) @@ -508,12 +469,28 @@ stamps/stamp-configure-nopie: stamps/stamp-patch $(call __post_configure,$(buildd_nopie)) touch $@ +stamps/stamp-build-nopie: stamps/stamp-configure-nopie + dh_testdir + $(MAKE) $(NJOBS) -C $(buildd_nopie) \ + PROFILE_TASK='$(PROFILE_TASK)' $(make_build_target) + +ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) + : # check that things are correctly built + ifneq (,$(filter $(DEB_HOST_ARCH_OS), linux)) + cd $(buildd_nopie) && ./python -c 'from _multiprocessing import SemLock' + endif + cd $(buildd_nopie) && ./python -c 'import _decimal' + cd $(buildd_nopie) && ./python -c 'import math, cmath' +endif + touch $@ + stamps/stamp-configure-debug: stamps/stamp-patch rm -rf $(buildd_debug) mkdir -p $(buildd_debug) cd $(buildd_debug) && \ - AR="$(AR)" RANLIB="$(RANLIB)" CFLAGS="$(DEBUG_CFLAGS)" \ - CPPFLAGS="$(DPKG_CPPFLAGS)" LDFLAGS="$(DPKG_LDFLAGS)" \ + AR="$(AR)" RANLIB="$(RANLIB)" \ + CFLAGS_NODIST="$(DPKG_CPPFLAGS) $(DEBUG_CFLAGS)" \ + LDFLAGS_NODIST="$(DPKG_LDFLAGS)" \ $(config_site) \ ../configure \ $(common_configure_args) \ @@ -523,12 +500,23 @@ stamps/stamp-configure-debug: stamps/stamp-patch $(call __post_configure,$(buildd_debug)) touch $@ +stamps/stamp-build-debug: stamps/stamp-configure-debug + dh_testdir + $(MAKE) $(NJOBS) -C $(buildd_debug) + +ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) + cd $(buildd_static) && ./python -c 'import _decimal' + cd $(buildd_debug) && ./python -c 'import math, cmath' +endif + touch $@ + stamps/stamp-configure-shared-debug: stamps/stamp-patch rm -rf $(buildd_shdebug) mkdir -p $(buildd_shdebug) cd $(buildd_shdebug) && \ - AR="$(AR)" RANLIB="$(RANLIB)" CFLAGS="$(DEBUG_CFLAGS)" \ - CPPFLAGS="$(DPKG_CPPFLAGS)" LDFLAGS="$(DPKG_LDFLAGS)" \ + AR="$(AR)" RANLIB="$(RANLIB)" \ + CFLAGS_NODIST="$(DPKG_CPPFLAGS) $(DEBUG_CFLAGS)" \ + LDFLAGS_NODIST="$(DPKG_LDFLAGS)" \ $(config_site) \ ../configure \ $(common_configure_args) \ @@ -539,6 +527,13 @@ stamps/stamp-configure-shared-debug: stamps/stamp-patch $(call __post_configure,$(buildd_shdebug)) touch $@ +stamps/stamp-build-shared-debug: stamps/stamp-configure-shared-debug + dh_testdir + : # build the shared debug library + $(MAKE) $(NJOBS) -C $(buildd_shdebug) + touch $@ + + define __post_configure egrep \ "^#($$(awk -v ORS='|' '$$2 ~ /^extension$$/ {print $$1}' debian/PVER-minimal.README.Debian.in)XX)" \ @@ -657,13 +652,6 @@ stamps/stamp-check: ifeq ($(WITHOUT_CHECK),yes) echo "check run disabled for this build" > $(buildd_static)/test_results else - : # build locales needed by the testsuite - rm -rf locales - mkdir locales - if command -v localedef >/dev/null 2>&1; then \ - sh debian/locale-gen; \ - fi - @echo ========== test environment ============ @env @echo ======================================== @@ -821,11 +809,12 @@ control-file: -e "s/@bd_dbm@/$(bd_dbm)/g" \ -e "s/@bd_dpkgdev@/$(bd_dpkgdev)/g" \ debian/control.in \ + debian/control.stdlib \ $(if $(with_udeb),debian/control.udeb) \ | $(ma_filter) \ > debian/control.tmp ifeq ($(distribution),Ubuntu) - ifneq (,$(findstring ubuntu, $(PKGVERSION))) + ifneq (,$(findstring ubuntu, $(DEB_VERSION))) m='Ubuntu Core Developers '; \ sed -i "/^Maintainer:/s/\(.*\)/Maintainer: $$m\nXSBC-Original-\1/" \ debian/control.tmp @@ -1023,7 +1012,7 @@ endif test -e $(scriptdir)/lib-dynload/$$i.*.so \ && echo $(scriptdir)/lib-dynload/$$i.*.so; \ done` - ls -l $(d_lmin)/$(scriptdir)/lib-dynload/*.so + -ls -l $(d_lmin)/$(scriptdir)/lib-dynload/*.so : # Move the binary into $(p_min). dh_installdirs -p$(p_min) \ @@ -1118,12 +1107,22 @@ endif ln -sf $(DEB_HOST_MULTIARCH)-$(PVER)-config $(d_dev)/usr/bin/$(PVER)-config ln -sf $(DEB_HOST_MULTIARCH)-$(PVER)-config.1.gz $(d_dev)/usr/share/man/man1/$(PVER)-config.1.gz +ifeq ($(with_gdbm),yes) + : # Move the gdbm extension file into $(p_gdbm). + dh_installdirs -p$(p_gdbm) \ + $(scriptdir) \ + usr/lib/python$(VER)/lib-dynload + $(dh_compat2) dh_movefiles -p$(p_gdbm) --sourcedir=$(d) \ + usr/lib/python$(VER)/lib-dynload/_gdbm*.so +endif + ifeq ($(with_tk),yes) : # Move the Tkinter extension files into $(p_tk). dh_installdirs -p$(p_tk) \ $(scriptdir) \ usr/lib/python$(VER)/lib-dynload $(dh_compat2) dh_movefiles -p$(p_tk) --sourcedir=$(d) \ + usr/lib/python$(VER)/tkinter \ usr/lib/python$(VER)/lib-dynload/_tkinter*.so endif @@ -1141,9 +1140,6 @@ endif : # fixed upstream ... chmod -x $(d_ltst)/$(scriptdir)/test/{test_dbm_gnu,test_dbm_ndbm}.py - : # Tkinter library files shipped in python3-tk - rm -rf $(d)/usr/lib/python$(VER)/tkinter - : # lib2to3 shipped in python3-lib2to3 rm -rf \ $(d)/usr/bin/2to3-$(VER) \ @@ -1195,7 +1191,9 @@ endif install -m 644 -p debian/README.$(p_idle) \ $(d_idle)/usr/share/doc/$(p_idle)/README.Debian ifeq ($(with_tk),yes) - cp -p debian/README.Tk $(d_tk)/usr/share/doc/$(p_tk)/ + mkdir -p $(d_tk)/usr/share/doc/$(p_base) $(d_tk)/usr/share/doc/$(p_tk) + cp -p debian/README.Tk $(d_tk)/usr/share/doc/$(p_base)/ + ln -sf ../$(p_base)/README.Tk $(d_tk)/usr/share/doc/$(p_tk)/README.Tk endif : # pyvenv and ensurepip files into $(p_venv) @@ -1327,14 +1325,6 @@ endif cp -p $(buildd_debug)/python $(d_dbg)/usr/bin/$(PVER)d ln -sf python$(VER)d $(d_dbg)/usr/bin/$(PVER)-dbg -ifneq ($(with_tk),yes) - rm -f $(d_lbase)/$(scriptdir)/lib-dynload/_tkinter*.so - rm -f $(d_ldbg)/$(scriptdir)/lib-dynload/_tkinter*.so -endif -ifneq ($(with_gdbm),yes) - rm -f $(d_lbase)/$(scriptdir)/lib-dynload/_gdbm*.so - rm -f $(d_ldbg)/$(scriptdir)/lib-dynload/_gdbm*.so -endif ifneq ($(with_dbmmodule),yes) rm -f $(d_lbase)/$(scriptdir)/lib-dynload/_dbm*.so rm -f $(d_ldbg)/$(scriptdir)/lib-dynload/_dbm*.so @@ -1518,10 +1508,13 @@ binary-arch: build-arch install done -find debian ! -perm -200 -print -exec chmod +w {} \; ifneq ($(with_tk),yes) + rm -f $(d_lbase)/$(scriptdir)/tkinter rm -f $(d_lbase)/$(scriptdir)/lib-dynload/_tkinter*.so + rm -f $(d_ldbg)/$(scriptdir)/lib-dynload/_tkinter*.so endif ifneq ($(with_gdbm),yes) rm -f $(d_lbase)/$(scriptdir)/lib-dynload/_gdbm*.so + rm -f $(d_ldbg)/$(scriptdir)/lib-dynload/_gdbm*.so endif find $(d_ldbg) $(d_ldev) -name '*.a' ! -type l \ @@ -1603,6 +1596,9 @@ stamps/stamp-patch: touch Lib/test/libregrtest/__init__.py touch Lib/test/tokenizedata/__init__.py + # Check if patchlevel-noplus.diff is missing + grep -Eq '^#define PY_VERSION +"[^+]+"$$' Include/patchlevel.h + mv stamps/pxx $@ reverse-patches: unpatch diff --git a/debian/tests/control b/debian/tests/control index d7892071..8a87a975 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -4,9 +4,8 @@ Depends: build-essential, locales-all, python3.12-dev, libpython3.12-testsuite:native, - python3-gdbm (>= 3.11.4), - python3-distutils, - python3-tk (>= 3.11.4), + python3.12-gdbm, + python3.12-tk, idle-python3.12, systemtap-sdt-dev, python3.12-venv, @@ -19,10 +18,7 @@ Depends: build-essential, locales-all, python3.12-dev, python3.12-dbg, libpython3.12-testsuite:native, - python3-gdbm-dbg (>= 3.11.4), gdb, - python3-distutils, - python3-tk-dbg (>= 3.11.4), idle-python3.12, systemtap-sdt-dev, python3.12-venv, @@ -35,9 +31,8 @@ Depends: build-essential, locales-all, python3.12-dev, libpython3.12-testsuite:native, - python3-gdbm (>= 3.11.4), - python3-tk (>= 3.11.4), - python3-distutils, + python3.12-gdbm, + python3.12-tk, python3.12-venv, # need to turn off apport Restrictions: needs-root, allow-stderr @@ -49,10 +44,7 @@ Depends: build-essential, python3.12-dev, python3.12-dbg, libpython3.12-testsuite:native, - python3-gdbm-dbg (>= 3.11.4), - python3-tk-dbg (>= 3.11.4), gdb, - python3-distutils, python3.12-venv, # need to turn off apport Restrictions: needs-root, allow-stderr diff --git a/debian/tests/test-common.sh b/debian/tests/test-common.sh index 4e4e37ec..4e24ec65 100644 --- a/debian/tests/test-common.sh +++ b/debian/tests/test-common.sh @@ -7,9 +7,6 @@ else vendor=Unknown fi -export LOCPATH=$(pwd)/locales -sh $debian_dir/locale-gen - export LANG=C.UTF-8 export DEB_PYTHON_INSTALL_LAYOUT=deb_system @@ -61,3 +58,8 @@ TESTEXCLUSIONS="$TESTEXCLUSIONS test_ttk_textonly" # FIXME: test_multiprocessing_fork times out sometimes. See #1000188 TESTEXCLUSIONS="$TESTEXCLUSIONS test_multiprocessing_fork" + +# FIXME, tests never run to completion on Ubuntu infra +if [ "$vendor" = Ubuntu ]; then + TESTNEVERCOMPLETE="$TESTNEVERCOMPLETE test_exceptions test_repl" +fi diff --git a/debian/tests/testsuite b/debian/tests/testsuite index 7b235ce8..ce88338c 100755 --- a/debian/tests/testsuite +++ b/debian/tests/testsuite @@ -31,8 +31,10 @@ debian_dir=$(dirname $(dirname $0)) TESTPYTHON="python3.12 -W default -bb -E -R -m test" TESTEXCLUSIONS="-x" +TESTNEVERCOMPLETE="" . $debian_dir/tests/test-common.sh +TESTEXCLUSIONS="$TESTEXCLUSIONS $TESTNEVERCOMPLETE" if [ "$su_user" = nobody ]; then log=/dev/null diff --git a/debian/tests/testsuite-dbg b/debian/tests/testsuite-dbg index 4d567998..ec5ddd1c 100755 --- a/debian/tests/testsuite-dbg +++ b/debian/tests/testsuite-dbg @@ -30,8 +30,10 @@ debian_dir=$(dirname $(dirname $0)) TESTPYTHON="python3.12d -W default -bb -E -R -m test" TESTEXCLUSIONS="-x" +TESTNEVERCOMPLETE="" . $debian_dir/tests/test-common.sh +TESTEXCLUSIONS="$TESTEXCLUSIONS $TESTNEVERCOMPLETE" if [ "$su_user" = nobody ]; then log=/dev/null diff --git a/debian/upstream/signing-key.asc b/debian/upstream/signing-key.asc new file mode 100644 index 00000000..90b22ec2 --- /dev/null +++ b/debian/upstream/signing-key.asc @@ -0,0 +1,104 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBFUAInYBEACrmKcXagNRlo1VjznrJZMMUh0rxUn2iK2wy9H5qrCo4EgMYahZ +ibBunSWB4RNeVQevzUm3eSyOixnt+BmGZbSYqKp8tJIXRRcnKhEtC62X+7NVMc7B +9uPu/aJ3HNqXrsQwBJUzZxzLMLg6obCyarhhHAYbWmfaafU4yNk3J4dGNKoZtHvz +bjnUtlsUAkCmuyt3MsUuSYz34BviRLSEZEKW6xNoyQmD9dUhQ5exBuTPjtmdTf+x +gOKpBluRkJ4TADGlWf42lIkaI+8DYRj1R8eQdLFwS7sDTu/MMPceKU7nTWOoj8HF +3xXRJ+bJbpOJXZFEzVKjXHKuMFkhKr562i0LD8pdl1+s+9LRovmAvGwggt04Drzb +AK437QoyjPKiTnFlg4tOeIuN0Y+GGk2hXOdH7fNw79B9Tq5ENxth8NsnKVlz1zpF +X+aV0zCvAjNWutAUpikqZT/ibpwmM+NJcz3pgzQOq+LfPFskyrv7zkVODEjH3SG3 +s4ROvyoWfLPWmX92kJMOkvzyQObZmU2zWJgJbjYRApZiTfbfnH1tE+wxH4ZR5dji +FpEdUJn1yjpYp21Q10khIdsj6q9IvS3RDq0ygc5wfl5111byEsdP12y36lvPTclT +33VHBR1vxr+js9d8FI4wwt/o+7TmAO39DYhLrtn+ZgyRgIBYY65lhEaUtwARAQAB +tCJUaG9tYXMgV291dGVycyA8dGhvbWFzQHB5dGhvbi5vcmc+iQJXBBMBCgBBAhsD +BQsJCAcDBRUKCQgLBRYCAwEAAh4BAheABQkVRkQLFiEEcWlgX2LHUTVtBUomqCHm +gOX6YwUFAmM7V3UCGQEACgkQqCHmgOX6YwVFeRAAkXE+BC/8O7VVtNe3iCdcQtW3 +PiCINEJgOQbXSwjkIGjD/Noheu+2cdwznjUmAX3qgnOyxIvo1AzYXagRazKVl1A+ +AiMctMNUCuVAkPeTL3nUERzOzZP6fE9OB/XNyiFeNPGg3qGz/HEJH8OMzahfOpzM +VC3bCcZrn3JmMp6X8gLgArcK20L7qu/USO/Ico9vT8n+IkZIyxv9GNzfr4QZtGQN +DkcHXHbX7p6juffdF9PpQgeAHfP4F9ZuDC+Mc5AGQaxY0z+gNLQGbTEjBBxkrGqd +3iOHWb+RLLRJkHkF95KegatrgRkK3d+WLsHwCWzySDAKsjcvM33+N5YB9vWiL/K+ +kRbgEiecQHwsV1WT+DLY4yoLEBDVbThSw90R2b4bDzCOWShYMX8hDu5HaP3vT1Ye +lLSYT/1TxX1yvGeCuA8D+V9OZbSi7eKVT7W4pxqiCcDTpvMvx3o9NfiHEFGQfjlZ +nQsIBt9YeBG2c/GL0h1v4X9kBHjxv58576L9olEuWViuCam3OmW31Ik8OjYUwHs0 +tVqc/ciKsot/3ci96wxnG0RajkXL4ybQI7QzJ3OJJyLMZUPx7UTkdYlD7ZKJyU/N +kdcmEjtvBtWeCROZOdivvZeJnSe/vANbH9Oibongl9Zwlq0w/Sd8fHKJQZC7c4dA +bTVfbTLXuaLUE86ZCdS0IVRob21hcyBXb3V0ZXJzIDx0aG9tYXNAeHM0YWxsLm5s +PokCVAQTAQoAPgIbAwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAUJFUZECxYhBHFp +YF9ix1E1bQVKJqgh5oDl+mMFBQJjO1dvAAoJEKgh5oDl+mMFIlIQAKmkHcJbQ1lt +BexoJSsoCi7+9IOCSJpD0fsP6210/hkcSdcbz4EuN9omf7BdCW9SOicBB8bxVid3 +uF0NnLjqyRusNbRVIXiKWzxb2+36cA9D6ugv1u8oV7FqsD+zAEWJTNDjd4/rJjEM +TMhUxN0EFNrQLDngDnx7AeJyGD2n4eFB6RCJ7qtJtCPqxqiW9jH6vH+YlAz8zbWK +F7Z52CPVxAt/yoo6dwLFV6615Mo5n4VN6NiXQeKw5XmZprXvxDQFkodpjBpoN3fc +AX6UTX4yJOR9DhALorr2H1ldI9xdQ0pawlPTDT/gRMsYuHh3NVflUzoLny7TWqd7 +xLyocH2TqC3OAsF78oR+4W2P0QxuEq/W1WAf+LIpRjeIQ4Xt6TGDku694VHE0pfK +5BjpHApyWlGRPVq89x6Z78pCrKiMMtoW30mCPWkSd63h3cPgQNAzo+BBoNYUdvQC +AAMEFdBpUjVCQaInAqFuKw1N8IpahsKKSg4jMheLmocGKYbO5IIinjXxIz87skKD +6xkukIwfcnhvRM/IkHuxuG+ltO17nbWQNvmvZtEZ47xN9hAVZkaK/5eBDmICH1N8 +o0gHGU61KfEaCRLuQkFRe72QnbxzUkIwYtC9TCAiYieAxsSRwY5boZsKEnzLmPfM +1b96Rj7JKCiMDOBgNbUNcKXuAMqrOMZttCRUaG9tYXMgV291dGVycyA8dHdvdXRl +cnNAZ29vZ2xlLmNvbT6JAlQEEwEKAD4CGwMFCwkIBwMFFQoJCAsFFgIDAQACHgEC +F4AWIQRxaWBfYsdRNW0FSiaoIeaA5fpjBQUCYOBlAQUJFUZECwAKCRCoIeaA5fpj +BTvxEACfyEt5rN5QGmVgahD/83l7lQpZUzLSq5MnIfRjCz50seh+oWsOuecayHZ7 +9IDVSkF2L2kE1rumcB7UKPez0kHVrTdh3mQIsfCzQZEMsWTDYotlZbrPPvT3lKGL ++O7fU321q9GVotJAssYcQFIK9F2p3jhN2coOzguikVlSc4nswnq2KRIJ4BpSJ3fk +1rWLr8oJxN2pSpskYtHdUyUxfZ+fOrMHLbW94JWsLYDad4wpr8etBneVAaUPfphh +bIwfhRXlHuTreDtwr3LJYKp1VjUjzGVVT2CXkS9LbJ7aM2BYa/1MJyHxkglu8O9L +IDGH2arlbtmBKMbCXPSX/42HsGpUgQYRwG4f+2CfPj4fNx5GK8LO/EJjaw2Qh542 +U0356RRVZquN6E6SS6Sndlf9sO4cKU/ptT8IsfWKKaLwvr0l71hgLRqqe3rSpTV5 +4cKpJfYIG+Qf4Do69etJLxjYUsyCqzuFocxZa0DGkqDQ+f1cD1bdg7Twso041NZG +6y9+E7kCf3jtKkiYAHBY902qZi8FvtI2tDAqwlfJjdiH5rUtYZALO3KGT+l9p3FT +YIdDD1iVC41CeF6loJk0gQZiNmJtyY1TTyNS5Chtr8fSV9yYuoB5XoYYpLu1NCks +4Cwva1tE45VhFrl8lPaM3EABOV+JeHYHX/DgooJRIwgpXCBmwbQvVGhvbWFzIFdv +dXRlcnMgPHRob21hcy53b3V0ZXJzLnByaXZlQGdtYWlsLmNvbT6JAj0EEwEKACcF +AlUAOTkCGwMFCQlmAYAFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AACgkQqCHmgOX6 +YwV6Ug/8CS3leyQyFLv2qP0uJsX7Sl6vbUVxQpOnYtKtlJS4OsB7/9IUXlqvt/pP +pnUoEtgZ+U9ljxJvNXXPuxoRVkw2e+ylYH+NaojXNdX0T2iDf0G4EVvH2g18eW5l +5KhyezkwMEZtWjUAfjXreGLL7dS3cvmvsHLzvcdgojwfNABoQiC41mlhTnKNFH9m +hbZQfD/7adiFYTxERDtdrD+qYkDo/3hQmkmUHw5RpJeEBT/j1mEe2+SxepsZitLE +yMj4BPOy+C8GiKyBjgN3LwYsPahEfV3zWf1Sh8wgC0cIJLAkvwqeU7xRBbaBOJkm +mN/gp2X4B/WPLNezARGnF5qOR7WsCc8eXxdhphY/OvjYHwC56qq42JIS/ldlgWv5 +CkcAilto3ED28I8rPugSvzx0JJqk96F0Hba4ZG3FUz9ZRyrUv//1fdH4K8wUgUvi +/tIXPoUZ4jHPVEpe2RaYm9OpgXUlh6KMCHFAcZ72uZ5SH3xqhvCSeHuNxzwcXvg5 +5Plc2HlZsaY04yrx8y+s8sWpshNGARyaHP7KTfS+xVlnQljbGpHCf5zdekC5A7jH +qmqD7ndbE4Gt99/+cgXZQUDAvnxMogaocz3Uh58Tp+CjRWT+8XRiPg+AvAFmNVuQ +x78Q4QIMmRwT/b5h8GpIGd1lzuLZlAq9hBQK39d0P6SnR4Px/jS0JVRob21hcyBX +b3V0ZXJzIDx0aG9tYXN3b3V0QGdtYWlsLmNvbT6JAj0EEwEKACcFAlUAOUgCGwMF +CQlmAYAFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AACgkQqCHmgOX6YwUHOg/9Fvdy +KIJ8YKIUBqnHYm/uLWi5HSZg1o5IhveRpVFSnKeGhY8UuQaAy4o8w/ehkXWJcafm +ULynKTEk/ORCsds7hE3ooTTL1LVqffsdPMQovGTp1n92sKjk146WS+4s3mWJiP6Y +wz8hZuoVSSfS9KHAHSGF0Jp7SfLx+6i833nD63THm0o1IdSQrJFVsQIFvE6THosw +FrC7BHa3wnyagxhBQ2TWEOyoW7X/X5M2ZoJC+M66R4qD0lnPsJSPEhLffFOC2toP +rZUphwNxNXBC6X6MLtm0IBdhI4F+6Css9kwyJsHPkoCAWzLSsS8sNe8D1Bjvz3ar +uVQuhkxXBVtHmjhS0Aglk7ORkIGbZ30bquIVCmQxCkm7o9EMcMev2Q07lwSJtm91 +2ulJxWIZ8EPGqtfTGwJj6IROc/Ce7y7u6bxAeQtEtF4ro/edH+4DSndo7pRudpNK +tWWYBHP6mfRnLVkQS577axp01xgEVMPo1v3ACqqp+B1nbuzzMEe56M//L7smWj4g +ToiHl5mINqU/y+pE5zryw9dh2q7+YSaskGmLisIP3Po39CaN71Zu9ycsNZVtRvu3 +YDalJHa7ARP2RBiPxlqdPLhPylu8bXvC7Q26WtRMcObcuTW3ynWg/e0v0w01WaQy +VLAcndM4r0F1IuXXfkrB1EdLH6sX2ux/Yi2B5Du5Ag0EVQAidgEQAOJaW1vFng6s +kRX36kM1VCuuOegpDOxXe+59RXWNCsDXgJlC2HokNSqdjw88RTsqCTXvGkGswe4z +6hrYdPiYBQjsRpZwLQT+w0JdjK2AC/gHCidHOXV3Pejm2esbXdNZ/YAKKLqaSSDW +gNmhF/D+p4UBrvajc/MjAQttsNDGCWft/GVXlxnAQktwBoIHkTsDT8jUmZ1uUz1R +4vknmuWwhOHqOVGCADKnE6MYniN1eANnIkFfZwRESxdGwGnQ9RxHgm+sDIOofM+l +SET4rZOOQ8O93ctcgujr4ZMhkNchrjj8cFZxt8NAi0lJjEHqsjQLn5rTdsnqEjFe ++CvZDqZMQs80rpVxoRIAl1hOxFygtoPIujOAcGJtwGgRqnqPs+w4p331rPFtlL0F +DeiUwHRlYDVH2nGGz/GEe3zjtRHMyfxWBsaviZw1BUaSjbA6LsOmXkSNRIkE9xRC +liN5njZkzwZiHFi6GBjWHZmnm+KahwW+kn1eOR+EI08iIzR4lvy5KbiO6DaP7yJT +RfDkMMlBbZJ1yMeewNFUnSPr389XK53oP24NKswc+UqGGdF2VH75mCwKA2dPyi2q +mdcdWfcIi23t4iupxNZo5ln+6zn5lh7sR/4GwoVzAw3zjMIDmBVzVyJrDT1j191w +Ng64Ra5TVswPJMYvYVya4AH5EXMf/OKFABEBAAGJAjwEGAEKACYCGwwWIQRxaWBf +YsdRNW0FSiaoIeaA5fpjBQUCYOBlDwUJFUZEGQAKCRCoIeaA5fpjBYSHD/497SWp +syqSRiQMHLKJ3hbWH5mZywOFKLH32j5bCxkVS9W7skbo9nRQa9llODQJXWK0DyuE +/nIkqX6ICfQ5PLNXlDIWYu4MSpnjh1A8nnz1yKe79z0huMXJ3148hCvcwu9eKhbC +PREY04O7msOqphb/F4bfDvEyxjIKg4o0CIKx9qBnerRHWMjjgjj0O3ejwUpuUsOd +y5QlpVuSPW3NDQo258Fo4e2fVF7S3382csYMYIEsNL34OT7oXKa2dkXdzMMyZgCy +NgQe3lltcfjNIV5rXao+zqZmo4flDKxYy7QJRGX7JScM1fTZABcQ2M0Yto77Jice +/LzjwdV4V4E75RDrwO6hGA1xWmSR5QQ5hVPSasrRmej7YkBDbixyHuITumh24SQO +CPRKqBtVNQjkAMK7B63levn6XBZ+JV27voFj8lMyokDEHfZCNxBImsjm1K6NtThR +0u89d9ZCmzHnP6HNkXwAwrxMGPKGsu6NEvWk6rz0kDg7PJ2JG2XITRaAvqBfZ/KQ +TDc4WAbE5NTl5Xg9cjLnLLssK+YtJnsr7uqEOPqXT2A+sIeyWrSYdIWsist9xhrF +3du/CdRJNaejBBZxi3P8x/jWWSyFO0J9aBVPoCuHFXmi19oNPwSynEPwBJmCMJ3n +C6/APmOJmVcMLJ0h7XxC7aBkrGsDdum8ym50bA== +=FLhQ +-----END PGP PUBLIC KEY BLOCK----- diff --git a/debian/watch b/debian/watch index 2113457e..6b0eb6ca 100644 --- a/debian/watch +++ b/debian/watch @@ -1,3 +1,5 @@ -version=3 -opts=dversionmangle=s/.*\+//,uversionmangle=s/([abcr]+[1-9])$/~$1/ \ +version=4 +opts=dversionmangle=s/.*\+//,\ + uversionmangle=s/([abcr]+[1-9])$/~$1/,\ + pgpsigurlmangle=s/$/.asc/ \ http://www.python.org/ftp/python/3\.12(\.\d)?/Python-(3\.12[.\dabcr]*)\.tar.xz diff --git a/pyconfig.h.in b/pyconfig.h.in index 6d370f66..7d3537e5 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -47,10 +47,6 @@ /* Define if --enable-ipv6 is specified */ #undef ENABLE_IPV6 -/* Define to 1 if your system stores words within floats with the most - significant word first */ -#undef FLOAT_WORDS_BIGENDIAN - /* Define if getpgrp() must be called as getpgrp(0). */ #undef GETPGRP_HAVE_ARG