diff --git a/.gitattributes b/.gitattributes
index 1f2f8a4cd8735a..317a613217a9b3 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -75,6 +75,7 @@ Include/internal/pycore_opcode.h generated
Include/internal/pycore_opcode_metadata.h generated
Include/internal/pycore_*_generated.h generated
Include/opcode.h generated
+Include/opcode_ids.h generated
Include/token.h generated
Lib/_opcode_metadata.py generated
Lib/keyword.py generated
@@ -89,6 +90,7 @@ Programs/test_frozenmain.h generated
Python/Python-ast.c generated
Python/executor_cases.c.h generated
Python/generated_cases.c.h generated
+Python/abstract_interp_cases.c.h generated
Python/opcode_targets.h generated
Python/stdlib_module_names.h generated
Tools/peg_generator/pegen/grammar_parser.py generated
diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md
deleted file mode 100644
index 47037cd319e7e2..00000000000000
--- a/.github/ISSUE_TEMPLATE/bug.md
+++ /dev/null
@@ -1,50 +0,0 @@
----
-name: Bug report
-about: Submit a bug report
-labels: "type-bug"
----
-
-
-
-# Bug report
-
-## Checklist
-
-
-
-- [ ] I am confident this is a bug in CPython, not a bug in a third-party project
-- [ ] I have searched the CPython issue tracker, and am confident this bug has not been reported before
-
-## A clear and concise description of the bug
-
-
-
-
-
-# Your environment
-
-
-
-- CPython versions tested on:
-- Operating system and architecture:
-
-
diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml
new file mode 100644
index 00000000000000..05f4f317ccc97e
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug.yml
@@ -0,0 +1,69 @@
+name: Bug report
+description: Submit a bug report
+labels: ["type-bug"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ **New to Python?**
+
+ For help or advice on using Python, try one of the following options instead of opening a GitHub issue:
+
+ - Posting on [Discourse](https://discuss.python.org/c/users/7)
+ - Reading the [Python tutorial](https://docs.python.org/3/tutorial/)
+ - Emailing [python-list](https://mail.python.org/mailman/listinfo/python-list)
+ - type: checkboxes
+ attributes:
+ label: Checklist
+ description: A bug in a third-party project (for example, `pip` or `requests`) should be reported to that project's issue tracker, not CPython
+ options:
+ - label: I am confident this is a bug in CPython, not a bug in a third-party project
+ required: false
+ - label: |
+ I have searched the [CPython issue tracker](https://github.com/python/cpython/issues?q=is%3Aissue+sort%3Acreated-desc),
+ and am confident this bug has not been reported before
+ required: false
+ - type: dropdown
+ attributes:
+ label: "CPython versions tested on:"
+ multiple: true
+ options:
+ - "3.8"
+ - "3.9"
+ - "3.10"
+ - "3.11"
+ - "3.12"
+ - "CPython main branch"
+ validations:
+ required: true
+ - type: dropdown
+ attributes:
+ label: "Operating systems tested on:"
+ multiple: true
+ options:
+ - Linux
+ - macOS
+ - Windows
+ - Other
+ validations:
+ required: false
+ - type: input
+ attributes:
+ label: "Output from running 'python -VV' on the command line:"
+ description: If you tested with multiple operating systems or architectures, feel free to provide details in the main bug description.
+ validations:
+ required: false
+ - type: textarea
+ attributes:
+ label: "A clear and concise description of the bug:"
+ description: >
+ Tell us what happened.
+ Include a [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) if possible.
+ Put any code blocks inside triple backticks.
+
+ value: |
+ ```python
+ # Add a code block here, if required
+ ```
+ validations:
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/crash.md b/.github/ISSUE_TEMPLATE/crash.md
deleted file mode 100644
index a268249d1c1e65..00000000000000
--- a/.github/ISSUE_TEMPLATE/crash.md
+++ /dev/null
@@ -1,48 +0,0 @@
----
-name: Crash report
-about: A hard crash of the interpreter, possibly with a core dump
-labels: "type-crash"
----
-
-
-
-# Crash report
-
-
-
-
-
-# Error messages
-
-
-
-
-
-# Your environment
-
-
-
-- CPython versions tested on:
-- Operating system and architecture:
-
-
diff --git a/.github/ISSUE_TEMPLATE/crash.yml b/.github/ISSUE_TEMPLATE/crash.yml
new file mode 100644
index 00000000000000..1ea84b893697a6
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/crash.yml
@@ -0,0 +1,71 @@
+name: Crash report
+description: A hard crash of the interpreter, possibly with a core dump
+labels: ["type-crash"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ This form is for hard crashes of the Python interpreter, segmentation faults, failed C-level assertions, and similar. Unexpected exceptions raised from Python functions in the standard library count as bugs rather than crashes.
+
+ The CPython interpreter is written in a different programming language, C. A "CPython crash" is when Python itself fails, leading to a traceback in the C stack.
+ - type: dropdown
+ attributes:
+ label: "CPython versions tested on:"
+ multiple: true
+ options:
+ - "3.8"
+ - "3.9"
+ - "3.10"
+ - "3.11"
+ - "3.12"
+ - "CPython main branch"
+ validations:
+ required: true
+ - type: dropdown
+ attributes:
+ label: "Operating systems tested on:"
+ multiple: true
+ options:
+ - Linux
+ - macOS
+ - Windows
+ - Other
+ validations:
+ required: false
+ - type: input
+ attributes:
+ label: "Output from running 'python -VV' on the command line:"
+ description: If you tested with multiple operating systems or architectures, feel free to provide details in the main bug description.
+ validations:
+ required: false
+ - type: textarea
+ attributes:
+ label: What happened?
+ description: >
+ Include a [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) if possible.
+ Put any code blocks inside triple backticks.
+
+ value: |
+ ```python
+ # Add a code block here, if required
+ ```
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: Error messages
+ description: >
+ Enter any error messages caused by the crash, including a core dump if there is one.
+ Feel free to leave this bit blank if it isn't relevant.
+ placeholder: |
+ Error messages should be formatted like this:
+
+
+ Error messages/core dump
+
+ ```
+ # paste errors here, if you have any
+ ```
+
+ validations:
+ required: false
diff --git a/.github/ISSUE_TEMPLATE/feature.md b/.github/ISSUE_TEMPLATE/feature.md
deleted file mode 100644
index 7e96bc9df665c2..00000000000000
--- a/.github/ISSUE_TEMPLATE/feature.md
+++ /dev/null
@@ -1,50 +0,0 @@
----
-name: Feature or enhancement
-about: Submit a proposal for a new CPython feature or enhancement
-labels: "type-feature"
----
-
-
-
-# Feature or enhancement
-
-
-
-
-
-# Pitch
-
-
-
-
-
-# Previous discussion
-
-
-
-
-
-
diff --git a/.github/ISSUE_TEMPLATE/feature.yml b/.github/ISSUE_TEMPLATE/feature.yml
new file mode 100644
index 00000000000000..0200e623d2a3b0
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature.yml
@@ -0,0 +1,40 @@
+name: Feature or enhancement
+description: Submit a proposal for a new CPython feature or enhancement
+labels: ["type-feature"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ # Proposing a feature to CPython?
+
+ You'll need to demonstrate widespread support for your idea among the community.
+
+ Major feature proposals should generally be discussed on [Discourse](https://discuss.python.org/c/ideas/6) before opening a GitHub issue. Wait until it's clear that most people support your idea before filling in this form.
+ - type: dropdown
+ attributes:
+ label: Has this already been discussed elsewhere?
+ options:
+ - No response given
+ - I have already discussed this feature proposal on Discourse
+ - This is a minor feature, which does not need previous discussion elsewhere
+ multiple: false
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: "Links to previous discussion of this feature:"
+ validations:
+ required: false
+ - type: textarea
+ attributes:
+ label: "Proposal:"
+ description: >
+ Explain your proposal, why it should be implemented, and how it would be used.
+ Add examples, if applicable.
+ Put any code blocks inside triple backticks.
+ value: |
+ ```python
+ # Add a code block here, if required
+ ```
+ validations:
+ required: true
diff --git a/.github/problem-matchers/sphinx.json b/.github/problem-matchers/sphinx.json
deleted file mode 100644
index 09848608a7b034..00000000000000
--- a/.github/problem-matchers/sphinx.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "problemMatcher": [
- {
- "owner": "sphinx-problem-matcher",
- "pattern": [
- {
- "regexp": "^(.*):(\\d+):\\s+(\\w*):\\s+(.*)$",
- "file": 1,
- "line": 2,
- "severity": 3,
- "message": 4
- }
- ]
- },
- {
- "owner": "sphinx-problem-matcher-loose",
- "pattern": [
- {
- "_comment": "A bit of a looser pattern, doesn't look for line numbers, just looks for file names relying on them to start with / and end with .rst",
- "regexp": "(\/.*\\.rst):\\s+(\\w*):\\s+(.*)$",
- "file": 1,
- "severity": 2,
- "message": 3
- }
- ]
- },
- {
- "owner": "sphinx-problem-matcher-loose-no-severity",
- "pattern": [
- {
- "_comment": "Looks for file names ending with .rst and line numbers but without severity",
- "regexp": "^(.*\\.rst):(\\d+):(.*)$",
- "file": 1,
- "line": 2,
- "message": 3
- }
- ]
- }
- ]
-}
\ No newline at end of file
diff --git a/.github/workflows/reusable-docs.yml b/.github/workflows/reusable-docs.yml
index 56932c4860573c..39e5ad62924ad3 100644
--- a/.github/workflows/reusable-docs.yml
+++ b/.github/workflows/reusable-docs.yml
@@ -18,8 +18,6 @@ jobs:
timeout-minutes: 60
steps:
- uses: actions/checkout@v3
- - name: Register Sphinx problem matcher
- run: echo "::add-matcher::.github/problem-matchers/sphinx.json"
- name: 'Set up Python'
uses: actions/setup-python@v4
with:
@@ -76,8 +74,6 @@ jobs:
timeout-minutes: 60
steps:
- uses: actions/checkout@v3
- - name: Register Sphinx problem matcher
- run: echo "::add-matcher::.github/problem-matchers/sphinx.json"
- uses: actions/cache@v3
with:
path: ~/.cache/pip
diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst
index 8ca1c190dab9a9..e572815ffd6259 100644
--- a/Doc/c-api/buffer.rst
+++ b/Doc/c-api/buffer.rst
@@ -161,10 +161,7 @@ a buffer, see :c:func:`PyObject_GetBuffer`.
If it is ``0``, :c:member:`~Py_buffer.buf` points to a single item representing
a scalar. In this case, :c:member:`~Py_buffer.shape`, :c:member:`~Py_buffer.strides`
and :c:member:`~Py_buffer.suboffsets` MUST be ``NULL``.
-
- The macro :c:macro:`PyBUF_MAX_NDIM` limits the maximum number of dimensions
- to 64. Exporters MUST respect this limit, consumers of multi-dimensional
- buffers SHOULD be able to handle up to :c:macro:`PyBUF_MAX_NDIM` dimensions.
+ The maximum number of dimensions is given by :c:macro:`PyBUF_MAX_NDIM`.
.. c:member:: Py_ssize_t *shape
@@ -217,6 +214,17 @@ a buffer, see :c:func:`PyObject_GetBuffer`.
freed when the buffer is released. The consumer MUST NOT alter this
value.
+
+Constants:
+
+.. c:macro:: PyBUF_MAX_NDIM
+
+ The maximum number of dimensions the memory represents.
+ Exporters MUST respect this limit, consumers of multi-dimensional
+ buffers SHOULD be able to handle up to :c:macro:`!PyBUF_MAX_NDIM` dimensions.
+ Currently set to 64.
+
+
.. _buffer-request-types:
Buffer request types
@@ -440,7 +448,7 @@ Buffer-related functions
Send a request to *exporter* to fill in *view* as specified by *flags*.
If the exporter cannot provide a buffer of the exact type, it MUST raise
- :c:data:`PyExc_BufferError`, set ``view->obj`` to ``NULL`` and
+ :exc:`BufferError`, set ``view->obj`` to ``NULL`` and
return ``-1``.
On success, fill in *view*, set ``view->obj`` to a new reference
@@ -527,7 +535,7 @@ Buffer-related functions
and :c:macro:`PyBUF_WRITABLE` is set in *flags*.
On success, set ``view->obj`` to a new reference to *exporter* and
- return 0. Otherwise, raise :c:data:`PyExc_BufferError`, set
+ return 0. Otherwise, raise :exc:`BufferError`, set
``view->obj`` to ``NULL`` and return ``-1``;
If this function is used as part of a :ref:`getbufferproc `,
diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst
index 221a05b1922404..cd037b4de882e1 100644
--- a/Doc/c-api/typeobj.rst
+++ b/Doc/c-api/typeobj.rst
@@ -147,7 +147,7 @@ Quick Reference
+------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
| :c:member:`~PyTypeObject.tp_vectorcall` | :c:type:`vectorcallfunc` | | | | | |
+------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
- | [:c:member:`~PyTypeObject.tp_watched`] | char | | | | | |
+ | [:c:member:`~PyTypeObject.tp_watched`] | unsigned char | | | | | |
+------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
.. [#slots]
@@ -1697,7 +1697,7 @@ and :c:data:`PyType_Type` effectively act as defaults.)
to a pointer, are valid C99 address constants.
However, the unary '&' operator applied to a non-static variable
- like :c:func:`PyBaseObject_Type` is not required to produce an address
+ like :c:data:`PyBaseObject_Type` is not required to produce an address
constant. Compilers may support this (gcc does), MSVC does not.
Both compilers are strictly standard conforming in this particular
behavior.
@@ -2141,7 +2141,7 @@ and :c:data:`PyType_Type` effectively act as defaults.)
.. versionadded:: 3.9 (the field exists since 3.8 but it's only used since 3.9)
-.. c:member:: char PyTypeObject.tp_watched
+.. c:member:: unsigned char PyTypeObject.tp_watched
Internal. Do not use.
@@ -2443,7 +2443,7 @@ Buffer Object Structures
Except for point (3), an implementation of this function MUST take these
steps:
- (1) Check if the request can be met. If not, raise :c:data:`PyExc_BufferError`,
+ (1) Check if the request can be met. If not, raise :exc:`BufferError`,
set :c:expr:`view->obj` to ``NULL`` and return ``-1``.
(2) Fill in the requested fields.
diff --git a/Doc/conf.py b/Doc/conf.py
index 19e05e1aa8fe19..16fd8bf257179e 100644
--- a/Doc/conf.py
+++ b/Doc/conf.py
@@ -157,6 +157,77 @@
('envvar', 'USER'),
('envvar', 'USERNAME'),
('envvar', 'USERPROFILE'),
+]
+
+# Temporary undocumented names.
+# In future this list must be empty.
+nitpick_ignore += [
+ # C API: Standard Python exception classes
+ ('c:data', 'PyExc_ArithmeticError'),
+ ('c:data', 'PyExc_AssertionError'),
+ ('c:data', 'PyExc_AttributeError'),
+ ('c:data', 'PyExc_BaseException'),
+ ('c:data', 'PyExc_BlockingIOError'),
+ ('c:data', 'PyExc_BrokenPipeError'),
+ ('c:data', 'PyExc_BufferError'),
+ ('c:data', 'PyExc_ChildProcessError'),
+ ('c:data', 'PyExc_ConnectionAbortedError'),
+ ('c:data', 'PyExc_ConnectionError'),
+ ('c:data', 'PyExc_ConnectionRefusedError'),
+ ('c:data', 'PyExc_ConnectionResetError'),
+ ('c:data', 'PyExc_EOFError'),
+ ('c:data', 'PyExc_Exception'),
+ ('c:data', 'PyExc_FileExistsError'),
+ ('c:data', 'PyExc_FileNotFoundError'),
+ ('c:data', 'PyExc_FloatingPointError'),
+ ('c:data', 'PyExc_GeneratorExit'),
+ ('c:data', 'PyExc_ImportError'),
+ ('c:data', 'PyExc_IndentationError'),
+ ('c:data', 'PyExc_IndexError'),
+ ('c:data', 'PyExc_InterruptedError'),
+ ('c:data', 'PyExc_IsADirectoryError'),
+ ('c:data', 'PyExc_KeyboardInterrupt'),
+ ('c:data', 'PyExc_KeyError'),
+ ('c:data', 'PyExc_LookupError'),
+ ('c:data', 'PyExc_MemoryError'),
+ ('c:data', 'PyExc_ModuleNotFoundError'),
+ ('c:data', 'PyExc_NameError'),
+ ('c:data', 'PyExc_NotADirectoryError'),
+ ('c:data', 'PyExc_NotImplementedError'),
+ ('c:data', 'PyExc_OSError'),
+ ('c:data', 'PyExc_OverflowError'),
+ ('c:data', 'PyExc_PermissionError'),
+ ('c:data', 'PyExc_ProcessLookupError'),
+ ('c:data', 'PyExc_RecursionError'),
+ ('c:data', 'PyExc_ReferenceError'),
+ ('c:data', 'PyExc_RuntimeError'),
+ ('c:data', 'PyExc_StopAsyncIteration'),
+ ('c:data', 'PyExc_StopIteration'),
+ ('c:data', 'PyExc_SyntaxError'),
+ ('c:data', 'PyExc_SystemError'),
+ ('c:data', 'PyExc_SystemExit'),
+ ('c:data', 'PyExc_TabError'),
+ ('c:data', 'PyExc_TimeoutError'),
+ ('c:data', 'PyExc_TypeError'),
+ ('c:data', 'PyExc_UnboundLocalError'),
+ ('c:data', 'PyExc_UnicodeDecodeError'),
+ ('c:data', 'PyExc_UnicodeEncodeError'),
+ ('c:data', 'PyExc_UnicodeError'),
+ ('c:data', 'PyExc_UnicodeTranslateError'),
+ ('c:data', 'PyExc_ValueError'),
+ ('c:data', 'PyExc_ZeroDivisionError'),
+ # C API: Standard Python warning classes
+ ('c:data', 'PyExc_BytesWarning'),
+ ('c:data', 'PyExc_DeprecationWarning'),
+ ('c:data', 'PyExc_FutureWarning'),
+ ('c:data', 'PyExc_ImportWarning'),
+ ('c:data', 'PyExc_PendingDeprecationWarning'),
+ ('c:data', 'PyExc_ResourceWarning'),
+ ('c:data', 'PyExc_RuntimeWarning'),
+ ('c:data', 'PyExc_SyntaxWarning'),
+ ('c:data', 'PyExc_UnicodeWarning'),
+ ('c:data', 'PyExc_UserWarning'),
+ ('c:data', 'PyExc_Warning'),
# 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.
@@ -283,8 +354,6 @@
latex_documents = [
('c-api/index', 'c-api.tex',
'The Python/C API', _stdauthor, 'manual'),
- ('distributing/index', 'distributing.tex',
- 'Distributing Python Modules', _stdauthor, 'manual'),
('extending/index', 'extending.tex',
'Extending and Embedding Python', _stdauthor, 'manual'),
('installing/index', 'installing.tex',
diff --git a/Doc/contents.rst b/Doc/contents.rst
index 464f93bdf85f95..24ceacb0076b5e 100644
--- a/Doc/contents.rst
+++ b/Doc/contents.rst
@@ -11,7 +11,6 @@
library/index.rst
extending/index.rst
c-api/index.rst
- distributing/index.rst
installing/index.rst
howto/index.rst
faq/index.rst
@@ -21,10 +20,3 @@
bugs.rst
copyright.rst
license.rst
-
-.. to include legacy packaging docs in build
-
-.. toctree::
- :hidden:
-
- install/index.rst
diff --git a/Doc/distributing/index.rst b/Doc/distributing/index.rst
index d237f8f082d87b..2430564b45d6d2 100644
--- a/Doc/distributing/index.rst
+++ b/Doc/distributing/index.rst
@@ -1,174 +1,19 @@
+:orphan:
+
+.. This page is retained solely for existing links to /distributing/index.html.
+ Direct readers to the PPUG instead.
+
.. _distributing-index:
###############################
Distributing Python Modules
###############################
-:Email: distutils-sig@python.org
-
-
-As a popular open source development project, Python has an active
-supporting community of contributors and users that also make their software
-available for other Python developers to use under open source license terms.
-
-This allows Python users to share and collaborate effectively, benefiting
-from the solutions others have already created to common (and sometimes
-even rare!) problems, as well as potentially contributing their own
-solutions to the common pool.
-
-This guide covers the distribution part of the process. For a guide to
-installing other Python projects, refer to the
-:ref:`installation guide `.
-
.. note::
- For corporate and other institutional users, be aware that many
- organisations have their own policies around using and contributing to
- open source software. Please take such policies into account when making
- use of the distribution and installation tools provided with Python.
-
-
-Key terms
-=========
-
-* the `Python Package Index `__ is a public
- repository of open source licensed packages made available for use by
- other Python users
-* the `Python Packaging Authority
- `__ are the group of
- developers and documentation authors responsible for the maintenance and
- evolution of the standard packaging tools and the associated metadata and
- file format standards. They maintain a variety of tools, documentation
- and issue trackers on `GitHub `__.
-* ``distutils`` is the original build and distribution system first added
- to the Python standard library in 1998. While direct use of ``distutils``
- is being phased out, it still laid the foundation for the current packaging
- and distribution infrastructure, and it not only remains part of the
- standard library, but its name lives on in other ways (such as the name
- of the mailing list used to coordinate Python packaging standards
- development).
-* `setuptools`_ is a (largely) drop-in replacement for ``distutils`` first
- published in 2004. Its most notable addition over the unmodified
- ``distutils`` tools was the ability to declare dependencies on other
- packages. It is currently recommended as a more regularly updated
- alternative to ``distutils`` that offers consistent support for more
- recent packaging standards across a wide range of Python versions.
-* `wheel`_ (in this context) is a project that adds the ``bdist_wheel``
- command to ``distutils``/`setuptools`_. This produces a cross platform
- binary packaging format (called "wheels" or "wheel files" and defined in
- :pep:`427`) that allows Python libraries, even those including binary
- extensions, to be installed on a system without needing to be built
- locally.
-
-.. _setuptools: https://setuptools.readthedocs.io/en/latest/
-.. _wheel: https://wheel.readthedocs.io/
-
-Open source licensing and collaboration
-=======================================
-
-In most parts of the world, software is automatically covered by copyright.
-This means that other developers require explicit permission to copy, use,
-modify and redistribute the software.
-
-Open source licensing is a way of explicitly granting such permission in a
-relatively consistent way, allowing developers to share and collaborate
-efficiently by making common solutions to various problems freely available.
-This leaves many developers free to spend more time focusing on the problems
-that are relatively unique to their specific situation.
-
-The distribution tools provided with Python are designed to make it
-reasonably straightforward for developers to make their own contributions
-back to that common pool of software if they choose to do so.
-
-The same distribution tools can also be used to distribute software within
-an organisation, regardless of whether that software is published as open
-source software or not.
-
-
-Installing the tools
-====================
-
-The standard library does not include build tools that support modern
-Python packaging standards, as the core development team has found that it
-is important to have standard tools that work consistently, even on older
-versions of Python.
-
-The currently recommended build and distribution tools can be installed
-by invoking the ``pip`` module at the command line::
-
- python -m pip install setuptools wheel twine
-
-.. note::
-
- For POSIX users (including macOS and Linux users), these instructions
- assume the use of a :term:`virtual environment`.
-
- For Windows users, these instructions assume that the option to
- adjust the system PATH environment variable was selected when installing
- Python.
-
-The Python Packaging User Guide includes more details on the `currently
-recommended tools`_.
-
-.. _currently recommended tools: https://packaging.python.org/guides/tool-recommendations/#packaging-tool-recommendations
-
-.. index::
- single: Python Package Index (PyPI)
- single: PyPI; (see Python Package Index (PyPI))
-
-.. _publishing-python-packages:
-
-Reading the Python Packaging User Guide
-=======================================
-
-The Python Packaging User Guide covers the various key steps and elements
-involved in creating and publishing a project:
-
-* `Project structure`_
-* `Building and packaging the project`_
-* `Uploading the project to the Python Package Index`_
-* `The .pypirc file`_
-
-.. _Project structure: https://packaging.python.org/tutorials/packaging-projects/#packaging-python-projects
-.. _Building and packaging the project: https://packaging.python.org/tutorials/packaging-projects/#creating-the-package-files
-.. _Uploading the project to the Python Package Index: https://packaging.python.org/tutorials/packaging-projects/#uploading-the-distribution-archives
-.. _The .pypirc file: https://packaging.python.org/specifications/pypirc/
-
-
-How do I...?
-============
-
-These are quick answers or links for some common tasks.
-
-... choose a name for my project?
----------------------------------
-
-This isn't an easy topic, but here are a few tips:
-
-* check the Python Package Index to see if the name is already in use
-* check popular hosting sites like GitHub, Bitbucket, etc to see if there
- is already a project with that name
-* check what comes up in a web search for the name you're considering
-* avoid particularly common words, especially ones with multiple meanings,
- as they can make it difficult for users to find your software when
- searching for it
-
-
-... create and distribute binary extensions?
---------------------------------------------
-
-This is actually quite a complex topic, with a variety of alternatives
-available depending on exactly what you're aiming to achieve. See the
-Python Packaging User Guide for more information and recommendations.
-
-.. seealso::
-
- `Python Packaging User Guide: Binary Extensions
- `__
-
-.. other topics:
+ Information and guidance on distributing Python modules and packages
+ has been moved to the `Python Packaging User Guide`_,
+ and the tutorial on `packaging Python projects`_.
- Once the Development & Deployment part of PPUG is fleshed out, some of
- those sections should be linked from new questions here (most notably,
- we should have a question about avoiding depending on PyPI that links to
- https://packaging.python.org/en/latest/mirrors/)
+ .. _Python Packaging User Guide: https://packaging.python.org/
+ .. _packaging Python projects: https://packaging.python.org/en/latest/tutorials/packaging-projects/
diff --git a/Doc/extending/building.rst b/Doc/extending/building.rst
index 880bb33ee56718..ddde567f6f3efa 100644
--- a/Doc/extending/building.rst
+++ b/Doc/extending/building.rst
@@ -45,6 +45,7 @@ See the *"Multiple modules in one library"* section in :pep:`489` for details.
.. highlight:: c
+.. _install-index:
.. _setuptools-index:
Building C and C++ Extensions with setuptools
diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst
index f58b4f28113e8c..1ee7f28b2ba220 100644
--- a/Doc/extending/extending.rst
+++ b/Doc/extending/extending.rst
@@ -242,7 +242,7 @@ needed to ensure that it will not be discarded, causing :c:data:`!SpamError` to
become a dangling pointer. Should it become a dangling pointer, C code which
raises the exception could cause a core dump or other unintended side effects.
-We discuss the use of ``PyMODINIT_FUNC`` as a function return type later in this
+We discuss the use of :c:macro:`PyMODINIT_FUNC` as a function return type later in this
sample.
The :exc:`!spam.error` exception can be raised in your extension module using a
@@ -363,7 +363,7 @@ only non-\ ``static`` item defined in the module file::
return PyModule_Create(&spammodule);
}
-Note that PyMODINIT_FUNC declares the function as ``PyObject *`` return type,
+Note that :c:macro:`PyMODINIT_FUNC` declares the function as ``PyObject *`` return type,
declares any special linkage declarations required by the platform, and for C++
declares the function as ``extern "C"``.
diff --git a/Doc/includes/typestruct.h b/Doc/includes/typestruct.h
index f0ad1e47cb0d86..ec939c28831c33 100644
--- a/Doc/includes/typestruct.h
+++ b/Doc/includes/typestruct.h
@@ -82,5 +82,5 @@ typedef struct _typeobject {
vectorcallfunc tp_vectorcall;
/* bitset of which type-watchers care about this type */
- char tp_watched;
+ unsigned char tp_watched;
} PyTypeObject;
diff --git a/Doc/install/index.rst b/Doc/install/index.rst
deleted file mode 100644
index ffb4a202fe89f2..00000000000000
--- a/Doc/install/index.rst
+++ /dev/null
@@ -1,1081 +0,0 @@
-.. highlight:: none
-
-.. _install-index:
-
-********************************************
- Installing Python Modules (Legacy version)
-********************************************
-
-:Author: Greg Ward
-
-.. TODO: Fill in XXX comments
-
-.. note::
-
- The entire ``distutils`` package has been deprecated and will be
- removed in Python 3.12. This documentation is retained as a
- reference only, and will be removed with the package. See the
- :ref:`What's New ` entry for more information.
-
-.. seealso::
-
- :ref:`installing-index`
- The up to date module installation documentation. For regular Python
- usage, you almost certainly want that document rather than this one.
-
-.. note::
-
- This document is being retained solely until the ``setuptools`` documentation
- at https://setuptools.readthedocs.io/en/latest/setuptools.html
- independently covers all of the relevant information currently included here.
-
-.. note::
-
- This guide only covers the basic tools for building and distributing
- extensions that are provided as part of this version of Python. Third party
- tools offer easier to use and more secure alternatives. Refer to the `quick
- recommendations section `__
- in the Python Packaging User Guide for more information.
-
-
-.. _inst-intro:
-
-
-Introduction
-============
-
-In Python 2.0, the ``distutils`` API was first added to the standard library.
-This provided Linux distro maintainers with a standard way of converting
-Python projects into Linux distro packages, and system administrators with a
-standard way of installing them directly onto target systems.
-
-In the many years since Python 2.0 was released, tightly coupling the build
-system and package installer to the language runtime release cycle has turned
-out to be problematic, and it is now recommended that projects use the
-``pip`` package installer and the ``setuptools`` build system, rather than
-using ``distutils`` directly.
-
-See :ref:`installing-index` and :ref:`distributing-index` for more details.
-
-This legacy documentation is being retained only until we're confident that the
-``setuptools`` documentation covers everything needed.
-
-.. _inst-new-standard:
-
-Distutils based source distributions
-------------------------------------
-
-If you download a module source distribution, you can tell pretty quickly if it
-was packaged and distributed in the standard way, i.e. using the Distutils.
-First, the distribution's name and version number will be featured prominently
-in the name of the downloaded archive, e.g. :file:`foo-1.0.tar.gz` or
-:file:`widget-0.9.7.zip`. Next, the archive will unpack into a similarly named
-directory: :file:`foo-1.0` or :file:`widget-0.9.7`. Additionally, the
-distribution will contain a setup script :file:`setup.py`, and a file named
-:file:`README.txt` or possibly just :file:`README`, which should explain that
-building and installing the module distribution is a simple matter of running
-one command from a terminal::
-
- python setup.py install
-
-For Windows, this command should be run from a command prompt window
-(:menuselection:`Start --> Accessories`)::
-
- setup.py install
-
-If all these things are true, then you already know how to build and install the
-modules you've just downloaded: Run the command above. Unless you need to
-install things in a non-standard way or customize the build process, you don't
-really need this manual. Or rather, the above command is everything you need to
-get out of this manual.
-
-
-.. _inst-standard-install:
-
-Standard Build and Install
-==========================
-
-As described in section :ref:`inst-new-standard`, building and installing a module
-distribution using the Distutils is usually one simple command to run from a
-terminal::
-
- python setup.py install
-
-
-.. _inst-platform-variations:
-
-Platform variations
--------------------
-
-You should always run the setup command from the distribution root directory,
-i.e. the top-level subdirectory that the module source distribution unpacks
-into. For example, if you've just downloaded a module source distribution
-:file:`foo-1.0.tar.gz` onto a Unix system, the normal thing to do is::
-
- gunzip -c foo-1.0.tar.gz | tar xf - # unpacks into directory foo-1.0
- cd foo-1.0
- python setup.py install
-
-On Windows, you'd probably download :file:`foo-1.0.zip`. If you downloaded the
-archive file to :file:`C:\\Temp`, then it would unpack into
-:file:`C:\\Temp\\foo-1.0`; you can use either an archive manipulator with a
-graphical user interface (such as WinZip) or a command-line tool (such as
-:program:`unzip` or :program:`pkunzip`) to unpack the archive. Then, open a
-command prompt window and run::
-
- cd c:\Temp\foo-1.0
- python setup.py install
-
-
-.. _inst-splitting-up:
-
-Splitting the job up
---------------------
-
-Running ``setup.py install`` builds and installs all modules in one run. If you
-prefer to work incrementally---especially useful if you want to customize the
-build process, or if things are going wrong---you can use the setup script to do
-one thing at a time. This is particularly helpful when the build and install
-will be done by different users---for example, you might want to build a module
-distribution and hand it off to a system administrator for installation (or do
-it yourself, with super-user privileges).
-
-For example, you can build everything in one step, and then install everything
-in a second step, by invoking the setup script twice::
-
- python setup.py build
- python setup.py install
-
-If you do this, you will notice that running the :command:`install` command
-first runs the :command:`build` command, which---in this case---quickly notices
-that it has nothing to do, since everything in the :file:`build` directory is
-up-to-date.
-
-You may not need this ability to break things down often if all you do is
-install modules downloaded off the 'net, but it's very handy for more advanced
-tasks. If you get into distributing your own Python modules and extensions,
-you'll run lots of individual Distutils commands on their own.
-
-
-.. _inst-how-build-works:
-
-How building works
-------------------
-
-As implied above, the :command:`build` command is responsible for putting the
-files to install into a *build directory*. By default, this is :file:`build`
-under the distribution root; if you're excessively concerned with speed, or want
-to keep the source tree pristine, you can change the build directory with the
-:option:`!--build-base` option. For example::
-
- python setup.py build --build-base=/path/to/pybuild/foo-1.0
-
-(Or you could do this permanently with a directive in your system or personal
-Distutils configuration file; see section :ref:`inst-config-files`.) Normally, this
-isn't necessary.
-
-The default layout for the build tree is as follows::
-
- --- build/ --- lib/
- or
- --- build/ --- lib./
- temp./
-
-where ```` expands to a brief description of the current OS/hardware
-platform and Python version. The first form, with just a :file:`lib` directory,
-is used for "pure module distributions"---that is, module distributions that
-include only pure Python modules. If a module distribution contains any
-extensions (modules written in C/C++), then the second form, with two ````
-directories, is used. In that case, the :file:`temp.{plat}` directory holds
-temporary files generated by the compile/link process that don't actually get
-installed. In either case, the :file:`lib` (or :file:`lib.{plat}`) directory
-contains all Python modules (pure Python and extensions) that will be installed.
-
-In the future, more directories will be added to handle Python scripts,
-documentation, binary executables, and whatever else is needed to handle the job
-of installing Python modules and applications.
-
-
-.. _inst-how-install-works:
-
-How installation works
-----------------------
-
-After the :command:`build` command runs (whether you run it explicitly, or the
-:command:`install` command does it for you), the work of the :command:`install`
-command is relatively simple: all it has to do is copy everything under
-:file:`build/lib` (or :file:`build/lib.{plat}`) to your chosen installation
-directory.
-
-If you don't choose an installation directory---i.e., if you just run ``setup.py
-install``\ ---then the :command:`install` command installs to the standard
-location for third-party Python modules. This location varies by platform and
-by how you built/installed Python itself. On Unix (and macOS, which is also
-Unix-based), it also depends on whether the module distribution being installed
-is pure Python or contains extensions ("non-pure"):
-
-.. tabularcolumns:: |l|l|l|l|
-
-+-----------------+-----------------------------------------------------+--------------------------------------------------+-------+
-| Platform | Standard installation location | Default value | Notes |
-+=================+=====================================================+==================================================+=======+
-| Unix (pure) | :file:`{prefix}/lib/python{X.Y}/site-packages` | :file:`/usr/local/lib/python{X.Y}/site-packages` | \(1) |
-+-----------------+-----------------------------------------------------+--------------------------------------------------+-------+
-| Unix (non-pure) | :file:`{exec-prefix}/lib/python{X.Y}/site-packages` | :file:`/usr/local/lib/python{X.Y}/site-packages` | \(1) |
-+-----------------+-----------------------------------------------------+--------------------------------------------------+-------+
-| Windows | :file:`{prefix}\\Lib\\site-packages` | :file:`C:\\Python{XY}\\Lib\\site-packages` | \(2) |
-+-----------------+-----------------------------------------------------+--------------------------------------------------+-------+
-
-Notes:
-
-(1)
- Most Linux distributions include Python as a standard part of the system, so
- :file:`{prefix}` and :file:`{exec-prefix}` are usually both :file:`/usr` on
- Linux. If you build Python yourself on Linux (or any Unix-like system), the
- default :file:`{prefix}` and :file:`{exec-prefix}` are :file:`/usr/local`.
-
-(2)
- The default installation directory on Windows was :file:`C:\\Program
- Files\\Python` under Python 1.6a1, 1.5.2, and earlier.
-
-:file:`{prefix}` and :file:`{exec-prefix}` stand for the directories that Python
-is installed to, and where it finds its libraries at run-time. They are always
-the same under Windows, and very often the same under Unix and macOS. You
-can find out what your Python installation uses for :file:`{prefix}` and
-:file:`{exec-prefix}` by running Python in interactive mode and typing a few
-simple commands. Under Unix, just type ``python`` at the shell prompt. Under
-Windows, choose :menuselection:`Start --> Programs --> Python X.Y -->
-Python (command line)`. Once the interpreter is started, you type Python code
-at the prompt. For example, on my Linux system, I type the three Python
-statements shown below, and get the output as shown, to find out my
-:file:`{prefix}` and :file:`{exec-prefix}`:
-
-.. code-block:: pycon
-
- Python 2.4 (#26, Aug 7 2004, 17:19:02)
- Type "help", "copyright", "credits" or "license" for more information.
- >>> import sys
- >>> sys.prefix
- '/usr'
- >>> sys.exec_prefix
- '/usr'
-
-A few other placeholders are used in this document: :file:`{X.Y}` stands for the
-version of Python, for example ``3.2``; :file:`{abiflags}` will be replaced by
-the value of :data:`sys.abiflags` or the empty string for platforms which don't
-define ABI flags; :file:`{distname}` will be replaced by the name of the module
-distribution being installed. Dots and capitalization are important in the
-paths; for example, a value that uses ``python3.2`` on UNIX will typically use
-``Python32`` on Windows.
-
-If you don't want to install modules to the standard location, or if you don't
-have permission to write there, then you need to read about alternate
-installations in section :ref:`inst-alt-install`. If you want to customize your
-installation directories more heavily, see section :ref:`inst-custom-install` on
-custom installations.
-
-
-.. _inst-alt-install:
-
-Alternate Installation
-======================
-
-Often, it is necessary or desirable to install modules to a location other than
-the standard location for third-party Python modules. For example, on a Unix
-system you might not have permission to write to the standard third-party module
-directory. Or you might wish to try out a module before making it a standard
-part of your local Python installation. This is especially true when upgrading
-a distribution already present: you want to make sure your existing base of
-scripts still works with the new version before actually upgrading.
-
-The Distutils :command:`install` command is designed to make installing module
-distributions to an alternate location simple and painless. The basic idea is
-that you supply a base directory for the installation, and the
-:command:`install` command picks a set of directories (called an *installation
-scheme*) under this base directory in which to install files. The details
-differ across platforms, so read whichever of the following sections applies to
-you.
-
-Note that the various alternate installation schemes are mutually exclusive: you
-can pass ``--user``, or ``--home``, or ``--prefix`` and ``--exec-prefix``, or
-``--install-base`` and ``--install-platbase``, but you can't mix from these
-groups.
-
-
-.. _inst-alt-install-user:
-
-Alternate installation: the user scheme
----------------------------------------
-
-This scheme is designed to be the most convenient solution for users that don't
-have write permission to the global site-packages directory or don't want to
-install into it. It is enabled with a simple option::
-
- python setup.py install --user
-
-Files will be installed into subdirectories of :const:`site.USER_BASE` (written
-as :file:`{userbase}` hereafter). This scheme installs pure Python modules and
-extension modules in the same location (also known as :const:`site.USER_SITE`).
-Here are the values for UNIX, including macOS:
-
-=============== ===========================================================
-Type of file Installation directory
-=============== ===========================================================
-modules :file:`{userbase}/lib/python{X.Y}/site-packages`
-scripts :file:`{userbase}/bin`
-data :file:`{userbase}`
-C headers :file:`{userbase}/include/python{X.Y}{abiflags}/{distname}`
-=============== ===========================================================
-
-And here are the values used on Windows:
-
-=============== ===========================================================
-Type of file Installation directory
-=============== ===========================================================
-modules :file:`{userbase}\\Python{XY}\\site-packages`
-scripts :file:`{userbase}\\Python{XY}\\Scripts`
-data :file:`{userbase}`
-C headers :file:`{userbase}\\Python{XY}\\Include\\{distname}`
-=============== ===========================================================
-
-The advantage of using this scheme compared to the other ones described below is
-that the user site-packages directory is under normal conditions always included
-in :data:`sys.path` (see :mod:`site` for more information), which means that
-there is no additional step to perform after running the :file:`setup.py` script
-to finalize the installation.
-
-The :command:`build_ext` command also has a ``--user`` option to add
-:file:`{userbase}/include` to the compiler search path for header files and
-:file:`{userbase}/lib` to the compiler search path for libraries as well as to
-the runtime search path for shared C libraries (rpath).
-
-
-.. _inst-alt-install-home:
-
-Alternate installation: the home scheme
----------------------------------------
-
-The idea behind the "home scheme" is that you build and maintain a personal
-stash of Python modules. This scheme's name is derived from the idea of a
-"home" directory on Unix, since it's not unusual for a Unix user to make their
-home directory have a layout similar to :file:`/usr/` or :file:`/usr/local/`.
-This scheme can be used by anyone, regardless of the operating system they
-are installing for.
-
-Installing a new module distribution is as simple as ::
-
- python setup.py install --home=
-
-where you can supply any directory you like for the :option:`!--home` option. On
-Unix, lazy typists can just type a tilde (``~``); the :command:`install` command
-will expand this to your home directory::
-
- python setup.py install --home=~
-
-To make Python find the distributions installed with this scheme, you may have
-to :ref:`modify Python's search path ` or edit
-:mod:`!sitecustomize` (see :mod:`site`) to call :func:`site.addsitedir` or edit
-:data:`sys.path`.
-
-The :option:`!--home` option defines the installation base directory. Files are
-installed to the following directories under the installation base as follows:
-
-=============== ===========================================================
-Type of file Installation directory
-=============== ===========================================================
-modules :file:`{home}/lib/python`
-scripts :file:`{home}/bin`
-data :file:`{home}`
-C headers :file:`{home}/include/python/{distname}`
-=============== ===========================================================
-
-(Mentally replace slashes with backslashes if you're on Windows.)
-
-
-.. _inst-alt-install-prefix-unix:
-
-Alternate installation: Unix (the prefix scheme)
-------------------------------------------------
-
-The "prefix scheme" is useful when you wish to use one Python installation to
-perform the build/install (i.e., to run the setup script), but install modules
-into the third-party module directory of a different Python installation (or
-something that looks like a different Python installation). If this sounds a
-trifle unusual, it is---that's why the user and home schemes come before. However,
-there are at least two known cases where the prefix scheme will be useful.
-
-First, consider that many Linux distributions put Python in :file:`/usr`, rather
-than the more traditional :file:`/usr/local`. This is entirely appropriate,
-since in those cases Python is part of "the system" rather than a local add-on.
-However, if you are installing Python modules from source, you probably want
-them to go in :file:`/usr/local/lib/python2.{X}` rather than
-:file:`/usr/lib/python2.{X}`. This can be done with ::
-
- /usr/bin/python setup.py install --prefix=/usr/local
-
-Another possibility is a network filesystem where the name used to write to a
-remote directory is different from the name used to read it: for example, the
-Python interpreter accessed as :file:`/usr/local/bin/python` might search for
-modules in :file:`/usr/local/lib/python2.{X}`, but those modules would have to
-be installed to, say, :file:`/mnt/{@server}/export/lib/python2.{X}`. This could
-be done with ::
-
- /usr/local/bin/python setup.py install --prefix=/mnt/@server/export
-
-In either case, the :option:`!--prefix` option defines the installation base, and
-the :option:`!--exec-prefix` option defines the platform-specific installation
-base, which is used for platform-specific files. (Currently, this just means
-non-pure module distributions, but could be expanded to C libraries, binary
-executables, etc.) If :option:`!--exec-prefix` is not supplied, it defaults to
-:option:`!--prefix`. Files are installed as follows:
-
-================= ==========================================================
-Type of file Installation directory
-================= ==========================================================
-Python modules :file:`{prefix}/lib/python{X.Y}/site-packages`
-extension modules :file:`{exec-prefix}/lib/python{X.Y}/site-packages`
-scripts :file:`{prefix}/bin`
-data :file:`{prefix}`
-C headers :file:`{prefix}/include/python{X.Y}{abiflags}/{distname}`
-================= ==========================================================
-
-There is no requirement that :option:`!--prefix` or :option:`!--exec-prefix`
-actually point to an alternate Python installation; if the directories listed
-above do not already exist, they are created at installation time.
-
-Incidentally, the real reason the prefix scheme is important is simply that a
-standard Unix installation uses the prefix scheme, but with :option:`!--prefix`
-and :option:`!--exec-prefix` supplied by Python itself as ``sys.prefix`` and
-``sys.exec_prefix``. Thus, you might think you'll never use the prefix scheme,
-but every time you run ``python setup.py install`` without any other options,
-you're using it.
-
-Note that installing extensions to an alternate Python installation has no
-effect on how those extensions are built: in particular, the Python header files
-(:file:`Python.h` and friends) installed with the Python interpreter used to run
-the setup script will be used in compiling extensions. It is your
-responsibility to ensure that the interpreter used to run extensions installed
-in this way is compatible with the interpreter used to build them. The best way
-to do this is to ensure that the two interpreters are the same version of Python
-(possibly different builds, or possibly copies of the same build). (Of course,
-if your :option:`!--prefix` and :option:`!--exec-prefix` don't even point to an
-alternate Python installation, this is immaterial.)
-
-
-.. _inst-alt-install-prefix-windows:
-
-Alternate installation: Windows (the prefix scheme)
----------------------------------------------------
-
-Windows has no concept of a user's home directory, and since the standard Python
-installation under Windows is simpler than under Unix, the :option:`!--prefix`
-option has traditionally been used to install additional packages in separate
-locations on Windows. ::
-
- python setup.py install --prefix="\Temp\Python"
-
-to install modules to the :file:`\\Temp\\Python` directory on the current drive.
-
-The installation base is defined by the :option:`!--prefix` option; the
-:option:`!--exec-prefix` option is not supported under Windows, which means that
-pure Python modules and extension modules are installed into the same location.
-Files are installed as follows:
-
-=============== ==========================================================
-Type of file Installation directory
-=============== ==========================================================
-modules :file:`{prefix}\\Lib\\site-packages`
-scripts :file:`{prefix}\\Scripts`
-data :file:`{prefix}`
-C headers :file:`{prefix}\\Include\\{distname}`
-=============== ==========================================================
-
-
-.. _inst-custom-install:
-
-Custom Installation
-===================
-
-Sometimes, the alternate installation schemes described in section
-:ref:`inst-alt-install` just don't do what you want. You might want to tweak just
-one or two directories while keeping everything under the same base directory,
-or you might want to completely redefine the installation scheme. In either
-case, you're creating a *custom installation scheme*.
-
-To create a custom installation scheme, you start with one of the alternate
-schemes and override some of the installation directories used for the various
-types of files, using these options:
-
-====================== =======================
-Type of file Override option
-====================== =======================
-Python modules ``--install-purelib``
-extension modules ``--install-platlib``
-all modules ``--install-lib``
-scripts ``--install-scripts``
-data ``--install-data``
-C headers ``--install-headers``
-====================== =======================
-
-These override options can be relative, absolute,
-or explicitly defined in terms of one of the installation base directories.
-(There are two installation base directories, and they are normally the
-same---they only differ when you use the Unix "prefix scheme" and supply
-different ``--prefix`` and ``--exec-prefix`` options; using ``--install-lib``
-will override values computed or given for ``--install-purelib`` and
-``--install-platlib``, and is recommended for schemes that don't make a
-difference between Python and extension modules.)
-
-For example, say you're installing a module distribution to your home directory
-under Unix---but you want scripts to go in :file:`~/scripts` rather than
-:file:`~/bin`. As you might expect, you can override this directory with the
-:option:`!--install-scripts` option; in this case, it makes most sense to supply
-a relative path, which will be interpreted relative to the installation base
-directory (your home directory, in this case)::
-
- python setup.py install --home=~ --install-scripts=scripts
-
-Another Unix example: suppose your Python installation was built and installed
-with a prefix of :file:`/usr/local/python`, so under a standard installation
-scripts will wind up in :file:`/usr/local/python/bin`. If you want them in
-:file:`/usr/local/bin` instead, you would supply this absolute directory for the
-:option:`!--install-scripts` option::
-
- python setup.py install --install-scripts=/usr/local/bin
-
-(This performs an installation using the "prefix scheme", where the prefix is
-whatever your Python interpreter was installed with--- :file:`/usr/local/python`
-in this case.)
-
-If you maintain Python on Windows, you might want third-party modules to live in
-a subdirectory of :file:`{prefix}`, rather than right in :file:`{prefix}`
-itself. This is almost as easy as customizing the script installation
-directory---you just have to remember that there are two types of modules
-to worry about, Python and extension modules, which can conveniently be both
-controlled by one option::
-
- python setup.py install --install-lib=Site
-
-The specified installation directory is relative to :file:`{prefix}`. Of
-course, you also have to ensure that this directory is in Python's module
-search path, such as by putting a :file:`.pth` file in a site directory (see
-:mod:`site`). See section :ref:`inst-search-path` to find out how to modify
-Python's search path.
-
-If you want to define an entire installation scheme, you just have to supply all
-of the installation directory options. The recommended way to do this is to
-supply relative paths; for example, if you want to maintain all Python
-module-related files under :file:`python` in your home directory, and you want a
-separate directory for each platform that you use your home directory from, you
-might define the following installation scheme::
-
- python setup.py install --home=~ \
- --install-purelib=python/lib \
- --install-platlib=python/lib.$PLAT \
- --install-scripts=python/scripts
- --install-data=python/data
-
-or, equivalently, ::
-
- python setup.py install --home=~/python \
- --install-purelib=lib \
- --install-platlib='lib.$PLAT' \
- --install-scripts=scripts
- --install-data=data
-
-``$PLAT`` is not (necessarily) an environment variable---it will be expanded by
-the Distutils as it parses your command line options, just as it does when
-parsing your configuration file(s).
-
-Obviously, specifying the entire installation scheme every time you install a
-new module distribution would be very tedious. Thus, you can put these options
-into your Distutils config file (see section :ref:`inst-config-files`):
-
-.. code-block:: ini
-
- [install]
- install-base=$HOME
- install-purelib=python/lib
- install-platlib=python/lib.$PLAT
- install-scripts=python/scripts
- install-data=python/data
-
-or, equivalently,
-
-.. code-block:: ini
-
- [install]
- install-base=$HOME/python
- install-purelib=lib
- install-platlib=lib.$PLAT
- install-scripts=scripts
- install-data=data
-
-Note that these two are *not* equivalent if you supply a different installation
-base directory when you run the setup script. For example, ::
-
- python setup.py install --install-base=/tmp
-
-would install pure modules to :file:`/tmp/python/lib` in the first case, and
-to :file:`/tmp/lib` in the second case. (For the second case, you probably
-want to supply an installation base of :file:`/tmp/python`.)
-
-You probably noticed the use of ``$HOME`` and ``$PLAT`` in the sample
-configuration file input. These are Distutils configuration variables, which
-bear a strong resemblance to environment variables. In fact, you can use
-environment variables in config files on platforms that have such a notion but
-the Distutils additionally define a few extra variables that may not be in your
-environment, such as ``$PLAT``. (And of course, on systems that don't have
-environment variables, such as Mac OS 9, the configuration variables supplied by
-the Distutils are the only ones you can use.) See section :ref:`inst-config-files`
-for details.
-
-.. note:: When a :ref:`virtual environment ` is activated, any options
- that change the installation path will be ignored from all distutils configuration
- files to prevent inadvertently installing projects outside of the virtual
- environment.
-
-.. XXX need some Windows examples---when would custom installation schemes be
- needed on those platforms?
-
-
-.. XXX Move this to Doc/using
-
-.. _inst-search-path:
-
-Modifying Python's Search Path
-------------------------------
-
-When the Python interpreter executes an :keyword:`import` statement, it searches
-for both Python code and extension modules along a search path. A default value
-for the path is configured into the Python binary when the interpreter is built.
-You can determine the path by importing the :mod:`sys` module and printing the
-value of ``sys.path``. ::
-
- $ python
- Python 2.2 (#11, Oct 3 2002, 13:31:27)
- [GCC 2.96 20000731 (Red Hat Linux 7.3 2.96-112)] on linux2
- Type "help", "copyright", "credits" or "license" for more information.
- >>> import sys
- >>> sys.path
- ['', '/usr/local/lib/python2.3', '/usr/local/lib/python2.3/plat-linux2',
- '/usr/local/lib/python2.3/lib-tk', '/usr/local/lib/python2.3/lib-dynload',
- '/usr/local/lib/python2.3/site-packages']
- >>>
-
-The null string in ``sys.path`` represents the current working directory.
-
-The expected convention for locally installed packages is to put them in the
-:file:`{...}/site-packages/` directory, but you may want to install Python
-modules into some arbitrary directory. For example, your site may have a
-convention of keeping all software related to the web server under :file:`/www`.
-Add-on Python modules might then belong in :file:`/www/python`, and in order to
-import them, this directory must be added to ``sys.path``. There are several
-different ways to add the directory.
-
-The most convenient way is to add a path configuration file to a directory
-that's already on Python's path, usually to the :file:`.../site-packages/`
-directory. Path configuration files have an extension of :file:`.pth`, and each
-line must contain a single path that will be appended to ``sys.path``. (Because
-the new paths are appended to ``sys.path``, modules in the added directories
-will not override standard modules. This means you can't use this mechanism for
-installing fixed versions of standard modules.)
-
-Paths can be absolute or relative, in which case they're relative to the
-directory containing the :file:`.pth` file. See the documentation of
-the :mod:`site` module for more information.
-
-A slightly less convenient way is to edit the :file:`site.py` file in Python's
-standard library, and modify ``sys.path``. :file:`site.py` is automatically
-imported when the Python interpreter is executed, unless the :option:`-S` switch
-is supplied to suppress this behaviour. So you could simply edit
-:file:`site.py` and add two lines to it:
-
-.. code-block:: python
-
- import sys
- sys.path.append('/www/python/')
-
-However, if you reinstall the same minor version of Python (perhaps when
-upgrading from 2.2 to 2.2.2, for example) :file:`site.py` will be overwritten by
-the stock version. You'd have to remember that it was modified and save a copy
-before doing the installation.
-
-There are two environment variables that can modify ``sys.path``.
-:envvar:`PYTHONHOME` sets an alternate value for the prefix of the Python
-installation. For example, if :envvar:`PYTHONHOME` is set to ``/www/python``,
-the search path will be set to ``['', '/www/python/lib/pythonX.Y/',
-'/www/python/lib/pythonX.Y/plat-linux2', ...]``.
-
-The :envvar:`PYTHONPATH` variable can be set to a list of paths that will be
-added to the beginning of ``sys.path``. For example, if :envvar:`PYTHONPATH` is
-set to ``/www/python:/opt/py``, the search path will begin with
-``['/www/python', '/opt/py']``. (Note that directories must exist in order to
-be added to ``sys.path``; the :mod:`site` module removes paths that don't
-exist.)
-
-Finally, ``sys.path`` is just a regular Python list, so any Python application
-can modify it by adding or removing entries.
-
-
-.. _inst-config-files:
-
-Distutils Configuration Files
-=============================
-
-As mentioned above, you can use Distutils configuration files to record personal
-or site preferences for any Distutils options. That is, any option to any
-command can be stored in one of two or three (depending on your platform)
-configuration files, which will be consulted before the command-line is parsed.
-This means that configuration files will override default values, and the
-command-line will in turn override configuration files. Furthermore, if
-multiple configuration files apply, values from "earlier" files are overridden
-by "later" files.
-
-
-.. _inst-config-filenames:
-
-Location and names of config files
-----------------------------------
-
-The names and locations of the configuration files vary slightly across
-platforms. On Unix and macOS, the three configuration files (in the order
-they are processed) are:
-
-+--------------+----------------------------------------------------------+-------+
-| Type of file | Location and filename | Notes |
-+==============+==========================================================+=======+
-| system | :file:`{prefix}/lib/python{ver}/distutils/distutils.cfg` | \(1) |
-+--------------+----------------------------------------------------------+-------+
-| personal | :file:`$HOME/.pydistutils.cfg` | \(2) |
-+--------------+----------------------------------------------------------+-------+
-| local | :file:`setup.cfg` | \(3) |
-+--------------+----------------------------------------------------------+-------+
-
-And on Windows, the configuration files are:
-
-+--------------+-------------------------------------------------+-------+
-| Type of file | Location and filename | Notes |
-+==============+=================================================+=======+
-| system | :file:`{prefix}\\Lib\\distutils\\distutils.cfg` | \(4) |
-+--------------+-------------------------------------------------+-------+
-| personal | :file:`%HOME%\\pydistutils.cfg` | \(5) |
-+--------------+-------------------------------------------------+-------+
-| local | :file:`setup.cfg` | \(3) |
-+--------------+-------------------------------------------------+-------+
-
-On all platforms, the "personal" file can be temporarily disabled by
-passing the ``--no-user-cfg`` option.
-
-Notes:
-
-(1)
- Strictly speaking, the system-wide configuration file lives in the directory
- where the Distutils are installed; under Python 1.6 and later on Unix, this is
- as shown. For Python 1.5.2, the Distutils will normally be installed to
- :file:`{prefix}/lib/python1.5/site-packages/distutils`, so the system
- configuration file should be put there under Python 1.5.2.
-
-(2)
- On Unix, if the :envvar:`HOME` environment variable is not defined, the user's
- home directory will be determined with the :func:`~pwd.getpwuid` function from the
- standard :mod:`pwd` module. This is done by the :func:`os.path.expanduser`
- function used by Distutils.
-
-(3)
- I.e., in the current directory (usually the location of the setup script).
-
-(4)
- (See also note (1).) Under Python 1.6 and later, Python's default "installation
- prefix" is :file:`C:\\Python`, so the system configuration file is normally
- :file:`C:\\Python\\Lib\\distutils\\distutils.cfg`. Under Python 1.5.2, the
- default prefix was :file:`C:\\Program Files\\Python`, and the Distutils were not
- part of the standard library---so the system configuration file would be
- :file:`C:\\Program Files\\Python\\distutils\\distutils.cfg` in a standard Python
- 1.5.2 installation under Windows.
-
-(5)
- On Windows, if the :envvar:`HOME` environment variable is not defined,
- :envvar:`USERPROFILE` then :envvar:`HOMEDRIVE` and :envvar:`HOMEPATH` will
- be tried. This is done by the :func:`os.path.expanduser` function used
- by Distutils.
-
-
-.. _inst-config-syntax:
-
-Syntax of config files
-----------------------
-
-The Distutils configuration files all have the same syntax. The config files
-are grouped into sections. There is one section for each Distutils command,
-plus a ``global`` section for global options that affect every command. Each
-section consists of one option per line, specified as ``option=value``.
-
-For example, the following is a complete config file that just forces all
-commands to run quietly by default:
-
-.. code-block:: ini
-
- [global]
- verbose=0
-
-If this is installed as the system config file, it will affect all processing of
-any Python module distribution by any user on the current system. If it is
-installed as your personal config file (on systems that support them), it will
-affect only module distributions processed by you. And if it is used as the
-:file:`setup.cfg` for a particular module distribution, it affects only that
-distribution.
-
-You could override the default "build base" directory and make the
-:command:`build\*` commands always forcibly rebuild all files with the
-following:
-
-.. code-block:: ini
-
- [build]
- build-base=blib
- force=1
-
-which corresponds to the command-line arguments ::
-
- python setup.py build --build-base=blib --force
-
-except that including the :command:`build` command on the command-line means
-that command will be run. Including a particular command in config files has no
-such implication; it only means that if the command is run, the options in the
-config file will apply. (Or if other commands that derive values from it are
-run, they will use the values in the config file.)
-
-You can find out the complete list of options for any command using the
-:option:`!--help` option, e.g.::
-
- python setup.py build --help
-
-and you can find out the complete list of global options by using
-:option:`!--help` without a command::
-
- python setup.py --help
-
-See also the "Reference" section of the "Distributing Python Modules" manual.
-
-
-.. _inst-building-ext:
-
-Building Extensions: Tips and Tricks
-====================================
-
-Whenever possible, the Distutils try to use the configuration information made
-available by the Python interpreter used to run the :file:`setup.py` script.
-For example, the same compiler and linker flags used to compile Python will also
-be used for compiling extensions. Usually this will work well, but in
-complicated situations this might be inappropriate. This section discusses how
-to override the usual Distutils behaviour.
-
-
-.. _inst-tweak-flags:
-
-Tweaking compiler/linker flags
-------------------------------
-
-Compiling a Python extension written in C or C++ will sometimes require
-specifying custom flags for the compiler and linker in order to use a particular
-library or produce a special kind of object code. This is especially true if the
-extension hasn't been tested on your platform, or if you're trying to
-cross-compile Python.
-
-In the most general case, the extension author might have foreseen that
-compiling the extensions would be complicated, and provided a :file:`Setup` file
-for you to edit. This will likely only be done if the module distribution
-contains many separate extension modules, or if they often require elaborate
-sets of compiler flags in order to work.
-
-A :file:`Setup` file, if present, is parsed in order to get a list of extensions
-to build. Each line in a :file:`Setup` describes a single module. Lines have
-the following structure::
-
- module ... [sourcefile ...] [cpparg ...] [library ...]
-
-
-Let's examine each of the fields in turn.
-
-* *module* is the name of the extension module to be built, and should be a
- valid Python identifier. You can't just change this in order to rename a module
- (edits to the source code would also be needed), so this should be left alone.
-
-* *sourcefile* is anything that's likely to be a source code file, at least
- judging by the filename. Filenames ending in :file:`.c` are assumed to be
- written in C, filenames ending in :file:`.C`, :file:`.cc`, and :file:`.c++` are
- assumed to be C++, and filenames ending in :file:`.m` or :file:`.mm` are assumed
- to be in Objective C.
-
-* *cpparg* is an argument for the C preprocessor, and is anything starting with
- :option:`!-I`, :option:`!-D`, :option:`!-U` or :option:`!-C`.
-
-* *library* is anything ending in :file:`.a` or beginning with :option:`!-l` or
- :option:`!-L`.
-
-If a particular platform requires a special library on your platform, you can
-add it by editing the :file:`Setup` file and running ``python setup.py build``.
-For example, if the module defined by the line ::
-
- foo foomodule.c
-
-must be linked with the math library :file:`libm.a` on your platform, simply add
-:option:`!-lm` to the line::
-
- foo foomodule.c -lm
-
-Arbitrary switches intended for the compiler or the linker can be supplied with
-the :option:`!-Xcompiler` *arg* and :option:`!-Xlinker` *arg* options::
-
- foo foomodule.c -Xcompiler -o32 -Xlinker -shared -lm
-
-The next option after :option:`!-Xcompiler` and :option:`!-Xlinker` will be
-appended to the proper command line, so in the above example the compiler will
-be passed the :option:`!-o32` option, and the linker will be passed
-:option:`!-shared`. If a compiler option requires an argument, you'll have to
-supply multiple :option:`!-Xcompiler` options; for example, to pass ``-x c++``
-the :file:`Setup` file would have to contain ``-Xcompiler -x -Xcompiler c++``.
-
-Compiler flags can also be supplied through setting the :envvar:`CFLAGS`
-environment variable. If set, the contents of :envvar:`CFLAGS` will be added to
-the compiler flags specified in the :file:`Setup` file.
-
-
-.. _inst-non-ms-compilers:
-
-Using non-Microsoft compilers on Windows
-----------------------------------------
-
-.. sectionauthor:: Rene Liebscher
-
-
-
-Borland/CodeGear C++
-^^^^^^^^^^^^^^^^^^^^
-
-This subsection describes the necessary steps to use Distutils with the Borland
-C++ compiler version 5.5. First you have to know that Borland's object file
-format (OMF) is different from the format used by the Python version you can
-download from the Python or ActiveState web site. (Python is built with
-Microsoft Visual C++, which uses COFF as the object file format.) For this
-reason you have to convert Python's library :file:`python25.lib` into the
-Borland format. You can do this as follows:
-
-.. Should we mention that users have to create cfg-files for the compiler?
-.. see also http://community.borland.com/article/0,1410,21205,00.html
-
-::
-
- coff2omf python25.lib python25_bcpp.lib
-
-The :file:`coff2omf` program comes with the Borland compiler. The file
-:file:`python25.lib` is in the :file:`Libs` directory of your Python
-installation. If your extension uses other libraries (zlib, ...) you have to
-convert them too.
-
-The converted files have to reside in the same directories as the normal
-libraries.
-
-How does Distutils manage to use these libraries with their changed names? If
-the extension needs a library (eg. :file:`foo`) Distutils checks first if it
-finds a library with suffix :file:`_bcpp` (eg. :file:`foo_bcpp.lib`) and then
-uses this library. In the case it doesn't find such a special library it uses
-the default name (:file:`foo.lib`.) [#]_
-
-To let Distutils compile your extension with Borland C++ you now have to type::
-
- python setup.py build --compiler=bcpp
-
-If you want to use the Borland C++ compiler as the default, you could specify
-this in your personal or system-wide configuration file for Distutils (see
-section :ref:`inst-config-files`.)
-
-
-.. seealso::
-
- `C++Builder Compiler `_
- Information about the free C++ compiler from Borland, including links to the
- download pages.
-
- `Creating Python Extensions Using Borland's Free Compiler `_
- Document describing how to use Borland's free command-line C++ compiler to build
- Python.
-
-
-GNU C / Cygwin / MinGW
-^^^^^^^^^^^^^^^^^^^^^^
-
-This section describes the necessary steps to use Distutils with the GNU C/C++
-compilers in their Cygwin and MinGW distributions. [#]_ For a Python interpreter
-that was built with Cygwin, everything should work without any of these
-following steps.
-
-Not all extensions can be built with MinGW or Cygwin, but many can. Extensions
-most likely to not work are those that use C++ or depend on Microsoft Visual C
-extensions.
-
-To let Distutils compile your extension with Cygwin you have to type::
-
- python setup.py build --compiler=cygwin
-
-and for Cygwin in no-cygwin mode [#]_ or for MinGW type::
-
- python setup.py build --compiler=mingw32
-
-If you want to use any of these options/compilers as default, you should
-consider writing it in your personal or system-wide configuration file for
-Distutils (see section :ref:`inst-config-files`.)
-
-Older Versions of Python and MinGW
-""""""""""""""""""""""""""""""""""
-The following instructions only apply if you're using a version of Python
-inferior to 2.4.1 with a MinGW inferior to 3.0.0 (with
-binutils-2.13.90-20030111-1).
-
-These compilers require some special libraries. This task is more complex than
-for Borland's C++, because there is no program to convert the library. First
-you have to create a list of symbols which the Python DLL exports. (You can find
-a good program for this task at
-https://sourceforge.net/projects/mingw/files/MinGW/Extension/pexports/).
-
-.. I don't understand what the next line means. --amk
-.. (inclusive the references on data structures.)
-
-::
-
- pexports python25.dll >python25.def
-
-The location of an installed :file:`python25.dll` will depend on the
-installation options and the version and language of Windows. In a "just for
-me" installation, it will appear in the root of the installation directory. In
-a shared installation, it will be located in the system directory.
-
-Then you can create from these information an import library for gcc. ::
-
- /cygwin/bin/dlltool --dllname python25.dll --def python25.def --output-lib libpython25.a
-
-The resulting library has to be placed in the same directory as
-:file:`python25.lib`. (Should be the :file:`libs` directory under your Python
-installation directory.)
-
-If your extension uses other libraries (zlib,...) you might have to convert
-them too. The converted files have to reside in the same directories as the
-normal libraries do.
-
-
-.. seealso::
-
- `Building Python modules on MS Windows platform with MinGW `_
- Information about building the required libraries for the MinGW environment.
-
-
-.. rubric:: Footnotes
-
-.. [#] This also means you could replace all existing COFF-libraries with OMF-libraries
- of the same name.
-
-.. [#] Check https://www.sourceware.org/cygwin/ for more information
-
-.. [#] Then you have no POSIX emulation available, but you also don't need
- :file:`cygwin1.dll`.
diff --git a/Doc/installing/index.rst b/Doc/installing/index.rst
index 5aec5178d48f3d..a46c1caefe4d8a 100644
--- a/Doc/installing/index.rst
+++ b/Doc/installing/index.rst
@@ -19,7 +19,9 @@ solutions to the common pool.
This guide covers the installation part of the process. For a guide to
creating and sharing your own Python projects, refer to the
-:ref:`distribution guide `.
+`Python packaging user guide`_.
+
+.. _Python Packaging User Guide: https://packaging.python.org/en/latest/tutorials/packaging-projects/
.. note::
diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst
index bb46782c06e1c8..b8b231bb15b1b0 100644
--- a/Doc/library/collections.rst
+++ b/Doc/library/collections.rst
@@ -1224,7 +1224,7 @@ variants of :func:`functools.lru_cache`:
result = self.func(*args)
self.cache[args] = time(), result
if len(self.cache) > self.maxsize:
- self.cache.popitem(0)
+ self.cache.popitem(last=False)
return result
@@ -1256,12 +1256,12 @@ variants of :func:`functools.lru_cache`:
if self.requests[args] <= self.cache_after:
self.requests.move_to_end(args)
if len(self.requests) > self.maxrequests:
- self.requests.popitem(0)
+ self.requests.popitem(last=False)
else:
self.requests.pop(args, None)
self.cache[args] = result
if len(self.cache) > self.maxsize:
- self.cache.popitem(0)
+ self.cache.popitem(last=False)
return result
.. doctest::
diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst
index 2217c3a8035459..0b44d160de58a7 100644
--- a/Doc/library/dis.rst
+++ b/Doc/library/dis.rst
@@ -56,7 +56,7 @@ the following command can be used to display the disassembly of
>>> dis.dis(myfunc)
2 0 RESUME 0
- 3 2 LOAD_GLOBAL 1 (NULL + len)
+ 3 2 LOAD_GLOBAL 1 (len + NULL)
12 LOAD_FAST 0 (alist)
14 CALL 1
22 RETURN_VALUE
diff --git a/Doc/library/kde_example.png b/Doc/library/kde_example.png
new file mode 100644
index 00000000000000..f4504895699974
Binary files /dev/null and b/Doc/library/kde_example.png differ
diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst
index 4c6e74ff66a11a..49e870e9e2479b 100644
--- a/Doc/library/logging.rst
+++ b/Doc/library/logging.rst
@@ -397,21 +397,39 @@ have specific values relative to the predefined levels. If you define a level
with the same numeric value, it overwrites the predefined value; the predefined
name is lost.
-+-----------------------+---------------+
-| Level | Numeric value |
-+=======================+===============+
-| .. py:data:: CRITICAL | 50 |
-+-----------------------+---------------+
-| .. py:data:: ERROR | 40 |
-+-----------------------+---------------+
-| .. py:data:: WARNING | 30 |
-+-----------------------+---------------+
-| .. py:data:: INFO | 20 |
-+-----------------------+---------------+
-| .. py:data:: DEBUG | 10 |
-+-----------------------+---------------+
-| .. py:data:: NOTSET | 0 |
-+-----------------------+---------------+
++-----------------------+---------------+-------------------------------------+
+| Level | Numeric value | What it means / When to use it |
++=======================+===============+=====================================+
+| .. py:data:: NOTSET | 0 | When set on a logger, indicates that|
+| | | ancestor loggers are to be consulted|
+| | | to determine the effective level. |
+| | | If that still resolves to |
+| | | :const:`!NOTSET`, then all events |
+| | | are logged. When set on a handler, |
+| | | all events are handled. |
++-----------------------+---------------+-------------------------------------+
+| .. py:data:: DEBUG | 10 | Detailed information, typically only|
+| | | of interest to a developer trying to|
+| | | diagnose a problem. |
++-----------------------+---------------+-------------------------------------+
+| .. py:data:: INFO | 20 | Confirmation that things are working|
+| | | as expected. |
++-----------------------+---------------+-------------------------------------+
+| .. py:data:: WARNING | 30 | An indication that something |
+| | | unexpected happened, or that a |
+| | | problem might occur in the near |
+| | | future (e.g. 'disk space low'). The |
+| | | software is still working as |
+| | | expected. |
++-----------------------+---------------+-------------------------------------+
+| .. py:data:: ERROR | 40 | Due to a more serious problem, the |
+| | | software has not been able to |
+| | | perform some function. |
++-----------------------+---------------+-------------------------------------+
+| .. py:data:: CRITICAL | 50 | A serious error, indicating that the|
+| | | program itself may be unable to |
+| | | continue running. |
++-----------------------+---------------+-------------------------------------+
.. _handler:
@@ -984,10 +1002,14 @@ LoggerAdapter Objects
information into logging calls. For a usage example, see the section on
:ref:`adding contextual information to your logging output `.
-.. class:: LoggerAdapter(logger, extra)
+.. class:: LoggerAdapter(logger, extra, merge_extra=False)
Returns an instance of :class:`LoggerAdapter` initialized with an
- underlying :class:`Logger` instance and a dict-like object.
+ underlying :class:`Logger` instance, a dict-like object (*extra*), and a
+ boolean (*merge_extra*) indicating whether or not the *extra* argument of
+ individual log calls should be merged with the :class:`LoggerAdapter` extra.
+ The default behavior is to ignore the *extra* argument of individual log
+ calls and only use the one of the :class:`LoggerAdapter` instance
.. method:: process(msg, kwargs)
@@ -1019,6 +1041,9 @@ interchangeably.
Remove the undocumented ``warn()`` method which was an alias to the
``warning()`` method.
+.. versionchanged:: 3.13
+ The *merge_extra* argument was added.
+
Thread Safety
-------------
diff --git a/Doc/library/re.rst b/Doc/library/re.rst
index 3f03f0341d8166..ab201e2483f8e3 100644
--- a/Doc/library/re.rst
+++ b/Doc/library/re.rst
@@ -898,7 +898,7 @@ Functions
['Words', 'words', 'words', '']
>>> re.split(r'(\W+)', 'Words, words, words.')
['Words', ', ', 'words', ', ', 'words', '.', '']
- >>> re.split(r'\W+', 'Words, words, words.', 1)
+ >>> re.split(r'\W+', 'Words, words, words.', maxsplit=1)
['Words', 'words, words.']
>>> re.split('[a-f]+', '0a3B9', flags=re.IGNORECASE)
['0', '3', '9']
@@ -929,6 +929,11 @@ Functions
.. versionchanged:: 3.7
Added support of splitting on a pattern that could match an empty string.
+ .. deprecated:: 3.13
+ Passing *maxsplit* and *flags* as positional arguments is deprecated.
+ In future Python versions they will be
+ :ref:`keyword-only parameters `.
+
.. function:: findall(pattern, string, flags=0)
@@ -1027,8 +1032,6 @@ Functions
.. versionchanged:: 3.7
Unknown escapes in *repl* consisting of ``'\'`` and an ASCII letter
now are errors.
-
- .. versionchanged:: 3.7
Empty matches for the pattern are replaced when adjacent to a previous
non-empty match.
@@ -1037,18 +1040,17 @@ Functions
In :class:`bytes` replacement strings, group *name* can only contain bytes
in the ASCII range (``b'\x00'``-``b'\x7f'``).
+ .. deprecated:: 3.13
+ Passing *count* and *flags* as positional arguments is deprecated.
+ In future Python versions they will be
+ :ref:`keyword-only parameters `.
+
.. function:: subn(pattern, repl, string, count=0, flags=0)
Perform the same operation as :func:`sub`, but return a tuple ``(new_string,
number_of_subs_made)``.
- .. versionchanged:: 3.1
- Added the optional flags argument.
-
- .. versionchanged:: 3.5
- Unmatched groups are replaced with an empty string.
-
.. function:: escape(pattern)
@@ -1656,7 +1658,7 @@ because the address has spaces, our splitting pattern, in it:
.. doctest::
:options: +NORMALIZE_WHITESPACE
- >>> [re.split(":? ", entry, 3) for entry in entries]
+ >>> [re.split(":? ", entry, maxsplit=3) for entry in entries]
[['Ross', 'McFluff', '834.345.1254', '155 Elm Street'],
['Ronald', 'Heathmore', '892.345.3428', '436 Finley Avenue'],
['Frank', 'Burger', '925.541.7625', '662 South Dogwood Way'],
@@ -1669,7 +1671,7 @@ house number from the street name:
.. doctest::
:options: +NORMALIZE_WHITESPACE
- >>> [re.split(":? ", entry, 4) for entry in entries]
+ >>> [re.split(":? ", entry, maxsplit=4) for entry in entries]
[['Ross', 'McFluff', '834.345.1254', '155', 'Elm Street'],
['Ronald', 'Heathmore', '892.345.3428', '436', 'Finley Avenue'],
['Frank', 'Burger', '925.541.7625', '662', 'South Dogwood Way'],
diff --git a/Doc/library/site.rst b/Doc/library/site.rst
index 44f90a3b9e496f..ea3b2e996574ef 100644
--- a/Doc/library/site.rst
+++ b/Doc/library/site.rst
@@ -189,9 +189,9 @@ Module contents
:func:`getuserbase` hasn't been called yet. Default value is
:file:`~/.local` for UNIX and macOS non-framework builds,
:file:`~/Library/Python/{X.Y}` for macOS framework builds, and
- :file:`{%APPDATA%}\\Python` for Windows. This value is used by Distutils to
+ :file:`{%APPDATA%}\\Python` for Windows. This value is used to
compute the installation directories for scripts, data files, Python modules,
- etc. for the :ref:`user installation scheme `.
+ etc. for the user installation scheme.
See also :envvar:`PYTHONUSERBASE`.
diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst
index 50344058c26041..5f1676e5ae2f56 100644
--- a/Doc/library/sqlite3.rst
+++ b/Doc/library/sqlite3.rst
@@ -355,6 +355,12 @@ Module functions
.. versionadded:: 3.12
The *autocommit* parameter.
+ .. versionchanged:: 3.13
+ Positional use of the parameters *timeout*, *detect_types*,
+ *isolation_level*, *check_same_thread*, *factory*, *cached_statements*,
+ and *uri* is deprecated.
+ They will become keyword-only parameters in Python 3.15.
+
.. function:: complete_statement(statement)
Return ``True`` if the string *statement* appears to contain
diff --git a/Doc/library/statistics.rst b/Doc/library/statistics.rst
index 395b324c860389..483ebea67f0c6d 100644
--- a/Doc/library/statistics.rst
+++ b/Doc/library/statistics.rst
@@ -922,6 +922,10 @@ of applications in statistics.
:class:`NormalDist` Examples and Recipes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Classic probability problems
+****************************
+
:class:`NormalDist` readily solves classic probability problems.
For example, given `historical data for SAT exams
@@ -947,6 +951,10 @@ Find the `quartiles `_ and `deciles
>>> list(map(round, sat.quantiles(n=10)))
[810, 896, 958, 1011, 1060, 1109, 1162, 1224, 1310]
+
+Monte Carlo inputs for simulations
+**********************************
+
To estimate the distribution for a model than isn't easy to solve
analytically, :class:`NormalDist` can generate input samples for a `Monte
Carlo simulation `_:
@@ -963,6 +971,9 @@ Carlo simulation `_:
>>> quantiles(map(model, X, Y, Z)) # doctest: +SKIP
[1.4591308524824727, 1.8035946855390597, 2.175091447274739]
+Approximating binomial distributions
+************************************
+
Normal distributions can be used to approximate `Binomial
distributions `_
when the sample size is large and when the probability of a successful
@@ -1000,6 +1011,10 @@ probability that the Python room will stay within its capacity limits?
>>> mean(trial() <= k for i in range(10_000))
0.8398
+
+Naive bayesian classifier
+*************************
+
Normal distributions commonly arise in machine learning problems.
Wikipedia has a `nice example of a Naive Bayesian Classifier
@@ -1054,6 +1069,48 @@ The final prediction goes to the largest posterior. This is known as the
'female'
+Kernel density estimation
+*************************
+
+It is possible to estimate a continuous probability density function
+from a fixed number of discrete samples.
+
+The basic idea is to smooth the data using `a kernel function such as a
+normal distribution, triangular distribution, or uniform distribution
+`_.
+The degree of smoothing is controlled by a single
+parameter, ``h``, representing the variance of the kernel function.
+
+.. testcode::
+
+ import math
+
+ def kde_normal(sample, h):
+ "Create a continous probability density function from a sample."
+ # Smooth the sample with a normal distribution of variance h.
+ kernel_h = NormalDist(0.0, math.sqrt(h)).pdf
+ n = len(sample)
+ def pdf(x):
+ return sum(kernel_h(x - x_i) for x_i in sample) / n
+ return pdf
+
+`Wikipedia has an example
+`_
+where we can use the ``kde_normal()`` recipe to generate and plot
+a probability density function estimated from a small sample:
+
+.. doctest::
+
+ >>> sample = [-2.1, -1.3, -0.4, 1.9, 5.1, 6.2]
+ >>> f_hat = kde_normal(sample, h=2.25)
+ >>> xarr = [i/100 for i in range(-750, 1100)]
+ >>> yarr = [f_hat(x) for x in xarr]
+
+The points in ``xarr`` and ``yarr`` can be used to make a PDF plot:
+
+.. image:: kde_example.png
+ :alt: Scatter plot of the estimated probability density function.
+
..
# This modelines must appear within the last ten lines of the file.
kate: indent-width 3; remove-trailing-space on; replace-tabs on; encoding utf-8;
diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore
index 21b350c4134fd7..0f68cefc92b97b 100644
--- a/Doc/tools/.nitignore
+++ b/Doc/tools/.nitignore
@@ -2,7 +2,6 @@
# as tested on the CI via check-warnings.py in reusable-docs.yml.
# Keep lines sorted lexicographically to help avoid merge conflicts.
-Doc/c-api/buffer.rst
Doc/c-api/datetime.rst
Doc/c-api/descriptor.rst
Doc/c-api/exceptions.rst
diff --git a/Doc/tutorial/venv.rst b/Doc/tutorial/venv.rst
index d1bba098d7d23b..a6dead2eac11f6 100644
--- a/Doc/tutorial/venv.rst
+++ b/Doc/tutorial/venv.rst
@@ -207,4 +207,6 @@ necessary packages with ``install -r``:
``pip`` has many more options. Consult the :ref:`installing-index`
guide for complete documentation for ``pip``. When you've written
a package and want to make it available on the Python Package Index,
-consult the :ref:`distributing-index` guide.
+consult the `Python packaging user guide`_.
+
+.. _Python Packaging User Guide: https://packaging.python.org/en/latest/tutorials/packaging-projects/
diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst
index 4bf67eb439ec6c..921b6a6961c7b2 100644
--- a/Doc/using/cmdline.rst
+++ b/Doc/using/cmdline.rst
@@ -811,8 +811,8 @@ conflict.
Defines the :data:`user base directory `, which is used to
compute the path of the :data:`user site-packages directory `
- and :ref:`Distutils installation paths ` for
- ``python setup.py install --user``.
+ and installation paths for
+ ``python -m pip install --user``.
.. seealso::
diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst
index 924e73dc54da2e..f4adea82a87c38 100644
--- a/Doc/using/configure.rst
+++ b/Doc/using/configure.rst
@@ -686,7 +686,6 @@ Main files of the build system
* :file:`pyconfig.h` (created by :file:`configure`);
* :file:`Modules/Setup`: C extensions built by the Makefile using
:file:`Module/makesetup` shell script;
-* :file:`setup.py`: C extensions built using the ``setuptools`` package.
Main build steps
----------------
@@ -695,8 +694,7 @@ Main build steps
* A static ``libpython`` library (``.a``) is created from objects files.
* ``python.o`` and the static ``libpython`` library are linked into the
final ``python`` program.
-* C extensions are built by the Makefile (see :file:`Modules/Setup`)
- and ``python setup.py build``.
+* C extensions are built by the Makefile (see :file:`Modules/Setup`).
Main Makefile targets
---------------------
@@ -748,11 +746,8 @@ Example on Linux x86-64::
At the beginning of the files, C extensions are built as built-in modules.
Extensions defined after the ``*shared*`` marker are built as dynamic libraries.
-The :file:`setup.py` script only builds C extensions as shared libraries using
-the :mod:`distutils` module.
-
-The :c:macro:`PyAPI_FUNC()`, :c:macro:`PyAPI_API()` and
-:c:macro:`PyMODINIT_FUNC()` macros of :file:`Include/pyport.h` are defined
+The :c:macro:`PyAPI_FUNC()`, :c:macro:`PyAPI_DATA()` and
+:c:macro:`PyMODINIT_FUNC` macros of :file:`Include/pyport.h` are defined
differently depending if the ``Py_BUILD_CORE_MODULE`` macro is defined:
* Use ``Py_EXPORTED_SYMBOL`` if the ``Py_BUILD_CORE_MODULE`` is defined
@@ -784,7 +779,7 @@ Preprocessor flags
headers in a nonstandard directory ````.
Both :envvar:`CPPFLAGS` and :envvar:`LDFLAGS` need to contain the shell's
- value for setup.py to be able to build extension modules using the
+ value to be able to build extension modules using the
directories specified in the environment variables.
.. envvar:: BASECPPFLAGS
@@ -821,8 +816,8 @@ Compiler flags
.. envvar:: CFLAGS_NODIST
:envvar:`CFLAGS_NODIST` is used for building the interpreter and stdlib C
- extensions. Use it when a compiler flag should *not* be part of the
- distutils :envvar:`CFLAGS` once Python is installed (:issue:`21121`).
+ extensions. Use it when a compiler flag should *not* be part of
+ :envvar:`CFLAGS` once Python is installed (:gh:`65320`).
In particular, :envvar:`CFLAGS` should not contain:
@@ -952,7 +947,7 @@ Linker flags
:envvar:`LDFLAGS_NODIST` is used in the same manner as
:envvar:`CFLAGS_NODIST`. Use it when a linker flag should *not* be part of
- the distutils :envvar:`LDFLAGS` once Python is installed (:issue:`35257`).
+ :envvar:`LDFLAGS` once Python is installed (:gh:`65320`).
In particular, :envvar:`LDFLAGS` should not contain:
@@ -974,7 +969,7 @@ Linker flags
directory ````.
Both :envvar:`CPPFLAGS` and :envvar:`LDFLAGS` need to contain the shell's
- value for setup.py to be able to build extension modules using the
+ value to be able to build extension modules using the
directories specified in the environment variables.
.. envvar:: LIBS
diff --git a/Doc/using/mac.rst b/Doc/using/mac.rst
index 65178272862168..eb1413af2cbc3d 100644
--- a/Doc/using/mac.rst
+++ b/Doc/using/mac.rst
@@ -125,13 +125,9 @@ http://www.hashcollision.org/hkn/python/idle_intro/index.html.
Installing Additional Python Packages
=====================================
-There are several methods to install additional Python packages:
+This section has moved to the `Python Packaging User Guide`_.
-* Packages can be installed via the standard Python distutils mode (``python
- setup.py install``).
-
-* Many packages can also be installed via the :program:`setuptools` extension
- or :program:`pip` wrapper, see https://pip.pypa.io/.
+.. _Python Packaging User Guide: https://packaging.python.org/en/latest/tutorials/installing-packages/
GUI Programming on the Mac
diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst
index d24450e2f963ff..ca79c9d3a9d3a8 100644
--- a/Doc/using/windows.rst
+++ b/Doc/using/windows.rst
@@ -1246,8 +1246,8 @@ shipped with PyWin32. It is an embeddable IDE with a built-in debugger.
cx_Freeze
---------
-`cx_Freeze `_ is a ``distutils``
-extension which wraps Python scripts into executable Windows programs
+`cx_Freeze `_
+wraps Python scripts into executable Windows programs
(:file:`{*}.exe` files). When you have done this, you can distribute your
application without requiring your users to install Python.
diff --git a/Doc/whatsnew/2.2.rst b/Doc/whatsnew/2.2.rst
index 44e9bd8d492bfc..7de48a40263034 100644
--- a/Doc/whatsnew/2.2.rst
+++ b/Doc/whatsnew/2.2.rst
@@ -1109,7 +1109,7 @@ code, none of the changes described here will affect you very much.
definition tables to simplify implementation of methods with no arguments or a
single untyped argument. Calling such methods is more efficient than calling a
corresponding method that uses :c:macro:`METH_VARARGS`. Also, the old
- :c:macro:`METH_OLDARGS` style of writing C methods is now officially deprecated.
+ :c:macro:`!METH_OLDARGS` style of writing C methods is now officially deprecated.
* Two new wrapper functions, :c:func:`PyOS_snprintf` and :c:func:`PyOS_vsnprintf`
were added to provide cross-platform implementations for the relatively new
diff --git a/Doc/whatsnew/2.3.rst b/Doc/whatsnew/2.3.rst
index a96c1061455e00..2120ee49f7d6bd 100644
--- a/Doc/whatsnew/2.3.rst
+++ b/Doc/whatsnew/2.3.rst
@@ -1886,7 +1886,7 @@ Changes to Python's build process and to the C API include:
(:file:`libpython2.3.so`) by supplying :option:`!--enable-shared` when running
Python's :program:`configure` script. (Contributed by Ondrej Palkovsky.)
-* The :c:macro:`DL_EXPORT` and :c:macro:`DL_IMPORT` macros are now deprecated.
+* The :c:macro:`!DL_EXPORT` and :c:macro:`!DL_IMPORT` macros are now deprecated.
Initialization functions for Python extension modules should now be declared
using the new macro :c:macro:`PyMODINIT_FUNC`, while the Python core will
generally use the :c:macro:`PyAPI_FUNC` and :c:macro:`PyAPI_DATA` macros.
diff --git a/Doc/whatsnew/2.4.rst b/Doc/whatsnew/2.4.rst
index 9e8a9e6a622d00..40b404f87e5152 100644
--- a/Doc/whatsnew/2.4.rst
+++ b/Doc/whatsnew/2.4.rst
@@ -1476,7 +1476,7 @@ Some of the changes to Python's build process and to the C API are:
:c:func:`PyArg_ParseTupleAndKeywords` but takes a :c:type:`va_list` instead of a
number of arguments. (Contributed by Greg Chapman.)
-* A new method flag, :c:macro:`METH_COEXISTS`, allows a function defined in slots
+* A new method flag, :c:macro:`METH_COEXIST`, allows a function defined in slots
to co-exist with a :c:type:`PyCFunction` having the same name. This can halve
the access time for a method such as :meth:`set.__contains__`. (Contributed by
Raymond Hettinger.)
diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst
index ad899d53886c59..5c46dc8952154b 100644
--- a/Doc/whatsnew/2.6.rst
+++ b/Doc/whatsnew/2.6.rst
@@ -3060,9 +3060,9 @@ Changes to Python's build process and to the C API include:
* Some macros were renamed in both 3.0 and 2.6 to make it clearer that
they are macros,
- not functions. :c:macro:`Py_Size()` became :c:macro:`Py_SIZE()`,
- :c:macro:`Py_Type()` became :c:macro:`Py_TYPE()`, and
- :c:macro:`Py_Refcnt()` became :c:macro:`Py_REFCNT()`.
+ not functions. :c:macro:`!Py_Size()` became :c:macro:`Py_SIZE()`,
+ :c:macro:`!Py_Type()` became :c:macro:`Py_TYPE()`, and
+ :c:macro:`!Py_Refcnt()` became :c:macro:`Py_REFCNT()`.
The mixed-case macros are still available
in Python 2.6 for backward compatibility.
(:issue:`1629`)
diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst
index 4b5a31f8a84810..00001f92b51c82 100644
--- a/Doc/whatsnew/2.7.rst
+++ b/Doc/whatsnew/2.7.rst
@@ -2287,10 +2287,10 @@ object, and then get the ``void *`` pointer, which will usually point
to an array of pointers to the module's various API functions.
There is an existing data type already used for this,
-:c:type:`PyCObject`, but it doesn't provide type safety. Evil code
+:c:type:`!PyCObject`, but it doesn't provide type safety. Evil code
written in pure Python could cause a segmentation fault by taking a
-:c:type:`PyCObject` from module A and somehow substituting it for the
-:c:type:`PyCObject` in module B. Capsules know their own name,
+:c:type:`!PyCObject` from module A and somehow substituting it for the
+:c:type:`!PyCObject` in module B. Capsules know their own name,
and getting the pointer requires providing the name:
.. code-block:: c
@@ -2310,10 +2310,10 @@ detect the mismatched name and return false. Refer to
:ref:`using-capsules` for more information on using these objects.
Python 2.7 now uses capsules internally to provide various
-extension-module APIs, but the :c:func:`PyCObject_AsVoidPtr` was
+extension-module APIs, but the :c:func:`!PyCObject_AsVoidPtr` was
modified to handle capsules, preserving compile-time compatibility
-with the :c:type:`CObject` interface. Use of
-:c:func:`PyCObject_AsVoidPtr` will signal a
+with the :c:type:`!PyCObject` interface. Use of
+:c:func:`!PyCObject_AsVoidPtr` will signal a
:exc:`PendingDeprecationWarning`, which is silent by default.
Implemented in Python 3.1 and backported to 2.7 by Larry Hastings;
diff --git a/Doc/whatsnew/3.0.rst b/Doc/whatsnew/3.0.rst
index b767bbe177abeb..58d42bd94cb61e 100644
--- a/Doc/whatsnew/3.0.rst
+++ b/Doc/whatsnew/3.0.rst
@@ -875,7 +875,7 @@ to the C API.
* Renamed the boolean conversion C-level slot and method:
``nb_nonzero`` is now ``nb_bool``.
-* Removed :c:macro:`METH_OLDARGS` and :c:macro:`WITH_CYCLE_GC` from the C API.
+* Removed :c:macro:`!METH_OLDARGS` and :c:macro:`!WITH_CYCLE_GC` from the C API.
.. ======================================================================
diff --git a/Doc/whatsnew/3.1.rst b/Doc/whatsnew/3.1.rst
index c399f007fd63fb..3c1c9c3c4bc601 100644
--- a/Doc/whatsnew/3.1.rst
+++ b/Doc/whatsnew/3.1.rst
@@ -510,7 +510,7 @@ Changes to Python's build process and to the C API include:
(Contributed by Mark Dickinson; :issue:`5914`.)
-* Added :c:type:`PyCapsule` as a replacement for the :c:type:`PyCObject` API.
+* Added :c:type:`PyCapsule` as a replacement for the :c:type:`!PyCObject` API.
The principal difference is that the new type has a well defined interface
for passing typing safety information and a less complicated signature
for calling a destructor. The old type had a problematic API and is now
diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst
index 8ed435476c9cec..65ca4c332ce35f 100644
--- a/Doc/whatsnew/3.12.rst
+++ b/Doc/whatsnew/3.12.rst
@@ -1576,7 +1576,7 @@ Changes in the Python API
1,13-1,17: FSTRING_MIDDLE ' end'
1,17-1,18: FSTRING_END '"'
- Additionally, there may be some minor behavioral changes as a consecuence of the
+ Additionally, there may be some minor behavioral changes as a consequence of the
changes required to support :pep:`701`. Some of these changes include:
* The ``type`` attribute of the tokens emitted when tokenizing some invalid Python
diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst
index 63cdee6cf1a4f3..519dee5eb7d6cf 100644
--- a/Doc/whatsnew/3.13.rst
+++ b/Doc/whatsnew/3.13.rst
@@ -219,6 +219,11 @@ Deprecated
They will be removed in Python 3.15.
(Contributed by Victor Stinner in :gh:`105096`.)
+* Passing more than one positional argument to :func:`sqlite3.connect` and the
+ :class:`sqlite3.Connection` constructor is deprecated. The remaining
+ parameters will become keyword-only in Python 3.15.
+ (Contributed by Erlend E. Aasland in :gh:`107948`.)
+
Pending Removal in Python 3.14
------------------------------
@@ -827,6 +832,13 @@ Porting to Python 3.13
Deprecated
----------
+* Passing optional arguments *maxsplit*, *count* and *flags* in module-level
+ functions :func:`re.split`, :func:`re.sub` and :func:`re.subn` as positional
+ arguments is now deprecated.
+ In future Python versions these parameters will be
+ :ref:`keyword-only `.
+ (Contributed by Serhiy Storchaka in :gh:`56166`.)
+
* Deprecate the old ``Py_UNICODE`` and ``PY_UNICODE_TYPE`` types: use directly
the :c:type:`wchar_t` type instead. Since Python 3.3, ``Py_UNICODE`` and
``PY_UNICODE_TYPE`` are just aliases to :c:type:`wchar_t`.
@@ -936,7 +948,9 @@ Removed
* ``Py_SetPath()``: set :c:member:`PyConfig.module_search_paths` instead.
* ``Py_SetProgramName()``: set :c:member:`PyConfig.program_name` instead.
* ``Py_SetPythonHome()``: set :c:member:`PyConfig.home` instead.
- * ``Py_SetStandardStreamEncoding()``: set :c:member:`PyConfig.stdio_encoding` instead.
+ * ``Py_SetStandardStreamEncoding()``: set :c:member:`PyConfig.stdio_encoding`
+ instead, and set also maybe :c:member:`PyConfig.legacy_windows_stdio` (on
+ Windows).
* ``_Py_SetProgramFullPath()``: set :c:member:`PyConfig.executable` instead.
Use the new :c:type:`PyConfig` API of the :ref:`Python Initialization
diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst
index ed1c1770fb0f51..56ac5c4c0a1c1b 100644
--- a/Doc/whatsnew/3.2.rst
+++ b/Doc/whatsnew/3.2.rst
@@ -2658,7 +2658,7 @@ require changes to your code:
* "t#" format has been removed: use "s#" or "s*" instead
* "w" and "w#" formats has been removed: use "w*" instead
-* The :c:type:`PyCObject` type, deprecated in 3.1, has been removed. To wrap
+* The :c:type:`!PyCObject` type, deprecated in 3.1, has been removed. To wrap
opaque C pointers in Python objects, the :c:type:`PyCapsule` API should be used
instead; the new type has a well-defined interface for passing typing safety
information and a less complicated signature for calling a destructor.
diff --git a/Include/cpython/object.h b/Include/cpython/object.h
index fd45fa57e6282b..5f8b1f7c195501 100644
--- a/Include/cpython/object.h
+++ b/Include/cpython/object.h
@@ -227,7 +227,7 @@ struct _typeobject {
vectorcallfunc tp_vectorcall;
/* bitset of which type-watchers care about this type */
- char tp_watched;
+ unsigned char tp_watched;
};
/* This struct is used by the specializer
diff --git a/Include/cpython/optimizer.h b/Include/cpython/optimizer.h
index da34ec1882a539..e3fe0e8f0ffd59 100644
--- a/Include/cpython/optimizer.h
+++ b/Include/cpython/optimizer.h
@@ -22,7 +22,7 @@ typedef struct _PyExecutorObject {
typedef struct _PyOptimizerObject _PyOptimizerObject;
/* Should return > 0 if a new executor is created. O if no executor is produced and < 0 if an error occurred. */
-typedef int (*optimize_func)(_PyOptimizerObject* self, PyCodeObject *code, _Py_CODEUNIT *instr, _PyExecutorObject **);
+typedef int (*optimize_func)(_PyOptimizerObject* self, PyCodeObject *code, _Py_CODEUNIT *instr, _PyExecutorObject **, int curr_stackentries);
typedef struct _PyOptimizerObject {
PyObject_HEAD
diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h
index 56e473cc5e42d5..2a53838314c9d7 100644
--- a/Include/cpython/pystate.h
+++ b/Include/cpython/pystate.h
@@ -29,24 +29,6 @@ typedef int (*Py_tracefunc)(PyObject *, PyFrameObject *, int, PyObject *);
#define PyTrace_C_RETURN 6
#define PyTrace_OPCODE 7
-// Internal structure: you should not use it directly, but use public functions
-// like PyThreadState_EnterTracing() and PyThreadState_LeaveTracing().
-typedef struct _PyCFrame {
- /* This struct will be threaded through the C stack
- * allowing fast access to per-thread state that needs
- * to be accessed quickly by the interpreter, but can
- * be modified outside of the interpreter.
- *
- * WARNING: This makes data on the C stack accessible from
- * heap objects. Care must be taken to maintain stack
- * discipline and make sure that instances of this struct cannot
- * accessed outside of their lifetime.
- */
- /* Pointer to the currently executing frame (it can be NULL) */
- struct _PyInterpreterFrame *current_frame;
- struct _PyCFrame *previous;
-} _PyCFrame;
-
typedef struct _err_stackitem {
/* This struct represents a single execution context where we might
* be currently handling an exception. It is a per-coroutine state
@@ -123,9 +105,8 @@ struct _ts {
int tracing;
int what_event; /* The event currently being monitored, if any. */
- /* Pointer to current _PyCFrame in the C stack frame of the currently,
- * or most recently, executing _PyEval_EvalFrameDefault. */
- _PyCFrame *cframe;
+ /* Pointer to currently executing frame. */
+ struct _PyInterpreterFrame *current_frame;
Py_tracefunc c_profilefunc;
Py_tracefunc c_tracefunc;
@@ -211,8 +192,6 @@ struct _ts {
/* The thread's exception stack entry. (Always the last entry.) */
_PyErr_StackItem exc_state;
- /* The bottom-most frame on the stack. */
- _PyCFrame root_cframe;
};
/* WASI has limited call stack. Python's recursion limit depends on code
diff --git a/Include/internal/pycore_compile.h b/Include/internal/pycore_compile.h
index fa2f64021e73c9..ad657c0f0fcedc 100644
--- a/Include/internal/pycore_compile.h
+++ b/Include/internal/pycore_compile.h
@@ -54,6 +54,11 @@ typedef struct {
int s_next_free_label; /* next free label id */
} _PyCompile_InstructionSequence;
+int _PyCompile_InstructionSequence_UseLabel(_PyCompile_InstructionSequence *seq, int lbl);
+int _PyCompile_InstructionSequence_Addop(_PyCompile_InstructionSequence *seq,
+ int opcode, int oparg,
+ _PyCompilerSrcLocation loc);
+
typedef struct {
PyObject *u_name;
PyObject *u_qualname; /* dot-separated qualified name (lazy) */
diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h
index 26a913435ef9cf..2ad6ef0f7c04d5 100644
--- a/Include/internal/pycore_dict.h
+++ b/Include/internal/pycore_dict.h
@@ -10,6 +10,7 @@ extern "C" {
#endif
#include "pycore_dict_state.h"
+#include "pycore_object.h"
#include "pycore_runtime.h" // _PyRuntime
// Unsafe flavor of PyDict_GetItemWithError(): no error checking
@@ -62,6 +63,8 @@ extern uint32_t _PyDictKeys_GetVersionForCurrentState(
extern size_t _PyDict_KeysSize(PyDictKeysObject *keys);
+extern void _PyDictKeys_DecRef(PyDictKeysObject *keys);
+
/* _Py_dict_lookup() returns index of entry which can be used like DK_ENTRIES(dk)[index].
* -1 when no entry found, -3 when compare raises error.
*/
@@ -196,6 +199,7 @@ _PyDict_NotifyEvent(PyInterpreterState *interp,
}
extern PyObject *_PyObject_MakeDictFromInstanceAttributes(PyObject *obj, PyDictValues *values);
+extern bool _PyObject_MakeInstanceAttributesFromDict(PyObject *obj, PyDictOrValues *dorv);
extern PyObject *_PyDict_FromItems(
PyObject *const *keys, Py_ssize_t keys_offset,
PyObject *const *values, Py_ssize_t values_offset,
diff --git a/Include/internal/pycore_fileutils.h b/Include/internal/pycore_fileutils.h
index daa32c0dff6097..0ed139f79b1429 100644
--- a/Include/internal/pycore_fileutils.h
+++ b/Include/internal/pycore_fileutils.h
@@ -109,7 +109,8 @@ PyAPI_FUNC(int) _Py_stat(
PyObject *path,
struct stat *status);
-extern int _Py_open(
+// Export for 'select' shared extension (Solaris newDevPollObject() uses it)
+PyAPI_FUNC(int) _Py_open(
const char *pathname,
int flags);
@@ -126,7 +127,8 @@ extern Py_ssize_t _Py_read(
void *buf,
size_t count);
-extern Py_ssize_t _Py_write(
+// Export for 'select' shared extension (Solaris devpoll_flush() uses it)
+PyAPI_FUNC(Py_ssize_t) _Py_write(
int fd,
const void *buf,
size_t count);
@@ -260,6 +262,7 @@ extern int _Py_add_relfile(wchar_t *dirname,
size_t bufsize);
extern size_t _Py_find_basename(const wchar_t *filename);
PyAPI_FUNC(wchar_t*) _Py_normpath(wchar_t *path, Py_ssize_t size);
+extern wchar_t *_Py_normpath_and_size(wchar_t *path, Py_ssize_t size, Py_ssize_t *length);
// The Windows Games API family does not provide these functions
// so provide our own implementations. Remove them in case they get added
diff --git a/Include/internal/pycore_flowgraph.h b/Include/internal/pycore_flowgraph.h
index cb55f8712e7ad6..58fed46886ea45 100644
--- a/Include/internal/pycore_flowgraph.h
+++ b/Include/internal/pycore_flowgraph.h
@@ -11,88 +11,26 @@ extern "C" {
#include "pycore_opcode_utils.h"
#include "pycore_compile.h"
-
-typedef struct {
- int i_opcode;
- int i_oparg;
- _PyCompilerSrcLocation i_loc;
- struct _PyCfgBasicblock_ *i_target; /* target block (if jump instruction) */
- struct _PyCfgBasicblock_ *i_except; /* target block when exception is raised */
-} _PyCfgInstruction;
-
typedef struct {
int id;
} _PyCfgJumpTargetLabel;
+struct _PyCfgBuilder;
-typedef struct {
- struct _PyCfgBasicblock_ *handlers[CO_MAXBLOCKS+1];
- int depth;
-} _PyCfgExceptStack;
-
-typedef struct _PyCfgBasicblock_ {
- /* Each basicblock in a compilation unit is linked via b_list in the
- reverse order that the block are allocated. b_list points to the next
- block in this list, not to be confused with b_next, which is next by
- control flow. */
- struct _PyCfgBasicblock_ *b_list;
- /* The label of this block if it is a jump target, -1 otherwise */
- _PyCfgJumpTargetLabel b_label;
- /* Exception stack at start of block, used by assembler to create the exception handling table */
- _PyCfgExceptStack *b_exceptstack;
- /* pointer to an array of instructions, initially NULL */
- _PyCfgInstruction *b_instr;
- /* If b_next is non-NULL, it is a pointer to the next
- block reached by normal control flow. */
- struct _PyCfgBasicblock_ *b_next;
- /* number of instructions used */
- int b_iused;
- /* length of instruction array (b_instr) */
- int b_ialloc;
- /* Used by add_checks_for_loads_of_unknown_variables */
- uint64_t b_unsafe_locals_mask;
- /* Number of predecessors that a block has. */
- int b_predecessors;
- /* depth of stack upon entry of block, computed by stackdepth() */
- int b_startdepth;
- /* Basic block is an exception handler that preserves lasti */
- unsigned b_preserve_lasti : 1;
- /* Used by compiler passes to mark whether they have visited a basic block. */
- unsigned b_visited : 1;
- /* b_except_handler is used by the cold-detection algorithm to mark exception targets */
- unsigned b_except_handler : 1;
- /* b_cold is true if this block is not perf critical (like an exception handler) */
- unsigned b_cold : 1;
- /* b_warm is used by the cold-detection algorithm to mark blocks which are definitely not cold */
- unsigned b_warm : 1;
-} _PyCfgBasicblock;
+int _PyCfgBuilder_UseLabel(struct _PyCfgBuilder *g, _PyCfgJumpTargetLabel lbl);
+int _PyCfgBuilder_Addop(struct _PyCfgBuilder *g, int opcode, int oparg, _PyCompilerSrcLocation loc);
-int _PyBasicblock_InsertInstruction(_PyCfgBasicblock *block, int pos, _PyCfgInstruction *instr);
+struct _PyCfgBuilder* _PyCfgBuilder_New(void);
+void _PyCfgBuilder_Free(struct _PyCfgBuilder *g);
+int _PyCfgBuilder_CheckSize(struct _PyCfgBuilder* g);
-typedef struct cfg_builder_ {
- /* The entryblock, at which control flow begins. All blocks of the
- CFG are reachable through the b_next links */
- _PyCfgBasicblock *g_entryblock;
- /* Pointer to the most recently allocated block. By following
- b_list links, you can reach all allocated blocks. */
- _PyCfgBasicblock *g_block_list;
- /* pointer to the block currently being constructed */
- _PyCfgBasicblock *g_curblock;
- /* label for the next instruction to be placed */
- _PyCfgJumpTargetLabel g_current_label;
-} _PyCfgBuilder;
-
-int _PyCfgBuilder_UseLabel(_PyCfgBuilder *g, _PyCfgJumpTargetLabel lbl);
-int _PyCfgBuilder_Addop(_PyCfgBuilder *g, int opcode, int oparg, _PyCompilerSrcLocation loc);
-
-int _PyCfgBuilder_Init(_PyCfgBuilder *g);
-void _PyCfgBuilder_Fini(_PyCfgBuilder *g);
-
-int _PyCfg_OptimizeCodeUnit(_PyCfgBuilder *g, PyObject *consts, PyObject *const_cache,
+int _PyCfg_OptimizeCodeUnit(struct _PyCfgBuilder *g, PyObject *consts, PyObject *const_cache,
int nlocals, int nparams, int firstlineno);
-int _PyCfg_Stackdepth(_PyCfgBuilder *g);
-void _PyCfg_ConvertPseudoOps(_PyCfgBasicblock *entryblock);
-int _PyCfg_ResolveJumps(_PyCfgBuilder *g);
+
+int _PyCfg_ToInstructionSequence(struct _PyCfgBuilder *g, _PyCompile_InstructionSequence *seq);
+int _PyCfg_OptimizedCfgToInstructionSequence(struct _PyCfgBuilder *g, _PyCompile_CodeUnitMetadata *umd,
+ int code_flags, int *stackdepth, int *nlocalsplus,
+ _PyCompile_InstructionSequence *seq);
PyCodeObject *
_PyAssemble_MakeCodeObject(_PyCompile_CodeUnitMetadata *u, PyObject *const_cache,
diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h
index 5ff20ef845ab10..0dc2a1814cb1d5 100644
--- a/Include/internal/pycore_frame.h
+++ b/Include/internal/pycore_frame.h
@@ -196,7 +196,7 @@ _PyFrame_GetFirstComplete(_PyInterpreterFrame *frame)
static inline _PyInterpreterFrame *
_PyThreadState_GetFrame(PyThreadState *tstate)
{
- return _PyFrame_GetFirstComplete(tstate->cframe->current_frame);
+ return _PyFrame_GetFirstComplete(tstate->current_frame);
}
/* For use by _PyFrame_GetFrameObject
diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h
index 6d50ffd0a02f1f..ee9010583ff8b5 100644
--- a/Include/internal/pycore_global_objects_fini_generated.h
+++ b/Include/internal/pycore_global_objects_fini_generated.h
@@ -547,6 +547,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(anon_lambda));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(anon_listcomp));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(anon_module));
+ _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(anon_null));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(anon_setcomp));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(anon_string));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(anon_unknown));
diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h
index bb1fb13f342fc6..b081c0e023fa4a 100644
--- a/Include/internal/pycore_global_strings.h
+++ b/Include/internal/pycore_global_strings.h
@@ -33,6 +33,7 @@ struct _Py_global_strings {
STRUCT_FOR_STR(anon_lambda, "")
STRUCT_FOR_STR(anon_listcomp, "")
STRUCT_FOR_STR(anon_module, "")
+ STRUCT_FOR_STR(anon_null, "")
STRUCT_FOR_STR(anon_setcomp, "")
STRUCT_FOR_STR(anon_string, "")
STRUCT_FOR_STR(anon_unknown, "")
diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h
index 7cdf64bcdacb9f..857d6efec3b3b1 100644
--- a/Include/internal/pycore_object.h
+++ b/Include/internal/pycore_object.h
@@ -381,7 +381,7 @@ extern PyObject *_PyType_NewManagedObject(PyTypeObject *type);
extern PyTypeObject* _PyType_CalculateMetaclass(PyTypeObject *, PyObject *);
extern PyObject* _PyType_GetDocFromInternalDoc(const char *, const char *);
-extern PyObject* _PyType_GetTextSignatureFromInternalDoc(const char *, const char *);
+extern PyObject* _PyType_GetTextSignatureFromInternalDoc(const char *, const char *, int);
extern int _PyObject_InitializeDict(PyObject *obj);
int _PyObject_InitInlineValues(PyObject *obj, PyTypeObject *tp);
diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h
index a187da6e24730f..b47e796485236c 100644
--- a/Include/internal/pycore_opcode.h
+++ b/Include/internal/pycore_opcode.h
@@ -14,8 +14,6 @@ extern "C" {
extern const uint8_t _PyOpcode_Caches[256];
-extern const uint8_t _PyOpcode_Deopt[256];
-
#ifdef NEED_OPCODE_TABLES
const uint8_t _PyOpcode_Caches[256] = {
@@ -34,546 +32,8 @@ const uint8_t _PyOpcode_Caches[256] = {
[JUMP_BACKWARD] = 1,
[TO_BOOL] = 3,
};
-
-const uint8_t _PyOpcode_Deopt[256] = {
- [BEFORE_ASYNC_WITH] = BEFORE_ASYNC_WITH,
- [BEFORE_WITH] = BEFORE_WITH,
- [BINARY_OP] = BINARY_OP,
- [BINARY_OP_ADD_FLOAT] = BINARY_OP,
- [BINARY_OP_ADD_INT] = BINARY_OP,
- [BINARY_OP_ADD_UNICODE] = BINARY_OP,
- [BINARY_OP_INPLACE_ADD_UNICODE] = BINARY_OP,
- [BINARY_OP_MULTIPLY_FLOAT] = BINARY_OP,
- [BINARY_OP_MULTIPLY_INT] = BINARY_OP,
- [BINARY_OP_SUBTRACT_FLOAT] = BINARY_OP,
- [BINARY_OP_SUBTRACT_INT] = BINARY_OP,
- [BINARY_SLICE] = BINARY_SLICE,
- [BINARY_SUBSCR] = BINARY_SUBSCR,
- [BINARY_SUBSCR_DICT] = BINARY_SUBSCR,
- [BINARY_SUBSCR_GETITEM] = BINARY_SUBSCR,
- [BINARY_SUBSCR_LIST_INT] = BINARY_SUBSCR,
- [BINARY_SUBSCR_STR_INT] = BINARY_SUBSCR,
- [BINARY_SUBSCR_TUPLE_INT] = BINARY_SUBSCR,
- [BUILD_CONST_KEY_MAP] = BUILD_CONST_KEY_MAP,
- [BUILD_LIST] = BUILD_LIST,
- [BUILD_MAP] = BUILD_MAP,
- [BUILD_SET] = BUILD_SET,
- [BUILD_SLICE] = BUILD_SLICE,
- [BUILD_STRING] = BUILD_STRING,
- [BUILD_TUPLE] = BUILD_TUPLE,
- [CACHE] = CACHE,
- [CALL] = CALL,
- [CALL_BOUND_METHOD_EXACT_ARGS] = CALL,
- [CALL_BUILTIN_CLASS] = CALL,
- [CALL_BUILTIN_FAST_WITH_KEYWORDS] = CALL,
- [CALL_FUNCTION_EX] = CALL_FUNCTION_EX,
- [CALL_INTRINSIC_1] = CALL_INTRINSIC_1,
- [CALL_INTRINSIC_2] = CALL_INTRINSIC_2,
- [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = CALL,
- [CALL_NO_KW_ALLOC_AND_ENTER_INIT] = CALL,
- [CALL_NO_KW_BUILTIN_FAST] = CALL,
- [CALL_NO_KW_BUILTIN_O] = CALL,
- [CALL_NO_KW_ISINSTANCE] = CALL,
- [CALL_NO_KW_LEN] = CALL,
- [CALL_NO_KW_LIST_APPEND] = CALL,
- [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = CALL,
- [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = CALL,
- [CALL_NO_KW_METHOD_DESCRIPTOR_O] = CALL,
- [CALL_NO_KW_STR_1] = CALL,
- [CALL_NO_KW_TUPLE_1] = CALL,
- [CALL_NO_KW_TYPE_1] = CALL,
- [CALL_PY_EXACT_ARGS] = CALL,
- [CALL_PY_WITH_DEFAULTS] = CALL,
- [CHECK_EG_MATCH] = CHECK_EG_MATCH,
- [CHECK_EXC_MATCH] = CHECK_EXC_MATCH,
- [CLEANUP_THROW] = CLEANUP_THROW,
- [COMPARE_OP] = COMPARE_OP,
- [COMPARE_OP_FLOAT] = COMPARE_OP,
- [COMPARE_OP_INT] = COMPARE_OP,
- [COMPARE_OP_STR] = COMPARE_OP,
- [CONTAINS_OP] = CONTAINS_OP,
- [CONVERT_VALUE] = CONVERT_VALUE,
- [COPY] = COPY,
- [COPY_FREE_VARS] = COPY_FREE_VARS,
- [DELETE_ATTR] = DELETE_ATTR,
- [DELETE_DEREF] = DELETE_DEREF,
- [DELETE_FAST] = DELETE_FAST,
- [DELETE_GLOBAL] = DELETE_GLOBAL,
- [DELETE_NAME] = DELETE_NAME,
- [DELETE_SUBSCR] = DELETE_SUBSCR,
- [DICT_MERGE] = DICT_MERGE,
- [DICT_UPDATE] = DICT_UPDATE,
- [END_ASYNC_FOR] = END_ASYNC_FOR,
- [END_FOR] = END_FOR,
- [END_SEND] = END_SEND,
- [ENTER_EXECUTOR] = ENTER_EXECUTOR,
- [EXIT_INIT_CHECK] = EXIT_INIT_CHECK,
- [EXTENDED_ARG] = EXTENDED_ARG,
- [FORMAT_SIMPLE] = FORMAT_SIMPLE,
- [FORMAT_WITH_SPEC] = FORMAT_WITH_SPEC,
- [FOR_ITER] = FOR_ITER,
- [FOR_ITER_GEN] = FOR_ITER,
- [FOR_ITER_LIST] = FOR_ITER,
- [FOR_ITER_RANGE] = FOR_ITER,
- [FOR_ITER_TUPLE] = FOR_ITER,
- [GET_AITER] = GET_AITER,
- [GET_ANEXT] = GET_ANEXT,
- [GET_AWAITABLE] = GET_AWAITABLE,
- [GET_ITER] = GET_ITER,
- [GET_LEN] = GET_LEN,
- [GET_YIELD_FROM_ITER] = GET_YIELD_FROM_ITER,
- [IMPORT_FROM] = IMPORT_FROM,
- [IMPORT_NAME] = IMPORT_NAME,
- [INSTRUMENTED_CALL] = INSTRUMENTED_CALL,
- [INSTRUMENTED_CALL_FUNCTION_EX] = INSTRUMENTED_CALL_FUNCTION_EX,
- [INSTRUMENTED_END_FOR] = INSTRUMENTED_END_FOR,
- [INSTRUMENTED_END_SEND] = INSTRUMENTED_END_SEND,
- [INSTRUMENTED_FOR_ITER] = INSTRUMENTED_FOR_ITER,
- [INSTRUMENTED_INSTRUCTION] = INSTRUMENTED_INSTRUCTION,
- [INSTRUMENTED_JUMP_BACKWARD] = INSTRUMENTED_JUMP_BACKWARD,
- [INSTRUMENTED_JUMP_FORWARD] = INSTRUMENTED_JUMP_FORWARD,
- [INSTRUMENTED_LINE] = INSTRUMENTED_LINE,
- [INSTRUMENTED_LOAD_SUPER_ATTR] = INSTRUMENTED_LOAD_SUPER_ATTR,
- [INSTRUMENTED_POP_JUMP_IF_FALSE] = INSTRUMENTED_POP_JUMP_IF_FALSE,
- [INSTRUMENTED_POP_JUMP_IF_NONE] = INSTRUMENTED_POP_JUMP_IF_NONE,
- [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = INSTRUMENTED_POP_JUMP_IF_NOT_NONE,
- [INSTRUMENTED_POP_JUMP_IF_TRUE] = INSTRUMENTED_POP_JUMP_IF_TRUE,
- [INSTRUMENTED_RESUME] = INSTRUMENTED_RESUME,
- [INSTRUMENTED_RETURN_CONST] = INSTRUMENTED_RETURN_CONST,
- [INSTRUMENTED_RETURN_VALUE] = INSTRUMENTED_RETURN_VALUE,
- [INSTRUMENTED_YIELD_VALUE] = INSTRUMENTED_YIELD_VALUE,
- [INTERPRETER_EXIT] = INTERPRETER_EXIT,
- [IS_OP] = IS_OP,
- [JUMP_BACKWARD] = JUMP_BACKWARD,
- [JUMP_BACKWARD_NO_INTERRUPT] = JUMP_BACKWARD_NO_INTERRUPT,
- [JUMP_FORWARD] = JUMP_FORWARD,
- [KW_NAMES] = KW_NAMES,
- [LIST_APPEND] = LIST_APPEND,
- [LIST_EXTEND] = LIST_EXTEND,
- [LOAD_ASSERTION_ERROR] = LOAD_ASSERTION_ERROR,
- [LOAD_ATTR] = LOAD_ATTR,
- [LOAD_ATTR_CLASS] = LOAD_ATTR,
- [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = LOAD_ATTR,
- [LOAD_ATTR_INSTANCE_VALUE] = LOAD_ATTR,
- [LOAD_ATTR_METHOD_LAZY_DICT] = LOAD_ATTR,
- [LOAD_ATTR_METHOD_NO_DICT] = LOAD_ATTR,
- [LOAD_ATTR_METHOD_WITH_VALUES] = LOAD_ATTR,
- [LOAD_ATTR_MODULE] = LOAD_ATTR,
- [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = LOAD_ATTR,
- [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = LOAD_ATTR,
- [LOAD_ATTR_PROPERTY] = LOAD_ATTR,
- [LOAD_ATTR_SLOT] = LOAD_ATTR,
- [LOAD_ATTR_WITH_HINT] = LOAD_ATTR,
- [LOAD_BUILD_CLASS] = LOAD_BUILD_CLASS,
- [LOAD_CONST] = LOAD_CONST,
- [LOAD_DEREF] = LOAD_DEREF,
- [LOAD_FAST] = LOAD_FAST,
- [LOAD_FAST_AND_CLEAR] = LOAD_FAST_AND_CLEAR,
- [LOAD_FAST_CHECK] = LOAD_FAST_CHECK,
- [LOAD_FAST_LOAD_FAST] = LOAD_FAST_LOAD_FAST,
- [LOAD_FROM_DICT_OR_DEREF] = LOAD_FROM_DICT_OR_DEREF,
- [LOAD_FROM_DICT_OR_GLOBALS] = LOAD_FROM_DICT_OR_GLOBALS,
- [LOAD_GLOBAL] = LOAD_GLOBAL,
- [LOAD_GLOBAL_BUILTIN] = LOAD_GLOBAL,
- [LOAD_GLOBAL_MODULE] = LOAD_GLOBAL,
- [LOAD_LOCALS] = LOAD_LOCALS,
- [LOAD_NAME] = LOAD_NAME,
- [LOAD_SUPER_ATTR] = LOAD_SUPER_ATTR,
- [LOAD_SUPER_ATTR_ATTR] = LOAD_SUPER_ATTR,
- [LOAD_SUPER_ATTR_METHOD] = LOAD_SUPER_ATTR,
- [MAKE_CELL] = MAKE_CELL,
- [MAKE_FUNCTION] = MAKE_FUNCTION,
- [MAP_ADD] = MAP_ADD,
- [MATCH_CLASS] = MATCH_CLASS,
- [MATCH_KEYS] = MATCH_KEYS,
- [MATCH_MAPPING] = MATCH_MAPPING,
- [MATCH_SEQUENCE] = MATCH_SEQUENCE,
- [NOP] = NOP,
- [POP_EXCEPT] = POP_EXCEPT,
- [POP_JUMP_IF_FALSE] = POP_JUMP_IF_FALSE,
- [POP_JUMP_IF_NONE] = POP_JUMP_IF_NONE,
- [POP_JUMP_IF_NOT_NONE] = POP_JUMP_IF_NOT_NONE,
- [POP_JUMP_IF_TRUE] = POP_JUMP_IF_TRUE,
- [POP_TOP] = POP_TOP,
- [PUSH_EXC_INFO] = PUSH_EXC_INFO,
- [PUSH_NULL] = PUSH_NULL,
- [RAISE_VARARGS] = RAISE_VARARGS,
- [RERAISE] = RERAISE,
- [RESERVED] = RESERVED,
- [RESUME] = RESUME,
- [RETURN_CONST] = RETURN_CONST,
- [RETURN_GENERATOR] = RETURN_GENERATOR,
- [RETURN_VALUE] = RETURN_VALUE,
- [SEND] = SEND,
- [SEND_GEN] = SEND,
- [SETUP_ANNOTATIONS] = SETUP_ANNOTATIONS,
- [SET_ADD] = SET_ADD,
- [SET_FUNCTION_ATTRIBUTE] = SET_FUNCTION_ATTRIBUTE,
- [SET_UPDATE] = SET_UPDATE,
- [STORE_ATTR] = STORE_ATTR,
- [STORE_ATTR_INSTANCE_VALUE] = STORE_ATTR,
- [STORE_ATTR_SLOT] = STORE_ATTR,
- [STORE_ATTR_WITH_HINT] = STORE_ATTR,
- [STORE_DEREF] = STORE_DEREF,
- [STORE_FAST] = STORE_FAST,
- [STORE_FAST_LOAD_FAST] = STORE_FAST_LOAD_FAST,
- [STORE_FAST_STORE_FAST] = STORE_FAST_STORE_FAST,
- [STORE_GLOBAL] = STORE_GLOBAL,
- [STORE_NAME] = STORE_NAME,
- [STORE_SLICE] = STORE_SLICE,
- [STORE_SUBSCR] = STORE_SUBSCR,
- [STORE_SUBSCR_DICT] = STORE_SUBSCR,
- [STORE_SUBSCR_LIST_INT] = STORE_SUBSCR,
- [SWAP] = SWAP,
- [TO_BOOL] = TO_BOOL,
- [TO_BOOL_ALWAYS_TRUE] = TO_BOOL,
- [TO_BOOL_BOOL] = TO_BOOL,
- [TO_BOOL_INT] = TO_BOOL,
- [TO_BOOL_LIST] = TO_BOOL,
- [TO_BOOL_NONE] = TO_BOOL,
- [TO_BOOL_STR] = TO_BOOL,
- [UNARY_INVERT] = UNARY_INVERT,
- [UNARY_NEGATIVE] = UNARY_NEGATIVE,
- [UNARY_NOT] = UNARY_NOT,
- [UNPACK_EX] = UNPACK_EX,
- [UNPACK_SEQUENCE] = UNPACK_SEQUENCE,
- [UNPACK_SEQUENCE_LIST] = UNPACK_SEQUENCE,
- [UNPACK_SEQUENCE_TUPLE] = UNPACK_SEQUENCE,
- [UNPACK_SEQUENCE_TWO_TUPLE] = UNPACK_SEQUENCE,
- [WITH_EXCEPT_START] = WITH_EXCEPT_START,
- [YIELD_VALUE] = YIELD_VALUE,
-};
-#endif // NEED_OPCODE_TABLES
-
-
-extern const char *const _PyOpcode_OpName[268];
-
-#ifdef NEED_OPCODE_TABLES
-const char *const _PyOpcode_OpName[268] = {
- [CACHE] = "CACHE",
- [POP_TOP] = "POP_TOP",
- [PUSH_NULL] = "PUSH_NULL",
- [INTERPRETER_EXIT] = "INTERPRETER_EXIT",
- [END_FOR] = "END_FOR",
- [END_SEND] = "END_SEND",
- [TO_BOOL] = "TO_BOOL",
- [TO_BOOL_ALWAYS_TRUE] = "TO_BOOL_ALWAYS_TRUE",
- [TO_BOOL_BOOL] = "TO_BOOL_BOOL",
- [NOP] = "NOP",
- [TO_BOOL_INT] = "TO_BOOL_INT",
- [UNARY_NEGATIVE] = "UNARY_NEGATIVE",
- [UNARY_NOT] = "UNARY_NOT",
- [TO_BOOL_LIST] = "TO_BOOL_LIST",
- [TO_BOOL_NONE] = "TO_BOOL_NONE",
- [UNARY_INVERT] = "UNARY_INVERT",
- [EXIT_INIT_CHECK] = "EXIT_INIT_CHECK",
- [RESERVED] = "RESERVED",
- [TO_BOOL_STR] = "TO_BOOL_STR",
- [BINARY_OP_MULTIPLY_INT] = "BINARY_OP_MULTIPLY_INT",
- [BINARY_OP_ADD_INT] = "BINARY_OP_ADD_INT",
- [BINARY_OP_SUBTRACT_INT] = "BINARY_OP_SUBTRACT_INT",
- [BINARY_OP_MULTIPLY_FLOAT] = "BINARY_OP_MULTIPLY_FLOAT",
- [BINARY_OP_ADD_FLOAT] = "BINARY_OP_ADD_FLOAT",
- [MAKE_FUNCTION] = "MAKE_FUNCTION",
- [BINARY_SUBSCR] = "BINARY_SUBSCR",
- [BINARY_SLICE] = "BINARY_SLICE",
- [STORE_SLICE] = "STORE_SLICE",
- [BINARY_OP_SUBTRACT_FLOAT] = "BINARY_OP_SUBTRACT_FLOAT",
- [BINARY_OP_ADD_UNICODE] = "BINARY_OP_ADD_UNICODE",
- [GET_LEN] = "GET_LEN",
- [MATCH_MAPPING] = "MATCH_MAPPING",
- [MATCH_SEQUENCE] = "MATCH_SEQUENCE",
- [MATCH_KEYS] = "MATCH_KEYS",
- [BINARY_OP_INPLACE_ADD_UNICODE] = "BINARY_OP_INPLACE_ADD_UNICODE",
- [PUSH_EXC_INFO] = "PUSH_EXC_INFO",
- [CHECK_EXC_MATCH] = "CHECK_EXC_MATCH",
- [CHECK_EG_MATCH] = "CHECK_EG_MATCH",
- [BINARY_SUBSCR_DICT] = "BINARY_SUBSCR_DICT",
- [BINARY_SUBSCR_GETITEM] = "BINARY_SUBSCR_GETITEM",
- [FORMAT_SIMPLE] = "FORMAT_SIMPLE",
- [FORMAT_WITH_SPEC] = "FORMAT_WITH_SPEC",
- [BINARY_SUBSCR_LIST_INT] = "BINARY_SUBSCR_LIST_INT",
- [BINARY_SUBSCR_STR_INT] = "BINARY_SUBSCR_STR_INT",
- [BINARY_SUBSCR_TUPLE_INT] = "BINARY_SUBSCR_TUPLE_INT",
- [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT",
- [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT",
- [SEND_GEN] = "SEND_GEN",
- [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE",
- [WITH_EXCEPT_START] = "WITH_EXCEPT_START",
- [GET_AITER] = "GET_AITER",
- [GET_ANEXT] = "GET_ANEXT",
- [BEFORE_ASYNC_WITH] = "BEFORE_ASYNC_WITH",
- [BEFORE_WITH] = "BEFORE_WITH",
- [END_ASYNC_FOR] = "END_ASYNC_FOR",
- [CLEANUP_THROW] = "CLEANUP_THROW",
- [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE",
- [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST",
- [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE",
- [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT",
- [STORE_SUBSCR] = "STORE_SUBSCR",
- [DELETE_SUBSCR] = "DELETE_SUBSCR",
- [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT",
- [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE",
- [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN",
- [LOAD_SUPER_ATTR_ATTR] = "LOAD_SUPER_ATTR_ATTR",
- [LOAD_SUPER_ATTR_METHOD] = "LOAD_SUPER_ATTR_METHOD",
- [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE",
- [GET_ITER] = "GET_ITER",
- [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER",
- [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE",
- [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS",
- [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT",
- [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT",
- [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR",
- [RETURN_GENERATOR] = "RETURN_GENERATOR",
- [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS",
- [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY",
- [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN",
- [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES",
- [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT",
- [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT",
- [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = "LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES",
- [RETURN_VALUE] = "RETURN_VALUE",
- [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = "LOAD_ATTR_NONDESCRIPTOR_NO_DICT",
- [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS",
- [COMPARE_OP_FLOAT] = "COMPARE_OP_FLOAT",
- [LOAD_LOCALS] = "LOAD_LOCALS",
- [COMPARE_OP_INT] = "COMPARE_OP_INT",
- [POP_EXCEPT] = "POP_EXCEPT",
- [STORE_NAME] = "STORE_NAME",
- [DELETE_NAME] = "DELETE_NAME",
- [UNPACK_SEQUENCE] = "UNPACK_SEQUENCE",
- [FOR_ITER] = "FOR_ITER",
- [UNPACK_EX] = "UNPACK_EX",
- [STORE_ATTR] = "STORE_ATTR",
- [DELETE_ATTR] = "DELETE_ATTR",
- [STORE_GLOBAL] = "STORE_GLOBAL",
- [DELETE_GLOBAL] = "DELETE_GLOBAL",
- [SWAP] = "SWAP",
- [LOAD_CONST] = "LOAD_CONST",
- [LOAD_NAME] = "LOAD_NAME",
- [BUILD_TUPLE] = "BUILD_TUPLE",
- [BUILD_LIST] = "BUILD_LIST",
- [BUILD_SET] = "BUILD_SET",
- [BUILD_MAP] = "BUILD_MAP",
- [LOAD_ATTR] = "LOAD_ATTR",
- [COMPARE_OP] = "COMPARE_OP",
- [IMPORT_NAME] = "IMPORT_NAME",
- [IMPORT_FROM] = "IMPORT_FROM",
- [JUMP_FORWARD] = "JUMP_FORWARD",
- [COMPARE_OP_STR] = "COMPARE_OP_STR",
- [FOR_ITER_LIST] = "FOR_ITER_LIST",
- [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE",
- [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE",
- [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE",
- [LOAD_GLOBAL] = "LOAD_GLOBAL",
- [IS_OP] = "IS_OP",
- [CONTAINS_OP] = "CONTAINS_OP",
- [RERAISE] = "RERAISE",
- [COPY] = "COPY",
- [RETURN_CONST] = "RETURN_CONST",
- [BINARY_OP] = "BINARY_OP",
- [SEND] = "SEND",
- [LOAD_FAST] = "LOAD_FAST",
- [STORE_FAST] = "STORE_FAST",
- [DELETE_FAST] = "DELETE_FAST",
- [LOAD_FAST_CHECK] = "LOAD_FAST_CHECK",
- [POP_JUMP_IF_NOT_NONE] = "POP_JUMP_IF_NOT_NONE",
- [POP_JUMP_IF_NONE] = "POP_JUMP_IF_NONE",
- [RAISE_VARARGS] = "RAISE_VARARGS",
- [GET_AWAITABLE] = "GET_AWAITABLE",
- [FOR_ITER_RANGE] = "FOR_ITER_RANGE",
- [BUILD_SLICE] = "BUILD_SLICE",
- [JUMP_BACKWARD_NO_INTERRUPT] = "JUMP_BACKWARD_NO_INTERRUPT",
- [MAKE_CELL] = "MAKE_CELL",
- [FOR_ITER_GEN] = "FOR_ITER_GEN",
- [LOAD_DEREF] = "LOAD_DEREF",
- [STORE_DEREF] = "STORE_DEREF",
- [DELETE_DEREF] = "DELETE_DEREF",
- [JUMP_BACKWARD] = "JUMP_BACKWARD",
- [LOAD_SUPER_ATTR] = "LOAD_SUPER_ATTR",
- [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX",
- [LOAD_FAST_AND_CLEAR] = "LOAD_FAST_AND_CLEAR",
- [EXTENDED_ARG] = "EXTENDED_ARG",
- [LIST_APPEND] = "LIST_APPEND",
- [SET_ADD] = "SET_ADD",
- [MAP_ADD] = "MAP_ADD",
- [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS",
- [COPY_FREE_VARS] = "COPY_FREE_VARS",
- [YIELD_VALUE] = "YIELD_VALUE",
- [RESUME] = "RESUME",
- [MATCH_CLASS] = "MATCH_CLASS",
- [CALL_PY_EXACT_ARGS] = "CALL_PY_EXACT_ARGS",
- [CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS",
- [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1",
- [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP",
- [BUILD_STRING] = "BUILD_STRING",
- [CONVERT_VALUE] = "CONVERT_VALUE",
- [CALL_NO_KW_STR_1] = "CALL_NO_KW_STR_1",
- [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1",
- [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS",
- [LIST_EXTEND] = "LIST_EXTEND",
- [SET_UPDATE] = "SET_UPDATE",
- [DICT_MERGE] = "DICT_MERGE",
- [DICT_UPDATE] = "DICT_UPDATE",
- [CALL_NO_KW_BUILTIN_O] = "CALL_NO_KW_BUILTIN_O",
- [CALL_NO_KW_BUILTIN_FAST] = "CALL_NO_KW_BUILTIN_FAST",
- [LOAD_FAST_LOAD_FAST] = "LOAD_FAST_LOAD_FAST",
- [STORE_FAST_LOAD_FAST] = "STORE_FAST_LOAD_FAST",
- [STORE_FAST_STORE_FAST] = "STORE_FAST_STORE_FAST",
- [CALL] = "CALL",
- [KW_NAMES] = "KW_NAMES",
- [CALL_INTRINSIC_1] = "CALL_INTRINSIC_1",
- [CALL_INTRINSIC_2] = "CALL_INTRINSIC_2",
- [LOAD_FROM_DICT_OR_GLOBALS] = "LOAD_FROM_DICT_OR_GLOBALS",
- [LOAD_FROM_DICT_OR_DEREF] = "LOAD_FROM_DICT_OR_DEREF",
- [SET_FUNCTION_ATTRIBUTE] = "SET_FUNCTION_ATTRIBUTE",
- [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS",
- [CALL_NO_KW_LEN] = "CALL_NO_KW_LEN",
- [CALL_NO_KW_ISINSTANCE] = "CALL_NO_KW_ISINSTANCE",
- [CALL_NO_KW_LIST_APPEND] = "CALL_NO_KW_LIST_APPEND",
- [CALL_NO_KW_METHOD_DESCRIPTOR_O] = "CALL_NO_KW_METHOD_DESCRIPTOR_O",
- [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS",
- [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = "CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS",
- [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = "CALL_NO_KW_METHOD_DESCRIPTOR_FAST",
- [CALL_NO_KW_ALLOC_AND_ENTER_INIT] = "CALL_NO_KW_ALLOC_AND_ENTER_INIT",
- [187] = "<187>",
- [188] = "<188>",
- [189] = "<189>",
- [190] = "<190>",
- [191] = "<191>",
- [192] = "<192>",
- [193] = "<193>",
- [194] = "<194>",
- [195] = "<195>",
- [196] = "<196>",
- [197] = "<197>",
- [198] = "<198>",
- [199] = "<199>",
- [200] = "<200>",
- [201] = "<201>",
- [202] = "<202>",
- [203] = "<203>",
- [204] = "<204>",
- [205] = "<205>",
- [206] = "<206>",
- [207] = "<207>",
- [208] = "<208>",
- [209] = "<209>",
- [210] = "<210>",
- [211] = "<211>",
- [212] = "<212>",
- [213] = "<213>",
- [214] = "<214>",
- [215] = "<215>",
- [216] = "<216>",
- [217] = "<217>",
- [218] = "<218>",
- [219] = "<219>",
- [220] = "<220>",
- [221] = "<221>",
- [222] = "<222>",
- [223] = "<223>",
- [224] = "<224>",
- [225] = "<225>",
- [226] = "<226>",
- [227] = "<227>",
- [228] = "<228>",
- [229] = "<229>",
- [ENTER_EXECUTOR] = "ENTER_EXECUTOR",
- [231] = "<231>",
- [232] = "<232>",
- [233] = "<233>",
- [234] = "<234>",
- [235] = "<235>",
- [236] = "<236>",
- [INSTRUMENTED_LOAD_SUPER_ATTR] = "INSTRUMENTED_LOAD_SUPER_ATTR",
- [INSTRUMENTED_POP_JUMP_IF_NONE] = "INSTRUMENTED_POP_JUMP_IF_NONE",
- [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = "INSTRUMENTED_POP_JUMP_IF_NOT_NONE",
- [INSTRUMENTED_RESUME] = "INSTRUMENTED_RESUME",
- [INSTRUMENTED_CALL] = "INSTRUMENTED_CALL",
- [INSTRUMENTED_RETURN_VALUE] = "INSTRUMENTED_RETURN_VALUE",
- [INSTRUMENTED_YIELD_VALUE] = "INSTRUMENTED_YIELD_VALUE",
- [INSTRUMENTED_CALL_FUNCTION_EX] = "INSTRUMENTED_CALL_FUNCTION_EX",
- [INSTRUMENTED_JUMP_FORWARD] = "INSTRUMENTED_JUMP_FORWARD",
- [INSTRUMENTED_JUMP_BACKWARD] = "INSTRUMENTED_JUMP_BACKWARD",
- [INSTRUMENTED_RETURN_CONST] = "INSTRUMENTED_RETURN_CONST",
- [INSTRUMENTED_FOR_ITER] = "INSTRUMENTED_FOR_ITER",
- [INSTRUMENTED_POP_JUMP_IF_FALSE] = "INSTRUMENTED_POP_JUMP_IF_FALSE",
- [INSTRUMENTED_POP_JUMP_IF_TRUE] = "INSTRUMENTED_POP_JUMP_IF_TRUE",
- [INSTRUMENTED_END_FOR] = "INSTRUMENTED_END_FOR",
- [INSTRUMENTED_END_SEND] = "INSTRUMENTED_END_SEND",
- [INSTRUMENTED_INSTRUCTION] = "INSTRUMENTED_INSTRUCTION",
- [INSTRUMENTED_LINE] = "INSTRUMENTED_LINE",
- [255] = "<255>",
- [SETUP_FINALLY] = "SETUP_FINALLY",
- [SETUP_CLEANUP] = "SETUP_CLEANUP",
- [SETUP_WITH] = "SETUP_WITH",
- [POP_BLOCK] = "POP_BLOCK",
- [JUMP] = "JUMP",
- [JUMP_NO_INTERRUPT] = "JUMP_NO_INTERRUPT",
- [LOAD_METHOD] = "LOAD_METHOD",
- [LOAD_SUPER_METHOD] = "LOAD_SUPER_METHOD",
- [LOAD_ZERO_SUPER_METHOD] = "LOAD_ZERO_SUPER_METHOD",
- [LOAD_ZERO_SUPER_ATTR] = "LOAD_ZERO_SUPER_ATTR",
- [STORE_FAST_MAYBE_NULL] = "STORE_FAST_MAYBE_NULL",
- [LOAD_CLOSURE] = "LOAD_CLOSURE",
-};
#endif // NEED_OPCODE_TABLES
-#define EXTRA_CASES \
- case 187: \
- case 188: \
- case 189: \
- case 190: \
- case 191: \
- case 192: \
- case 193: \
- case 194: \
- case 195: \
- case 196: \
- case 197: \
- case 198: \
- case 199: \
- case 200: \
- case 201: \
- case 202: \
- case 203: \
- case 204: \
- case 205: \
- case 206: \
- case 207: \
- case 208: \
- case 209: \
- case 210: \
- case 211: \
- case 212: \
- case 213: \
- case 214: \
- case 215: \
- case 216: \
- case 217: \
- case 218: \
- case 219: \
- case 220: \
- case 221: \
- case 222: \
- case 223: \
- case 224: \
- case 225: \
- case 226: \
- case 227: \
- case 228: \
- case 229: \
- case 231: \
- case 232: \
- case 233: \
- case 234: \
- case 235: \
- case 236: \
- case 255: \
- ;
-
#ifdef __cplusplus
}
#endif
diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h
index 02303c42c75c8a..afe8aa172b703b 100644
--- a/Include/internal/pycore_opcode_metadata.h
+++ b/Include/internal/pycore_opcode_metadata.h
@@ -52,15 +52,20 @@
#define _ITER_CHECK_RANGE 328
#define _IS_ITER_EXHAUSTED_RANGE 329
#define _ITER_NEXT_RANGE 330
-#define _POP_JUMP_IF_FALSE 331
-#define _POP_JUMP_IF_TRUE 332
-#define JUMP_TO_TOP 333
+#define _CHECK_PEP_523 331
+#define _CHECK_FUNCTION_EXACT_ARGS 332
+#define _CHECK_STACK_SPACE 333
+#define _INIT_CALL_PY_EXACT_ARGS 334
+#define _PUSH_FRAME 335
+#define _POP_JUMP_IF_FALSE 336
+#define _POP_JUMP_IF_TRUE 337
+#define JUMP_TO_TOP 338
+#define SAVE_CURRENT_IP 339
+#define INSERT 340
-#ifndef NEED_OPCODE_METADATA
extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump);
-#else
-int
-_PyOpcode_num_popped(int opcode, int oparg, bool jump) {
+#ifdef NEED_OPCODE_METADATA
+int _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
switch(opcode) {
case NOP:
return 0;
@@ -120,18 +125,38 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return 1;
case UNARY_INVERT:
return 1;
+ case _GUARD_BOTH_INT:
+ return 2;
+ case _BINARY_OP_MULTIPLY_INT:
+ return 2;
+ case _BINARY_OP_ADD_INT:
+ return 2;
+ case _BINARY_OP_SUBTRACT_INT:
+ return 2;
case BINARY_OP_MULTIPLY_INT:
return 2;
case BINARY_OP_ADD_INT:
return 2;
case BINARY_OP_SUBTRACT_INT:
return 2;
+ case _GUARD_BOTH_FLOAT:
+ return 2;
+ case _BINARY_OP_MULTIPLY_FLOAT:
+ return 2;
+ case _BINARY_OP_ADD_FLOAT:
+ return 2;
+ case _BINARY_OP_SUBTRACT_FLOAT:
+ return 2;
case BINARY_OP_MULTIPLY_FLOAT:
return 2;
case BINARY_OP_ADD_FLOAT:
return 2;
case BINARY_OP_SUBTRACT_FLOAT:
return 2;
+ case _GUARD_BOTH_UNICODE:
+ return 2;
+ case _BINARY_OP_ADD_UNICODE:
+ return 2;
case BINARY_OP_ADD_UNICODE:
return 2;
case BINARY_OP_INPLACE_ADD_UNICODE:
@@ -228,14 +253,26 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return 1;
case DELETE_GLOBAL:
return 0;
+ case _LOAD_LOCALS:
+ return 0;
case LOAD_LOCALS:
return 0;
+ case _LOAD_FROM_DICT_OR_GLOBALS:
+ return 1;
case LOAD_NAME:
return 0;
case LOAD_FROM_DICT_OR_GLOBALS:
return 1;
case LOAD_GLOBAL:
return 0;
+ case _GUARD_GLOBALS_VERSION:
+ return 0;
+ case _GUARD_BUILTINS_VERSION:
+ return 0;
+ case _LOAD_GLOBAL_MODULE:
+ return 0;
+ case _LOAD_GLOBAL_BUILTINS:
+ return 0;
case LOAD_GLOBAL_MODULE:
return 0;
case LOAD_GLOBAL_BUILTIN:
@@ -273,11 +310,11 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
case BUILD_CONST_KEY_MAP:
return oparg + 1;
case DICT_UPDATE:
- return 1;
+ return (oparg - 1) + 2;
case DICT_MERGE:
- return 1;
+ return (oparg - 1) + 5;
case MAP_ADD:
- return 2;
+ return (oparg - 1) + 3;
case INSTRUMENTED_LOAD_SUPER_ATTR:
return 3;
case LOAD_SUPER_ATTR:
@@ -296,6 +333,12 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return 1;
case LOAD_METHOD:
return 1;
+ case _GUARD_TYPE_VERSION:
+ return 1;
+ case _CHECK_MANAGED_OBJECT_HAS_VALUES:
+ return 1;
+ case _LOAD_ATTR_INSTANCE_VALUE:
+ return 1;
case LOAD_ATTR_INSTANCE_VALUE:
return 1;
case LOAD_ATTR_MODULE:
@@ -350,6 +393,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return 1;
case POP_JUMP_IF_TRUE:
return 1;
+ case IS_NONE:
+ return 1;
case POP_JUMP_IF_NONE:
return 1;
case POP_JUMP_IF_NOT_NONE:
@@ -374,10 +419,28 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return 1;
case INSTRUMENTED_FOR_ITER:
return 0;
+ case _ITER_CHECK_LIST:
+ return 1;
+ case _IS_ITER_EXHAUSTED_LIST:
+ return 1;
+ case _ITER_NEXT_LIST:
+ return 1;
case FOR_ITER_LIST:
return 1;
+ case _ITER_CHECK_TUPLE:
+ return 1;
+ case _IS_ITER_EXHAUSTED_TUPLE:
+ return 1;
+ case _ITER_NEXT_TUPLE:
+ return 1;
case FOR_ITER_TUPLE:
return 1;
+ case _ITER_CHECK_RANGE:
+ return 1;
+ case _IS_ITER_EXHAUSTED_RANGE:
+ return 1;
+ case _ITER_NEXT_RANGE:
+ return 1;
case FOR_ITER_RANGE:
return 1;
case FOR_ITER_GEN:
@@ -416,6 +479,16 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return oparg + 2;
case CALL_BOUND_METHOD_EXACT_ARGS:
return oparg + 2;
+ case _CHECK_PEP_523:
+ return 0;
+ case _CHECK_FUNCTION_EXACT_ARGS:
+ return oparg + 2;
+ case _CHECK_STACK_SPACE:
+ return oparg + 2;
+ case _INIT_CALL_PY_EXACT_ARGS:
+ return oparg + 2;
+ case _PUSH_FRAME:
+ return 1;
case CALL_PY_EXACT_ARGS:
return oparg + 2;
case CALL_PY_WITH_DEFAULTS:
@@ -496,17 +569,29 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return 0;
case RESERVED:
return 0;
+ case _POP_JUMP_IF_FALSE:
+ return 1;
+ case _POP_JUMP_IF_TRUE:
+ return 1;
+ case JUMP_TO_TOP:
+ return 0;
+ case SAVE_IP:
+ return 0;
+ case SAVE_CURRENT_IP:
+ return 0;
+ case EXIT_TRACE:
+ return 0;
+ case INSERT:
+ return oparg + 1;
default:
return -1;
}
}
-#endif
+#endif // NEED_OPCODE_METADATA
-#ifndef NEED_OPCODE_METADATA
extern int _PyOpcode_num_pushed(int opcode, int oparg, bool jump);
-#else
-int
-_PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
+#ifdef NEED_OPCODE_METADATA
+int _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
switch(opcode) {
case NOP:
return 0;
@@ -566,18 +651,38 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
return 1;
case UNARY_INVERT:
return 1;
+ case _GUARD_BOTH_INT:
+ return 2;
+ case _BINARY_OP_MULTIPLY_INT:
+ return 1;
+ case _BINARY_OP_ADD_INT:
+ return 1;
+ case _BINARY_OP_SUBTRACT_INT:
+ return 1;
case BINARY_OP_MULTIPLY_INT:
return 1;
case BINARY_OP_ADD_INT:
return 1;
case BINARY_OP_SUBTRACT_INT:
return 1;
+ case _GUARD_BOTH_FLOAT:
+ return 2;
+ case _BINARY_OP_MULTIPLY_FLOAT:
+ return 1;
+ case _BINARY_OP_ADD_FLOAT:
+ return 1;
+ case _BINARY_OP_SUBTRACT_FLOAT:
+ return 1;
case BINARY_OP_MULTIPLY_FLOAT:
return 1;
case BINARY_OP_ADD_FLOAT:
return 1;
case BINARY_OP_SUBTRACT_FLOAT:
return 1;
+ case _GUARD_BOTH_UNICODE:
+ return 2;
+ case _BINARY_OP_ADD_UNICODE:
+ return 1;
case BINARY_OP_ADD_UNICODE:
return 1;
case BINARY_OP_INPLACE_ADD_UNICODE:
@@ -674,14 +779,26 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
return 0;
case DELETE_GLOBAL:
return 0;
+ case _LOAD_LOCALS:
+ return 1;
case LOAD_LOCALS:
return 1;
+ case _LOAD_FROM_DICT_OR_GLOBALS:
+ return 1;
case LOAD_NAME:
return 1;
case LOAD_FROM_DICT_OR_GLOBALS:
return 1;
case LOAD_GLOBAL:
return ((oparg & 1) ? 1 : 0) + 1;
+ case _GUARD_GLOBALS_VERSION:
+ return 0;
+ case _GUARD_BUILTINS_VERSION:
+ return 0;
+ case _LOAD_GLOBAL_MODULE:
+ return ((oparg & 1) ? 1 : 0) + 1;
+ case _LOAD_GLOBAL_BUILTINS:
+ return ((oparg & 1) ? 1 : 0) + 1;
case LOAD_GLOBAL_MODULE:
return (oparg & 1 ? 1 : 0) + 1;
case LOAD_GLOBAL_BUILTIN:
@@ -719,11 +836,11 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
case BUILD_CONST_KEY_MAP:
return 1;
case DICT_UPDATE:
- return 0;
+ return (oparg - 1) + 1;
case DICT_MERGE:
- return 0;
+ return (oparg - 1) + 4;
case MAP_ADD:
- return 0;
+ return (oparg - 1) + 1;
case INSTRUMENTED_LOAD_SUPER_ATTR:
return ((oparg & 1) ? 1 : 0) + 1;
case LOAD_SUPER_ATTR:
@@ -735,13 +852,19 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
case LOAD_ZERO_SUPER_ATTR:
return ((oparg & 1) ? 1 : 0) + 1;
case LOAD_SUPER_ATTR_ATTR:
- return ((oparg & 1) ? 1 : 0) + 1;
+ return 1;
case LOAD_SUPER_ATTR_METHOD:
return 2;
case LOAD_ATTR:
return ((oparg & 1) ? 1 : 0) + 1;
case LOAD_METHOD:
return ((oparg & 1) ? 1 : 0) + 1;
+ case _GUARD_TYPE_VERSION:
+ return 1;
+ case _CHECK_MANAGED_OBJECT_HAS_VALUES:
+ return 1;
+ case _LOAD_ATTR_INSTANCE_VALUE:
+ return ((oparg & 1) ? 1 : 0) + 1;
case LOAD_ATTR_INSTANCE_VALUE:
return (oparg & 1 ? 1 : 0) + 1;
case LOAD_ATTR_MODULE:
@@ -753,9 +876,9 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
case LOAD_ATTR_CLASS:
return ((oparg & 1) ? 1 : 0) + 1;
case LOAD_ATTR_PROPERTY:
- return ((oparg & 1) ? 1 : 0) + 1;
+ return 1;
case LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN:
- return ((oparg & 1) ? 1 : 0) + 1;
+ return 1;
case STORE_ATTR_INSTANCE_VALUE:
return 0;
case STORE_ATTR_WITH_HINT:
@@ -796,6 +919,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
return 0;
case POP_JUMP_IF_TRUE:
return 0;
+ case IS_NONE:
+ return 1;
case POP_JUMP_IF_NONE:
return 0;
case POP_JUMP_IF_NOT_NONE:
@@ -820,10 +945,28 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
return 2;
case INSTRUMENTED_FOR_ITER:
return 0;
+ case _ITER_CHECK_LIST:
+ return 1;
+ case _IS_ITER_EXHAUSTED_LIST:
+ return 2;
+ case _ITER_NEXT_LIST:
+ return 2;
case FOR_ITER_LIST:
return 2;
+ case _ITER_CHECK_TUPLE:
+ return 1;
+ case _IS_ITER_EXHAUSTED_TUPLE:
+ return 2;
+ case _ITER_NEXT_TUPLE:
+ return 2;
case FOR_ITER_TUPLE:
return 2;
+ case _ITER_CHECK_RANGE:
+ return 1;
+ case _IS_ITER_EXHAUSTED_RANGE:
+ return 2;
+ case _ITER_NEXT_RANGE:
+ return 2;
case FOR_ITER_RANGE:
return 2;
case FOR_ITER_GEN:
@@ -862,6 +1005,16 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
return 1;
case CALL_BOUND_METHOD_EXACT_ARGS:
return 1;
+ case _CHECK_PEP_523:
+ return 0;
+ case _CHECK_FUNCTION_EXACT_ARGS:
+ return oparg + 2;
+ case _CHECK_STACK_SPACE:
+ return oparg + 2;
+ case _INIT_CALL_PY_EXACT_ARGS:
+ return 1;
+ case _PUSH_FRAME:
+ return 1;
case CALL_PY_EXACT_ARGS:
return 1;
case CALL_PY_WITH_DEFAULTS:
@@ -942,15 +1095,30 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
return 0;
case RESERVED:
return 0;
+ case _POP_JUMP_IF_FALSE:
+ return 0;
+ case _POP_JUMP_IF_TRUE:
+ return 0;
+ case JUMP_TO_TOP:
+ return 0;
+ case SAVE_IP:
+ return 0;
+ case SAVE_CURRENT_IP:
+ return 0;
+ case EXIT_TRACE:
+ return 0;
+ case INSERT:
+ return oparg + 1;
default:
return -1;
}
}
-#endif
+#endif // NEED_OPCODE_METADATA
enum InstructionFormat {
INSTR_FMT_IB,
INSTR_FMT_IBC,
+ INSTR_FMT_IBC0,
INSTR_FMT_IBC00,
INSTR_FMT_IBC000,
INSTR_FMT_IBC00000000,
@@ -995,6 +1163,7 @@ struct opcode_macro_expansion {
#define OPARG_CACHE_4 4
#define OPARG_TOP 5
#define OPARG_BOTTOM 6
+#define OPARG_SAVE_IP 7
#define OPCODE_METADATA_FMT(OP) (_PyOpcode_opcode_metadata[(OP)].instr_format)
#define SAME_OPCODE_METADATA(OP1, OP2) \
@@ -1004,11 +1173,8 @@ struct opcode_macro_expansion {
#define OPCODE_UOP_NAME_SIZE 512
#define OPCODE_MACRO_EXPANSION_SIZE 256
-#ifndef NEED_OPCODE_METADATA
extern const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE];
-extern const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPANSION_SIZE];
-extern const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE];
-#else // if NEED_OPCODE_METADATA
+#ifdef NEED_OPCODE_METADATA
const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = {
[NOP] = { true, INSTR_FMT_IX, 0 },
[RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
@@ -1228,6 +1394,10 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = {
[CACHE] = { true, INSTR_FMT_IX, 0 },
[RESERVED] = { true, INSTR_FMT_IX, 0 },
};
+#endif // NEED_OPCODE_METADATA
+
+extern const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPANSION_SIZE];
+#ifdef NEED_OPCODE_METADATA
const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPANSION_SIZE] = {
[NOP] = { .nuops = 1, .uops = { { NOP, 0, 0 } } },
[LOAD_FAST_CHECK] = { .nuops = 1, .uops = { { LOAD_FAST_CHECK, 0, 0 } } },
@@ -1336,6 +1506,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN
[GET_YIELD_FROM_ITER] = { .nuops = 1, .uops = { { GET_YIELD_FROM_ITER, 0, 0 } } },
[WITH_EXCEPT_START] = { .nuops = 1, .uops = { { WITH_EXCEPT_START, 0, 0 } } },
[PUSH_EXC_INFO] = { .nuops = 1, .uops = { { PUSH_EXC_INFO, 0, 0 } } },
+ [CALL_PY_EXACT_ARGS] = { .nuops = 7, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 }, { _CHECK_STACK_SPACE, 0, 0 }, { _INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { SAVE_IP, 7, 3 }, { SAVE_CURRENT_IP, 0, 0 }, { _PUSH_FRAME, 0, 0 } } },
[CALL_NO_KW_TYPE_1] = { .nuops = 1, .uops = { { CALL_NO_KW_TYPE_1, 0, 0 } } },
[CALL_NO_KW_STR_1] = { .nuops = 1, .uops = { { CALL_NO_KW_STR_1, 0, 0 } } },
[CALL_NO_KW_TUPLE_1] = { .nuops = 1, .uops = { { CALL_NO_KW_TUPLE_1, 0, 0 } } },
@@ -1357,6 +1528,10 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN
[BINARY_OP] = { .nuops = 1, .uops = { { BINARY_OP, 0, 0 } } },
[SWAP] = { .nuops = 1, .uops = { { SWAP, 0, 0 } } },
};
+#endif // NEED_OPCODE_METADATA
+
+extern const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE];
+#ifdef NEED_OPCODE_METADATA
const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE] = {
[EXIT_TRACE] = "EXIT_TRACE",
[SAVE_IP] = "SAVE_IP",
@@ -1389,8 +1564,505 @@ const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE] = {
[_ITER_CHECK_RANGE] = "_ITER_CHECK_RANGE",
[_IS_ITER_EXHAUSTED_RANGE] = "_IS_ITER_EXHAUSTED_RANGE",
[_ITER_NEXT_RANGE] = "_ITER_NEXT_RANGE",
+ [_CHECK_PEP_523] = "_CHECK_PEP_523",
+ [_CHECK_FUNCTION_EXACT_ARGS] = "_CHECK_FUNCTION_EXACT_ARGS",
+ [_CHECK_STACK_SPACE] = "_CHECK_STACK_SPACE",
+ [_INIT_CALL_PY_EXACT_ARGS] = "_INIT_CALL_PY_EXACT_ARGS",
+ [_PUSH_FRAME] = "_PUSH_FRAME",
[_POP_JUMP_IF_FALSE] = "_POP_JUMP_IF_FALSE",
[_POP_JUMP_IF_TRUE] = "_POP_JUMP_IF_TRUE",
[JUMP_TO_TOP] = "JUMP_TO_TOP",
+ [SAVE_CURRENT_IP] = "SAVE_CURRENT_IP",
+ [INSERT] = "INSERT",
+};
+#endif // NEED_OPCODE_METADATA
+
+extern const char *const _PyOpcode_OpName[268];
+#ifdef NEED_OPCODE_METADATA
+const char *const _PyOpcode_OpName[268] = {
+ [CACHE] = "CACHE",
+ [RESERVED] = "RESERVED",
+ [RESUME] = "RESUME",
+ [BEFORE_ASYNC_WITH] = "BEFORE_ASYNC_WITH",
+ [BEFORE_WITH] = "BEFORE_WITH",
+ [BINARY_OP_ADD_FLOAT] = "BINARY_OP_ADD_FLOAT",
+ [BINARY_OP_ADD_INT] = "BINARY_OP_ADD_INT",
+ [BINARY_OP_ADD_UNICODE] = "BINARY_OP_ADD_UNICODE",
+ [BINARY_OP_INPLACE_ADD_UNICODE] = "BINARY_OP_INPLACE_ADD_UNICODE",
+ [BINARY_OP_MULTIPLY_FLOAT] = "BINARY_OP_MULTIPLY_FLOAT",
+ [BINARY_OP_MULTIPLY_INT] = "BINARY_OP_MULTIPLY_INT",
+ [BINARY_OP_SUBTRACT_FLOAT] = "BINARY_OP_SUBTRACT_FLOAT",
+ [BINARY_OP_SUBTRACT_INT] = "BINARY_OP_SUBTRACT_INT",
+ [BINARY_SLICE] = "BINARY_SLICE",
+ [BINARY_SUBSCR] = "BINARY_SUBSCR",
+ [BINARY_SUBSCR_DICT] = "BINARY_SUBSCR_DICT",
+ [BINARY_SUBSCR_GETITEM] = "BINARY_SUBSCR_GETITEM",
+ [BINARY_SUBSCR_LIST_INT] = "BINARY_SUBSCR_LIST_INT",
+ [BINARY_SUBSCR_STR_INT] = "BINARY_SUBSCR_STR_INT",
+ [BINARY_SUBSCR_TUPLE_INT] = "BINARY_SUBSCR_TUPLE_INT",
+ [CHECK_EG_MATCH] = "CHECK_EG_MATCH",
+ [CHECK_EXC_MATCH] = "CHECK_EXC_MATCH",
+ [CLEANUP_THROW] = "CLEANUP_THROW",
+ [DELETE_SUBSCR] = "DELETE_SUBSCR",
+ [END_ASYNC_FOR] = "END_ASYNC_FOR",
+ [END_FOR] = "END_FOR",
+ [END_SEND] = "END_SEND",
+ [EXIT_INIT_CHECK] = "EXIT_INIT_CHECK",
+ [FORMAT_SIMPLE] = "FORMAT_SIMPLE",
+ [FORMAT_WITH_SPEC] = "FORMAT_WITH_SPEC",
+ [GET_AITER] = "GET_AITER",
+ [GET_ANEXT] = "GET_ANEXT",
+ [GET_ITER] = "GET_ITER",
+ [GET_LEN] = "GET_LEN",
+ [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER",
+ [INTERPRETER_EXIT] = "INTERPRETER_EXIT",
+ [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR",
+ [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS",
+ [LOAD_LOCALS] = "LOAD_LOCALS",
+ [MAKE_FUNCTION] = "MAKE_FUNCTION",
+ [MATCH_KEYS] = "MATCH_KEYS",
+ [MATCH_MAPPING] = "MATCH_MAPPING",
+ [MATCH_SEQUENCE] = "MATCH_SEQUENCE",
+ [NOP] = "NOP",
+ [POP_EXCEPT] = "POP_EXCEPT",
+ [POP_TOP] = "POP_TOP",
+ [PUSH_EXC_INFO] = "PUSH_EXC_INFO",
+ [PUSH_NULL] = "PUSH_NULL",
+ [RETURN_GENERATOR] = "RETURN_GENERATOR",
+ [RETURN_VALUE] = "RETURN_VALUE",
+ [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS",
+ [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE",
+ [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT",
+ [STORE_SLICE] = "STORE_SLICE",
+ [STORE_SUBSCR] = "STORE_SUBSCR",
+ [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT",
+ [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT",
+ [TO_BOOL] = "TO_BOOL",
+ [TO_BOOL_ALWAYS_TRUE] = "TO_BOOL_ALWAYS_TRUE",
+ [TO_BOOL_BOOL] = "TO_BOOL_BOOL",
+ [TO_BOOL_INT] = "TO_BOOL_INT",
+ [TO_BOOL_LIST] = "TO_BOOL_LIST",
+ [TO_BOOL_NONE] = "TO_BOOL_NONE",
+ [TO_BOOL_STR] = "TO_BOOL_STR",
+ [UNARY_INVERT] = "UNARY_INVERT",
+ [UNARY_NEGATIVE] = "UNARY_NEGATIVE",
+ [UNARY_NOT] = "UNARY_NOT",
+ [WITH_EXCEPT_START] = "WITH_EXCEPT_START",
+ [BINARY_OP] = "BINARY_OP",
+ [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP",
+ [BUILD_LIST] = "BUILD_LIST",
+ [BUILD_MAP] = "BUILD_MAP",
+ [BUILD_SET] = "BUILD_SET",
+ [BUILD_SLICE] = "BUILD_SLICE",
+ [BUILD_STRING] = "BUILD_STRING",
+ [BUILD_TUPLE] = "BUILD_TUPLE",
+ [CALL] = "CALL",
+ [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS",
+ [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS",
+ [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS",
+ [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX",
+ [CALL_INTRINSIC_1] = "CALL_INTRINSIC_1",
+ [CALL_INTRINSIC_2] = "CALL_INTRINSIC_2",
+ [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS",
+ [CALL_NO_KW_ALLOC_AND_ENTER_INIT] = "CALL_NO_KW_ALLOC_AND_ENTER_INIT",
+ [CALL_NO_KW_BUILTIN_FAST] = "CALL_NO_KW_BUILTIN_FAST",
+ [CALL_NO_KW_BUILTIN_O] = "CALL_NO_KW_BUILTIN_O",
+ [CALL_NO_KW_ISINSTANCE] = "CALL_NO_KW_ISINSTANCE",
+ [CALL_NO_KW_LEN] = "CALL_NO_KW_LEN",
+ [CALL_NO_KW_LIST_APPEND] = "CALL_NO_KW_LIST_APPEND",
+ [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = "CALL_NO_KW_METHOD_DESCRIPTOR_FAST",
+ [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = "CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS",
+ [CALL_NO_KW_METHOD_DESCRIPTOR_O] = "CALL_NO_KW_METHOD_DESCRIPTOR_O",
+ [CALL_NO_KW_STR_1] = "CALL_NO_KW_STR_1",
+ [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1",
+ [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1",
+ [CALL_PY_EXACT_ARGS] = "CALL_PY_EXACT_ARGS",
+ [CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS",
+ [COMPARE_OP] = "COMPARE_OP",
+ [COMPARE_OP_FLOAT] = "COMPARE_OP_FLOAT",
+ [COMPARE_OP_INT] = "COMPARE_OP_INT",
+ [COMPARE_OP_STR] = "COMPARE_OP_STR",
+ [CONTAINS_OP] = "CONTAINS_OP",
+ [CONVERT_VALUE] = "CONVERT_VALUE",
+ [COPY] = "COPY",
+ [COPY_FREE_VARS] = "COPY_FREE_VARS",
+ [DELETE_ATTR] = "DELETE_ATTR",
+ [DELETE_DEREF] = "DELETE_DEREF",
+ [DELETE_FAST] = "DELETE_FAST",
+ [DELETE_GLOBAL] = "DELETE_GLOBAL",
+ [DELETE_NAME] = "DELETE_NAME",
+ [DICT_MERGE] = "DICT_MERGE",
+ [DICT_UPDATE] = "DICT_UPDATE",
+ [ENTER_EXECUTOR] = "ENTER_EXECUTOR",
+ [EXTENDED_ARG] = "EXTENDED_ARG",
+ [FOR_ITER] = "FOR_ITER",
+ [FOR_ITER_GEN] = "FOR_ITER_GEN",
+ [FOR_ITER_LIST] = "FOR_ITER_LIST",
+ [FOR_ITER_RANGE] = "FOR_ITER_RANGE",
+ [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE",
+ [GET_AWAITABLE] = "GET_AWAITABLE",
+ [IMPORT_FROM] = "IMPORT_FROM",
+ [IMPORT_NAME] = "IMPORT_NAME",
+ [IS_OP] = "IS_OP",
+ [JUMP_BACKWARD] = "JUMP_BACKWARD",
+ [JUMP_BACKWARD_NO_INTERRUPT] = "JUMP_BACKWARD_NO_INTERRUPT",
+ [JUMP_FORWARD] = "JUMP_FORWARD",
+ [KW_NAMES] = "KW_NAMES",
+ [LIST_APPEND] = "LIST_APPEND",
+ [LIST_EXTEND] = "LIST_EXTEND",
+ [LOAD_ATTR] = "LOAD_ATTR",
+ [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS",
+ [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN",
+ [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE",
+ [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT",
+ [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT",
+ [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES",
+ [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE",
+ [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = "LOAD_ATTR_NONDESCRIPTOR_NO_DICT",
+ [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = "LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES",
+ [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY",
+ [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT",
+ [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT",
+ [LOAD_CONST] = "LOAD_CONST",
+ [LOAD_DEREF] = "LOAD_DEREF",
+ [LOAD_FAST] = "LOAD_FAST",
+ [LOAD_FAST_AND_CLEAR] = "LOAD_FAST_AND_CLEAR",
+ [LOAD_FAST_CHECK] = "LOAD_FAST_CHECK",
+ [LOAD_FAST_LOAD_FAST] = "LOAD_FAST_LOAD_FAST",
+ [LOAD_FROM_DICT_OR_DEREF] = "LOAD_FROM_DICT_OR_DEREF",
+ [LOAD_FROM_DICT_OR_GLOBALS] = "LOAD_FROM_DICT_OR_GLOBALS",
+ [LOAD_GLOBAL] = "LOAD_GLOBAL",
+ [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN",
+ [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE",
+ [LOAD_NAME] = "LOAD_NAME",
+ [LOAD_SUPER_ATTR] = "LOAD_SUPER_ATTR",
+ [LOAD_SUPER_ATTR_ATTR] = "LOAD_SUPER_ATTR_ATTR",
+ [LOAD_SUPER_ATTR_METHOD] = "LOAD_SUPER_ATTR_METHOD",
+ [MAKE_CELL] = "MAKE_CELL",
+ [MAP_ADD] = "MAP_ADD",
+ [MATCH_CLASS] = "MATCH_CLASS",
+ [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE",
+ [POP_JUMP_IF_NONE] = "POP_JUMP_IF_NONE",
+ [POP_JUMP_IF_NOT_NONE] = "POP_JUMP_IF_NOT_NONE",
+ [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE",
+ [RAISE_VARARGS] = "RAISE_VARARGS",
+ [RERAISE] = "RERAISE",
+ [RETURN_CONST] = "RETURN_CONST",
+ [SEND] = "SEND",
+ [SEND_GEN] = "SEND_GEN",
+ [SET_ADD] = "SET_ADD",
+ [SET_FUNCTION_ATTRIBUTE] = "SET_FUNCTION_ATTRIBUTE",
+ [SET_UPDATE] = "SET_UPDATE",
+ [STORE_ATTR] = "STORE_ATTR",
+ [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT",
+ [STORE_DEREF] = "STORE_DEREF",
+ [STORE_FAST] = "STORE_FAST",
+ [STORE_FAST_LOAD_FAST] = "STORE_FAST_LOAD_FAST",
+ [STORE_FAST_STORE_FAST] = "STORE_FAST_STORE_FAST",
+ [STORE_GLOBAL] = "STORE_GLOBAL",
+ [STORE_NAME] = "STORE_NAME",
+ [SWAP] = "SWAP",
+ [UNPACK_EX] = "UNPACK_EX",
+ [UNPACK_SEQUENCE] = "UNPACK_SEQUENCE",
+ [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST",
+ [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE",
+ [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE",
+ [YIELD_VALUE] = "YIELD_VALUE",
+ [INSTRUMENTED_RESUME] = "INSTRUMENTED_RESUME",
+ [INSTRUMENTED_END_FOR] = "INSTRUMENTED_END_FOR",
+ [INSTRUMENTED_END_SEND] = "INSTRUMENTED_END_SEND",
+ [INSTRUMENTED_RETURN_VALUE] = "INSTRUMENTED_RETURN_VALUE",
+ [INSTRUMENTED_RETURN_CONST] = "INSTRUMENTED_RETURN_CONST",
+ [INSTRUMENTED_YIELD_VALUE] = "INSTRUMENTED_YIELD_VALUE",
+ [INSTRUMENTED_LOAD_SUPER_ATTR] = "INSTRUMENTED_LOAD_SUPER_ATTR",
+ [INSTRUMENTED_FOR_ITER] = "INSTRUMENTED_FOR_ITER",
+ [INSTRUMENTED_CALL] = "INSTRUMENTED_CALL",
+ [INSTRUMENTED_CALL_FUNCTION_EX] = "INSTRUMENTED_CALL_FUNCTION_EX",
+ [INSTRUMENTED_INSTRUCTION] = "INSTRUMENTED_INSTRUCTION",
+ [INSTRUMENTED_JUMP_FORWARD] = "INSTRUMENTED_JUMP_FORWARD",
+ [INSTRUMENTED_JUMP_BACKWARD] = "INSTRUMENTED_JUMP_BACKWARD",
+ [INSTRUMENTED_POP_JUMP_IF_TRUE] = "INSTRUMENTED_POP_JUMP_IF_TRUE",
+ [INSTRUMENTED_POP_JUMP_IF_FALSE] = "INSTRUMENTED_POP_JUMP_IF_FALSE",
+ [INSTRUMENTED_POP_JUMP_IF_NONE] = "INSTRUMENTED_POP_JUMP_IF_NONE",
+ [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = "INSTRUMENTED_POP_JUMP_IF_NOT_NONE",
+ [INSTRUMENTED_LINE] = "INSTRUMENTED_LINE",
+ [JUMP] = "JUMP",
+ [JUMP_NO_INTERRUPT] = "JUMP_NO_INTERRUPT",
+ [LOAD_CLOSURE] = "LOAD_CLOSURE",
+ [LOAD_METHOD] = "LOAD_METHOD",
+ [LOAD_SUPER_METHOD] = "LOAD_SUPER_METHOD",
+ [LOAD_ZERO_SUPER_ATTR] = "LOAD_ZERO_SUPER_ATTR",
+ [LOAD_ZERO_SUPER_METHOD] = "LOAD_ZERO_SUPER_METHOD",
+ [POP_BLOCK] = "POP_BLOCK",
+ [SETUP_CLEANUP] = "SETUP_CLEANUP",
+ [SETUP_FINALLY] = "SETUP_FINALLY",
+ [SETUP_WITH] = "SETUP_WITH",
+ [STORE_FAST_MAYBE_NULL] = "STORE_FAST_MAYBE_NULL",
};
#endif // NEED_OPCODE_METADATA
+
+extern const uint8_t _PyOpcode_Deopt[256];
+#ifdef NEED_OPCODE_METADATA
+const uint8_t _PyOpcode_Deopt[256] = {
+ [BEFORE_ASYNC_WITH] = BEFORE_ASYNC_WITH,
+ [BEFORE_WITH] = BEFORE_WITH,
+ [BINARY_OP] = BINARY_OP,
+ [BINARY_OP_ADD_FLOAT] = BINARY_OP,
+ [BINARY_OP_ADD_INT] = BINARY_OP,
+ [BINARY_OP_ADD_UNICODE] = BINARY_OP,
+ [BINARY_OP_INPLACE_ADD_UNICODE] = BINARY_OP,
+ [BINARY_OP_MULTIPLY_FLOAT] = BINARY_OP,
+ [BINARY_OP_MULTIPLY_INT] = BINARY_OP,
+ [BINARY_OP_SUBTRACT_FLOAT] = BINARY_OP,
+ [BINARY_OP_SUBTRACT_INT] = BINARY_OP,
+ [BINARY_SLICE] = BINARY_SLICE,
+ [BINARY_SUBSCR] = BINARY_SUBSCR,
+ [BINARY_SUBSCR_DICT] = BINARY_SUBSCR,
+ [BINARY_SUBSCR_GETITEM] = BINARY_SUBSCR,
+ [BINARY_SUBSCR_LIST_INT] = BINARY_SUBSCR,
+ [BINARY_SUBSCR_STR_INT] = BINARY_SUBSCR,
+ [BINARY_SUBSCR_TUPLE_INT] = BINARY_SUBSCR,
+ [BUILD_CONST_KEY_MAP] = BUILD_CONST_KEY_MAP,
+ [BUILD_LIST] = BUILD_LIST,
+ [BUILD_MAP] = BUILD_MAP,
+ [BUILD_SET] = BUILD_SET,
+ [BUILD_SLICE] = BUILD_SLICE,
+ [BUILD_STRING] = BUILD_STRING,
+ [BUILD_TUPLE] = BUILD_TUPLE,
+ [CACHE] = CACHE,
+ [CALL] = CALL,
+ [CALL_BOUND_METHOD_EXACT_ARGS] = CALL,
+ [CALL_BUILTIN_CLASS] = CALL,
+ [CALL_BUILTIN_FAST_WITH_KEYWORDS] = CALL,
+ [CALL_FUNCTION_EX] = CALL_FUNCTION_EX,
+ [CALL_INTRINSIC_1] = CALL_INTRINSIC_1,
+ [CALL_INTRINSIC_2] = CALL_INTRINSIC_2,
+ [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = CALL,
+ [CALL_NO_KW_ALLOC_AND_ENTER_INIT] = CALL,
+ [CALL_NO_KW_BUILTIN_FAST] = CALL,
+ [CALL_NO_KW_BUILTIN_O] = CALL,
+ [CALL_NO_KW_ISINSTANCE] = CALL,
+ [CALL_NO_KW_LEN] = CALL,
+ [CALL_NO_KW_LIST_APPEND] = CALL,
+ [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = CALL,
+ [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = CALL,
+ [CALL_NO_KW_METHOD_DESCRIPTOR_O] = CALL,
+ [CALL_NO_KW_STR_1] = CALL,
+ [CALL_NO_KW_TUPLE_1] = CALL,
+ [CALL_NO_KW_TYPE_1] = CALL,
+ [CALL_PY_EXACT_ARGS] = CALL,
+ [CALL_PY_WITH_DEFAULTS] = CALL,
+ [CHECK_EG_MATCH] = CHECK_EG_MATCH,
+ [CHECK_EXC_MATCH] = CHECK_EXC_MATCH,
+ [CLEANUP_THROW] = CLEANUP_THROW,
+ [COMPARE_OP] = COMPARE_OP,
+ [COMPARE_OP_FLOAT] = COMPARE_OP,
+ [COMPARE_OP_INT] = COMPARE_OP,
+ [COMPARE_OP_STR] = COMPARE_OP,
+ [CONTAINS_OP] = CONTAINS_OP,
+ [CONVERT_VALUE] = CONVERT_VALUE,
+ [COPY] = COPY,
+ [COPY_FREE_VARS] = COPY_FREE_VARS,
+ [DELETE_ATTR] = DELETE_ATTR,
+ [DELETE_DEREF] = DELETE_DEREF,
+ [DELETE_FAST] = DELETE_FAST,
+ [DELETE_GLOBAL] = DELETE_GLOBAL,
+ [DELETE_NAME] = DELETE_NAME,
+ [DELETE_SUBSCR] = DELETE_SUBSCR,
+ [DICT_MERGE] = DICT_MERGE,
+ [DICT_UPDATE] = DICT_UPDATE,
+ [END_ASYNC_FOR] = END_ASYNC_FOR,
+ [END_FOR] = END_FOR,
+ [END_SEND] = END_SEND,
+ [ENTER_EXECUTOR] = ENTER_EXECUTOR,
+ [EXIT_INIT_CHECK] = EXIT_INIT_CHECK,
+ [EXTENDED_ARG] = EXTENDED_ARG,
+ [FORMAT_SIMPLE] = FORMAT_SIMPLE,
+ [FORMAT_WITH_SPEC] = FORMAT_WITH_SPEC,
+ [FOR_ITER] = FOR_ITER,
+ [FOR_ITER_GEN] = FOR_ITER,
+ [FOR_ITER_LIST] = FOR_ITER,
+ [FOR_ITER_RANGE] = FOR_ITER,
+ [FOR_ITER_TUPLE] = FOR_ITER,
+ [GET_AITER] = GET_AITER,
+ [GET_ANEXT] = GET_ANEXT,
+ [GET_AWAITABLE] = GET_AWAITABLE,
+ [GET_ITER] = GET_ITER,
+ [GET_LEN] = GET_LEN,
+ [GET_YIELD_FROM_ITER] = GET_YIELD_FROM_ITER,
+ [IMPORT_FROM] = IMPORT_FROM,
+ [IMPORT_NAME] = IMPORT_NAME,
+ [INSTRUMENTED_CALL] = INSTRUMENTED_CALL,
+ [INSTRUMENTED_CALL_FUNCTION_EX] = INSTRUMENTED_CALL_FUNCTION_EX,
+ [INSTRUMENTED_END_FOR] = INSTRUMENTED_END_FOR,
+ [INSTRUMENTED_END_SEND] = INSTRUMENTED_END_SEND,
+ [INSTRUMENTED_FOR_ITER] = INSTRUMENTED_FOR_ITER,
+ [INSTRUMENTED_INSTRUCTION] = INSTRUMENTED_INSTRUCTION,
+ [INSTRUMENTED_JUMP_BACKWARD] = INSTRUMENTED_JUMP_BACKWARD,
+ [INSTRUMENTED_JUMP_FORWARD] = INSTRUMENTED_JUMP_FORWARD,
+ [INSTRUMENTED_LINE] = INSTRUMENTED_LINE,
+ [INSTRUMENTED_LOAD_SUPER_ATTR] = INSTRUMENTED_LOAD_SUPER_ATTR,
+ [INSTRUMENTED_POP_JUMP_IF_FALSE] = INSTRUMENTED_POP_JUMP_IF_FALSE,
+ [INSTRUMENTED_POP_JUMP_IF_NONE] = INSTRUMENTED_POP_JUMP_IF_NONE,
+ [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = INSTRUMENTED_POP_JUMP_IF_NOT_NONE,
+ [INSTRUMENTED_POP_JUMP_IF_TRUE] = INSTRUMENTED_POP_JUMP_IF_TRUE,
+ [INSTRUMENTED_RESUME] = INSTRUMENTED_RESUME,
+ [INSTRUMENTED_RETURN_CONST] = INSTRUMENTED_RETURN_CONST,
+ [INSTRUMENTED_RETURN_VALUE] = INSTRUMENTED_RETURN_VALUE,
+ [INSTRUMENTED_YIELD_VALUE] = INSTRUMENTED_YIELD_VALUE,
+ [INTERPRETER_EXIT] = INTERPRETER_EXIT,
+ [IS_OP] = IS_OP,
+ [JUMP_BACKWARD] = JUMP_BACKWARD,
+ [JUMP_BACKWARD_NO_INTERRUPT] = JUMP_BACKWARD_NO_INTERRUPT,
+ [JUMP_FORWARD] = JUMP_FORWARD,
+ [KW_NAMES] = KW_NAMES,
+ [LIST_APPEND] = LIST_APPEND,
+ [LIST_EXTEND] = LIST_EXTEND,
+ [LOAD_ASSERTION_ERROR] = LOAD_ASSERTION_ERROR,
+ [LOAD_ATTR] = LOAD_ATTR,
+ [LOAD_ATTR_CLASS] = LOAD_ATTR,
+ [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = LOAD_ATTR,
+ [LOAD_ATTR_INSTANCE_VALUE] = LOAD_ATTR,
+ [LOAD_ATTR_METHOD_LAZY_DICT] = LOAD_ATTR,
+ [LOAD_ATTR_METHOD_NO_DICT] = LOAD_ATTR,
+ [LOAD_ATTR_METHOD_WITH_VALUES] = LOAD_ATTR,
+ [LOAD_ATTR_MODULE] = LOAD_ATTR,
+ [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = LOAD_ATTR,
+ [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = LOAD_ATTR,
+ [LOAD_ATTR_PROPERTY] = LOAD_ATTR,
+ [LOAD_ATTR_SLOT] = LOAD_ATTR,
+ [LOAD_ATTR_WITH_HINT] = LOAD_ATTR,
+ [LOAD_BUILD_CLASS] = LOAD_BUILD_CLASS,
+ [LOAD_CONST] = LOAD_CONST,
+ [LOAD_DEREF] = LOAD_DEREF,
+ [LOAD_FAST] = LOAD_FAST,
+ [LOAD_FAST_AND_CLEAR] = LOAD_FAST_AND_CLEAR,
+ [LOAD_FAST_CHECK] = LOAD_FAST_CHECK,
+ [LOAD_FAST_LOAD_FAST] = LOAD_FAST_LOAD_FAST,
+ [LOAD_FROM_DICT_OR_DEREF] = LOAD_FROM_DICT_OR_DEREF,
+ [LOAD_FROM_DICT_OR_GLOBALS] = LOAD_FROM_DICT_OR_GLOBALS,
+ [LOAD_GLOBAL] = LOAD_GLOBAL,
+ [LOAD_GLOBAL_BUILTIN] = LOAD_GLOBAL,
+ [LOAD_GLOBAL_MODULE] = LOAD_GLOBAL,
+ [LOAD_LOCALS] = LOAD_LOCALS,
+ [LOAD_NAME] = LOAD_NAME,
+ [LOAD_SUPER_ATTR] = LOAD_SUPER_ATTR,
+ [LOAD_SUPER_ATTR_ATTR] = LOAD_SUPER_ATTR,
+ [LOAD_SUPER_ATTR_METHOD] = LOAD_SUPER_ATTR,
+ [MAKE_CELL] = MAKE_CELL,
+ [MAKE_FUNCTION] = MAKE_FUNCTION,
+ [MAP_ADD] = MAP_ADD,
+ [MATCH_CLASS] = MATCH_CLASS,
+ [MATCH_KEYS] = MATCH_KEYS,
+ [MATCH_MAPPING] = MATCH_MAPPING,
+ [MATCH_SEQUENCE] = MATCH_SEQUENCE,
+ [NOP] = NOP,
+ [POP_EXCEPT] = POP_EXCEPT,
+ [POP_JUMP_IF_FALSE] = POP_JUMP_IF_FALSE,
+ [POP_JUMP_IF_NONE] = POP_JUMP_IF_NONE,
+ [POP_JUMP_IF_NOT_NONE] = POP_JUMP_IF_NOT_NONE,
+ [POP_JUMP_IF_TRUE] = POP_JUMP_IF_TRUE,
+ [POP_TOP] = POP_TOP,
+ [PUSH_EXC_INFO] = PUSH_EXC_INFO,
+ [PUSH_NULL] = PUSH_NULL,
+ [RAISE_VARARGS] = RAISE_VARARGS,
+ [RERAISE] = RERAISE,
+ [RESERVED] = RESERVED,
+ [RESUME] = RESUME,
+ [RETURN_CONST] = RETURN_CONST,
+ [RETURN_GENERATOR] = RETURN_GENERATOR,
+ [RETURN_VALUE] = RETURN_VALUE,
+ [SEND] = SEND,
+ [SEND_GEN] = SEND,
+ [SETUP_ANNOTATIONS] = SETUP_ANNOTATIONS,
+ [SET_ADD] = SET_ADD,
+ [SET_FUNCTION_ATTRIBUTE] = SET_FUNCTION_ATTRIBUTE,
+ [SET_UPDATE] = SET_UPDATE,
+ [STORE_ATTR] = STORE_ATTR,
+ [STORE_ATTR_INSTANCE_VALUE] = STORE_ATTR,
+ [STORE_ATTR_SLOT] = STORE_ATTR,
+ [STORE_ATTR_WITH_HINT] = STORE_ATTR,
+ [STORE_DEREF] = STORE_DEREF,
+ [STORE_FAST] = STORE_FAST,
+ [STORE_FAST_LOAD_FAST] = STORE_FAST_LOAD_FAST,
+ [STORE_FAST_STORE_FAST] = STORE_FAST_STORE_FAST,
+ [STORE_GLOBAL] = STORE_GLOBAL,
+ [STORE_NAME] = STORE_NAME,
+ [STORE_SLICE] = STORE_SLICE,
+ [STORE_SUBSCR] = STORE_SUBSCR,
+ [STORE_SUBSCR_DICT] = STORE_SUBSCR,
+ [STORE_SUBSCR_LIST_INT] = STORE_SUBSCR,
+ [SWAP] = SWAP,
+ [TO_BOOL] = TO_BOOL,
+ [TO_BOOL_ALWAYS_TRUE] = TO_BOOL,
+ [TO_BOOL_BOOL] = TO_BOOL,
+ [TO_BOOL_INT] = TO_BOOL,
+ [TO_BOOL_LIST] = TO_BOOL,
+ [TO_BOOL_NONE] = TO_BOOL,
+ [TO_BOOL_STR] = TO_BOOL,
+ [UNARY_INVERT] = UNARY_INVERT,
+ [UNARY_NEGATIVE] = UNARY_NEGATIVE,
+ [UNARY_NOT] = UNARY_NOT,
+ [UNPACK_EX] = UNPACK_EX,
+ [UNPACK_SEQUENCE] = UNPACK_SEQUENCE,
+ [UNPACK_SEQUENCE_LIST] = UNPACK_SEQUENCE,
+ [UNPACK_SEQUENCE_TUPLE] = UNPACK_SEQUENCE,
+ [UNPACK_SEQUENCE_TWO_TUPLE] = UNPACK_SEQUENCE,
+ [WITH_EXCEPT_START] = WITH_EXCEPT_START,
+ [YIELD_VALUE] = YIELD_VALUE,
+};
+#endif // NEED_OPCODE_METADATA
+
+#define EXTRA_CASES \
+ case 188: \
+ case 189: \
+ case 190: \
+ case 191: \
+ case 192: \
+ case 193: \
+ case 194: \
+ case 195: \
+ case 196: \
+ case 197: \
+ case 198: \
+ case 199: \
+ case 200: \
+ case 201: \
+ case 202: \
+ case 203: \
+ case 204: \
+ case 205: \
+ case 206: \
+ case 207: \
+ case 208: \
+ case 209: \
+ case 210: \
+ case 211: \
+ case 212: \
+ case 213: \
+ case 214: \
+ case 215: \
+ case 216: \
+ case 217: \
+ case 218: \
+ case 219: \
+ case 220: \
+ case 221: \
+ case 222: \
+ case 223: \
+ case 224: \
+ case 225: \
+ case 226: \
+ case 227: \
+ case 228: \
+ case 229: \
+ case 230: \
+ case 231: \
+ case 232: \
+ case 233: \
+ case 234: \
+ case 235: \
+ case 236: \
+ case 255: \
+ ;
+
diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h
new file mode 100644
index 00000000000000..2ae657c4e117ff
--- /dev/null
+++ b/Include/internal/pycore_optimizer.h
@@ -0,0 +1,20 @@
+#ifndef Py_INTERNAL_OPTIMIZER_H
+#define Py_INTERNAL_OPTIMIZER_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef Py_BUILD_CORE
+# error "this header requires Py_BUILD_CORE define"
+#endif
+
+#include "pycore_uops.h"
+
+int _Py_uop_analyze_and_optimize(PyCodeObject *code,
+ _PyUOpInstruction *trace, int trace_len, int curr_stackentries);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_INTERNAL_OPTIMIZER_H */
diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h
index 0ec86ee6c50ca3..63b485027486bb 100644
--- a/Include/internal/pycore_runtime.h
+++ b/Include/internal/pycore_runtime.h
@@ -80,7 +80,7 @@ typedef struct _Py_DebugOffsets {
off_t prev;
off_t next;
off_t interp;
- off_t cframe;
+ off_t current_frame;
off_t thread_id;
off_t native_thread_id;
} thread_state;
diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h
index e89d368be07aa7..ea29c69f59acc7 100644
--- a/Include/internal/pycore_runtime_init.h
+++ b/Include/internal/pycore_runtime_init.h
@@ -45,7 +45,7 @@ extern PyTypeObject _PyExc_MemoryError;
.prev = offsetof(PyThreadState, prev), \
.next = offsetof(PyThreadState, next), \
.interp = offsetof(PyThreadState, interp), \
- .cframe = offsetof(PyThreadState, cframe), \
+ .current_frame = offsetof(PyThreadState, current_frame), \
.thread_id = offsetof(PyThreadState, thread_id), \
.native_thread_id = offsetof(PyThreadState, native_thread_id), \
}, \
@@ -56,10 +56,6 @@ extern PyTypeObject _PyExc_MemoryError;
.localsplus = offsetof(_PyInterpreterFrame, localsplus), \
.owner = offsetof(_PyInterpreterFrame, owner), \
}, \
- .cframe = { \
- .current_frame = offsetof(_PyCFrame, current_frame), \
- .previous = offsetof(_PyCFrame, previous), \
- }, \
.code_object = { \
.filename = offsetof(PyCodeObject, co_filename), \
.name = offsetof(PyCodeObject, co_name), \
diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h
index 2d66647438b193..8c9c7f753d8579 100644
--- a/Include/internal/pycore_runtime_init_generated.h
+++ b/Include/internal/pycore_runtime_init_generated.h
@@ -539,6 +539,7 @@ extern "C" {
INIT_STR(anon_lambda, ""), \
INIT_STR(anon_listcomp, ""), \
INIT_STR(anon_module, ""), \
+ INIT_STR(anon_null, ""), \
INIT_STR(anon_setcomp, ""), \
INIT_STR(anon_string, ""), \
INIT_STR(anon_unknown, ""), \
diff --git a/Include/internal/pycore_uops.h b/Include/internal/pycore_uops.h
index 57a5970353b360..254eeca2361bea 100644
--- a/Include/internal/pycore_uops.h
+++ b/Include/internal/pycore_uops.h
@@ -8,7 +8,7 @@ extern "C" {
# error "this header requires Py_BUILD_CORE define"
#endif
-#define _Py_UOP_MAX_TRACE_LENGTH 32
+#define _Py_UOP_MAX_TRACE_LENGTH 64
typedef struct {
uint32_t opcode;
diff --git a/Include/object.h b/Include/object.h
index e26cedf8ca3c97..be9a0cedb7205d 100644
--- a/Include/object.h
+++ b/Include/object.h
@@ -845,8 +845,6 @@ static inline PyObject* _Py_XNewRef(PyObject *obj)
/*
_Py_NoneStruct is an object of undefined type which can be used in contexts
where NULL (nil) is not suitable (since NULL often means 'error').
-
-Don't forget to apply Py_INCREF() when returning this value!!!
*/
PyAPI_DATA(PyObject) _Py_NoneStruct; /* Don't use this directly */
#define Py_None (&_Py_NoneStruct)
diff --git a/Include/opcode.h b/Include/opcode.h
index b3d6cba63096c8..e5c42d5a718286 100644
--- a/Include/opcode.h
+++ b/Include/opcode.h
@@ -6,227 +6,8 @@
extern "C" {
#endif
+#include "opcode_ids.h"
-/* Instruction opcodes for compiled code */
-#define CACHE 0
-#define POP_TOP 1
-#define PUSH_NULL 2
-#define INTERPRETER_EXIT 3
-#define END_FOR 4
-#define END_SEND 5
-#define TO_BOOL 6
-#define NOP 9
-#define UNARY_NEGATIVE 11
-#define UNARY_NOT 12
-#define UNARY_INVERT 15
-#define EXIT_INIT_CHECK 16
-#define RESERVED 17
-#define MAKE_FUNCTION 24
-#define BINARY_SUBSCR 25
-#define BINARY_SLICE 26
-#define STORE_SLICE 27
-#define GET_LEN 30
-#define MATCH_MAPPING 31
-#define MATCH_SEQUENCE 32
-#define MATCH_KEYS 33
-#define PUSH_EXC_INFO 35
-#define CHECK_EXC_MATCH 36
-#define CHECK_EG_MATCH 37
-#define FORMAT_SIMPLE 40
-#define FORMAT_WITH_SPEC 41
-#define WITH_EXCEPT_START 49
-#define GET_AITER 50
-#define GET_ANEXT 51
-#define BEFORE_ASYNC_WITH 52
-#define BEFORE_WITH 53
-#define END_ASYNC_FOR 54
-#define CLEANUP_THROW 55
-#define STORE_SUBSCR 60
-#define DELETE_SUBSCR 61
-#define GET_ITER 68
-#define GET_YIELD_FROM_ITER 69
-#define LOAD_BUILD_CLASS 71
-#define LOAD_ASSERTION_ERROR 74
-#define RETURN_GENERATOR 75
-#define RETURN_VALUE 83
-#define SETUP_ANNOTATIONS 85
-#define LOAD_LOCALS 87
-#define POP_EXCEPT 89
-#define STORE_NAME 90
-#define DELETE_NAME 91
-#define UNPACK_SEQUENCE 92
-#define FOR_ITER 93
-#define UNPACK_EX 94
-#define STORE_ATTR 95
-#define DELETE_ATTR 96
-#define STORE_GLOBAL 97
-#define DELETE_GLOBAL 98
-#define SWAP 99
-#define LOAD_CONST 100
-#define LOAD_NAME 101
-#define BUILD_TUPLE 102
-#define BUILD_LIST 103
-#define BUILD_SET 104
-#define BUILD_MAP 105
-#define LOAD_ATTR 106
-#define COMPARE_OP 107
-#define IMPORT_NAME 108
-#define IMPORT_FROM 109
-#define JUMP_FORWARD 110
-#define POP_JUMP_IF_FALSE 114
-#define POP_JUMP_IF_TRUE 115
-#define LOAD_GLOBAL 116
-#define IS_OP 117
-#define CONTAINS_OP 118
-#define RERAISE 119
-#define COPY 120
-#define RETURN_CONST 121
-#define BINARY_OP 122
-#define SEND 123
-#define LOAD_FAST 124
-#define STORE_FAST 125
-#define DELETE_FAST 126
-#define LOAD_FAST_CHECK 127
-#define POP_JUMP_IF_NOT_NONE 128
-#define POP_JUMP_IF_NONE 129
-#define RAISE_VARARGS 130
-#define GET_AWAITABLE 131
-#define BUILD_SLICE 133
-#define JUMP_BACKWARD_NO_INTERRUPT 134
-#define MAKE_CELL 135
-#define LOAD_DEREF 137
-#define STORE_DEREF 138
-#define DELETE_DEREF 139
-#define JUMP_BACKWARD 140
-#define LOAD_SUPER_ATTR 141
-#define CALL_FUNCTION_EX 142
-#define LOAD_FAST_AND_CLEAR 143
-#define EXTENDED_ARG 144
-#define LIST_APPEND 145
-#define SET_ADD 146
-#define MAP_ADD 147
-#define COPY_FREE_VARS 149
-#define YIELD_VALUE 150
-#define RESUME 151
-#define MATCH_CLASS 152
-#define BUILD_CONST_KEY_MAP 156
-#define BUILD_STRING 157
-#define CONVERT_VALUE 158
-#define LIST_EXTEND 162
-#define SET_UPDATE 163
-#define DICT_MERGE 164
-#define DICT_UPDATE 165
-#define LOAD_FAST_LOAD_FAST 168
-#define STORE_FAST_LOAD_FAST 169
-#define STORE_FAST_STORE_FAST 170
-#define CALL 171
-#define KW_NAMES 172
-#define CALL_INTRINSIC_1 173
-#define CALL_INTRINSIC_2 174
-#define LOAD_FROM_DICT_OR_GLOBALS 175
-#define LOAD_FROM_DICT_OR_DEREF 176
-#define SET_FUNCTION_ATTRIBUTE 177
-#define ENTER_EXECUTOR 230
-#define MIN_INSTRUMENTED_OPCODE 237
-#define INSTRUMENTED_LOAD_SUPER_ATTR 237
-#define INSTRUMENTED_POP_JUMP_IF_NONE 238
-#define INSTRUMENTED_POP_JUMP_IF_NOT_NONE 239
-#define INSTRUMENTED_RESUME 240
-#define INSTRUMENTED_CALL 241
-#define INSTRUMENTED_RETURN_VALUE 242
-#define INSTRUMENTED_YIELD_VALUE 243
-#define INSTRUMENTED_CALL_FUNCTION_EX 244
-#define INSTRUMENTED_JUMP_FORWARD 245
-#define INSTRUMENTED_JUMP_BACKWARD 246
-#define INSTRUMENTED_RETURN_CONST 247
-#define INSTRUMENTED_FOR_ITER 248
-#define INSTRUMENTED_POP_JUMP_IF_FALSE 249
-#define INSTRUMENTED_POP_JUMP_IF_TRUE 250
-#define INSTRUMENTED_END_FOR 251
-#define INSTRUMENTED_END_SEND 252
-#define INSTRUMENTED_INSTRUCTION 253
-#define INSTRUMENTED_LINE 254
-#define SETUP_FINALLY 256
-#define SETUP_CLEANUP 257
-#define SETUP_WITH 258
-#define POP_BLOCK 259
-#define JUMP 260
-#define JUMP_NO_INTERRUPT 261
-#define LOAD_METHOD 262
-#define LOAD_SUPER_METHOD 263
-#define LOAD_ZERO_SUPER_METHOD 264
-#define LOAD_ZERO_SUPER_ATTR 265
-#define STORE_FAST_MAYBE_NULL 266
-#define LOAD_CLOSURE 267
-#define TO_BOOL_ALWAYS_TRUE 7
-#define TO_BOOL_BOOL 8
-#define TO_BOOL_INT 10
-#define TO_BOOL_LIST 13
-#define TO_BOOL_NONE 14
-#define TO_BOOL_STR 18
-#define BINARY_OP_MULTIPLY_INT 19
-#define BINARY_OP_ADD_INT 20
-#define BINARY_OP_SUBTRACT_INT 21
-#define BINARY_OP_MULTIPLY_FLOAT 22
-#define BINARY_OP_ADD_FLOAT 23
-#define BINARY_OP_SUBTRACT_FLOAT 28
-#define BINARY_OP_ADD_UNICODE 29
-#define BINARY_OP_INPLACE_ADD_UNICODE 34
-#define BINARY_SUBSCR_DICT 38
-#define BINARY_SUBSCR_GETITEM 39
-#define BINARY_SUBSCR_LIST_INT 42
-#define BINARY_SUBSCR_STR_INT 43
-#define BINARY_SUBSCR_TUPLE_INT 44
-#define STORE_SUBSCR_DICT 45
-#define STORE_SUBSCR_LIST_INT 46
-#define SEND_GEN 47
-#define UNPACK_SEQUENCE_TWO_TUPLE 48
-#define UNPACK_SEQUENCE_TUPLE 56
-#define UNPACK_SEQUENCE_LIST 57
-#define STORE_ATTR_INSTANCE_VALUE 58
-#define STORE_ATTR_SLOT 59
-#define STORE_ATTR_WITH_HINT 62
-#define LOAD_GLOBAL_MODULE 63
-#define LOAD_GLOBAL_BUILTIN 64
-#define LOAD_SUPER_ATTR_ATTR 65
-#define LOAD_SUPER_ATTR_METHOD 66
-#define LOAD_ATTR_INSTANCE_VALUE 67
-#define LOAD_ATTR_MODULE 70
-#define LOAD_ATTR_WITH_HINT 72
-#define LOAD_ATTR_SLOT 73
-#define LOAD_ATTR_CLASS 76
-#define LOAD_ATTR_PROPERTY 77
-#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 78
-#define LOAD_ATTR_METHOD_WITH_VALUES 79
-#define LOAD_ATTR_METHOD_NO_DICT 80
-#define LOAD_ATTR_METHOD_LAZY_DICT 81
-#define LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 82
-#define LOAD_ATTR_NONDESCRIPTOR_NO_DICT 84
-#define COMPARE_OP_FLOAT 86
-#define COMPARE_OP_INT 88
-#define COMPARE_OP_STR 111
-#define FOR_ITER_LIST 112
-#define FOR_ITER_TUPLE 113
-#define FOR_ITER_RANGE 132
-#define FOR_ITER_GEN 136
-#define CALL_BOUND_METHOD_EXACT_ARGS 148
-#define CALL_PY_EXACT_ARGS 153
-#define CALL_PY_WITH_DEFAULTS 154
-#define CALL_NO_KW_TYPE_1 155
-#define CALL_NO_KW_STR_1 159
-#define CALL_NO_KW_TUPLE_1 160
-#define CALL_BUILTIN_CLASS 161
-#define CALL_NO_KW_BUILTIN_O 166
-#define CALL_NO_KW_BUILTIN_FAST 167
-#define CALL_BUILTIN_FAST_WITH_KEYWORDS 178
-#define CALL_NO_KW_LEN 179
-#define CALL_NO_KW_ISINSTANCE 180
-#define CALL_NO_KW_LIST_APPEND 181
-#define CALL_NO_KW_METHOD_DESCRIPTOR_O 182
-#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 183
-#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 184
-#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 185
-#define CALL_NO_KW_ALLOC_AND_ENTER_INIT 186
#define NB_ADD 0
#define NB_AND 1
diff --git a/Include/opcode_ids.h b/Include/opcode_ids.h
new file mode 100644
index 00000000000000..cd43716415d1db
--- /dev/null
+++ b/Include/opcode_ids.h
@@ -0,0 +1,237 @@
+// This file is generated by Tools/cases_generator/generate_cases.py
+// from:
+// Python/bytecodes.c
+// Do not edit!
+
+#ifndef Py_OPCODE_IDS_H
+#define Py_OPCODE_IDS_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Instruction opcodes for compiled code */
+#define CACHE 0
+#define BEFORE_ASYNC_WITH 1
+#define BEFORE_WITH 2
+#define BINARY_OP_ADD_FLOAT 3
+#define BINARY_OP_ADD_INT 4
+#define BINARY_OP_ADD_UNICODE 5
+#define BINARY_OP_INPLACE_ADD_UNICODE 6
+#define BINARY_OP_MULTIPLY_FLOAT 7
+#define BINARY_OP_MULTIPLY_INT 8
+#define BINARY_OP_SUBTRACT_FLOAT 9
+#define BINARY_OP_SUBTRACT_INT 10
+#define BINARY_SLICE 11
+#define BINARY_SUBSCR 12
+#define BINARY_SUBSCR_DICT 13
+#define BINARY_SUBSCR_GETITEM 14
+#define BINARY_SUBSCR_LIST_INT 15
+#define BINARY_SUBSCR_STR_INT 16
+#define RESERVED 17
+#define BINARY_SUBSCR_TUPLE_INT 18
+#define CHECK_EG_MATCH 19
+#define CHECK_EXC_MATCH 20
+#define CLEANUP_THROW 21
+#define DELETE_SUBSCR 22
+#define END_ASYNC_FOR 23
+#define END_FOR 24
+#define END_SEND 25
+#define EXIT_INIT_CHECK 26
+#define FORMAT_SIMPLE 27
+#define FORMAT_WITH_SPEC 28
+#define GET_AITER 29
+#define GET_ANEXT 30
+#define GET_ITER 31
+#define GET_LEN 32
+#define GET_YIELD_FROM_ITER 33
+#define INTERPRETER_EXIT 34
+#define LOAD_ASSERTION_ERROR 35
+#define LOAD_BUILD_CLASS 36
+#define LOAD_LOCALS 37
+#define MAKE_FUNCTION 38
+#define MATCH_KEYS 39
+#define MATCH_MAPPING 40
+#define MATCH_SEQUENCE 41
+#define NOP 42
+#define POP_EXCEPT 43
+#define POP_TOP 44
+#define PUSH_EXC_INFO 45
+#define PUSH_NULL 46
+#define RETURN_GENERATOR 47
+#define RETURN_VALUE 48
+#define SETUP_ANNOTATIONS 49
+#define STORE_ATTR_INSTANCE_VALUE 50
+#define STORE_ATTR_SLOT 51
+#define STORE_SLICE 52
+#define STORE_SUBSCR 53
+#define STORE_SUBSCR_DICT 54
+#define STORE_SUBSCR_LIST_INT 55
+#define TO_BOOL 56
+#define TO_BOOL_ALWAYS_TRUE 57
+#define TO_BOOL_BOOL 58
+#define TO_BOOL_INT 59
+#define TO_BOOL_LIST 60
+#define TO_BOOL_NONE 61
+#define TO_BOOL_STR 62
+#define UNARY_INVERT 63
+#define UNARY_NEGATIVE 64
+#define UNARY_NOT 65
+#define WITH_EXCEPT_START 66
+#define HAVE_ARGUMENT 67
+#define BINARY_OP 67
+#define BUILD_CONST_KEY_MAP 68
+#define BUILD_LIST 69
+#define BUILD_MAP 70
+#define BUILD_SET 71
+#define BUILD_SLICE 72
+#define BUILD_STRING 73
+#define BUILD_TUPLE 74
+#define CALL 75
+#define CALL_BOUND_METHOD_EXACT_ARGS 76
+#define CALL_BUILTIN_CLASS 77
+#define CALL_BUILTIN_FAST_WITH_KEYWORDS 78
+#define CALL_FUNCTION_EX 79
+#define CALL_INTRINSIC_1 80
+#define CALL_INTRINSIC_2 81
+#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 82
+#define CALL_NO_KW_ALLOC_AND_ENTER_INIT 83
+#define CALL_NO_KW_BUILTIN_FAST 84
+#define CALL_NO_KW_BUILTIN_O 85
+#define CALL_NO_KW_ISINSTANCE 86
+#define CALL_NO_KW_LEN 87
+#define CALL_NO_KW_LIST_APPEND 88
+#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 89
+#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 90
+#define CALL_NO_KW_METHOD_DESCRIPTOR_O 91
+#define CALL_NO_KW_STR_1 92
+#define CALL_NO_KW_TUPLE_1 93
+#define CALL_NO_KW_TYPE_1 94
+#define CALL_PY_EXACT_ARGS 95
+#define CALL_PY_WITH_DEFAULTS 96
+#define COMPARE_OP 97
+#define COMPARE_OP_FLOAT 98
+#define COMPARE_OP_INT 99
+#define COMPARE_OP_STR 100
+#define CONTAINS_OP 101
+#define CONVERT_VALUE 102
+#define COPY 103
+#define COPY_FREE_VARS 104
+#define DELETE_ATTR 105
+#define DELETE_DEREF 106
+#define DELETE_FAST 107
+#define DELETE_GLOBAL 108
+#define DELETE_NAME 109
+#define DICT_MERGE 110
+#define DICT_UPDATE 111
+#define ENTER_EXECUTOR 112
+#define EXTENDED_ARG 113
+#define FOR_ITER 114
+#define FOR_ITER_GEN 115
+#define FOR_ITER_LIST 116
+#define FOR_ITER_RANGE 117
+#define FOR_ITER_TUPLE 118
+#define GET_AWAITABLE 119
+#define IMPORT_FROM 120
+#define IMPORT_NAME 121
+#define IS_OP 122
+#define JUMP_BACKWARD 123
+#define JUMP_BACKWARD_NO_INTERRUPT 124
+#define JUMP_FORWARD 125
+#define KW_NAMES 126
+#define LIST_APPEND 127
+#define LIST_EXTEND 128
+#define LOAD_ATTR 129
+#define LOAD_ATTR_CLASS 130
+#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 131
+#define LOAD_ATTR_INSTANCE_VALUE 132
+#define LOAD_ATTR_METHOD_LAZY_DICT 133
+#define LOAD_ATTR_METHOD_NO_DICT 134
+#define LOAD_ATTR_METHOD_WITH_VALUES 135
+#define LOAD_ATTR_MODULE 136
+#define LOAD_ATTR_NONDESCRIPTOR_NO_DICT 137
+#define LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 138
+#define LOAD_ATTR_PROPERTY 139
+#define LOAD_ATTR_SLOT 140
+#define LOAD_ATTR_WITH_HINT 141
+#define LOAD_CONST 142
+#define LOAD_DEREF 143
+#define LOAD_FAST 144
+#define LOAD_FAST_AND_CLEAR 145
+#define LOAD_FAST_CHECK 146
+#define LOAD_FAST_LOAD_FAST 147
+#define LOAD_FROM_DICT_OR_DEREF 148
+#define LOAD_FROM_DICT_OR_GLOBALS 149
+#define LOAD_GLOBAL 150
+#define LOAD_GLOBAL_BUILTIN 151
+#define LOAD_GLOBAL_MODULE 152
+#define LOAD_NAME 153
+#define LOAD_SUPER_ATTR 154
+#define LOAD_SUPER_ATTR_ATTR 155
+#define LOAD_SUPER_ATTR_METHOD 156
+#define MAKE_CELL 157
+#define MAP_ADD 158
+#define MATCH_CLASS 159
+#define POP_JUMP_IF_FALSE 160
+#define POP_JUMP_IF_NONE 161
+#define POP_JUMP_IF_NOT_NONE 162
+#define POP_JUMP_IF_TRUE 163
+#define RAISE_VARARGS 164
+#define RERAISE 165
+#define RESUME 166
+#define RETURN_CONST 167
+#define SEND 168
+#define SEND_GEN 169
+#define SET_ADD 170
+#define SET_FUNCTION_ATTRIBUTE 171
+#define SET_UPDATE 172
+#define STORE_ATTR 173
+#define STORE_ATTR_WITH_HINT 174
+#define STORE_DEREF 175
+#define STORE_FAST 176
+#define STORE_FAST_LOAD_FAST 177
+#define STORE_FAST_STORE_FAST 178
+#define STORE_GLOBAL 179
+#define STORE_NAME 180
+#define SWAP 181
+#define UNPACK_EX 182
+#define UNPACK_SEQUENCE 183
+#define UNPACK_SEQUENCE_LIST 184
+#define UNPACK_SEQUENCE_TUPLE 185
+#define UNPACK_SEQUENCE_TWO_TUPLE 186
+#define YIELD_VALUE 187
+#define MIN_INSTRUMENTED_OPCODE 237
+#define INSTRUMENTED_RESUME 237
+#define INSTRUMENTED_END_FOR 238
+#define INSTRUMENTED_END_SEND 239
+#define INSTRUMENTED_RETURN_VALUE 240
+#define INSTRUMENTED_RETURN_CONST 241
+#define INSTRUMENTED_YIELD_VALUE 242
+#define INSTRUMENTED_LOAD_SUPER_ATTR 243
+#define INSTRUMENTED_FOR_ITER 244
+#define INSTRUMENTED_CALL 245
+#define INSTRUMENTED_CALL_FUNCTION_EX 246
+#define INSTRUMENTED_INSTRUCTION 247
+#define INSTRUMENTED_JUMP_FORWARD 248
+#define INSTRUMENTED_JUMP_BACKWARD 249
+#define INSTRUMENTED_POP_JUMP_IF_TRUE 250
+#define INSTRUMENTED_POP_JUMP_IF_FALSE 251
+#define INSTRUMENTED_POP_JUMP_IF_NONE 252
+#define INSTRUMENTED_POP_JUMP_IF_NOT_NONE 253
+#define INSTRUMENTED_LINE 254
+#define JUMP 256
+#define JUMP_NO_INTERRUPT 257
+#define LOAD_CLOSURE 258
+#define LOAD_METHOD 259
+#define LOAD_SUPER_METHOD 260
+#define LOAD_ZERO_SUPER_ATTR 261
+#define LOAD_ZERO_SUPER_METHOD 262
+#define POP_BLOCK 263
+#define SETUP_CLEANUP 264
+#define SETUP_FINALLY 265
+#define SETUP_WITH 266
+#define STORE_FAST_MAYBE_NULL 267
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_OPCODE_IDS_H */
diff --git a/Include/pystats.h b/Include/pystats.h
index e24aef5fe8072b..b1957596745f00 100644
--- a/Include/pystats.h
+++ b/Include/pystats.h
@@ -65,6 +65,7 @@ typedef struct _object_stats {
uint64_t dict_materialized_new_key;
uint64_t dict_materialized_too_big;
uint64_t dict_materialized_str_subclass;
+ uint64_t dict_dematerialized;
uint64_t type_cache_hits;
uint64_t type_cache_misses;
uint64_t type_cache_dunder_hits;
diff --git a/Lib/_opcode_metadata.py b/Lib/_opcode_metadata.py
index 17101d1d94757b..b02aa771c347e7 100644
--- a/Lib/_opcode_metadata.py
+++ b/Lib/_opcode_metadata.py
@@ -103,4 +103,228 @@
# An irregular case:
_specializations["BINARY_OP"].append("BINARY_OP_INPLACE_ADD_UNICODE")
-_specialized_instructions = [opcode for family in _specializations.values() for opcode in family]
+_specialized_opmap = {
+ 'BINARY_OP_ADD_FLOAT': 3,
+ 'BINARY_OP_ADD_INT': 4,
+ 'BINARY_OP_ADD_UNICODE': 5,
+ 'BINARY_OP_INPLACE_ADD_UNICODE': 6,
+ 'BINARY_OP_MULTIPLY_FLOAT': 7,
+ 'BINARY_OP_MULTIPLY_INT': 8,
+ 'BINARY_OP_SUBTRACT_FLOAT': 9,
+ 'BINARY_OP_SUBTRACT_INT': 10,
+ 'BINARY_SUBSCR_DICT': 13,
+ 'BINARY_SUBSCR_GETITEM': 14,
+ 'BINARY_SUBSCR_LIST_INT': 15,
+ 'BINARY_SUBSCR_STR_INT': 16,
+ 'BINARY_SUBSCR_TUPLE_INT': 18,
+ 'STORE_ATTR_INSTANCE_VALUE': 50,
+ 'STORE_ATTR_SLOT': 51,
+ 'STORE_SUBSCR_DICT': 54,
+ 'STORE_SUBSCR_LIST_INT': 55,
+ 'TO_BOOL_ALWAYS_TRUE': 57,
+ 'TO_BOOL_BOOL': 58,
+ 'TO_BOOL_INT': 59,
+ 'TO_BOOL_LIST': 60,
+ 'TO_BOOL_NONE': 61,
+ 'TO_BOOL_STR': 62,
+ 'CALL_BOUND_METHOD_EXACT_ARGS': 76,
+ 'CALL_BUILTIN_CLASS': 77,
+ 'CALL_BUILTIN_FAST_WITH_KEYWORDS': 78,
+ 'CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS': 82,
+ 'CALL_NO_KW_ALLOC_AND_ENTER_INIT': 83,
+ 'CALL_NO_KW_BUILTIN_FAST': 84,
+ 'CALL_NO_KW_BUILTIN_O': 85,
+ 'CALL_NO_KW_ISINSTANCE': 86,
+ 'CALL_NO_KW_LEN': 87,
+ 'CALL_NO_KW_LIST_APPEND': 88,
+ 'CALL_NO_KW_METHOD_DESCRIPTOR_FAST': 89,
+ 'CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS': 90,
+ 'CALL_NO_KW_METHOD_DESCRIPTOR_O': 91,
+ 'CALL_NO_KW_STR_1': 92,
+ 'CALL_NO_KW_TUPLE_1': 93,
+ 'CALL_NO_KW_TYPE_1': 94,
+ 'CALL_PY_EXACT_ARGS': 95,
+ 'CALL_PY_WITH_DEFAULTS': 96,
+ 'COMPARE_OP_FLOAT': 98,
+ 'COMPARE_OP_INT': 99,
+ 'COMPARE_OP_STR': 100,
+ 'FOR_ITER_GEN': 115,
+ 'FOR_ITER_LIST': 116,
+ 'FOR_ITER_RANGE': 117,
+ 'FOR_ITER_TUPLE': 118,
+ 'LOAD_ATTR_CLASS': 130,
+ 'LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN': 131,
+ 'LOAD_ATTR_INSTANCE_VALUE': 132,
+ 'LOAD_ATTR_METHOD_LAZY_DICT': 133,
+ 'LOAD_ATTR_METHOD_NO_DICT': 134,
+ 'LOAD_ATTR_METHOD_WITH_VALUES': 135,
+ 'LOAD_ATTR_MODULE': 136,
+ 'LOAD_ATTR_NONDESCRIPTOR_NO_DICT': 137,
+ 'LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES': 138,
+ 'LOAD_ATTR_PROPERTY': 139,
+ 'LOAD_ATTR_SLOT': 140,
+ 'LOAD_ATTR_WITH_HINT': 141,
+ 'LOAD_GLOBAL_BUILTIN': 151,
+ 'LOAD_GLOBAL_MODULE': 152,
+ 'LOAD_SUPER_ATTR_ATTR': 155,
+ 'LOAD_SUPER_ATTR_METHOD': 156,
+ 'SEND_GEN': 169,
+ 'STORE_ATTR_WITH_HINT': 174,
+ 'UNPACK_SEQUENCE_LIST': 184,
+ 'UNPACK_SEQUENCE_TUPLE': 185,
+ 'UNPACK_SEQUENCE_TWO_TUPLE': 186,
+}
+
+opmap = {
+ 'CACHE': 0,
+ 'BEFORE_ASYNC_WITH': 1,
+ 'BEFORE_WITH': 2,
+ 'BINARY_SLICE': 11,
+ 'BINARY_SUBSCR': 12,
+ 'RESERVED': 17,
+ 'CHECK_EG_MATCH': 19,
+ 'CHECK_EXC_MATCH': 20,
+ 'CLEANUP_THROW': 21,
+ 'DELETE_SUBSCR': 22,
+ 'END_ASYNC_FOR': 23,
+ 'END_FOR': 24,
+ 'END_SEND': 25,
+ 'EXIT_INIT_CHECK': 26,
+ 'FORMAT_SIMPLE': 27,
+ 'FORMAT_WITH_SPEC': 28,
+ 'GET_AITER': 29,
+ 'GET_ANEXT': 30,
+ 'GET_ITER': 31,
+ 'GET_LEN': 32,
+ 'GET_YIELD_FROM_ITER': 33,
+ 'INTERPRETER_EXIT': 34,
+ 'LOAD_ASSERTION_ERROR': 35,
+ 'LOAD_BUILD_CLASS': 36,
+ 'LOAD_LOCALS': 37,
+ 'MAKE_FUNCTION': 38,
+ 'MATCH_KEYS': 39,
+ 'MATCH_MAPPING': 40,
+ 'MATCH_SEQUENCE': 41,
+ 'NOP': 42,
+ 'POP_EXCEPT': 43,
+ 'POP_TOP': 44,
+ 'PUSH_EXC_INFO': 45,
+ 'PUSH_NULL': 46,
+ 'RETURN_GENERATOR': 47,
+ 'RETURN_VALUE': 48,
+ 'SETUP_ANNOTATIONS': 49,
+ 'STORE_SLICE': 52,
+ 'STORE_SUBSCR': 53,
+ 'TO_BOOL': 56,
+ 'UNARY_INVERT': 63,
+ 'UNARY_NEGATIVE': 64,
+ 'UNARY_NOT': 65,
+ 'WITH_EXCEPT_START': 66,
+ 'BINARY_OP': 67,
+ 'BUILD_CONST_KEY_MAP': 68,
+ 'BUILD_LIST': 69,
+ 'BUILD_MAP': 70,
+ 'BUILD_SET': 71,
+ 'BUILD_SLICE': 72,
+ 'BUILD_STRING': 73,
+ 'BUILD_TUPLE': 74,
+ 'CALL': 75,
+ 'CALL_FUNCTION_EX': 79,
+ 'CALL_INTRINSIC_1': 80,
+ 'CALL_INTRINSIC_2': 81,
+ 'COMPARE_OP': 97,
+ 'CONTAINS_OP': 101,
+ 'CONVERT_VALUE': 102,
+ 'COPY': 103,
+ 'COPY_FREE_VARS': 104,
+ 'DELETE_ATTR': 105,
+ 'DELETE_DEREF': 106,
+ 'DELETE_FAST': 107,
+ 'DELETE_GLOBAL': 108,
+ 'DELETE_NAME': 109,
+ 'DICT_MERGE': 110,
+ 'DICT_UPDATE': 111,
+ 'ENTER_EXECUTOR': 112,
+ 'EXTENDED_ARG': 113,
+ 'FOR_ITER': 114,
+ 'GET_AWAITABLE': 119,
+ 'IMPORT_FROM': 120,
+ 'IMPORT_NAME': 121,
+ 'IS_OP': 122,
+ 'JUMP_BACKWARD': 123,
+ 'JUMP_BACKWARD_NO_INTERRUPT': 124,
+ 'JUMP_FORWARD': 125,
+ 'KW_NAMES': 126,
+ 'LIST_APPEND': 127,
+ 'LIST_EXTEND': 128,
+ 'LOAD_ATTR': 129,
+ 'LOAD_CONST': 142,
+ 'LOAD_DEREF': 143,
+ 'LOAD_FAST': 144,
+ 'LOAD_FAST_AND_CLEAR': 145,
+ 'LOAD_FAST_CHECK': 146,
+ 'LOAD_FAST_LOAD_FAST': 147,
+ 'LOAD_FROM_DICT_OR_DEREF': 148,
+ 'LOAD_FROM_DICT_OR_GLOBALS': 149,
+ 'LOAD_GLOBAL': 150,
+ 'LOAD_NAME': 153,
+ 'LOAD_SUPER_ATTR': 154,
+ 'MAKE_CELL': 157,
+ 'MAP_ADD': 158,
+ 'MATCH_CLASS': 159,
+ 'POP_JUMP_IF_FALSE': 160,
+ 'POP_JUMP_IF_NONE': 161,
+ 'POP_JUMP_IF_NOT_NONE': 162,
+ 'POP_JUMP_IF_TRUE': 163,
+ 'RAISE_VARARGS': 164,
+ 'RERAISE': 165,
+ 'RESUME': 166,
+ 'RETURN_CONST': 167,
+ 'SEND': 168,
+ 'SET_ADD': 170,
+ 'SET_FUNCTION_ATTRIBUTE': 171,
+ 'SET_UPDATE': 172,
+ 'STORE_ATTR': 173,
+ 'STORE_DEREF': 175,
+ 'STORE_FAST': 176,
+ 'STORE_FAST_LOAD_FAST': 177,
+ 'STORE_FAST_STORE_FAST': 178,
+ 'STORE_GLOBAL': 179,
+ 'STORE_NAME': 180,
+ 'SWAP': 181,
+ 'UNPACK_EX': 182,
+ 'UNPACK_SEQUENCE': 183,
+ 'YIELD_VALUE': 187,
+ 'INSTRUMENTED_RESUME': 237,
+ 'INSTRUMENTED_END_FOR': 238,
+ 'INSTRUMENTED_END_SEND': 239,
+ 'INSTRUMENTED_RETURN_VALUE': 240,
+ 'INSTRUMENTED_RETURN_CONST': 241,
+ 'INSTRUMENTED_YIELD_VALUE': 242,
+ 'INSTRUMENTED_LOAD_SUPER_ATTR': 243,
+ 'INSTRUMENTED_FOR_ITER': 244,
+ 'INSTRUMENTED_CALL': 245,
+ 'INSTRUMENTED_CALL_FUNCTION_EX': 246,
+ 'INSTRUMENTED_INSTRUCTION': 247,
+ 'INSTRUMENTED_JUMP_FORWARD': 248,
+ 'INSTRUMENTED_JUMP_BACKWARD': 249,
+ 'INSTRUMENTED_POP_JUMP_IF_TRUE': 250,
+ 'INSTRUMENTED_POP_JUMP_IF_FALSE': 251,
+ 'INSTRUMENTED_POP_JUMP_IF_NONE': 252,
+ 'INSTRUMENTED_POP_JUMP_IF_NOT_NONE': 253,
+ 'INSTRUMENTED_LINE': 254,
+ 'JUMP': 256,
+ 'JUMP_NO_INTERRUPT': 257,
+ 'LOAD_CLOSURE': 258,
+ 'LOAD_METHOD': 259,
+ 'LOAD_SUPER_METHOD': 260,
+ 'LOAD_ZERO_SUPER_ATTR': 261,
+ 'LOAD_ZERO_SUPER_METHOD': 262,
+ 'POP_BLOCK': 263,
+ 'SETUP_CLEANUP': 264,
+ 'SETUP_FINALLY': 265,
+ 'SETUP_WITH': 266,
+ 'STORE_FAST_MAYBE_NULL': 267,
+}
+MIN_INSTRUMENTED_OPCODE = 237
+HAVE_ARGUMENT = 67
diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py
index 3c72c289e43882..21f3fa5c213f1f 100644
--- a/Lib/dataclasses.py
+++ b/Lib/dataclasses.py
@@ -575,15 +575,15 @@ def _init_fn(fields, std_fields, kw_only_fields, frozen, has_post_init,
# message, and future-proofs us in case we build up the function
# using ast.
- seen_default = False
+ seen_default = None
for f in std_fields:
# Only consider the non-kw-only fields in the __init__ call.
if f.init:
if not (f.default is MISSING and f.default_factory is MISSING):
- seen_default = True
+ seen_default = f
elif seen_default:
raise TypeError(f'non-default argument {f.name!r} '
- 'follows default argument')
+ f'follows default argument {seen_default.name!r}')
locals = {f'__dataclass_type_{f.name}__': f.type for f in fields}
locals.update({
diff --git a/Lib/dis.py b/Lib/dis.py
index b167773dfe7b0c..4f4e77f32503df 100644
--- a/Lib/dis.py
+++ b/Lib/dis.py
@@ -14,7 +14,7 @@
_intrinsic_1_descs,
_intrinsic_2_descs,
_specializations,
- _specialized_instructions,
+ _specialized_opmap,
)
__all__ = ["code_info", "dis", "disassemble", "distb", "disco",
@@ -49,11 +49,11 @@
_all_opname = list(opname)
_all_opmap = dict(opmap)
-_empty_slot = [slot for slot, name in enumerate(_all_opname) if name.startswith("<")]
-for spec_op, specialized in zip(_empty_slot, _specialized_instructions):
+for name, op in _specialized_opmap.items():
# fill opname and opmap
- _all_opname[spec_op] = specialized
- _all_opmap[specialized] = spec_op
+ assert op < len(_all_opname)
+ _all_opname[op] = name
+ _all_opmap[name] = op
deoptmap = {
specialized: base for base, family in _specializations.items() for specialized in family
@@ -552,15 +552,15 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
if deop == LOAD_GLOBAL:
argval, argrepr = _get_name_info(arg//2, get_name)
if (arg & 1) and argrepr:
- argrepr = "NULL + " + argrepr
+ argrepr = f"{argrepr} + NULL"
elif deop == LOAD_ATTR:
argval, argrepr = _get_name_info(arg//2, get_name)
if (arg & 1) and argrepr:
- argrepr = "NULL|self + " + argrepr
+ argrepr = f"{argrepr} + NULL|self"
elif deop == LOAD_SUPER_ATTR:
argval, argrepr = _get_name_info(arg//4, get_name)
if (arg & 1) and argrepr:
- argrepr = "NULL|self + " + argrepr
+ argrepr = f"{argrepr} + NULL|self"
else:
argval, argrepr = _get_name_info(arg, get_name)
elif deop in hasjabs:
diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py
index 16a82bef2ba71f..0717e202ecbcde 100644
--- a/Lib/importlib/_bootstrap_external.py
+++ b/Lib/importlib/_bootstrap_external.py
@@ -453,6 +453,8 @@ def _write_atomic(path, data, mode=0o666):
# Python 3.13a1 3555 (generate specialized opcodes metadata from bytecodes.c)
# Python 3.13a1 3556 (Convert LOAD_CLOSURE to a pseudo-op)
# Python 3.13a1 3557 (Make the conversion to boolean in jumps explicit)
+# Python 3.13a1 3558 (Reorder the stack items for CALL)
+# Python 3.13a1 3559 (Generate opcode IDs from bytecodes.c)
# Python 3.14 will start with 3600
@@ -469,7 +471,7 @@ def _write_atomic(path, data, mode=0o666):
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
# in PC/launcher.c must also be updated.
-MAGIC_NUMBER = (3557).to_bytes(2, 'little') + b'\r\n'
+MAGIC_NUMBER = (3559).to_bytes(2, 'little') + b'\r\n'
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py
index 527fc5c631730a..2d228e563094c8 100644
--- a/Lib/logging/__init__.py
+++ b/Lib/logging/__init__.py
@@ -1879,7 +1879,7 @@ class LoggerAdapter(object):
information in logging output.
"""
- def __init__(self, logger, extra=None):
+ def __init__(self, logger, extra=None, merge_extra=False):
"""
Initialize the adapter with a logger and a dict-like object which
provides contextual information. This constructor signature allows
@@ -1889,9 +1889,20 @@ def __init__(self, logger, extra=None):
following example:
adapter = LoggerAdapter(someLogger, dict(p1=v1, p2="v2"))
+
+ By default, LoggerAdapter objects will drop the "extra" argument
+ passed on the individual log calls to use its own instead.
+
+ Initializing it with merge_extra=True will instead merge both
+ maps when logging, the individual call extra taking precedence
+ over the LoggerAdapter instance extra
+
+ .. versionchanged:: 3.13
+ The *merge_extra* argument was added.
"""
self.logger = logger
self.extra = extra
+ self.merge_extra = merge_extra
def process(self, msg, kwargs):
"""
@@ -1903,7 +1914,10 @@ def process(self, msg, kwargs):
Normally, you'll only need to override this one method in a
LoggerAdapter subclass for your specific needs.
"""
- kwargs["extra"] = self.extra
+ if self.merge_extra and "extra" in kwargs:
+ kwargs["extra"] = {**self.extra, **kwargs["extra"]}
+ else:
+ kwargs["extra"] = self.extra
return msg, kwargs
#
diff --git a/Lib/multiprocessing/forkserver.py b/Lib/multiprocessing/forkserver.py
index 22a911a7a29cdc..4642707dae2f4e 100644
--- a/Lib/multiprocessing/forkserver.py
+++ b/Lib/multiprocessing/forkserver.py
@@ -61,7 +61,7 @@ def _stop_unlocked(self):
def set_forkserver_preload(self, modules_names):
'''Set list of module names to try to load in forkserver process.'''
- if not all(type(mod) is str for mod in self._preload_modules):
+ if not all(type(mod) is str for mod in modules_names):
raise TypeError('module_names must be a list of strings')
self._preload_modules = modules_names
diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py
index b6534939b4d98b..273c22a7654f05 100644
--- a/Lib/multiprocessing/managers.py
+++ b/Lib/multiprocessing/managers.py
@@ -90,7 +90,10 @@ def dispatch(c, id, methodname, args=(), kwds={}):
kind, result = c.recv()
if kind == '#RETURN':
return result
- raise convert_to_error(kind, result)
+ try:
+ raise convert_to_error(kind, result)
+ finally:
+ del result # break reference cycle
def convert_to_error(kind, result):
if kind == '#ERROR':
@@ -833,7 +836,10 @@ def _callmethod(self, methodname, args=(), kwds={}):
conn = self._Client(token.address, authkey=self._authkey)
dispatch(conn, None, 'decref', (token.id,))
return proxy
- raise convert_to_error(kind, result)
+ try:
+ raise convert_to_error(kind, result)
+ finally:
+ del result # break reference cycle
def _getvalue(self):
'''
diff --git a/Lib/multiprocessing/spawn.py b/Lib/multiprocessing/spawn.py
index f1af7709104714..daac1ecc34b55e 100644
--- a/Lib/multiprocessing/spawn.py
+++ b/Lib/multiprocessing/spawn.py
@@ -150,7 +150,11 @@ def _check_not_importing_main():
...
The "freeze_support()" line can be omitted if the program
- is not going to be frozen to produce an executable.''')
+ is not going to be frozen to produce an executable.
+
+ To fix this issue, refer to the "Safe importing of main module"
+ section in https://docs.python.org/3/library/multiprocessing.html
+ ''')
def get_preparation_data(name):
diff --git a/Lib/opcode.py b/Lib/opcode.py
index 5a9f8ddd0738db..6b9d9ce811a61c 100644
--- a/Lib/opcode.py
+++ b/Lib/opcode.py
@@ -6,8 +6,7 @@
# Note that __all__ is further extended below
-__all__ = ["cmp_op", "opname", "opmap", "stack_effect", "hascompare",
- "HAVE_ARGUMENT", "EXTENDED_ARG"]
+__all__ = ["cmp_op", "stack_effect", "hascompare"]
import _opcode
from _opcode import stack_effect
@@ -15,214 +14,17 @@
import sys
# The build uses older versions of Python which do not have _opcode_metadata
if sys.version_info[:2] >= (3, 13):
- from _opcode_metadata import _specializations, _specialized_instructions
+ from _opcode_metadata import _specializations, _specialized_opmap
+ from _opcode_metadata import opmap, HAVE_ARGUMENT, MIN_INSTRUMENTED_OPCODE
+ EXTENDED_ARG = opmap['EXTENDED_ARG']
-cmp_op = ('<', '<=', '==', '!=', '>', '>=')
-
-opmap = {}
-
-def def_op(name, op):
- opmap[name] = op
-
-# Instruction opcodes for compiled code
-# Blank lines correspond to available opcodes
-
-def_op('CACHE', 0)
-def_op('POP_TOP', 1)
-def_op('PUSH_NULL', 2)
-def_op('INTERPRETER_EXIT', 3)
-def_op('END_FOR', 4)
-def_op('END_SEND', 5)
-def_op('TO_BOOL', 6)
-
-def_op('NOP', 9)
-
-def_op('UNARY_NEGATIVE', 11)
-def_op('UNARY_NOT', 12)
-
-def_op('UNARY_INVERT', 15)
-def_op('EXIT_INIT_CHECK', 16)
-
-# We reserve 17 as it is the initial value for the specializing counter
-# This helps us catch cases where we attempt to execute a cache.
-def_op('RESERVED', 17)
-
-def_op('MAKE_FUNCTION', 24)
-def_op('BINARY_SUBSCR', 25)
-def_op('BINARY_SLICE', 26)
-def_op('STORE_SLICE', 27)
-
-def_op('GET_LEN', 30)
-def_op('MATCH_MAPPING', 31)
-def_op('MATCH_SEQUENCE', 32)
-def_op('MATCH_KEYS', 33)
-
-def_op('PUSH_EXC_INFO', 35)
-def_op('CHECK_EXC_MATCH', 36)
-def_op('CHECK_EG_MATCH', 37)
-
-def_op('FORMAT_SIMPLE', 40)
-def_op('FORMAT_WITH_SPEC', 41)
-
-def_op('WITH_EXCEPT_START', 49)
-def_op('GET_AITER', 50)
-def_op('GET_ANEXT', 51)
-def_op('BEFORE_ASYNC_WITH', 52)
-def_op('BEFORE_WITH', 53)
-def_op('END_ASYNC_FOR', 54)
-def_op('CLEANUP_THROW', 55)
-
-def_op('STORE_SUBSCR', 60)
-def_op('DELETE_SUBSCR', 61)
-
-def_op('GET_ITER', 68)
-def_op('GET_YIELD_FROM_ITER', 69)
-
-def_op('LOAD_BUILD_CLASS', 71)
-
-def_op('LOAD_ASSERTION_ERROR', 74)
-def_op('RETURN_GENERATOR', 75)
-
-def_op('RETURN_VALUE', 83)
+ opname = ['<%r>' % (op,) for op in range(max(opmap.values()) + 1)]
+ for op, i in opmap.items():
+ opname[i] = op
-def_op('SETUP_ANNOTATIONS', 85)
+ __all__.extend(["opname", "opmap", "HAVE_ARGUMENT", "EXTENDED_ARG"])
-def_op('LOAD_LOCALS', 87)
-
-def_op('POP_EXCEPT', 89)
-
-HAVE_ARGUMENT = 90 # real opcodes from here have an argument:
-
-def_op('STORE_NAME', 90) # Index in name list
-def_op('DELETE_NAME', 91) # ""
-def_op('UNPACK_SEQUENCE', 92) # Number of tuple items
-def_op('FOR_ITER', 93)
-def_op('UNPACK_EX', 94)
-def_op('STORE_ATTR', 95) # Index in name list
-def_op('DELETE_ATTR', 96) # ""
-def_op('STORE_GLOBAL', 97) # ""
-def_op('DELETE_GLOBAL', 98) # ""
-def_op('SWAP', 99)
-def_op('LOAD_CONST', 100) # Index in const list
-def_op('LOAD_NAME', 101) # Index in name list
-def_op('BUILD_TUPLE', 102) # Number of tuple items
-def_op('BUILD_LIST', 103) # Number of list items
-def_op('BUILD_SET', 104) # Number of set items
-def_op('BUILD_MAP', 105) # Number of dict entries
-def_op('LOAD_ATTR', 106) # Index in name list
-def_op('COMPARE_OP', 107) # Comparison operator
-def_op('IMPORT_NAME', 108) # Index in name list
-def_op('IMPORT_FROM', 109) # Index in name list
-def_op('JUMP_FORWARD', 110) # Number of words to skip
-
-def_op('POP_JUMP_IF_FALSE', 114)
-def_op('POP_JUMP_IF_TRUE', 115)
-def_op('LOAD_GLOBAL', 116) # Index in name list
-def_op('IS_OP', 117)
-def_op('CONTAINS_OP', 118)
-def_op('RERAISE', 119)
-def_op('COPY', 120)
-def_op('RETURN_CONST', 121)
-def_op('BINARY_OP', 122)
-def_op('SEND', 123) # Number of words to skip
-def_op('LOAD_FAST', 124) # Local variable number, no null check
-def_op('STORE_FAST', 125) # Local variable number
-def_op('DELETE_FAST', 126) # Local variable number
-def_op('LOAD_FAST_CHECK', 127) # Local variable number
-def_op('POP_JUMP_IF_NOT_NONE', 128)
-def_op('POP_JUMP_IF_NONE', 129)
-def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3)
-def_op('GET_AWAITABLE', 131)
-def_op('BUILD_SLICE', 133) # Number of items
-def_op('JUMP_BACKWARD_NO_INTERRUPT', 134) # Number of words to skip (backwards)
-def_op('MAKE_CELL', 135)
-def_op('LOAD_DEREF', 137)
-def_op('STORE_DEREF', 138)
-def_op('DELETE_DEREF', 139)
-def_op('JUMP_BACKWARD', 140) # Number of words to skip (backwards)
-def_op('LOAD_SUPER_ATTR', 141)
-def_op('CALL_FUNCTION_EX', 142) # Flags
-def_op('LOAD_FAST_AND_CLEAR', 143) # Local variable number
-def_op('EXTENDED_ARG', 144)
-EXTENDED_ARG = opmap['EXTENDED_ARG']
-def_op('LIST_APPEND', 145)
-def_op('SET_ADD', 146)
-def_op('MAP_ADD', 147)
-def_op('COPY_FREE_VARS', 149)
-def_op('YIELD_VALUE', 150)
-def_op('RESUME', 151) # This must be kept in sync with deepfreeze.py
-def_op('MATCH_CLASS', 152)
-
-def_op('BUILD_CONST_KEY_MAP', 156)
-def_op('BUILD_STRING', 157)
-def_op('CONVERT_VALUE', 158)
-
-def_op('LIST_EXTEND', 162)
-def_op('SET_UPDATE', 163)
-def_op('DICT_MERGE', 164)
-def_op('DICT_UPDATE', 165)
-
-def_op('LOAD_FAST_LOAD_FAST', 168)
-def_op('STORE_FAST_LOAD_FAST', 169)
-def_op('STORE_FAST_STORE_FAST', 170)
-def_op('CALL', 171)
-def_op('KW_NAMES', 172)
-def_op('CALL_INTRINSIC_1', 173)
-def_op('CALL_INTRINSIC_2', 174)
-def_op('LOAD_FROM_DICT_OR_GLOBALS', 175)
-def_op('LOAD_FROM_DICT_OR_DEREF', 176)
-def_op('SET_FUNCTION_ATTRIBUTE', 177) # Attribute
-
-# Optimizer hook
-def_op('ENTER_EXECUTOR', 230)
-
-# Instrumented instructions
-MIN_INSTRUMENTED_OPCODE = 237
-
-def_op('INSTRUMENTED_LOAD_SUPER_ATTR', 237)
-def_op('INSTRUMENTED_POP_JUMP_IF_NONE', 238)
-def_op('INSTRUMENTED_POP_JUMP_IF_NOT_NONE', 239)
-def_op('INSTRUMENTED_RESUME', 240)
-def_op('INSTRUMENTED_CALL', 241)
-def_op('INSTRUMENTED_RETURN_VALUE', 242)
-def_op('INSTRUMENTED_YIELD_VALUE', 243)
-def_op('INSTRUMENTED_CALL_FUNCTION_EX', 244)
-def_op('INSTRUMENTED_JUMP_FORWARD', 245)
-def_op('INSTRUMENTED_JUMP_BACKWARD', 246)
-def_op('INSTRUMENTED_RETURN_CONST', 247)
-def_op('INSTRUMENTED_FOR_ITER', 248)
-def_op('INSTRUMENTED_POP_JUMP_IF_FALSE', 249)
-def_op('INSTRUMENTED_POP_JUMP_IF_TRUE', 250)
-def_op('INSTRUMENTED_END_FOR', 251)
-def_op('INSTRUMENTED_END_SEND', 252)
-def_op('INSTRUMENTED_INSTRUCTION', 253)
-def_op('INSTRUMENTED_LINE', 254)
-# 255 is reserved
-
-
-# Pseudo ops are above 255:
-
-def_op('SETUP_FINALLY', 256)
-def_op('SETUP_CLEANUP', 257)
-def_op('SETUP_WITH', 258)
-def_op('POP_BLOCK', 259)
-
-def_op('JUMP', 260)
-def_op('JUMP_NO_INTERRUPT', 261)
-
-def_op('LOAD_METHOD', 262)
-def_op('LOAD_SUPER_METHOD', 263)
-def_op('LOAD_ZERO_SUPER_METHOD', 264)
-def_op('LOAD_ZERO_SUPER_ATTR', 265)
-
-def_op('STORE_FAST_MAYBE_NULL', 266)
-def_op('LOAD_CLOSURE', 267)
-
-del def_op
-
-opname = ['<%r>' % (op,) for op in range(max(opmap.values()) + 1)]
-for op, i in opmap.items():
- opname[i] = op
+cmp_op = ('<', '<=', '==', '!=', '>', '>=')
# The build uses older versions of Python which do not have _opcode.has_* functions
if sys.version_info[:2] >= (3, 13):
@@ -243,7 +45,7 @@ def def_op(name, op):
_intrinsic_1_descs = _opcode.get_intrinsic1_descs()
_intrinsic_2_descs = _opcode.get_intrinsic2_descs()
-hascompare = [opmap["COMPARE_OP"]]
+ hascompare = [opmap["COMPARE_OP"]]
_nb_ops = [
("NB_ADD", "+"),
diff --git a/Lib/pydoc.py b/Lib/pydoc.py
index 185f09e603df2e..c9a55799b39f0c 100755
--- a/Lib/pydoc.py
+++ b/Lib/pydoc.py
@@ -197,6 +197,24 @@ def splitdoc(doc):
return lines[0], '\n'.join(lines[2:])
return '', '\n'.join(lines)
+def _getargspec(object):
+ try:
+ signature = inspect.signature(object)
+ if signature:
+ return str(signature)
+ except (ValueError, TypeError):
+ argspec = getattr(object, '__text_signature__', None)
+ if argspec:
+ if argspec[:2] == '($':
+ argspec = '(' + argspec[2:]
+ if getattr(object, '__self__', None) is not None:
+ # Strip the bound argument.
+ m = re.match(r'\(\w+(?:(?=\))|,\s*(?:/(?:(?=\))|,\s*))?)', argspec)
+ if m:
+ argspec = '(' + argspec[m.end():]
+ return argspec
+ return None
+
def classname(object, modname):
"""Get a class name and qualify it with a module name if necessary."""
name = object.__name__
@@ -1003,14 +1021,9 @@ def spilldata(msg, attrs, predicate):
title = title + '(%s)' % ', '.join(parents)
decl = ''
- try:
- signature = inspect.signature(object)
- except (ValueError, TypeError):
- signature = None
- if signature:
- argspec = str(signature)
- if argspec and argspec != '()':
- decl = name + self.escape(argspec) + '\n\n'
+ argspec = _getargspec(object)
+ if argspec and argspec != '()':
+ decl = name + self.escape(argspec) + '\n\n'
doc = getdoc(object)
if decl:
@@ -1063,18 +1076,13 @@ def docroutine(self, object, name=None, mod=None,
anchor, name, reallink)
argspec = None
if inspect.isroutine(object):
- try:
- signature = inspect.signature(object)
- except (ValueError, TypeError):
- signature = None
- if signature:
- argspec = str(signature)
- if realname == '':
- title = '%s lambda ' % name
- # XXX lambda's won't usually have func_annotations['return']
- # since the syntax doesn't support but it is possible.
- # So removing parentheses isn't truly safe.
- argspec = argspec[1:-1] # remove parentheses
+ argspec = _getargspec(object)
+ if argspec and realname == '':
+ title = '%s lambda ' % name
+ # XXX lambda's won't usually have func_annotations['return']
+ # since the syntax doesn't support but it is possible.
+ # So removing parentheses isn't truly safe.
+ argspec = argspec[1:-1] # remove parentheses
if not argspec:
argspec = '(...)'
@@ -1321,14 +1329,9 @@ def makename(c, m=object.__module__):
contents = []
push = contents.append
- try:
- signature = inspect.signature(object)
- except (ValueError, TypeError):
- signature = None
- if signature:
- argspec = str(signature)
- if argspec and argspec != '()':
- push(name + argspec + '\n')
+ argspec = _getargspec(object)
+ if argspec and argspec != '()':
+ push(name + argspec + '\n')
doc = getdoc(object)
if doc:
@@ -1492,18 +1495,13 @@ def docroutine(self, object, name=None, mod=None, cl=None):
argspec = None
if inspect.isroutine(object):
- try:
- signature = inspect.signature(object)
- except (ValueError, TypeError):
- signature = None
- if signature:
- argspec = str(signature)
- if realname == '':
- title = self.bold(name) + ' lambda '
- # XXX lambda's won't usually have func_annotations['return']
- # since the syntax doesn't support but it is possible.
- # So removing parentheses isn't truly safe.
- argspec = argspec[1:-1] # remove parentheses
+ argspec = _getargspec(object)
+ if argspec and realname == '':
+ title = self.bold(name) + ' lambda '
+ # XXX lambda's won't usually have func_annotations['return']
+ # since the syntax doesn't support but it is possible.
+ # So removing parentheses isn't truly safe.
+ argspec = argspec[1:-1] # remove parentheses
if not argspec:
argspec = '(...)'
decl = asyncqualifier + title + argspec + note
diff --git a/Lib/re/__init__.py b/Lib/re/__init__.py
index d6fccd5bc97cc0..428d1b0d5fbd87 100644
--- a/Lib/re/__init__.py
+++ b/Lib/re/__init__.py
@@ -175,16 +175,39 @@ def search(pattern, string, flags=0):
a Match object, or None if no match was found."""
return _compile(pattern, flags).search(string)
-def sub(pattern, repl, string, count=0, flags=0):
+class _ZeroSentinel(int):
+ pass
+_zero_sentinel = _ZeroSentinel()
+
+def sub(pattern, repl, string, *args, count=_zero_sentinel, flags=_zero_sentinel):
"""Return the string obtained by replacing the leftmost
non-overlapping occurrences of the pattern in string by the
replacement repl. repl can be either a string or a callable;
if a string, backslash escapes in it are processed. If it is
a callable, it's passed the Match object and must return
a replacement string to be used."""
+ if args:
+ if count is not _zero_sentinel:
+ raise TypeError("sub() got multiple values for argument 'count'")
+ count, *args = args
+ if args:
+ if flags is not _zero_sentinel:
+ raise TypeError("sub() got multiple values for argument 'flags'")
+ flags, *args = args
+ if args:
+ raise TypeError("sub() takes from 3 to 5 positional arguments "
+ "but %d were given" % (5 + len(args)))
+
+ import warnings
+ warnings.warn(
+ "'count' is passed as positional argument",
+ DeprecationWarning, stacklevel=2
+ )
+
return _compile(pattern, flags).sub(repl, string, count)
+sub.__text_signature__ = '(pattern, repl, string, count=0, flags=0)'
-def subn(pattern, repl, string, count=0, flags=0):
+def subn(pattern, repl, string, *args, count=_zero_sentinel, flags=_zero_sentinel):
"""Return a 2-tuple containing (new_string, number).
new_string is the string obtained by replacing the leftmost
non-overlapping occurrences of the pattern in the source
@@ -193,9 +216,28 @@ def subn(pattern, repl, string, count=0, flags=0):
callable; if a string, backslash escapes in it are processed.
If it is a callable, it's passed the Match object and must
return a replacement string to be used."""
+ if args:
+ if count is not _zero_sentinel:
+ raise TypeError("subn() got multiple values for argument 'count'")
+ count, *args = args
+ if args:
+ if flags is not _zero_sentinel:
+ raise TypeError("subn() got multiple values for argument 'flags'")
+ flags, *args = args
+ if args:
+ raise TypeError("subn() takes from 3 to 5 positional arguments "
+ "but %d were given" % (5 + len(args)))
+
+ import warnings
+ warnings.warn(
+ "'count' is passed as positional argument",
+ DeprecationWarning, stacklevel=2
+ )
+
return _compile(pattern, flags).subn(repl, string, count)
+subn.__text_signature__ = '(pattern, repl, string, count=0, flags=0)'
-def split(pattern, string, maxsplit=0, flags=0):
+def split(pattern, string, *args, maxsplit=_zero_sentinel, flags=_zero_sentinel):
"""Split the source string by the occurrences of the pattern,
returning a list containing the resulting substrings. If
capturing parentheses are used in pattern, then the text of all
@@ -203,7 +245,26 @@ def split(pattern, string, maxsplit=0, flags=0):
list. If maxsplit is nonzero, at most maxsplit splits occur,
and the remainder of the string is returned as the final element
of the list."""
+ if args:
+ if maxsplit is not _zero_sentinel:
+ raise TypeError("split() got multiple values for argument 'maxsplit'")
+ maxsplit, *args = args
+ if args:
+ if flags is not _zero_sentinel:
+ raise TypeError("split() got multiple values for argument 'flags'")
+ flags, *args = args
+ if args:
+ raise TypeError("split() takes from 2 to 4 positional arguments "
+ "but %d were given" % (4 + len(args)))
+
+ import warnings
+ warnings.warn(
+ "'maxsplit' is passed as positional argument",
+ DeprecationWarning, stacklevel=2
+ )
+
return _compile(pattern, flags).split(string, maxsplit)
+split.__text_signature__ = '(pattern, string, maxsplit=0, flags=0)'
def findall(pattern, string, flags=0):
"""Return a list of all non-overlapping matches in the string.
diff --git a/Lib/re/_compiler.py b/Lib/re/_compiler.py
index f5fd160ba00435..d0a4c55caf6e41 100644
--- a/Lib/re/_compiler.py
+++ b/Lib/re/_compiler.py
@@ -100,13 +100,6 @@ def _compile(code, pattern, flags):
emit(ANY_ALL)
else:
emit(ANY)
- elif op is POSSESSIVE_REPEAT:
- # gh-106052: Possessive quantifiers do not work when the
- # subpattern contains backtracking, i.e. "(?:ab?c)*+".
- # Implement it as equivalent greedy qualifier in atomic group.
- p = [(MAX_REPEAT, av)]
- p = [(ATOMIC_GROUP, p)]
- _compile(code, p, flags)
elif op in REPEATING_CODES:
if _simple(av[2]):
emit(REPEATING_CODES[op][2])
diff --git a/Lib/reprlib.py b/Lib/reprlib.py
index a92b3e3dbb613a..840dd0e20132b1 100644
--- a/Lib/reprlib.py
+++ b/Lib/reprlib.py
@@ -29,6 +29,7 @@ def wrapper(self):
wrapper.__name__ = getattr(user_function, '__name__')
wrapper.__qualname__ = getattr(user_function, '__qualname__')
wrapper.__annotations__ = getattr(user_function, '__annotations__', {})
+ wrapper.__wrapped__ = user_function
return wrapper
return decorating_function
diff --git a/Lib/shutil.py b/Lib/shutil.py
index 3f2864af517e7d..b37bd082eee0c6 100644
--- a/Lib/shutil.py
+++ b/Lib/shutil.py
@@ -1156,6 +1156,10 @@ def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
supports_root_dir = getattr(func, 'supports_root_dir', False)
save_cwd = None
if root_dir is not None:
+ stmd = os.stat(root_dir).st_mode
+ if not stat.S_ISDIR(stmd):
+ raise NotADirectoryError(errno.ENOTDIR, 'Not a directory', root_dir)
+
if supports_root_dir:
# Support path-like base_name here for backwards-compatibility.
base_name = os.fspath(base_name)
diff --git a/Lib/statistics.py b/Lib/statistics.py
index 93c44f1f13fab7..a8036e9928c464 100644
--- a/Lib/statistics.py
+++ b/Lib/statistics.py
@@ -137,6 +137,7 @@
from itertools import count, groupby, repeat
from bisect import bisect_left, bisect_right
from math import hypot, sqrt, fabs, exp, erf, tau, log, fsum, sumprod
+from math import isfinite, isinf
from functools import reduce
from operator import itemgetter
from collections import Counter, namedtuple, defaultdict
@@ -1005,14 +1006,25 @@ def _mean_stdev(data):
return float(xbar), float(xbar) / float(ss)
def _sqrtprod(x: float, y: float) -> float:
- "Return sqrt(x * y) computed with high accuracy."
- # Square root differential correction:
- # https://www.wolframalpha.com/input/?i=Maclaurin+series+sqrt%28h**2+%2B+x%29+at+x%3D0
+ "Return sqrt(x * y) computed with improved accuracy and without overflow/underflow."
h = sqrt(x * y)
+ if not isfinite(h):
+ if isinf(h) and not isinf(x) and not isinf(y):
+ # Finite inputs overflowed, so scale down, and recompute.
+ scale = 2.0 ** -512 # sqrt(1 / sys.float_info.max)
+ return _sqrtprod(scale * x, scale * y) / scale
+ return h
if not h:
- return 0.0
- x = sumprod((x, h), (y, -h))
- return h + x / (2.0 * h)
+ if x and y:
+ # Non-zero inputs underflowed, so scale up, and recompute.
+ # Scale: 1 / sqrt(sys.float_info.min * sys.float_info.epsilon)
+ scale = 2.0 ** 537
+ return _sqrtprod(scale * x, scale * y) / scale
+ return h
+ # Improve accuracy with a differential correction.
+ # https://www.wolframalpha.com/input/?i=Maclaurin+series+sqrt%28h**2+%2B+x%29+at+x%3D0
+ d = sumprod((x, h), (y, -h))
+ return h + d / (2.0 * h)
# === Statistics for relations between two inputs ===
diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py
index c1f9487ae80511..10754964e73bc5 100644
--- a/Lib/test/_test_multiprocessing.py
+++ b/Lib/test/_test_multiprocessing.py
@@ -3149,6 +3149,44 @@ def test_rapid_restart(self):
if hasattr(manager, "shutdown"):
self.addCleanup(manager.shutdown)
+
+class FakeConnection:
+ def send(self, payload):
+ pass
+
+ def recv(self):
+ return '#ERROR', pyqueue.Empty()
+
+class TestManagerExceptions(unittest.TestCase):
+ # Issue 106558: Manager exceptions avoids creating cyclic references.
+ def setUp(self):
+ self.mgr = multiprocessing.Manager()
+
+ def tearDown(self):
+ self.mgr.shutdown()
+ self.mgr.join()
+
+ def test_queue_get(self):
+ queue = self.mgr.Queue()
+ if gc.isenabled():
+ gc.disable()
+ self.addCleanup(gc.enable)
+ try:
+ queue.get_nowait()
+ except pyqueue.Empty as e:
+ wr = weakref.ref(e)
+ self.assertEqual(wr(), None)
+
+ def test_dispatch(self):
+ if gc.isenabled():
+ gc.disable()
+ self.addCleanup(gc.enable)
+ try:
+ multiprocessing.managers.dispatch(FakeConnection(), None, None)
+ except pyqueue.Empty as e:
+ wr = weakref.ref(e)
+ self.assertEqual(wr(), None)
+
#
#
#
@@ -5331,6 +5369,14 @@ def test_context(self):
self.assertRaises(ValueError, ctx.set_start_method, None)
self.check_context(ctx)
+ def test_context_check_module_types(self):
+ try:
+ ctx = multiprocessing.get_context('forkserver')
+ except ValueError:
+ raise unittest.SkipTest('forkserver should be available')
+ with self.assertRaisesRegex(TypeError, 'module_names must be a list of strings'):
+ ctx.set_forkserver_preload([1, 2, 3])
+
def test_set_get(self):
multiprocessing.set_forkserver_preload(PRELOAD)
count = 0
diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py
index 0edc9d9c472766..9504829e96f00e 100644
--- a/Lib/test/audit-tests.py
+++ b/Lib/test/audit-tests.py
@@ -514,6 +514,17 @@ def test_not_in_gc():
assert hook not in o
+def test_sys_monitoring_register_callback():
+ import sys
+
+ def hook(event, args):
+ if event.startswith("sys.monitoring"):
+ print(event, args)
+
+ sys.addaudithook(hook)
+ sys.monitoring.register_callback(1, 1, None)
+
+
if __name__ == "__main__":
from test.support import suppress_msvcrt_asserts
diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c
index 9fcee0dad7118b..019dc10073e986 100644
--- a/Lib/test/clinic.test.c
+++ b/Lib/test/clinic.test.c
@@ -4,9 +4,11 @@ output preset block
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=3c81ac2402d06a8b]*/
/*[clinic input]
+module m
+class m.T "TestObj *" "TestType"
class Test "TestObj *" "TestType"
[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=fc7e50384d12b83f]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=f761b4d55cb179cf]*/
/*[clinic input]
test_object_converter
@@ -5465,975 +5467,3 @@ docstr_fallback_to_converter_default(PyObject *module, PyObject *const *args, Py
static PyObject *
docstr_fallback_to_converter_default_impl(PyObject *module, str a)
/*[clinic end generated code: output=ae24a9c6f60ee8a6 input=0cbe6a4d24bc2274]*/
-
-
-/*[clinic input]
-test_deprecate_positional_pos1_len1_optional
- a: object
- * [from 3.14]
- b: object = None
-[clinic start generated code]*/
-
-PyDoc_STRVAR(test_deprecate_positional_pos1_len1_optional__doc__,
-"test_deprecate_positional_pos1_len1_optional($module, /, a, b=None)\n"
-"--\n"
-"\n"
-"Note: Passing 2 positional arguments to\n"
-"test_deprecate_positional_pos1_len1_optional() is deprecated.\n"
-"Parameter \'b\' will become a keyword-only parameter in Python 3.14.\n"
-"");
-
-#define TEST_DEPRECATE_POSITIONAL_POS1_LEN1_OPTIONAL_METHODDEF \
- {"test_deprecate_positional_pos1_len1_optional", _PyCFunction_CAST(test_deprecate_positional_pos1_len1_optional), METH_FASTCALL|METH_KEYWORDS, test_deprecate_positional_pos1_len1_optional__doc__},
-
-static PyObject *
-test_deprecate_positional_pos1_len1_optional_impl(PyObject *module,
- PyObject *a, PyObject *b);
-
-static PyObject *
-test_deprecate_positional_pos1_len1_optional(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 2
- 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(a), &_Py_ID(b), },
- };
- #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", NULL};
- static _PyArg_Parser _parser = {
- .keywords = _keywords,
- .fname = "test_deprecate_positional_pos1_len1_optional",
- .kwtuple = KWTUPLE,
- };
- #undef KWTUPLE
- PyObject *argsbuf[2];
- Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
- PyObject *a;
- PyObject *b = Py_None;
-
- // Emit compiler warnings when we get to Python 3.14.
- #if PY_VERSION_HEX >= 0x030e00C0
- # error \
- "In clinic.test.c, update parameter(s) 'b' in the clinic input of" \
- " 'test_deprecate_positional_pos1_len1_optional' to be " \
- "keyword-only."
- #elif PY_VERSION_HEX >= 0x030e00A0
- # ifdef _MSC_VER
- # pragma message ( \
- "In clinic.test.c, update parameter(s) 'b' in the clinic input of" \
- " 'test_deprecate_positional_pos1_len1_optional' to be " \
- "keyword-only.")
- # else
- # warning \
- "In clinic.test.c, update parameter(s) 'b' in the clinic input of" \
- " 'test_deprecate_positional_pos1_len1_optional' to be " \
- "keyword-only."
- # endif
- #endif
- if (nargs == 2) {
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "Passing 2 positional arguments to "
- "test_deprecate_positional_pos1_len1_optional() is deprecated. "
- "Parameter 'b' will become a keyword-only parameter in Python "
- "3.14.", 1))
- {
- goto exit;
- }
- }
- args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 2, 0, argsbuf);
- if (!args) {
- goto exit;
- }
- a = args[0];
- if (!noptargs) {
- goto skip_optional_pos;
- }
- b = args[1];
-skip_optional_pos:
- return_value = test_deprecate_positional_pos1_len1_optional_impl(module, a, b);
-
-exit:
- return return_value;
-}
-
-static PyObject *
-test_deprecate_positional_pos1_len1_optional_impl(PyObject *module,
- PyObject *a, PyObject *b)
-/*[clinic end generated code: output=144cbf1adc574dd9 input=89099f3dacd757da]*/
-
-
-/*[clinic input]
-test_deprecate_positional_pos1_len1
- a: object
- * [from 3.14]
- b: object
-[clinic start generated code]*/
-
-PyDoc_STRVAR(test_deprecate_positional_pos1_len1__doc__,
-"test_deprecate_positional_pos1_len1($module, /, a, b)\n"
-"--\n"
-"\n"
-"Note: Passing 2 positional arguments to\n"
-"test_deprecate_positional_pos1_len1() is deprecated. Parameter \'b\'\n"
-"will become a keyword-only parameter in Python 3.14.\n"
-"");
-
-#define TEST_DEPRECATE_POSITIONAL_POS1_LEN1_METHODDEF \
- {"test_deprecate_positional_pos1_len1", _PyCFunction_CAST(test_deprecate_positional_pos1_len1), METH_FASTCALL|METH_KEYWORDS, test_deprecate_positional_pos1_len1__doc__},
-
-static PyObject *
-test_deprecate_positional_pos1_len1_impl(PyObject *module, PyObject *a,
- PyObject *b);
-
-static PyObject *
-test_deprecate_positional_pos1_len1(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 2
- 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(a), &_Py_ID(b), },
- };
- #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", NULL};
- static _PyArg_Parser _parser = {
- .keywords = _keywords,
- .fname = "test_deprecate_positional_pos1_len1",
- .kwtuple = KWTUPLE,
- };
- #undef KWTUPLE
- PyObject *argsbuf[2];
- PyObject *a;
- PyObject *b;
-
- // Emit compiler warnings when we get to Python 3.14.
- #if PY_VERSION_HEX >= 0x030e00C0
- # error \
- "In clinic.test.c, update parameter(s) 'b' in the clinic input of" \
- " 'test_deprecate_positional_pos1_len1' to be keyword-only."
- #elif PY_VERSION_HEX >= 0x030e00A0
- # ifdef _MSC_VER
- # pragma message ( \
- "In clinic.test.c, update parameter(s) 'b' in the clinic input of" \
- " 'test_deprecate_positional_pos1_len1' to be keyword-only.")
- # else
- # warning \
- "In clinic.test.c, update parameter(s) 'b' in the clinic input of" \
- " 'test_deprecate_positional_pos1_len1' to be keyword-only."
- # endif
- #endif
- if (nargs == 2) {
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "Passing 2 positional arguments to "
- "test_deprecate_positional_pos1_len1() is deprecated. Parameter "
- "'b' will become a keyword-only parameter in Python 3.14.", 1))
- {
- goto exit;
- }
- }
- args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf);
- if (!args) {
- goto exit;
- }
- a = args[0];
- b = args[1];
- return_value = test_deprecate_positional_pos1_len1_impl(module, a, b);
-
-exit:
- return return_value;
-}
-
-static PyObject *
-test_deprecate_positional_pos1_len1_impl(PyObject *module, PyObject *a,
- PyObject *b)
-/*[clinic end generated code: output=994bd57c1c634709 input=1702bbab1e9b3b99]*/
-
-
-/*[clinic input]
-test_deprecate_positional_pos1_len2_with_kwd
- a: object
- * [from 3.14]
- b: object
- c: object
- *
- d: object
-[clinic start generated code]*/
-
-PyDoc_STRVAR(test_deprecate_positional_pos1_len2_with_kwd__doc__,
-"test_deprecate_positional_pos1_len2_with_kwd($module, /, a, b, c, *, d)\n"
-"--\n"
-"\n"
-"Note: Passing more than 1 positional argument to\n"
-"test_deprecate_positional_pos1_len2_with_kwd() is deprecated.\n"
-"Parameters \'b\' and \'c\' will become keyword-only parameters in Python\n"
-"3.14.\n"
-"");
-
-#define TEST_DEPRECATE_POSITIONAL_POS1_LEN2_WITH_KWD_METHODDEF \
- {"test_deprecate_positional_pos1_len2_with_kwd", _PyCFunction_CAST(test_deprecate_positional_pos1_len2_with_kwd), METH_FASTCALL|METH_KEYWORDS, test_deprecate_positional_pos1_len2_with_kwd__doc__},
-
-static PyObject *
-test_deprecate_positional_pos1_len2_with_kwd_impl(PyObject *module,
- PyObject *a, PyObject *b,
- PyObject *c, PyObject *d);
-
-static PyObject *
-test_deprecate_positional_pos1_len2_with_kwd(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 4
- 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(a), &_Py_ID(b), &_Py_ID(c), &_Py_ID(d), },
- };
- #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", "d", NULL};
- static _PyArg_Parser _parser = {
- .keywords = _keywords,
- .fname = "test_deprecate_positional_pos1_len2_with_kwd",
- .kwtuple = KWTUPLE,
- };
- #undef KWTUPLE
- PyObject *argsbuf[4];
- PyObject *a;
- PyObject *b;
- PyObject *c;
- PyObject *d;
-
- // Emit compiler warnings when we get to Python 3.14.
- #if PY_VERSION_HEX >= 0x030e00C0
- # error \
- "In clinic.test.c, update parameter(s) 'b' and 'c' in the clinic " \
- "input of 'test_deprecate_positional_pos1_len2_with_kwd' to be " \
- "keyword-only."
- #elif PY_VERSION_HEX >= 0x030e00A0
- # ifdef _MSC_VER
- # pragma message ( \
- "In clinic.test.c, update parameter(s) 'b' and 'c' in the clinic " \
- "input of 'test_deprecate_positional_pos1_len2_with_kwd' to be " \
- "keyword-only.")
- # else
- # warning \
- "In clinic.test.c, update parameter(s) 'b' and 'c' in the clinic " \
- "input of 'test_deprecate_positional_pos1_len2_with_kwd' to be " \
- "keyword-only."
- # endif
- #endif
- if (nargs > 1 && nargs <= 3) {
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "Passing more than 1 positional argument to "
- "test_deprecate_positional_pos1_len2_with_kwd() is deprecated. "
- "Parameters 'b' and 'c' will become keyword-only parameters in "
- "Python 3.14.", 1))
- {
- goto exit;
- }
- }
- args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 3, 1, argsbuf);
- if (!args) {
- goto exit;
- }
- a = args[0];
- b = args[1];
- c = args[2];
- d = args[3];
- return_value = test_deprecate_positional_pos1_len2_with_kwd_impl(module, a, b, c, d);
-
-exit:
- return return_value;
-}
-
-static PyObject *
-test_deprecate_positional_pos1_len2_with_kwd_impl(PyObject *module,
- PyObject *a, PyObject *b,
- PyObject *c, PyObject *d)
-/*[clinic end generated code: output=146c60ecbcdbf4b8 input=28cdb885f6c34eab]*/
-
-
-/*[clinic input]
-test_deprecate_positional_pos0_len1
- * [from 3.14]
- a: object
-[clinic start generated code]*/
-
-PyDoc_STRVAR(test_deprecate_positional_pos0_len1__doc__,
-"test_deprecate_positional_pos0_len1($module, /, a)\n"
-"--\n"
-"\n"
-"Note: Passing positional arguments to\n"
-"test_deprecate_positional_pos0_len1() is deprecated. Parameter \'a\'\n"
-"will become a keyword-only parameter in Python 3.14.\n"
-"");
-
-#define TEST_DEPRECATE_POSITIONAL_POS0_LEN1_METHODDEF \
- {"test_deprecate_positional_pos0_len1", _PyCFunction_CAST(test_deprecate_positional_pos0_len1), METH_FASTCALL|METH_KEYWORDS, test_deprecate_positional_pos0_len1__doc__},
-
-static PyObject *
-test_deprecate_positional_pos0_len1_impl(PyObject *module, PyObject *a);
-
-static PyObject *
-test_deprecate_positional_pos0_len1(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(a), },
- };
- #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", NULL};
- static _PyArg_Parser _parser = {
- .keywords = _keywords,
- .fname = "test_deprecate_positional_pos0_len1",
- .kwtuple = KWTUPLE,
- };
- #undef KWTUPLE
- PyObject *argsbuf[1];
- PyObject *a;
-
- // Emit compiler warnings when we get to Python 3.14.
- #if PY_VERSION_HEX >= 0x030e00C0
- # error \
- "In clinic.test.c, update parameter(s) 'a' in the clinic input of" \
- " 'test_deprecate_positional_pos0_len1' to be keyword-only."
- #elif PY_VERSION_HEX >= 0x030e00A0
- # ifdef _MSC_VER
- # pragma message ( \
- "In clinic.test.c, update parameter(s) 'a' in the clinic input of" \
- " 'test_deprecate_positional_pos0_len1' to be keyword-only.")
- # else
- # warning \
- "In clinic.test.c, update parameter(s) 'a' in the clinic input of" \
- " 'test_deprecate_positional_pos0_len1' to be keyword-only."
- # endif
- #endif
- if (nargs == 1) {
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "Passing positional arguments to "
- "test_deprecate_positional_pos0_len1() is deprecated. Parameter "
- "'a' will become a keyword-only parameter in Python 3.14.", 1))
- {
- goto exit;
- }
- }
- args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf);
- if (!args) {
- goto exit;
- }
- a = args[0];
- return_value = test_deprecate_positional_pos0_len1_impl(module, a);
-
-exit:
- return return_value;
-}
-
-static PyObject *
-test_deprecate_positional_pos0_len1_impl(PyObject *module, PyObject *a)
-/*[clinic end generated code: output=dce99971a2494f9f input=678206db25c0652c]*/
-
-
-/*[clinic input]
-test_deprecate_positional_pos0_len2
- * [from 3.14]
- a: object
- b: object
-[clinic start generated code]*/
-
-PyDoc_STRVAR(test_deprecate_positional_pos0_len2__doc__,
-"test_deprecate_positional_pos0_len2($module, /, a, b)\n"
-"--\n"
-"\n"
-"Note: Passing positional arguments to\n"
-"test_deprecate_positional_pos0_len2() is deprecated. Parameters \'a\'\n"
-"and \'b\' will become keyword-only parameters in Python 3.14.\n"
-"");
-
-#define TEST_DEPRECATE_POSITIONAL_POS0_LEN2_METHODDEF \
- {"test_deprecate_positional_pos0_len2", _PyCFunction_CAST(test_deprecate_positional_pos0_len2), METH_FASTCALL|METH_KEYWORDS, test_deprecate_positional_pos0_len2__doc__},
-
-static PyObject *
-test_deprecate_positional_pos0_len2_impl(PyObject *module, PyObject *a,
- PyObject *b);
-
-static PyObject *
-test_deprecate_positional_pos0_len2(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 2
- 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(a), &_Py_ID(b), },
- };
- #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", NULL};
- static _PyArg_Parser _parser = {
- .keywords = _keywords,
- .fname = "test_deprecate_positional_pos0_len2",
- .kwtuple = KWTUPLE,
- };
- #undef KWTUPLE
- PyObject *argsbuf[2];
- PyObject *a;
- PyObject *b;
-
- // Emit compiler warnings when we get to Python 3.14.
- #if PY_VERSION_HEX >= 0x030e00C0
- # error \
- "In clinic.test.c, update parameter(s) 'a' and 'b' in the clinic " \
- "input of 'test_deprecate_positional_pos0_len2' to be " \
- "keyword-only."
- #elif PY_VERSION_HEX >= 0x030e00A0
- # ifdef _MSC_VER
- # pragma message ( \
- "In clinic.test.c, update parameter(s) 'a' and 'b' in the clinic " \
- "input of 'test_deprecate_positional_pos0_len2' to be " \
- "keyword-only.")
- # else
- # warning \
- "In clinic.test.c, update parameter(s) 'a' and 'b' in the clinic " \
- "input of 'test_deprecate_positional_pos0_len2' to be " \
- "keyword-only."
- # endif
- #endif
- if (nargs > 0 && nargs <= 2) {
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "Passing positional arguments to "
- "test_deprecate_positional_pos0_len2() is deprecated. Parameters "
- "'a' and 'b' will become keyword-only parameters in Python 3.14.", 1))
- {
- goto exit;
- }
- }
- args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf);
- if (!args) {
- goto exit;
- }
- a = args[0];
- b = args[1];
- return_value = test_deprecate_positional_pos0_len2_impl(module, a, b);
-
-exit:
- return return_value;
-}
-
-static PyObject *
-test_deprecate_positional_pos0_len2_impl(PyObject *module, PyObject *a,
- PyObject *b)
-/*[clinic end generated code: output=06999692e0c8dac4 input=fae0d0b1d480c939]*/
-
-
-/*[clinic input]
-test_deprecate_positional_pos0_len3_with_kwdonly
- * [from 3.14]
- a: object
- b: object
- c: object
- *
- e: object
-[clinic start generated code]*/
-
-PyDoc_STRVAR(test_deprecate_positional_pos0_len3_with_kwdonly__doc__,
-"test_deprecate_positional_pos0_len3_with_kwdonly($module, /, a, b, c,\n"
-" *, e)\n"
-"--\n"
-"\n"
-"Note: Passing positional arguments to\n"
-"test_deprecate_positional_pos0_len3_with_kwdonly() is deprecated.\n"
-"Parameters \'a\', \'b\' and \'c\' will become keyword-only parameters in\n"
-"Python 3.14.\n"
-"");
-
-#define TEST_DEPRECATE_POSITIONAL_POS0_LEN3_WITH_KWDONLY_METHODDEF \
- {"test_deprecate_positional_pos0_len3_with_kwdonly", _PyCFunction_CAST(test_deprecate_positional_pos0_len3_with_kwdonly), METH_FASTCALL|METH_KEYWORDS, test_deprecate_positional_pos0_len3_with_kwdonly__doc__},
-
-static PyObject *
-test_deprecate_positional_pos0_len3_with_kwdonly_impl(PyObject *module,
- PyObject *a,
- PyObject *b,
- PyObject *c,
- PyObject *e);
-
-static PyObject *
-test_deprecate_positional_pos0_len3_with_kwdonly(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 4
- 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(a), &_Py_ID(b), &_Py_ID(c), &_Py_ID(e), },
- };
- #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", "e", NULL};
- static _PyArg_Parser _parser = {
- .keywords = _keywords,
- .fname = "test_deprecate_positional_pos0_len3_with_kwdonly",
- .kwtuple = KWTUPLE,
- };
- #undef KWTUPLE
- PyObject *argsbuf[4];
- PyObject *a;
- PyObject *b;
- PyObject *c;
- PyObject *e;
-
- // Emit compiler warnings when we get to Python 3.14.
- #if PY_VERSION_HEX >= 0x030e00C0
- # error \
- "In clinic.test.c, update parameter(s) 'a', 'b' and 'c' in the " \
- "clinic input of " \
- "'test_deprecate_positional_pos0_len3_with_kwdonly' to be " \
- "keyword-only."
- #elif PY_VERSION_HEX >= 0x030e00A0
- # ifdef _MSC_VER
- # pragma message ( \
- "In clinic.test.c, update parameter(s) 'a', 'b' and 'c' in the " \
- "clinic input of " \
- "'test_deprecate_positional_pos0_len3_with_kwdonly' to be " \
- "keyword-only.")
- # else
- # warning \
- "In clinic.test.c, update parameter(s) 'a', 'b' and 'c' in the " \
- "clinic input of " \
- "'test_deprecate_positional_pos0_len3_with_kwdonly' to be " \
- "keyword-only."
- # endif
- #endif
- if (nargs > 0 && nargs <= 3) {
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "Passing positional arguments to "
- "test_deprecate_positional_pos0_len3_with_kwdonly() is "
- "deprecated. Parameters 'a', 'b' and 'c' will become keyword-only"
- " parameters in Python 3.14.", 1))
- {
- goto exit;
- }
- }
- args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 3, 1, argsbuf);
- if (!args) {
- goto exit;
- }
- a = args[0];
- b = args[1];
- c = args[2];
- e = args[3];
- return_value = test_deprecate_positional_pos0_len3_with_kwdonly_impl(module, a, b, c, e);
-
-exit:
- return return_value;
-}
-
-static PyObject *
-test_deprecate_positional_pos0_len3_with_kwdonly_impl(PyObject *module,
- PyObject *a,
- PyObject *b,
- PyObject *c,
- PyObject *e)
-/*[clinic end generated code: output=a553e33101dc42b2 input=1b0121770c0c52e0]*/
-
-
-/*[clinic input]
-test_deprecate_positional_pos2_len1
- a: object
- b: object
- * [from 3.14]
- c: object
-[clinic start generated code]*/
-
-PyDoc_STRVAR(test_deprecate_positional_pos2_len1__doc__,
-"test_deprecate_positional_pos2_len1($module, /, a, b, c)\n"
-"--\n"
-"\n"
-"Note: Passing 3 positional arguments to\n"
-"test_deprecate_positional_pos2_len1() is deprecated. Parameter \'c\'\n"
-"will become a keyword-only parameter in Python 3.14.\n"
-"");
-
-#define TEST_DEPRECATE_POSITIONAL_POS2_LEN1_METHODDEF \
- {"test_deprecate_positional_pos2_len1", _PyCFunction_CAST(test_deprecate_positional_pos2_len1), METH_FASTCALL|METH_KEYWORDS, test_deprecate_positional_pos2_len1__doc__},
-
-static PyObject *
-test_deprecate_positional_pos2_len1_impl(PyObject *module, PyObject *a,
- PyObject *b, PyObject *c);
-
-static PyObject *
-test_deprecate_positional_pos2_len1(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_ID(a), &_Py_ID(b), &_Py_ID(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 = "test_deprecate_positional_pos2_len1",
- .kwtuple = KWTUPLE,
- };
- #undef KWTUPLE
- PyObject *argsbuf[3];
- PyObject *a;
- PyObject *b;
- PyObject *c;
-
- // Emit compiler warnings when we get to Python 3.14.
- #if PY_VERSION_HEX >= 0x030e00C0
- # error \
- "In clinic.test.c, update parameter(s) 'c' in the clinic input of" \
- " 'test_deprecate_positional_pos2_len1' to be keyword-only."
- #elif PY_VERSION_HEX >= 0x030e00A0
- # ifdef _MSC_VER
- # pragma message ( \
- "In clinic.test.c, update parameter(s) 'c' in the clinic input of" \
- " 'test_deprecate_positional_pos2_len1' to be keyword-only.")
- # else
- # warning \
- "In clinic.test.c, update parameter(s) 'c' in the clinic input of" \
- " 'test_deprecate_positional_pos2_len1' to be keyword-only."
- # endif
- #endif
- if (nargs == 3) {
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "Passing 3 positional arguments to "
- "test_deprecate_positional_pos2_len1() is deprecated. Parameter "
- "'c' will become a keyword-only parameter in Python 3.14.", 1))
- {
- goto exit;
- }
- }
- args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 3, 0, argsbuf);
- if (!args) {
- goto exit;
- }
- a = args[0];
- b = args[1];
- c = args[2];
- return_value = test_deprecate_positional_pos2_len1_impl(module, a, b, c);
-
-exit:
- return return_value;
-}
-
-static PyObject *
-test_deprecate_positional_pos2_len1_impl(PyObject *module, PyObject *a,
- PyObject *b, PyObject *c)
-/*[clinic end generated code: output=f96454a4970b443c input=e1d129689e69ec7c]*/
-
-
-/*[clinic input]
-test_deprecate_positional_pos2_len2
- a: object
- b: object
- * [from 3.14]
- c: object
- d: object
-[clinic start generated code]*/
-
-PyDoc_STRVAR(test_deprecate_positional_pos2_len2__doc__,
-"test_deprecate_positional_pos2_len2($module, /, a, b, c, d)\n"
-"--\n"
-"\n"
-"Note: Passing more than 2 positional arguments to\n"
-"test_deprecate_positional_pos2_len2() is deprecated. Parameters \'c\'\n"
-"and \'d\' will become keyword-only parameters in Python 3.14.\n"
-"");
-
-#define TEST_DEPRECATE_POSITIONAL_POS2_LEN2_METHODDEF \
- {"test_deprecate_positional_pos2_len2", _PyCFunction_CAST(test_deprecate_positional_pos2_len2), METH_FASTCALL|METH_KEYWORDS, test_deprecate_positional_pos2_len2__doc__},
-
-static PyObject *
-test_deprecate_positional_pos2_len2_impl(PyObject *module, PyObject *a,
- PyObject *b, PyObject *c,
- PyObject *d);
-
-static PyObject *
-test_deprecate_positional_pos2_len2(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 4
- 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(a), &_Py_ID(b), &_Py_ID(c), &_Py_ID(d), },
- };
- #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", "d", NULL};
- static _PyArg_Parser _parser = {
- .keywords = _keywords,
- .fname = "test_deprecate_positional_pos2_len2",
- .kwtuple = KWTUPLE,
- };
- #undef KWTUPLE
- PyObject *argsbuf[4];
- PyObject *a;
- PyObject *b;
- PyObject *c;
- PyObject *d;
-
- // Emit compiler warnings when we get to Python 3.14.
- #if PY_VERSION_HEX >= 0x030e00C0
- # error \
- "In clinic.test.c, update parameter(s) 'c' and 'd' in the clinic " \
- "input of 'test_deprecate_positional_pos2_len2' to be " \
- "keyword-only."
- #elif PY_VERSION_HEX >= 0x030e00A0
- # ifdef _MSC_VER
- # pragma message ( \
- "In clinic.test.c, update parameter(s) 'c' and 'd' in the clinic " \
- "input of 'test_deprecate_positional_pos2_len2' to be " \
- "keyword-only.")
- # else
- # warning \
- "In clinic.test.c, update parameter(s) 'c' and 'd' in the clinic " \
- "input of 'test_deprecate_positional_pos2_len2' to be " \
- "keyword-only."
- # endif
- #endif
- if (nargs > 2 && nargs <= 4) {
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "Passing more than 2 positional arguments to "
- "test_deprecate_positional_pos2_len2() is deprecated. Parameters "
- "'c' and 'd' will become keyword-only parameters in Python 3.14.", 1))
- {
- goto exit;
- }
- }
- args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 4, 4, 0, argsbuf);
- if (!args) {
- goto exit;
- }
- a = args[0];
- b = args[1];
- c = args[2];
- d = args[3];
- return_value = test_deprecate_positional_pos2_len2_impl(module, a, b, c, d);
-
-exit:
- return return_value;
-}
-
-static PyObject *
-test_deprecate_positional_pos2_len2_impl(PyObject *module, PyObject *a,
- PyObject *b, PyObject *c,
- PyObject *d)
-/*[clinic end generated code: output=5e648e887da0a804 input=0d53533463a12792]*/
-
-
-/*[clinic input]
-test_deprecate_positional_pos2_len3_with_kwdonly
- a: object
- b: object
- * [from 3.14]
- c: object
- d: object
- *
- e: object
-[clinic start generated code]*/
-
-PyDoc_STRVAR(test_deprecate_positional_pos2_len3_with_kwdonly__doc__,
-"test_deprecate_positional_pos2_len3_with_kwdonly($module, /, a, b, c,\n"
-" d, *, e)\n"
-"--\n"
-"\n"
-"Note: Passing more than 2 positional arguments to\n"
-"test_deprecate_positional_pos2_len3_with_kwdonly() is deprecated.\n"
-"Parameters \'c\' and \'d\' will become keyword-only parameters in Python\n"
-"3.14.\n"
-"");
-
-#define TEST_DEPRECATE_POSITIONAL_POS2_LEN3_WITH_KWDONLY_METHODDEF \
- {"test_deprecate_positional_pos2_len3_with_kwdonly", _PyCFunction_CAST(test_deprecate_positional_pos2_len3_with_kwdonly), METH_FASTCALL|METH_KEYWORDS, test_deprecate_positional_pos2_len3_with_kwdonly__doc__},
-
-static PyObject *
-test_deprecate_positional_pos2_len3_with_kwdonly_impl(PyObject *module,
- PyObject *a,
- PyObject *b,
- PyObject *c,
- PyObject *d,
- PyObject *e);
-
-static PyObject *
-test_deprecate_positional_pos2_len3_with_kwdonly(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 5
- 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(a), &_Py_ID(b), &_Py_ID(c), &_Py_ID(d), &_Py_ID(e), },
- };
- #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", "d", "e", NULL};
- static _PyArg_Parser _parser = {
- .keywords = _keywords,
- .fname = "test_deprecate_positional_pos2_len3_with_kwdonly",
- .kwtuple = KWTUPLE,
- };
- #undef KWTUPLE
- PyObject *argsbuf[5];
- PyObject *a;
- PyObject *b;
- PyObject *c;
- PyObject *d;
- PyObject *e;
-
- // Emit compiler warnings when we get to Python 3.14.
- #if PY_VERSION_HEX >= 0x030e00C0
- # error \
- "In clinic.test.c, update parameter(s) 'c' and 'd' in the clinic " \
- "input of 'test_deprecate_positional_pos2_len3_with_kwdonly' to " \
- "be keyword-only."
- #elif PY_VERSION_HEX >= 0x030e00A0
- # ifdef _MSC_VER
- # pragma message ( \
- "In clinic.test.c, update parameter(s) 'c' and 'd' in the clinic " \
- "input of 'test_deprecate_positional_pos2_len3_with_kwdonly' to " \
- "be keyword-only.")
- # else
- # warning \
- "In clinic.test.c, update parameter(s) 'c' and 'd' in the clinic " \
- "input of 'test_deprecate_positional_pos2_len3_with_kwdonly' to " \
- "be keyword-only."
- # endif
- #endif
- if (nargs > 2 && nargs <= 4) {
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "Passing more than 2 positional arguments to "
- "test_deprecate_positional_pos2_len3_with_kwdonly() is "
- "deprecated. Parameters 'c' and 'd' will become keyword-only "
- "parameters in Python 3.14.", 1))
- {
- goto exit;
- }
- }
- args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 4, 4, 1, argsbuf);
- if (!args) {
- goto exit;
- }
- a = args[0];
- b = args[1];
- c = args[2];
- d = args[3];
- e = args[4];
- return_value = test_deprecate_positional_pos2_len3_with_kwdonly_impl(module, a, b, c, d, e);
-
-exit:
- return return_value;
-}
-
-static PyObject *
-test_deprecate_positional_pos2_len3_with_kwdonly_impl(PyObject *module,
- PyObject *a,
- PyObject *b,
- PyObject *c,
- PyObject *d,
- PyObject *e)
-/*[clinic end generated code: output=383d56b03f7c2dcb input=154fd450448d8935]*/
diff --git a/Lib/test/test_audit.py b/Lib/test/test_audit.py
index 0b69864751d83d..b12ffa5d872e83 100644
--- a/Lib/test/test_audit.py
+++ b/Lib/test/test_audit.py
@@ -257,5 +257,18 @@ def test_not_in_gc(self):
self.fail(stderr)
+ def test_sys_monitoring_register_callback(self):
+ returncode, events, stderr = self.run_python("test_sys_monitoring_register_callback")
+ if returncode:
+ self.fail(stderr)
+
+ if support.verbose:
+ print(*events, sep='\n')
+ actual = [(ev[0], ev[2]) for ev in events]
+ expected = [("sys.monitoring.register_callback", "(None,)")]
+
+ self.assertEqual(actual, expected)
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py
index 001d37de8e0eb3..3dfbfdc26e7416 100644
--- a/Lib/test/test_capi/test_misc.py
+++ b/Lib/test/test_capi/test_misc.py
@@ -611,7 +611,7 @@ class Base(metaclass=metaclass):
# Class creation from C
with warnings_helper.check_warnings(
- ('.*custom tp_new.*in Python 3.14.*', DeprecationWarning),
+ ('.* _testcapi.Subclass .* custom tp_new.*in Python 3.14.*', DeprecationWarning),
):
sub = _testcapi.make_type_with_base(Base)
self.assertTrue(issubclass(sub, Base))
@@ -2618,6 +2618,23 @@ def testfunc(it):
with self.assertRaises(StopIteration):
next(it)
+ def test_call_py_exact_args(self):
+ def testfunc(n):
+ def dummy(x):
+ return x+1
+ for i in range(n):
+ dummy(i)
+
+ opt = _testinternalcapi.get_uop_optimizer()
+ with temporary_optimizer(opt):
+ testfunc(10)
+
+ ex = get_first_executor(testfunc)
+ self.assertIsNotNone(ex)
+ uops = {opname for opname, _, _ in ex}
+ self.assertIn("_PUSH_FRAME", uops)
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_capi/test_watchers.py b/Lib/test/test_capi/test_watchers.py
index 93f6ef752d0663..6b8855ec219d27 100644
--- a/Lib/test/test_capi/test_watchers.py
+++ b/Lib/test/test_capi/test_watchers.py
@@ -294,6 +294,18 @@ class C2: pass
C2.hmm = "baz"
self.assert_events([C1, [C2]])
+ def test_all_watchers(self):
+ class C: pass
+ with ExitStack() as stack:
+ last_wid = -1
+ # don't make assumptions about how many watchers are already
+ # registered, just go until we reach the max ID
+ while last_wid < self.TYPE_MAX_WATCHERS - 1:
+ last_wid = stack.enter_context(self.watcher())
+ self.watch(last_wid, C)
+ C.foo = "bar"
+ self.assert_events([C])
+
def test_watch_non_type(self):
with self.watcher() as wid:
with self.assertRaisesRegex(ValueError, r"Cannot watch non-type"):
@@ -339,12 +351,10 @@ def test_clear_unassigned_watcher_id(self):
self.clear_watcher(1)
def test_no_more_ids_available(self):
- contexts = [self.watcher() for i in range(self.TYPE_MAX_WATCHERS)]
- with ExitStack() as stack:
- for ctx in contexts:
- stack.enter_context(ctx)
- with self.assertRaisesRegex(RuntimeError, r"no more type watcher IDs"):
- self.add_watcher()
+ with self.assertRaisesRegex(RuntimeError, r"no more type watcher IDs"):
+ with ExitStack() as stack:
+ for _ in range(self.TYPE_MAX_WATCHERS + 1):
+ stack.enter_context(self.watcher())
class TestCodeObjectWatchers(unittest.TestCase):
diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py
index 026cd18d646ad7..38eabd2f7f21dc 100644
--- a/Lib/test/test_clinic.py
+++ b/Lib/test/test_clinic.py
@@ -2,6 +2,7 @@
# Copyright 2012-2013 by Larry Hastings.
# Licensed to the PSF under a contributor agreement.
+from functools import partial
from test import support, test_tools
from test.support import os_helper
from test.support.os_helper import TESTFN, unlink
@@ -27,7 +28,8 @@ def _make_clinic(*, filename='clinic_tests'):
return c
-def _expect_failure(tc, parser, code, errmsg, *, filename=None, lineno=None):
+def _expect_failure(tc, parser, code, errmsg, *, filename=None, lineno=None,
+ strip=True):
"""Helper for the parser tests.
tc: unittest.TestCase; passed self in the wrapper
@@ -37,7 +39,9 @@ def _expect_failure(tc, parser, code, errmsg, *, filename=None, lineno=None):
filename: str, optional filename
lineno: int, optional line number
"""
- code = dedent(code).strip()
+ code = dedent(code)
+ if strip:
+ code = code.strip()
errmsg = re.escape(errmsg)
with tc.assertRaisesRegex(clinic.ClinicError, errmsg) as cm:
parser(code)
@@ -608,6 +612,79 @@ def test_directive_output_invalid_command(self):
"""
self.expect_failure(block, err, lineno=2)
+ def test_validate_cloned_init(self):
+ block = """
+ /*[clinic input]
+ class C "void *" ""
+ C.meth
+ a: int
+ [clinic start generated code]*/
+ /*[clinic input]
+ @classmethod
+ C.__init__ = C.meth
+ [clinic start generated code]*/
+ """
+ err = "'__init__' must be a normal method, not a class or static method"
+ self.expect_failure(block, err, lineno=8)
+
+ def test_validate_cloned_new(self):
+ block = """
+ /*[clinic input]
+ class C "void *" ""
+ C.meth
+ a: int
+ [clinic start generated code]*/
+ /*[clinic input]
+ C.__new__ = C.meth
+ [clinic start generated code]*/
+ """
+ err = "'__new__' must be a class method"
+ self.expect_failure(block, err, lineno=7)
+
+ def test_no_c_basename_cloned(self):
+ block = """
+ /*[clinic input]
+ foo2
+ [clinic start generated code]*/
+ /*[clinic input]
+ foo as = foo2
+ [clinic start generated code]*/
+ """
+ err = "No C basename provided after 'as' keyword"
+ self.expect_failure(block, err, lineno=5)
+
+ def test_cloned_with_custom_c_basename(self):
+ raw = dedent("""
+ /*[clinic input]
+ # Make sure we don't create spurious clinic/ directories.
+ output everything suppress
+ foo2
+ [clinic start generated code]*/
+
+ /*[clinic input]
+ foo as foo1 = foo2
+ [clinic start generated code]*/
+ """)
+ self.clinic.parse(raw)
+ funcs = self.clinic.functions
+ self.assertEqual(len(funcs), 2)
+ self.assertEqual(funcs[1].name, "foo")
+ self.assertEqual(funcs[1].c_basename, "foo1")
+
+ def test_cloned_with_illegal_c_basename(self):
+ block = """
+ /*[clinic input]
+ class C "void *" ""
+ foo1
+ [clinic start generated code]*/
+
+ /*[clinic input]
+ foo2 as .illegal. = foo1
+ [clinic start generated code]*/
+ """
+ err = "Illegal C basename: '.illegal.'"
+ self.expect_failure(block, err, lineno=7)
+
class ParseFileUnitTest(TestCase):
def expect_parsing_failure(
@@ -827,14 +904,15 @@ def parse_function(self, text, signatures_in_block=2, function_index=1):
assert isinstance(s[function_index], clinic.Function)
return s[function_index]
- def expect_failure(self, block, err, *, filename=None, lineno=None):
+ def expect_failure(self, block, err, *,
+ filename=None, lineno=None, strip=True):
return _expect_failure(self, self.parse_function, block, err,
- filename=filename, lineno=lineno)
+ filename=filename, lineno=lineno, strip=strip)
def checkDocstring(self, fn, expected):
self.assertTrue(hasattr(fn, "docstring"))
- self.assertEqual(fn.docstring.strip(),
- dedent(expected).strip())
+ self.assertEqual(dedent(expected).strip(),
+ fn.docstring.strip())
def test_trivial(self):
parser = DSLParser(_make_clinic())
@@ -997,8 +1075,12 @@ def test_function_docstring(self):
path: str
Path to be examined
+ Ensure that multiple lines are indented correctly.
Perform a stat system call on the given path.
+
+ Ensure that multiple lines are indented correctly.
+ Ensure that multiple lines are indented correctly.
""")
self.checkDocstring(function, """
stat($module, /, path)
@@ -1008,6 +1090,10 @@ def test_function_docstring(self):
path
Path to be examined
+ Ensure that multiple lines are indented correctly.
+
+ Ensure that multiple lines are indented correctly.
+ Ensure that multiple lines are indented correctly.
""")
def test_docstring_trailing_whitespace(self):
@@ -1438,6 +1524,27 @@ def test_disallowed_grouping__no_matching_bracket(self):
err = "Function 'empty_group' has a ']' without a matching '['"
self.expect_failure(block, err)
+ def test_disallowed_grouping__must_be_position_only(self):
+ dataset = ("""
+ with_kwds
+ [
+ *
+ a: object
+ ]
+ """, """
+ with_kwds
+ [
+ a: object
+ ]
+ """)
+ err = (
+ "You cannot use optional groups ('[' and ']') unless all "
+ "parameters are positional-only ('/')"
+ )
+ for block in dataset:
+ with self.subTest(block=block):
+ self.expect_failure(block, err)
+
def test_no_parameters(self):
function = self.parse_function("""
module foo
@@ -1482,6 +1589,11 @@ def test_illegal_c_basename(self):
err = "Illegal C basename: '935'"
self.expect_failure(block, err)
+ def test_no_c_basename(self):
+ block = "foo as "
+ err = "No C basename provided after 'as' keyword"
+ self.expect_failure(block, err, strip=False)
+
def test_single_star(self):
block = """
module foo
@@ -1504,6 +1616,60 @@ def test_parameters_required_after_star(self):
with self.subTest(block=block):
self.expect_failure(block, err)
+ def test_fulldisplayname_class(self):
+ dataset = (
+ ("T", """
+ class T "void *" ""
+ T.__init__
+ """),
+ ("m.T", """
+ module m
+ class m.T "void *" ""
+ @classmethod
+ m.T.__new__
+ """),
+ ("m.T.C", """
+ module m
+ class m.T "void *" ""
+ class m.T.C "void *" ""
+ m.T.C.__init__
+ """),
+ )
+ for name, code in dataset:
+ with self.subTest(name=name, code=code):
+ block = self.parse(code)
+ func = block.signatures[-1]
+ self.assertEqual(func.fulldisplayname, name)
+
+ def test_fulldisplayname_meth(self):
+ dataset = (
+ ("func", "func"),
+ ("m.func", """
+ module m
+ m.func
+ """),
+ ("T.meth", """
+ class T "void *" ""
+ T.meth
+ """),
+ ("m.T.meth", """
+ module m
+ class m.T "void *" ""
+ m.T.meth
+ """),
+ ("m.T.C.meth", """
+ module m
+ class m.T "void *" ""
+ class m.T.C "void *" ""
+ m.T.C.meth
+ """),
+ )
+ for name, code in dataset:
+ with self.subTest(name=name, code=code):
+ block = self.parse(code)
+ func = block.signatures[-1]
+ self.assertEqual(func.fulldisplayname, name)
+
def test_depr_star_invalid_format_1(self):
block = """
module foo
@@ -1855,7 +2021,7 @@ class Foo "" ""
self.parse_function(block)
def test_new_must_be_a_class_method(self):
- err = "__new__ must be a class method!"
+ err = "'__new__' must be a class method!"
block = """
module foo
class Foo "" ""
@@ -1864,7 +2030,7 @@ class Foo "" ""
self.expect_failure(block, err, lineno=2)
def test_init_must_be_a_normal_method(self):
- err = "__init__ must be a normal method, not a class or static method!"
+ err = "'__init__' must be a normal method, not a class or static method!"
block = """
module foo
class Foo "" ""
@@ -1967,7 +2133,7 @@ def test_illegal_c_identifier(self):
self.expect_failure(block, err, lineno=2)
def test_cannot_convert_special_method(self):
- err = "__len__ is a special method and cannot be converted"
+ err = "'__len__' is a special method and cannot be converted"
block = """
class T "" ""
T.__len__
@@ -2423,6 +2589,19 @@ class ClinicFunctionalTest(unittest.TestCase):
locals().update((name, getattr(ac_tester, name))
for name in dir(ac_tester) if name.startswith('test_'))
+ def check_depr_star(self, pnames, fn, *args, **kwds):
+ regex = (
+ fr"Passing( more than)?( [0-9]+)? positional argument(s)? to "
+ fr"{fn.__name__}\(\) is deprecated. Parameter(s)? {pnames} will "
+ fr"become( a)? keyword-only parameter(s)? in Python 3\.14"
+ )
+ with self.assertWarnsRegex(DeprecationWarning, regex) as cm:
+ # Record the line number, so we're sure we've got the correct stack
+ # level on the deprecation warning.
+ _, lineno = fn(*args, **kwds), sys._getframe().f_lineno
+ self.assertEqual(cm.filename, __file__)
+ self.assertEqual(cm.lineno, lineno)
+
def test_objects_converter(self):
with self.assertRaises(TypeError):
ac_tester.objects_converter()
@@ -2887,6 +3066,117 @@ def test_cloned_func_with_converter_exception_message(self):
func = getattr(ac_tester, name)
self.assertEqual(func(), name)
+ def test_depr_star_new(self):
+ regex = re.escape(
+ "Passing positional arguments to _testclinic.DeprStarNew() is "
+ "deprecated. Parameter 'a' will become a keyword-only parameter "
+ "in Python 3.14."
+ )
+ with self.assertWarnsRegex(DeprecationWarning, regex) as cm:
+ ac_tester.DeprStarNew(None)
+ self.assertEqual(cm.filename, __file__)
+
+ def test_depr_star_new_cloned(self):
+ regex = re.escape(
+ "Passing positional arguments to _testclinic.DeprStarNew.cloned() "
+ "is deprecated. Parameter 'a' will become a keyword-only parameter "
+ "in Python 3.14."
+ )
+ obj = ac_tester.DeprStarNew(a=None)
+ with self.assertWarnsRegex(DeprecationWarning, regex) as cm:
+ obj.cloned(None)
+ self.assertEqual(cm.filename, __file__)
+
+ def test_depr_star_init(self):
+ regex = re.escape(
+ "Passing positional arguments to _testclinic.DeprStarInit() is "
+ "deprecated. Parameter 'a' will become a keyword-only parameter "
+ "in Python 3.14."
+ )
+ with self.assertWarnsRegex(DeprecationWarning, regex) as cm:
+ ac_tester.DeprStarInit(None)
+ self.assertEqual(cm.filename, __file__)
+
+ def test_depr_star_init_cloned(self):
+ regex = re.escape(
+ "Passing positional arguments to _testclinic.DeprStarInit.cloned() "
+ "is deprecated. Parameter 'a' will become a keyword-only parameter "
+ "in Python 3.14."
+ )
+ obj = ac_tester.DeprStarInit(a=None)
+ with self.assertWarnsRegex(DeprecationWarning, regex) as cm:
+ obj.cloned(None)
+ self.assertEqual(cm.filename, __file__)
+
+ def test_depr_star_pos0_len1(self):
+ fn = ac_tester.depr_star_pos0_len1
+ fn(a=None)
+ self.check_depr_star("'a'", fn, "a")
+
+ def test_depr_star_pos0_len2(self):
+ fn = ac_tester.depr_star_pos0_len2
+ fn(a=0, b=0)
+ check = partial(self.check_depr_star, "'a' and 'b'", fn)
+ check("a", b=0)
+ check("a", "b")
+
+ def test_depr_star_pos0_len3_with_kwd(self):
+ fn = ac_tester.depr_star_pos0_len3_with_kwd
+ fn(a=0, b=0, c=0, d=0)
+ check = partial(self.check_depr_star, "'a', 'b' and 'c'", fn)
+ check("a", b=0, c=0, d=0)
+ check("a", "b", c=0, d=0)
+ check("a", "b", "c", d=0)
+
+ def test_depr_star_pos1_len1_opt(self):
+ fn = ac_tester.depr_star_pos1_len1_opt
+ fn(a=0, b=0)
+ fn("a", b=0)
+ fn(a=0) # b is optional
+ check = partial(self.check_depr_star, "'b'", fn)
+ check("a", "b")
+
+ def test_depr_star_pos1_len1(self):
+ fn = ac_tester.depr_star_pos1_len1
+ fn(a=0, b=0)
+ fn("a", b=0)
+ check = partial(self.check_depr_star, "'b'", fn)
+ check("a", "b")
+
+ def test_depr_star_pos1_len2_with_kwd(self):
+ fn = ac_tester.depr_star_pos1_len2_with_kwd
+ fn(a=0, b=0, c=0, d=0),
+ fn("a", b=0, c=0, d=0),
+ check = partial(self.check_depr_star, "'b' and 'c'", fn)
+ check("a", "b", c=0, d=0),
+ check("a", "b", "c", d=0),
+
+ def test_depr_star_pos2_len1(self):
+ fn = ac_tester.depr_star_pos2_len1
+ fn(a=0, b=0, c=0)
+ fn("a", b=0, c=0)
+ fn("a", "b", c=0)
+ check = partial(self.check_depr_star, "'c'", fn)
+ check("a", "b", "c")
+
+ def test_depr_star_pos2_len2(self):
+ fn = ac_tester.depr_star_pos2_len2
+ fn(a=0, b=0, c=0, d=0)
+ fn("a", b=0, c=0, d=0)
+ fn("a", "b", c=0, d=0)
+ check = partial(self.check_depr_star, "'c' and 'd'", fn)
+ check("a", "b", "c", d=0)
+ check("a", "b", "c", "d")
+
+ def test_depr_star_pos2_len2_with_kwd(self):
+ fn = ac_tester.depr_star_pos2_len2_with_kwd
+ fn(a=0, b=0, c=0, d=0, e=0)
+ fn("a", b=0, c=0, d=0, e=0)
+ fn("a", "b", c=0, d=0, e=0)
+ check = partial(self.check_depr_star, "'c' and 'd'", fn)
+ check("a", "b", "c", d=0, e=0)
+ check("a", "b", "c", "d", e=0)
+
class PermutationTests(unittest.TestCase):
"""Test permutation support functions."""
diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py
index 770184c5ef9a91..2ed8ae04961376 100644
--- a/Lib/test/test_compile.py
+++ b/Lib/test/test_compile.py
@@ -1315,18 +1315,18 @@ def test_multiline_assert(self):
snippet = textwrap.dedent("""\
assert (a > 0 and
bb > 0 and
- ccc == 4), "error msg"
+ ccc == 1000000), "error msg"
""")
compiled_code, _ = self.check_positions_against_ast(snippet)
self.assertOpcodeSourcePositionIs(compiled_code, 'LOAD_ASSERTION_ERROR',
- line=1, end_line=3, column=0, end_column=30, occurrence=1)
+ line=1, end_line=3, column=0, end_column=36, occurrence=1)
# The "error msg":
self.assertOpcodeSourcePositionIs(compiled_code, 'LOAD_CONST',
- line=3, end_line=3, column=19, end_column=30, occurrence=4)
+ line=3, end_line=3, column=25, end_column=36, occurrence=4)
self.assertOpcodeSourcePositionIs(compiled_code, 'CALL',
- line=1, end_line=3, column=0, end_column=30, occurrence=1)
+ line=1, end_line=3, column=0, end_column=36, occurrence=1)
self.assertOpcodeSourcePositionIs(compiled_code, 'RAISE_VARARGS',
- line=1, end_line=3, column=0, end_column=30, occurrence=1)
+ line=1, end_line=3, column=8, end_column=22, occurrence=1)
def test_multiline_generator_expression(self):
snippet = textwrap.dedent("""\
diff --git a/Lib/test/test_compiler_assemble.py b/Lib/test/test_compiler_assemble.py
index 6df72cbc54666b..5696433e529d0a 100644
--- a/Lib/test/test_compiler_assemble.py
+++ b/Lib/test/test_compiler_assemble.py
@@ -94,12 +94,12 @@ def inner():
instructions = [
('RESUME', 0,),
- ('PUSH_NULL', 0, 1),
('LOAD_CLOSURE', 0, 1),
('BUILD_TUPLE', 1, 1),
('LOAD_CONST', 1, 1),
('MAKE_FUNCTION', 0, 2),
('SET_FUNCTION_ATTRIBUTE', 8, 2),
+ ('PUSH_NULL', 0, 1),
('CALL', 0, 2), # (lambda: x)()
('LOAD_CONST', 2, 2), # 2
('BINARY_OP', 6, 2), # %
diff --git a/Lib/test/test_compiler_codegen.py b/Lib/test/test_compiler_codegen.py
index d99bb8c6cd472d..6d7731ddba02c5 100644
--- a/Lib/test/test_compiler_codegen.py
+++ b/Lib/test/test_compiler_codegen.py
@@ -41,8 +41,8 @@ def test_for_loop(self):
loop_lbl := self.Label(),
('FOR_ITER', exit_lbl := self.Label(), 1),
('STORE_NAME', 1, 1),
- ('PUSH_NULL', None, 2),
('LOAD_NAME', 2, 2),
+ ('PUSH_NULL', None, 2),
('LOAD_NAME', 1, 2),
('CALL', 1, 2),
('POP_TOP', None),
diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py
index 6669f1c57e2e78..bd8d82438414e6 100644
--- a/Lib/test/test_dataclasses.py
+++ b/Lib/test/test_dataclasses.py
@@ -134,7 +134,7 @@ class C:
# Non-defaults following defaults.
with self.assertRaisesRegex(TypeError,
"non-default argument 'y' follows "
- "default argument"):
+ "default argument 'x'"):
@dataclass
class C:
x: int = 0
@@ -143,7 +143,7 @@ class C:
# A derived class adds a non-default field after a default one.
with self.assertRaisesRegex(TypeError,
"non-default argument 'y' follows "
- "default argument"):
+ "default argument 'x'"):
@dataclass
class B:
x: int = 0
@@ -156,7 +156,7 @@ class C(B):
# a field which didn't use to have a default.
with self.assertRaisesRegex(TypeError,
"non-default argument 'y' follows "
- "default argument"):
+ "default argument 'x'"):
@dataclass
class B:
x: int
@@ -4521,7 +4521,7 @@ class A:
# Make sure we still check for non-kwarg non-defaults not following
# defaults.
- err_regex = "non-default argument 'z' follows default argument"
+ err_regex = "non-default argument 'z' follows default argument 'a'"
with self.assertRaisesRegex(TypeError, err_regex):
@dataclass
class A:
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index ad3eefba365856..fc8d0a305d8da0 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -989,8 +989,8 @@ class EditableScrollablePane(ScrollablePane,EditablePane): pass
def test_mro_disagreement(self):
# Testing error messages for MRO disagreement...
- mro_err_msg = """Cannot create a consistent method resolution
-order (MRO) for bases """
+ mro_err_msg = ("Cannot create a consistent method resolution "
+ "order (MRO) for bases ")
def raises(exc, expected, callable, *args):
try:
diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py
index 642b26163ab248..aa967178c1dc39 100644
--- a/Lib/test/test_dis.py
+++ b/Lib/test/test_dis.py
@@ -102,7 +102,7 @@ def _f(a):
dis_f = """\
%3d RESUME 0
-%3d LOAD_GLOBAL 1 (NULL + print)
+%3d LOAD_GLOBAL 1 (print + NULL)
LOAD_FAST 0 (a)
CALL 1
POP_TOP
@@ -131,7 +131,7 @@ def bug708901():
dis_bug708901 = """\
%3d RESUME 0
-%3d LOAD_GLOBAL 1 (NULL + range)
+%3d LOAD_GLOBAL 1 (range + NULL)
LOAD_CONST 1 (1)
%3d LOAD_CONST 2 (10)
@@ -196,11 +196,11 @@ def bug42562():
# Extended arg followed by NOP
code_bug_45757 = bytes([
- 0x90, 0x01, # EXTENDED_ARG 0x01
- 0x09, 0xFF, # NOP 0xFF
- 0x90, 0x01, # EXTENDED_ARG 0x01
- 0x64, 0x29, # LOAD_CONST 0x29
- 0x53, 0x00, # RETURN_VALUE 0x00
+ opcode.opmap['EXTENDED_ARG'], 0x01, # EXTENDED_ARG 0x01
+ opcode.opmap['NOP'], 0xFF, # NOP 0xFF
+ opcode.opmap['EXTENDED_ARG'], 0x01, # EXTENDED_ARG 0x01
+ opcode.opmap['LOAD_CONST'], 0x29, # LOAD_CONST 0x29
+ opcode.opmap['RETURN_VALUE'], 0x00, # RETURN_VALUE 0x00
])
dis_bug_45757 = """\
@@ -236,7 +236,7 @@ def wrap_func_w_kwargs():
dis_kw_names = """\
%3d RESUME 0
-%3d LOAD_GLOBAL 1 (NULL + func_w_kwargs)
+%3d LOAD_GLOBAL 1 (func_w_kwargs + NULL)
LOAD_CONST 1 (1)
LOAD_CONST 2 (2)
LOAD_CONST 3 (5)
@@ -345,8 +345,8 @@ def wrap_func_w_kwargs():
LOAD_CONST 1 ('x')
STORE_SUBSCR
- 3 PUSH_NULL
- LOAD_NAME 3 (fun)
+ 3 LOAD_NAME 3 (fun)
+ PUSH_NULL
LOAD_CONST 0 (1)
CALL 1
LOAD_NAME 2 (__annotations__)
@@ -355,8 +355,8 @@ def wrap_func_w_kwargs():
4 LOAD_CONST 0 (1)
LOAD_NAME 4 (lst)
- PUSH_NULL
LOAD_NAME 3 (fun)
+ PUSH_NULL
LOAD_CONST 3 (0)
CALL 1
STORE_SUBSCR
@@ -615,14 +615,14 @@ def _tryfinallyconst(b):
%3d LOAD_FAST 0 (a)
-%3d PUSH_NULL
- LOAD_FAST 1 (b)
+%3d LOAD_FAST 1 (b)
+ PUSH_NULL
CALL 0
POP_TOP
RETURN_VALUE
>> PUSH_EXC_INFO
- PUSH_NULL
LOAD_FAST 1 (b)
+ PUSH_NULL
CALL 0
POP_TOP
RERAISE 0
@@ -644,14 +644,14 @@ def _tryfinallyconst(b):
%3d NOP
-%3d PUSH_NULL
- LOAD_FAST 0 (b)
+%3d LOAD_FAST 0 (b)
+ PUSH_NULL
CALL 0
POP_TOP
RETURN_CONST 1 (1)
PUSH_EXC_INFO
- PUSH_NULL
LOAD_FAST 0 (b)
+ PUSH_NULL
CALL 0
POP_TOP
RERAISE 0
@@ -710,7 +710,7 @@ def foo(x):
%3d RESUME 0
-%3d LOAD_GLOBAL 1 (NULL + list)
+%3d LOAD_GLOBAL 1 (list + NULL)
LOAD_FAST 0 (x)
BUILD_TUPLE 1
LOAD_CONST 1 ( at 0x..., file "%s", line %d>)
@@ -792,7 +792,7 @@ def loop_test():
>> FOR_ITER_LIST 14 (to 48)
STORE_FAST 0 (i)
-%3d LOAD_GLOBAL_MODULE 1 (NULL + load_test)
+%3d LOAD_GLOBAL_MODULE 1 (load_test + NULL)
LOAD_FAST 0 (i)
CALL_PY_WITH_DEFAULTS 1
POP_TOP
@@ -931,7 +931,7 @@ def do_disassembly_test(self, func, expected, with_offsets=False):
with_offsets)
def test_opmap(self):
- self.assertEqual(dis.opmap["NOP"], 9)
+ self.assertEqual(dis.opmap["CACHE"], 0)
self.assertIn(dis.opmap["LOAD_CONST"], dis.hasconst)
self.assertIn(dis.opmap["STORE_NAME"], dis.hasname)
@@ -940,7 +940,6 @@ def test_opname(self):
def test_boundaries(self):
self.assertEqual(dis.opmap["EXTENDED_ARG"], dis.EXTENDED_ARG)
- self.assertEqual(dis.opmap["STORE_NAME"], dis.HAVE_ARGUMENT)
def test_widths(self):
long_opcodes = set(['JUMP_BACKWARD_NO_INTERRUPT',
@@ -1230,8 +1229,8 @@ def test_call_specialize(self):
call_quicken = """\
0 RESUME 0
- 1 PUSH_NULL
- LOAD_NAME 0 (str)
+ 1 LOAD_NAME 0 (str)
+ PUSH_NULL
LOAD_CONST 0 (1)
CALL_NO_KW_STR_1 1
RETURN_VALUE
@@ -1617,197 +1616,197 @@ def _prepare_test_cases():
Instruction = dis.Instruction
expected_opinfo_outer = [
- Instruction(opname='MAKE_CELL', opcode=135, arg=0, argval='a', argrepr='a', offset=0, start_offset=0, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='MAKE_CELL', opcode=135, arg=1, argval='b', argrepr='b', offset=2, start_offset=2, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=4, start_offset=4, starts_line=1, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=(3, 4), argrepr='(3, 4)', offset=6, start_offset=6, starts_line=2, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='a', argrepr='a', offset=8, start_offset=8, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='b', argrepr='b', offset=10, start_offset=10, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='BUILD_TUPLE', opcode=102, arg=2, argval=2, argrepr='', offset=12, start_offset=12, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=code_object_f, argrepr=repr(code_object_f), offset=14, start_offset=14, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='MAKE_FUNCTION', opcode=24, arg=None, argval=None, argrepr='', offset=16, start_offset=16, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=177, arg=8, argval=8, argrepr='closure', offset=18, start_offset=18, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=177, arg=1, argval=1, argrepr='defaults', offset=20, start_offset=20, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='f', argrepr='f', offset=22, start_offset=22, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='NULL + print', offset=24, start_offset=24, starts_line=7, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='a', argrepr='a', offset=34, start_offset=34, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='b', argrepr='b', offset=36, start_offset=36, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval='', argrepr="''", offset=38, start_offset=38, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=1, argrepr='1', offset=40, start_offset=40, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=42, start_offset=42, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=44, start_offset=44, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='Hello world!', argrepr="'Hello world!'", offset=46, start_offset=46, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='CALL', opcode=171, arg=7, argval=7, argrepr='', offset=48, start_offset=48, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=56, start_offset=56, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=58, start_offset=58, starts_line=8, is_jump_target=False, positions=None),
- Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=60, start_offset=60, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='MAKE_CELL', opcode=157, arg=0, argval='a', argrepr='a', offset=0, start_offset=0, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='MAKE_CELL', opcode=157, arg=1, argval='b', argrepr='b', offset=2, start_offset=2, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='RESUME', opcode=166, arg=0, argval=0, argrepr='', offset=4, start_offset=4, starts_line=1, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=142, arg=5, argval=(3, 4), argrepr='(3, 4)', offset=6, start_offset=6, starts_line=2, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_FAST', opcode=144, arg=0, argval='a', argrepr='a', offset=8, start_offset=8, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_FAST', opcode=144, arg=1, argval='b', argrepr='b', offset=10, start_offset=10, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='BUILD_TUPLE', opcode=74, arg=2, argval=2, argrepr='', offset=12, start_offset=12, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=142, arg=1, argval=code_object_f, argrepr=repr(code_object_f), offset=14, start_offset=14, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='MAKE_FUNCTION', opcode=38, arg=None, argval=None, argrepr='', offset=16, start_offset=16, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=171, arg=8, argval=8, argrepr='closure', offset=18, start_offset=18, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=171, arg=1, argval=1, argrepr='defaults', offset=20, start_offset=20, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='STORE_FAST', opcode=176, arg=2, argval='f', argrepr='f', offset=22, start_offset=22, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_GLOBAL', opcode=150, arg=1, argval='print', argrepr='print + NULL', offset=24, start_offset=24, starts_line=7, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_DEREF', opcode=143, arg=0, argval='a', argrepr='a', offset=34, start_offset=34, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_DEREF', opcode=143, arg=1, argval='b', argrepr='b', offset=36, start_offset=36, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=142, arg=2, argval='', argrepr="''", offset=38, start_offset=38, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=142, arg=3, argval=1, argrepr='1', offset=40, start_offset=40, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='BUILD_LIST', opcode=69, arg=0, argval=0, argrepr='', offset=42, start_offset=42, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='BUILD_MAP', opcode=70, arg=0, argval=0, argrepr='', offset=44, start_offset=44, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=142, arg=4, argval='Hello world!', argrepr="'Hello world!'", offset=46, start_offset=46, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='CALL', opcode=75, arg=7, argval=7, argrepr='', offset=48, start_offset=48, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=56, start_offset=56, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_FAST', opcode=144, arg=2, argval='f', argrepr='f', offset=58, start_offset=58, starts_line=8, is_jump_target=False, positions=None),
+ Instruction(opname='RETURN_VALUE', opcode=48, arg=None, argval=None, argrepr='', offset=60, start_offset=60, starts_line=None, is_jump_target=False, positions=None),
]
expected_opinfo_f = [
- Instruction(opname='COPY_FREE_VARS', opcode=149, arg=2, argval=2, argrepr='', offset=0, start_offset=0, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='MAKE_CELL', opcode=135, arg=0, argval='c', argrepr='c', offset=2, start_offset=2, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='MAKE_CELL', opcode=135, arg=1, argval='d', argrepr='d', offset=4, start_offset=4, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=6, start_offset=6, starts_line=2, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=(5, 6), argrepr='(5, 6)', offset=8, start_offset=8, starts_line=3, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_FAST', opcode=124, arg=3, argval='a', argrepr='a', offset=10, start_offset=10, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_FAST', opcode=124, arg=4, argval='b', argrepr='b', offset=12, start_offset=12, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='c', argrepr='c', offset=14, start_offset=14, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='d', argrepr='d', offset=16, start_offset=16, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=18, start_offset=18, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=code_object_inner, argrepr=repr(code_object_inner), offset=20, start_offset=20, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='MAKE_FUNCTION', opcode=24, arg=None, argval=None, argrepr='', offset=22, start_offset=22, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=177, arg=8, argval=8, argrepr='closure', offset=24, start_offset=24, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=177, arg=1, argval=1, argrepr='defaults', offset=26, start_offset=26, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=28, start_offset=28, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='NULL + print', offset=30, start_offset=30, starts_line=5, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='a', argrepr='a', offset=40, start_offset=40, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='b', argrepr='b', offset=42, start_offset=42, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='c', argrepr='c', offset=44, start_offset=44, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='d', argrepr='d', offset=46, start_offset=46, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='CALL', opcode=171, arg=4, argval=4, argrepr='', offset=48, start_offset=48, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=56, start_offset=56, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=58, start_offset=58, starts_line=6, is_jump_target=False, positions=None),
- Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=60, start_offset=60, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='COPY_FREE_VARS', opcode=104, arg=2, argval=2, argrepr='', offset=0, start_offset=0, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='MAKE_CELL', opcode=157, arg=0, argval='c', argrepr='c', offset=2, start_offset=2, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='MAKE_CELL', opcode=157, arg=1, argval='d', argrepr='d', offset=4, start_offset=4, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='RESUME', opcode=166, arg=0, argval=0, argrepr='', offset=6, start_offset=6, starts_line=2, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=142, arg=2, argval=(5, 6), argrepr='(5, 6)', offset=8, start_offset=8, starts_line=3, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_FAST', opcode=144, arg=3, argval='a', argrepr='a', offset=10, start_offset=10, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_FAST', opcode=144, arg=4, argval='b', argrepr='b', offset=12, start_offset=12, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_FAST', opcode=144, arg=0, argval='c', argrepr='c', offset=14, start_offset=14, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_FAST', opcode=144, arg=1, argval='d', argrepr='d', offset=16, start_offset=16, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='BUILD_TUPLE', opcode=74, arg=4, argval=4, argrepr='', offset=18, start_offset=18, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=142, arg=1, argval=code_object_inner, argrepr=repr(code_object_inner), offset=20, start_offset=20, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='MAKE_FUNCTION', opcode=38, arg=None, argval=None, argrepr='', offset=22, start_offset=22, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=171, arg=8, argval=8, argrepr='closure', offset=24, start_offset=24, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=171, arg=1, argval=1, argrepr='defaults', offset=26, start_offset=26, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='STORE_FAST', opcode=176, arg=2, argval='inner', argrepr='inner', offset=28, start_offset=28, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_GLOBAL', opcode=150, arg=1, argval='print', argrepr='print + NULL', offset=30, start_offset=30, starts_line=5, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_DEREF', opcode=143, arg=3, argval='a', argrepr='a', offset=40, start_offset=40, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_DEREF', opcode=143, arg=4, argval='b', argrepr='b', offset=42, start_offset=42, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_DEREF', opcode=143, arg=0, argval='c', argrepr='c', offset=44, start_offset=44, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_DEREF', opcode=143, arg=1, argval='d', argrepr='d', offset=46, start_offset=46, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='CALL', opcode=75, arg=4, argval=4, argrepr='', offset=48, start_offset=48, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=56, start_offset=56, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_FAST', opcode=144, arg=2, argval='inner', argrepr='inner', offset=58, start_offset=58, starts_line=6, is_jump_target=False, positions=None),
+ Instruction(opname='RETURN_VALUE', opcode=48, arg=None, argval=None, argrepr='', offset=60, start_offset=60, starts_line=None, is_jump_target=False, positions=None),
]
expected_opinfo_inner = [
- Instruction(opname='COPY_FREE_VARS', opcode=149, arg=4, argval=4, argrepr='', offset=0, start_offset=0, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=2, start_offset=2, starts_line=3, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='NULL + print', offset=4, start_offset=4, starts_line=4, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_DEREF', opcode=137, arg=2, argval='a', argrepr='a', offset=14, start_offset=14, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='b', argrepr='b', offset=16, start_offset=16, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='c', argrepr='c', offset=18, start_offset=18, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_DEREF', opcode=137, arg=5, argval='d', argrepr='d', offset=20, start_offset=20, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_FAST_LOAD_FAST', opcode=168, arg=1, argval=('e', 'f'), argrepr='e, f', offset=22, start_offset=22, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='CALL', opcode=171, arg=6, argval=6, argrepr='', offset=24, start_offset=24, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=32, start_offset=32, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='RETURN_CONST', opcode=121, arg=0, argval=None, argrepr='None', offset=34, start_offset=34, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='COPY_FREE_VARS', opcode=104, arg=4, argval=4, argrepr='', offset=0, start_offset=0, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='RESUME', opcode=166, arg=0, argval=0, argrepr='', offset=2, start_offset=2, starts_line=3, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_GLOBAL', opcode=150, arg=1, argval='print', argrepr='print + NULL', offset=4, start_offset=4, starts_line=4, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_DEREF', opcode=143, arg=2, argval='a', argrepr='a', offset=14, start_offset=14, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_DEREF', opcode=143, arg=3, argval='b', argrepr='b', offset=16, start_offset=16, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_DEREF', opcode=143, arg=4, argval='c', argrepr='c', offset=18, start_offset=18, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_DEREF', opcode=143, arg=5, argval='d', argrepr='d', offset=20, start_offset=20, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_FAST_LOAD_FAST', opcode=147, arg=1, argval=('e', 'f'), argrepr='e, f', offset=22, start_offset=22, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='CALL', opcode=75, arg=6, argval=6, argrepr='', offset=24, start_offset=24, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=32, start_offset=32, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='RETURN_CONST', opcode=167, arg=0, argval=None, argrepr='None', offset=34, start_offset=34, starts_line=None, is_jump_target=False, positions=None),
]
expected_opinfo_jumpy = [
- Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=0, start_offset=0, starts_line=1, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='range', argrepr='NULL + range', offset=2, start_offset=2, starts_line=3, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=10, argrepr='10', offset=12, start_offset=12, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=14, start_offset=14, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=22, start_offset=22, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='FOR_ITER', opcode=93, arg=28, argval=84, argrepr='to 84', offset=24, start_offset=24, starts_line=None, is_jump_target=True, positions=None),
- Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=28, start_offset=28, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=30, start_offset=30, starts_line=4, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=40, start_offset=40, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=42, start_offset=42, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=50, start_offset=50, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=52, start_offset=52, starts_line=5, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=54, start_offset=54, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='COMPARE_OP', opcode=107, arg=18, argval='<', argrepr='bool(<)', offset=56, start_offset=56, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=2, argval=66, argrepr='to 66', offset=60, start_offset=60, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='JUMP_BACKWARD', opcode=140, arg=21, argval=24, argrepr='to 24', offset=62, start_offset=62, starts_line=6, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=66, start_offset=66, starts_line=7, is_jump_target=True, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=68, start_offset=68, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='COMPARE_OP', opcode=107, arg=148, argval='>', argrepr='bool(>)', offset=70, start_offset=70, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=2, argval=80, argrepr='to 80', offset=74, start_offset=74, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='JUMP_BACKWARD', opcode=140, arg=28, argval=24, argrepr='to 24', offset=76, start_offset=76, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=80, start_offset=80, starts_line=8, is_jump_target=True, positions=None),
- Instruction(opname='JUMP_FORWARD', opcode=110, arg=12, argval=108, argrepr='to 108', offset=82, start_offset=82, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='END_FOR', opcode=4, arg=None, argval=None, argrepr='', offset=84, start_offset=84, starts_line=3, is_jump_target=True, positions=None),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=86, start_offset=86, starts_line=10, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=96, start_offset=96, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=98, start_offset=98, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=106, start_offset=106, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_FAST_CHECK', opcode=127, arg=0, argval='i', argrepr='i', offset=108, start_offset=108, starts_line=11, is_jump_target=True, positions=None),
- Instruction(opname='TO_BOOL', opcode=6, arg=None, argval=None, argrepr='', offset=110, start_offset=110, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=37, argval=194, argrepr='to 194', offset=118, start_offset=118, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=120, start_offset=120, starts_line=12, is_jump_target=True, positions=None),
- Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=130, start_offset=130, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=132, start_offset=132, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=140, start_offset=140, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=142, start_offset=142, starts_line=13, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=144, start_offset=144, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='BINARY_OP', opcode=122, arg=23, argval=23, argrepr='-=', offset=146, start_offset=146, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=150, start_offset=150, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=152, start_offset=152, starts_line=14, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=154, start_offset=154, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='COMPARE_OP', opcode=107, arg=148, argval='>', argrepr='bool(>)', offset=156, start_offset=156, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=2, argval=166, argrepr='to 166', offset=160, start_offset=160, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='JUMP_BACKWARD', opcode=140, arg=29, argval=108, argrepr='to 108', offset=162, start_offset=162, starts_line=15, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=166, start_offset=166, starts_line=16, is_jump_target=True, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=168, start_offset=168, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='COMPARE_OP', opcode=107, arg=18, argval='<', argrepr='bool(<)', offset=170, start_offset=170, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=178, argrepr='to 178', offset=174, start_offset=174, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='JUMP_FORWARD', opcode=110, arg=19, argval=216, argrepr='to 216', offset=176, start_offset=176, starts_line=17, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=178, start_offset=178, starts_line=11, is_jump_target=True, positions=None),
- Instruction(opname='TO_BOOL', opcode=6, arg=None, argval=None, argrepr='', offset=180, start_offset=180, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=2, argval=194, argrepr='to 194', offset=188, start_offset=188, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='JUMP_BACKWARD', opcode=140, arg=37, argval=120, argrepr='to 120', offset=190, start_offset=190, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=194, start_offset=194, starts_line=19, is_jump_target=True, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=204, start_offset=204, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=206, start_offset=206, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=214, start_offset=214, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=216, start_offset=216, starts_line=20, is_jump_target=True, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=218, start_offset=218, starts_line=21, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=220, start_offset=220, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='BINARY_OP', opcode=122, arg=11, argval=11, argrepr='/', offset=222, start_offset=222, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=226, start_offset=226, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=228, start_offset=228, starts_line=25, is_jump_target=False, positions=None),
- Instruction(opname='BEFORE_WITH', opcode=53, arg=None, argval=None, argrepr='', offset=230, start_offset=230, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=232, start_offset=232, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=234, start_offset=234, starts_line=26, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Never reach this', argrepr="'Never reach this'", offset=244, start_offset=244, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=246, start_offset=246, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=254, start_offset=254, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=256, start_offset=256, starts_line=25, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=258, start_offset=258, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=260, start_offset=260, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='CALL', opcode=171, arg=2, argval=2, argrepr='', offset=262, start_offset=262, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=270, start_offset=270, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=272, start_offset=272, starts_line=28, is_jump_target=True, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=282, start_offset=282, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=284, start_offset=284, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=292, start_offset=292, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='RETURN_CONST', opcode=121, arg=0, argval=None, argrepr='None', offset=294, start_offset=294, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=296, start_offset=296, starts_line=25, is_jump_target=False, positions=None),
- Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=298, start_offset=298, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='TO_BOOL', opcode=6, arg=None, argval=None, argrepr='', offset=300, start_offset=300, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=1, argval=312, argrepr='to 312', offset=308, start_offset=308, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=310, start_offset=310, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=312, start_offset=312, starts_line=None, is_jump_target=True, positions=None),
- Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=314, start_offset=314, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=316, start_offset=316, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=318, start_offset=318, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='JUMP_BACKWARD', opcode=140, arg=26, argval=272, argrepr='to 272', offset=320, start_offset=320, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=324, start_offset=324, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=326, start_offset=326, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=328, start_offset=328, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=330, start_offset=330, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=332, start_offset=332, starts_line=22, is_jump_target=False, positions=None),
- Instruction(opname='CHECK_EXC_MATCH', opcode=36, arg=None, argval=None, argrepr='', offset=342, start_offset=342, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=15, argval=376, argrepr='to 376', offset=344, start_offset=344, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=346, start_offset=346, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=348, start_offset=348, starts_line=23, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=358, start_offset=358, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=360, start_offset=360, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=368, start_offset=368, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=370, start_offset=370, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='JUMP_BACKWARD', opcode=140, arg=52, argval=272, argrepr='to 272', offset=372, start_offset=372, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=376, start_offset=376, starts_line=22, is_jump_target=True, positions=None),
- Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=378, start_offset=378, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=380, start_offset=380, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=382, start_offset=382, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=384, start_offset=384, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=386, start_offset=386, starts_line=28, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=396, start_offset=396, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=398, start_offset=398, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=406, start_offset=406, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=408, start_offset=408, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=410, start_offset=410, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=412, start_offset=412, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=414, start_offset=414, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='RESUME', opcode=166, arg=0, argval=0, argrepr='', offset=0, start_offset=0, starts_line=1, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_GLOBAL', opcode=150, arg=1, argval='range', argrepr='range + NULL', offset=2, start_offset=2, starts_line=3, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=142, arg=1, argval=10, argrepr='10', offset=12, start_offset=12, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='CALL', opcode=75, arg=1, argval=1, argrepr='', offset=14, start_offset=14, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='GET_ITER', opcode=31, arg=None, argval=None, argrepr='', offset=22, start_offset=22, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='FOR_ITER', opcode=114, arg=28, argval=84, argrepr='to 84', offset=24, start_offset=24, starts_line=None, is_jump_target=True, positions=None),
+ Instruction(opname='STORE_FAST', opcode=176, arg=0, argval='i', argrepr='i', offset=28, start_offset=28, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_GLOBAL', opcode=150, arg=3, argval='print', argrepr='print + NULL', offset=30, start_offset=30, starts_line=4, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_FAST', opcode=144, arg=0, argval='i', argrepr='i', offset=40, start_offset=40, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='CALL', opcode=75, arg=1, argval=1, argrepr='', offset=42, start_offset=42, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=50, start_offset=50, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_FAST', opcode=144, arg=0, argval='i', argrepr='i', offset=52, start_offset=52, starts_line=5, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=142, arg=2, argval=4, argrepr='4', offset=54, start_offset=54, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='COMPARE_OP', opcode=97, arg=18, argval='<', argrepr='bool(<)', offset=56, start_offset=56, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_JUMP_IF_FALSE', opcode=160, arg=2, argval=66, argrepr='to 66', offset=60, start_offset=60, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='JUMP_BACKWARD', opcode=123, arg=21, argval=24, argrepr='to 24', offset=62, start_offset=62, starts_line=6, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_FAST', opcode=144, arg=0, argval='i', argrepr='i', offset=66, start_offset=66, starts_line=7, is_jump_target=True, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=142, arg=3, argval=6, argrepr='6', offset=68, start_offset=68, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='COMPARE_OP', opcode=97, arg=148, argval='>', argrepr='bool(>)', offset=70, start_offset=70, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_JUMP_IF_TRUE', opcode=163, arg=2, argval=80, argrepr='to 80', offset=74, start_offset=74, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='JUMP_BACKWARD', opcode=123, arg=28, argval=24, argrepr='to 24', offset=76, start_offset=76, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=80, start_offset=80, starts_line=8, is_jump_target=True, positions=None),
+ Instruction(opname='JUMP_FORWARD', opcode=125, arg=12, argval=108, argrepr='to 108', offset=82, start_offset=82, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='END_FOR', opcode=24, arg=None, argval=None, argrepr='', offset=84, start_offset=84, starts_line=3, is_jump_target=True, positions=None),
+ Instruction(opname='LOAD_GLOBAL', opcode=150, arg=3, argval='print', argrepr='print + NULL', offset=86, start_offset=86, starts_line=10, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=142, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=96, start_offset=96, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='CALL', opcode=75, arg=1, argval=1, argrepr='', offset=98, start_offset=98, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=106, start_offset=106, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_FAST_CHECK', opcode=146, arg=0, argval='i', argrepr='i', offset=108, start_offset=108, starts_line=11, is_jump_target=True, positions=None),
+ Instruction(opname='TO_BOOL', opcode=56, arg=None, argval=None, argrepr='', offset=110, start_offset=110, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_JUMP_IF_FALSE', opcode=160, arg=37, argval=194, argrepr='to 194', offset=118, start_offset=118, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_GLOBAL', opcode=150, arg=3, argval='print', argrepr='print + NULL', offset=120, start_offset=120, starts_line=12, is_jump_target=True, positions=None),
+ Instruction(opname='LOAD_FAST', opcode=144, arg=0, argval='i', argrepr='i', offset=130, start_offset=130, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='CALL', opcode=75, arg=1, argval=1, argrepr='', offset=132, start_offset=132, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=140, start_offset=140, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_FAST', opcode=144, arg=0, argval='i', argrepr='i', offset=142, start_offset=142, starts_line=13, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=142, arg=5, argval=1, argrepr='1', offset=144, start_offset=144, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='BINARY_OP', opcode=67, arg=23, argval=23, argrepr='-=', offset=146, start_offset=146, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='STORE_FAST', opcode=176, arg=0, argval='i', argrepr='i', offset=150, start_offset=150, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_FAST', opcode=144, arg=0, argval='i', argrepr='i', offset=152, start_offset=152, starts_line=14, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=142, arg=3, argval=6, argrepr='6', offset=154, start_offset=154, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='COMPARE_OP', opcode=97, arg=148, argval='>', argrepr='bool(>)', offset=156, start_offset=156, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_JUMP_IF_FALSE', opcode=160, arg=2, argval=166, argrepr='to 166', offset=160, start_offset=160, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='JUMP_BACKWARD', opcode=123, arg=29, argval=108, argrepr='to 108', offset=162, start_offset=162, starts_line=15, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_FAST', opcode=144, arg=0, argval='i', argrepr='i', offset=166, start_offset=166, starts_line=16, is_jump_target=True, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=142, arg=2, argval=4, argrepr='4', offset=168, start_offset=168, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='COMPARE_OP', opcode=97, arg=18, argval='<', argrepr='bool(<)', offset=170, start_offset=170, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_JUMP_IF_FALSE', opcode=160, arg=1, argval=178, argrepr='to 178', offset=174, start_offset=174, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='JUMP_FORWARD', opcode=125, arg=19, argval=216, argrepr='to 216', offset=176, start_offset=176, starts_line=17, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_FAST', opcode=144, arg=0, argval='i', argrepr='i', offset=178, start_offset=178, starts_line=11, is_jump_target=True, positions=None),
+ Instruction(opname='TO_BOOL', opcode=56, arg=None, argval=None, argrepr='', offset=180, start_offset=180, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_JUMP_IF_FALSE', opcode=160, arg=2, argval=194, argrepr='to 194', offset=188, start_offset=188, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='JUMP_BACKWARD', opcode=123, arg=37, argval=120, argrepr='to 120', offset=190, start_offset=190, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_GLOBAL', opcode=150, arg=3, argval='print', argrepr='print + NULL', offset=194, start_offset=194, starts_line=19, is_jump_target=True, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=142, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=204, start_offset=204, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='CALL', opcode=75, arg=1, argval=1, argrepr='', offset=206, start_offset=206, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=214, start_offset=214, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='NOP', opcode=42, arg=None, argval=None, argrepr='', offset=216, start_offset=216, starts_line=20, is_jump_target=True, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=142, arg=5, argval=1, argrepr='1', offset=218, start_offset=218, starts_line=21, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=142, arg=7, argval=0, argrepr='0', offset=220, start_offset=220, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='BINARY_OP', opcode=67, arg=11, argval=11, argrepr='/', offset=222, start_offset=222, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=226, start_offset=226, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_FAST', opcode=144, arg=0, argval='i', argrepr='i', offset=228, start_offset=228, starts_line=25, is_jump_target=False, positions=None),
+ Instruction(opname='BEFORE_WITH', opcode=2, arg=None, argval=None, argrepr='', offset=230, start_offset=230, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='STORE_FAST', opcode=176, arg=1, argval='dodgy', argrepr='dodgy', offset=232, start_offset=232, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_GLOBAL', opcode=150, arg=3, argval='print', argrepr='print + NULL', offset=234, start_offset=234, starts_line=26, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=142, arg=8, argval='Never reach this', argrepr="'Never reach this'", offset=244, start_offset=244, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='CALL', opcode=75, arg=1, argval=1, argrepr='', offset=246, start_offset=246, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=254, start_offset=254, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=142, arg=0, argval=None, argrepr='None', offset=256, start_offset=256, starts_line=25, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=142, arg=0, argval=None, argrepr='None', offset=258, start_offset=258, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=142, arg=0, argval=None, argrepr='None', offset=260, start_offset=260, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='CALL', opcode=75, arg=2, argval=2, argrepr='', offset=262, start_offset=262, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=270, start_offset=270, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_GLOBAL', opcode=150, arg=3, argval='print', argrepr='print + NULL', offset=272, start_offset=272, starts_line=28, is_jump_target=True, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=142, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=282, start_offset=282, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='CALL', opcode=75, arg=1, argval=1, argrepr='', offset=284, start_offset=284, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=292, start_offset=292, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='RETURN_CONST', opcode=167, arg=0, argval=None, argrepr='None', offset=294, start_offset=294, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='PUSH_EXC_INFO', opcode=45, arg=None, argval=None, argrepr='', offset=296, start_offset=296, starts_line=25, is_jump_target=False, positions=None),
+ Instruction(opname='WITH_EXCEPT_START', opcode=66, arg=None, argval=None, argrepr='', offset=298, start_offset=298, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='TO_BOOL', opcode=56, arg=None, argval=None, argrepr='', offset=300, start_offset=300, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_JUMP_IF_TRUE', opcode=163, arg=1, argval=312, argrepr='to 312', offset=308, start_offset=308, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='RERAISE', opcode=165, arg=2, argval=2, argrepr='', offset=310, start_offset=310, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=312, start_offset=312, starts_line=None, is_jump_target=True, positions=None),
+ Instruction(opname='POP_EXCEPT', opcode=43, arg=None, argval=None, argrepr='', offset=314, start_offset=314, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=316, start_offset=316, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=318, start_offset=318, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='JUMP_BACKWARD', opcode=123, arg=26, argval=272, argrepr='to 272', offset=320, start_offset=320, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='COPY', opcode=103, arg=3, argval=3, argrepr='', offset=324, start_offset=324, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_EXCEPT', opcode=43, arg=None, argval=None, argrepr='', offset=326, start_offset=326, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='RERAISE', opcode=165, arg=1, argval=1, argrepr='', offset=328, start_offset=328, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='PUSH_EXC_INFO', opcode=45, arg=None, argval=None, argrepr='', offset=330, start_offset=330, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_GLOBAL', opcode=150, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=332, start_offset=332, starts_line=22, is_jump_target=False, positions=None),
+ Instruction(opname='CHECK_EXC_MATCH', opcode=20, arg=None, argval=None, argrepr='', offset=342, start_offset=342, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_JUMP_IF_FALSE', opcode=160, arg=15, argval=376, argrepr='to 376', offset=344, start_offset=344, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=346, start_offset=346, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_GLOBAL', opcode=150, arg=3, argval='print', argrepr='print + NULL', offset=348, start_offset=348, starts_line=23, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=142, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=358, start_offset=358, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='CALL', opcode=75, arg=1, argval=1, argrepr='', offset=360, start_offset=360, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=368, start_offset=368, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_EXCEPT', opcode=43, arg=None, argval=None, argrepr='', offset=370, start_offset=370, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='JUMP_BACKWARD', opcode=123, arg=52, argval=272, argrepr='to 272', offset=372, start_offset=372, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='RERAISE', opcode=165, arg=0, argval=0, argrepr='', offset=376, start_offset=376, starts_line=22, is_jump_target=True, positions=None),
+ Instruction(opname='COPY', opcode=103, arg=3, argval=3, argrepr='', offset=378, start_offset=378, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_EXCEPT', opcode=43, arg=None, argval=None, argrepr='', offset=380, start_offset=380, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='RERAISE', opcode=165, arg=1, argval=1, argrepr='', offset=382, start_offset=382, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='PUSH_EXC_INFO', opcode=45, arg=None, argval=None, argrepr='', offset=384, start_offset=384, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_GLOBAL', opcode=150, arg=3, argval='print', argrepr='print + NULL', offset=386, start_offset=386, starts_line=28, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=142, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=396, start_offset=396, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='CALL', opcode=75, arg=1, argval=1, argrepr='', offset=398, start_offset=398, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=406, start_offset=406, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='RERAISE', opcode=165, arg=0, argval=0, argrepr='', offset=408, start_offset=408, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='COPY', opcode=103, arg=3, argval=3, argrepr='', offset=410, start_offset=410, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_EXCEPT', opcode=43, arg=None, argval=None, argrepr='', offset=412, start_offset=412, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='RERAISE', opcode=165, arg=1, argval=1, argrepr='', offset=414, start_offset=414, starts_line=None, is_jump_target=False, positions=None),
]
# One last piece of inspect fodder to check the default line number handling
def simple(): pass
expected_opinfo_simple = [
- Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=0, start_offset=0, starts_line=simple.__code__.co_firstlineno, is_jump_target=False, positions=None),
- Instruction(opname='RETURN_CONST', opcode=121, arg=0, argval=None, argrepr='None', offset=2, start_offset=2, starts_line=None, is_jump_target=False),
+ Instruction(opname='RESUME', opcode=166, arg=0, argval=0, argrepr='', offset=0, start_offset=0, starts_line=simple.__code__.co_firstlineno, is_jump_target=False, positions=None),
+ Instruction(opname='RETURN_CONST', opcode=167, arg=0, argval=None, argrepr='None', offset=2, start_offset=2, starts_line=None, is_jump_target=False),
]
@@ -1943,7 +1942,7 @@ def test_baseopname_and_baseopcode(self):
self.assertEqual(code, baseopcode)
# Specialized instructions
- for name in opcode._specialized_instructions:
+ for name in opcode._specialized_opmap:
instruction = Instruction(opname=name, opcode=dis._all_opmap[name], arg=None, argval=None, argrepr='',
offset=0, start_offset=0, starts_line=1, is_jump_target=False, positions=None)
baseopname = instruction.baseopname
diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py
index 582392ecddcb91..50c9f61017e022 100644
--- a/Lib/test/test_embed.py
+++ b/Lib/test/test_embed.py
@@ -361,7 +361,7 @@ def is_specialized(f):
for instruction in dis.get_instructions(f, adaptive=True):
opname = instruction.opname
if (
- opname in opcode._specialized_instructions
+ opname in opcode._specialized_opmap
# Exclude superinstructions:
and "__" not in opname
):
diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py
index a286411f7bcf57..6e128439fa3569 100644
--- a/Lib/test/test_enum.py
+++ b/Lib/test/test_enum.py
@@ -38,6 +38,25 @@ def load_tests(loader, tests, ignore):
))
return tests
+def reraise_if_not_enum(*enum_types_or_exceptions):
+ from functools import wraps
+
+ def decorator(func):
+ @wraps(func)
+ def inner(*args, **kwargs):
+ excs = [
+ e
+ for e in enum_types_or_exceptions
+ if isinstance(e, Exception)
+ ]
+ if len(excs) == 1:
+ raise excs[0]
+ elif excs:
+ raise ExceptionGroup('Enum Exceptions', excs)
+ return func(*args, **kwargs)
+ return inner
+ return decorator
+
MODULE = __name__
SHORT_MODULE = MODULE.split('.')[-1]
@@ -75,30 +94,42 @@ class FlagStooges(Flag):
except Exception as exc:
FlagStooges = exc
-class FlagStoogesWithZero(Flag):
- NOFLAG = 0
- LARRY = 1
- CURLY = 2
- MOE = 4
- BIG = 389
-
-class IntFlagStooges(IntFlag):
- LARRY = 1
- CURLY = 2
- MOE = 4
- BIG = 389
-
-class IntFlagStoogesWithZero(IntFlag):
- NOFLAG = 0
- LARRY = 1
- CURLY = 2
- MOE = 4
- BIG = 389
+try:
+ class FlagStoogesWithZero(Flag):
+ NOFLAG = 0
+ LARRY = 1
+ CURLY = 2
+ MOE = 4
+ BIG = 389
+except Exception as exc:
+ FlagStoogesWithZero = exc
+
+try:
+ class IntFlagStooges(IntFlag):
+ LARRY = 1
+ CURLY = 2
+ MOE = 4
+ BIG = 389
+except Exception as exc:
+ IntFlagStooges = exc
+
+try:
+ class IntFlagStoogesWithZero(IntFlag):
+ NOFLAG = 0
+ LARRY = 1
+ CURLY = 2
+ MOE = 4
+ BIG = 389
+except Exception as exc:
+ IntFlagStoogesWithZero = exc
# for pickle test and subclass tests
-class Name(StrEnum):
- BDFL = 'Guido van Rossum'
- FLUFL = 'Barry Warsaw'
+try:
+ class Name(StrEnum):
+ BDFL = 'Guido van Rossum'
+ FLUFL = 'Barry Warsaw'
+except Exception as exc:
+ Name = exc
try:
Question = Enum('Question', 'who what when where why', module=__name__)
@@ -204,26 +235,35 @@ def __get__(self, instance, ownerclass):
# for global repr tests
-@enum.global_enum
-class HeadlightsK(IntFlag, boundary=enum.KEEP):
- OFF_K = 0
- LOW_BEAM_K = auto()
- HIGH_BEAM_K = auto()
- FOG_K = auto()
+try:
+ @enum.global_enum
+ class HeadlightsK(IntFlag, boundary=enum.KEEP):
+ OFF_K = 0
+ LOW_BEAM_K = auto()
+ HIGH_BEAM_K = auto()
+ FOG_K = auto()
+except Exception as exc:
+ HeadlightsK = exc
-@enum.global_enum
-class HeadlightsC(IntFlag, boundary=enum.CONFORM):
- OFF_C = 0
- LOW_BEAM_C = auto()
- HIGH_BEAM_C = auto()
- FOG_C = auto()
+try:
+ @enum.global_enum
+ class HeadlightsC(IntFlag, boundary=enum.CONFORM):
+ OFF_C = 0
+ LOW_BEAM_C = auto()
+ HIGH_BEAM_C = auto()
+ FOG_C = auto()
+except Exception as exc:
+ HeadlightsC = exc
-@enum.global_enum
-class NoName(Flag):
- ONE = 1
- TWO = 2
+try:
+ @enum.global_enum
+ class NoName(Flag):
+ ONE = 1
+ TWO = 2
+except Exception as exc:
+ NoName = exc
# tests
@@ -1124,9 +1164,8 @@ def red(self):
green = 2
blue = 3
+ @reraise_if_not_enum(Theory)
def test_enum_function_with_qualname(self):
- if isinstance(Theory, Exception):
- raise Theory
self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
def test_enum_of_types(self):
@@ -1355,6 +1394,7 @@ class MyUnBrokenEnum(UnBrokenInt, Enum):
test_pickle_dump_load(self.assertIs, MyUnBrokenEnum.I)
test_pickle_dump_load(self.assertIs, MyUnBrokenEnum)
+ @reraise_if_not_enum(FloatStooges)
def test_floatenum_fromhex(self):
h = float.hex(FloatStooges.MOE.value)
self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
@@ -1475,6 +1515,7 @@ class ThreePart(Enum):
self.assertIs(ThreePart((3, 3.0, 'three')), ThreePart.THREE)
self.assertIs(ThreePart(3, 3.0, 'three'), ThreePart.THREE)
+ @reraise_if_not_enum(IntStooges)
def test_intenum_from_bytes(self):
self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
with self.assertRaises(ValueError):
@@ -1503,33 +1544,28 @@ def repr(self):
class Huh(MyStr, MyInt, Enum):
One = 1
+ @reraise_if_not_enum(Stooges)
def test_pickle_enum(self):
- if isinstance(Stooges, Exception):
- raise Stooges
test_pickle_dump_load(self.assertIs, Stooges.CURLY)
test_pickle_dump_load(self.assertIs, Stooges)
+ @reraise_if_not_enum(IntStooges)
def test_pickle_int(self):
- if isinstance(IntStooges, Exception):
- raise IntStooges
test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
test_pickle_dump_load(self.assertIs, IntStooges)
+ @reraise_if_not_enum(FloatStooges)
def test_pickle_float(self):
- if isinstance(FloatStooges, Exception):
- raise FloatStooges
test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
test_pickle_dump_load(self.assertIs, FloatStooges)
+ @reraise_if_not_enum(Answer)
def test_pickle_enum_function(self):
- if isinstance(Answer, Exception):
- raise Answer
test_pickle_dump_load(self.assertIs, Answer.him)
test_pickle_dump_load(self.assertIs, Answer)
+ @reraise_if_not_enum(Question)
def test_pickle_enum_function_with_module(self):
- if isinstance(Question, Exception):
- raise Question
test_pickle_dump_load(self.assertIs, Question.who)
test_pickle_dump_load(self.assertIs, Question)
@@ -1592,9 +1628,8 @@ class Season(Enum):
[Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
)
+ @reraise_if_not_enum(Name)
def test_subclassing(self):
- if isinstance(Name, Exception):
- raise Name
self.assertEqual(Name.BDFL, 'Guido van Rossum')
self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
@@ -3330,9 +3365,13 @@ def test_programatic_function_from_dict(self):
self.assertIn(e, Perm)
self.assertIs(type(e), Perm)
+ @reraise_if_not_enum(
+ FlagStooges,
+ FlagStoogesWithZero,
+ IntFlagStooges,
+ IntFlagStoogesWithZero,
+ )
def test_pickle(self):
- if isinstance(FlagStooges, Exception):
- raise FlagStooges
test_pickle_dump_load(self.assertIs, FlagStooges.CURLY)
test_pickle_dump_load(self.assertEqual,
FlagStooges.CURLY|FlagStooges.MOE)
@@ -3637,6 +3676,7 @@ def test_type(self):
self.assertTrue(isinstance(Open.WO | Open.RW, Open))
self.assertEqual(Open.WO | Open.RW, 3)
+ @reraise_if_not_enum(HeadlightsK)
def test_global_repr_keep(self):
self.assertEqual(
repr(HeadlightsK(0)),
@@ -3651,6 +3691,7 @@ def test_global_repr_keep(self):
'%(m)s.HeadlightsK(8)' % {'m': SHORT_MODULE},
)
+ @reraise_if_not_enum(HeadlightsC)
def test_global_repr_conform1(self):
self.assertEqual(
repr(HeadlightsC(0)),
@@ -3665,6 +3706,7 @@ def test_global_repr_conform1(self):
'%(m)s.OFF_C' % {'m': SHORT_MODULE},
)
+ @reraise_if_not_enum(NoName)
def test_global_enum_str(self):
self.assertEqual(str(NoName.ONE & NoName.TWO), 'NoName(0)')
self.assertEqual(str(NoName(0)), 'NoName(0)')
diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py
index f3554f1c4bb3f3..764122ed4ef783 100644
--- a/Lib/test/test_exceptions.py
+++ b/Lib/test/test_exceptions.py
@@ -1931,6 +1931,123 @@ def test_copy_pickle(self):
self.assertEqual(exc.name, orig.name)
self.assertEqual(exc.path, orig.path)
+
+class AssertionErrorTests(unittest.TestCase):
+ def tearDown(self):
+ unlink(TESTFN)
+
+ def write_source(self, source):
+ with open(TESTFN, 'w') as testfile:
+ testfile.write(dedent(source))
+ _rc, _out, err = script_helper.assert_python_failure('-Wd', '-X', 'utf8', TESTFN)
+ return err.decode('utf-8').splitlines()
+
+ 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, "message"',
+ [
+ ' assert 1 > 2, "message"',
+ ' ^^^^^',
+ 'AssertionError: message',
+ ],
+ ),
+
+ # 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):
+ result = self.write_source(source)
+ self.assertEqual(result[-3:], expected)
+
+ def test_multiline_not_highlighted(self):
+ cases = [
+ ("""
+ assert (
+ 1 > 2
+ )
+ """,
+ [
+ ' 1 > 2',
+ 'AssertionError',
+ ],
+ ),
+ ("""
+ assert (
+ 1 < 2 and
+ 3 > 4
+ )
+ """,
+ [
+ ' 1 < 2 and',
+ 'AssertionError',
+ ],
+ ),
+ ]
+ for source, expected in cases:
+ with self.subTest(source):
+ result = self.write_source(source)
+ self.assertEqual(result[-2:], expected)
+
+
class SyntaxErrorTests(unittest.TestCase):
def test_range_of_offsets(self):
cases = [
diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py
index cb14bba2602def..16f01973f99f3e 100644
--- a/Lib/test/test_fstring.py
+++ b/Lib/test/test_fstring.py
@@ -1673,5 +1673,15 @@ def test_debug_in_file(self):
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:
+ f.write(r"print(f'\{1}')")
+
+ _, stdout, stderr = assert_python_ok(script)
+ self.assertIn(rb'\1', stdout)
+ self.assertEqual(len(stderr.strip().splitlines()), 2)
+
if __name__ == '__main__':
unittest.main()
diff --git a/Lib/test/test_funcattrs.py b/Lib/test/test_funcattrs.py
index e08d72877d8aef..35b473d5e9a0b4 100644
--- a/Lib/test/test_funcattrs.py
+++ b/Lib/test/test_funcattrs.py
@@ -194,16 +194,19 @@ def test___qualname__(self):
def test___type_params__(self):
def generic[T](): pass
def not_generic(): pass
+ lambda_ = lambda: ...
T, = generic.__type_params__
self.assertIsInstance(T, typing.TypeVar)
self.assertEqual(generic.__type_params__, (T,))
- self.assertEqual(not_generic.__type_params__, ())
- with self.assertRaises(TypeError):
- del not_generic.__type_params__
- with self.assertRaises(TypeError):
- not_generic.__type_params__ = 42
- not_generic.__type_params__ = (T,)
- self.assertEqual(not_generic.__type_params__, (T,))
+ for func in (not_generic, lambda_):
+ with self.subTest(func=func):
+ self.assertEqual(func.__type_params__, ())
+ with self.assertRaises(TypeError):
+ del func.__type_params__
+ with self.assertRaises(TypeError):
+ func.__type_params__ = 42
+ func.__type_params__ = (T,)
+ self.assertEqual(func.__type_params__, (T,))
def test___code__(self):
num_one, num_two = 7, 8
diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py
index 489044f8090d3b..4f311c2d498e9f 100644
--- a/Lib/test/test_genericpath.py
+++ b/Lib/test/test_genericpath.py
@@ -460,6 +460,10 @@ def test_normpath_issue5827(self):
for path in ('', '.', '/', '\\', '///foo/.//bar//'):
self.assertIsInstance(self.pathmodule.normpath(path), str)
+ def test_normpath_issue106242(self):
+ for path in ('\x00', 'foo\x00bar', '\x00\x00', '\x00foo', 'foo\x00'):
+ self.assertEqual(self.pathmodule.normpath(path), path)
+
def test_abspath_issue3426(self):
# Check that abspath returns unicode when the arg is unicode
# with both ASCII and non-ASCII cwds.
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index 5c31748ce2caac..07c48eac5b48b0 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -13,7 +13,9 @@
import _pickle
import pickle
import shutil
+import stat
import sys
+import time
import types
import tempfile
import textwrap
@@ -22,6 +24,7 @@
import unittest.mock
import warnings
+
try:
from concurrent.futures import ThreadPoolExecutor
except ImportError:
@@ -136,6 +139,14 @@ def gen_coroutine_function_example(self):
yield
return 'spam'
+def meth_noargs(): pass
+def meth_o(object, /): pass
+def meth_self_noargs(self, /): pass
+def meth_self_o(self, object, /): pass
+def meth_type_noargs(type, /): pass
+def meth_type_o(type, object, /): pass
+
+
class TestPredicates(IsTestBase):
def test_excluding_predicates(self):
@@ -1173,6 +1184,39 @@ def test_getfullargspec_builtin_func_no_signature(self):
with self.assertRaises(TypeError):
inspect.getfullargspec(builtin)
+ cls = _testcapi.DocStringNoSignatureTest
+ obj = _testcapi.DocStringNoSignatureTest()
+ for builtin, template in [
+ (_testcapi.docstring_no_signature_noargs, meth_noargs),
+ (_testcapi.docstring_no_signature_o, meth_o),
+ (cls.meth_noargs, meth_self_noargs),
+ (cls.meth_o, meth_self_o),
+ (obj.meth_noargs, meth_self_noargs),
+ (obj.meth_o, meth_self_o),
+ (cls.meth_noargs_class, meth_type_noargs),
+ (cls.meth_o_class, meth_type_o),
+ (cls.meth_noargs_static, meth_noargs),
+ (cls.meth_o_static, meth_o),
+ (cls.meth_noargs_coexist, meth_self_noargs),
+ (cls.meth_o_coexist, meth_self_o),
+
+ (time.time, meth_noargs),
+ (stat.S_IMODE, meth_o),
+ (str.lower, meth_self_noargs),
+ (''.lower, meth_self_noargs),
+ (set.add, meth_self_o),
+ (set().add, meth_self_o),
+ (set.__contains__, meth_self_o),
+ (set().__contains__, meth_self_o),
+ (datetime.datetime.__dict__['utcnow'], meth_type_noargs),
+ (datetime.datetime.utcnow, meth_type_noargs),
+ (dict.__dict__['__class_getitem__'], meth_type_o),
+ (dict.__class_getitem__, meth_type_o),
+ ]:
+ with self.subTest(builtin):
+ self.assertEqual(inspect.getfullargspec(builtin),
+ inspect.getfullargspec(template))
+
def test_getfullargspec_definition_order_preserved_on_kwonly(self):
for fn in signatures_with_lexicographic_keyword_only_parameters():
signature = inspect.getfullargspec(fn)
@@ -2888,6 +2932,39 @@ def test_signature_on_builtins_no_signature(self):
'no signature found for builtin'):
inspect.signature(str)
+ cls = _testcapi.DocStringNoSignatureTest
+ obj = _testcapi.DocStringNoSignatureTest()
+ for builtin, template in [
+ (_testcapi.docstring_no_signature_noargs, meth_noargs),
+ (_testcapi.docstring_no_signature_o, meth_o),
+ (cls.meth_noargs, meth_self_noargs),
+ (cls.meth_o, meth_self_o),
+ (obj.meth_noargs, meth_noargs),
+ (obj.meth_o, meth_o),
+ (cls.meth_noargs_class, meth_noargs),
+ (cls.meth_o_class, meth_o),
+ (cls.meth_noargs_static, meth_noargs),
+ (cls.meth_o_static, meth_o),
+ (cls.meth_noargs_coexist, meth_self_noargs),
+ (cls.meth_o_coexist, meth_self_o),
+
+ (time.time, meth_noargs),
+ (stat.S_IMODE, meth_o),
+ (str.lower, meth_self_noargs),
+ (''.lower, meth_noargs),
+ (set.add, meth_self_o),
+ (set().add, meth_o),
+ (set.__contains__, meth_self_o),
+ (set().__contains__, meth_o),
+ (datetime.datetime.__dict__['utcnow'], meth_type_noargs),
+ (datetime.datetime.utcnow, meth_noargs),
+ (dict.__dict__['__class_getitem__'], meth_type_o),
+ (dict.__class_getitem__, meth_o),
+ ]:
+ with self.subTest(builtin):
+ self.assertEqual(inspect.signature(builtin),
+ inspect.signature(template))
+
def test_signature_on_non_function(self):
with self.assertRaisesRegex(TypeError, 'is not a callable object'):
inspect.signature(42)
diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
index def976fbe96ba3..f26846f9663e5c 100644
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -5433,6 +5433,46 @@ def process(self, msg, kwargs):
self.assertIs(adapter.manager, orig_manager)
self.assertIs(self.logger.manager, orig_manager)
+ def test_extra_in_records(self):
+ self.adapter = logging.LoggerAdapter(logger=self.logger,
+ extra={'foo': '1'})
+
+ self.adapter.critical('foo should be here')
+ self.assertEqual(len(self.recording.records), 1)
+ record = self.recording.records[0]
+ self.assertTrue(hasattr(record, 'foo'))
+ self.assertEqual(record.foo, '1')
+
+ def test_extra_not_merged_by_default(self):
+ self.adapter.critical('foo should NOT be here', extra={'foo': 'nope'})
+ self.assertEqual(len(self.recording.records), 1)
+ record = self.recording.records[0]
+ self.assertFalse(hasattr(record, 'foo'))
+
+ def test_extra_merged(self):
+ self.adapter = logging.LoggerAdapter(logger=self.logger,
+ extra={'foo': '1'},
+ merge_extra=True)
+
+ self.adapter.critical('foo and bar should be here', extra={'bar': '2'})
+ self.assertEqual(len(self.recording.records), 1)
+ record = self.recording.records[0]
+ self.assertTrue(hasattr(record, 'foo'))
+ self.assertTrue(hasattr(record, 'bar'))
+ self.assertEqual(record.foo, '1')
+ self.assertEqual(record.bar, '2')
+
+ def test_extra_merged_log_call_has_precedence(self):
+ self.adapter = logging.LoggerAdapter(logger=self.logger,
+ extra={'foo': '1'},
+ merge_extra=True)
+
+ self.adapter.critical('foo shall be min', extra={'foo': '2'})
+ self.assertEqual(len(self.recording.records), 1)
+ record = self.recording.records[0]
+ self.assertTrue(hasattr(record, 'foo'))
+ self.assertEqual(record.foo, '2')
+
class LoggerTest(BaseTest, AssertErrorMessage):
diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py
index 538d758624c9d6..78e1cb582512b0 100644
--- a/Lib/test/test_ntpath.py
+++ b/Lib/test/test_ntpath.py
@@ -1036,6 +1036,7 @@ def test_path_normcase(self):
self._check_function(self.path.normcase)
if sys.platform == 'win32':
self.assertEqual(ntpath.normcase('\u03a9\u2126'), 'ωΩ')
+ self.assertEqual(ntpath.normcase('abc\x00def'), 'abc\x00def')
def test_path_isabs(self):
self._check_function(self.path.isabs)
diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py
index 564dc4745ae64e..1baa10cbdfdef2 100644
--- a/Lib/test/test_opcache.py
+++ b/Lib/test/test_opcache.py
@@ -1,8 +1,11 @@
+import copy
+import pickle
import dis
import threading
import types
import unittest
from test.support import threading_helper
+import _testinternalcapi
class TestLoadSuperAttrCache(unittest.TestCase):
@@ -865,8 +868,10 @@ class C:
items = []
for _ in range(self.ITEMS):
item = C()
- item.__dict__
item.a = None
+ # Resize into a combined unicode dict:
+ for i in range(29):
+ setattr(item, f"_{i}", None)
items.append(item)
return items
@@ -932,7 +937,9 @@ class C:
items = []
for _ in range(self.ITEMS):
item = C()
- item.__dict__
+ # Resize into a combined unicode dict:
+ for i in range(29):
+ setattr(item, f"_{i}", None)
items.append(item)
return items
@@ -993,6 +1000,124 @@ def write(items):
opname = "UNPACK_SEQUENCE_LIST"
self.assert_races_do_not_crash(opname, get_items, read, write)
+class C:
+ pass
+
+class TestInstanceDict(unittest.TestCase):
+
+ def setUp(self):
+ c = C()
+ c.a, c.b, c.c = 0,0,0
+
+ def test_values_on_instance(self):
+ c = C()
+ c.a = 1
+ C().b = 2
+ c.c = 3
+ self.assertEqual(
+ _testinternalcapi.get_object_dict_values(c),
+ (1, '', 3)
+ )
+
+ def test_dict_materialization(self):
+ c = C()
+ c.a = 1
+ c.b = 2
+ c.__dict__
+ self.assertIs(
+ _testinternalcapi.get_object_dict_values(c),
+ None
+ )
+
+ def test_dict_dematerialization(self):
+ c = C()
+ c.a = 1
+ c.b = 2
+ c.__dict__
+ self.assertIs(
+ _testinternalcapi.get_object_dict_values(c),
+ None
+ )
+ for _ in range(100):
+ c.a
+ self.assertEqual(
+ _testinternalcapi.get_object_dict_values(c),
+ (1, 2, '')
+ )
+
+ def test_dict_dematerialization_multiple_refs(self):
+ c = C()
+ c.a = 1
+ c.b = 2
+ d = c.__dict__
+ for _ in range(100):
+ c.a
+ self.assertIs(
+ _testinternalcapi.get_object_dict_values(c),
+ None
+ )
+ self.assertIs(c.__dict__, d)
+
+ def test_dict_dematerialization_copy(self):
+ c = C()
+ c.a = 1
+ c.b = 2
+ c2 = copy.copy(c)
+ for _ in range(100):
+ c.a
+ c2.a
+ self.assertEqual(
+ _testinternalcapi.get_object_dict_values(c),
+ (1, 2, '')
+ )
+ self.assertEqual(
+ _testinternalcapi.get_object_dict_values(c2),
+ (1, 2, '')
+ )
+ c3 = copy.deepcopy(c)
+ for _ in range(100):
+ c.a
+ c3.a
+ self.assertEqual(
+ _testinternalcapi.get_object_dict_values(c),
+ (1, 2, '')
+ )
+ #NOTE -- c3.__dict__ does not de-materialize
+
+ def test_dict_dematerialization_pickle(self):
+ c = C()
+ c.a = 1
+ c.b = 2
+ c2 = pickle.loads(pickle.dumps(c))
+ for _ in range(100):
+ c.a
+ c2.a
+ self.assertEqual(
+ _testinternalcapi.get_object_dict_values(c),
+ (1, 2, '')
+ )
+ self.assertEqual(
+ _testinternalcapi.get_object_dict_values(c2),
+ (1, 2, '')
+ )
+
+ def test_dict_dematerialization_subclass(self):
+ class D(dict): pass
+ c = C()
+ c.a = 1
+ c.b = 2
+ c.__dict__ = D(c.__dict__)
+ for _ in range(100):
+ c.a
+ self.assertIs(
+ _testinternalcapi.get_object_dict_values(c),
+ None
+ )
+ self.assertEqual(
+ c.__dict__,
+ {'a':1, 'b':2}
+ )
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py
index ddb5187f90da9b..fe4e37d4858c85 100644
--- a/Lib/test/test_pydoc.py
+++ b/Lib/test/test_pydoc.py
@@ -1,3 +1,4 @@
+import datetime
import os
import sys
import contextlib
@@ -12,6 +13,7 @@
import stat
import tempfile
import test.support
+import time
import types
import typing
import unittest
@@ -1180,6 +1182,108 @@ def test_module_level_callable(self):
self.assertEqual(self._get_summary_line(os.stat),
"stat(path, *, dir_fd=None, follow_symlinks=True)")
+ def test_module_level_callable_noargs(self):
+ self.assertEqual(self._get_summary_line(time.time),
+ "time()")
+
+ def test_module_level_callable_o(self):
+ self.assertEqual(self._get_summary_line(stat.S_IMODE),
+ "S_IMODE(object, /)")
+
+ def test_unbound_builtin_method_noargs(self):
+ self.assertEqual(self._get_summary_line(str.lower),
+ "lower(self, /)")
+
+ def test_bound_builtin_method_noargs(self):
+ self.assertEqual(self._get_summary_line(''.lower),
+ "lower() method of builtins.str instance")
+
+ def test_unbound_builtin_method_o(self):
+ self.assertEqual(self._get_summary_line(set.add),
+ "add(self, object, /)")
+
+ def test_bound_builtin_method_o(self):
+ self.assertEqual(self._get_summary_line(set().add),
+ "add(object, /) method of builtins.set instance")
+
+ def test_unbound_builtin_method_coexist_o(self):
+ self.assertEqual(self._get_summary_line(set.__contains__),
+ "__contains__(self, object, /)")
+
+ def test_bound_builtin_method_coexist_o(self):
+ self.assertEqual(self._get_summary_line(set().__contains__),
+ "__contains__(object, /) method of builtins.set instance")
+
+ def test_unbound_builtin_classmethod_noargs(self):
+ self.assertEqual(self._get_summary_line(datetime.datetime.__dict__['utcnow']),
+ "utcnow(type, /)")
+
+ def test_bound_builtin_classmethod_noargs(self):
+ self.assertEqual(self._get_summary_line(datetime.datetime.utcnow),
+ "utcnow() method of builtins.type instance")
+
+ def test_unbound_builtin_classmethod_o(self):
+ self.assertEqual(self._get_summary_line(dict.__dict__['__class_getitem__']),
+ "__class_getitem__(type, object, /)")
+
+ def test_bound_builtin_classmethod_o(self):
+ self.assertEqual(self._get_summary_line(dict.__class_getitem__),
+ "__class_getitem__(object, /) method of builtins.type instance")
+
+ def test_module_level_callable_unrepresentable_default(self):
+ self.assertEqual(self._get_summary_line(getattr),
+ "getattr(object, name, default=, /)")
+
+ def test_builtin_staticmethod_unrepresentable_default(self):
+ self.assertEqual(self._get_summary_line(str.maketrans),
+ "maketrans(x, y=, z=, /)")
+
+ def test_unbound_builtin_method_unrepresentable_default(self):
+ self.assertEqual(self._get_summary_line(dict.pop),
+ "pop(self, key, default=, /)")
+
+ def test_bound_builtin_method_unrepresentable_default(self):
+ self.assertEqual(self._get_summary_line({}.pop),
+ "pop(key, default=, /) "
+ "method of builtins.dict instance")
+
+ def test_overridden_text_signature(self):
+ class C:
+ def meth(*args, **kwargs):
+ pass
+ @classmethod
+ def cmeth(*args, **kwargs):
+ pass
+ @staticmethod
+ def smeth(*args, **kwargs):
+ pass
+ for text_signature, unbound, bound in [
+ ("($slf)", "(slf, /)", "()"),
+ ("($slf, /)", "(slf, /)", "()"),
+ ("($slf, /, arg)", "(slf, /, arg)", "(arg)"),
+ ("($slf, /, arg=)", "(slf, /, arg=)", "(arg=)"),
+ ("($slf, arg, /)", "(slf, arg, /)", "(arg, /)"),
+ ("($slf, arg=, /)", "(slf, arg=, /)", "(arg=, /)"),
+ ("(/, slf, arg)", "(/, slf, arg)", "(/, slf, arg)"),
+ ("(/, slf, arg=)", "(/, slf, arg=)", "(/, slf, arg=)"),
+ ("(slf, /, arg)", "(slf, /, arg)", "(arg)"),
+ ("(slf, /, arg=)", "(slf, /, arg=)", "(arg=)"),
+ ("(slf, arg, /)", "(slf, arg, /)", "(arg, /)"),
+ ("(slf, arg=, /)", "(slf, arg=, /)", "(arg=, /)"),
+ ]:
+ with self.subTest(text_signature):
+ C.meth.__text_signature__ = text_signature
+ self.assertEqual(self._get_summary_line(C.meth),
+ "meth" + unbound)
+ self.assertEqual(self._get_summary_line(C().meth),
+ "meth" + bound + " method of test.test_pydoc.C instance")
+ C.cmeth.__func__.__text_signature__ = text_signature
+ self.assertEqual(self._get_summary_line(C.cmeth),
+ "cmeth" + bound + " method of builtins.type instance")
+ C.smeth.__text_signature__ = text_signature
+ self.assertEqual(self._get_summary_line(C.smeth),
+ "smeth" + unbound)
+
@requires_docstrings
def test_staticmethod(self):
class X:
diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py
index bf3698ac78a880..45bce1925f9e89 100644
--- a/Lib/test/test_re.py
+++ b/Lib/test/test_re.py
@@ -127,8 +127,10 @@ def test_basic_re_sub(self):
self.assertEqual(re.sub("(?i)b+", "x", "bbbb BBBB"), 'x x')
self.assertEqual(re.sub(r'\d+', self.bump_num, '08.2 -2 23x99y'),
'9.3 -3 24x100y')
- self.assertEqual(re.sub(r'\d+', self.bump_num, '08.2 -2 23x99y', 3),
- '9.3 -3 23x99y')
+ with self.assertWarns(DeprecationWarning) as w:
+ self.assertEqual(re.sub(r'\d+', self.bump_num, '08.2 -2 23x99y', 3),
+ '9.3 -3 23x99y')
+ self.assertEqual(w.filename, __file__)
self.assertEqual(re.sub(r'\d+', self.bump_num, '08.2 -2 23x99y', count=3),
'9.3 -3 23x99y')
@@ -235,9 +237,42 @@ def test_sub_template_numeric_escape(self):
def test_qualified_re_sub(self):
self.assertEqual(re.sub('a', 'b', 'aaaaa'), 'bbbbb')
- self.assertEqual(re.sub('a', 'b', 'aaaaa', 1), 'baaaa')
+ with self.assertWarns(DeprecationWarning) as w:
+ self.assertEqual(re.sub('a', 'b', 'aaaaa', 1), 'baaaa')
+ self.assertEqual(w.filename, __file__)
self.assertEqual(re.sub('a', 'b', 'aaaaa', count=1), 'baaaa')
+ with self.assertRaisesRegex(TypeError,
+ r"sub\(\) got multiple values for argument 'count'"):
+ re.sub('a', 'b', 'aaaaa', 1, count=1)
+ with self.assertRaisesRegex(TypeError,
+ r"sub\(\) got multiple values for argument 'flags'"):
+ re.sub('a', 'b', 'aaaaa', 1, 0, flags=0)
+ with self.assertRaisesRegex(TypeError,
+ r"sub\(\) takes from 3 to 5 positional arguments but 6 "
+ r"were given"):
+ re.sub('a', 'b', 'aaaaa', 1, 0, 0)
+
+ def test_misuse_flags(self):
+ with self.assertWarns(DeprecationWarning) as w:
+ result = re.sub('a', 'b', 'aaaaa', re.I)
+ self.assertEqual(result, re.sub('a', 'b', 'aaaaa', count=int(re.I)))
+ self.assertEqual(str(w.warning),
+ "'count' is passed as positional argument")
+ self.assertEqual(w.filename, __file__)
+ with self.assertWarns(DeprecationWarning) as w:
+ result = re.subn("b*", "x", "xyz", re.I)
+ self.assertEqual(result, re.subn("b*", "x", "xyz", count=int(re.I)))
+ self.assertEqual(str(w.warning),
+ "'count' is passed as positional argument")
+ self.assertEqual(w.filename, __file__)
+ with self.assertWarns(DeprecationWarning) as w:
+ result = re.split(":", ":a:b::c", re.I)
+ self.assertEqual(result, re.split(":", ":a:b::c", maxsplit=int(re.I)))
+ self.assertEqual(str(w.warning),
+ "'maxsplit' is passed as positional argument")
+ self.assertEqual(w.filename, __file__)
+
def test_bug_114660(self):
self.assertEqual(re.sub(r'(\S)\s+(\S)', r'\1 \2', 'hello there'),
'hello there')
@@ -344,9 +379,22 @@ def test_re_subn(self):
self.assertEqual(re.subn("b+", "x", "bbbb BBBB"), ('x BBBB', 1))
self.assertEqual(re.subn("b+", "x", "xyz"), ('xyz', 0))
self.assertEqual(re.subn("b*", "x", "xyz"), ('xxxyxzx', 4))
- self.assertEqual(re.subn("b*", "x", "xyz", 2), ('xxxyz', 2))
+ with self.assertWarns(DeprecationWarning) as w:
+ self.assertEqual(re.subn("b*", "x", "xyz", 2), ('xxxyz', 2))
+ self.assertEqual(w.filename, __file__)
self.assertEqual(re.subn("b*", "x", "xyz", count=2), ('xxxyz', 2))
+ with self.assertRaisesRegex(TypeError,
+ r"subn\(\) got multiple values for argument 'count'"):
+ re.subn('a', 'b', 'aaaaa', 1, count=1)
+ with self.assertRaisesRegex(TypeError,
+ r"subn\(\) got multiple values for argument 'flags'"):
+ re.subn('a', 'b', 'aaaaa', 1, 0, flags=0)
+ with self.assertRaisesRegex(TypeError,
+ r"subn\(\) takes from 3 to 5 positional arguments but 6 "
+ r"were given"):
+ re.subn('a', 'b', 'aaaaa', 1, 0, 0)
+
def test_re_split(self):
for string in ":a:b::c", S(":a:b::c"):
self.assertTypedEqual(re.split(":", string),
@@ -401,7 +449,9 @@ def test_re_split(self):
self.assertTypedEqual(re.split(sep, ':a:b::c'), expected)
def test_qualified_re_split(self):
- self.assertEqual(re.split(":", ":a:b::c", 2), ['', 'a', 'b::c'])
+ with self.assertWarns(DeprecationWarning) as w:
+ self.assertEqual(re.split(":", ":a:b::c", 2), ['', 'a', 'b::c'])
+ self.assertEqual(w.filename, __file__)
self.assertEqual(re.split(":", ":a:b::c", maxsplit=2), ['', 'a', 'b::c'])
self.assertEqual(re.split(':', 'a:b:c:d', maxsplit=2), ['a', 'b', 'c:d'])
self.assertEqual(re.split("(:)", ":a:b::c", maxsplit=2),
@@ -411,6 +461,17 @@ def test_qualified_re_split(self):
self.assertEqual(re.split("(:*)", ":a:b::c", maxsplit=2),
['', ':', '', '', 'a:b::c'])
+ with self.assertRaisesRegex(TypeError,
+ r"split\(\) got multiple values for argument 'maxsplit'"):
+ re.split(":", ":a:b::c", 2, maxsplit=2)
+ with self.assertRaisesRegex(TypeError,
+ r"split\(\) got multiple values for argument 'flags'"):
+ re.split(":", ":a:b::c", 2, 0, flags=0)
+ with self.assertRaisesRegex(TypeError,
+ r"split\(\) takes from 2 to 4 positional arguments but 5 "
+ r"were given"):
+ re.split(":", ":a:b::c", 2, 0, 0)
+
def test_re_findall(self):
self.assertEqual(re.findall(":+", "abc"), [])
for string in "a:b::c:::d", S("a:b::c:::d"):
@@ -2342,7 +2403,17 @@ def test_bug_gh91616(self):
self.assertTrue(re.fullmatch(r'(?s:(?>.*?\.).*)\Z', "a.txt")) # reproducer
self.assertTrue(re.fullmatch(r'(?s:(?=(?P.*?\.))(?P=g0).*)\Z', "a.txt"))
- def test_bug_gh106052(self):
+ def test_bug_gh100061(self):
+ # gh-100061
+ self.assertEqual(re.match('(?>(?:.(?!D))+)', 'ABCDE').span(), (0, 2))
+ self.assertEqual(re.match('(?:.(?!D))++', 'ABCDE').span(), (0, 2))
+ self.assertEqual(re.match('(?>(?:.(?!D))*)', 'ABCDE').span(), (0, 2))
+ self.assertEqual(re.match('(?:.(?!D))*+', 'ABCDE').span(), (0, 2))
+ self.assertEqual(re.match('(?>(?:.(?!D))?)', 'CDE').span(), (0, 0))
+ self.assertEqual(re.match('(?:.(?!D))?+', 'CDE').span(), (0, 0))
+ self.assertEqual(re.match('(?>(?:.(?!D)){1,3})', 'ABCDE').span(), (0, 2))
+ self.assertEqual(re.match('(?:.(?!D)){1,3}+', 'ABCDE').span(), (0, 2))
+ # gh-106052
self.assertEqual(re.match("(?>(?:ab?c)+)", "aca").span(), (0, 2))
self.assertEqual(re.match("(?:ab?c)++", "aca").span(), (0, 2))
self.assertEqual(re.match("(?>(?:ab?c)*)", "aca").span(), (0, 2))
@@ -2451,7 +2522,6 @@ def test_atomic_group(self):
17: SUCCESS
''')
- @unittest.expectedFailure # gh-106052
def test_possesive_repeat_one(self):
self.assertEqual(get_debug_out(r'a?+'), '''\
POSSESSIVE_REPEAT 0 1
@@ -2464,7 +2534,6 @@ def test_possesive_repeat_one(self):
12: SUCCESS
''')
- @unittest.expectedFailure # gh-106052
def test_possesive_repeat(self):
self.assertEqual(get_debug_out(r'(?:ab)?+'), '''\
POSSESSIVE_REPEAT 0 1
diff --git a/Lib/test/test_reprlib.py b/Lib/test/test_reprlib.py
index e7216d427200c1..502287b620d066 100644
--- a/Lib/test/test_reprlib.py
+++ b/Lib/test/test_reprlib.py
@@ -765,5 +765,14 @@ def test_assigned_attributes(self):
for name in assigned:
self.assertIs(getattr(wrapper, name), getattr(wrapped, name))
+ def test__wrapped__(self):
+ class X:
+ def __repr__(self):
+ return 'X()'
+ f = __repr__ # save reference to check it later
+ __repr__ = recursive_repr()(__repr__)
+
+ self.assertIs(X.f, X.__repr__.__wrapped__)
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_rlcompleter.py b/Lib/test/test_rlcompleter.py
index 6b5fc9a0247f4b..7347fca71be2fe 100644
--- a/Lib/test/test_rlcompleter.py
+++ b/Lib/test/test_rlcompleter.py
@@ -53,7 +53,10 @@ def test_attr_matches(self):
['str.{}('.format(x) for x in dir(str)
if x.startswith('s')])
self.assertEqual(self.stdcompleter.attr_matches('tuple.foospamegg'), [])
- expected = sorted({'None.%s%s' % (x, '(' if x != '__doc__' else '')
+ expected = sorted({'None.%s%s' % (x,
+ '()' if x == '__init_subclass__'
+ else '' if x == '__doc__'
+ else '(')
for x in dir(None)})
self.assertEqual(self.stdcompleter.attr_matches('None.'), expected)
self.assertEqual(self.stdcompleter.attr_matches('None._'), expected)
diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py
index 93f20a6ff41332..a2ca4df135846f 100644
--- a/Lib/test/test_shutil.py
+++ b/Lib/test/test_shutil.py
@@ -1839,6 +1839,49 @@ def test_register_archive_format(self):
formats = [name for name, params in get_archive_formats()]
self.assertNotIn('xxx', formats)
+ def test_make_tarfile_rootdir_nodir(self):
+ # GH-99203
+ self.addCleanup(os_helper.unlink, f'{TESTFN}.tar')
+ for dry_run in (False, True):
+ with self.subTest(dry_run=dry_run):
+ tmp_dir = self.mkdtemp()
+ nonexisting_file = os.path.join(tmp_dir, 'nonexisting')
+ with self.assertRaises(FileNotFoundError) as cm:
+ make_archive(TESTFN, 'tar', nonexisting_file, dry_run=dry_run)
+ self.assertEqual(cm.exception.errno, errno.ENOENT)
+ self.assertEqual(cm.exception.filename, nonexisting_file)
+ self.assertFalse(os.path.exists(f'{TESTFN}.tar'))
+
+ tmp_fd, tmp_file = tempfile.mkstemp(dir=tmp_dir)
+ os.close(tmp_fd)
+ with self.assertRaises(NotADirectoryError) as cm:
+ make_archive(TESTFN, 'tar', tmp_file, dry_run=dry_run)
+ self.assertEqual(cm.exception.errno, errno.ENOTDIR)
+ self.assertEqual(cm.exception.filename, tmp_file)
+ self.assertFalse(os.path.exists(f'{TESTFN}.tar'))
+
+ @support.requires_zlib()
+ def test_make_zipfile_rootdir_nodir(self):
+ # GH-99203
+ self.addCleanup(os_helper.unlink, f'{TESTFN}.zip')
+ for dry_run in (False, True):
+ with self.subTest(dry_run=dry_run):
+ tmp_dir = self.mkdtemp()
+ nonexisting_file = os.path.join(tmp_dir, 'nonexisting')
+ with self.assertRaises(FileNotFoundError) as cm:
+ make_archive(TESTFN, 'zip', nonexisting_file, dry_run=dry_run)
+ self.assertEqual(cm.exception.errno, errno.ENOENT)
+ self.assertEqual(cm.exception.filename, nonexisting_file)
+ self.assertFalse(os.path.exists(f'{TESTFN}.zip'))
+
+ tmp_fd, tmp_file = tempfile.mkstemp(dir=tmp_dir)
+ os.close(tmp_fd)
+ with self.assertRaises(NotADirectoryError) as cm:
+ make_archive(TESTFN, 'zip', tmp_file, dry_run=dry_run)
+ self.assertEqual(cm.exception.errno, errno.ENOTDIR)
+ self.assertEqual(cm.exception.filename, tmp_file)
+ self.assertFalse(os.path.exists(f'{TESTFN}.zip'))
+
### shutil.unpack_archive
def check_unpack_archive(self, format, **kwargs):
diff --git a/Lib/test/test_sqlite3/test_backup.py b/Lib/test/test_sqlite3/test_backup.py
index 87ab29c54d65e2..4584d976bce0c6 100644
--- a/Lib/test/test_sqlite3/test_backup.py
+++ b/Lib/test/test_sqlite3/test_backup.py
@@ -1,6 +1,8 @@
import sqlite3 as sqlite
import unittest
+from .util import memory_database
+
class BackupTests(unittest.TestCase):
def setUp(self):
@@ -32,32 +34,32 @@ def test_bad_target_same_connection(self):
self.cx.backup(self.cx)
def test_bad_target_closed_connection(self):
- bck = sqlite.connect(':memory:')
- bck.close()
- with self.assertRaises(sqlite.ProgrammingError):
- self.cx.backup(bck)
+ with memory_database() as bck:
+ bck.close()
+ with self.assertRaises(sqlite.ProgrammingError):
+ self.cx.backup(bck)
def test_bad_source_closed_connection(self):
- bck = sqlite.connect(':memory:')
- source = sqlite.connect(":memory:")
- source.close()
- with self.assertRaises(sqlite.ProgrammingError):
- source.backup(bck)
+ with memory_database() as bck:
+ source = sqlite.connect(":memory:")
+ source.close()
+ with self.assertRaises(sqlite.ProgrammingError):
+ source.backup(bck)
def test_bad_target_in_transaction(self):
- bck = sqlite.connect(':memory:')
- bck.execute('CREATE TABLE bar (key INTEGER)')
- bck.executemany('INSERT INTO bar (key) VALUES (?)', [(3,), (4,)])
- with self.assertRaises(sqlite.OperationalError) as cm:
- self.cx.backup(bck)
+ with memory_database() as bck:
+ bck.execute('CREATE TABLE bar (key INTEGER)')
+ bck.executemany('INSERT INTO bar (key) VALUES (?)', [(3,), (4,)])
+ with self.assertRaises(sqlite.OperationalError) as cm:
+ self.cx.backup(bck)
def test_keyword_only_args(self):
with self.assertRaises(TypeError):
- with sqlite.connect(':memory:') as bck:
+ with memory_database() as bck:
self.cx.backup(bck, 1)
def test_simple(self):
- with sqlite.connect(':memory:') as bck:
+ with memory_database() as bck:
self.cx.backup(bck)
self.verify_backup(bck)
@@ -67,7 +69,7 @@ def test_progress(self):
def progress(status, remaining, total):
journal.append(status)
- with sqlite.connect(':memory:') as bck:
+ with memory_database() as bck:
self.cx.backup(bck, pages=1, progress=progress)
self.verify_backup(bck)
@@ -81,7 +83,7 @@ def test_progress_all_pages_at_once_1(self):
def progress(status, remaining, total):
journal.append(remaining)
- with sqlite.connect(':memory:') as bck:
+ with memory_database() as bck:
self.cx.backup(bck, progress=progress)
self.verify_backup(bck)
@@ -94,7 +96,7 @@ def test_progress_all_pages_at_once_2(self):
def progress(status, remaining, total):
journal.append(remaining)
- with sqlite.connect(':memory:') as bck:
+ with memory_database() as bck:
self.cx.backup(bck, pages=-1, progress=progress)
self.verify_backup(bck)
@@ -103,7 +105,7 @@ def progress(status, remaining, total):
def test_non_callable_progress(self):
with self.assertRaises(TypeError) as cm:
- with sqlite.connect(':memory:') as bck:
+ with memory_database() as bck:
self.cx.backup(bck, pages=1, progress='bar')
self.assertEqual(str(cm.exception), 'progress argument must be a callable')
@@ -116,7 +118,7 @@ def progress(status, remaining, total):
self.cx.commit()
journal.append(remaining)
- with sqlite.connect(':memory:') as bck:
+ with memory_database() as bck:
self.cx.backup(bck, pages=1, progress=progress)
self.verify_backup(bck)
@@ -140,12 +142,12 @@ def progress(status, remaining, total):
self.assertEqual(str(err.exception), 'nearly out of space')
def test_database_source_name(self):
- with sqlite.connect(':memory:') as bck:
+ with memory_database() as bck:
self.cx.backup(bck, name='main')
- with sqlite.connect(':memory:') as bck:
+ with memory_database() as bck:
self.cx.backup(bck, name='temp')
with self.assertRaises(sqlite.OperationalError) as cm:
- with sqlite.connect(':memory:') as bck:
+ with memory_database() as bck:
self.cx.backup(bck, name='non-existing')
self.assertIn("unknown database", str(cm.exception))
@@ -153,7 +155,7 @@ def test_database_source_name(self):
self.cx.execute('CREATE TABLE attached_db.foo (key INTEGER)')
self.cx.executemany('INSERT INTO attached_db.foo (key) VALUES (?)', [(3,), (4,)])
self.cx.commit()
- with sqlite.connect(':memory:') as bck:
+ with memory_database() as bck:
self.cx.backup(bck, name='attached_db')
self.verify_backup(bck)
diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py
index 3f9bd0248a8b96..df3c2ea8d1dbda 100644
--- a/Lib/test/test_sqlite3/test_dbapi.py
+++ b/Lib/test/test_sqlite3/test_dbapi.py
@@ -33,26 +33,13 @@
SHORT_TIMEOUT, check_disallow_instantiation, requires_subprocess,
is_emscripten, is_wasi
)
+from test.support import gc_collect
from test.support import threading_helper
from _testcapi import INT_MAX, ULLONG_MAX
from os import SEEK_SET, SEEK_CUR, SEEK_END
from test.support.os_helper import TESTFN, TESTFN_UNDECODABLE, unlink, temp_dir, FakePath
-
-# Helper for temporary memory databases
-def memory_database(*args, **kwargs):
- cx = sqlite.connect(":memory:", *args, **kwargs)
- return contextlib.closing(cx)
-
-
-# Temporarily limit a database connection parameter
-@contextlib.contextmanager
-def cx_limit(cx, category=sqlite.SQLITE_LIMIT_SQL_LENGTH, limit=128):
- try:
- _prev = cx.setlimit(category, limit)
- yield limit
- finally:
- cx.setlimit(category, _prev)
+from .util import memory_database, cx_limit
class ModuleTests(unittest.TestCase):
@@ -326,9 +313,9 @@ def test_extended_error_code_on_exception(self):
self.assertEqual(exc.sqlite_errorname, "SQLITE_CONSTRAINT_CHECK")
def test_disallow_instantiation(self):
- cx = sqlite.connect(":memory:")
- check_disallow_instantiation(self, type(cx("select 1")))
- check_disallow_instantiation(self, sqlite.Blob)
+ with memory_database() as cx:
+ check_disallow_instantiation(self, type(cx("select 1")))
+ check_disallow_instantiation(self, sqlite.Blob)
def test_complete_statement(self):
self.assertFalse(sqlite.complete_statement("select t"))
@@ -342,6 +329,7 @@ def setUp(self):
cu = self.cx.cursor()
cu.execute("create table test(id integer primary key, name text)")
cu.execute("insert into test(name) values (?)", ("foo",))
+ cu.close()
def tearDown(self):
self.cx.close()
@@ -412,21 +400,22 @@ def test_exceptions(self):
def test_in_transaction(self):
# Can't use db from setUp because we want to test initial state.
- cx = sqlite.connect(":memory:")
- cu = cx.cursor()
- self.assertEqual(cx.in_transaction, False)
- cu.execute("create table transactiontest(id integer primary key, name text)")
- self.assertEqual(cx.in_transaction, False)
- cu.execute("insert into transactiontest(name) values (?)", ("foo",))
- self.assertEqual(cx.in_transaction, True)
- cu.execute("select name from transactiontest where name=?", ["foo"])
- row = cu.fetchone()
- self.assertEqual(cx.in_transaction, True)
- cx.commit()
- self.assertEqual(cx.in_transaction, False)
- cu.execute("select name from transactiontest where name=?", ["foo"])
- row = cu.fetchone()
- self.assertEqual(cx.in_transaction, False)
+ with memory_database() as cx:
+ cu = cx.cursor()
+ self.assertEqual(cx.in_transaction, False)
+ cu.execute("create table transactiontest(id integer primary key, name text)")
+ self.assertEqual(cx.in_transaction, False)
+ cu.execute("insert into transactiontest(name) values (?)", ("foo",))
+ self.assertEqual(cx.in_transaction, True)
+ cu.execute("select name from transactiontest where name=?", ["foo"])
+ row = cu.fetchone()
+ self.assertEqual(cx.in_transaction, True)
+ cx.commit()
+ self.assertEqual(cx.in_transaction, False)
+ cu.execute("select name from transactiontest where name=?", ["foo"])
+ row = cu.fetchone()
+ self.assertEqual(cx.in_transaction, False)
+ cu.close()
def test_in_transaction_ro(self):
with self.assertRaises(AttributeError):
@@ -450,10 +439,9 @@ def test_connection_exceptions(self):
self.assertIs(getattr(sqlite, exc), getattr(self.cx, exc))
def test_interrupt_on_closed_db(self):
- cx = sqlite.connect(":memory:")
- cx.close()
+ self.cx.close()
with self.assertRaises(sqlite.ProgrammingError):
- cx.interrupt()
+ self.cx.interrupt()
def test_interrupt(self):
self.assertIsNone(self.cx.interrupt())
@@ -521,29 +509,29 @@ def test_connection_init_good_isolation_levels(self):
self.assertEqual(cx.isolation_level, level)
def test_connection_reinit(self):
- db = ":memory:"
- cx = sqlite.connect(db)
- cx.text_factory = bytes
- cx.row_factory = sqlite.Row
- cu = cx.cursor()
- cu.execute("create table foo (bar)")
- cu.executemany("insert into foo (bar) values (?)",
- ((str(v),) for v in range(4)))
- cu.execute("select bar from foo")
-
- rows = [r for r in cu.fetchmany(2)]
- self.assertTrue(all(isinstance(r, sqlite.Row) for r in rows))
- self.assertEqual([r[0] for r in rows], [b"0", b"1"])
-
- cx.__init__(db)
- cx.execute("create table foo (bar)")
- cx.executemany("insert into foo (bar) values (?)",
- ((v,) for v in ("a", "b", "c", "d")))
-
- # This uses the old database, old row factory, but new text factory
- rows = [r for r in cu.fetchall()]
- self.assertTrue(all(isinstance(r, sqlite.Row) for r in rows))
- self.assertEqual([r[0] for r in rows], ["2", "3"])
+ with memory_database() as cx:
+ cx.text_factory = bytes
+ cx.row_factory = sqlite.Row
+ cu = cx.cursor()
+ cu.execute("create table foo (bar)")
+ cu.executemany("insert into foo (bar) values (?)",
+ ((str(v),) for v in range(4)))
+ cu.execute("select bar from foo")
+
+ rows = [r for r in cu.fetchmany(2)]
+ self.assertTrue(all(isinstance(r, sqlite.Row) for r in rows))
+ self.assertEqual([r[0] for r in rows], [b"0", b"1"])
+
+ cx.__init__(":memory:")
+ cx.execute("create table foo (bar)")
+ cx.executemany("insert into foo (bar) values (?)",
+ ((v,) for v in ("a", "b", "c", "d")))
+
+ # This uses the old database, old row factory, but new text factory
+ rows = [r for r in cu.fetchall()]
+ self.assertTrue(all(isinstance(r, sqlite.Row) for r in rows))
+ self.assertEqual([r[0] for r in rows], ["2", "3"])
+ cu.close()
def test_connection_bad_reinit(self):
cx = sqlite.connect(":memory:")
@@ -582,6 +570,19 @@ def test_connection_config(self):
with self.assertRaisesRegex(sqlite.IntegrityError, "constraint"):
cx.execute("insert into u values(0)")
+ def test_connect_positional_arguments(self):
+ regex = (
+ r"Passing more than 1 positional argument to sqlite3.connect\(\)"
+ " is deprecated. Parameters 'timeout', 'detect_types', "
+ "'isolation_level', 'check_same_thread', 'factory', "
+ "'cached_statements' and 'uri' will become keyword-only "
+ "parameters in Python 3.15."
+ )
+ with self.assertWarnsRegex(DeprecationWarning, regex) as cm:
+ cx = sqlite.connect(":memory:", 1.0)
+ cx.close()
+ self.assertEqual(cm.filename, __file__)
+
class UninitialisedConnectionTests(unittest.TestCase):
def setUp(self):
@@ -1558,12 +1559,12 @@ def run(con, err):
except sqlite.Error:
err.append("multi-threading not allowed")
- con = sqlite.connect(":memory:", check_same_thread=False)
- err = []
- t = threading.Thread(target=run, kwargs={"con": con, "err": err})
- t.start()
- t.join()
- self.assertEqual(len(err), 0, "\n".join(err))
+ with memory_database(check_same_thread=False) as con:
+ err = []
+ t = threading.Thread(target=run, kwargs={"con": con, "err": err})
+ t.start()
+ t.join()
+ self.assertEqual(len(err), 0, "\n".join(err))
class ConstructorTests(unittest.TestCase):
@@ -1589,9 +1590,16 @@ def test_binary(self):
b = sqlite.Binary(b"\0'")
class ExtensionTests(unittest.TestCase):
+ def setUp(self):
+ self.con = sqlite.connect(":memory:")
+ self.cur = self.con.cursor()
+
+ def tearDown(self):
+ self.cur.close()
+ self.con.close()
+
def test_script_string_sql(self):
- con = sqlite.connect(":memory:")
- cur = con.cursor()
+ cur = self.cur
cur.executescript("""
-- bla bla
/* a stupid comment */
@@ -1603,40 +1611,40 @@ def test_script_string_sql(self):
self.assertEqual(res, 5)
def test_script_syntax_error(self):
- con = sqlite.connect(":memory:")
- cur = con.cursor()
with self.assertRaises(sqlite.OperationalError):
- cur.executescript("create table test(x); asdf; create table test2(x)")
+ self.cur.executescript("""
+ CREATE TABLE test(x);
+ asdf;
+ CREATE TABLE test2(x)
+ """)
def test_script_error_normal(self):
- con = sqlite.connect(":memory:")
- cur = con.cursor()
with self.assertRaises(sqlite.OperationalError):
- cur.executescript("create table test(sadfsadfdsa); select foo from hurz;")
+ self.cur.executescript("""
+ CREATE TABLE test(sadfsadfdsa);
+ SELECT foo FROM hurz;
+ """)
def test_cursor_executescript_as_bytes(self):
- con = sqlite.connect(":memory:")
- cur = con.cursor()
with self.assertRaises(TypeError):
- cur.executescript(b"create table test(foo); insert into test(foo) values (5);")
+ self.cur.executescript(b"""
+ CREATE TABLE test(foo);
+ INSERT INTO test(foo) VALUES (5);
+ """)
def test_cursor_executescript_with_null_characters(self):
- con = sqlite.connect(":memory:")
- cur = con.cursor()
with self.assertRaises(ValueError):
- cur.executescript("""
- create table a(i);\0
- insert into a(i) values (5);
- """)
+ self.cur.executescript("""
+ CREATE TABLE a(i);\0
+ INSERT INTO a(i) VALUES (5);
+ """)
def test_cursor_executescript_with_surrogates(self):
- con = sqlite.connect(":memory:")
- cur = con.cursor()
with self.assertRaises(UnicodeEncodeError):
- cur.executescript("""
- create table a(s);
- insert into a(s) values ('\ud8ff');
- """)
+ self.cur.executescript("""
+ CREATE TABLE a(s);
+ INSERT INTO a(s) VALUES ('\ud8ff');
+ """)
def test_cursor_executescript_too_large_script(self):
msg = "query string is too large"
@@ -1646,19 +1654,18 @@ def test_cursor_executescript_too_large_script(self):
cx.executescript("select 'too large'".ljust(lim+1))
def test_cursor_executescript_tx_control(self):
- con = sqlite.connect(":memory:")
+ con = self.con
con.execute("begin")
self.assertTrue(con.in_transaction)
con.executescript("select 1")
self.assertFalse(con.in_transaction)
def test_connection_execute(self):
- con = sqlite.connect(":memory:")
- result = con.execute("select 5").fetchone()[0]
+ result = self.con.execute("select 5").fetchone()[0]
self.assertEqual(result, 5, "Basic test of Connection.execute")
def test_connection_executemany(self):
- con = sqlite.connect(":memory:")
+ con = self.con
con.execute("create table test(foo)")
con.executemany("insert into test(foo) values (?)", [(3,), (4,)])
result = con.execute("select foo from test order by foo").fetchall()
@@ -1666,47 +1673,44 @@ def test_connection_executemany(self):
self.assertEqual(result[1][0], 4, "Basic test of Connection.executemany")
def test_connection_executescript(self):
- con = sqlite.connect(":memory:")
- con.executescript("create table test(foo); insert into test(foo) values (5);")
+ con = self.con
+ con.executescript("""
+ CREATE TABLE test(foo);
+ INSERT INTO test(foo) VALUES (5);
+ """)
result = con.execute("select foo from test").fetchone()[0]
self.assertEqual(result, 5, "Basic test of Connection.executescript")
+
class ClosedConTests(unittest.TestCase):
+ def check(self, fn, *args, **kwds):
+ regex = "Cannot operate on a closed database."
+ with self.assertRaisesRegex(sqlite.ProgrammingError, regex):
+ fn(*args, **kwds)
+
+ def setUp(self):
+ self.con = sqlite.connect(":memory:")
+ self.cur = self.con.cursor()
+ self.con.close()
+
def test_closed_con_cursor(self):
- con = sqlite.connect(":memory:")
- con.close()
- with self.assertRaises(sqlite.ProgrammingError):
- cur = con.cursor()
+ self.check(self.con.cursor)
def test_closed_con_commit(self):
- con = sqlite.connect(":memory:")
- con.close()
- with self.assertRaises(sqlite.ProgrammingError):
- con.commit()
+ self.check(self.con.commit)
def test_closed_con_rollback(self):
- con = sqlite.connect(":memory:")
- con.close()
- with self.assertRaises(sqlite.ProgrammingError):
- con.rollback()
+ self.check(self.con.rollback)
def test_closed_cur_execute(self):
- con = sqlite.connect(":memory:")
- cur = con.cursor()
- con.close()
- with self.assertRaises(sqlite.ProgrammingError):
- cur.execute("select 4")
+ self.check(self.cur.execute, "select 4")
def test_closed_create_function(self):
- con = sqlite.connect(":memory:")
- con.close()
- def f(x): return 17
- with self.assertRaises(sqlite.ProgrammingError):
- con.create_function("foo", 1, f)
+ def f(x):
+ return 17
+ self.check(self.con.create_function, "foo", 1, f)
def test_closed_create_aggregate(self):
- con = sqlite.connect(":memory:")
- con.close()
class Agg:
def __init__(self):
pass
@@ -1714,29 +1718,21 @@ def step(self, x):
pass
def finalize(self):
return 17
- with self.assertRaises(sqlite.ProgrammingError):
- con.create_aggregate("foo", 1, Agg)
+ self.check(self.con.create_aggregate, "foo", 1, Agg)
def test_closed_set_authorizer(self):
- con = sqlite.connect(":memory:")
- con.close()
def authorizer(*args):
return sqlite.DENY
- with self.assertRaises(sqlite.ProgrammingError):
- con.set_authorizer(authorizer)
+ self.check(self.con.set_authorizer, authorizer)
def test_closed_set_progress_callback(self):
- con = sqlite.connect(":memory:")
- con.close()
- def progress(): pass
- with self.assertRaises(sqlite.ProgrammingError):
- con.set_progress_handler(progress, 100)
+ def progress():
+ pass
+ self.check(self.con.set_progress_handler, progress, 100)
def test_closed_call(self):
- con = sqlite.connect(":memory:")
- con.close()
- with self.assertRaises(sqlite.ProgrammingError):
- con()
+ self.check(self.con)
+
class ClosedCurTests(unittest.TestCase):
def test_closed(self):
diff --git a/Lib/test/test_sqlite3/test_dump.py b/Lib/test/test_sqlite3/test_dump.py
index d0c24b9c60e613..5f6811fb5cc0a5 100644
--- a/Lib/test/test_sqlite3/test_dump.py
+++ b/Lib/test/test_sqlite3/test_dump.py
@@ -2,16 +2,12 @@
import unittest
import sqlite3 as sqlite
-from .test_dbapi import memory_database
+from .util import memory_database
+from .util import MemoryDatabaseMixin
-class DumpTests(unittest.TestCase):
- def setUp(self):
- self.cx = sqlite.connect(":memory:")
- self.cu = self.cx.cursor()
- def tearDown(self):
- self.cx.close()
+class DumpTests(MemoryDatabaseMixin, unittest.TestCase):
def test_table_dump(self):
expected_sqls = [
diff --git a/Lib/test/test_sqlite3/test_factory.py b/Lib/test/test_sqlite3/test_factory.py
index 7c36135ecadccd..a7c4417862aff7 100644
--- a/Lib/test/test_sqlite3/test_factory.py
+++ b/Lib/test/test_sqlite3/test_factory.py
@@ -24,6 +24,9 @@
import sqlite3 as sqlite
from collections.abc import Sequence
+from .util import memory_database
+from .util import MemoryDatabaseMixin
+
def dict_factory(cursor, row):
d = {}
@@ -45,10 +48,12 @@ class OkFactory(sqlite.Connection):
def __init__(self, *args, **kwargs):
sqlite.Connection.__init__(self, *args, **kwargs)
- for factory in DefectFactory, OkFactory:
- with self.subTest(factory=factory):
- con = sqlite.connect(":memory:", factory=factory)
- self.assertIsInstance(con, factory)
+ with memory_database(factory=OkFactory) as con:
+ self.assertIsInstance(con, OkFactory)
+ regex = "Base Connection.__init__ not called."
+ with self.assertRaisesRegex(sqlite.ProgrammingError, regex):
+ with memory_database(factory=DefectFactory) as con:
+ self.assertIsInstance(con, DefectFactory)
def test_connection_factory_relayed_call(self):
# gh-95132: keyword args must not be passed as positional args
@@ -57,26 +62,30 @@ def __init__(self, *args, **kwargs):
kwargs["isolation_level"] = None
super(Factory, self).__init__(*args, **kwargs)
- con = sqlite.connect(":memory:", factory=Factory)
- self.assertIsNone(con.isolation_level)
- self.assertIsInstance(con, Factory)
+ with memory_database(factory=Factory) as con:
+ self.assertIsNone(con.isolation_level)
+ self.assertIsInstance(con, Factory)
def test_connection_factory_as_positional_arg(self):
class Factory(sqlite.Connection):
def __init__(self, *args, **kwargs):
super(Factory, self).__init__(*args, **kwargs)
- con = sqlite.connect(":memory:", 5.0, 0, None, True, Factory)
- self.assertIsNone(con.isolation_level)
- self.assertIsInstance(con, Factory)
+ regex = (
+ r"Passing more than 1 positional argument to _sqlite3.Connection\(\) "
+ r"is deprecated. Parameters 'timeout', 'detect_types', "
+ r"'isolation_level', 'check_same_thread', 'factory', "
+ r"'cached_statements' and 'uri' will become keyword-only "
+ r"parameters in Python 3.15."
+ )
+ with self.assertWarnsRegex(DeprecationWarning, regex) as cm:
+ with memory_database(5.0, 0, None, True, Factory) as con:
+ self.assertIsNone(con.isolation_level)
+ self.assertIsInstance(con, Factory)
+ self.assertEqual(cm.filename, __file__)
-class CursorFactoryTests(unittest.TestCase):
- def setUp(self):
- self.con = sqlite.connect(":memory:")
-
- def tearDown(self):
- self.con.close()
+class CursorFactoryTests(MemoryDatabaseMixin, unittest.TestCase):
def test_is_instance(self):
cur = self.con.cursor()
@@ -94,9 +103,8 @@ def test_invalid_factory(self):
# invalid callable returning non-cursor
self.assertRaises(TypeError, self.con.cursor, lambda con: None)
-class RowFactoryTestsBackwardsCompat(unittest.TestCase):
- def setUp(self):
- self.con = sqlite.connect(":memory:")
+
+class RowFactoryTestsBackwardsCompat(MemoryDatabaseMixin, unittest.TestCase):
def test_is_produced_by_factory(self):
cur = self.con.cursor(factory=MyCursor)
@@ -105,12 +113,8 @@ def test_is_produced_by_factory(self):
self.assertIsInstance(row, dict)
cur.close()
- def tearDown(self):
- self.con.close()
-class RowFactoryTests(unittest.TestCase):
- def setUp(self):
- self.con = sqlite.connect(":memory:")
+class RowFactoryTests(MemoryDatabaseMixin, unittest.TestCase):
def test_custom_factory(self):
self.con.row_factory = lambda cur, row: list(row)
@@ -256,12 +260,8 @@ class FakeCursor(str):
self.assertRaises(TypeError, self.con.cursor, FakeCursor)
self.assertRaises(TypeError, sqlite.Row, FakeCursor(), ())
- def tearDown(self):
- self.con.close()
-class TextFactoryTests(unittest.TestCase):
- def setUp(self):
- self.con = sqlite.connect(":memory:")
+class TextFactoryTests(MemoryDatabaseMixin, unittest.TestCase):
def test_unicode(self):
austria = "Österreich"
@@ -282,15 +282,17 @@ def test_custom(self):
self.assertEqual(type(row[0]), str, "type of row[0] must be unicode")
self.assertTrue(row[0].endswith("reich"), "column must contain original data")
- def tearDown(self):
- self.con.close()
class TextFactoryTestsWithEmbeddedZeroBytes(unittest.TestCase):
+
def setUp(self):
self.con = sqlite.connect(":memory:")
self.con.execute("create table test (value text)")
self.con.execute("insert into test (value) values (?)", ("a\x00b",))
+ def tearDown(self):
+ self.con.close()
+
def test_string(self):
# text_factory defaults to str
row = self.con.execute("select value from test").fetchone()
@@ -316,9 +318,6 @@ def test_custom(self):
self.assertIs(type(row[0]), bytes)
self.assertEqual(row[0], b"a\x00b")
- def tearDown(self):
- self.con.close()
-
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_sqlite3/test_hooks.py b/Lib/test/test_sqlite3/test_hooks.py
index 89230c08cc9143..33f0af99532a10 100644
--- a/Lib/test/test_sqlite3/test_hooks.py
+++ b/Lib/test/test_sqlite3/test_hooks.py
@@ -26,34 +26,31 @@
from test.support.os_helper import TESTFN, unlink
-from test.test_sqlite3.test_dbapi import memory_database, cx_limit
-from test.test_sqlite3.test_userfunctions import with_tracebacks
+from .util import memory_database, cx_limit, with_tracebacks
+from .util import MemoryDatabaseMixin
-class CollationTests(unittest.TestCase):
+class CollationTests(MemoryDatabaseMixin, unittest.TestCase):
+
def test_create_collation_not_string(self):
- con = sqlite.connect(":memory:")
with self.assertRaises(TypeError):
- con.create_collation(None, lambda x, y: (x > y) - (x < y))
+ self.con.create_collation(None, lambda x, y: (x > y) - (x < y))
def test_create_collation_not_callable(self):
- con = sqlite.connect(":memory:")
with self.assertRaises(TypeError) as cm:
- con.create_collation("X", 42)
+ self.con.create_collation("X", 42)
self.assertEqual(str(cm.exception), 'parameter must be callable')
def test_create_collation_not_ascii(self):
- con = sqlite.connect(":memory:")
- con.create_collation("collä", lambda x, y: (x > y) - (x < y))
+ self.con.create_collation("collä", lambda x, y: (x > y) - (x < y))
def test_create_collation_bad_upper(self):
class BadUpperStr(str):
def upper(self):
return None
- con = sqlite.connect(":memory:")
mycoll = lambda x, y: -((x > y) - (x < y))
- con.create_collation(BadUpperStr("mycoll"), mycoll)
- result = con.execute("""
+ self.con.create_collation(BadUpperStr("mycoll"), mycoll)
+ result = self.con.execute("""
select x from (
select 'a' as x
union
@@ -68,8 +65,7 @@ def mycoll(x, y):
# reverse order
return -((x > y) - (x < y))
- con = sqlite.connect(":memory:")
- con.create_collation("mycoll", mycoll)
+ self.con.create_collation("mycoll", mycoll)
sql = """
select x from (
select 'a' as x
@@ -79,21 +75,20 @@ def mycoll(x, y):
select 'c' as x
) order by x collate mycoll
"""
- result = con.execute(sql).fetchall()
+ result = self.con.execute(sql).fetchall()
self.assertEqual(result, [('c',), ('b',), ('a',)],
msg='the expected order was not returned')
- con.create_collation("mycoll", None)
+ self.con.create_collation("mycoll", None)
with self.assertRaises(sqlite.OperationalError) as cm:
- result = con.execute(sql).fetchall()
+ result = self.con.execute(sql).fetchall()
self.assertEqual(str(cm.exception), 'no such collation sequence: mycoll')
def test_collation_returns_large_integer(self):
def mycoll(x, y):
# reverse order
return -((x > y) - (x < y)) * 2**32
- con = sqlite.connect(":memory:")
- con.create_collation("mycoll", mycoll)
+ self.con.create_collation("mycoll", mycoll)
sql = """
select x from (
select 'a' as x
@@ -103,7 +98,7 @@ def mycoll(x, y):
select 'c' as x
) order by x collate mycoll
"""
- result = con.execute(sql).fetchall()
+ result = self.con.execute(sql).fetchall()
self.assertEqual(result, [('c',), ('b',), ('a',)],
msg="the expected order was not returned")
@@ -112,7 +107,7 @@ def test_collation_register_twice(self):
Register two different collation functions under the same name.
Verify that the last one is actually used.
"""
- con = sqlite.connect(":memory:")
+ con = self.con
con.create_collation("mycoll", lambda x, y: (x > y) - (x < y))
con.create_collation("mycoll", lambda x, y: -((x > y) - (x < y)))
result = con.execute("""
@@ -126,25 +121,26 @@ def test_deregister_collation(self):
Register a collation, then deregister it. Make sure an error is raised if we try
to use it.
"""
- con = sqlite.connect(":memory:")
+ con = self.con
con.create_collation("mycoll", lambda x, y: (x > y) - (x < y))
con.create_collation("mycoll", None)
with self.assertRaises(sqlite.OperationalError) as cm:
con.execute("select 'a' as x union select 'b' as x order by x collate mycoll")
self.assertEqual(str(cm.exception), 'no such collation sequence: mycoll')
-class ProgressTests(unittest.TestCase):
+
+class ProgressTests(MemoryDatabaseMixin, unittest.TestCase):
+
def test_progress_handler_used(self):
"""
Test that the progress handler is invoked once it is set.
"""
- con = sqlite.connect(":memory:")
progress_calls = []
def progress():
progress_calls.append(None)
return 0
- con.set_progress_handler(progress, 1)
- con.execute("""
+ self.con.set_progress_handler(progress, 1)
+ self.con.execute("""
create table foo(a, b)
""")
self.assertTrue(progress_calls)
@@ -153,7 +149,7 @@ def test_opcode_count(self):
"""
Test that the opcode argument is respected.
"""
- con = sqlite.connect(":memory:")
+ con = self.con
progress_calls = []
def progress():
progress_calls.append(None)
@@ -176,11 +172,10 @@ def test_cancel_operation(self):
"""
Test that returning a non-zero value stops the operation in progress.
"""
- con = sqlite.connect(":memory:")
def progress():
return 1
- con.set_progress_handler(progress, 1)
- curs = con.cursor()
+ self.con.set_progress_handler(progress, 1)
+ curs = self.con.cursor()
self.assertRaises(
sqlite.OperationalError,
curs.execute,
@@ -190,7 +185,7 @@ def test_clear_handler(self):
"""
Test that setting the progress handler to None clears the previously set handler.
"""
- con = sqlite.connect(":memory:")
+ con = self.con
action = 0
def progress():
nonlocal action
@@ -203,31 +198,30 @@ def progress():
@with_tracebacks(ZeroDivisionError, name="bad_progress")
def test_error_in_progress_handler(self):
- con = sqlite.connect(":memory:")
def bad_progress():
1 / 0
- con.set_progress_handler(bad_progress, 1)
+ self.con.set_progress_handler(bad_progress, 1)
with self.assertRaises(sqlite.OperationalError):
- con.execute("""
+ self.con.execute("""
create table foo(a, b)
""")
@with_tracebacks(ZeroDivisionError, name="bad_progress")
def test_error_in_progress_handler_result(self):
- con = sqlite.connect(":memory:")
class BadBool:
def __bool__(self):
1 / 0
def bad_progress():
return BadBool()
- con.set_progress_handler(bad_progress, 1)
+ self.con.set_progress_handler(bad_progress, 1)
with self.assertRaises(sqlite.OperationalError):
- con.execute("""
+ self.con.execute("""
create table foo(a, b)
""")
-class TraceCallbackTests(unittest.TestCase):
+class TraceCallbackTests(MemoryDatabaseMixin, unittest.TestCase):
+
@contextlib.contextmanager
def check_stmt_trace(self, cx, expected):
try:
@@ -242,12 +236,11 @@ def test_trace_callback_used(self):
"""
Test that the trace callback is invoked once it is set.
"""
- con = sqlite.connect(":memory:")
traced_statements = []
def trace(statement):
traced_statements.append(statement)
- con.set_trace_callback(trace)
- con.execute("create table foo(a, b)")
+ self.con.set_trace_callback(trace)
+ self.con.execute("create table foo(a, b)")
self.assertTrue(traced_statements)
self.assertTrue(any("create table foo" in stmt for stmt in traced_statements))
@@ -255,7 +248,7 @@ def test_clear_trace_callback(self):
"""
Test that setting the trace callback to None clears the previously set callback.
"""
- con = sqlite.connect(":memory:")
+ con = self.con
traced_statements = []
def trace(statement):
traced_statements.append(statement)
@@ -269,7 +262,7 @@ def test_unicode_content(self):
Test that the statement can contain unicode literals.
"""
unicode_value = '\xf6\xe4\xfc\xd6\xc4\xdc\xdf\u20ac'
- con = sqlite.connect(":memory:")
+ con = self.con
traced_statements = []
def trace(statement):
traced_statements.append(statement)
diff --git a/Lib/test/test_sqlite3/test_regression.py b/Lib/test/test_sqlite3/test_regression.py
index 7e8221e7227e6e..db4e13222da9da 100644
--- a/Lib/test/test_sqlite3/test_regression.py
+++ b/Lib/test/test_sqlite3/test_regression.py
@@ -28,15 +28,12 @@
from test import support
from unittest.mock import patch
-from test.test_sqlite3.test_dbapi import memory_database, cx_limit
+from .util import memory_database, cx_limit
+from .util import MemoryDatabaseMixin
-class RegressionTests(unittest.TestCase):
- def setUp(self):
- self.con = sqlite.connect(":memory:")
- def tearDown(self):
- self.con.close()
+class RegressionTests(MemoryDatabaseMixin, unittest.TestCase):
def test_pragma_user_version(self):
# This used to crash pysqlite because this pragma command returns NULL for the column name
@@ -45,28 +42,24 @@ def test_pragma_user_version(self):
def test_pragma_schema_version(self):
# This still crashed pysqlite <= 2.2.1
- con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_COLNAMES)
- try:
+ with memory_database(detect_types=sqlite.PARSE_COLNAMES) as con:
cur = self.con.cursor()
cur.execute("pragma schema_version")
- finally:
- cur.close()
- con.close()
def test_statement_reset(self):
# pysqlite 2.1.0 to 2.2.0 have the problem that not all statements are
# reset before a rollback, but only those that are still in the
# statement cache. The others are not accessible from the connection object.
- con = sqlite.connect(":memory:", cached_statements=5)
- cursors = [con.cursor() for x in range(5)]
- cursors[0].execute("create table test(x)")
- for i in range(10):
- cursors[0].executemany("insert into test(x) values (?)", [(x,) for x in range(10)])
+ with memory_database(cached_statements=5) as con:
+ cursors = [con.cursor() for x in range(5)]
+ cursors[0].execute("create table test(x)")
+ for i in range(10):
+ cursors[0].executemany("insert into test(x) values (?)", [(x,) for x in range(10)])
- for i in range(5):
- cursors[i].execute(" " * i + "select x from test")
+ for i in range(5):
+ cursors[i].execute(" " * i + "select x from test")
- con.rollback()
+ con.rollback()
def test_column_name_with_spaces(self):
cur = self.con.cursor()
@@ -81,17 +74,15 @@ def test_statement_finalization_on_close_db(self):
# cache when closing the database. statements that were still
# referenced in cursors weren't closed and could provoke "
# "OperationalError: Unable to close due to unfinalised statements".
- con = sqlite.connect(":memory:")
cursors = []
# default statement cache size is 100
for i in range(105):
- cur = con.cursor()
+ cur = self.con.cursor()
cursors.append(cur)
cur.execute("select 1 x union select " + str(i))
- con.close()
def test_on_conflict_rollback(self):
- con = sqlite.connect(":memory:")
+ con = self.con
con.execute("create table foo(x, unique(x) on conflict rollback)")
con.execute("insert into foo(x) values (1)")
try:
@@ -126,16 +117,16 @@ def test_type_map_usage(self):
a statement. This test exhibits the problem.
"""
SELECT = "select * from foo"
- con = sqlite.connect(":memory:",detect_types=sqlite.PARSE_DECLTYPES)
- cur = con.cursor()
- cur.execute("create table foo(bar timestamp)")
- with self.assertWarnsRegex(DeprecationWarning, "adapter"):
- cur.execute("insert into foo(bar) values (?)", (datetime.datetime.now(),))
- cur.execute(SELECT)
- cur.execute("drop table foo")
- cur.execute("create table foo(bar integer)")
- cur.execute("insert into foo(bar) values (5)")
- cur.execute(SELECT)
+ with memory_database(detect_types=sqlite.PARSE_DECLTYPES) as con:
+ cur = con.cursor()
+ cur.execute("create table foo(bar timestamp)")
+ with self.assertWarnsRegex(DeprecationWarning, "adapter"):
+ cur.execute("insert into foo(bar) values (?)", (datetime.datetime.now(),))
+ cur.execute(SELECT)
+ cur.execute("drop table foo")
+ cur.execute("create table foo(bar integer)")
+ cur.execute("insert into foo(bar) values (5)")
+ cur.execute(SELECT)
def test_bind_mutating_list(self):
# Issue41662: Crash when mutate a list of parameters during iteration.
@@ -144,11 +135,11 @@ def __conform__(self, protocol):
parameters.clear()
return "..."
parameters = [X(), 0]
- con = sqlite.connect(":memory:",detect_types=sqlite.PARSE_DECLTYPES)
- con.execute("create table foo(bar X, baz integer)")
- # Should not crash
- with self.assertRaises(IndexError):
- con.execute("insert into foo(bar, baz) values (?, ?)", parameters)
+ with memory_database(detect_types=sqlite.PARSE_DECLTYPES) as con:
+ con.execute("create table foo(bar X, baz integer)")
+ # Should not crash
+ with self.assertRaises(IndexError):
+ con.execute("insert into foo(bar, baz) values (?, ?)", parameters)
def test_error_msg_decode_error(self):
# When porting the module to Python 3.0, the error message about
@@ -173,7 +164,7 @@ def upper(self):
def __del__(self):
con.isolation_level = ""
- con = sqlite.connect(":memory:")
+ con = self.con
con.isolation_level = None
for level in "", "DEFERRED", "IMMEDIATE", "EXCLUSIVE":
with self.subTest(level=level):
@@ -204,8 +195,7 @@ class Cursor(sqlite.Cursor):
def __init__(self, con):
pass
- con = sqlite.connect(":memory:")
- cur = Cursor(con)
+ cur = Cursor(self.con)
with self.assertRaises(sqlite.ProgrammingError):
cur.execute("select 4+5").fetchall()
with self.assertRaisesRegex(sqlite.ProgrammingError,
@@ -238,7 +228,9 @@ def test_auto_commit(self):
2.5.3 introduced a regression so that these could no longer
be created.
"""
- con = sqlite.connect(":memory:", isolation_level=None)
+ with memory_database(isolation_level=None) as con:
+ self.assertIsNone(con.isolation_level)
+ self.assertFalse(con.in_transaction)
def test_pragma_autocommit(self):
"""
@@ -273,9 +265,7 @@ def test_recursive_cursor_use(self):
Recursively using a cursor, such as when reusing it from a generator led to segfaults.
Now we catch recursive cursor usage and raise a ProgrammingError.
"""
- con = sqlite.connect(":memory:")
-
- cur = con.cursor()
+ cur = self.con.cursor()
cur.execute("create table a (bar)")
cur.execute("create table b (baz)")
@@ -295,29 +285,30 @@ def test_convert_timestamp_microsecond_padding(self):
since the microsecond string "456" actually represents "456000".
"""
- con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_DECLTYPES)
- cur = con.cursor()
- cur.execute("CREATE TABLE t (x TIMESTAMP)")
+ with memory_database(detect_types=sqlite.PARSE_DECLTYPES) as con:
+ cur = con.cursor()
+ cur.execute("CREATE TABLE t (x TIMESTAMP)")
- # Microseconds should be 456000
- cur.execute("INSERT INTO t (x) VALUES ('2012-04-04 15:06:00.456')")
+ # Microseconds should be 456000
+ cur.execute("INSERT INTO t (x) VALUES ('2012-04-04 15:06:00.456')")
- # Microseconds should be truncated to 123456
- cur.execute("INSERT INTO t (x) VALUES ('2012-04-04 15:06:00.123456789')")
+ # Microseconds should be truncated to 123456
+ cur.execute("INSERT INTO t (x) VALUES ('2012-04-04 15:06:00.123456789')")
- cur.execute("SELECT * FROM t")
- with self.assertWarnsRegex(DeprecationWarning, "converter"):
- values = [x[0] for x in cur.fetchall()]
+ cur.execute("SELECT * FROM t")
+ with self.assertWarnsRegex(DeprecationWarning, "converter"):
+ values = [x[0] for x in cur.fetchall()]
- self.assertEqual(values, [
- datetime.datetime(2012, 4, 4, 15, 6, 0, 456000),
- datetime.datetime(2012, 4, 4, 15, 6, 0, 123456),
- ])
+ self.assertEqual(values, [
+ datetime.datetime(2012, 4, 4, 15, 6, 0, 456000),
+ datetime.datetime(2012, 4, 4, 15, 6, 0, 123456),
+ ])
def test_invalid_isolation_level_type(self):
# isolation level is a string, not an integer
- self.assertRaises(TypeError,
- sqlite.connect, ":memory:", isolation_level=123)
+ regex = "isolation_level must be str or None"
+ with self.assertRaisesRegex(TypeError, regex):
+ memory_database(isolation_level=123).__enter__()
def test_null_character(self):
@@ -333,7 +324,7 @@ def test_null_character(self):
cur.execute, query)
def test_surrogates(self):
- con = sqlite.connect(":memory:")
+ con = self.con
self.assertRaises(UnicodeEncodeError, con, "select '\ud8ff'")
self.assertRaises(UnicodeEncodeError, con, "select '\udcff'")
cur = con.cursor()
@@ -359,7 +350,7 @@ def test_commit_cursor_reset(self):
to return rows multiple times when fetched from cursors
after commit. See issues 10513 and 23129 for details.
"""
- con = sqlite.connect(":memory:")
+ con = self.con
con.executescript("""
create table t(c);
create table t2(c);
@@ -391,10 +382,9 @@ def test_bpo31770(self):
"""
def callback(*args):
pass
- con = sqlite.connect(":memory:")
- cur = sqlite.Cursor(con)
+ cur = sqlite.Cursor(self.con)
ref = weakref.ref(cur, callback)
- cur.__init__(con)
+ cur.__init__(self.con)
del cur
# The interpreter shouldn't crash when ref is collected.
del ref
@@ -425,6 +415,7 @@ def test_return_empty_bytestring(self):
def test_table_lock_cursor_replace_stmt(self):
with memory_database() as con:
+ con = self.con
cur = con.cursor()
cur.execute("create table t(t)")
cur.executemany("insert into t values(?)",
diff --git a/Lib/test/test_sqlite3/test_transactions.py b/Lib/test/test_sqlite3/test_transactions.py
index 5d211dd47b0b6b..b7b231d2225852 100644
--- a/Lib/test/test_sqlite3/test_transactions.py
+++ b/Lib/test/test_sqlite3/test_transactions.py
@@ -28,7 +28,8 @@
from test.support.os_helper import TESTFN, unlink
from test.support.script_helper import assert_python_ok
-from test.test_sqlite3.test_dbapi import memory_database
+from .util import memory_database
+from .util import MemoryDatabaseMixin
TIMEOUT = LOOPBACK_TIMEOUT / 10
@@ -132,14 +133,14 @@ def test_locking(self):
def test_rollback_cursor_consistency(self):
"""Check that cursors behave correctly after rollback."""
- con = sqlite.connect(":memory:")
- cur = con.cursor()
- cur.execute("create table test(x)")
- cur.execute("insert into test(x) values (5)")
- cur.execute("select 1 union select 2 union select 3")
+ with memory_database() as con:
+ cur = con.cursor()
+ cur.execute("create table test(x)")
+ cur.execute("insert into test(x) values (5)")
+ cur.execute("select 1 union select 2 union select 3")
- con.rollback()
- self.assertEqual(cur.fetchall(), [(1,), (2,), (3,)])
+ con.rollback()
+ self.assertEqual(cur.fetchall(), [(1,), (2,), (3,)])
def test_multiple_cursors_and_iternext(self):
# gh-94028: statements are cleared and reset in cursor iternext.
@@ -218,10 +219,7 @@ def test_no_duplicate_rows_after_rollback_new_query(self):
-class SpecialCommandTests(unittest.TestCase):
- def setUp(self):
- self.con = sqlite.connect(":memory:")
- self.cur = self.con.cursor()
+class SpecialCommandTests(MemoryDatabaseMixin, unittest.TestCase):
def test_drop_table(self):
self.cur.execute("create table test(i)")
@@ -233,14 +231,8 @@ def test_pragma(self):
self.cur.execute("insert into test(i) values (5)")
self.cur.execute("pragma count_changes=1")
- def tearDown(self):
- self.cur.close()
- self.con.close()
-
-class TransactionalDDL(unittest.TestCase):
- def setUp(self):
- self.con = sqlite.connect(":memory:")
+class TransactionalDDL(MemoryDatabaseMixin, unittest.TestCase):
def test_ddl_does_not_autostart_transaction(self):
# For backwards compatibility reasons, DDL statements should not
@@ -268,9 +260,6 @@ def test_transactional_ddl(self):
with self.assertRaises(sqlite.OperationalError):
self.con.execute("select * from test")
- def tearDown(self):
- self.con.close()
-
class IsolationLevelFromInit(unittest.TestCase):
CREATE = "create table t(t)"
diff --git a/Lib/test/test_sqlite3/test_userfunctions.py b/Lib/test/test_sqlite3/test_userfunctions.py
index 05c2fb3aa6f8f2..5d12636dcd2b63 100644
--- a/Lib/test/test_sqlite3/test_userfunctions.py
+++ b/Lib/test/test_sqlite3/test_userfunctions.py
@@ -21,54 +21,15 @@
# misrepresented as being the original software.
# 3. This notice may not be removed or altered from any source distribution.
-import contextlib
-import functools
-import io
-import re
import sys
import unittest
import sqlite3 as sqlite
from unittest.mock import Mock, patch
-from test.support import bigmemtest, catch_unraisable_exception, gc_collect
-
-from test.test_sqlite3.test_dbapi import cx_limit
-
-
-def with_tracebacks(exc, regex="", name=""):
- """Convenience decorator for testing callback tracebacks."""
- def decorator(func):
- _regex = re.compile(regex) if regex else None
- @functools.wraps(func)
- def wrapper(self, *args, **kwargs):
- with catch_unraisable_exception() as cm:
- # First, run the test with traceback enabled.
- with check_tracebacks(self, cm, exc, _regex, name):
- func(self, *args, **kwargs)
-
- # Then run the test with traceback disabled.
- func(self, *args, **kwargs)
- return wrapper
- return decorator
-
-
-@contextlib.contextmanager
-def check_tracebacks(self, cm, exc, regex, obj_name):
- """Convenience context manager for testing callback tracebacks."""
- sqlite.enable_callback_tracebacks(True)
- try:
- buf = io.StringIO()
- with contextlib.redirect_stderr(buf):
- yield
-
- self.assertEqual(cm.unraisable.exc_type, exc)
- if regex:
- msg = str(cm.unraisable.exc_value)
- self.assertIsNotNone(regex.search(msg))
- if obj_name:
- self.assertEqual(cm.unraisable.object.__name__, obj_name)
- finally:
- sqlite.enable_callback_tracebacks(False)
+from test.support import bigmemtest, gc_collect
+
+from .util import cx_limit, memory_database
+from .util import with_tracebacks, check_tracebacks
def func_returntext():
@@ -405,19 +366,19 @@ def test_func_deterministic_keyword_only(self):
def test_function_destructor_via_gc(self):
# See bpo-44304: The destructor of the user function can
# crash if is called without the GIL from the gc functions
- dest = sqlite.connect(':memory:')
def md5sum(t):
return
- dest.create_function("md5", 1, md5sum)
- x = dest("create table lang (name, first_appeared)")
- del md5sum, dest
+ with memory_database() as dest:
+ dest.create_function("md5", 1, md5sum)
+ x = dest("create table lang (name, first_appeared)")
+ del md5sum, dest
- y = [x]
- y.append(y)
+ y = [x]
+ y.append(y)
- del x,y
- gc_collect()
+ del x,y
+ gc_collect()
@with_tracebacks(OverflowError)
def test_func_return_too_large_int(self):
@@ -514,6 +475,10 @@ def setUp(self):
"""
self.con.create_window_function("sumint", 1, WindowSumInt)
+ def tearDown(self):
+ self.cur.close()
+ self.con.close()
+
def test_win_sum_int(self):
self.cur.execute(self.query % "sumint")
self.assertEqual(self.cur.fetchall(), self.expected)
@@ -634,6 +599,7 @@ def setUp(self):
""")
cur.execute("insert into test(t, i, f, n, b) values (?, ?, ?, ?, ?)",
("foo", 5, 3.14, None, memoryview(b"blob"),))
+ cur.close()
self.con.create_aggregate("nostep", 1, AggrNoStep)
self.con.create_aggregate("nofinalize", 1, AggrNoFinalize)
@@ -646,9 +612,7 @@ def setUp(self):
self.con.create_aggregate("aggtxt", 1, AggrText)
def tearDown(self):
- #self.cur.close()
- #self.con.close()
- pass
+ self.con.close()
def test_aggr_error_on_create(self):
with self.assertRaises(sqlite.OperationalError):
@@ -775,7 +739,7 @@ def setUp(self):
self.con.set_authorizer(self.authorizer_cb)
def tearDown(self):
- pass
+ self.con.close()
def test_table_access(self):
with self.assertRaises(sqlite.DatabaseError) as cm:
diff --git a/Lib/test/test_sqlite3/util.py b/Lib/test/test_sqlite3/util.py
new file mode 100644
index 00000000000000..505406c437b632
--- /dev/null
+++ b/Lib/test/test_sqlite3/util.py
@@ -0,0 +1,78 @@
+import contextlib
+import functools
+import io
+import re
+import sqlite3
+import test.support
+import unittest
+
+
+# Helper for temporary memory databases
+def memory_database(*args, **kwargs):
+ cx = sqlite3.connect(":memory:", *args, **kwargs)
+ return contextlib.closing(cx)
+
+
+# Temporarily limit a database connection parameter
+@contextlib.contextmanager
+def cx_limit(cx, category=sqlite3.SQLITE_LIMIT_SQL_LENGTH, limit=128):
+ try:
+ _prev = cx.setlimit(category, limit)
+ yield limit
+ finally:
+ cx.setlimit(category, _prev)
+
+
+def with_tracebacks(exc, regex="", name=""):
+ """Convenience decorator for testing callback tracebacks."""
+ def decorator(func):
+ _regex = re.compile(regex) if regex else None
+ @functools.wraps(func)
+ def wrapper(self, *args, **kwargs):
+ with test.support.catch_unraisable_exception() as cm:
+ # First, run the test with traceback enabled.
+ with check_tracebacks(self, cm, exc, _regex, name):
+ func(self, *args, **kwargs)
+
+ # Then run the test with traceback disabled.
+ func(self, *args, **kwargs)
+ return wrapper
+ return decorator
+
+
+@contextlib.contextmanager
+def check_tracebacks(self, cm, exc, regex, obj_name):
+ """Convenience context manager for testing callback tracebacks."""
+ sqlite3.enable_callback_tracebacks(True)
+ try:
+ buf = io.StringIO()
+ with contextlib.redirect_stderr(buf):
+ yield
+
+ self.assertEqual(cm.unraisable.exc_type, exc)
+ if regex:
+ msg = str(cm.unraisable.exc_value)
+ self.assertIsNotNone(regex.search(msg))
+ if obj_name:
+ self.assertEqual(cm.unraisable.object.__name__, obj_name)
+ finally:
+ sqlite3.enable_callback_tracebacks(False)
+
+
+class MemoryDatabaseMixin:
+
+ def setUp(self):
+ self.con = sqlite3.connect(":memory:")
+ self.cur = self.con.cursor()
+
+ def tearDown(self):
+ self.cur.close()
+ self.con.close()
+
+ @property
+ def cx(self):
+ return self.con
+
+ @property
+ def cu(self):
+ return self.cur
diff --git a/Lib/test/test_statistics.py b/Lib/test/test_statistics.py
index f0fa6454b1f91a..aa2cf2b1edc584 100644
--- a/Lib/test/test_statistics.py
+++ b/Lib/test/test_statistics.py
@@ -28,6 +28,12 @@
# === Helper functions and class ===
+# Test copied from Lib/test/test_math.py
+# detect evidence of double-rounding: fsum is not always correctly
+# rounded on machines that suffer from double rounding.
+x, y = 1e16, 2.9999 # use temporary values to defeat peephole optimizer
+HAVE_DOUBLE_ROUNDING = (x + y == 1e16 + 4)
+
def sign(x):
"""Return -1.0 for negatives, including -0.0, otherwise +1.0."""
return math.copysign(1, x)
@@ -2564,6 +2570,79 @@ def test_different_scales(self):
self.assertAlmostEqual(statistics.correlation(x, y), 1)
self.assertAlmostEqual(statistics.covariance(x, y), 0.1)
+ def test_sqrtprod_helper_function_fundamentals(self):
+ # Verify that results are close to sqrt(x * y)
+ for i in range(100):
+ x = random.expovariate()
+ y = random.expovariate()
+ expected = math.sqrt(x * y)
+ actual = statistics._sqrtprod(x, y)
+ with self.subTest(x=x, y=y, expected=expected, actual=actual):
+ self.assertAlmostEqual(expected, actual)
+
+ x, y, target = 0.8035720646477457, 0.7957468097636939, 0.7996498651651661
+ self.assertEqual(statistics._sqrtprod(x, y), target)
+ self.assertNotEqual(math.sqrt(x * y), target)
+
+ # Test that range extremes avoid underflow and overflow
+ smallest = sys.float_info.min * sys.float_info.epsilon
+ self.assertEqual(statistics._sqrtprod(smallest, smallest), smallest)
+ biggest = sys.float_info.max
+ self.assertEqual(statistics._sqrtprod(biggest, biggest), biggest)
+
+ # Check special values and the sign of the result
+ special_values = [0.0, -0.0, 1.0, -1.0, 4.0, -4.0,
+ math.nan, -math.nan, math.inf, -math.inf]
+ for x, y in itertools.product(special_values, repeat=2):
+ try:
+ expected = math.sqrt(x * y)
+ except ValueError:
+ expected = 'ValueError'
+ try:
+ actual = statistics._sqrtprod(x, y)
+ except ValueError:
+ actual = 'ValueError'
+ with self.subTest(x=x, y=y, expected=expected, actual=actual):
+ if isinstance(expected, str) and expected == 'ValueError':
+ self.assertEqual(actual, 'ValueError')
+ continue
+ self.assertIsInstance(actual, float)
+ if math.isnan(expected):
+ self.assertTrue(math.isnan(actual))
+ continue
+ self.assertEqual(actual, expected)
+ self.assertEqual(sign(actual), sign(expected))
+
+ @requires_IEEE_754
+ @unittest.skipIf(HAVE_DOUBLE_ROUNDING,
+ "accuracy not guaranteed on machines with double rounding")
+ @support.cpython_only # Allow for a weaker sumprod() implmentation
+ def test_sqrtprod_helper_function_improved_accuracy(self):
+ # Test a known example where accuracy is improved
+ x, y, target = 0.8035720646477457, 0.7957468097636939, 0.7996498651651661
+ self.assertEqual(statistics._sqrtprod(x, y), target)
+ self.assertNotEqual(math.sqrt(x * y), target)
+
+ def reference_value(x: float, y: float) -> float:
+ x = decimal.Decimal(x)
+ y = decimal.Decimal(y)
+ with decimal.localcontext() as ctx:
+ ctx.prec = 200
+ return float((x * y).sqrt())
+
+ # Verify that the new function with improved accuracy
+ # agrees with a reference value more often than old version.
+ new_agreements = 0
+ old_agreements = 0
+ for i in range(10_000):
+ x = random.expovariate()
+ y = random.expovariate()
+ new = statistics._sqrtprod(x, y)
+ old = math.sqrt(x * y)
+ ref = reference_value(x, y)
+ new_agreements += (new == ref)
+ old_agreements += (old == ref)
+ self.assertGreater(new_agreements, old_agreements)
def test_correlation_spearman(self):
# https://statistics.laerd.com/statistical-guides/spearmans-rank-order-correlation-statistical-guide-2.php
diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py
index bced641a9661fd..0045057f181e1c 100644
--- a/Lib/test/test_type_params.py
+++ b/Lib/test/test_type_params.py
@@ -148,6 +148,10 @@ def test_disallowed_expressions(self):
check_syntax_error(self, "def f[T: [(x := 3) for _ in range(2)]](): pass")
check_syntax_error(self, "type T = [(x := 3) for _ in range(2)]")
+ def test_incorrect_mro_explicit_object(self):
+ with self.assertRaisesRegex(TypeError, r"\(MRO\) for bases object, Generic"):
+ class My[X](object): ...
+
class TypeParamsNonlocalTest(unittest.TestCase):
def test_nonlocal_disallowed_01(self):
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 0450a87577ecea..fa39c796197959 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -4091,6 +4091,22 @@ class C(Generic[T]): pass
with self.assertRaises(TypeError):
C[()]
+ def test_generic_subclass_checks(self):
+ for typ in [list[int], List[int],
+ tuple[int, str], Tuple[int, str],
+ typing.Callable[..., None],
+ collections.abc.Callable[..., None]]:
+ with self.subTest(typ=typ):
+ self.assertRaises(TypeError, issubclass, typ, object)
+ self.assertRaises(TypeError, issubclass, typ, type)
+ self.assertRaises(TypeError, issubclass, typ, typ)
+ self.assertRaises(TypeError, issubclass, object, typ)
+
+ # isinstance is fine:
+ self.assertTrue(isinstance(typ, object))
+ # but, not when the right arg is also a generic:
+ self.assertRaises(TypeError, isinstance, typ, typ)
+
def test_init(self):
T = TypeVar('T')
S = TypeVar('S')
diff --git a/Lib/test/test_unittest/test_runner.py b/Lib/test/test_unittest/test_runner.py
index f3b2c0cffd4513..1b9cef43e3f9c5 100644
--- a/Lib/test/test_unittest/test_runner.py
+++ b/Lib/test/test_unittest/test_runner.py
@@ -24,6 +24,13 @@ def getRunner():
stream=io.StringIO())
+class CustomError(Exception):
+ pass
+
+# For test output compat:
+CustomErrorRepr = f"{__name__ + '.' if __name__ != '__main__' else ''}CustomError"
+
+
def runTests(*cases):
suite = unittest.TestSuite()
for case in cases:
@@ -46,7 +53,7 @@ def cleanup(ordering, blowUp=False):
ordering.append('cleanup_good')
else:
ordering.append('cleanup_exc')
- raise Exception('CleanUpExc')
+ raise CustomError('CleanUpExc')
class TestCM:
@@ -108,8 +115,8 @@ def testNothing(self):
result = unittest.TestResult()
outcome = test._outcome = _Outcome(result=result)
- CleanUpExc = Exception('foo')
- exc2 = Exception('bar')
+ CleanUpExc = CustomError('foo')
+ exc2 = CustomError('bar')
def cleanup1():
raise CleanUpExc
@@ -125,10 +132,10 @@ def cleanup2():
(_, msg2), (_, msg1) = result.errors
self.assertIn('in cleanup1', msg1)
self.assertIn('raise CleanUpExc', msg1)
- self.assertIn('Exception: foo', msg1)
+ self.assertIn(f'{CustomErrorRepr}: foo', msg1)
self.assertIn('in cleanup2', msg2)
self.assertIn('raise exc2', msg2)
- self.assertIn('Exception: bar', msg2)
+ self.assertIn(f'{CustomErrorRepr}: bar', msg2)
def testCleanupInRun(self):
blowUp = False
@@ -139,7 +146,7 @@ def setUp(self):
ordering.append('setUp')
test.addCleanup(cleanup2)
if blowUp:
- raise Exception('foo')
+ raise CustomError('foo')
def testNothing(self):
ordering.append('test')
@@ -280,7 +287,7 @@ def setUpClass(cls):
ordering.append('setUpClass')
cls.addClassCleanup(cleanup, ordering)
if blowUp:
- raise Exception()
+ raise CustomError()
def testNothing(self):
ordering.append('test')
@classmethod
@@ -306,7 +313,7 @@ def setUpClass(cls):
ordering.append('setUpClass')
cls.addClassCleanup(cleanup, ordering)
if blowUp:
- raise Exception()
+ raise CustomError()
def testNothing(self):
ordering.append('test')
@classmethod
@@ -346,7 +353,7 @@ def tearDownClass(cls):
ordering = []
blowUp = True
suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestableTest)
- with self.assertRaises(Exception) as cm:
+ with self.assertRaises(CustomError) as cm:
suite.debug()
self.assertEqual(str(cm.exception), 'CleanUpExc')
self.assertEqual(ordering,
@@ -366,10 +373,10 @@ def testNothing(self):
@classmethod
def tearDownClass(cls):
ordering.append('tearDownClass')
- raise Exception('TearDownClassExc')
+ raise CustomError('TearDownClassExc')
suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestableTest)
- with self.assertRaises(Exception) as cm:
+ with self.assertRaises(CustomError) as cm:
suite.debug()
self.assertEqual(str(cm.exception), 'TearDownClassExc')
self.assertEqual(ordering, ['setUpClass', 'test', 'tearDownClass'])
@@ -379,7 +386,7 @@ def tearDownClass(cls):
ordering = []
blowUp = True
suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestableTest)
- with self.assertRaises(Exception) as cm:
+ with self.assertRaises(CustomError) as cm:
suite.debug()
self.assertEqual(str(cm.exception), 'TearDownClassExc')
self.assertEqual(ordering, ['setUpClass', 'test', 'tearDownClass'])
@@ -392,16 +399,22 @@ def testNothing(self):
pass
def cleanup1():
- raise Exception('cleanup1')
+ raise CustomError('cleanup1')
def cleanup2():
- raise Exception('cleanup2')
+ raise CustomError('cleanup2')
TestableTest.addClassCleanup(cleanup1)
TestableTest.addClassCleanup(cleanup2)
- with self.assertRaises(Exception) as e:
- TestableTest.doClassCleanups()
- self.assertEqual(e, 'cleanup1')
+ TestableTest.doClassCleanups()
+
+ self.assertEqual(len(TestableTest.tearDown_exceptions), 2)
+
+ e1, e2 = TestableTest.tearDown_exceptions
+ self.assertIsInstance(e1[1], CustomError)
+ self.assertEqual(str(e1[1]), 'cleanup2')
+ self.assertIsInstance(e2[1], CustomError)
+ self.assertEqual(str(e2[1]), 'cleanup1')
def test_with_errors_addCleanUp(self):
ordering = []
@@ -421,7 +434,7 @@ def tearDownClass(cls):
result = runTests(TestableTest)
self.assertEqual(result.errors[0][1].splitlines()[-1],
- 'Exception: CleanUpExc')
+ f'{CustomErrorRepr}: CleanUpExc')
self.assertEqual(ordering,
['setUpClass', 'setUp', 'cleanup_exc',
'tearDownClass', 'cleanup_good'])
@@ -444,7 +457,7 @@ def tearDownClass(cls):
result = runTests(TestableTest)
self.assertEqual(result.errors[0][1].splitlines()[-1],
- 'Exception: CleanUpExc')
+ f'{CustomErrorRepr}: CleanUpExc')
self.assertEqual(ordering,
['setUpClass', 'setUp', 'test', 'cleanup_good',
'tearDownClass', 'cleanup_exc'])
@@ -460,11 +473,11 @@ def setUpClass(cls):
ordering.append('setUpClass')
cls.addClassCleanup(cleanup, ordering, blowUp=True)
if class_blow_up:
- raise Exception('ClassExc')
+ raise CustomError('ClassExc')
def setUp(self):
ordering.append('setUp')
if method_blow_up:
- raise Exception('MethodExc')
+ raise CustomError('MethodExc')
def testNothing(self):
ordering.append('test')
@classmethod
@@ -473,7 +486,7 @@ def tearDownClass(cls):
result = runTests(TestableTest)
self.assertEqual(result.errors[0][1].splitlines()[-1],
- 'Exception: CleanUpExc')
+ f'{CustomErrorRepr}: CleanUpExc')
self.assertEqual(ordering,
['setUpClass', 'setUp', 'test',
'tearDownClass', 'cleanup_exc'])
@@ -483,9 +496,9 @@ def tearDownClass(cls):
method_blow_up = False
result = runTests(TestableTest)
self.assertEqual(result.errors[0][1].splitlines()[-1],
- 'Exception: ClassExc')
+ f'{CustomErrorRepr}: ClassExc')
self.assertEqual(result.errors[1][1].splitlines()[-1],
- 'Exception: CleanUpExc')
+ f'{CustomErrorRepr}: CleanUpExc')
self.assertEqual(ordering,
['setUpClass', 'cleanup_exc'])
@@ -494,9 +507,9 @@ def tearDownClass(cls):
method_blow_up = True
result = runTests(TestableTest)
self.assertEqual(result.errors[0][1].splitlines()[-1],
- 'Exception: MethodExc')
+ f'{CustomErrorRepr}: MethodExc')
self.assertEqual(result.errors[1][1].splitlines()[-1],
- 'Exception: CleanUpExc')
+ f'{CustomErrorRepr}: CleanUpExc')
self.assertEqual(ordering,
['setUpClass', 'setUp', 'tearDownClass',
'cleanup_exc'])
@@ -513,11 +526,11 @@ def testNothing(self):
@classmethod
def tearDownClass(cls):
ordering.append('tearDownClass')
- raise Exception('TearDownExc')
+ raise CustomError('TearDownExc')
result = runTests(TestableTest)
self.assertEqual(result.errors[0][1].splitlines()[-1],
- 'Exception: TearDownExc')
+ f'{CustomErrorRepr}: TearDownExc')
self.assertEqual(ordering,
['setUpClass', 'test', 'tearDownClass', 'cleanup_good'])
@@ -620,7 +633,7 @@ def module_cleanup_good(*args, **kwargs):
module_cleanups.append((3, args, kwargs))
def module_cleanup_bad(*args, **kwargs):
- raise Exception('CleanUpExc')
+ raise CustomError('CleanUpExc')
class Module(object):
unittest.addModuleCleanup(module_cleanup_good, 1, 2, 3,
@@ -630,7 +643,7 @@ class Module(object):
[(module_cleanup_good, (1, 2, 3),
dict(four='hello', five='goodbye')),
(module_cleanup_bad, (), {})])
- with self.assertRaises(Exception) as e:
+ with self.assertRaises(CustomError) as e:
unittest.case.doModuleCleanups()
self.assertEqual(str(e.exception), 'CleanUpExc')
self.assertEqual(unittest.case._module_cleanups, [])
@@ -659,7 +672,7 @@ def setUpModule():
ordering.append('setUpModule')
unittest.addModuleCleanup(cleanup, ordering)
if blowUp:
- raise Exception('setUpModule Exc')
+ raise CustomError('setUpModule Exc')
@staticmethod
def tearDownModule():
ordering.append('tearDownModule')
@@ -679,7 +692,7 @@ def tearDownClass(cls):
result = runTests(TestableTest)
self.assertEqual(ordering, ['setUpModule', 'cleanup_good'])
self.assertEqual(result.errors[0][1].splitlines()[-1],
- 'Exception: setUpModule Exc')
+ f'{CustomErrorRepr}: setUpModule Exc')
ordering = []
blowUp = False
@@ -699,7 +712,7 @@ def setUpModule():
ordering.append('setUpModule')
unittest.addModuleCleanup(cleanup, ordering)
if blowUp:
- raise Exception()
+ raise CustomError()
@staticmethod
def tearDownModule():
ordering.append('tearDownModule')
@@ -710,7 +723,7 @@ def setUpModule():
ordering.append('setUpModule2')
unittest.addModuleCleanup(cleanup, ordering)
if blowUp2:
- raise Exception()
+ raise CustomError()
@staticmethod
def tearDownModule():
ordering.append('tearDownModule2')
@@ -799,7 +812,7 @@ def setUpModule():
@staticmethod
def tearDownModule():
ordering.append('tearDownModule')
- raise Exception('CleanUpExc')
+ raise CustomError('CleanUpExc')
class TestableTest(unittest.TestCase):
@classmethod
@@ -815,7 +828,7 @@ def tearDownClass(cls):
sys.modules['Module'] = Module
result = runTests(TestableTest)
self.assertEqual(result.errors[0][1].splitlines()[-1],
- 'Exception: CleanUpExc')
+ f'{CustomErrorRepr}: CleanUpExc')
self.assertEqual(ordering, ['setUpModule', 'setUpClass', 'test',
'tearDownClass', 'tearDownModule',
'cleanup_good'])
@@ -855,7 +868,7 @@ def tearDownClass(cls):
ordering = []
blowUp = True
suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestableTest)
- with self.assertRaises(Exception) as cm:
+ with self.assertRaises(CustomError) as cm:
suite.debug()
self.assertEqual(str(cm.exception), 'CleanUpExc')
self.assertEqual(ordering, ['setUpModule', 'setUpClass', 'test',
@@ -873,7 +886,7 @@ def setUpModule():
@staticmethod
def tearDownModule():
ordering.append('tearDownModule')
- raise Exception('TearDownModuleExc')
+ raise CustomError('TearDownModuleExc')
class TestableTest(unittest.TestCase):
@classmethod
@@ -888,7 +901,7 @@ def tearDownClass(cls):
TestableTest.__module__ = 'Module'
sys.modules['Module'] = Module
suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestableTest)
- with self.assertRaises(Exception) as cm:
+ with self.assertRaises(CustomError) as cm:
suite.debug()
self.assertEqual(str(cm.exception), 'TearDownModuleExc')
self.assertEqual(ordering, ['setUpModule', 'setUpClass', 'test',
@@ -899,7 +912,7 @@ def tearDownClass(cls):
ordering = []
blowUp = True
suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestableTest)
- with self.assertRaises(Exception) as cm:
+ with self.assertRaises(CustomError) as cm:
suite.debug()
self.assertEqual(str(cm.exception), 'TearDownModuleExc')
self.assertEqual(ordering, ['setUpModule', 'setUpClass', 'test',
@@ -978,7 +991,7 @@ def tearDownClass(cls):
result = runTests(TestableTest)
self.assertEqual(result.errors[0][1].splitlines()[-1],
- 'Exception: CleanUpExc')
+ f'{CustomErrorRepr}: CleanUpExc')
self.assertEqual(ordering,
['setUpModule', 'setUpClass', 'test', 'tearDownClass',
'cleanup_exc', 'tearDownModule', 'cleanup_good'])
@@ -1008,7 +1021,7 @@ def tearDown(self):
result = runTests(TestableTest)
self.assertEqual(result.errors[0][1].splitlines()[-1],
- 'Exception: CleanUpExc')
+ f'{CustomErrorRepr}: CleanUpExc')
self.assertEqual(ordering,
['setUpModule', 'setUp', 'test', 'tearDown',
'cleanup_exc', 'tearDownModule', 'cleanup_good'])
@@ -1024,7 +1037,7 @@ def setUpModule():
ordering.append('setUpModule')
unittest.addModuleCleanup(cleanup, ordering, blowUp=True)
if module_blow_up:
- raise Exception('ModuleExc')
+ raise CustomError('ModuleExc')
@staticmethod
def tearDownModule():
ordering.append('tearDownModule')
@@ -1034,11 +1047,11 @@ class TestableTest(unittest.TestCase):
def setUpClass(cls):
ordering.append('setUpClass')
if class_blow_up:
- raise Exception('ClassExc')
+ raise CustomError('ClassExc')
def setUp(self):
ordering.append('setUp')
if method_blow_up:
- raise Exception('MethodExc')
+ raise CustomError('MethodExc')
def testNothing(self):
ordering.append('test')
@classmethod
@@ -1050,7 +1063,7 @@ def tearDownClass(cls):
result = runTests(TestableTest)
self.assertEqual(result.errors[0][1].splitlines()[-1],
- 'Exception: CleanUpExc')
+ f'{CustomErrorRepr}: CleanUpExc')
self.assertEqual(ordering,
['setUpModule', 'setUpClass', 'setUp', 'test',
'tearDownClass', 'tearDownModule',
@@ -1062,9 +1075,9 @@ def tearDownClass(cls):
method_blow_up = False
result = runTests(TestableTest)
self.assertEqual(result.errors[0][1].splitlines()[-1],
- 'Exception: ModuleExc')
+ f'{CustomErrorRepr}: ModuleExc')
self.assertEqual(result.errors[1][1].splitlines()[-1],
- 'Exception: CleanUpExc')
+ f'{CustomErrorRepr}: CleanUpExc')
self.assertEqual(ordering, ['setUpModule', 'cleanup_exc'])
ordering = []
@@ -1073,9 +1086,9 @@ def tearDownClass(cls):
method_blow_up = False
result = runTests(TestableTest)
self.assertEqual(result.errors[0][1].splitlines()[-1],
- 'Exception: ClassExc')
+ f'{CustomErrorRepr}: ClassExc')
self.assertEqual(result.errors[1][1].splitlines()[-1],
- 'Exception: CleanUpExc')
+ f'{CustomErrorRepr}: CleanUpExc')
self.assertEqual(ordering, ['setUpModule', 'setUpClass',
'tearDownModule', 'cleanup_exc'])
@@ -1085,9 +1098,9 @@ def tearDownClass(cls):
method_blow_up = True
result = runTests(TestableTest)
self.assertEqual(result.errors[0][1].splitlines()[-1],
- 'Exception: MethodExc')
+ f'{CustomErrorRepr}: MethodExc')
self.assertEqual(result.errors[1][1].splitlines()[-1],
- 'Exception: CleanUpExc')
+ f'{CustomErrorRepr}: CleanUpExc')
self.assertEqual(ordering, ['setUpModule', 'setUpClass', 'setUp',
'tearDownClass', 'tearDownModule',
'cleanup_exc'])
diff --git a/Makefile.pre.in b/Makefile.pre.in
index d8fdb34747011d..bcec0782f6e95e 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -405,6 +405,7 @@ PYTHON_OBJS= \
Python/mysnprintf.o \
Python/mystrtoul.o \
Python/optimizer.o \
+ Python/optimizer_analysis.o \
Python/pathconfig.o \
Python/preconfig.o \
Python/pyarena.o \
@@ -1253,7 +1254,7 @@ regen-frozen: Tools/build/freeze_modules.py $(FROZEN_FILES_IN)
.PHONY: regen-deepfreeze
regen-deepfreeze: $(DEEPFREEZE_OBJS)
-DEEPFREEZE_DEPS=$(srcdir)/Tools/build/deepfreeze.py $(FREEZE_MODULE_DEPS) $(FROZEN_FILES_OUT)
+DEEPFREEZE_DEPS=$(srcdir)/Tools/build/deepfreeze.py Include/internal/pycore_global_strings.h $(FREEZE_MODULE_DEPS) $(FROZEN_FILES_OUT)
# BEGIN: deepfreeze modules
Python/deepfreeze/deepfreeze.c: $(DEEPFREEZE_DEPS)
@@ -1430,12 +1431,9 @@ regen-opcode:
# using Tools/build/generate_opcode_h.py
$(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/generate_opcode_h.py \
$(srcdir)/Lib/opcode.py \
- $(srcdir)/Lib/_opcode_metadata.py \
$(srcdir)/Include/opcode.h.new \
- $(srcdir)/Python/opcode_targets.h.new \
$(srcdir)/Include/internal/pycore_opcode.h.new
$(UPDATE_FILE) $(srcdir)/Include/opcode.h $(srcdir)/Include/opcode.h.new
- $(UPDATE_FILE) $(srcdir)/Python/opcode_targets.h $(srcdir)/Python/opcode_targets.h.new
$(UPDATE_FILE) $(srcdir)/Include/internal/pycore_opcode.h $(srcdir)/Include/internal/pycore_opcode.h.new
.PHONY: regen-token
@@ -1547,13 +1545,19 @@ regen-cases:
$(srcdir)/Tools/cases_generator/generate_cases.py \
$(CASESFLAG) \
-o $(srcdir)/Python/generated_cases.c.h.new \
+ -n $(srcdir)/Include/opcode_ids.h.new \
+ -t $(srcdir)/Python/opcode_targets.h.new \
-m $(srcdir)/Include/internal/pycore_opcode_metadata.h.new \
-e $(srcdir)/Python/executor_cases.c.h.new \
-p $(srcdir)/Lib/_opcode_metadata.py.new \
+ -a $(srcdir)/Python/abstract_interp_cases.c.h.new \
$(srcdir)/Python/bytecodes.c
$(UPDATE_FILE) $(srcdir)/Python/generated_cases.c.h $(srcdir)/Python/generated_cases.c.h.new
+ $(UPDATE_FILE) $(srcdir)/Include/opcode_ids.h $(srcdir)/Include/opcode_ids.h.new
+ $(UPDATE_FILE) $(srcdir)/Python/opcode_targets.h $(srcdir)/Python/opcode_targets.h.new
$(UPDATE_FILE) $(srcdir)/Include/internal/pycore_opcode_metadata.h $(srcdir)/Include/internal/pycore_opcode_metadata.h.new
$(UPDATE_FILE) $(srcdir)/Python/executor_cases.c.h $(srcdir)/Python/executor_cases.c.h.new
+ $(UPDATE_FILE) $(srcdir)/Python/abstract_interp_cases.c.h $(srcdir)/Python/abstract_interp_cases.c.h.new
$(UPDATE_FILE) $(srcdir)/Lib/_opcode_metadata.py $(srcdir)/Lib/_opcode_metadata.py.new
Python/compile.o: $(srcdir)/Include/internal/pycore_opcode_metadata.h
@@ -1566,6 +1570,7 @@ Python/ceval.o: \
Python/executor.o: \
$(srcdir)/Include/internal/pycore_opcode_metadata.h \
+ $(srcdir)/Include/internal/pycore_optimizer.h \
$(srcdir)/Python/ceval_macros.h \
$(srcdir)/Python/executor_cases.c.h
@@ -1574,7 +1579,12 @@ Python/flowgraph.o: \
Python/optimizer.o: \
$(srcdir)/Python/executor_cases.c.h \
- $(srcdir)/Include/internal/pycore_opcode_metadata.h
+ $(srcdir)/Include/internal/pycore_opcode_metadata.h \
+ $(srcdir)/Include/internal/pycore_optimizer.h
+
+Python/optimizer_analysis.o: \
+ $(srcdir)/Include/internal/pycore_opcode_metadata.h \
+ $(srcdir)/Include/internal/pycore_optimizer.h
Python/frozen.o: $(FROZEN_FILES_OUT)
@@ -1784,6 +1794,7 @@ PYTHON_HEADERS= \
$(srcdir)/Include/internal/pycore_obmalloc_init.h \
$(srcdir)/Include/internal/pycore_opcode.h \
$(srcdir)/Include/internal/pycore_opcode_utils.h \
+ $(srcdir)/Include/internal/pycore_optimizer.h \
$(srcdir)/Include/internal/pycore_pathconfig.h \
$(srcdir)/Include/internal/pycore_pyarena.h \
$(srcdir)/Include/internal/pycore_pyerrors.h \
diff --git a/Misc/NEWS.d/next/Build/2023-08-09-17-05-33.gh-issue-107814.c0Oapq.rst b/Misc/NEWS.d/next/Build/2023-08-09-17-05-33.gh-issue-107814.c0Oapq.rst
new file mode 100644
index 00000000000000..d3723353470ce2
--- /dev/null
+++ b/Misc/NEWS.d/next/Build/2023-08-09-17-05-33.gh-issue-107814.c0Oapq.rst
@@ -0,0 +1 @@
+When calling ``find_python.bat`` with ``-q`` it did not properly silence the output of nuget. That is now fixed.
diff --git a/Misc/NEWS.d/next/C API/2023-08-10-11-12-25.gh-issue-107810.oJ40Qx.rst b/Misc/NEWS.d/next/C API/2023-08-10-11-12-25.gh-issue-107810.oJ40Qx.rst
new file mode 100644
index 00000000000000..c8a1f6d122b61b
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2023-08-10-11-12-25.gh-issue-107810.oJ40Qx.rst
@@ -0,0 +1 @@
+Improve :exc:`DeprecationWarning` for uses of :c:type:`PyType_Spec` with metaclasses that have custom ``tp_new``.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-20-10-53-17.gh-issue-105724.d23L4M.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-20-10-53-17.gh-issue-105724.d23L4M.rst
new file mode 100644
index 00000000000000..281c139d1a8d1c
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-20-10-53-17.gh-issue-105724.d23L4M.rst
@@ -0,0 +1 @@
+Improve ``assert`` error messages by providing exact error range.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-16-07-55-19.gh-issue-106485.wPb1bH.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-16-07-55-19.gh-issue-106485.wPb1bH.rst
new file mode 100644
index 00000000000000..1f80082821edac
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-16-07-55-19.gh-issue-106485.wPb1bH.rst
@@ -0,0 +1,2 @@
+Reduce the number of materialized instances dictionaries by dematerializing
+them when possible.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-02-09-55-21.gh-issue-107557.P1z-in.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-02-09-55-21.gh-issue-107557.P1z-in.rst
new file mode 100644
index 00000000000000..392f59c79e8de9
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-08-02-09-55-21.gh-issue-107557.P1z-in.rst
@@ -0,0 +1 @@
+Generate the cases needed for the barebones tier 2 abstract interpreter for optimization passes in CPython.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-05-04-47-18.gh-issue-107674.0sYhR2.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-05-04-47-18.gh-issue-107674.0sYhR2.rst
new file mode 100644
index 00000000000000..acfbf1fa2adf2c
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-08-05-04-47-18.gh-issue-107674.0sYhR2.rst
@@ -0,0 +1 @@
+Fixed performance regression in ``sys.settrace``.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-05-09-06-56.gh-issue-105848.Drc-1-.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-05-09-06-56.gh-issue-105848.Drc-1-.rst
new file mode 100644
index 00000000000000..6c1c3229475f6f
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-08-05-09-06-56.gh-issue-105848.Drc-1-.rst
@@ -0,0 +1,3 @@
+Modify the bytecode so that the actual callable for a :opcode:`CALL` is at a
+consistent position on the stack (regardless of whether or not
+bound-method-calling optimizations are active).
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-09-08-31-20.gh-issue-84805.7JRWua.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-09-08-31-20.gh-issue-84805.7JRWua.rst
new file mode 100644
index 00000000000000..23dfba989fa552
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-08-09-08-31-20.gh-issue-84805.7JRWua.rst
@@ -0,0 +1,2 @@
+Autogenerate signature for :c:macro:`METH_NOARGS` and :c:macro:`METH_O`
+extension functions.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-10-17-36-27.gh-issue-91051.LfaeNW.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-10-17-36-27.gh-issue-91051.LfaeNW.rst
new file mode 100644
index 00000000000000..b4b90ad4ea0ecc
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-08-10-17-36-27.gh-issue-91051.LfaeNW.rst
@@ -0,0 +1,2 @@
+Fix abort / segfault when using all eight type watcher slots, on platforms
+where ``char`` is signed by default.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-11-16-18-19.gh-issue-108035.e2msOD.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-11-16-18-19.gh-issue-108035.e2msOD.rst
new file mode 100644
index 00000000000000..fc2369ddabb83c
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-08-11-16-18-19.gh-issue-108035.e2msOD.rst
@@ -0,0 +1,4 @@
+Remove the ``_PyCFrame`` struct, moving the pointer to the current intepreter frame
+back to the threadstate, as it was for 3.10 and earlier. The ``_PyCFrame``
+existed as a performance optimization for tracing. Since PEP 669 has been
+implemented, this optimization no longer applies.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-15-13-06-05.gh-issue-107971.lPbx04.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-15-13-06-05.gh-issue-107971.lPbx04.rst
new file mode 100644
index 00000000000000..dc10f672d8871e
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-08-15-13-06-05.gh-issue-107971.lPbx04.rst
@@ -0,0 +1,2 @@
+Opcode IDs are generated from bytecodes.c instead of being hard coded in
+opcode.py.
diff --git a/Misc/NEWS.d/next/Library/2022-11-26-22-05-22.gh-issue-99203.j0DUae.rst b/Misc/NEWS.d/next/Library/2022-11-26-22-05-22.gh-issue-99203.j0DUae.rst
new file mode 100644
index 00000000000000..fcfb044d476acc
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-11-26-22-05-22.gh-issue-99203.j0DUae.rst
@@ -0,0 +1,5 @@
+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 ``format`` choice. Beyond the brought-back behavior, the function
+may now also raise these exceptions in ``dry_run`` mode.
diff --git a/Misc/NEWS.d/next/Library/2023-03-14-01-19-57.gh-issue-100061.CiXJYn.rst b/Misc/NEWS.d/next/Library/2023-03-14-01-19-57.gh-issue-100061.CiXJYn.rst
new file mode 100644
index 00000000000000..dfed34f6ae9768
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-03-14-01-19-57.gh-issue-100061.CiXJYn.rst
@@ -0,0 +1,2 @@
+Fix a bug that causes wrong matches for regular expressions with possessive
+qualifier.
diff --git a/Misc/NEWS.d/next/Library/2023-04-08-12-43-52.gh-issue-101162.yOCd_J.rst b/Misc/NEWS.d/next/Library/2023-04-08-12-43-52.gh-issue-101162.yOCd_J.rst
new file mode 100644
index 00000000000000..e9fadc8f436d9b
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-08-12-43-52.gh-issue-101162.yOCd_J.rst
@@ -0,0 +1,2 @@
+Forbid using :func:`builtins.issubclass` with :class:`types.GenericAlias` as
+the first argument.
diff --git a/Misc/NEWS.d/next/Library/2023-07-09-00-36-33.gh-issue-106558.Zqsj6F.rst b/Misc/NEWS.d/next/Library/2023-07-09-00-36-33.gh-issue-106558.Zqsj6F.rst
new file mode 100644
index 00000000000000..8fe677f5d84b5f
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-07-09-00-36-33.gh-issue-106558.Zqsj6F.rst
@@ -0,0 +1,3 @@
+Remove ref cycle in callers of
+:func:`~multiprocessing.managers.convert_to_error` by deleting ``result``
+from scope in a ``finally`` block.
diff --git a/Misc/NEWS.d/next/Library/2023-07-29-02-36-50.gh-issue-107409.HG27Nu.rst b/Misc/NEWS.d/next/Library/2023-07-29-02-36-50.gh-issue-107409.HG27Nu.rst
new file mode 100644
index 00000000000000..1ecc7207605c70
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-07-29-02-36-50.gh-issue-107409.HG27Nu.rst
@@ -0,0 +1 @@
+Set :attr:`!__wrapped__` attribute in :func:`reprlib.recursive_repr`.
diff --git a/Misc/NEWS.d/next/Library/2023-08-08-16-09-59.gh-issue-56166.WUMhYG.rst b/Misc/NEWS.d/next/Library/2023-08-08-16-09-59.gh-issue-56166.WUMhYG.rst
new file mode 100644
index 00000000000000..34d776ae8fc3ff
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-08-08-16-09-59.gh-issue-56166.WUMhYG.rst
@@ -0,0 +1,3 @@
+Deprecate passing optional arguments *maxsplit*, *count* and *flags* in
+module-level functions :func:`re.split`, :func:`re.sub` and :func:`re.subn` as positional.
+They should only be passed by keyword.
diff --git a/Misc/NEWS.d/next/Library/2023-08-08-19-57-45.gh-issue-107782.mInjFE.rst b/Misc/NEWS.d/next/Library/2023-08-08-19-57-45.gh-issue-107782.mInjFE.rst
new file mode 100644
index 00000000000000..fb8a50de3a9eee
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-08-08-19-57-45.gh-issue-107782.mInjFE.rst
@@ -0,0 +1,2 @@
+:mod:`pydoc` is now able to show signatures which are not representable in
+Python, e.g. for ``getattr`` and ``dict.pop``.
diff --git a/Misc/NEWS.d/next/Library/2023-08-09-15-37-20.gh-issue-107812.CflAXa.rst b/Misc/NEWS.d/next/Library/2023-08-09-15-37-20.gh-issue-107812.CflAXa.rst
new file mode 100644
index 00000000000000..0aac44fb418836
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-08-09-15-37-20.gh-issue-107812.CflAXa.rst
@@ -0,0 +1 @@
+Extend socket's netlink support to the FreeBSD platform.
diff --git a/Misc/NEWS.d/next/Library/2023-08-14-17-15-59.gh-issue-76913.LLD0rT.rst b/Misc/NEWS.d/next/Library/2023-08-14-17-15-59.gh-issue-76913.LLD0rT.rst
new file mode 100644
index 00000000000000..5f9a84e714ae20
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-08-14-17-15-59.gh-issue-76913.LLD0rT.rst
@@ -0,0 +1 @@
+Add *merge_extra* parameter/feature to :class:`logging.LoggerAdapter`
diff --git a/Misc/NEWS.d/next/Library/2023-08-14-19-49-02.gh-issue-93057.5nJwO5.rst b/Misc/NEWS.d/next/Library/2023-08-14-19-49-02.gh-issue-93057.5nJwO5.rst
new file mode 100644
index 00000000000000..6a4feaac25bc11
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-08-14-19-49-02.gh-issue-93057.5nJwO5.rst
@@ -0,0 +1,3 @@
+Passing more than one positional argument to :func:`sqlite3.connect` and the
+:class:`sqlite3.Connection` constructor is deprecated. The remaining parameters
+will become keyword-only in Python 3.15. Patch by Erlend E. Aasland.
diff --git a/Misc/NEWS.d/next/Library/2023-08-14-23-11-11.gh-issue-106242.71HMym.rst b/Misc/NEWS.d/next/Library/2023-08-14-23-11-11.gh-issue-106242.71HMym.rst
new file mode 100644
index 00000000000000..44237a9f15708c
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-08-14-23-11-11.gh-issue-106242.71HMym.rst
@@ -0,0 +1 @@
+Fixes :func:`os.path.normpath` to handle embedded null characters without truncating the path.
diff --git a/Misc/NEWS.d/next/Library/2023-08-15-18-20-00.gh-issue-107963.20g5BG.rst b/Misc/NEWS.d/next/Library/2023-08-15-18-20-00.gh-issue-107963.20g5BG.rst
new file mode 100644
index 00000000000000..3a73b2da0c4334
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-08-15-18-20-00.gh-issue-107963.20g5BG.rst
@@ -0,0 +1,2 @@
+Fix :func:`multiprocessing.set_forkserver_preload` to check the given list
+of modules names. Patch by Dong-hee Na.
diff --git a/Misc/NEWS.d/next/Security/2023-08-05-03-51-05.gh-issue-107774.VPjaTR.rst b/Misc/NEWS.d/next/Security/2023-08-05-03-51-05.gh-issue-107774.VPjaTR.rst
new file mode 100644
index 00000000000000..b89b50c79f7e2a
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2023-08-05-03-51-05.gh-issue-107774.VPjaTR.rst
@@ -0,0 +1,3 @@
+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.
diff --git a/Misc/NEWS.d/next/Tools-Demos/2023-08-13-11-18-06.gh-issue-107880.gBVVQ7.rst b/Misc/NEWS.d/next/Tools-Demos/2023-08-13-11-18-06.gh-issue-107880.gBVVQ7.rst
new file mode 100644
index 00000000000000..fd9d6717f3a33f
--- /dev/null
+++ b/Misc/NEWS.d/next/Tools-Demos/2023-08-13-11-18-06.gh-issue-107880.gBVVQ7.rst
@@ -0,0 +1,2 @@
+Argument Clinic can now clone :meth:`!__init__` and :meth:`!__new__`
+methods.
diff --git a/Misc/NEWS.d/next/Windows/2023-07-18-13-01-26.gh-issue-106844.mci4xO.rst b/Misc/NEWS.d/next/Windows/2023-07-18-13-01-26.gh-issue-106844.mci4xO.rst
new file mode 100644
index 00000000000000..1fdf162ef4ecdd
--- /dev/null
+++ b/Misc/NEWS.d/next/Windows/2023-07-18-13-01-26.gh-issue-106844.mci4xO.rst
@@ -0,0 +1 @@
+Fix integer overflow and truncating by the null character in :func:`!_winapi.LCMapStringEx` which affects :func:`ntpath.normcase`.
diff --git a/Misc/python.man b/Misc/python.man
index bf7cf767d164a6..9f89c94adf5028 100644
--- a/Misc/python.man
+++ b/Misc/python.man
@@ -592,8 +592,8 @@ works on Mac OS X.
.IP PYTHONUSERBASE
Defines the user base directory, which is used to compute the path of the user
.IR site-packages
-directory and Distutils installation paths for
-.IR "python setup\.py install \-\-user" .
+directory and installation paths for
+.IR "python \-m pip install \-\-user" .
.IP PYTHONPROFILEIMPORTTIME
If this environment variable is set to a non-empty string, Python will
show how long each import takes. This is exactly equivalent to setting
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
index 9aee37a9d954ef..dc80291d3b810b 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -4793,6 +4793,16 @@ static PyMappingMethods Array_as_mapping = {
Array_ass_subscript,
};
+PyDoc_STRVAR(array_doc,
+"Abstract base class for arrays.\n"
+"\n"
+"The recommended way to create concrete array types is by multiplying any\n"
+"ctypes data type with a non-negative integer. Alternatively, you can subclass\n"
+"this type and define _length_ and _type_ class variables. Array elements can\n"
+"be read and written using standard subscript and slice accesses for slice\n"
+"reads, the resulting object is not itself an Array."
+);
+
PyTypeObject PyCArray_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_ctypes.Array",
@@ -4813,8 +4823,8 @@ PyTypeObject PyCArray_Type = {
0, /* tp_getattro */
0, /* tp_setattro */
&PyCData_as_buffer, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- PyDoc_STR("XXX to be provided"), /* tp_doc */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ array_doc, /* tp_doc */
(traverseproc)PyCData_traverse, /* tp_traverse */
(inquiry)PyCData_clear, /* tp_clear */
0, /* tp_richcompare */
diff --git a/Modules/_sqlite/clinic/_sqlite3.connect.c.h b/Modules/_sqlite/clinic/_sqlite3.connect.c.h
new file mode 100644
index 00000000000000..998c8de1e09f16
--- /dev/null
+++ b/Modules/_sqlite/clinic/_sqlite3.connect.c.h
@@ -0,0 +1,31 @@
+/*[clinic input]
+preserve
+[clinic start generated code]*/
+
+#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+# include "pycore_gc.h" // PyGC_Head
+# include "pycore_runtime.h" // _Py_ID()
+#endif
+
+
+PyDoc_STRVAR(pysqlite_connect__doc__,
+"connect($module, /, database, timeout=5.0, detect_types=0,\n"
+" isolation_level=\'\', check_same_thread=True,\n"
+" factory=ConnectionType, cached_statements=128, uri=False, *,\n"
+" autocommit=sqlite3.LEGACY_TRANSACTION_CONTROL)\n"
+"--\n"
+"\n"
+"Open a connection to the SQLite database file \'database\'.\n"
+"\n"
+"You can use \":memory:\" to open a database connection to a database that\n"
+"resides in RAM instead of on disk.\n"
+"\n"
+"Note: Passing more than 1 positional argument to _sqlite3.connect() is\n"
+"deprecated. Parameters \'timeout\', \'detect_types\', \'isolation_level\',\n"
+"\'check_same_thread\', \'factory\', \'cached_statements\' and \'uri\' will\n"
+"become keyword-only parameters in Python 3.15.\n"
+"");
+
+#define PYSQLITE_CONNECT_METHODDEF \
+ {"connect", _PyCFunction_CAST(pysqlite_connect), METH_FASTCALL|METH_KEYWORDS, pysqlite_connect__doc__},
+/*[clinic end generated code: output=8d49736db880f09a input=a9049054013a1b77]*/
diff --git a/Modules/_sqlite/clinic/connection.c.h b/Modules/_sqlite/clinic/connection.c.h
index e869d7d9e9384c..af98d61ea7cccc 100644
--- a/Modules/_sqlite/clinic/connection.c.h
+++ b/Modules/_sqlite/clinic/connection.c.h
@@ -59,6 +59,39 @@ pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs)
int uri = 0;
enum autocommit_mode autocommit = LEGACY_TRANSACTION_CONTROL;
+ // Emit compiler warnings when we get to Python 3.15.
+ #if PY_VERSION_HEX >= 0x030f00C0
+ # error \
+ "In connection.c, update parameter(s) 'timeout', 'detect_types', " \
+ "'isolation_level', 'check_same_thread', 'factory', " \
+ "'cached_statements' and 'uri' in the clinic input of " \
+ "'_sqlite3.Connection.__init__' to be keyword-only."
+ #elif PY_VERSION_HEX >= 0x030f00A0
+ # ifdef _MSC_VER
+ # pragma message ( \
+ "In connection.c, update parameter(s) 'timeout', 'detect_types', " \
+ "'isolation_level', 'check_same_thread', 'factory', " \
+ "'cached_statements' and 'uri' in the clinic input of " \
+ "'_sqlite3.Connection.__init__' to be keyword-only.")
+ # else
+ # warning \
+ "In connection.c, update parameter(s) 'timeout', 'detect_types', " \
+ "'isolation_level', 'check_same_thread', 'factory', " \
+ "'cached_statements' and 'uri' in the clinic input of " \
+ "'_sqlite3.Connection.__init__' to be keyword-only."
+ # endif
+ #endif
+ if (nargs > 1 && nargs <= 8) {
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "Passing more than 1 positional argument to _sqlite3.Connection()"
+ " is deprecated. Parameters 'timeout', 'detect_types', "
+ "'isolation_level', 'check_same_thread', 'factory', "
+ "'cached_statements' and 'uri' will become keyword-only "
+ "parameters in Python 3.15.", 1))
+ {
+ goto exit;
+ }
+ }
fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 8, 0, argsbuf);
if (!fastargs) {
goto exit;
@@ -1659,4 +1692,4 @@ getconfig(pysqlite_Connection *self, PyObject *arg)
#ifndef DESERIALIZE_METHODDEF
#define DESERIALIZE_METHODDEF
#endif /* !defined(DESERIALIZE_METHODDEF) */
-/*[clinic end generated code: output=d3c6cb9326736ea5 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=5a05e5294ad9d2ce input=a9049054013a1b77]*/
diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c
index ddd7ace81198bb..0819acd0940964 100644
--- a/Modules/_sqlite/connection.c
+++ b/Modules/_sqlite/connection.c
@@ -212,11 +212,11 @@ class sqlite3_int64_converter(CConverter):
[python start generated code]*/
/*[python end generated code: output=da39a3ee5e6b4b0d input=dff8760fb1eba6a1]*/
-// NB: This needs to be in sync with the sqlite3.connect docstring
/*[clinic input]
_sqlite3.Connection.__init__ as pysqlite_connection_init
database: object
+ * [from 3.15]
timeout: double = 5.0
detect_types: int = 0
isolation_level: IsolationLevel = ""
@@ -235,7 +235,7 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database,
int check_same_thread, PyObject *factory,
int cache_size, int uri,
enum autocommit_mode autocommit)
-/*[clinic end generated code: output=cba057313ea7712f input=9b0ab6c12f674fa3]*/
+/*[clinic end generated code: output=cba057313ea7712f input=219c3dbecbae7d99]*/
{
if (PySys_Audit("sqlite3.connect", "O", database) < 0) {
return -1;
@@ -346,6 +346,34 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database,
return -1;
}
+/*[clinic input]
+# Create a new destination 'connect' for the docstring and methoddef only.
+# This makes it possible to keep the signatures for Connection.__init__ and
+# sqlite3.connect() synchronised.
+output push
+destination connect new file '{dirname}/clinic/_sqlite3.connect.c.h'
+
+# Only output the docstring and the PyMethodDef entry.
+output everything suppress
+output docstring_definition connect
+output methoddef_define connect
+
+# Define the sqlite3.connect function by cloning Connection.__init__.
+_sqlite3.connect as pysqlite_connect = _sqlite3.Connection.__init__
+
+Open a connection to the SQLite database file 'database'.
+
+You can use ":memory:" to open a database connection to a database that
+resides in RAM instead of on disk.
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=92260edff95d1720]*/
+
+/*[clinic input]
+# Restore normal Argument Clinic operation for the rest of this file.
+output pop
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=b899ba9273edcce7]*/
+
#define VISIT_CALLBACK_CONTEXT(ctx) \
do { \
if (ctx) { \
diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c
index 368e581b4f3355..dd45ffc1988f7e 100644
--- a/Modules/_sqlite/module.c
+++ b/Modules/_sqlite/module.c
@@ -48,31 +48,33 @@ module _sqlite3
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=81e330492d57488e]*/
-// NB: This needs to be in sync with the Connection.__init__ docstring.
-PyDoc_STRVAR(module_connect_doc,
-"connect($module, /, database, timeout=5.0, detect_types=0,\n"
-" isolation_level='', check_same_thread=True,\n"
-" factory=ConnectionType, cached_statements=128, uri=False, *,\n"
-" autocommit=sqlite3.LEGACY_TRANSACTION_CONTROL)\n"
-"--\n"
-"\n"
-"Opens a connection to the SQLite database file database.\n"
-"\n"
-"You can use \":memory:\" to open a database connection to a database that resides\n"
-"in RAM instead of on disk.");
-
-#define PYSQLITE_CONNECT_METHODDEF \
- {"connect", _PyCFunction_CAST(module_connect), METH_FASTCALL|METH_KEYWORDS, module_connect_doc},
+/*
+ * We create 'clinic/_sqlite3.connect.c.h' in connection.c, in order to
+ * keep the signatures of sqlite3.Connection.__init__ and
+ * sqlite3.connect() synchronised.
+ */
+#include "clinic/_sqlite3.connect.c.h"
static PyObject *
-module_connect(PyObject *module, PyObject *const *args, Py_ssize_t nargsf,
- PyObject *kwnames)
+pysqlite_connect(PyObject *module, PyObject *const *args, Py_ssize_t nargsf,
+ PyObject *kwnames)
{
pysqlite_state *state = pysqlite_get_state(module);
PyObject *factory = (PyObject *)state->ConnectionType;
static const int FACTORY_POS = 5;
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
+ if (nargs > 1 && nargs <= 8) {
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "Passing more than 1 positional argument to sqlite3.connect()"
+ " is deprecated. Parameters 'timeout', 'detect_types', "
+ "'isolation_level', 'check_same_thread', 'factory', "
+ "'cached_statements' and 'uri' will become keyword-only "
+ "parameters in Python 3.15.", 1))
+ {
+ return NULL;
+ }
+ }
if (nargs > FACTORY_POS) {
factory = args[FACTORY_POS];
}
diff --git a/Modules/_sre/sre_lib.h b/Modules/_sre/sre_lib.h
index c1a774f69090b3..ae80009fd63bbe 100644
--- a/Modules/_sre/sre_lib.h
+++ b/Modules/_sre/sre_lib.h
@@ -1336,6 +1336,10 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel)
MARK_POP(ctx->lastmark);
LASTMARK_RESTORE();
+ /* Restore the global Input Stream pointer
+ since it can change after jumps. */
+ state->ptr = ptr;
+
/* We have sufficient matches, so exit loop. */
break;
}
diff --git a/Modules/_testcapi/docstring.c b/Modules/_testcapi/docstring.c
index a997c54a8a69c4..b680171cc1437a 100644
--- a/Modules/_testcapi/docstring.c
+++ b/Modules/_testcapi/docstring.c
@@ -66,42 +66,88 @@ test_with_docstring(PyObject *self, PyObject *Py_UNUSED(ignored))
static PyMethodDef test_methods[] = {
{"docstring_empty",
- (PyCFunction)test_with_docstring, METH_NOARGS,
+ (PyCFunction)test_with_docstring, METH_VARARGS,
docstring_empty},
{"docstring_no_signature",
+ (PyCFunction)test_with_docstring, METH_VARARGS,
+ docstring_no_signature},
+ {"docstring_no_signature_noargs",
(PyCFunction)test_with_docstring, METH_NOARGS,
docstring_no_signature},
+ {"docstring_no_signature_o",
+ (PyCFunction)test_with_docstring, METH_O,
+ docstring_no_signature},
{"docstring_with_invalid_signature",
- (PyCFunction)test_with_docstring, METH_NOARGS,
+ (PyCFunction)test_with_docstring, METH_VARARGS,
docstring_with_invalid_signature},
{"docstring_with_invalid_signature2",
- (PyCFunction)test_with_docstring, METH_NOARGS,
+ (PyCFunction)test_with_docstring, METH_VARARGS,
docstring_with_invalid_signature2},
{"docstring_with_signature",
- (PyCFunction)test_with_docstring, METH_NOARGS,
+ (PyCFunction)test_with_docstring, METH_VARARGS,
docstring_with_signature},
{"docstring_with_signature_and_extra_newlines",
- (PyCFunction)test_with_docstring, METH_NOARGS,
+ (PyCFunction)test_with_docstring, METH_VARARGS,
docstring_with_signature_and_extra_newlines},
{"docstring_with_signature_but_no_doc",
- (PyCFunction)test_with_docstring, METH_NOARGS,
+ (PyCFunction)test_with_docstring, METH_VARARGS,
docstring_with_signature_but_no_doc},
{"docstring_with_signature_with_defaults",
- (PyCFunction)test_with_docstring, METH_NOARGS,
+ (PyCFunction)test_with_docstring, METH_VARARGS,
docstring_with_signature_with_defaults},
{"no_docstring",
- (PyCFunction)test_with_docstring, METH_NOARGS},
+ (PyCFunction)test_with_docstring, METH_VARARGS},
{"test_with_docstring",
- test_with_docstring, METH_NOARGS,
+ test_with_docstring, METH_VARARGS,
PyDoc_STR("This is a pretty normal docstring.")},
{NULL},
};
+static PyMethodDef DocStringNoSignatureTest_methods[] = {
+ {"meth_noargs",
+ (PyCFunction)test_with_docstring, METH_NOARGS,
+ docstring_no_signature},
+ {"meth_o",
+ (PyCFunction)test_with_docstring, METH_O,
+ docstring_no_signature},
+ {"meth_noargs_class",
+ (PyCFunction)test_with_docstring, METH_NOARGS|METH_CLASS,
+ docstring_no_signature},
+ {"meth_o_class",
+ (PyCFunction)test_with_docstring, METH_O|METH_CLASS,
+ docstring_no_signature},
+ {"meth_noargs_static",
+ (PyCFunction)test_with_docstring, METH_NOARGS|METH_STATIC,
+ docstring_no_signature},
+ {"meth_o_static",
+ (PyCFunction)test_with_docstring, METH_O|METH_STATIC,
+ docstring_no_signature},
+ {"meth_noargs_coexist",
+ (PyCFunction)test_with_docstring, METH_NOARGS|METH_COEXIST,
+ docstring_no_signature},
+ {"meth_o_coexist",
+ (PyCFunction)test_with_docstring, METH_O|METH_COEXIST,
+ docstring_no_signature},
+ {NULL},
+};
+
+static PyTypeObject DocStringNoSignatureTest = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "_testcapi.DocStringNoSignatureTest",
+ .tp_basicsize = sizeof(PyObject),
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_methods = DocStringNoSignatureTest_methods,
+ .tp_new = PyType_GenericNew,
+};
+
int
_PyTestCapi_Init_Docstring(PyObject *mod)
{
if (PyModule_AddFunctions(mod, test_methods) < 0) {
return -1;
}
+ if (PyModule_AddType(mod, &DocStringNoSignatureTest) < 0) {
+ return -1;
+ }
return 0;
}
diff --git a/Modules/_testcapi/watchers.c b/Modules/_testcapi/watchers.c
index 4cf567b3314980..8a264bba4ed6ed 100644
--- a/Modules/_testcapi/watchers.c
+++ b/Modules/_testcapi/watchers.c
@@ -295,6 +295,7 @@ _testcapi_unwatch_type_impl(PyObject *module, int watcher_id, PyObject *type)
// Test code object watching
#define NUM_CODE_WATCHERS 2
+static int code_watcher_ids[NUM_CODE_WATCHERS] = {-1, -1};
static int num_code_object_created_events[NUM_CODE_WATCHERS] = {0, 0};
static int num_code_object_destroyed_events[NUM_CODE_WATCHERS] = {0, 0};
@@ -345,11 +346,13 @@ add_code_watcher(PyObject *self, PyObject *which_watcher)
long which_l = PyLong_AsLong(which_watcher);
if (which_l == 0) {
watcher_id = PyCode_AddWatcher(first_code_object_callback);
+ code_watcher_ids[0] = watcher_id;
num_code_object_created_events[0] = 0;
num_code_object_destroyed_events[0] = 0;
}
else if (which_l == 1) {
watcher_id = PyCode_AddWatcher(second_code_object_callback);
+ code_watcher_ids[1] = watcher_id;
num_code_object_created_events[1] = 0;
num_code_object_destroyed_events[1] = 0;
}
@@ -375,9 +378,14 @@ clear_code_watcher(PyObject *self, PyObject *watcher_id)
return NULL;
}
// reset static events counters
- if (watcher_id_l >= 0 && watcher_id_l < NUM_CODE_WATCHERS) {
- num_code_object_created_events[watcher_id_l] = 0;
- num_code_object_destroyed_events[watcher_id_l] = 0;
+ if (watcher_id_l >= 0) {
+ for (int i = 0; i < NUM_CODE_WATCHERS; i++) {
+ if (watcher_id_l == code_watcher_ids[i]) {
+ code_watcher_ids[i] = -1;
+ num_code_object_created_events[i] = 0;
+ num_code_object_destroyed_events[i] = 0;
+ }
+ }
}
Py_RETURN_NONE;
}
diff --git a/Modules/_testclinic.c b/Modules/_testclinic.c
index 8ba8f8ecadec7a..c33536234af0bc 100644
--- a/Modules/_testclinic.c
+++ b/Modules/_testclinic.c
@@ -1193,6 +1193,274 @@ clone_with_conv_f2_impl(PyObject *module, custom_t path)
}
+/*[clinic input]
+output push
+destination deprstar new file '{dirname}/clinic/_testclinic_depr_star.c.h'
+output everything deprstar
+#output methoddef_ifndef buffer 1
+output docstring_prototype suppress
+output parser_prototype suppress
+output impl_definition block
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=f88f37038e00fb0a]*/
+
+
+// Mock Python version 3.8
+#define _SAVED_PY_VERSION PY_VERSION_HEX
+#undef PY_VERSION_HEX
+#define PY_VERSION_HEX 0x03080000
+
+
+#include "clinic/_testclinic_depr_star.c.h"
+
+
+/*[clinic input]
+class _testclinic.DeprStarNew "PyObject *" "PyObject"
+@classmethod
+_testclinic.DeprStarNew.__new__ as depr_star_new
+ * [from 3.14]
+ a: object
+The deprecation message should use the class name instead of __new__.
+[clinic start generated code]*/
+
+static PyObject *
+depr_star_new_impl(PyTypeObject *type, PyObject *a)
+/*[clinic end generated code: output=bdbb36244f90cf46 input=f4ae7dafbc23c378]*/
+{
+ return type->tp_alloc(type, 0);
+}
+
+/*[clinic input]
+_testclinic.DeprStarNew.cloned as depr_star_new_clone = _testclinic.DeprStarNew.__new__
+[clinic start generated code]*/
+
+static PyObject *
+depr_star_new_clone_impl(PyObject *type, PyObject *a)
+/*[clinic end generated code: output=3b17bf885fa736bc input=ea659285d5dbec6c]*/
+{
+ Py_RETURN_NONE;
+}
+
+static struct PyMethodDef depr_star_new_methods[] = {
+ DEPR_STAR_NEW_CLONE_METHODDEF
+ {NULL, NULL}
+};
+
+static PyTypeObject DeprStarNew = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "_testclinic.DeprStarNew",
+ .tp_basicsize = sizeof(PyObject),
+ .tp_new = depr_star_new,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_methods = depr_star_new_methods,
+};
+
+
+/*[clinic input]
+class _testclinic.DeprStarInit "PyObject *" "PyObject"
+_testclinic.DeprStarInit.__init__ as depr_star_init
+ * [from 3.14]
+ a: object
+The deprecation message should use the class name instead of __init__.
+[clinic start generated code]*/
+
+static int
+depr_star_init_impl(PyObject *self, PyObject *a)
+/*[clinic end generated code: output=8d27b43c286d3ecc input=659ebc748d87fa86]*/
+{
+ return 0;
+}
+
+/*[clinic input]
+_testclinic.DeprStarInit.cloned as depr_star_init_clone = _testclinic.DeprStarInit.__init__
+[clinic start generated code]*/
+
+static PyObject *
+depr_star_init_clone_impl(PyObject *self, PyObject *a)
+/*[clinic end generated code: output=ddfe8a1b5531e7cc input=561e103fe7f8e94f]*/
+{
+ Py_RETURN_NONE;
+}
+
+static struct PyMethodDef depr_star_init_methods[] = {
+ DEPR_STAR_INIT_CLONE_METHODDEF
+ {NULL, NULL}
+};
+
+static PyTypeObject DeprStarInit = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "_testclinic.DeprStarInit",
+ .tp_basicsize = sizeof(PyObject),
+ .tp_new = PyType_GenericNew,
+ .tp_init = depr_star_init,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_methods = depr_star_init_methods,
+};
+
+
+/*[clinic input]
+depr_star_pos0_len1
+ * [from 3.14]
+ a: object
+[clinic start generated code]*/
+
+static PyObject *
+depr_star_pos0_len1_impl(PyObject *module, PyObject *a)
+/*[clinic end generated code: output=e1c6c2b423129499 input=089b9aee25381b69]*/
+{
+ Py_RETURN_NONE;
+}
+
+
+/*[clinic input]
+depr_star_pos0_len2
+ * [from 3.14]
+ a: object
+ b: object
+[clinic start generated code]*/
+
+static PyObject *
+depr_star_pos0_len2_impl(PyObject *module, PyObject *a, PyObject *b)
+/*[clinic end generated code: output=96df9be39859c7e4 input=65c83a32e01495c6]*/
+{
+ Py_RETURN_NONE;
+}
+
+
+/*[clinic input]
+depr_star_pos0_len3_with_kwd
+ * [from 3.14]
+ a: object
+ b: object
+ c: object
+ *
+ d: object
+[clinic start generated code]*/
+
+static PyObject *
+depr_star_pos0_len3_with_kwd_impl(PyObject *module, PyObject *a, PyObject *b,
+ PyObject *c, PyObject *d)
+/*[clinic end generated code: output=7f2531eda837052f input=b33f620f57d9270f]*/
+{
+ Py_RETURN_NONE;
+}
+
+
+/*[clinic input]
+depr_star_pos1_len1_opt
+ a: object
+ * [from 3.14]
+ b: object = None
+[clinic start generated code]*/
+
+static PyObject *
+depr_star_pos1_len1_opt_impl(PyObject *module, PyObject *a, PyObject *b)
+/*[clinic end generated code: output=b5b4e326ee3b216f input=4a4b8ff72eae9ff7]*/
+{
+ Py_RETURN_NONE;
+}
+
+
+/*[clinic input]
+depr_star_pos1_len1
+ a: object
+ * [from 3.14]
+ b: object
+[clinic start generated code]*/
+
+static PyObject *
+depr_star_pos1_len1_impl(PyObject *module, PyObject *a, PyObject *b)
+/*[clinic end generated code: output=eab92e37d5b0a480 input=1e7787a9fe5f62a0]*/
+{
+ Py_RETURN_NONE;
+}
+
+
+/*[clinic input]
+depr_star_pos1_len2_with_kwd
+ a: object
+ * [from 3.14]
+ b: object
+ c: object
+ *
+ d: object
+[clinic start generated code]*/
+
+static PyObject *
+depr_star_pos1_len2_with_kwd_impl(PyObject *module, PyObject *a, PyObject *b,
+ PyObject *c, PyObject *d)
+/*[clinic end generated code: output=3bccab672b7cfbb8 input=6bc7bd742fa8be15]*/
+{
+ Py_RETURN_NONE;
+}
+
+
+/*[clinic input]
+depr_star_pos2_len1
+ a: object
+ b: object
+ * [from 3.14]
+ c: object
+[clinic start generated code]*/
+
+static PyObject *
+depr_star_pos2_len1_impl(PyObject *module, PyObject *a, PyObject *b,
+ PyObject *c)
+/*[clinic end generated code: output=20f5b230e9beeb70 input=5fc3e1790dec00d5]*/
+{
+ Py_RETURN_NONE;
+}
+
+
+/*[clinic input]
+depr_star_pos2_len2
+ a: object
+ b: object
+ * [from 3.14]
+ c: object
+ d: object
+[clinic start generated code]*/
+
+static PyObject *
+depr_star_pos2_len2_impl(PyObject *module, PyObject *a, PyObject *b,
+ PyObject *c, PyObject *d)
+/*[clinic end generated code: output=9f90ed8fbce27d7a input=9cc8003b89d38779]*/
+{
+ Py_RETURN_NONE;
+}
+
+
+/*[clinic input]
+depr_star_pos2_len2_with_kwd
+ a: object
+ b: object
+ * [from 3.14]
+ c: object
+ d: object
+ *
+ e: object
+[clinic start generated code]*/
+
+static PyObject *
+depr_star_pos2_len2_with_kwd_impl(PyObject *module, PyObject *a, PyObject *b,
+ PyObject *c, PyObject *d, PyObject *e)
+/*[clinic end generated code: output=05432c4f20527215 input=831832d90534da91]*/
+{
+ Py_RETURN_NONE;
+}
+
+
+// Reset PY_VERSION_HEX
+#undef PY_VERSION_HEX
+#define PY_VERSION_HEX _SAVED_PY_VERSION
+#undef _SAVED_PY_VERSION
+
+
+/*[clinic input]
+output pop
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=e7c7c42daced52b0]*/
+
static PyMethodDef tester_methods[] = {
TEST_EMPTY_FUNCTION_METHODDEF
OBJECTS_CONVERTER_METHODDEF
@@ -1248,6 +1516,16 @@ static PyMethodDef tester_methods[] = {
CLONE_F2_METHODDEF
CLONE_WITH_CONV_F1_METHODDEF
CLONE_WITH_CONV_F2_METHODDEF
+
+ DEPR_STAR_POS0_LEN1_METHODDEF
+ DEPR_STAR_POS0_LEN2_METHODDEF
+ DEPR_STAR_POS0_LEN3_WITH_KWD_METHODDEF
+ DEPR_STAR_POS1_LEN1_OPT_METHODDEF
+ DEPR_STAR_POS1_LEN1_METHODDEF
+ DEPR_STAR_POS1_LEN2_WITH_KWD_METHODDEF
+ DEPR_STAR_POS2_LEN1_METHODDEF
+ DEPR_STAR_POS2_LEN2_METHODDEF
+ DEPR_STAR_POS2_LEN2_WITH_KWD_METHODDEF
{NULL, NULL}
};
@@ -1261,7 +1539,21 @@ static struct PyModuleDef _testclinic_module = {
PyMODINIT_FUNC
PyInit__testclinic(void)
{
- return PyModule_Create(&_testclinic_module);
+ PyObject *m = PyModule_Create(&_testclinic_module);
+ if (m == NULL) {
+ return NULL;
+ }
+ if (PyModule_AddType(m, &DeprStarNew) < 0) {
+ goto error;
+ }
+ if (PyModule_AddType(m, &DeprStarInit) < 0) {
+ goto error;
+ }
+ return m;
+
+error:
+ Py_DECREF(m);
+ return NULL;
}
#undef RETURN_PACKED_ARGS
diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c
index f28b46dd9846c8..d1082c7dae8aee 100644
--- a/Modules/_testinternalcapi.c
+++ b/Modules/_testinternalcapi.c
@@ -15,6 +15,7 @@
#include "pycore_bytesobject.h" // _PyBytes_Find()
#include "pycore_compile.h" // _PyCompile_CodeGen, _PyCompile_OptimizeCfg, _PyCompile_Assemble, _PyCompile_CleanDoc
#include "pycore_ceval.h" // _PyEval_AddPendingCall
+#include "pycore_dict.h" // _PyDictOrValues_GetValues
#include "pycore_fileutils.h" // _Py_normpath
#include "pycore_frame.h" // _PyInterpreterFrame
#include "pycore_gc.h" // PyGC_Head
@@ -1530,6 +1531,40 @@ test_pymem_getallocatorsname(PyObject *self, PyObject *args)
return PyUnicode_FromString(name);
}
+static PyObject *
+get_object_dict_values(PyObject *self, PyObject *obj)
+{
+ PyTypeObject *type = Py_TYPE(obj);
+ if (!_PyType_HasFeature(type, Py_TPFLAGS_MANAGED_DICT)) {
+ Py_RETURN_NONE;
+ }
+ PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(obj);
+ if (!_PyDictOrValues_IsValues(dorv)) {
+ Py_RETURN_NONE;
+ }
+ PyDictValues *values = _PyDictOrValues_GetValues(dorv);
+ PyDictKeysObject *keys = ((PyHeapTypeObject *)type)->ht_cached_keys;
+ assert(keys != NULL);
+ int size = (int)keys->dk_nentries;
+ assert(size >= 0);
+ PyObject *res = PyTuple_New(size);
+ if (res == NULL) {
+ return NULL;
+ }
+ _Py_DECLARE_STR(anon_null, "");
+ for(int i = 0; i < size; i++) {
+ PyObject *item = values->values[i];
+ if (item == NULL) {
+ item = &_Py_STR(anon_null);
+ }
+ else {
+ Py_INCREF(item);
+ }
+ PyTuple_SET_ITEM(res, i, item);
+ }
+ return res;
+}
+
static PyMethodDef module_functions[] = {
{"get_configs", get_configs, METH_NOARGS},
@@ -1594,6 +1629,7 @@ static PyMethodDef module_functions[] = {
{"check_pyobject_uninitialized_is_freed",
check_pyobject_uninitialized_is_freed, METH_NOARGS},
{"pymem_getallocatorsname", test_pymem_getallocatorsname, METH_NOARGS},
+ {"get_object_dict_values", get_object_dict_values, METH_O},
{NULL, NULL} /* sentinel */
};
diff --git a/Modules/_typingmodule.c b/Modules/_typingmodule.c
index 59d3a80a9305db..9ea72bf89ce0b2 100644
--- a/Modules/_typingmodule.c
+++ b/Modules/_typingmodule.c
@@ -40,7 +40,7 @@ static PyMethodDef typing_methods[] = {
};
PyDoc_STRVAR(typing_doc,
-"Accelerators for the typing module.\n");
+"Primitives and accelerators for the typing module.\n");
static int
_typing_exec(PyObject *m)
diff --git a/Modules/_winapi.c b/Modules/_winapi.c
index 0edb36d18dd3ff..eec33499b983fe 100644
--- a/Modules/_winapi.c
+++ b/Modules/_winapi.c
@@ -1539,40 +1539,56 @@ _winapi.LCMapStringEx
locale: LPCWSTR
flags: DWORD
- src: LPCWSTR
+ src: unicode
[clinic start generated code]*/
static PyObject *
_winapi_LCMapStringEx_impl(PyObject *module, LPCWSTR locale, DWORD flags,
- LPCWSTR src)
-/*[clinic end generated code: output=cf4713d80e2b47c9 input=9fe26f95d5ab0001]*/
+ PyObject *src)
+/*[clinic end generated code: output=b90e6b26e028ff0a input=3e3dcd9b8164012f]*/
{
if (flags & (LCMAP_SORTHANDLE | LCMAP_HASH | LCMAP_BYTEREV |
LCMAP_SORTKEY)) {
return PyErr_Format(PyExc_ValueError, "unsupported flags");
}
- int dest_size = LCMapStringEx(locale, flags, src, -1, NULL, 0,
+ Py_ssize_t src_size;
+ wchar_t *src_ = PyUnicode_AsWideCharString(src, &src_size);
+ if (!src_) {
+ return NULL;
+ }
+ if (src_size > INT_MAX) {
+ PyMem_Free(src_);
+ PyErr_SetString(PyExc_OverflowError, "input string is too long");
+ return NULL;
+ }
+
+ int dest_size = LCMapStringEx(locale, flags, src_, (int)src_size, NULL, 0,
NULL, NULL, 0);
- if (dest_size == 0) {
- return PyErr_SetFromWindowsErr(0);
+ if (dest_size <= 0) {
+ DWORD error = GetLastError();
+ PyMem_Free(src_);
+ return PyErr_SetFromWindowsErr(error);
}
wchar_t* dest = PyMem_NEW(wchar_t, dest_size);
if (dest == NULL) {
+ PyMem_Free(src_);
return PyErr_NoMemory();
}
- int nmapped = LCMapStringEx(locale, flags, src, -1, dest, dest_size,
+ int nmapped = LCMapStringEx(locale, flags, src_, (int)src_size, dest, dest_size,
NULL, NULL, 0);
- if (nmapped == 0) {
+ if (nmapped <= 0) {
DWORD error = GetLastError();
+ PyMem_Free(src_);
PyMem_DEL(dest);
return PyErr_SetFromWindowsErr(error);
}
- PyObject *ret = PyUnicode_FromWideChar(dest, dest_size - 1);
+ PyMem_Free(src_);
+ PyObject *ret = PyUnicode_FromWideChar(dest, nmapped);
PyMem_DEL(dest);
return ret;
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 31373f8fdf8c71..ea91e70cad991d 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -369,7 +369,7 @@ _is_running(PyInterpreterState *interp)
}
assert(!PyErr_Occurred());
- struct _PyInterpreterFrame *frame = tstate->cframe->current_frame;
+ struct _PyInterpreterFrame *frame = tstate->current_frame;
if (frame == NULL) {
return 0;
}
diff --git a/Modules/clinic/_testclinic_depr_star.c.h b/Modules/clinic/_testclinic_depr_star.c.h
new file mode 100644
index 00000000000000..1aa42dd4059777
--- /dev/null
+++ b/Modules/clinic/_testclinic_depr_star.c.h
@@ -0,0 +1,1140 @@
+/*[clinic input]
+preserve
+[clinic start generated code]*/
+
+#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+# include "pycore_gc.h" // PyGC_Head
+# include "pycore_runtime.h" // _Py_ID()
+#endif
+
+
+PyDoc_STRVAR(depr_star_new__doc__,
+"DeprStarNew(a)\n"
+"--\n"
+"\n"
+"The deprecation message should use the class name instead of __new__.\n"
+"\n"
+"Note: Passing positional arguments to _testclinic.DeprStarNew() is\n"
+"deprecated. Parameter \'a\' will become a keyword-only parameter in\n"
+"Python 3.14.\n"
+"");
+
+static PyObject *
+depr_star_new_impl(PyTypeObject *type, PyObject *a);
+
+static PyObject *
+depr_star_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ 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(a), },
+ };
+ #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", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "DeprStarNew",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[1];
+ PyObject * const *fastargs;
+ Py_ssize_t nargs = PyTuple_GET_SIZE(args);
+ PyObject *a;
+
+ // Emit compiler warnings when we get to Python 3.14.
+ #if PY_VERSION_HEX >= 0x030e00C0
+ # error \
+ "In _testclinic.c, update parameter(s) 'a' in the clinic input of" \
+ " '_testclinic.DeprStarNew.__new__' to be keyword-only."
+ #elif PY_VERSION_HEX >= 0x030e00A0
+ # ifdef _MSC_VER
+ # pragma message ( \
+ "In _testclinic.c, update parameter(s) 'a' in the clinic input of" \
+ " '_testclinic.DeprStarNew.__new__' to be keyword-only.")
+ # else
+ # warning \
+ "In _testclinic.c, update parameter(s) 'a' in the clinic input of" \
+ " '_testclinic.DeprStarNew.__new__' to be keyword-only."
+ # endif
+ #endif
+ if (nargs == 1) {
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "Passing positional arguments to _testclinic.DeprStarNew() is "
+ "deprecated. Parameter 'a' will become a keyword-only parameter "
+ "in Python 3.14.", 1))
+ {
+ goto exit;
+ }
+ }
+ fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 1, 0, argsbuf);
+ if (!fastargs) {
+ goto exit;
+ }
+ a = fastargs[0];
+ return_value = depr_star_new_impl(type, a);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(depr_star_new_clone__doc__,
+"cloned($self, /, a)\n"
+"--\n"
+"\n"
+"Note: Passing positional arguments to _testclinic.DeprStarNew.cloned()\n"
+"is deprecated. Parameter \'a\' will become a keyword-only parameter in\n"
+"Python 3.14.\n"
+"");
+
+#define DEPR_STAR_NEW_CLONE_METHODDEF \
+ {"cloned", _PyCFunction_CAST(depr_star_new_clone), METH_FASTCALL|METH_KEYWORDS, depr_star_new_clone__doc__},
+
+static PyObject *
+depr_star_new_clone_impl(PyObject *type, PyObject *a);
+
+static PyObject *
+depr_star_new_clone(PyObject *type, 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(a), },
+ };
+ #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", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "cloned",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[1];
+ PyObject *a;
+
+ // Emit compiler warnings when we get to Python 3.14.
+ #if PY_VERSION_HEX >= 0x030e00C0
+ # error \
+ "In _testclinic.c, update parameter(s) 'a' in the clinic input of" \
+ " '_testclinic.DeprStarNew.cloned' to be keyword-only."
+ #elif PY_VERSION_HEX >= 0x030e00A0
+ # ifdef _MSC_VER
+ # pragma message ( \
+ "In _testclinic.c, update parameter(s) 'a' in the clinic input of" \
+ " '_testclinic.DeprStarNew.cloned' to be keyword-only.")
+ # else
+ # warning \
+ "In _testclinic.c, update parameter(s) 'a' in the clinic input of" \
+ " '_testclinic.DeprStarNew.cloned' to be keyword-only."
+ # endif
+ #endif
+ if (nargs == 1) {
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "Passing positional arguments to _testclinic.DeprStarNew.cloned()"
+ " is deprecated. Parameter 'a' will become a keyword-only "
+ "parameter in Python 3.14.", 1))
+ {
+ goto exit;
+ }
+ }
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ a = args[0];
+ return_value = depr_star_new_clone_impl(type, a);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(depr_star_init__doc__,
+"DeprStarInit(a)\n"
+"--\n"
+"\n"
+"The deprecation message should use the class name instead of __init__.\n"
+"\n"
+"Note: Passing positional arguments to _testclinic.DeprStarInit() is\n"
+"deprecated. Parameter \'a\' will become a keyword-only parameter in\n"
+"Python 3.14.\n"
+"");
+
+static int
+depr_star_init_impl(PyObject *self, PyObject *a);
+
+static int
+depr_star_init(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ int return_value = -1;
+ #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(a), },
+ };
+ #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", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "DeprStarInit",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[1];
+ PyObject * const *fastargs;
+ Py_ssize_t nargs = PyTuple_GET_SIZE(args);
+ PyObject *a;
+
+ // Emit compiler warnings when we get to Python 3.14.
+ #if PY_VERSION_HEX >= 0x030e00C0
+ # error \
+ "In _testclinic.c, update parameter(s) 'a' in the clinic input of" \
+ " '_testclinic.DeprStarInit.__init__' to be keyword-only."
+ #elif PY_VERSION_HEX >= 0x030e00A0
+ # ifdef _MSC_VER
+ # pragma message ( \
+ "In _testclinic.c, update parameter(s) 'a' in the clinic input of" \
+ " '_testclinic.DeprStarInit.__init__' to be keyword-only.")
+ # else
+ # warning \
+ "In _testclinic.c, update parameter(s) 'a' in the clinic input of" \
+ " '_testclinic.DeprStarInit.__init__' to be keyword-only."
+ # endif
+ #endif
+ if (nargs == 1) {
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "Passing positional arguments to _testclinic.DeprStarInit() is "
+ "deprecated. Parameter 'a' will become a keyword-only parameter "
+ "in Python 3.14.", 1))
+ {
+ goto exit;
+ }
+ }
+ fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 1, 0, argsbuf);
+ if (!fastargs) {
+ goto exit;
+ }
+ a = fastargs[0];
+ return_value = depr_star_init_impl(self, a);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(depr_star_init_clone__doc__,
+"cloned($self, /, a)\n"
+"--\n"
+"\n"
+"Note: Passing positional arguments to\n"
+"_testclinic.DeprStarInit.cloned() is deprecated. Parameter \'a\' will\n"
+"become a keyword-only parameter in Python 3.14.\n"
+"");
+
+#define DEPR_STAR_INIT_CLONE_METHODDEF \
+ {"cloned", _PyCFunction_CAST(depr_star_init_clone), METH_FASTCALL|METH_KEYWORDS, depr_star_init_clone__doc__},
+
+static PyObject *
+depr_star_init_clone_impl(PyObject *self, PyObject *a);
+
+static PyObject *
+depr_star_init_clone(PyObject *self, 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(a), },
+ };
+ #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", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "cloned",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[1];
+ PyObject *a;
+
+ // Emit compiler warnings when we get to Python 3.14.
+ #if PY_VERSION_HEX >= 0x030e00C0
+ # error \
+ "In _testclinic.c, update parameter(s) 'a' in the clinic input of" \
+ " '_testclinic.DeprStarInit.cloned' to be keyword-only."
+ #elif PY_VERSION_HEX >= 0x030e00A0
+ # ifdef _MSC_VER
+ # pragma message ( \
+ "In _testclinic.c, update parameter(s) 'a' in the clinic input of" \
+ " '_testclinic.DeprStarInit.cloned' to be keyword-only.")
+ # else
+ # warning \
+ "In _testclinic.c, update parameter(s) 'a' in the clinic input of" \
+ " '_testclinic.DeprStarInit.cloned' to be keyword-only."
+ # endif
+ #endif
+ if (nargs == 1) {
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "Passing positional arguments to "
+ "_testclinic.DeprStarInit.cloned() is deprecated. Parameter 'a' "
+ "will become a keyword-only parameter in Python 3.14.", 1))
+ {
+ goto exit;
+ }
+ }
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ a = args[0];
+ return_value = depr_star_init_clone_impl(self, a);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(depr_star_pos0_len1__doc__,
+"depr_star_pos0_len1($module, /, a)\n"
+"--\n"
+"\n"
+"Note: Passing positional arguments to depr_star_pos0_len1() is\n"
+"deprecated. Parameter \'a\' will become a keyword-only parameter in\n"
+"Python 3.14.\n"
+"");
+
+#define DEPR_STAR_POS0_LEN1_METHODDEF \
+ {"depr_star_pos0_len1", _PyCFunction_CAST(depr_star_pos0_len1), METH_FASTCALL|METH_KEYWORDS, depr_star_pos0_len1__doc__},
+
+static PyObject *
+depr_star_pos0_len1_impl(PyObject *module, PyObject *a);
+
+static PyObject *
+depr_star_pos0_len1(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(a), },
+ };
+ #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", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "depr_star_pos0_len1",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[1];
+ PyObject *a;
+
+ // Emit compiler warnings when we get to Python 3.14.
+ #if PY_VERSION_HEX >= 0x030e00C0
+ # error \
+ "In _testclinic.c, update parameter(s) 'a' in the clinic input of" \
+ " 'depr_star_pos0_len1' to be keyword-only."
+ #elif PY_VERSION_HEX >= 0x030e00A0
+ # ifdef _MSC_VER
+ # pragma message ( \
+ "In _testclinic.c, update parameter(s) 'a' in the clinic input of" \
+ " 'depr_star_pos0_len1' to be keyword-only.")
+ # else
+ # warning \
+ "In _testclinic.c, update parameter(s) 'a' in the clinic input of" \
+ " 'depr_star_pos0_len1' to be keyword-only."
+ # endif
+ #endif
+ if (nargs == 1) {
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "Passing positional arguments to depr_star_pos0_len1() is "
+ "deprecated. Parameter 'a' will become a keyword-only parameter "
+ "in Python 3.14.", 1))
+ {
+ goto exit;
+ }
+ }
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ a = args[0];
+ return_value = depr_star_pos0_len1_impl(module, a);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(depr_star_pos0_len2__doc__,
+"depr_star_pos0_len2($module, /, a, b)\n"
+"--\n"
+"\n"
+"Note: Passing positional arguments to depr_star_pos0_len2() is\n"
+"deprecated. Parameters \'a\' and \'b\' will become keyword-only parameters\n"
+"in Python 3.14.\n"
+"");
+
+#define DEPR_STAR_POS0_LEN2_METHODDEF \
+ {"depr_star_pos0_len2", _PyCFunction_CAST(depr_star_pos0_len2), METH_FASTCALL|METH_KEYWORDS, depr_star_pos0_len2__doc__},
+
+static PyObject *
+depr_star_pos0_len2_impl(PyObject *module, PyObject *a, PyObject *b);
+
+static PyObject *
+depr_star_pos0_len2(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 2
+ 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(a), &_Py_ID(b), },
+ };
+ #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", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "depr_star_pos0_len2",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[2];
+ PyObject *a;
+ PyObject *b;
+
+ // Emit compiler warnings when we get to Python 3.14.
+ #if PY_VERSION_HEX >= 0x030e00C0
+ # error \
+ "In _testclinic.c, update parameter(s) 'a' and 'b' in the clinic " \
+ "input of 'depr_star_pos0_len2' to be keyword-only."
+ #elif PY_VERSION_HEX >= 0x030e00A0
+ # ifdef _MSC_VER
+ # pragma message ( \
+ "In _testclinic.c, update parameter(s) 'a' and 'b' in the clinic " \
+ "input of 'depr_star_pos0_len2' to be keyword-only.")
+ # else
+ # warning \
+ "In _testclinic.c, update parameter(s) 'a' and 'b' in the clinic " \
+ "input of 'depr_star_pos0_len2' to be keyword-only."
+ # endif
+ #endif
+ if (nargs > 0 && nargs <= 2) {
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "Passing positional arguments to depr_star_pos0_len2() is "
+ "deprecated. Parameters 'a' and 'b' will become keyword-only "
+ "parameters in Python 3.14.", 1))
+ {
+ goto exit;
+ }
+ }
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ a = args[0];
+ b = args[1];
+ return_value = depr_star_pos0_len2_impl(module, a, b);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(depr_star_pos0_len3_with_kwd__doc__,
+"depr_star_pos0_len3_with_kwd($module, /, a, b, c, *, d)\n"
+"--\n"
+"\n"
+"Note: Passing positional arguments to depr_star_pos0_len3_with_kwd()\n"
+"is deprecated. Parameters \'a\', \'b\' and \'c\' will become keyword-only\n"
+"parameters in Python 3.14.\n"
+"");
+
+#define DEPR_STAR_POS0_LEN3_WITH_KWD_METHODDEF \
+ {"depr_star_pos0_len3_with_kwd", _PyCFunction_CAST(depr_star_pos0_len3_with_kwd), METH_FASTCALL|METH_KEYWORDS, depr_star_pos0_len3_with_kwd__doc__},
+
+static PyObject *
+depr_star_pos0_len3_with_kwd_impl(PyObject *module, PyObject *a, PyObject *b,
+ PyObject *c, PyObject *d);
+
+static PyObject *
+depr_star_pos0_len3_with_kwd(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 4
+ 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(a), &_Py_ID(b), &_Py_ID(c), &_Py_ID(d), },
+ };
+ #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", "d", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "depr_star_pos0_len3_with_kwd",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[4];
+ PyObject *a;
+ PyObject *b;
+ PyObject *c;
+ PyObject *d;
+
+ // Emit compiler warnings when we get to Python 3.14.
+ #if PY_VERSION_HEX >= 0x030e00C0
+ # error \
+ "In _testclinic.c, update parameter(s) 'a', 'b' and 'c' in the " \
+ "clinic input of 'depr_star_pos0_len3_with_kwd' to be " \
+ "keyword-only."
+ #elif PY_VERSION_HEX >= 0x030e00A0
+ # ifdef _MSC_VER
+ # pragma message ( \
+ "In _testclinic.c, update parameter(s) 'a', 'b' and 'c' in the " \
+ "clinic input of 'depr_star_pos0_len3_with_kwd' to be " \
+ "keyword-only.")
+ # else
+ # warning \
+ "In _testclinic.c, update parameter(s) 'a', 'b' and 'c' in the " \
+ "clinic input of 'depr_star_pos0_len3_with_kwd' to be " \
+ "keyword-only."
+ # endif
+ #endif
+ if (nargs > 0 && nargs <= 3) {
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "Passing positional arguments to depr_star_pos0_len3_with_kwd() "
+ "is deprecated. Parameters 'a', 'b' and 'c' will become "
+ "keyword-only parameters in Python 3.14.", 1))
+ {
+ goto exit;
+ }
+ }
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 3, 1, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ a = args[0];
+ b = args[1];
+ c = args[2];
+ d = args[3];
+ return_value = depr_star_pos0_len3_with_kwd_impl(module, a, b, c, d);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(depr_star_pos1_len1_opt__doc__,
+"depr_star_pos1_len1_opt($module, /, a, b=None)\n"
+"--\n"
+"\n"
+"Note: Passing 2 positional arguments to depr_star_pos1_len1_opt() is\n"
+"deprecated. Parameter \'b\' will become a keyword-only parameter in\n"
+"Python 3.14.\n"
+"");
+
+#define DEPR_STAR_POS1_LEN1_OPT_METHODDEF \
+ {"depr_star_pos1_len1_opt", _PyCFunction_CAST(depr_star_pos1_len1_opt), METH_FASTCALL|METH_KEYWORDS, depr_star_pos1_len1_opt__doc__},
+
+static PyObject *
+depr_star_pos1_len1_opt_impl(PyObject *module, PyObject *a, PyObject *b);
+
+static PyObject *
+depr_star_pos1_len1_opt(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 2
+ 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(a), &_Py_ID(b), },
+ };
+ #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", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "depr_star_pos1_len1_opt",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[2];
+ Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
+ PyObject *a;
+ PyObject *b = Py_None;
+
+ // Emit compiler warnings when we get to Python 3.14.
+ #if PY_VERSION_HEX >= 0x030e00C0
+ # error \
+ "In _testclinic.c, update parameter(s) 'b' in the clinic input of" \
+ " 'depr_star_pos1_len1_opt' to be keyword-only."
+ #elif PY_VERSION_HEX >= 0x030e00A0
+ # ifdef _MSC_VER
+ # pragma message ( \
+ "In _testclinic.c, update parameter(s) 'b' in the clinic input of" \
+ " 'depr_star_pos1_len1_opt' to be keyword-only.")
+ # else
+ # warning \
+ "In _testclinic.c, update parameter(s) 'b' in the clinic input of" \
+ " 'depr_star_pos1_len1_opt' to be keyword-only."
+ # endif
+ #endif
+ if (nargs == 2) {
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "Passing 2 positional arguments to depr_star_pos1_len1_opt() is "
+ "deprecated. Parameter 'b' will become a keyword-only parameter "
+ "in Python 3.14.", 1))
+ {
+ goto exit;
+ }
+ }
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 2, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ a = args[0];
+ if (!noptargs) {
+ goto skip_optional_pos;
+ }
+ b = args[1];
+skip_optional_pos:
+ return_value = depr_star_pos1_len1_opt_impl(module, a, b);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(depr_star_pos1_len1__doc__,
+"depr_star_pos1_len1($module, /, a, b)\n"
+"--\n"
+"\n"
+"Note: Passing 2 positional arguments to depr_star_pos1_len1() is\n"
+"deprecated. Parameter \'b\' will become a keyword-only parameter in\n"
+"Python 3.14.\n"
+"");
+
+#define DEPR_STAR_POS1_LEN1_METHODDEF \
+ {"depr_star_pos1_len1", _PyCFunction_CAST(depr_star_pos1_len1), METH_FASTCALL|METH_KEYWORDS, depr_star_pos1_len1__doc__},
+
+static PyObject *
+depr_star_pos1_len1_impl(PyObject *module, PyObject *a, PyObject *b);
+
+static PyObject *
+depr_star_pos1_len1(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 2
+ 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(a), &_Py_ID(b), },
+ };
+ #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", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "depr_star_pos1_len1",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[2];
+ PyObject *a;
+ PyObject *b;
+
+ // Emit compiler warnings when we get to Python 3.14.
+ #if PY_VERSION_HEX >= 0x030e00C0
+ # error \
+ "In _testclinic.c, update parameter(s) 'b' in the clinic input of" \
+ " 'depr_star_pos1_len1' to be keyword-only."
+ #elif PY_VERSION_HEX >= 0x030e00A0
+ # ifdef _MSC_VER
+ # pragma message ( \
+ "In _testclinic.c, update parameter(s) 'b' in the clinic input of" \
+ " 'depr_star_pos1_len1' to be keyword-only.")
+ # else
+ # warning \
+ "In _testclinic.c, update parameter(s) 'b' in the clinic input of" \
+ " 'depr_star_pos1_len1' to be keyword-only."
+ # endif
+ #endif
+ if (nargs == 2) {
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "Passing 2 positional arguments to depr_star_pos1_len1() is "
+ "deprecated. Parameter 'b' will become a keyword-only parameter "
+ "in Python 3.14.", 1))
+ {
+ goto exit;
+ }
+ }
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ a = args[0];
+ b = args[1];
+ return_value = depr_star_pos1_len1_impl(module, a, b);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(depr_star_pos1_len2_with_kwd__doc__,
+"depr_star_pos1_len2_with_kwd($module, /, a, b, c, *, d)\n"
+"--\n"
+"\n"
+"Note: Passing more than 1 positional argument to\n"
+"depr_star_pos1_len2_with_kwd() is deprecated. Parameters \'b\' and \'c\'\n"
+"will become keyword-only parameters in Python 3.14.\n"
+"");
+
+#define DEPR_STAR_POS1_LEN2_WITH_KWD_METHODDEF \
+ {"depr_star_pos1_len2_with_kwd", _PyCFunction_CAST(depr_star_pos1_len2_with_kwd), METH_FASTCALL|METH_KEYWORDS, depr_star_pos1_len2_with_kwd__doc__},
+
+static PyObject *
+depr_star_pos1_len2_with_kwd_impl(PyObject *module, PyObject *a, PyObject *b,
+ PyObject *c, PyObject *d);
+
+static PyObject *
+depr_star_pos1_len2_with_kwd(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 4
+ 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(a), &_Py_ID(b), &_Py_ID(c), &_Py_ID(d), },
+ };
+ #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", "d", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "depr_star_pos1_len2_with_kwd",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[4];
+ PyObject *a;
+ PyObject *b;
+ PyObject *c;
+ PyObject *d;
+
+ // Emit compiler warnings when we get to Python 3.14.
+ #if PY_VERSION_HEX >= 0x030e00C0
+ # error \
+ "In _testclinic.c, update parameter(s) 'b' and 'c' in the clinic " \
+ "input of 'depr_star_pos1_len2_with_kwd' to be keyword-only."
+ #elif PY_VERSION_HEX >= 0x030e00A0
+ # ifdef _MSC_VER
+ # pragma message ( \
+ "In _testclinic.c, update parameter(s) 'b' and 'c' in the clinic " \
+ "input of 'depr_star_pos1_len2_with_kwd' to be keyword-only.")
+ # else
+ # warning \
+ "In _testclinic.c, update parameter(s) 'b' and 'c' in the clinic " \
+ "input of 'depr_star_pos1_len2_with_kwd' to be keyword-only."
+ # endif
+ #endif
+ if (nargs > 1 && nargs <= 3) {
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "Passing more than 1 positional argument to "
+ "depr_star_pos1_len2_with_kwd() is deprecated. Parameters 'b' and"
+ " 'c' will become keyword-only parameters in Python 3.14.", 1))
+ {
+ goto exit;
+ }
+ }
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 3, 1, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ a = args[0];
+ b = args[1];
+ c = args[2];
+ d = args[3];
+ return_value = depr_star_pos1_len2_with_kwd_impl(module, a, b, c, d);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(depr_star_pos2_len1__doc__,
+"depr_star_pos2_len1($module, /, a, b, c)\n"
+"--\n"
+"\n"
+"Note: Passing 3 positional arguments to depr_star_pos2_len1() is\n"
+"deprecated. Parameter \'c\' will become a keyword-only parameter in\n"
+"Python 3.14.\n"
+"");
+
+#define DEPR_STAR_POS2_LEN1_METHODDEF \
+ {"depr_star_pos2_len1", _PyCFunction_CAST(depr_star_pos2_len1), METH_FASTCALL|METH_KEYWORDS, depr_star_pos2_len1__doc__},
+
+static PyObject *
+depr_star_pos2_len1_impl(PyObject *module, PyObject *a, PyObject *b,
+ PyObject *c);
+
+static PyObject *
+depr_star_pos2_len1(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_ID(a), &_Py_ID(b), &_Py_ID(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 = "depr_star_pos2_len1",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[3];
+ PyObject *a;
+ PyObject *b;
+ PyObject *c;
+
+ // Emit compiler warnings when we get to Python 3.14.
+ #if PY_VERSION_HEX >= 0x030e00C0
+ # error \
+ "In _testclinic.c, update parameter(s) 'c' in the clinic input of" \
+ " 'depr_star_pos2_len1' to be keyword-only."
+ #elif PY_VERSION_HEX >= 0x030e00A0
+ # ifdef _MSC_VER
+ # pragma message ( \
+ "In _testclinic.c, update parameter(s) 'c' in the clinic input of" \
+ " 'depr_star_pos2_len1' to be keyword-only.")
+ # else
+ # warning \
+ "In _testclinic.c, update parameter(s) 'c' in the clinic input of" \
+ " 'depr_star_pos2_len1' to be keyword-only."
+ # endif
+ #endif
+ if (nargs == 3) {
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "Passing 3 positional arguments to depr_star_pos2_len1() is "
+ "deprecated. Parameter 'c' will become a keyword-only parameter "
+ "in Python 3.14.", 1))
+ {
+ goto exit;
+ }
+ }
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 3, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ a = args[0];
+ b = args[1];
+ c = args[2];
+ return_value = depr_star_pos2_len1_impl(module, a, b, c);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(depr_star_pos2_len2__doc__,
+"depr_star_pos2_len2($module, /, a, b, c, d)\n"
+"--\n"
+"\n"
+"Note: Passing more than 2 positional arguments to\n"
+"depr_star_pos2_len2() is deprecated. Parameters \'c\' and \'d\' will\n"
+"become keyword-only parameters in Python 3.14.\n"
+"");
+
+#define DEPR_STAR_POS2_LEN2_METHODDEF \
+ {"depr_star_pos2_len2", _PyCFunction_CAST(depr_star_pos2_len2), METH_FASTCALL|METH_KEYWORDS, depr_star_pos2_len2__doc__},
+
+static PyObject *
+depr_star_pos2_len2_impl(PyObject *module, PyObject *a, PyObject *b,
+ PyObject *c, PyObject *d);
+
+static PyObject *
+depr_star_pos2_len2(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 4
+ 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(a), &_Py_ID(b), &_Py_ID(c), &_Py_ID(d), },
+ };
+ #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", "d", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "depr_star_pos2_len2",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[4];
+ PyObject *a;
+ PyObject *b;
+ PyObject *c;
+ PyObject *d;
+
+ // Emit compiler warnings when we get to Python 3.14.
+ #if PY_VERSION_HEX >= 0x030e00C0
+ # error \
+ "In _testclinic.c, update parameter(s) 'c' and 'd' in the clinic " \
+ "input of 'depr_star_pos2_len2' to be keyword-only."
+ #elif PY_VERSION_HEX >= 0x030e00A0
+ # ifdef _MSC_VER
+ # pragma message ( \
+ "In _testclinic.c, update parameter(s) 'c' and 'd' in the clinic " \
+ "input of 'depr_star_pos2_len2' to be keyword-only.")
+ # else
+ # warning \
+ "In _testclinic.c, update parameter(s) 'c' and 'd' in the clinic " \
+ "input of 'depr_star_pos2_len2' to be keyword-only."
+ # endif
+ #endif
+ if (nargs > 2 && nargs <= 4) {
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "Passing more than 2 positional arguments to "
+ "depr_star_pos2_len2() is deprecated. Parameters 'c' and 'd' will"
+ " become keyword-only parameters in Python 3.14.", 1))
+ {
+ goto exit;
+ }
+ }
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 4, 4, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ a = args[0];
+ b = args[1];
+ c = args[2];
+ d = args[3];
+ return_value = depr_star_pos2_len2_impl(module, a, b, c, d);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(depr_star_pos2_len2_with_kwd__doc__,
+"depr_star_pos2_len2_with_kwd($module, /, a, b, c, d, *, e)\n"
+"--\n"
+"\n"
+"Note: Passing more than 2 positional arguments to\n"
+"depr_star_pos2_len2_with_kwd() is deprecated. Parameters \'c\' and \'d\'\n"
+"will become keyword-only parameters in Python 3.14.\n"
+"");
+
+#define DEPR_STAR_POS2_LEN2_WITH_KWD_METHODDEF \
+ {"depr_star_pos2_len2_with_kwd", _PyCFunction_CAST(depr_star_pos2_len2_with_kwd), METH_FASTCALL|METH_KEYWORDS, depr_star_pos2_len2_with_kwd__doc__},
+
+static PyObject *
+depr_star_pos2_len2_with_kwd_impl(PyObject *module, PyObject *a, PyObject *b,
+ PyObject *c, PyObject *d, PyObject *e);
+
+static PyObject *
+depr_star_pos2_len2_with_kwd(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 5
+ 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(a), &_Py_ID(b), &_Py_ID(c), &_Py_ID(d), &_Py_ID(e), },
+ };
+ #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", "d", "e", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "depr_star_pos2_len2_with_kwd",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[5];
+ PyObject *a;
+ PyObject *b;
+ PyObject *c;
+ PyObject *d;
+ PyObject *e;
+
+ // Emit compiler warnings when we get to Python 3.14.
+ #if PY_VERSION_HEX >= 0x030e00C0
+ # error \
+ "In _testclinic.c, update parameter(s) 'c' and 'd' in the clinic " \
+ "input of 'depr_star_pos2_len2_with_kwd' to be keyword-only."
+ #elif PY_VERSION_HEX >= 0x030e00A0
+ # ifdef _MSC_VER
+ # pragma message ( \
+ "In _testclinic.c, update parameter(s) 'c' and 'd' in the clinic " \
+ "input of 'depr_star_pos2_len2_with_kwd' to be keyword-only.")
+ # else
+ # warning \
+ "In _testclinic.c, update parameter(s) 'c' and 'd' in the clinic " \
+ "input of 'depr_star_pos2_len2_with_kwd' to be keyword-only."
+ # endif
+ #endif
+ if (nargs > 2 && nargs <= 4) {
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "Passing more than 2 positional arguments to "
+ "depr_star_pos2_len2_with_kwd() is deprecated. Parameters 'c' and"
+ " 'd' will become keyword-only parameters in Python 3.14.", 1))
+ {
+ goto exit;
+ }
+ }
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 4, 4, 1, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ a = args[0];
+ b = args[1];
+ c = args[2];
+ d = args[3];
+ e = args[4];
+ return_value = depr_star_pos2_len2_with_kwd_impl(module, a, b, c, d, e);
+
+exit:
+ return return_value;
+}
+/*[clinic end generated code: output=7a16fee4d6742d54 input=a9049054013a1b77]*/
diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h
index 8f46b8f1095e98..35ac053547121c 100644
--- a/Modules/clinic/_winapi.c.h
+++ b/Modules/clinic/_winapi.c.h
@@ -884,7 +884,7 @@ PyDoc_STRVAR(_winapi_LCMapStringEx__doc__,
static PyObject *
_winapi_LCMapStringEx_impl(PyObject *module, LPCWSTR locale, DWORD flags,
- LPCWSTR src);
+ PyObject *src);
static PyObject *
_winapi_LCMapStringEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -911,16 +911,16 @@ _winapi_LCMapStringEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs,
static const char * const _keywords[] = {"locale", "flags", "src", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
- .format = "O&kO&:LCMapStringEx",
+ .format = "O&kU:LCMapStringEx",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
LPCWSTR locale = NULL;
DWORD flags;
- LPCWSTR src = NULL;
+ PyObject *src;
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
- _PyUnicode_WideCharString_Converter, &locale, &flags, _PyUnicode_WideCharString_Converter, &src)) {
+ _PyUnicode_WideCharString_Converter, &locale, &flags, &src)) {
goto exit;
}
return_value = _winapi_LCMapStringEx_impl(module, locale, flags, src);
@@ -928,8 +928,6 @@ _winapi_LCMapStringEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs,
exit:
/* Cleanup for locale */
PyMem_Free((void *)locale);
- /* Cleanup for src */
- PyMem_Free((void *)src);
return return_value;
}
@@ -1480,4 +1478,4 @@ _winapi_CopyFile2(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyO
return return_value;
}
-/*[clinic end generated code: output=f32fe6ecdbffd74d input=a9049054013a1b77]*/
+/*[clinic end generated code: output=ff91ab5cae8961dd input=a9049054013a1b77]*/
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index a42e41c081e5b7..c391aab6fdce1d 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -5274,7 +5274,9 @@ os__path_normpath_impl(PyObject *module, PyObject *path)
if (!buffer) {
return NULL;
}
- PyObject *result = PyUnicode_FromWideChar(_Py_normpath(buffer, len), -1);
+ Py_ssize_t norm_len;
+ wchar_t *norm_path = _Py_normpath_and_size(buffer, len, &norm_len);
+ PyObject *result = PyUnicode_FromWideChar(norm_path, norm_len);
PyMem_Free(buffer);
return result;
}
diff --git a/Modules/socketmodule.h b/Modules/socketmodule.h
index 663ae3d6e0dd6c..47146a28e02c8f 100644
--- a/Modules/socketmodule.h
+++ b/Modules/socketmodule.h
@@ -100,6 +100,8 @@ typedef int socklen_t;
# include
# endif
# include
+#elif defined(HAVE_NETLINK_NETLINK_H)
+# include
#else
# undef AF_NETLINK
#endif
diff --git a/Objects/abstract.c b/Objects/abstract.c
index b4edcec6007710..c113364a88a26a 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -2812,7 +2812,7 @@ object_issubclass(PyThreadState *tstate, PyObject *derived, PyObject *cls)
return -1;
}
- /* Probably never reached anymore. */
+ /* Can be reached when infinite recursion happens. */
return recursive_issubclass(derived, cls);
}
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index 6987a2382d81c2..2c9c8cec77ff9f 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -6,7 +6,8 @@
#include "pycore_code.h" // _PyCodeConstructor
#include "pycore_frame.h" // FRAME_SPECIALS_SIZE
#include "pycore_interp.h" // PyInterpreterState.co_extra_freefuncs
-#include "pycore_opcode.h" // _PyOpcode_Deopt
+#include "pycore_opcode.h" // _PyOpcode_Caches
+#include "pycore_opcode_metadata.h" // _PyOpcode_Deopt
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include "pycore_setobject.h" // _PySet_NextEntry()
#include "pycore_tuple.h" // _PyTuple_ITEMS()
diff --git a/Objects/descrobject.c b/Objects/descrobject.c
index 60383dd06d1add..a744c3d1e58658 100644
--- a/Objects/descrobject.c
+++ b/Objects/descrobject.c
@@ -588,7 +588,9 @@ method_get_doc(PyMethodDescrObject *descr, void *closure)
static PyObject *
method_get_text_signature(PyMethodDescrObject *descr, void *closure)
{
- return _PyType_GetTextSignatureFromInternalDoc(descr->d_method->ml_name, descr->d_method->ml_doc);
+ return _PyType_GetTextSignatureFromInternalDoc(descr->d_method->ml_name,
+ descr->d_method->ml_doc,
+ descr->d_method->ml_flags);
}
static PyObject *
@@ -691,7 +693,8 @@ wrapperdescr_get_doc(PyWrapperDescrObject *descr, void *closure)
static PyObject *
wrapperdescr_get_text_signature(PyWrapperDescrObject *descr, void *closure)
{
- return _PyType_GetTextSignatureFromInternalDoc(descr->d_base->name, descr->d_base->doc);
+ return _PyType_GetTextSignatureFromInternalDoc(descr->d_base->name,
+ descr->d_base->doc, 0);
}
static PyGetSetDef wrapperdescr_getset[] = {
@@ -1384,7 +1387,8 @@ wrapper_doc(wrapperobject *wp, void *Py_UNUSED(ignored))
static PyObject *
wrapper_text_signature(wrapperobject *wp, void *Py_UNUSED(ignored))
{
- return _PyType_GetTextSignatureFromInternalDoc(wp->descr->d_base->name, wp->descr->d_base->doc);
+ return _PyType_GetTextSignatureFromInternalDoc(wp->descr->d_base->name,
+ wp->descr->d_base->doc, 0);
}
static PyObject *
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 41ae1fca90b468..f9701f6b4b09ad 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -5464,6 +5464,37 @@ _PyObject_MakeDictFromInstanceAttributes(PyObject *obj, PyDictValues *values)
return make_dict_from_instance_attributes(interp, keys, values);
}
+// Return true if the dict was dematerialized, false otherwise.
+bool
+_PyObject_MakeInstanceAttributesFromDict(PyObject *obj, PyDictOrValues *dorv)
+{
+ assert(_PyObject_DictOrValuesPointer(obj) == dorv);
+ assert(!_PyDictOrValues_IsValues(*dorv));
+ PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(*dorv);
+ if (dict == NULL) {
+ return false;
+ }
+ // It's likely that this dict still shares its keys (if it was materialized
+ // on request and not heavily modified):
+ if (!PyDict_CheckExact(dict)) {
+ return false;
+ }
+ assert(_PyType_HasFeature(Py_TYPE(obj), Py_TPFLAGS_HEAPTYPE));
+ if (dict->ma_keys != CACHED_KEYS(Py_TYPE(obj)) || Py_REFCNT(dict) != 1) {
+ return false;
+ }
+ assert(dict->ma_values);
+ // We have an opportunity to do something *really* cool: dematerialize it!
+ _PyDictKeys_DecRef(dict->ma_keys);
+ _PyDictOrValues_SetValues(dorv, dict->ma_values);
+ OBJECT_STAT_INC(dict_dematerialized);
+ // Don't try this at home, kids:
+ dict->ma_keys = NULL;
+ dict->ma_values = NULL;
+ Py_DECREF(dict);
+ return true;
+}
+
int
_PyObject_StoreInstanceAttribute(PyObject *obj, PyDictValues *values,
PyObject *name, PyObject *value)
@@ -5688,6 +5719,7 @@ PyObject_GenericGetDict(PyObject *obj, void *context)
dict = _PyDictOrValues_GetDict(*dorv_ptr);
if (dict == NULL) {
dictkeys_incref(CACHED_KEYS(tp));
+ OBJECT_STAT_INC(dict_materialized_on_request);
dict = new_dict_with_shared_keys(interp, CACHED_KEYS(tp));
dorv_ptr->dict = dict;
}
@@ -5730,6 +5762,7 @@ _PyObjectDict_SetItem(PyTypeObject *tp, PyObject **dictptr,
assert(dictptr != NULL);
dict = *dictptr;
if (dict == NULL) {
+ assert(!_PyType_HasFeature(tp, Py_TPFLAGS_MANAGED_DICT));
dictkeys_incref(cached);
dict = new_dict_with_shared_keys(interp, cached);
if (dict == NULL)
diff --git a/Objects/exception_handling_notes.txt b/Objects/exception_handling_notes.txt
index 7de01fdbf5ff48..387ef935ce739e 100644
--- a/Objects/exception_handling_notes.txt
+++ b/Objects/exception_handling_notes.txt
@@ -47,7 +47,7 @@ a table to determine where to jump to when an exception is raised.
2 2 NOP
- 3 4 LOAD_GLOBAL 1 (NULL + g)
+ 3 4 LOAD_GLOBAL 1 (g + NULL)
16 LOAD_CONST 1 (0)
18 PRECALL 1
22 CALL 1
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 17571535048e23..80e118e8a8aa93 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -7,6 +7,8 @@
#include "pycore_moduleobject.h" // _PyModule_GetDict()
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_opcode.h" // _PyOpcode_Caches
+#include "pycore_opcode_metadata.h" // _PyOpcode_Deopt
+
#include "frameobject.h" // PyFrameObject
#include "pycore_frame.h"
diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c
index df8873454aeb36..faf517b66b9350 100644
--- a/Objects/genericaliasobject.c
+++ b/Objects/genericaliasobject.c
@@ -626,6 +626,7 @@ ga_vectorcall(PyObject *self, PyObject *const *args,
static const char* const attr_exceptions[] = {
"__class__",
+ "__bases__",
"__origin__",
"__args__",
"__unpacked__",
diff --git a/Objects/genobject.c b/Objects/genobject.c
index 65782be182cd71..10c55efb1b1e9b 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -476,9 +476,9 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
will be reported correctly to the user. */
/* XXX We should probably be updating the current frame
somewhere in ceval.c. */
- _PyInterpreterFrame *prev = tstate->cframe->current_frame;
+ _PyInterpreterFrame *prev = tstate->current_frame;
frame->previous = prev;
- tstate->cframe->current_frame = frame;
+ tstate->current_frame = frame;
/* Close the generator that we are currently iterating with
'yield from' or awaiting on with 'await'. */
PyFrameState state = gen->gi_frame_state;
@@ -486,7 +486,7 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
ret = _gen_throw((PyGenObject *)yf, close_on_genexit,
typ, val, tb);
gen->gi_frame_state = state;
- tstate->cframe->current_frame = prev;
+ tstate->current_frame = prev;
frame->previous = NULL;
} else {
/* `yf` is an iterator or a coroutine-like object. */
@@ -938,7 +938,7 @@ _Py_MakeCoro(PyFunctionObject *func)
if (origin_depth == 0) {
((PyCoroObject *)coro)->cr_origin_or_finalizer = NULL;
} else {
- _PyInterpreterFrame *frame = tstate->cframe->current_frame;
+ _PyInterpreterFrame *frame = tstate->current_frame;
assert(frame);
assert(_PyFrame_IsIncomplete(frame));
frame = _PyFrame_GetFirstComplete(frame->previous);
diff --git a/Objects/lnotab_notes.txt b/Objects/lnotab_notes.txt
index 362b87a86a481f..d45d09d4ab9a50 100644
--- a/Objects/lnotab_notes.txt
+++ b/Objects/lnotab_notes.txt
@@ -1,4 +1,7 @@
-Description of the internal format of the line number table
+Description of the internal format of the line number table in Python 3.10
+and earlier.
+
+(For 3.11 onwards, see Objects/locations.md)
Conceptually, the line number table consists of a sequence of triples:
start-offset (inclusive), end-offset (exclusive), line-number.
diff --git a/Objects/methodobject.c b/Objects/methodobject.c
index 628d227ef33c39..521c9059770acb 100644
--- a/Objects/methodobject.c
+++ b/Objects/methodobject.c
@@ -192,7 +192,9 @@ static PyMethodDef meth_methods[] = {
static PyObject *
meth_get__text_signature__(PyCFunctionObject *m, void *closure)
{
- return _PyType_GetTextSignatureFromInternalDoc(m->m_ml->ml_name, m->m_ml->ml_doc);
+ return _PyType_GetTextSignatureFromInternalDoc(m->m_ml->ml_name,
+ m->m_ml->ml_doc,
+ m->m_ml->ml_flags);
}
static PyObject *
diff --git a/Objects/object.c b/Objects/object.c
index d1154eb344fab1..868623a9f7bffc 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -1577,6 +1577,14 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
goto error_check;
}
dictptr = &dorv_ptr->dict;
+ if (*dictptr == NULL) {
+ if (_PyObject_InitInlineValues(obj, tp) < 0) {
+ goto done;
+ }
+ res = _PyObject_StoreInstanceAttribute(
+ obj, _PyDictOrValues_GetValues(*dorv_ptr), name, value);
+ goto error_check;
+ }
}
else {
dictptr = _PyObject_ComputedDictPointer(obj);
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 76809494dd8817..7ce3de4d58d0d3 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -586,8 +586,29 @@ _PyType_GetDocFromInternalDoc(const char *name, const char *internal_doc)
return PyUnicode_FromString(doc);
}
+static const char *
+signature_from_flags(int flags)
+{
+ switch (flags & ~METH_COEXIST) {
+ case METH_NOARGS:
+ return "($self, /)";
+ case METH_NOARGS|METH_CLASS:
+ return "($type, /)";
+ case METH_NOARGS|METH_STATIC:
+ return "()";
+ case METH_O:
+ return "($self, object, /)";
+ case METH_O|METH_CLASS:
+ return "($type, object, /)";
+ case METH_O|METH_STATIC:
+ return "(object, /)";
+ default:
+ return NULL;
+ }
+}
+
PyObject *
-_PyType_GetTextSignatureFromInternalDoc(const char *name, const char *internal_doc)
+_PyType_GetTextSignatureFromInternalDoc(const char *name, const char *internal_doc, int flags)
{
const char *start = find_signature(name, internal_doc);
const char *end;
@@ -597,6 +618,10 @@ _PyType_GetTextSignatureFromInternalDoc(const char *name, const char *internal_d
else
end = NULL;
if (!end) {
+ start = signature_from_flags(flags);
+ if (start) {
+ return PyUnicode_FromString(start);
+ }
Py_RETURN_NONE;
}
@@ -1429,7 +1454,7 @@ type_get_doc(PyTypeObject *type, void *context)
static PyObject *
type_get_text_signature(PyTypeObject *type, void *context)
{
- return _PyType_GetTextSignatureFromInternalDoc(type->tp_name, type->tp_doc);
+ return _PyType_GetTextSignatureFromInternalDoc(type->tp_name, type->tp_doc, 0);
}
static int
@@ -2419,7 +2444,7 @@ set_mro_error(PyObject **to_merge, Py_ssize_t to_merge_size, int *remain)
n = PyDict_GET_SIZE(set);
off = PyOS_snprintf(buf, sizeof(buf), "Cannot create a \
-consistent method resolution\norder (MRO) for bases");
+consistent method resolution order (MRO) for bases");
i = 0;
while (PyDict_Next(set, &i, &k, &v) && (size_t)off < sizeof(buf)) {
PyObject *name = class_name(k);
@@ -4264,9 +4289,9 @@ _PyType_FromMetaclass_impl(
if (_allow_tp_new) {
if (PyErr_WarnFormat(
PyExc_DeprecationWarning, 1,
- "Using PyType_Spec with metaclasses that have custom "
- "tp_new is deprecated and will no longer be allowed in "
- "Python 3.14.") < 0) {
+ "Type %s uses PyType_Spec with a metaclass that has custom "
+ "tp_new. This is deprecated and will no longer be allowed in "
+ "Python 3.14.", spec->name) < 0) {
goto finally;
}
}
@@ -4965,9 +4990,6 @@ type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
return res;
}
-extern void
-_PyDictKeys_DecRef(PyDictKeysObject *keys);
-
static void
type_dealloc_common(PyTypeObject *type)
diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c
index e09e6a62553cff..66122e36283ad0 100644
--- a/Objects/typevarobject.c
+++ b/Objects/typevarobject.c
@@ -107,7 +107,7 @@ make_union(PyObject *self, PyObject *other)
static PyObject *
caller(void)
{
- _PyInterpreterFrame *f = _PyThreadState_GET()->cframe->current_frame;
+ _PyInterpreterFrame *f = _PyThreadState_GET()->current_frame;
if (f == NULL) {
Py_RETURN_NONE;
}
diff --git a/PCbuild/_freeze_module.vcxproj b/PCbuild/_freeze_module.vcxproj
index e247637a0dfe5c..bdcf29ba44dab5 100644
--- a/PCbuild/_freeze_module.vcxproj
+++ b/PCbuild/_freeze_module.vcxproj
@@ -218,6 +218,7 @@
+
diff --git a/PCbuild/_freeze_module.vcxproj.filters b/PCbuild/_freeze_module.vcxproj.filters
index 2a0e009308022b..45333fa97f1c64 100644
--- a/PCbuild/_freeze_module.vcxproj.filters
+++ b/PCbuild/_freeze_module.vcxproj.filters
@@ -283,6 +283,9 @@
Source Files
+
+ Source Files
+
Source Files
diff --git a/PCbuild/find_python.bat b/PCbuild/find_python.bat
index 7af5503d80a0fc..d3f62c93869003 100644
--- a/PCbuild/find_python.bat
+++ b/PCbuild/find_python.bat
@@ -52,7 +52,7 @@
@if "%_Py_NUGET%"=="" (set _Py_NUGET=%_Py_EXTERNALS_DIR%\nuget.exe)
@if "%_Py_NUGET_URL%"=="" (set _Py_NUGET_URL=https://aka.ms/nugetclidl)
@if NOT exist "%_Py_NUGET%" (
- @echo Downloading nuget...
+ @if not "%_Py_Quiet%"=="1" @echo Downloading nuget...
@rem NB: Must use single quotes around NUGET here, NOT double!
@rem Otherwise, a space in the path would break things
@rem If it fails, retry with any available copy of Python
@@ -63,7 +63,11 @@
)
@if not "%_Py_Quiet%"=="1" @echo Installing Python via nuget...
-@"%_Py_NUGET%" install pythonx86 -ExcludeVersion -OutputDirectory "%_Py_EXTERNALS_DIR%"
+@if not "%_Py_Quiet%"=="1" (
+ @"%_Py_NUGET%" install pythonx86 -ExcludeVersion -OutputDirectory "%_Py_EXTERNALS_DIR%"
+) else (
+ @"%_Py_NUGET%" install pythonx86 -Verbosity quiet -ExcludeVersion -OutputDirectory "%_Py_EXTERNALS_DIR%"
+)
@rem Quote it here; it's not quoted later because "py -x.y" wouldn't work
@if not errorlevel 1 (set PYTHON="%_Py_EXTERNALS_DIR%\pythonx86\tools\python.exe") & (set _Py_Python_Source=found on nuget.org) & goto :found
diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj
index bfe59acf12a69d..b0e62864421e17 100644
--- a/PCbuild/pythoncore.vcxproj
+++ b/PCbuild/pythoncore.vcxproj
@@ -248,6 +248,7 @@
+
@@ -279,6 +280,7 @@
+
@@ -548,6 +550,7 @@
+
diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters
index 0a8b0c3faf51e1..d5f61e9c5d7c89 100644
--- a/PCbuild/pythoncore.vcxproj.filters
+++ b/PCbuild/pythoncore.vcxproj.filters
@@ -648,6 +648,9 @@
Include\internal
+
+ Include\internal
+
Include\internal
@@ -732,6 +735,9 @@
Include\internal
+
+ Include\internal
+
Modules\zlib
@@ -1223,6 +1229,9 @@
Python
+
+ Python
+
Python
diff --git a/PCbuild/regen.targets b/PCbuild/regen.targets
index 99cfff5acc0baf..ed02f9163549b9 100644
--- a/PCbuild/regen.targets
+++ b/PCbuild/regen.targets
@@ -14,7 +14,7 @@
-C
<_OpcodeSources Include="$(PySourcePath)Tools\build\generate_opcode_h.py;$(PySourcePath)Lib\opcode.py" />
- <_OpcodeOutputs Include="$(PySourcePath)Include\opcode.h;$(PySourcePath)Include\internal\pycore_opcode.h;$(PySourcePath)Python\opcode_targets.h" />
+ <_OpcodeOutputs Include="$(PySourcePath)Include\opcode.h;$(PySourcePath)Include\internal\pycore_opcode.h" />
<_TokenSources Include="$(PySourcePath)Grammar\Tokens" />
<_TokenOutputs Include="$(PySourcePath)Doc\library\token-list.inc">
rst
@@ -59,7 +59,7 @@
Inputs="@(_OpcodeSources)" Outputs="@(_OpcodeOutputs)"
DependsOnTargets="FindPythonForBuild">
-
diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c
index 5a42f6f357317f..b10c9f1f8ea2cc 100644
--- a/Parser/tokenizer.c
+++ b/Parser/tokenizer.c
@@ -1539,6 +1539,9 @@ parser_warn(struct tok_state *tok, PyObject *category, const char *format, ...)
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'",
diff --git a/Programs/_testembed.c b/Programs/_testembed.c
index 351cdc302e8cb0..7ee64b22925f0c 100644
--- a/Programs/_testembed.c
+++ b/Programs/_testembed.c
@@ -237,6 +237,11 @@ static void check_stdio_details(const wchar_t *encoding, const wchar_t *errors)
if (errors) {
config_set_string(&config, &config.stdio_errors, errors);
}
+#ifdef MS_WINDOWS
+ // gh-106659: On Windows, don't use _io._WindowsConsoleIO which always
+ // announce UTF-8 for sys.stdin.encoding.
+ config.legacy_windows_stdio = 1;
+#endif
config_set_program_name(&config);
init_from_config_clear(&config);
diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h
index 9058327e846dc3..3fd6cdade69f9e 100644
--- a/Programs/test_frozenmain.h
+++ b/Programs/test_frozenmain.h
@@ -1,17 +1,17 @@
// Auto-generated by Programs/freeze_test_frozenmain.py
unsigned char M_test_frozenmain[] = {
227,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,
- 0,0,0,0,0,243,164,0,0,0,151,0,100,0,100,1,
- 108,0,90,0,100,0,100,1,108,1,90,1,2,0,101,2,
- 100,2,171,1,0,0,0,0,0,0,1,0,2,0,101,2,
- 100,3,101,0,106,6,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,171,2,0,0,0,0,0,0,
- 1,0,2,0,101,1,106,8,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,171,0,0,0,0,0,
- 0,0,100,4,25,0,0,0,90,5,100,5,68,0,93,20,
- 0,0,90,6,2,0,101,2,100,6,101,6,40,0,100,7,
- 101,5,101,6,25,0,0,0,40,0,157,4,171,1,0,0,
- 0,0,0,0,1,0,140,22,0,0,4,0,121,1,41,8,
+ 0,0,0,0,0,243,164,0,0,0,166,0,142,0,142,1,
+ 121,0,180,0,142,0,142,1,121,1,180,1,153,2,46,0,
+ 142,2,75,1,0,0,0,0,0,0,44,0,153,2,46,0,
+ 142,3,153,0,129,6,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,75,2,0,0,0,0,0,0,
+ 44,0,153,1,129,8,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,46,0,75,0,0,0,0,0,
+ 0,0,142,4,12,0,0,0,180,5,142,5,31,0,114,20,
+ 0,0,180,6,153,2,46,0,142,6,153,6,27,0,142,7,
+ 153,5,153,6,12,0,0,0,27,0,73,4,75,1,0,0,
+ 0,0,0,0,44,0,123,22,0,0,24,0,167,1,41,8,
233,0,0,0,0,78,122,18,70,114,111,122,101,110,32,72,
101,108,108,111,32,87,111,114,108,100,122,8,115,121,115,46,
97,114,103,118,218,6,99,111,110,102,105,103,41,5,218,12,
@@ -27,12 +27,12 @@ unsigned char M_test_frozenmain[] = {
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,
+ 0,1,0,0,0,115,99,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,214,4,41,241,15,7,1,42,
- 114,16,0,0,0,
+ 26,215,9,38,210,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,214,4,41,241,15,7,1,42,114,16,0,
+ 0,0,
};
diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h
new file mode 100644
index 00000000000000..eef071119bcd84
--- /dev/null
+++ b/Python/abstract_interp_cases.c.h
@@ -0,0 +1,789 @@
+// This file is generated by Tools/cases_generator/generate_cases.py
+// from:
+// Python/bytecodes.c
+// Do not edit!
+
+ case NOP: {
+ break;
+ }
+
+ case POP_TOP: {
+ STACK_SHRINK(1);
+ break;
+ }
+
+ case PUSH_NULL: {
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case END_SEND: {
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case UNARY_NEGATIVE: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case UNARY_NOT: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case TO_BOOL: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case TO_BOOL_BOOL: {
+ break;
+ }
+
+ case TO_BOOL_INT: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case TO_BOOL_LIST: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case TO_BOOL_NONE: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case TO_BOOL_STR: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case TO_BOOL_ALWAYS_TRUE: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case UNARY_INVERT: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case _GUARD_BOTH_INT: {
+ break;
+ }
+
+ case _GUARD_BOTH_FLOAT: {
+ break;
+ }
+
+ case _BINARY_OP_MULTIPLY_FLOAT: {
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case _BINARY_OP_ADD_FLOAT: {
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case _BINARY_OP_SUBTRACT_FLOAT: {
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case _GUARD_BOTH_UNICODE: {
+ break;
+ }
+
+ case _BINARY_OP_ADD_UNICODE: {
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case BINARY_SUBSCR: {
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case BINARY_SLICE: {
+ STACK_SHRINK(2);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case STORE_SLICE: {
+ STACK_SHRINK(4);
+ break;
+ }
+
+ case BINARY_SUBSCR_LIST_INT: {
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case BINARY_SUBSCR_STR_INT: {
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case BINARY_SUBSCR_TUPLE_INT: {
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case BINARY_SUBSCR_DICT: {
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case LIST_APPEND: {
+ STACK_SHRINK(1);
+ break;
+ }
+
+ case SET_ADD: {
+ STACK_SHRINK(1);
+ break;
+ }
+
+ case STORE_SUBSCR: {
+ STACK_SHRINK(3);
+ break;
+ }
+
+ case STORE_SUBSCR_LIST_INT: {
+ STACK_SHRINK(3);
+ break;
+ }
+
+ case STORE_SUBSCR_DICT: {
+ STACK_SHRINK(3);
+ break;
+ }
+
+ case DELETE_SUBSCR: {
+ STACK_SHRINK(2);
+ break;
+ }
+
+ case CALL_INTRINSIC_1: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case CALL_INTRINSIC_2: {
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case GET_AITER: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case GET_ANEXT: {
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case GET_AWAITABLE: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case POP_EXCEPT: {
+ STACK_SHRINK(1);
+ break;
+ }
+
+ case LOAD_ASSERTION_ERROR: {
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case LOAD_BUILD_CLASS: {
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case STORE_NAME: {
+ STACK_SHRINK(1);
+ break;
+ }
+
+ case DELETE_NAME: {
+ break;
+ }
+
+ case UNPACK_SEQUENCE: {
+ STACK_SHRINK(1);
+ STACK_GROW(oparg);
+ break;
+ }
+
+ case UNPACK_SEQUENCE_TWO_TUPLE: {
+ STACK_SHRINK(1);
+ STACK_GROW(oparg);
+ break;
+ }
+
+ case UNPACK_SEQUENCE_TUPLE: {
+ STACK_SHRINK(1);
+ STACK_GROW(oparg);
+ break;
+ }
+
+ case UNPACK_SEQUENCE_LIST: {
+ STACK_SHRINK(1);
+ STACK_GROW(oparg);
+ break;
+ }
+
+ case UNPACK_EX: {
+ STACK_GROW((oparg & 0xFF) + (oparg >> 8));
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1 - (oparg >> 8))), true);
+ break;
+ }
+
+ case STORE_ATTR: {
+ STACK_SHRINK(2);
+ break;
+ }
+
+ case DELETE_ATTR: {
+ STACK_SHRINK(1);
+ break;
+ }
+
+ case STORE_GLOBAL: {
+ STACK_SHRINK(1);
+ break;
+ }
+
+ case DELETE_GLOBAL: {
+ break;
+ }
+
+ case _LOAD_LOCALS: {
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case _LOAD_FROM_DICT_OR_GLOBALS: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case LOAD_GLOBAL: {
+ STACK_GROW(1);
+ STACK_GROW(((oparg & 1) ? 1 : 0));
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1 - (oparg & 1 ? 1 : 0))), true);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-(oparg & 1 ? 1 : 0))), true);
+ break;
+ }
+
+ case _GUARD_GLOBALS_VERSION: {
+ break;
+ }
+
+ case _GUARD_BUILTINS_VERSION: {
+ break;
+ }
+
+ case _LOAD_GLOBAL_MODULE: {
+ STACK_GROW(1);
+ STACK_GROW(((oparg & 1) ? 1 : 0));
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1 - (oparg & 1 ? 1 : 0))), true);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-(oparg & 1 ? 1 : 0))), true);
+ break;
+ }
+
+ case _LOAD_GLOBAL_BUILTINS: {
+ STACK_GROW(1);
+ STACK_GROW(((oparg & 1) ? 1 : 0));
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1 - (oparg & 1 ? 1 : 0))), true);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-(oparg & 1 ? 1 : 0))), true);
+ break;
+ }
+
+ case DELETE_FAST: {
+ break;
+ }
+
+ case DELETE_DEREF: {
+ break;
+ }
+
+ case LOAD_FROM_DICT_OR_DEREF: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case LOAD_DEREF: {
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case STORE_DEREF: {
+ STACK_SHRINK(1);
+ break;
+ }
+
+ case COPY_FREE_VARS: {
+ break;
+ }
+
+ case BUILD_STRING: {
+ STACK_SHRINK(oparg);
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case BUILD_TUPLE: {
+ STACK_SHRINK(oparg);
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case BUILD_LIST: {
+ STACK_SHRINK(oparg);
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case LIST_EXTEND: {
+ STACK_SHRINK(1);
+ break;
+ }
+
+ case SET_UPDATE: {
+ STACK_SHRINK(1);
+ break;
+ }
+
+ case BUILD_SET: {
+ STACK_SHRINK(oparg);
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case BUILD_MAP: {
+ STACK_SHRINK(oparg*2);
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case SETUP_ANNOTATIONS: {
+ break;
+ }
+
+ case BUILD_CONST_KEY_MAP: {
+ STACK_SHRINK(oparg);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case DICT_UPDATE: {
+ STACK_SHRINK(1);
+ break;
+ }
+
+ case DICT_MERGE: {
+ STACK_SHRINK(1);
+ break;
+ }
+
+ case MAP_ADD: {
+ STACK_SHRINK(2);
+ break;
+ }
+
+ case LOAD_SUPER_ATTR_ATTR: {
+ STACK_SHRINK(2);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(0)), true);
+ break;
+ }
+
+ case LOAD_SUPER_ATTR_METHOD: {
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-2)), true);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case LOAD_ATTR: {
+ STACK_GROW(((oparg & 1) ? 1 : 0));
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1 - (oparg & 1 ? 1 : 0))), true);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-(oparg & 1 ? 1 : 0))), true);
+ break;
+ }
+
+ case _GUARD_TYPE_VERSION: {
+ break;
+ }
+
+ case _CHECK_MANAGED_OBJECT_HAS_VALUES: {
+ break;
+ }
+
+ case _LOAD_ATTR_INSTANCE_VALUE: {
+ STACK_GROW(((oparg & 1) ? 1 : 0));
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1 - (oparg & 1 ? 1 : 0))), true);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-(oparg & 1 ? 1 : 0))), true);
+ break;
+ }
+
+ case COMPARE_OP: {
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case COMPARE_OP_FLOAT: {
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case COMPARE_OP_INT: {
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case COMPARE_OP_STR: {
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case IS_OP: {
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case CONTAINS_OP: {
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case CHECK_EG_MATCH: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-2)), true);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case CHECK_EXC_MATCH: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case IS_NONE: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case GET_LEN: {
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case MATCH_CLASS: {
+ STACK_SHRINK(2);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case MATCH_MAPPING: {
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case MATCH_SEQUENCE: {
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case MATCH_KEYS: {
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case GET_ITER: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case GET_YIELD_FROM_ITER: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case _ITER_CHECK_LIST: {
+ break;
+ }
+
+ case _IS_ITER_EXHAUSTED_LIST: {
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case _ITER_NEXT_LIST: {
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case _ITER_CHECK_TUPLE: {
+ break;
+ }
+
+ case _IS_ITER_EXHAUSTED_TUPLE: {
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case _ITER_NEXT_TUPLE: {
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case _ITER_CHECK_RANGE: {
+ break;
+ }
+
+ case _IS_ITER_EXHAUSTED_RANGE: {
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case _ITER_NEXT_RANGE: {
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case WITH_EXCEPT_START: {
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case PUSH_EXC_INFO: {
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-2)), true);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case _CHECK_PEP_523: {
+ break;
+ }
+
+ case _CHECK_FUNCTION_EXACT_ARGS: {
+ break;
+ }
+
+ case _CHECK_STACK_SPACE: {
+ break;
+ }
+
+ case _INIT_CALL_PY_EXACT_ARGS: {
+ STACK_SHRINK(oparg);
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case _PUSH_FRAME: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case CALL_NO_KW_TYPE_1: {
+ STACK_SHRINK(oparg);
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case CALL_NO_KW_STR_1: {
+ STACK_SHRINK(oparg);
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case CALL_NO_KW_TUPLE_1: {
+ STACK_SHRINK(oparg);
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case EXIT_INIT_CHECK: {
+ STACK_SHRINK(1);
+ break;
+ }
+
+ case CALL_NO_KW_BUILTIN_O: {
+ STACK_SHRINK(oparg);
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case CALL_NO_KW_BUILTIN_FAST: {
+ STACK_SHRINK(oparg);
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case CALL_NO_KW_LEN: {
+ STACK_SHRINK(oparg);
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case CALL_NO_KW_ISINSTANCE: {
+ STACK_SHRINK(oparg);
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case CALL_NO_KW_METHOD_DESCRIPTOR_O: {
+ STACK_SHRINK(oparg);
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS: {
+ STACK_SHRINK(oparg);
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case CALL_NO_KW_METHOD_DESCRIPTOR_FAST: {
+ STACK_SHRINK(oparg);
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case MAKE_FUNCTION: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case SET_FUNCTION_ATTRIBUTE: {
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case BUILD_SLICE: {
+ STACK_SHRINK(((oparg == 3) ? 1 : 0));
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case CONVERT_VALUE: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case FORMAT_SIMPLE: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case FORMAT_WITH_SPEC: {
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case BINARY_OP: {
+ STACK_SHRINK(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case SWAP: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-2 - (oparg-2))), true);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case _POP_JUMP_IF_FALSE: {
+ STACK_SHRINK(1);
+ break;
+ }
+
+ case _POP_JUMP_IF_TRUE: {
+ STACK_SHRINK(1);
+ break;
+ }
+
+ case JUMP_TO_TOP: {
+ break;
+ }
+
+ case SAVE_IP: {
+ break;
+ }
+
+ case SAVE_CURRENT_IP: {
+ break;
+ }
+
+ case EXIT_TRACE: {
+ break;
+ }
+
+ case INSERT: {
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1 - oparg)), true);
+ break;
+ }
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index d6bfb624c77133..6f17472e04e5e3 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -17,7 +17,6 @@
#include "pycore_long.h" // _PyLong_GetZero()
#include "pycore_moduleobject.h" // PyModuleObject
#include "pycore_object.h" // _PyObject_GC_TRACK()
-#include "pycore_opcode.h" // EXTRA_CASES
#include "pycore_opcode_metadata.h" // uop names
#include "pycore_opcode_utils.h" // MAKE_FUNCTION_*
#include "pycore_pyerrors.h" // _PyErr_GetRaisedException()
@@ -73,7 +72,6 @@ dummy_func(
_PyInterpreterFrame *frame,
unsigned char opcode,
unsigned int oparg,
- _PyCFrame cframe,
_Py_CODEUNIT *next_instr,
PyObject **stack_pointer,
PyObject *kwnames,
@@ -135,8 +133,7 @@ dummy_func(
}
inst(RESUME, (--)) {
- assert(tstate->cframe == &cframe);
- assert(frame == cframe.current_frame);
+ assert(frame == tstate->current_frame);
/* Possibly combine this with eval breaker */
if (_PyFrame_GetCode(frame)->_co_instrumentation_version != tstate->interp->monitoring_version) {
int err = _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp);
@@ -753,9 +750,8 @@ dummy_func(
inst(INTERPRETER_EXIT, (retval --)) {
assert(frame == &entry_frame);
assert(_PyFrame_IsIncomplete(frame));
- /* Restore previous cframe and return. */
- tstate->cframe = cframe.previous;
- assert(tstate->cframe->current_frame == frame->previous);
+ /* Restore previous frame and return. */
+ tstate->current_frame = frame->previous;
assert(!_PyErr_Occurred(tstate));
tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS;
return retval;
@@ -769,7 +765,7 @@ dummy_func(
assert(frame != &entry_frame);
// GH-99729: We need to unlink the frame *before* clearing it:
_PyInterpreterFrame *dying = frame;
- frame = cframe.current_frame = dying->previous;
+ frame = tstate->current_frame = dying->previous;
_PyEvalFrameClearAndPop(tstate, dying);
frame->prev_instr += frame->return_offset;
_PyFrame_StackPush(frame, retval);
@@ -788,7 +784,7 @@ dummy_func(
assert(frame != &entry_frame);
// GH-99729: We need to unlink the frame *before* clearing it:
_PyInterpreterFrame *dying = frame;
- frame = cframe.current_frame = dying->previous;
+ frame = tstate->current_frame = dying->previous;
_PyEvalFrameClearAndPop(tstate, dying);
frame->prev_instr += frame->return_offset;
_PyFrame_StackPush(frame, retval);
@@ -804,7 +800,7 @@ dummy_func(
assert(frame != &entry_frame);
// GH-99729: We need to unlink the frame *before* clearing it:
_PyInterpreterFrame *dying = frame;
- frame = cframe.current_frame = dying->previous;
+ frame = tstate->current_frame = dying->previous;
_PyEvalFrameClearAndPop(tstate, dying);
frame->prev_instr += frame->return_offset;
_PyFrame_StackPush(frame, retval);
@@ -824,7 +820,7 @@ dummy_func(
assert(frame != &entry_frame);
// GH-99729: We need to unlink the frame *before* clearing it:
_PyInterpreterFrame *dying = frame;
- frame = cframe.current_frame = dying->previous;
+ frame = tstate->current_frame = dying->previous;
_PyEvalFrameClearAndPop(tstate, dying);
frame->prev_instr += frame->return_offset;
_PyFrame_StackPush(frame, retval);
@@ -957,13 +953,13 @@ dummy_func(
{
PyGenObject *gen = (PyGenObject *)receiver;
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
- frame->return_offset = oparg;
STACK_SHRINK(1);
_PyFrame_StackPush(gen_frame, v);
gen->gi_frame_state = FRAME_EXECUTING;
gen->gi_exc_state.previous_item = tstate->exc_info;
tstate->exc_info = &gen->gi_exc_state;
SKIP_OVER(INLINE_CACHE_ENTRIES_SEND);
+ frame->return_offset = oparg;
DISPATCH_INLINED(gen_frame);
}
if (Py_IsNone(v) && PyIter_Check(receiver)) {
@@ -996,13 +992,13 @@ dummy_func(
DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, SEND);
STAT_INC(SEND, hit);
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
- frame->return_offset = oparg;
STACK_SHRINK(1);
_PyFrame_StackPush(gen_frame, v);
gen->gi_frame_state = FRAME_EXECUTING;
gen->gi_exc_state.previous_item = tstate->exc_info;
tstate->exc_info = &gen->gi_exc_state;
SKIP_OVER(INLINE_CACHE_ENTRIES_SEND);
+ frame->return_offset = oparg;
DISPATCH_INLINED(gen_frame);
}
@@ -1020,7 +1016,7 @@ dummy_func(
gen->gi_exc_state.previous_item = NULL;
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *gen_frame = frame;
- frame = cframe.current_frame = frame->previous;
+ frame = tstate->current_frame = frame->previous;
gen_frame->previous = NULL;
_PyFrame_StackPush(frame, retval);
goto resume_frame;
@@ -1039,7 +1035,7 @@ dummy_func(
gen->gi_exc_state.previous_item = NULL;
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *gen_frame = frame;
- frame = cframe.current_frame = frame->previous;
+ frame = tstate->current_frame = frame->previous;
gen_frame->previous = NULL;
_PyFrame_StackPush(frame, retval);
goto resume_frame;
@@ -1315,7 +1311,7 @@ dummy_func(
LOAD_GLOBAL_BUILTIN,
};
- inst(LOAD_GLOBAL, (unused/1, unused/1, unused/1, unused/1 -- null if (oparg & 1), v)) {
+ inst(LOAD_GLOBAL, (unused/1, unused/1, unused/1, unused/1 -- res, null if (oparg & 1))) {
#if ENABLE_SPECIALIZATION
_PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
@@ -1331,10 +1327,10 @@ dummy_func(
if (PyDict_CheckExact(GLOBALS())
&& PyDict_CheckExact(BUILTINS()))
{
- v = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(),
- (PyDictObject *)BUILTINS(),
- name);
- if (v == NULL) {
+ res = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(),
+ (PyDictObject *)BUILTINS(),
+ name);
+ if (res == NULL) {
if (!_PyErr_Occurred(tstate)) {
/* _PyDict_LoadGlobal() returns NULL without raising
* an exception if the key doesn't exist */
@@ -1343,17 +1339,17 @@ dummy_func(
}
ERROR_IF(true, error);
}
- Py_INCREF(v);
+ Py_INCREF(res);
}
else {
/* Slow-path if globals or builtins is not a dict */
/* namespace 1: globals */
- ERROR_IF(PyMapping_GetOptionalItem(GLOBALS(), name, &v) < 0, error);
- if (v == NULL) {
+ ERROR_IF(PyMapping_GetOptionalItem(GLOBALS(), name, &res) < 0, error);
+ if (res == NULL) {
/* namespace 2: builtins */
- ERROR_IF(PyMapping_GetOptionalItem(BUILTINS(), name, &v) < 0, error);
- if (v == NULL) {
+ ERROR_IF(PyMapping_GetOptionalItem(BUILTINS(), name, &res) < 0, error);
+ if (res == NULL) {
_PyEval_FormatExcCheckArg(
tstate, PyExc_NameError,
NAME_ERROR_MSG, name);
@@ -1378,7 +1374,7 @@ dummy_func(
assert(DK_IS_UNICODE(dict->ma_keys));
}
- op(_LOAD_GLOBAL_MODULE, (index/1 -- null if (oparg & 1), res)) {
+ op(_LOAD_GLOBAL_MODULE, (index/1 -- res, null if (oparg & 1))) {
PyDictObject *dict = (PyDictObject *)GLOBALS();
PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys);
res = entries[index].me_value;
@@ -1388,7 +1384,7 @@ dummy_func(
null = NULL;
}
- op(_LOAD_GLOBAL_BUILTINS, (index/1 -- null if (oparg & 1), res)) {
+ op(_LOAD_GLOBAL_BUILTINS, (index/1 -- res, null if (oparg & 1))) {
PyDictObject *bdict = (PyDictObject *)BUILTINS();
PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(bdict->ma_keys);
res = entries[index].me_value;
@@ -1614,8 +1610,7 @@ dummy_func(
ERROR_IF(map == NULL, error);
}
- inst(DICT_UPDATE, (update --)) {
- PyObject *dict = PEEK(oparg + 1); // update is still on the stack
+ inst(DICT_UPDATE, (dict, unused[oparg - 1], update -- dict, unused[oparg - 1])) {
if (PyDict_Update(dict, update) < 0) {
if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) {
_PyErr_Format(tstate, PyExc_TypeError,
@@ -1628,26 +1623,23 @@ dummy_func(
DECREF_INPUTS();
}
- inst(DICT_MERGE, (update --)) {
- PyObject *dict = PEEK(oparg + 1); // update is still on the stack
-
+ inst(DICT_MERGE, (callable, unused, unused, dict, unused[oparg - 1], update -- callable, unused, unused, dict, unused[oparg - 1])) {
if (_PyDict_MergeEx(dict, update, 2) < 0) {
- _PyEval_FormatKwargsError(tstate, PEEK(3 + oparg), update);
+ _PyEval_FormatKwargsError(tstate, callable, update);
DECREF_INPUTS();
ERROR_IF(true, error);
}
DECREF_INPUTS();
}
- inst(MAP_ADD, (key, value --)) {
- PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack
+ inst(MAP_ADD, (dict, unused[oparg - 1], key, value -- dict, unused[oparg - 1])) {
assert(PyDict_CheckExact(dict));
/* dict[key] = value */
// Do not DECREF INPUTS because the function steals the references
ERROR_IF(_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0, error);
}
- inst(INSTRUMENTED_LOAD_SUPER_ATTR, (unused/9, unused, unused, unused -- unused if (oparg & 1), unused)) {
+ inst(INSTRUMENTED_LOAD_SUPER_ATTR, (unused/9, unused, unused, unused -- unused, unused if (oparg & 1))) {
_PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr;
// cancel out the decrement that will happen in LOAD_SUPER_ATTR; we
// don't want to specialize instrumented instructions
@@ -1660,7 +1652,7 @@ dummy_func(
LOAD_SUPER_ATTR_METHOD,
};
- inst(LOAD_SUPER_ATTR, (unused/1, global_super, class, self -- res2 if (oparg & 1), res)) {
+ inst(LOAD_SUPER_ATTR, (unused/1, global_super, class, self -- attr, null if (oparg & 1))) {
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2);
int load_method = oparg & 1;
#if ENABLE_SPECIALIZATION
@@ -1704,9 +1696,10 @@ dummy_func(
}
DECREF_INPUTS();
ERROR_IF(super == NULL, error);
- res = PyObject_GetAttr(super, name);
+ attr = PyObject_GetAttr(super, name);
Py_DECREF(super);
- ERROR_IF(res == NULL, error);
+ ERROR_IF(attr == NULL, error);
+ null = NULL;
}
pseudo(LOAD_SUPER_METHOD) = {
@@ -1721,18 +1714,18 @@ dummy_func(
LOAD_SUPER_ATTR,
};
- inst(LOAD_SUPER_ATTR_ATTR, (unused/1, global_super, class, self -- res2 if (oparg & 1), res)) {
+ inst(LOAD_SUPER_ATTR_ATTR, (unused/1, global_super, class, self -- attr, unused if (0))) {
assert(!(oparg & 1));
DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR);
DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR);
STAT_INC(LOAD_SUPER_ATTR, hit);
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2);
- res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL);
+ attr = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL);
DECREF_INPUTS();
- ERROR_IF(res == NULL, error);
+ ERROR_IF(attr == NULL, error);
}
- inst(LOAD_SUPER_ATTR_METHOD, (unused/1, global_super, class, self -- res2, res)) {
+ inst(LOAD_SUPER_ATTR_METHOD, (unused/1, global_super, class, self -- attr, self_or_null)) {
assert(oparg & 1);
DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR);
DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR);
@@ -1740,20 +1733,19 @@ dummy_func(
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2);
PyTypeObject *cls = (PyTypeObject *)class;
int method_found = 0;
- res2 = _PySuper_Lookup(cls, self, name,
+ attr = _PySuper_Lookup(cls, self, name,
Py_TYPE(self)->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL);
Py_DECREF(global_super);
Py_DECREF(class);
- if (res2 == NULL) {
+ if (attr == NULL) {
Py_DECREF(self);
ERROR_IF(true, error);
}
if (method_found) {
- res = self; // transfer ownership
+ self_or_null = self; // transfer ownership
} else {
Py_DECREF(self);
- res = res2;
- res2 = NULL;
+ self_or_null = NULL;
}
}
@@ -1772,7 +1764,7 @@ dummy_func(
LOAD_ATTR_NONDESCRIPTOR_NO_DICT,
};
- inst(LOAD_ATTR, (unused/9, owner -- res2 if (oparg & 1), res)) {
+ inst(LOAD_ATTR, (unused/9, owner -- attr, self_or_null if (oparg & 1))) {
#if ENABLE_SPECIALIZATION
_PyAttrCache *cache = (_PyAttrCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
@@ -1787,16 +1779,15 @@ dummy_func(
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1);
if (oparg & 1) {
/* Designed to work in tandem with CALL, pushes two values. */
- PyObject* meth = NULL;
- if (_PyObject_GetMethod(owner, name, &meth)) {
+ attr = NULL;
+ if (_PyObject_GetMethod(owner, name, &attr)) {
/* We can bypass temporary bound method object.
meth is unbound method and obj is self.
meth | self | arg1 | ... | argN
*/
- assert(meth != NULL); // No errors on this branch
- res2 = meth;
- res = owner; // Transfer ownership
+ assert(attr != NULL); // No errors on this branch
+ self_or_null = owner; // Transfer ownership
}
else {
/* meth is not an unbound method (but a regular attr, or
@@ -1807,16 +1798,15 @@ dummy_func(
NULL | meth | arg1 | ... | argN
*/
DECREF_INPUTS();
- ERROR_IF(meth == NULL, error);
- res2 = NULL;
- res = meth;
+ ERROR_IF(attr == NULL, error);
+ self_or_null = NULL;
}
}
else {
/* Classic, pushes one value. */
- res = PyObject_GetAttr(owner, name);
+ attr = PyObject_GetAttr(owner, name);
DECREF_INPUTS();
- ERROR_IF(res == NULL, error);
+ ERROR_IF(attr == NULL, error);
}
}
@@ -1833,17 +1823,19 @@ dummy_func(
op(_CHECK_MANAGED_OBJECT_HAS_VALUES, (owner -- owner)) {
assert(Py_TYPE(owner)->tp_dictoffset < 0);
assert(Py_TYPE(owner)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
- DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR);
+ PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner);
+ DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) &&
+ !_PyObject_MakeInstanceAttributesFromDict(owner, dorv),
+ LOAD_ATTR);
}
- op(_LOAD_ATTR_INSTANCE_VALUE, (index/1, owner -- res2 if (oparg & 1), res)) {
+ op(_LOAD_ATTR_INSTANCE_VALUE, (index/1, owner -- attr, null if (oparg & 1))) {
PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
- res = _PyDictOrValues_GetValues(dorv)->values[index];
- DEOPT_IF(res == NULL, LOAD_ATTR);
+ attr = _PyDictOrValues_GetValues(dorv)->values[index];
+ DEOPT_IF(attr == NULL, LOAD_ATTR);
STAT_INC(LOAD_ATTR, hit);
- Py_INCREF(res);
- res2 = NULL;
+ Py_INCREF(attr);
+ null = NULL;
DECREF_INPUTS();
}
@@ -1854,7 +1846,7 @@ dummy_func(
_LOAD_ATTR_INSTANCE_VALUE +
unused/5; // Skip over rest of cache
- inst(LOAD_ATTR_MODULE, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) {
+ inst(LOAD_ATTR_MODULE, (unused/1, type_version/2, index/1, unused/5, owner -- attr, null if (oparg & 1))) {
DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR);
PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict;
assert(dict != NULL);
@@ -1862,15 +1854,15 @@ dummy_func(
assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE);
assert(index < dict->ma_keys->dk_nentries);
PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + index;
- res = ep->me_value;
- DEOPT_IF(res == NULL, LOAD_ATTR);
+ attr = ep->me_value;
+ DEOPT_IF(attr == NULL, LOAD_ATTR);
STAT_INC(LOAD_ATTR, hit);
- Py_INCREF(res);
- res2 = NULL;
+ Py_INCREF(attr);
+ null = NULL;
DECREF_INPUTS();
}
- inst(LOAD_ATTR_WITH_HINT, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) {
+ inst(LOAD_ATTR_WITH_HINT, (unused/1, type_version/2, index/1, unused/5, owner -- attr, null if (oparg & 1))) {
PyTypeObject *tp = Py_TYPE(owner);
assert(type_version != 0);
DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
@@ -1886,49 +1878,50 @@ dummy_func(
if (DK_IS_UNICODE(dict->ma_keys)) {
PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint;
DEOPT_IF(ep->me_key != name, LOAD_ATTR);
- res = ep->me_value;
+ attr = ep->me_value;
}
else {
PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + hint;
DEOPT_IF(ep->me_key != name, LOAD_ATTR);
- res = ep->me_value;
+ attr = ep->me_value;
}
- DEOPT_IF(res == NULL, LOAD_ATTR);
+ DEOPT_IF(attr == NULL, LOAD_ATTR);
STAT_INC(LOAD_ATTR, hit);
- Py_INCREF(res);
- res2 = NULL;
+ Py_INCREF(attr);
+ null = NULL;
DECREF_INPUTS();
}
- inst(LOAD_ATTR_SLOT, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) {
+ inst(LOAD_ATTR_SLOT, (unused/1, type_version/2, index/1, unused/5, owner -- attr, null if (oparg & 1))) {
PyTypeObject *tp = Py_TYPE(owner);
assert(type_version != 0);
DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
char *addr = (char *)owner + index;
- res = *(PyObject **)addr;
- DEOPT_IF(res == NULL, LOAD_ATTR);
+ attr = *(PyObject **)addr;
+ DEOPT_IF(attr == NULL, LOAD_ATTR);
STAT_INC(LOAD_ATTR, hit);
- Py_INCREF(res);
- res2 = NULL;
+ Py_INCREF(attr);
+ null = NULL;
DECREF_INPUTS();
}
- inst(LOAD_ATTR_CLASS, (unused/1, type_version/2, unused/2, descr/4, cls -- res2 if (oparg & 1), res)) {
+ inst(LOAD_ATTR_CLASS, (unused/1, type_version/2, unused/2, descr/4, owner -- attr, null if (oparg & 1))) {
- DEOPT_IF(!PyType_Check(cls), LOAD_ATTR);
- DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version,
+ DEOPT_IF(!PyType_Check(owner), LOAD_ATTR);
+ DEOPT_IF(((PyTypeObject *)owner)->tp_version_tag != type_version,
LOAD_ATTR);
assert(type_version != 0);
STAT_INC(LOAD_ATTR, hit);
- res2 = NULL;
- res = descr;
- assert(res != NULL);
- Py_INCREF(res);
+ null = NULL;
+ attr = descr;
+ assert(attr != NULL);
+ Py_INCREF(attr);
DECREF_INPUTS();
}
- inst(LOAD_ATTR_PROPERTY, (unused/1, type_version/2, func_version/2, fget/4, owner -- unused if (oparg & 1), unused)) {
+ inst(LOAD_ATTR_PROPERTY, (unused/1, type_version/2, func_version/2, fget/4, owner -- unused, unused if (0))) {
+ assert((oparg & 1) == 0);
DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR);
PyTypeObject *cls = Py_TYPE(owner);
@@ -1945,16 +1938,15 @@ dummy_func(
Py_INCREF(fget);
_PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 1);
// Manipulate stack directly because we exit with DISPATCH_INLINED().
- SET_TOP(NULL);
- int shrink_stack = !(oparg & 1);
- STACK_SHRINK(shrink_stack);
+ STACK_SHRINK(1);
new_frame->localsplus[0] = owner;
SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR);
frame->return_offset = 0;
DISPATCH_INLINED(new_frame);
}
- inst(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, (unused/1, type_version/2, func_version/2, getattribute/4, owner -- unused if (oparg & 1), unused)) {
+ inst(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, (unused/1, type_version/2, func_version/2, getattribute/4, owner -- unused, unused if (0))) {
+ assert((oparg & 1) == 0);
DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR);
PyTypeObject *cls = Py_TYPE(owner);
DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR);
@@ -1972,9 +1964,7 @@ dummy_func(
Py_INCREF(f);
_PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 2);
// Manipulate stack directly because we exit with DISPATCH_INLINED().
- SET_TOP(NULL);
- int shrink_stack = !(oparg & 1);
- STACK_SHRINK(shrink_stack);
+ STACK_SHRINK(1);
new_frame->localsplus[0] = owner;
new_frame->localsplus[1] = Py_NewRef(name);
SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR);
@@ -2214,10 +2204,10 @@ dummy_func(
OBJECT_STAT_INC(optimization_attempts);
frame = _PyOptimizer_BackEdge(frame, here, next_instr, stack_pointer);
if (frame == NULL) {
- frame = cframe.current_frame;
+ frame = tstate->current_frame;
goto resume_with_error;
}
- assert(frame == cframe.current_frame);
+ assert(frame == tstate->current_frame);
here[1].cache &= ((1 << OPTIMIZER_BITS_IN_COUNTER) -1);
goto resume_frame;
}
@@ -2245,7 +2235,7 @@ dummy_func(
Py_INCREF(executor);
frame = executor->execute(executor, frame, stack_pointer);
if (frame == NULL) {
- frame = cframe.current_frame;
+ frame = tstate->current_frame;
goto resume_with_error;
}
goto resume_frame;
@@ -2594,7 +2584,6 @@ dummy_func(
DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER);
STAT_INC(FOR_ITER, hit);
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
- frame->return_offset = oparg;
_PyFrame_StackPush(gen_frame, Py_None);
gen->gi_frame_state = FRAME_EXECUTING;
gen->gi_exc_state.previous_item = tstate->exc_info;
@@ -2602,6 +2591,7 @@ dummy_func(
SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER);
assert(next_instr[oparg].op.code == END_FOR ||
next_instr[oparg].op.code == INSTRUMENTED_END_FOR);
+ frame->return_offset = oparg;
DISPATCH_INLINED(gen_frame);
}
@@ -2728,80 +2718,84 @@ dummy_func(
exc_info->exc_value = Py_NewRef(new_exc);
}
- inst(LOAD_ATTR_METHOD_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, self -- res2 if (1), res)) {
+ inst(LOAD_ATTR_METHOD_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, owner -- attr, self if (1))) {
assert(oparg & 1);
/* Cached method object */
- PyTypeObject *self_cls = Py_TYPE(self);
+ PyTypeObject *owner_cls = Py_TYPE(owner);
assert(type_version != 0);
- DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR);
- assert(self_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self);
- DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR);
- PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls;
- DEOPT_IF(self_heap_type->ht_cached_keys->dk_version !=
+ DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR);
+ assert(owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT);
+ PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner);
+ DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) &&
+ !_PyObject_MakeInstanceAttributesFromDict(owner, dorv),
+ LOAD_ATTR);
+ PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls;
+ DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version !=
keys_version, LOAD_ATTR);
STAT_INC(LOAD_ATTR, hit);
assert(descr != NULL);
- res2 = Py_NewRef(descr);
- assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR));
- res = self;
+ attr = Py_NewRef(descr);
+ assert(_PyType_HasFeature(Py_TYPE(attr), Py_TPFLAGS_METHOD_DESCRIPTOR));
+ self = owner;
}
- inst(LOAD_ATTR_METHOD_NO_DICT, (unused/1, type_version/2, unused/2, descr/4, self -- res2 if (1), res)) {
+ inst(LOAD_ATTR_METHOD_NO_DICT, (unused/1, type_version/2, unused/2, descr/4, owner -- attr, self if (1))) {
assert(oparg & 1);
- PyTypeObject *self_cls = Py_TYPE(self);
- DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR);
- assert(self_cls->tp_dictoffset == 0);
+ PyTypeObject *owner_cls = Py_TYPE(owner);
+ DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR);
+ assert(owner_cls->tp_dictoffset == 0);
STAT_INC(LOAD_ATTR, hit);
assert(descr != NULL);
assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR));
- res2 = Py_NewRef(descr);
- res = self;
+ attr = Py_NewRef(descr);
+ self = owner;
}
- inst(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, self -- res2 if (0), res)) {
+ inst(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, owner -- attr, unused if (0))) {
assert((oparg & 1) == 0);
- PyTypeObject *self_cls = Py_TYPE(self);
+ PyTypeObject *owner_cls = Py_TYPE(owner);
assert(type_version != 0);
- DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR);
- assert(self_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self);
- DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR);
- PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls;
- DEOPT_IF(self_heap_type->ht_cached_keys->dk_version !=
+ DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR);
+ assert(owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT);
+ PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner);
+ DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) &&
+ !_PyObject_MakeInstanceAttributesFromDict(owner, dorv),
+ LOAD_ATTR);
+ PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls;
+ DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version !=
keys_version, LOAD_ATTR);
STAT_INC(LOAD_ATTR, hit);
assert(descr != NULL);
DECREF_INPUTS();
- res = Py_NewRef(descr);
+ attr = Py_NewRef(descr);
}
- inst(LOAD_ATTR_NONDESCRIPTOR_NO_DICT, (unused/1, type_version/2, unused/2, descr/4, self -- res2 if (0), res)) {
+ inst(LOAD_ATTR_NONDESCRIPTOR_NO_DICT, (unused/1, type_version/2, unused/2, descr/4, owner -- attr, unused if (0))) {
assert((oparg & 1) == 0);
- PyTypeObject *self_cls = Py_TYPE(self);
+ PyTypeObject *owner_cls = Py_TYPE(owner);
assert(type_version != 0);
- DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR);
- assert(self_cls->tp_dictoffset == 0);
+ DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR);
+ assert(owner_cls->tp_dictoffset == 0);
STAT_INC(LOAD_ATTR, hit);
assert(descr != NULL);
DECREF_INPUTS();
- res = Py_NewRef(descr);
+ attr = Py_NewRef(descr);
}
- inst(LOAD_ATTR_METHOD_LAZY_DICT, (unused/1, type_version/2, unused/2, descr/4, self -- res2 if (1), res)) {
+ inst(LOAD_ATTR_METHOD_LAZY_DICT, (unused/1, type_version/2, unused/2, descr/4, owner -- attr, self if (1))) {
assert(oparg & 1);
- 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;
+ PyTypeObject *owner_cls = Py_TYPE(owner);
+ DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR);
+ Py_ssize_t dictoffset = owner_cls->tp_dictoffset;
assert(dictoffset > 0);
- PyObject *dict = *(PyObject **)((char *)self + dictoffset);
+ PyObject *dict = *(PyObject **)((char *)owner + dictoffset);
/* This object has a __dict__, just not yet created */
DEOPT_IF(dict != NULL, LOAD_ATTR);
STAT_INC(LOAD_ATTR, hit);
assert(descr != NULL);
assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR));
- res2 = Py_NewRef(descr);
- res = self;
+ attr = Py_NewRef(descr);
+ self = owner;
}
inst(KW_NAMES, (--)) {
@@ -2811,9 +2805,9 @@ dummy_func(
}
inst(INSTRUMENTED_CALL, ( -- )) {
- int is_meth = PEEK(oparg+2) != NULL;
+ int is_meth = PEEK(oparg + 1) != NULL;
int total_args = oparg + is_meth;
- PyObject *function = PEEK(total_args + 1);
+ PyObject *function = PEEK(oparg + 2);
PyObject *arg = total_args == 0 ?
&_PyInstrumentation_MISSING : PEEK(total_args);
int err = _Py_call_instrumentation_2args(
@@ -2855,11 +2849,9 @@ dummy_func(
// (Some args may be keywords, see KW_NAMES, which sets 'kwnames'.)
// On exit, the stack is [result].
// When calling Python, inline the call using DISPATCH_INLINED().
- inst(CALL, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
- int is_meth = method != NULL;
+ inst(CALL, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
int total_args = oparg;
- if (is_meth) {
- callable = method;
+ if (self_or_null != NULL) {
args--;
total_args++;
}
@@ -2873,13 +2865,12 @@ dummy_func(
STAT_INC(CALL, deferred);
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
#endif /* ENABLE_SPECIALIZATION */
- if (!is_meth && Py_TYPE(callable) == &PyMethod_Type) {
- is_meth = 1; // For consistenct; it's dead, though
+ if (self_or_null == NULL && Py_TYPE(callable) == &PyMethod_Type) {
args--;
total_args++;
PyObject *self = ((PyMethodObject *)callable)->im_self;
args[0] = Py_NewRef(self);
- method = ((PyMethodObject *)callable)->im_func;
+ PyObject *method = ((PyMethodObject *)callable)->im_func;
args[-1] = Py_NewRef(method);
Py_DECREF(callable);
callable = method;
@@ -2915,7 +2906,7 @@ dummy_func(
kwnames);
if (opcode == INSTRUMENTED_CALL) {
PyObject *arg = total_args == 0 ?
- &_PyInstrumentation_MISSING : PEEK(total_args);
+ &_PyInstrumentation_MISSING : args[0];
if (res == NULL) {
_Py_call_instrumentation_exc2(
tstate, PY_MONITORING_EVENT_C_RAISE,
@@ -2943,53 +2934,88 @@ dummy_func(
// Start out with [NULL, bound_method, arg1, arg2, ...]
// Transform to [callable, self, arg1, arg2, ...]
// Then fall through to CALL_PY_EXACT_ARGS
- inst(CALL_BOUND_METHOD_EXACT_ARGS, (unused/1, unused/2, method, callable, unused[oparg] -- unused)) {
- DEOPT_IF(method != NULL, CALL);
+ inst(CALL_BOUND_METHOD_EXACT_ARGS, (unused/1, unused/2, callable, null, unused[oparg] -- unused)) {
+ DEOPT_IF(null != NULL, CALL);
DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL);
STAT_INC(CALL, hit);
PyObject *self = ((PyMethodObject *)callable)->im_self;
- PEEK(oparg + 1) = Py_NewRef(self); // callable
+ PEEK(oparg + 1) = Py_NewRef(self); // self_or_null
PyObject *meth = ((PyMethodObject *)callable)->im_func;
- PEEK(oparg + 2) = Py_NewRef(meth); // method
+ PEEK(oparg + 2) = Py_NewRef(meth); // callable
Py_DECREF(callable);
GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS);
}
- inst(CALL_PY_EXACT_ARGS, (unused/1, func_version/2, method, callable, args[oparg] -- unused)) {
- ASSERT_KWNAMES_IS_NULL();
+ op(_CHECK_PEP_523, (--)) {
DEOPT_IF(tstate->interp->eval_frame, CALL);
- int is_meth = method != NULL;
- int argcount = oparg;
- if (is_meth) {
- callable = method;
- args--;
- argcount++;
- }
+ }
+
+ op(_CHECK_FUNCTION_EXACT_ARGS, (func_version/2, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) {
+ ASSERT_KWNAMES_IS_NULL();
DEOPT_IF(!PyFunction_Check(callable), CALL);
PyFunctionObject *func = (PyFunctionObject *)callable;
DEOPT_IF(func->func_version != func_version, CALL);
PyCodeObject *code = (PyCodeObject *)func->func_code;
- DEOPT_IF(code->co_argcount != argcount, CALL);
+ DEOPT_IF(code->co_argcount != oparg + (self_or_null != NULL), CALL);
+ }
+
+ op(_CHECK_STACK_SPACE, (callable, unused, unused[oparg] -- callable, unused, unused[oparg])) {
+ PyFunctionObject *func = (PyFunctionObject *)callable;
+ PyCodeObject *code = (PyCodeObject *)func->func_code;
DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL);
+ }
+
+ op(_INIT_CALL_PY_EXACT_ARGS, (callable, self_or_null, args[oparg] -- new_frame: _PyInterpreterFrame*)) {
+ int argcount = oparg;
+ if (self_or_null != NULL) {
+ args--;
+ argcount++;
+ }
STAT_INC(CALL, hit);
- _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, func, argcount);
+ PyFunctionObject *func = (PyFunctionObject *)callable;
+ new_frame = _PyFrame_PushUnchecked(tstate, func, argcount);
for (int i = 0; i < argcount; i++) {
new_frame->localsplus[i] = args[i];
}
- // Manipulate stack directly since we leave using DISPATCH_INLINED().
- STACK_SHRINK(oparg + 2);
- SKIP_OVER(INLINE_CACHE_ENTRIES_CALL);
+ }
+
+ // The 'unused' output effect represents the return value
+ // (which will be pushed when the frame returns).
+ // It is needed so CALL_PY_EXACT_ARGS matches its family.
+ op(_PUSH_FRAME, (new_frame: _PyInterpreterFrame* -- unused)) {
+ // Write it out explicitly because it's subtly different.
+ // Eventually this should be the only occurrence of this code.
frame->return_offset = 0;
- DISPATCH_INLINED(new_frame);
+ assert(tstate->interp->eval_frame == NULL);
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+ new_frame->previous = frame;
+ CALL_STAT_INC(inlined_py_calls);
+ frame = tstate->current_frame = new_frame;
+ #if TIER_ONE
+ goto start_frame;
+ #endif
+ #if TIER_TWO
+ ERROR_IF(_Py_EnterRecursivePy(tstate), exit_unwind);
+ stack_pointer = _PyFrame_GetStackPointer(frame);
+ ip_offset = (_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive;
+ #endif
}
- inst(CALL_PY_WITH_DEFAULTS, (unused/1, func_version/2, method, callable, args[oparg] -- unused)) {
+ macro(CALL_PY_EXACT_ARGS) =
+ unused/1 + // Skip over the counter
+ _CHECK_PEP_523 +
+ _CHECK_FUNCTION_EXACT_ARGS +
+ _CHECK_STACK_SPACE +
+ _INIT_CALL_PY_EXACT_ARGS +
+ SAVE_IP + // Tier 2 only; special-cased oparg
+ SAVE_CURRENT_IP + // Sets frame->prev_instr
+ _PUSH_FRAME;
+
+ inst(CALL_PY_WITH_DEFAULTS, (unused/1, func_version/2, callable, self_or_null, args[oparg] -- unused)) {
ASSERT_KWNAMES_IS_NULL();
DEOPT_IF(tstate->interp->eval_frame, CALL);
- int is_meth = method != NULL;
int argcount = oparg;
- if (is_meth) {
- callable = method;
+ if (self_or_null != NULL) {
args--;
argcount++;
}
@@ -3021,7 +3047,7 @@ dummy_func(
DISPATCH_INLINED(new_frame);
}
- inst(CALL_NO_KW_TYPE_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) {
+ inst(CALL_NO_KW_TYPE_1, (unused/1, unused/2, callable, null, args[oparg] -- res)) {
ASSERT_KWNAMES_IS_NULL();
assert(oparg == 1);
DEOPT_IF(null != NULL, CALL);
@@ -3033,7 +3059,7 @@ dummy_func(
Py_DECREF(&PyType_Type); // I.e., callable
}
- inst(CALL_NO_KW_STR_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) {
+ inst(CALL_NO_KW_STR_1, (unused/1, unused/2, callable, null, args[oparg] -- res)) {
ASSERT_KWNAMES_IS_NULL();
assert(oparg == 1);
DEOPT_IF(null != NULL, CALL);
@@ -3047,7 +3073,7 @@ dummy_func(
CHECK_EVAL_BREAKER();
}
- inst(CALL_NO_KW_TUPLE_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) {
+ inst(CALL_NO_KW_TUPLE_1, (unused/1, unused/2, callable, null, args[oparg] -- res)) {
ASSERT_KWNAMES_IS_NULL();
assert(oparg == 1);
DEOPT_IF(null != NULL, CALL);
@@ -3061,7 +3087,7 @@ dummy_func(
CHECK_EVAL_BREAKER();
}
- inst(CALL_NO_KW_ALLOC_AND_ENTER_INIT, (unused/1, unused/2, null, callable, args[oparg] -- unused)) {
+ inst(CALL_NO_KW_ALLOC_AND_ENTER_INIT, (unused/1, unused/2, callable, null, args[oparg] -- unused)) {
/* This instruction does the following:
* 1. Creates the object (by calling ``object.__new__``)
* 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``)
@@ -3105,7 +3131,7 @@ dummy_func(
/* Link frames */
init_frame->previous = shim;
shim->previous = frame;
- frame = cframe.current_frame = init_frame;
+ frame = tstate->current_frame = init_frame;
CALL_STAT_INC(inlined_py_calls);
/* Account for pushing the extra frame.
* We don't check recursion depth here,
@@ -3124,11 +3150,9 @@ dummy_func(
}
}
- inst(CALL_BUILTIN_CLASS, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
- int is_meth = method != NULL;
+ inst(CALL_BUILTIN_CLASS, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
int total_args = oparg;
- if (is_meth) {
- callable = method;
+ if (self_or_null != NULL) {
args--;
total_args++;
}
@@ -3149,13 +3173,11 @@ dummy_func(
CHECK_EVAL_BREAKER();
}
- inst(CALL_NO_KW_BUILTIN_O, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
+ inst(CALL_NO_KW_BUILTIN_O, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
/* Builtin METH_O functions */
ASSERT_KWNAMES_IS_NULL();
- int is_meth = method != NULL;
int total_args = oparg;
- if (is_meth) {
- callable = method;
+ if (self_or_null != NULL) {
args--;
total_args++;
}
@@ -3180,13 +3202,11 @@ dummy_func(
CHECK_EVAL_BREAKER();
}
- inst(CALL_NO_KW_BUILTIN_FAST, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
+ inst(CALL_NO_KW_BUILTIN_FAST, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
/* Builtin METH_FASTCALL functions, without keywords */
ASSERT_KWNAMES_IS_NULL();
- int is_meth = method != NULL;
int total_args = oparg;
- if (is_meth) {
- callable = method;
+ if (self_or_null != NULL) {
args--;
total_args++;
}
@@ -3215,12 +3235,10 @@ dummy_func(
CHECK_EVAL_BREAKER();
}
- inst(CALL_BUILTIN_FAST_WITH_KEYWORDS, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
+ inst(CALL_BUILTIN_FAST_WITH_KEYWORDS, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
/* Builtin METH_FASTCALL | METH_KEYWORDS functions */
- int is_meth = method != NULL;
int total_args = oparg;
- if (is_meth) {
- callable = method;
+ if (self_or_null != NULL) {
args--;
total_args++;
}
@@ -3250,13 +3268,11 @@ dummy_func(
CHECK_EVAL_BREAKER();
}
- inst(CALL_NO_KW_LEN, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
+ inst(CALL_NO_KW_LEN, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
ASSERT_KWNAMES_IS_NULL();
/* len(o) */
- int is_meth = method != NULL;
int total_args = oparg;
- if (is_meth) {
- callable = method;
+ if (self_or_null != NULL) {
args--;
total_args++;
}
@@ -3277,13 +3293,11 @@ dummy_func(
ERROR_IF(res == NULL, error);
}
- inst(CALL_NO_KW_ISINSTANCE, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
+ inst(CALL_NO_KW_ISINSTANCE, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
ASSERT_KWNAMES_IS_NULL();
/* isinstance(o, o2) */
- int is_meth = method != NULL;
int total_args = oparg;
- if (is_meth) {
- callable = method;
+ if (self_or_null != NULL) {
args--;
total_args++;
}
@@ -3307,19 +3321,19 @@ dummy_func(
}
// This is secretly a super-instruction
- inst(CALL_NO_KW_LIST_APPEND, (unused/1, unused/2, method, self, args[oparg] -- unused)) {
+ inst(CALL_NO_KW_LIST_APPEND, (unused/1, unused/2, callable, self, args[oparg] -- unused)) {
ASSERT_KWNAMES_IS_NULL();
assert(oparg == 1);
- assert(method != NULL);
+ assert(self != NULL);
PyInterpreterState *interp = tstate->interp;
- DEOPT_IF(method != interp->callable_cache.list_append, CALL);
+ DEOPT_IF(callable != interp->callable_cache.list_append, CALL);
DEOPT_IF(!PyList_Check(self), CALL);
STAT_INC(CALL, hit);
if (_PyList_AppendTakeRef((PyListObject *)self, args[0]) < 0) {
goto pop_1_error; // Since arg is DECREF'ed already
}
Py_DECREF(self);
- Py_DECREF(method);
+ Py_DECREF(callable);
STACK_SHRINK(3);
// CALL + POP_TOP
SKIP_OVER(INLINE_CACHE_ENTRIES_CALL + 1);
@@ -3327,23 +3341,21 @@ dummy_func(
DISPATCH();
}
- inst(CALL_NO_KW_METHOD_DESCRIPTOR_O, (unused/1, unused/2, method, unused, args[oparg] -- res)) {
+ inst(CALL_NO_KW_METHOD_DESCRIPTOR_O, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
ASSERT_KWNAMES_IS_NULL();
- int is_meth = method != NULL;
int total_args = oparg;
- if (is_meth) {
+ if (self_or_null != NULL) {
args--;
total_args++;
}
- PyMethodDescrObject *callable =
- (PyMethodDescrObject *)PEEK(total_args + 1);
+ PyMethodDescrObject *method = (PyMethodDescrObject *)callable;
DEOPT_IF(total_args != 2, CALL);
- DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
- PyMethodDef *meth = callable->d_method;
+ DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL);
+ PyMethodDef *meth = method->d_method;
DEOPT_IF(meth->ml_flags != METH_O, CALL);
PyObject *arg = args[1];
PyObject *self = args[0];
- DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL);
+ DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL);
STAT_INC(CALL, hit);
PyCFunction cfunc = meth->ml_meth;
// This is slower but CPython promises to check all non-vectorcall
@@ -3361,19 +3373,17 @@ dummy_func(
CHECK_EVAL_BREAKER();
}
- inst(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, (unused/1, unused/2, method, unused, args[oparg] -- res)) {
- int is_meth = method != NULL;
+ inst(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
int total_args = oparg;
- if (is_meth) {
+ if (self_or_null != NULL) {
args--;
total_args++;
}
- PyMethodDescrObject *callable =
- (PyMethodDescrObject *)PEEK(total_args + 1);
- DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
- PyMethodDef *meth = callable->d_method;
+ PyMethodDescrObject *method = (PyMethodDescrObject *)callable;
+ DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL);
+ PyMethodDef *meth = method->d_method;
DEOPT_IF(meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS), CALL);
- PyTypeObject *d_type = callable->d_common.d_type;
+ PyTypeObject *d_type = method->d_common.d_type;
PyObject *self = args[0];
DEOPT_IF(!Py_IS_TYPE(self, d_type), CALL);
STAT_INC(CALL, hit);
@@ -3393,21 +3403,20 @@ dummy_func(
CHECK_EVAL_BREAKER();
}
- inst(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, (unused/1, unused/2, method, unused, args[oparg] -- res)) {
+ inst(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
ASSERT_KWNAMES_IS_NULL();
assert(oparg == 0 || oparg == 1);
- int is_meth = method != NULL;
int total_args = oparg;
- if (is_meth) {
+ if (self_or_null != NULL) {
args--;
total_args++;
}
DEOPT_IF(total_args != 1, CALL);
- PyMethodDescrObject *callable = (PyMethodDescrObject *)SECOND();
- DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
- PyMethodDef *meth = callable->d_method;
+ PyMethodDescrObject *method = (PyMethodDescrObject *)callable;
+ DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL);
+ PyMethodDef *meth = method->d_method;
PyObject *self = args[0];
- DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL);
+ DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL);
DEOPT_IF(meth->ml_flags != METH_NOARGS, CALL);
STAT_INC(CALL, hit);
PyCFunction cfunc = meth->ml_meth;
@@ -3425,22 +3434,20 @@ dummy_func(
CHECK_EVAL_BREAKER();
}
- inst(CALL_NO_KW_METHOD_DESCRIPTOR_FAST, (unused/1, unused/2, method, unused, args[oparg] -- res)) {
+ inst(CALL_NO_KW_METHOD_DESCRIPTOR_FAST, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
ASSERT_KWNAMES_IS_NULL();
- int is_meth = method != NULL;
int total_args = oparg;
- if (is_meth) {
+ if (self_or_null != NULL) {
args--;
total_args++;
}
- PyMethodDescrObject *callable =
- (PyMethodDescrObject *)PEEK(total_args + 1);
+ PyMethodDescrObject *method = (PyMethodDescrObject *)callable;
/* Builtin METH_FASTCALL methods, without keywords */
- DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
- PyMethodDef *meth = callable->d_method;
+ DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL);
+ PyMethodDef *meth = method->d_method;
DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL);
PyObject *self = args[0];
- DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL);
+ DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL);
STAT_INC(CALL, hit);
_PyCFunctionFast cfunc =
(_PyCFunctionFast)(void(*)(void))meth->ml_meth;
@@ -3460,7 +3467,7 @@ dummy_func(
GO_TO_INSTRUCTION(CALL_FUNCTION_EX);
}
- inst(CALL_FUNCTION_EX, (unused, func, callargs, kwargs if (oparg & 1) -- result)) {
+ inst(CALL_FUNCTION_EX, (func, unused, callargs, kwargs if (oparg & 1) -- result)) {
// 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));
@@ -3523,7 +3530,7 @@ dummy_func(
result = PyObject_Call(func, callargs, kwargs);
}
DECREF_INPUTS();
- assert(PEEK(3 + (oparg & 1)) == NULL);
+ assert(PEEK(2 + (oparg & 1)) == NULL);
ERROR_IF(result == NULL, error);
CHECK_EVAL_BREAKER();
}
@@ -3587,7 +3594,7 @@ dummy_func(
assert(frame != &entry_frame);
_PyInterpreterFrame *prev = frame->previous;
_PyThreadState_PopFrame(tstate, frame);
- frame = cframe.current_frame = prev;
+ frame = tstate->current_frame = prev;
_PyFrame_StackPush(frame, (PyObject *)gen);
goto resume_frame;
}
@@ -3764,6 +3771,16 @@ dummy_func(
frame->prev_instr = ip_offset + oparg;
}
+ op(SAVE_CURRENT_IP, (--)) {
+ #if TIER_ONE
+ frame->prev_instr = next_instr - 1;
+ #endif
+ #if TIER_TWO
+ // Relies on a preceding SAVE_IP
+ frame->prev_instr--;
+ #endif
+ }
+
op(EXIT_TRACE, (--)) {
frame->prev_instr--; // Back up to just before destination
_PyFrame_SetStackPointer(frame, stack_pointer);
@@ -3771,6 +3788,11 @@ dummy_func(
return frame;
}
+ op(INSERT, (unused[oparg], top -- top, unused[oparg])) {
+ // Inserts TOS at position specified by oparg;
+ memmove(&stack_pointer[-1 - oparg], &stack_pointer[-oparg], oparg * sizeof(stack_pointer[0]));
+ }
+
// END BYTECODES //
diff --git a/Python/ceval.c b/Python/ceval.c
index b966399a342d08..1e2262c1f18c3e 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -602,11 +602,6 @@ int _Py_CheckRecursiveCallPy(
return 0;
}
-static inline int _Py_EnterRecursivePy(PyThreadState *tstate) {
- return (tstate->py_recursion_remaining-- <= 0) &&
- _Py_CheckRecursiveCallPy(tstate);
-}
-
static inline void _Py_LeaveRecursiveCallPy(PyThreadState *tstate) {
tstate->py_recursion_remaining++;
@@ -661,17 +656,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
int lltrace = 0;
#endif
- _PyCFrame cframe;
_PyInterpreterFrame entry_frame;
PyObject *kwnames = NULL; // Borrowed reference. Reset by CALL instructions.
- /* WARNING: Because the _PyCFrame lives on the C stack,
- * but can be accessed from a heap allocated object (tstate)
- * strict stack discipline must be maintained.
- */
- _PyCFrame *prev_cframe = tstate->cframe;
- cframe.previous = prev_cframe;
- tstate->cframe = &cframe;
+
#ifdef Py_DEBUG
/* Set these to invalid but identifiable values for debugging. */
@@ -687,9 +675,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
entry_frame.owner = FRAME_OWNED_BY_CSTACK;
entry_frame.return_offset = 0;
/* Push frame */
- entry_frame.previous = prev_cframe->current_frame;
+ entry_frame.previous = tstate->current_frame;
frame->previous = &entry_frame;
- cframe.current_frame = frame;
+ tstate->current_frame = frame;
tstate->c_recursion_remaining -= (PY_EVAL_C_STACK_UNITS - 1);
if (_Py_EnterRecursiveCallTstate(tstate, "")) {
@@ -770,6 +758,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
#endif
{
+#define TIER_ONE 1
#include "generated_cases.c.h"
/* INSTRUMENTED_LINE has to be here, rather than in bytecodes.c,
@@ -928,13 +917,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
assert(frame != &entry_frame);
// GH-99729: We need to unlink the frame *before* clearing it:
_PyInterpreterFrame *dying = frame;
- frame = cframe.current_frame = dying->previous;
+ frame = tstate->current_frame = dying->previous;
_PyEvalFrameClearAndPop(tstate, dying);
frame->return_offset = 0;
if (frame == &entry_frame) {
- /* Restore previous cframe and exit */
- tstate->cframe = cframe.previous;
- assert(tstate->cframe->current_frame == frame->previous);
+ /* Restore previous frame and exit */
+ tstate->current_frame = frame->previous;
tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS;
return NULL;
}
@@ -2301,7 +2289,7 @@ int
PyEval_MergeCompilerFlags(PyCompilerFlags *cf)
{
PyThreadState *tstate = _PyThreadState_GET();
- _PyInterpreterFrame *current_frame = tstate->cframe->current_frame;
+ _PyInterpreterFrame *current_frame = tstate->current_frame;
int result = cf->cf_flags != 0;
if (current_frame != NULL) {
diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h
index 8dc8b754485856..08f19cd9a397f1 100644
--- a/Python/ceval_macros.h
+++ b/Python/ceval_macros.h
@@ -109,7 +109,7 @@
_PyFrame_SetStackPointer(frame, stack_pointer); \
frame->prev_instr = next_instr - 1; \
(NEW_FRAME)->previous = frame; \
- frame = cframe.current_frame = (NEW_FRAME); \
+ frame = tstate->current_frame = (NEW_FRAME); \
CALL_STAT_INC(inlined_py_calls); \
goto start_frame; \
} while (0)
@@ -364,3 +364,8 @@ static const convertion_func_ptr CONVERSION_FUNCTIONS[4] = {
#else
#define _Py_atomic_load_relaxed_int32(ATOMIC_VAL) _Py_atomic_load_relaxed(ATOMIC_VAL)
#endif
+
+static inline int _Py_EnterRecursivePy(PyThreadState *tstate) {
+ return (tstate->py_recursion_remaining-- <= 0) &&
+ _Py_CheckRecursiveCallPy(tstate);
+}
diff --git a/Python/compile.c b/Python/compile.c
index b673e3ac6c1cc5..3260dba57eac8f 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -70,9 +70,7 @@
&& ((C)->u->u_ste->ste_type == ModuleBlock))
typedef _PyCompilerSrcLocation location;
-typedef _PyCfgInstruction cfg_instr;
-typedef _PyCfgBasicblock basicblock;
-typedef _PyCfgBuilder cfg_builder;
+typedef struct _PyCfgBuilder cfg_builder;
#define LOCATION(LNO, END_LNO, COL, END_COL) \
((const _PyCompilerSrcLocation){(LNO), (END_LNO), (COL), (END_COL)})
@@ -101,7 +99,7 @@ static jump_target_label NO_LABEL = {-1};
}
#define USE_LABEL(C, LBL) \
- RETURN_IF_ERROR(instr_sequence_use_label(INSTR_SEQUENCE(C), (LBL).id))
+ RETURN_IF_ERROR(_PyCompile_InstructionSequence_UseLabel(INSTR_SEQUENCE(C), (LBL).id))
/* fblockinfo tracks the current frame block.
@@ -218,8 +216,9 @@ instr_sequence_new_label(instr_sequence *seq)
return lbl;
}
-static int
-instr_sequence_use_label(instr_sequence *seq, int lbl) {
+int
+_PyCompile_InstructionSequence_UseLabel(instr_sequence *seq, int lbl)
+{
int old_size = seq->s_labelmap_size;
RETURN_IF_ERROR(
_PyCompile_EnsureArrayLargeEnough(lbl,
@@ -238,8 +237,9 @@ instr_sequence_use_label(instr_sequence *seq, int lbl) {
#define MAX_OPCODE 511
-static int
-instr_sequence_addop(instr_sequence *seq, int opcode, int oparg, location loc)
+int
+_PyCompile_InstructionSequence_Addop(instr_sequence *seq, int opcode, int oparg,
+ location loc)
{
assert(0 <= opcode && opcode <= MAX_OPCODE);
assert(IS_WITHIN_OPCODE_RANGE(opcode));
@@ -288,10 +288,12 @@ instr_sequence_fini(instr_sequence *seq) {
seq->s_instrs = NULL;
}
-static int
-instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) {
- memset(g, 0, sizeof(cfg_builder));
- RETURN_IF_ERROR(_PyCfgBuilder_Init(g));
+static cfg_builder*
+instr_sequence_to_cfg(instr_sequence *seq) {
+ cfg_builder *g = _PyCfgBuilder_New();
+ if (g == NULL) {
+ return NULL;
+ }
/* There can be more than one label for the same offset. The
* offset2lbl maping selects one of them which we use consistently.
@@ -300,7 +302,7 @@ instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) {
int *offset2lbl = PyMem_Malloc(seq->s_used * sizeof(int));
if (offset2lbl == NULL) {
PyErr_NoMemory();
- return ERROR;
+ goto error;
}
for (int i = 0; i < seq->s_used; i++) {
offset2lbl[i] = -1;
@@ -336,23 +338,17 @@ instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) {
goto error;
}
}
- PyMem_Free(offset2lbl);
-
- int nblocks = 0;
- for (basicblock *b = g->g_block_list; b != NULL; b = b->b_list) {
- nblocks++;
- }
- if ((size_t)nblocks > SIZE_MAX / sizeof(basicblock *)) {
- PyErr_NoMemory();
- return ERROR;
+ if (_PyCfgBuilder_CheckSize(g) < 0) {
+ goto error;
}
- return SUCCESS;
+ PyMem_Free(offset2lbl);
+ return g;
error:
+ _PyCfgBuilder_Free(g);
PyMem_Free(offset2lbl);
- return ERROR;
+ return NULL;
}
-
/* The following items change on entry and exit of code blocks.
They must be saved and restored when returning to a block.
*/
@@ -920,7 +916,7 @@ codegen_addop_noarg(instr_sequence *seq, int opcode, location loc)
{
assert(!OPCODE_HAS_ARG(opcode));
assert(!IS_ASSEMBLER_OPCODE(opcode));
- return instr_sequence_addop(seq, opcode, 0, loc);
+ return _PyCompile_InstructionSequence_Addop(seq, opcode, 0, loc);
}
static Py_ssize_t
@@ -1153,7 +1149,7 @@ codegen_addop_i(instr_sequence *seq, int opcode, Py_ssize_t oparg, location loc)
int oparg_ = Py_SAFE_DOWNCAST(oparg, Py_ssize_t, int);
assert(!IS_ASSEMBLER_OPCODE(opcode));
- return instr_sequence_addop(seq, opcode, oparg_, loc);
+ return _PyCompile_InstructionSequence_Addop(seq, opcode, oparg_, loc);
}
static int
@@ -1163,7 +1159,7 @@ codegen_addop_j(instr_sequence *seq, location loc,
assert(IS_LABEL(target));
assert(OPCODE_HAS_JUMP(opcode) || IS_BLOCK_PUSH_OPCODE(opcode));
assert(!IS_ASSEMBLER_OPCODE(opcode));
- return instr_sequence_addop(seq, opcode, target.id, loc);
+ return _PyCompile_InstructionSequence_Addop(seq, opcode, target.id, loc);
}
#define RETURN_IF_ERROR_IN_SCOPE(C, CALL) { \
@@ -2361,11 +2357,6 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async)
int is_generic = asdl_seq_LEN(type_params) > 0;
- if (is_generic) {
- // Used by the CALL to the type parameters function.
- ADDOP(c, loc, PUSH_NULL);
- }
-
funcflags = compiler_default_arguments(c, loc, args);
if (funcflags == -1) {
return ERROR;
@@ -2436,8 +2427,12 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async)
Py_DECREF(co);
if (num_typeparam_args > 0) {
ADDOP_I(c, loc, SWAP, num_typeparam_args + 1);
+ ADDOP_I(c, loc, CALL, num_typeparam_args - 1);
+ }
+ else {
+ ADDOP(c, loc, PUSH_NULL);
+ ADDOP_I(c, loc, CALL, 0);
}
- ADDOP_I(c, loc, CALL, num_typeparam_args);
}
RETURN_IF_ERROR(compiler_apply_decorators(c, decos));
@@ -2565,8 +2560,8 @@ compiler_class_body(struct compiler *c, stmt_ty s, int firstlineno)
// these instructions should be attributed to the class line,
// not a decorator line
loc = LOC(s);
- ADDOP(c, loc, PUSH_NULL);
ADDOP(c, loc, LOAD_BUILD_CLASS);
+ ADDOP(c, loc, PUSH_NULL);
/* 3. load a function (or closure) made from the code object */
if (compiler_make_closure(c, loc, co, 0) < 0) {
@@ -2598,7 +2593,6 @@ compiler_class(struct compiler *c, stmt_ty s)
int is_generic = asdl_seq_LEN(type_params) > 0;
if (is_generic) {
Py_XSETREF(c->u->u_private, Py_NewRef(s->v.ClassDef.name));
- ADDOP(c, loc, PUSH_NULL);
PyObject *type_params_name = PyUnicode_FromFormat("",
s->v.ClassDef.name);
if (!type_params_name) {
@@ -2666,6 +2660,7 @@ compiler_class(struct compiler *c, stmt_ty s)
return ERROR;
}
Py_DECREF(co);
+ ADDOP(c, loc, PUSH_NULL);
ADDOP_I(c, loc, CALL, 0);
} else {
RETURN_IF_ERROR(compiler_call_helper(c, loc, 2,
@@ -2716,7 +2711,6 @@ compiler_typealias(struct compiler *c, stmt_ty s)
int is_generic = asdl_seq_LEN(type_params) > 0;
PyObject *name = s->v.TypeAlias.name->v.Name.id;
if (is_generic) {
- ADDOP(c, loc, PUSH_NULL);
PyObject *type_params_name = PyUnicode_FromFormat("",
name);
if (!type_params_name) {
@@ -2756,6 +2750,7 @@ compiler_typealias(struct compiler *c, stmt_ty s)
return ERROR;
}
Py_DECREF(co);
+ ADDOP(c, loc, PUSH_NULL);
ADDOP_I(c, loc, CALL, 0);
}
RETURN_IF_ERROR(compiler_nameop(c, loc, name, Store));
@@ -3957,7 +3952,7 @@ compiler_assert(struct compiler *c, stmt_ty s)
VISIT(c, expr, s->v.Assert.msg);
ADDOP_I(c, LOC(s), CALL, 0);
}
- ADDOP_I(c, LOC(s), RAISE_VARARGS, 1);
+ ADDOP_I(c, LOC(s->v.Assert.test), RAISE_VARARGS, 1);
USE_LABEL(c, end);
return SUCCESS;
@@ -4994,9 +4989,9 @@ compiler_call(struct compiler *c, expr_ty e)
return SUCCESS;
}
RETURN_IF_ERROR(check_caller(c, e->v.Call.func));
+ VISIT(c, expr, e->v.Call.func);
location loc = LOC(e->v.Call.func);
ADDOP(c, loc, PUSH_NULL);
- VISIT(c, expr, e->v.Call.func);
loc = LOC(e);
return compiler_call_helper(c, loc, 0,
e->v.Call.args,
@@ -7493,201 +7488,6 @@ _PyCompile_ConstCacheMergeOne(PyObject *const_cache, PyObject **obj)
return SUCCESS;
}
-
-static int *
-build_cellfixedoffsets(_PyCompile_CodeUnitMetadata *umd)
-{
- int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames);
- int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars);
- int nfreevars = (int)PyDict_GET_SIZE(umd->u_freevars);
-
- int noffsets = ncellvars + nfreevars;
- int *fixed = PyMem_New(int, noffsets);
- if (fixed == NULL) {
- PyErr_NoMemory();
- return NULL;
- }
- for (int i = 0; i < noffsets; i++) {
- fixed[i] = nlocals + i;
- }
-
- PyObject *varname, *cellindex;
- Py_ssize_t pos = 0;
- while (PyDict_Next(umd->u_cellvars, &pos, &varname, &cellindex)) {
- PyObject *varindex = PyDict_GetItem(umd->u_varnames, varname);
- if (varindex != NULL) {
- assert(PyLong_AS_LONG(cellindex) < INT_MAX);
- assert(PyLong_AS_LONG(varindex) < INT_MAX);
- int oldindex = (int)PyLong_AS_LONG(cellindex);
- int argoffset = (int)PyLong_AS_LONG(varindex);
- fixed[oldindex] = argoffset;
- }
- }
-
- return fixed;
-}
-
-#define IS_GENERATOR(CF) \
- ((CF) & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR))
-
-static int
-insert_prefix_instructions(_PyCompile_CodeUnitMetadata *umd, basicblock *entryblock,
- int *fixed, int nfreevars, int code_flags)
-{
- assert(umd->u_firstlineno > 0);
-
- /* Add the generator prefix instructions. */
- if (IS_GENERATOR(code_flags)) {
- /* Note that RETURN_GENERATOR + POP_TOP have a net stack effect
- * of 0. This is because RETURN_GENERATOR pushes an element
- * with _PyFrame_StackPush before switching stacks.
- */
- cfg_instr make_gen = {
- .i_opcode = RETURN_GENERATOR,
- .i_oparg = 0,
- .i_loc = LOCATION(umd->u_firstlineno, umd->u_firstlineno, -1, -1),
- .i_target = NULL,
- };
- RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, 0, &make_gen));
- cfg_instr pop_top = {
- .i_opcode = POP_TOP,
- .i_oparg = 0,
- .i_loc = NO_LOCATION,
- .i_target = NULL,
- };
- RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, 1, &pop_top));
- }
-
- /* Set up cells for any variable that escapes, to be put in a closure. */
- const int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars);
- if (ncellvars) {
- // umd->u_cellvars has the cells out of order so we sort them
- // before adding the MAKE_CELL instructions. Note that we
- // adjust for arg cells, which come first.
- const int nvars = ncellvars + (int)PyDict_GET_SIZE(umd->u_varnames);
- int *sorted = PyMem_RawCalloc(nvars, sizeof(int));
- if (sorted == NULL) {
- PyErr_NoMemory();
- return ERROR;
- }
- for (int i = 0; i < ncellvars; i++) {
- sorted[fixed[i]] = i + 1;
- }
- for (int i = 0, ncellsused = 0; ncellsused < ncellvars; i++) {
- int oldindex = sorted[i] - 1;
- if (oldindex == -1) {
- continue;
- }
- cfg_instr make_cell = {
- .i_opcode = MAKE_CELL,
- // This will get fixed in offset_derefs().
- .i_oparg = oldindex,
- .i_loc = NO_LOCATION,
- .i_target = NULL,
- };
- if (_PyBasicblock_InsertInstruction(entryblock, ncellsused, &make_cell) < 0) {
- PyMem_RawFree(sorted);
- return ERROR;
- }
- ncellsused += 1;
- }
- PyMem_RawFree(sorted);
- }
-
- if (nfreevars) {
- cfg_instr copy_frees = {
- .i_opcode = COPY_FREE_VARS,
- .i_oparg = nfreevars,
- .i_loc = NO_LOCATION,
- .i_target = NULL,
- };
- RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, 0, ©_frees));
- }
-
- return SUCCESS;
-}
-
-static int
-fix_cell_offsets(_PyCompile_CodeUnitMetadata *umd, basicblock *entryblock, int *fixedmap)
-{
- int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames);
- int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars);
- int nfreevars = (int)PyDict_GET_SIZE(umd->u_freevars);
- int noffsets = ncellvars + nfreevars;
-
- // First deal with duplicates (arg cells).
- int numdropped = 0;
- for (int i = 0; i < noffsets ; i++) {
- if (fixedmap[i] == i + nlocals) {
- fixedmap[i] -= numdropped;
- }
- else {
- // It was a duplicate (cell/arg).
- numdropped += 1;
- }
- }
-
- // Then update offsets, either relative to locals or by cell2arg.
- for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
- for (int i = 0; i < b->b_iused; i++) {
- cfg_instr *inst = &b->b_instr[i];
- // This is called before extended args are generated.
- assert(inst->i_opcode != EXTENDED_ARG);
- int oldoffset = inst->i_oparg;
- switch(inst->i_opcode) {
- case MAKE_CELL:
- case LOAD_CLOSURE:
- case LOAD_DEREF:
- case STORE_DEREF:
- case DELETE_DEREF:
- case LOAD_FROM_DICT_OR_DEREF:
- assert(oldoffset >= 0);
- assert(oldoffset < noffsets);
- assert(fixedmap[oldoffset] >= 0);
- inst->i_oparg = fixedmap[oldoffset];
- }
- }
- }
-
- return numdropped;
-}
-
-
-static int
-prepare_localsplus(_PyCompile_CodeUnitMetadata *umd, cfg_builder *g, int code_flags)
-{
- assert(PyDict_GET_SIZE(umd->u_varnames) < INT_MAX);
- assert(PyDict_GET_SIZE(umd->u_cellvars) < INT_MAX);
- assert(PyDict_GET_SIZE(umd->u_freevars) < INT_MAX);
- int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames);
- int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars);
- int nfreevars = (int)PyDict_GET_SIZE(umd->u_freevars);
- assert(INT_MAX - nlocals - ncellvars > 0);
- assert(INT_MAX - nlocals - ncellvars - nfreevars > 0);
- int nlocalsplus = nlocals + ncellvars + nfreevars;
- int* cellfixedoffsets = build_cellfixedoffsets(umd);
- if (cellfixedoffsets == NULL) {
- return ERROR;
- }
-
-
- // This must be called before fix_cell_offsets().
- if (insert_prefix_instructions(umd, g->g_entryblock, cellfixedoffsets, nfreevars, code_flags)) {
- PyMem_Free(cellfixedoffsets);
- return ERROR;
- }
-
- int numdropped = fix_cell_offsets(umd, g->g_entryblock, cellfixedoffsets);
- PyMem_Free(cellfixedoffsets); // At this point we're done with it.
- cellfixedoffsets = NULL;
- if (numdropped < 0) {
- return ERROR;
- }
-
- nlocalsplus -= numdropped;
- return nlocalsplus;
-}
-
static int
add_return_at_end(struct compiler *c, int addNone)
{
@@ -7701,12 +7501,11 @@ add_return_at_end(struct compiler *c, int addNone)
return SUCCESS;
}
-static int cfg_to_instr_sequence(cfg_builder *g, instr_sequence *seq);
-
static PyCodeObject *
optimize_and_assemble_code_unit(struct compiler_unit *u, PyObject *const_cache,
int code_flags, PyObject *filename)
{
+ cfg_builder *g = NULL;
instr_sequence optimized_instrs;
memset(&optimized_instrs, 0, sizeof(instr_sequence));
@@ -7715,51 +7514,28 @@ optimize_and_assemble_code_unit(struct compiler_unit *u, PyObject *const_cache,
if (consts == NULL) {
goto error;
}
- cfg_builder g;
- if (instr_sequence_to_cfg(&u->u_instr_sequence, &g) < 0) {
+ g = instr_sequence_to_cfg(&u->u_instr_sequence);
+ if (g == NULL) {
goto error;
}
- int nparams = (int)PyList_GET_SIZE(u->u_ste->ste_varnames);
int nlocals = (int)PyDict_GET_SIZE(u->u_metadata.u_varnames);
+ int nparams = (int)PyList_GET_SIZE(u->u_ste->ste_varnames);
assert(u->u_metadata.u_firstlineno);
- if (_PyCfg_OptimizeCodeUnit(&g, consts, const_cache, nlocals,
+
+ if (_PyCfg_OptimizeCodeUnit(g, consts, const_cache, nlocals,
nparams, u->u_metadata.u_firstlineno) < 0) {
goto error;
}
- int stackdepth = _PyCfg_Stackdepth(&g);
- if (stackdepth < 0) {
+ int stackdepth;
+ int nlocalsplus;
+ if (_PyCfg_OptimizedCfgToInstructionSequence(g, &u->u_metadata, code_flags,
+ &stackdepth, &nlocalsplus,
+ &optimized_instrs) < 0) {
goto error;
}
- /* prepare_localsplus adds instructions for generators that push
- * and pop an item on the stack. This assertion makes sure there
- * is space on the stack for that.
- * It should always be true, because a generator must have at
- * least one expression or call to INTRINSIC_STOPITERATION_ERROR,
- * which requires stackspace.
- */
- assert(!(IS_GENERATOR(code_flags) && stackdepth == 0));
-
/** Assembly **/
- int nlocalsplus = prepare_localsplus(&u->u_metadata, &g, code_flags);
- if (nlocalsplus < 0) {
- goto error;
- }
-
- _PyCfg_ConvertPseudoOps(g.g_entryblock);
-
- /* Order of basic blocks must have been determined by now */
-
- if (_PyCfg_ResolveJumps(&g) < 0) {
- goto error;
- }
-
- /* Can't modify the bytecode after computing jump offsets. */
-
- if (cfg_to_instr_sequence(&g, &optimized_instrs) < 0) {
- goto error;
- }
co = _PyAssemble_MakeCodeObject(&u->u_metadata, const_cache, consts,
stackdepth, &optimized_instrs, nlocalsplus,
@@ -7768,7 +7544,7 @@ optimize_and_assemble_code_unit(struct compiler_unit *u, PyObject *const_cache,
error:
Py_XDECREF(consts);
instr_sequence_fini(&optimized_instrs);
- _PyCfgBuilder_Fini(&g);
+ _PyCfgBuilder_Free(g);
return co;
}
@@ -7791,39 +7567,6 @@ optimize_and_assemble(struct compiler *c, int addNone)
return optimize_and_assemble_code_unit(u, const_cache, code_flags, filename);
}
-static int
-cfg_to_instr_sequence(cfg_builder *g, instr_sequence *seq)
-{
- int lbl = 0;
- for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
- b->b_label = (jump_target_label){lbl};
- lbl += b->b_iused;
- }
- for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
- RETURN_IF_ERROR(instr_sequence_use_label(seq, b->b_label.id));
- for (int i = 0; i < b->b_iused; i++) {
- cfg_instr *instr = &b->b_instr[i];
- if (OPCODE_HAS_JUMP(instr->i_opcode)) {
- instr->i_oparg = instr->i_target->b_label.id;
- }
- RETURN_IF_ERROR(
- instr_sequence_addop(seq, instr->i_opcode, instr->i_oparg, instr->i_loc));
-
- _PyCompile_ExceptHandlerInfo *hi = &seq->s_instrs[seq->s_used-1].i_except_handler_info;
- if (instr->i_except != NULL) {
- hi->h_label = instr->i_except->b_label.id;
- hi->h_startdepth = instr->i_except->b_startdepth;
- hi->h_preserve_lasti = instr->i_except->b_preserve_lasti;
- }
- else {
- hi->h_label = -1;
- }
- }
- }
- return SUCCESS;
-}
-
-
/* Access to compiler optimizations for unit tests.
*
* _PyCompile_CodeGen takes and AST, applies code-gen and
@@ -7873,7 +7616,7 @@ instructions_to_instr_sequence(PyObject *instructions, instr_sequence *seq)
for (int i = 0; i < num_insts; i++) {
if (is_target[i]) {
- if (instr_sequence_use_label(seq, i) < 0) {
+ if (_PyCompile_InstructionSequence_UseLabel(seq, i) < 0) {
goto error;
}
}
@@ -7913,7 +7656,7 @@ instructions_to_instr_sequence(PyObject *instructions, instr_sequence *seq)
if (PyErr_Occurred()) {
goto error;
}
- if (instr_sequence_addop(seq, opcode, oparg, loc) < 0) {
+ if (_PyCompile_InstructionSequence_Addop(seq, opcode, oparg, loc) < 0) {
goto error;
}
}
@@ -7924,23 +7667,26 @@ instructions_to_instr_sequence(PyObject *instructions, instr_sequence *seq)
return ERROR;
}
-static int
-instructions_to_cfg(PyObject *instructions, cfg_builder *g)
+static cfg_builder*
+instructions_to_cfg(PyObject *instructions)
{
+ cfg_builder *g = NULL;
instr_sequence seq;
memset(&seq, 0, sizeof(instr_sequence));
if (instructions_to_instr_sequence(instructions, &seq) < 0) {
goto error;
}
- if (instr_sequence_to_cfg(&seq, g) < 0) {
+ g = instr_sequence_to_cfg(&seq);
+ if (g == NULL) {
goto error;
}
instr_sequence_fini(&seq);
- return SUCCESS;
+ return g;
error:
+ _PyCfgBuilder_Free(g);
instr_sequence_fini(&seq);
- return ERROR;
+ return NULL;
}
static PyObject *
@@ -7979,42 +7725,14 @@ instr_sequence_to_instructions(instr_sequence *seq)
static PyObject *
cfg_to_instructions(cfg_builder *g)
{
- PyObject *instructions = PyList_New(0);
- if (instructions == NULL) {
+ instr_sequence seq;
+ memset(&seq, 0, sizeof(seq));
+ if (_PyCfg_ToInstructionSequence(g, &seq) < 0) {
return NULL;
}
- int lbl = 0;
- for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
- b->b_label = (jump_target_label){lbl};
- lbl += b->b_iused;
- }
- for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
- for (int i = 0; i < b->b_iused; i++) {
- cfg_instr *instr = &b->b_instr[i];
- location loc = instr->i_loc;
- int arg = HAS_TARGET(instr->i_opcode) ?
- instr->i_target->b_label.id : instr->i_oparg;
-
- PyObject *inst_tuple = Py_BuildValue(
- "(iiiiii)", instr->i_opcode, arg,
- loc.lineno, loc.end_lineno,
- loc.col_offset, loc.end_col_offset);
- if (inst_tuple == NULL) {
- goto error;
- }
-
- if (PyList_Append(instructions, inst_tuple) != 0) {
- Py_DECREF(inst_tuple);
- goto error;
- }
- Py_DECREF(inst_tuple);
- }
- }
-
- return instructions;
-error:
- Py_DECREF(instructions);
- return NULL;
+ PyObject *res = instr_sequence_to_instructions(&seq);
+ instr_sequence_fini(&seq);
+ return res;
}
// C implementation of inspect.cleandoc()
@@ -8196,34 +7914,36 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags,
PyObject *
_PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts, int nlocals)
{
+ cfg_builder *g = NULL;
PyObject *res = NULL;
PyObject *const_cache = PyDict_New();
if (const_cache == NULL) {
return NULL;
}
- cfg_builder g;
- if (instructions_to_cfg(instructions, &g) < 0) {
+ g = instructions_to_cfg(instructions);
+ if (g == NULL) {
goto error;
}
int nparams = 0, firstlineno = 1;
- if (_PyCfg_OptimizeCodeUnit(&g, consts, const_cache, nlocals,
+ if (_PyCfg_OptimizeCodeUnit(g, consts, const_cache, nlocals,
nparams, firstlineno) < 0) {
goto error;
}
- res = cfg_to_instructions(&g);
+ res = cfg_to_instructions(g);
error:
Py_DECREF(const_cache);
- _PyCfgBuilder_Fini(&g);
+ _PyCfgBuilder_Free(g);
return res;
}
-int _PyCfg_JumpLabelsToTargets(basicblock *entryblock);
+int _PyCfg_JumpLabelsToTargets(cfg_builder *g);
PyCodeObject *
_PyCompile_Assemble(_PyCompile_CodeUnitMetadata *umd, PyObject *filename,
PyObject *instructions)
{
+ cfg_builder *g = NULL;
PyCodeObject *co = NULL;
instr_sequence optimized_instrs;
memset(&optimized_instrs, 0, sizeof(instr_sequence));
@@ -8233,37 +7953,20 @@ _PyCompile_Assemble(_PyCompile_CodeUnitMetadata *umd, PyObject *filename,
return NULL;
}
- cfg_builder g;
- if (instructions_to_cfg(instructions, &g) < 0) {
- goto error;
- }
-
- if (_PyCfg_JumpLabelsToTargets(g.g_entryblock) < 0) {
+ g = instructions_to_cfg(instructions);
+ if (g == NULL) {
goto error;
}
- int stackdepth = _PyCfg_Stackdepth(&g);
- if (stackdepth < 0) {
+ if (_PyCfg_JumpLabelsToTargets(g) < 0) {
goto error;
}
int code_flags = 0;
- int nlocalsplus = prepare_localsplus(umd, &g, code_flags);
- if (nlocalsplus < 0) {
- goto error;
- }
-
- _PyCfg_ConvertPseudoOps(g.g_entryblock);
-
- /* Order of basic blocks must have been determined by now */
-
- if (_PyCfg_ResolveJumps(&g) < 0) {
- goto error;
- }
-
- /* Can't modify the bytecode after computing jump offsets. */
-
- if (cfg_to_instr_sequence(&g, &optimized_instrs) < 0) {
+ int stackdepth, nlocalsplus;
+ if (_PyCfg_OptimizedCfgToInstructionSequence(g, umd, code_flags,
+ &stackdepth, &nlocalsplus,
+ &optimized_instrs) < 0) {
goto error;
}
@@ -8278,7 +7981,7 @@ _PyCompile_Assemble(_PyCompile_CodeUnitMetadata *umd, PyObject *filename,
error:
Py_DECREF(const_cache);
- _PyCfgBuilder_Fini(&g);
+ _PyCfgBuilder_Free(g);
instr_sequence_fini(&optimized_instrs);
return co;
}
diff --git a/Python/executor.c b/Python/executor.c
index 4a18618c0c6c0c..88c039da8539e2 100644
--- a/Python/executor.c
+++ b/Python/executor.c
@@ -81,6 +81,7 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject
OBJECT_STAT_INC(optimization_uops_executed);
switch (opcode) {
+#define TIER_TWO 2
#include "executor_cases.c.h"
default:
@@ -106,10 +107,11 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject
pop_2_error:
STACK_SHRINK(1);
pop_1_error:
+pop_1_exit_unwind:
STACK_SHRINK(1);
error:
// On ERROR_IF we return NULL as the frame.
- // The caller recovers the frame from cframe.current_frame.
+ // The caller recovers the frame from tstate->current_frame.
DPRINTF(2, "Error: [Opcode %d, operand %" PRIu64 "]\n", opcode, operand);
_PyFrame_SetStackPointer(frame, stack_pointer);
Py_DECREF(self);
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index 27be8a383989ee..9fbf026f164a60 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -103,7 +103,6 @@
}
case TO_BOOL: {
- static_assert(INLINE_CACHE_ENTRIES_TO_BOOL == 3, "incorrect cache size");
PyObject *value;
PyObject *res;
value = stack_pointer[-1];
@@ -363,7 +362,6 @@
}
case BINARY_SUBSCR: {
- static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 1, "incorrect cache size");
PyObject *sub;
PyObject *container;
PyObject *res;
@@ -557,7 +555,6 @@
}
case STORE_SUBSCR: {
- static_assert(INLINE_CACHE_ENTRIES_STORE_SUBSCR == 1, "incorrect cache size");
PyObject *sub;
PyObject *container;
PyObject *v;
@@ -862,7 +859,6 @@
}
case UNPACK_SEQUENCE: {
- static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size");
PyObject *seq;
seq = stack_pointer[-1];
#if ENABLE_SPECIALIZATION
@@ -950,7 +946,6 @@
}
case STORE_ATTR: {
- static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size");
PyObject *owner;
PyObject *v;
owner = stack_pointer[-1];
@@ -1061,9 +1056,8 @@
}
case LOAD_GLOBAL: {
- static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size");
+ PyObject *res;
PyObject *null = NULL;
- PyObject *v;
#if ENABLE_SPECIALIZATION
_PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
@@ -1079,10 +1073,10 @@
if (PyDict_CheckExact(GLOBALS())
&& PyDict_CheckExact(BUILTINS()))
{
- v = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(),
- (PyDictObject *)BUILTINS(),
- name);
- if (v == NULL) {
+ res = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(),
+ (PyDictObject *)BUILTINS(),
+ name);
+ if (res == NULL) {
if (!_PyErr_Occurred(tstate)) {
/* _PyDict_LoadGlobal() returns NULL without raising
* an exception if the key doesn't exist */
@@ -1091,17 +1085,17 @@
}
if (true) goto error;
}
- Py_INCREF(v);
+ Py_INCREF(res);
}
else {
/* Slow-path if globals or builtins is not a dict */
/* namespace 1: globals */
- if (PyMapping_GetOptionalItem(GLOBALS(), name, &v) < 0) goto error;
- if (v == NULL) {
+ if (PyMapping_GetOptionalItem(GLOBALS(), name, &res) < 0) goto error;
+ if (res == NULL) {
/* namespace 2: builtins */
- if (PyMapping_GetOptionalItem(BUILTINS(), name, &v) < 0) goto error;
- if (v == NULL) {
+ if (PyMapping_GetOptionalItem(BUILTINS(), name, &res) < 0) goto error;
+ if (res == NULL) {
_PyEval_FormatExcCheckArg(
tstate, PyExc_NameError,
NAME_ERROR_MSG, name);
@@ -1112,8 +1106,8 @@
null = NULL;
STACK_GROW(1);
STACK_GROW(((oparg & 1) ? 1 : 0));
- if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = null; }
- stack_pointer[-1] = v;
+ stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res;
+ if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; }
break;
}
@@ -1136,8 +1130,8 @@
}
case _LOAD_GLOBAL_MODULE: {
- PyObject *null = NULL;
PyObject *res;
+ PyObject *null = NULL;
uint16_t index = (uint16_t)operand;
PyDictObject *dict = (PyDictObject *)GLOBALS();
PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys);
@@ -1148,14 +1142,14 @@
null = NULL;
STACK_GROW(1);
STACK_GROW(((oparg & 1) ? 1 : 0));
- if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = null; }
- stack_pointer[-1] = res;
+ stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res;
+ if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; }
break;
}
case _LOAD_GLOBAL_BUILTINS: {
- PyObject *null = NULL;
PyObject *res;
+ PyObject *null = NULL;
uint16_t index = (uint16_t)operand;
PyDictObject *bdict = (PyDictObject *)BUILTINS();
PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(bdict->ma_keys);
@@ -1166,8 +1160,8 @@
null = NULL;
STACK_GROW(1);
STACK_GROW(((oparg & 1) ? 1 : 0));
- if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = null; }
- stack_pointer[-1] = res;
+ stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res;
+ if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; }
break;
}
@@ -1445,8 +1439,9 @@
case DICT_UPDATE: {
PyObject *update;
+ PyObject *dict;
update = stack_pointer[-1];
- PyObject *dict = PEEK(oparg + 1); // update is still on the stack
+ dict = stack_pointer[-2 - (oparg - 1)];
if (PyDict_Update(dict, update) < 0) {
if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) {
_PyErr_Format(tstate, PyExc_TypeError,
@@ -1463,11 +1458,13 @@
case DICT_MERGE: {
PyObject *update;
+ PyObject *dict;
+ PyObject *callable;
update = stack_pointer[-1];
- PyObject *dict = PEEK(oparg + 1); // update is still on the stack
-
+ dict = stack_pointer[-2 - (oparg - 1)];
+ callable = stack_pointer[-5 - (oparg - 1)];
if (_PyDict_MergeEx(dict, update, 2) < 0) {
- _PyEval_FormatKwargsError(tstate, PEEK(3 + oparg), update);
+ _PyEval_FormatKwargsError(tstate, callable, update);
Py_DECREF(update);
if (true) goto pop_1_error;
}
@@ -1479,9 +1476,10 @@
case MAP_ADD: {
PyObject *value;
PyObject *key;
+ PyObject *dict;
value = stack_pointer[-1];
key = stack_pointer[-2];
- PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack
+ dict = stack_pointer[-3 - (oparg - 1)];
assert(PyDict_CheckExact(dict));
/* dict[key] = value */
// Do not DECREF INPUTS because the function steals the references
@@ -1494,8 +1492,7 @@
PyObject *self;
PyObject *class;
PyObject *global_super;
- PyObject *res2 = NULL;
- PyObject *res;
+ PyObject *attr;
self = stack_pointer[-1];
class = stack_pointer[-2];
global_super = stack_pointer[-3];
@@ -1504,15 +1501,13 @@
DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR);
STAT_INC(LOAD_SUPER_ATTR, hit);
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2);
- res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL);
+ attr = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL);
Py_DECREF(global_super);
Py_DECREF(class);
Py_DECREF(self);
- if (res == NULL) goto pop_3_error;
+ if (attr == NULL) goto pop_3_error;
STACK_SHRINK(2);
- STACK_GROW(((oparg & 1) ? 1 : 0));
- if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res2; }
- stack_pointer[-1] = res;
+ stack_pointer[-1] = attr;
break;
}
@@ -1520,8 +1515,8 @@
PyObject *self;
PyObject *class;
PyObject *global_super;
- PyObject *res2;
- PyObject *res;
+ PyObject *attr;
+ PyObject *self_or_null;
self = stack_pointer[-1];
class = stack_pointer[-2];
global_super = stack_pointer[-3];
@@ -1532,32 +1527,30 @@
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2);
PyTypeObject *cls = (PyTypeObject *)class;
int method_found = 0;
- res2 = _PySuper_Lookup(cls, self, name,
+ attr = _PySuper_Lookup(cls, self, name,
Py_TYPE(self)->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL);
Py_DECREF(global_super);
Py_DECREF(class);
- if (res2 == NULL) {
+ if (attr == NULL) {
Py_DECREF(self);
if (true) goto pop_3_error;
}
if (method_found) {
- res = self; // transfer ownership
+ self_or_null = self; // transfer ownership
} else {
Py_DECREF(self);
- res = res2;
- res2 = NULL;
+ self_or_null = NULL;
}
STACK_SHRINK(1);
- stack_pointer[-2] = res2;
- stack_pointer[-1] = res;
+ stack_pointer[-2] = attr;
+ stack_pointer[-1] = self_or_null;
break;
}
case LOAD_ATTR: {
- static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size");
PyObject *owner;
- PyObject *res2 = NULL;
- PyObject *res;
+ PyObject *attr;
+ PyObject *self_or_null = NULL;
owner = stack_pointer[-1];
#if ENABLE_SPECIALIZATION
_PyAttrCache *cache = (_PyAttrCache *)next_instr;
@@ -1573,16 +1566,15 @@
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1);
if (oparg & 1) {
/* Designed to work in tandem with CALL, pushes two values. */
- PyObject* meth = NULL;
- if (_PyObject_GetMethod(owner, name, &meth)) {
+ attr = NULL;
+ if (_PyObject_GetMethod(owner, name, &attr)) {
/* We can bypass temporary bound method object.
meth is unbound method and obj is self.
meth | self | arg1 | ... | argN
*/
- assert(meth != NULL); // No errors on this branch
- res2 = meth;
- res = owner; // Transfer ownership
+ assert(attr != NULL); // No errors on this branch
+ self_or_null = owner; // Transfer ownership
}
else {
/* meth is not an unbound method (but a regular attr, or
@@ -1593,20 +1585,19 @@
NULL | meth | arg1 | ... | argN
*/
Py_DECREF(owner);
- if (meth == NULL) goto pop_1_error;
- res2 = NULL;
- res = meth;
+ if (attr == NULL) goto pop_1_error;
+ self_or_null = NULL;
}
}
else {
/* Classic, pushes one value. */
- res = PyObject_GetAttr(owner, name);
+ attr = PyObject_GetAttr(owner, name);
Py_DECREF(owner);
- if (res == NULL) goto pop_1_error;
+ if (attr == NULL) goto pop_1_error;
}
STACK_GROW(((oparg & 1) ? 1 : 0));
- if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res2; }
- stack_pointer[-1] = res;
+ stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr;
+ if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = self_or_null; }
break;
}
@@ -1625,32 +1616,33 @@
owner = stack_pointer[-1];
assert(Py_TYPE(owner)->tp_dictoffset < 0);
assert(Py_TYPE(owner)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
- DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR);
+ PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner);
+ DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) &&
+ !_PyObject_MakeInstanceAttributesFromDict(owner, dorv),
+ LOAD_ATTR);
break;
}
case _LOAD_ATTR_INSTANCE_VALUE: {
PyObject *owner;
- PyObject *res2 = NULL;
- PyObject *res;
+ PyObject *attr;
+ PyObject *null = NULL;
owner = stack_pointer[-1];
uint16_t index = (uint16_t)operand;
PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
- res = _PyDictOrValues_GetValues(dorv)->values[index];
- DEOPT_IF(res == NULL, LOAD_ATTR);
+ attr = _PyDictOrValues_GetValues(dorv)->values[index];
+ DEOPT_IF(attr == NULL, LOAD_ATTR);
STAT_INC(LOAD_ATTR, hit);
- Py_INCREF(res);
- res2 = NULL;
+ Py_INCREF(attr);
+ null = NULL;
Py_DECREF(owner);
STACK_GROW(((oparg & 1) ? 1 : 0));
- if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res2; }
- stack_pointer[-1] = res;
+ stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr;
+ if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; }
break;
}
case COMPARE_OP: {
- static_assert(INLINE_CACHE_ENTRIES_COMPARE_OP == 1, "incorrect cache size");
PyObject *right;
PyObject *left;
PyObject *res;
@@ -2155,14 +2147,91 @@
break;
}
- case CALL_NO_KW_TYPE_1: {
+ case _CHECK_PEP_523: {
+ DEOPT_IF(tstate->interp->eval_frame, CALL);
+ break;
+ }
+
+ case _CHECK_FUNCTION_EXACT_ARGS: {
+ PyObject *self_or_null;
+ PyObject *callable;
+ self_or_null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
+ uint32_t func_version = (uint32_t)operand;
+ ASSERT_KWNAMES_IS_NULL();
+ DEOPT_IF(!PyFunction_Check(callable), CALL);
+ PyFunctionObject *func = (PyFunctionObject *)callable;
+ DEOPT_IF(func->func_version != func_version, CALL);
+ PyCodeObject *code = (PyCodeObject *)func->func_code;
+ DEOPT_IF(code->co_argcount != oparg + (self_or_null != NULL), CALL);
+ break;
+ }
+
+ case _CHECK_STACK_SPACE: {
+ PyObject *callable;
+ callable = stack_pointer[-2 - oparg];
+ PyFunctionObject *func = (PyFunctionObject *)callable;
+ PyCodeObject *code = (PyCodeObject *)func->func_code;
+ DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL);
+ break;
+ }
+
+ case _INIT_CALL_PY_EXACT_ARGS: {
PyObject **args;
+ PyObject *self_or_null;
PyObject *callable;
+ _PyInterpreterFrame *new_frame;
+ args = stack_pointer - oparg;
+ self_or_null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
+ int argcount = oparg;
+ if (self_or_null != NULL) {
+ args--;
+ argcount++;
+ }
+ STAT_INC(CALL, hit);
+ PyFunctionObject *func = (PyFunctionObject *)callable;
+ new_frame = _PyFrame_PushUnchecked(tstate, func, argcount);
+ for (int i = 0; i < argcount; i++) {
+ new_frame->localsplus[i] = args[i];
+ }
+ STACK_SHRINK(oparg);
+ STACK_SHRINK(1);
+ stack_pointer[-1] = (PyObject *)new_frame;
+ break;
+ }
+
+ case _PUSH_FRAME: {
+ _PyInterpreterFrame *new_frame;
+ new_frame = (_PyInterpreterFrame *)stack_pointer[-1];
+ STACK_SHRINK(1);
+ // Write it out explicitly because it's subtly different.
+ // Eventually this should be the only occurrence of this code.
+ frame->return_offset = 0;
+ assert(tstate->interp->eval_frame == NULL);
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+ new_frame->previous = frame;
+ CALL_STAT_INC(inlined_py_calls);
+ frame = tstate->current_frame = new_frame;
+ #if TIER_ONE
+ goto start_frame;
+ #endif
+ #if TIER_TWO
+ if (_Py_EnterRecursivePy(tstate)) goto pop_1_exit_unwind;
+ stack_pointer = _PyFrame_GetStackPointer(frame);
+ ip_offset = (_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive;
+ #endif
+ break;
+ }
+
+ case CALL_NO_KW_TYPE_1: {
+ PyObject **args;
PyObject *null;
+ PyObject *callable;
PyObject *res;
args = stack_pointer - oparg;
- callable = stack_pointer[-1 - oparg];
- null = stack_pointer[-2 - oparg];
+ null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
ASSERT_KWNAMES_IS_NULL();
assert(oparg == 1);
DEOPT_IF(null != NULL, CALL);
@@ -2180,12 +2249,12 @@
case CALL_NO_KW_STR_1: {
PyObject **args;
- PyObject *callable;
PyObject *null;
+ PyObject *callable;
PyObject *res;
args = stack_pointer - oparg;
- callable = stack_pointer[-1 - oparg];
- null = stack_pointer[-2 - oparg];
+ null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
ASSERT_KWNAMES_IS_NULL();
assert(oparg == 1);
DEOPT_IF(null != NULL, CALL);
@@ -2205,12 +2274,12 @@
case CALL_NO_KW_TUPLE_1: {
PyObject **args;
- PyObject *callable;
PyObject *null;
+ PyObject *callable;
PyObject *res;
args = stack_pointer - oparg;
- callable = stack_pointer[-1 - oparg];
- null = stack_pointer[-2 - oparg];
+ null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
ASSERT_KWNAMES_IS_NULL();
assert(oparg == 1);
DEOPT_IF(null != NULL, CALL);
@@ -2244,18 +2313,16 @@
case CALL_NO_KW_BUILTIN_O: {
PyObject **args;
+ PyObject *self_or_null;
PyObject *callable;
- PyObject *method;
PyObject *res;
args = stack_pointer - oparg;
- callable = stack_pointer[-1 - oparg];
- method = stack_pointer[-2 - oparg];
+ self_or_null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
/* Builtin METH_O functions */
ASSERT_KWNAMES_IS_NULL();
- int is_meth = method != NULL;
int total_args = oparg;
- if (is_meth) {
- callable = method;
+ if (self_or_null != NULL) {
args--;
total_args++;
}
@@ -2286,18 +2353,16 @@
case CALL_NO_KW_BUILTIN_FAST: {
PyObject **args;
+ PyObject *self_or_null;
PyObject *callable;
- PyObject *method;
PyObject *res;
args = stack_pointer - oparg;
- callable = stack_pointer[-1 - oparg];
- method = stack_pointer[-2 - oparg];
+ self_or_null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
/* Builtin METH_FASTCALL functions, without keywords */
ASSERT_KWNAMES_IS_NULL();
- int is_meth = method != NULL;
int total_args = oparg;
- if (is_meth) {
- callable = method;
+ if (self_or_null != NULL) {
args--;
total_args++;
}
@@ -2332,18 +2397,16 @@
case CALL_NO_KW_LEN: {
PyObject **args;
+ PyObject *self_or_null;
PyObject *callable;
- PyObject *method;
PyObject *res;
args = stack_pointer - oparg;
- callable = stack_pointer[-1 - oparg];
- method = stack_pointer[-2 - oparg];
+ self_or_null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
ASSERT_KWNAMES_IS_NULL();
/* len(o) */
- int is_meth = method != NULL;
int total_args = oparg;
- if (is_meth) {
- callable = method;
+ if (self_or_null != NULL) {
args--;
total_args++;
}
@@ -2370,18 +2433,16 @@
case CALL_NO_KW_ISINSTANCE: {
PyObject **args;
+ PyObject *self_or_null;
PyObject *callable;
- PyObject *method;
PyObject *res;
args = stack_pointer - oparg;
- callable = stack_pointer[-1 - oparg];
- method = stack_pointer[-2 - oparg];
+ self_or_null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
ASSERT_KWNAMES_IS_NULL();
/* isinstance(o, o2) */
- int is_meth = method != NULL;
int total_args = oparg;
- if (is_meth) {
- callable = method;
+ if (self_or_null != NULL) {
args--;
total_args++;
}
@@ -2410,26 +2471,26 @@
case CALL_NO_KW_METHOD_DESCRIPTOR_O: {
PyObject **args;
- PyObject *method;
+ PyObject *self_or_null;
+ PyObject *callable;
PyObject *res;
args = stack_pointer - oparg;
- method = stack_pointer[-2 - oparg];
+ self_or_null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
ASSERT_KWNAMES_IS_NULL();
- int is_meth = method != NULL;
int total_args = oparg;
- if (is_meth) {
+ if (self_or_null != NULL) {
args--;
total_args++;
}
- PyMethodDescrObject *callable =
- (PyMethodDescrObject *)PEEK(total_args + 1);
+ PyMethodDescrObject *method = (PyMethodDescrObject *)callable;
DEOPT_IF(total_args != 2, CALL);
- DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
- PyMethodDef *meth = callable->d_method;
+ DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL);
+ PyMethodDef *meth = method->d_method;
DEOPT_IF(meth->ml_flags != METH_O, CALL);
PyObject *arg = args[1];
PyObject *self = args[0];
- DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL);
+ DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL);
STAT_INC(CALL, hit);
PyCFunction cfunc = meth->ml_meth;
// This is slower but CPython promises to check all non-vectorcall
@@ -2453,24 +2514,25 @@
case CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS: {
PyObject **args;
- PyObject *method;
+ PyObject *self_or_null;
+ PyObject *callable;
PyObject *res;
args = stack_pointer - oparg;
- method = stack_pointer[-2 - oparg];
+ self_or_null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
ASSERT_KWNAMES_IS_NULL();
assert(oparg == 0 || oparg == 1);
- int is_meth = method != NULL;
int total_args = oparg;
- if (is_meth) {
+ if (self_or_null != NULL) {
args--;
total_args++;
}
DEOPT_IF(total_args != 1, CALL);
- PyMethodDescrObject *callable = (PyMethodDescrObject *)SECOND();
- DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
- PyMethodDef *meth = callable->d_method;
+ PyMethodDescrObject *method = (PyMethodDescrObject *)callable;
+ DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL);
+ PyMethodDef *meth = method->d_method;
PyObject *self = args[0];
- DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL);
+ DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL);
DEOPT_IF(meth->ml_flags != METH_NOARGS, CALL);
STAT_INC(CALL, hit);
PyCFunction cfunc = meth->ml_meth;
@@ -2494,25 +2556,25 @@
case CALL_NO_KW_METHOD_DESCRIPTOR_FAST: {
PyObject **args;
- PyObject *method;
+ PyObject *self_or_null;
+ PyObject *callable;
PyObject *res;
args = stack_pointer - oparg;
- method = stack_pointer[-2 - oparg];
+ self_or_null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
ASSERT_KWNAMES_IS_NULL();
- int is_meth = method != NULL;
int total_args = oparg;
- if (is_meth) {
+ if (self_or_null != NULL) {
args--;
total_args++;
}
- PyMethodDescrObject *callable =
- (PyMethodDescrObject *)PEEK(total_args + 1);
+ PyMethodDescrObject *method = (PyMethodDescrObject *)callable;
/* Builtin METH_FASTCALL methods, without keywords */
- DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
- PyMethodDef *meth = callable->d_method;
+ DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL);
+ PyMethodDef *meth = method->d_method;
DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL);
PyObject *self = args[0];
- DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL);
+ DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL);
STAT_INC(CALL, hit);
_PyCFunctionFast cfunc =
(_PyCFunctionFast)(void(*)(void))meth->ml_meth;
@@ -2663,7 +2725,6 @@
}
case BINARY_OP: {
- static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size");
PyObject *rhs;
PyObject *lhs;
PyObject *res;
@@ -2733,6 +2794,17 @@
break;
}
+ case SAVE_CURRENT_IP: {
+ #if TIER_ONE
+ frame->prev_instr = next_instr - 1;
+ #endif
+ #if TIER_TWO
+ // Relies on a preceding SAVE_IP
+ frame->prev_instr--;
+ #endif
+ break;
+ }
+
case EXIT_TRACE: {
frame->prev_instr--; // Back up to just before destination
_PyFrame_SetStackPointer(frame, stack_pointer);
@@ -2740,3 +2812,12 @@
return frame;
break;
}
+
+ case INSERT: {
+ PyObject *top;
+ top = stack_pointer[-1];
+ // Inserts TOS at position specified by oparg;
+ memmove(&stack_pointer[-1 - oparg], &stack_pointer[-oparg], oparg * sizeof(stack_pointer[0]));
+ stack_pointer[-1 - oparg] = top;
+ break;
+ }
diff --git a/Python/fileutils.c b/Python/fileutils.c
index 19b23f6bd18b30..9c4998397c4ac8 100644
--- a/Python/fileutils.c
+++ b/Python/fileutils.c
@@ -2377,12 +2377,14 @@ _Py_find_basename(const wchar_t *filename)
path, which will be within the original buffer. Guaranteed to not
make the path longer, and will not fail. 'size' is the length of
the path, if known. If -1, the first null character will be assumed
- to be the end of the path. */
+ to be the end of the path. 'normsize' will be set to contain the
+ length of the resulting normalized path. */
wchar_t *
-_Py_normpath(wchar_t *path, Py_ssize_t size)
+_Py_normpath_and_size(wchar_t *path, Py_ssize_t size, Py_ssize_t *normsize)
{
assert(path != NULL);
- if (!path[0] || size == 0) {
+ if ((size < 0 && !path[0]) || size == 0) {
+ *normsize = 0;
return path;
}
wchar_t *pEnd = size >= 0 ? &path[size] : NULL;
@@ -2431,11 +2433,7 @@ _Py_normpath(wchar_t *path, Py_ssize_t size)
*p2++ = lastC = *p1;
}
}
- if (sepCount) {
- minP2 = p2; // Invalid path
- } else {
- minP2 = p2 - 1; // Absolute path has SEP at minP2
- }
+ minP2 = p2 - 1;
}
#else
// Skip past two leading SEPs
@@ -2495,13 +2493,28 @@ _Py_normpath(wchar_t *path, Py_ssize_t size)
while (--p2 != minP2 && *p2 == SEP) {
*p2 = L'\0';
}
+ } else {
+ --p2;
}
+ *normsize = p2 - path + 1;
#undef SEP_OR_END
#undef IS_SEP
#undef IS_END
return path;
}
+/* In-place path normalisation. Returns the start of the normalized
+ path, which will be within the original buffer. Guaranteed to not
+ make the path longer, and will not fail. 'size' is the length of
+ the path, if known. If -1, the first null character will be assumed
+ to be the end of the path. */
+wchar_t *
+_Py_normpath(wchar_t *path, Py_ssize_t size)
+{
+ Py_ssize_t norm_length;
+ return _Py_normpath_and_size(path, size, &norm_length);
+}
+
/* Get the current directory. buflen is the buffer size in wide characters
including the null character. Decode the path from the locale encoding.
diff --git a/Python/flowgraph.c b/Python/flowgraph.c
index a72b85d45aa27d..9d7865661a8036 100644
--- a/Python/flowgraph.c
+++ b/Python/flowgraph.c
@@ -24,15 +24,75 @@
typedef _PyCompilerSrcLocation location;
typedef _PyCfgJumpTargetLabel jump_target_label;
-typedef _PyCfgBasicblock basicblock;
-typedef _PyCfgBuilder cfg_builder;
-typedef _PyCfgInstruction cfg_instr;
+
+typedef struct _PyCfgInstruction {
+ int i_opcode;
+ int i_oparg;
+ _PyCompilerSrcLocation i_loc;
+ struct _PyCfgBasicblock *i_target; /* target block (if jump instruction) */
+ struct _PyCfgBasicblock *i_except; /* target block when exception is raised */
+} cfg_instr;
+
+typedef struct _PyCfgBasicblock {
+ /* Each basicblock in a compilation unit is linked via b_list in the
+ reverse order that the block are allocated. b_list points to the next
+ block in this list, not to be confused with b_next, which is next by
+ control flow. */
+ struct _PyCfgBasicblock *b_list;
+ /* The label of this block if it is a jump target, -1 otherwise */
+ _PyCfgJumpTargetLabel b_label;
+ /* Exception stack at start of block, used by assembler to create the exception handling table */
+ struct _PyCfgExceptStack *b_exceptstack;
+ /* pointer to an array of instructions, initially NULL */
+ cfg_instr *b_instr;
+ /* If b_next is non-NULL, it is a pointer to the next
+ block reached by normal control flow. */
+ struct _PyCfgBasicblock *b_next;
+ /* number of instructions used */
+ int b_iused;
+ /* length of instruction array (b_instr) */
+ int b_ialloc;
+ /* Used by add_checks_for_loads_of_unknown_variables */
+ uint64_t b_unsafe_locals_mask;
+ /* Number of predecessors that a block has. */
+ int b_predecessors;
+ /* depth of stack upon entry of block, computed by stackdepth() */
+ int b_startdepth;
+ /* Basic block is an exception handler that preserves lasti */
+ unsigned b_preserve_lasti : 1;
+ /* Used by compiler passes to mark whether they have visited a basic block. */
+ unsigned b_visited : 1;
+ /* b_except_handler is used by the cold-detection algorithm to mark exception targets */
+ unsigned b_except_handler : 1;
+ /* b_cold is true if this block is not perf critical (like an exception handler) */
+ unsigned b_cold : 1;
+ /* b_warm is used by the cold-detection algorithm to mark blocks which are definitely not cold */
+ unsigned b_warm : 1;
+} basicblock;
+
+
+struct _PyCfgBuilder {
+ /* The entryblock, at which control flow begins. All blocks of the
+ CFG are reachable through the b_next links */
+ struct _PyCfgBasicblock *g_entryblock;
+ /* Pointer to the most recently allocated block. By following
+ b_list links, you can reach all allocated blocks. */
+ struct _PyCfgBasicblock *g_block_list;
+ /* pointer to the block currently being constructed */
+ struct _PyCfgBasicblock *g_curblock;
+ /* label for the next instruction to be placed */
+ _PyCfgJumpTargetLabel g_current_label;
+};
+
+typedef struct _PyCfgBuilder cfg_builder;
static const jump_target_label NO_LABEL = {-1};
#define SAME_LABEL(L1, L2) ((L1).id == (L2).id)
#define IS_LABEL(L) (!SAME_LABEL((L), (NO_LABEL)))
+#define LOCATION(LNO, END_LNO, COL, END_COL) \
+ ((const _PyCompilerSrcLocation){(LNO), (END_LNO), (COL), (END_COL)})
static inline int
is_block_push(cfg_instr *i)
@@ -50,7 +110,7 @@ is_jump(cfg_instr *i)
#define INSTR_SET_OP1(I, OP, ARG) \
do { \
assert(OPCODE_HAS_ARG(OP)); \
- _PyCfgInstruction *_instr__ptr_ = (I); \
+ cfg_instr *_instr__ptr_ = (I); \
_instr__ptr_->i_opcode = (OP); \
_instr__ptr_->i_oparg = (ARG); \
} while (0);
@@ -59,7 +119,7 @@ is_jump(cfg_instr *i)
#define INSTR_SET_OP0(I, OP) \
do { \
assert(!OPCODE_HAS_ARG(OP)); \
- _PyCfgInstruction *_instr__ptr_ = (I); \
+ cfg_instr *_instr__ptr_ = (I); \
_instr__ptr_->i_opcode = (OP); \
_instr__ptr_->i_oparg = 0; \
} while (0);
@@ -148,8 +208,8 @@ basicblock_last_instr(const basicblock *b) {
}
static inline int
-basicblock_nofallthrough(const _PyCfgBasicblock *b) {
- _PyCfgInstruction *last = basicblock_last_instr(b);
+basicblock_nofallthrough(const basicblock *b) {
+ cfg_instr *last = basicblock_last_instr(b);
return (last &&
(IS_SCOPE_EXIT_OPCODE(last->i_opcode) ||
IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)));
@@ -175,8 +235,8 @@ copy_basicblock(cfg_builder *g, basicblock *block)
return result;
}
-int
-_PyBasicblock_InsertInstruction(basicblock *block, int pos, cfg_instr *instr) {
+static int
+basicblock_insert_instruction(basicblock *block, int pos, cfg_instr *instr) {
RETURN_IF_ERROR(basicblock_next_instr(block));
for (int i = block->b_iused - 1; i > pos; i--) {
block->b_instr[i] = block->b_instr[i-1];
@@ -311,8 +371,8 @@ cfg_builder_check(cfg_builder *g)
}
#endif
-int
-_PyCfgBuilder_Init(cfg_builder *g)
+static int
+init_cfg_builder(cfg_builder *g)
{
g->g_block_list = NULL;
basicblock *block = cfg_builder_new_block(g);
@@ -324,9 +384,28 @@ _PyCfgBuilder_Init(cfg_builder *g)
return SUCCESS;
}
+cfg_builder *
+_PyCfgBuilder_New(void)
+{
+ cfg_builder *g = PyMem_Malloc(sizeof(cfg_builder));
+ if (g == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ memset(g, 0, sizeof(cfg_builder));
+ if (init_cfg_builder(g) < 0) {
+ PyMem_Free(g);
+ return NULL;
+ }
+ return g;
+}
+
void
-_PyCfgBuilder_Fini(cfg_builder* g)
+_PyCfgBuilder_Free(cfg_builder *g)
{
+ if (g == NULL) {
+ return;
+ }
assert(cfg_builder_check(g));
basicblock *b = g->g_block_list;
while (b != NULL) {
@@ -337,6 +416,21 @@ _PyCfgBuilder_Fini(cfg_builder* g)
PyObject_Free((void *)b);
b = next;
}
+ PyMem_Free(g);
+}
+
+int
+_PyCfgBuilder_CheckSize(cfg_builder *g)
+{
+ int nblocks = 0;
+ for (basicblock *b = g->g_block_list; b != NULL; b = b->b_list) {
+ nblocks++;
+ }
+ if ((size_t)nblocks > SIZE_MAX / sizeof(basicblock *)) {
+ PyErr_NoMemory();
+ return ERROR;
+ }
+ return SUCCESS;
}
int
@@ -450,7 +544,7 @@ normalize_jumps_in_block(cfg_builder *g, basicblock *b) {
static int
-normalize_jumps(_PyCfgBuilder *g)
+normalize_jumps(cfg_builder *g)
{
basicblock *entryblock = g->g_entryblock;
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
@@ -463,14 +557,6 @@ normalize_jumps(_PyCfgBuilder *g)
return SUCCESS;
}
-int
-_PyCfg_ResolveJumps(_PyCfgBuilder *g)
-{
- RETURN_IF_ERROR(normalize_jumps(g));
- assert(no_redundant_jumps(g));
- return SUCCESS;
-}
-
static int
check_cfg(cfg_builder *g) {
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
@@ -529,9 +615,9 @@ translate_jump_labels_to_targets(basicblock *entryblock)
}
int
-_PyCfg_JumpLabelsToTargets(basicblock *entryblock)
+_PyCfg_JumpLabelsToTargets(cfg_builder *g)
{
- return translate_jump_labels_to_targets(entryblock);
+ return translate_jump_labels_to_targets(g->g_entryblock);
}
static int
@@ -553,10 +639,14 @@ mark_except_handlers(basicblock *entryblock) {
}
-typedef _PyCfgExceptStack ExceptStack;
+struct _PyCfgExceptStack {
+ basicblock *handlers[CO_MAXBLOCKS+1];
+ int depth;
+};
+
static basicblock *
-push_except_block(ExceptStack *stack, cfg_instr *setup) {
+push_except_block(struct _PyCfgExceptStack *stack, cfg_instr *setup) {
assert(is_block_push(setup));
int opcode = setup->i_opcode;
basicblock * target = setup->i_target;
@@ -568,19 +658,19 @@ push_except_block(ExceptStack *stack, cfg_instr *setup) {
}
static basicblock *
-pop_except_block(ExceptStack *stack) {
+pop_except_block(struct _PyCfgExceptStack *stack) {
assert(stack->depth > 0);
return stack->handlers[--stack->depth];
}
static basicblock *
-except_stack_top(ExceptStack *stack) {
+except_stack_top(struct _PyCfgExceptStack *stack) {
return stack->handlers[stack->depth];
}
-static ExceptStack *
+static struct _PyCfgExceptStack *
make_except_stack(void) {
- ExceptStack *new = PyMem_Malloc(sizeof(ExceptStack));
+ struct _PyCfgExceptStack *new = PyMem_Malloc(sizeof(struct _PyCfgExceptStack));
if (new == NULL) {
PyErr_NoMemory();
return NULL;
@@ -590,14 +680,14 @@ make_except_stack(void) {
return new;
}
-static ExceptStack *
-copy_except_stack(ExceptStack *stack) {
- ExceptStack *copy = PyMem_Malloc(sizeof(ExceptStack));
+static struct _PyCfgExceptStack *
+copy_except_stack(struct _PyCfgExceptStack *stack) {
+ struct _PyCfgExceptStack *copy = PyMem_Malloc(sizeof(struct _PyCfgExceptStack));
if (copy == NULL) {
PyErr_NoMemory();
return NULL;
}
- memcpy(copy, stack, sizeof(ExceptStack));
+ memcpy(copy, stack, sizeof(struct _PyCfgExceptStack));
return copy;
}
@@ -633,8 +723,8 @@ stackdepth_push(basicblock ***sp, basicblock *b, int depth)
/* Find the flow path that needs the largest stack. We assume that
* cycles in the flow graph have no net effect on the stack depth.
*/
-int
-_PyCfg_Stackdepth(cfg_builder *g)
+static int
+calculate_stackdepth(cfg_builder *g)
{
basicblock *entryblock = g->g_entryblock;
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
@@ -723,7 +813,7 @@ label_exception_targets(basicblock *entryblock) {
if (todo_stack == NULL) {
return ERROR;
}
- ExceptStack *except_stack = make_except_stack();
+ struct _PyCfgExceptStack *except_stack = make_except_stack();
if (except_stack == NULL) {
PyMem_Free(todo_stack);
PyErr_NoMemory();
@@ -747,7 +837,7 @@ label_exception_targets(basicblock *entryblock) {
cfg_instr *instr = &b->b_instr[i];
if (is_block_push(instr)) {
if (!instr->i_target->b_visited) {
- ExceptStack *copy = copy_except_stack(except_stack);
+ struct _PyCfgExceptStack *copy = copy_except_stack(except_stack);
if (copy == NULL) {
goto error;
}
@@ -766,7 +856,7 @@ label_exception_targets(basicblock *entryblock) {
assert(i == b->b_iused -1);
if (!instr->i_target->b_visited) {
if (BB_HAS_FALLTHROUGH(b)) {
- ExceptStack *copy = copy_except_stack(except_stack);
+ struct _PyCfgExceptStack *copy = copy_except_stack(except_stack);
if (copy == NULL) {
goto error;
}
@@ -1536,10 +1626,10 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts)
break;
case KW_NAMES:
break;
- case PUSH_NULL:
- if (nextop == LOAD_GLOBAL && (inst[1].i_opcode & 1) == 0) {
- INSTR_SET_OP0(inst, NOP);
- inst[1].i_oparg |= 1;
+ case LOAD_GLOBAL:
+ if (nextop == PUSH_NULL && (oparg & 1) == 0) {
+ INSTR_SET_OP1(inst, LOAD_GLOBAL, oparg | 1);
+ INSTR_SET_OP0(&bb->b_instr[i + 1], NOP);
}
break;
case COMPARE_OP:
@@ -2103,8 +2193,8 @@ push_cold_blocks_to_end(cfg_builder *g) {
return SUCCESS;
}
-void
-_PyCfg_ConvertPseudoOps(basicblock *entryblock)
+static void
+convert_pseudo_ops(basicblock *entryblock)
{
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
for (int i = 0; i < b->b_iused; i++) {
@@ -2293,3 +2383,270 @@ _PyCfg_OptimizeCodeUnit(cfg_builder *g, PyObject *consts, PyObject *const_cache,
RETURN_IF_ERROR(resolve_line_numbers(g, firstlineno));
return SUCCESS;
}
+
+static int *
+build_cellfixedoffsets(_PyCompile_CodeUnitMetadata *umd)
+{
+ int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames);
+ int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars);
+ int nfreevars = (int)PyDict_GET_SIZE(umd->u_freevars);
+
+ int noffsets = ncellvars + nfreevars;
+ int *fixed = PyMem_New(int, noffsets);
+ if (fixed == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ for (int i = 0; i < noffsets; i++) {
+ fixed[i] = nlocals + i;
+ }
+
+ PyObject *varname, *cellindex;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(umd->u_cellvars, &pos, &varname, &cellindex)) {
+ PyObject *varindex = PyDict_GetItem(umd->u_varnames, varname);
+ if (varindex != NULL) {
+ assert(PyLong_AS_LONG(cellindex) < INT_MAX);
+ assert(PyLong_AS_LONG(varindex) < INT_MAX);
+ int oldindex = (int)PyLong_AS_LONG(cellindex);
+ int argoffset = (int)PyLong_AS_LONG(varindex);
+ fixed[oldindex] = argoffset;
+ }
+ }
+
+ return fixed;
+}
+
+#define IS_GENERATOR(CF) \
+ ((CF) & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR))
+
+static int
+insert_prefix_instructions(_PyCompile_CodeUnitMetadata *umd, basicblock *entryblock,
+ int *fixed, int nfreevars, int code_flags)
+{
+ assert(umd->u_firstlineno > 0);
+
+ /* Add the generator prefix instructions. */
+ if (IS_GENERATOR(code_flags)) {
+ /* Note that RETURN_GENERATOR + POP_TOP have a net stack effect
+ * of 0. This is because RETURN_GENERATOR pushes an element
+ * with _PyFrame_StackPush before switching stacks.
+ */
+ cfg_instr make_gen = {
+ .i_opcode = RETURN_GENERATOR,
+ .i_oparg = 0,
+ .i_loc = LOCATION(umd->u_firstlineno, umd->u_firstlineno, -1, -1),
+ .i_target = NULL,
+ };
+ RETURN_IF_ERROR(basicblock_insert_instruction(entryblock, 0, &make_gen));
+ cfg_instr pop_top = {
+ .i_opcode = POP_TOP,
+ .i_oparg = 0,
+ .i_loc = NO_LOCATION,
+ .i_target = NULL,
+ };
+ RETURN_IF_ERROR(basicblock_insert_instruction(entryblock, 1, &pop_top));
+ }
+
+ /* Set up cells for any variable that escapes, to be put in a closure. */
+ const int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars);
+ if (ncellvars) {
+ // umd->u_cellvars has the cells out of order so we sort them
+ // before adding the MAKE_CELL instructions. Note that we
+ // adjust for arg cells, which come first.
+ const int nvars = ncellvars + (int)PyDict_GET_SIZE(umd->u_varnames);
+ int *sorted = PyMem_RawCalloc(nvars, sizeof(int));
+ if (sorted == NULL) {
+ PyErr_NoMemory();
+ return ERROR;
+ }
+ for (int i = 0; i < ncellvars; i++) {
+ sorted[fixed[i]] = i + 1;
+ }
+ for (int i = 0, ncellsused = 0; ncellsused < ncellvars; i++) {
+ int oldindex = sorted[i] - 1;
+ if (oldindex == -1) {
+ continue;
+ }
+ cfg_instr make_cell = {
+ .i_opcode = MAKE_CELL,
+ // This will get fixed in offset_derefs().
+ .i_oparg = oldindex,
+ .i_loc = NO_LOCATION,
+ .i_target = NULL,
+ };
+ if (basicblock_insert_instruction(entryblock, ncellsused, &make_cell) < 0) {
+ PyMem_RawFree(sorted);
+ return ERROR;
+ }
+ ncellsused += 1;
+ }
+ PyMem_RawFree(sorted);
+ }
+
+ if (nfreevars) {
+ cfg_instr copy_frees = {
+ .i_opcode = COPY_FREE_VARS,
+ .i_oparg = nfreevars,
+ .i_loc = NO_LOCATION,
+ .i_target = NULL,
+ };
+ RETURN_IF_ERROR(basicblock_insert_instruction(entryblock, 0, ©_frees));
+ }
+
+ return SUCCESS;
+}
+
+static int
+fix_cell_offsets(_PyCompile_CodeUnitMetadata *umd, basicblock *entryblock, int *fixedmap)
+{
+ int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames);
+ int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars);
+ int nfreevars = (int)PyDict_GET_SIZE(umd->u_freevars);
+ int noffsets = ncellvars + nfreevars;
+
+ // First deal with duplicates (arg cells).
+ int numdropped = 0;
+ for (int i = 0; i < noffsets ; i++) {
+ if (fixedmap[i] == i + nlocals) {
+ fixedmap[i] -= numdropped;
+ }
+ else {
+ // It was a duplicate (cell/arg).
+ numdropped += 1;
+ }
+ }
+
+ // Then update offsets, either relative to locals or by cell2arg.
+ for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
+ for (int i = 0; i < b->b_iused; i++) {
+ cfg_instr *inst = &b->b_instr[i];
+ // This is called before extended args are generated.
+ assert(inst->i_opcode != EXTENDED_ARG);
+ int oldoffset = inst->i_oparg;
+ switch(inst->i_opcode) {
+ case MAKE_CELL:
+ case LOAD_CLOSURE:
+ case LOAD_DEREF:
+ case STORE_DEREF:
+ case DELETE_DEREF:
+ case LOAD_FROM_DICT_OR_DEREF:
+ assert(oldoffset >= 0);
+ assert(oldoffset < noffsets);
+ assert(fixedmap[oldoffset] >= 0);
+ inst->i_oparg = fixedmap[oldoffset];
+ }
+ }
+ }
+
+ return numdropped;
+}
+
+static int
+prepare_localsplus(_PyCompile_CodeUnitMetadata *umd, cfg_builder *g, int code_flags)
+{
+ assert(PyDict_GET_SIZE(umd->u_varnames) < INT_MAX);
+ assert(PyDict_GET_SIZE(umd->u_cellvars) < INT_MAX);
+ assert(PyDict_GET_SIZE(umd->u_freevars) < INT_MAX);
+ int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames);
+ int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars);
+ int nfreevars = (int)PyDict_GET_SIZE(umd->u_freevars);
+ assert(INT_MAX - nlocals - ncellvars > 0);
+ assert(INT_MAX - nlocals - ncellvars - nfreevars > 0);
+ int nlocalsplus = nlocals + ncellvars + nfreevars;
+ int* cellfixedoffsets = build_cellfixedoffsets(umd);
+ if (cellfixedoffsets == NULL) {
+ return ERROR;
+ }
+
+ // This must be called before fix_cell_offsets().
+ if (insert_prefix_instructions(umd, g->g_entryblock, cellfixedoffsets, nfreevars, code_flags)) {
+ PyMem_Free(cellfixedoffsets);
+ return ERROR;
+ }
+
+ int numdropped = fix_cell_offsets(umd, g->g_entryblock, cellfixedoffsets);
+ PyMem_Free(cellfixedoffsets); // At this point we're done with it.
+ cellfixedoffsets = NULL;
+ if (numdropped < 0) {
+ return ERROR;
+ }
+
+ nlocalsplus -= numdropped;
+ return nlocalsplus;
+}
+
+int
+_PyCfg_ToInstructionSequence(cfg_builder *g, _PyCompile_InstructionSequence *seq)
+{
+ int lbl = 0;
+ for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
+ b->b_label = (jump_target_label){lbl};
+ lbl += b->b_iused;
+ }
+ for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
+ RETURN_IF_ERROR(_PyCompile_InstructionSequence_UseLabel(seq, b->b_label.id));
+ for (int i = 0; i < b->b_iused; i++) {
+ cfg_instr *instr = &b->b_instr[i];
+ if (OPCODE_HAS_JUMP(instr->i_opcode)) {
+ instr->i_oparg = instr->i_target->b_label.id;
+ }
+ RETURN_IF_ERROR(
+ _PyCompile_InstructionSequence_Addop(
+ seq, instr->i_opcode, instr->i_oparg, instr->i_loc));
+
+ _PyCompile_ExceptHandlerInfo *hi = &seq->s_instrs[seq->s_used-1].i_except_handler_info;
+ if (instr->i_except != NULL) {
+ hi->h_label = instr->i_except->b_label.id;
+ hi->h_startdepth = instr->i_except->b_startdepth;
+ hi->h_preserve_lasti = instr->i_except->b_preserve_lasti;
+ }
+ else {
+ hi->h_label = -1;
+ }
+ }
+ }
+ return SUCCESS;
+}
+
+
+int
+_PyCfg_OptimizedCfgToInstructionSequence(cfg_builder *g,
+ _PyCompile_CodeUnitMetadata *umd, int code_flags,
+ int *stackdepth, int *nlocalsplus,
+ _PyCompile_InstructionSequence *seq)
+{
+ *stackdepth = calculate_stackdepth(g);
+ if (*stackdepth < 0) {
+ return ERROR;
+ }
+
+ /* prepare_localsplus adds instructions for generators that push
+ * and pop an item on the stack. This assertion makes sure there
+ * is space on the stack for that.
+ * It should always be true, because a generator must have at
+ * least one expression or call to INTRINSIC_STOPITERATION_ERROR,
+ * which requires stackspace.
+ */
+ assert(!(IS_GENERATOR(code_flags) && *stackdepth == 0));
+
+ *nlocalsplus = prepare_localsplus(umd, g, code_flags);
+ if (*nlocalsplus < 0) {
+ return ERROR;
+ }
+
+ convert_pseudo_ops(g->g_entryblock);
+
+ /* Order of basic blocks must have been determined by now */
+
+ RETURN_IF_ERROR(normalize_jumps(g));
+ assert(no_redundant_jumps(g));
+
+ /* Can't modify the bytecode after computing jump offsets. */
+ if (_PyCfg_ToInstructionSequence(g, seq) < 0) {
+ return ERROR;
+ }
+
+ return SUCCESS;
+}
+
diff --git a/Python/frame.c b/Python/frame.c
index 581e4f95710fe2..fbfa54398c72b6 100644
--- a/Python/frame.c
+++ b/Python/frame.c
@@ -124,7 +124,7 @@ _PyFrame_ClearExceptCode(_PyInterpreterFrame *frame)
_PyFrame_GetGenerator(frame)->gi_frame_state == FRAME_CLEARED);
// GH-99729: Clearing this frame can expose the stack (via finalizers). It's
// crucial that this frame has been unlinked, and is no longer visible:
- assert(_PyThreadState_GET()->cframe->current_frame != frame);
+ assert(_PyThreadState_GET()->current_frame != frame);
if (frame->frame_obj) {
PyFrameObject *f = frame->frame_obj;
frame->frame_obj = NULL;
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index d7db8b07005fd1..80af8a7bcd56df 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -8,8 +8,7 @@
}
TARGET(RESUME) {
- assert(tstate->cframe == &cframe);
- assert(frame == cframe.current_frame);
+ assert(frame == tstate->current_frame);
/* Possibly combine this with eval breaker */
if (_PyFrame_GetCode(frame)->_co_instrumentation_version != tstate->interp->monitoring_version) {
int err = _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp);
@@ -961,9 +960,8 @@
retval = stack_pointer[-1];
assert(frame == &entry_frame);
assert(_PyFrame_IsIncomplete(frame));
- /* Restore previous cframe and return. */
- tstate->cframe = cframe.previous;
- assert(tstate->cframe->current_frame == frame->previous);
+ /* Restore previous frame and return. */
+ tstate->current_frame = frame->previous;
assert(!_PyErr_Occurred(tstate));
tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS;
return retval;
@@ -980,7 +978,7 @@
assert(frame != &entry_frame);
// GH-99729: We need to unlink the frame *before* clearing it:
_PyInterpreterFrame *dying = frame;
- frame = cframe.current_frame = dying->previous;
+ frame = tstate->current_frame = dying->previous;
_PyEvalFrameClearAndPop(tstate, dying);
frame->prev_instr += frame->return_offset;
_PyFrame_StackPush(frame, retval);
@@ -1002,7 +1000,7 @@
assert(frame != &entry_frame);
// GH-99729: We need to unlink the frame *before* clearing it:
_PyInterpreterFrame *dying = frame;
- frame = cframe.current_frame = dying->previous;
+ frame = tstate->current_frame = dying->previous;
_PyEvalFrameClearAndPop(tstate, dying);
frame->prev_instr += frame->return_offset;
_PyFrame_StackPush(frame, retval);
@@ -1019,7 +1017,7 @@
assert(frame != &entry_frame);
// GH-99729: We need to unlink the frame *before* clearing it:
_PyInterpreterFrame *dying = frame;
- frame = cframe.current_frame = dying->previous;
+ frame = tstate->current_frame = dying->previous;
_PyEvalFrameClearAndPop(tstate, dying);
frame->prev_instr += frame->return_offset;
_PyFrame_StackPush(frame, retval);
@@ -1039,7 +1037,7 @@
assert(frame != &entry_frame);
// GH-99729: We need to unlink the frame *before* clearing it:
_PyInterpreterFrame *dying = frame;
- frame = cframe.current_frame = dying->previous;
+ frame = tstate->current_frame = dying->previous;
_PyEvalFrameClearAndPop(tstate, dying);
frame->prev_instr += frame->return_offset;
_PyFrame_StackPush(frame, retval);
@@ -1191,13 +1189,13 @@
{
PyGenObject *gen = (PyGenObject *)receiver;
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
- frame->return_offset = oparg;
STACK_SHRINK(1);
_PyFrame_StackPush(gen_frame, v);
gen->gi_frame_state = FRAME_EXECUTING;
gen->gi_exc_state.previous_item = tstate->exc_info;
tstate->exc_info = &gen->gi_exc_state;
SKIP_OVER(INLINE_CACHE_ENTRIES_SEND);
+ frame->return_offset = oparg;
DISPATCH_INLINED(gen_frame);
}
if (Py_IsNone(v) && PyIter_Check(receiver)) {
@@ -1237,13 +1235,13 @@
DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, SEND);
STAT_INC(SEND, hit);
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
- frame->return_offset = oparg;
STACK_SHRINK(1);
_PyFrame_StackPush(gen_frame, v);
gen->gi_frame_state = FRAME_EXECUTING;
gen->gi_exc_state.previous_item = tstate->exc_info;
tstate->exc_info = &gen->gi_exc_state;
SKIP_OVER(INLINE_CACHE_ENTRIES_SEND);
+ frame->return_offset = oparg;
DISPATCH_INLINED(gen_frame);
}
@@ -1263,7 +1261,7 @@
gen->gi_exc_state.previous_item = NULL;
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *gen_frame = frame;
- frame = cframe.current_frame = frame->previous;
+ frame = tstate->current_frame = frame->previous;
gen_frame->previous = NULL;
_PyFrame_StackPush(frame, retval);
goto resume_frame;
@@ -1284,7 +1282,7 @@
gen->gi_exc_state.previous_item = NULL;
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *gen_frame = frame;
- frame = cframe.current_frame = frame->previous;
+ frame = tstate->current_frame = frame->previous;
gen_frame->previous = NULL;
_PyFrame_StackPush(frame, retval);
goto resume_frame;
@@ -1695,8 +1693,8 @@
TARGET(LOAD_GLOBAL) {
PREDICTED(LOAD_GLOBAL);
static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size");
+ PyObject *res;
PyObject *null = NULL;
- PyObject *v;
#if ENABLE_SPECIALIZATION
_PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
@@ -1712,10 +1710,10 @@
if (PyDict_CheckExact(GLOBALS())
&& PyDict_CheckExact(BUILTINS()))
{
- v = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(),
- (PyDictObject *)BUILTINS(),
- name);
- if (v == NULL) {
+ res = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(),
+ (PyDictObject *)BUILTINS(),
+ name);
+ if (res == NULL) {
if (!_PyErr_Occurred(tstate)) {
/* _PyDict_LoadGlobal() returns NULL without raising
* an exception if the key doesn't exist */
@@ -1724,17 +1722,17 @@
}
if (true) goto error;
}
- Py_INCREF(v);
+ Py_INCREF(res);
}
else {
/* Slow-path if globals or builtins is not a dict */
/* namespace 1: globals */
- if (PyMapping_GetOptionalItem(GLOBALS(), name, &v) < 0) goto error;
- if (v == NULL) {
+ if (PyMapping_GetOptionalItem(GLOBALS(), name, &res) < 0) goto error;
+ if (res == NULL) {
/* namespace 2: builtins */
- if (PyMapping_GetOptionalItem(BUILTINS(), name, &v) < 0) goto error;
- if (v == NULL) {
+ if (PyMapping_GetOptionalItem(BUILTINS(), name, &res) < 0) goto error;
+ if (res == NULL) {
_PyEval_FormatExcCheckArg(
tstate, PyExc_NameError,
NAME_ERROR_MSG, name);
@@ -1745,15 +1743,15 @@
null = NULL;
STACK_GROW(1);
STACK_GROW(((oparg & 1) ? 1 : 0));
- if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = null; }
- stack_pointer[-1] = v;
+ stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res;
+ if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; }
next_instr += 4;
DISPATCH();
}
TARGET(LOAD_GLOBAL_MODULE) {
- PyObject *null = NULL;
PyObject *res;
+ PyObject *null = NULL;
// _GUARD_GLOBALS_VERSION
{
uint16_t version = read_u16(&next_instr[1].cache);
@@ -1775,15 +1773,15 @@
}
STACK_GROW(1);
STACK_GROW(((oparg & 1) ? 1 : 0));
- if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = null; }
- stack_pointer[-1] = res;
+ stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res;
+ if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; }
next_instr += 4;
DISPATCH();
}
TARGET(LOAD_GLOBAL_BUILTIN) {
- PyObject *null = NULL;
PyObject *res;
+ PyObject *null = NULL;
// _GUARD_GLOBALS_VERSION
{
uint16_t version = read_u16(&next_instr[1].cache);
@@ -1813,8 +1811,8 @@
}
STACK_GROW(1);
STACK_GROW(((oparg & 1) ? 1 : 0));
- if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = null; }
- stack_pointer[-1] = res;
+ stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res;
+ if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; }
next_instr += 4;
DISPATCH();
}
@@ -2105,8 +2103,9 @@
TARGET(DICT_UPDATE) {
PyObject *update;
+ PyObject *dict;
update = stack_pointer[-1];
- PyObject *dict = PEEK(oparg + 1); // update is still on the stack
+ dict = stack_pointer[-2 - (oparg - 1)];
if (PyDict_Update(dict, update) < 0) {
if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) {
_PyErr_Format(tstate, PyExc_TypeError,
@@ -2123,11 +2122,13 @@
TARGET(DICT_MERGE) {
PyObject *update;
+ PyObject *dict;
+ PyObject *callable;
update = stack_pointer[-1];
- PyObject *dict = PEEK(oparg + 1); // update is still on the stack
-
+ dict = stack_pointer[-2 - (oparg - 1)];
+ callable = stack_pointer[-5 - (oparg - 1)];
if (_PyDict_MergeEx(dict, update, 2) < 0) {
- _PyEval_FormatKwargsError(tstate, PEEK(3 + oparg), update);
+ _PyEval_FormatKwargsError(tstate, callable, update);
Py_DECREF(update);
if (true) goto pop_1_error;
}
@@ -2139,9 +2140,10 @@
TARGET(MAP_ADD) {
PyObject *value;
PyObject *key;
+ PyObject *dict;
value = stack_pointer[-1];
key = stack_pointer[-2];
- PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack
+ dict = stack_pointer[-3 - (oparg - 1)];
assert(PyDict_CheckExact(dict));
/* dict[key] = value */
// Do not DECREF INPUTS because the function steals the references
@@ -2166,8 +2168,8 @@
PyObject *self;
PyObject *class;
PyObject *global_super;
- PyObject *res2 = NULL;
- PyObject *res;
+ PyObject *attr;
+ PyObject *null = NULL;
self = stack_pointer[-1];
class = stack_pointer[-2];
global_super = stack_pointer[-3];
@@ -2216,13 +2218,14 @@
Py_DECREF(class);
Py_DECREF(self);
if (super == NULL) goto pop_3_error;
- res = PyObject_GetAttr(super, name);
+ attr = PyObject_GetAttr(super, name);
Py_DECREF(super);
- if (res == NULL) goto pop_3_error;
+ if (attr == NULL) goto pop_3_error;
+ null = NULL;
STACK_SHRINK(2);
STACK_GROW(((oparg & 1) ? 1 : 0));
- if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res2; }
- stack_pointer[-1] = res;
+ stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr;
+ if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; }
next_instr += 1;
DISPATCH();
}
@@ -2231,8 +2234,7 @@
PyObject *self;
PyObject *class;
PyObject *global_super;
- PyObject *res2 = NULL;
- PyObject *res;
+ PyObject *attr;
self = stack_pointer[-1];
class = stack_pointer[-2];
global_super = stack_pointer[-3];
@@ -2241,15 +2243,13 @@
DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR);
STAT_INC(LOAD_SUPER_ATTR, hit);
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2);
- res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL);
+ attr = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL);
Py_DECREF(global_super);
Py_DECREF(class);
Py_DECREF(self);
- if (res == NULL) goto pop_3_error;
+ if (attr == NULL) goto pop_3_error;
STACK_SHRINK(2);
- STACK_GROW(((oparg & 1) ? 1 : 0));
- if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res2; }
- stack_pointer[-1] = res;
+ stack_pointer[-1] = attr;
next_instr += 1;
DISPATCH();
}
@@ -2258,8 +2258,8 @@
PyObject *self;
PyObject *class;
PyObject *global_super;
- PyObject *res2;
- PyObject *res;
+ PyObject *attr;
+ PyObject *self_or_null;
self = stack_pointer[-1];
class = stack_pointer[-2];
global_super = stack_pointer[-3];
@@ -2270,24 +2270,23 @@
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2);
PyTypeObject *cls = (PyTypeObject *)class;
int method_found = 0;
- res2 = _PySuper_Lookup(cls, self, name,
+ attr = _PySuper_Lookup(cls, self, name,
Py_TYPE(self)->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL);
Py_DECREF(global_super);
Py_DECREF(class);
- if (res2 == NULL) {
+ if (attr == NULL) {
Py_DECREF(self);
if (true) goto pop_3_error;
}
if (method_found) {
- res = self; // transfer ownership
+ self_or_null = self; // transfer ownership
} else {
Py_DECREF(self);
- res = res2;
- res2 = NULL;
+ self_or_null = NULL;
}
STACK_SHRINK(1);
- stack_pointer[-2] = res2;
- stack_pointer[-1] = res;
+ stack_pointer[-2] = attr;
+ stack_pointer[-1] = self_or_null;
next_instr += 1;
DISPATCH();
}
@@ -2296,8 +2295,8 @@
PREDICTED(LOAD_ATTR);
static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size");
PyObject *owner;
- PyObject *res2 = NULL;
- PyObject *res;
+ PyObject *attr;
+ PyObject *self_or_null = NULL;
owner = stack_pointer[-1];
#if ENABLE_SPECIALIZATION
_PyAttrCache *cache = (_PyAttrCache *)next_instr;
@@ -2313,16 +2312,15 @@
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1);
if (oparg & 1) {
/* Designed to work in tandem with CALL, pushes two values. */
- PyObject* meth = NULL;
- if (_PyObject_GetMethod(owner, name, &meth)) {
+ attr = NULL;
+ if (_PyObject_GetMethod(owner, name, &attr)) {
/* We can bypass temporary bound method object.
meth is unbound method and obj is self.
meth | self | arg1 | ... | argN
*/
- assert(meth != NULL); // No errors on this branch
- res2 = meth;
- res = owner; // Transfer ownership
+ assert(attr != NULL); // No errors on this branch
+ self_or_null = owner; // Transfer ownership
}
else {
/* meth is not an unbound method (but a regular attr, or
@@ -2333,28 +2331,27 @@
NULL | meth | arg1 | ... | argN
*/
Py_DECREF(owner);
- if (meth == NULL) goto pop_1_error;
- res2 = NULL;
- res = meth;
+ if (attr == NULL) goto pop_1_error;
+ self_or_null = NULL;
}
}
else {
/* Classic, pushes one value. */
- res = PyObject_GetAttr(owner, name);
+ attr = PyObject_GetAttr(owner, name);
Py_DECREF(owner);
- if (res == NULL) goto pop_1_error;
+ if (attr == NULL) goto pop_1_error;
}
STACK_GROW(((oparg & 1) ? 1 : 0));
- if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res2; }
- stack_pointer[-1] = res;
+ stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr;
+ if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = self_or_null; }
next_instr += 9;
DISPATCH();
}
TARGET(LOAD_ATTR_INSTANCE_VALUE) {
PyObject *owner;
- PyObject *res2 = NULL;
- PyObject *res;
+ PyObject *attr;
+ PyObject *null = NULL;
// _GUARD_TYPE_VERSION
owner = stack_pointer[-1];
{
@@ -2367,31 +2364,33 @@
{
assert(Py_TYPE(owner)->tp_dictoffset < 0);
assert(Py_TYPE(owner)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
- DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR);
+ PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner);
+ DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) &&
+ !_PyObject_MakeInstanceAttributesFromDict(owner, dorv),
+ LOAD_ATTR);
}
// _LOAD_ATTR_INSTANCE_VALUE
{
uint16_t index = read_u16(&next_instr[3].cache);
PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
- res = _PyDictOrValues_GetValues(dorv)->values[index];
- DEOPT_IF(res == NULL, LOAD_ATTR);
+ attr = _PyDictOrValues_GetValues(dorv)->values[index];
+ DEOPT_IF(attr == NULL, LOAD_ATTR);
STAT_INC(LOAD_ATTR, hit);
- Py_INCREF(res);
- res2 = NULL;
+ Py_INCREF(attr);
+ null = NULL;
Py_DECREF(owner);
}
STACK_GROW(((oparg & 1) ? 1 : 0));
- if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res2; }
- stack_pointer[-1] = res;
+ stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr;
+ if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; }
next_instr += 9;
DISPATCH();
}
TARGET(LOAD_ATTR_MODULE) {
PyObject *owner;
- PyObject *res2 = NULL;
- PyObject *res;
+ PyObject *attr;
+ PyObject *null = NULL;
owner = stack_pointer[-1];
uint32_t type_version = read_u32(&next_instr[1].cache);
uint16_t index = read_u16(&next_instr[3].cache);
@@ -2402,23 +2401,23 @@
assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE);
assert(index < dict->ma_keys->dk_nentries);
PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + index;
- res = ep->me_value;
- DEOPT_IF(res == NULL, LOAD_ATTR);
+ attr = ep->me_value;
+ DEOPT_IF(attr == NULL, LOAD_ATTR);
STAT_INC(LOAD_ATTR, hit);
- Py_INCREF(res);
- res2 = NULL;
+ Py_INCREF(attr);
+ null = NULL;
Py_DECREF(owner);
STACK_GROW(((oparg & 1) ? 1 : 0));
- if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res2; }
- stack_pointer[-1] = res;
+ stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr;
+ if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; }
next_instr += 9;
DISPATCH();
}
TARGET(LOAD_ATTR_WITH_HINT) {
PyObject *owner;
- PyObject *res2 = NULL;
- PyObject *res;
+ PyObject *attr;
+ PyObject *null = NULL;
owner = stack_pointer[-1];
uint32_t type_version = read_u32(&next_instr[1].cache);
uint16_t index = read_u16(&next_instr[3].cache);
@@ -2437,29 +2436,29 @@
if (DK_IS_UNICODE(dict->ma_keys)) {
PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint;
DEOPT_IF(ep->me_key != name, LOAD_ATTR);
- res = ep->me_value;
+ attr = ep->me_value;
}
else {
PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + hint;
DEOPT_IF(ep->me_key != name, LOAD_ATTR);
- res = ep->me_value;
+ attr = ep->me_value;
}
- DEOPT_IF(res == NULL, LOAD_ATTR);
+ DEOPT_IF(attr == NULL, LOAD_ATTR);
STAT_INC(LOAD_ATTR, hit);
- Py_INCREF(res);
- res2 = NULL;
+ Py_INCREF(attr);
+ null = NULL;
Py_DECREF(owner);
STACK_GROW(((oparg & 1) ? 1 : 0));
- if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res2; }
- stack_pointer[-1] = res;
+ stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr;
+ if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; }
next_instr += 9;
DISPATCH();
}
TARGET(LOAD_ATTR_SLOT) {
PyObject *owner;
- PyObject *res2 = NULL;
- PyObject *res;
+ PyObject *attr;
+ PyObject *null = NULL;
owner = stack_pointer[-1];
uint32_t type_version = read_u32(&next_instr[1].cache);
uint16_t index = read_u16(&next_instr[3].cache);
@@ -2467,41 +2466,41 @@
assert(type_version != 0);
DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
char *addr = (char *)owner + index;
- res = *(PyObject **)addr;
- DEOPT_IF(res == NULL, LOAD_ATTR);
+ attr = *(PyObject **)addr;
+ DEOPT_IF(attr == NULL, LOAD_ATTR);
STAT_INC(LOAD_ATTR, hit);
- Py_INCREF(res);
- res2 = NULL;
+ Py_INCREF(attr);
+ null = NULL;
Py_DECREF(owner);
STACK_GROW(((oparg & 1) ? 1 : 0));
- if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res2; }
- stack_pointer[-1] = res;
+ stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr;
+ if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; }
next_instr += 9;
DISPATCH();
}
TARGET(LOAD_ATTR_CLASS) {
- PyObject *cls;
- PyObject *res2 = NULL;
- PyObject *res;
- cls = stack_pointer[-1];
+ PyObject *owner;
+ PyObject *attr;
+ PyObject *null = NULL;
+ owner = stack_pointer[-1];
uint32_t type_version = read_u32(&next_instr[1].cache);
PyObject *descr = read_obj(&next_instr[5].cache);
- DEOPT_IF(!PyType_Check(cls), LOAD_ATTR);
- DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version,
+ DEOPT_IF(!PyType_Check(owner), LOAD_ATTR);
+ DEOPT_IF(((PyTypeObject *)owner)->tp_version_tag != type_version,
LOAD_ATTR);
assert(type_version != 0);
STAT_INC(LOAD_ATTR, hit);
- res2 = NULL;
- res = descr;
- assert(res != NULL);
- Py_INCREF(res);
- Py_DECREF(cls);
+ null = NULL;
+ attr = descr;
+ assert(attr != NULL);
+ Py_INCREF(attr);
+ Py_DECREF(owner);
STACK_GROW(((oparg & 1) ? 1 : 0));
- if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res2; }
- stack_pointer[-1] = res;
+ stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr;
+ if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; }
next_instr += 9;
DISPATCH();
}
@@ -2512,6 +2511,7 @@
uint32_t type_version = read_u32(&next_instr[1].cache);
uint32_t func_version = read_u32(&next_instr[3].cache);
PyObject *fget = read_obj(&next_instr[5].cache);
+ assert((oparg & 1) == 0);
DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR);
PyTypeObject *cls = Py_TYPE(owner);
@@ -2528,14 +2528,11 @@
Py_INCREF(fget);
_PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 1);
// Manipulate stack directly because we exit with DISPATCH_INLINED().
- SET_TOP(NULL);
- int shrink_stack = !(oparg & 1);
- STACK_SHRINK(shrink_stack);
+ STACK_SHRINK(1);
new_frame->localsplus[0] = owner;
SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR);
frame->return_offset = 0;
DISPATCH_INLINED(new_frame);
- STACK_GROW(((oparg & 1) ? 1 : 0));
}
TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) {
@@ -2544,6 +2541,7 @@
uint32_t type_version = read_u32(&next_instr[1].cache);
uint32_t func_version = read_u32(&next_instr[3].cache);
PyObject *getattribute = read_obj(&next_instr[5].cache);
+ assert((oparg & 1) == 0);
DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR);
PyTypeObject *cls = Py_TYPE(owner);
DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR);
@@ -2561,15 +2559,12 @@
Py_INCREF(f);
_PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 2);
// Manipulate stack directly because we exit with DISPATCH_INLINED().
- SET_TOP(NULL);
- int shrink_stack = !(oparg & 1);
- STACK_SHRINK(shrink_stack);
+ STACK_SHRINK(1);
new_frame->localsplus[0] = owner;
new_frame->localsplus[1] = Py_NewRef(name);
SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR);
frame->return_offset = 0;
DISPATCH_INLINED(new_frame);
- STACK_GROW(((oparg & 1) ? 1 : 0));
}
TARGET(STORE_ATTR_INSTANCE_VALUE) {
@@ -2914,10 +2909,10 @@
OBJECT_STAT_INC(optimization_attempts);
frame = _PyOptimizer_BackEdge(frame, here, next_instr, stack_pointer);
if (frame == NULL) {
- frame = cframe.current_frame;
+ frame = tstate->current_frame;
goto resume_with_error;
}
- assert(frame == cframe.current_frame);
+ assert(frame == tstate->current_frame);
here[1].cache &= ((1 << OPTIMIZER_BITS_IN_COUNTER) -1);
goto resume_frame;
}
@@ -2936,7 +2931,7 @@
Py_INCREF(executor);
frame = executor->execute(executor, frame, stack_pointer);
if (frame == NULL) {
- frame = cframe.current_frame;
+ frame = tstate->current_frame;
goto resume_with_error;
}
goto resume_frame;
@@ -3346,7 +3341,6 @@
DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER);
STAT_INC(FOR_ITER, hit);
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
- frame->return_offset = oparg;
_PyFrame_StackPush(gen_frame, Py_None);
gen->gi_frame_state = FRAME_EXECUTING;
gen->gi_exc_state.previous_item = tstate->exc_info;
@@ -3354,6 +3348,7 @@
SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER);
assert(next_instr[oparg].op.code == END_FOR ||
next_instr[oparg].op.code == INSTRUMENTED_END_FOR);
+ frame->return_offset = oparg;
DISPATCH_INLINED(gen_frame);
STACK_GROW(1);
}
@@ -3499,128 +3494,132 @@
}
TARGET(LOAD_ATTR_METHOD_WITH_VALUES) {
+ PyObject *owner;
+ PyObject *attr;
PyObject *self;
- PyObject *res2;
- PyObject *res;
- self = stack_pointer[-1];
+ owner = stack_pointer[-1];
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);
assert(oparg & 1);
/* Cached method object */
- PyTypeObject *self_cls = Py_TYPE(self);
+ PyTypeObject *owner_cls = Py_TYPE(owner);
assert(type_version != 0);
- DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR);
- assert(self_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self);
- DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR);
- PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls;
- DEOPT_IF(self_heap_type->ht_cached_keys->dk_version !=
+ DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR);
+ assert(owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT);
+ PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner);
+ DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) &&
+ !_PyObject_MakeInstanceAttributesFromDict(owner, dorv),
+ LOAD_ATTR);
+ PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls;
+ DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version !=
keys_version, LOAD_ATTR);
STAT_INC(LOAD_ATTR, hit);
assert(descr != NULL);
- res2 = Py_NewRef(descr);
- assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR));
- res = self;
+ attr = Py_NewRef(descr);
+ assert(_PyType_HasFeature(Py_TYPE(attr), Py_TPFLAGS_METHOD_DESCRIPTOR));
+ self = owner;
STACK_GROW(1);
- stack_pointer[-2] = res2;
- stack_pointer[-1] = res;
+ stack_pointer[-2] = attr;
+ stack_pointer[-1] = self;
next_instr += 9;
DISPATCH();
}
TARGET(LOAD_ATTR_METHOD_NO_DICT) {
+ PyObject *owner;
+ PyObject *attr;
PyObject *self;
- PyObject *res2;
- PyObject *res;
- self = stack_pointer[-1];
+ owner = stack_pointer[-1];
uint32_t type_version = read_u32(&next_instr[1].cache);
PyObject *descr = read_obj(&next_instr[5].cache);
assert(oparg & 1);
- PyTypeObject *self_cls = Py_TYPE(self);
- DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR);
- assert(self_cls->tp_dictoffset == 0);
+ PyTypeObject *owner_cls = Py_TYPE(owner);
+ DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR);
+ assert(owner_cls->tp_dictoffset == 0);
STAT_INC(LOAD_ATTR, hit);
assert(descr != NULL);
assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR));
- res2 = Py_NewRef(descr);
- res = self;
+ attr = Py_NewRef(descr);
+ self = owner;
STACK_GROW(1);
- stack_pointer[-2] = res2;
- stack_pointer[-1] = res;
+ stack_pointer[-2] = attr;
+ stack_pointer[-1] = self;
next_instr += 9;
DISPATCH();
}
TARGET(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES) {
- PyObject *self;
- PyObject *res;
- self = stack_pointer[-1];
+ PyObject *owner;
+ PyObject *attr;
+ owner = stack_pointer[-1];
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);
assert((oparg & 1) == 0);
- PyTypeObject *self_cls = Py_TYPE(self);
+ PyTypeObject *owner_cls = Py_TYPE(owner);
assert(type_version != 0);
- DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR);
- assert(self_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self);
- DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR);
- PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls;
- DEOPT_IF(self_heap_type->ht_cached_keys->dk_version !=
+ DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR);
+ assert(owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT);
+ PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner);
+ DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) &&
+ !_PyObject_MakeInstanceAttributesFromDict(owner, dorv),
+ LOAD_ATTR);
+ PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls;
+ DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version !=
keys_version, LOAD_ATTR);
STAT_INC(LOAD_ATTR, hit);
assert(descr != NULL);
- Py_DECREF(self);
- res = Py_NewRef(descr);
- stack_pointer[-1] = res;
+ Py_DECREF(owner);
+ attr = Py_NewRef(descr);
+ stack_pointer[-1] = attr;
next_instr += 9;
DISPATCH();
}
TARGET(LOAD_ATTR_NONDESCRIPTOR_NO_DICT) {
- PyObject *self;
- PyObject *res;
- self = stack_pointer[-1];
+ PyObject *owner;
+ PyObject *attr;
+ owner = stack_pointer[-1];
uint32_t type_version = read_u32(&next_instr[1].cache);
PyObject *descr = read_obj(&next_instr[5].cache);
assert((oparg & 1) == 0);
- PyTypeObject *self_cls = Py_TYPE(self);
+ PyTypeObject *owner_cls = Py_TYPE(owner);
assert(type_version != 0);
- DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR);
- assert(self_cls->tp_dictoffset == 0);
+ DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR);
+ assert(owner_cls->tp_dictoffset == 0);
STAT_INC(LOAD_ATTR, hit);
assert(descr != NULL);
- Py_DECREF(self);
- res = Py_NewRef(descr);
- stack_pointer[-1] = res;
+ Py_DECREF(owner);
+ attr = Py_NewRef(descr);
+ stack_pointer[-1] = attr;
next_instr += 9;
DISPATCH();
}
TARGET(LOAD_ATTR_METHOD_LAZY_DICT) {
+ PyObject *owner;
+ PyObject *attr;
PyObject *self;
- PyObject *res2;
- PyObject *res;
- self = stack_pointer[-1];
+ owner = stack_pointer[-1];
uint32_t type_version = read_u32(&next_instr[1].cache);
PyObject *descr = read_obj(&next_instr[5].cache);
assert(oparg & 1);
- 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;
+ PyTypeObject *owner_cls = Py_TYPE(owner);
+ DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR);
+ Py_ssize_t dictoffset = owner_cls->tp_dictoffset;
assert(dictoffset > 0);
- PyObject *dict = *(PyObject **)((char *)self + dictoffset);
+ PyObject *dict = *(PyObject **)((char *)owner + dictoffset);
/* This object has a __dict__, just not yet created */
DEOPT_IF(dict != NULL, LOAD_ATTR);
STAT_INC(LOAD_ATTR, hit);
assert(descr != NULL);
assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR));
- res2 = Py_NewRef(descr);
- res = self;
+ attr = Py_NewRef(descr);
+ self = owner;
STACK_GROW(1);
- stack_pointer[-2] = res2;
- stack_pointer[-1] = res;
+ stack_pointer[-2] = attr;
+ stack_pointer[-1] = self;
next_instr += 9;
DISPATCH();
}
@@ -3633,9 +3632,9 @@
}
TARGET(INSTRUMENTED_CALL) {
- int is_meth = PEEK(oparg+2) != NULL;
+ int is_meth = PEEK(oparg + 1) != NULL;
int total_args = oparg + is_meth;
- PyObject *function = PEEK(total_args + 1);
+ PyObject *function = PEEK(oparg + 2);
PyObject *arg = total_args == 0 ?
&_PyInstrumentation_MISSING : PEEK(total_args);
int err = _Py_call_instrumentation_2args(
@@ -3651,16 +3650,14 @@
PREDICTED(CALL);
static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size");
PyObject **args;
+ PyObject *self_or_null;
PyObject *callable;
- PyObject *method;
PyObject *res;
args = stack_pointer - oparg;
- callable = stack_pointer[-1 - oparg];
- method = stack_pointer[-2 - oparg];
- int is_meth = method != NULL;
+ self_or_null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
int total_args = oparg;
- if (is_meth) {
- callable = method;
+ if (self_or_null != NULL) {
args--;
total_args++;
}
@@ -3674,13 +3671,12 @@
STAT_INC(CALL, deferred);
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
#endif /* ENABLE_SPECIALIZATION */
- if (!is_meth && Py_TYPE(callable) == &PyMethod_Type) {
- is_meth = 1; // For consistenct; it's dead, though
+ if (self_or_null == NULL && Py_TYPE(callable) == &PyMethod_Type) {
args--;
total_args++;
PyObject *self = ((PyMethodObject *)callable)->im_self;
args[0] = Py_NewRef(self);
- method = ((PyMethodObject *)callable)->im_func;
+ PyObject *method = ((PyMethodObject *)callable)->im_func;
args[-1] = Py_NewRef(method);
Py_DECREF(callable);
callable = method;
@@ -3716,7 +3712,7 @@
kwnames);
if (opcode == INSTRUMENTED_CALL) {
PyObject *arg = total_args == 0 ?
- &_PyInstrumentation_MISSING : PEEK(total_args);
+ &_PyInstrumentation_MISSING : args[0];
if (res == NULL) {
_Py_call_instrumentation_exc2(
tstate, PY_MONITORING_EVENT_C_RAISE,
@@ -3747,17 +3743,17 @@
}
TARGET(CALL_BOUND_METHOD_EXACT_ARGS) {
+ PyObject *null;
PyObject *callable;
- PyObject *method;
- callable = stack_pointer[-1 - oparg];
- method = stack_pointer[-2 - oparg];
- DEOPT_IF(method != NULL, CALL);
+ null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
+ DEOPT_IF(null != NULL, CALL);
DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL);
STAT_INC(CALL, hit);
PyObject *self = ((PyMethodObject *)callable)->im_self;
- PEEK(oparg + 1) = Py_NewRef(self); // callable
+ PEEK(oparg + 1) = Py_NewRef(self); // self_or_null
PyObject *meth = ((PyMethodObject *)callable)->im_func;
- PEEK(oparg + 2) = Py_NewRef(meth); // method
+ PEEK(oparg + 2) = Py_NewRef(meth); // callable
Py_DECREF(callable);
GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS);
STACK_SHRINK(oparg);
@@ -3766,56 +3762,96 @@
TARGET(CALL_PY_EXACT_ARGS) {
PREDICTED(CALL_PY_EXACT_ARGS);
- PyObject **args;
+ PyObject *self_or_null;
PyObject *callable;
- PyObject *method;
- args = stack_pointer - oparg;
- callable = stack_pointer[-1 - oparg];
- method = stack_pointer[-2 - oparg];
- uint32_t func_version = read_u32(&next_instr[1].cache);
- ASSERT_KWNAMES_IS_NULL();
- DEOPT_IF(tstate->interp->eval_frame, CALL);
- int is_meth = method != NULL;
- int argcount = oparg;
- if (is_meth) {
- callable = method;
- args--;
- argcount++;
+ PyObject **args;
+ _PyInterpreterFrame *new_frame;
+ // _CHECK_PEP_523
+ {
+ DEOPT_IF(tstate->interp->eval_frame, CALL);
}
- DEOPT_IF(!PyFunction_Check(callable), CALL);
- PyFunctionObject *func = (PyFunctionObject *)callable;
- DEOPT_IF(func->func_version != func_version, CALL);
- PyCodeObject *code = (PyCodeObject *)func->func_code;
- DEOPT_IF(code->co_argcount != argcount, CALL);
- DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL);
- STAT_INC(CALL, hit);
- _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, func, argcount);
- for (int i = 0; i < argcount; i++) {
- new_frame->localsplus[i] = args[i];
+ // _CHECK_FUNCTION_EXACT_ARGS
+ self_or_null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
+ {
+ uint32_t func_version = read_u32(&next_instr[1].cache);
+ ASSERT_KWNAMES_IS_NULL();
+ DEOPT_IF(!PyFunction_Check(callable), CALL);
+ PyFunctionObject *func = (PyFunctionObject *)callable;
+ DEOPT_IF(func->func_version != func_version, CALL);
+ PyCodeObject *code = (PyCodeObject *)func->func_code;
+ DEOPT_IF(code->co_argcount != oparg + (self_or_null != NULL), CALL);
+ }
+ // _CHECK_STACK_SPACE
+ callable = stack_pointer[-2 - oparg];
+ {
+ PyFunctionObject *func = (PyFunctionObject *)callable;
+ PyCodeObject *code = (PyCodeObject *)func->func_code;
+ DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL);
}
- // Manipulate stack directly since we leave using DISPATCH_INLINED().
- STACK_SHRINK(oparg + 2);
- SKIP_OVER(INLINE_CACHE_ENTRIES_CALL);
- frame->return_offset = 0;
- DISPATCH_INLINED(new_frame);
+ // _INIT_CALL_PY_EXACT_ARGS
+ args = stack_pointer - oparg;
+ self_or_null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
+ {
+ int argcount = oparg;
+ if (self_or_null != NULL) {
+ args--;
+ argcount++;
+ }
+ STAT_INC(CALL, hit);
+ PyFunctionObject *func = (PyFunctionObject *)callable;
+ new_frame = _PyFrame_PushUnchecked(tstate, func, argcount);
+ for (int i = 0; i < argcount; i++) {
+ new_frame->localsplus[i] = args[i];
+ }
+ }
+ // SAVE_CURRENT_IP
+ next_instr += 3;
+ {
+ #if TIER_ONE
+ frame->prev_instr = next_instr - 1;
+ #endif
+ #if TIER_TWO
+ // Relies on a preceding SAVE_IP
+ frame->prev_instr--;
+ #endif
+ }
+ // _PUSH_FRAME
STACK_SHRINK(oparg);
- STACK_SHRINK(1);
+ STACK_SHRINK(2);
+ {
+ // Write it out explicitly because it's subtly different.
+ // Eventually this should be the only occurrence of this code.
+ frame->return_offset = 0;
+ assert(tstate->interp->eval_frame == NULL);
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+ new_frame->previous = frame;
+ CALL_STAT_INC(inlined_py_calls);
+ frame = tstate->current_frame = new_frame;
+ #if TIER_ONE
+ goto start_frame;
+ #endif
+ #if TIER_TWO
+ if (_Py_EnterRecursivePy(tstate)) goto pop_1_exit_unwind;
+ stack_pointer = _PyFrame_GetStackPointer(frame);
+ ip_offset = (_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive;
+ #endif
+ }
}
TARGET(CALL_PY_WITH_DEFAULTS) {
PyObject **args;
+ PyObject *self_or_null;
PyObject *callable;
- PyObject *method;
args = stack_pointer - oparg;
- callable = stack_pointer[-1 - oparg];
- method = stack_pointer[-2 - oparg];
+ self_or_null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
uint32_t func_version = read_u32(&next_instr[1].cache);
ASSERT_KWNAMES_IS_NULL();
DEOPT_IF(tstate->interp->eval_frame, CALL);
- int is_meth = method != NULL;
int argcount = oparg;
- if (is_meth) {
- callable = method;
+ if (self_or_null != NULL) {
args--;
argcount++;
}
@@ -3851,12 +3887,12 @@
TARGET(CALL_NO_KW_TYPE_1) {
PyObject **args;
- PyObject *callable;
PyObject *null;
+ PyObject *callable;
PyObject *res;
args = stack_pointer - oparg;
- callable = stack_pointer[-1 - oparg];
- null = stack_pointer[-2 - oparg];
+ null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
ASSERT_KWNAMES_IS_NULL();
assert(oparg == 1);
DEOPT_IF(null != NULL, CALL);
@@ -3875,12 +3911,12 @@
TARGET(CALL_NO_KW_STR_1) {
PyObject **args;
- PyObject *callable;
PyObject *null;
+ PyObject *callable;
PyObject *res;
args = stack_pointer - oparg;
- callable = stack_pointer[-1 - oparg];
- null = stack_pointer[-2 - oparg];
+ null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
ASSERT_KWNAMES_IS_NULL();
assert(oparg == 1);
DEOPT_IF(null != NULL, CALL);
@@ -3901,12 +3937,12 @@
TARGET(CALL_NO_KW_TUPLE_1) {
PyObject **args;
- PyObject *callable;
PyObject *null;
+ PyObject *callable;
PyObject *res;
args = stack_pointer - oparg;
- callable = stack_pointer[-1 - oparg];
- null = stack_pointer[-2 - oparg];
+ null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
ASSERT_KWNAMES_IS_NULL();
assert(oparg == 1);
DEOPT_IF(null != NULL, CALL);
@@ -3927,11 +3963,11 @@
TARGET(CALL_NO_KW_ALLOC_AND_ENTER_INIT) {
PyObject **args;
- PyObject *callable;
PyObject *null;
+ PyObject *callable;
args = stack_pointer - oparg;
- callable = stack_pointer[-1 - oparg];
- null = stack_pointer[-2 - oparg];
+ null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
/* This instruction does the following:
* 1. Creates the object (by calling ``object.__new__``)
* 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``)
@@ -3975,7 +4011,7 @@
/* Link frames */
init_frame->previous = shim;
shim->previous = frame;
- frame = cframe.current_frame = init_frame;
+ frame = tstate->current_frame = init_frame;
CALL_STAT_INC(inlined_py_calls);
/* Account for pushing the extra frame.
* We don't check recursion depth here,
@@ -4002,16 +4038,14 @@
TARGET(CALL_BUILTIN_CLASS) {
PyObject **args;
+ PyObject *self_or_null;
PyObject *callable;
- PyObject *method;
PyObject *res;
args = stack_pointer - oparg;
- callable = stack_pointer[-1 - oparg];
- method = stack_pointer[-2 - oparg];
- int is_meth = method != NULL;
+ self_or_null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
int total_args = oparg;
- if (is_meth) {
- callable = method;
+ if (self_or_null != NULL) {
args--;
total_args++;
}
@@ -4039,18 +4073,16 @@
TARGET(CALL_NO_KW_BUILTIN_O) {
PyObject **args;
+ PyObject *self_or_null;
PyObject *callable;
- PyObject *method;
PyObject *res;
args = stack_pointer - oparg;
- callable = stack_pointer[-1 - oparg];
- method = stack_pointer[-2 - oparg];
+ self_or_null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
/* Builtin METH_O functions */
ASSERT_KWNAMES_IS_NULL();
- int is_meth = method != NULL;
int total_args = oparg;
- if (is_meth) {
- callable = method;
+ if (self_or_null != NULL) {
args--;
total_args++;
}
@@ -4082,18 +4114,16 @@
TARGET(CALL_NO_KW_BUILTIN_FAST) {
PyObject **args;
+ PyObject *self_or_null;
PyObject *callable;
- PyObject *method;
PyObject *res;
args = stack_pointer - oparg;
- callable = stack_pointer[-1 - oparg];
- method = stack_pointer[-2 - oparg];
+ self_or_null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
/* Builtin METH_FASTCALL functions, without keywords */
ASSERT_KWNAMES_IS_NULL();
- int is_meth = method != NULL;
int total_args = oparg;
- if (is_meth) {
- callable = method;
+ if (self_or_null != NULL) {
args--;
total_args++;
}
@@ -4129,17 +4159,15 @@
TARGET(CALL_BUILTIN_FAST_WITH_KEYWORDS) {
PyObject **args;
+ PyObject *self_or_null;
PyObject *callable;
- PyObject *method;
PyObject *res;
args = stack_pointer - oparg;
- callable = stack_pointer[-1 - oparg];
- method = stack_pointer[-2 - oparg];
+ self_or_null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
/* Builtin METH_FASTCALL | METH_KEYWORDS functions */
- int is_meth = method != NULL;
int total_args = oparg;
- if (is_meth) {
- callable = method;
+ if (self_or_null != NULL) {
args--;
total_args++;
}
@@ -4176,18 +4204,16 @@
TARGET(CALL_NO_KW_LEN) {
PyObject **args;
+ PyObject *self_or_null;
PyObject *callable;
- PyObject *method;
PyObject *res;
args = stack_pointer - oparg;
- callable = stack_pointer[-1 - oparg];
- method = stack_pointer[-2 - oparg];
+ self_or_null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
ASSERT_KWNAMES_IS_NULL();
/* len(o) */
- int is_meth = method != NULL;
int total_args = oparg;
- if (is_meth) {
- callable = method;
+ if (self_or_null != NULL) {
args--;
total_args++;
}
@@ -4215,18 +4241,16 @@
TARGET(CALL_NO_KW_ISINSTANCE) {
PyObject **args;
+ PyObject *self_or_null;
PyObject *callable;
- PyObject *method;
PyObject *res;
args = stack_pointer - oparg;
- callable = stack_pointer[-1 - oparg];
- method = stack_pointer[-2 - oparg];
+ self_or_null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
ASSERT_KWNAMES_IS_NULL();
/* isinstance(o, o2) */
- int is_meth = method != NULL;
int total_args = oparg;
- if (is_meth) {
- callable = method;
+ if (self_or_null != NULL) {
args--;
total_args++;
}
@@ -4257,22 +4281,22 @@
TARGET(CALL_NO_KW_LIST_APPEND) {
PyObject **args;
PyObject *self;
- PyObject *method;
+ PyObject *callable;
args = stack_pointer - oparg;
self = stack_pointer[-1 - oparg];
- method = stack_pointer[-2 - oparg];
+ callable = stack_pointer[-2 - oparg];
ASSERT_KWNAMES_IS_NULL();
assert(oparg == 1);
- assert(method != NULL);
+ assert(self != NULL);
PyInterpreterState *interp = tstate->interp;
- DEOPT_IF(method != interp->callable_cache.list_append, CALL);
+ DEOPT_IF(callable != interp->callable_cache.list_append, CALL);
DEOPT_IF(!PyList_Check(self), CALL);
STAT_INC(CALL, hit);
if (_PyList_AppendTakeRef((PyListObject *)self, args[0]) < 0) {
goto pop_1_error; // Since arg is DECREF'ed already
}
Py_DECREF(self);
- Py_DECREF(method);
+ Py_DECREF(callable);
STACK_SHRINK(3);
// CALL + POP_TOP
SKIP_OVER(INLINE_CACHE_ENTRIES_CALL + 1);
@@ -4284,26 +4308,26 @@
TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) {
PyObject **args;
- PyObject *method;
+ PyObject *self_or_null;
+ PyObject *callable;
PyObject *res;
args = stack_pointer - oparg;
- method = stack_pointer[-2 - oparg];
+ self_or_null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
ASSERT_KWNAMES_IS_NULL();
- int is_meth = method != NULL;
int total_args = oparg;
- if (is_meth) {
+ if (self_or_null != NULL) {
args--;
total_args++;
}
- PyMethodDescrObject *callable =
- (PyMethodDescrObject *)PEEK(total_args + 1);
+ PyMethodDescrObject *method = (PyMethodDescrObject *)callable;
DEOPT_IF(total_args != 2, CALL);
- DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
- PyMethodDef *meth = callable->d_method;
+ DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL);
+ PyMethodDef *meth = method->d_method;
DEOPT_IF(meth->ml_flags != METH_O, CALL);
PyObject *arg = args[1];
PyObject *self = args[0];
- DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL);
+ DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL);
STAT_INC(CALL, hit);
PyCFunction cfunc = meth->ml_meth;
// This is slower but CPython promises to check all non-vectorcall
@@ -4328,22 +4352,22 @@
TARGET(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS) {
PyObject **args;
- PyObject *method;
+ PyObject *self_or_null;
+ PyObject *callable;
PyObject *res;
args = stack_pointer - oparg;
- method = stack_pointer[-2 - oparg];
- int is_meth = method != NULL;
+ self_or_null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
int total_args = oparg;
- if (is_meth) {
+ if (self_or_null != NULL) {
args--;
total_args++;
}
- PyMethodDescrObject *callable =
- (PyMethodDescrObject *)PEEK(total_args + 1);
- DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
- PyMethodDef *meth = callable->d_method;
+ PyMethodDescrObject *method = (PyMethodDescrObject *)callable;
+ DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL);
+ PyMethodDef *meth = method->d_method;
DEOPT_IF(meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS), CALL);
- PyTypeObject *d_type = callable->d_common.d_type;
+ PyTypeObject *d_type = method->d_common.d_type;
PyObject *self = args[0];
DEOPT_IF(!Py_IS_TYPE(self, d_type), CALL);
STAT_INC(CALL, hit);
@@ -4370,24 +4394,25 @@
TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS) {
PyObject **args;
- PyObject *method;
+ PyObject *self_or_null;
+ PyObject *callable;
PyObject *res;
args = stack_pointer - oparg;
- method = stack_pointer[-2 - oparg];
+ self_or_null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
ASSERT_KWNAMES_IS_NULL();
assert(oparg == 0 || oparg == 1);
- int is_meth = method != NULL;
int total_args = oparg;
- if (is_meth) {
+ if (self_or_null != NULL) {
args--;
total_args++;
}
DEOPT_IF(total_args != 1, CALL);
- PyMethodDescrObject *callable = (PyMethodDescrObject *)SECOND();
- DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
- PyMethodDef *meth = callable->d_method;
+ PyMethodDescrObject *method = (PyMethodDescrObject *)callable;
+ DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL);
+ PyMethodDef *meth = method->d_method;
PyObject *self = args[0];
- DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL);
+ DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL);
DEOPT_IF(meth->ml_flags != METH_NOARGS, CALL);
STAT_INC(CALL, hit);
PyCFunction cfunc = meth->ml_meth;
@@ -4412,25 +4437,25 @@
TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_FAST) {
PyObject **args;
- PyObject *method;
+ PyObject *self_or_null;
+ PyObject *callable;
PyObject *res;
args = stack_pointer - oparg;
- method = stack_pointer[-2 - oparg];
+ self_or_null = stack_pointer[-1 - oparg];
+ callable = stack_pointer[-2 - oparg];
ASSERT_KWNAMES_IS_NULL();
- int is_meth = method != NULL;
int total_args = oparg;
- if (is_meth) {
+ if (self_or_null != NULL) {
args--;
total_args++;
}
- PyMethodDescrObject *callable =
- (PyMethodDescrObject *)PEEK(total_args + 1);
+ PyMethodDescrObject *method = (PyMethodDescrObject *)callable;
/* Builtin METH_FASTCALL methods, without keywords */
- DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
- PyMethodDef *meth = callable->d_method;
+ DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL);
+ PyMethodDef *meth = method->d_method;
DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL);
PyObject *self = args[0];
- DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL);
+ DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL);
STAT_INC(CALL, hit);
_PyCFunctionFast cfunc =
(_PyCFunctionFast)(void(*)(void))meth->ml_meth;
@@ -4463,7 +4488,7 @@
PyObject *result;
if (oparg & 1) { kwargs = stack_pointer[-(oparg & 1 ? 1 : 0)]; }
callargs = stack_pointer[-1 - (oparg & 1 ? 1 : 0)];
- func = stack_pointer[-2 - (oparg & 1 ? 1 : 0)];
+ func = stack_pointer[-3 - (oparg & 1 ? 1 : 0)];
// 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));
@@ -4528,7 +4553,7 @@
Py_DECREF(func);
Py_DECREF(callargs);
Py_XDECREF(kwargs);
- assert(PEEK(3 + (oparg & 1)) == NULL);
+ assert(PEEK(2 + (oparg & 1)) == NULL);
if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; }
STACK_SHRINK(((oparg & 1) ? 1 : 0));
STACK_SHRINK(2);
@@ -4608,7 +4633,7 @@
assert(frame != &entry_frame);
_PyInterpreterFrame *prev = frame->previous;
_PyThreadState_PopFrame(tstate, frame);
- frame = cframe.current_frame = prev;
+ frame = tstate->current_frame = prev;
_PyFrame_StackPush(frame, (PyObject *)gen);
goto resume_frame;
}
diff --git a/Python/instrumentation.c b/Python/instrumentation.c
index 65ea7902a80a60..a7a5b4a5dc5f6e 100644
--- a/Python/instrumentation.c
+++ b/Python/instrumentation.c
@@ -7,6 +7,7 @@
#include "pycore_namespace.h"
#include "pycore_object.h"
#include "pycore_opcode.h"
+#include "pycore_opcode_metadata.h" // IS_VALID_OPCODE
#include "pycore_pyerrors.h"
#include "pycore_pystate.h" // _PyInterpreterState_GET()
@@ -120,7 +121,7 @@ static inline bool
opcode_has_event(int opcode)
{
return (
- opcode < INSTRUMENTED_LINE &&
+ opcode != INSTRUMENTED_LINE &&
INSTRUMENTED_OPCODES[opcode] > 0
);
}
@@ -437,11 +438,10 @@ dump_instrumentation_data(PyCodeObject *code, int star, FILE*out)
static bool
valid_opcode(int opcode)
{
- if (opcode > 0 &&
+ if (IS_VALID_OPCODE(opcode) &&
+ opcode != CACHE &&
opcode != RESERVED &&
- opcode < 255 &&
- _PyOpcode_OpName[opcode] &&
- _PyOpcode_OpName[opcode][0] != '<')
+ opcode < 255)
{
return true;
}
@@ -961,7 +961,7 @@ call_instrumentation_vector(
/* Offset visible to user should be the offset in bytes, as that is the
* convention for APIs involving code offsets. */
int bytes_offset = offset * (int)sizeof(_Py_CODEUNIT);
- PyObject *offset_obj = PyLong_FromSsize_t(bytes_offset);
+ PyObject *offset_obj = PyLong_FromLong(bytes_offset);
if (offset_obj == NULL) {
return -1;
}
@@ -1141,14 +1141,46 @@ _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame,
(interp->monitors.tools[PY_MONITORING_EVENT_LINE] |
code->_co_monitoring->local_monitors.tools[PY_MONITORING_EVENT_LINE]
);
- PyObject *line_obj = PyLong_FromSsize_t(line);
+ /* Special case sys.settrace to avoid boxing the line number,
+ * only to immediately unbox it. */
+ if (tools & (1 << PY_MONITORING_SYS_TRACE_ID)) {
+ if (tstate->c_tracefunc != NULL && line >= 0) {
+ PyFrameObject *frame_obj = _PyFrame_GetFrameObject(frame);
+ if (frame_obj == NULL) {
+ return -1;
+ }
+ if (frame_obj->f_trace_lines) {
+ /* Need to set tracing and what_event as if using
+ * the instrumentation call. */
+ int old_what = tstate->what_event;
+ tstate->what_event = PY_MONITORING_EVENT_LINE;
+ tstate->tracing++;
+ /* Call c_tracefunc directly, having set the line number. */
+ Py_INCREF(frame_obj);
+ frame_obj->f_lineno = line;
+ int err = tstate->c_tracefunc(tstate->c_traceobj, frame_obj, PyTrace_LINE, Py_None);
+ frame_obj->f_lineno = 0;
+ tstate->tracing--;
+ tstate->what_event = old_what;
+ Py_DECREF(frame_obj);
+ if (err) {
+ return -1;
+ }
+ }
+ }
+ tools &= (255 - (1 << PY_MONITORING_SYS_TRACE_ID));
+ }
+ if (tools == 0) {
+ goto done;
+ }
+ PyObject *line_obj = PyLong_FromLong(line);
if (line_obj == NULL) {
return -1;
}
PyObject *args[3] = { NULL, (PyObject *)code, line_obj };
- while (tools) {
+ do {
int tool = most_significant_bit(tools);
- assert(tool >= 0 && tool < 8);
+ assert(tool >= 0 && tool < PY_MONITORING_SYS_PROFILE_ID);
assert(tools & (1 << tool));
tools &= ~(1 << tool);
int res = call_one_instrument(interp, tstate, &args[1],
@@ -1166,11 +1198,11 @@ _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame,
/* DISABLE */
remove_line_tools(code, i, 1 << tool);
}
- }
+ } while (tools);
Py_DECREF(line_obj);
done:
assert(original_opcode != 0);
- assert(original_opcode < INSTRUMENTED_LINE);
+ assert(original_opcode != INSTRUMENTED_LINE);
assert(_PyOpcode_Deopt[original_opcode] == original_opcode);
return original_opcode;
}
@@ -1195,7 +1227,7 @@ _Py_call_instrumentation_instruction(PyThreadState *tstate, _PyInterpreterFrame*
code->_co_monitoring->local_monitors.tools[PY_MONITORING_EVENT_INSTRUCTION]
);
int bytes_offset = offset * (int)sizeof(_Py_CODEUNIT);
- PyObject *offset_obj = PyLong_FromSsize_t(bytes_offset);
+ PyObject *offset_obj = PyLong_FromLong(bytes_offset);
if (offset_obj == NULL) {
return -1;
}
@@ -1645,7 +1677,7 @@ instrument_all_executing_code_objects(PyInterpreterState *interp) {
PyThreadState* ts = PyInterpreterState_ThreadHead(interp);
HEAD_UNLOCK(runtime);
while (ts) {
- _PyInterpreterFrame *frame = ts->cframe->current_frame;
+ _PyInterpreterFrame *frame = ts->current_frame;
while (frame) {
if (frame->owner != FRAME_OWNED_BY_CSTACK) {
if (_Py_Instrument(_PyFrame_GetCode(frame), interp)) {
@@ -1851,6 +1883,9 @@ monitoring_register_callback_impl(PyObject *module, int tool_id, int event,
PyErr_Format(PyExc_ValueError, "invalid event %d", event);
return NULL;
}
+ if (PySys_Audit("sys.monitoring.register_callback", "O", func) < 0) {
+ return NULL;
+ }
if (func == Py_None) {
func = NULL;
}
diff --git a/Python/intrinsics.c b/Python/intrinsics.c
index 61a8e75872d2e2..5267c10238e626 100644
--- a/Python/intrinsics.c
+++ b/Python/intrinsics.c
@@ -120,7 +120,7 @@ import_all_from(PyThreadState *tstate, PyObject *locals, PyObject *v)
static PyObject *
import_star(PyThreadState* tstate, PyObject *from)
{
- _PyInterpreterFrame *frame = tstate->cframe->current_frame;
+ _PyInterpreterFrame *frame = tstate->current_frame;
if (_PyFrame_FastToLocalsWithError(frame) < 0) {
return NULL;
}
@@ -142,7 +142,7 @@ import_star(PyThreadState* tstate, PyObject *from)
static PyObject *
stopiteration_error(PyThreadState* tstate, PyObject *exc)
{
- _PyInterpreterFrame *frame = tstate->cframe->current_frame;
+ _PyInterpreterFrame *frame = tstate->current_frame;
assert(frame->owner == FRAME_OWNED_BY_GENERATOR);
assert(PyExceptionInstance_Check(exc));
const char *msg = NULL;
diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h
index 210c37b37225bb..305eb0bfe2a7c4 100644
--- a/Python/opcode_targets.h
+++ b/Python/opcode_targets.h
@@ -1,191 +1,192 @@
static void *opcode_targets[256] = {
&&TARGET_CACHE,
- &&TARGET_POP_TOP,
- &&TARGET_PUSH_NULL,
- &&TARGET_INTERPRETER_EXIT,
- &&TARGET_END_FOR,
- &&TARGET_END_SEND,
- &&TARGET_TO_BOOL,
- &&TARGET_TO_BOOL_ALWAYS_TRUE,
- &&TARGET_TO_BOOL_BOOL,
- &&TARGET_NOP,
- &&TARGET_TO_BOOL_INT,
- &&TARGET_UNARY_NEGATIVE,
- &&TARGET_UNARY_NOT,
- &&TARGET_TO_BOOL_LIST,
- &&TARGET_TO_BOOL_NONE,
- &&TARGET_UNARY_INVERT,
- &&TARGET_EXIT_INIT_CHECK,
- &&TARGET_RESERVED,
- &&TARGET_TO_BOOL_STR,
- &&TARGET_BINARY_OP_MULTIPLY_INT,
- &&TARGET_BINARY_OP_ADD_INT,
- &&TARGET_BINARY_OP_SUBTRACT_INT,
- &&TARGET_BINARY_OP_MULTIPLY_FLOAT,
+ &&TARGET_BEFORE_ASYNC_WITH,
+ &&TARGET_BEFORE_WITH,
&&TARGET_BINARY_OP_ADD_FLOAT,
- &&TARGET_MAKE_FUNCTION,
- &&TARGET_BINARY_SUBSCR,
- &&TARGET_BINARY_SLICE,
- &&TARGET_STORE_SLICE,
- &&TARGET_BINARY_OP_SUBTRACT_FLOAT,
+ &&TARGET_BINARY_OP_ADD_INT,
&&TARGET_BINARY_OP_ADD_UNICODE,
- &&TARGET_GET_LEN,
- &&TARGET_MATCH_MAPPING,
- &&TARGET_MATCH_SEQUENCE,
- &&TARGET_MATCH_KEYS,
&&TARGET_BINARY_OP_INPLACE_ADD_UNICODE,
- &&TARGET_PUSH_EXC_INFO,
- &&TARGET_CHECK_EXC_MATCH,
- &&TARGET_CHECK_EG_MATCH,
+ &&TARGET_BINARY_OP_MULTIPLY_FLOAT,
+ &&TARGET_BINARY_OP_MULTIPLY_INT,
+ &&TARGET_BINARY_OP_SUBTRACT_FLOAT,
+ &&TARGET_BINARY_OP_SUBTRACT_INT,
+ &&TARGET_BINARY_SLICE,
+ &&TARGET_BINARY_SUBSCR,
&&TARGET_BINARY_SUBSCR_DICT,
&&TARGET_BINARY_SUBSCR_GETITEM,
- &&TARGET_FORMAT_SIMPLE,
- &&TARGET_FORMAT_WITH_SPEC,
&&TARGET_BINARY_SUBSCR_LIST_INT,
&&TARGET_BINARY_SUBSCR_STR_INT,
+ &&TARGET_RESERVED,
&&TARGET_BINARY_SUBSCR_TUPLE_INT,
- &&TARGET_STORE_SUBSCR_DICT,
- &&TARGET_STORE_SUBSCR_LIST_INT,
- &&TARGET_SEND_GEN,
- &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE,
- &&TARGET_WITH_EXCEPT_START,
- &&TARGET_GET_AITER,
- &&TARGET_GET_ANEXT,
- &&TARGET_BEFORE_ASYNC_WITH,
- &&TARGET_BEFORE_WITH,
- &&TARGET_END_ASYNC_FOR,
+ &&TARGET_CHECK_EG_MATCH,
+ &&TARGET_CHECK_EXC_MATCH,
&&TARGET_CLEANUP_THROW,
- &&TARGET_UNPACK_SEQUENCE_TUPLE,
- &&TARGET_UNPACK_SEQUENCE_LIST,
- &&TARGET_STORE_ATTR_INSTANCE_VALUE,
- &&TARGET_STORE_ATTR_SLOT,
- &&TARGET_STORE_SUBSCR,
&&TARGET_DELETE_SUBSCR,
- &&TARGET_STORE_ATTR_WITH_HINT,
- &&TARGET_LOAD_GLOBAL_MODULE,
- &&TARGET_LOAD_GLOBAL_BUILTIN,
- &&TARGET_LOAD_SUPER_ATTR_ATTR,
- &&TARGET_LOAD_SUPER_ATTR_METHOD,
- &&TARGET_LOAD_ATTR_INSTANCE_VALUE,
+ &&TARGET_END_ASYNC_FOR,
+ &&TARGET_END_FOR,
+ &&TARGET_END_SEND,
+ &&TARGET_EXIT_INIT_CHECK,
+ &&TARGET_FORMAT_SIMPLE,
+ &&TARGET_FORMAT_WITH_SPEC,
+ &&TARGET_GET_AITER,
+ &&TARGET_GET_ANEXT,
&&TARGET_GET_ITER,
+ &&TARGET_GET_LEN,
&&TARGET_GET_YIELD_FROM_ITER,
- &&TARGET_LOAD_ATTR_MODULE,
- &&TARGET_LOAD_BUILD_CLASS,
- &&TARGET_LOAD_ATTR_WITH_HINT,
- &&TARGET_LOAD_ATTR_SLOT,
+ &&TARGET_INTERPRETER_EXIT,
&&TARGET_LOAD_ASSERTION_ERROR,
+ &&TARGET_LOAD_BUILD_CLASS,
+ &&TARGET_LOAD_LOCALS,
+ &&TARGET_MAKE_FUNCTION,
+ &&TARGET_MATCH_KEYS,
+ &&TARGET_MATCH_MAPPING,
+ &&TARGET_MATCH_SEQUENCE,
+ &&TARGET_NOP,
+ &&TARGET_POP_EXCEPT,
+ &&TARGET_POP_TOP,
+ &&TARGET_PUSH_EXC_INFO,
+ &&TARGET_PUSH_NULL,
&&TARGET_RETURN_GENERATOR,
- &&TARGET_LOAD_ATTR_CLASS,
- &&TARGET_LOAD_ATTR_PROPERTY,
- &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN,
- &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES,
- &&TARGET_LOAD_ATTR_METHOD_NO_DICT,
- &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT,
- &&TARGET_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES,
&&TARGET_RETURN_VALUE,
- &&TARGET_LOAD_ATTR_NONDESCRIPTOR_NO_DICT,
&&TARGET_SETUP_ANNOTATIONS,
- &&TARGET_COMPARE_OP_FLOAT,
- &&TARGET_LOAD_LOCALS,
- &&TARGET_COMPARE_OP_INT,
- &&TARGET_POP_EXCEPT,
- &&TARGET_STORE_NAME,
- &&TARGET_DELETE_NAME,
- &&TARGET_UNPACK_SEQUENCE,
- &&TARGET_FOR_ITER,
- &&TARGET_UNPACK_EX,
- &&TARGET_STORE_ATTR,
- &&TARGET_DELETE_ATTR,
- &&TARGET_STORE_GLOBAL,
- &&TARGET_DELETE_GLOBAL,
- &&TARGET_SWAP,
- &&TARGET_LOAD_CONST,
- &&TARGET_LOAD_NAME,
- &&TARGET_BUILD_TUPLE,
+ &&TARGET_STORE_ATTR_INSTANCE_VALUE,
+ &&TARGET_STORE_ATTR_SLOT,
+ &&TARGET_STORE_SLICE,
+ &&TARGET_STORE_SUBSCR,
+ &&TARGET_STORE_SUBSCR_DICT,
+ &&TARGET_STORE_SUBSCR_LIST_INT,
+ &&TARGET_TO_BOOL,
+ &&TARGET_TO_BOOL_ALWAYS_TRUE,
+ &&TARGET_TO_BOOL_BOOL,
+ &&TARGET_TO_BOOL_INT,
+ &&TARGET_TO_BOOL_LIST,
+ &&TARGET_TO_BOOL_NONE,
+ &&TARGET_TO_BOOL_STR,
+ &&TARGET_UNARY_INVERT,
+ &&TARGET_UNARY_NEGATIVE,
+ &&TARGET_UNARY_NOT,
+ &&TARGET_WITH_EXCEPT_START,
+ &&TARGET_BINARY_OP,
+ &&TARGET_BUILD_CONST_KEY_MAP,
&&TARGET_BUILD_LIST,
- &&TARGET_BUILD_SET,
&&TARGET_BUILD_MAP,
- &&TARGET_LOAD_ATTR,
+ &&TARGET_BUILD_SET,
+ &&TARGET_BUILD_SLICE,
+ &&TARGET_BUILD_STRING,
+ &&TARGET_BUILD_TUPLE,
+ &&TARGET_CALL,
+ &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS,
+ &&TARGET_CALL_BUILTIN_CLASS,
+ &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS,
+ &&TARGET_CALL_FUNCTION_EX,
+ &&TARGET_CALL_INTRINSIC_1,
+ &&TARGET_CALL_INTRINSIC_2,
+ &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS,
+ &&TARGET_CALL_NO_KW_ALLOC_AND_ENTER_INIT,
+ &&TARGET_CALL_NO_KW_BUILTIN_FAST,
+ &&TARGET_CALL_NO_KW_BUILTIN_O,
+ &&TARGET_CALL_NO_KW_ISINSTANCE,
+ &&TARGET_CALL_NO_KW_LEN,
+ &&TARGET_CALL_NO_KW_LIST_APPEND,
+ &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_FAST,
+ &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS,
+ &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O,
+ &&TARGET_CALL_NO_KW_STR_1,
+ &&TARGET_CALL_NO_KW_TUPLE_1,
+ &&TARGET_CALL_NO_KW_TYPE_1,
+ &&TARGET_CALL_PY_EXACT_ARGS,
+ &&TARGET_CALL_PY_WITH_DEFAULTS,
&&TARGET_COMPARE_OP,
- &&TARGET_IMPORT_NAME,
- &&TARGET_IMPORT_FROM,
- &&TARGET_JUMP_FORWARD,
+ &&TARGET_COMPARE_OP_FLOAT,
+ &&TARGET_COMPARE_OP_INT,
&&TARGET_COMPARE_OP_STR,
- &&TARGET_FOR_ITER_LIST,
- &&TARGET_FOR_ITER_TUPLE,
- &&TARGET_POP_JUMP_IF_FALSE,
- &&TARGET_POP_JUMP_IF_TRUE,
- &&TARGET_LOAD_GLOBAL,
- &&TARGET_IS_OP,
&&TARGET_CONTAINS_OP,
- &&TARGET_RERAISE,
+ &&TARGET_CONVERT_VALUE,
&&TARGET_COPY,
- &&TARGET_RETURN_CONST,
- &&TARGET_BINARY_OP,
- &&TARGET_SEND,
- &&TARGET_LOAD_FAST,
- &&TARGET_STORE_FAST,
+ &&TARGET_COPY_FREE_VARS,
+ &&TARGET_DELETE_ATTR,
+ &&TARGET_DELETE_DEREF,
&&TARGET_DELETE_FAST,
- &&TARGET_LOAD_FAST_CHECK,
- &&TARGET_POP_JUMP_IF_NOT_NONE,
- &&TARGET_POP_JUMP_IF_NONE,
- &&TARGET_RAISE_VARARGS,
- &&TARGET_GET_AWAITABLE,
+ &&TARGET_DELETE_GLOBAL,
+ &&TARGET_DELETE_NAME,
+ &&TARGET_DICT_MERGE,
+ &&TARGET_DICT_UPDATE,
+ &&TARGET_ENTER_EXECUTOR,
+ &&TARGET_EXTENDED_ARG,
+ &&TARGET_FOR_ITER,
+ &&TARGET_FOR_ITER_GEN,
+ &&TARGET_FOR_ITER_LIST,
&&TARGET_FOR_ITER_RANGE,
- &&TARGET_BUILD_SLICE,
+ &&TARGET_FOR_ITER_TUPLE,
+ &&TARGET_GET_AWAITABLE,
+ &&TARGET_IMPORT_FROM,
+ &&TARGET_IMPORT_NAME,
+ &&TARGET_IS_OP,
+ &&TARGET_JUMP_BACKWARD,
&&TARGET_JUMP_BACKWARD_NO_INTERRUPT,
- &&TARGET_MAKE_CELL,
- &&TARGET_FOR_ITER_GEN,
+ &&TARGET_JUMP_FORWARD,
+ &&TARGET_KW_NAMES,
+ &&TARGET_LIST_APPEND,
+ &&TARGET_LIST_EXTEND,
+ &&TARGET_LOAD_ATTR,
+ &&TARGET_LOAD_ATTR_CLASS,
+ &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN,
+ &&TARGET_LOAD_ATTR_INSTANCE_VALUE,
+ &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT,
+ &&TARGET_LOAD_ATTR_METHOD_NO_DICT,
+ &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES,
+ &&TARGET_LOAD_ATTR_MODULE,
+ &&TARGET_LOAD_ATTR_NONDESCRIPTOR_NO_DICT,
+ &&TARGET_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES,
+ &&TARGET_LOAD_ATTR_PROPERTY,
+ &&TARGET_LOAD_ATTR_SLOT,
+ &&TARGET_LOAD_ATTR_WITH_HINT,
+ &&TARGET_LOAD_CONST,
&&TARGET_LOAD_DEREF,
- &&TARGET_STORE_DEREF,
- &&TARGET_DELETE_DEREF,
- &&TARGET_JUMP_BACKWARD,
- &&TARGET_LOAD_SUPER_ATTR,
- &&TARGET_CALL_FUNCTION_EX,
+ &&TARGET_LOAD_FAST,
&&TARGET_LOAD_FAST_AND_CLEAR,
- &&TARGET_EXTENDED_ARG,
- &&TARGET_LIST_APPEND,
- &&TARGET_SET_ADD,
+ &&TARGET_LOAD_FAST_CHECK,
+ &&TARGET_LOAD_FAST_LOAD_FAST,
+ &&TARGET_LOAD_FROM_DICT_OR_DEREF,
+ &&TARGET_LOAD_FROM_DICT_OR_GLOBALS,
+ &&TARGET_LOAD_GLOBAL,
+ &&TARGET_LOAD_GLOBAL_BUILTIN,
+ &&TARGET_LOAD_GLOBAL_MODULE,
+ &&TARGET_LOAD_NAME,
+ &&TARGET_LOAD_SUPER_ATTR,
+ &&TARGET_LOAD_SUPER_ATTR_ATTR,
+ &&TARGET_LOAD_SUPER_ATTR_METHOD,
+ &&TARGET_MAKE_CELL,
&&TARGET_MAP_ADD,
- &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS,
- &&TARGET_COPY_FREE_VARS,
- &&TARGET_YIELD_VALUE,
- &&TARGET_RESUME,
&&TARGET_MATCH_CLASS,
- &&TARGET_CALL_PY_EXACT_ARGS,
- &&TARGET_CALL_PY_WITH_DEFAULTS,
- &&TARGET_CALL_NO_KW_TYPE_1,
- &&TARGET_BUILD_CONST_KEY_MAP,
- &&TARGET_BUILD_STRING,
- &&TARGET_CONVERT_VALUE,
- &&TARGET_CALL_NO_KW_STR_1,
- &&TARGET_CALL_NO_KW_TUPLE_1,
- &&TARGET_CALL_BUILTIN_CLASS,
- &&TARGET_LIST_EXTEND,
+ &&TARGET_POP_JUMP_IF_FALSE,
+ &&TARGET_POP_JUMP_IF_NONE,
+ &&TARGET_POP_JUMP_IF_NOT_NONE,
+ &&TARGET_POP_JUMP_IF_TRUE,
+ &&TARGET_RAISE_VARARGS,
+ &&TARGET_RERAISE,
+ &&TARGET_RESUME,
+ &&TARGET_RETURN_CONST,
+ &&TARGET_SEND,
+ &&TARGET_SEND_GEN,
+ &&TARGET_SET_ADD,
+ &&TARGET_SET_FUNCTION_ATTRIBUTE,
&&TARGET_SET_UPDATE,
- &&TARGET_DICT_MERGE,
- &&TARGET_DICT_UPDATE,
- &&TARGET_CALL_NO_KW_BUILTIN_O,
- &&TARGET_CALL_NO_KW_BUILTIN_FAST,
- &&TARGET_LOAD_FAST_LOAD_FAST,
+ &&TARGET_STORE_ATTR,
+ &&TARGET_STORE_ATTR_WITH_HINT,
+ &&TARGET_STORE_DEREF,
+ &&TARGET_STORE_FAST,
&&TARGET_STORE_FAST_LOAD_FAST,
&&TARGET_STORE_FAST_STORE_FAST,
- &&TARGET_CALL,
- &&TARGET_KW_NAMES,
- &&TARGET_CALL_INTRINSIC_1,
- &&TARGET_CALL_INTRINSIC_2,
- &&TARGET_LOAD_FROM_DICT_OR_GLOBALS,
- &&TARGET_LOAD_FROM_DICT_OR_DEREF,
- &&TARGET_SET_FUNCTION_ATTRIBUTE,
- &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS,
- &&TARGET_CALL_NO_KW_LEN,
- &&TARGET_CALL_NO_KW_ISINSTANCE,
- &&TARGET_CALL_NO_KW_LIST_APPEND,
- &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O,
- &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS,
- &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS,
- &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_FAST,
- &&TARGET_CALL_NO_KW_ALLOC_AND_ENTER_INIT,
+ &&TARGET_STORE_GLOBAL,
+ &&TARGET_STORE_NAME,
+ &&TARGET_SWAP,
+ &&TARGET_UNPACK_EX,
+ &&TARGET_UNPACK_SEQUENCE,
+ &&TARGET_UNPACK_SEQUENCE_LIST,
+ &&TARGET_UNPACK_SEQUENCE_TUPLE,
+ &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE,
+ &&TARGET_YIELD_VALUE,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
@@ -229,30 +230,28 @@ static void *opcode_targets[256] = {
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
- &&TARGET_ENTER_EXECUTOR,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
- &&TARGET_INSTRUMENTED_LOAD_SUPER_ATTR,
- &&TARGET_INSTRUMENTED_POP_JUMP_IF_NONE,
- &&TARGET_INSTRUMENTED_POP_JUMP_IF_NOT_NONE,
&&TARGET_INSTRUMENTED_RESUME,
- &&TARGET_INSTRUMENTED_CALL,
+ &&TARGET_INSTRUMENTED_END_FOR,
+ &&TARGET_INSTRUMENTED_END_SEND,
&&TARGET_INSTRUMENTED_RETURN_VALUE,
+ &&TARGET_INSTRUMENTED_RETURN_CONST,
&&TARGET_INSTRUMENTED_YIELD_VALUE,
+ &&TARGET_INSTRUMENTED_LOAD_SUPER_ATTR,
+ &&TARGET_INSTRUMENTED_FOR_ITER,
+ &&TARGET_INSTRUMENTED_CALL,
&&TARGET_INSTRUMENTED_CALL_FUNCTION_EX,
+ &&TARGET_INSTRUMENTED_INSTRUCTION,
&&TARGET_INSTRUMENTED_JUMP_FORWARD,
&&TARGET_INSTRUMENTED_JUMP_BACKWARD,
- &&TARGET_INSTRUMENTED_RETURN_CONST,
- &&TARGET_INSTRUMENTED_FOR_ITER,
- &&TARGET_INSTRUMENTED_POP_JUMP_IF_FALSE,
&&TARGET_INSTRUMENTED_POP_JUMP_IF_TRUE,
- &&TARGET_INSTRUMENTED_END_FOR,
- &&TARGET_INSTRUMENTED_END_SEND,
- &&TARGET_INSTRUMENTED_INSTRUCTION,
+ &&TARGET_INSTRUMENTED_POP_JUMP_IF_FALSE,
+ &&TARGET_INSTRUMENTED_POP_JUMP_IF_NONE,
+ &&TARGET_INSTRUMENTED_POP_JUMP_IF_NOT_NONE,
&&TARGET_INSTRUMENTED_LINE,
- &&_unknown_opcode
-};
+ &&_unknown_opcode};
diff --git a/Python/optimizer.c b/Python/optimizer.c
index 6c730aa14b9a47..559c4ae987263e 100644
--- a/Python/optimizer.c
+++ b/Python/optimizer.c
@@ -4,6 +4,7 @@
#include "pycore_opcode.h"
#include "pycore_opcode_metadata.h"
#include "pycore_opcode_utils.h"
+#include "pycore_optimizer.h"
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include "pycore_uops.h"
#include "cpython/optimizer.h"
@@ -103,7 +104,8 @@ error_optimize(
_PyOptimizerObject* self,
PyCodeObject *code,
_Py_CODEUNIT *instr,
- _PyExecutorObject **exec)
+ _PyExecutorObject **exec,
+ int Py_UNUSED(stack_entries))
{
PyErr_Format(PyExc_SystemError, "Should never call error_optimize");
return -1;
@@ -164,7 +166,7 @@ _PyOptimizer_BackEdge(_PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNI
}
_PyOptimizerObject *opt = interp->optimizer;
_PyExecutorObject *executor = NULL;
- int err = opt->optimize(opt, code, dest, &executor);
+ int err = opt->optimize(opt, code, dest, &executor, (int)(stack_pointer - _PyFrame_Stackbase(frame)));
if (err <= 0) {
assert(executor == NULL);
if (err < 0) {
@@ -254,7 +256,9 @@ counter_optimize(
_PyOptimizerObject* self,
PyCodeObject *code,
_Py_CODEUNIT *instr,
- _PyExecutorObject **exec_ptr)
+ _PyExecutorObject **exec_ptr,
+ int Py_UNUSED(curr_stackentries)
+)
{
_PyCounterExecutorObject *executor = (_PyCounterExecutorObject *)_PyObject_New(&CounterExecutor_Type);
if (executor == NULL) {
@@ -602,6 +606,10 @@ translate_bytecode_to_trace(
case OPARG_BOTTOM: // Second half of super-instr
oparg = orig_oparg & 0xF;
break;
+ case OPARG_SAVE_IP: // op==SAVE_IP; oparg=next instr
+ oparg = INSTR_IP(instr + offset, code);
+ break;
+
default:
fprintf(stderr,
"opcode=%d, oparg=%d; nuops=%d, i=%d; size=%d, offset=%d\n",
@@ -611,6 +619,11 @@ translate_bytecode_to_trace(
Py_FatalError("garbled expansion");
}
ADD_TO_TRACE(expansion->uops[i].uop, oparg, operand);
+ if (expansion->uops[i].uop == _PUSH_FRAME) {
+ assert(i + 1 == nuops);
+ ADD_TO_TRACE(SAVE_IP, 0, 0);
+ goto done;
+ }
}
break;
}
@@ -684,7 +697,8 @@ uop_optimize(
_PyOptimizerObject *self,
PyCodeObject *code,
_Py_CODEUNIT *instr,
- _PyExecutorObject **exec_ptr)
+ _PyExecutorObject **exec_ptr,
+ int curr_stackentries)
{
_PyUOpInstruction trace[_Py_UOP_MAX_TRACE_LENGTH];
int trace_length = translate_bytecode_to_trace(code, instr, trace, _Py_UOP_MAX_TRACE_LENGTH);
@@ -693,6 +707,10 @@ uop_optimize(
return trace_length;
}
OBJECT_STAT_INC(optimization_traces_created);
+ char *uop_optimize = Py_GETENV("PYTHONUOPSOPTIMIZE");
+ if (uop_optimize != NULL && *uop_optimize > '0') {
+ trace_length = _Py_uop_analyze_and_optimize(code, trace, trace_length, curr_stackentries);
+ }
_PyUOpExecutorObject *executor = PyObject_NewVar(_PyUOpExecutorObject, &UOpExecutor_Type, trace_length);
if (executor == NULL) {
return -1;
diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c
new file mode 100644
index 00000000000000..e48e018052c712
--- /dev/null
+++ b/Python/optimizer_analysis.c
@@ -0,0 +1,26 @@
+#include "Python.h"
+#include "opcode.h"
+#include "pycore_interp.h"
+#include "pycore_opcode.h"
+#include "pycore_opcode_metadata.h"
+#include "pycore_opcode_utils.h"
+#include "pycore_pystate.h" // _PyInterpreterState_GET()
+#include "pycore_uops.h"
+#include "pycore_long.h"
+#include "cpython/optimizer.h"
+#include
+#include
+#include
+#include "pycore_optimizer.h"
+
+
+int
+_Py_uop_analyze_and_optimize(
+ PyCodeObject *co,
+ _PyUOpInstruction *trace,
+ int trace_len,
+ int curr_stacklen
+)
+{
+ return trace_len;
+}
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 0de3abf9407899..90633960cb00ee 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -2147,7 +2147,7 @@ Py_EndInterpreter(PyThreadState *tstate)
if (tstate != _PyThreadState_GET()) {
Py_FatalError("thread is not current");
}
- if (tstate->cframe->current_frame != NULL) {
+ if (tstate->current_frame != NULL) {
Py_FatalError("thread still has a frame");
}
interp->finalizing = 1;
diff --git a/Python/pystate.c b/Python/pystate.c
index 3a05cb0fa7988d..01651d79f9acc0 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -1310,7 +1310,7 @@ init_threadstate(PyThreadState *tstate,
// This is cleared when PyGILState_Ensure() creates the thread state.
tstate->gilstate_counter = 1;
- tstate->cframe = &tstate->root_cframe;
+ tstate->current_frame = NULL;
tstate->datastack_chunk = NULL;
tstate->datastack_top = NULL;
tstate->datastack_limit = NULL;
@@ -1452,7 +1452,7 @@ PyThreadState_Clear(PyThreadState *tstate)
int verbose = _PyInterpreterState_GetConfig(tstate->interp)->verbose;
- if (verbose && tstate->cframe->current_frame != NULL) {
+ if (verbose && tstate->current_frame != NULL) {
/* bpo-20526: After the main thread calls
_PyInterpreterState_SetFinalizing() in Py_FinalizeEx()
(or in Py_EndInterpreter() for subinterpreters),
@@ -1953,7 +1953,7 @@ _PyThread_CurrentFrames(void)
for (i = runtime->interpreters.head; i != NULL; i = i->next) {
PyThreadState *t;
for (t = i->threads.head; t != NULL; t = t->next) {
- _PyInterpreterFrame *frame = t->cframe->current_frame;
+ _PyInterpreterFrame *frame = t->current_frame;
frame = _PyFrame_GetFirstComplete(frame);
if (frame == NULL) {
continue;
diff --git a/Python/specialize.c b/Python/specialize.c
index 855252e066dea1..2d514c0dc476d3 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -192,6 +192,7 @@ print_object_stats(FILE *out, ObjectStats *stats)
fprintf(out, "Object materialize dict (new key): %" PRIu64 "\n", stats->dict_materialized_new_key);
fprintf(out, "Object materialize dict (too big): %" PRIu64 "\n", stats->dict_materialized_too_big);
fprintf(out, "Object materialize dict (str subclass): %" PRIu64 "\n", stats->dict_materialized_str_subclass);
+ fprintf(out, "Object dematerialize dict: %" PRIu64 "\n", stats->dict_dematerialized);
fprintf(out, "Object method cache hits: %" PRIu64 "\n", stats->type_cache_hits);
fprintf(out, "Object method cache misses: %" PRIu64 "\n", stats->type_cache_misses);
fprintf(out, "Object method cache collisions: %" PRIu64 "\n", stats->type_cache_collisions);
@@ -685,8 +686,10 @@ specialize_dict_access(
return 0;
}
_PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
- PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
- if (_PyDictOrValues_IsValues(dorv)) {
+ PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner);
+ if (_PyDictOrValues_IsValues(*dorv) ||
+ _PyObject_MakeInstanceAttributesFromDict(owner, dorv))
+ {
// Virtual dictionary
PyDictKeysObject *keys = ((PyHeapTypeObject *)type)->ht_cached_keys;
assert(PyUnicode_CheckExact(name));
@@ -704,12 +707,16 @@ specialize_dict_access(
instr->op.code = values_op;
}
else {
- PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv);
+ PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(*dorv);
if (dict == NULL || !PyDict_CheckExact(dict)) {
SPECIALIZATION_FAIL(base_op, SPEC_FAIL_NO_DICT);
return 0;
}
// We found an instance with a __dict__.
+ if (dict->ma_values) {
+ SPECIALIZATION_FAIL(base_op, SPEC_FAIL_ATTR_NON_STRING_OR_SPLIT);
+ return 0;
+ }
Py_ssize_t index =
_PyDict_LookupIndex(dict, name);
if (index != (uint16_t)index) {
@@ -793,6 +800,10 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
if (!function_check_args(fget, 1, LOAD_ATTR)) {
goto fail;
}
+ if (instr->op.arg & 1) {
+ SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METHOD);
+ goto fail;
+ }
uint32_t version = function_get_version(fget, LOAD_ATTR);
if (version == 0) {
goto fail;
@@ -859,6 +870,10 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
if (!function_check_args(descr, 2, LOAD_ATTR)) {
goto fail;
}
+ if (instr->op.arg & 1) {
+ SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METHOD);
+ goto fail;
+ }
uint32_t version = function_get_version(descr, LOAD_ATTR);
if (version == 0) {
goto fail;
@@ -1092,9 +1107,11 @@ PyObject *descr, DescriptorClassification kind, bool is_method)
assert(descr != NULL);
assert((is_method && kind == METHOD) || (!is_method && kind == NON_DESCRIPTOR));
if (owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
- PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
+ PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner);
PyDictKeysObject *keys = ((PyHeapTypeObject *)owner_cls)->ht_cached_keys;
- if (!_PyDictOrValues_IsValues(dorv)) {
+ if (!_PyDictOrValues_IsValues(*dorv) &&
+ !_PyObject_MakeInstanceAttributesFromDict(owner, dorv))
+ {
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_HAS_MANAGED_DICT);
return 0;
}
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index be026d95ba7e77..f82901181f8866 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -1954,7 +1954,7 @@ sys__getframe_impl(PyObject *module, int depth)
/*[clinic end generated code: output=d438776c04d59804 input=c1be8a6464b11ee5]*/
{
PyThreadState *tstate = _PyThreadState_GET();
- _PyInterpreterFrame *frame = tstate->cframe->current_frame;
+ _PyInterpreterFrame *frame = tstate->current_frame;
if (frame != NULL) {
while (depth > 0) {
@@ -2270,7 +2270,7 @@ sys__getframemodulename_impl(PyObject *module, int depth)
if (PySys_Audit("sys._getframemodulename", "i", depth) < 0) {
return NULL;
}
- _PyInterpreterFrame *f = _PyThreadState_GET()->cframe->current_frame;
+ _PyInterpreterFrame *f = _PyThreadState_GET()->current_frame;
while (f && (_PyFrame_IsIncomplete(f) || depth-- > 0)) {
f = f->previous;
}
diff --git a/Python/traceback.c b/Python/traceback.c
index ca524b1b9af78b..bddb8763a2f9be 100644
--- a/Python/traceback.c
+++ b/Python/traceback.c
@@ -1207,7 +1207,7 @@ dump_traceback(int fd, PyThreadState *tstate, int write_header)
PUTS(fd, "Stack (most recent call first):\n");
}
- frame = tstate->cframe->current_frame;
+ frame = tstate->current_frame;
if (frame == NULL) {
PUTS(fd, " \n");
return;
diff --git a/Tools/build/deepfreeze.py b/Tools/build/deepfreeze.py
index a11fe6a62811ab..996d5f65a923b2 100644
--- a/Tools/build/deepfreeze.py
+++ b/Tools/build/deepfreeze.py
@@ -6,7 +6,6 @@
by Python 3.10, and 3.11 features are not available.
"""
import argparse
-import ast
import builtins
import collections
import contextlib
@@ -17,13 +16,13 @@
from typing import Dict, FrozenSet, TextIO, Tuple
import umarshal
-from generate_global_objects import get_identifiers_and_strings
+
+ROOT = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
verbose = False
-identifiers, strings = get_identifiers_and_strings()
-# This must be kept in sync with opcode.py
-RESUME = 151
+# This must be kept in sync with Tools/cases_generator/generate_cases.py
+RESUME = 166
def isprintable(b: bytes) -> bool:
return all(0x20 <= c < 0x7f for c in b)
@@ -114,6 +113,7 @@ def __init__(self, file: TextIO) -> None:
self.hits, self.misses = 0, 0
self.finis: list[str] = []
self.inits: list[str] = []
+ self.identifiers, self.strings = self.get_identifiers_and_strings()
self.write('#include "Python.h"')
self.write('#include "internal/pycore_gc.h"')
self.write('#include "internal/pycore_code.h"')
@@ -121,6 +121,19 @@ def __init__(self, file: TextIO) -> None:
self.write('#include "internal/pycore_long.h"')
self.write("")
+ def get_identifiers_and_strings(self) -> tuple[set[str], dict[str, str]]:
+ filename = os.path.join(ROOT, "Include", "internal", "pycore_global_strings.h")
+ with open(filename) as fp:
+ lines = fp.readlines()
+ identifiers: set[str] = set()
+ strings: dict[str, str] = {}
+ for line in lines:
+ if m := re.search(r"STRUCT_FOR_ID\((\w+)\)", line):
+ identifiers.add(m.group(1))
+ if m := re.search(r'STRUCT_FOR_STR\((\w+), "(.*?)"\)', line):
+ strings[m.group(2)] = m.group(1)
+ return identifiers, strings
+
@contextlib.contextmanager
def indent(self) -> None:
save_level = self.level
@@ -171,9 +184,9 @@ def generate_bytes(self, name: str, b: bytes) -> str:
return f"& {name}.ob_base.ob_base"
def generate_unicode(self, name: str, s: str) -> str:
- if s in strings:
- return f"&_Py_STR({strings[s]})"
- if s in identifiers:
+ if s in self.strings:
+ return f"&_Py_STR({self.strings[s]})"
+ if s in self.identifiers:
return f"&_Py_ID({s})"
if len(s) == 1:
c = ord(s)
@@ -284,10 +297,12 @@ def generate_code(self, name: str, code: types.CodeType) -> str:
self.write(f".co_linetable = {co_linetable},")
self.write(f"._co_cached = NULL,")
self.write(f".co_code_adaptive = {co_code_adaptive},")
- for i, op in enumerate(code.co_code[::2]):
+ first_traceable = 0
+ for op in code.co_code[::2]:
if op == RESUME:
- self.write(f"._co_firsttraceable = {i},")
break
+ first_traceable += 1
+ self.write(f"._co_firsttraceable = {first_traceable},")
name_as_code = f"(PyCodeObject *)&{name}"
self.finis.append(f"_PyStaticCode_Fini({name_as_code});")
self.inits.append(f"_PyStaticCode_Init({name_as_code})")
@@ -441,12 +456,10 @@ def is_frozen_header(source: str) -> bool:
def decode_frozen_data(source: str) -> types.CodeType:
- lines = source.splitlines()
- while lines and re.match(FROZEN_DATA_LINE, lines[0]) is None:
- del lines[0]
- while lines and re.match(FROZEN_DATA_LINE, lines[-1]) is None:
- del lines[-1]
- values: Tuple[int, ...] = ast.literal_eval("".join(lines).strip())
+ values: list[int] = []
+ for line in source.splitlines():
+ if re.match(FROZEN_DATA_LINE, line):
+ values.extend([int(x) for x in line.split(",") if x.strip()])
data = bytes(values)
return umarshal.loads(data)
diff --git a/Tools/build/generate_opcode_h.py b/Tools/build/generate_opcode_h.py
index 3a817326c94cbb..344709a05184ce 100644
--- a/Tools/build/generate_opcode_h.py
+++ b/Tools/build/generate_opcode_h.py
@@ -6,7 +6,7 @@
SCRIPT_NAME = "Tools/build/generate_opcode_h.py"
PYTHON_OPCODE = "Lib/opcode.py"
-header = f"""
+opcode_h_header = f"""
// Auto-generated by {SCRIPT_NAME} from {PYTHON_OPCODE}
#ifndef Py_OPCODE_H
@@ -15,11 +15,11 @@
extern "C" {{
#endif
+#include "opcode_ids.h"
-/* Instruction opcodes for compiled code */
""".lstrip()
-footer = """
+opcode_h_footer = """
#ifdef __cplusplus
}
@@ -62,53 +62,24 @@ def get_python_module_dict(filename):
return mod
def main(opcode_py,
- _opcode_metadata_py='Lib/_opcode_metadata.py',
- outfile='Include/opcode.h',
- opcode_targets_h='Python/opcode_targets.h',
- internaloutfile='Include/internal/pycore_opcode.h'):
-
- _opcode_metadata = get_python_module_dict(_opcode_metadata_py)
+ opcode_h='Include/opcode.h',
+ internal_opcode_h='Include/internal/pycore_opcode.h'):
opcode = get_python_module_dict(opcode_py)
- opmap = opcode['opmap']
- opname = opcode['opname']
-
- MIN_INSTRUMENTED_OPCODE = opcode["MIN_INSTRUMENTED_OPCODE"]
- NUM_OPCODES = len(opname)
- used = [ False ] * len(opname)
- next_op = 1
+ with open(opcode_h, 'w') as fobj:
+ fobj.write(opcode_h_header)
- for name, op in opmap.items():
- used[op] = True
+ fobj.write("\n")
+ for i, (op, _) in enumerate(opcode["_nb_ops"]):
+ fobj.write(DEFINE.format(op, i))
- specialized_opmap = {}
- opname_including_specialized = opname.copy()
- for name in _opcode_metadata['_specialized_instructions']:
- while used[next_op]:
- next_op += 1
- specialized_opmap[name] = next_op
- opname_including_specialized[next_op] = name
- used[next_op] = True
+ fobj.write(opcode_h_footer)
- with open(outfile, 'w') as fobj, open(internaloutfile, 'w') as iobj:
- fobj.write(header)
+ with open(internal_opcode_h, 'w') as iobj:
iobj.write(internal_header)
- for name in opname:
- if name in opmap:
- op = opmap[name]
- if op == MIN_INSTRUMENTED_OPCODE:
- fobj.write(DEFINE.format("MIN_INSTRUMENTED_OPCODE", MIN_INSTRUMENTED_OPCODE))
-
- fobj.write(DEFINE.format(name, op))
-
-
- for name, op in specialized_opmap.items():
- fobj.write(DEFINE.format(name, op))
-
iobj.write("\nextern const uint8_t _PyOpcode_Caches[256];\n")
- iobj.write("\nextern const uint8_t _PyOpcode_Deopt[256];\n")
iobj.write("\n#ifdef NEED_OPCODE_TABLES\n")
iobj.write("\nconst uint8_t _PyOpcode_Caches[256] = {\n")
@@ -116,56 +87,12 @@ def main(opcode_py,
iobj.write(f" [{name}] = {entries},\n")
iobj.write("};\n")
- deoptcodes = {}
- for basic, op in opmap.items():
- if op < 256:
- deoptcodes[basic] = basic
- for basic, family in _opcode_metadata["_specializations"].items():
- for specialized in family:
- deoptcodes[specialized] = basic
- iobj.write("\nconst uint8_t _PyOpcode_Deopt[256] = {\n")
- for opt, deopt in sorted(deoptcodes.items()):
- iobj.write(f" [{opt}] = {deopt},\n")
- iobj.write("};\n")
iobj.write("#endif // NEED_OPCODE_TABLES\n")
- fobj.write("\n")
- for i, (op, _) in enumerate(opcode["_nb_ops"]):
- fobj.write(DEFINE.format(op, i))
-
- iobj.write("\n")
- iobj.write(f"\nextern const char *const _PyOpcode_OpName[{NUM_OPCODES}];\n")
- iobj.write("\n#ifdef NEED_OPCODE_TABLES\n")
- iobj.write(f"const char *const _PyOpcode_OpName[{NUM_OPCODES}] = {{\n")
- for op, name in enumerate(opname_including_specialized):
- if name[0] != "<":
- op = name
- iobj.write(f''' [{op}] = "{name}",\n''')
- iobj.write("};\n")
- iobj.write("#endif // NEED_OPCODE_TABLES\n")
-
- iobj.write("\n")
- iobj.write("#define EXTRA_CASES \\\n")
- for i, flag in enumerate(used):
- if not flag:
- iobj.write(f" case {i}: \\\n")
- iobj.write(" ;\n")
-
- fobj.write(footer)
iobj.write(internal_footer)
- with open(opcode_targets_h, "w") as f:
- targets = ["_unknown_opcode"] * 256
- for op, name in enumerate(opname_including_specialized):
- if op < 256 and not name.startswith("<"):
- targets[op] = f"TARGET_{name}"
-
- f.write("static void *opcode_targets[256] = {\n")
- f.write(",\n".join([f" &&{s}" for s in targets]))
- f.write("\n};\n")
-
- print(f"{outfile} regenerated from {opcode_py}")
+ print(f"{opcode_h} regenerated from {opcode_py}")
if __name__ == '__main__':
- main(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5])
+ main(sys.argv[1], sys.argv[2], sys.argv[3])
diff --git a/Tools/build/umarshal.py b/Tools/build/umarshal.py
index f61570cbaff751..e05d93cf23c921 100644
--- a/Tools/build/umarshal.py
+++ b/Tools/build/umarshal.py
@@ -125,10 +125,10 @@ def r_long64(self) -> int:
x |= buf[1] << 8
x |= buf[2] << 16
x |= buf[3] << 24
- x |= buf[1] << 32
- x |= buf[1] << 40
- x |= buf[1] << 48
- x |= buf[1] << 56
+ x |= buf[4] << 32
+ x |= buf[5] << 40
+ x |= buf[6] << 48
+ x |= buf[7] << 56
x |= -(x & (1<<63)) # Sign-extend
return x
diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py
index 9bc7285e18b2fb..90334d0e79da80 100644
--- a/Tools/c-analyzer/cpython/_parser.py
+++ b/Tools/c-analyzer/cpython/_parser.py
@@ -84,6 +84,7 @@ def clean_lines(text):
Python/frozen_modules/*.h
Python/generated_cases.c.h
Python/executor_cases.c.h
+Python/abstract_interp_cases.c.h
# not actually source
Python/bytecodes.c
diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv
index dedcb3141457c0..28bd2a4430d14e 100644
--- a/Tools/c-analyzer/cpython/globals-to-fix.tsv
+++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv
@@ -322,6 +322,8 @@ Modules/_testcapi/vectorcall.c - MethodDescriptorBase_Type -
Modules/_testcapi/vectorcall.c - MethodDescriptorDerived_Type -
Modules/_testcapi/vectorcall.c - MethodDescriptorNopGet_Type -
Modules/_testcapi/vectorcall.c - MethodDescriptor2_Type -
+Modules/_testclinic.c - DeprStarInit -
+Modules/_testclinic.c - DeprStarNew -
##################################
diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv
index 099f20b5a1b433..d1ac0410619c96 100644
--- a/Tools/c-analyzer/cpython/ignored.tsv
+++ b/Tools/c-analyzer/cpython/ignored.tsv
@@ -419,6 +419,7 @@ Modules/_testbuffer.c staticarray_init kwlist -
Modules/_testcapi/buffer.c - testBufType -
Modules/_testcapi/code.c get_code_extra_index key -
Modules/_testcapi/datetime.c - test_run_counter -
+Modules/_testcapi/docstring.c - DocStringNoSignatureTest -
Modules/_testcapi/exceptions.c - PyRecursingInfinitelyError_Type -
Modules/_testcapi/heaptype.c - _testcapimodule -
Modules/_testcapi/mem.c - FmData -
@@ -429,6 +430,7 @@ Modules/_testcapi/watchers.c - g_dict_watch_events -
Modules/_testcapi/watchers.c - g_dict_watchers_installed -
Modules/_testcapi/watchers.c - g_type_modified_events -
Modules/_testcapi/watchers.c - g_type_watchers_installed -
+Modules/_testcapi/watchers.c - code_watcher_ids -
Modules/_testcapi/watchers.c - num_code_object_created_events -
Modules/_testcapi/watchers.c - num_code_object_destroyed_events -
Modules/_testcapi/watchers.c - pyfunc_watchers -
@@ -714,3 +716,5 @@ Modules/expat/xmlrole.c - error -
## other
Modules/_io/_iomodule.c - _PyIO_Module -
Modules/_sqlite/module.c - _sqlite3module -
+Python/optimizer_analysis.c - _Py_PartitionRootNode_Type -
+Python/optimizer_analysis.c - _Py_UOpsAbstractInterpContext_Type -
diff --git a/Tools/cases_generator/README.md b/Tools/cases_generator/README.md
index fc9331656fe787..ed802e44f31ad5 100644
--- a/Tools/cases_generator/README.md
+++ b/Tools/cases_generator/README.md
@@ -7,10 +7,14 @@ What's currently here:
- `lexer.py`: lexer for C, originally written by Mark Shannon
- `plexer.py`: OO interface on top of lexer.py; main class: `PLexer`
-- `parser.py`: Parser for instruction definition DSL; main class `Parser`
+- `parsing.py`: Parser for instruction definition DSL; main class `Parser`
- `generate_cases.py`: driver script to read `Python/bytecodes.c` and
write `Python/generated_cases.c.h` (and several other files)
-- `test_generator.py`: tests, require manual running using `pytest`
+- `analysis.py`: `Analyzer` class used to read the input files
+- `flags.py`: abstractions related to metadata flags for instructions
+- `formatting.py`: `Formatter` class used to write the output files
+- `instructions.py`: classes to analyze and write instructions
+- `stacking.py`: code to handle generalized stack effects
Note that there is some dummy C code at the top and bottom of
`Python/bytecodes.c`
diff --git a/Tools/cases_generator/flags.py b/Tools/cases_generator/flags.py
index f7ebdeb0d65677..962f003b194dbd 100644
--- a/Tools/cases_generator/flags.py
+++ b/Tools/cases_generator/flags.py
@@ -92,7 +92,7 @@ def variable_used_unspecialized(node: parsing.Node, name: str) -> bool:
if text == "#if":
if (
i + 1 < len(node.tokens)
- and node.tokens[i + 1].text == "ENABLE_SPECIALIZATION"
+ and node.tokens[i + 1].text in ("ENABLE_SPECIALIZATION", "TIER_ONE")
):
skipping = True
elif text in ("#else", "#endif"):
diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py
index d35a16a80e8d00..f31b6658d6599e 100644
--- a/Tools/cases_generator/generate_cases.py
+++ b/Tools/cases_generator/generate_cases.py
@@ -4,6 +4,8 @@
"""
import argparse
+import contextlib
+import itertools
import os
import posixpath
import sys
@@ -15,6 +17,7 @@
from flags import InstructionFlags, variable_used
from instructions import (
AnyInstruction,
+ AbstractInstruction,
Component,
Instruction,
MacroInstruction,
@@ -22,6 +25,7 @@
PseudoInstruction,
StackEffect,
OverriddenInstructionPlaceHolder,
+ TIER_ONE,
TIER_TWO,
)
import parsing
@@ -34,6 +38,12 @@
DEFAULT_INPUT = os.path.relpath(os.path.join(ROOT, "Python/bytecodes.c"))
DEFAULT_OUTPUT = os.path.relpath(os.path.join(ROOT, "Python/generated_cases.c.h"))
+DEFAULT_OPCODE_IDS_H_OUTPUT = os.path.relpath(
+ os.path.join(ROOT, "Include/opcode_ids.h")
+)
+DEFAULT_OPCODE_TARGETS_H_OUTPUT = os.path.relpath(
+ os.path.join(ROOT, "Python/opcode_targets.h")
+)
DEFAULT_METADATA_OUTPUT = os.path.relpath(
os.path.join(ROOT, "Include/internal/pycore_opcode_metadata.h")
)
@@ -43,6 +53,9 @@
DEFAULT_EXECUTOR_OUTPUT = os.path.relpath(
os.path.join(ROOT, "Python/executor_cases.c.h")
)
+DEFAULT_ABSTRACT_INTERPRETER_OUTPUT = os.path.relpath(
+ os.path.join(ROOT, "Python/abstract_interp_cases.c.h")
+)
# Constants used instead of size for macro expansions.
# Note: 1, 2, 4 must match actual cache entry sizes.
@@ -53,10 +66,28 @@
"OPARG_CACHE_4": 4,
"OPARG_TOP": 5,
"OPARG_BOTTOM": 6,
+ "OPARG_SAVE_IP": 7,
}
INSTR_FMT_PREFIX = "INSTR_FMT_"
+# TODO: generate all these after updating the DSL
+SPECIALLY_HANDLED_ABSTRACT_INSTR = {
+ "LOAD_FAST",
+ "LOAD_FAST_CHECK",
+ "LOAD_FAST_AND_CLEAR",
+ "LOAD_CONST",
+ "STORE_FAST",
+ "STORE_FAST_MAYBE_NULL",
+ "COPY",
+
+ # Arithmetic
+ "_BINARY_OP_MULTIPLY_INT",
+ "_BINARY_OP_ADD_INT",
+ "_BINARY_OP_SUBTRACT_INT",
+
+}
+
arg_parser = argparse.ArgumentParser(
description="Generate the code for the interpreter switch.",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
@@ -64,6 +95,20 @@
arg_parser.add_argument(
"-o", "--output", type=str, help="Generated code", default=DEFAULT_OUTPUT
)
+arg_parser.add_argument(
+ "-n",
+ "--opcode_ids_h",
+ type=str,
+ help="Header file with opcode number definitions",
+ default=DEFAULT_OPCODE_IDS_H_OUTPUT,
+)
+arg_parser.add_argument(
+ "-t",
+ "--opcode_targets_h",
+ type=str,
+ help="File with opcode targets for computed gotos",
+ default=DEFAULT_OPCODE_TARGETS_H_OUTPUT,
+)
arg_parser.add_argument(
"-m",
"--metadata",
@@ -91,7 +136,13 @@
help="Write executor cases to this file",
default=DEFAULT_EXECUTOR_OUTPUT,
)
-
+arg_parser.add_argument(
+ "-a",
+ "--abstract-interpreter-cases",
+ type=str,
+ help="Write abstract interpreter cases to this file",
+ default=DEFAULT_ABSTRACT_INTERPRETER_OUTPUT,
+)
class Generator(Analyzer):
def get_stack_effect_info(
@@ -108,7 +159,7 @@ def effect_str(effects: list[StackEffect]) -> str:
pushed: str | None
match thing:
case parsing.InstDef():
- if thing.kind != "op":
+ if thing.kind != "op" or self.instrs[thing.name].is_viable_uop():
instr = self.instrs[thing.name]
popped = effect_str(instr.input_effects)
pushed = effect_str(instr.output_effects)
@@ -141,6 +192,15 @@ def effect_str(effects: list[StackEffect]) -> str:
typing.assert_never(thing)
return instr, popped, pushed
+ @contextlib.contextmanager
+ def metadata_item(self, signature, open, close):
+ self.out.emit("")
+ self.out.emit(f"extern {signature};")
+ self.out.emit("#ifdef NEED_OPCODE_METADATA")
+ with self.out.block(f"{signature} {open}", close):
+ yield
+ self.out.emit("#endif // NEED_OPCODE_METADATA")
+
def write_stack_effect_functions(self) -> None:
popped_data: list[tuple[AnyInstruction, str]] = []
pushed_data: list[tuple[AnyInstruction, str]] = []
@@ -156,25 +216,16 @@ def write_stack_effect_functions(self) -> None:
def write_function(
direction: str, data: list[tuple[AnyInstruction, str]]
) -> None:
- self.out.emit("")
- self.out.emit("#ifndef NEED_OPCODE_METADATA")
- self.out.emit(
- f"extern int _PyOpcode_num_{direction}(int opcode, int oparg, bool jump);"
- )
- self.out.emit("#else")
- self.out.emit("int")
- self.out.emit(
- f"_PyOpcode_num_{direction}(int opcode, int oparg, bool jump) {{"
- )
- self.out.emit(" switch(opcode) {")
- for instr, effect in data:
- self.out.emit(f" case {instr.name}:")
- self.out.emit(f" return {effect};")
- self.out.emit(" default:")
- self.out.emit(" return -1;")
- self.out.emit(" }")
- self.out.emit("}")
- self.out.emit("#endif")
+
+ with self.metadata_item(
+ f"int _PyOpcode_num_{direction}(int opcode, int oparg, bool jump)", "", ""
+ ):
+ with self.out.block("switch(opcode)"):
+ for instr, effect in data:
+ self.out.emit(f"case {instr.name}:")
+ self.out.emit(f" return {effect};")
+ self.out.emit("default:")
+ self.out.emit(" return -1;")
write_function("popped", popped_data)
write_function("pushed", pushed_data)
@@ -197,6 +248,129 @@ def write_provenance_header(self):
self.out.write_raw(self.from_source_files())
self.out.write_raw(f"{self.out.comment} Do not edit!\n")
+ def assign_opcode_ids(self):
+ """Assign IDs to opcodes"""
+
+ ops: list[(bool, str)] = [] # (has_arg, name) for each opcode
+ instrumented_ops: list[str] = []
+
+ for instr in itertools.chain(
+ [instr for instr in self.instrs.values() if instr.kind != "op"],
+ self.macro_instrs.values()):
+
+ name = instr.name
+ if name.startswith('INSTRUMENTED_'):
+ instrumented_ops.append(name)
+ else:
+ ops.append((instr.instr_flags.HAS_ARG_FLAG, name))
+
+ # Special case: this instruction is implemented in ceval.c
+ # rather than bytecodes.c, so we need to add it explicitly
+ # here (at least until we add something to bytecodes.c to
+ # declare external instructions).
+ instrumented_ops.append('INSTRUMENTED_LINE')
+
+ # assert lists are unique
+ assert len(set(ops)) == len(ops)
+ assert len(set(instrumented_ops)) == len(instrumented_ops)
+
+ opname: list[str or None] = [None] * 512
+ opmap: dict = {}
+ markers: dict = {}
+
+ def map_op(op, name):
+ assert op < len(opname)
+ assert opname[op] is None
+ assert name not in opmap
+ opname[op] = name
+ opmap[name] = op
+
+
+ # 0 is reserved for cache entries. This helps debugging.
+ map_op(0, 'CACHE')
+
+ # 17 is reserved as it is the initial value for the specializing counter.
+ # This helps catch cases where we attempt to execute a cache.
+ map_op(17, 'RESERVED')
+
+ # 166 is RESUME - it is hard coded as such in Tools/build/deepfreeze.py
+ map_op(166, 'RESUME')
+
+ next_opcode = 1
+
+ for has_arg, name in sorted(ops):
+ if name in opmap:
+ continue # an anchored name, like CACHE
+ while opname[next_opcode] is not None:
+ next_opcode += 1
+ assert next_opcode < 255
+ map_op(next_opcode, name)
+
+ if has_arg and 'HAVE_ARGUMENT' not in markers:
+ markers['HAVE_ARGUMENT'] = next_opcode
+
+ # Instrumented opcodes are at the end of the valid range
+ min_instrumented = 254 - (len(instrumented_ops) - 1)
+ assert next_opcode <= min_instrumented
+ markers['MIN_INSTRUMENTED_OPCODE'] = min_instrumented
+ for i, op in enumerate(instrumented_ops):
+ map_op(min_instrumented + i, op)
+
+ # Pseudo opcodes are after the valid range
+ for i, op in enumerate(sorted(self.pseudos)):
+ map_op(256 + i, op)
+
+ assert 255 not in opmap # 255 is reserved
+ self.opmap = opmap
+ self.markers = markers
+
+ def write_opcode_ids(self, opcode_ids_h_filename, opcode_targets_filename):
+ """Write header file that defined the opcode IDs"""
+
+ with open(opcode_ids_h_filename, "w") as f:
+ # Create formatter
+ self.out = Formatter(f, 0)
+
+ self.write_provenance_header()
+
+ self.out.emit("")
+ self.out.emit("#ifndef Py_OPCODE_IDS_H")
+ self.out.emit("#define Py_OPCODE_IDS_H")
+ self.out.emit("#ifdef __cplusplus")
+ self.out.emit("extern \"C\" {")
+ self.out.emit("#endif")
+ self.out.emit("")
+ self.out.emit("/* Instruction opcodes for compiled code */")
+
+ def define(name, opcode):
+ self.out.emit(f"#define {name:<38} {opcode:>3}")
+
+ all_pairs = []
+ # the second item in the tuple sorts the markers before the ops
+ all_pairs.extend((i, 1, name) for (name, i) in self.markers.items())
+ all_pairs.extend((i, 2, name) for (name, i) in self.opmap.items())
+ for i, _, name in sorted(all_pairs):
+ assert name is not None
+ define(name, i)
+
+ self.out.emit("")
+ self.out.emit("#ifdef __cplusplus")
+ self.out.emit("}")
+ self.out.emit("#endif")
+ self.out.emit("#endif /* !Py_OPCODE_IDS_H */")
+
+ with open(opcode_targets_filename, "w") as f:
+ # Create formatter
+ self.out = Formatter(f, 0)
+
+ with self.out.block("static void *opcode_targets[256] =", ";"):
+ targets = ["_unknown_opcode"] * 256
+ for name, op in self.opmap.items():
+ if op < 256:
+ targets[op] = f"TARGET_{name}"
+ f.write(",\n".join([f" &&{s}" for s in targets]))
+
+
def write_metadata(self, metadata_filename: str, pymetadata_filename: str) -> None:
"""Write instruction metadata to output file."""
@@ -290,48 +464,33 @@ def write_metadata(self, metadata_filename: str, pymetadata_filename: str) -> No
self.out.emit("#define OPCODE_METADATA_SIZE 512")
self.out.emit("#define OPCODE_UOP_NAME_SIZE 512")
self.out.emit("#define OPCODE_MACRO_EXPANSION_SIZE 256")
- self.out.emit("")
- self.out.emit("#ifndef NEED_OPCODE_METADATA")
- self.out.emit(
- "extern const struct opcode_metadata "
- "_PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE];"
- )
- self.out.emit(
- "extern const struct opcode_macro_expansion "
- "_PyOpcode_macro_expansion[OPCODE_MACRO_EXPANSION_SIZE];"
- )
- self.out.emit(
- "extern const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE];"
- )
- self.out.emit("#else // if NEED_OPCODE_METADATA")
- self.out.emit(
+ with self.metadata_item(
"const struct opcode_metadata "
- "_PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = {"
- )
-
- # Write metadata for each instruction
- for thing in self.everything:
- match thing:
- case OverriddenInstructionPlaceHolder():
- continue
- case parsing.InstDef():
- if thing.kind != "op":
- self.write_metadata_for_inst(self.instrs[thing.name])
- case parsing.Macro():
- self.write_metadata_for_macro(self.macro_instrs[thing.name])
- case parsing.Pseudo():
- self.write_metadata_for_pseudo(self.pseudo_instrs[thing.name])
- case _:
- typing.assert_never(thing)
-
- # Write end of array
- self.out.emit("};")
+ "_PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE]",
+ "=",
+ ";"
+ ):
+ # Write metadata for each instruction
+ for thing in self.everything:
+ match thing:
+ case OverriddenInstructionPlaceHolder():
+ continue
+ case parsing.InstDef():
+ if thing.kind != "op":
+ self.write_metadata_for_inst(self.instrs[thing.name])
+ case parsing.Macro():
+ self.write_metadata_for_macro(self.macro_instrs[thing.name])
+ case parsing.Pseudo():
+ self.write_metadata_for_pseudo(self.pseudo_instrs[thing.name])
+ case _:
+ typing.assert_never(thing)
- with self.out.block(
+ with self.metadata_item(
"const struct opcode_macro_expansion "
- "_PyOpcode_macro_expansion[OPCODE_MACRO_EXPANSION_SIZE] =",
- ";",
+ "_PyOpcode_macro_expansion[OPCODE_MACRO_EXPANSION_SIZE]",
+ "=",
+ ";"
):
# Write macro expansion for each non-pseudo instruction
for thing in self.everything:
@@ -344,7 +503,9 @@ def write_metadata(self, metadata_filename: str, pymetadata_filename: str) -> No
if instr.kind == "inst" and instr.is_viable_uop():
# Construct a dummy Component -- input/output mappings are not used
part = Component(instr, instr.active_caches)
- self.write_macro_expansions(instr.name, [part])
+ self.write_macro_expansions(
+ instr.name, [part], instr.cache_offset
+ )
elif instr.kind == "inst" and variable_used(
instr.inst, "oparg1"
):
@@ -354,18 +515,49 @@ def write_metadata(self, metadata_filename: str, pymetadata_filename: str) -> No
self.write_super_expansions(instr.name)
case parsing.Macro():
mac = self.macro_instrs[thing.name]
- self.write_macro_expansions(mac.name, mac.parts)
+ self.write_macro_expansions(
+ mac.name, mac.parts, mac.cache_offset
+ )
case parsing.Pseudo():
pass
case _:
typing.assert_never(thing)
- with self.out.block(
- "const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE] =", ";"
+ with self.metadata_item(
+ "const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE]", "=", ";"
):
self.write_uop_items(lambda name, counter: f'[{name}] = "{name}",')
- self.out.emit("#endif // NEED_OPCODE_METADATA")
+ with self.metadata_item(
+ f"const char *const _PyOpcode_OpName[{1 + max(self.opmap.values())}]", "=", ";"
+ ):
+ for name in self.opmap:
+ self.out.emit(f'[{name}] = "{name}",')
+
+ deoptcodes = {}
+ for name, op in self.opmap.items():
+ if op < 256:
+ deoptcodes[name] = name
+ for name, family in self.families.items():
+ for m in family.members:
+ deoptcodes[m] = name
+ # special case:
+ deoptcodes['BINARY_OP_INPLACE_ADD_UNICODE'] = 'BINARY_OP'
+
+ with self.metadata_item(
+ f"const uint8_t _PyOpcode_Deopt[256]", "=", ";"
+ ):
+ for opt, deopt in sorted(deoptcodes.items()):
+ self.out.emit(f"[{opt}] = {deopt},")
+
+ self.out.emit("")
+ self.out.emit("#define EXTRA_CASES \\")
+ valid_opcodes = set(self.opmap.values())
+ with self.out.indent():
+ for op in range(256):
+ if op not in valid_opcodes:
+ self.out.emit(f"case {op}: \\")
+ self.out.emit(" ;\n")
with open(pymetadata_filename, "w") as f:
# Create formatter
@@ -373,6 +565,9 @@ def write_metadata(self, metadata_filename: str, pymetadata_filename: str) -> No
self.write_provenance_header()
+ # emit specializations
+ specialized_ops = set()
+
self.out.emit("")
self.out.emit("_specializations = {")
for name, family in self.families.items():
@@ -381,6 +576,7 @@ def write_metadata(self, metadata_filename: str, pymetadata_filename: str) -> No
with self.out.indent():
for m in family.members:
self.out.emit(f'"{m}",')
+ specialized_ops.update(family.members)
self.out.emit(f"],")
self.out.emit("}")
@@ -391,14 +587,26 @@ def write_metadata(self, metadata_filename: str, pymetadata_filename: str) -> No
'_specializations["BINARY_OP"].append('
'"BINARY_OP_INPLACE_ADD_UNICODE")'
)
+ specialized_ops.add("BINARY_OP_INPLACE_ADD_UNICODE")
- # Make list of specialized instructions
+ ops = sorted((id, name) for (name, id) in self.opmap.items())
+ # emit specialized opmap
self.out.emit("")
- self.out.emit(
- "_specialized_instructions = ["
- "opcode for family in _specializations.values() for opcode in family"
- "]"
- )
+ with self.out.block("_specialized_opmap ="):
+ for op, name in ops:
+ if name in specialized_ops:
+ self.out.emit(f"'{name}': {op},")
+
+ # emit opmap
+ self.out.emit("")
+ with self.out.block("opmap ="):
+ for op, name in ops:
+ if name not in specialized_ops:
+ self.out.emit(f"'{name}': {op},")
+
+ for name in ['MIN_INSTRUMENTED_OPCODE', 'HAVE_ARGUMENT']:
+ self.out.emit(f"{name} = {self.markers[name]}")
+
def write_pseudo_instrs(self) -> None:
"""Write the IS_PSEUDO_INSTR macro"""
@@ -428,7 +636,9 @@ def add(name: str) -> None:
if instr.kind == "op" and instr.is_viable_uop():
add(instr.name)
- def write_macro_expansions(self, name: str, parts: MacroParts) -> None:
+ def write_macro_expansions(
+ self, name: str, parts: MacroParts, cache_offset: int
+ ) -> None:
"""Write the macro expansions for a macro-instruction."""
# TODO: Refactor to share code with write_cody(), is_viaible_uop(), etc.
offset = 0 # Cache effect offset
@@ -448,7 +658,10 @@ def write_macro_expansions(self, name: str, parts: MacroParts) -> None:
)
return
if not part.active_caches:
- size, offset = OPARG_SIZES["OPARG_FULL"], 0
+ if part.instr.name == "SAVE_IP":
+ size, offset = OPARG_SIZES["OPARG_SAVE_IP"], cache_offset
+ else:
+ size, offset = OPARG_SIZES["OPARG_FULL"], 0
else:
# If this assert triggers, is_viable_uops() lied
assert len(part.active_caches) == 1, (name, part.instr.name)
@@ -511,7 +724,7 @@ def emit_metadata_entry(self, name: str, fmt: str, flags: InstructionFlags) -> N
if not flag_names:
flag_names.append("0")
self.out.emit(
- f" [{name}] = {{ true, {INSTR_FMT_PREFIX}{fmt},"
+ f"[{name}] = {{ true, {INSTR_FMT_PREFIX}{fmt},"
f" {' | '.join(flag_names)} }},"
)
@@ -551,7 +764,9 @@ def write_instructions(
case parsing.Macro():
n_macros += 1
mac = self.macro_instrs[thing.name]
- stacking.write_macro_instr(mac, self.out, self.families.get(mac.name))
+ stacking.write_macro_instr(
+ mac, self.out, self.families.get(mac.name)
+ )
# self.write_macro(self.macro_instrs[thing.name])
case parsing.Pseudo():
pass
@@ -587,7 +802,9 @@ def write_executor_instructions(
n_instrs += 1
self.out.emit("")
with self.out.block(f"case {thing.name}:"):
- instr.write(self.out, tier=TIER_TWO)
+ stacking.write_single_instr(
+ instr, self.out, tier=TIER_TWO
+ )
if instr.check_eval_breaker:
self.out.emit("CHECK_EVAL_BREAKER();")
self.out.emit("break;")
@@ -604,6 +821,35 @@ def write_executor_instructions(
file=sys.stderr,
)
+ def write_abstract_interpreter_instructions(
+ self, abstract_interpreter_filename: str, emit_line_directives: bool
+ ) -> None:
+ """Generate cases for the Tier 2 abstract interpreter/analzyer."""
+ with open(abstract_interpreter_filename, "w") as f:
+ self.out = Formatter(f, 8, emit_line_directives)
+ self.write_provenance_header()
+ for thing in self.everything:
+ match thing:
+ case OverriddenInstructionPlaceHolder():
+ pass
+ case parsing.InstDef():
+ instr = AbstractInstruction(self.instrs[thing.name].inst)
+ if instr.is_viable_uop() and instr.name not in SPECIALLY_HANDLED_ABSTRACT_INSTR:
+ self.out.emit("")
+ with self.out.block(f"case {thing.name}:"):
+ instr.write(self.out, tier=TIER_TWO)
+ self.out.emit("break;")
+ case parsing.Macro():
+ pass
+ case parsing.Pseudo():
+ pass
+ case _:
+ typing.assert_never(thing)
+ print(
+ f"Wrote some stuff to {abstract_interpreter_filename}",
+ file=sys.stderr,
+ )
+
def write_overridden_instr_place_holder(
self, place_holder: OverriddenInstructionPlaceHolder
) -> None:
@@ -620,8 +866,13 @@ def write_instr(self, instr: Instruction) -> None:
with self.out.block(f"TARGET({name})"):
if instr.predicted:
self.out.emit(f"PREDICTED({name});")
- instr.write(self.out)
+ self.out.static_assert_family_size(
+ instr.name, instr.family, instr.cache_offset
+ )
+ stacking.write_single_instr(instr, self.out, tier=TIER_ONE)
if not instr.always_exits:
+ if instr.cache_offset:
+ self.out.emit(f"next_instr += {instr.cache_offset};")
if instr.check_eval_breaker:
self.out.emit("CHECK_EVAL_BREAKER();")
self.out.emit(f"DISPATCH();")
@@ -643,8 +894,13 @@ def main():
# These raise OSError if output can't be written
a.write_instructions(args.output, args.emit_line_directives)
+
+ a.assign_opcode_ids()
+ a.write_opcode_ids(args.opcode_ids_h, args.opcode_targets_h)
a.write_metadata(args.metadata, args.pymetadata)
a.write_executor_instructions(args.executor_cases, args.emit_line_directives)
+ a.write_abstract_interpreter_instructions(args.abstract_interpreter_cases,
+ args.emit_line_directives)
if __name__ == "__main__":
diff --git a/Tools/cases_generator/instructions.py b/Tools/cases_generator/instructions.py
index aa94dbb07ea1c0..9143ae0db7be81 100644
--- a/Tools/cases_generator/instructions.py
+++ b/Tools/cases_generator/instructions.py
@@ -59,7 +59,7 @@ class Instruction:
block_line: int # First line of block in original code
# Computed by constructor
- always_exits: bool
+ always_exits: str # If the block always exits, its last line; else ""
has_deopt: bool
cache_offset: int
cache_effects: list[parsing.CacheEffect]
@@ -120,13 +120,13 @@ def __init__(self, inst: parsing.InstDef):
def is_viable_uop(self) -> bool:
"""Whether this instruction is viable as a uop."""
dprint: typing.Callable[..., None] = lambda *args, **kwargs: None
- # if self.name.startswith("CALL"):
- # dprint = print
+ if "FRAME" in self.name:
+ dprint = print
if self.name == "EXIT_TRACE":
return True # This has 'return frame' but it's okay
if self.always_exits:
- dprint(f"Skipping {self.name} because it always exits")
+ dprint(f"Skipping {self.name} because it always exits: {self.always_exits}")
return False
if len(self.active_caches) > 1:
# print(f"Skipping {self.name} because it has >1 cache entries")
@@ -140,23 +140,6 @@ def is_viable_uop(self) -> bool:
res = False
return res
- def write(self, out: Formatter, tier: Tiers = TIER_ONE) -> None:
- """Write one instruction, sans prologue and epilogue."""
-
- # Write a static assertion that a family's cache size is correct
- out.static_assert_family_size(self.name, self.family, self.cache_offset)
-
- # Write input stack effect variable declarations and initializations
- stacking.write_single_instr(self, out, tier)
-
- # Skip the rest if the block always exits
- if self.always_exits:
- return
-
- # Write cache effect
- if tier == TIER_ONE and self.cache_offset:
- out.emit(f"next_instr += {self.cache_offset};")
-
def write_body(
self,
out: Formatter,
@@ -248,6 +231,25 @@ def write_body(
InstructionOrCacheEffect = Instruction | parsing.CacheEffect
+# Instruction used for abstract interpretation.
+class AbstractInstruction(Instruction):
+ def __init__(self, inst: parsing.InstDef):
+ super().__init__(inst)
+
+ def write(self, out: Formatter, tier: Tiers = TIER_ONE) -> None:
+ """Write one abstract instruction, sans prologue and epilogue."""
+ stacking.write_single_instr_for_abstract_interp(self, out)
+
+ def write_body(
+ self,
+ out: Formatter,
+ dedent: int,
+ active_caches: list[ActiveCacheEffect],
+ tier: Tiers = TIER_ONE,
+ ) -> None:
+ pass
+
+
@dataclasses.dataclass
class Component:
instr: Instruction
@@ -322,16 +324,16 @@ def extract_block_text(block: parsing.Block) -> tuple[list[str], bool, int]:
return blocklines, check_eval_breaker, block_line
-def always_exits(lines: list[str]) -> bool:
+def always_exits(lines: list[str]) -> str:
"""Determine whether a block always ends in a return/goto/etc."""
if not lines:
- return False
+ return ""
line = lines[-1].rstrip()
# Indent must match exactly (TODO: Do something better)
if line[:12] != " " * 12:
- return False
+ return ""
line = line[12:]
- return line.startswith(
+ if line.startswith(
(
"goto ",
"return ",
@@ -340,4 +342,6 @@ def always_exits(lines: list[str]) -> bool:
"Py_UNREACHABLE()",
"ERROR_IF(true, ",
)
- )
+ ):
+ return line
+ return ""
diff --git a/Tools/cases_generator/stacking.py b/Tools/cases_generator/stacking.py
index d457ce01a8f438..8361eb99f88a7c 100644
--- a/Tools/cases_generator/stacking.py
+++ b/Tools/cases_generator/stacking.py
@@ -1,6 +1,7 @@
import dataclasses
import typing
+from flags import variable_used_unspecialized
from formatting import (
Formatter,
UNUSED,
@@ -61,14 +62,14 @@ def as_terms(self) -> list[tuple[str, str]]:
for eff in self.deep:
if eff.size:
terms.append(("-", maybe_parenthesize(eff.size)))
- elif eff.cond and eff.cond != "1":
+ elif eff.cond and eff.cond not in ("0", "1"):
terms.append(("-", f"({parenthesize_cond(eff.cond)} ? 1 : 0)"))
elif eff.cond != "0":
num -= 1
for eff in self.high:
if eff.size:
terms.append(("+", maybe_parenthesize(eff.size)))
- elif eff.cond and eff.cond != "1":
+ elif eff.cond and eff.cond not in ("0", "1"):
terms.append(("+", f"({parenthesize_cond(eff.cond)} ? 1 : 0)"))
elif eff.cond != "0":
num += 1
@@ -146,6 +147,8 @@ class EffectManager:
# Track offsets from stack pointer
min_offset: StackOffset
final_offset: StackOffset
+ # Link to previous manager
+ pred: "EffectManager | None" = None
def __init__(
self,
@@ -167,7 +170,8 @@ def __init__(
self.pokes.append(StackItem(offset=self.final_offset.clone(), effect=eff))
self.final_offset.higher(eff)
- if pred:
+ self.pred = pred
+ while pred:
# Replace push(x) + pop(y) with copy(x, y).
# Check that the sources and destinations are disjoint.
sources: set[str] = set()
@@ -192,6 +196,11 @@ def __init__(
sources,
destinations,
)
+ # See if we can get more copies of a earlier predecessor.
+ if self.peeks and not pred.pokes and not pred.peeks:
+ pred = pred.pred
+ else:
+ pred = None # Break
def adjust_deeper(self, eff: StackEffect) -> None:
for peek in self.peeks:
@@ -295,6 +304,7 @@ def write_single_instr(
[Component(instr, instr.active_caches)],
out,
tier,
+ 0,
)
except AssertionError as err:
raise AssertionError(f"Error writing instruction {instr.name}") from err
@@ -303,37 +313,32 @@ def write_single_instr(
def write_macro_instr(
mac: MacroInstruction, out: Formatter, family: Family | None
) -> None:
- parts = [part for part in mac.parts if isinstance(part, Component)]
-
- cache_adjust = 0
- for part in mac.parts:
- match part:
- case CacheEffect(size=size):
- cache_adjust += size
- case Component(instr=instr):
- cache_adjust += instr.cache_offset
- case _:
- typing.assert_never(part)
-
+ parts = [
+ part
+ for part in mac.parts
+ if isinstance(part, Component) and part.instr.name != "SAVE_IP"
+ ]
out.emit("")
with out.block(f"TARGET({mac.name})"):
if mac.predicted:
out.emit(f"PREDICTED({mac.name});")
- out.static_assert_family_size(mac.name, family, cache_adjust)
+ out.static_assert_family_size(mac.name, family, mac.cache_offset)
try:
- write_components(parts, out, TIER_ONE)
+ next_instr_is_set = write_components(parts, out, TIER_ONE, mac.cache_offset)
except AssertionError as err:
raise AssertionError(f"Error writing macro {mac.name}") from err
- if cache_adjust:
- out.emit(f"next_instr += {cache_adjust};")
- out.emit("DISPATCH();")
+ if not parts[-1].instr.always_exits and not next_instr_is_set:
+ if mac.cache_offset:
+ out.emit(f"next_instr += {mac.cache_offset};")
+ out.emit("DISPATCH();")
def write_components(
parts: list[Component],
out: Formatter,
tier: Tiers,
-) -> None:
+ cache_offset: int,
+) -> bool:
managers = get_managers(parts)
all_vars: dict[str, StackEffect] = {}
@@ -354,6 +359,7 @@ def write_components(
for name, eff in all_vars.items():
out.declare(eff, None)
+ next_instr_is_set = False
for mgr in managers:
if len(parts) > 1:
out.emit(f"// {mgr.instr.name}")
@@ -374,13 +380,25 @@ def write_components(
poke.as_stack_effect(lax=True),
)
+ if mgr.instr.name == "_PUSH_FRAME":
+ # Adjust stack to min_offset (input effects materialized)
+ out.stack_adjust(mgr.min_offset.deep, mgr.min_offset.high)
+ # Use clone() since adjust_inverse() mutates final_offset
+ mgr.adjust_inverse(mgr.final_offset.clone())
+
+ if mgr.instr.name == "SAVE_CURRENT_IP":
+ next_instr_is_set = True
+ if cache_offset:
+ out.emit(f"next_instr += {cache_offset};")
+
if len(parts) == 1:
mgr.instr.write_body(out, 0, mgr.active_caches, tier)
else:
with out.block(""):
mgr.instr.write_body(out, -4, mgr.active_caches, tier)
- if mgr is managers[-1]:
+ if mgr is managers[-1] and not next_instr_is_set:
+ # TODO: Explain why this adjustment is needed.
out.stack_adjust(mgr.final_offset.deep, mgr.final_offset.high)
# Use clone() since adjust_inverse() mutates final_offset
mgr.adjust_inverse(mgr.final_offset.clone())
@@ -391,3 +409,34 @@ def write_components(
poke.as_stack_effect(),
poke.effect,
)
+
+ return next_instr_is_set
+
+
+def write_single_instr_for_abstract_interp(
+ instr: Instruction, out: Formatter
+):
+ try:
+ _write_components_for_abstract_interp(
+ [Component(instr, instr.active_caches)],
+ out,
+ )
+ except AssertionError as err:
+ raise AssertionError(f"Error writing abstract instruction {instr.name}") from err
+
+
+def _write_components_for_abstract_interp(
+ parts: list[Component],
+ out: Formatter,
+):
+ managers = get_managers(parts)
+ for mgr in managers:
+ if mgr is managers[-1]:
+ out.stack_adjust(mgr.final_offset.deep, mgr.final_offset.high)
+ # Use clone() since adjust_inverse() mutates final_offset
+ mgr.adjust_inverse(mgr.final_offset.clone())
+ # NULL out the output stack effects
+ for poke in mgr.pokes:
+ if not poke.effect.size and poke.effect.name not in mgr.instr.unmoved_names:
+ out.emit(f"PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)"
+ f"PARTITIONNODE_NULLROOT, PEEK(-({poke.offset.as_index()})), true);")
diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py
index 059c2db27288db..9f7c47430772f7 100755
--- a/Tools/clinic/clinic.py
+++ b/Tools/clinic/clinic.py
@@ -928,7 +928,7 @@ def deprecate_positional_use(
if first_pos:
preamble = f"Passing {first_pos+1} positional arguments to "
depr_message = preamble + (
- f"{func.full_name}() is deprecated. Parameter {pstr} will "
+ f"{func.fulldisplayname}() is deprecated. Parameter {pstr} will "
f"become a keyword-only parameter in Python {major}.{minor}."
)
else:
@@ -939,7 +939,7 @@ def deprecate_positional_use(
f"argument{'s' if first_pos != 1 else ''} to "
)
depr_message = preamble + (
- f"{func.full_name}() is deprecated. Parameters {pstr} will "
+ f"{func.fulldisplayname}() is deprecated. Parameters {pstr} will "
f"become keyword-only parameters in Python {major}.{minor}."
)
@@ -1673,26 +1673,9 @@ def render_function(
full_name = f.full_name
template_dict = {'full_name': full_name}
-
- if new_or_init:
- assert isinstance(f.cls, Class)
- name = f.cls.name
- else:
- name = f.name
-
- template_dict['name'] = name
-
- if f.c_basename:
- c_basename = f.c_basename
- else:
- fields = full_name.split(".")
- if fields[-1] == '__new__':
- fields.pop()
- c_basename = "_".join(fields)
-
- template_dict['c_basename'] = c_basename
-
- template_dict['methoddef_name'] = c_basename.upper() + "_METHODDEF"
+ template_dict['name'] = f.displayname
+ template_dict['c_basename'] = f.c_basename
+ template_dict['methoddef_name'] = f.c_basename.upper() + "_METHODDEF"
template_dict['docstring'] = self.docstring_for_c_string(f)
@@ -2660,7 +2643,7 @@ class Function:
name: str
module: Module | Clinic
cls: Class | None
- c_basename: str | None
+ c_basename: str
full_name: str
return_converter: CReturnConverter
kind: FunctionKind
@@ -2678,6 +2661,28 @@ def __post_init__(self) -> None:
self.self_converter: self_converter | None = None
self.__render_parameters__: list[Parameter] | None = None
+ @functools.cached_property
+ def displayname(self) -> str:
+ """Pretty-printable name."""
+ if self.kind.new_or_init:
+ assert isinstance(self.cls, Class)
+ return self.cls.name
+ else:
+ return self.name
+
+ @functools.cached_property
+ def fulldisplayname(self) -> str:
+ parent: Class | Module | Clinic | None
+ if self.kind.new_or_init:
+ parent = getattr(self.cls, "parent", None)
+ else:
+ parent = self.parent
+ name = self.displayname
+ while isinstance(parent, (Module, Class)):
+ name = f"{parent.name}.{name}"
+ parent = parent.parent
+ return name
+
@property
def render_parameters(self) -> list[Parameter]:
if not self.__render_parameters__:
@@ -2775,6 +2780,13 @@ def get_displayname(self, i: int) -> str:
else:
return f'"argument {i}"'
+ def render_docstring(self) -> str:
+ add, out = text_accumulator()
+ add(f" {self.name}\n")
+ for line in self.docstring.split("\n"):
+ add(f" {line}\n")
+ return out().rstrip()
+
CConverterClassT = TypeVar("CConverterClassT", bound=type["CConverter"])
@@ -4555,6 +4567,11 @@ class ParamState(enum.IntEnum):
RIGHT_SQUARE_AFTER = 6
+class FunctionNames(NamedTuple):
+ full_name: str
+ c_basename: str
+
+
class DSLParser:
function: Function | None
state: StateKeeper
@@ -4818,6 +4835,39 @@ def state_dsl_start(self, line: str) -> None:
self.next(self.state_modulename_name, line)
+ @staticmethod
+ def parse_function_names(line: str) -> FunctionNames:
+ left, as_, right = line.partition(' as ')
+ full_name = left.strip()
+ c_basename = right.strip()
+ if as_ and not c_basename:
+ fail("No C basename provided after 'as' keyword")
+ if not c_basename:
+ fields = full_name.split(".")
+ if fields[-1] == '__new__':
+ fields.pop()
+ c_basename = "_".join(fields)
+ if not is_legal_py_identifier(full_name):
+ fail(f"Illegal function name: {full_name!r}")
+ if not is_legal_c_identifier(c_basename):
+ fail(f"Illegal C basename: {c_basename!r}")
+ return FunctionNames(full_name=full_name, c_basename=c_basename)
+
+ def update_function_kind(self, fullname: str) -> None:
+ fields = fullname.split('.')
+ name = fields.pop()
+ _, cls = self.clinic._module_and_class(fields)
+ if name in unsupported_special_methods:
+ fail(f"{name!r} is a special method and cannot be converted to Argument Clinic!")
+ if name == '__new__':
+ if (self.kind is not CLASS_METHOD) or (not cls):
+ fail("'__new__' must be a class method!")
+ self.kind = METHOD_NEW
+ elif name == '__init__':
+ if (self.kind is not CALLABLE) or (not cls):
+ fail("'__init__' must be a normal method, not a class or static method!")
+ self.kind = METHOD_INIT
+
def state_modulename_name(self, line: str) -> None:
# looking for declaration, which establishes the leftmost column
# line should be
@@ -4840,15 +4890,10 @@ def state_modulename_name(self, line: str) -> None:
# are we cloning?
before, equals, existing = line.rpartition('=')
- c_basename: str | None
if equals:
- full_name, _, c_basename = before.partition(' as ')
- full_name = full_name.strip()
- c_basename = c_basename.strip()
+ full_name, c_basename = self.parse_function_names(before)
existing = existing.strip()
- if (is_legal_py_identifier(full_name) and
- (not c_basename or is_legal_c_identifier(c_basename)) and
- is_legal_py_identifier(existing)):
+ if is_legal_py_identifier(existing):
# we're cloning!
fields = [x.strip() for x in existing.split('.')]
function_name = fields.pop()
@@ -4866,13 +4911,26 @@ def state_modulename_name(self, line: str) -> None:
function_name = fields.pop()
module, cls = self.clinic._module_and_class(fields)
- if not (existing_function.kind is self.kind and existing_function.coexist == self.coexist):
- fail("'kind' of function and cloned function don't match! "
- "(@classmethod/@staticmethod/@coexist)")
- function = existing_function.copy(
- name=function_name, full_name=full_name, module=module,
- cls=cls, c_basename=c_basename, docstring=''
- )
+ self.update_function_kind(full_name)
+ overrides: dict[str, Any] = {
+ "name": function_name,
+ "full_name": full_name,
+ "module": module,
+ "cls": cls,
+ "c_basename": c_basename,
+ "docstring": "",
+ }
+ if not (existing_function.kind is self.kind and
+ existing_function.coexist == self.coexist):
+ # Allow __new__ or __init__ methods.
+ if existing_function.kind.new_or_init:
+ overrides["kind"] = self.kind
+ # Future enhancement: allow custom return converters
+ overrides["return_converter"] = CReturnConverter()
+ else:
+ fail("'kind' of function and cloned function don't match! "
+ "(@classmethod/@staticmethod/@coexist)")
+ function = existing_function.copy(**overrides)
self.function = function
self.block.signatures.append(function)
(cls or module).functions.append(function)
@@ -4881,15 +4939,7 @@ def state_modulename_name(self, line: str) -> None:
line, _, returns = line.partition('->')
returns = returns.strip()
-
- full_name, _, c_basename = line.partition(' as ')
- full_name = full_name.strip()
- c_basename = c_basename.strip() or None
-
- if not is_legal_py_identifier(full_name):
- fail(f"Illegal function name: {full_name!r}")
- if c_basename and not is_legal_c_identifier(c_basename):
- fail(f"Illegal C basename: {c_basename!r}")
+ full_name, c_basename = self.parse_function_names(line)
return_converter = None
if returns:
@@ -4914,20 +4964,9 @@ def state_modulename_name(self, line: str) -> None:
function_name = fields.pop()
module, cls = self.clinic._module_and_class(fields)
- fields = full_name.split('.')
- if fields[-1] in unsupported_special_methods:
- fail(f"{fields[-1]} is a special method and cannot be converted to Argument Clinic! (Yet.)")
-
- if fields[-1] == '__new__':
- if (self.kind is not CLASS_METHOD) or (not cls):
- fail("__new__ must be a class method!")
- self.kind = METHOD_NEW
- elif fields[-1] == '__init__':
- if (self.kind is not CALLABLE) or (not cls):
- fail("__init__ must be a normal method, not a class or static method!")
- self.kind = METHOD_INIT
- if not return_converter:
- return_converter = init_return_converter()
+ self.update_function_kind(full_name)
+ if self.kind is METHOD_INIT and not return_converter:
+ return_converter = init_return_converter()
if not return_converter:
return_converter = CReturnConverter()
@@ -5515,13 +5554,7 @@ def format_docstring_signature(
self, f: Function, parameters: list[Parameter]
) -> str:
text, add, output = _text_accumulator()
- if f.kind.new_or_init:
- # classes get *just* the name of the class
- # not __new__, not __init__, and not module.classname
- assert f.cls
- add(f.cls.name)
- else:
- add(f.name)
+ add(f.displayname)
if self.forced_text_signature:
add(self.forced_text_signature)
else:
@@ -5686,23 +5719,11 @@ def add_parameter(text: str) -> None:
@staticmethod
def format_docstring_parameters(params: list[Parameter]) -> str:
"""Create substitution text for {parameters}"""
- text, add, output = _text_accumulator()
- spacer_line = False
- for param in params:
- docstring = param.docstring.strip()
- if not docstring:
- continue
- if spacer_line:
+ add, output = text_accumulator()
+ for p in params:
+ if p.docstring:
+ add(p.render_docstring())
add('\n')
- else:
- spacer_line = True
- add(" ")
- add(param.name)
- add('\n')
- stripped = rstrip_lines(docstring)
- add(textwrap.indent(stripped, " "))
- if text:
- add('\n')
return output()
def format_docstring(self) -> str:
diff --git a/Tools/scripts/summarize_stats.py b/Tools/scripts/summarize_stats.py
index f798b2f772d08a..2d198506fb5c6c 100644
--- a/Tools/scripts/summarize_stats.py
+++ b/Tools/scripts/summarize_stats.py
@@ -17,7 +17,7 @@
DEFAULT_DIR = "/tmp/py_stats/"
#Create list of all instruction names
-specialized = iter(opcode._specialized_instructions)
+specialized = iter(opcode._specialized_opmap.keys())
opname = ["<0>"]
for name in opcode.opname[1:]:
if name.startswith("<"):
@@ -244,7 +244,7 @@ def categorized_counts(opcode_stats):
specialized = 0
not_specialized = 0
specialized_instructions = {
- op for op in opcode._specialized_instructions
+ op for op in opcode._specialized_opmap.keys()
if "__" not in op}
for i, opcode_stat in enumerate(opcode_stats):
if "execution_count" not in opcode_stat:
diff --git a/configure b/configure
index 80b4a001c6d6d7..aaacf8d2669c16 100755
--- a/configure
+++ b/configure
@@ -11153,6 +11153,7 @@ fi
# On Linux, netlink.h requires asm/types.h
+# On FreeBSD, netlink.h is located in netlink/netlink.h
ac_fn_c_check_header_compile "$LINENO" "linux/netlink.h" "ac_cv_header_linux_netlink_h" "
#ifdef HAVE_ASM_TYPES_H
#include
@@ -11167,6 +11168,20 @@ then :
printf "%s\n" "#define HAVE_LINUX_NETLINK_H 1" >>confdefs.h
fi
+ac_fn_c_check_header_compile "$LINENO" "netlink/netlink.h" "ac_cv_header_netlink_netlink_h" "
+#ifdef HAVE_ASM_TYPES_H
+#include
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include
+#endif
+
+"
+if test "x$ac_cv_header_netlink_netlink_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_NETLINK_NETLINK_H 1" >>confdefs.h
+
+fi
# On Linux, qrtr.h requires asm/types.h
diff --git a/configure.ac b/configure.ac
index 8a84eaf6b370a1..ddf6da0b9da123 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2880,7 +2880,8 @@ AC_CHECK_HEADERS([net/if.h], [], [],
])
# On Linux, netlink.h requires asm/types.h
-AC_CHECK_HEADERS([linux/netlink.h], [], [], [
+# On FreeBSD, netlink.h is located in netlink/netlink.h
+AC_CHECK_HEADERS([linux/netlink.h netlink/netlink.h], [], [], [
#ifdef HAVE_ASM_TYPES_H
#include
#endif
diff --git a/pyconfig.h.in b/pyconfig.h.in
index dab8ebf64371f3..181dc3d7d11370 100644
--- a/pyconfig.h.in
+++ b/pyconfig.h.in
@@ -841,6 +841,9 @@
/* Define to 1 if you have the header file. */
#undef HAVE_NETINET_IN_H
+/* Define to 1 if you have the header file. */
+#undef HAVE_NETLINK_NETLINK_H
+
/* Define to 1 if you have the header file. */
#undef HAVE_NETPACKET_PACKET_H